Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
49a6823df0 | |||
89da01a51b |
12
.github/workflows/ci.yaml
vendored
12
.github/workflows/ci.yaml
vendored
@ -3,7 +3,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- unocss-fk
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
surge:
|
surge:
|
||||||
@ -17,3 +16,14 @@ jobs:
|
|||||||
cp dist/index.html dist/200.html
|
cp dist/index.html dist/200.html
|
||||||
npx surge --project ./dist --domain $DEPLOY_DOMAIN --token d843de16b331c626f10771245c56ed93 # npx surge token
|
npx surge --project ./dist --domain $DEPLOY_DOMAIN --token d843de16b331c626f10771245c56ed93 # npx surge token
|
||||||
echo the preview URL is $DEPLOY_DOMAIN
|
echo the preview URL is $DEPLOY_DOMAIN
|
||||||
|
netlify:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: yanhao98/composite-actions/setup-node-environment@main
|
||||||
|
- name: deploy
|
||||||
|
run: |
|
||||||
|
npx vite build
|
||||||
|
npx netlify deploy --prod --dir dist
|
||||||
|
env:
|
||||||
|
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||||
|
NETLIFY_SITE_ID: 9273cadf-2b0a-4616-bbd6-b06a33646100
|
||||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -22,8 +22,3 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
# Local Netlify folder
|
|
||||||
.netlify
|
|
||||||
|
|
||||||
components.d.ts
|
|
5
.npmrc
5
.npmrc
@ -1,4 +1 @@
|
|||||||
registry=https://nexus.oo1.dev/repository/npm/
|
shamefully-hoist=true
|
||||||
use-node-version=22.14.0
|
|
||||||
|
|
||||||
shamefully-hoist=true
|
|
||||||
|
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@ -3,12 +3,9 @@
|
|||||||
"source.fixAll": "explicit"
|
"source.fixAll": "explicit"
|
||||||
},
|
},
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "Vue.volar"
|
"editor.defaultFormatter": "Vue.volar",
|
||||||
},
|
|
||||||
"[typescript]": {
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
},
|
},
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.formatOnSaveMode": "file",
|
"editor.formatOnSaveMode": "file",
|
||||||
"typescript.tsdk": "node_modules/typescript/lib"
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
}
|
}
|
11
README.md
11
README.md
@ -1,30 +1,21 @@
|
|||||||
# [Vue FormKit Example](https://formkit.com)
|
# [Vue FormKit Example](https://formkit.com)
|
||||||
|
|
||||||
## Knowledge
|
## Knowledge
|
||||||
|
|
||||||
- https://youtu.be/v8Sb1mXDWa8
|
- https://youtu.be/v8Sb1mXDWa8
|
||||||
- [sections](https://formkit.com/inputs/text#sections)
|
- [sections](https://formkit.com/inputs/text#sections)
|
||||||
- [sections](https://formkit.com/essentials/inputs#sections)
|
- [sections](https://formkit.com/essentials/inputs#sections)
|
||||||
- [useformkitcontext](https://formkit.com/inputs/form#useformkitcontext)
|
- [useformkitcontext](https://formkit.com/inputs/form#useformkitcontext)
|
||||||
- [debouncing](https://formkit.com/essentials/inputs#debouncing)
|
|
||||||
|
|
||||||
延迟 prop 的默认值是 20 毫秒。然而,group 和 list 输入默认使用 0 毫秒,以防止防抖延迟在每个深度级别“累积”。
|
|
||||||
|
|
||||||
## Custom Input
|
## Custom Input
|
||||||
|
|
||||||
- https://formkit.com/guides/export-and-restructure-inputs
|
- https://formkit.com/guides/export-and-restructure-inputs
|
||||||
- `npx formkit@latest export`
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
- https://formkit.com/essentials/examples
|
- https://formkit.com/essentials/examples
|
||||||
|
|
||||||
## Theme
|
## Theme
|
||||||
|
|
||||||
- https://themes.formkit.com/editor?theme=regenesis
|
- https://themes.formkit.com/editor?theme=regenesis
|
||||||
- [Creating a Tailwind CSS theme for FormKit](https://dev.to/andrewboyd/creating-a-tailwind-css-theme-for-formkit-45o4)
|
- [Creating a Tailwind CSS theme for FormKit](https://dev.to/andrewboyd/creating-a-tailwind-css-theme-for-formkit-45o4)
|
||||||
- [issues: Tailwind prefix support for regenesis theme](https://github.com/formkit/formkit/issues/1157)
|
- [issues: Tailwind prefix support for regenesis theme](https://github.com/formkit/formkit/issues/1157)
|
||||||
|
|
||||||
## 3rd Party
|
## 3rd Party
|
||||||
|
- https://github.com/mathsgod/formkit-element
|
||||||
- https://github.com/mathsgod/formkit-element
|
|
39
formkit.addAsteriskPlugin.ts
Normal file
39
formkit.addAsteriskPlugin.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import type { FormKitNode } from "@formkit/core";
|
||||||
|
|
||||||
|
const legends = ['checkbox_multi', 'radio_multi', 'repeater', 'transferlist'];
|
||||||
|
export function addAsteriskPlugin(node: FormKitNode) {
|
||||||
|
if (['button', 'submit', 'hidden', 'group', 'list', 'meta'].includes(node.props.type)) return;
|
||||||
|
|
||||||
|
node.on('created', () => {
|
||||||
|
const legendOrLabel = legends.includes(`${node.props.type}${node.props.options ? '_multi' : ''}`) ? 'legend' : 'label';
|
||||||
|
|
||||||
|
console.group('[node created]', node.props.label || node.props.submitLabel)
|
||||||
|
console.debug(`node :>> `, node);
|
||||||
|
console.debug(`node.props.definition :>> `, node.props.definition);
|
||||||
|
// if (typeof node.props.definition!.schema === 'function') {
|
||||||
|
// console.debug(`node.props.definition.schema.call :>> `, node.props.definition!.schema.call(node.props.definition, {}));
|
||||||
|
// }
|
||||||
|
console.debug(`legendOrLabel :>> `, legendOrLabel);
|
||||||
|
console.groupEnd()
|
||||||
|
|
||||||
|
if (node.props.definition?.schemaMemoKey) {
|
||||||
|
node.props.definition.schemaMemoKey += `${node.props.options ? '_multi' : ''}_add_asterisk`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const schemaFn = node.props.definition!.schema!;
|
||||||
|
node.props.definition!.schema = (sectionsSchema = {}) => {
|
||||||
|
sectionsSchema[legendOrLabel] = {
|
||||||
|
children: ['$label', {
|
||||||
|
$el: 'span',
|
||||||
|
if: '$state.required',
|
||||||
|
attrs: {
|
||||||
|
class: '$classes.asterisk',
|
||||||
|
},
|
||||||
|
children: ['*']
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeof schemaFn === 'function' ? schemaFn(sectionsSchema) : schemaFn
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
import type { FormKitExtendableSchemaRoot, FormKitNode } from '@formkit/core';
|
|
||||||
|
|
||||||
const legends = ['checkbox_multi', 'radio_multi', 'repeater', 'transferlist'];
|
|
||||||
export function addAsteriskPlugin(node: FormKitNode) {
|
|
||||||
if (['button', 'submit', 'hidden', 'group', 'list', 'meta'].includes(node.props.type)) return;
|
|
||||||
|
|
||||||
node.on('created', () => {
|
|
||||||
const legendOrLabel = legends.includes(`${node.props.type}${node.props.options ? '_multi' : ''}`)
|
|
||||||
? 'legend'
|
|
||||||
: 'label';
|
|
||||||
|
|
||||||
if (!node.props.definition) return;
|
|
||||||
|
|
||||||
if (node.props.definition.schemaMemoKey) {
|
|
||||||
node.props.definition.schemaMemoKey += `${node.props.options ? '_multi' : ''}_add_asterisk`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const schemaFn = node.props.definition.schema! as FormKitExtendableSchemaRoot;
|
|
||||||
node.props.definition!.schema = (sectionsSchema = {}) => {
|
|
||||||
sectionsSchema[legendOrLabel] = {
|
|
||||||
children: [
|
|
||||||
'$label',
|
|
||||||
{
|
|
||||||
$el: 'span',
|
|
||||||
if: '$state.required',
|
|
||||||
attrs: {
|
|
||||||
class: '$classes.asterisk',
|
|
||||||
},
|
|
||||||
children: ['*'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
return schemaFn(sectionsSchema);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
export function debugPlugin(node: import('@formkit/core').FormKitNode) {
|
|
||||||
if (['button', 'submit', 'hidden', 'group', 'list', 'meta'].includes(node.props.type)) return;
|
|
||||||
|
|
||||||
node.on('created', () => {
|
|
||||||
console.group('[node created]', node.props.label || node.props.submitLabel || node.name);
|
|
||||||
console.debug(`node :>> `, node);
|
|
||||||
console.debug(`node.props.definition :>> `, node.props.definition);
|
|
||||||
console.groupEnd();
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,79 +1,56 @@
|
|||||||
import { form } from '@/__fk-inputs__/inputs/form';
|
import { createAutoAnimatePlugin, createAutoHeightTextareaPlugin } from '@formkit/addons'
|
||||||
import { PCascadeSelect } from '@/__fk-inputs__/inputs/p-cascade-select';
|
import type { FormKitOptions } from '@formkit/core'
|
||||||
import { PDatePicker } from '@/__fk-inputs__/inputs/p-date-picker';
|
import { createI18nPlugin, zh } from '@formkit/i18n'
|
||||||
import { PFileUpload } from '@/__fk-inputs__/inputs/p-file-upload';
|
import { genesisIcons } from '@formkit/icons'
|
||||||
import { PInputPassword } from '@/__fk-inputs__/inputs/p-input-password';
|
import { checkbox, createLibraryPlugin, form, group, list, number, range, submit, text, textarea, } from '@formkit/inputs'
|
||||||
import { PInputText } from '@/__fk-inputs__/inputs/p-input-text';
|
import { createProPlugin, toggle } from '@formkit/pro'
|
||||||
import { PSelect } from '@/__fk-inputs__/inputs/p-select';
|
import * as defaultRules from '@formkit/rules'
|
||||||
import { createAutoAnimatePlugin, createAutoHeightTextareaPlugin } from '@formkit/addons';
|
import { createThemePlugin } from '@formkit/themes'
|
||||||
import { autoAnimatePlugin } from '@formkit/auto-animate/vue';
|
import { createValidationPlugin } from '@formkit/validation'
|
||||||
import type { FormKitOptions, FormKitPlugin } from '@formkit/core';
|
import { /* defaultConfig, */ bindings, createInput } from '@formkit/vue'
|
||||||
import { register as decodeErrors } from '@formkit/dev';
|
import { addAsteriskPlugin } from './formkit.addAsteriskPlugin'
|
||||||
import { createI18nPlugin, zh } from '@formkit/i18n';
|
import { rootClasses } from "./formkit.config.theme"
|
||||||
import { createLibraryPlugin, group, list, submit } from '@formkit/inputs';
|
import HeadlessuiToggle from "./src/headlessui-switch.vue";
|
||||||
import * as defaultRules from '@formkit/rules';
|
|
||||||
import { createValidationPlugin } from '@formkit/validation';
|
|
||||||
import { /* defaultConfig, */ bindings, plugin /* defaultConfig */ } from '@formkit/vue';
|
const library = createLibraryPlugin({
|
||||||
import type { App } from 'vue';
|
text, form, submit, group, checkbox, range, list, number, textarea,
|
||||||
import { addAsteriskPlugin } from './formkit.config.plugin.addAsteriskPlugin';
|
'headlessuiSwitch': createInput(HeadlessuiToggle)
|
||||||
import { debugPlugin } from './formkit.config.plugin.debug';
|
})
|
||||||
|
const validation = createValidationPlugin(defaultRules)
|
||||||
|
const i18n = createI18nPlugin({ zh })
|
||||||
|
const theme = undefined;
|
||||||
|
const icons = genesisIcons;
|
||||||
|
const themePlugin = createThemePlugin(theme, icons/* , iconLoaderUrl, iconLoader */)
|
||||||
|
|
||||||
|
const apiKey = 'fk-6cdd5192223'
|
||||||
|
export default {
|
||||||
|
plugins: [
|
||||||
|
createProPlugin(apiKey, { toggle }),
|
||||||
|
|
||||||
|
library,
|
||||||
|
|
||||||
|
themePlugin, bindings, i18n, validation, addAsteriskPlugin,
|
||||||
|
|
||||||
|
// https://github.com/formkit/formkit/blob/ac1947a305eb5082ba95f53800305d080787cb32/packages/addons/src/plugins/autoHeightTextarea.ts
|
||||||
|
createAutoHeightTextareaPlugin(),
|
||||||
|
|
||||||
const plugins: FormKitPlugin[] = [
|
|
||||||
// createLibraryPlugin(fkLibrary),
|
|
||||||
createLibraryPlugin({
|
|
||||||
submit,
|
|
||||||
list,
|
|
||||||
group,
|
|
||||||
// ==============================
|
|
||||||
form,
|
|
||||||
PInputText,
|
|
||||||
PInputPassword,
|
|
||||||
PSelect,
|
|
||||||
PDatePicker,
|
|
||||||
PCascadeSelect,
|
|
||||||
PFileUpload,
|
|
||||||
}),
|
|
||||||
// createLibraryPlugin(
|
|
||||||
// {
|
|
||||||
// 'headlessuiSwitch': createInput(HeadlessuiToggle),
|
|
||||||
// }
|
|
||||||
// ),
|
|
||||||
// createThemePlugin(
|
|
||||||
// theme: undefined /* icons: genesisIcons, iconLoaderUrl, iconLoader */,
|
|
||||||
// ),
|
|
||||||
// #############################
|
|
||||||
bindings,
|
|
||||||
createI18nPlugin({ zh }),
|
|
||||||
createValidationPlugin(defaultRules),
|
|
||||||
addAsteriskPlugin,
|
|
||||||
createAutoHeightTextareaPlugin(/* https://github.com/formkit/formkit/blob/ac1947a305eb5082ba95f53800305d080787cb32/packages/addons/src/plugins/autoHeightTextarea.ts */),
|
|
||||||
createAutoAnimatePlugin(
|
|
||||||
// https://auto-animate.formkit.com/#usage
|
// https://auto-animate.formkit.com/#usage
|
||||||
// https://github.com/formkit/auto-animate/
|
// https://github.com/formkit/auto-animate/
|
||||||
// https://github.com/formkit/formkit/blob/46d64d05c1b37875fc6227853f2bcfa987550c91/packages/addons/src/plugins/autoAnimatePlugin.ts
|
// https://github.com/formkit/formkit/blob/46d64d05c1b37875fc6227853f2bcfa987550c91/packages/addons/src/plugins/autoAnimatePlugin.ts
|
||||||
{
|
createAutoAnimatePlugin(
|
||||||
duration: 250,
|
{
|
||||||
easing: 'ease-in-out',
|
duration: 250,
|
||||||
},
|
easing: 'ease-in-out',
|
||||||
{
|
},
|
||||||
/* optional animation targets object */
|
// {
|
||||||
// default:
|
// /* optional animation targets object */
|
||||||
global: ['outer', 'inner'],
|
// // default:
|
||||||
form: ['form'],
|
// global: ['outer', 'inner'],
|
||||||
repeater: ['items'],
|
// form: ['form'],
|
||||||
},
|
// repeater: ['items'],
|
||||||
),
|
// }
|
||||||
];
|
)
|
||||||
|
],
|
||||||
if (import.meta.env.VITE_DEBUG_FORMKIT === 'true') plugins.push(debugPlugin);
|
config: { rootClasses },
|
||||||
|
} satisfies FormKitOptions
|
||||||
const config: FormKitOptions = {
|
|
||||||
plugins,
|
|
||||||
config: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
export function setupFormKit(app: App) {
|
|
||||||
decodeErrors();
|
|
||||||
app.use(plugin, config);
|
|
||||||
app.use(autoAnimatePlugin); // v-auto-animate="{ duration: 100 }"
|
|
||||||
}
|
|
91
index.html
91
index.html
@ -1,69 +1,30 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<link
|
|
||||||
rel="icon"
|
|
||||||
type="image/svg+xml"
|
|
||||||
href="/vite.svg"
|
|
||||||
/>
|
|
||||||
<meta
|
|
||||||
name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
|
||||||
/>
|
|
||||||
<title>Vue FormKit Example</title>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="/src/assets/tailwind.css"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="/src/assets/main.css"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<script>
|
<head>
|
||||||
function setAppHeight() {
|
<meta charset="UTF-8" />
|
||||||
const app = document.getElementById('app');
|
<link
|
||||||
app.style.minHeight = `${window.innerHeight}px`;
|
rel="icon"
|
||||||
}
|
type="image/svg+xml"
|
||||||
|
href="/vite.svg"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0"
|
||||||
|
/>
|
||||||
|
<title>Vue FormKit Example</title>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="/src/assets/main.css"
|
||||||
|
>
|
||||||
|
</head>
|
||||||
|
|
||||||
window.addEventListener('resize', setAppHeight);
|
<body>
|
||||||
window.addEventListener('load', setAppHeight);
|
<div id="app"></div>
|
||||||
</script>
|
<script
|
||||||
<style>
|
type="module"
|
||||||
#app {
|
src="/src/main.ts"
|
||||||
min-height: 100vh;
|
></script>
|
||||||
max-width: 100vw;
|
</body>
|
||||||
overflow-x: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
@supports (min-height: 100dvh) {
|
</html>
|
||||||
#app {
|
|
||||||
min-height: 100dvh;
|
|
||||||
max-width: 100dvw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-wrapper {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="app">
|
|
||||||
<div
|
|
||||||
class="page-wrapper"
|
|
||||||
style="display: flex; justify-content: center; align-items: center"
|
|
||||||
>
|
|
||||||
Loading...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script
|
|
||||||
type="module"
|
|
||||||
src="/src/main.ts"
|
|
||||||
></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
46
package.json
46
package.json
@ -7,42 +7,30 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --port 1115",
|
"dev": "vite --port 1115",
|
||||||
"build": "vue-tsc -b && vite build",
|
"build": "vue-tsc -b && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview"
|
||||||
"preview:netlify": "netlify deploy --dir dist"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formkit/addons": "^1.6.9",
|
"@formkit/addons": "^1.6.9",
|
||||||
"@formkit/core": "^1.6.9",
|
"@formkit/core": "latest",
|
||||||
"@formkit/icons": "^1.6.9",
|
"@formkit/icons": "latest",
|
||||||
"@formkit/pro": "^0.127.21",
|
"@formkit/pro": "^0.127.7",
|
||||||
"@formkit/themes": "^1.6.9",
|
"@formkit/themes": "latest",
|
||||||
"@formkit/vue": "1.6.10-fix.202501212134",
|
"@formkit/vue": "latest",
|
||||||
"@formkit/zod": "^1.6.9",
|
"@formkit/zod": "^1.6.9",
|
||||||
"@headlessui/vue": "^1.7.23",
|
"@headlessui/vue": "^1.7.23",
|
||||||
"@primevue/forms": "^4.2.5",
|
"autoprefixer": "latest",
|
||||||
"@primevue/themes": "^4.2.5",
|
"i18next": "^23.16.6",
|
||||||
"autoprefixer": "^10.4.20",
|
"postcss": "latest",
|
||||||
"axios": "^1.7.9",
|
"sweetalert2": "^11.14.5",
|
||||||
"dayjs": "^1.11.13",
|
"tailwindcss": "latest",
|
||||||
"i18next": "^24.2.2",
|
|
||||||
"postcss": "^8.5.2",
|
|
||||||
"primeicons": "^7.0.0",
|
|
||||||
"primelocale": "^1.6.0",
|
|
||||||
"primevue": "4.2.5",
|
|
||||||
"sweetalert2": "^11.17.2",
|
|
||||||
"tailwindcss": "^3.4.17",
|
|
||||||
"utils4u": "^4.0.0",
|
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"zod-i18n-map": "^2.27.0"
|
"zod-i18n-map": "^2.27.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@primevue/auto-import-resolver": "^4.2.5",
|
"@vitejs/plugin-vue": "^5.2.0",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"netlify-cli": "^17.37.2",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
"typescript": "~5.6.3",
|
||||||
"typescript": "~5.7.3",
|
"vite": "^5.4.11",
|
||||||
"unocss": "^65.5.0",
|
"vue-tsc": "^2.1.10"
|
||||||
"unplugin-vue-components": "^28.2.0",
|
|
||||||
"vite": "^6.1.0",
|
|
||||||
"vue-tsc": "^2.2.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
9609
pnpm-lock.yaml
generated
9609
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
109
src/App.vue
109
src/App.vue
@ -1,110 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import TutorialForm from './tutorial-form/index.vue'
|
||||||
import AllCustom from './all-custom/all-custom.vue';
|
import ZodForm from './zod-form/index.vue'
|
||||||
import TutorialForm from './tutorial-form/index.vue';
|
|
||||||
import ZodForm from './zod-form/index.vue';
|
|
||||||
|
|
||||||
const selectedCity = ref();
|
|
||||||
const countries = ref([
|
|
||||||
{
|
|
||||||
name: 'Australia',
|
|
||||||
code: 'AU',
|
|
||||||
states: [
|
|
||||||
{
|
|
||||||
name: 'New South Wales',
|
|
||||||
cities: [
|
|
||||||
{ cname: 'Sydney', code: 'A-SY' },
|
|
||||||
{ cname: 'Newcastle', code: 'A-NE' },
|
|
||||||
{ cname: 'Wollongong', code: 'A-WO' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Queensland',
|
|
||||||
cities: [
|
|
||||||
{ cname: 'Brisbane', code: 'A-BR' },
|
|
||||||
{ cname: 'Townsville', code: 'A-TO' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Canada',
|
|
||||||
code: 'CA',
|
|
||||||
states: [
|
|
||||||
{
|
|
||||||
name: 'Quebec',
|
|
||||||
cities: [
|
|
||||||
{ cname: 'Montreal', code: 'C-MO' },
|
|
||||||
{ cname: 'Quebec City', code: 'C-QU' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Ontario',
|
|
||||||
cities: [
|
|
||||||
{ cname: 'Ottawa', code: 'C-OT' },
|
|
||||||
{ cname: 'Toronto', code: 'C-TO' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'United States',
|
|
||||||
code: 'US',
|
|
||||||
states: [
|
|
||||||
{
|
|
||||||
name: 'California',
|
|
||||||
cities: [
|
|
||||||
{ cname: 'Los Angeles', code: 'US-LA' },
|
|
||||||
{ cname: 'San Diego', code: 'US-SD' },
|
|
||||||
{ cname: 'San Francisco', code: 'US-SF' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Florida',
|
|
||||||
cities: [
|
|
||||||
{ cname: 'Jacksonville', code: 'US-JA' },
|
|
||||||
{ cname: 'Miami', code: 'US-MI' },
|
|
||||||
{ cname: 'Tampa', code: 'US-TA' },
|
|
||||||
{ cname: 'Orlando', code: 'US-OR' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Texas',
|
|
||||||
cities: [
|
|
||||||
{ cname: 'Austin', code: 'US-AU' },
|
|
||||||
{ cname: 'Dallas', code: 'US-DA' },
|
|
||||||
{ cname: 'Houston', code: 'US-HO' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="page-wrapper p-4">
|
<ZodForm />
|
||||||
<ZodForm v-if="false" />
|
<TutorialForm />
|
||||||
<TutorialForm v-if="false" />
|
|
||||||
|
|
||||||
<!-- <div class="flex flex-col md:flex-row items-start p-4 gap-4"> -->
|
|
||||||
<div class="p-4 w-full bg-white rounded-lg shadow-md dark:bg-gray-800 dark:text-white">
|
|
||||||
<AllCustom />
|
|
||||||
</div>
|
|
||||||
<!-- </div> -->
|
|
||||||
|
|
||||||
<div class="p-4 w-full bg-white rounded-lg shadow-md dark:bg-gray-800 dark:text-white mt-4">
|
|
||||||
|
|
||||||
<CascadeSelect
|
|
||||||
loading
|
|
||||||
v-model="selectedCity"
|
|
||||||
:options="countries"
|
|
||||||
optionLabel="cname"
|
|
||||||
optionGroupLabel="name"
|
|
||||||
:optionGroupChildren="['states', 'cities']"
|
|
||||||
class="w-56"
|
|
||||||
placeholder="Select a City"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import TimesIcon from '@primevue/icons/times';
|
|
||||||
import type { FileUploadStatus } from './types';
|
|
||||||
import { computed } from 'vue';
|
|
||||||
import type { BadgeProps } from 'primevue/badge';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
disabled: boolean;
|
|
||||||
url: string;
|
|
||||||
filename: string;
|
|
||||||
status?: FileUploadStatus;
|
|
||||||
progress?: number;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
defineEmits<{
|
|
||||||
remove: () => void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const bageValue = computed(() => {
|
|
||||||
switch (props.status) {
|
|
||||||
case 'pending':
|
|
||||||
return '待上传';
|
|
||||||
case 'uploading':
|
|
||||||
return '上传中';
|
|
||||||
case 'failed':
|
|
||||||
return '上传失败';
|
|
||||||
case 'uploaded':
|
|
||||||
return '已上传';
|
|
||||||
default:
|
|
||||||
return '未知状态';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const bageSeverity = computed<BadgeProps['severity']>(() => {
|
|
||||||
switch (props.status) {
|
|
||||||
case 'pending':
|
|
||||||
return 'info';
|
|
||||||
case 'uploading':
|
|
||||||
return 'warn';
|
|
||||||
case 'failed':
|
|
||||||
return 'danger';
|
|
||||||
case 'uploaded':
|
|
||||||
return 'success';
|
|
||||||
default:
|
|
||||||
return 'contrast';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="border border-[var(--p-fileupload-border-color)] p-2 rounded-md flex flex-wrap items-center gap-2">
|
|
||||||
<slot name="image">
|
|
||||||
<img
|
|
||||||
:src="url"
|
|
||||||
class="w-10 h-10 shrink-0 of-hidden"
|
|
||||||
/>
|
|
||||||
</slot>
|
|
||||||
<div class="break-all break-anywhere">{{ filename }}</div>
|
|
||||||
<Badge
|
|
||||||
:value="bageValue"
|
|
||||||
:severity="bageSeverity"
|
|
||||||
/>
|
|
||||||
<ProgressBar
|
|
||||||
v-if="status === 'uploading'"
|
|
||||||
:value="progress"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
:disabled="disabled"
|
|
||||||
text
|
|
||||||
:rounded="true"
|
|
||||||
severity="danger"
|
|
||||||
class="ml-auto"
|
|
||||||
@click="$emit('remove')"
|
|
||||||
>
|
|
||||||
<TimesIcon aria-hidden="true" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
@ -1,237 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import type { FormKitFrameworkContext } from '@formkit/core';
|
|
||||||
import FileUpload, { type FileUploadUploaderEvent } from 'primevue/fileupload';
|
|
||||||
import { computed, onMounted, useTemplateRef } from 'vue';
|
|
||||||
import FileUploadItem from './file-upload-item.vue';
|
|
||||||
import type { CustomRequest, FileExt, FileUploadInst, PropFilesToValue, PropValueToFiles } from './types';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
context: FormKitFrameworkContext & {
|
|
||||||
fileLimit?: number;
|
|
||||||
maxFileSize?: number;
|
|
||||||
customRequest?: CustomRequest;
|
|
||||||
valueToFiles?: PropValueToFiles;
|
|
||||||
filesToValue?: PropFilesToValue;
|
|
||||||
autoUpload?: boolean;
|
|
||||||
};
|
|
||||||
}>();
|
|
||||||
const formkitContext = props.context;
|
|
||||||
|
|
||||||
const customRequest = props.context.customRequest;
|
|
||||||
|
|
||||||
const fileUploadRef = useTemplateRef<FileUploadInst>('fileUploadRef');
|
|
||||||
|
|
||||||
const cmpt_disabled = computed(() => {
|
|
||||||
if (formkitContext.disabled === true) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (fileUploadRef.value) {
|
|
||||||
// 有上传失败的文件
|
|
||||||
if (fileUploadRef.value.uploadedFiles.some((f) => f.status === 'failed')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 已上传文件数量超过限制(这里是大于*等于*)
|
|
||||||
if (fileUploadRef.value.uploadedFileCount >= (formkitContext.fileLimit ?? Infinity)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 已上传和待上传文件数量超过限制(这里是*大于*)
|
|
||||||
const uploaded_and_pending_count = fileUploadRef.value.uploadedFileCount + fileUploadRef.value.files.length;
|
|
||||||
if (uploaded_and_pending_count > (formkitContext.fileLimit ?? Infinity)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
const cmpt_showUploadButton = computed(() => {
|
|
||||||
if (fileUploadRef.value?.files?.length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
const changeModelValue = () => {
|
|
||||||
const uploadedFiles = fileUploadRef.value!.uploadedFiles.filter((f) => f.status === 'uploaded');
|
|
||||||
if (!formkitContext.filesToValue) {
|
|
||||||
console.warn('[FileUpload] filesToValue is not defined');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (uploadedFiles.length === 0) {
|
|
||||||
formkitContext.node.input(null);
|
|
||||||
} else {
|
|
||||||
formkitContext.node.input(formkitContext.filesToValue(uploadedFiles));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const changeUploadedFiles = () => {
|
|
||||||
if (!formkitContext.valueToFiles) {
|
|
||||||
console.warn('[FileUpload] valueToFiles is not defined');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const files = formkitContext.valueToFiles(formkitContext._value);
|
|
||||||
if (files === null) return;
|
|
||||||
|
|
||||||
fileUploadRef.value!.uploadedFiles = files.map((f) => ({
|
|
||||||
name: f.name,
|
|
||||||
url: f.url,
|
|
||||||
status: f.status || 'uploaded',
|
|
||||||
progress: f.progress || 100,
|
|
||||||
}));
|
|
||||||
fileUploadRef.value!.uploadedFileCount = files.length;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('[FileUpload] valueToFiles error:', error, 'value:', formkitContext._value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
changeUploadedFiles();
|
|
||||||
});
|
|
||||||
|
|
||||||
const onUploader = (event: FileUploadUploaderEvent) => {
|
|
||||||
if (!customRequest) {
|
|
||||||
console.warn('[FileUpload] customRequest is not defined');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = event.files as FileExt[];
|
|
||||||
for (const file of files) {
|
|
||||||
fileUploadRef.value!.uploadedFiles.push({
|
|
||||||
rawFile: file,
|
|
||||||
name: file.name,
|
|
||||||
url: '',
|
|
||||||
status: 'uploading',
|
|
||||||
progress: 0,
|
|
||||||
});
|
|
||||||
const fileItem = fileUploadRef.value!.uploadedFiles[fileUploadRef.value!.uploadedFiles.length - 1];
|
|
||||||
customRequest({
|
|
||||||
file,
|
|
||||||
onProgress: (percent) => {
|
|
||||||
fileItem.progress = percent;
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((result) => {
|
|
||||||
fileItem.status = 'uploaded';
|
|
||||||
fileItem.url = result.url;
|
|
||||||
changeModelValue();
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
fileItem.status = 'failed';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// fileUploadRef.value?.uploadedFiles
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<FileUpload
|
|
||||||
ref="fileUploadRef"
|
|
||||||
:auto="formkitContext.autoUpload"
|
|
||||||
:disabled="cmpt_disabled"
|
|
||||||
:showUploadButton="cmpt_showUploadButton"
|
|
||||||
:showCancelButton="false"
|
|
||||||
:customUpload="true"
|
|
||||||
mode="advanced"
|
|
||||||
:multiple="true"
|
|
||||||
accept="image/*"
|
|
||||||
:maxFileSize="formkitContext.maxFileSize"
|
|
||||||
invalidFileSizeMessage="文件 {0} 大小超过限制 {1}"
|
|
||||||
:fileLimit="formkitContext.fileLimit"
|
|
||||||
invalidFileLimitMessage="最多只能上传 {0} 个文件,请移除多余文件后点击上传"
|
|
||||||
@uploader="onUploader"
|
|
||||||
:chooseButtonProps="{ size: 'small' }"
|
|
||||||
:uploadButtonProps="{ size: 'small', severity: 'secondary' }"
|
|
||||||
:cancelButtonProps="{ size: 'small', severity: 'secondary' }"
|
|
||||||
@remove="changeModelValue()"
|
|
||||||
@removeUploadedFile="changeModelValue()"
|
|
||||||
>
|
|
||||||
<template #empty>
|
|
||||||
<Message
|
|
||||||
size="small"
|
|
||||||
severity="secondary"
|
|
||||||
>未上传附件</Message
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #content="{ messages, removeFileCallback, removeUploadedFileCallback }">
|
|
||||||
<Message
|
|
||||||
size="small"
|
|
||||||
v-for="msg of messages"
|
|
||||||
closable
|
|
||||||
@close="fileUploadRef!.messages = []"
|
|
||||||
:key="msg"
|
|
||||||
severity="error"
|
|
||||||
>{{ msg }}</Message
|
|
||||||
>
|
|
||||||
|
|
||||||
<!-- 已上传列表(上传中、上传成功、上传失败) -->
|
|
||||||
<template
|
|
||||||
v-for="(file, index) of fileUploadRef?.uploadedFiles"
|
|
||||||
:key="file.name + file.url"
|
|
||||||
>
|
|
||||||
<FileUploadItem
|
|
||||||
:disabled="formkitContext.disabled === true"
|
|
||||||
:url="file.url || file.rawFile?.objectURL || ''"
|
|
||||||
:filename="file.name || file.url || '未知文件'"
|
|
||||||
@remove="
|
|
||||||
() => {
|
|
||||||
fileUploadRef!.uploadedFileCount--;
|
|
||||||
removeUploadedFileCallback(index);
|
|
||||||
}
|
|
||||||
"
|
|
||||||
:status="file.status"
|
|
||||||
:progress="file.progress"
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
#image
|
|
||||||
v-if="formkitContext.slots.image"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="formkitContext.slots.image"
|
|
||||||
:url="file.url || file.rawFile?.objectURL || ''"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</FileUploadItem>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 待上传列表 -->
|
|
||||||
<template
|
|
||||||
v-for="(file, index) of fileUploadRef?.files"
|
|
||||||
:key="file.name + file.type + file.size"
|
|
||||||
>
|
|
||||||
<FileUploadItem
|
|
||||||
:disabled="formkitContext.disabled === true"
|
|
||||||
:url="file.objectURL"
|
|
||||||
:filename="file.name"
|
|
||||||
@remove="removeFileCallback(index)"
|
|
||||||
status="pending"
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
#image
|
|
||||||
v-if="formkitContext.slots.image"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="formkitContext.slots.image"
|
|
||||||
:url="file.objectURL"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</FileUploadItem>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</FileUpload>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.p-floatlabel:has(.p-fileupload) label {
|
|
||||||
top: var(--p-floatlabel-over-active-top);
|
|
||||||
transform: translateY(0);
|
|
||||||
font-size: var(--p-floatlabel-active-font-size);
|
|
||||||
font-weight: var(--p-floatlabel-label-active-font-weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-fileupload-content .p-progressbar {
|
|
||||||
--p-fileupload-progressbar-height: 1rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,28 +0,0 @@
|
|||||||
import type { FileUploadState } from 'primevue/fileupload';
|
|
||||||
|
|
||||||
export interface FileExt extends File {
|
|
||||||
objectURL: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type FileUploadStatus = 'pending' | 'uploading' | 'uploaded' | 'failed';
|
|
||||||
|
|
||||||
export type UploadedFileInfo = {
|
|
||||||
rawFile?: FileExt;
|
|
||||||
name?: string;
|
|
||||||
url?: string;
|
|
||||||
status?: FileUploadStatus;
|
|
||||||
progress?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface FileUploadInst extends FileUploadState {
|
|
||||||
files: FileExt[];
|
|
||||||
uploadedFiles: UploadedFileInfo[];
|
|
||||||
chooseDisabled?: boolean;
|
|
||||||
}
|
|
||||||
export type CustomRequest = (options: {
|
|
||||||
file: File;
|
|
||||||
onProgress: (percent: number) => void;
|
|
||||||
}) => Promise<{ url: string }>;
|
|
||||||
|
|
||||||
export type PropValueToFiles = (value: unknown) => UploadedFileInfo[] | null;
|
|
||||||
export type PropFilesToValue = (filelist: UploadedFileInfo[]) => unknown;
|
|
@ -1,31 +0,0 @@
|
|||||||
<template>
|
|
||||||
<Message
|
|
||||||
severity="error"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<!-- <template #container> -->
|
|
||||||
<ul class="my-0 flex flex-col gap-1">
|
|
||||||
<li
|
|
||||||
v-for="message in context.messages"
|
|
||||||
:key="message.key"
|
|
||||||
:id="`${context.id}-${message.key}`"
|
|
||||||
:data-message-type="message.type"
|
|
||||||
>
|
|
||||||
{{ message.value }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<!-- </template> -->
|
|
||||||
</Message>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { type FormKitFrameworkContext } from '@formkit/core';
|
|
||||||
import Message from 'primevue/message';
|
|
||||||
defineProps<{ context: FormKitFrameworkContext }>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.p-floatlabel + .p-message {
|
|
||||||
margin-top: 0.25rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,50 +0,0 @@
|
|||||||
import type { FormKitTypeDefinition } from '@formkit/core';
|
|
||||||
import { createSection, disablesChildren, forms } from '@formkit/inputs';
|
|
||||||
import PButton from 'primevue/button';
|
|
||||||
import { markRaw } from 'vue';
|
|
||||||
import { messages } from '../sections/messages';
|
|
||||||
|
|
||||||
const formInput = createSection('form', () => ({
|
|
||||||
$el: 'form',
|
|
||||||
bind: '$attrs',
|
|
||||||
meta: {
|
|
||||||
autoAnimate: true,
|
|
||||||
},
|
|
||||||
attrs: {
|
|
||||||
'id': '$id',
|
|
||||||
'name': '$node.name',
|
|
||||||
'onSubmit': '$handlers.submit',
|
|
||||||
'data-loading': '$state.loading || undefined',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const button = createSection(
|
|
||||||
// https://formkit.com/playground?fkv=latest&fileTab=Playground.vue&files=jc%5B%28%27name%21%27Playground.vue%27%7Eeditor%21%27%3Cscripzsetup%3EBtestUgWasyncJEqawaiznew+Promise%7Br3%3E+setTimeout%7Br%2C+5000%7D%7D-%29-BsGW%5Bq%286%24formkit142*lX1LogU2%29-%5D%3B-B_W%28qY1Uput2sG8%5B6%286*%24cmp19xbUdZsHAttrsxprops8%286Nignore8true%2C6NY1sHx*OZOx*lXZsHLXx%29%2C6*V6N%22%24lXx*%286N*ifZOxN%24el1spanxNV%22+loadUg...%22%5D6N%29%2C6*%5D6%29q%5D%2C-%29-BC3JE%29--%2F%2F+Then+we+attach+a+library-C.library3JnodeEqifJnode.props.Y3%3D%3D+%224%22%7D+%286node.defUe%7B_%7Dq%29-%29--MscriptQ-%3Cj-+%3C96YRform76%3AplugUsR%5BC%5D76%3AactionsRfalse76%40sHRtestUg7q%3E6%3C9SG+%3AsGRsG7+%2F%3E6M9Q*M9QMj%27%7Eadded%21true%29%5D*++-%5Cn18%222%22%2CqW%3D4spUnUgSH6-N7%5C%278%3A+9FormKitB-conszCcustomInputsE%7D3%3E+%28GchemaHubmitJ+%7BM%3C%2FN**OdisabledQ%3E-R%3D7UinVchildren8%5BW3+XabelYtypeZ1%24_4DefUitionjtemplateQq-*x2Nzt+%01zxqj_ZYXWVURQONMJHGECB98764321-*_&imports=jc%28%27name%21%27ImportMap%27%7Eeditor%21%27%28*+1vue%5C%211https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fvue%403%2Fdist%2Fvue.esm-browser.min.js0*%29*%27%29*%5Cn0%5C%271+0%0110*_&css-framework=genesis
|
|
||||||
'button',
|
|
||||||
() => ({
|
|
||||||
$cmp: markRaw(PButton) as never,
|
|
||||||
bind: '$submitAttrs',
|
|
||||||
props: {
|
|
||||||
type: 'submit',
|
|
||||||
label: '$submitLabel',
|
|
||||||
loading: '$state.loading || undefined',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const form: FormKitTypeDefinition = {
|
|
||||||
type: 'group',
|
|
||||||
schema: formInput(
|
|
||||||
'$slots.default',
|
|
||||||
messages(),
|
|
||||||
button(), //
|
|
||||||
),
|
|
||||||
props: [
|
|
||||||
'submitLabel',
|
|
||||||
'submitAttrs',
|
|
||||||
'submitBehavior',
|
|
||||||
'incompleteMessage', // 抱歉,部分字段未被正确填写。
|
|
||||||
],
|
|
||||||
features: [forms, disablesChildren],
|
|
||||||
schemaMemoKey: 'i90xrn9dyre', // Math.random().toString(36).substring(2, 15)
|
|
||||||
};
|
|
@ -1,115 +0,0 @@
|
|||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
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';
|
|
||||||
import { help } from '../sections/help';
|
|
||||||
|
|
||||||
// :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'),
|
|
||||||
),
|
|
||||||
help('$help'),
|
|
||||||
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'];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
import type { FormKitTypeDefinition } from '@formkit/core';
|
|
||||||
import type { FormKitInputs, FormKitSlotData } from '@formkit/inputs';
|
|
||||||
import { createSection, label, outer } from '@formkit/inputs';
|
|
||||||
import { markRaw } from 'vue';
|
|
||||||
import FileUploadComponent from '../components/file-upload/file-upload.vue';
|
|
||||||
import type { CustomRequest, PropFilesToValue, PropValueToFiles } from '../components/file-upload/types';
|
|
||||||
import { floatLabel } from '../sections/floatLabel';
|
|
||||||
import { help } from '../sections/help';
|
|
||||||
import { messages } from '../sections/messages';
|
|
||||||
|
|
||||||
const input = createSection('input', () => ({
|
|
||||||
$cmp: markRaw(FileUploadComponent) as never,
|
|
||||||
bind: '$attrs',
|
|
||||||
props: {
|
|
||||||
context: '$node.context',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const PFileUpload: FormKitTypeDefinition = {
|
|
||||||
type: 'input',
|
|
||||||
schema: outer(
|
|
||||||
floatLabel(
|
|
||||||
input(), //
|
|
||||||
label('$label'),
|
|
||||||
),
|
|
||||||
help('$help'),
|
|
||||||
messages(),
|
|
||||||
),
|
|
||||||
props: ['fileLimit', 'maxFileSize', 'customRequest', 'valueToFiles', 'filesToValue', 'autoUpload'],
|
|
||||||
schemaMemoKey: 'ihcxd4qdgh7', // 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>> {
|
|
||||||
PFileUpload: {
|
|
||||||
type: 'PFileUpload';
|
|
||||||
value?: unknown;
|
|
||||||
fileLimit?: number;
|
|
||||||
maxFileSize?: number;
|
|
||||||
customRequest?: CustomRequest;
|
|
||||||
valueToFiles?: PropValueToFiles;
|
|
||||||
filesToValue?: PropFilesToValue;
|
|
||||||
autoUpload?: boolean;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FormKitInputSlots<Props extends FormKitInputs<Props>> {
|
|
||||||
PFileUpload: {
|
|
||||||
image: FormKitSlotData<
|
|
||||||
Props,
|
|
||||||
{
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import type { FormKitTypeDefinition } from '@formkit/core';
|
|
||||||
import type { FormKitInputs } from '@formkit/inputs';
|
|
||||||
import { casts, createSection, label, outer } from '@formkit/inputs';
|
|
||||||
import SchemaComponent from 'primevue/password';
|
|
||||||
import { markRaw } from 'vue';
|
|
||||||
import { messages } from '../sections/messages';
|
|
||||||
import { floatLabel } from '../sections/floatLabel';
|
|
||||||
import { help } from '../sections/help';
|
|
||||||
|
|
||||||
const input = createSection('input', () => ({
|
|
||||||
$cmp: markRaw(SchemaComponent) as never,
|
|
||||||
bind: '$attrs',
|
|
||||||
props: {
|
|
||||||
invalid: '$state.invalid',
|
|
||||||
disabled: '$disabled',
|
|
||||||
modelValue: '$_value',
|
|
||||||
onInput: '$handlers.DOMInput',
|
|
||||||
onBlur: '$handlers.blur',
|
|
||||||
inputId: '$id',
|
|
||||||
fluid: true,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const PInputPassword: FormKitTypeDefinition = {
|
|
||||||
type: 'input',
|
|
||||||
schema: outer(
|
|
||||||
floatLabel(
|
|
||||||
input(), //
|
|
||||||
label('$label'),
|
|
||||||
),
|
|
||||||
help('$help'),
|
|
||||||
messages(),
|
|
||||||
),
|
|
||||||
features: [casts],
|
|
||||||
schemaMemoKey: '9h771fci93n', // 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>> {
|
|
||||||
PInputPassword: {
|
|
||||||
type: 'PInputPassword';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
import type { FormKitTypeDefinition } from '@formkit/core';
|
|
||||||
import type { FormKitInputs } from '@formkit/inputs';
|
|
||||||
import { casts, createSection, label, outer } from '@formkit/inputs';
|
|
||||||
import SchemaComponent from 'primevue/inputtext';
|
|
||||||
import { markRaw } from 'vue';
|
|
||||||
import { floatLabel } from '../sections/floatLabel';
|
|
||||||
import { messages } from '../sections/messages';
|
|
||||||
import { help } from '../sections/help';
|
|
||||||
|
|
||||||
const input = createSection('input', () => ({
|
|
||||||
$cmp: markRaw(SchemaComponent) as never,
|
|
||||||
bind: '$attrs',
|
|
||||||
props: {
|
|
||||||
invalid: '$state.invalid',
|
|
||||||
type: '$type',
|
|
||||||
disabled: '$disabled',
|
|
||||||
name: '$node.name',
|
|
||||||
modelValue: '$_value',
|
|
||||||
onInput: '$handlers.DOMInput',
|
|
||||||
onBlur: '$handlers.blur',
|
|
||||||
id: '$id',
|
|
||||||
fluid: true,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const PInputText: FormKitTypeDefinition = {
|
|
||||||
type: 'input',
|
|
||||||
schema: outer(
|
|
||||||
floatLabel(
|
|
||||||
input(), //
|
|
||||||
label('$label'),
|
|
||||||
),
|
|
||||||
help('$help'),
|
|
||||||
messages(),
|
|
||||||
),
|
|
||||||
features: [casts],
|
|
||||||
schemaMemoKey: 'nnvujvlf2xr', // 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>> {
|
|
||||||
PInputText: {
|
|
||||||
type: 'PInputText';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,139 +0,0 @@
|
|||||||
import type { FormKitFrameworkContext, FormKitTypeDefinition } from '@formkit/core';
|
|
||||||
import type { FormKitInputs } from '@formkit/inputs';
|
|
||||||
import { createSection, label, outer } from '@formkit/inputs';
|
|
||||||
import PrimevueSelect, { type SelectEmitsOptions, type SelectSlots } from 'primevue/select';
|
|
||||||
import { computed, 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 = {
|
|
||||||
// 'onFocus': SelectEmitsOptions['focus'];
|
|
||||||
'onUpdate:modelValue': SelectEmitsOptions['update:modelValue'];
|
|
||||||
// 'onChange': SelectEmitsOptions['change'];
|
|
||||||
'onBlur': SelectEmitsOptions['blur'];
|
|
||||||
};
|
|
||||||
|
|
||||||
const SchemaComponent = defineComponent(
|
|
||||||
(vueProps: { context: FormKitFrameworkContext }) => {
|
|
||||||
const formkitContext = vueProps.context;
|
|
||||||
const primevueSelectInstance = ref<{ label: string } | undefined>();
|
|
||||||
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事件延迟一点,可以考虑优化。
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// [optionsLoader](https://github.com/formkit/formkit/blob/2d5387ba98597775cb2a752af65aee84bc438863/packages/inputs/src/features/options.ts#L125)
|
|
||||||
|
|
||||||
const p_options = ref();
|
|
||||||
const loading = ref(true);
|
|
||||||
|
|
||||||
const loadOptions = async () => {
|
|
||||||
try {
|
|
||||||
let result;
|
|
||||||
if (formkitContext.options instanceof Promise) {
|
|
||||||
result = await formkitContext.options;
|
|
||||||
} else if (typeof formkitContext.options === 'function') {
|
|
||||||
const funcResult = await (formkitContext.options as () => unknown).call(undefined);
|
|
||||||
result = funcResult instanceof Promise ? await funcResult : funcResult;
|
|
||||||
} else {
|
|
||||||
result = formkitContext.options;
|
|
||||||
}
|
|
||||||
p_options.value = result;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to load options:', error);
|
|
||||||
p_options.value = [];
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loadOptions(); // 立即加载options
|
|
||||||
|
|
||||||
const valueSlot = computed(() => {
|
|
||||||
if (primevueSelectInstance.value?.label === 'p-emptylabel' && !!formkitContext._value) {
|
|
||||||
return ((slotProps) => {
|
|
||||||
return slotProps.value as never;
|
|
||||||
}) satisfies SelectSlots['value'];
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
return (
|
|
||||||
<PrimevueSelect
|
|
||||||
style={{
|
|
||||||
'border-color':
|
|
||||||
!formkitContext.state.invalid && valueSlot.value !== undefined ? 'var(--p-yellow-200)' : undefined,
|
|
||||||
}}
|
|
||||||
ref={primevueSelectInstance}
|
|
||||||
labelId={formkitContext.id}
|
|
||||||
fluid
|
|
||||||
invalid={formkitContext.state.invalid}
|
|
||||||
disabled={!!formkitContext.disabled}
|
|
||||||
loading={loading.value}
|
|
||||||
options={p_options.value}
|
|
||||||
modelValue={formkitContext._value}
|
|
||||||
optionLabel={formkitContext.optionLabel as never}
|
|
||||||
optionValue={formkitContext.optionValue as never}
|
|
||||||
{...listeners}
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
value: valueSlot.value,
|
|
||||||
}}
|
|
||||||
</PrimevueSelect>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
// 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 PSelect: FormKitTypeDefinition = {
|
|
||||||
type: 'input',
|
|
||||||
schema: outer(
|
|
||||||
floatLabel(
|
|
||||||
input(), //
|
|
||||||
label('$label'),
|
|
||||||
),
|
|
||||||
help('$help'),
|
|
||||||
messages(),
|
|
||||||
),
|
|
||||||
props: ['options', 'optionLabel', 'optionValue'],
|
|
||||||
schemaMemoKey: 'nip9j70lb1', // Math.random().toString(36).substring(2, 15)
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
type OptionsItem = Record<string, any>;
|
|
||||||
type OptionsType = Array<OptionsItem>;
|
|
||||||
|
|
||||||
declare module '@formkit/inputs' {
|
|
||||||
// https://formkit.com/essentials/custom-inputs#typescript-support
|
|
||||||
interface FormKitInputProps<Props extends FormKitInputs<Props>> {
|
|
||||||
PSelect: {
|
|
||||||
type: 'PSelect';
|
|
||||||
options: OptionsType | Promise<OptionsType> | (() => OptionsType | Promise<OptionsType>);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import { createSection } from '@formkit/inputs';
|
|
||||||
import FloatLabel from 'primevue/floatlabel';
|
|
||||||
import { markRaw } from 'vue';
|
|
||||||
|
|
||||||
export const floatLabel = createSection('floatLabel', () => ({
|
|
||||||
$cmp: markRaw(FloatLabel) as never,
|
|
||||||
bind: '$attrs',
|
|
||||||
}));
|
|
@ -1,14 +0,0 @@
|
|||||||
import { createSection } from '@formkit/inputs';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Help section that shows help text
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export const help = createSection('help', () => ({
|
|
||||||
$el: 'div',
|
|
||||||
if: '$help',
|
|
||||||
attrs: {
|
|
||||||
id: '$: "help-" + $id',
|
|
||||||
},
|
|
||||||
}));
|
|
@ -1,9 +0,0 @@
|
|||||||
import MessagesCmp from '../components/messages.vue';
|
|
||||||
import { createSection } from '@formkit/inputs';
|
|
||||||
import { markRaw } from 'vue';
|
|
||||||
|
|
||||||
export const messages = createSection('messages', () => ({
|
|
||||||
$cmp: markRaw(MessagesCmp) as unknown as never, // [element = node.$cmp](https://github.com/formkit/formkit/blob/2d5387ba98597775cb2a752af65aee84bc438863/packages/vue/src/FormKitSchema.ts#L449)
|
|
||||||
props: { context: '$node.context' },
|
|
||||||
if: '$defaultMessagePlacement && $fns.length($messages)',
|
|
||||||
}));
|
|
@ -1,253 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { FormKitNode } from '@formkit/core';
|
|
||||||
import { text } from '@formkit/inputs';
|
|
||||||
import Swal from 'sweetalert2';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import { arrayToTree } from 'utils4u/array';
|
|
||||||
import { CustomRequest } from '@/__fk-inputs__/components/file-upload/types';
|
|
||||||
|
|
||||||
async function submit(formData: Record<string, any>, formNode: FormKitNode) {
|
|
||||||
console.group('submit');
|
|
||||||
console.log('formData :>> ', formData);
|
|
||||||
console.log('formNode :>> ', formNode);
|
|
||||||
console.groupEnd();
|
|
||||||
|
|
||||||
await new Promise(r => setTimeout(r, 2000))
|
|
||||||
Swal.fire({
|
|
||||||
title: 'Submitted! 🎉',
|
|
||||||
icon: 'success',
|
|
||||||
showConfirmButton: false,
|
|
||||||
timer: 1500
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const K_OPTIONS = [
|
|
||||||
{ label: 'Option 1', value: 'Value 1' },
|
|
||||||
{ label: 'Option 2', value: 'Value 2' },
|
|
||||||
{ label: 'Option 3', value: 'Value 3' },
|
|
||||||
];
|
|
||||||
const promiseOptions = new Promise<typeof K_OPTIONS>(resolve => {
|
|
||||||
setTimeout(() => resolve(K_OPTIONS), 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
const K_FLAT_TREE = [
|
|
||||||
{
|
|
||||||
dictLabel: '北京市',
|
|
||||||
dictValue: '110000',
|
|
||||||
fullName: '北京市',
|
|
||||||
abbrName: '北京',
|
|
||||||
dictParent: '00',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dictLabel: '山西省',
|
|
||||||
dictValue: '140000',
|
|
||||||
fullName: '山西省',
|
|
||||||
abbrName: '山西',
|
|
||||||
dictParent: '00',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dictLabel: '太原市',
|
|
||||||
dictValue: '140100',
|
|
||||||
fullName: '山西省,太原市',
|
|
||||||
abbrName: '山西太原',
|
|
||||||
dictParent: '140000',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dictLabel: '大同市',
|
|
||||||
dictValue: '140200',
|
|
||||||
fullName: '山西省,大同市',
|
|
||||||
abbrName: '山西大同',
|
|
||||||
dictParent: '140000',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
const promiseCascadeOptions = new Promise<typeof K_FLAT_TREE>((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
resolve(arrayToTree(K_FLAT_TREE, { id: 'dictValue', parentId: 'dictParent', rootId: '00' }));
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
/* const funcOptions = async () => {
|
|
||||||
await new Promise(r => setTimeout(r, 1000))
|
|
||||||
return K_OPTIONS;
|
|
||||||
} */
|
|
||||||
|
|
||||||
import axios from 'axios';
|
|
||||||
const customRequest: CustomRequest = (async ({ file, onProgress, }) => {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('file', file);
|
|
||||||
return axios
|
|
||||||
.post('https://jsonplaceholder.typicode.com/posts', formData, {
|
|
||||||
headers: { 'Content-Type': 'multipart/form-data' },
|
|
||||||
onUploadProgress: (e) => {
|
|
||||||
onProgress(Math.round((e.loaded * 100) / (e.total || 1)));
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
// onProgress(100);
|
|
||||||
return { url: 'https://picsum.photos/200/300' };
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Fieldset
|
|
||||||
legend="表单"
|
|
||||||
toggleable
|
|
||||||
class="min-w-full"
|
|
||||||
pt:content:class="flex justify-center"
|
|
||||||
>
|
|
||||||
<!-- https://formkit.com/inputs/form#props-attributes -->
|
|
||||||
<FormKit
|
|
||||||
:value="{
|
|
||||||
a: '1', b: '2',
|
|
||||||
PInputText: 'PInputText default value from form',
|
|
||||||
notInForm: 'not in form',
|
|
||||||
}"
|
|
||||||
:config="{
|
|
||||||
classes: {
|
|
||||||
form: 'flex flex-col w-full py-6 gap-8',
|
|
||||||
outer: 'flex flex-col gap-2',
|
|
||||||
/* label: 'font-medium block' */
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
type="form"
|
|
||||||
#default="{ value }"
|
|
||||||
@submit="submit"
|
|
||||||
submit-label="提交 ✨"
|
|
||||||
:submit-attrs="{
|
|
||||||
'some-submit-attr': 'value',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<FormKit
|
|
||||||
type="PInputText"
|
|
||||||
name="PInputText"
|
|
||||||
label="输入框"
|
|
||||||
value="`default value from field`"
|
|
||||||
help="帮助信息帮助信息帮助信息帮助信息"
|
|
||||||
some="prop"
|
|
||||||
some-boolean-prop
|
|
||||||
validation="required"
|
|
||||||
>
|
|
||||||
</FormKit>
|
|
||||||
<FormKit
|
|
||||||
name="PFileUpload"
|
|
||||||
type="PFileUpload"
|
|
||||||
label="文件上传"
|
|
||||||
:maxFileSize="1024 * 1024 * 2"
|
|
||||||
:customRequest
|
|
||||||
:fileLimit="99"
|
|
||||||
:autoUpload="true"
|
|
||||||
:filesToValue="(files) => JSON.stringify(files.map(f => ({ name: f.name, url: f.url })))"
|
|
||||||
:valueToFiles="(value) => JSON.parse(value as string)"
|
|
||||||
value='[{"name":"2KB图片_副本.jpeg","url":"https://picsum.photos/200/300"}]'
|
|
||||||
/>
|
|
||||||
<FormKit
|
|
||||||
type="PInputPassword"
|
|
||||||
name="PInputPassword"
|
|
||||||
label="密码"
|
|
||||||
validation="required"
|
|
||||||
toggleMask
|
|
||||||
:feedback="false"
|
|
||||||
/>
|
|
||||||
<FormKit
|
|
||||||
type="PSelect"
|
|
||||||
name="PSelect_1"
|
|
||||||
label="选择框"
|
|
||||||
validation="required"
|
|
||||||
:options="K_OPTIONS"
|
|
||||||
optionLabel="label"
|
|
||||||
optionValue="value"
|
|
||||||
value="数据的值不在options里"
|
|
||||||
/>
|
|
||||||
<FormKit
|
|
||||||
type="PSelect"
|
|
||||||
name="PSelect_2"
|
|
||||||
label="选择框"
|
|
||||||
validation="required"
|
|
||||||
:options="promiseOptions"
|
|
||||||
optionLabel="label"
|
|
||||||
optionValue="value"
|
|
||||||
/>
|
|
||||||
<FormKit
|
|
||||||
type="PCascadeSelect"
|
|
||||||
name="PCascadeSelect"
|
|
||||||
label="级联选择框"
|
|
||||||
validation="required"
|
|
||||||
:options="promiseCascadeOptions"
|
|
||||||
optionLabel="dictLabel"
|
|
||||||
optionValue="dictValue"
|
|
||||||
/>
|
|
||||||
<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
|
|
||||||
v-if="!value?.PInputPassword"
|
|
||||||
:type="text"
|
|
||||||
:preserve="false"
|
|
||||||
name="customType"
|
|
||||||
value="this input will display if the password is empty"
|
|
||||||
help="helppppppppppp"
|
|
||||||
>
|
|
||||||
<!-- <template #label>
|
|
||||||
<div>labelll</div>
|
|
||||||
</template> -->
|
|
||||||
</FormKit>
|
|
||||||
|
|
||||||
|
|
||||||
<FormKit
|
|
||||||
type="group"
|
|
||||||
name="group"
|
|
||||||
>
|
|
||||||
<FormKit
|
|
||||||
:type="text"
|
|
||||||
name="text-in-group-1"
|
|
||||||
>
|
|
||||||
</FormKit>
|
|
||||||
</FormKit>
|
|
||||||
|
|
||||||
<FormKit
|
|
||||||
type="group"
|
|
||||||
name="group"
|
|
||||||
>
|
|
||||||
<FormKit
|
|
||||||
:type="text"
|
|
||||||
name="text-in-group-2"
|
|
||||||
>
|
|
||||||
</FormKit>
|
|
||||||
</FormKit>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
label="Button"
|
|
||||||
@click="() => {
|
|
||||||
value!.button = value!.button || {};
|
|
||||||
(value!.button as any).clicked = 'clicked-这个值在@submit回调的formData里不会出现';
|
|
||||||
(value!.group as any)['text-in-group-1'] = 'changed-by-button';
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<pre class="font-mono text-sm p-4 bg-slate-100 dark:bg-gray-900 overflow-x-auto rounded-md shadow-inner dark:text-gray-300
|
|
||||||
">{{ value }}</pre>
|
|
||||||
<!-- <FormKitSummary /> -->
|
|
||||||
</FormKit>
|
|
||||||
</Fieldset>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.formkit-input) {
|
|
||||||
border: 1px solid #e2e8f0;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,15 +1,20 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #f3f4f6;
|
background-color:#f3f4f6;
|
||||||
color: #1f2937;
|
color:#1f2937;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
body {
|
body {
|
||||||
background-color: #1a202c;
|
background-color:#1a202c;
|
||||||
color: #e5e7eb;
|
color:#e5e7eb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.attributes-group {
|
.attributes-group {
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
@ -23,10 +28,4 @@ body {
|
|||||||
border-color: #374151;
|
border-color: #374151;
|
||||||
background-color: #1f2937;
|
background-color: #1f2937;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* DEV: */
|
|
||||||
/* .formkit-outer {
|
|
||||||
border: 1px solid #e5e7eb;
|
|
||||||
} */
|
|
@ -1,3 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
1
src/assets/vue.svg
Normal file
1
src/assets/vue.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
After Width: | Height: | Size: 496 B |
45
src/main.ts
45
src/main.ts
@ -1,40 +1,13 @@
|
|||||||
import Aura from '@primevue/themes/aura';
|
import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
|
||||||
import zhCN from 'primelocale/zh-CN.json';
|
import { plugin, /* defaultConfig */ } from '@formkit/vue'
|
||||||
import PrimeVue from 'primevue/config';
|
import { createApp } from 'vue'
|
||||||
import ToastService from 'primevue/toastservice';
|
import formKitConfig from '../formkit.config'
|
||||||
import { createApp } from 'vue';
|
import App from './App.vue'
|
||||||
import { setupFormKit } from '../formkit.config';
|
|
||||||
import App from './App.vue';
|
|
||||||
|
|
||||||
// import '@unocss/reset/normalize.css'
|
const app = createApp(App)
|
||||||
// import '@unocss/reset/sanitize/sanitize.css'
|
|
||||||
// import '@unocss/reset/sanitize/assets.css'
|
|
||||||
// import '@unocss/reset/eric-meyer.css'
|
|
||||||
// import '@unocss/reset/tailwind-compat.css'
|
|
||||||
// import '@unocss/reset/tailwind.css'
|
|
||||||
|
|
||||||
import 'primeicons/primeicons.css';
|
|
||||||
import 'virtual:uno.css';
|
|
||||||
|
|
||||||
const app = createApp(App);
|
|
||||||
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
|
// https://github.dev/formkit/auto-animate/blob/master/docs/src/examples/formkit/ActualFormKit.vue
|
||||||
|
app.use(autoAnimatePlugin) // v-auto-animate="{ duration: 100 }"
|
||||||
|
|
||||||
setupFormKit(app);
|
app.use(plugin, formKitConfig)
|
||||||
|
app.mount('#app')
|
||||||
app.mount('#app');
|
|
||||||
|
79
src/style.css
Normal file
79
src/style.css
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
:root {
|
||||||
|
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
color-scheme: light dark;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
background-color: #242424;
|
||||||
|
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #646cff;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #535bf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
min-width: 320px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3.2em;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: 0.6em 1.2em;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: inherit;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.25s;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
border-color: #646cff;
|
||||||
|
}
|
||||||
|
button:focus,
|
||||||
|
button:focus-visible {
|
||||||
|
outline: 4px auto -webkit-focus-ring-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
:root {
|
||||||
|
color: #213547;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #747bff;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
}
|
@ -220,7 +220,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<div class="bg-gray-100 p-4 rounded-xl dark:bg-gray-800">
|
<div class="bg-gray-100 p-4 rounded-xl dark:bg-gray-800">
|
||||||
<h2 class="font-bold text-lg mb-4 color:gray-800 dark:text-white">Pro Inputs</h2>
|
<h2 class="font-bold text-lg mb-4 color:gray-800 dark:text-white">Pro Inputs</h2>
|
||||||
<!-- <FormKit type="toggle" /> -->
|
<FormKit type="toggle" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</FormKit>
|
</FormKit>
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
export default {
|
export default {
|
||||||
prefix: '',
|
prefix: '',
|
||||||
content: [
|
content: [
|
||||||
// "./index.html",
|
"./index.html",
|
||||||
// "./src/**/*.vue",
|
"./src/**/*.vue",
|
||||||
"./formkit.config.theme.ts",
|
"./formkit.config.theme.ts",
|
||||||
"./formkit.config.ts",
|
"./formkit.config.ts",
|
||||||
],
|
],
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"moduleResolution": "Bundler",
|
"moduleResolution": "Bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
@ -14,17 +14,13 @@
|
|||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"jsxImportSource": "vue",
|
|
||||||
/* Linting */
|
/* Linting */
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true,
|
"noUncheckedSideEffectImports": true
|
||||||
"paths": {
|
|
||||||
"@/*": ["src/*"],
|
|
||||||
"__fk-inputs__/*": ["src/__fk-inputs__/*"]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import { extractorArbitraryVariants } from "@unocss/extractor-arbitrary-variants";
|
|
||||||
import {
|
|
||||||
defineConfig,
|
|
||||||
presetUno,
|
|
||||||
transformerVariantGroup
|
|
||||||
} from "unocss";
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
presets: [
|
|
||||||
presetUno({
|
|
||||||
dark: "media",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
transformers: [transformerVariantGroup()],
|
|
||||||
extractors: [extractorArbitraryVariants()],
|
|
||||||
});
|
|
@ -1,27 +1,10 @@
|
|||||||
import UnoCSS from 'unocss/vite';
|
import { defineConfig } from 'vite'
|
||||||
import { defineConfig } from 'vite';
|
import vue from '@vitejs/plugin-vue'
|
||||||
import vue from '@vitejs/plugin-vue';
|
|
||||||
import Components from 'unplugin-vue-components/vite';
|
|
||||||
import { PrimeVueResolver } from '@primevue/auto-import-resolver';
|
|
||||||
import VueJsx from '@vitejs/plugin-vue-jsx';
|
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [vue()],
|
||||||
vue(),
|
|
||||||
VueJsx(),
|
|
||||||
UnoCSS(),
|
|
||||||
Components({
|
|
||||||
resolvers: [PrimeVueResolver()],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'__fk-inputs__': '/src/__fk-inputs__',
|
|
||||||
'@': '/src',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
build: {
|
build: {
|
||||||
sourcemap: true,
|
sourcemap: true
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
Reference in New Issue
Block a user