1
0
Fork 0
mirror of synced 2025-04-17 23:20:54 +00:00

Compare commits

..

No commits in common. "master" and "v0.6.3" have entirely different histories.

34 changed files with 4321 additions and 2718 deletions

View file

@ -1,27 +1,30 @@
module.exports = { module.exports = {
root: true, root: true,
parserOptions: {
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: [
'standard',
'@vue/standard',
'@vue/typescript',
'plugin:@typescript-eslint/recommended',
'plugin:vue/recommended',
],
env: { env: {
browser: true, browser: true,
}, },
parserOptions: {
parser: '@typescript-eslint/parser',
},
plugins: [
'@typescript-eslint',
'vue',
],
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:vue/recommended',
],
rules: { rules: {
'@typescript-eslint/camelcase': ['error', {
allow: ['^__Formulario'],
}],
'@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-explicit-any': 'off', // @TODO '@typescript-eslint/no-explicit-any': 'off', // @TODO
'@typescript-eslint/no-unused-vars': ['error'], // @TODO '@typescript-eslint/no-unused-vars': ['error'], // @TODO

11
.gitignore vendored
View file

@ -1,16 +1,11 @@
node_modules
coverage
.cache .cache
.DS_Store .DS_Store
.idea .idea
.vscode .vscode
coverage
dist/
node_modules
*.sublime-project *.sublime-project
*.sublime-workspace *.sublime-workspace
*.dev.tale.vue *.dev.tale.vue
*.dev.stories.js *.dev.stories.js
storybook-static
storybook-static
.npmrc

View file

@ -2,73 +2,6 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.8.3](https://github.com/retailcrm/vue-formulario/compare/v0.8.2...v0.8.3) (2024-12-06)
### Features
* Updated package.json manifest ([cbe80e3](https://github.com/retailcrm/vue-formulario/commit/cbe80e3de498732af8db34f0846cc92d977d9420))
### [0.8.2](https://github.com/retailcrm/vue-formulario/compare/v0.8.1...v0.8.2) (2023-12-28)
### Features
* Added web-types declaration ([eda7a1d](https://github.com/retailcrm/vue-formulario/commit/eda7a1d79d98e4ccd76e67bc93c1bf8dc5249e67))
### [0.8.1](https://github.com/retailcrm/vue-formulario/compare/v0.8.0...v0.8.1) (2023-12-28)
### Fixes
* build ([92a3f8c](https://github.com/retailcrm/vue-formulario/commit/92a3f8cc60fdfb1f7588b281febcc833b17d3521))
## [0.8.0](https://github.com/retailcrm/vue-formulario/compare/v0.7.3...v0.8.0) (2023-12-28)
### ⚠ BREAKING CHANGES
* Old names of FormularioField & FormularioFieldGroup no longer available
### Features
* Components conststructors are exposed as external API, added TypeScript declarations ([dfc6557](https://github.com/retailcrm/vue-formulario/commit/dfc6557bc632489daeb8f4ae44ad208f6c6a9997))
* Old names of FormularioField & FormularioFieldGroup no longer available ([b83a429](https://github.com/retailcrm/vue-formulario/commit/b83a42911749272c9c8bd35c4ea10f687c5d8821))
### [0.7.3](https://github.com/retailcrm/vue-formulario/compare/v0.7.2...v0.7.3) (2021-11-11)
### Fixes
* Fixed toString calls in validators ([da56b04](https://github.com/retailcrm/vue-formulario/commit/da56b04213b6ebc3d001a273b26a350a59e0382b))
### [0.7.2](https://github.com/retailcrm/vue-formulario/compare/v0.7.1...v0.7.2) (2021-10-21)
### Fixes
* Blob objects are no longer cloned ([67dba98](https://github.com/retailcrm/vue-formulario/commit/67dba981a15b04a84512de277f633d0f7d19d543))
### [0.7.1](https://github.com/retailcrm/vue-formulario/compare/v0.7.0...v0.7.1) (2021-09-30)
### Fixes
* Build ([8e36a9f](https://github.com/retailcrm/vue-formulario/commit/8e36a9f59dc21d0efc4f3dfe97fe992c204ee3e0))
## [0.7.0](https://github.com/retailcrm/vue-formulario/compare/v0.6.3...v0.7.0) (2021-09-30)
### ⚠ BREAKING CHANGES
* Added property "unregisterBehavior" to FormularioField to control value unset behavior on field component removal
### Features
* Added property "unregisterBehavior" to FormularioField to control value unset behavior on field component removal ([d39ca17](https://github.com/retailcrm/vue-formulario/commit/d39ca17e45cb5957bd9b9916b6e904993e660bc5))
### [0.6.3](https://github.com/retailcrm/vue-formulario/compare/v0.6.2...v0.6.3) (2021-09-29) ### [0.6.3](https://github.com/retailcrm/vue-formulario/compare/v0.6.2...v0.6.3) (2021-09-29)

View file

@ -9,7 +9,9 @@ export default {
input: 'src/index.ts', input: 'src/index.ts',
output: [{ output: [{
name: 'Formulario', name: 'Formulario',
exports: 'default',
globals: { globals: {
'is-plain-object': 'isPlainObject',
'is-url': 'isUrl', 'is-url': 'isUrl',
vue: 'Vue', vue: 'Vue',
'vue-property-decorator': 'vuePropertyDecorator', 'vue-property-decorator': 'vuePropertyDecorator',

View file

@ -11,8 +11,10 @@ export default {
input: 'src/index.ts', input: 'src/index.ts',
output: { output: {
name: 'VueFormulario', name: 'VueFormulario',
exports: 'default',
format: 'iife', format: 'iife',
globals: { globals: {
'is-plain-object': 'isPlainObject',
'is-url': 'isUrl', 'is-url': 'isUrl',
vue: 'Vue', vue: 'Vue',
'vue-property-decorator': 'vuePropertyDecorator', 'vue-property-decorator': 'vuePropertyDecorator',
@ -28,7 +30,7 @@ export default {
vue({ css: true, compileTemplate: true }), vue({ css: true, compileTemplate: true }),
alias({ entries: [{ find: /^@\/(.+)/, replacement: './$1' }] }), alias({ entries: [{ find: /^@\/(.+)/, replacement: './$1' }] }),
commonjs(), commonjs(),
internal(['is-url', 'vue-property-decorator']), internal(['is-plain-object', 'is-url', 'vue-property-decorator']),
terser(), terser(),
] ]
} }

1531
dist/formulario.esm.js vendored Normal file

File diff suppressed because it is too large Load diff

34
dist/formulario.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1538
dist/formulario.umd.js vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
version: '3.6' version: '3.6'
services: services:
node: node:
image: node:16-alpine image: node:12-alpine
user: node user: node
volumes: volumes:
- ./:/var/www/vue-formulario - ./:/var/www/vue-formulario

94
index.d.ts vendored
View file

@ -1,94 +0,0 @@
// noinspection JSUnusedGlobalSymbols
import type { Vue } from 'vue/types/vue'
import type { PluginObject } from 'vue/types/plugin'
import type { DefineComponent } from './types/vue'
import type { FormularioFormConstructor } from './types/form'
import type {
ModelGetConverter,
ModelSetConverter,
ValidationBehaviour,
UnregisterBehaviour,
} from './types/field'
import type {
ValidationMessageFn,
ValidationMessageI18NFn,
ValidationRuleFn,
Violation,
} from './types/validation'
import type { Options } from './types/plugin'
declare const FormularioForm: FormularioFormConstructor
export { FormularioForm }
declare const FormularioField: DefineComponent<{
name: string;
value?: unknown;
validation?: string|any[];
/** Defaults to 'demand' */
validationBehavior?: ValidationBehaviour;
validationRules?: Record<string, ValidationRuleFn>;
validationMessages?: Record<string, ValidationMessageI18NFn|string>;
errorsDisabled?: boolean;
modelGetConverter?: ModelGetConverter;
modelSetConverter?: ModelSetConverter;
/** Defaults to 'none' */
unregisterBehavior?: UnregisterBehaviour;
tag?: string;
}, {
runValidation(): Promise<Violation[]>;
hasValidationErrors (): Promise<boolean>;
/** @internal */
resetValidation(): void;
}>
export { FormularioField }
declare class Formulario {
public validationRules: Record<string, ValidationRuleFn>;
public validationMessages: Record<string, ValidationMessageI18NFn|string>;
constructor (options?: Options);
/** Given a set of options, apply them to the pre-existing options. */
public extend (extendWith: Options): Formulario;
public runValidation (id: string): Promise<Record<string, Violation[]>>;
public resetValidation (id: string): void;
/** Used by forms instances to add themselves into a registry */
public register (id: string, form: InstanceType<FormularioFormConstructor>): void;
/** Used by forms instances to remove themselves from a registry */
public unregister (id: string): void;
/** Get validation rules by merging any passed in with global rules. */
public getRules (extendWith: Record<string, ValidationRuleFn> = {}): Record<string, ValidationRuleFn>;
/** Get validation messages by merging any passed in with global messages. */
public getMessages (
vm: Vue,
extendWith: Record<string, ValidationMessageI18NFn|string>
): Record<string, ValidationMessageFn>;
}
export { Formulario }
declare module 'vue/types/vue' {
interface Vue {
readonly $formulario: Formulario;
}
}
declare const VueFormulario: PluginObject<Options> & {
Formulario: Formulario,
}
export default VueFormulario

View file

@ -1,6 +1,6 @@
{ {
"name": "@retailcrm/vue-formulario", "name": "@retailcrm/vue-formulario",
"version": "0.8.3", "version": "0.6.3",
"license": "MIT", "license": "MIT",
"author": "RetailDriverLLC <integration@retailcrm.ru>", "author": "RetailDriverLLC <integration@retailcrm.ru>",
"main": "dist/formulario.umd.js", "main": "dist/formulario.umd.js",
@ -9,22 +9,12 @@
"./sfc": "src/index.ts" "./sfc": "src/index.ts"
}, },
"unpkg": "dist/formulario.min.js", "unpkg": "dist/formulario.min.js",
"web-types": "web-types.json",
"files": [
"dist",
"types",
"CHANGELOG.md",
"LICENSE.txt",
"README.md"
],
"dependencies": { "dependencies": {
"is-plain-object": "^3.0.0",
"is-url": "^1.2.4", "is-url": "^1.2.4",
"vue-class-component": "^7.2.3", "vue-class-component": "^7.2.3",
"vue-property-decorator": "^8.4.2" "vue-property-decorator": "^8.4.2"
}, },
"peerDependencies": {
"vue": "^2.6"
},
"bugs": { "bugs": {
"url": "https://github.com/retailcrm/vue-formulario/issues" "url": "https://github.com/retailcrm/vue-formulario/issues"
}, },
@ -34,7 +24,7 @@
"build:iife": "rollup --config build/rollup.iife.config.js --format iife --file dist/formulario.min.js", "build:iife": "rollup --config build/rollup.iife.config.js --format iife --file dist/formulario.min.js",
"build:size": "gzip -c dist/formulario.esm.js | wc -c", "build:size": "gzip -c dist/formulario.esm.js | wc -c",
"build:umd": "rollup --config build/rollup.config.js --format umd --file dist/formulario.umd.js", "build:umd": "rollup --config build/rollup.config.js --format umd --file dist/formulario.umd.js",
"lint": "eslint --ext .js,.mjs,.ts,.vue", "lint": "vue-cli-service lint",
"release": "standard-version", "release": "standard-version",
"release:minor": "standard-version --release-as minor", "release:minor": "standard-version --release-as minor",
"release:patch": "standard-version --release-as patch", "release:patch": "standard-version --release-as patch",
@ -62,28 +52,32 @@
"@storybook/vue": "^6.0.26", "@storybook/vue": "^6.0.26",
"@types/is-url": "^1.2.28", "@types/is-url": "^1.2.28",
"@types/jest": "^26.0.14", "@types/jest": "^26.0.14",
"@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/eslint-plugin": "^2.26.0",
"@typescript-eslint/parser": "^6.16.0", "@typescript-eslint/parser": "^2.26.0",
"@vue/cli-plugin-babel": "^4.3.1", "@vue/cli-plugin-babel": "^4.3.1",
"@vue/cli-plugin-eslint": "^4.3.1",
"@vue/cli-plugin-typescript": "^4.5.7", "@vue/cli-plugin-typescript": "^4.5.7",
"@vue/cli-service": "^4.5.4", "@vue/cli-service": "^4.5.4",
"@vue/component-compiler-utils": "^3.1.2", "@vue/component-compiler-utils": "^3.1.2",
"@vue/eslint-config-standard": "^5.1.2",
"@vue/eslint-config-typescript": "^5.0.2",
"@vue/test-utils": "^1.0.2", "@vue/test-utils": "^1.0.2",
"autoprefixer": "^9.7.6", "autoprefixer": "^9.7.6",
"babel-core": "^7.0.0-bridge.0", "babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^25.5.1", "babel-jest": "^25.5.1",
"bootstrap-scss": "^4.5.2", "bootstrap-scss": "^4.5.2",
"eslint": "^8.56.0", "eslint": "^5.16.0",
"eslint-config-standard": "^17.1.0", "eslint-config-standard": "^12.0.0",
"eslint-friendly-formatter": "^4.0.1", "eslint-plugin-import": "^2.20.1",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-node": "^8.0.1",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.1.1",
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^9.19.2", "eslint-plugin-vue": "^5.2.3",
"flush-promises": "^1.0.2", "flush-promises": "^1.0.2",
"jest": "^26.5.2", "jest": "^26.5.2",
"jest-vue-preprocessor": "^1.7.1", "jest-vue-preprocessor": "^1.7.1",
"node-sass": "^9.0.0", "node-sass": "^4.14.1",
"rollup": "^1.32.1", "rollup": "^1.32.1",
"rollup-plugin-auto-external": "^2.0.0", "rollup-plugin-auto-external": "^2.0.0",
"rollup-plugin-internal": "^1.0.4", "rollup-plugin-internal": "^1.0.4",
@ -94,7 +88,7 @@
"sass-loader": "^10.0.3", "sass-loader": "^10.0.3",
"standard-version": "^9.3.0", "standard-version": "^9.3.0",
"ts-jest": "^26.4.1", "ts-jest": "^26.4.1",
"typescript": "^4.9.5", "typescript": "~3.9.3",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-cli-plugin-storybook": "^1.3.0", "vue-cli-plugin-storybook": "^1.3.0",
"vue-jest": "^3.0.5", "vue-jest": "^3.0.5",

View file

@ -1,26 +1,33 @@
import type { FormularioFormConstructor } from '../types/form' import merge from '@/utils/merge'
import validationRules from '@/validation/rules'
import validationMessages from '@/validation/messages'
import type { import {
ValidationContext, ValidationContext,
ValidationRuleFn, ValidationRuleFn,
ValidationMessageFn, ValidationMessageFn,
ValidationMessageI18NFn, ValidationMessageI18NFn,
Violation, Violation,
} from '../types/validation' } from '@/validation/validator'
import type { Options } from '../types/plugin' import { FormularioForm } from '@/types'
import validationRules from '@/validation/rules' export interface FormularioOptions {
import validationMessages from '@/validation/messages' validationRules?: Record<string, ValidationRuleFn>;
validationMessages?: Record<string, ValidationMessageI18NFn|string>;
}
/**
* The base formulario library.
*/
export default class Formulario { export default class Formulario {
public validationRules: Record<string, ValidationRuleFn> = {} public validationRules: Record<string, ValidationRuleFn> = {}
public validationMessages: Record<string, ValidationMessageI18NFn|string> = {} public validationMessages: Record<string, ValidationMessageI18NFn|string> = {}
private readonly _registry: Map<string, InstanceType<FormularioFormConstructor>> private readonly registry: Map<string, FormularioForm>
public constructor (options?: Options) { public constructor (options?: FormularioOptions) {
this._registry = new Map() this.registry = new Map()
this.validationRules = validationRules this.validationRules = validationRules
this.validationMessages = validationMessages this.validationMessages = validationMessages
@ -31,31 +38,31 @@ export default class Formulario {
/** /**
* Given a set of options, apply them to the pre-existing options. * Given a set of options, apply them to the pre-existing options.
*/ */
public extend (extendWith: Options): Formulario { public extend (extendWith: FormularioOptions): Formulario {
if (typeof extendWith === 'object') { if (typeof extendWith === 'object') {
this.validationRules = { ...this.validationRules, ...(extendWith.validationRules || {}) } this.validationRules = merge(this.validationRules, extendWith.validationRules || {})
this.validationMessages = { ...this.validationMessages, ...(extendWith.validationMessages || {}) } this.validationMessages = merge(this.validationMessages, extendWith.validationMessages || {})
return this return this
} }
throw new Error(`[Formulario]: Formulario.extend(): should be passed an object (was ${typeof extendWith})`) throw new Error(`[Formulario]: Formulario.extend(): should be passed an object (was ${typeof extendWith})`)
} }
public runValidation (id: string): Promise<Record<string, Violation[]>> { public runValidation (id: string): Promise<Record<string, Violation[]>> {
if (!this._registry.has(id)) { if (!this.registry.has(id)) {
throw new Error(`[Formulario]: Formulario.runValidation(): no forms with id "${id}"`) throw new Error(`[Formulario]: Formulario.runValidation(): no forms with id "${id}"`)
} }
const form = this._registry.get(id) as InstanceType<FormularioFormConstructor> const form = this.registry.get(id) as FormularioForm
return form.runValidation() return form.runValidation()
} }
public resetValidation (id: string): void { public resetValidation (id: string): void {
if (!this._registry.has(id)) { if (!this.registry.has(id)) {
return return
} }
const form = this._registry.get(id) as InstanceType<FormularioFormConstructor> const form = this.registry.get(id) as FormularioForm
form.resetValidation() form.resetValidation()
} }
@ -64,12 +71,12 @@ export default class Formulario {
* Used by forms instances to add themselves into a registry * Used by forms instances to add themselves into a registry
* @internal * @internal
*/ */
public register (id: string, form: InstanceType<FormularioFormConstructor>): void { public register (id: string, form: FormularioForm): void {
if (this._registry.has(id)) { if (this.registry.has(id)) {
throw new Error(`[Formulario]: Formulario.register(): id "${id}" is already in use`) throw new Error(`[Formulario]: Formulario.register(): id "${id}" is already in use`)
} }
this._registry.set(id, form) this.registry.set(id, form)
} }
/** /**
@ -77,8 +84,8 @@ export default class Formulario {
* @internal * @internal
*/ */
public unregister (id: string): void { public unregister (id: string): void {
if (this._registry.has(id)) { if (this.registry.has(id)) {
this._registry.delete(id) this.registry.delete(id)
} }
} }
@ -87,7 +94,7 @@ export default class Formulario {
* @internal * @internal
*/ */
public getRules (extendWith: Record<string, ValidationRuleFn> = {}): Record<string, ValidationRuleFn> { public getRules (extendWith: Record<string, ValidationRuleFn> = {}): Record<string, ValidationRuleFn> {
return { ...this.validationRules, ...extendWith } return merge(this.validationRules, extendWith)
} }
/** /**
@ -95,14 +102,12 @@ export default class Formulario {
* @internal * @internal
*/ */
public getMessages (vm: Vue, extendWith: Record<string, ValidationMessageI18NFn|string>): Record<string, ValidationMessageFn> { public getMessages (vm: Vue, extendWith: Record<string, ValidationMessageI18NFn|string>): Record<string, ValidationMessageFn> {
const raw = { ...this.validationMessages, ...extendWith } const raw = merge(this.validationMessages || {}, extendWith)
const messages: Record<string, ValidationMessageFn> = {} const messages: Record<string, ValidationMessageFn> = {}
for (const name in raw) { for (const name in raw) {
messages[name] = (context: ValidationContext, ...args: unknown[]): string => { messages[name] = (context: ValidationContext, ...args: any[]): string => {
const fn = raw[name] return typeof raw[name] === 'string' ? raw[name] : raw[name](vm, context, ...args)
return typeof fn === 'string' ? fn : fn(vm, context, ...args)
} }
} }

View file

@ -8,21 +8,6 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import type {
Context,
Empty,
ModelGetConverter,
ModelSetConverter,
ValidationBehaviour,
UnregisterBehaviour,
} from '../types/field'
import type {
ValidationRuleFn,
ValidationMessageI18NFn,
Violation,
} from '../types/validation'
import Vue from 'vue' import Vue from 'vue'
import { import {
Component, Component,
@ -31,22 +16,39 @@ import {
Prop, Prop,
Watch, Watch,
} from 'vue-property-decorator' } from 'vue-property-decorator'
import { processConstraints, validate } from '@/validation/validator'
import { deepEquals, has, snakeToCamel } from './utils' import { deepEquals, has, snakeToCamel } from './utils'
import {
processConstraints,
validate,
ValidationRuleFn,
ValidationMessageI18NFn,
Violation,
} from '@/validation/validator'
import {
FormularioFieldContext,
FormularioFieldModelGetConverter as ModelGetConverter,
FormularioFieldModelSetConverter as ModelSetConverter,
Empty,
} from '@/types'
const VALIDATION_BEHAVIOR = {
DEMAND: 'demand',
LIVE: 'live',
SUBMIT: 'submit',
}
@Component({ name: 'FormularioField', inheritAttrs: false }) @Component({ name: 'FormularioField', inheritAttrs: false })
export default class FormularioField extends Vue { export default class FormularioField extends Vue {
@Inject({ default: '' }) __Formulario_path!: string @Inject({ default: '' }) __Formulario_path!: string
@Inject({ default: undefined }) __FormularioForm_set!: ((path: string, value: unknown) => void)|undefined @Inject({ default: undefined }) __FormularioForm_set!: Function|undefined
@Inject({ default: () => (): void => {} }) __FormularioForm_emitInput!: () => void @Inject({ default: () => (): void => {} }) __FormularioForm_emitInput!: Function
@Inject({ default: () => (): void => {} }) __FormularioForm_emitValidation!: (path: string, violations: Violation[]) => void @Inject({ default: () => (): void => {} }) __FormularioForm_emitValidation!: Function
@Inject({ default: undefined }) __FormularioForm_register!: ((path: string, field: FormularioField) => void)|undefined @Inject({ default: undefined }) __FormularioForm_register!: Function|undefined
@Inject({ default: undefined }) __FormularioForm_unregister!: ((path: string, behavior: UnregisterBehaviour) => void)|undefined @Inject({ default: undefined }) __FormularioForm_unregister!: Function|undefined
@Inject({ default: () => (): Record<string, unknown> => ({}) }) @Inject({ default: () => (): Record<string, unknown> => ({}) })
__FormularioForm_getState!: () => Record<string, unknown> __FormularioForm_getState!: () => Record<string, unknown>
@Model('input', { default: '' }) value!: unknown @Model('input', { default: '' }) value!: unknown
@ -59,9 +61,9 @@ export default class FormularioField extends Vue {
@Prop({ default: () => ({}) }) validationRules!: Record<string, ValidationRuleFn> @Prop({ default: () => ({}) }) validationRules!: Record<string, ValidationRuleFn>
@Prop({ default: () => ({}) }) validationMessages!: Record<string, ValidationMessageI18NFn|string> @Prop({ default: () => ({}) }) validationMessages!: Record<string, ValidationMessageI18NFn|string>
@Prop({ @Prop({
default: 'demand', default: VALIDATION_BEHAVIOR.DEMAND,
validator: (behavior: string) => ['demand', 'live', 'submit'].includes(behavior) validator: behavior => Object.values(VALIDATION_BEHAVIOR).includes(behavior)
}) validationBehavior!: ValidationBehaviour }) validationBehavior!: string
// Affects only setting of local errors // Affects only setting of local errors
@Prop({ default: false }) errorsDisabled!: boolean @Prop({ default: false }) errorsDisabled!: boolean
@ -70,7 +72,6 @@ export default class FormularioField extends Vue {
@Prop({ default: () => <T, U>(value: U|T): U|T => value }) modelSetConverter!: ModelSetConverter @Prop({ default: () => <T, U>(value: U|T): U|T => value }) modelSetConverter!: ModelSetConverter
@Prop({ default: 'div' }) tag!: string @Prop({ default: 'div' }) tag!: string
@Prop({ default: 'none' }) unregisterBehavior!: UnregisterBehaviour
public proxy: unknown = this.hasModel ? this.value : '' public proxy: unknown = this.hasModel ? this.value : ''
@ -84,12 +85,14 @@ export default class FormularioField extends Vue {
return this.__Formulario_path !== '' ? `${this.__Formulario_path}.${this.name}` : this.name return this.__Formulario_path !== '' ? `${this.__Formulario_path}.${this.name}` : this.name
} }
/** Determines if this formulario element is v-modeled or not. */ /**
* Determines if this formulario element is v-modeled or not.
*/
public get hasModel (): boolean { public get hasModel (): boolean {
return has(this.$options.propsData || {}, 'value') return has(this.$options.propsData || {}, 'value')
} }
private get context (): Context<unknown> { private get context (): FormularioFieldContext<unknown> {
return Object.defineProperty({ return Object.defineProperty({
name: this.fullPath, name: this.fullPath,
path: this.fullPath, path: this.fullPath,
@ -97,15 +100,15 @@ export default class FormularioField extends Vue {
violations: this.violations, violations: this.violations,
errors: this.localErrors, errors: this.localErrors,
allErrors: [...this.localErrors, ...this.violations.map(v => v.message)], allErrors: [...this.localErrors, ...this.violations.map(v => v.message)],
} as Context<unknown>, 'model', { }, 'model', {
get: () => this.modelGetConverter(this.proxy), get: () => this.modelGetConverter(this.proxy),
set: (value: unknown): void => { set: (value: unknown): void => {
this._syncProxy(this.modelSetConverter(value, this.proxy)) this.syncProxy(this.modelSetConverter(value, this.proxy))
}, },
}) })
} }
private get _normalizedValidationRules (): Record<string, ValidationRuleFn> { private get normalizedValidationRules (): Record<string, ValidationRuleFn> {
const rules: Record<string, ValidationRuleFn> = {} const rules: Record<string, ValidationRuleFn> = {}
Object.keys(this.validationRules).forEach(key => { Object.keys(this.validationRules).forEach(key => {
rules[snakeToCamel(key)] = this.validationRules[key] rules[snakeToCamel(key)] = this.validationRules[key]
@ -113,7 +116,7 @@ export default class FormularioField extends Vue {
return rules return rules
} }
private get _normalizedValidationMessages (): Record<string, ValidationMessageI18NFn|string> { private get normalizedValidationMessages (): Record<string, ValidationMessageI18NFn|string> {
const messages: Record<string, ValidationMessageI18NFn|string> = {} const messages: Record<string, ValidationMessageI18NFn|string> = {}
Object.keys(this.validationMessages).forEach(key => { Object.keys(this.validationMessages).forEach(key => {
messages[snakeToCamel(key)] = this.validationMessages[key] messages[snakeToCamel(key)] = this.validationMessages[key]
@ -122,70 +125,42 @@ export default class FormularioField extends Vue {
} }
@Watch('value') @Watch('value')
private _onValueChange (): void { private onValueChange (): void {
this._syncProxy(this.value) this.syncProxy(this.value)
} }
@Watch('proxy') @Watch('proxy')
private _onProxyChange (): void { private onProxyChange (): void {
if (this.validationBehavior === 'live') { if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) {
this.runValidation() this.runValidation()
} else { } else {
this.resetValidation() this.resetValidation()
} }
} }
/** @internal */ /**
* @internal
*/
public created (): void { public created (): void {
if (typeof this.__FormularioForm_register === 'function') { if (typeof this.__FormularioForm_register === 'function') {
this.__FormularioForm_register(this.fullPath, this) this.__FormularioForm_register(this.fullPath, this)
} }
if (this.validationBehavior === 'live') { if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) {
this.runValidation() this.runValidation()
} }
} }
/** @internal */ /**
* @internal
*/
public beforeDestroy (): void { public beforeDestroy (): void {
if (typeof this.__FormularioForm_unregister === 'function') { if (typeof this.__FormularioForm_unregister === 'function') {
this.__FormularioForm_unregister(this.fullPath, this.unregisterBehavior) this.__FormularioForm_unregister(this.fullPath)
} }
} }
public runValidation (): Promise<Violation[]> { private syncProxy (value: unknown): void {
this.validationRun = this._validate().then(violations => {
this.violations = violations
this._emitValidation(this.fullPath, violations)
return this.violations
})
return this.validationRun
}
public hasValidationErrors (): Promise<boolean> {
return new Promise(resolve => {
this.$nextTick(() => {
this.validationRun.then(() => resolve(this.violations.length > 0))
})
})
}
/** @internal */
public setErrors (errors: string[]): void {
if (!this.errorsDisabled) {
this.localErrors = errors
}
}
/** @internal */
public resetValidation (): void {
this.localErrors = []
this.violations = []
}
private _syncProxy (value: unknown): void {
if (!deepEquals(value, this.proxy)) { if (!deepEquals(value, this.proxy)) {
this.proxy = value this.proxy = value
this.$emit('input', value) this.$emit('input', value)
@ -197,11 +172,22 @@ export default class FormularioField extends Vue {
} }
} }
private _validate (): Promise<Violation[]> { public runValidation (): Promise<Violation[]> {
this.validationRun = this.validate().then(violations => {
this.violations = violations
this.emitValidation(this.fullPath, violations)
return this.violations
})
return this.validationRun
}
private validate (): Promise<Violation[]> {
return validate(processConstraints( return validate(processConstraints(
this.validation, this.validation,
this.$formulario.getRules(this._normalizedValidationRules), this.$formulario.getRules(this.normalizedValidationRules),
this.$formulario.getMessages(this, this._normalizedValidationMessages), this.$formulario.getMessages(this, this.normalizedValidationMessages),
), { ), {
value: this.proxy, value: this.proxy,
name: this.fullPath, name: this.fullPath,
@ -209,11 +195,36 @@ export default class FormularioField extends Vue {
}) })
} }
private _emitValidation (path: string, violations: Violation[]): void { private emitValidation (path: string, violations: Violation[]): void {
this.$emit('validation', { path, violations }) this.$emit('validation', { path, violations })
if (typeof this.__FormularioForm_emitValidation === 'function') { if (typeof this.__FormularioForm_emitValidation === 'function') {
this.__FormularioForm_emitValidation(path, violations) this.__FormularioForm_emitValidation(path, violations)
} }
} }
public hasValidationErrors (): Promise<boolean> {
return new Promise(resolve => {
this.$nextTick(() => {
this.validationRun.then(() => resolve(this.violations.length > 0))
})
})
}
/**
* @internal
*/
public setErrors (errors: string[]): void {
if (!this.errorsDisabled) {
this.localErrors = errors
}
}
/**
* @internal
*/
public resetValidation (): void {
this.localErrors = []
this.violations = []
}
} }
</script> </script>

View file

@ -5,11 +5,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import type { UnregisterBehaviour } from '../types/field'
import type { Violation } from '../types/validation'
import Vue from 'vue' import Vue from 'vue'
import { import {
Component, Component,
Model, Model,
@ -17,18 +13,19 @@ import {
Provide, Provide,
Watch, Watch,
} from 'vue-property-decorator' } from 'vue-property-decorator'
import { import {
id, id,
clone, clone,
deepEquals, deepEquals,
get, get,
has, has,
merge,
set, set,
unset, unset,
} from '@/utils' } from '@/utils'
import { FormularioField } from '@/types' import { FormularioField } from '@/types'
import { Violation } from '@/validation/validator'
const update = (state: Record<string, unknown>, path: string, value: unknown): Record<string, unknown> => { const update = (state: Record<string, unknown>, path: string, value: unknown): Record<string, unknown> => {
if (value === undefined) { if (value === undefined) {
@ -58,7 +55,7 @@ export default class FormularioForm extends Vue {
private localFormErrors: string[] = [] private localFormErrors: string[] = []
private get fieldsErrorsComputed (): Record<string, string[]> { private get fieldsErrorsComputed (): Record<string, string[]> {
return { ...this.fieldsErrors, ...this.localFieldsErrors } return merge(this.fieldsErrors || {}, this.localFieldsErrors)
} }
private get formErrorsComputed (): string[] { private get formErrorsComputed (): string[] {
@ -91,14 +88,11 @@ export default class FormularioForm extends Vue {
} }
@Provide('__FormularioForm_unregister') @Provide('__FormularioForm_unregister')
private unregister (path: string, behavior: UnregisterBehaviour): void { private unregister (path: string): void {
if (this.registry.has(path)) { if (this.registry.has(path)) {
this.registry.delete(path) this.registry.delete(path)
this.proxy = unset(this.proxy, path) as Record<string, unknown>
if (behavior === 'unset') { this.emitInput()
this.proxy = unset(this.proxy, path) as Record<string, unknown>
this.emitInput()
}
} }
} }
@ -184,17 +178,17 @@ export default class FormularioForm extends Vue {
}) })
} }
public setErrors ({ formErrors, fieldsErrors }: { public setErrors ({ fieldsErrors, formErrors }: {
formErrors?: string[];
fieldsErrors?: Record<string, string[]>; fieldsErrors?: Record<string, string[]>;
formErrors?: string[];
}): void { }): void {
this.localFormErrors = formErrors || []
this.localFieldsErrors = fieldsErrors || {} this.localFieldsErrors = fieldsErrors || {}
this.localFormErrors = formErrors || []
} }
public resetValidation (): void { public resetValidation (): void {
this.localFormErrors = []
this.localFieldsErrors = {} this.localFieldsErrors = {}
this.localFormErrors = []
this.registry.forEach((field: FormularioField) => { this.registry.forEach((field: FormularioField) => {
field.resetValidation() field.resetValidation()
}) })

View file

@ -1,26 +1,23 @@
import type { VueConstructor } from 'vue' import { VueConstructor } from 'vue'
import type { Options } from '../types/plugin'
import Formulario from '@/Formulario' import Formulario, { FormularioOptions } from '@/Formulario.ts'
import FormularioField from '@/FormularioField.vue' import FormularioField from '@/FormularioField.vue'
import FormularioFieldGroup from '@/FormularioFieldGroup.vue' import FormularioFieldGroup from '@/FormularioFieldGroup.vue'
import FormularioForm from '@/FormularioForm.vue' import FormularioForm from '@/FormularioForm.vue'
export {
Formulario,
FormularioField,
FormularioFieldGroup,
FormularioForm,
}
export default { export default {
Formulario, Formulario,
install (Vue: VueConstructor, options?: Options): void { install (Vue: VueConstructor, options?: FormularioOptions): void {
Vue.component('FormularioField', FormularioField) Vue.component('FormularioField', FormularioField)
Vue.component('FormularioFieldGroup', FormularioFieldGroup) Vue.component('FormularioFieldGroup', FormularioFieldGroup)
Vue.component('FormularioForm', FormularioForm) Vue.component('FormularioForm', FormularioForm)
// @deprecated Use FormularioField instead
Vue.component('FormularioInput', FormularioField)
// @deprecated Use FormularioFieldGroup instead
Vue.component('FormularioGrouping', FormularioFieldGroup)
Vue.mixin({ Vue.mixin({
beforeCreate () { beforeCreate () {
const o = this.$options as Record<string, any> const o = this.$options as Record<string, any>

9
src/shims-ext.d.ts vendored
View file

@ -3,7 +3,12 @@ import Formulario from '@/Formulario'
declare module 'vue/types/vue' { declare module 'vue/types/vue' {
interface Vue { interface Vue {
$formulario: Formulario; $formulario: Formulario;
$t: any; $route: VueRoute;
$tc: any; $t: Function;
$tc: Function;
}
interface VueRoute {
path: string;
} }
} }

View file

@ -1,6 +1,10 @@
import type { Violation } from '../types/validation'
import Vue from 'vue' import Vue from 'vue'
import { Violation } from '@/validation/validator'
export interface FormularioForm extends Vue {
runValidation(): Promise<Record<string, Violation[]>>;
resetValidation(): void;
}
export interface FormularioField extends Vue { export interface FormularioField extends Vue {
hasModel: boolean; hasModel: boolean;
@ -10,6 +14,25 @@ export interface FormularioField extends Vue {
resetValidation(): void; resetValidation(): void;
} }
export type FormularioFieldContext<T> = {
model: T;
name: string;
runValidation(): Promise<Violation[]>;
violations: Violation[];
errors: string[];
allErrors: string[];
}
export interface FormularioFieldModelGetConverter {
<U, T>(value: U|Empty): U|T|Empty;
}
export interface FormularioFieldModelSetConverter {
<T, U>(curr: U|T, prev: U|Empty): U|T;
}
export type Empty = undefined | null
export enum TYPE { export enum TYPE {
ARRAY = 'ARRAY', ARRAY = 'ARRAY',
BIGINT = 'BIGINT', BIGINT = 'BIGINT',
@ -72,7 +95,7 @@ export function typeOf (value: unknown): string {
return 'InstanceOf<' + (constructorOf(value) as { name?: string }).name + '>' return 'InstanceOf<' + (constructorOf(value) as { name?: string }).name + '>'
} }
throw new Error('[Formulario] typeOf - unknown type detected') throw new Error()
} }
export function isScalar (value: unknown): boolean { export function isScalar (value: unknown): boolean {

View file

@ -9,8 +9,7 @@ const cloneInstance = <T>(original: T): T => {
* case of needing to unbind reactive watchers. * case of needing to unbind reactive watchers.
*/ */
export default function clone<T = unknown> (value: T): T { export default function clone<T = unknown> (value: T): T {
// scalars & immutables if (isScalar(value)) {
if (isScalar(value) || value instanceof Blob) {
return value return value
} }

View file

@ -1,6 +1,7 @@
export { default as id } from './id' export { default as id } from './id'
export { default as clone } from './clone' export { default as clone } from './clone'
export { default as has } from './has' export { default as has } from './has'
export { default as merge } from './merge'
export { get, set, unset } from './access' export { get, set, unset } from './access'
export { default as regexForFormat } from './regexForFormat' export { default as regexForFormat } from './regexForFormat'
export { deepEquals, shallowEquals } from './compare' export { deepEquals, shallowEquals } from './compare'

40
src/utils/merge.ts Normal file
View file

@ -0,0 +1,40 @@
import isPlainObject from 'is-plain-object'
import has from '@/utils/has.ts'
/**
* Create a new object by copying properties of base and mergeWith.
* Note: arrays don't overwrite - they push
*
* @param {Object} a
* @param {Object} b
* @param {boolean} concatArrays
*/
export default function merge (
a: Record<string, any>,
b: Record<string, any>,
concatArrays = true
): Record<string, any> {
const merged: Record<string, any> = {}
for (const key in a) {
if (has(b, key)) {
if (isPlainObject(b[key]) && isPlainObject(a[key])) {
merged[key] = merge(a[key], b[key], concatArrays)
} else if (concatArrays && Array.isArray(a[key]) && Array.isArray(b[key])) {
merged[key] = a[key].concat(b[key])
} else {
merged[key] = b[key]
}
} else {
merged[key] = a[key]
}
}
for (const prop in b) {
if (!has(merged, prop)) {
merged[prop] = b[prop]
}
}
return merged
}

View file

@ -1,7 +1,7 @@
import type { import {
ValidationContext, ValidationContext,
ValidationMessageI18NFn, ValidationMessageI18NFn,
} from '../../types/validation' } from '@/validation/validator'
/** /**
* Message builders, names match rules names, see @/validation/rules * Message builders, names match rules names, see @/validation/rules

View file

@ -1,10 +1,9 @@
import type {
ValidationContext,
ValidationRuleFn,
} from '../../types/validation'
import isUrl from 'is-url' import isUrl from 'is-url'
import { has, regexForFormat, shallowEquals } from '@/utils' import { has, regexForFormat, shallowEquals } from '@/utils'
import {
ValidationContext,
ValidationRuleFn,
} from '@/validation/validator'
const rules: Record<string, ValidationRuleFn> = { const rules: Record<string, ValidationRuleFn> = {
/** /**
@ -166,7 +165,7 @@ const rules: Record<string, ValidationRuleFn> = {
} }
if (typeof value === 'string' || (force === 'length')) { if (typeof value === 'string' || (force === 'length')) {
value = !isNaN(value) ? String(value) : value value = !isNaN(value) ? value.toString() : value
return value.length <= maximum return value.length <= maximum
} }
@ -188,7 +187,7 @@ const rules: Record<string, ValidationRuleFn> = {
} }
if (typeof value === 'string' || (force === 'length')) { if (typeof value === 'string' || (force === 'length')) {
value = !isNaN(value) ? String(value) : value value = !isNaN(value) ? value.toString() : value
return value.length >= minimum return value.length >= minimum
} }

View file

@ -1,14 +1,42 @@
import type {
ValidationContext,
ValidationMessageFn,
ValidationRuleFn,
Validator,
ValidatorGroup,
Violation,
} from '../../types/validation'
import { has, snakeToCamel } from '@/utils' import { has, snakeToCamel } from '@/utils'
export interface Validator {
(context: ValidationContext): Promise<Violation|null>;
}
export interface Violation {
message: string;
rule: string|null;
args: any[];
context: ValidationContext|null;
}
export interface ValidationRuleFn {
(context: ValidationContext, ...args: any[]): Promise<boolean>|boolean;
}
export interface ValidationMessageFn {
(context: ValidationContext, ...args: any[]): string;
}
export interface ValidationMessageI18NFn {
(vm: Vue, context: ValidationContext, ...args: any[]): string;
}
export interface ValidationContext {
// The value of the field (do not mutate!),
value: any;
// If wrapped in a FormulateForm, the value of other form fields.
formValues: Record<string, any>;
// The validation name to be used
name: string;
}
export type ValidatorGroup = {
validators: Validator[];
bail: boolean;
}
export function createValidator ( export function createValidator (
ruleFn: ValidationRuleFn, ruleFn: ValidationRuleFn,
ruleName: string|null, ruleName: string|null,

View file

@ -286,37 +286,4 @@ describe('FormularioField', () => {
[{ date: new Date('2001-05-12') }], [{ date: new Date('2001-05-12') }],
]) ])
}) })
test('unregister behavior', async () => {
const wrapper = mount({
props: {
formExists: {
type: Boolean,
default: true,
}
},
data: () => ({ state: { fieldA: '', fieldB: '' } }),
watch: {
state () {
this.$emit('updated', this.state)
},
},
template: `
<div>
<FormularioForm v-if="formExists" v-model="state">
<FormularioField name="fieldA" />
<FormularioField name="fieldB" unregister-behavior="unset" />
</FormularioForm>
</div>
`,
})
await wrapper.vm.$nextTick()
wrapper.setProps({ formExists: false })
await wrapper.vm.$nextTick()
expect(wrapper.emitted('updated')).toEqual([[{ fieldA: '' }]])
})
}) })

View file

@ -4,6 +4,7 @@ import { mount } from '@vue/test-utils'
import flushPromises from 'flush-promises' import flushPromises from 'flush-promises'
import Formulario from '@/index.ts' import Formulario from '@/index.ts'
import FormularioFieldGroup from '@/FormularioFieldGroup.vue'
import FormularioForm from '@/FormularioForm.vue' import FormularioForm from '@/FormularioForm.vue'
Vue.use(Formulario) Vue.use(Formulario)

View file

@ -76,11 +76,4 @@ describe('clone', () => {
expect(copy.sample.doSomething).toBeTruthy() expect(copy.sample.doSomething).toBeTruthy()
expect(copy.sample.doSomething).not.toThrow() expect(copy.sample.doSomething).not.toThrow()
}) })
test('does not create a copy of a blob', () => {
const blob = new Blob(['{"fieldA": "fieldA"}'], { type : 'application/json' })
const copy = clone(blob)
expect(blob === copy).toBeTruthy()
})
}) })

View file

@ -0,0 +1,56 @@
import merge from '@/utils/merge.ts'
describe('merge', () => {
it('Can merge simple object', () => {
expect(merge({
optionA: true,
optionB: '1234',
}, {
optionA: false,
})).toEqual({
optionA: false,
optionB: '1234',
})
})
it('Can add to simple array', () => {
expect(merge({
optionA: true,
optionB: ['first', 'second']
}, {
optionB: ['third']
}, true)).toEqual({
optionA: true,
optionB: ['first', 'second', 'third']
})
})
it('Can merge recursively', () => {
expect(merge({
optionA: true,
optionC: {
first: '123',
third: {
a: 'b',
},
},
optionB: '1234',
}, {
optionB: '567',
optionC: {
first: '1234',
second: '789',
}
})).toEqual({
optionA: true,
optionC: {
first: '1234',
third: {
a: 'b',
},
second: '789',
},
optionB: '567',
})
})
})

34
types/field.d.ts vendored
View file

@ -1,34 +0,0 @@
import type { Violation } from './validation'
export type Empty = undefined | null
export type Context<T> = {
model: T;
name: string;
path: string;
violations: Violation[];
errors: string[];
allErrors: string[];
runValidation(): Promise<Violation[]>;
}
export interface ModelGetConverter {
<U, T>(value: U|Empty): U|T|Empty;
}
export interface ModelSetConverter {
<T, U>(curr: U|T, prev: U|Empty): U|T;
}
/**
* - 'demand': triggers validation on manual call
* - 'live': triggers validation on any changes
* - 'submit': triggers validation on form submit event
*/
export type ValidationBehaviour = 'demand' | 'live' | 'submit'
/**
* - 'none': no any specific effects
* - 'unset': the value under field's path will be unset and path will be removed from the state
*/
export type UnregisterBehaviour = 'none' | 'unset'

17
types/form.d.ts vendored
View file

@ -1,17 +0,0 @@
import type { DefineComponent } from './vue'
import type { Violation } from './validation'
export type FormularioFormConstructor = DefineComponent<{
id?: string;
state?: Record<string, unknown>;
fieldsErrors?: Record<string, string[]>;
formErrors?: string[];
}, {
setErrors ({ formErrors, fieldsErrors }: {
formErrors?: string[];
fieldsErrors?: Record<string, string[]>;
}): void;
runValidation(): Promise<Record<string, Violation[]>>;
hasValidationErrors (): Promise<boolean>;
resetValidation(): void;
}>

9
types/plugin.d.ts vendored
View file

@ -1,9 +0,0 @@
import type {
ValidationMessageI18NFn,
ValidationRuleFn
} from './validation'
export interface Options {
validationRules?: Record<string, ValidationRuleFn>;
validationMessages?: Record<string, ValidationMessageI18NFn|string>;
}

38
types/validation.d.ts vendored
View file

@ -1,38 +0,0 @@
import { Vue } from 'vue/types/vue'
export interface ValidationContext {
// The value of the field (do not mutate!),
value: any;
// If wrapped in a FormulateForm, the value of other form fields.
formValues: Record<string, any>;
// The validation name to be used
name: string;
}
export interface Violation {
message: string;
rule: string|null;
args: any[];
context: ValidationContext|null;
}
export interface Validator {
(context: ValidationContext): Promise<Violation|null>;
}
export type ValidatorGroup = {
validators: Validator[];
bail: boolean;
}
export interface ValidationRuleFn {
(context: ValidationContext, ...args: any[]): Promise<boolean>|boolean;
}
export interface ValidationMessageFn {
(context: ValidationContext, ...args: any[]): string;
}
export interface ValidationMessageI18NFn {
(vm: Vue, context: ValidationContext, ...args: any[]): string;
}

3
types/vue.d.ts vendored
View file

@ -1,3 +0,0 @@
import type { Vue, VueConstructor } from 'vue/types/vue'
export type DefineComponent<Props, Methods> = VueConstructor<Vue & Required<Props> & Methods>

View file

@ -1,207 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
"framework": "vue",
"name": "@omnica/accordion-vue2",
"version": "0.24.22",
"js-types-syntax": "typescript",
"description-markup": "markdown",
"contributions": {
"html": {
"vue-components": [
{
"name": "FormularioForm",
"description": "Form root",
"source": {
"module": "@retailcrm/vue-formulario",
"symbol": "FormularioForm"
},
"props": [
{
"name": "state",
"type": "object",
"default": "{}",
"description": ""
},
{
"name": "id",
"type": "string",
"default": "id('formulario-form')",
"description": ""
},
{
"name": "fieldsErrors",
"type": "object",
"default": "{}",
"description": "Describes validation errors of concrete fields"
},
{
"name": "formErrors",
"type": "array",
"default": "[]",
"description": "Describes validation errors of entire state"
}
],
"events": [
{
"name": "input",
"description": "Occurs on state change",
"arguments": [
{
"name": "...",
"type": {
"name": "any"
}
}
]
},
{
"name": "validation",
"description": "Occurs at the end of a validation run",
"arguments": [
{
"name": "...",
"type": {
"name": "any"
}
}
]
}
],
"slots": [
{
"name": "default",
"description": "Form content",
"scoped": true
}
]
},
{
"name": "FormularioField",
"description": "Form field",
"source": {
"module": "@retailcrm/vue-formulario",
"symbol": "FormularioField"
},
"props": [
{
"name": "value",
"type": "any",
"description": "The field's value, if not set explicitly, will be extracted from the state using 'path'"
},
{
"name": "name",
"type": "string",
"description": "Path to field's value in the state",
"required": true
},
{
"name": "validation",
"type": "string|array",
"description": ""
},
{
"name": "validationRules",
"type": "object",
"description": "Validation rules override/extension opportunity",
"default": "{}"
},
{
"name": "validationMessages",
"type": "object",
"description": "Validation messages override/extension opportunity",
"default": "{}"
},
{
"name": "validationBehavior",
"type": "string",
"description": "",
"default": "'demand'"
},
{
"name": "errorsDisabled",
"type": "boolean",
"description": "Disables passing errors to the field from FormularioForm's fieldsErrors",
"default": "false"
},
{
"name": "modelGetConverter",
"type": "function",
"description": "Simple middleware that provides opportunity to transform value before passing it to a template"
},
{
"name": "modelSetConverter",
"type": "function",
"description": "Simple middleware that provides opportunity to transform new value before assigning"
},
{
"name": "tag",
"type": "string",
"description": "Root element's tagName in lowercase"
},
{
"name": "unregisterBehavior",
"type": "string",
"description": "Possible values: 'none', 'unset'",
"default": "'none'"
}
],
"events": [
{
"name": "input",
"description": "Occurs on value change",
"arguments": [
{
"name": "...",
"type": {
"name": "any"
}
}
]
},
{
"name": "validation",
"description": "Occurs at the end of a validation run",
"arguments": [
{
"name": "...",
"type": {
"name": "any"
}
}
]
}
],
"slots": [
{
"name": "default",
"description": "Field content",
"scoped": true
}
]
},
{
"name": "FormularioFieldGroup",
"description": "Field group",
"source": {
"module": "@retailcrm/vue-formulario",
"symbol": "FormularioFieldGroup"
},
"props": [
{
"name": "name",
"type": "string",
"description": "Path to a nested state",
"required": true
}
],
"slots": [
{
"name": "default",
"description": "Group content"
}
]
}
]
}
}
}

2856
yarn.lock

File diff suppressed because it is too large Load diff