Files
directus/packages/shared/src/composables/use-layout.ts
Nicola Krumschmidt 9ee6e97cd9 Move useLayout composable to shared and expose it through extensions-sdk (#10850)
* Move useLayout composable to shared

* Expose useLayout through extensions-sdk
2022-01-05 15:38:48 -05:00

112 lines
2.9 KiB
TypeScript

import { computed, reactive, toRefs, defineComponent, Ref, PropType, Component, ComputedRef } from 'vue';
import { Filter, LayoutConfig, ShowSelect } from '../types';
import { useExtensions } from './use-system';
const NAME_SUFFIX = 'wrapper';
const WRITABLE_PROPS = ['selection', 'layoutOptions', 'layoutQuery'] as const;
type WritableProp = typeof WRITABLE_PROPS[number];
function isWritableProp(prop: string): prop is WritableProp {
return (WRITABLE_PROPS as readonly string[]).includes(prop);
}
function createLayoutWrapper<Options, Query>(layout: LayoutConfig): Component {
return defineComponent({
name: `${layout.id}-${NAME_SUFFIX}`,
props: {
collection: {
type: String,
required: true,
},
selection: {
type: Array as PropType<(number | string)[]>,
default: () => [],
},
layoutOptions: {
type: Object as PropType<Options>,
default: () => ({}),
},
layoutQuery: {
type: Object as PropType<Query>,
default: () => ({}),
},
filter: {
type: Object as PropType<Filter>,
default: null,
},
filterUser: {
type: Object as PropType<Filter>,
default: null,
},
filterSystem: {
type: Object as PropType<Filter>,
default: null,
},
search: {
type: String as PropType<string | null>,
default: null,
},
showSelect: {
type: String as PropType<ShowSelect>,
default: 'multiple',
},
selectMode: {
type: Boolean,
default: false,
},
readonly: {
type: Boolean,
default: false,
},
resetPreset: {
type: Function as PropType<() => Promise<void>>,
default: null,
},
clearFilters: {
type: Function as PropType<() => void>,
default: null,
},
},
emits: WRITABLE_PROPS.map((prop) => `update:${prop}` as const),
setup(props, { emit }) {
const state: Record<string, unknown> = reactive({ ...layout.setup(props, { emit }), ...toRefs(props) });
for (const key in state) {
state[`onUpdate:${key}`] = (value: unknown) => {
if (isWritableProp(key)) {
emit(`update:${key}`, value);
} else if (!Object.keys(props).includes(key)) {
state[key] = value;
}
};
}
return { state };
},
render(ctx: any) {
return ctx.$slots.default !== undefined ? ctx.$slots.default({ layoutState: ctx.state }) : null;
},
});
}
export function useLayout<Options = any, Query = any>(
layoutId: Ref<string | null>
): { layoutWrapper: ComputedRef<Component> } {
const { layouts } = useExtensions();
const layoutWrappers = computed(() => layouts.value.map((layout) => createLayoutWrapper<Options, Query>(layout)));
const layoutWrapper = computed(() => {
const layout = layoutWrappers.value.find((layout) => layout.name === `${layoutId.value}-${NAME_SUFFIX}`);
if (layout === undefined) {
return layoutWrappers.value.find((layout) => layout.name === `tabular-${NAME_SUFFIX}`)!;
}
return layout;
});
return { layoutWrapper };
}