diff --git a/packages/core/lib/App.tsx b/packages/core/lib/App.tsx index e63d271..5a48fc8 100644 --- a/packages/core/lib/App.tsx +++ b/packages/core/lib/App.tsx @@ -1,8 +1,9 @@ import { defineComponent, reactive, ref } from 'vue'; import Schlechtenburg from '/@components/Schlechtenburg'; -import { Block, SbMode } from '/@components/TreeElement'; +import { Block } from '/@/blocks'; +import { SbMode } from '/@/mode'; -import initialData from './initial-data.json'; +import initialData from './initial-data'; import './App.scss'; @@ -11,38 +12,40 @@ export default defineComponent({ setup() { const activeTab = ref('edit'); - const block = reactive(initialData) as Block; + const block: Block = reactive(initialData); return () => (
- { - block.name = newBlock.name; - block.blockId = newBlock.blockId; - block.data = newBlock.data; - }} - /> - - - -
-          {JSON.stringify(block, null, 2)}
-        
+ {(() => { + switch (activeTab.value) { + case SbMode.Edit: + return ) => { + block.data = newBlock.data; + }} + key="edit" + mode="edit" + />; + case SbMode.Edit: + return ; + case 'data': + return
{JSON.stringify(block, null, 2)}
; + } + })()}
); }, diff --git a/packages/core/lib/blocks.ts b/packages/core/lib/blocks.ts new file mode 100644 index 0000000..7959327 --- /dev/null +++ b/packages/core/lib/blocks.ts @@ -0,0 +1,34 @@ +import { Component } from 'vue'; + +export interface BlockDefinition { + name: string; + getDefaultData: any; + edit: Component; + display: Component; +} + +export interface BlockLibraryDefinition { + [name: string]: BlockDefinition; +} + +export interface BlockProps { + blockId: string; + data: T; +} + +export interface Block extends BlockProps { + name: string; +} + +export const model = { + prop: 'block', + event: 'update', +}; + +export const blockProps = { + blockId: { + type: String, + default: () => `${+(new Date())}`, + }, + data: { type: Object, default: () => ({}) }, +}; diff --git a/packages/core/lib/components/Schlechtenburg.tsx b/packages/core/lib/components/Schlechtenburg.tsx index fa8f596..3288493 100644 --- a/packages/core/lib/components/Schlechtenburg.tsx +++ b/packages/core/lib/components/Schlechtenburg.tsx @@ -8,16 +8,14 @@ import { } from 'vue'; import { model, - ActiveBlock, Block, - SbMode, - Mode, - EditorDimensions, BlockDefinition, BlockLibraryDefinition, - BlockLibrary, - useResizeObserver, -} from '/@components/TreeElement'; +} from '/@/blocks'; +import { Mode, SbMode } from '/@/mode'; +import { BlockLibrary } from '/@/use-dynamic-blocks'; +import { EditorDimensions, useResizeObserver } from '/@/use-resize-observer'; +import { ActiveBlock } from '/@/use-activation'; import SbBlock from '/@internal/Block'; @@ -30,8 +28,8 @@ import './Schlechtenburg.scss'; export interface SchlechtenburgProps { customBlocks: BlockDefinition[]; - eventUpdate: (b: Block) => void; - block: Block; + eventUpdate: (b: Block) => void; + block: Block; mode: SbMode; } @@ -42,18 +40,18 @@ export default defineComponent({ props: { customBlocks: { type: Array as PropType, default: () => [] }, - block: { type: Object as PropType, required: true }, + block: { type: Object as PropType>, required: true }, eventUpdate: { type: Function, default: () => {} }, mode: { - type: String as SbMode, - validator(value: string) { + type: String as PropType, + validator(value: any) { return Object.values(SbMode).includes(value); }, default: SbMode.Edit, }, }, - setup(props: SchlechtenburgProps) { + setup(props) { const el: Ref = ref(null); useResizeObserver(el, EditorDimensions); @@ -69,10 +67,7 @@ export default defineComponent({ 'sb-paragraph': SbParagraph, 'sb-heading': SbHeading, ...props.customBlocks.reduce( - ( - blocks, - block, - ) => ({ ...blocks, [block.name]: block }), + (blocks: {[name: string]: Block}, block: Block) => ({ ...blocks, [block.name]: block }), {}, ), }); diff --git a/packages/core/lib/components/TreeElement.ts b/packages/core/lib/components/TreeElement.ts deleted file mode 100644 index 2ae68b9..0000000 --- a/packages/core/lib/components/TreeElement.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { - Ref, - ref, - inject, - reactive, - computed, - watch, - provide, -} from 'vue'; - -export interface BlockDefinition { - name: string; - getDefaultData: any; - edit: () => Promise; - display: () => Promise; -} - -export interface BlockLibraryDefinition { - [name: string]: BlockDefinition; -} - -export interface BlockData { [name: string]: any } - -export interface Block { - name: string; - blockId: string; - data: BlockData; -} - -export interface BlockProps { - blockId: string; - data: { [key: string]: any}; -} - -export const model = { - prop: 'block', - event: 'update', -}; - -export const blockProps = { - blockId: { type: String, required: true }, - data: { type: Object, default: () => ({}) }, -}; - -export enum SbMode { - Edit = 'edit', - Display = 'display', -} -export const Mode = Symbol('Schlechtenburg mode'); -export const BlockLibrary = Symbol('Schlechtenburg block library'); -export function useDynamicBlocks() { - const mode = inject(Mode, ref(SbMode.Edit)); - const customBlocks: BlockLibraryDefinition = inject(BlockLibrary, reactive({})); - const getBlock = (name: string) => customBlocks[name][mode.value]; - - return { - mode, - customBlocks, - getBlock, - }; -} - -interface BlockRect { - height: number; - width: number; - left: number; - top: number; -} - -export const BlockDimensions = Symbol('Schlechtenburg block dimensions'); -export const EditorDimensions = Symbol('Schlechtenburg editor dimensions'); -export function useResizeObserver(el: Ref, symbol: symbol) { - const dimensions: Ref = ref(null); - provide(symbol, dimensions); - const triggerSizeCalculation = () => { - if (!el.value) { - return; - } - - const clientRect = el.value.getBoundingClientRect(); - dimensions.value = { - width: clientRect.width, - height: clientRect.height, - left: el.value.offsetLeft, - top: el.value.offsetTop, - }; - }; - - const resizeObserver = new ResizeObserver(triggerSizeCalculation); - const mutationObserver = new MutationObserver(triggerSizeCalculation); - - watch(el, () => { - if (!el.value) { - return; - } - resizeObserver.observe(el.value); - mutationObserver.observe(el.value, { attributes: true, childList: false, subtree: false }); - }); - - return { triggerSizeCalculation, dimensions }; -} - -export function useBlockSizing() { - const editorDimensions: Ref = inject(EditorDimensions, ref(null)); - const blockDimensions: Ref = inject(BlockDimensions, ref(null)); - - return { editorDimensions, blockDimensions }; -} - -export const ActiveBlock = Symbol('Schlechtenburg active block'); -export function useActivation(currentBlockId: string) { - const activeBlockId: Ref = inject(ActiveBlock, ref(null)); - const isActive = computed(() => activeBlockId.value === currentBlockId); - const activate = (blockId?: string|null) => { - activeBlockId.value = blockId !== undefined ? blockId : currentBlockId; - }; - const requestActivation = () => { - if (activeBlockId.value) { - return; - } - - activate(); - }; - - return { - isActive, - activate, - requestActivation, - }; -} diff --git a/packages/core/lib/components/internal/Block.tsx b/packages/core/lib/components/internal/Block.tsx index 31476cc..9937501 100644 --- a/packages/core/lib/components/internal/Block.tsx +++ b/packages/core/lib/components/internal/Block.tsx @@ -6,14 +6,11 @@ import { ref, Ref, } from 'vue'; -import { - Block, - useDynamicBlocks, - useActivation, - SbMode, - BlockDimensions, - useResizeObserver, -} from '/@components/TreeElement'; +import { Block } from '/@/blocks'; +import { SbMode } from '/@/mode'; +import { useResizeObserver, BlockDimensions } from '/@/use-resize-observer'; +import { useActivation } from '/@/use-activation'; +import { useDynamicBlocks } from '/@/use-dynamic-blocks'; import SbBlockOrdering from './BlockOrdering'; @@ -22,7 +19,7 @@ import './Block.scss'; interface BlockProps { block: Block; eventUpdate: (b?: Block) => void; - eventInsertBlock: (b?: Block) => void; + eventPrependBlock: (b?: Block) => void; eventAppendBlock: (b?: Block) => void; eventRemoveBlock: () => void; eventMoveUp: () => void; @@ -43,7 +40,7 @@ export default defineComponent({ default: null, }, eventUpdate: { type: Function, default: () => {} }, - eventInsertBlock: { type: Function, default: () => {} }, + eventPrependBlock: { type: Function, default: () => {} }, eventAppendBlock: { type: Function, default: () => {} }, eventRemoveBlock: { type: Function, default: () => {} }, eventMoveUp: { type: Function, default: () => {} }, @@ -88,31 +85,19 @@ export default defineComponent({ class={classes.value} >
- {props.sortable - ? - : null} + {context.slots['context-toolbar'] ? context.slots['context-toolbar']() : null} { - $event.stopPropagation(); - activate(); - }, - ...context.listeners, - }, + onClick={($event: MouseEvent) => { + $event.stopPropagation(); + activate(); }} + {...context.attrs} /> ; }, diff --git a/packages/core/lib/components/internal/BlockOrdering.tsx b/packages/core/lib/components/internal/BlockOrdering.tsx index 59fd461..6d7d684 100644 --- a/packages/core/lib/components/internal/BlockOrdering.tsx +++ b/packages/core/lib/components/internal/BlockOrdering.tsx @@ -3,17 +3,15 @@ import { watch, reactive, computed, - defineAsyncComponent, + defineComponent, } from 'vue'; -import { - useBlockSizing, -} from '/@components/TreeElement'; +import { useBlockSizing } from '/@/use-resize-observer'; import SbButton from './Button'; import './BlockOrdering.scss'; -export default defineAsyncComponent({ +export default defineComponent({ name: 'sb-block-ordering', props: { diff --git a/packages/core/lib/components/internal/BlockPicker.tsx b/packages/core/lib/components/internal/BlockPicker.tsx index 0d11ff2..e50a128 100644 --- a/packages/core/lib/components/internal/BlockPicker.tsx +++ b/packages/core/lib/components/internal/BlockPicker.tsx @@ -6,10 +6,10 @@ import { import { useDynamicBlocks, BlockDefinition, -} from '../TreeElement'; +} from '/@/use-dynamic-blocks'; -import SbButton from './Button'; -import SbModal from './Modal'; +import SbButton from '/@internal/Button'; +import SbModal from '/@internal/Modal'; import './BlockPicker.scss'; diff --git a/packages/core/lib/components/internal/BlockPlaceholder.tsx b/packages/core/lib/components/internal/BlockPlaceholder.tsx index 204448b..1059712 100644 --- a/packages/core/lib/components/internal/BlockPlaceholder.tsx +++ b/packages/core/lib/components/internal/BlockPlaceholder.tsx @@ -1,6 +1,6 @@ import { defineComponent } from 'vue'; -import { BlockDefinition } from '../TreeElement'; -import BlockPicker from './BlockPicker'; +import { BlockDefinition } from '/@/blocks'; +import BlockPicker from '/@internal/BlockPicker'; import './BlockPlaceholder.scss'; @@ -11,11 +11,7 @@ export default defineComponent({ return () => (
context.emit('insert-block', block), - }, - }} + onPickedBlock={(block: BlockDefinition) => context.emit('insert-block', block)} />
); diff --git a/packages/core/lib/components/internal/Button.tsx b/packages/core/lib/components/internal/Button.tsx index 2fd04b6..ad3ae84 100644 --- a/packages/core/lib/components/internal/Button.tsx +++ b/packages/core/lib/components/internal/Button.tsx @@ -9,10 +9,9 @@ export default defineComponent({ setup(props, context) { return () => (