feat: 添加 PDatePicker 组件
This commit is contained in:
@ -14,6 +14,7 @@ import { /* defaultConfig, */ bindings, plugin /* defaultConfig */ } from '@form
|
||||
import type { App } from 'vue';
|
||||
import { addAsteriskPlugin } from './formkit.config.plugin.addAsteriskPlugin';
|
||||
import { debugPlugin } from './formkit.config.plugin.debug';
|
||||
import { PDatePicker } from '@/__fk-inputs__/inputs/p-date-picker';
|
||||
|
||||
const plugins: FormKitPlugin[] = [
|
||||
// createLibraryPlugin(fkLibrary),
|
||||
@ -26,6 +27,7 @@ const plugins: FormKitPlugin[] = [
|
||||
PInputText,
|
||||
PInputPassword,
|
||||
PSelect,
|
||||
PDatePicker,
|
||||
}),
|
||||
// createLibraryPlugin(
|
||||
// {
|
||||
|
26
package.json
26
package.json
@ -14,31 +14,33 @@
|
||||
"@formkit/addons": "^1.6.9",
|
||||
"@formkit/core": "^1.6.9",
|
||||
"@formkit/icons": "^1.6.9",
|
||||
"@formkit/pro": "^0.127.8",
|
||||
"@formkit/pro": "^0.127.15",
|
||||
"@formkit/themes": "^1.6.9",
|
||||
"@formkit/vue": "^1.6.9",
|
||||
"@formkit/zod": "^1.6.9",
|
||||
"@headlessui/vue": "^1.7.23",
|
||||
"@primevue/forms": "^4.2.4",
|
||||
"@primevue/themes": "^4.2.4",
|
||||
"@primevue/forms": "^4.2.5",
|
||||
"@primevue/themes": "^4.2.5",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"i18next": "^24.0.5",
|
||||
"dayjs": "^1.11.13",
|
||||
"i18next": "^24.2.0",
|
||||
"postcss": "^8.4.49",
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.2.4",
|
||||
"sweetalert2": "^11.14.5",
|
||||
"tailwindcss": "^3.4.15",
|
||||
"primelocale": "^1.2.2",
|
||||
"primevue": "^4.2.5",
|
||||
"sweetalert2": "^11.15.3",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"vue": "^3.5.13",
|
||||
"zod-i18n-map": "^2.27.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@primevue/auto-import-resolver": "^4.2.4",
|
||||
"@primevue/auto-import-resolver": "^4.2.5",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||
"typescript": "~5.6.0",
|
||||
"unocss": "^0.65.0",
|
||||
"unplugin-vue-components": "^0.27.5",
|
||||
"vite": "^6.0.2",
|
||||
"typescript": "~5.7.2",
|
||||
"unocss": "^0.65.2",
|
||||
"unplugin-vue-components": "^0.28.0",
|
||||
"vite": "^6.0.5",
|
||||
"vue-tsc": "^2.1.10"
|
||||
}
|
||||
}
|
1277
pnpm-lock.yaml
generated
1277
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
106
src/App.vue
106
src/App.vue
@ -4,27 +4,12 @@ import AllCustom from './all-custom/all-custom.vue';
|
||||
import TutorialForm from './tutorial-form/index.vue';
|
||||
import ZodForm from './zod-form/index.vue';
|
||||
|
||||
const selectedCity = ref('NY');
|
||||
const loading = ref(false);
|
||||
const cities = ref([
|
||||
{ name: 'New York', code: 'NY' },
|
||||
{ name: 'Rome', code: 'RM' },
|
||||
{ name: 'London', code: 'LDN' },
|
||||
{ name: 'Istanbul', code: 'IST' },
|
||||
{ name: 'Paris', code: 'PRS' }
|
||||
]);
|
||||
const loadSelectedCity = () => {
|
||||
loading.value = true;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 2000);
|
||||
};
|
||||
const handleE = (eventName: string) => {
|
||||
return (...args: any[]) => {
|
||||
console.log('eventName :>> ', eventName);
|
||||
console.log('args :>> ', args);
|
||||
};
|
||||
};
|
||||
const datetime12h = ref();
|
||||
const datetime24h = ref();
|
||||
const time = ref();
|
||||
const date = ref();
|
||||
const dates = ref();
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@ -40,31 +25,62 @@ const handleE = (eventName: string) => {
|
||||
<!-- </div> -->
|
||||
|
||||
<div class="p-4 w-full bg-white rounded-lg shadow-md dark:bg-gray-800 dark:text-white mt-4">
|
||||
<Select
|
||||
v-model="selectedCity"
|
||||
:placeholder="loading ? 'Loading' : 'Select a City'"
|
||||
:loading="loading"
|
||||
class="w-full md:w-56"
|
||||
:options="cities"
|
||||
optionLabel="name"
|
||||
optionValue="code"
|
||||
@input="(e: any) => handleE('input')(e)"
|
||||
@value-change="(e) => handleE('value-change')(e)"
|
||||
@change="(e) => handleE('change')(e)"
|
||||
@blur="(e) => handleE('blur')(e)"
|
||||
></Select>
|
||||
<Select
|
||||
:options="cities"
|
||||
class="w-full md:w-56"
|
||||
>
|
||||
<template #value="slotProps">{{ slotProps.value }}</template>
|
||||
</Select>
|
||||
<Button
|
||||
id="load-selected-city"
|
||||
label="Load Selected City"
|
||||
@click="loadSelectedCity"
|
||||
|
||||
|
||||
<div class="card flex flex-wrap gap-4 items-start">
|
||||
<DatePicker
|
||||
v-model="date"
|
||||
view="month"
|
||||
dateFormat="mm/yy"
|
||||
/>
|
||||
{{ { selectedCity } }}
|
||||
|
||||
<DatePicker
|
||||
v-model="dates"
|
||||
selectionMode="range"
|
||||
:manualInput="false"
|
||||
/>
|
||||
|
||||
|
||||
<div class="flex-auto">
|
||||
<label
|
||||
for="datepicker-12h"
|
||||
class="font-bold block mb-2"
|
||||
> 12h Format </label>
|
||||
<DatePicker
|
||||
id="datepicker-12h"
|
||||
v-model="datetime12h"
|
||||
showTime
|
||||
hourFormat="12"
|
||||
fluid
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-auto">
|
||||
<label
|
||||
for="datepicker-24h"
|
||||
class="font-bold block mb-2"
|
||||
> 24h Format </label>
|
||||
<DatePicker
|
||||
id="datepicker-24h"
|
||||
v-model="datetime24h"
|
||||
showTime
|
||||
hourFormat="24"
|
||||
fluid
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-auto">
|
||||
<label
|
||||
for="datepicker-timeonly"
|
||||
class="font-bold block mb-2"
|
||||
> Time Only </label>
|
||||
<DatePicker
|
||||
id="datepicker-timeonly"
|
||||
v-model="time"
|
||||
timeOnly
|
||||
fluid
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
105
src/__fk-inputs__/inputs/p-date-picker.tsx
Normal file
105
src/__fk-inputs__/inputs/p-date-picker.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import type { FormKitFrameworkContext, FormKitTypeDefinition } from '@formkit/core';
|
||||
import type { FormKitInputs } from '@formkit/inputs';
|
||||
import { createSection, label, outer } from '@formkit/inputs';
|
||||
import type { DatePickerEmitsOptions, DatePickerProps } from 'primevue/datepicker';
|
||||
import PrimevueDatepicker from 'primevue/datepicker';
|
||||
import { defineComponent, markRaw } from 'vue';
|
||||
import { floatLabel } from '../sections/floatLabel';
|
||||
import { messages } from '../sections/messages';
|
||||
|
||||
// :plugins="[castNumber]"
|
||||
type PickerValue = Date | Array<Date> | Array<Date | null> | undefined | null;
|
||||
type PropValueToDate = (value: unknown) => PickerValue;
|
||||
type PropDateToValue = (date?: PickerValue) => unknown;
|
||||
|
||||
type PrimevueDatepickerListeners = {
|
||||
'onUpdate:modelValue': DatePickerEmitsOptions['update:modelValue'];
|
||||
'onBlur': DatePickerEmitsOptions['blur'];
|
||||
};
|
||||
|
||||
const SchemaComponent = defineComponent(
|
||||
(vueProps: { context: FormKitFrameworkContext & { valueToDate: PropValueToDate; dateToValue: PropDateToValue } }) => {
|
||||
const formkitContext = vueProps.context;
|
||||
const { valueToDate, dateToValue } = formkitContext;
|
||||
const listeners: PrimevueDatepickerListeners = {
|
||||
'onUpdate:modelValue': value => {
|
||||
let newValue = value as unknown;
|
||||
try {
|
||||
newValue = dateToValue(value);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
formkitContext.node.input(newValue);
|
||||
},
|
||||
'onBlur': async e => {
|
||||
setTimeout(
|
||||
() => formkitContext.handlers.blur.call(undefined, e as never),
|
||||
166, // 因为会触发两次。所以让blur事件延迟一点,可以考虑优化。
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
return () => {
|
||||
let value = formkitContext._value;
|
||||
try {
|
||||
value = valueToDate(formkitContext._value);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return (
|
||||
<PrimevueDatepicker
|
||||
inputId={formkitContext.id}
|
||||
fluid
|
||||
invalid={formkitContext.state.invalid}
|
||||
disabled={!!formkitContext.disabled}
|
||||
modelValue={value}
|
||||
dateFormat={formkitContext.dateFormat as never}
|
||||
manualInput={formkitContext.manualInput as never}
|
||||
{...listeners}
|
||||
/>
|
||||
);
|
||||
};
|
||||
},
|
||||
{
|
||||
props: ['context'],
|
||||
},
|
||||
);
|
||||
|
||||
const input = createSection('input', () => ({
|
||||
$cmp: markRaw(SchemaComponent) as never,
|
||||
bind: '$attrs',
|
||||
props: {
|
||||
context: '$node.context',
|
||||
},
|
||||
}));
|
||||
|
||||
export const PDatePicker: FormKitTypeDefinition = {
|
||||
type: 'input',
|
||||
schema: outer(
|
||||
floatLabel(
|
||||
input(), //
|
||||
label('$label'),
|
||||
),
|
||||
messages(),
|
||||
),
|
||||
props: ['valueToDate', 'dateToValue', 'dateFormat'],
|
||||
schemaMemoKey: 'q2dkascustq', // Math.random().toString(36).substring(2, 15)
|
||||
};
|
||||
|
||||
declare module '@formkit/inputs' {
|
||||
// https://formkit.com/essentials/custom-inputs#typescript-support
|
||||
interface FormKitInputProps<Props extends FormKitInputs<Props>> {
|
||||
PDatePicker: {
|
||||
type: 'PDatePicker';
|
||||
valueToDate?: PropValueToDate;
|
||||
dateToValue?: PropDateToValue;
|
||||
value?: unknown;
|
||||
view?: DatePickerProps['view'];
|
||||
/**
|
||||
* https://primevue.org/datepicker/#format
|
||||
*/
|
||||
dateFormat?: DatePickerProps['dateFormat'];
|
||||
manualInput?: DatePickerProps['manualInput'];
|
||||
};
|
||||
}
|
||||
}
|
@ -15,10 +15,10 @@ type PrimevueSelectListeners = {
|
||||
'onBlur': SelectEmitsOptions['blur'];
|
||||
};
|
||||
|
||||
const PSelectComp = defineComponent(
|
||||
const SchemaComponent = defineComponent(
|
||||
(vueProps: { context: FormKitFrameworkContext }) => {
|
||||
const formkitContext = vueProps.context;
|
||||
const primevueSelectInstance = ref<Record<string, unknown> | undefined>();
|
||||
const primevueSelectInstance = ref<{ label: string } | undefined>();
|
||||
const listeners: PrimevueSelectListeners = {
|
||||
'onUpdate:modelValue': (value: unknown) => {
|
||||
formkitContext.node.input(value);
|
||||
@ -98,7 +98,7 @@ const PSelectComp = defineComponent(
|
||||
);
|
||||
|
||||
const input = createSection('input', () => ({
|
||||
$cmp: markRaw(PSelectComp) as never,
|
||||
$cmp: markRaw(SchemaComponent) as never,
|
||||
bind: '$attrs',
|
||||
props: {
|
||||
context: '$node.context',
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { FormKitNode } from '@formkit/core';
|
||||
import { text } from '@formkit/inputs';
|
||||
import Swal from 'sweetalert2';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
async function submit(formData: Record<string, any>, formNode: FormKitNode) {
|
||||
console.group('submit');
|
||||
@ -98,6 +99,18 @@ const promiseOptions = new Promise<typeof K_OPTIONS>(resolve => {
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
/>
|
||||
<FormKit
|
||||
type="PDatePicker"
|
||||
name="PDatePicker"
|
||||
:manualInput="false"
|
||||
dateFormat="yy年mm月"
|
||||
:dateToValue="(date) => dayjs(date as Date).format('YYYY-MM')"
|
||||
:valueToDate="(value) => dayjs(value as string).toDate()"
|
||||
view="month"
|
||||
value="2022-01"
|
||||
label="选日期"
|
||||
validation="required"
|
||||
/>
|
||||
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<FormKit
|
||||
|
34
src/main.ts
34
src/main.ts
@ -1,9 +1,10 @@
|
||||
import Aura from "@primevue/themes/aura";
|
||||
import PrimeVue from "primevue/config";
|
||||
import ToastService from "primevue/toastservice";
|
||||
import { createApp } from "vue";
|
||||
import { setupFormKit } from "../formkit.config";
|
||||
import App from "./App.vue";
|
||||
import Aura from '@primevue/themes/aura';
|
||||
import zhCN from 'primelocale/zh-CN.json';
|
||||
import PrimeVue from 'primevue/config';
|
||||
import ToastService from 'primevue/toastservice';
|
||||
import { createApp } from 'vue';
|
||||
import { setupFormKit } from '../formkit.config';
|
||||
import App from './App.vue';
|
||||
|
||||
// import '@unocss/reset/normalize.css'
|
||||
// import '@unocss/reset/sanitize/sanitize.css'
|
||||
@ -12,15 +13,28 @@ import App from "./App.vue";
|
||||
// import '@unocss/reset/tailwind-compat.css'
|
||||
// import '@unocss/reset/tailwind.css'
|
||||
|
||||
import "primeicons/primeicons.css";
|
||||
import "virtual:uno.css";
|
||||
import 'primeicons/primeicons.css';
|
||||
import 'virtual:uno.css';
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(PrimeVue, { theme: { preset: Aura } });
|
||||
app.use(PrimeVue, {
|
||||
locale: {
|
||||
...zhCN['zh-CN'],
|
||||
noFileChosenMessage: '未选择文件',
|
||||
pending: '待上传',
|
||||
completed: '已上传',
|
||||
}, // usePrimeVue().config.locale
|
||||
theme: { preset: Aura },
|
||||
options: {
|
||||
prefix: 'p',
|
||||
darkModeSelector: 'system',
|
||||
cssLayer: false,
|
||||
},
|
||||
});
|
||||
app.use(ToastService);
|
||||
|
||||
// https://github.dev/formkit/auto-animate/blob/master/docs/src/examples/formkit/ActualFormKit.vue
|
||||
|
||||
setupFormKit(app);
|
||||
|
||||
app.mount("#app");
|
||||
app.mount('#app');
|
||||
|
Reference in New Issue
Block a user