116 lines
3.8 KiB
TypeScript
116 lines
3.8 KiB
TypeScript
import type { FormKitFrameworkContext, FormKitTypeDefinition } from '@formkit/core';
|
||
import type { FormKitInputs } from '@formkit/inputs';
|
||
import { createSection, label, outer } from '@formkit/inputs';
|
||
import type { CascadeSelectEmitsOptions, CascadeSelectProps } from 'primevue/cascadeselect';
|
||
import PrimevueCascadeselect from 'primevue/cascadeselect';
|
||
import { defineComponent, markRaw, ref } from 'vue';
|
||
import { floatLabel } from '../sections/floatLabel';
|
||
import { messages } from '../sections/messages';
|
||
import { help } from '../sections/help';
|
||
|
||
// https://formkit.com/inputs/dropdown
|
||
|
||
type PrimevueSelectListeners = {
|
||
'onUpdate:modelValue': CascadeSelectEmitsOptions['update:modelValue'];
|
||
'onBlur': CascadeSelectEmitsOptions['blur'];
|
||
};
|
||
|
||
const SchemaComponent = defineComponent(
|
||
(vueProps: { context: FormKitFrameworkContext }) => {
|
||
const formkitContext = vueProps.context;
|
||
const listeners: PrimevueSelectListeners = {
|
||
'onUpdate:modelValue': (value: unknown) => {
|
||
formkitContext.node.input(value);
|
||
},
|
||
'onBlur': async (e) => {
|
||
setTimeout(
|
||
() => formkitContext.handlers.blur.call(undefined, e as never),
|
||
166, // 因为会触发两次。所以让blur事件延迟一点,可以考虑优化。(Cascadeselect好像没有这个问题)
|
||
);
|
||
},
|
||
};
|
||
const p_options = ref();
|
||
const loading = ref(true);
|
||
|
||
const loadOptions = async () => {
|
||
try {
|
||
let result;
|
||
if (formkitContext.options instanceof Promise) {
|
||
result = await formkitContext.options;
|
||
} else {
|
||
console.warn('未支持的 options 类型 :>> ', typeof formkitContext.options);
|
||
}
|
||
p_options.value = result;
|
||
} catch (error) {
|
||
console.error('Failed to load options:', error);
|
||
p_options.value = [];
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
};
|
||
|
||
loadOptions(); // 立即加载options
|
||
|
||
return () => {
|
||
return (
|
||
<PrimevueCascadeselect
|
||
inputId={formkitContext.id}
|
||
optionLabel={formkitContext.optionLabel as never}
|
||
optionValue={formkitContext.optionValue as never}
|
||
optionGroupChildren={(formkitContext.optionGroupChildren as never) || 'children'}
|
||
optionGroupLabel={(formkitContext.optionGroupLabel as never) || (formkitContext.optionLabel as never)}
|
||
loading={loading.value}
|
||
options={p_options.value}
|
||
invalid={formkitContext.state.invalid}
|
||
fluid
|
||
disabled={!!formkitContext.disabled}
|
||
modelValue={formkitContext._value}
|
||
{...listeners}
|
||
/>
|
||
);
|
||
};
|
||
},
|
||
// https://cn.vuejs.org/api/general#definecomponent
|
||
// 目前仍然需要手动声明运行时的 props
|
||
// 在将来,我们计划提供一个 Babel 插件,自动推断并注入运行时 props (就像在单文件组件中的 defineProps 一样),以便省略运行时 props 的声明。
|
||
{
|
||
props: ['context'],
|
||
},
|
||
);
|
||
|
||
const input = createSection('input', () => ({
|
||
$cmp: markRaw(SchemaComponent) as never,
|
||
bind: '$attrs',
|
||
props: {
|
||
context: '$node.context',
|
||
},
|
||
}));
|
||
|
||
export const PCascadeSelect: FormKitTypeDefinition = {
|
||
type: 'input',
|
||
schema: outer(
|
||
floatLabel(
|
||
input(), //
|
||
label('$label'),
|
||
),
|
||
help('$help'),
|
||
messages(),
|
||
),
|
||
props: ['options', 'optionLabel', 'optionValue'],
|
||
schemaMemoKey: '72psvunq45', // Math.random().toString(36).substring(2, 15)
|
||
};
|
||
|
||
type OptionsType = CascadeSelectProps['options'];
|
||
|
||
declare module '@formkit/inputs' {
|
||
// https://formkit.com/essentials/custom-inputs#typescript-support
|
||
interface FormKitInputProps<Props extends FormKitInputs<Props>> {
|
||
PCascadeSelect: {
|
||
type: 'PCascadeSelect';
|
||
options: Promise<OptionsType>;
|
||
optionLabel: string;
|
||
optionValue: string;
|
||
};
|
||
}
|
||
}
|