@sfxcode/nuxt-ui-formkit 1.2.12 → 1.3.2

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/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.0.0"
6
6
  },
7
- "version": "1.2.12",
7
+ "version": "1.3.2",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.3",
10
10
  "unbuild": "3.6.1"
@@ -10,12 +10,17 @@ const { handleInput, handleChange, isInvalid, color, styleClass, modelValue, ite
10
10
  </script>
11
11
 
12
12
  <template>
13
+ <!-- Nuxt UI's own USelect shrinks its trigger to whatever's currently
14
+ selected (or just the chevron, unselected) - `w-fit min-w-48` keeps it from
15
+ collapsing that small while still growing for longer option labels, rather
16
+ than forcing every instance to one fixed width. Only applies when the
17
+ consumer hasn't already set their own `class`. -->
13
18
  <USelect
14
19
  :id="context.id"
15
20
  v-model="modelValue"
16
21
  :name="context.node.name"
17
22
  v-bind="{ ...context?.attrs }"
18
- :class="styleClass"
23
+ :class="[styleClass, !context?.attrs?.class && 'w-fit min-w-48']"
19
24
  :disabled="!!context?.disabled"
20
25
  :style="context?.attrs.style"
21
26
  :color="color"
@@ -10,12 +10,17 @@ const { handleInput, handleChange, isInvalid, styleClass, color, modelValue, ite
10
10
  </script>
11
11
 
12
12
  <template>
13
+ <!-- Nuxt UI's own USelectMenu shrinks its trigger to whatever's currently
14
+ selected (or just the chevron, unselected) - `w-fit min-w-48` keeps it from
15
+ collapsing that small while still growing for longer option labels, rather
16
+ than forcing every instance to one fixed width. Only applies when the
17
+ consumer hasn't already set their own `class`. -->
13
18
  <USelectMenu
14
19
  :id="context.id"
15
20
  v-model="modelValue"
16
21
  :name="context.node.name"
17
22
  v-bind="{ ...context?.attrs }"
18
- :class="styleClass"
23
+ :class="[styleClass, !context?.attrs?.class && 'w-fit min-w-48']"
19
24
  :disabled="!!context?.disabled"
20
25
  :style="context?.attrs.style"
21
26
  :color="color"
@@ -0,0 +1,36 @@
1
+ type EditorData = Record<string, unknown> & {
2
+ _dollar_formkit?: string;
3
+ $formkit?: string;
4
+ attrs?: {
5
+ attrKey?: string;
6
+ attrValue?: unknown;
7
+ }[];
8
+ options?: unknown[];
9
+ label?: unknown;
10
+ legend?: unknown;
11
+ outerClass?: unknown;
12
+ wrapperClass?: unknown;
13
+ innerClass?: unknown;
14
+ readonly?: unknown;
15
+ disabled?: unknown;
16
+ preserve?: unknown;
17
+ };
18
+ /**
19
+ * Converts between a single FormKit schema node (`{ $formkit: 'nuxtUIInput', ... }`)
20
+ * and the "editor data" shape used by the property-editor form built in
21
+ * `useFormKitEditorSchema`. The editor form is itself a FormKit form, so its
22
+ * field names can't collide with FormKit's own `$`-prefixed schema syntax -
23
+ * `_dollar_formkit` stands in for `$formkit` while editing and gets mapped
24
+ * back on the way out.
25
+ */
26
+ export declare function useFormKitEditor(): {
27
+ inputNames: string[];
28
+ outputNames: string[];
29
+ inputNamesWithOptions: string[];
30
+ inputNamesWithLegend: string[];
31
+ editorDataToSchema: (data: EditorData) => Record<string, unknown>;
32
+ editorDataToJson: (data: EditorData) => string;
33
+ editorDataToCode: (data: EditorData) => string;
34
+ schemaToEditorData: (schema: Record<string, unknown>) => EditorData;
35
+ };
36
+ export {};
@@ -0,0 +1,120 @@
1
+ export function useFormKitEditor() {
2
+ const inputNamesWithOptions = ["nuxtUICheckboxGroup", "nuxtUIInputMenu", "nuxtUIListbox", "nuxtUIRadioGroup", "nuxtUISelect", "nuxtUISelectMenu", "nuxtUITree"];
3
+ const inputNamesWithLegend = ["nuxtUICheckboxGroup", "nuxtUIRadioGroup"];
4
+ const inputNames = ["nuxtUICalendar", "nuxtUICheckbox", "nuxtUICheckboxGroup", "nuxtUIColorPicker", "nuxtUIEditor", "nuxtUIFileUpload", "nuxtUIInput", "nuxtUIInputDate", "nuxtUIInputMenu", "nuxtUIInputNumber", "nuxtUIInputRating", "nuxtUIInputTags", "nuxtUIInputTime", "nuxtUIListbox", "nuxtUIPinInput", "nuxtUIRadioGroup", "nuxtUISelect", "nuxtUISelectMenu", "nuxtUISlider", "nuxtUISwitch", "nuxtUITextarea", "nuxtUITree"].sort();
5
+ const outputNames = ["nuxtUIOutputBadge", "nuxtUIOutputBoolean", "nuxtUIOutputDate", "nuxtUIOutputLink", "nuxtUIOutputList", "nuxtUIOutputNumber", "nuxtUIOutputProgress", "nuxtUIOutputRating", "nuxtUIOutputText", "nuxtUIOutputUser"].sort();
6
+ function parseAttrValue(value) {
7
+ if (typeof value !== "string")
8
+ return value;
9
+ const trimmed = value.trim();
10
+ if (trimmed.length === 0)
11
+ return value;
12
+ try {
13
+ return JSON.parse(trimmed);
14
+ } catch {
15
+ return value;
16
+ }
17
+ }
18
+ function sanitizeOptions(options) {
19
+ if (!Array.isArray(options))
20
+ return void 0;
21
+ return options.filter((option) => Boolean(option) && typeof option === "object").filter((option) => option.label !== "" || option.value !== "").map((option) => ({ ...option }));
22
+ }
23
+ function editorDataToSchema(data) {
24
+ if (!data)
25
+ return {};
26
+ const formkitInput = data._dollar_formkit;
27
+ let extraAttrs = {};
28
+ if (data.attrs && Array.isArray(data.attrs) && data.attrs.length > 0) {
29
+ const mapped = data.attrs.filter((entry) => entry && typeof entry === "object" && entry.attrKey).map((entry) => [entry.attrKey, parseAttrValue(entry.attrValue)]);
30
+ extraAttrs = Object.fromEntries(mapped);
31
+ }
32
+ const defaultObject = {
33
+ readonly: data.readonly === true ? true : void 0,
34
+ disabled: data.disabled === true ? true : void 0,
35
+ preserve: data.preserve === true ? true : void 0
36
+ };
37
+ const outerClass = data.outerClass ? String(data.outerClass).trim() : void 0;
38
+ const wrapperClass = data.wrapperClass ? String(data.wrapperClass).trim() : void 0;
39
+ const innerClass = data.innerClass ? String(data.innerClass).trim() : void 0;
40
+ const undefinedObject = {
41
+ attrs: void 0,
42
+ schemaResultFormKey: void 0,
43
+ _dollar_formkit: void 0,
44
+ section: void 0,
45
+ slots: void 0
46
+ };
47
+ const useOptions = formkitInput ? inputNamesWithOptions.includes(formkitInput) : false;
48
+ const useLegend = formkitInput ? inputNamesWithLegend.includes(formkitInput) : false;
49
+ const result = {
50
+ ...data,
51
+ $formkit: formkitInput,
52
+ ...extraAttrs,
53
+ ...undefinedObject,
54
+ ...defaultObject,
55
+ outerClass,
56
+ wrapperClass,
57
+ innerClass,
58
+ // Cloned (not the same array/objects as `data.options`) so nothing
59
+ // downstream - the live preview's own rendered Select, `JSON.stringify`
60
+ // for the debug/copy views - can ever mutate the editor form's own
61
+ // repeater value by touching a shared reference. Also drops rows the
62
+ // user hasn't finished filling in yet, which Nuxt UI's Select/SelectMenu
63
+ // otherwise reject for having an empty `value`.
64
+ options: useOptions ? sanitizeOptions(data.options) : void 0,
65
+ label: useLegend ? void 0 : data.label,
66
+ legend: useLegend ? data.legend : void 0
67
+ };
68
+ for (const key in result) {
69
+ const value = result[key];
70
+ if (typeof value === "string" && value.trim().length === 0)
71
+ result[key] = void 0;
72
+ }
73
+ return result;
74
+ }
75
+ function editorDataToJson(data) {
76
+ if (!data)
77
+ return "{}";
78
+ return JSON.stringify(editorDataToSchema(data));
79
+ }
80
+ function objectToString(data) {
81
+ if (!data)
82
+ return "{}";
83
+ return `{ ${Object.entries(data).filter(([, value]) => value !== void 0).map(([key, value]) => {
84
+ if (key === "options" && Array.isArray(value) && value.length > 0) {
85
+ const options = value.map((option) => option && typeof option === "object" ? objectToString(option) : JSON.stringify(option));
86
+ return `${key}: [${options.join(", ")}]`;
87
+ }
88
+ if (typeof value === "number" || typeof value === "boolean") {
89
+ return `${key}: ${value}`;
90
+ }
91
+ return `${key}: '${value}'`;
92
+ }).join(", ")} }`;
93
+ }
94
+ function editorDataToCode(data) {
95
+ if (!data)
96
+ return "{}";
97
+ try {
98
+ const jsonData = editorDataToJson(data);
99
+ return objectToString(JSON.parse(jsonData));
100
+ } catch (error) {
101
+ console.error("Error in editorDataToCode:", error);
102
+ return "{}";
103
+ }
104
+ }
105
+ function schemaToEditorData(schema) {
106
+ if (!schema)
107
+ return {};
108
+ return { ...schema, _dollar_formkit: schema.$formkit };
109
+ }
110
+ return {
111
+ inputNames,
112
+ outputNames,
113
+ inputNamesWithOptions,
114
+ inputNamesWithLegend,
115
+ editorDataToSchema,
116
+ editorDataToJson,
117
+ editorDataToCode,
118
+ schemaToEditorData
119
+ };
120
+ }
@@ -0,0 +1,74 @@
1
+ export declare function useFormKitEditorSchema(isChangeTypePossible?: boolean): {
2
+ editorSchema: (typeOptionsOverride?: {
3
+ label: string;
4
+ value: string;
5
+ }[]) => (string | import("@formkit/core").FormKitSchemaDOMNode | import("@formkit/core").FormKitSchemaComponent | import("@formkit/core").FormKitSchemaCondition | import("@formkit/core").FormKitSchemaFormKit | {
6
+ $formkit: string;
7
+ if: string;
8
+ name: string;
9
+ label: string;
10
+ help: string;
11
+ listClass: string;
12
+ listItemClass: string;
13
+ insertButtonLabel: string;
14
+ alwaysDisplayInsertButton: boolean;
15
+ displayDeleteButton: boolean;
16
+ draggable: boolean;
17
+ displayDragHandle: boolean;
18
+ dragHandleClass: string;
19
+ buttonGroupClass: string;
20
+ hideMoveButtons: boolean;
21
+ newItem: {
22
+ label: string;
23
+ value: string;
24
+ attrKey?: undefined;
25
+ attrValue?: undefined;
26
+ };
27
+ key: string;
28
+ preserve: boolean;
29
+ children: {
30
+ $formkit: string;
31
+ label: string;
32
+ name: string;
33
+ outerClass: string;
34
+ }[];
35
+ } | {
36
+ $formkit: string;
37
+ if: string;
38
+ name: string;
39
+ label: string;
40
+ help: string;
41
+ listClass: string;
42
+ listItemClass: string;
43
+ insertButtonLabel: string;
44
+ alwaysDisplayInsertButton: boolean;
45
+ displayDeleteButton: boolean;
46
+ draggable: boolean;
47
+ displayDragHandle: boolean;
48
+ dragHandleClass: string;
49
+ buttonGroupClass: string;
50
+ hideMoveButtons: boolean;
51
+ newItem: {
52
+ attrKey: string;
53
+ attrValue: string;
54
+ label?: undefined;
55
+ value?: undefined;
56
+ };
57
+ key: string;
58
+ preserve: boolean;
59
+ children: {
60
+ $formkit: string;
61
+ label: string;
62
+ name: string;
63
+ outerClass: string;
64
+ }[];
65
+ })[];
66
+ fieldTypeOptions: {
67
+ label: string;
68
+ value: string;
69
+ }[];
70
+ typeOptions: (names: string[], kind?: string) => {
71
+ label: string;
72
+ value: string;
73
+ }[];
74
+ };
@@ -0,0 +1,337 @@
1
+ import { useFormKitSchema } from "./useFormKitSchema.js";
2
+ import { useFormKitEditor } from "./useFormKitEditor.ts";
3
+ let instanceCounter = 0;
4
+ export function useFormKitEditorSchema(isChangeTypePossible = true) {
5
+ const { addElement } = useFormKitSchema();
6
+ const { inputNames, outputNames, inputNamesWithOptions, inputNamesWithLegend } = useFormKitEditor();
7
+ instanceCounter += 1;
8
+ const dollarFormkitId = `_dollar_formkit_${instanceCounter}`;
9
+ const sectionId = `section_${instanceCounter}`;
10
+ function ifGet(id, value) {
11
+ return `$get(${id}).value === '${value}'`;
12
+ }
13
+ function ifSection(section) {
14
+ return ifGet(sectionId, section);
15
+ }
16
+ function ifAnyType(names) {
17
+ return names.map((name) => ifGet(dollarFormkitId, name)).join(" || ");
18
+ }
19
+ function ifNoneType(names) {
20
+ return names.map((name) => `$get(${dollarFormkitId}).value !== '${name}'`).join(" && ");
21
+ }
22
+ const optionsCapableIf = `(${ifAnyType(inputNamesWithOptions)})`;
23
+ const notOptionsCapableIf = `(${ifNoneType(inputNamesWithOptions)})`;
24
+ const legendTypeIf = `(${ifAnyType(inputNamesWithLegend)})`;
25
+ const notLegendTypeIf = `(${ifNoneType(inputNamesWithLegend)})`;
26
+ function typeOptions(names, kind) {
27
+ return names.map((name) => ({ label: kind ? `${name} (${kind})` : name, value: name }));
28
+ }
29
+ const fieldTypeOptions = [...typeOptions(inputNames), ...typeOptions(outputNames, "output")];
30
+ const sectionOptions = [
31
+ { label: "Base", value: "base" },
32
+ { label: "Display", value: "display" },
33
+ { label: "Style", value: "style" },
34
+ { label: "Validation", value: "validation" },
35
+ { label: "Options", value: "options" },
36
+ { label: "Attributes", value: "attrs" }
37
+ ];
38
+ const validationVisibilityOptions = [
39
+ { label: "Blur", value: "blur" },
40
+ { label: "Live", value: "live" },
41
+ { label: "Dirty", value: "dirty" },
42
+ { label: "Submit", value: "submit" }
43
+ ];
44
+ function editorSchema(typeOptionsOverride = fieldTypeOptions) {
45
+ return [
46
+ {
47
+ $formkit: "nuxtUISelectMenu",
48
+ // `$get()` addresses nodes by `id`, not `name` - this has to match
49
+ // `dollarFormkitId`, the identifier `ifGet`/`ifAnyType`/`ifNoneType`
50
+ // use below. `name` stays the fixed `'_dollar_formkit'` string -
51
+ // that's the form-data key consumers (`useFormKitEditor`, the
52
+ // Form Builder/Input Editor pages) read, and unlike `id` it isn't
53
+ // addressed through FormKit's cross-instance global registry, so it
54
+ // doesn't need to be unique.
55
+ // Disabled rather than hidden (`if: false`) when type-switching is
56
+ // turned off - hiding would unmount this node entirely, and every
57
+ // other `$get(dollarFormkitId)` comparison below (legend vs label,
58
+ // the Options tab's capability check) would then find nothing and
59
+ // always evaluate false.
60
+ id: dollarFormkitId,
61
+ name: "_dollar_formkit",
62
+ disabled: !isChangeTypePossible,
63
+ label: "Field Type",
64
+ value: "nuxtUIInput",
65
+ // Without `valueKey`, nuxtUISelectMenu's model value is the whole
66
+ // `{ label, value }` option object rather than just its `value` -
67
+ // every `$get(_dollar_formkit).value === '...'` comparison below
68
+ // would silently compare an object to a string and always be false.
69
+ valueKey: "value",
70
+ options: typeOptionsOverride,
71
+ key: "schema_inputSelection",
72
+ preserve: true
73
+ },
74
+ {
75
+ $formkit: "nuxtUIInput",
76
+ name: "name",
77
+ label: "Field Name",
78
+ validation: "required",
79
+ validationVisibility: "live",
80
+ key: "schema_name",
81
+ preserve: true
82
+ },
83
+ {
84
+ $formkit: "nuxtUIRadioGroup",
85
+ // See the `dollarFormkitId` comment above - same reasoning, `id`
86
+ // needs to be globally unique per mount, `name` doesn't.
87
+ id: sectionId,
88
+ name: "section",
89
+ legend: "Properties",
90
+ options: sectionOptions,
91
+ orientation: "horizontal",
92
+ // Nuxt UI's horizontal RadioGroup fieldset is `flex flex-row` with no
93
+ // wrap by default - in the narrow Properties panel that overflows
94
+ // instead of dropping "Attributes" etc. to a second line.
95
+ ui: { fieldset: "flex-wrap" },
96
+ value: "base",
97
+ key: "schema_section",
98
+ preserve: true
99
+ },
100
+ // --- Base -----------------------------------------------------------
101
+ {
102
+ $formkit: "nuxtUIInput",
103
+ if: `${ifSection("base")} && ${notLegendTypeIf}`,
104
+ name: "label",
105
+ label: "Field Label",
106
+ key: "schema_label",
107
+ preserve: true
108
+ },
109
+ {
110
+ $formkit: "nuxtUIInput",
111
+ if: `${ifSection("base")} && ${legendTypeIf}`,
112
+ name: "legend",
113
+ label: "Field Legend",
114
+ key: "schema_legend",
115
+ preserve: true
116
+ },
117
+ {
118
+ $formkit: "nuxtUIInput",
119
+ if: ifSection("base"),
120
+ name: "help",
121
+ label: "Help Text",
122
+ key: "schema_help",
123
+ preserve: true
124
+ },
125
+ {
126
+ $formkit: "nuxtUIInput",
127
+ if: ifSection("base"),
128
+ name: "value",
129
+ label: "Default Value",
130
+ key: "schema_value",
131
+ preserve: true
132
+ },
133
+ {
134
+ $formkit: "nuxtUIInput",
135
+ if: ifSection("base"),
136
+ name: "id",
137
+ label: "Field ID",
138
+ key: "schema_id",
139
+ preserve: true
140
+ },
141
+ {
142
+ $formkit: "nuxtUIInput",
143
+ if: ifSection("base"),
144
+ name: "key",
145
+ label: "Schema Key",
146
+ help: "Forces FormKit to re-render this node when the key changes.",
147
+ key: "schema_key",
148
+ preserve: true
149
+ },
150
+ {
151
+ $formkit: "nuxtUICheckbox",
152
+ if: ifSection("base"),
153
+ name: "preserve",
154
+ label: "Preserve value when hidden",
155
+ key: "schema_preserve",
156
+ value: false,
157
+ preserve: true
158
+ },
159
+ // --- Display ----------------------------------------------------------
160
+ {
161
+ $formkit: "nuxtUIInput",
162
+ if: ifSection("display"),
163
+ name: "class",
164
+ label: "CSS Class",
165
+ key: "schema_class",
166
+ preserve: true
167
+ },
168
+ {
169
+ $formkit: "nuxtUIInput",
170
+ if: ifSection("display"),
171
+ name: "if",
172
+ label: "Render Condition (if-expression)",
173
+ help: "e.g. $get(otherField).value === true",
174
+ key: "schema_if",
175
+ preserve: true
176
+ },
177
+ {
178
+ $formkit: "nuxtUICheckbox",
179
+ if: ifSection("display"),
180
+ name: "disabled",
181
+ label: "Disabled",
182
+ key: "schema_disabled",
183
+ value: false,
184
+ preserve: true
185
+ },
186
+ {
187
+ $formkit: "nuxtUICheckbox",
188
+ if: ifSection("display"),
189
+ name: "readonly",
190
+ label: "Read Only",
191
+ key: "schema_readonly",
192
+ value: false,
193
+ preserve: true
194
+ },
195
+ // --- Style ------------------------------------------------------------
196
+ {
197
+ $formkit: "nuxtUIInput",
198
+ if: ifSection("style"),
199
+ name: "outerClass",
200
+ label: "Outer Class",
201
+ key: "schema_outerClass",
202
+ preserve: true
203
+ },
204
+ {
205
+ $formkit: "nuxtUIInput",
206
+ if: ifSection("style"),
207
+ name: "wrapperClass",
208
+ label: "Wrapper Class",
209
+ key: "schema_wrapperClass",
210
+ preserve: true
211
+ },
212
+ {
213
+ $formkit: "nuxtUIInput",
214
+ if: ifSection("style"),
215
+ name: "innerClass",
216
+ label: "Inner Class",
217
+ key: "schema_innerClass",
218
+ preserve: true
219
+ },
220
+ // --- Validation ---------------------------------------------------------
221
+ {
222
+ $formkit: "nuxtUIInput",
223
+ if: ifSection("validation"),
224
+ name: "validation",
225
+ label: "Validation Rules",
226
+ help: "e.g. required|email",
227
+ key: "schema_validation",
228
+ preserve: true
229
+ },
230
+ {
231
+ $formkit: "nuxtUISelect",
232
+ if: ifSection("validation"),
233
+ name: "validationVisibility",
234
+ label: "Validation Visibility",
235
+ options: validationVisibilityOptions,
236
+ key: "schema_validationVisibility",
237
+ preserve: true
238
+ },
239
+ {
240
+ $formkit: "nuxtUIInput",
241
+ if: ifSection("validation"),
242
+ name: "validationLabel",
243
+ label: "Validation Label",
244
+ key: "schema_validationLabel",
245
+ preserve: true
246
+ },
247
+ // --- Options (only for field types with an options/items list) --------
248
+ // `listClass`/`listItemClass` match the flex row layout from the
249
+ // Repeater sample (pages/form/repeater-sample.vue); `draggable` +
250
+ // `displayDragHandle` add drag-and-drop reordering the way the
251
+ // Drag-and-Drop Repeater sample (pages/form/repeater-drag.vue) does -
252
+ // `hideMoveButtons` follows that same sample's convention of hiding the
253
+ // up/down buttons once dragging covers reordering.
254
+ addElement("p", "The selected field type does not use an options list.", { class: "text-muted text-sm" }, `${ifSection("options")} && ${notOptionsCapableIf}`),
255
+ {
256
+ $formkit: "nuxtUIRepeater",
257
+ if: `${ifSection("options")} && ${optionsCapableIf}`,
258
+ name: "options",
259
+ label: "Options",
260
+ help: "Shown to the user as label, submitted as value.",
261
+ listClass: "grid gap-2",
262
+ listItemClass: "flex items-start gap-2",
263
+ insertButtonLabel: "Add Option",
264
+ alwaysDisplayInsertButton: true,
265
+ displayDeleteButton: true,
266
+ draggable: true,
267
+ displayDragHandle: true,
268
+ // Each row's children render with their own label above their input
269
+ // (like every other field), but the drag handle and delete button
270
+ // don't have one - `items-start` alone lines them up with the
271
+ // *labels*, not the inputs below. `mt-6` nudges both down to roughly
272
+ // where the inputs start instead.
273
+ dragHandleClass: "mt-6 cursor-grab active:cursor-grabbing text-muted",
274
+ buttonGroupClass: "mt-6 shrink-0",
275
+ hideMoveButtons: true,
276
+ newItem: { label: "", value: "" },
277
+ key: "schema_options",
278
+ preserve: true,
279
+ children: [
280
+ {
281
+ $formkit: "nuxtUIInput",
282
+ label: "Label",
283
+ name: "label",
284
+ outerClass: "w-48"
285
+ },
286
+ {
287
+ $formkit: "nuxtUIInput",
288
+ label: "Value",
289
+ name: "value",
290
+ outerClass: "w-48"
291
+ }
292
+ ]
293
+ },
294
+ // --- Attributes (escape hatch for anything not covered above) ---------
295
+ {
296
+ $formkit: "nuxtUIRepeater",
297
+ if: ifSection("attrs"),
298
+ name: "attrs",
299
+ label: "Extra Properties",
300
+ help: "Any additional schema property this field type supports (e.g. rows, min, max, icon).",
301
+ listClass: "grid gap-2",
302
+ listItemClass: "flex items-start gap-2",
303
+ insertButtonLabel: "Add Property",
304
+ alwaysDisplayInsertButton: true,
305
+ displayDeleteButton: true,
306
+ draggable: true,
307
+ displayDragHandle: true,
308
+ // Each row's children render with their own label above their input
309
+ // (like every other field), but the drag handle and delete button
310
+ // don't have one - `items-start` alone lines them up with the
311
+ // *labels*, not the inputs below. `mt-6` nudges both down to roughly
312
+ // where the inputs start instead.
313
+ dragHandleClass: "mt-6 cursor-grab active:cursor-grabbing text-muted",
314
+ buttonGroupClass: "mt-6 shrink-0",
315
+ hideMoveButtons: true,
316
+ newItem: { attrKey: "", attrValue: "" },
317
+ key: "schema_attrs",
318
+ preserve: true,
319
+ children: [
320
+ {
321
+ $formkit: "nuxtUIInput",
322
+ label: "Property",
323
+ name: "attrKey",
324
+ outerClass: "w-48"
325
+ },
326
+ {
327
+ $formkit: "nuxtUIInput",
328
+ label: "Value",
329
+ name: "attrValue",
330
+ outerClass: "w-48"
331
+ }
332
+ ]
333
+ }
334
+ ];
335
+ }
336
+ return { editorSchema, fieldTypeOptions, typeOptions };
337
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sfxcode/nuxt-ui-formkit",
3
- "version": "1.2.12",
3
+ "version": "1.3.2",
4
4
  "description": "FormKit integration for Nuxt UI - Seamlessly connect FormKit form handling with Nuxt UI components",
5
5
  "author": {
6
6
  "name": "Tom",
@@ -90,43 +90,43 @@
90
90
  "dependencies": {
91
91
  "@formkit/addons": "^2.1.2",
92
92
  "@formkit/nuxt": "^2.1.2",
93
- "@nuxt/ui": "^4.10.0",
93
+ "@nuxt/ui": "^4.11.0",
94
94
  "@standard-schema/spec": "^1.1.0",
95
- "@vue/compiler-dom": "^3.5.41"
95
+ "@vue/compiler-dom": "^3.5.42"
96
96
  },
97
97
  "devDependencies": {
98
98
  "@codemirror/lang-json": "^6.0.2",
99
- "@codemirror/state": "^6.7.1",
99
+ "@codemirror/state": "^6.7.2",
100
100
  "@codemirror/theme-one-dark": "^6.1.3",
101
- "@codemirror/view": "^6.43.8",
101
+ "@codemirror/view": "^6.43.10",
102
102
  "@iconify-json/heroicons": "^1.2.3",
103
- "@iconify-json/lucide": "^1.2.123",
104
- "@iconify-json/simple-icons": "^1.2.93",
105
- "@nuxt/devtools": "4.0.0-alpha.9",
103
+ "@iconify-json/lucide": "^1.2.129",
104
+ "@iconify-json/simple-icons": "^1.2.94",
105
+ "@nuxt/devtools": "4.0.0-alpha.16",
106
106
  "@nuxt/eslint-config": "^1.17.0",
107
107
  "@nuxt/kit": "^4.5.2",
108
108
  "@nuxt/module-builder": "^1.0.3",
109
109
  "@nuxt/schema": "^4.5.2",
110
- "@nuxt/test-utils": "^4.1.0",
110
+ "@nuxt/test-utils": "^4.2.0",
111
111
  "@types/node": "latest",
112
112
  "@vitejs/plugin-vue": "^6.0.8",
113
- "@vue/test-utils": "^2.4.11",
113
+ "@vue/test-utils": "^2.5.0",
114
114
  "changelogen": "^0.6.2",
115
115
  "codemirror": "^6.0.2",
116
- "eslint": "^10.8.1",
116
+ "eslint": "^10.9.1",
117
117
  "jsdom": "^30.0.1",
118
118
  "mkdist": "^2.4.1",
119
119
  "nuxt": "^4.5.2",
120
- "sass-embedded": "^1.100.0",
120
+ "sass-embedded": "^1.103.1",
121
121
  "typescript": "~6.0.3",
122
122
  "unbuild": "^3.6.1",
123
123
  "valibot": "^1.4.2",
124
124
  "vitepress": "2.0.0-alpha.17",
125
- "vitest": "^4.1.10",
126
- "vue": "^3.5.41",
127
- "vue-i18n": "^11.4.8",
128
- "vue-tsc": "^3.3.9",
129
- "zod": "^4.4.3"
125
+ "vitest": "^4.1.11",
126
+ "vue": "^3.5.42",
127
+ "vue-i18n": "^11.4.10",
128
+ "vue-tsc": "^3.3.11",
129
+ "zod": "^4.5.4"
130
130
  },
131
131
  "packageManager": "pnpm@11.17.0+sha512.cca3cea332ad254bb84145f966d19f4879615210346fc92c79a047f23a0d7b3cca3c3792f0076ba1f1831d277efbcf0a9119b31a9a60eca7fb3d6231f331ef72"
132
132
  }