Create `@primevue/form` package and add `form` component
parent
69d0407fe6
commit
9870b303cf
|
@ -0,0 +1 @@
|
||||||
|
# PrimeVue Form
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"name": "@primevue/form",
|
||||||
|
"version": "4.1.0",
|
||||||
|
"author": "PrimeTek Informatics",
|
||||||
|
"description": "",
|
||||||
|
"homepage": "https://primevue.org/",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/primefaces/primevue.git",
|
||||||
|
"directory": "packages/form"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/primefaces/primevue/issues"
|
||||||
|
},
|
||||||
|
"main": "./src/index.js",
|
||||||
|
"module": "./src/index.js",
|
||||||
|
"types": "./src/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": "./src/index.js",
|
||||||
|
"./form/style": "./src/form/style/FormStyle.js",
|
||||||
|
"./form": "./src/form/Form.vue",
|
||||||
|
"./*": "./src/*/index.js"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"main": "./index.mjs",
|
||||||
|
"module": "./index.mjs",
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"import": "./index.mjs"
|
||||||
|
},
|
||||||
|
"./*": {
|
||||||
|
"types": "./*/index.d.ts",
|
||||||
|
"import": "./*/index.mjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"directory": "dist",
|
||||||
|
"linkDirectory": false,
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "NODE_ENV=production INPUT_DIR=src/ OUTPUT_DIR=dist/ pnpm run build:package",
|
||||||
|
"build:package": "pnpm run build:prebuild && rollup -c && pnpm run build:postbuild",
|
||||||
|
"build:prebuild": "node ./scripts/prebuild.mjs",
|
||||||
|
"build:postbuild": "node ./scripts/postbuild.mjs",
|
||||||
|
"dev:link": "pnpm link --global && npm link"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@primeuix/utils": "catalog:",
|
||||||
|
"@primeuix/form": "catalog:",
|
||||||
|
"@primevue/core": "workspace:*"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.11.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
import alias from '@rollup/plugin-alias';
|
||||||
|
import { babel } from '@rollup/plugin-babel';
|
||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
import terser from '@rollup/plugin-terser';
|
||||||
|
import postcss from 'rollup-plugin-postcss';
|
||||||
|
import vue from 'rollup-plugin-vue';
|
||||||
|
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import path, { dirname } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
// @todo - Remove
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
// globals
|
||||||
|
const GLOBALS = {
|
||||||
|
vue: 'Vue'
|
||||||
|
};
|
||||||
|
|
||||||
|
// externals
|
||||||
|
const GLOBAL_EXTERNALS = ['vue'];
|
||||||
|
const INLINE_EXTERNALS = [/@primevue\/core\/.*/];
|
||||||
|
const EXTERNALS = [...GLOBAL_EXTERNALS, ...INLINE_EXTERNALS];
|
||||||
|
|
||||||
|
// alias
|
||||||
|
const ALIAS_ENTRIES = [
|
||||||
|
{
|
||||||
|
find: /^@primevue\/icons\/(.*)$/,
|
||||||
|
replacement: path.resolve(__dirname, './src/$1/index.vue')
|
||||||
|
},
|
||||||
|
{ find: '@primevue/icons/baseicon/style', replacement: path.resolve(__dirname, './src/baseicon/style/BaseIconStyle.js') },
|
||||||
|
{ find: '@primevue/icons/baseicon', replacement: path.resolve(__dirname, './src/baseicon/BaseIcon.vue') }
|
||||||
|
];
|
||||||
|
|
||||||
|
// plugins
|
||||||
|
const BABEL_PLUGIN_OPTIONS = {
|
||||||
|
extensions: ['.js', '.vue'],
|
||||||
|
exclude: 'node_modules/**',
|
||||||
|
presets: ['@babel/preset-env'],
|
||||||
|
plugins: [],
|
||||||
|
skipPreflightCheck: true,
|
||||||
|
babelHelpers: 'runtime',
|
||||||
|
babelrc: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const ALIAS_PLUGIN_OPTIONS = {
|
||||||
|
entries: ALIAS_ENTRIES
|
||||||
|
};
|
||||||
|
|
||||||
|
const POSTCSS_PLUGIN_OPTIONS = {
|
||||||
|
sourceMap: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const TERSER_PLUGIN_OPTIONS = {
|
||||||
|
compress: {
|
||||||
|
keep_infinity: true,
|
||||||
|
pure_getters: true,
|
||||||
|
reduce_funcs: true
|
||||||
|
},
|
||||||
|
mangle: {
|
||||||
|
reserved: ['theme', 'css']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const PLUGINS = [vue(), postcss(POSTCSS_PLUGIN_OPTIONS), babel(BABEL_PLUGIN_OPTIONS)];
|
||||||
|
|
||||||
|
const ENTRY = {
|
||||||
|
entries: [],
|
||||||
|
onwarn(warning) {
|
||||||
|
if (warning.code === 'CIRCULAR_DEPENDENCY') {
|
||||||
|
//console.error(`(!) ${warning.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
format: {
|
||||||
|
cjs_es(options) {
|
||||||
|
return ENTRY.format.cjs(options).es(options);
|
||||||
|
},
|
||||||
|
cjs({ input, output, minify }) {
|
||||||
|
ENTRY.entries.push({
|
||||||
|
onwarn: ENTRY.onwarn,
|
||||||
|
input,
|
||||||
|
plugins: [...PLUGINS, minify && terser(TERSER_PLUGIN_OPTIONS)],
|
||||||
|
external: EXTERNALS,
|
||||||
|
inlineDynamicImports: true,
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
format: 'cjs',
|
||||||
|
file: `${output}${minify ? '.min' : ''}.cjs`,
|
||||||
|
sourcemap: true,
|
||||||
|
exports: 'auto'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
ENTRY.update.packageJson({ input, output, options: { main: `${output}.cjs` } });
|
||||||
|
|
||||||
|
return ENTRY.format;
|
||||||
|
},
|
||||||
|
es({ input, output, minify }) {
|
||||||
|
ENTRY.entries.push({
|
||||||
|
onwarn: ENTRY.onwarn,
|
||||||
|
input,
|
||||||
|
plugins: [...PLUGINS, minify && terser(TERSER_PLUGIN_OPTIONS)],
|
||||||
|
external: EXTERNALS,
|
||||||
|
inlineDynamicImports: true,
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
format: 'es',
|
||||||
|
file: `${output}${minify ? '.min' : ''}.mjs`,
|
||||||
|
sourcemap: true,
|
||||||
|
exports: 'auto'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
ENTRY.update.packageJson({ input, output, options: { main: `${output}.mjs`, module: `${output}.mjs` } });
|
||||||
|
|
||||||
|
return ENTRY.format;
|
||||||
|
},
|
||||||
|
umd({ name, input, output, minify }) {
|
||||||
|
ENTRY.entries.push({
|
||||||
|
onwarn: ENTRY.onwarn,
|
||||||
|
input,
|
||||||
|
plugins: [alias(ALIAS_PLUGIN_OPTIONS), resolve(), ...PLUGINS, minify && terser(TERSER_PLUGIN_OPTIONS)],
|
||||||
|
external: GLOBAL_EXTERNALS,
|
||||||
|
inlineDynamicImports: true,
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
format: 'umd',
|
||||||
|
name: name ?? 'PrimeVue',
|
||||||
|
file: `${output}${minify ? '.min' : ''}.js`,
|
||||||
|
globals: GLOBALS,
|
||||||
|
exports: 'auto'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return ENTRY.format;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
packageJson({ input, output, options }) {
|
||||||
|
try {
|
||||||
|
const inputDir = path.resolve(__dirname, path.dirname(input));
|
||||||
|
const outputDir = path.resolve(__dirname, path.dirname(output));
|
||||||
|
const packageJson = path.resolve(outputDir, 'package.json');
|
||||||
|
|
||||||
|
!fs.existsSync(packageJson) && fs.copySync(path.resolve(inputDir, './package.json'), packageJson);
|
||||||
|
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(packageJson, { encoding: 'utf8', flag: 'r' }));
|
||||||
|
|
||||||
|
!pkg?.main?.includes('.cjs') && (pkg.main = path.basename(options?.main) ? `./${path.basename(options.main)}` : pkg.main);
|
||||||
|
pkg.module = path.basename(options?.module) ? `./${path.basename(options.module)}` : packageJson.module;
|
||||||
|
pkg.types && (pkg.types = './index.d.ts');
|
||||||
|
|
||||||
|
fs.writeFileSync(packageJson, JSON.stringify(pkg, null, 4));
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function addIcons() {
|
||||||
|
const iconDir = path.resolve(__dirname, process.env.INPUT_DIR);
|
||||||
|
|
||||||
|
fs.readdirSync(path.resolve(__dirname, iconDir), { withFileTypes: true })
|
||||||
|
.filter((dir) => dir.isDirectory())
|
||||||
|
.forEach(({ name: folderName }) => {
|
||||||
|
fs.readdirSync(path.resolve(__dirname, iconDir + '/' + folderName)).forEach((file) => {
|
||||||
|
if (/\.vue$/.test(file)) {
|
||||||
|
const input = process.env.INPUT_DIR + folderName + '/' + file;
|
||||||
|
const output = process.env.OUTPUT_DIR + folderName + '/index';
|
||||||
|
|
||||||
|
ENTRY.format.es({ input, output });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStyle() {
|
||||||
|
fs.readdirSync(path.resolve(__dirname, process.env.INPUT_DIR), { withFileTypes: true })
|
||||||
|
.filter((dir) => dir.isDirectory())
|
||||||
|
.forEach(({ name: folderName }) => {
|
||||||
|
try {
|
||||||
|
fs.readdirSync(path.resolve(__dirname, process.env.INPUT_DIR + folderName + '/style')).forEach((file) => {
|
||||||
|
if (/\.js$/.test(file)) {
|
||||||
|
const name = file.split(/(.js)$/)[0].toLowerCase();
|
||||||
|
const input = process.env.INPUT_DIR + folderName + '/style/' + file;
|
||||||
|
const output = process.env.OUTPUT_DIR + folderName + '/style/index';
|
||||||
|
|
||||||
|
ENTRY.format.es({ input, output });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addIcons();
|
||||||
|
addStyle();
|
||||||
|
|
||||||
|
export default ENTRY.entries;
|
|
@ -0,0 +1,14 @@
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import { clearPackageJson, copyDependencies, renameDTSFile, resolvePath } from '../../../scripts/build-helper.mjs';
|
||||||
|
|
||||||
|
const { __dirname, __workspace, INPUT_DIR, OUTPUT_DIR } = resolvePath(import.meta.url);
|
||||||
|
|
||||||
|
copyDependencies(INPUT_DIR, OUTPUT_DIR, '/style');
|
||||||
|
renameDTSFile(OUTPUT_DIR, 'index');
|
||||||
|
|
||||||
|
fs.copySync(path.resolve(__dirname, '../package.json'), `${OUTPUT_DIR}/package.json`);
|
||||||
|
fs.copySync(path.resolve(__dirname, '../README.md'), `${OUTPUT_DIR}/README.md`);
|
||||||
|
fs.copySync(path.resolve(__workspace, './LICENSE.md'), `${OUTPUT_DIR}/LICENSE.md`);
|
||||||
|
|
||||||
|
clearPackageJson(path.resolve(__dirname, `../${OUTPUT_DIR}/package.json`));
|
|
@ -0,0 +1,5 @@
|
||||||
|
import path from 'path';
|
||||||
|
import { removeBuild, resolvePath, updatePackageJson } from '../../../scripts/build-helper.mjs';
|
||||||
|
|
||||||
|
removeBuild(import.meta.url);
|
||||||
|
updatePackageJson(path.resolve(resolvePath(import.meta.url).__dirname, '../package.json'));
|
|
@ -0,0 +1,42 @@
|
||||||
|
<script>
|
||||||
|
import BaseComponent from '@primevue/core/basecomponent';
|
||||||
|
import FormStyle from '@primevue/form/form/style';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BaseForm',
|
||||||
|
extends: BaseComponent,
|
||||||
|
style: FormStyle,
|
||||||
|
props: {
|
||||||
|
resolver: {
|
||||||
|
type: Function,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
defaultValues: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
validateOnValueUpdate: {
|
||||||
|
type: [Boolean, Array],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
validateOnBlur: {
|
||||||
|
type: [Boolean, Array],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
validateOnMount: {
|
||||||
|
type: [Boolean, Array],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
validateOnSubmit: {
|
||||||
|
type: [Boolean, Array],
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
$pcForm: this,
|
||||||
|
$parentInstance: this
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,130 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Fluid is a layout component to make descendant components span full width of their container.
|
||||||
|
*
|
||||||
|
* [Live Demo](https://www.primevue.org/fluid/)
|
||||||
|
*
|
||||||
|
* @module fluid
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import type { DefineComponent, DesignToken, EmitFn, PassThrough } from '@primevue/core';
|
||||||
|
import type { ComponentHooks } from '@primevue/core/basecomponent';
|
||||||
|
import type { PassThroughOptions } from 'primevue/passthrough';
|
||||||
|
import { TransitionProps, VNode } from 'vue';
|
||||||
|
|
||||||
|
export declare type FluidPassThroughOptionType = FluidPassThroughAttributes | ((options: FluidPassThroughMethodOptions) => FluidPassThroughAttributes | string) | string | null | undefined;
|
||||||
|
|
||||||
|
export declare type FluidPassThroughTransitionType = TransitionProps | ((options: FluidPassThroughMethodOptions) => TransitionProps) | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom passthrough(pt) option method.
|
||||||
|
*/
|
||||||
|
export interface FluidPassThroughMethodOptions {
|
||||||
|
/**
|
||||||
|
* Defines instance.
|
||||||
|
*/
|
||||||
|
instance: any;
|
||||||
|
/**
|
||||||
|
* Defines valid properties.
|
||||||
|
*/
|
||||||
|
props: FluidProps;
|
||||||
|
/**
|
||||||
|
* Defines valid attributes.
|
||||||
|
*/
|
||||||
|
attrs: any;
|
||||||
|
/**
|
||||||
|
* Defines parent options.
|
||||||
|
*/
|
||||||
|
parent: any;
|
||||||
|
/**
|
||||||
|
* Defines passthrough(pt) options in global config.
|
||||||
|
*/
|
||||||
|
global: object | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom passthrough(pt) options.
|
||||||
|
* @see {@link FluidProps.pt}
|
||||||
|
*/
|
||||||
|
export interface FluidPassThroughOptions {
|
||||||
|
/**
|
||||||
|
* Used to pass attributes to the root's DOM element.
|
||||||
|
*/
|
||||||
|
root?: FluidPassThroughOptionType;
|
||||||
|
/**
|
||||||
|
* Used to manage all lifecycle hooks.
|
||||||
|
* @see {@link BaseComponent.ComponentHooks}
|
||||||
|
*/
|
||||||
|
hooks?: ComponentHooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom passthrough attributes for each DOM elements
|
||||||
|
*/
|
||||||
|
export interface FluidPassThroughAttributes {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines valid properties in Fluid component.
|
||||||
|
*/
|
||||||
|
export interface FluidProps {
|
||||||
|
/**
|
||||||
|
* It generates scoped CSS variables using design tokens for the component.
|
||||||
|
*/
|
||||||
|
dt?: DesignToken<any>;
|
||||||
|
/**
|
||||||
|
* Used to pass attributes to DOM elements inside the component.
|
||||||
|
* @type {FluidPassThroughOptions}
|
||||||
|
*/
|
||||||
|
pt?: PassThrough<FluidPassThroughOptions>;
|
||||||
|
/**
|
||||||
|
* Used to configure passthrough(pt) options of the component.
|
||||||
|
* @type {PassThroughOptions}
|
||||||
|
*/
|
||||||
|
ptOptions?: PassThroughOptions;
|
||||||
|
/**
|
||||||
|
* When enabled, it removes component related styles in the core.
|
||||||
|
* @defaultValue false
|
||||||
|
*/
|
||||||
|
unstyled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines valid slots in Fluid component.
|
||||||
|
*/
|
||||||
|
export interface FluidSlots {
|
||||||
|
/**
|
||||||
|
* Default content slot.
|
||||||
|
*/
|
||||||
|
default: () => VNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines valid emits in Fluid component.
|
||||||
|
*/
|
||||||
|
export interface FluidEmitsOptions {}
|
||||||
|
|
||||||
|
export declare type FluidEmits = EmitFn<FluidEmitsOptions>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **PrimeVue - Fluid**
|
||||||
|
*
|
||||||
|
* _Fluid is a layout component to make descendant components span full width of their container._
|
||||||
|
*
|
||||||
|
* [Live Demo](https://www.primevue.org/fluid/)
|
||||||
|
* --- ---
|
||||||
|
* ![PrimeVue](https://primefaces.org/cdn/primevue/images/logo-100.png)
|
||||||
|
*
|
||||||
|
* @group Component
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
declare const Fluid: DefineComponent<FluidProps, FluidSlots, FluidEmits>;
|
||||||
|
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
Fluid: DefineComponent<FluidProps, FluidSlots, FluidEmits>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Fluid;
|
|
@ -0,0 +1,37 @@
|
||||||
|
<template>
|
||||||
|
<form @submit.prevent="onSubmit" v-bind="ptmi('root')">
|
||||||
|
<slot :register :valid v-bind="states" />
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { omit } from '@primeuix/utils';
|
||||||
|
import { useForm } from '@primevue/form/useform';
|
||||||
|
import BaseForm from './BaseForm.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Form',
|
||||||
|
extends: BaseForm,
|
||||||
|
inheritAttrs: false,
|
||||||
|
emits: ['submit'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const $form = useForm(props);
|
||||||
|
|
||||||
|
const register = (field, options) => {
|
||||||
|
const [, fieldProps] = $form.defineField(field, options);
|
||||||
|
|
||||||
|
return fieldProps;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = $form.handleSubmit((e) => {
|
||||||
|
emit('submit', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
register,
|
||||||
|
onSubmit,
|
||||||
|
...omit($form, ['defineField', 'handleSubmit'])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"main": "./Form.vue",
|
||||||
|
"module": "./Form.vue",
|
||||||
|
"types": "./Form.d.ts",
|
||||||
|
"browser": {
|
||||||
|
"./sfc": "./Form.vue"
|
||||||
|
},
|
||||||
|
"sideEffects": [
|
||||||
|
"*.vue"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* [Live Demo](https://www.primevue.org/form/)
|
||||||
|
*
|
||||||
|
* @module formstyle
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import type { BaseStyle } from '@primevue/core/base/style';
|
||||||
|
|
||||||
|
export interface FormStyle extends BaseStyle {}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import BaseStyle from '@primevue/core/base/style';
|
||||||
|
|
||||||
|
export default BaseStyle.extend({
|
||||||
|
name: 'form'
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"main": "./FormStyle.js",
|
||||||
|
"module": "./FormStyle.js",
|
||||||
|
"types": "./FormStyle.d.ts",
|
||||||
|
"sideEffects": false
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export { default as Form } from '@primevue/form/form';
|
||||||
|
export * from '@primevue/form/resolvers';
|
||||||
|
export * from '@primevue/form/useform';
|
|
@ -0,0 +1 @@
|
||||||
|
export * from '@primeuix/form/resolvers';
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"main": "./index.js",
|
||||||
|
"module": "./index.js"
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
import { resolve } from '@primeuix/utils';
|
||||||
|
import { computed, mergeProps, nextTick, onMounted, reactive, toValue, watch } from 'vue';
|
||||||
|
|
||||||
|
function tryOnMounted(fn, sync = true) {
|
||||||
|
if (getCurrentInstance()) onMounted(fn);
|
||||||
|
else if (sync) fn();
|
||||||
|
else nextTick(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useForm = (options = {}) => {
|
||||||
|
const states = reactive({});
|
||||||
|
const valid = computed(() => Object.values(states).every((field) => !field.invalid));
|
||||||
|
|
||||||
|
const getInitialState = (field) => {
|
||||||
|
return {
|
||||||
|
value: options.defaultValues?.[field],
|
||||||
|
touched: false,
|
||||||
|
dirty: false,
|
||||||
|
pristine: true,
|
||||||
|
valid: true,
|
||||||
|
invalid: false,
|
||||||
|
errors: []
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const isFieldValidate = (field, validateOn) => {
|
||||||
|
const value = resolve(validateOn, field);
|
||||||
|
|
||||||
|
return value === true || (Array.isArray(value) && value.includes(field));
|
||||||
|
};
|
||||||
|
|
||||||
|
const defineField = (field, fieldOptions) => {
|
||||||
|
states[field] ||= getInitialState(field);
|
||||||
|
|
||||||
|
const props = mergeProps(resolve(fieldOptions, states[field])?.props, resolve(fieldOptions?.props, states[field]), {
|
||||||
|
name: field,
|
||||||
|
onBlur: () => {
|
||||||
|
states[field].touched = true;
|
||||||
|
(fieldOptions?.validateOnBlur ?? isFieldValidate(field, options.validateOnBlur)) && validate(field);
|
||||||
|
},
|
||||||
|
onChange: (event) => {
|
||||||
|
states[field].value = event.hasOwnProperty('value') ? event.value : event.target.type === 'checkbox' || event.target.type === 'radio' ? event.target.checked : event.target.value;
|
||||||
|
},
|
||||||
|
onInvalid: (errors) => {
|
||||||
|
states[field].invalid = true;
|
||||||
|
states[field].errors = errors;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => states[field].value,
|
||||||
|
(newValue, oldValue) => {
|
||||||
|
if (states[field].pristine) {
|
||||||
|
states[field].pristine = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newValue !== oldValue) {
|
||||||
|
states[field].dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
(fieldOptions?.validateOnBlur ?? isFieldValidate(field, options.validateOnValueUpdate ?? true)) && validate(field);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return [states[field], props];
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = (callback) => {
|
||||||
|
return async (event) => {
|
||||||
|
let results = undefined;
|
||||||
|
|
||||||
|
(options.validateOnSubmit ?? true) && (results = await validate());
|
||||||
|
|
||||||
|
return callback({
|
||||||
|
originalEvent: event,
|
||||||
|
valid: toValue(valid),
|
||||||
|
states: toValue(states),
|
||||||
|
...results
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const validate = async (field) => {
|
||||||
|
const values = Object.entries(states).reduce((acc, [key, val]) => {
|
||||||
|
acc[key] = val.value;
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const result = (await options.resolver?.({ values })) ?? {};
|
||||||
|
|
||||||
|
for (const sField of Object.keys(states)) {
|
||||||
|
if (sField === field || !field) {
|
||||||
|
const errors = result.errors?.[sField] ?? [];
|
||||||
|
const value = result.values?.[sField] ?? states[sField].value;
|
||||||
|
|
||||||
|
states[sField].invalid = errors.length > 0;
|
||||||
|
states[sField].valid = !states[sField].invalid;
|
||||||
|
states[sField].errors = errors;
|
||||||
|
states[sField].value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
Object.keys(states).forEach((field) => (states[field] = getInitialState(field)));
|
||||||
|
};
|
||||||
|
|
||||||
|
options.validateOnMount && tryOnMounted(validate);
|
||||||
|
|
||||||
|
return {
|
||||||
|
defineField,
|
||||||
|
handleSubmit,
|
||||||
|
validate,
|
||||||
|
reset,
|
||||||
|
valid: toValue(valid),
|
||||||
|
states: toValue(states)
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"main": "./index.js",
|
||||||
|
"module": "./index.js"
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": false,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": false,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@primevue/form/*": ["./src/*"],
|
||||||
|
"@primevue/core/*": ["../../packages/core/src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["**/*.ts", "src/*"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
Loading…
Reference in New Issue