@whatsaaaa/form-builder-vue 0.2.0 → 0.3.1

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/README.md CHANGED
@@ -1,20 +1,26 @@
1
1
  # @whatsaaaa/form-builder-vue
2
2
 
3
- [![npm](https://img.shields.io/npm/v/@whatsaaaa/form-builder-vue)](https://www.npmjs.com/package/@whatsaaaa/form-builder-vue)
4
-
5
3
  Render JSON form definitions with [Formisch](https://formisch.dev) and your own Vue components.
6
4
 
7
- It's headless: it reads the definition, connects every field to Formisch and turns input into the values the schema expects, but it renders nothing of its own. You give it a component per field type, so it works with plain HTML, Nuxt UI or any other UI library.
5
+ [![npm version](https://img.shields.io/npm/v/@whatsaaaa/form-builder-vue)](https://www.npmjs.com/package/@whatsaaaa/form-builder-vue)
6
+ [![npm downloads](https://img.shields.io/npm/dm/@whatsaaaa/form-builder-vue)](https://www.npmjs.com/package/@whatsaaaa/form-builder-vue)
7
+ [![CI](https://img.shields.io/github/actions/workflow/status/whatsaaaa/form-builder/ci.yml?branch=main&label=CI)](https://github.com/whatsaaaa/form-builder/actions/workflows/ci.yml)
8
+ [![Coverage](https://codecov.io/gh/whatsaaaa/form-builder/graph/badge.svg?flag=vue)](https://codecov.io/gh/whatsaaaa/form-builder)
9
+ [![Vue](https://img.shields.io/npm/dependency-version/@whatsaaaa/form-builder-vue/peer/vue?logo=vuedotjs)](https://vuejs.org)
10
+ [![Types](https://img.shields.io/npm/types/@whatsaaaa/form-builder-vue)](https://www.npmjs.com/package/@whatsaaaa/form-builder-vue)
11
+ [![License](https://img.shields.io/npm/l/@whatsaaaa/form-builder-vue)](https://github.com/whatsaaaa/form-builder/blob/main/LICENSE)
12
+
13
+ This is the Vue adapter of [form-builder](https://github.com/whatsaaaa/form-builder). It is headless: it reads the definition, connects every field to Formisch and turns input into the values the schema expects, but renders nothing of its own. You give it a component per field type, so it works with plain HTML, Nuxt UI or any other UI library.
8
14
 
9
15
  ## Install
10
16
 
11
17
  ```sh
12
- pnpm add @whatsaaaa/form-builder-vue @formisch/vue valibot
18
+ pnpm add @whatsaaaa/form-builder-vue @whatsaaaa/form-builder-schema @formisch/vue valibot
13
19
  ```
14
20
 
15
- Vue 3.5, `@formisch/vue` 1.1 and Valibot 1.3 or later are required. `@whatsaaaa/form-builder-schema` comes with it.
21
+ Vue 3.5, `@formisch/vue` 1.1 and Valibot 1.3 or later are required. Install `@whatsaaaa/form-builder-schema` too: the examples import its types, such as `JsonForm`.
16
22
 
17
- ## Usage
23
+ ## Example
18
24
 
19
25
  ```vue
20
26
  <script setup lang="ts">
@@ -40,58 +46,7 @@ function save(output: unknown) {
40
46
  </template>
41
47
  ```
42
48
 
43
- - `useJsonForm(definition, options?)` builds the schema and the initial input, and creates the Formisch form. `jsonForm.form` is a normal Formisch form, so every Formisch method works on it.
44
- - `<JsonFields>` renders the fields inside your `<Form>`. The form element, the submit button and anything around them are yours.
45
- - A definition with issues throws the builder's `DefinitionError`. Run `validate()` first when the definition comes from outside your code.
46
- - The definition is read once. To show another one, give the component that calls `useJsonForm` a new `:key`.
47
-
48
- ### Options
49
-
50
- ```ts
51
- useJsonForm(definition, {
52
- builder: createSchemaBuilder({ fieldTypes: { money } }), // your own types, rules and messages
53
- components, // your component per field type, see below
54
- layoutComponents, // your component per layout type, see Layout
55
- validate: 'blur', // when a field is validated the first time, as in Formisch
56
- revalidate: 'input', // when it is validated again
57
- })
58
- ```
59
-
60
- ## Components
61
-
62
- `components` has one component per field type, by type name. Pass it to `useJsonForm`, or to `<JsonFields>` and `<JsonField>` as a prop, which wins. Several types can share one:
63
-
64
- ```ts
65
- import type { FieldComponents } from '@whatsaaaa/form-builder-vue'
66
-
67
- export const components: FieldComponents = {
68
- text: TextInput,
69
- email: TextInput,
70
- number: TextInput,
71
- select: SelectInput,
72
- group: Fieldset,
73
- array: Repeater,
74
- heading: Heading,
75
- // …one for every type your definitions use
76
- }
77
- ```
78
-
79
- A type that a definition uses but `components` doesn't have throws a `TypeError` that names every missing type, when `<JsonFields>` or `<JsonField>` sets up. Only the fields it renders count.
80
-
81
- What a component gets depends on the field's role:
82
-
83
- | Role | Which fields | Props | Slot |
84
- | ------- | ------------------------------ | -------------------------------------------------------------------------------- | -------------------------------------------- |
85
- | value | every field with a value | `field`, `path`, `kind`, `required`, `input`, `errors`, `inputProps`, `setInput` | — |
86
- | group | a container of kind `object` | `field`, `path` | default: the group's fields |
87
- | array | a container of kind `array` | `field`, `path`, `items`, `errors`, `add`, `remove`, `move` | default, with `{ index }`: one item's fields |
88
- | display | a display element, kind `none` | `field` | — |
89
-
90
- The props are typed as `ValueFieldProps`, `GroupFieldProps`, `ArrayFieldProps` and `DisplayFieldProps`, and the slots as `GroupFieldSlots` and `ArrayFieldSlots`. `defineProps<ValueFieldProps>()` works in `<script setup>`.
91
-
92
- Your own container types render through the group or array role too, by their kind.
93
-
94
- ### A value field
49
+ `components` maps each field type to a component of yours. A text input looks like this:
95
50
 
96
51
  ```vue
97
52
  <script setup lang="ts">
@@ -115,256 +70,28 @@ defineProps<ValueFieldProps>()
115
70
  </template>
116
71
  ```
117
72
 
118
- - `field` is the field from the definition, with its `label`, `placeholder`, `options` and `ui`.
119
- - `path` is its Formisch path with real indexes, like `['lines', 0, 'quantity']`.
120
- - `inputProps` are Formisch's element props: the field's name, a ref, and focus, change and blur handlers. Bind them to the input element, so Formisch knows when the field is touched and can focus it after a failed submit.
121
- - `required` is true when the definition makes the field required.
122
-
123
- ### setInput
124
-
125
- `setInput` sets the field's input after turning what an input element gives into what the schema expects, by the field's kind:
126
-
127
- | Kind | Input | Value set |
128
- | ------------------- | ----------------------- | ------------------------------ |
129
- | `number` | `''` or only spaces | `undefined` |
130
- | `number` | a numeric string, `'5'` | `5` |
131
- | `file` | a `FileList` | its first file, or `undefined` |
132
- | `array` of `file` | a `FileList` | an array of its files |
133
- | `array` of `number` | numeric strings | numbers |
134
-
135
- Anything else is set as it is, and the schema reports it. For a choice, like a radio or a select, set the option's value from `field.options` rather than the element's value: that keeps `2` a number and `true` a boolean.
136
-
137
- ### A group
138
-
139
- ```vue
140
- <script setup lang="ts">
141
- import type { GroupFieldProps, GroupFieldSlots } from '@whatsaaaa/form-builder-vue'
142
-
143
- defineProps<GroupFieldProps>()
144
- defineSlots<GroupFieldSlots>()
145
- </script>
146
-
147
- <template>
148
- <fieldset>
149
- <legend>{{ field.label }}</legend>
150
- <slot />
151
- </fieldset>
152
- </template>
153
- ```
154
-
155
- ### An array
73
+ `jsonForm.form` is a normal Formisch form, so every Formisch method works on it.
156
74
 
157
- ```vue
158
- <script setup lang="ts">
159
- import type { ArrayFieldProps, ArrayFieldSlots } from '@whatsaaaa/form-builder-vue'
75
+ ## Highlights
160
76
 
161
- defineProps<ArrayFieldProps>()
162
- defineSlots<ArrayFieldSlots>()
163
- </script>
77
+ - Headless: one component of yours per field type, and per layout type
78
+ - `setInput` turns what an element gives into the value the schema expects
79
+ - Groups, arrays and display elements, with stable keys for array items
80
+ - Sections, 12-column rows, slots and multi-step forms from the definition's layout
81
+ - Steps that validate on Next and only show errors the user has seen
82
+ - Conditions from the affects package, with hidden steps skipped by Next and Back
83
+ - Fields placed in your own markup with `<JsonField>`, `only` and `except`
164
84
 
165
- <template>
166
- <fieldset>
167
- <legend>{{ field.label }}</legend>
168
- <div v-for="(item, index) in items" :key="item">
169
- <slot :index="index" />
170
- <button type="button" @click="remove(index)">Remove</button>
171
- </div>
172
- <button type="button" @click="add()">Add</button>
173
- <small v-if="errors">{{ errors[0] }}</small>
174
- </fieldset>
175
- </template>
176
- ```
85
+ ## Documentation
177
86
 
178
- - `items` has one id per item. Use it as the `key`, so each item keeps its inputs when one is removed or moved.
179
- - `add()` adds an item at the end, with the defaults its fields have in the definition.
180
- - `errors` are the array's own messages, like a required array's or `maxLength`'s. Its items' fields show their own.
87
+ The [guide](https://github.com/whatsaaaa/form-builder/blob/main/frameworks/vue/docs/guide.md) covers options, components for every role, layout, steps, conditions, placing fields yourself and typing the form.
181
88
 
182
- ### A display element
183
-
184
- ```vue
185
- <script setup lang="ts">
186
- import type { DisplayFieldProps } from '@whatsaaaa/form-builder-vue'
187
-
188
- defineProps<DisplayFieldProps>()
189
- </script>
190
-
191
- <template>
192
- <h2>{{ field.text }}</h2>
193
- </template>
194
- ```
195
-
196
- Declare the props even when a component doesn't use them, like a divider, or Vue adds `field` to its element as an attribute.
197
-
198
- ## Layout
199
-
200
- A definition's [`layout`](https://github.com/whatsaaaa/form-builder/tree/main/packages/schema#layout) puts its fields in sections, rows of a 12-column grid and steps, and leaves slots for content of yours. `<JsonFields>` renders the current step of it. Give `useJsonForm` a component for each layout type the definition uses, and `<JsonFields>` a named slot for each of its slots:
201
-
202
- ```vue
203
- <!-- Row.vue: one line of a 12-column grid. On a narrow screen, give each cell the whole row. -->
204
- <script setup lang="ts">
205
- import type { RowProps, RowSlots } from '@whatsaaaa/form-builder-vue'
206
-
207
- defineProps<RowProps>()
208
- defineSlots<RowSlots>()
209
- </script>
210
-
211
- <template>
212
- <div class="row">
213
- <div v-for="(span, index) in spans" :key="index" :style="{ gridColumn: `span ${span}` }">
214
- <slot :index="index" />
215
- </div>
216
- </div>
217
- </template>
218
-
219
- <style scoped>
220
- .row {
221
- display: grid;
222
- grid-template-columns: repeat(12, 1fr);
223
- gap: 1rem;
224
- }
225
- </style>
226
- ```
227
-
228
- ```vue
229
- <!-- Section.vue -->
230
- <script setup lang="ts">
231
- import type { SectionProps, SectionSlots } from '@whatsaaaa/form-builder-vue'
232
-
233
- defineProps<SectionProps>()
234
- defineSlots<SectionSlots>()
235
- </script>
236
-
237
- <template>
238
- <fieldset>
239
- <legend>{{ section.label }}</legend>
240
- <slot />
241
- </fieldset>
242
- </template>
243
- ```
244
-
245
- ```vue
246
- <script setup lang="ts">
247
- const jsonForm = useJsonForm(definition, {
248
- components,
249
- layoutComponents: { section: Section, row: Row },
250
- })
251
- </script>
252
-
253
- <template>
254
- <Form :of="jsonForm.form" @submit="save">
255
- <JsonFields :of="jsonForm">
256
- <template #submit><button type="submit">Place order</button></template>
257
- </JsonFields>
258
- </Form>
259
- </template>
260
- ```
261
-
262
- | Layout type | Props | Slot |
263
- | ----------- | ------------------------------------------------------------------------- | ---------------------------------------------- |
264
- | `section` | `section`, as written, with its `id`, `label`, `description` and `ui` | default: the section's items |
265
- | `row` | `row`, as written, with its `id` and `ui`; `spans`, the span of each cell | default, with `{ index }`: the cell at `index` |
266
-
267
- The props are typed as `SectionProps` and `RowProps`, and the slots as `SectionSlots` and `RowSlots`.
268
-
269
- - `layoutComponents` goes to `useJsonForm`, or to `<JsonFields>` as a prop, which wins. A definition without sections or rows needs none, and one without a `layout` renders as it always did.
270
- - A layout type the layout uses without a component, or a slot without content, throws a `TypeError` naming each one when `<JsonFields>` sets up, on every step.
271
- - Display elements written in the layout render with your field components, like the ones in `fields`.
272
- - `except` leaves fields out of the layout too, and a section or a row left without fields drops out. The other cells of a row keep their spans. `only` renders the fields it names without the layout.
273
- - The spans are for a wide screen: the layout says nothing about narrow ones, so your row component decides, e.g. with a media query.
274
-
275
- ### Steps
276
-
277
- `jsonForm.steps` is where the form is, and how to move. It is reactive, so templates follow it:
278
-
279
- ```vue
280
- <template>
281
- <Form :of="jsonForm.form" @submit="save">
282
- <ol>
283
- <li
284
- v-for="(step, i) in jsonForm.steps.list"
285
- :key="step.step.id ?? i"
286
- :aria-current="i === jsonForm.steps.index ? 'step' : undefined"
287
- >
288
- {{ step.step.label }}
289
- </li>
290
- </ol>
291
- <JsonFields :of="jsonForm" />
292
- <button v-if="!jsonForm.steps.isFirst" type="button" @click="jsonForm.steps.back()">
293
- Back
294
- </button>
295
- <button v-if="!jsonForm.steps.isLast" type="button" @click="jsonForm.steps.next()">Next</button>
296
- <button v-else type="submit">Sign up</button>
297
- </Form>
298
- </template>
299
- ```
300
-
301
- | Member | |
302
- | ------------------- | ---------------------------------------------------------------------------------------------------- |
303
- | `list` | every step, with its `step` as written (`id`, `label`, `description`, `ui`), `children` and `fields` |
304
- | `index`, `current` | the step `<JsonFields>` renders |
305
- | `isFirst`, `isLast` | |
306
- | `next()` | validates, and moves on when the step's fields have no issues. Resolves to whether it moved |
307
- | `back()` | moves back, without validating |
308
- | `goTo(index)` | back freely; forward through each step on the way, stopping at the first with issues |
309
-
310
- The form is one Formisch form, so Formisch validates all of it at once. The steps make that work:
311
-
312
- - **Next** validates the whole form, and only the issues on the current step's fields keep the user there. It focuses the first one, in layout order.
313
- - **A step shows what the user left**: the errors it had when they left it, and none the first time they get to it, so the issues of steps nobody saw yet stay out of sight.
314
- - **A step that failed Next revalidates** as the user fixes it, on the `revalidate` event, like a form after a failed submit.
315
- - **A submit before the last step is a Next**, so Enter in a step with a single text input doesn't submit the form early. On the last step, Formisch submits as usual.
316
- - **A submit that fails because of an earlier step**, like a form rule that reads fields of two steps, goes back to that step.
317
- - `<JsonFields :step="2" />` renders a given step instead of the current one, e.g. on a review page. A form without steps has one, and nothing changes for it.
318
-
319
- ## Placing fields yourself
320
-
321
- Without a `layout`, `<JsonFields>` renders every field in the order of the definition. To put some of them somewhere else, in code rather than in the definition, place them with `<JsonField>` and leave them out of `<JsonFields>` with `except`:
322
-
323
- ```vue
324
- <template>
325
- <Form :of="jsonForm.form" @submit="save">
326
- <main>
327
- <JsonFields :of="jsonForm" :except="['coupon', 'acceptTerms']" />
328
- </main>
329
- <aside>
330
- <JsonField :of="jsonForm" path="coupon" />
331
- <JsonField :of="jsonForm" path="acceptTerms" />
332
- <button type="submit">Place order</button>
333
- </aside>
334
- </Form>
335
- </template>
336
- ```
337
-
338
- - A path is the field's names joined with dots: `'email'`, or `'address.city'` for a field of a group. A placed field validates, focuses and submits like any other, because it is still part of the one Formisch form.
339
- - A group or an array comes with all its fields. A field of an array's items can't be placed on its own, because it has no index outside its item, so place the array. To leave such a field out of every item, use `'*'` for the index: `except: ['lines.*.note']`.
340
- - `only` renders just the fields it names, in the order of the definition: `<JsonFields :of="jsonForm" :only="['name', 'email']" />`. Display elements have no dot path, even with a name, so `only` leaves them out.
341
- - A path that names no field throws a `TypeError`, so a typo shows up at once. `only` and `except` are read when the component sets up.
342
-
343
- ## Typing the form
344
-
345
- The definition is data, so TypeScript doesn't know its fields, and `jsonForm.form` is typed loosely: Formisch's own functions accept only top-level paths on it. Give `useJsonForm` your input type, and your output type when it differs, and they check paths and values as in any Formisch form:
346
-
347
- ```ts
348
- import { getInput, useFieldArray } from '@formisch/vue'
349
-
350
- interface CheckoutInput {
351
- name: string
352
- address: { city: string }
353
- lines: { product: string; quantity: number }[]
354
- }
355
-
356
- const jsonForm = useJsonForm<CheckoutInput>(definition, { components })
357
-
358
- getInput(jsonForm.form, { path: ['address', 'city'] }) // string | undefined
359
- useFieldArray(jsonForm.form, { path: ['lines'] })
360
- ```
89
+ ## Related packages
361
90
 
362
- - Formisch's `<Field>`, `<FieldArray>`, `useField`, `getInput` and `setInput` work on `jsonForm.form` either way. With a type, nested paths type-check, their values are typed, and so is the output your submit handler gets.
363
- - The type is a promise you make: nothing checks it against the definition. Keep the two in step.
364
- - A field you render with Formisch's `<Field>` gets none of the adapter's help, like `setInput` turning `'5'` into `5`, or the defaults of a new array item. Leave it out of `<JsonFields>` with `except`.
91
+ - [`@whatsaaaa/form-builder-schema`](https://github.com/whatsaaaa/form-builder/tree/main/packages/schema): build Formisch-ready Valibot schemas from JSON definitions
92
+ - [`@whatsaaaa/form-builder-affects`](https://github.com/whatsaaaa/form-builder/tree/main/packages/affects): show, hide and clear fields by conditions
93
+ - [`@whatsaaaa/form-builder-react`](https://github.com/whatsaaaa/form-builder/tree/main/frameworks/react): the same adapter for React
365
94
 
366
- ## Not included
95
+ ## License
367
96
 
368
- - Labels and display text reach your components as written in the definition. The builder's `resolveMessage` only changes what goes into the schema, so translate `field.label` in your components.
369
- - `ui.widget` doesn't pick a component. A component can read `field.ui` itself, e.g. to show a multiselect as checkboxes.
370
- - Showing and hiding fields, or making one required because of another, belongs to a future affects package. The layout already hides a section, a row or a step whose fields are all hidden, through `shownNodes` in the schema package.
97
+ [MIT](https://github.com/whatsaaaa/form-builder/blob/main/LICENSE)
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { FieldNode, FieldNode as FieldNode$1, FieldPath, FieldPath as FieldPath$1, FieldRole, FormLayout, FormLayout as FormLayout$1, JsonField as JsonField$1, JsonForm, JsonFormSchema, JsonFormSchema as JsonFormSchema$1, JsonLayoutRow, JsonLayoutSection, LayoutNode, LayoutStep, LayoutStep as LayoutStep$1, SchemaBuilder, TypedJsonFormSchema, TypedJsonFormSchema as TypedJsonFormSchema$1, ValueKind } from "@whatsaaaa/form-builder-schema";
1
+ import { FieldNode, FieldNode as FieldNode$1, FieldPath, FieldPath as FieldPath$1, FieldRole, FormLayout, FormLayout as FormLayout$1, JsonField as JsonField$1, JsonForm, JsonFormSchema, JsonFormSchema as JsonFormSchema$1, JsonLayoutRow, JsonLayoutSection, LayoutNode, LayoutStep, LayoutStep as LayoutStep$1, SchemaBuilder, TypedJsonFormSchema, TypedJsonFormSchema as TypedJsonFormSchema$1, ValueKind, VisibilityState, VisibilityState as VisibilityState$1 } from "@whatsaaaa/form-builder-schema";
2
2
  import { Component, PropType, VNode } from "vue";
3
3
  import { FieldElementProps, FormSchema, FormStore, ValidationMode } from "@formisch/vue";
4
4
  /** Your component for each field type, by type name: `{ text: TextInput, group: Fieldset }`. */
@@ -84,7 +84,10 @@ interface RowSlots {
84
84
  }
85
85
  /** The steps of a form, from its layout. A form without `steps` in its layout has one. */
86
86
  interface JsonFormSteps {
87
- /** Every step, in order. */
87
+ /**
88
+ * The steps on show, in order. A step whose fields are all hidden by conditions, or that is
89
+ * hidden itself, is left out, unless it is the current one: Next and Back skip it.
90
+ */
88
91
  readonly list: readonly LayoutStep$1[];
89
92
  /** The index of the current step in `list`. */
90
93
  readonly index: number;
@@ -134,6 +137,12 @@ interface JsonFormInstance<TSchema extends FormSchema = JsonFormSchema$1> {
134
137
  readonly layout: FormLayout$1;
135
138
  /** The layout's steps: the current one, and Next, Back and Go to. A form without steps has one. */
136
139
  readonly steps: JsonFormSteps;
140
+ /**
141
+ * What the conditions of the builder's extensions hide for the form's input now, like the
142
+ * `affects` of `@whatsaaaa/form-builder-affects`: `<JsonFields>` and `<JsonField>` leave it out.
143
+ * Read it in your own renderers. Without conditions, it hides nothing.
144
+ */
145
+ readonly visibility: VisibilityState$1;
137
146
  }
138
147
  /** Any form `useJsonForm` returns, typed or not: what the components take. */
139
148
  type AnyJsonFormInstance = JsonFormInstance<FormSchema>;
@@ -141,7 +150,8 @@ type AnyJsonFormInstance = JsonFormInstance<FormSchema>;
141
150
  * A Formisch form for a definition, with its schema and initial input from the builder. A
142
151
  * definition with issues throws the builder's `DefinitionError`, so run `validate()` first when it
143
152
  * comes from outside your code. The definition is read once: give the form a new `:key` to use
144
- * another one.
153
+ * another one. With conditions, it clears the fields they clear as soon as they do, with
154
+ * Formisch's `setInput`, wherever the fields are rendered.
145
155
  */
146
156
  export declare function useJsonForm(definition: JsonForm, options?: UseJsonFormOptions): JsonFormInstance;
147
157
  /**
@@ -152,6 +162,7 @@ export declare function useJsonForm<TInput extends object, TOutput extends objec
152
162
  /**
153
163
  * Renders one field of a `useJsonForm` form, wherever you put it inside Formisch's `<Form>`. A
154
164
  * group or an array comes with its fields. Leave the field out of `<JsonFields>` with `except`.
165
+ * It renders nothing while conditions hide the field.
155
166
  */
156
167
  export declare const JsonField: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
157
168
  /** What `useJsonForm` returned. */
@@ -170,7 +181,7 @@ export declare const JsonField: import("vue").DefineComponent<import("vue").Extr
170
181
  };
171
182
  }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
172
183
  [key: string]: any;
173
- }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
184
+ }> | null, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
174
185
  /** What `useJsonForm` returned. */
175
186
  of: {
176
187
  type: PropType<AnyJsonFormInstance>;
@@ -255,5 +266,5 @@ export declare const JsonFields: import("vue").DefineComponent<import("vue").Ext
255
266
  type: NumberConstructor;
256
267
  };
257
268
  }>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
258
- export type { AnyJsonFormInstance, ArrayFieldProps, ArrayFieldSlots, DisplayFieldProps, FieldComponents, FieldNode, FieldPath, FieldRole, FormLayout, GroupFieldProps, GroupFieldSlots, JsonFormInstance, JsonFormSchema, JsonFormSteps, LayoutComponents, LayoutNode, LayoutStep, RowProps, RowSlots, SectionProps, SectionSlots, TypedJsonFormSchema, UseJsonFormOptions, ValueFieldProps };
269
+ export type { AnyJsonFormInstance, ArrayFieldProps, ArrayFieldSlots, DisplayFieldProps, FieldComponents, FieldNode, FieldPath, FieldRole, FormLayout, GroupFieldProps, GroupFieldSlots, JsonFormInstance, JsonFormSchema, JsonFormSteps, LayoutComponents, LayoutNode, LayoutStep, RowProps, RowSlots, SectionProps, SectionSlots, TypedJsonFormSchema, UseJsonFormOptions, ValueFieldProps, VisibilityState };
259
270
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,38 +1,43 @@
1
- import { checkComponents, checkLayoutComponents, coerceInput, createSchemaBuilder, dotPathOf, fieldPathsOf, findField, isRequired, issuesOfStep, selectFields, shownNodes, toFieldPath } from "@whatsaaaa/form-builder-schema";
1
+ import { checkComponents, checkLayoutComponents, coerceInput, createSchemaBuilder, dotPathOf, fieldPathsOf, findField, isRequired, issuesOfStep, selectFields, toFieldPath } from "@whatsaaaa/form-builder-schema";
2
2
  import { Fragment, computed, defineComponent, getCurrentScope, h, nextTick, onScopeDispose, ref, watch } from "vue";
3
- import { focus, getErrors, getInput, insert, move, remove, setErrors, useField, useFieldArray, useForm, validate } from "@formisch/vue";
3
+ import { focus, getErrors, getInput, insert, move, remove, setErrors, setInput, useField, useFieldArray, useForm, validate } from "@formisch/vue";
4
4
  // src/json-form-steps.ts
5
5
  const fieldEvents = /* @__PURE__ */ new WeakMap();
6
6
  /** What a field of `form` calls on each event, for a form with steps. Undefined with one step. */
7
7
  const fieldEventsOf = (form) => fieldEvents.get(form);
8
8
  /**
9
9
  * The steps of `layout`, for `useJsonForm`. With more than one, a step shows the errors it had
10
- * when the user left it, and none the first time they get to it, a step that failed Next revalidates as the user fixes it, a submit
11
- * before the last step moves on like Next, and a submit that fails because of an earlier step
12
- * goes back to it.
10
+ * when the user left it, and none the first time they get to it, a step that failed Next
11
+ * revalidates as the user fixes it, a submit before the last step moves on like Next, and a submit
12
+ * that fails because of an earlier step goes back to it. The steps `visibility` hides are skipped.
13
13
  */
14
- function useJsonFormSteps(form, layout, modes) {
15
- const list = layout.steps;
16
- const index = ref(0);
17
- const current = computed(() => list[index.value]);
14
+ function useJsonFormSteps(form, layout, modes, visibility) {
15
+ const all = layout.steps;
16
+ const at = ref(0);
17
+ const current = computed(() => all[at.value]);
18
+ const list = computed(() => all.filter((step, i) => i === at.value || !visibility.value.isStepHidden(step)));
19
+ const index = computed(() => list.value.indexOf(current.value));
18
20
  const left = /* @__PURE__ */ new Map();
19
21
  const failed = /* @__PURE__ */ new Set();
20
22
  async function goTo(target) {
21
- if (!Number.isInteger(target) || target < 0 || target >= list.length) throw new RangeError(`No step ${target}. The form has ${list.length}.`);
23
+ const shown = list.value;
24
+ if (!Number.isInteger(target) || target < 0 || target >= shown.length) throw new RangeError(`No step ${target}. The form has ${shown.length}.`);
25
+ const to = all.indexOf(shown[target]);
22
26
  if (target <= index.value) {
23
- move(target);
27
+ move(to);
24
28
  return true;
25
29
  }
30
+ await afterTask();
26
31
  const { issues } = await validate(form);
27
- for (let at = index.value; at < target; at++) {
28
- const found = issuesOfStep(list[at], issues);
32
+ for (const step of shown.slice(index.value, target)) {
33
+ const found = issuesOfStep(step, issues);
29
34
  if (found.length) {
30
- await stop(at, found);
35
+ await stop(all.indexOf(step), found);
31
36
  return false;
32
37
  }
33
- failed.delete(at);
38
+ failed.delete(all.indexOf(step));
34
39
  }
35
- move(target);
40
+ move(to);
36
41
  return true;
37
42
  }
38
43
  /**
@@ -43,29 +48,31 @@ function useJsonFormSteps(form, layout, modes) {
43
48
  function move(target) {
44
49
  leave();
45
50
  const errors = left.get(target);
46
- for (const path of fieldPathsOf(list[target], getInput(form))) setErrors(form, {
51
+ for (const path of fieldPathsOf(all[target], getInput(form))) setErrors(form, {
47
52
  path,
48
53
  errors: errors?.get(JSON.stringify(path)) ?? null
49
54
  });
50
- index.value = target;
55
+ at.value = target;
51
56
  }
52
57
  /** Keeps the errors of the current step, for when the user comes back to it. */
53
58
  function leave() {
54
59
  const errors = fieldPathsOf(current.value, getInput(form)).map((path) => [JSON.stringify(path), errorsAt(path)]);
55
- left.set(index.value, new Map(errors));
60
+ left.set(at.value, new Map(errors));
56
61
  }
57
62
  const errorsAt = (path) => getErrors(form, { path });
58
- /** Stays on, or goes to, the step at `at`, with its issues shown. */
59
- async function stop(at, found) {
60
- failed.add(at);
61
- if (at !== index.value) leave();
62
- index.value = at;
63
+ /** Stays on, or goes to, the step at `target`, with its issues shown. */
64
+ async function stop(target, found) {
65
+ failed.add(target);
66
+ if (target !== at.value) leave();
67
+ at.value = target;
63
68
  await nextTick();
64
69
  const first = found.find((issue) => issue.field.role === "value");
65
70
  if (first) focus(form, { path: first.path });
66
71
  }
67
72
  const steps = {
68
- list,
73
+ get list() {
74
+ return list.value;
75
+ },
69
76
  get index() {
70
77
  return index.value;
71
78
  },
@@ -76,27 +83,29 @@ function useJsonFormSteps(form, layout, modes) {
76
83
  return index.value === 0;
77
84
  },
78
85
  get isLast() {
79
- return index.value === list.length - 1;
86
+ return index.value === list.value.length - 1;
80
87
  },
81
88
  next: () => steps.isLast ? Promise.resolve(false) : goTo(index.value + 1),
82
89
  back: () => {
83
- if (index.value > 0) move(index.value - 1);
90
+ if (index.value > 0) move(all.indexOf(list.value[index.value - 1]));
84
91
  },
85
92
  goTo
86
93
  };
87
- if (list.length > 1) watchSteps();
94
+ if (all.length > 1) watchSteps();
88
95
  return steps;
89
96
  function watchSteps() {
90
97
  fieldEvents.set(form, (event) => {
91
98
  const validateMode = modes.validate ?? "submit";
92
- if (!failed.has(index.value) || validateMode !== "submit" || form.isSubmitted) return;
99
+ if (!failed.has(at.value) || validateMode !== "submit" || form.isSubmitted) return;
93
100
  if (event === (modes.revalidate ?? "input")) validate(form);
94
101
  });
95
102
  watch(() => form.isSubmitting, async (submitting, was) => {
96
103
  if (submitting || !was || form.isValid) return;
97
104
  const { issues } = await validate(form);
98
- const at = list.findIndex((step) => issuesOfStep(step, issues).length);
99
- if (at !== -1 && at < index.value) await stop(at, issuesOfStep(list[at], issues));
105
+ const shown = list.value;
106
+ const first = shown.find((step) => issuesOfStep(step, issues).length);
107
+ const target = first ? all.indexOf(first) : -1;
108
+ if (first && shown.indexOf(first) < index.value) await stop(target, issuesOfStep(first, issues));
100
109
  });
101
110
  if (typeof document === "undefined") return;
102
111
  const onSubmit = (event) => {
@@ -109,6 +118,8 @@ function useJsonFormSteps(form, layout, modes) {
109
118
  if (getCurrentScope()) onScopeDispose(() => document.removeEventListener("submit", onSubmit, { capture: true }));
110
119
  }
111
120
  }
121
+ /** Resolves once the task that called it is over, and the browser is done with its event. */
122
+ const afterTask = () => new Promise((resolve) => setTimeout(resolve));
112
123
  /** The `<form>` Formisch's `<Form>` renders, which it keeps on the store for its `submit()`. */
113
124
  function formElementOf(form) {
114
125
  return form["~internal"]?.element;
@@ -252,9 +263,13 @@ function resolveComponents(components, of) {
252
263
  if (!resolved) throw new TypeError("No field components. Pass them to useJsonForm, or to the component.");
253
264
  return resolved;
254
265
  }
255
- /** `indexes` are the indexes of the array items the fields are in, outermost first. */
266
+ /**
267
+ * Renders the fields that conditions don't hide. `indexes` are the indexes of the array items the
268
+ * fields are in, outermost first.
269
+ */
256
270
  function renderFields(ctx, nodes, indexes) {
257
- return nodes.map((node, position) => renderField(ctx, node, indexes, dotPathOf(node) ?? `#${position}`, (inner) => renderFields(ctx, node.children, inner)));
271
+ const { visibility } = ctx.of;
272
+ return nodes.flatMap((node, position) => visibility.isHidden(node, indexes) ? [] : [renderField(ctx, node, indexes, dotPathOf(node) ?? `#${position}`, (inner) => renderFields(ctx, node.children, inner))]);
258
273
  }
259
274
  /**
260
275
  * Renders one field with its component. `children` renders the fields inside a group, or inside
@@ -294,6 +309,7 @@ function renderField(ctx, node, indexes, key, children) {
294
309
  /**
295
310
  * Renders one field of a `useJsonForm` form, wherever you put it inside Formisch's `<Form>`. A
296
311
  * group or an array comes with its fields. Leave the field out of `<JsonFields>` with `except`.
312
+ * It renders nothing while conditions hide the field.
297
313
  */
298
314
  const JsonField = defineComponent({
299
315
  name: "JsonField",
@@ -318,16 +334,17 @@ const JsonField = defineComponent({
318
334
  components: resolveComponents(props.components, props.of)
319
335
  };
320
336
  checkComponents([node], ctx.components);
321
- return () => renderField(ctx, node, [], dotPathOf(node) ?? "#0", (indexes) => renderFields(ctx, node.children, indexes));
337
+ return () => props.of.visibility.isHidden(node, []) ? null : renderField(ctx, node, [], dotPathOf(node) ?? "#0", (indexes) => renderFields(ctx, node.children, indexes));
322
338
  }
323
339
  });
324
340
  // src/render-layout.ts
325
341
  /**
326
- * Renders layout nodes. A field left out drops out, and so does a section or a row left without
327
- * fields. `indexes` are the indexes of the array items the nodes are in, outermost first.
342
+ * Renders layout nodes. A field left out or hidden by conditions drops out, and so does a section
343
+ * hidden by them, and a section or a row left without fields. `indexes` are the indexes of the
344
+ * array items the nodes are in, outermost first.
328
345
  */
329
346
  function renderLayout(ctx, nodes, indexes) {
330
- return shownNodes(nodes, indexes, ctx.isShown).map((node) => renderNode(ctx, node, indexes));
347
+ return ctx.of.visibility.shownNodes(nodes, indexes, ctx.isShown).map((node) => renderNode(ctx, node, indexes));
331
348
  }
332
349
  function renderNode(ctx, node, indexes) {
333
350
  const { key } = node;
@@ -423,6 +440,14 @@ function useJsonForm(definition, options = {}) {
423
440
  revalidate: options.revalidate
424
441
  });
425
442
  const layout = builder.getLayout(definition);
443
+ const visibility = builder.getVisibility(definition);
444
+ const state = visibility.conditional ? computed(() => visibility.of(getInput(form))) : { value: visibility.of(void 0) };
445
+ if (visibility.conditional) watch(() => state.value.toClear, (fields) => {
446
+ for (const { path, input } of fields) setInput(form, {
447
+ path,
448
+ input
449
+ });
450
+ });
426
451
  return {
427
452
  form,
428
453
  definition,
@@ -431,7 +456,10 @@ function useJsonForm(definition, options = {}) {
431
456
  layoutComponents: options.layoutComponents,
432
457
  fields: builder.getFieldTree(definition),
433
458
  layout,
434
- steps: useJsonFormSteps(form, layout, options)
459
+ steps: useJsonFormSteps(form, layout, options, state),
460
+ get visibility() {
461
+ return state.value;
462
+ }
435
463
  };
436
464
  }
437
465
  export { JsonField, JsonFields, useJsonForm };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/json-form-steps.ts","../src/array-field.ts","../src/value-field.ts","../src/render-fields.ts","../src/json-field.ts","../src/render-layout.ts","../src/json-fields.ts","../src/use-json-form.ts"],"sourcesContent":["import {\n focus,\n type FormStore,\n getErrors,\n getInput,\n setErrors,\n validate,\n type ValidationMode,\n} from '@formisch/vue'\nimport {\n type FieldPath,\n fieldPathsOf,\n type FormLayout,\n issuesOfStep,\n type LayoutStep,\n type StepIssue,\n} from '@whatsaaaa/form-builder-schema'\nimport { computed, getCurrentScope, nextTick, onScopeDispose, ref, watch } from 'vue'\n\n/** The steps of a form, from its layout. A form without `steps` in its layout has one. */\nexport interface JsonFormSteps {\n /** Every step, in order. */\n readonly list: readonly LayoutStep[]\n /** The index of the current step in `list`. */\n readonly index: number\n /** The step `<JsonFields>` renders. */\n readonly current: LayoutStep\n readonly isFirst: boolean\n readonly isLast: boolean\n /**\n * Validates the whole form, and moves to the next step when the fields of this one have no\n * issues. Otherwise it stays, and focuses the first field with an issue, in layout order.\n * Resolves to whether it moved.\n */\n next(): Promise<boolean>\n /** Moves to the step before, without validating. */\n back(): void\n /**\n * Moves to the step at `index`. Back is free, and forward validates every step on the way, like\n * `next()`, and stops at the first with issues. Resolves to whether it got there.\n */\n goTo(index: number): Promise<boolean>\n}\n\n/** A field's error messages in Formisch, or null. */\ntype Errors = [string, ...string[]] | null\n\n/** What a field tells the steps it was through, by Formisch's name for the validation mode. */\nexport type FieldEvent = Exclude<ValidationMode, 'initial' | 'submit'>\n\n/** Revalidates a step that failed Next on each field event, like a form after a failed submit. */\ntype FieldEvents = (event: FieldEvent) => void\n\nconst fieldEvents = new WeakMap<FormStore, FieldEvents>()\n\n/** What a field of `form` calls on each event, for a form with steps. Undefined with one step. */\nexport const fieldEventsOf = (form: FormStore): FieldEvents | undefined => fieldEvents.get(form)\n\n/**\n * The steps of `layout`, for `useJsonForm`. With more than one, a step shows the errors it had\n * when the user left it, and none the first time they get to it, a step that failed Next revalidates as the user fixes it, a submit\n * before the last step moves on like Next, and a submit that fails because of an earlier step\n * goes back to it.\n */\nexport function useJsonFormSteps(\n form: FormStore,\n layout: FormLayout,\n modes: {\n validate?: ValidationMode | undefined\n revalidate?: Exclude<ValidationMode, 'initial'> | undefined\n },\n): JsonFormSteps {\n const list = layout.steps\n const index = ref(0)\n const current = computed(() => list[index.value] as LayoutStep)\n // The errors each step had when the user left it, by the JSON of each field's path.\n const left = new Map<number, Map<string, Errors>>()\n // The steps that failed Next, and haven't passed since.\n const failed = new Set<number>()\n\n async function goTo(target: number): Promise<boolean> {\n if (!Number.isInteger(target) || target < 0 || target >= list.length) {\n throw new RangeError(`No step ${target}. The form has ${list.length}.`)\n }\n if (target <= index.value) {\n move(target)\n return true\n }\n const { issues } = await validate(form)\n for (let at = index.value; at < target; at++) {\n const found = issuesOfStep(list[at] as LayoutStep, issues)\n if (found.length) {\n await stop(at, found)\n return false\n }\n failed.delete(at)\n }\n move(target)\n return true\n }\n\n /**\n * Moves to a step as the user left it: with the errors it had then, and none the first time, and\n * revalidating if it failed Next. Validating the steps before set errors on its fields, which\n * the user never saw.\n */\n function move(target: number) {\n leave()\n const errors = left.get(target)\n for (const path of fieldPathsOf(list[target] as LayoutStep, getInput(form))) {\n setErrors(form, { path, errors: errors?.get(JSON.stringify(path)) ?? null } as never)\n }\n index.value = target\n }\n\n /** Keeps the errors of the current step, for when the user comes back to it. */\n function leave() {\n const paths = fieldPathsOf(current.value, getInput(form))\n const errors = paths.map((path): [string, Errors] => [JSON.stringify(path), errorsAt(path)])\n left.set(index.value, new Map(errors))\n }\n\n const errorsAt = (path: FieldPath): Errors => getErrors(form, { path } as never)\n\n /** Stays on, or goes to, the step at `at`, with its issues shown. */\n async function stop(at: number, found: readonly StepIssue[]) {\n failed.add(at)\n if (at !== index.value) leave()\n index.value = at\n await nextTick()\n // A group or an array has no element: the first field that has one gets the focus.\n const first = found.find((issue) => issue.field.role === 'value')\n if (first) focus(form, { path: first.path as never })\n }\n\n const steps: JsonFormSteps = {\n list,\n get index() {\n return index.value\n },\n get current() {\n return current.value\n },\n get isFirst() {\n return index.value === 0\n },\n get isLast() {\n return index.value === list.length - 1\n },\n next: () => (steps.isLast ? Promise.resolve(false) : goTo(index.value + 1)),\n back: () => {\n if (index.value > 0) move(index.value - 1)\n },\n goTo,\n }\n if (list.length > 1) watchSteps()\n return steps\n\n function watchSteps() {\n fieldEvents.set(form, (event) => {\n // In the other modes, Formisch revalidates a field with errors itself.\n const validateMode = modes.validate ?? 'submit'\n if (!failed.has(index.value) || validateMode !== 'submit' || form.isSubmitted) return\n if (event === (modes.revalidate ?? 'input')) void validate(form)\n })\n\n // A submit that fails because of a step before the last, e.g. on a form rule, goes back to it.\n watch(\n () => form.isSubmitting,\n async (submitting, was) => {\n if (submitting || !was || form.isValid) return\n const { issues } = await validate(form)\n const at = list.findIndex((step) => issuesOfStep(step, issues).length)\n if (at !== -1 && at < index.value)\n await stop(at, issuesOfStep(list[at] as LayoutStep, issues))\n },\n )\n\n // Before the last step, a submit, like Enter in a step with a single text input, is a Next.\n // It is caught on its way down to the form, before Formisch's own handler sees it.\n if (typeof document === 'undefined') return\n const onSubmit = (event: Event) => {\n if (event.target !== formElementOf(form) || steps.isLast) return\n event.preventDefault()\n event.stopImmediatePropagation()\n void steps.next()\n }\n document.addEventListener('submit', onSubmit, { capture: true })\n if (getCurrentScope()) {\n onScopeDispose(() => document.removeEventListener('submit', onSubmit, { capture: true }))\n }\n }\n}\n\n/** The `<form>` Formisch's `<Form>` renders, which it keeps on the store for its `submit()`. */\nfunction formElementOf(form: FormStore): HTMLFormElement | undefined {\n return (form as unknown as { '~internal'?: { element?: HTMLFormElement } })['~internal']?.element\n}\n","import { insert, move, remove, useFieldArray } from '@formisch/vue'\nimport type { FieldNode, FieldPath } from '@whatsaaaa/form-builder-schema'\nimport { type Component, defineComponent, h, type PropType, type VNode } from 'vue'\nimport type { ArrayFieldProps } from './field-components'\nimport { fieldEventsOf } from './json-form-steps'\nimport type { AnyJsonFormInstance } from './use-json-form'\n\n/** Connects a container of kind `array` to Formisch, and renders your component for it. */\nexport const ArrayField = defineComponent({\n name: 'ArrayField',\n props: {\n of: { type: Object as PropType<AnyJsonFormInstance>, required: true },\n node: { type: Object as PropType<FieldNode>, required: true },\n path: { type: Array as PropType<FieldPath>, required: true },\n component: { type: [Object, Function] as PropType<Component>, required: true },\n /** Renders the fields of the item at `index`. */\n renderItem: { type: Function as PropType<(index: number) => VNode[]>, required: true },\n },\n setup(props) {\n // The path comes from the definition at runtime, so the schema's types can't check it.\n const path = () => props.path as never\n const array = useFieldArray(\n () => props.of.form,\n () => ({ path: path() }),\n )\n\n // In a form with steps, a step that failed Next revalidates on a change of its items too.\n const events = fieldEventsOf(props.of.form)\n const methods = {\n // A new item starts with the defaults of its fields, like the items of a new form.\n add: () => {\n insert(props.of.form, {\n path: path(),\n initialInput: props.of.builder.getItemInput(props.node.field) as never,\n })\n events?.('input')\n },\n remove: (index: number) => {\n remove(props.of.form, { path: path(), at: index })\n events?.('input')\n },\n move: (from: number, to: number) => {\n move(props.of.form, { path: path(), from, to })\n events?.('input')\n },\n }\n\n return () => {\n const fieldProps: ArrayFieldProps = {\n field: props.node.field,\n path: props.path,\n items: array.items,\n errors: array.errors,\n ...methods,\n }\n return h(props.component, fieldProps, {\n default: ({ index }: { index: number }) => props.renderItem(index),\n })\n }\n },\n})\n","import { type FieldElementProps, useField } from '@formisch/vue'\nimport {\n coerceInput,\n type FieldNode,\n type FieldPath,\n isRequired,\n} from '@whatsaaaa/form-builder-schema'\nimport { type Component, defineComponent, h, type PropType } from 'vue'\nimport type { ValueFieldProps } from './field-components'\nimport { fieldEventsOf } from './json-form-steps'\nimport type { AnyJsonFormInstance } from './use-json-form'\n\n/** Connects a field with a value to Formisch, and renders your component for it. */\nexport const ValueField = defineComponent({\n name: 'ValueField',\n props: {\n of: { type: Object as PropType<AnyJsonFormInstance>, required: true },\n node: { type: Object as PropType<FieldNode>, required: true },\n path: { type: Array as PropType<FieldPath>, required: true },\n component: { type: [Object, Function] as PropType<Component>, required: true },\n },\n setup(props) {\n // The path comes from the definition at runtime, so the schema's types can't check it.\n const field = useField(\n () => props.of.form,\n () => ({ path: props.path as never }),\n )\n\n // In a form with steps, a step that failed Next revalidates on these events too.\n const events = fieldEventsOf(props.of.form)\n const setInput = (input: unknown) => {\n field.input = coerceInput(input, props.node) as never\n events?.('input')\n }\n const inputProps: FieldElementProps = events\n ? {\n get name() {\n return field.props.name\n },\n get autofocus() {\n return field.props.autofocus\n },\n ref: (element) => field.props.ref(element),\n onFocus: () => {\n field.props.onFocus()\n events('touch')\n },\n onChange: (event) => {\n field.props.onChange(event)\n events('change')\n },\n onBlur: () => {\n field.props.onBlur()\n events('blur')\n },\n }\n : field.props\n\n return () => {\n const fieldProps: ValueFieldProps = {\n field: props.node.field,\n path: props.path,\n kind: props.node.kind,\n required: isRequired(props.node.field),\n input: field.input,\n errors: field.errors,\n inputProps,\n setInput,\n }\n return h(props.component, fieldProps)\n }\n },\n})\n","import { dotPathOf, type FieldNode, toFieldPath } from '@whatsaaaa/form-builder-schema'\nimport { type Component, h, type VNode } from 'vue'\nimport { ArrayField } from './array-field'\nimport type { FieldComponents } from './field-components'\nimport type { AnyJsonFormInstance } from './use-json-form'\nimport { ValueField } from './value-field'\n\n/** What `<JsonFields>` and `<JsonField>` render with. */\nexport interface RenderContext {\n of: AnyJsonFormInstance\n components: FieldComponents\n}\n\n/** The components from the props, or else the ones `useJsonForm` got. */\nexport function resolveComponents(\n components: FieldComponents | undefined,\n of: AnyJsonFormInstance,\n): FieldComponents {\n const resolved = components ?? of.components\n if (!resolved) {\n throw new TypeError('No field components. Pass them to useJsonForm, or to the component.')\n }\n return resolved\n}\n\n/** `indexes` are the indexes of the array items the fields are in, outermost first. */\nexport function renderFields(\n ctx: RenderContext,\n nodes: readonly FieldNode[],\n indexes: readonly number[],\n): VNode[] {\n return nodes.map((node, position) =>\n renderField(ctx, node, indexes, dotPathOf(node) ?? `#${position}`, (inner) =>\n renderFields(ctx, node.children, inner),\n ),\n )\n}\n\n/**\n * Renders one field with its component. `children` renders the fields inside a group, or inside\n * the item of an array, with the indexes of the items they are in.\n */\nexport function renderField(\n ctx: RenderContext,\n node: FieldNode,\n indexes: readonly number[],\n key: string,\n children: (indexes: readonly number[]) => VNode[],\n): VNode {\n const component = ctx.components[node.type] as Component\n const path = toFieldPath(node.dataPath, indexes)\n switch (node.role) {\n case 'display':\n return h(component, { key, field: node.field })\n case 'group':\n return h(component, { key, field: node.field, path }, { default: () => children(indexes) })\n case 'array':\n return h(ArrayField, {\n key,\n of: ctx.of,\n node,\n path,\n component,\n renderItem: (index: number) => children([...indexes, index]),\n })\n case 'value':\n return h(ValueField, { key, of: ctx.of, node, path, component })\n }\n}\n","import { checkComponents, dotPathOf, findField } from '@whatsaaaa/form-builder-schema'\nimport { defineComponent, type PropType } from 'vue'\nimport type { FieldComponents } from './field-components'\nimport { type RenderContext, renderField, renderFields, resolveComponents } from './render-fields'\nimport type { AnyJsonFormInstance } from './use-json-form'\n\n/**\n * Renders one field of a `useJsonForm` form, wherever you put it inside Formisch's `<Form>`. A\n * group or an array comes with its fields. Leave the field out of `<JsonFields>` with `except`.\n */\nexport const JsonField = defineComponent({\n name: 'JsonField',\n props: {\n /** What `useJsonForm` returned. */\n of: { type: Object as PropType<AnyJsonFormInstance>, required: true },\n /** The field's path: `'email'`, or `'address.city'` for a field of a group. */\n path: { type: String, required: true },\n /** Defaults to the components `useJsonForm` got. */\n components: { type: Object as PropType<FieldComponents> },\n },\n setup(props) {\n const node = findField(props.of.fields, props.path, { placed: true })\n const ctx: RenderContext = {\n of: props.of,\n components: resolveComponents(props.components, props.of),\n }\n checkComponents([node], ctx.components)\n\n return () =>\n renderField(ctx, node, [], dotPathOf(node) ?? '#0', (indexes) =>\n renderFields(ctx, node.children, indexes),\n )\n },\n})\n","import { type IsFieldShown, type LayoutNode, shownNodes } from '@whatsaaaa/form-builder-schema'\nimport { type Component, Fragment, h, type Slots, type VNode } from 'vue'\nimport type { LayoutComponents } from './field-components'\nimport { type RenderContext, renderField } from './render-fields'\n\n/** What `<JsonFields>` renders a layout with. */\nexport interface LayoutContext extends RenderContext {\n layoutComponents: LayoutComponents\n /** The content of the layout's slots, by name. */\n slots: Slots\n /** False for a field left out with `except`. */\n isShown: IsFieldShown\n}\n\n/**\n * Renders layout nodes. A field left out drops out, and so does a section or a row left without\n * fields. `indexes` are the indexes of the array items the nodes are in, outermost first.\n */\nexport function renderLayout(\n ctx: LayoutContext,\n nodes: readonly LayoutNode[],\n indexes: readonly number[],\n): VNode[] {\n return shownNodes(nodes, indexes, ctx.isShown).map((node) => renderNode(ctx, node, indexes))\n}\n\nfunction renderNode(ctx: LayoutContext, node: LayoutNode, indexes: readonly number[]): VNode {\n const { key } = node\n switch (node.type) {\n case 'field':\n return renderField(ctx, node.node, indexes, key, (inner) =>\n renderLayout(ctx, node.children, inner),\n )\n case 'section':\n return h(\n ctx.layoutComponents.section as Component,\n { key, section: node.section },\n { default: () => renderLayout(ctx, node.children, indexes) },\n )\n case 'row':\n return h(\n ctx.layoutComponents.row as Component,\n { key, row: node.row, spans: node.children.map((cell) => cell.span) },\n {\n default: ({ index }: { index: number }) => [\n renderNode(ctx, node.children[index] as LayoutNode, indexes),\n ],\n },\n )\n case 'slot':\n return h(Fragment, { key }, ctx.slots[node.name]?.())\n }\n}\n","import {\n checkComponents,\n checkLayoutComponents,\n dotPathOf,\n type FieldNode,\n type LayoutNode,\n selectFields,\n} from '@whatsaaaa/form-builder-schema'\nimport { defineComponent, Fragment, h, type PropType } from 'vue'\nimport type { FieldComponents, LayoutComponents } from './field-components'\nimport { type LayoutContext, renderLayout } from './render-layout'\nimport { type RenderContext, renderFields, resolveComponents } from './render-fields'\nimport type { AnyJsonFormInstance } from './use-json-form'\n\n/**\n * Renders the fields of a `useJsonForm` form with your components, one per field type, where the\n * definition's `layout` puts them: the current step, with its sections, rows and slots. It renders\n * nothing of its own, so put it inside Formisch's `<Form>` with your own submit button. Its named\n * slots fill the layout's slots. `only` and `except` are read when it sets up.\n */\nexport const JsonFields = defineComponent({\n name: 'JsonFields',\n props: {\n /** What `useJsonForm` returned. */\n of: { type: Object as PropType<AnyJsonFormInstance>, required: true },\n /** Defaults to the components `useJsonForm` got. */\n components: { type: Object as PropType<FieldComponents> },\n /** Defaults to the layout components `useJsonForm` got. */\n layoutComponents: { type: Object as PropType<LayoutComponents> },\n /** Renders only these fields, by path, in the order of the definition, without the layout. */\n only: { type: Array as PropType<readonly string[]> },\n /**\n * Leaves out these fields, by path, e.g. the ones you place with `<JsonField>`. A section or a\n * row left without fields drops out too.\n */\n except: { type: Array as PropType<readonly string[]> },\n /** Renders the step at this index instead of the current one, e.g. on a review page. */\n step: { type: Number },\n },\n setup(props, { slots }) {\n const ctx: RenderContext = {\n of: props.of,\n components: resolveComponents(props.components, props.of),\n }\n const nodes = selectFields(props.of.fields, { only: props.only, except: props.except })\n // Without a layout, it renders the fields the way it always did, and so with `only`.\n if (props.only || !props.of.definition.layout) {\n checkComponents(nodes, ctx.components)\n return () => renderFields(ctx, nodes, [])\n }\n\n const { layout, steps } = props.of\n const except = new Set(props.except)\n const layoutCtx: LayoutContext = {\n ...ctx,\n layoutComponents: props.layoutComponents ?? props.of.layoutComponents ?? {},\n slots,\n isShown: (node) => !except.has(dotPathOf(node) ?? ''),\n }\n checkComponents(\n layout.steps.flatMap((step) => fieldsOf(step.children)),\n ctx.components,\n )\n checkLayoutComponents(layout, layoutCtx.layoutComponents, slots)\n\n return () => {\n const index = props.step ?? steps.index\n const step = steps.list[index]\n if (!step) throw new RangeError(`No step ${props.step}. The form has ${steps.list.length}.`)\n // Keyed by the step, so another step's fields don't take over this one's components.\n return h(Fragment, { key: index }, renderLayout(layoutCtx, step.children, []))\n }\n },\n})\n\n/** Every field of the nodes, display elements written in the layout included. */\nfunction fieldsOf(nodes: readonly LayoutNode[]): FieldNode[] {\n return nodes.flatMap((node) => {\n if (node.type === 'slot') return []\n const inner = fieldsOf(node.children)\n return node.type === 'field' ? [node.node, ...inner] : inner\n })\n}\n","import { type FormSchema, type FormStore, useForm, type ValidationMode } from '@formisch/vue'\nimport {\n createSchemaBuilder,\n type FieldNode,\n type FormLayout,\n type JsonForm,\n type JsonFormSchema,\n type SchemaBuilder,\n type TypedJsonFormSchema,\n} from '@whatsaaaa/form-builder-schema'\nimport type { FieldComponents, LayoutComponents } from './field-components'\nimport { type JsonFormSteps, useJsonFormSteps } from './json-form-steps'\n\nexport interface UseJsonFormOptions {\n /** Builds the schema and knows your own types and rules. Defaults to `createSchemaBuilder()`. */\n builder?: SchemaBuilder\n /** Your component for each field type, so `<JsonFields>` and `<JsonField>` don't need them. */\n components?: FieldComponents\n /** Your component for each layout type the definition's `layout` uses, like `section`. */\n layoutComponents?: LayoutComponents\n /** When a field is validated the first time, as in Formisch. */\n validate?: ValidationMode\n /** When a field is validated again after that, as in Formisch. */\n revalidate?: Exclude<ValidationMode, 'initial'>\n}\n\n/** What `useJsonForm` returns. Pass it to `<JsonFields>`. */\nexport interface JsonFormInstance<TSchema extends FormSchema = JsonFormSchema> {\n /** The Formisch form: pass it to Formisch's `<Form :of>`, or to any of its methods. */\n readonly form: FormStore<TSchema>\n readonly definition: JsonForm\n readonly builder: SchemaBuilder\n /** The components from the options, if any. */\n readonly components: FieldComponents | undefined\n /** The layout components from the options, if any. */\n readonly layoutComponents: LayoutComponents | undefined\n /** The definition's fields as a tree, for `<JsonFields :only>` and `<JsonField>`. */\n readonly fields: readonly FieldNode[]\n /** The definition's layout, the way `<JsonFields>` renders it. */\n readonly layout: FormLayout\n /** The layout's steps: the current one, and Next, Back and Go to. A form without steps has one. */\n readonly steps: JsonFormSteps\n}\n\n/** Any form `useJsonForm` returns, typed or not: what the components take. */\nexport type AnyJsonFormInstance = JsonFormInstance<FormSchema>\n\n/**\n * A Formisch form for a definition, with its schema and initial input from the builder. A\n * definition with issues throws the builder's `DefinitionError`, so run `validate()` first when it\n * comes from outside your code. The definition is read once: give the form a new `:key` to use\n * another one.\n */\nexport function useJsonForm(definition: JsonForm, options?: UseJsonFormOptions): JsonFormInstance\n/**\n * The same, with the form typed by your input type, and output type when it differs, so Formisch's\n * paths and values are checked. The types are yours to keep in step with the definition.\n */\nexport function useJsonForm<TInput extends object, TOutput extends object = TInput>(\n definition: JsonForm,\n options?: UseJsonFormOptions,\n): JsonFormInstance<TypedJsonFormSchema<TInput, TOutput>>\nexport function useJsonForm(\n definition: JsonForm,\n options: UseJsonFormOptions = {},\n): JsonFormInstance {\n const builder = options.builder ?? createSchemaBuilder()\n const form = useForm({\n schema: builder.build(definition),\n initialInput: builder.getInitialInput(definition),\n validate: options.validate,\n revalidate: options.revalidate,\n })\n const layout = builder.getLayout(definition)\n return {\n form,\n definition,\n builder,\n components: options.components,\n layoutComponents: options.layoutComponents,\n fields: builder.getFieldTree(definition),\n layout,\n steps: useJsonFormSteps(form, layout, options),\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/json-form-steps.ts","../src/array-field.ts","../src/value-field.ts","../src/render-fields.ts","../src/json-field.ts","../src/render-layout.ts","../src/json-fields.ts","../src/use-json-form.ts"],"sourcesContent":["import {\n focus,\n type FormStore,\n getErrors,\n getInput,\n setErrors,\n validate,\n type ValidationMode,\n} from '@formisch/vue'\nimport {\n type FieldPath,\n fieldPathsOf,\n type FormLayout,\n issuesOfStep,\n type LayoutStep,\n type StepIssue,\n type VisibilityState,\n} from '@whatsaaaa/form-builder-schema'\nimport { computed, getCurrentScope, nextTick, onScopeDispose, ref, watch } from 'vue'\n\n/** The steps of a form, from its layout. A form without `steps` in its layout has one. */\nexport interface JsonFormSteps {\n /**\n * The steps on show, in order. A step whose fields are all hidden by conditions, or that is\n * hidden itself, is left out, unless it is the current one: Next and Back skip it.\n */\n readonly list: readonly LayoutStep[]\n /** The index of the current step in `list`. */\n readonly index: number\n /** The step `<JsonFields>` renders. */\n readonly current: LayoutStep\n readonly isFirst: boolean\n readonly isLast: boolean\n /**\n * Validates the whole form, and moves to the next step when the fields of this one have no\n * issues. Otherwise it stays, and focuses the first field with an issue, in layout order.\n * Resolves to whether it moved.\n */\n next(): Promise<boolean>\n /** Moves to the step before, without validating. */\n back(): void\n /**\n * Moves to the step at `index`. Back is free, and forward validates every step on the way, like\n * `next()`, and stops at the first with issues. Resolves to whether it got there.\n */\n goTo(index: number): Promise<boolean>\n}\n\n/** A field's error messages in Formisch, or null. */\ntype Errors = [string, ...string[]] | null\n\n/** What a field tells the steps it was through, by Formisch's name for the validation mode. */\nexport type FieldEvent = Exclude<ValidationMode, 'initial' | 'submit'>\n\n/** Revalidates a step that failed Next on each field event, like a form after a failed submit. */\ntype FieldEvents = (event: FieldEvent) => void\n\nconst fieldEvents = new WeakMap<FormStore, FieldEvents>()\n\n/** What a field of `form` calls on each event, for a form with steps. Undefined with one step. */\nexport const fieldEventsOf = (form: FormStore): FieldEvents | undefined => fieldEvents.get(form)\n\n/**\n * The steps of `layout`, for `useJsonForm`. With more than one, a step shows the errors it had\n * when the user left it, and none the first time they get to it, a step that failed Next\n * revalidates as the user fixes it, a submit before the last step moves on like Next, and a submit\n * that fails because of an earlier step goes back to it. The steps `visibility` hides are skipped.\n */\nexport function useJsonFormSteps(\n form: FormStore,\n layout: FormLayout,\n modes: {\n validate?: ValidationMode | undefined\n revalidate?: Exclude<ValidationMode, 'initial'> | undefined\n },\n visibility: { readonly value: VisibilityState },\n): JsonFormSteps {\n const all = layout.steps\n // The current step, by its index in `all`, as are the steps of the maps and sets below.\n const at = ref(0)\n const current = computed(() => all[at.value] as LayoutStep)\n // The current step stays on show, so it never goes from under the user.\n const list = computed(() =>\n all.filter((step, i) => i === at.value || !visibility.value.isStepHidden(step)),\n )\n const index = computed(() => list.value.indexOf(current.value))\n // The errors each step had when the user left it, by the JSON of each field's path.\n const left = new Map<number, Map<string, Errors>>()\n // The steps that failed Next, and haven't passed since.\n const failed = new Set<number>()\n\n async function goTo(target: number): Promise<boolean> {\n const shown = list.value\n if (!Number.isInteger(target) || target < 0 || target >= shown.length) {\n throw new RangeError(`No step ${target}. The form has ${shown.length}.`)\n }\n const to = all.indexOf(shown[target] as LayoutStep)\n if (target <= index.value) {\n move(to)\n return true\n }\n // Next goes on once the task that called it is over. A click runs its default action after its\n // handlers, and Vue can render in between: a Next button that turns into the submit button on\n // the last step would then submit the form as the user gets there.\n await afterTask()\n const { issues } = await validate(form)\n for (const step of shown.slice(index.value, target)) {\n const found = issuesOfStep(step, issues)\n if (found.length) {\n await stop(all.indexOf(step), found)\n return false\n }\n failed.delete(all.indexOf(step))\n }\n move(to)\n return true\n }\n\n /**\n * Moves to a step as the user left it: with the errors it had then, and none the first time, and\n * revalidating if it failed Next. Validating the steps before set errors on its fields, which\n * the user never saw.\n */\n function move(target: number) {\n leave()\n const errors = left.get(target)\n for (const path of fieldPathsOf(all[target] as LayoutStep, getInput(form))) {\n setErrors(form, { path, errors: errors?.get(JSON.stringify(path)) ?? null } as never)\n }\n at.value = target\n }\n\n /** Keeps the errors of the current step, for when the user comes back to it. */\n function leave() {\n const paths = fieldPathsOf(current.value, getInput(form))\n const errors = paths.map((path): [string, Errors] => [JSON.stringify(path), errorsAt(path)])\n left.set(at.value, new Map(errors))\n }\n\n const errorsAt = (path: FieldPath): Errors => getErrors(form, { path } as never)\n\n /** Stays on, or goes to, the step at `target`, with its issues shown. */\n async function stop(target: number, found: readonly StepIssue[]) {\n failed.add(target)\n if (target !== at.value) leave()\n at.value = target\n await nextTick()\n // A group or an array has no element: the first field that has one gets the focus.\n const first = found.find((issue) => issue.field.role === 'value')\n if (first) focus(form, { path: first.path as never })\n }\n\n const steps: JsonFormSteps = {\n get list() {\n return list.value\n },\n get index() {\n return index.value\n },\n get current() {\n return current.value\n },\n get isFirst() {\n return index.value === 0\n },\n get isLast() {\n return index.value === list.value.length - 1\n },\n next: () => (steps.isLast ? Promise.resolve(false) : goTo(index.value + 1)),\n back: () => {\n if (index.value > 0) move(all.indexOf(list.value[index.value - 1] as LayoutStep))\n },\n goTo,\n }\n if (all.length > 1) watchSteps()\n return steps\n\n function watchSteps() {\n fieldEvents.set(form, (event) => {\n // In the other modes, Formisch revalidates a field with errors itself.\n const validateMode = modes.validate ?? 'submit'\n if (!failed.has(at.value) || validateMode !== 'submit' || form.isSubmitted) return\n if (event === (modes.revalidate ?? 'input')) void validate(form)\n })\n\n // A submit that fails because of a step before the last, e.g. on a form rule, goes back to it.\n watch(\n () => form.isSubmitting,\n async (submitting, was) => {\n if (submitting || !was || form.isValid) return\n const { issues } = await validate(form)\n const shown = list.value\n const first = shown.find((step) => issuesOfStep(step, issues).length)\n const target = first ? all.indexOf(first) : -1\n if (first && shown.indexOf(first) < index.value) {\n await stop(target, issuesOfStep(first, issues))\n }\n },\n )\n\n // Before the last step, a submit, like Enter in a step with a single text input, is a Next.\n // It is caught on its way down to the form, before Formisch's own handler sees it.\n if (typeof document === 'undefined') return\n const onSubmit = (event: Event) => {\n if (event.target !== formElementOf(form) || steps.isLast) return\n event.preventDefault()\n event.stopImmediatePropagation()\n void steps.next()\n }\n document.addEventListener('submit', onSubmit, { capture: true })\n if (getCurrentScope()) {\n onScopeDispose(() => document.removeEventListener('submit', onSubmit, { capture: true }))\n }\n }\n}\n\n/** Resolves once the task that called it is over, and the browser is done with its event. */\nconst afterTask = () => new Promise<void>((resolve) => setTimeout(resolve))\n\n/** The `<form>` Formisch's `<Form>` renders, which it keeps on the store for its `submit()`. */\nfunction formElementOf(form: FormStore): HTMLFormElement | undefined {\n return (form as unknown as { '~internal'?: { element?: HTMLFormElement } })['~internal']?.element\n}\n","import { insert, move, remove, useFieldArray } from '@formisch/vue'\nimport type { FieldNode, FieldPath } from '@whatsaaaa/form-builder-schema'\nimport { type Component, defineComponent, h, type PropType, type VNode } from 'vue'\nimport type { ArrayFieldProps } from './field-components'\nimport { fieldEventsOf } from './json-form-steps'\nimport type { AnyJsonFormInstance } from './use-json-form'\n\n/** Connects a container of kind `array` to Formisch, and renders your component for it. */\nexport const ArrayField = defineComponent({\n name: 'ArrayField',\n props: {\n of: { type: Object as PropType<AnyJsonFormInstance>, required: true },\n node: { type: Object as PropType<FieldNode>, required: true },\n path: { type: Array as PropType<FieldPath>, required: true },\n component: { type: [Object, Function] as PropType<Component>, required: true },\n /** Renders the fields of the item at `index`. */\n renderItem: { type: Function as PropType<(index: number) => VNode[]>, required: true },\n },\n setup(props) {\n // The path comes from the definition at runtime, so the schema's types can't check it.\n const path = () => props.path as never\n const array = useFieldArray(\n () => props.of.form,\n () => ({ path: path() }),\n )\n\n // In a form with steps, a step that failed Next revalidates on a change of its items too.\n const events = fieldEventsOf(props.of.form)\n const methods = {\n // A new item starts with the defaults of its fields, like the items of a new form.\n add: () => {\n insert(props.of.form, {\n path: path(),\n initialInput: props.of.builder.getItemInput(props.node.field) as never,\n })\n events?.('input')\n },\n remove: (index: number) => {\n remove(props.of.form, { path: path(), at: index })\n events?.('input')\n },\n move: (from: number, to: number) => {\n move(props.of.form, { path: path(), from, to })\n events?.('input')\n },\n }\n\n return () => {\n const fieldProps: ArrayFieldProps = {\n field: props.node.field,\n path: props.path,\n items: array.items,\n errors: array.errors,\n ...methods,\n }\n return h(props.component, fieldProps, {\n default: ({ index }: { index: number }) => props.renderItem(index),\n })\n }\n },\n})\n","import { type FieldElementProps, useField } from '@formisch/vue'\nimport {\n coerceInput,\n type FieldNode,\n type FieldPath,\n isRequired,\n} from '@whatsaaaa/form-builder-schema'\nimport { type Component, defineComponent, h, type PropType } from 'vue'\nimport type { ValueFieldProps } from './field-components'\nimport { fieldEventsOf } from './json-form-steps'\nimport type { AnyJsonFormInstance } from './use-json-form'\n\n/** Connects a field with a value to Formisch, and renders your component for it. */\nexport const ValueField = defineComponent({\n name: 'ValueField',\n props: {\n of: { type: Object as PropType<AnyJsonFormInstance>, required: true },\n node: { type: Object as PropType<FieldNode>, required: true },\n path: { type: Array as PropType<FieldPath>, required: true },\n component: { type: [Object, Function] as PropType<Component>, required: true },\n },\n setup(props) {\n // The path comes from the definition at runtime, so the schema's types can't check it.\n const field = useField(\n () => props.of.form,\n () => ({ path: props.path as never }),\n )\n\n // In a form with steps, a step that failed Next revalidates on these events too.\n const events = fieldEventsOf(props.of.form)\n const setInput = (input: unknown) => {\n field.input = coerceInput(input, props.node) as never\n events?.('input')\n }\n const inputProps: FieldElementProps = events\n ? {\n get name() {\n return field.props.name\n },\n get autofocus() {\n return field.props.autofocus\n },\n ref: (element) => field.props.ref(element),\n onFocus: () => {\n field.props.onFocus()\n events('touch')\n },\n onChange: (event) => {\n field.props.onChange(event)\n events('change')\n },\n onBlur: () => {\n field.props.onBlur()\n events('blur')\n },\n }\n : field.props\n\n return () => {\n const fieldProps: ValueFieldProps = {\n field: props.node.field,\n path: props.path,\n kind: props.node.kind,\n required: isRequired(props.node.field),\n input: field.input,\n errors: field.errors,\n inputProps,\n setInput,\n }\n return h(props.component, fieldProps)\n }\n },\n})\n","import { dotPathOf, type FieldNode, toFieldPath } from '@whatsaaaa/form-builder-schema'\nimport { type Component, h, type VNode } from 'vue'\nimport { ArrayField } from './array-field'\nimport type { FieldComponents } from './field-components'\nimport type { AnyJsonFormInstance } from './use-json-form'\nimport { ValueField } from './value-field'\n\n/** What `<JsonFields>` and `<JsonField>` render with. */\nexport interface RenderContext {\n of: AnyJsonFormInstance\n components: FieldComponents\n}\n\n/** The components from the props, or else the ones `useJsonForm` got. */\nexport function resolveComponents(\n components: FieldComponents | undefined,\n of: AnyJsonFormInstance,\n): FieldComponents {\n const resolved = components ?? of.components\n if (!resolved) {\n throw new TypeError('No field components. Pass them to useJsonForm, or to the component.')\n }\n return resolved\n}\n\n/**\n * Renders the fields that conditions don't hide. `indexes` are the indexes of the array items the\n * fields are in, outermost first.\n */\nexport function renderFields(\n ctx: RenderContext,\n nodes: readonly FieldNode[],\n indexes: readonly number[],\n): VNode[] {\n const { visibility } = ctx.of\n // A display element is keyed by its position among all the nodes, which stays the same.\n return nodes.flatMap((node, position) =>\n visibility.isHidden(node, indexes)\n ? []\n : [\n renderField(ctx, node, indexes, dotPathOf(node) ?? `#${position}`, (inner) =>\n renderFields(ctx, node.children, inner),\n ),\n ],\n )\n}\n\n/**\n * Renders one field with its component. `children` renders the fields inside a group, or inside\n * the item of an array, with the indexes of the items they are in.\n */\nexport function renderField(\n ctx: RenderContext,\n node: FieldNode,\n indexes: readonly number[],\n key: string,\n children: (indexes: readonly number[]) => VNode[],\n): VNode {\n const component = ctx.components[node.type] as Component\n const path = toFieldPath(node.dataPath, indexes)\n switch (node.role) {\n case 'display':\n return h(component, { key, field: node.field })\n case 'group':\n return h(component, { key, field: node.field, path }, { default: () => children(indexes) })\n case 'array':\n return h(ArrayField, {\n key,\n of: ctx.of,\n node,\n path,\n component,\n renderItem: (index: number) => children([...indexes, index]),\n })\n case 'value':\n return h(ValueField, { key, of: ctx.of, node, path, component })\n }\n}\n","import { checkComponents, dotPathOf, findField } from '@whatsaaaa/form-builder-schema'\nimport { defineComponent, type PropType } from 'vue'\nimport type { FieldComponents } from './field-components'\nimport { type RenderContext, renderField, renderFields, resolveComponents } from './render-fields'\nimport type { AnyJsonFormInstance } from './use-json-form'\n\n/**\n * Renders one field of a `useJsonForm` form, wherever you put it inside Formisch's `<Form>`. A\n * group or an array comes with its fields. Leave the field out of `<JsonFields>` with `except`.\n * It renders nothing while conditions hide the field.\n */\nexport const JsonField = defineComponent({\n name: 'JsonField',\n props: {\n /** What `useJsonForm` returned. */\n of: { type: Object as PropType<AnyJsonFormInstance>, required: true },\n /** The field's path: `'email'`, or `'address.city'` for a field of a group. */\n path: { type: String, required: true },\n /** Defaults to the components `useJsonForm` got. */\n components: { type: Object as PropType<FieldComponents> },\n },\n setup(props) {\n const node = findField(props.of.fields, props.path, { placed: true })\n const ctx: RenderContext = {\n of: props.of,\n components: resolveComponents(props.components, props.of),\n }\n checkComponents([node], ctx.components)\n\n return () =>\n props.of.visibility.isHidden(node, [])\n ? null\n : renderField(ctx, node, [], dotPathOf(node) ?? '#0', (indexes) =>\n renderFields(ctx, node.children, indexes),\n )\n },\n})\n","import type { IsFieldShown, LayoutNode } from '@whatsaaaa/form-builder-schema'\nimport { type Component, Fragment, h, type Slots, type VNode } from 'vue'\nimport type { LayoutComponents } from './field-components'\nimport { type RenderContext, renderField } from './render-fields'\n\n/** What `<JsonFields>` renders a layout with. */\nexport interface LayoutContext extends RenderContext {\n layoutComponents: LayoutComponents\n /** The content of the layout's slots, by name. */\n slots: Slots\n /** False for a field left out with `except`. */\n isShown: IsFieldShown\n}\n\n/**\n * Renders layout nodes. A field left out or hidden by conditions drops out, and so does a section\n * hidden by them, and a section or a row left without fields. `indexes` are the indexes of the\n * array items the nodes are in, outermost first.\n */\nexport function renderLayout(\n ctx: LayoutContext,\n nodes: readonly LayoutNode[],\n indexes: readonly number[],\n): VNode[] {\n return ctx.of.visibility\n .shownNodes(nodes, indexes, ctx.isShown)\n .map((node) => renderNode(ctx, node, indexes))\n}\n\nfunction renderNode(ctx: LayoutContext, node: LayoutNode, indexes: readonly number[]): VNode {\n const { key } = node\n switch (node.type) {\n case 'field':\n return renderField(ctx, node.node, indexes, key, (inner) =>\n renderLayout(ctx, node.children, inner),\n )\n case 'section':\n return h(\n ctx.layoutComponents.section as Component,\n { key, section: node.section },\n { default: () => renderLayout(ctx, node.children, indexes) },\n )\n case 'row':\n return h(\n ctx.layoutComponents.row as Component,\n { key, row: node.row, spans: node.children.map((cell) => cell.span) },\n {\n default: ({ index }: { index: number }) => [\n renderNode(ctx, node.children[index] as LayoutNode, indexes),\n ],\n },\n )\n case 'slot':\n return h(Fragment, { key }, ctx.slots[node.name]?.())\n }\n}\n","import {\n checkComponents,\n checkLayoutComponents,\n dotPathOf,\n type FieldNode,\n type LayoutNode,\n selectFields,\n} from '@whatsaaaa/form-builder-schema'\nimport { defineComponent, Fragment, h, type PropType } from 'vue'\nimport type { FieldComponents, LayoutComponents } from './field-components'\nimport { type LayoutContext, renderLayout } from './render-layout'\nimport { type RenderContext, renderFields, resolveComponents } from './render-fields'\nimport type { AnyJsonFormInstance } from './use-json-form'\n\n/**\n * Renders the fields of a `useJsonForm` form with your components, one per field type, where the\n * definition's `layout` puts them: the current step, with its sections, rows and slots. It renders\n * nothing of its own, so put it inside Formisch's `<Form>` with your own submit button. Its named\n * slots fill the layout's slots. `only` and `except` are read when it sets up.\n */\nexport const JsonFields = defineComponent({\n name: 'JsonFields',\n props: {\n /** What `useJsonForm` returned. */\n of: { type: Object as PropType<AnyJsonFormInstance>, required: true },\n /** Defaults to the components `useJsonForm` got. */\n components: { type: Object as PropType<FieldComponents> },\n /** Defaults to the layout components `useJsonForm` got. */\n layoutComponents: { type: Object as PropType<LayoutComponents> },\n /** Renders only these fields, by path, in the order of the definition, without the layout. */\n only: { type: Array as PropType<readonly string[]> },\n /**\n * Leaves out these fields, by path, e.g. the ones you place with `<JsonField>`. A section or a\n * row left without fields drops out too.\n */\n except: { type: Array as PropType<readonly string[]> },\n /** Renders the step at this index instead of the current one, e.g. on a review page. */\n step: { type: Number },\n },\n setup(props, { slots }) {\n const ctx: RenderContext = {\n of: props.of,\n components: resolveComponents(props.components, props.of),\n }\n const nodes = selectFields(props.of.fields, { only: props.only, except: props.except })\n // Without a layout, it renders the fields the way it always did, and so with `only`.\n if (props.only || !props.of.definition.layout) {\n checkComponents(nodes, ctx.components)\n return () => renderFields(ctx, nodes, [])\n }\n\n const { layout, steps } = props.of\n const except = new Set(props.except)\n const layoutCtx: LayoutContext = {\n ...ctx,\n layoutComponents: props.layoutComponents ?? props.of.layoutComponents ?? {},\n slots,\n isShown: (node) => !except.has(dotPathOf(node) ?? ''),\n }\n checkComponents(\n layout.steps.flatMap((step) => fieldsOf(step.children)),\n ctx.components,\n )\n checkLayoutComponents(layout, layoutCtx.layoutComponents, slots)\n\n return () => {\n const index = props.step ?? steps.index\n const step = steps.list[index]\n if (!step) throw new RangeError(`No step ${props.step}. The form has ${steps.list.length}.`)\n // Keyed by the step, so another step's fields don't take over this one's components.\n return h(Fragment, { key: index }, renderLayout(layoutCtx, step.children, []))\n }\n },\n})\n\n/** Every field of the nodes, display elements written in the layout included. */\nfunction fieldsOf(nodes: readonly LayoutNode[]): FieldNode[] {\n return nodes.flatMap((node) => {\n if (node.type === 'slot') return []\n const inner = fieldsOf(node.children)\n return node.type === 'field' ? [node.node, ...inner] : inner\n })\n}\n","import {\n type FormSchema,\n type FormStore,\n getInput,\n setInput,\n useForm,\n type ValidationMode,\n} from '@formisch/vue'\nimport {\n createSchemaBuilder,\n type FieldNode,\n type FormLayout,\n type JsonForm,\n type JsonFormSchema,\n type SchemaBuilder,\n type TypedJsonFormSchema,\n type VisibilityState,\n} from '@whatsaaaa/form-builder-schema'\nimport { computed, watch } from 'vue'\nimport type { FieldComponents, LayoutComponents } from './field-components'\nimport { type JsonFormSteps, useJsonFormSteps } from './json-form-steps'\n\nexport interface UseJsonFormOptions {\n /** Builds the schema and knows your own types and rules. Defaults to `createSchemaBuilder()`. */\n builder?: SchemaBuilder\n /** Your component for each field type, so `<JsonFields>` and `<JsonField>` don't need them. */\n components?: FieldComponents\n /** Your component for each layout type the definition's `layout` uses, like `section`. */\n layoutComponents?: LayoutComponents\n /** When a field is validated the first time, as in Formisch. */\n validate?: ValidationMode\n /** When a field is validated again after that, as in Formisch. */\n revalidate?: Exclude<ValidationMode, 'initial'>\n}\n\n/** What `useJsonForm` returns. Pass it to `<JsonFields>`. */\nexport interface JsonFormInstance<TSchema extends FormSchema = JsonFormSchema> {\n /** The Formisch form: pass it to Formisch's `<Form :of>`, or to any of its methods. */\n readonly form: FormStore<TSchema>\n readonly definition: JsonForm\n readonly builder: SchemaBuilder\n /** The components from the options, if any. */\n readonly components: FieldComponents | undefined\n /** The layout components from the options, if any. */\n readonly layoutComponents: LayoutComponents | undefined\n /** The definition's fields as a tree, for `<JsonFields :only>` and `<JsonField>`. */\n readonly fields: readonly FieldNode[]\n /** The definition's layout, the way `<JsonFields>` renders it. */\n readonly layout: FormLayout\n /** The layout's steps: the current one, and Next, Back and Go to. A form without steps has one. */\n readonly steps: JsonFormSteps\n /**\n * What the conditions of the builder's extensions hide for the form's input now, like the\n * `affects` of `@whatsaaaa/form-builder-affects`: `<JsonFields>` and `<JsonField>` leave it out.\n * Read it in your own renderers. Without conditions, it hides nothing.\n */\n readonly visibility: VisibilityState\n}\n\n/** Any form `useJsonForm` returns, typed or not: what the components take. */\nexport type AnyJsonFormInstance = JsonFormInstance<FormSchema>\n\n/**\n * A Formisch form for a definition, with its schema and initial input from the builder. A\n * definition with issues throws the builder's `DefinitionError`, so run `validate()` first when it\n * comes from outside your code. The definition is read once: give the form a new `:key` to use\n * another one. With conditions, it clears the fields they clear as soon as they do, with\n * Formisch's `setInput`, wherever the fields are rendered.\n */\nexport function useJsonForm(definition: JsonForm, options?: UseJsonFormOptions): JsonFormInstance\n/**\n * The same, with the form typed by your input type, and output type when it differs, so Formisch's\n * paths and values are checked. The types are yours to keep in step with the definition.\n */\nexport function useJsonForm<TInput extends object, TOutput extends object = TInput>(\n definition: JsonForm,\n options?: UseJsonFormOptions,\n): JsonFormInstance<TypedJsonFormSchema<TInput, TOutput>>\nexport function useJsonForm(\n definition: JsonForm,\n options: UseJsonFormOptions = {},\n): JsonFormInstance {\n const builder = options.builder ?? createSchemaBuilder()\n const form = useForm({\n schema: builder.build(definition),\n initialInput: builder.getInitialInput(definition),\n validate: options.validate,\n revalidate: options.revalidate,\n })\n const layout = builder.getLayout(definition)\n const visibility = builder.getVisibility(definition)\n // Without conditions, nothing is hidden whatever the input, so the input isn't watched.\n const state = visibility.conditional\n ? computed(() => visibility.of(getInput(form)))\n : { value: visibility.of(undefined) }\n // A new state means something to clear may have come. It is empty once the fields are blank.\n if (visibility.conditional) {\n watch(\n () => state.value.toClear,\n (fields) => {\n // The paths come from the definition at runtime, so the schema's types can't check them.\n for (const { path, input } of fields) setInput(form, { path, input } as never)\n },\n )\n }\n return {\n form,\n definition,\n builder,\n components: options.components,\n layoutComponents: options.layoutComponents,\n fields: builder.getFieldTree(definition),\n layout,\n steps: useJsonFormSteps(form, layout, options, state),\n get visibility() {\n return state.value\n },\n }\n}\n"],"mappings":";;;;AAyDA,MAAM,8BAAc,IAAI,QAAgC;;AAGxD,MAAa,iBAAiB,SAA6C,YAAY,IAAI,IAAI;;;;;;;AAQ/F,SAAgB,iBACd,MACA,QACA,OAIA,YACe;CACf,MAAM,MAAM,OAAO;CAEnB,MAAM,KAAK,IAAI,CAAC;CAChB,MAAM,UAAU,eAAe,IAAI,GAAG,MAAoB;CAE1D,MAAM,OAAO,eACX,IAAI,QAAQ,MAAM,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,MAAM,aAAa,IAAI,CAAC,CAChF;CACA,MAAM,QAAQ,eAAe,KAAK,MAAM,QAAQ,QAAQ,KAAK,CAAC;CAE9D,MAAM,uBAAO,IAAI,IAAiC;CAElD,MAAM,yBAAS,IAAI,IAAY;CAE/B,eAAe,KAAK,QAAkC;EACpD,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,OAAO,UAAU,MAAM,KAAK,SAAS,KAAK,UAAU,MAAM,QAC7D,MAAM,IAAI,WAAW,WAAW,OAAO,iBAAiB,MAAM,OAAO,EAAE;EAEzE,MAAM,KAAK,IAAI,QAAQ,MAAM,OAAqB;EAClD,IAAI,UAAU,MAAM,OAAO;GACzB,KAAK,EAAE;GACP,OAAO;EACT;EAIA,MAAM,UAAU;EAChB,MAAM,EAAE,WAAW,MAAM,SAAS,IAAI;EACtC,KAAK,MAAM,QAAQ,MAAM,MAAM,MAAM,OAAO,MAAM,GAAG;GACnD,MAAM,QAAQ,aAAa,MAAM,MAAM;GACvC,IAAI,MAAM,QAAQ;IAChB,MAAM,KAAK,IAAI,QAAQ,IAAI,GAAG,KAAK;IACnC,OAAO;GACT;GACA,OAAO,OAAO,IAAI,QAAQ,IAAI,CAAC;EACjC;EACA,KAAK,EAAE;EACP,OAAO;CACT;;;;;;CAOA,SAAS,KAAK,QAAgB;EAC5B,MAAM;EACN,MAAM,SAAS,KAAK,IAAI,MAAM;EAC9B,KAAK,MAAM,QAAQ,aAAa,IAAI,SAAuB,SAAS,IAAI,CAAC,GACvE,UAAU,MAAM;GAAE;GAAM,QAAQ,QAAQ,IAAI,KAAK,UAAU,IAAI,CAAC,KAAK;EAAK,CAAU;EAEtF,GAAG,QAAQ;CACb;;CAGA,SAAS,QAAQ;EAEf,MAAM,SADQ,aAAa,QAAQ,OAAO,SAAS,IAAI,CACpC,CAAC,CAAC,KAAK,SAA2B,CAAC,KAAK,UAAU,IAAI,GAAG,SAAS,IAAI,CAAC,CAAC;EAC3F,KAAK,IAAI,GAAG,OAAO,IAAI,IAAI,MAAM,CAAC;CACpC;CAEA,MAAM,YAAY,SAA4B,UAAU,MAAM,EAAE,KAAK,CAAU;;CAG/E,eAAe,KAAK,QAAgB,OAA6B;EAC/D,OAAO,IAAI,MAAM;EACjB,IAAI,WAAW,GAAG,OAAO,MAAM;EAC/B,GAAG,QAAQ;EACX,MAAM,SAAS;EAEf,MAAM,QAAQ,MAAM,MAAM,UAAU,MAAM,MAAM,SAAS,OAAO;EAChE,IAAI,OAAO,MAAM,MAAM,EAAE,MAAM,MAAM,KAAc,CAAC;CACtD;CAEA,MAAM,QAAuB;EAC3B,IAAI,OAAO;GACT,OAAO,KAAK;EACd;EACA,IAAI,QAAQ;GACV,OAAO,MAAM;EACf;EACA,IAAI,UAAU;GACZ,OAAO,QAAQ;EACjB;EACA,IAAI,UAAU;GACZ,OAAO,MAAM,UAAU;EACzB;EACA,IAAI,SAAS;GACX,OAAO,MAAM,UAAU,KAAK,MAAM,SAAS;EAC7C;EACA,YAAa,MAAM,SAAS,QAAQ,QAAQ,KAAK,IAAI,KAAK,MAAM,QAAQ,CAAC;EACzE,YAAY;GACV,IAAI,MAAM,QAAQ,GAAG,KAAK,IAAI,QAAQ,KAAK,MAAM,MAAM,QAAQ,EAAgB,CAAC;EAClF;EACA;CACF;CACA,IAAI,IAAI,SAAS,GAAG,WAAW;CAC/B,OAAO;CAEP,SAAS,aAAa;EACpB,YAAY,IAAI,OAAO,UAAU;GAE/B,MAAM,eAAe,MAAM,YAAY;GACvC,IAAI,CAAC,OAAO,IAAI,GAAG,KAAK,KAAK,iBAAiB,YAAY,KAAK,aAAa;GAC5E,IAAI,WAAW,MAAM,cAAc,UAAU,SAAc,IAAI;EACjE,CAAC;EAGD,YACQ,KAAK,cACX,OAAO,YAAY,QAAQ;GACzB,IAAI,cAAc,CAAC,OAAO,KAAK,SAAS;GACxC,MAAM,EAAE,WAAW,MAAM,SAAS,IAAI;GACtC,MAAM,QAAQ,KAAK;GACnB,MAAM,QAAQ,MAAM,MAAM,SAAS,aAAa,MAAM,MAAM,CAAC,CAAC,MAAM;GACpE,MAAM,SAAS,QAAQ,IAAI,QAAQ,KAAK,IAAI;GAC5C,IAAI,SAAS,MAAM,QAAQ,KAAK,IAAI,MAAM,OACxC,MAAM,KAAK,QAAQ,aAAa,OAAO,MAAM,CAAC;EAElD,CACF;EAIA,IAAI,OAAO,aAAa,aAAa;EACrC,MAAM,YAAY,UAAiB;GACjC,IAAI,MAAM,WAAW,cAAc,IAAI,KAAK,MAAM,QAAQ;GAC1D,MAAM,eAAe;GACrB,MAAM,yBAAyB;GAC/B,MAAW,KAAK;EAClB;EACA,SAAS,iBAAiB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC;EAC/D,IAAI,gBAAgB,GAClB,qBAAqB,SAAS,oBAAoB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;CAE5F;AACF;;AAGA,MAAM,kBAAkB,IAAI,SAAe,YAAY,WAAW,OAAO,CAAC;;AAG1E,SAAS,cAAc,MAA8C;CACnE,OAAQ,KAAoE,YAAY,EAAE;AAC5F;;;ACtNA,MAAa,aAAa,gBAAgB;CACxC,MAAM;CACN,OAAO;EACL,IAAI;GAAE,MAAM;GAAyC,UAAU;EAAK;EACpE,MAAM;GAAE,MAAM;GAA+B,UAAU;EAAK;EAC5D,MAAM;GAAE,MAAM;GAA8B,UAAU;EAAK;EAC3D,WAAW;GAAE,MAAM,CAAC,QAAQ,QAAQ;GAA0B,UAAU;EAAK;;EAE7E,YAAY;GAAE,MAAM;GAAkD,UAAU;EAAK;CACvF;CACA,MAAM,OAAO;EAEX,MAAM,aAAa,MAAM;EACzB,MAAM,QAAQ,oBACN,MAAM,GAAG,aACR,EAAE,MAAM,KAAK,EAAE,EACxB;EAGA,MAAM,SAAS,cAAc,MAAM,GAAG,IAAI;EAC1C,MAAM,UAAU;GAEd,WAAW;IACT,OAAO,MAAM,GAAG,MAAM;KACpB,MAAM,KAAK;KACX,cAAc,MAAM,GAAG,QAAQ,aAAa,MAAM,KAAK,KAAK;IAC9D,CAAC;IACD,SAAS,OAAO;GAClB;GACA,SAAS,UAAkB;IACzB,OAAO,MAAM,GAAG,MAAM;KAAE,MAAM,KAAK;KAAG,IAAI;IAAM,CAAC;IACjD,SAAS,OAAO;GAClB;GACA,OAAO,MAAc,OAAe;IAClC,KAAK,MAAM,GAAG,MAAM;KAAE,MAAM,KAAK;KAAG;KAAM;IAAG,CAAC;IAC9C,SAAS,OAAO;GAClB;EACF;EAEA,aAAa;GACX,MAAM,aAA8B;IAClC,OAAO,MAAM,KAAK;IAClB,MAAM,MAAM;IACZ,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,GAAG;GACL;GACA,OAAO,EAAE,MAAM,WAAW,YAAY,EACpC,UAAU,EAAE,YAA+B,MAAM,WAAW,KAAK,EACnE,CAAC;EACH;CACF;AACF,CAAC;;;AC/CD,MAAa,aAAa,gBAAgB;CACxC,MAAM;CACN,OAAO;EACL,IAAI;GAAE,MAAM;GAAyC,UAAU;EAAK;EACpE,MAAM;GAAE,MAAM;GAA+B,UAAU;EAAK;EAC5D,MAAM;GAAE,MAAM;GAA8B,UAAU;EAAK;EAC3D,WAAW;GAAE,MAAM,CAAC,QAAQ,QAAQ;GAA0B,UAAU;EAAK;CAC/E;CACA,MAAM,OAAO;EAEX,MAAM,QAAQ,eACN,MAAM,GAAG,aACR,EAAE,MAAM,MAAM,KAAc,EACrC;EAGA,MAAM,SAAS,cAAc,MAAM,GAAG,IAAI;EAC1C,MAAM,YAAY,UAAmB;GACnC,MAAM,QAAQ,YAAY,OAAO,MAAM,IAAI;GAC3C,SAAS,OAAO;EAClB;EACA,MAAM,aAAgC,SAClC;GACE,IAAI,OAAO;IACT,OAAO,MAAM,MAAM;GACrB;GACA,IAAI,YAAY;IACd,OAAO,MAAM,MAAM;GACrB;GACA,MAAM,YAAY,MAAM,MAAM,IAAI,OAAO;GACzC,eAAe;IACb,MAAM,MAAM,QAAQ;IACpB,OAAO,OAAO;GAChB;GACA,WAAW,UAAU;IACnB,MAAM,MAAM,SAAS,KAAK;IAC1B,OAAO,QAAQ;GACjB;GACA,cAAc;IACZ,MAAM,MAAM,OAAO;IACnB,OAAO,MAAM;GACf;EACF,IACA,MAAM;EAEV,aAAa;GACX,MAAM,aAA8B;IAClC,OAAO,MAAM,KAAK;IAClB,MAAM,MAAM;IACZ,MAAM,MAAM,KAAK;IACjB,UAAU,WAAW,MAAM,KAAK,KAAK;IACrC,OAAO,MAAM;IACb,QAAQ,MAAM;IACd;IACA;GACF;GACA,OAAO,EAAE,MAAM,WAAW,UAAU;EACtC;CACF;AACF,CAAC;;;AC1DD,SAAgB,kBACd,YACA,IACiB;CACjB,MAAM,WAAW,cAAc,GAAG;CAClC,IAAI,CAAC,UACH,MAAM,IAAI,UAAU,qEAAqE;CAE3F,OAAO;AACT;;;;;AAMA,SAAgB,aACd,KACA,OACA,SACS;CACT,MAAM,EAAE,eAAe,IAAI;CAE3B,OAAO,MAAM,SAAS,MAAM,aAC1B,WAAW,SAAS,MAAM,OAAO,IAC7B,CAAC,IACD,CACE,YAAY,KAAK,MAAM,SAAS,UAAU,IAAI,KAAK,IAAI,aAAa,UAClE,aAAa,KAAK,KAAK,UAAU,KAAK,CACxC,CACF,CACN;AACF;;;;;AAMA,SAAgB,YACd,KACA,MACA,SACA,KACA,UACO;CACP,MAAM,YAAY,IAAI,WAAW,KAAK;CACtC,MAAM,OAAO,YAAY,KAAK,UAAU,OAAO;CAC/C,QAAQ,KAAK,MAAb;EACE,KAAK,WACH,OAAO,EAAE,WAAW;GAAE;GAAK,OAAO,KAAK;EAAM,CAAC;EAChD,KAAK,SACH,OAAO,EAAE,WAAW;GAAE;GAAK,OAAO,KAAK;GAAO;EAAK,GAAG,EAAE,eAAe,SAAS,OAAO,EAAE,CAAC;EAC5F,KAAK,SACH,OAAO,EAAE,YAAY;GACnB;GACA,IAAI,IAAI;GACR;GACA;GACA;GACA,aAAa,UAAkB,SAAS,CAAC,GAAG,SAAS,KAAK,CAAC;EAC7D,CAAC;EACH,KAAK,SACH,OAAO,EAAE,YAAY;GAAE;GAAK,IAAI,IAAI;GAAI;GAAM;GAAM;EAAU,CAAC;CACnE;AACF;;;;;;;AClEA,MAAa,YAAY,gBAAgB;CACvC,MAAM;CACN,OAAO;;EAEL,IAAI;GAAE,MAAM;GAAyC,UAAU;EAAK;;EAEpE,MAAM;GAAE,MAAM;GAAQ,UAAU;EAAK;;EAErC,YAAY,EAAE,MAAM,OAAoC;CAC1D;CACA,MAAM,OAAO;EACX,MAAM,OAAO,UAAU,MAAM,GAAG,QAAQ,MAAM,MAAM,EAAE,QAAQ,KAAK,CAAC;EACpE,MAAM,MAAqB;GACzB,IAAI,MAAM;GACV,YAAY,kBAAkB,MAAM,YAAY,MAAM,EAAE;EAC1D;EACA,gBAAgB,CAAC,IAAI,GAAG,IAAI,UAAU;EAEtC,aACE,MAAM,GAAG,WAAW,SAAS,MAAM,CAAC,CAAC,IACjC,OACA,YAAY,KAAK,MAAM,CAAC,GAAG,UAAU,IAAI,KAAK,OAAO,YACnD,aAAa,KAAK,KAAK,UAAU,OAAO,CAC1C;CACR;AACF,CAAC;;;;;;;ACjBD,SAAgB,aACd,KACA,OACA,SACS;CACT,OAAO,IAAI,GAAG,WACX,WAAW,OAAO,SAAS,IAAI,OAAO,CAAC,CACvC,KAAK,SAAS,WAAW,KAAK,MAAM,OAAO,CAAC;AACjD;AAEA,SAAS,WAAW,KAAoB,MAAkB,SAAmC;CAC3F,MAAM,EAAE,QAAQ;CAChB,QAAQ,KAAK,MAAb;EACE,KAAK,SACH,OAAO,YAAY,KAAK,KAAK,MAAM,SAAS,MAAM,UAChD,aAAa,KAAK,KAAK,UAAU,KAAK,CACxC;EACF,KAAK,WACH,OAAO,EACL,IAAI,iBAAiB,SACrB;GAAE;GAAK,SAAS,KAAK;EAAQ,GAC7B,EAAE,eAAe,aAAa,KAAK,KAAK,UAAU,OAAO,EAAE,CAC7D;EACF,KAAK,OACH,OAAO,EACL,IAAI,iBAAiB,KACrB;GAAE;GAAK,KAAK,KAAK;GAAK,OAAO,KAAK,SAAS,KAAK,SAAS,KAAK,IAAI;EAAE,GACpE,EACE,UAAU,EAAE,YAA+B,CACzC,WAAW,KAAK,KAAK,SAAS,QAAsB,OAAO,CAC7D,EACF,CACF;EACF,KAAK,QACH,OAAO,EAAE,UAAU,EAAE,IAAI,GAAG,IAAI,MAAM,KAAK,KAAK,GAAG,CAAC;CACxD;AACF;;;;;;;;ACnCA,MAAa,aAAa,gBAAgB;CACxC,MAAM;CACN,OAAO;;EAEL,IAAI;GAAE,MAAM;GAAyC,UAAU;EAAK;;EAEpE,YAAY,EAAE,MAAM,OAAoC;;EAExD,kBAAkB,EAAE,MAAM,OAAqC;;EAE/D,MAAM,EAAE,MAAM,MAAqC;;;;;EAKnD,QAAQ,EAAE,MAAM,MAAqC;;EAErD,MAAM,EAAE,MAAM,OAAO;CACvB;CACA,MAAM,OAAO,EAAE,SAAS;EACtB,MAAM,MAAqB;GACzB,IAAI,MAAM;GACV,YAAY,kBAAkB,MAAM,YAAY,MAAM,EAAE;EAC1D;EACA,MAAM,QAAQ,aAAa,MAAM,GAAG,QAAQ;GAAE,MAAM,MAAM;GAAM,QAAQ,MAAM;EAAO,CAAC;EAEtF,IAAI,MAAM,QAAQ,CAAC,MAAM,GAAG,WAAW,QAAQ;GAC7C,gBAAgB,OAAO,IAAI,UAAU;GACrC,aAAa,aAAa,KAAK,OAAO,CAAC,CAAC;EAC1C;EAEA,MAAM,EAAE,QAAQ,UAAU,MAAM;EAChC,MAAM,SAAS,IAAI,IAAI,MAAM,MAAM;EACnC,MAAM,YAA2B;GAC/B,GAAG;GACH,kBAAkB,MAAM,oBAAoB,MAAM,GAAG,oBAAoB,CAAC;GAC1E;GACA,UAAU,SAAS,CAAC,OAAO,IAAI,UAAU,IAAI,KAAK,EAAE;EACtD;EACA,gBACE,OAAO,MAAM,SAAS,SAAS,SAAS,KAAK,QAAQ,CAAC,GACtD,IAAI,UACN;EACA,sBAAsB,QAAQ,UAAU,kBAAkB,KAAK;EAE/D,aAAa;GACX,MAAM,QAAQ,MAAM,QAAQ,MAAM;GAClC,MAAM,OAAO,MAAM,KAAK;GACxB,IAAI,CAAC,MAAM,MAAM,IAAI,WAAW,WAAW,MAAM,KAAK,iBAAiB,MAAM,KAAK,OAAO,EAAE;GAE3F,OAAO,EAAE,UAAU,EAAE,KAAK,MAAM,GAAG,aAAa,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC;EAC/E;CACF;AACF,CAAC;;AAGD,SAAS,SAAS,OAA2C;CAC3D,OAAO,MAAM,SAAS,SAAS;EAC7B,IAAI,KAAK,SAAS,QAAQ,OAAO,CAAC;EAClC,MAAM,QAAQ,SAAS,KAAK,QAAQ;EACpC,OAAO,KAAK,SAAS,UAAU,CAAC,KAAK,MAAM,GAAG,KAAK,IAAI;CACzD,CAAC;AACH;;ACJA,SAAgB,YACd,YACA,UAA8B,CAAC,GACb;CAClB,MAAM,UAAU,QAAQ,WAAW,oBAAoB;CACvD,MAAM,OAAO,QAAQ;EACnB,QAAQ,QAAQ,MAAM,UAAU;EAChC,cAAc,QAAQ,gBAAgB,UAAU;EAChD,UAAU,QAAQ;EAClB,YAAY,QAAQ;CACtB,CAAC;CACD,MAAM,SAAS,QAAQ,UAAU,UAAU;CAC3C,MAAM,aAAa,QAAQ,cAAc,UAAU;CAEnD,MAAM,QAAQ,WAAW,cACrB,eAAe,WAAW,GAAG,SAAS,IAAI,CAAC,CAAC,IAC5C,EAAE,OAAO,WAAW,GAAG,KAAA,CAAS,EAAE;CAEtC,IAAI,WAAW,aACb,YACQ,MAAM,MAAM,UACjB,WAAW;EAEV,KAAK,MAAM,EAAE,MAAM,WAAW,QAAQ,SAAS,MAAM;GAAE;GAAM;EAAM,CAAU;CAC/E,CACF;CAEF,OAAO;EACL;EACA;EACA;EACA,YAAY,QAAQ;EACpB,kBAAkB,QAAQ;EAC1B,QAAQ,QAAQ,aAAa,UAAU;EACvC;EACA,OAAO,iBAAiB,MAAM,QAAQ,SAAS,KAAK;EACpD,IAAI,aAAa;GACf,OAAO,MAAM;EACf;CACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whatsaaaa/form-builder-vue",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Render JSON form definitions with Formisch and your own Vue components.",
5
5
  "keywords": [
6
6
  "form",
@@ -33,11 +33,13 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@whatsaaaa/form-builder-schema": "^0.14.0"
36
+ "@whatsaaaa/form-builder-schema": "^0.15.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@arethetypeswrong/cli": "^0.18.5",
40
40
  "@formisch/vue": "^1.1.1",
41
+ "@vitest/coverage-v8": "^5.0.5",
42
+ "@whatsaaaa/form-builder-affects": "^0.1.1",
41
43
  "happy-dom": "^20.0.0",
42
44
  "publint": "^0.3.25",
43
45
  "tsdown": "^0.23.2",
@@ -54,6 +56,7 @@
54
56
  "scripts": {
55
57
  "build": "tsdown",
56
58
  "test": "vitest run",
59
+ "test:coverage": "vitest run --coverage",
57
60
  "type-check": "tsc --noEmit",
58
61
  "lint:pkg": "publint && pnpm pack --pack-destination .attw && attw .attw/*.tgz --profile esm-only"
59
62
  }