@extclp/vexip-ui
Version:
A Vue 3 UI library, Highly customizability, full TypeScript, performance pretty good
1 lines • 8.53 kB
Source Map (JSON)
{"version":3,"file":"helper.mjs","sources":["../../../components/form/helper.ts"],"sourcesContent":["import { computed, getCurrentInstance, inject, onBeforeUnmount, provide } from 'vue'\r\n\r\nimport { isNull, noop, toFalse } from '@vexip-ui/utils'\r\nimport { FIELD_OPTIONS } from './symbol'\r\n\r\nimport type { Ref } from 'vue'\r\nimport type { ComponentSize, ComponentState } from '@vexip-ui/config'\r\n\r\n/**\r\n * 根据路径读取对象中的值 (实现 ?. 的逻辑)\r\n *\r\n * @param obj 需要被读取的对象\r\n * @param path 读取的路径\r\n * @param strict 是否开启严格模式 (非法路径报错)\r\n */\r\nexport function getValueByPath<T = unknown>(\r\n obj: Record<string, any>,\r\n path: string | string[],\r\n strict = false,\r\n): T | null {\r\n if (!obj || !path) return null\r\n\r\n if (typeof path === 'string') {\r\n if (path in obj) return obj[path]\r\n\r\n path = path.split('.')\r\n }\r\n\r\n if (Array.isArray(path) && path.length) {\r\n const lastKey = path.pop()\r\n\r\n if (!lastKey) return null\r\n\r\n for (let i = 0, len = path.length; i < len; ++i) {\r\n const key = String(path[i])\r\n\r\n if (!key) break\r\n\r\n obj = obj[key]\r\n\r\n if (isNull(obj)) {\r\n if (strict) {\r\n throw new Error('[vexip-ui:Form] Get value by an invalid path')\r\n }\r\n\r\n return obj\r\n }\r\n }\r\n\r\n if (strict && isNull(obj[lastKey])) {\r\n throw new Error('[vexip-ui:Form] Get value by an invalid path')\r\n }\r\n\r\n return obj[lastKey]\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * 根据路径设置对象中的值\r\n *\r\n * @param obj 需要被设置的对象\r\n * @param path 设置的路径\r\n * @param value 需要设置的值\r\n * @param strict 是否开启严格模式 (非法路径报错)\r\n */\r\nexport function setValueByPath(\r\n obj: Record<string, any>,\r\n path: string | string[],\r\n value: unknown,\r\n strict = false,\r\n): boolean {\r\n if (!obj || !path) return false\r\n\r\n if (typeof path === 'string') {\r\n if (path in obj) {\r\n obj[path] = value\r\n\r\n return true\r\n }\r\n\r\n path = path.split('.')\r\n }\r\n\r\n if (Array.isArray(path) && path.length) {\r\n const lastKey = path.pop()\r\n\r\n if (!lastKey) return false\r\n\r\n for (let i = 0, len = path.length; i < len; ++i) {\r\n const key = String(path[i])\r\n\r\n if (!key) {\r\n return false\r\n }\r\n\r\n if (typeof obj[key] !== 'object') {\r\n if (strict) {\r\n throw new Error('[vexip-ui:Form] Set value by an invalid path')\r\n }\r\n\r\n obj[key] = {}\r\n }\r\n\r\n obj = obj[key]\r\n }\r\n\r\n if (strict && typeof obj !== 'object') {\r\n throw new Error('[vexip-ui:Form] Set value by an invalid path')\r\n }\r\n\r\n obj[lastKey] = value\r\n\r\n return true\r\n }\r\n\r\n return false\r\n}\r\n\r\nexport interface FormFieldStore<V = unknown> {\r\n isField: boolean,\r\n idFor: Ref<string | undefined>,\r\n labelId: Ref<string | undefined>,\r\n state: Ref<ComponentState>,\r\n disabled: Ref<boolean>,\r\n loading: Ref<boolean>,\r\n size: Ref<ComponentSize>,\r\n validateField: () => Promise<string[] | null>,\r\n clearField: (defaultValue?: V) => void,\r\n resetField: () => boolean,\r\n getFieldValue: (defaultValue?: V) => V,\r\n setFieldValue: (value: V, strict?: boolean) => void,\r\n}\r\n\r\nconst defaultId = computed(() => undefined as string | undefined)\r\nconst defaultState = computed(() => 'default' as ComponentState)\r\nconst defaultFalse = computed(() => false)\r\nconst defaultSize = computed(() => 'default' as ComponentSize)\r\n\r\nfunction getEmptyActions<V>() {\r\n return {\r\n isField: false,\r\n idFor: defaultId,\r\n labelId: defaultId,\r\n state: defaultState,\r\n disabled: defaultFalse,\r\n loading: defaultFalse,\r\n size: defaultSize,\r\n validateField: noop,\r\n clearField: noop,\r\n resetField: toFalse,\r\n getFieldValue: v => v,\r\n setFieldValue: noop,\r\n } as FormFieldStore<V>\r\n}\r\n\r\n/**\r\n * Create a field store, provide field states and control methods\r\n *\r\n * @param onFocus a focus method for focusing when label is clicked\r\n */\r\nexport function useFieldStore<V = unknown>(onFocus?: () => void): FormFieldStore<V> {\r\n const instance = getCurrentInstance()\r\n\r\n if (!instance) return getEmptyActions<V>()\r\n\r\n const fieldOptions = inject(FIELD_OPTIONS, null)\r\n\r\n if (!fieldOptions) {\r\n return getEmptyActions<V>()\r\n }\r\n\r\n // Block the provided if there are dependencies between control components.\r\n // e.g. AutoComplete -> Select, ColorPicker -> Input\r\n provide(FIELD_OPTIONS, null)\r\n fieldOptions.sync(instance)\r\n onFocus && fieldOptions.emitter.on('focus', onFocus)\r\n\r\n onBeforeUnmount(() => {\r\n fieldOptions.unSync(instance)\r\n onFocus && fieldOptions.emitter.off('focus', onFocus)\r\n })\r\n\r\n function clearField(defaultValue?: V) {\r\n if (!fieldOptions) return\r\n\r\n fieldOptions.setValue(defaultValue)\r\n fieldOptions.clearError()\r\n }\r\n\r\n return {\r\n isField: true,\r\n idFor: fieldOptions.idFor,\r\n labelId: fieldOptions.labelId,\r\n state: fieldOptions.state,\r\n disabled: fieldOptions.disabled,\r\n loading: fieldOptions.loading,\r\n size: fieldOptions.size,\r\n validateField: fieldOptions.validate,\r\n clearField,\r\n resetField: fieldOptions.reset,\r\n getFieldValue: fieldOptions.getValue as (defaultValue?: V) => V,\r\n setFieldValue: fieldOptions.setValue as (value: V, strict?: boolean) => void,\r\n }\r\n}\r\n"],"names":["getValueByPath","obj","path","strict","lastKey","i","len","key","isNull","setValueByPath","value","defaultId","computed","defaultState","defaultFalse","defaultSize","getEmptyActions","noop","toFalse","v","useFieldStore","onFocus","instance","getCurrentInstance","fieldOptions","inject","FIELD_OPTIONS","provide","onBeforeUnmount","clearField","defaultValue"],"mappings":"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"}