vue-formless 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +130 -0
- package/README.md +136 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +278 -422
- package/dist/index.js +618 -834
- package/docs/mixed-layout-code.png +0 -0
- package/docs/mixed-layout-preview.png +0 -0
- package/package.json +6 -19
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Xu Yiming
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# vue-formless
|
|
2
|
+
|
|
3
|
+
English | [简体中文](./README.md)
|
|
4
|
+
|
|
5
|
+
> Vue 3 form library: a page-level control table plus FormView, with layout kept off the inputs. **0.2.0** — APIs may still change in 0.x.
|
|
6
|
+
|
|
7
|
+
Same mixed layout: Element Row/Col/Item on the left, `<User.*>` plus nested `FormView` density on the right.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
Playground side by side (layout match):
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add vue-formless
|
|
17
|
+
# or npm i vue-formless
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Peer: `vue` ^3.3.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
Bind host Form / Item / Row / Col once in the project (no official Element adapter):
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { ElCol, ElForm, ElFormItem, ElInput, ElRow } from 'element-plus'
|
|
28
|
+
import { defineComponent, h, ref, type PropType } from 'vue'
|
|
29
|
+
import { createFormFields, createFormView, type FormFieldFormless } from 'vue-formless'
|
|
30
|
+
|
|
31
|
+
declare module 'vue-formless' {
|
|
32
|
+
interface FormFieldCustomOptions {
|
|
33
|
+
label?: string
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ElFormItem `prop` speaks dot paths; the kernel location (`buyers[0].name`)
|
|
38
|
+
// is encoded here, in the adapter (design.md §20.9). One host `prop` cannot hold
|
|
39
|
+
// several ports, so such a field stays unbound (`undefined`) — use
|
|
40
|
+
// `fl:field="wrap-embed"` (one port per field) when the host must validate it.
|
|
41
|
+
function toItemProp(prop: FormFieldFormless['prop']): string | undefined {
|
|
42
|
+
if (prop == null || prop.length !== 1) return undefined
|
|
43
|
+
const [location] = prop
|
|
44
|
+
if (location == null) return undefined
|
|
45
|
+
const dotted = location.replace(/\[(\d+)\]/g, '.$1').replace(/^\./, '')
|
|
46
|
+
if (!dotted || /[[\]]/.test(dotted)) return undefined // unencodable: leave unbound
|
|
47
|
+
return dotted
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// The no-prefix write model `modelValue` falls through to the host Form, but
|
|
51
|
+
// ElForm names its model port `model`: the adapter wraps it in a MyForm that
|
|
52
|
+
// maps the port and forwards ElForm's exposed instance methods (validate /
|
|
53
|
+
// resetFields) up to FormView's ref proxy. The factory no longer takes a
|
|
54
|
+
// functional `form.props`.
|
|
55
|
+
const MyForm = defineComponent({
|
|
56
|
+
inheritAttrs: false,
|
|
57
|
+
props: { modelValue: { type: [Object, Array] as PropType<unknown>, default: undefined } },
|
|
58
|
+
setup(props, { attrs, slots, expose }) {
|
|
59
|
+
const form = ref<Record<string, unknown> | null>(null)
|
|
60
|
+
expose(new Proxy({}, {
|
|
61
|
+
get: (_, key) => {
|
|
62
|
+
const inner = form.value
|
|
63
|
+
if (inner == null) return undefined
|
|
64
|
+
const value = Reflect.get(inner, key, inner)
|
|
65
|
+
return typeof value === 'function' ? value.bind(inner) : value
|
|
66
|
+
},
|
|
67
|
+
has: (_, key) => form.value != null && key in form.value,
|
|
68
|
+
}))
|
|
69
|
+
return () => h(ElForm, { ...attrs, ref: form, model: props.modelValue }, slots)
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
export const FormView = createFormView({
|
|
74
|
+
layout: { Row: ElRow, Col: ElCol, props: { column: 2 } },
|
|
75
|
+
form: { component: MyForm },
|
|
76
|
+
item: {
|
|
77
|
+
component: ElFormItem,
|
|
78
|
+
props: (fl: FormFieldFormless) => ({
|
|
79
|
+
label: fl.label,
|
|
80
|
+
prop: toItemProp(fl.prop),
|
|
81
|
+
}),
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
export const User = createFormFields({
|
|
86
|
+
name: { label: 'Name', component: ElInput },
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```vue
|
|
91
|
+
<FormView ref="formRef" v-model="form" fl:layout label-width="96px">
|
|
92
|
+
<User.Name />
|
|
93
|
+
<User.Name layout-item:span="max" />
|
|
94
|
+
</FormView>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`validate()` / `resetFields()` go through the FormView ref (proxied host Form). Layout details: [docs/adr](./docs/adr.md).
|
|
98
|
+
|
|
99
|
+
## Live playgrounds
|
|
100
|
+
|
|
101
|
+
GitHub Pages (set **Settings → Pages → Source** to GitHub Actions; deploys from `main`):
|
|
102
|
+
|
|
103
|
+
- Forms: [https://xuyimingwork.github.io/vue-formx/](https://xuyimingwork.github.io/vue-formx/)
|
|
104
|
+
- 24-col layout: [https://xuyimingwork.github.io/vue-formx/layout/](https://xuyimingwork.github.io/vue-formx/layout/)
|
|
105
|
+
|
|
106
|
+
Local preview of the Pages bundle: `PAGES_BASE=/vue-formx/ pnpm build:pages`, then serve `site/`.
|
|
107
|
+
|
|
108
|
+
## Layout
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
packages/vue-formless # kernel (npm: vue-formless)
|
|
112
|
+
packages/layout # internal grid, bundled into the kernel
|
|
113
|
+
playground # Element Plus baseline vs Formless
|
|
114
|
+
playground-layout # 24-col layout studio
|
|
115
|
+
docs/adr.md # architecture decisions (single doc)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pnpm i
|
|
122
|
+
pnpm dev # playground
|
|
123
|
+
pnpm build # library
|
|
124
|
+
pnpm test
|
|
125
|
+
pnpm typecheck
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
[MIT](./LICENSE)
|
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# vue-formless
|
|
2
|
+
|
|
3
|
+
简体中文 | [English](./README.en.md)
|
|
4
|
+
|
|
5
|
+
> Vue 3 表单组合式库:控件表 + FormView,布局与输入拆开。当前 **0.2.0**,`0.x` 期间 API 仍可能调整。
|
|
6
|
+
|
|
7
|
+
同一套混合布局:左边手写 Element Row/Col/Item,右边 `<User.*>` + 嵌套 `FormView` 换密度。
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
Playground 平铺对比(布局对齐):
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add vue-formless
|
|
17
|
+
# 或 npm i vue-formless
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
peer:`vue` ^3.3。
|
|
21
|
+
|
|
22
|
+
## 用法
|
|
23
|
+
|
|
24
|
+
项目里绑一次宿主(无官方 Element 适配包):
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { ElCol, ElForm, ElFormItem, ElInput, ElRow } from 'element-plus'
|
|
28
|
+
import { defineComponent, h, ref, type PropType } from 'vue'
|
|
29
|
+
import { createFormFields, createFormView, type FormFieldFormless } from 'vue-formless'
|
|
30
|
+
|
|
31
|
+
declare module 'vue-formless' {
|
|
32
|
+
interface FormFieldCustomOptions {
|
|
33
|
+
label?: string
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ElFormItem 的 `prop` 用点分路径;内核位置(`buyers[0].name`)由本层编码(design.md §20.9)。
|
|
38
|
+
// 一个宿主 `prop` 装不下多个口 → 多口一格不绑宿主(`undefined`),
|
|
39
|
+
// 需要宿主校验就用 `fl:field="wrap-embed"` 拆成一格一口。
|
|
40
|
+
function toItemProp(prop: FormFieldFormless['prop']): string | undefined {
|
|
41
|
+
if (prop == null || prop.length !== 1) return undefined
|
|
42
|
+
const [location] = prop
|
|
43
|
+
if (location == null) return undefined
|
|
44
|
+
const dotted = location.replace(/\[(\d+)\]/g, '.$1').replace(/^\./, '')
|
|
45
|
+
if (!dotted || /[[\]]/.test(dotted)) return undefined // 编不出来:不绑宿主
|
|
46
|
+
return dotted
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 无前缀的写口 `modelValue` 按 no-prefix 规则透传到宿主 Form,而 ElForm 的 model
|
|
50
|
+
// 口叫 `model`:适配层用一个 MyForm 包住 ElForm 完成映射,并把 ElForm 实例的
|
|
51
|
+
// validate / resetFields 透出给 FormView 的 ref 代理。工厂不再接受 form.props 函数。
|
|
52
|
+
const MyForm = defineComponent({
|
|
53
|
+
inheritAttrs: false,
|
|
54
|
+
props: { modelValue: { type: [Object, Array] as PropType<unknown>, default: undefined } },
|
|
55
|
+
setup(props, { attrs, slots, expose }) {
|
|
56
|
+
const form = ref<Record<string, unknown> | null>(null)
|
|
57
|
+
expose(new Proxy({}, {
|
|
58
|
+
get: (_, key) => {
|
|
59
|
+
const inner = form.value
|
|
60
|
+
if (inner == null) return undefined
|
|
61
|
+
const value = Reflect.get(inner, key, inner)
|
|
62
|
+
return typeof value === 'function' ? value.bind(inner) : value
|
|
63
|
+
},
|
|
64
|
+
has: (_, key) => form.value != null && key in form.value,
|
|
65
|
+
}))
|
|
66
|
+
return () => h(ElForm, { ...attrs, ref: form, model: props.modelValue }, slots)
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
export const FormView = createFormView({
|
|
71
|
+
layout: { Row: ElRow, Col: ElCol, props: { column: 2 } },
|
|
72
|
+
form: { component: MyForm },
|
|
73
|
+
item: {
|
|
74
|
+
component: ElFormItem,
|
|
75
|
+
props: (fl: FormFieldFormless) => ({
|
|
76
|
+
label: fl.label,
|
|
77
|
+
prop: toItemProp(fl.prop),
|
|
78
|
+
}),
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
export const User = createFormFields({
|
|
83
|
+
name: { label: '姓名', component: ElInput },
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```vue
|
|
88
|
+
<FormView ref="formRef" v-model="form" fl:layout label-width="96px">
|
|
89
|
+
<User.Name />
|
|
90
|
+
<User.Name layout-item:span="max" />
|
|
91
|
+
</FormView>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`validate()` / `resetFields()` 走 FormView 的 ref(代理内层 Form)。栅格细节见 [docs/adr](./docs/adr.md)。
|
|
95
|
+
|
|
96
|
+
## 在线 Playground
|
|
97
|
+
|
|
98
|
+
GitHub Pages(仓库需在 **Settings → Pages → Source** 选 GitHub Actions,推 `main` 后生成):
|
|
99
|
+
|
|
100
|
+
- 表单对照:[https://xuyimingwork.github.io/vue-formx/](https://xuyimingwork.github.io/vue-formx/)
|
|
101
|
+
- 24 格布局:[https://xuyimingwork.github.io/vue-formx/layout/](https://xuyimingwork.github.io/vue-formx/layout/)
|
|
102
|
+
|
|
103
|
+
本地预览打包结果:`PAGES_BASE=/vue-formx/ pnpm build:pages`,再用任意静态服务器打开 `site/`。
|
|
104
|
+
|
|
105
|
+
## 仓库结构
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
packages/vue-formless # 内核(npm:vue-formless)
|
|
109
|
+
packages/layout # 内部栅格,打进内核 dist
|
|
110
|
+
playground # Element Plus 基线 vs Formless
|
|
111
|
+
playground-layout # 24 格布局工作台
|
|
112
|
+
docs/adr.md # 架构决策(单篇汇总)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 开发
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
pnpm i
|
|
119
|
+
pnpm dev # 启动 playground
|
|
120
|
+
pnpm build # 构建库
|
|
121
|
+
pnpm test
|
|
122
|
+
pnpm typecheck
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Playground 对照:基础表单、筛选条、只读详情、混合布局、DateRange。
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pnpm playground
|
|
129
|
+
# http://localhost:5173
|
|
130
|
+
pnpm playground:layout
|
|
131
|
+
# http://localhost:5174
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
[MIT](./LICENSE)
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("vue"),N=Symbol("vue-formless.formContext");function Y(){const e=l.inject(N,null);if(!e)throw new Error("[vue-formless] useFormContext() must be used inside <FormView>.");return e}function D(e){if(!e)return[];const t=[];let o=0;for(;o<e.length;){if(e[o]==="."){o++;continue}if(e[o]==="["){const n=e.indexOf("]",o+1);if(n===-1)throw new Error(`Invalid path "${e}": unclosed bracket`);const r=e.slice(o+1,n),s=Number(r);if(!Number.isInteger(s)||String(s)!==r||s<0)throw new Error(`Invalid path "${e}": index must be a non-negative integer`);t.push({type:"index",index:s}),o=n+1}else{const n=/^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(e.slice(o));if(!n)throw new Error(`Invalid path "${e}" at position ${o}`);t.push({type:"key",key:n[0]}),o+=n[0].length}}return t}function Ne(e,t){let o=e;for(const n of t)n.type==="key"?o=o[n.key]:o=o[n.index];return o}function _e(e,t){if(t.type==="key")return e==null||typeof e!="object"||Array.isArray(e)?void 0:e[t.key];if(Array.isArray(e))return e[t.index]}function k(e,t){const o=D(t);if(o.length===0)return;const n=o[o.length-1],r=Ne(e,o.slice(0,-1));return _e(r,n)}function J(e,t,o,n){const r=t[o],s=o===t.length-1;if(r.type==="key"){if(Array.isArray(e))throw new Error(`Cannot set "${r.key}" on an array node`);const i=e!=null&&typeof e=="object"?e:{};return s?{...i,[r.key]:n}:{...i,[r.key]:J(i[r.key],t,o+1,n)}}const u=Array.isArray(e)?[...e]:[];return s?(u[r.index]=n,u):(u[r.index]=J(u[r.index],t,o+1,n),u)}function we(e,t,o){const n=D(t);if(n.length===0)throw new Error("Cannot set an empty prop");return J(e,n,0,o)}function ye(e){return D(e).map(t=>t.type==="key"?t.key:String(t.index)).join(".")}function Me(e,t){let o=null;function n(r,s){o||(o=[],l.nextTick(()=>{if(!o?.length){o=null;return}let u=e();for(const i of o)u=we(u,i.prop,i.value);o=null,t(u)})),o.push({prop:r,value:s})}return{update:n}}const p=24,V={column:1};function Te(e){const t=Math.floor(Number(e));return t===1/0?p:Number.isFinite(t)?Math.min(p,Math.max(1,t)):V.column}function Be(...e){return Te(e.find(t=>t!=null)??V.column)}function Ue(e,t){const o=t>0?t:V.column,n=Math.max(1,Math.floor(p/o));if(e==null||e==="")return n;if(typeof e=="number")return ce(e),e;const r=e.trim();if(r==="max")return p;const s=/^(\d+)x$/.exec(r);if(s){const u=Number(s[1]);if(u<1)throw new Error(`[vue-formless] col:span "${e}" is invalid`);return Math.min(p,u*n)}if(/^\d+$/.test(r)){const u=Number(r);return ce(u),u}throw new Error(`[vue-formless] col:span "${e}" is invalid`)}function ce(e){if(!Number.isInteger(e)||e<1||e>p)throw new Error(`[vue-formless] col:span ${e} must be an integer 1–${p}`)}function We(e){if(e==null||e===""||e==="auto")return"auto";if(e==="start"||e==="end")return e;throw new Error(`[vue-formless] col:place "${String(e)}" is invalid`)}const W=Symbol("vue-formless:layout-view");function Ge(e,t,o={childList:!0}){if(typeof MutationObserver>"u")return;let n=null;function r(u){n?.disconnect(),n=null,u&&(n=new MutationObserver(t),n.observe(u,o))}l.onMounted(()=>r(l.toValue(e)));const s=l.watch(()=>l.toValue(e),r,{flush:"post"});l.onBeforeUnmount(()=>{s(),n?.disconnect(),n=null})}function Ye(e,t=0){const o=l.ref([]);function n(){const r=l.toValue(e);o.value=r?Array.from(r.children):[]}return l.watch(()=>[l.toValue(e),l.toValue(t)],n,{immediate:!0}),Ge(e,n),o}function De(e,t,o){const n=[];if(o==="auto")return e.n+t>p&&(e.n=0),n;if(o==="start")return e.n>0&&(n.push(p-e.n),e.n=0),n;e.n+t>p&&e.n>0&&(n.push(p-e.n),e.n=0);const r=p-e.n-t;return r>0&&(n.push(r),e.n+=r),n}function ze(e){return l.computed(()=>{const t={n:0},o=new Map;for(const n of l.toValue(e)){const r=De(t,n.span,n.place);o.set(n.id,r),t.n+=n.span}return o})}function ge(e){if(e==null||typeof e!="object")return null;if(typeof Element<"u"&&e instanceof Element)return e;const t=e;return U(t.vnode?.el)??U(t.subTree?.el)??U(t.subTree?.component?.vnode?.el)??U(t.$el)}function U(e){if(typeof Element<"u"&&e instanceof Element)return e;if(e&&e.nodeType===8){for(let t=e.nextSibling;t;t=t.nextSibling)if(typeof Element<"u"&&t instanceof Element)return t}return null}const Ke=l.defineComponent({name:"LayoutBlanks",inheritAttrs:!1,props:{is:{type:Object,default:void 0},spans:{type:Array,required:!0}},setup(e){return()=>{if(e.spans.length===0||e.is==null)return null;const t=e.is;return l.createVNode(l.Fragment,null,[e.spans.map((o,n)=>l.createVNode(t,{key:n,span:o},null))])}}}),qe=l.defineComponent({name:"LayoutItem",inheritAttrs:!1,props:{span:{type:[String,Number],default:void 0},place:{type:String,default:void 0}},setup(e,{slots:t}){const o=l.inject(W,null);if(!o)return()=>t.default?.()??null;const{span:n,blanks:r,itemRef:s,Col:u,disabled:i}=o(()=>e.span,()=>e.place);return()=>{if(i.value)return t.default?.()??null;const f=u;return l.createVNode(l.Fragment,null,[l.createVNode(Ke,{is:u,spans:r.value},null),l.createVNode(f,{ref:s,span:n.value},{default:()=>[t.default?.()??null]})])}}}),He=l.defineComponent({name:"LayoutItemPassThrough",inheritAttrs:!1,setup(e,{slots:t}){return()=>t.default?.()??null}});function he(){return l.inject(W,null)?qe:He}function Xe(e){const t=l.ref({});let o=0;return{get value(){return t.value},setup(n,r){const s=String(++o),u=l.computed(()=>Ue(l.toValue(n),l.toValue(e))),i=l.computed(()=>We(l.toValue(r)));return t.value[s]={span:u,place:i,el:null,mounted:!1},l.onMounted(()=>{const f=t.value[s];f&&(f.mounted=!0)}),l.onBeforeUnmount(()=>{delete t.value[s]}),s},span(n){return t.value[n]?.span??0},ref(n,r){const s=t.value[n];if(!s)return;const u=ge(r);s.el!==u&&(s.el=u)}}}function Ze(e,t){const o=new Map(Object.entries(e).filter(([,n])=>n.el).map(([n,r])=>[r.el,{id:n,span:r.span,place:r.place}]));return t.filter(n=>o.has(n)).map(n=>o.get(n))}function Je(e,t){const o=Ye(()=>ge(t.value),()=>Object.keys(e.value).filter(n=>e.value[n].mounted).join(","));return ze(()=>Ze(e.value,o.value))}function ne(e={}){const{Row:t,Col:o}=e;return l.defineComponent({name:"LayoutView",inheritAttrs:!1,props:{disabled:{type:Boolean,default:!1},column:{type:Number,default:void 0}},setup(n,{slots:r,attrs:s}){const u=l.computed(()=>!t||!o||n.disabled),i=Xe(()=>Be(n.column,e.column)),f=l.ref(null),a=Je(i,f);return l.provide(W,(m,g)=>{l.provide(W,null);const w=i.setup(m,g);return{span:l.computed(()=>i.span(w)),blanks:l.computed(()=>a.value.get(w)??[]),itemRef:b=>i.ref(w,b),Col:o,disabled:u}}),()=>{if(u.value)return r.default?.()??null;const m=t;return l.createVNode(m,l.mergeProps({ref:f},s),{default:()=>[r.default?.()??null]})}}})}const Qe=new Set(["item","layout","model","span"]),et=new Set(["component","props","model","prop","item","layout"]);function Q(e){const t={};for(const[o,n]of Object.entries(e))n!==void 0&&(t[o]=n);return t}function oe(e){const t={};for(const[o,n]of Object.entries(e))o==="span"&&n!==void 0&&console.warn("[vue-formless] fl:span is removed; use col:span"),Qe.has(o)||(t[o]=n);return t}function tt(e){const t={};for(const[o,n]of Object.entries(e))!et.has(o)&&n!==void 0&&(t[o]=n);return t}function nt(e){if(e==null||typeof e!="object")return{};const t=e.formless;if(t==null||typeof t!="object")return{};const{model:o,item:n}=t;return Q({model:o,item:n})}function ve(e){const t={};for(const[o,n]of Object.entries(e))!o.startsWith("fl:")||o.length<=3||n===void 0||(t[o.slice(3)]=n);return t}function ot(e,t){const o=new Set;for(const r of t)o.add(r),o.add(`onUpdate:${r}`);const n={};for(const[r,s]of Object.entries(e))o.has(r)||(n[r]=s);return n}function $(e,t){return e==null?{}:Q(typeof e=="function"?e(t)??{}:e)}function z(...e){const t={};for(const o of e)if(o!=null)for(const[n,r]of Object.entries(o))r!==void 0&&(t[n]=r);return t}function rt(e){const t=e.Item?l.markRaw(e.Item):void 0;return(o,n)=>t&&n.item!==!1&&(n.item===!0||(e.isItemEnabled?.()??!0))?l.h(t,z($(e.itemProps,n.fl),n.itemAttrs,n.itemOn),{...n.itemSlots,default:()=>o}):o}function ee(e){return typeof e=="string"?[e]:[...e]}function re(e,t={},o={}){if(o.prop==="")throw new Error(`[vue-formless] fl:prop cannot be an empty string (control "${e}")`);if(t.prop==="")throw new Error(`[vue-formless] prop cannot be an empty string (control "${e}")`);const n=ee(t.model??"modelValue"),r=ee(o.prop!==void 0?o.prop:t.prop??e);if(r.length>n.length)throw new Error(`createFormControls: prop cannot be longer than model (control "${e}": model has ${n.length}, prop has ${r.length})`);if(r.some(s=>s===""))throw new Error(`[vue-formless] prop cannot be an empty string (control "${e}")`);return{models:n,props:r}}function lt(e,t){return e.props.length===1?ye(e.props[0]):t}function be(e,t){const o=e.models.indexOf(t);if(o===-1)throw new Error(`[vue-formless] useFormItem("${t}"): not a v-model port of this control`);const n=e.props[o];if(n===void 0)throw new Error(`[vue-formless] useFormItem("${t}"): port is not bound to a prop`);return{models:[t],props:[n]}}function le(e,t,o){const n={};for(let r=0;r<t.props.length;r++){const s=t.models[r],u=t.props[r];n[s]=k(e,u),n[`onUpdate:${s}`]=i=>{o(u,i)}}return n}const O="item:",q="onItem:",H="fl:",X="row:",Z="col:",st=new Set(["column","gutter"]),ut=new Set(["span","place"]);function fe(e){console.warn(e)}function Ie(e){const t={},o={};for(const n of Object.keys(e)){const r=e[n];r&&(n.startsWith(O)&&n.length>O.length?t[n.slice(O.length)]=r:o[n]=r)}return{itemSlots:t,inputSlots:o}}function Ce(e){const t={},o={};for(const[n,r]of Object.entries(e))n.startsWith(H)&&n.length>H.length?t[n.slice(H.length)]=r:o[n]=r;return{fl:t,rest:o}}function Fe(e){const t={},o={},n={};for(const[r,s]of Object.entries(e))if(r.startsWith(X)&&r.length>X.length){const u=r.slice(X.length);st.has(u)?t[u]=s:fe(`[vue-formless] unknown row:${u} is ignored`)}else if(r.startsWith(Z)&&r.length>Z.length){const u=r.slice(Z.length);ut.has(u)?o[u]=s:fe(`[vue-formless] unknown col:${u} is ignored`)}else n[r]=s;return{row:t,col:o,rest:n}}function me(e){if(e==null||e==="")return;const t=typeof e=="number"?e:Number(e);if(Number.isFinite(t))return t}function Ee(e){const t={},o={},n={};for(const[r,s]of Object.entries(e))r.startsWith(q)&&r.length>q.length?o[it(r.slice(q.length))]=s:r.startsWith(O)&&r.length>O.length?t[r.slice(O.length)]=s:n[r]=s;return{itemAttrs:t,itemOn:o,inputAttrs:n}}function it(e){const t=e.indexOf(":");return t===-1?`on${de(e)}`:`on${de(e.slice(0,t))}:${e.slice(t+1)}`}function de(e){return e&&e.charAt(0).toUpperCase()+e.slice(1)}const Ve=Symbol("vue-formless.controlRuntime");function at(e){l.provide(Ve,e)}const ct={"fl:prop":{type:[String,Array],default:void 0},"col:span":{type:[String,Number],default:void 0},"col:place":{type:String,default:void 0}};function Se(e){return l.defineComponent({name:e?`FormViewItem_${e}`:"FormViewItem",inheritAttrs:!1,props:ct,setup(t,{slots:o,attrs:n}){const r=Y(),s=he(),u=l.inject(Ve,null);if(e!=null&&!u)throw new Error("[vue-formless] useFormItem(port) must be used inside a namespaced control.");return()=>ft(r,s,u,e,o,n,t)}})}const se=Se();function Ae(e){return Y(),e===void 0?se:Se(e)}function ft(e,t,o,n,r,s,u){const{fl:i,rest:f}=Ce(s),{row:a,col:m,rest:g}=Fe(f),w={...i,...ve(u)},{itemAttrs:b,itemOn:v,inputAttrs:S}=Ee(g),I={...b,...S},{itemSlots:y}=Ie(r),d=n==null&&o!=null,C=u["col:span"]??m.span,A=u["col:place"]??m.place,c=o?.getFrame(),L=C??(d?c?.colSpan:void 0),x=A??(d?c?.colPlace:void 0),_=mt(e,o,n,w),M=le(e.model,_.binding,e.update),K=r.default?.({field:M})??null;!d&&(a.column!=null||a.gutter!=null)&&console.warn("[vue-formless] :row:* is ignored on a leaf cell");let F=I,E=v,T=y;d&&c&&(F={...c.itemAttrs,...I},E={...c.itemOn,...v},T={...c.itemSlots,...y});let R,B,P=!1;d&&c&&(R=c.wrapItem,B=c.wrapCol,P=c.extraRow);let h=K;if(P&&c){const j=h;h=l.h(e.LayoutView,{disabled:!e.isLayoutEnabled(),column:c.rowColumn??e.factoryColumn,gutter:c.rowGutter??e.factoryGutter},()=>j)}if(h=e.wrap(h,{item:R===!1?!1:R===!0?!0:void 0,fl:_.fl,itemAttrs:F,itemOn:E,itemSlots:T}),B!==!1){const j=h;h=l.h(t,{span:L,place:x},()=>j)}return h}function mt(e,t,o,n){const r=oe(n);if(t){const a=t.getFrame(),m=o!=null?be(a.binding,o):a.binding,g={...a.fl,...r,controlKey:t.controlKey,binding:m,getValues:()=>m.props.map(w=>k(e.model,w))};return{binding:m,fl:g}}const s=n.prop;if(s==="")throw new Error("[vue-formless] fl:prop cannot be an empty string");const u=typeof s=="string"?s:Array.isArray(s)&&s[0]?String(s[0]):"",i=s===void 0?{models:["modelValue"],props:[]}:re(u||"field",{prop:s}),f={...r,controlKey:u,binding:i,getValues:()=>i.props.map(a=>k(e.model,a))};return{binding:i,fl:f}}function Le(e){const t=e;return t.Item=se,t}const te=0;function dt(e){return new Proxy({},{get(t,o){const n=e.value;if(n==null)return;const r=Reflect.get(n,o,n);return typeof r=="function"?r.bind(n):r},has(t,o){return e.value!=null&&o in e.value}})}const Oe={modelValue:{type:[Object,Array],default:void 0},"fl:layout":{type:Boolean,default:!1},"row:column":{type:Number,default:void 0},"row:gutter":{type:Number,default:void 0},"fl:form":{type:[Boolean,String],default:"auto"},"fl:item":{type:Boolean,default:!0}},ke={"update:modelValue":e=>!0};function G(e){if(e!=null&&typeof e=="object")throw new Error("[vue-formless] fl:layout is boolean only; use :row:column / :row:gutter");return e===!0||e===""}function pt(e,t){return e===!0||e===!1?e:!t}function wt(e){return e==null?!1:"modelValue"in e||"model-value"in e||"onUpdate:modelValue"in e||"onUpdate:model-value"in e}function xe(e){const t=rt({Item:e.Item,itemProps:e.itemProps,isItemEnabled:e.isItemEnabled}),o=e.isItemEnabled??(()=>!0);l.provide(N,l.reactive({get model(){return e.getModel()},update:e.update,wrap:t,isItemEnabled:o,isLayoutEnabled:e.isLayoutEnabled,LayoutView:l.markRaw(e.LayoutView),factoryColumn:e.factoryColumn,factoryGutter:e.factoryGutter}))}function Re(e,t){const o=l.inject(N,null);if(wt(l.getCurrentInstance()?.vnode.props)){const r=Me(e,t);return{getModel:e,update:r.update}}if(o)return{getModel:()=>o.model,update:o.update};throw new Error("[vue-formless] FormView requires v-model unless nested inside another FormView.")}function yt(e){if(e!=null){if(e.Row==null||e.Col==null)throw new Error("[vue-formless] createFormView layout requires both Row and Col.");return{Row:l.markRaw(e.Row),Col:l.markRaw(e.Col),column:e.column,gutter:e.gutter}}}function gt(e={}){const t=yt(e.layout),o=e.form?.component?l.markRaw(e.form.component):void 0,n=e.form?.props,r=e.item?.component?l.markRaw(e.item.component):void 0,s=e.item?.props,u=ne(t?{Row:t.Row,Col:t.Col}:{}),i=t?.column??V.column,f=t?.gutter??te;return Le(l.defineComponent({name:"FormView",inheritAttrs:!1,props:Oe,emits:ke,setup(a,{slots:m,emit:g,attrs:w,expose:b}){const v=l.ref(null);b(dt(v));const S=l.inject(N,null)!=null,{getModel:I,update:y}=Re(()=>a.modelValue,d=>g("update:modelValue",d));return xe({getModel:I,update:y,Item:r,itemProps:s,isItemEnabled:()=>a["fl:item"]!==!1,isLayoutEnabled:()=>G(a["fl:layout"]),LayoutView:u,factoryColumn:i,factoryGutter:f}),()=>{const d=m.default?.()??null,C=G(a["fl:layout"]),A={column:a["row:column"]??i,gutter:a["row:gutter"]??f},c=l.h(u,{disabled:!C,column:A.column,gutter:A.gutter},()=>d),L=o?pt(a["fl:form"],S):!1;if(!o||!L)return c;const x={layout:C,form:L,item:a["fl:item"]!==!1,modelValue:I()};return l.h(o,{ref:v,...z($(n,x),w)},{default:()=>c})}}}))}const pe=ne(),ht=Le(l.defineComponent({name:"FormView",inheritAttrs:!1,props:Oe,emits:ke,setup(e,{slots:t,emit:o}){const{getModel:n,update:r}=Re(()=>e.modelValue,s=>o("update:modelValue",s));return xe({getModel:n,update:r,isLayoutEnabled:()=>G(e["fl:layout"]),LayoutView:pe,factoryColumn:V.column,factoryGutter:te}),()=>l.h(pe,{disabled:!G(e["fl:layout"]),column:e["row:column"]??V.column,gutter:e["row:gutter"]??te},()=>t.default?.()??null)}}));function ue(e){return e&&e.charAt(0).toUpperCase()+e.slice(1)}function vt(e){return e&&e.charAt(0).toLowerCase()+e.slice(1)}function Pe(e,t){if(e==="self"&&t===!1||e===!1&&t==="self")throw new Error('[vue-formless] formless.item "self" conflicts with schema item: false');return e??t}function je(e){const t=e.internalItem==="self";let o;e.tagItem===!0?o=!0:e.tagItem===!1||t||e.internalItem===!1?o=!1:e.internalItem===!0?o=!0:o=e.pageItem;let n=e.pageLayoutOn;t&&e.tagItem!==!0&&(o=!1,n=!1);const r=t&&e.tagItem===!0&&e.pageLayoutOn;return{wrapItem:o,wrapCol:n,extraRow:r,self:t}}const bt={"fl:prop":{type:[String,Array],default:void 0},"fl:item":{type:Boolean,default:void 0},"col:span":{type:[String,Number],default:void 0},"col:place":{type:String,default:void 0},"row:column":{type:Number,default:void 0},"row:gutter":{type:Number,default:void 0}};function It(e,t){const o=Et(e),n={};for(const r of Object.keys(o)){const s=o[r];if(!s)continue;const u=ue(r);n[u]=Ct(r,s,t)}return n}function Ct(e,t,o){const n=nt(t.component),r=n.model??t.model,s=Pe(n.item,t.item);return l.defineComponent({name:`Control_${ue(e)}`,inheritAttrs:!1,props:bt,setup(u,{attrs:i,slots:f}){const a=Y();let m;at({controlKey:e,getFrame:()=>m});const g=Ae();return()=>{const{fl:w,rest:b}=Ce(i),{row:v,col:S,rest:I}=Fe(b),y={...w,...ve(u)},d=re(e,{model:r,prop:t.prop},{prop:y.prop}),C=t.component,{itemSlots:A,inputSlots:c}=Ie(f),{itemAttrs:L,itemOn:x,inputAttrs:_}=Ee(I),M=tt(t),K=y.item===!0?!0:y.item===!1?!1:void 0,F=je({pageItem:a.isItemEnabled(),pageLayoutOn:a.isLayoutEnabled(),internalItem:s,tagItem:K}),E=Ft(a,e,d,M,y),T=z($(o?.props,E),$(t.props,E),ot(_,d.models)),R=le(a.model,d,a.update),B=d.props[0]??e,P=typeof E.label=="string"?E.label:void 0,h=u["col:span"]??S.span,j=u["col:place"]??S.place,ie=me(u["row:column"]??v.column),ae=me(u["row:gutter"]??v.gutter);!F.extraRow&&(ie!=null||ae!=null)&&console.warn("[vue-formless] :row:* is ignored on a leaf control");const $e=C?l.h(C,{...T,...R},c):l.h("div",{class:"vue-formless-control","data-control":e},[P?l.h("label",{class:"vue-formless-control__label"},String(P)):null,String(k(a.model,B)??"")]);return m={fl:{...M,...oe(y)},binding:d,wrapItem:F.wrapItem,wrapCol:F.wrapCol,extraRow:F.extraRow,colSpan:h,colPlace:j,rowColumn:ie,rowGutter:ae,itemAttrs:L,itemOn:x,itemSlots:A},l.h(g,null,()=>$e)}}})}function Ft(e,t,o,n,r){return{...n,...oe(r),controlKey:t,binding:o,getValues:()=>o.props.map(s=>k(e.model,s))}}function Et(e){const t={...e};for(const o of Object.keys(t)){const n=t[o];n&&(t[o]={...n,component:n.component&&typeof n.component=="object"?l.markRaw(n.component):n.component})}return t}exports.DEFAULT_LAYOUT=V;exports.FormView=ht;exports.FormViewItem=se;exports.GRID_TOTAL=p;exports.applyControlBinding=le;exports.bindingForPort=be;exports.camelToPascal=ue;exports.createFormControls=It;exports.createFormView=gt;exports.createLayoutView=ne;exports.formContextKey=N;exports.formItemProp=ye;exports.getIn=k;exports.mergeInternalItem=Pe;exports.overlayProps=z;exports.parsePath=D;exports.pascalToCamel=vt;exports.resolveControlBinding=re;exports.resolveControlShell=je;exports.resolveFormItemProp=lt;exports.resolveProps=$;exports.setIn=we;exports.toBindingList=ee;exports.useFormContext=Y;exports.useFormItem=Ae;exports.useLayoutItem=he;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("vue"),F=24,Y=1;function E(e){return Math.min(F,Math.max(1,e))}function G(e){return Math.floor(F/R(e))}function R(e){const t=Math.floor(Number(e));return Number.isNaN(t)?Y:E(t)}function Z(...e){return R([...e].reverse().find(t=>t!=null))}function X(e,t){const n=G(t);if(typeof e!="number"&&typeof e!="string"||(e=typeof e=="string"?e.trim().toLowerCase():e,e===""))return n;if(e==="max")return F;if(typeof e=="string"&&e.endsWith("x")){const r=Math.floor(Number(e.substring(0,e.length-1)));return Number.isNaN(r)?n:E(E(r)*n)}return e=Math.floor(Number(e)),Number.isNaN(e)?n:E(e)}function J(e){return e=typeof e=="string"?e.trim().toLowerCase():e,e==="start"||e==="end"?e:"auto"}const w=Symbol("vue-formless:layout-view");function Q(e){return e.reduce((t,n,r)=>{const o=t[r-1],i=o?o.$start+o.$occupied:0,c=i%F,d=ee({cursor:c,span:n.span,place:n.place});return t.push({...n,$start:i,$occupied:d}),t},[])}function ee({cursor:e,place:t,span:n}){const r=F-e;return t==="start"?e===0?n:r+n:t==="end"?r>=n?r:r+F:r>=n?n:r+n}function te(e,t,n){const r=e%F,o=r+t>F?F-r:0,i=t-o-n;return[o,i].filter(c=>c>0)}function ne(e,t,n={childList:!0}){if(typeof MutationObserver>"u")return;let r=null;function o(c){r?.disconnect(),r=null,c&&(r=new MutationObserver(t),r.observe(c,n))}u.onMounted(()=>o(u.toValue(e)));const i=u.watch(()=>u.toValue(e),o,{flush:"post"});u.onBeforeUnmount(()=>{i(),r?.disconnect(),r=null})}function re(e,t=0){const n=u.ref([]);function r(){const o=u.toValue(e);n.value=o?Array.from(o.children):[]}return u.watch(()=>[u.toValue(e),u.toValue(t)],r,{immediate:!0}),ne(e,r),n}function S(e){if(e==null||typeof e!="object")return null;if(typeof Element<"u"&&e instanceof Element)return e;const t=e.$el;return typeof Element<"u"&&t instanceof Element?t:null}const j=u.defineComponent({name:"LayoutBlanks",inheritAttrs:!1,props:{is:{type:Object,default:void 0},spans:{type:Array,required:!0}},setup(e){return()=>{if(e.spans.length===0||e.is==null)return null;const t=e.is;return u.createVNode(u.Fragment,null,[e.spans.map((n,r)=>u.createVNode(t,{key:r,span:n,"aria-hidden":"true","data-layout-blank":""},null))])}}}),T=u.defineComponent({name:"LayoutItem",inheritAttrs:!1,props:{span:{type:[String,Number],default:void 0},place:{type:String,default:void 0}},setup(e,{slots:t,attrs:n,expose:r}){const o=u.inject(w,null);if(!o)return()=>t.default?.()??null;const{span:i,blank:c,ref:d,Col:a,disabled:s,place:f}=o(()=>e.span,()=>e.place),m=u.ref(null);r({el:u.computed(()=>S(m.value))});function y(p){m.value=p,d(p)}return()=>{if(s.value)return t.default?.()??null;const p=a;return u.createVNode(u.Fragment,null,[u.createVNode(j,{is:a,spans:c.value.before},null),u.createVNode(p,u.mergeProps(n,{ref:y,span:i.value,"data-layout-item":"","data-layout-place":f.value}),{default:()=>[t.default?.()??null]}),u.createVNode(j,{is:a,spans:c.value.after},null)])}}});function ue({column:e,rowRef:t}){let n=0;const r=u.ref({}),o=re(()=>S(t.value),()=>Object.keys(r.value).filter(a=>r.value[a].mounted).join(",")),i=u.computed(()=>oe(r.value,o.value)),c=u.computed(()=>Q(i.value)),d=u.computed(()=>new Map(c.value.map(a=>[a.id,te(a.$start,a.$occupied,a.span)])));return{setup(a,s){const f=String(++n);return r.value[f]={span:u.computed(()=>X(u.toValue(a),u.toValue(e))),place:u.computed(()=>J(u.toValue(s))),el:null,mounted:!1},u.onMounted(()=>{const m=r.value[f];m&&(m.mounted=!0)}),u.onBeforeUnmount(()=>{delete r.value[f]}),f},span(a){return r.value[a]?.span??0},blank(a){return{before:d.value.get(a)??[],after:[]}},place(a){return r.value[a]?.place??"unknown"},ref(a,s){const f=r.value[a];if(!f)return;const m=S(s);f.el!==m&&(f.el=m)},placed(a){return c.value.findIndex(s=>s.id===a)>-1}}}function oe(e,t){const n=new Map(Object.entries(e).filter(([,r])=>r.el).map(([r,o])=>[o.el,{id:r,span:o.span,place:o.place}]));return t.filter(r=>n.has(r)).map(r=>n.get(r))}function P(e={}){const{Row:t,Col:n}=e;return u.defineComponent({name:"LayoutView",inheritAttrs:!1,props:{disabled:{type:Boolean,default:!1},column:{type:Number,default:void 0}},setup(r,{slots:o,attrs:i}){const c=u.computed(()=>!t||!n||r.disabled),d=u.computed(()=>Z(e.column,r.column)),a=u.ref(null),s=ue({column:d,rowRef:a});return u.provide(w,(f,m)=>{u.provide(w,null);const y=s.setup(f,m);return{span:u.computed(()=>s.span(y)),blank:u.computed(()=>s.blank(y)),ref:p=>s.ref(y,p),place:u.computed(()=>s.place(y)),placed:u.computed(()=>s.placed(y)),Col:n,disabled:c}}),()=>{if(c.value)return o.default?.()??null;const f=t;return u.createVNode(f,u.mergeProps({ref:a},i,{"data-layout-row":""}),{default:()=>[o.default?.()??null]})}}})}function le(e={}){const t=e.component?u.markRaw(e.component):void 0;return u.defineComponent({name:"FormItem",inheritAttrs:!1,props:{fl:{type:Object,required:!0},item:{type:Object,required:!0}},setup(n,{slots:r}){return()=>{if(!t||!n.fl?.item)return r.default?.()??null;const o=t,i=typeof e.props=="function"?e.props(n.fl):e.props;return u.createVNode(o,{...i,...n.item},r)}}})}const k=Symbol("vue-formless:form-view"),_=Symbol("vue-formless:form-field"),A=Symbol("EOF"),g=Symbol("failed"),ae=/[a-zA-Z_$0-9]/,ie=/[a-zA-Z0-9_$]/,ce=/[0-9]/;function $(e){if(!e)return;const t=[];let n="",r="",o=0;function i(l){if(l==="[")return s;if(l!==A)return typeof l=="string"&&ae.test(l)?(n=l,a):g}function c(l){return l==="."?d:i(l)}function d(l){return l===A||l==="."?g:i(l)}function a(l){return typeof l=="string"&&ie.test(l)?(n+=l,a):(t.push({type:"key",key:n}),n="",c(l))}function s(l){if(l===A)return g;if(typeof l=="string"&&(l==='"'||l==="'"))return r=l,n="",f;if(typeof l=="string"&&ce.test(l))return n+=l,s;if(l!=="]")return g;const v=Number(n);return n===""||String(v)!==n||v<0?g:(t.push({type:"index",index:v}),n="",c)}function f(l){return l===A?g:l==="\\"?m:l===r?y:(n+=l,f)}function m(l){return l===A?g:(n+=l,f)}function y(l){return l===A||l!=="]"?g:(t.push({type:"key",key:n}),n="",c)}let p=i;for(;o<e.length;o++){const l=p(e[o]);if(l===g)return;p=l}if(p(A)!==g)return t}function H(e){return typeof e=="object"&&e!==null}const se=Object.prototype.hasOwnProperty;function fe(e,t){return se.call(e,t)?e[t]:void 0}function q(e,t){if(H(e)){if(t.type==="key")return Array.isArray(e)?void 0:fe(e,t.key);if(t.type==="index")return Array.isArray(e)?e[t.index]:void 0}}function de(e,t){let n=e;for(const r of t)n=q(n,r);return n}function me(e,t){const n=$(t);return n?de(e,n):void 0}function pe(e,t,n){const r=$(t);return r?D(e,r,n):e}function D(e,t,n){if(!t.length)return e;if(t.length===1)return x(e,t[0],n);const[r,...o]=t;return x(e,r,D(q(e,r),o,n))}function x(e,t,n){if(t.type==="key")return{...H(e)&&!Array.isArray(e)?e:{},[t.key]:n};if(t.type==="index"){const r=Array.isArray(e)?[...e]:[];return r[t.index]=n,r}return e}function ye(e){let t=null;function n(o){return me(e.value,o)}function r(o,i){t||(t=[],u.nextTick(()=>{const c=t;if(t=null,!c?.length)return;let d=e.value;for(const a of c)d=pe(d,a.path,a.value);e.value=d})),t.push({path:o,value:i})}return{getIn:n,setIn:r}}const ve=["modelValue","model-value"],be=["onUpdate:modelValue","onUpdate:model-value"];function ge(e,t){const n=u.computed(()=>ve.find(i=>i in e)),r=u.computed(()=>be.find(i=>typeof e[i]=="function")),o=u.computed(()=>n.value?"controlled":t?"inherit":"local");return{key:n,event:r,source:o}}function Fe(){const e=u.useAttrs(),t=u.inject(k,null),{source:n,key:r,event:o}=ge(e,!!t),i=u.ref(),c=u.computed({get:()=>n.value==="controlled"?e[r.value]:i.value,set:m=>{n.value==="local"&&(i.value=m),o.value&&e[o.value](m)}}),d=ye(c),a=u.computed(()=>n.value==="inherit"?t.value.value:c.value);function s(m){return n.value==="inherit"?t.getIn(m):d.getIn(m)}function f(m,y){return n.value==="inherit"?t.setIn(m,y):d.setIn(m,y)}return u.provide(k,{value:a,getIn:s,setIn:f}),{value:a,getIn:s,setIn:f}}function C(e){return e&&e.charAt(0).toUpperCase()+e.slice(1)}function B(...e){const t=n=>{if(n!==void 0)return n===""?!0:!!n};return e.reduce((n,r)=>typeof t(r)=="boolean"?t(r):n,void 0)}function L(e){return e.replace(/-([a-z])/g,(t,n)=>n.toUpperCase())}const Ve=["fl","layout-item","layout","item"],Ie=new Map(Ve.map(e=>{const t=L(e);return[[`${e}:`,{channel:e,type:"prop"}],[`${t}:`,{channel:e,type:"prop"}],[`on${C(e)}:`,{channel:e,type:"listener"}],[`on${C(t)}:`,{channel:e,type:"listener"}]]}).flat());function U(e,t,n={}){const r=n.prefix==="keep",o={};for(const c of[...t,"default"])o[c]=Object.create(null);const i=Object.entries(e).map(([c,d])=>({...Ne(c,t),rawKey:c,value:d}));for(const{rawKey:c,key:d,value:a,channel:s,type:f}of i)f!=="listener"&&(o[s||"default"][r&&s?c:d]=a);for(const{rawKey:c,key:d,value:a,channel:s,type:f}of i)f==="listener"&&(o[s||"default"][r&&s?c:d]=a);return o}function Ne(e,t){const n=e.indexOf(":");if(n===-1)return{key:e};const r=e.substring(0,n+1);if(e.length===r.length)return{key:e};const o=Ie.get(r);return!o||!t.includes(o.channel)?{key:e}:{key:o.type==="listener"?`on${C(e.replace(r,""))}`:e.replace(r,""),channel:o.channel,type:o.type}}const he=["fl","layout"],Ae=["fl","layout","layout-item","item"],Oe=["item"];function z(e,t,n){const r=u.computed(()=>U(e,t,n)),o={};for(const i of t)o[L(i)]=u.computed(()=>r.value[i]);return o.default=u.computed(()=>r.value.default),o}function Ce(e){return new Proxy({},{get(t,n){const r=e.value;if(r==null)return;const o=Reflect.get(r,n,r);return typeof o=="function"?o.bind(r):o},has(t,n){return e.value!=null&&n in e.value}})}function Ee(e={}){const{Row:t,Col:n}=e.layout??{},r=P({Row:t,Col:n}),o=e.form?.component?u.markRaw(e.form.component):void 0,i=le(e.item);return u.defineComponent({name:"FormView",inheritAttrs:!1,setup(c,{slots:d,attrs:a,expose:s}){const f=u.ref(null);s(Ce(f));const y=u.inject(k,null)!=null,{fl:p,layout:l,default:v}=z(a,he),N=u.computed(()=>B(!1,p.value.layout)),V=u.computed(()=>{const b=p.value.form;return b===void 0||b==="auto"?!y:b===""?!0:!!b}),{getIn:I,setIn:h}=Fe();return u.provide(_,{access(b){return{value:u.computed(()=>I(u.toValue(b))),update:O=>h(u.toValue(b),O)}},FormItem:u.markRaw(i),LayoutView:u.markRaw(r),fl:p}),()=>{const b=r,O=u.createVNode(b,u.mergeProps({...e.layout?.props,...l.value},{disabled:!N.value}),{default:d.default});if(!o||!V.value)return O;const W=o;return u.createVNode(W,u.mergeProps({ref:f},{...e.form?.props,...v.value}),{default:()=>O})}}})}function Le(e){return typeof e=="function"||Object.prototype.toString.call(e)==="[object Object]"&&!u.isVNode(e)}function M(e){if(!(typeof e>"u"))return(Array.isArray(e)?e:[e]).map(t=>{if(typeof t=="string")return t})}function we(e){if(!(typeof e>"u"))return(Array.isArray(e)?e:[e]).map(t=>{if(typeof t=="string")return t})}const Se=u.defineComponent({name:"FormFieldCore",inheritAttrs:!1,props:{preset:{type:Object},fl:{type:Object,required:!0},layoutItem:{type:Object,required:!0},layout:{type:Object,required:!0},item:{type:Object,required:!0},control:{type:[Object,Function],required:!0}},setup(e,{slots:t}){const n=u.inject(_,null),r=u.computed(()=>e.fl?.component?.formless),o=u.computed(()=>({...e.preset?.fl,...e.fl})),i=u.computed(()=>M(o.value?.model)||M(r.value?.model)||["modelValue"]),c=u.computed(()=>we(o.value?.prop)||n?.getProp?.(i.value)),d=u.computed(()=>{const p={},l={};return i.value.forEach((v,N)=>{if(typeof v!="string"||v.trim()==="")return;const V=c.value?.[N];if(typeof V!="string"||V.trim()==="")return;const I=n?.access(V);if(!I)return;const h=L(v);p[h]=I.value.value,l[`onUpdate:${h}`]=I.update}),{values:p,events:l}}),a=u.computed(()=>({...d.value.values,...d.value.events}));u.provide(_,{...n,getProp(p){return p.map(l=>{if(typeof l!="string")return;const v=i.value.indexOf(l);return v!==-1?c.value?.[v]:void 0})}});const s=u.computed(()=>{const p=r.value?.field==="embed"?"embed":"auto",l=o.value?.field==="embed"?"embed":o.value?.field==="wrap-embed"?"wrap-embed":"auto";return p==="auto"?l==="auto"?"wrap":l:l==="auto"?"embed":l}),f=u.computed(()=>B(!0,u.toValue(n?.fl)?.item,o.value?.item)),m=u.computed(()=>({...o.value,model:i.value,prop:c.value,field:s.value,item:f.value})),y=u.computed(()=>{const p=typeof e.preset?.props=="function"?e.preset?.props(m.value):e.preset?.props;return u.mergeProps(d.value.events,{...p,...e.control},d.value.values)});return()=>{const{item:p,default:l}=U(t,Oe),v=e.fl.component,N=v?u.createVNode(v,y.value,l):t.default?.({$bindings:a.value})??null;if(s.value==="embed")return N;const V=n?.LayoutView,I=s.value==="wrap-embed"&&V?u.createVNode(V,e.layout,{default:()=>N}):N,h=n?.FormItem,b=h?u.createVNode(h,{fl:m.value,item:e.item},{...p,default:()=>I}):I;return u.createVNode(T,e.layoutItem,Le(b)?b:{default:()=>[b]})}}});function K(e={}){const{name:t,component:n,props:r,...o}=e;return u.defineComponent({name:t?`FormField${C(t)}`:"FormField",inheritAttrs:!1,setup(i,{attrs:c,slots:d}){const{fl:a,layoutItem:s,layout:f,item:m,default:y}=z(c,Ae);return()=>u.createVNode(Se,{preset:{fl:o,props:r},fl:{...a.value,component:n??a.value.component},layoutItem:s.value,layout:f.value,item:m.value,control:y.value},d)}})}const ke=K();function _e(e){const t={};for(const n of Object.keys(e)){const r=e[n];if(!r)continue;const o=C(L(n));t[o]=K({name:o,prop:n,...r})}return t}exports.FormField=ke;exports.LayoutItem=T;exports.createFormFields=_e;exports.createFormView=Ee;exports.createLayoutView=P;
|