diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 86966d7..beeb84b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,16 +31,17 @@ jobs: with: node-version: ${{ matrix.node }} - # - name: Cache dependencies - # id: cache-modules - # uses: actions/cache@v2 - # with: - # path: ~/.npm - # key: npm-${{ hashFiles('package-lock.json') }} - # restore-keys: npm- + - name: Cache dependencies + id: cache-modules + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- - name: NPM Install - # if: steps.cache-modules.outputs.cache-hit != 'true' + if: steps.cache-modules.outputs.cache-hit != 'true' run: | npm install diff --git a/.gitignore b/.gitignore index ff8f825..80bfadf 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ yarn.lock /index.cjs.js /index.esm.js /index.js -/rules yarn-error.log !src/components/*.d.ts -# !index.d.ts \ No newline at end of file +*.tgz \ No newline at end of file diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 0cb3f24..0000000 --- a/.npmignore +++ /dev/null @@ -1,16 +0,0 @@ -.vscode -.github -docs -node_modules -public -src -package-lock.json -babel.config.js -.gitignore -yarn.lock -TODO.md -.DS_Store -**/*.spec.js -**/*.test.js -**/*.spec.ts -**/*.test.ts \ No newline at end of file diff --git a/lerna.json b/lerna.json index 6505c5c..ca37e06 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "0.16.1", + "version": "0.16.4", "npmClient": "yarn", "useWorkspaces": true } diff --git a/package.json b/package.json index 4446054..ac21901 100644 --- a/package.json +++ b/package.json @@ -7,21 +7,21 @@ "license": "MIT", "repository": "https://github.com/wetix/svelte-reactive-form", "scripts": { - "prepublishOnly": "npm run test && npm run tsd && npm run build", + "prepublishOnly": "npm run test && npm run tsd && npm run format && npm run build", "test": "jest packages", "dev": "rollup -w --config rollup.dev.config.js", "start": "sirv public --port 5500", "build": "rollup -c", "svelte-check": "svelte-check --workspace=packages", "tsd": "lerna run tsd", - "format": "prettier --write ./packages/*/{src,__test__}/**/*.{js,svelte,ts} ./stories/**/*.{js,svelte,ts}", - "lint": "eslint './packages/*/{src,__test__}/**/*.{js,ts,svelte}'", - "lint:fix": "eslint --fix './packages/*/{src,__test__}/**/*.{js,ts,svelte}'" + "format": "prettier --write './packages/*/{src,types,__test__}/**/*.{js,svelte,ts}'", + "lint": "eslint './packages/*/{src,types,__test__}/**/*.{js,ts,svelte}'", + "lint:fix": "eslint --fix './packages/*/{src,types,__test__}/**/*.{js,ts,svelte}'" }, "devDependencies": { - "@babel/core": "^7.16.12", + "@babel/core": "^7.17.0", "@babel/preset-env": "^7.16.11", - "@rollup/plugin-commonjs": "^22.0.0-8", + "@rollup/plugin-commonjs": "^22.0.0-9", "@rollup/plugin-node-resolve": "^13.1.3", "@rollup/plugin-strip": "^2.1.0", "@rollup/plugin-typescript": "^8.3.0", @@ -31,29 +31,28 @@ "@types/jest": "^27.4.0", "@typescript-eslint/eslint-plugin": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", - "babel-jest": "^27.4.6", + "babel-jest": "^27.5.0", "eslint": "^8.8.0", "eslint-plugin-svelte3": "^3.4.0", - "jest": "^27.4.7", + "jest": "^27.5.0", "jest-transform-svelte": "^2.1.1", "lerna": "^4.0.0", "prettier": "^2.5.1", "prettier-plugin-svelte": "^2.6.0", - "rollup": "^2.66.1", + "rollup": "^2.67.0", "rollup-plugin-bundle-size": "^1.0.3", "rollup-plugin-css-only": "^3.1.0", "rollup-plugin-livereload": "^2.0.5", "rollup-plugin-svelte": "^7.1.0", "rollup-plugin-terser": "^7.0.2", "sirv-cli": "^2.0.2", - "svelte": "^3.46.3", + "svelte": "^3.46.4", "svelte-check": "^2.4.1", "svelte-jester": "^2.3.1", "svelte-preprocess": "^4.10.2", "ts-jest": "^27.1.3", "tslib": "^2.3.1", "typescript": "^4.5.4", - "uuid": "^8.3.2", "yup": "^1.0.0-beta.2" }, "jest": { diff --git a/packages/rules/package.json b/packages/rules/package.json index afdda8a..73a3128 100644 --- a/packages/rules/package.json +++ b/packages/rules/package.json @@ -1,6 +1,6 @@ { "name": "@svelte-reactive-form/rules", - "version": "0.16.1", + "version": "0.16.4", "type": "module", "description": "Form validation rules of svelte-reactive-form.", "author": "si3nloong (https://github.com/si3nloong)", @@ -37,5 +37,5 @@ "bugs": { "url": "https://github.com/wetix/svelte-reactive-form/issues" }, - "gitHead": "78eff2173d221b0f5b5bf5923119f27f78b28745" + "gitHead": "e136deabc1bfc4e8ac42ef4593087d28cf8e7429" } diff --git a/packages/rules/src/index.ts b/packages/rules/src/index.ts index d2a3df4..819675b 100644 --- a/packages/rules/src/index.ts +++ b/packages/rules/src/index.ts @@ -62,7 +62,7 @@ export const unique = (v: T[]): ValidationResult => { /** * Check both field are equals - * + * * @param {any} v * @param param1 * @param {FormControl} ctx diff --git a/packages/rules/types/index.d.ts b/packages/rules/types/index.d.ts index 338030e..d5ee19f 100644 --- a/packages/rules/types/index.d.ts +++ b/packages/rules/types/index.d.ts @@ -31,13 +31,18 @@ export declare const url: (v: string) => ValidationResult; */ export declare const unique: (v: T[]) => ValidationResult; /** + * Check both field are equals * - * @param v + * @param {any} v * @param param1 - * @param ctx - * @returns + * @param {FormControl} ctx + * @returns {ValidationResult} */ -export declare const same: (v: any, [field]: string[], ctx: FormControl) => ValidationResult; +export declare const same: ( + v: any, + [name]: string[], + ctx: FormControl +) => ValidationResult; /** * * @param v diff --git a/packages/svelte-reactive-form/__tests__/App.svelte b/packages/svelte-reactive-form/__tests__/App.svelte index f1129d7..219d2a8 100644 --- a/packages/svelte-reactive-form/__tests__/App.svelte +++ b/packages/svelte-reactive-form/__tests__/App.svelte @@ -1,10 +1,10 @@ - {#if type != "none"} - + {/if} + import { useForm } from "../form"; + + const form$ = useForm(); + // your script goes here + + +
+ + diff --git a/packages/svelte-reactive-form/src/form.ts b/packages/svelte-reactive-form/src/form.ts index a10fbcb..cb516ee 100644 --- a/packages/svelte-reactive-form/src/form.ts +++ b/packages/svelte-reactive-form/src/form.ts @@ -212,6 +212,7 @@ export const useForm = (config: Config = { validateOnChange: true }): Form if (e instanceof Event) { const target = e.target as HTMLInputElement; path = target.name || target.id; + if (!path) console.error("[svelte-reactive-form] missing name for input"); value = target.value; } if (cache.has(path)) { @@ -222,7 +223,7 @@ export const useForm = (config: Config = { validateOnChange: true }): Form field[0].update((v) => Object.assign(v, { dirty: true, value })); } } else { - _setStore(path); + _setStore(path, { value }); } }; @@ -359,6 +360,7 @@ export const useForm = (config: Config = { validateOnChange: true }): Form errors$.set({}); // reset errors let data = {}, valid = true; + const { elements = [] } = e.currentTarget; for (let i = 0, len = elements.length; i < len; i++) { const el = elements[i]; @@ -373,9 +375,9 @@ export const useForm = (config: Config = { validateOnChange: true }): Form if (cache.has(name)) { const field = cache.get(name); // TODO: check checkbox and radio - const { nodeName, type } = el; + const { type } = el; switch (type) { - case "checkbox": + case "checkbox" || "radio": value = el.checked ? value : ""; break; } @@ -386,6 +388,17 @@ export const useForm = (config: Config = { validateOnChange: true }): Form } } + // for (const [name, [store$]] of cache.entries()) { + // const state = get(store$); + // console.log("debug =>",name, state) + // const { value} = state; + // data = normalizeObject(data, name, value); + // const field = cache.get(name); + // const result = await _validate(field, name, { value }); + // valid = valid && result.valid; // update valid + // data = normalizeObject(data, name, value); + // } + if (config.resolver) { try { await config.resolver.validate(data); diff --git a/packages/svelte-reactive-form/tsdef.json b/packages/svelte-reactive-form/tsconfig.json similarity index 88% rename from packages/svelte-reactive-form/tsdef.json rename to packages/svelte-reactive-form/tsconfig.json index c1e5e6b..d1c2e8e 100644 --- a/packages/svelte-reactive-form/tsdef.json +++ b/packages/svelte-reactive-form/tsconfig.json @@ -1,10 +1,9 @@ { "compilerOptions": { "rootDir": "./src", - "declaration": true, - "emitDeclarationOnly": true, "outDir": "./types", "esModuleInterop": true, + "strict": true, "allowSyntheticDefaultImports": true, "types": ["jest", "node", "svelte"] }, diff --git a/packages/svelte-reactive-form/types/Field.svelte.d.ts b/packages/svelte-reactive-form/types/Field.svelte.d.ts new file mode 100644 index 0000000..3db853f --- /dev/null +++ b/packages/svelte-reactive-form/types/Field.svelte.d.ts @@ -0,0 +1,31 @@ +import type { SvelteComponentTyped } from "svelte"; +import type { Readable } from "svelte/store"; +import type { RuleExpression, FormControl } from "./types"; + +type FieldProps = { + name: string; + control: Readable; + validateOnMount?: boolean; + bail?: boolean; + defaultValue?: any; + rules?: RuleExpression; + type?: "none" | "hidden" | "text"; +}; + +type FieldSlot = { + default: { + pending: boolean; + valid: boolean; + errors: string[]; + dirty: boolean; + touched: boolean; + value: any; + onChange(e: Event | CustomEvent | any): void; + onFocus(): void; + onBlur(): void; + }; +}; + +declare class Field extends SvelteComponentTyped {} + +export default Field; diff --git a/packages/svelte-reactive-form/types/index.d.ts b/packages/svelte-reactive-form/types/index.d.ts index 92b9794..ae4ca36 100644 --- a/packages/svelte-reactive-form/types/index.d.ts +++ b/packages/svelte-reactive-form/types/index.d.ts @@ -1,33 +1,5 @@ -import type { SvelteComponentTyped } from "svelte"; -import type { Readable } from "svelte/store"; import { useForm } from "./form"; -import type { RuleExpression, FormControl } from "./types"; import { defineRule, resolveRule } from "./rule"; - -type FieldProps = { - name: string; - control: Readable; - validateOnMount?: boolean; - bail?: boolean; - defaultValue?: unknown; - rules?: RuleExpression; - type?: "none" | "hidden" | "text"; -}; - -type FieldSlot = { - default: { - pending: boolean; - valid: boolean; - errors: string[]; - dirty: boolean; - touched: boolean; - value: unknown; - onChange(e: Event | CustomEvent | unknown): void; - onFocus(): void; - onBlur(): void; - }; -}; - -declare class Field extends SvelteComponentTyped {} +import Field from "./Field.svelte"; export { useForm, Field, defineRule, resolveRule }; diff --git a/packages/svelte-reactive-form/types/types.d.ts b/packages/svelte-reactive-form/types/types.d.ts index ac461da..d8ec0f3 100644 --- a/packages/svelte-reactive-form/types/types.d.ts +++ b/packages/svelte-reactive-form/types/types.d.ts @@ -2,87 +2,110 @@ import type { Readable, Writable } from "svelte/store"; export declare type Fields = Record; export declare type FieldValue = any; interface Resolver { - validate(data: any): Promise; + validate(data: any): Promise; } export declare type Config = { - resolver?: Resolver; - validateOnChange?: boolean; + resolver?: Resolver; + validateOnChange?: boolean; }; export declare type ErrorCallback = (errors: Record, e: Event) => any; -export declare type NodeElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; +export declare type NodeElement = + | HTMLInputElement + | HTMLSelectElement + | HTMLTextAreaElement; declare type Success = true; declare type Error = string; export declare type ValidationResult = Success | Error; -export declare type ValidationFunction = (...args: any[]) => ValidationResult | Promise; +export declare type ValidationFunction = ( + ...args: any[] +) => ValidationResult | Promise; export declare type Validator = string | ValidationFunction; -export declare type RuleExpression = string | Array | Record | Record; +export declare type RuleExpression = + | string + | Array + | Record + | Record; export declare type RegisterOption = { - defaultValue?: T; - bail?: boolean; - validateOnBlur?: boolean; - validateOnMount?: boolean; - rules?: RuleExpression; + defaultValue?: T; + bail?: boolean; + validateOnBlur?: boolean; + validateOnMount?: boolean; + rules?: RuleExpression; }; export declare type FieldOption = { - defaultValue?: any; - rules?: RuleExpression; - validateOnMount?: boolean; - handleChange?: (state: FieldState, node: Element) => void; + defaultValue?: any; + rules?: RuleExpression; + validateOnMount?: boolean; + handleChange?: (state: FieldState, node: Element) => void; }; export interface FormControl> { - register: (path: string, option?: RegisterOption) => Readable; - unregister: (path: string) => void; - setValue: (e: Event | string, val?: any) => void; - getValue: (path: string) => any; - getValues: () => F; - setError: (path: string, values: string[]) => void; - setTouched: (path: string, state: boolean) => void; - reset: (values?: Fields) => void; + register: (path: string, option?: RegisterOption) => Readable; + unregister: (path: string) => void; + setValue: (e: Event | string, val?: any) => void; + getValue: (path: string) => any; + getValues: () => F; + setError: (path: string, values: string[]) => void; + setTouched: (path: string, state: boolean) => void; + reset: (values?: Fields) => void; } declare type FieldErrors = Readable; -declare type UseField = (node: HTMLElement, option?: FieldOption) => { - update(v: FieldOption): void; - destroy(): void; +declare type UseField = ( + node: HTMLElement, + option?: FieldOption +) => { + update(v: FieldOption): void; + destroy(): void; }; export interface Form extends Readable, FormControl { - control: Readable>; - field: UseField; - errors: FieldErrors; - validate: (paths?: string | Array) => Promise<{ - valid: boolean; - data: T; - }>; - onSubmit: (success: (data: T, e: Event) => void, error?: ErrorCallback) => (e: Event) => void; + control: Readable>; + field: UseField; + errors: FieldErrors; + validate: (paths?: string | Array) => Promise<{ + valid: boolean; + data: T; + }>; + onSubmit: ( + success: (data: T, e: Event) => void, + error?: ErrorCallback + ) => (e: Event) => void; } export declare type FormState = { - pending: boolean; - submitting: boolean; - dirty: boolean; - touched: boolean; - valid: boolean; + pending: boolean; + submitting: boolean; + dirty: boolean; + touched: boolean; + valid: boolean; }; export declare type FieldState = { - defaultValue: any; - value: any; - pending: boolean; - dirty: boolean; - touched: boolean; - valid: boolean; - errors: string[]; + defaultValue: any; + value: any; + pending: boolean; + dirty: boolean; + touched: boolean; + valid: boolean; + errors: string[]; }; export interface FieldStateStore extends Writable { - destroy(): void; + destroy(): void; } export declare type ValidationRule = { - name: string; - validate: (value: any, params?: string[], ctx?: FormControl) => Promise; - params: any[]; + name: string; + validate: ( + value: any, + params?: string[], + ctx?: FormControl + ) => Promise; + params: any[]; }; export declare type ResetFormOption = { - errors: boolean; - dirtyFields: boolean; + errors: boolean; + dirtyFields: boolean; }; -export declare type Field = [FieldStateStore, ValidationRule[], { +export declare type Field = [ + FieldStateStore, + ValidationRule[], + { bail: boolean; -}]; + } +]; export {}; diff --git a/packages/svelte-reactive-form/types/util.d.ts b/packages/svelte-reactive-form/types/util.d.ts index bc82fef..b5bec64 100644 --- a/packages/svelte-reactive-form/types/util.d.ts +++ b/packages/svelte-reactive-form/types/util.d.ts @@ -18,4 +18,8 @@ export declare const toPromise: (fn: Function) => (...args: any[]) => Promise * normalizeObject({ z: 440.056 }, "a[0].b.c[2]", "hello world!") * ``` */ -export declare const normalizeObject: (src: Record, key: string, value: any) => Record; +export declare const normalizeObject: ( + src: Record, + key: string, + value: any +) => Record; diff --git a/public/DefaultValuesForm.svelte b/public/DefaultValuesForm.svelte index 834907e..2354c5d 100644 --- a/public/DefaultValuesForm.svelte +++ b/public/DefaultValuesForm.svelte @@ -40,9 +40,16 @@ console.log("Values =>", form$.getValues()); alert(JSON.stringify(form$.getValues())); }; + + const onUpload = (e: Event) => { + const target = e.target as HTMLInputElement; + form$.setValue(target.name, target.files?.item(0)); + console.log(form$.getValues()); + };
+ - import { v4 as uuidv4 } from "uuid"; import * as yup from "yup"; import { useForm } from "../packages/svelte-reactive-form/src"; + const randomId = () => { + return `id_${Math.floor(Math.random() * Date.now())}`; + }; + let items: { id: string; name: string }[] = []; const schema = yup.object().shape({ @@ -33,7 +36,7 @@ const { onSubmit, errors } = form$; const handleAdd = () => { - items = [...items, { id: uuidv4(), name: "" }]; + items = [...items, { id: randomId(), name: "" }]; }; const handleRemove = (i: number) => {