schlechtenburg/packages/core/lib/components/Block.tsx

173 lines
4.4 KiB
TypeScript
Raw Normal View History

2020-05-24 15:33:25 +00:00
import {
defineComponent,
2020-12-27 21:32:43 +00:00
computed,
2020-05-28 20:16:35 +00:00
watch,
2020-05-24 15:33:25 +00:00
PropType,
2020-05-28 20:16:35 +00:00
ref,
Ref,
2020-12-27 21:32:43 +00:00
} from 'vue';
2022-03-12 16:16:24 +00:00
import {
IBlockData,
OnUpdateBlockCb,
OnActivateNextCb,
OnRemoveSelfCb,
OnAppendBlockCb,
OnPrependBlockCb,
OnActivatePreviousCb,
} from '../types';
2020-12-30 13:34:23 +00:00
import { SbMode } from '../mode';
2021-03-08 15:29:35 +00:00
import { useResizeObserver, SymBlockDimensions } from '../use-resize-observer';
2020-12-30 13:34:23 +00:00
import { useActivation } from '../use-activation';
2021-03-07 17:47:28 +00:00
import { useBlockTree } from '../use-block-tree';
2020-12-30 13:34:23 +00:00
import { useDynamicBlocks } from '../use-dynamic-blocks';
2022-03-11 18:14:50 +00:00
import hoverCover from '../directives/hover-cover';
2020-05-20 14:21:08 +00:00
2021-03-08 15:29:35 +00:00
import SbMissingBlock from './MissingBlock';
2020-05-27 18:59:20 +00:00
2020-05-20 14:21:08 +00:00
import './Block.scss';
2022-03-13 22:12:18 +00:00
/**
* Displays a Schlechtenburg block either the mode of the schlechtenburg instance.
* You can use this to display child blocks inside your own blocks.
*/
2020-12-30 13:34:23 +00:00
export const SbBlock = defineComponent({
2020-05-20 14:21:08 +00:00
name: 'sb-block',
2022-03-11 18:14:50 +00:00
directives: {
hoverCover,
},
2020-05-20 14:21:08 +00:00
props: {
2022-03-13 22:12:18 +00:00
/**
* The state for the block.
*/
2020-05-27 15:06:14 +00:00
block: {
type: (null as unknown) as PropType<IBlockData<any>>,
2020-05-27 15:06:14 +00:00
required: true,
2020-05-27 13:57:57 +00:00
},
2022-03-13 22:12:18 +00:00
/**
* Called when the block should be updated.
*/
2022-03-12 16:16:24 +00:00
onUpdate: {
type: (null as unknown) as PropType<OnUpdateBlockCb>,
default: () => {},
},
2022-03-13 22:12:18 +00:00
/**
* Called when a sibling block should be inserted before the block
*/
2022-03-12 16:16:24 +00:00
onPrependBlock: {
type: (null as unknown) as PropType<OnPrependBlockCb>,
default: () => {},
},
2022-03-13 22:12:18 +00:00
/**
* Called when a sibling block should be inserted after the block
*/
2022-03-12 16:16:24 +00:00
onAppendBlock: {
type: (null as unknown) as PropType<OnAppendBlockCb>,
default: () => {},
},
2022-03-13 22:12:18 +00:00
/**
* Called when the block should be removed
*/
2022-03-12 16:16:24 +00:00
onRemoveSelf: {
type: (null as unknown) as PropType<OnRemoveSelfCb>,
default: () => {},
},
2022-03-13 22:12:18 +00:00
/**
* Called when the previous sibling block should be activated
*/
2022-03-12 16:16:24 +00:00
onActivatePrevious: {
type: (null as unknown) as PropType<OnActivatePreviousCb>,
default: () => {},
},
2022-03-13 22:12:18 +00:00
/**
* Called when the next sibling block should be activated
*/
2022-03-12 16:16:24 +00:00
onActivateNext: {
type: (null as unknown) as PropType<OnActivateNextCb>,
default: () => {},
},
2020-05-20 14:21:08 +00:00
},
2021-03-08 15:29:35 +00:00
setup(props, context) {
2020-05-28 20:16:35 +00:00
const el: Ref<null|HTMLElement> = ref(null);
2020-05-27 15:32:35 +00:00
const { mode, getBlock } = useDynamicBlocks();
2021-03-07 17:47:28 +00:00
const {
isActive,
activate,
} = useActivation(props.block.id);
2020-05-20 14:21:08 +00:00
const classes = computed(() => ({
'sb-block': true,
2020-05-24 20:39:14 +00:00
'sb-block_active': isActive.value,
2020-05-20 14:21:08 +00:00
}));
2021-03-08 15:29:35 +00:00
const { triggerSizeCalculation } = useResizeObserver(el, SymBlockDimensions);
2020-05-28 20:16:35 +00:00
watch(() => props.block.data, triggerSizeCalculation);
2021-03-07 17:47:28 +00:00
const { register } = useBlockTree();
register(props.block);
watch(props.block, () => { register(props.block); });
2020-05-28 20:16:35 +00:00
const onChildUpdate = (updated: {[key: string]: any}) => {
2021-02-22 18:13:37 +00:00
props.onUpdate({
2020-05-28 20:16:35 +00:00
...props.block,
data: {
...props.block.data,
...updated,
},
});
};
2020-12-30 20:17:34 +00:00
return () => {
2021-02-22 23:12:06 +00:00
const BlockComponent = getBlock(props.block.name)?.[mode.value] as any;
2020-12-30 20:17:34 +00:00
if (!BlockComponent) {
const MissingBlock = SbMissingBlock[mode.value];
return <MissingBlock
name={props.block.name}
2021-03-07 17:47:28 +00:00
blockId={props.block.id}
2020-12-30 20:17:34 +00:00
/>;
}
2022-03-20 13:49:44 +00:00
if (mode.value === SbMode.View) {
2021-02-22 23:12:06 +00:00
return <BlockComponent
data={props.block.data}
2021-03-07 17:47:28 +00:00
blockId={props.block.id}
2021-02-22 23:12:06 +00:00
/>;
2020-12-30 20:17:34 +00:00
}
return <div
ref={el}
class={classes.value}
2022-03-11 18:14:50 +00:00
v-hover-cover
2020-12-30 20:17:34 +00:00
>
2022-03-13 22:12:18 +00:00
{
/**
* This is an alternative toolbar location that parent blocks can use to offer UI elements specific to child blocks.
* @slot context-toolbar
*/
context.slots['context-toolbar'] ? context.slots['context-toolbar']() : null
}
2020-12-30 20:17:34 +00:00
<BlockComponent
data={props.block.data}
2021-03-07 17:47:28 +00:00
blockId={props.block.id}
2021-02-22 18:13:37 +00:00
onUpdate={onChildUpdate}
onPrependBlock={props.onPrependBlock}
onAppendBlock={props.onAppendBlock}
onRemoveSelf={props.onRemoveSelf}
onActivatePrevious={props.onActivatePrevious}
onActivateNext={props.onActivateNext}
2021-03-08 15:29:35 +00:00
{...{
2021-03-08 16:45:21 +00:00
onClick: ($event: MouseEvent) => {
2021-03-08 15:29:35 +00:00
$event.stopPropagation();
activate();
},
...context.attrs,
2020-12-30 20:17:34 +00:00
}}
/>
</div>;
};
2020-05-20 14:21:08 +00:00
},
});