Providing/injecting, adding blocks
This commit is contained in:
parent
2153b06b2d
commit
d49ea3e99f
11
src/App.tsx
11
src/App.tsx
|
@ -12,13 +12,16 @@ export default defineComponent({
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const block = reactive({
|
const block = reactive({
|
||||||
block: 'sb-layout',
|
name: 'sb-layout',
|
||||||
orientation: 'vertical',
|
blockId: `${+(new Date())}`,
|
||||||
children: [],
|
data: {
|
||||||
|
orientation: 'vertical',
|
||||||
|
children: [],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
console.log(block);
|
console.log('base block update', block);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { block };
|
return { block };
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
|
provide,
|
||||||
computed,
|
computed,
|
||||||
reactive,
|
reactive,
|
||||||
|
ref,
|
||||||
|
PropType,
|
||||||
} from '@vue/composition-api';
|
} from '@vue/composition-api';
|
||||||
import { model, useDynamicBlocks } from '@components/TreeElement';
|
import {
|
||||||
|
model,
|
||||||
|
ActiveBlock,
|
||||||
|
BlockProps,
|
||||||
|
BlockDefinition,
|
||||||
|
BlockLibraryDefinition,
|
||||||
|
BlockLibrary,
|
||||||
|
} from '@components/TreeElement';
|
||||||
|
|
||||||
|
import SbBlock from '@internal/Block';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'schlechtenburg-main',
|
name: 'schlechtenburg-main',
|
||||||
|
@ -11,29 +23,55 @@ export default defineComponent({
|
||||||
model,
|
model,
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
customBlocks: { type: (null as unknown) as PropType<BlockDefinition[]>, default: () => [] },
|
||||||
block: { type: Object, required: true },
|
block: { type: Object, required: true },
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, context) {
|
setup(props: BlockProps) {
|
||||||
const { getBlock } = useDynamicBlocks(context);
|
const activeBlock = ref(null);
|
||||||
|
provide(ActiveBlock, activeBlock);
|
||||||
|
|
||||||
return {
|
const blockLibrary: BlockLibraryDefinition = reactive({
|
||||||
getBlock,
|
'sb-layout': {
|
||||||
};
|
name: 'sb-layout',
|
||||||
|
edit: () => import('@user/Layout'),
|
||||||
|
display: () => import('@user/Layout'),
|
||||||
|
},
|
||||||
|
'sb-image': {
|
||||||
|
name: 'sb-image',
|
||||||
|
edit: () => import('@user/Image'),
|
||||||
|
display: () => import('@user/Image'),
|
||||||
|
},
|
||||||
|
'sb-paragraph': {
|
||||||
|
name: 'sb-paragraph',
|
||||||
|
edit: () => import('@user/Paragraph'),
|
||||||
|
display: () => import('@user/Paragraph'),
|
||||||
|
},
|
||||||
|
'sb-heading': {
|
||||||
|
name: 'sb-heading',
|
||||||
|
edit: () => import('@user/Heading'),
|
||||||
|
display: () => import('@user/Heading'),
|
||||||
|
},
|
||||||
|
...props.customBlocks.reduce(
|
||||||
|
(
|
||||||
|
blocks: BlockLibraryDefinition,
|
||||||
|
block: BlockLibraryDefinition,
|
||||||
|
) => ({ ...blocks, [block.name]: block }),
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
});
|
||||||
|
provide(BlockLibrary, blockLibrary);
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const Block = this.getBlock(this.block.name);
|
console.log('render base');
|
||||||
console.log(this.name, Block);
|
|
||||||
return (
|
return (
|
||||||
<Component
|
<SbBlock
|
||||||
class="sb-main"
|
class="sb-main"
|
||||||
user-components={this.components}
|
block={this.block}
|
||||||
data={this.block.data}
|
|
||||||
id={this.block.id}
|
|
||||||
{...{
|
{...{
|
||||||
on: {
|
on: {
|
||||||
blockUpdate: (block) => this.$emit('block-update', block),
|
update: (block: BlockDefinition) => this.$emit('update', block),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,34 +1,61 @@
|
||||||
import {
|
import {
|
||||||
Context,
|
Ref,
|
||||||
|
ref,
|
||||||
|
inject,
|
||||||
|
reactive,
|
||||||
|
computed,
|
||||||
} from '@vue/composition-api';
|
} from '@vue/composition-api';
|
||||||
|
|
||||||
type IComponentDefinition = { [name: string]: () => Promise<any> };
|
export const ActiveBlock = Symbol('Schlechtenburg active block');
|
||||||
|
export const BlockLibrary = Symbol('Schlechtenburg block library');
|
||||||
|
|
||||||
type IBlockData = {
|
export interface BlockDefinition {
|
||||||
name: string;
|
name: string;
|
||||||
id: string;
|
edit: () => Promise<any>;
|
||||||
|
display: () => Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BlockLibraryDefinition {
|
||||||
|
[name: string]: BlockDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BlockData {
|
||||||
|
name: string;
|
||||||
|
blockId: string|number;
|
||||||
data: { [name: string]: any };
|
data: { [name: string]: any };
|
||||||
}
|
}
|
||||||
|
|
||||||
type ITreeElementProps = {
|
export interface BlockProps {
|
||||||
id: string;
|
blockId: string|number;
|
||||||
data: { [key: string]: any};
|
data: { [key: string]: any};
|
||||||
};
|
}
|
||||||
|
|
||||||
export const model = {
|
export const model = {
|
||||||
prop: 'block',
|
prop: 'block',
|
||||||
event: 'block-update',
|
event: 'update',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const blockProps = {
|
export const blockProps = {
|
||||||
id: { type: String, required: true },
|
blockId: { type: [String, Number], required: true },
|
||||||
data: { type: Object, default: () => ({}) },
|
data: { type: Object, default: () => ({}) },
|
||||||
};
|
};
|
||||||
|
|
||||||
// export function useActivation
|
export function useDynamicBlocks() {
|
||||||
|
const customBlocks: BlockLibraryDefinition = inject(BlockLibrary, reactive({}));
|
||||||
|
const getBlock = (name: string) => customBlocks[name];
|
||||||
|
|
||||||
export function useDynamicBlocks(context: Context) {
|
return { customBlocks, getBlock };
|
||||||
const getBlock = (name: string) => context.root.$sb.blocks[name];
|
}
|
||||||
|
|
||||||
return { getBlock };
|
export function useActivation(currentBlockId: string|number) {
|
||||||
|
const activeBlockId: Ref<string|number|null> = inject(ActiveBlock, ref(null));
|
||||||
|
const isActive = computed(() => activeBlockId.value === currentBlockId);
|
||||||
|
const activate = (blockId?: string|number|null) => {
|
||||||
|
activeBlockId.value = blockId !== undefined ? blockId : currentBlockId;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isActive,
|
||||||
|
activate,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
import { computed, defineComponent } from '@vue/composition-api';
|
import {
|
||||||
|
computed,
|
||||||
|
defineComponent,
|
||||||
|
PropType,
|
||||||
|
} from '@vue/composition-api';
|
||||||
|
import {
|
||||||
|
BlockData,
|
||||||
|
useDynamicBlocks,
|
||||||
|
useActivation,
|
||||||
|
BlockDefinition,
|
||||||
|
} from '@components/TreeElement';
|
||||||
|
|
||||||
import './Block.scss';
|
import './Block.scss';
|
||||||
|
|
||||||
|
@ -6,43 +16,51 @@ export default defineComponent({
|
||||||
name: 'sb-block',
|
name: 'sb-block',
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
active: { type: Boolean, default: false },
|
block: { type: (null as unknown) as PropType<BlockData>, default: false },
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
|
const { isActive, activate } = useActivation(props.block.blockId);
|
||||||
|
const { getBlock } = useDynamicBlocks();
|
||||||
const classes = computed(() => ({
|
const classes = computed(() => ({
|
||||||
'sb-block': true,
|
'sb-block': true,
|
||||||
'sb-block_active': props.active,
|
'sb-block_active': isActive,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const activate = () => {
|
const onChildUpdate = (updated: {[key: string]: any}) => {
|
||||||
if (props.active) {
|
console.log('child update', updated);
|
||||||
return;
|
context.emit('update', {
|
||||||
}
|
...props.block,
|
||||||
|
data: {
|
||||||
context.emit('activate');
|
...props.block.data,
|
||||||
|
...updated,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
getBlock,
|
||||||
classes,
|
classes,
|
||||||
activate,
|
activate,
|
||||||
|
onChildUpdate,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
console.log('render block', this.block);
|
||||||
<div
|
const Block = this.getBlock(this.block.name).edit;
|
||||||
class="sb-block"
|
return <Block
|
||||||
tabindex="0"
|
data={this.block.data}
|
||||||
{...{
|
block-id={this.block.blockId}
|
||||||
on: {
|
{...{
|
||||||
click: this.activate,
|
attrs: this.$attrs,
|
||||||
},
|
on: {
|
||||||
}}
|
...this.$listeners,
|
||||||
>
|
update: this.onChildUpdate,
|
||||||
{this.$slots.toolbar}
|
'insert-block': (block: BlockDefinition) => this.$emit('insert-block', block),
|
||||||
{this.$slots.default ? this.$slots.default : <div>Your content here</div>}
|
'append-block': (block: BlockDefinition) => this.$emit('append-block', block),
|
||||||
</div>
|
},
|
||||||
);
|
}}
|
||||||
|
/>;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,25 +1,20 @@
|
||||||
import { defineComponent } from '@vue/composition-api';
|
import { defineComponent } from '@vue/composition-api';
|
||||||
import { treeElementProps, useDynamicComponents } from './TreeElement';
|
import { useDynamicComponents } from './TreeElement';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {},
|
||||||
...treeElementProps,
|
|
||||||
orientation: String,
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const getComponent = useDynamicComponents(props.components || {});
|
const { customBlocks } = useDynamicComponents(props.components || {});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getComponent,
|
customBlocks,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div class="sb-layout">
|
<div class="sb-block-picker">
|
||||||
{{ orientation }}
|
|
||||||
|
|
||||||
<component
|
<component
|
||||||
class="sb-main"
|
class="sb-main"
|
||||||
v-for="child in children"
|
v-for="child in children"
|
|
@ -1,19 +1,10 @@
|
||||||
.sb-block-placeholder {
|
.sb-block-placeholder {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 0px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
|
||||||
&__add {
|
&__add {
|
||||||
background-color: var(--grey-1);
|
background-color: var(--grey-1);
|
||||||
height: 50px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
pointer-events: all;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,12 @@ export default defineComponent({
|
||||||
type="button"
|
type="button"
|
||||||
{...{
|
{...{
|
||||||
on: {
|
on: {
|
||||||
click: () => this.$emit('add-block', {
|
click: () => this.$emit('insert-block', {
|
||||||
component: 'sb-paragraph',
|
name: 'sb-paragraph',
|
||||||
id: +(new Date()),
|
blockId: +(new Date()),
|
||||||
value: '',
|
data: {
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
import {
|
import {
|
||||||
|
inject,
|
||||||
reactive,
|
reactive,
|
||||||
|
computed,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
watchEffect,
|
watch,
|
||||||
} from '@vue/composition-api';
|
} from '@vue/composition-api';
|
||||||
import {
|
import {
|
||||||
model,
|
model,
|
||||||
treeElementProps,
|
blockProps,
|
||||||
useDynamicComponents,
|
useDynamicBlocks,
|
||||||
|
useActivation,
|
||||||
|
BlockData,
|
||||||
} from '@components/TreeElement';
|
} from '@components/TreeElement';
|
||||||
|
|
||||||
import SbBlock from '@internal/Block';
|
import SbBlock from '@internal/Block';
|
||||||
|
@ -21,51 +25,52 @@ export default defineComponent({
|
||||||
model,
|
model,
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
...treeElementProps,
|
...blockProps,
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, context) {
|
setup(props: BlockProps, context) {
|
||||||
const { getComponent } = useDynamicComponents(props.userComponents);
|
const { getBlock } = useDynamicBlocks();
|
||||||
|
const { isActive, activate } = useActivation(props.blockId);
|
||||||
|
|
||||||
const localData = reactive({
|
const localData = reactive({
|
||||||
orientation: props.tree.data.orientation,
|
orientation: props.data.orientation,
|
||||||
children: [...props.tree.data.children],
|
children: [...props.data.children],
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watch(() => props.data, () => {
|
||||||
localData.orientation = props.tree.data.orientation;
|
localData.orientation = props.data.orientation;
|
||||||
localData.children = [...props.tree.data.children];
|
localData.children = [...props.data.children];
|
||||||
});
|
});
|
||||||
|
|
||||||
const classes = {
|
const classes = computed(() => ({
|
||||||
'sb-layout': true,
|
'sb-layout': true,
|
||||||
|
'sb-layout_active': isActive,
|
||||||
[`sb-layout_${localData.orientation}`]: true,
|
[`sb-layout_${localData.orientation}`]: true,
|
||||||
};
|
}));
|
||||||
|
|
||||||
const toggleOrientation = () => {
|
const toggleOrientation = () => {
|
||||||
context.emit('data', {
|
context.emit('update', {
|
||||||
id: props.blockId,
|
|
||||||
|
|
||||||
...localData,
|
|
||||||
orientation: localData.orientation === 'vertical' ? 'horizontal' : 'vertical',
|
orientation: localData.orientation === 'vertical' ? 'horizontal' : 'vertical',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChildUpdate = (child, updated) => {
|
const onChildUpdate = (child, updated) => {
|
||||||
const index = localData.children.indexOf(child);
|
const index = localData.children.indexOf(child);
|
||||||
context.emit('data', {
|
context.emit('update', {
|
||||||
...localData,
|
|
||||||
children: [
|
children: [
|
||||||
...localData.children.slice(0, index),
|
...localData.children.slice(0, index),
|
||||||
updated,
|
{
|
||||||
|
...child,
|
||||||
|
...updated,
|
||||||
|
},
|
||||||
...localData.children.slice(index + 1),
|
...localData.children.slice(index + 1),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addBlock = (block) => {
|
const appendBlock = (block: BlockData) => {
|
||||||
context.emit('tree', {
|
console.log('append block', block);
|
||||||
...localData,
|
context.emit('update', {
|
||||||
children: [
|
children: [
|
||||||
...localData.children,
|
...localData.children,
|
||||||
block,
|
block,
|
||||||
|
@ -73,19 +78,35 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const insertBlock = (index: number, block: BlockData) => {
|
||||||
|
console.log('insert block', index, block);
|
||||||
|
context.emit('update', {
|
||||||
|
children: [
|
||||||
|
...localData.children.slice(0, index + 1),
|
||||||
|
block,
|
||||||
|
...localData.children.slice(index + 1),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
isActive,
|
||||||
|
activate,
|
||||||
|
|
||||||
classes,
|
classes,
|
||||||
onChildUpdate,
|
onChildUpdate,
|
||||||
toggleOrientation,
|
toggleOrientation,
|
||||||
localData,
|
localData,
|
||||||
getComponent,
|
getBlock,
|
||||||
addBlock,
|
appendBlock,
|
||||||
|
insertBlock,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
console.log('render layout');
|
||||||
return (
|
return (
|
||||||
<SbBlock class={this.classes}>
|
<div class={this.classes}>
|
||||||
<SbToolbar slot="toolbar">
|
<SbToolbar slot="toolbar">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -94,31 +115,31 @@ export default defineComponent({
|
||||||
click: this.toggleOrientation,
|
click: this.toggleOrientation,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>{this.localTree.orientation}</button>
|
>{this.localData.orientation}</button>
|
||||||
</SbToolbar>
|
</SbToolbar>
|
||||||
|
|
||||||
{...this.localTree.children.map((child) => {
|
{...this.localData.children.map((child, index) => (
|
||||||
const Component = this.getComponent(child.component);
|
<SbBlock
|
||||||
return <Component
|
|
||||||
class="sb-main"
|
|
||||||
key={child.id}
|
key={child.id}
|
||||||
components={this.components}
|
block={child}
|
||||||
tree={child}
|
|
||||||
{...{
|
{...{
|
||||||
on: {
|
on: {
|
||||||
tree: (updated) => this.onChildUpdate(child, updated),
|
update: (updated) => this.onChildUpdate(child, updated),
|
||||||
|
'insert-block': (block: BlockDefinition) => this.insertBlock(index, block),
|
||||||
|
'append-block': this.appendBlock,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>;
|
/>
|
||||||
})}
|
))}
|
||||||
|
|
||||||
<SbBlockPlaceholder
|
<SbBlockPlaceholder
|
||||||
{...{
|
{...{
|
||||||
on: {
|
on: {
|
||||||
'add-block': this.addBlock,
|
'insert-block': this.appendBlock,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SbBlock>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,12 +2,15 @@ import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
reactive,
|
reactive,
|
||||||
ref,
|
ref,
|
||||||
|
Ref,
|
||||||
onMounted,
|
onMounted,
|
||||||
|
watch,
|
||||||
} from '@vue/composition-api';
|
} from '@vue/composition-api';
|
||||||
import {
|
import {
|
||||||
model,
|
model,
|
||||||
treeElementProps,
|
blockProps,
|
||||||
useDynamicComponents,
|
BlockProps,
|
||||||
|
useActivation,
|
||||||
} from '@components/TreeElement';
|
} from '@components/TreeElement';
|
||||||
|
|
||||||
import SbBlock from '@internal/Block';
|
import SbBlock from '@internal/Block';
|
||||||
|
@ -21,56 +24,87 @@ export default defineComponent({
|
||||||
model,
|
model,
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
...treeElementProps,
|
...blockProps,
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, context) {
|
setup(props: BlockProps, context) {
|
||||||
const { localTree } = useTree(props);
|
const localData = reactive({
|
||||||
|
value: props.data.value,
|
||||||
|
focused: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputEl: Ref<null|HTMLElement> = ref(null);
|
||||||
|
|
||||||
|
const { isActive, activate } = useActivation(props.blockId);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (inputEl.value) {
|
||||||
|
inputEl.value.innerHTML = localData.value;
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
inputEl.value.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => props.data, () => {
|
||||||
|
localData.value = props.data.value;
|
||||||
|
if (inputEl.value) {
|
||||||
|
inputEl.value.innerHTML = localData.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const onTextUpdate = ($event: InputEvent) => {
|
const onTextUpdate = ($event: InputEvent) => {
|
||||||
localTree.value = $event.target.innerHTML;
|
localData.value = $event.target.innerHTML;
|
||||||
};
|
};
|
||||||
|
|
||||||
const focused = ref(false);
|
|
||||||
|
|
||||||
const classes = reactive({
|
const classes = reactive({
|
||||||
'sb-paragraph': true,
|
'sb-paragraph': true,
|
||||||
'sb-paragraph_focused': focused,
|
'sb-paragraph_focused': localData.focused,
|
||||||
});
|
});
|
||||||
|
|
||||||
const onFocus = () => {
|
const onFocus = () => {
|
||||||
console.log('focus');
|
localData.focused = true;
|
||||||
focused.value = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onBlur = () => {
|
const onBlur = () => {
|
||||||
console.log('blur');
|
localData.focused = false;
|
||||||
focused.value = false;
|
context.emit('update', {
|
||||||
context.emit('tree', {
|
value: localData.value,
|
||||||
value: localTree.value.value,
|
|
||||||
});
|
});
|
||||||
|
activate(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const inputEl = ref(null);
|
const onKeypress = ($event: KeyboardEvent) => {
|
||||||
|
if ($event.key === 'Enter') {
|
||||||
|
const blockId = +(new Date());
|
||||||
|
context.emit('insert-block', {
|
||||||
|
blockId,
|
||||||
|
name: 'sb-paragraph',
|
||||||
|
data: { value: '' },
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
activate(blockId);
|
||||||
console.log(inputEl);
|
|
||||||
inputEl.value.innerHTML = localTree.value;
|
$event.preventDefault();
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
classes,
|
classes,
|
||||||
localTree,
|
localData,
|
||||||
onTextUpdate,
|
onTextUpdate,
|
||||||
focused,
|
|
||||||
onFocus,
|
onFocus,
|
||||||
onBlur,
|
onBlur,
|
||||||
|
onKeypress,
|
||||||
inputEl,
|
inputEl,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
console.log('render paragraph');
|
||||||
return (
|
return (
|
||||||
<SbBlock>
|
<div class="sb-paragraph">
|
||||||
<SbToolbar>Paragraph editing</SbToolbar>
|
<SbToolbar>Paragraph editing</SbToolbar>
|
||||||
<p
|
<p
|
||||||
class={this.classes}
|
class={this.classes}
|
||||||
|
@ -81,10 +115,11 @@ export default defineComponent({
|
||||||
input: this.onTextUpdate,
|
input: this.onTextUpdate,
|
||||||
focus: this.onFocus,
|
focus: this.onFocus,
|
||||||
blur: this.onBlur,
|
blur: this.onBlur,
|
||||||
|
keypress: this.onKeypress,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
></p>
|
></p>
|
||||||
</SbBlock>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
/* eslint no-param-reassign: 0 */
|
/* eslint no-param-reassign: 0 */
|
||||||
|
|
||||||
interface UserBlock {
|
|
||||||
name: string;
|
|
||||||
edit: () => Promise<any>;
|
|
||||||
display: () => Promise<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addUserBlock(Vue, block) {
|
function addUserBlock(Vue, block) {
|
||||||
if (Vue.prototype.$sb.blocks[block.name]) {
|
if (Vue.prototype.$sb.blocks[block.name]) {
|
||||||
console.warn(`Block ${block.name} is already registered`);
|
console.warn(`Block ${block.name} is already registered`);
|
||||||
|
|
|
@ -1,19 +1,13 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Vuex from 'vuex';
|
|
||||||
import VueCompositionApi from '@vue/composition-api';
|
import VueCompositionApi from '@vue/composition-api';
|
||||||
import VueSchlechtenburg from './lib';
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
import './main.scss';
|
import './main.scss';
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
Vue.use(Vuex);
|
|
||||||
const store = new Vuex.Store({});
|
|
||||||
Vue.use(VueCompositionApi);
|
Vue.use(VueCompositionApi);
|
||||||
Vue.use(VueSchlechtenburg);
|
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
store,
|
|
||||||
render: (h) => h(App),
|
render: (h) => h(App),
|
||||||
}).$mount('#app');
|
}).$mount('#app');
|
||||||
|
|
Loading…
Reference in a new issue