nuxt-ui-tools 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +18 -2
  3. package/dist/runtime/dashboard/components/block/dashboard-block-state.d.vue.ts +2 -0
  4. package/dist/runtime/dashboard/components/block/dashboard-block-state.vue +4 -1
  5. package/dist/runtime/dashboard/components/block/dashboard-block-state.vue.d.ts +2 -0
  6. package/dist/runtime/dashboard/components/block/dashboard-chips.d.vue.ts +20 -0
  7. package/dist/runtime/dashboard/components/block/dashboard-chips.vue +42 -0
  8. package/dist/runtime/dashboard/components/block/dashboard-chips.vue.d.ts +20 -0
  9. package/dist/runtime/dashboard/components/block/dashboard-series-picker.d.vue.ts +8 -0
  10. package/dist/runtime/dashboard/components/block/dashboard-series-picker.vue +29 -0
  11. package/dist/runtime/dashboard/components/block/dashboard-series-picker.vue.d.ts +8 -0
  12. package/dist/runtime/dashboard/components/block/dashboard-skeleton.d.vue.ts +1 -1
  13. package/dist/runtime/dashboard/components/block/dashboard-skeleton.vue.d.ts +1 -1
  14. package/dist/runtime/dashboard/components/block/dashboard-view-scope.d.vue.ts +21 -0
  15. package/dist/runtime/dashboard/components/block/dashboard-view-scope.vue +12 -0
  16. package/dist/runtime/dashboard/components/block/dashboard-view-scope.vue.d.ts +21 -0
  17. package/dist/runtime/dashboard/components/dashboard-alerts.vue +3 -3
  18. package/dist/runtime/dashboard/components/dashboard-bar-chart.d.vue.ts +14 -3
  19. package/dist/runtime/dashboard/components/dashboard-bar-chart.vue +30 -9
  20. package/dist/runtime/dashboard/components/dashboard-bar-chart.vue.d.ts +14 -3
  21. package/dist/runtime/dashboard/components/dashboard-bars.vue +4 -4
  22. package/dist/runtime/dashboard/components/dashboard-card.vue +28 -6
  23. package/dist/runtime/dashboard/components/dashboard-combo-chart.d.vue.ts +6 -1
  24. package/dist/runtime/dashboard/components/dashboard-combo-chart.vue +13 -3
  25. package/dist/runtime/dashboard/components/dashboard-combo-chart.vue.d.ts +6 -1
  26. package/dist/runtime/dashboard/components/dashboard-donut-chart.vue +5 -5
  27. package/dist/runtime/dashboard/components/dashboard-feed.vue +1 -1
  28. package/dist/runtime/dashboard/components/dashboard-filter.d.vue.ts +67 -0
  29. package/dist/runtime/dashboard/components/dashboard-filter.vue +134 -0
  30. package/dist/runtime/dashboard/components/dashboard-filter.vue.d.ts +67 -0
  31. package/dist/runtime/dashboard/components/dashboard-filters.d.vue.ts +49 -0
  32. package/dist/runtime/dashboard/components/dashboard-filters.vue +96 -0
  33. package/dist/runtime/dashboard/components/dashboard-filters.vue.d.ts +49 -0
  34. package/dist/runtime/dashboard/components/dashboard-funnel.vue +5 -5
  35. package/dist/runtime/dashboard/components/dashboard-gauge.vue +3 -3
  36. package/dist/runtime/dashboard/components/dashboard-grid.d.vue.ts +10 -3
  37. package/dist/runtime/dashboard/components/dashboard-grid.vue +24 -9
  38. package/dist/runtime/dashboard/components/dashboard-grid.vue.d.ts +10 -3
  39. package/dist/runtime/dashboard/components/dashboard-line-chart.d.vue.ts +14 -3
  40. package/dist/runtime/dashboard/components/dashboard-line-chart.vue +30 -9
  41. package/dist/runtime/dashboard/components/dashboard-line-chart.vue.d.ts +14 -3
  42. package/dist/runtime/dashboard/components/dashboard-list.d.vue.ts +3 -0
  43. package/dist/runtime/dashboard/components/dashboard-list.vue +18 -6
  44. package/dist/runtime/dashboard/components/dashboard-list.vue.d.ts +3 -0
  45. package/dist/runtime/dashboard/components/dashboard-page.d.vue.ts +53 -0
  46. package/dist/runtime/dashboard/components/dashboard-page.vue +156 -0
  47. package/dist/runtime/dashboard/components/dashboard-page.vue.d.ts +53 -0
  48. package/dist/runtime/dashboard/components/dashboard-paired-bars.vue +4 -4
  49. package/dist/runtime/dashboard/components/dashboard-refresh.d.vue.ts +1 -1
  50. package/dist/runtime/dashboard/components/dashboard-refresh.vue +1 -0
  51. package/dist/runtime/dashboard/components/dashboard-refresh.vue.d.ts +1 -1
  52. package/dist/runtime/dashboard/components/dashboard-stack-bar.vue +4 -4
  53. package/dist/runtime/dashboard/components/dashboard-stat.d.vue.ts +14 -2
  54. package/dist/runtime/dashboard/components/dashboard-stat.vue +28 -10
  55. package/dist/runtime/dashboard/components/dashboard-stat.vue.d.ts +14 -2
  56. package/dist/runtime/dashboard/components/dashboard-stats.vue +3 -3
  57. package/dist/runtime/dashboard/components/dashboard-table.d.vue.ts +1 -1
  58. package/dist/runtime/dashboard/components/dashboard-table.vue +3 -3
  59. package/dist/runtime/dashboard/components/dashboard-table.vue.d.ts +1 -1
  60. package/dist/runtime/dashboard/components/dashboard-tabs.d.vue.ts +1 -1
  61. package/dist/runtime/dashboard/components/dashboard-tabs.vue.d.ts +1 -1
  62. package/dist/runtime/dashboard/components/dashboard-total.d.vue.ts +7 -2
  63. package/dist/runtime/dashboard/components/dashboard-total.vue +10 -2
  64. package/dist/runtime/dashboard/components/dashboard-total.vue.d.ts +7 -2
  65. package/dist/runtime/dashboard/components/dashboard-view-tabs.d.vue.ts +33 -0
  66. package/dist/runtime/dashboard/components/dashboard-view-tabs.vue +66 -0
  67. package/dist/runtime/dashboard/components/dashboard-view-tabs.vue.d.ts +33 -0
  68. package/dist/runtime/dashboard/components/dashboard-widget.vue +1 -1
  69. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.d.vue.ts +44 -0
  70. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.vue +220 -0
  71. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.vue.d.ts +44 -0
  72. package/dist/runtime/dashboard/composables/use-dashboard-api.d.ts +6 -1
  73. package/dist/runtime/dashboard/composables/use-dashboard-api.js +29 -6
  74. package/dist/runtime/dashboard/composables/use-dashboard-block.d.ts +5 -4
  75. package/dist/runtime/dashboard/composables/use-dashboard-block.js +32 -15
  76. package/dist/runtime/dashboard/composables/use-dashboard-chart.d.ts +8 -1
  77. package/dist/runtime/dashboard/composables/use-dashboard-chart.js +16 -4
  78. package/dist/runtime/dashboard/composables/use-dashboard-context.d.ts +50 -0
  79. package/dist/runtime/dashboard/composables/use-dashboard-context.js +56 -0
  80. package/dist/runtime/dashboard/composables/use-dashboard-derived.js +6 -1
  81. package/dist/runtime/dashboard/composables/use-dashboard-filter-control.d.ts +16 -0
  82. package/dist/runtime/dashboard/composables/use-dashboard-filter-control.js +161 -0
  83. package/dist/runtime/dashboard/composables/use-dashboard-filter-scope.d.ts +37 -0
  84. package/dist/runtime/dashboard/composables/use-dashboard-filter-scope.js +107 -0
  85. package/dist/runtime/dashboard/composables/use-dashboard-format.d.ts +46 -6
  86. package/dist/runtime/dashboard/composables/use-dashboard-format.js +51 -8
  87. package/dist/runtime/dashboard/composables/use-dashboard-options.d.ts +11 -4
  88. package/dist/runtime/dashboard/composables/use-dashboard-options.js +33 -47
  89. package/dist/runtime/dashboard/composables/use-dashboard-remote-options.d.ts +8 -5
  90. package/dist/runtime/dashboard/composables/use-dashboard-remote-options.js +59 -70
  91. package/dist/runtime/dashboard/composables/use-dashboard-resource.d.ts +15 -4
  92. package/dist/runtime/dashboard/composables/use-dashboard-resource.js +52 -17
  93. package/dist/runtime/dashboard/composables/use-dashboard-scope.d.ts +10 -7
  94. package/dist/runtime/dashboard/composables/use-dashboard-scope.js +26 -16
  95. package/dist/runtime/dashboard/composables/use-dashboard-series-picker.d.ts +20 -0
  96. package/dist/runtime/dashboard/composables/use-dashboard-series-picker.js +30 -0
  97. package/dist/runtime/dashboard/composables/use-dashboard-time.d.ts +2 -0
  98. package/dist/runtime/dashboard/composables/use-dashboard-time.js +4 -1
  99. package/dist/runtime/dashboard/composables/use-dashboard-ui.d.ts +12 -2
  100. package/dist/runtime/dashboard/composables/use-dashboard-ui.js +3 -0
  101. package/dist/runtime/dashboard/composables/use-dashboard-views.d.ts +15 -3
  102. package/dist/runtime/dashboard/composables/use-dashboard-views.js +33 -10
  103. package/dist/runtime/dashboard/composables/use-dashboard.d.ts +18 -12
  104. package/dist/runtime/dashboard/composables/use-dashboard.js +98 -9
  105. package/dist/runtime/dashboard/index.d.ts +3 -1
  106. package/dist/runtime/dashboard/index.js +3 -1
  107. package/dist/runtime/dashboard/schema/index.d.ts +62 -30
  108. package/dist/runtime/dashboard/schema/index.js +3 -0
  109. package/dist/runtime/dashboard/types/blocks.d.ts +30 -4
  110. package/dist/runtime/dashboard/types/charts.d.ts +2 -2
  111. package/dist/runtime/dashboard/types/controls.d.ts +123 -0
  112. package/dist/runtime/dashboard/types/filters.d.ts +236 -0
  113. package/dist/runtime/dashboard/types/index.d.ts +3 -2
  114. package/dist/runtime/dashboard/types/page.d.ts +17 -0
  115. package/dist/runtime/dashboard/types/page.js +0 -0
  116. package/dist/runtime/dashboard/types/resource.d.ts +66 -28
  117. package/dist/runtime/dashboard/types/runtime.d.ts +39 -8
  118. package/dist/runtime/dashboard/types/schema.d.ts +94 -54
  119. package/dist/runtime/dashboard/types/ui.d.ts +78 -0
  120. package/dist/runtime/dashboard/utils/builders/dashboard-filters.d.ts +142 -0
  121. package/dist/runtime/dashboard/utils/builders/dashboard-filters.js +135 -0
  122. package/dist/runtime/dashboard/utils/charts.d.ts +4 -15
  123. package/dist/runtime/dashboard/utils/charts.js +26 -28
  124. package/dist/runtime/dashboard/utils/{params/codecs.d.ts → codecs.d.ts} +2 -2
  125. package/dist/runtime/dashboard/utils/{params/codecs.js → codecs.js} +1 -1
  126. package/dist/runtime/dashboard/utils/environment.d.ts +36 -0
  127. package/dist/runtime/dashboard/utils/environment.js +30 -0
  128. package/dist/runtime/dashboard/utils/filters.d.ts +44 -0
  129. package/dist/runtime/dashboard/utils/filters.js +62 -0
  130. package/dist/runtime/dashboard/utils/format.d.ts +25 -0
  131. package/dist/runtime/dashboard/utils/format.js +66 -0
  132. package/dist/runtime/dashboard/utils/grid.d.ts +17 -0
  133. package/dist/runtime/dashboard/utils/grid.js +14 -0
  134. package/dist/runtime/dashboard/utils/options.d.ts +3 -1
  135. package/dist/runtime/dashboard/utils/options.js +6 -0
  136. package/dist/runtime/dashboard/utils/remote.d.ts +7 -0
  137. package/dist/runtime/dashboard/utils/remote.js +14 -0
  138. package/dist/runtime/dashboard/utils/resource.d.ts +16 -7
  139. package/dist/runtime/dashboard/utils/resource.js +15 -9
  140. package/dist/runtime/dashboard/utils/schema.d.ts +8 -3
  141. package/dist/runtime/dashboard/utils/schema.js +9 -4
  142. package/dist/runtime/dashboard/utils/state.d.ts +11 -6
  143. package/dist/runtime/dashboard/utils/state.js +10 -5
  144. package/dist/runtime/dashboard/utils/time.d.ts +2 -0
  145. package/dist/runtime/dashboard/utils/time.js +11 -1
  146. package/dist/runtime/dashboard/utils/ui.d.ts +1 -1
  147. package/dist/runtime/dashboard/utils/ui.js +1 -1
  148. package/dist/runtime/form/components/actions/form-actions.vue +13 -127
  149. package/dist/runtime/form/components/page/form-page-actions.d.vue.ts +3 -0
  150. package/dist/runtime/form/components/page/form-page-actions.vue +40 -0
  151. package/dist/runtime/form/components/page/form-page-actions.vue.d.ts +3 -0
  152. package/dist/runtime/form/components/page/form-page-header.d.vue.ts +24 -0
  153. package/dist/runtime/form/components/page/form-page-header.vue +99 -0
  154. package/dist/runtime/form/components/page/form-page-header.vue.d.ts +24 -0
  155. package/dist/runtime/form/components/page/form-page-navigation.d.vue.ts +34 -0
  156. package/dist/runtime/form/components/page/form-page-navigation.vue +229 -0
  157. package/dist/runtime/form/components/page/form-page-navigation.vue.d.ts +34 -0
  158. package/dist/runtime/form/components/page/form-page-section.d.vue.ts +19 -0
  159. package/dist/runtime/form/components/page/form-page-section.vue +114 -0
  160. package/dist/runtime/form/components/page/form-page-section.vue.d.ts +19 -0
  161. package/dist/runtime/form/components/page/form-page-sections.d.vue.ts +21 -0
  162. package/dist/runtime/form/components/page/form-page-sections.vue +75 -0
  163. package/dist/runtime/form/components/page/form-page-sections.vue.d.ts +21 -0
  164. package/dist/runtime/form/components/page/form-page.d.vue.ts +80 -0
  165. package/dist/runtime/form/components/page/form-page.vue +91 -0
  166. package/dist/runtime/form/components/page/form-page.vue.d.ts +80 -0
  167. package/dist/runtime/form/components/renderer/form-field-shell.vue +7 -11
  168. package/dist/runtime/form/components/root/form.vue +26 -195
  169. package/dist/runtime/form/composables/use-form-action-buttons.d.ts +32 -0
  170. package/dist/runtime/form/composables/use-form-action-buttons.js +89 -0
  171. package/dist/runtime/form/composables/use-form-actions.d.ts +8 -5
  172. package/dist/runtime/form/composables/use-form-actions.js +1 -1
  173. package/dist/runtime/form/composables/use-form-page-scroll.d.ts +22 -0
  174. package/dist/runtime/form/composables/use-form-page-scroll.js +178 -0
  175. package/dist/runtime/form/composables/use-form-page.d.ts +114 -0
  176. package/dist/runtime/form/composables/use-form-page.js +83 -0
  177. package/dist/runtime/form/composables/use-form-root.d.ts +34 -0
  178. package/dist/runtime/form/composables/use-form-root.js +171 -0
  179. package/dist/runtime/form/composables/use-form-runtime.js +13 -4
  180. package/dist/runtime/form/composables/use-form.js +2 -22
  181. package/dist/runtime/form/fields/card-selection.d.ts +1 -0
  182. package/dist/runtime/form/fields/card-selection.js +1 -0
  183. package/dist/runtime/form/fields/checkbox-card/component.vue +28 -17
  184. package/dist/runtime/form/fields/checkbox-card/types.d.ts +2 -5
  185. package/dist/runtime/form/fields/checkbox-group/component.vue +5 -0
  186. package/dist/runtime/form/fields/choice-card/choice-card-label.d.vue.ts +17 -0
  187. package/dist/runtime/form/fields/choice-card/choice-card-label.vue +50 -0
  188. package/dist/runtime/form/fields/choice-card/choice-card-label.vue.d.ts +17 -0
  189. package/dist/runtime/form/fields/choice-card/types.d.ts +31 -0
  190. package/dist/runtime/form/fields/choice-card/types.js +0 -0
  191. package/dist/runtime/form/fields/choice-card/use-choice-card.d.ts +22 -0
  192. package/dist/runtime/form/fields/choice-card/use-choice-card.js +52 -0
  193. package/dist/runtime/form/fields/radio/component.vue +10 -0
  194. package/dist/runtime/form/fields/radio-card/component.vue +17 -16
  195. package/dist/runtime/form/fields/radio-card/types.d.ts +2 -4
  196. package/dist/runtime/form/index.d.ts +1 -1
  197. package/dist/runtime/form/index.js +7 -1
  198. package/dist/runtime/form/schema/index.d.ts +1 -1
  199. package/dist/runtime/form/schema/index.js +1 -0
  200. package/dist/runtime/form/schema/page.d.ts +50 -0
  201. package/dist/runtime/form/schema/page.js +25 -0
  202. package/dist/runtime/form/types/index.d.ts +1 -0
  203. package/dist/runtime/form/types/options.d.ts +1 -11
  204. package/dist/runtime/form/types/page.d.ts +172 -0
  205. package/dist/runtime/form/types/page.js +0 -0
  206. package/dist/runtime/form/types/ui.d.ts +60 -0
  207. package/dist/runtime/form/utils/controls.d.ts +15 -0
  208. package/dist/runtime/form/utils/controls.js +38 -0
  209. package/dist/runtime/form/utils/focus.js +1 -1
  210. package/dist/runtime/form/utils/layout.js +3 -1
  211. package/dist/runtime/form/utils/page.d.ts +20 -0
  212. package/dist/runtime/form/utils/page.js +107 -0
  213. package/dist/runtime/form/utils/state.d.ts +2 -0
  214. package/dist/runtime/form/utils/state.js +1 -1
  215. package/dist/runtime/form/utils/ui.js +1 -0
  216. package/dist/runtime/i18n/locales/en.js +47 -0
  217. package/dist/runtime/i18n/locales/fr.js +47 -0
  218. package/dist/runtime/i18n/types.d.ts +70 -0
  219. package/dist/runtime/shared/styles/tokens.css +1 -1
  220. package/dist/runtime/shared/types/query.d.ts +8 -0
  221. package/dist/runtime/table/types/index.d.ts +1 -0
  222. package/dist/runtime/table/types/remote-options.d.ts +64 -0
  223. package/dist/runtime/table/types/remote-options.js +0 -0
  224. package/dist/runtime/table/types/source.d.ts +10 -1
  225. package/dist/runtime/table/utils/builders/table-source.d.ts +2 -6
  226. package/dist/runtime/table/utils/index.d.ts +1 -0
  227. package/dist/runtime/table/utils/index.js +1 -0
  228. package/dist/runtime/table/utils/remote-table-options.d.ts +26 -0
  229. package/dist/runtime/table/utils/remote-table-options.js +88 -0
  230. package/package.json +4 -1
  231. package/dist/runtime/dashboard/composables/use-dashboard-param-scope.d.ts +0 -30
  232. package/dist/runtime/dashboard/composables/use-dashboard-param-scope.js +0 -71
  233. package/dist/runtime/dashboard/types/options.d.ts +0 -46
  234. package/dist/runtime/dashboard/types/params.d.ts +0 -115
  235. package/dist/runtime/dashboard/utils/builders/dashboard-params.d.ts +0 -85
  236. package/dist/runtime/dashboard/utils/builders/dashboard-params.js +0 -87
  237. /package/dist/runtime/dashboard/types/{options.js → controls.js} +0 -0
  238. /package/dist/runtime/dashboard/types/{params.js → filters.js} +0 -0
@@ -1,10 +1,8 @@
1
1
  import type { FormStatefulFieldBase } from '../../types/field-base.js';
2
2
  import type { FieldOptionValue, NullableValue } from '../../types/field-output-utils.js';
3
3
  import type { FormOptionItem, FormOptionValue, FormOptionsSource } from '../../types/options.js';
4
- export interface FormRadioCardProps {
5
- orientation?: 'horizontal' | 'vertical';
6
- }
7
- export interface FormRadioCardField<TContext = NonNullable<unknown>, TDeps = NonNullable<unknown>, TValue extends FormOptionValue = FormOptionValue, TOption extends FormOptionItem<TValue> = FormOptionItem<TValue>> extends FormStatefulFieldBase<'radio-card', TValue | null, TContext, TDeps, FormRadioCardProps> {
4
+ import type { FormChoiceCardProps } from '../choice-card/types.js';
5
+ export interface FormRadioCardField<TContext = NonNullable<unknown>, TDeps = NonNullable<unknown>, TValue extends FormOptionValue = FormOptionValue, TOption extends FormOptionItem<TValue> = FormOptionItem<TValue>> extends FormStatefulFieldBase<'radio-card', TValue | null, TContext, TDeps, FormChoiceCardProps> {
8
6
  options: FormOptionsSource<TOption, TContext, TDeps, TValue | null>;
9
7
  }
10
8
  export type RadioCardFieldOutput<TField> = FieldOptionValue<TField> | NullableValue;
@@ -1,4 +1,4 @@
1
- export { defineFormField, defineFormFields, defineFormSchema } from './schema/index.js';
1
+ export { defineFormField, defineFormFields, defineFormPageSchema, defineFormPageSection, defineFormSchema, } from './schema/index.js';
2
2
  export { useForm } from './composables/use-form.js';
3
3
  export { useFormUi } from './composables/use-form-ui.js';
4
4
  export { provideFormApi, useFormApi } from './composables/use-form-api.js';
@@ -1,4 +1,10 @@
1
- export { defineFormField, defineFormFields, defineFormSchema } from "./schema/index.js";
1
+ export {
2
+ defineFormField,
3
+ defineFormFields,
4
+ defineFormPageSchema,
5
+ defineFormPageSection,
6
+ defineFormSchema
7
+ } from "./schema/index.js";
2
8
  export { useForm } from "./composables/use-form.js";
3
9
  export { useFormUi } from "./composables/use-form-ui.js";
4
10
  export { provideFormApi, useFormApi } from "./composables/use-form-api.js";
@@ -81,4 +81,4 @@ export declare function defineFormField<const TField extends FormField>(field: T
81
81
  * Defines a reusable field group while preserving literal inference.
82
82
  */
83
83
  export declare function defineFormFields<const TFields extends readonly FormField[]>(fields: TFields): TFields;
84
- export {};
84
+ export { defineFormPageSchema, defineFormPageSection } from './page.js';
@@ -7,3 +7,4 @@ export function defineFormField(field) {
7
7
  export function defineFormFields(fields) {
8
8
  return fields;
9
9
  }
10
+ export { defineFormPageSchema, defineFormPageSection } from "./page.js";
@@ -0,0 +1,50 @@
1
+ import type { FormContextData, FormContextDefinition, FormPageSchema, FormPageSchemaInput, FormPageSection } from '../types/index.js';
2
+ /**
3
+ * Defines one section of a form page while preserving literal field inference, so each section
4
+ * can live in its own file as a plain typed function.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * export function billingSection({ hasActiveContract }: { hasActiveContract: boolean }) {
9
+ * return defineFormPageSection({
10
+ * key: 'billing',
11
+ * label: () => t('account.sections.billing'),
12
+ * fields: [
13
+ * {
14
+ * key: 'vtestId',
15
+ * type: 'text',
16
+ * label: 'VTEST ID',
17
+ * // `accountType` belongs to another section: a page is one form, one state.
18
+ * dependencies: ['accountType'],
19
+ * required: ({ deps }) => hasActiveContract || 'accountType' in deps,
20
+ * },
21
+ * ],
22
+ * })
23
+ * }
24
+ * ```
25
+ */
26
+ export declare function defineFormPageSection<const TSection extends FormPageSection>(section: TSection): TSection;
27
+ /**
28
+ * Defines a form page: one form whose fields are grouped in `sections`. Each section becomes a
29
+ * card of the page and an entry of its navigation; render it with `<UiFormPage :form />`.
30
+ *
31
+ * The result is a normal form schema. Its `fields` are the cards generated from the sections,
32
+ * so `useForm`, validation, cross-section dependencies, and the typed `formData` work as for any
33
+ * schema, and the same schema opens in a modal or drawer as a stack of cards.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * export function accountFormSchema({ account }: { account?: Account } = {}) {
38
+ * return defineFormPageSchema({
39
+ * header: { title: () => t(account ? 'account.edit' : 'account.create') },
40
+ * controls: { dirtyCheck: Boolean(account) },
41
+ * navigation: { title: () => t('account.sections.title') },
42
+ * sections: [accountTypeSection(), identitySection(), billingSection({ hasActiveContract: false })],
43
+ * })
44
+ * }
45
+ * ```
46
+ */
47
+ export declare function defineFormPageSchema<const TContext extends FormContextDefinition, const TSections extends readonly FormPageSection<FormContextData<NoInfer<TContext>>>[]>(schema: FormPageSchemaInput<TContext, TSections> & {
48
+ context: TContext;
49
+ }): FormPageSchema<FormPageSchemaInput<TContext, TSections>>;
50
+ export declare function defineFormPageSchema<const TSections extends readonly FormPageSection<FormContextData<undefined>>[]>(schema: FormPageSchemaInput<undefined, TSections>): FormPageSchema<FormPageSchemaInput<undefined, TSections>>;
@@ -0,0 +1,25 @@
1
+ import { isRecord } from "../utils/path.js";
2
+ export function defineFormPageSection(section) {
3
+ return section;
4
+ }
5
+ export function defineFormPageSchema(schema) {
6
+ if (!isRecord(schema) || !Array.isArray(schema.sections)) {
7
+ return schema;
8
+ }
9
+ return { ...schema, fields: schema.sections.filter(isRecord).map(toSectionCard) };
10
+ }
11
+ const CARD_PROPERTIES = ["condition", "dependencies", "description"];
12
+ function toSectionCard(section) {
13
+ const card = {
14
+ fields: section.fields,
15
+ key: section.key,
16
+ label: section.label,
17
+ type: "card"
18
+ };
19
+ for (const property of CARD_PROPERTIES) {
20
+ if (section[property] !== void 0) {
21
+ card[property] = section[property];
22
+ }
23
+ }
24
+ return card;
25
+ }
@@ -15,6 +15,7 @@ export type * from './layout';
15
15
  export type * from './options';
16
16
  export type * from './options-runtime';
17
17
  export type * from './overlay';
18
+ export type * from './page';
18
19
  export type * from './output';
19
20
  export type * from './runtime';
20
21
  export type * from './schema';
@@ -1,4 +1,4 @@
1
- import type { RemoteCursorOptionsPage, RemoteOptionsPage, RemoteOptionsPageRequest, RemoteOptionsPagination, RemoteOptionsResult, RemoteOptionsSearch } from '../../shared/types/remote-options.js';
1
+ import type { RemoteOptionsPageRequest, RemoteOptionsPagination, RemoteOptionsResult, RemoteOptionsSearch } from '../../shared/types/remote-options.js';
2
2
  import type { FormValue } from './/index.js';
3
3
  import type { FormFieldCallback, FormFieldCallbackParams } from './callbacks.js';
4
4
  import type { FormQueryOptions } from './context.js';
@@ -68,12 +68,6 @@ export interface FormOptionConfig<TOption, TContext = NonNullable<unknown>, TDep
68
68
  /** Disable the field while its option source has no usable data yet. */
69
69
  disableOnLoading?: boolean;
70
70
  }
71
- /** @deprecated Use `RemoteOptionsPage` from `#ui-tools/shared`. Kept for public type compatibility. */
72
- export type FormRemoteOptionsPage<TOption> = RemoteOptionsPage<TOption>;
73
- /** @deprecated Use `RemoteCursorOptionsPage` from `#ui-tools/shared`. Kept for public type compatibility. */
74
- export type FormRemoteCursorOptionsPage<TOption> = RemoteCursorOptionsPage<TOption>;
75
- /** @deprecated Use `RemoteOptionsResult` from `#ui-tools/shared`. Kept for public type compatibility. */
76
- export type FormRemoteOptionsResult<TOption> = RemoteOptionsResult<TOption>;
77
71
  export interface FormRemoteOptionsRequest<TContext = NonNullable<unknown>, TDeps = NonNullable<unknown>, TValue = FormValue, TOption = FormValue> extends FormFieldCallbackParams<TContext, TDeps, TValue, TOption> {
78
72
  /** Current debounced search term. Empty when the menu lists unfiltered options. */
79
73
  search: string;
@@ -87,10 +81,6 @@ export interface FormRemoteSelectedRequest<TContext = NonNullable<unknown>, TDep
87
81
  values: readonly FormOptionValue[];
88
82
  }
89
83
  export type FormRemoteSource<TResult> = FormQueryOptions<TResult> | Promise<TResult>;
90
- /** @deprecated Use `RemoteOptionsPagination` from `#ui-tools/shared`. Kept for public type compatibility. */
91
- export type FormRemotePagination = RemoteOptionsPagination;
92
- /** @deprecated Use `RemoteOptionsSearch` from `#ui-tools/shared`. Kept for public type compatibility. */
93
- export type FormRemoteSearch = RemoteOptionsSearch;
94
84
  /**
95
85
  * Remote option configuration: server-side search, pagination, and selected-value hydration.
96
86
  */
@@ -0,0 +1,172 @@
1
+ import type { FormValue } from './/index.js';
2
+ import type { FormAction } from './actions.js';
3
+ import type { FormApi, FormSubmitHandler } from './api.js';
4
+ import type { FormFieldCallback } from './callbacks.js';
5
+ import type { FormContextData, FormContextDefinition } from './context.js';
6
+ import type { FormField } from './field.js';
7
+ import type { FormLayoutConfig } from './layout.js';
8
+ import type { FormControlsConfig, FormDrawerConfig, FormFullscreenConfig, FormHeaderConfig, FormModalConfig } from './schema.js';
9
+ import type { FormUiConfig } from './ui.js';
10
+ import type { FormText } from './utils.js';
11
+ /**
12
+ * One section of a form page: a card in the page and an entry in its navigation.
13
+ *
14
+ * Every text accepts a function, so it can be translated:
15
+ * `label: () => t('account.sections.identity')`.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * export function identitySection() {
20
+ * return defineFormPageSection({
21
+ * key: 'identity',
22
+ * label: 'Identity',
23
+ * description: 'display name, legal entity and official identifiers',
24
+ * fields: [
25
+ * { key: 'name', type: 'text', label: 'Name', required: true },
26
+ * { key: 'legalEntity', type: 'text', label: 'Legal entity', required: true },
27
+ * ],
28
+ * })
29
+ * }
30
+ * ```
31
+ */
32
+ export interface FormPageSection<TContext = NonNullable<unknown>, TFields extends readonly FormField<TContext>[] = readonly FormField<TContext>[]> {
33
+ /**
34
+ * Names the section: its navigation entry, its scroll target, and the URL hash that opens the
35
+ * page on it (`#identity`). Also used as the section element's `id`, so keep it unique on the
36
+ * page. It does not prefix the keys of the section's fields.
37
+ */
38
+ key: string;
39
+ /** Title on the section card and in the navigation. */
40
+ label: FormText;
41
+ /** Supporting copy next to the title. */
42
+ description?: FormText;
43
+ /**
44
+ * Shows the section as optional and leaves it out of the sections left to complete. A section
45
+ * without a required field is optional already; set this when its required fields are filled
46
+ * by their defaults and the user has nothing to do there.
47
+ */
48
+ optional?: boolean;
49
+ /** Grid of the section's fields, merged over the schema `layout`. */
50
+ layout?: FormLayoutConfig;
51
+ /** Raw dependency paths read before evaluating `condition`. */
52
+ dependencies?: readonly (string | readonly [string, string])[];
53
+ /** Hides the section, its navigation entry, and its fields while it returns `false`. */
54
+ condition?: FormFieldCallback<boolean, TContext>;
55
+ /** Fields of the section. They write at the form root, as if the section were not there. */
56
+ fields: TFields;
57
+ }
58
+ /**
59
+ * Side navigation of a form page. Its entries are the page sections.
60
+ */
61
+ export interface FormPageNavigationConfig {
62
+ /** Heading above the entries, e.g. `'Création'`. Accepts a function to translate it. */
63
+ title?: FormText;
64
+ }
65
+ /**
66
+ * Schema accepted by `defineFormPageSchema`: a form schema whose `sections` replace `fields`.
67
+ */
68
+ export interface FormPageSchemaInput<TContext extends FormContextDefinition | undefined, TSections extends readonly FormPageSection<FormContextData<TContext>>[]> {
69
+ /** Stable key used by persistence, diagnostics, and test selectors. */
70
+ formKey?: string;
71
+ /** Page heading: `title`, `description`, and the `eyebrow` above the title. */
72
+ header?: FormHeaderConfig;
73
+ /** Form-scoped data sources exposed to fields as `ctx`. */
74
+ context?: TContext;
75
+ /** Default grid of every section. */
76
+ layout?: FormLayoutConfig;
77
+ /** Form-scoped presentation overrides, merged after app defaults. */
78
+ ui?: FormUiConfig;
79
+ /** Runtime lifecycle and validation controls. `dirtyCheck` rings the modified sections. */
80
+ controls?: FormControlsConfig;
81
+ /** Modal-shell sizing, used when the same schema opens in a modal. */
82
+ modal?: FormModalConfig;
83
+ /** Drawer-shell sizing, used when the same schema opens in a drawer. */
84
+ drawer?: FormDrawerConfig;
85
+ /** Fullscreen-shell behavior, used when the same schema opens fullscreen. */
86
+ fullscreen?: FormFullscreenConfig;
87
+ /** Page actions. Omit to render the built-in submit action. */
88
+ actions?: readonly FormAction[];
89
+ /** Runs after validation and before the external submit handler. Return `false` to cancel submit. */
90
+ onBeforeSubmit?: FormSubmitHandler<FormValue, never>;
91
+ /** Submit lifecycle hook. */
92
+ submit?: (params: {
93
+ value: FormValue;
94
+ api: FormApi;
95
+ ctx: FormContextData<TContext>;
96
+ }) => Promise<void> | void;
97
+ /** Side navigation of the page. */
98
+ navigation?: FormPageNavigationConfig;
99
+ /** Sections of the page, in navigation order. */
100
+ sections: TSections;
101
+ }
102
+ /**
103
+ * Card field generated from a section. It renders the section when the schema opens in an
104
+ * overlay, and its fields keep their root paths because a card adds no path segment.
105
+ */
106
+ export type FormPageSectionCard<TSection> = TSection extends {
107
+ readonly key: infer TKey extends string;
108
+ readonly fields: infer TFields;
109
+ } ? {
110
+ readonly type: 'card';
111
+ readonly key: TKey;
112
+ readonly fields: TFields;
113
+ } : never;
114
+ /** Card fields generated from the sections of a form page, in order. */
115
+ export type FormPageSectionCards<TSections extends readonly FormValue[]> = {
116
+ readonly [TIndex in keyof TSections]: FormPageSectionCard<TSections[TIndex]>;
117
+ };
118
+ /**
119
+ * Schema returned by `defineFormPageSchema`: a normal form schema whose `fields` are the cards
120
+ * generated from `sections`, plus the `sections` and `navigation` that `FormPage` reads.
121
+ */
122
+ export type FormPageSchema<TInput extends {
123
+ readonly sections: readonly FormValue[];
124
+ }> = TInput & {
125
+ readonly fields: FormPageSectionCards<TInput['sections']>;
126
+ };
127
+ /** A section paired with the card generated for it, as the page runtime reads them. */
128
+ export interface FormPageSectionEntry {
129
+ section: FormPageSection;
130
+ card: FormField;
131
+ }
132
+ /** How a form page scrolls to a section. */
133
+ export interface FormPageScrollOptions {
134
+ /** Defaults to `smooth`, or `instant` when the user prefers reduced motion. */
135
+ behavior?: ScrollBehavior;
136
+ /** Records the section in the URL hash. Defaults to the page `hash` option. */
137
+ hash?: boolean;
138
+ /** Moves focus to the section title, for keyboard and screen reader users. */
139
+ focus?: boolean;
140
+ }
141
+ /**
142
+ * Where a section stands:
143
+ *
144
+ * - `invalid`: it shows at least one validation error
145
+ * - `complete`: nothing required is missing and it shows no error; an optional section also
146
+ * needs a value, entered by the user or provided by the form input
147
+ * - `pending`: anything else
148
+ */
149
+ export type FormPageSectionStatus = 'invalid' | 'complete' | 'pending';
150
+ /**
151
+ * Live state of a visible section, as the page navigation and section slots receive it.
152
+ */
153
+ export interface FormPageSectionState {
154
+ /** Section key. */
155
+ key: string;
156
+ /** Position among the visible sections. */
157
+ index: number;
158
+ /** Resolved title. */
159
+ label: string;
160
+ /** Resolved supporting copy. */
161
+ description?: string;
162
+ /** True when the section is declared optional or has no required field. */
163
+ optional: boolean;
164
+ /** Number of required fields without a value. */
165
+ missing: number;
166
+ /** Summary of the section's requirements, see `FormPageSectionStatus`. */
167
+ status: FormPageSectionStatus;
168
+ /** True when a value of the section differs from the form's baseline. */
169
+ dirty: boolean;
170
+ /** Dirty paths inside the section. */
171
+ dirtyPaths: readonly string[];
172
+ }
File without changes
@@ -183,6 +183,64 @@ export interface FormOverlayUi {
183
183
  overlay?: FormUiClass;
184
184
  content?: FormUiClass;
185
185
  }
186
+ /**
187
+ * Slots of a form page and its parts. Data attributes carry the live state, so a slot can
188
+ * restyle one state: `data-active` on the current navigation entry, `data-state`
189
+ * (`complete`, `invalid`, `pending`) on entries and indicators, `data-dirty` on modified
190
+ * sections and entries.
191
+ *
192
+ * Two CSS variables place sections under the pinned header: `--nut-form-page-header` (its
193
+ * measured height, set by the page) and `--nut-form-page-gap` (the room below it, `24px` by
194
+ * default). Set them on an element around the navigation and sections, such as the root.
195
+ */
196
+ export interface FormPageUi {
197
+ /** The `<form>` element, which scrolls on its own and is the container of the page queries. */
198
+ root?: FormUiClass;
199
+ /** Grid holding the navigation and the sections. */
200
+ body?: FormUiClass;
201
+ header?: FormUiClass;
202
+ headerContent?: FormUiClass;
203
+ heading?: FormUiClass;
204
+ eyebrow?: FormUiClass;
205
+ title?: FormUiClass;
206
+ /** Line under the title: the description and the unsaved-changes badge. */
207
+ meta?: FormUiClass;
208
+ unsaved?: FormUiClass;
209
+ actions?: FormUiClass;
210
+ navigation?: FormUiClass;
211
+ /** Holds the navigation title and the entries. */
212
+ navigationGroup?: FormUiClass;
213
+ navigationTitle?: FormUiClass;
214
+ navigationList?: FormUiClass;
215
+ /** List item around each entry. */
216
+ navigationEntry?: FormUiClass;
217
+ navigationItem?: FormUiClass;
218
+ navigationIndicator?: FormUiClass;
219
+ /** Check of a complete section in the indicator. */
220
+ navigationIndicatorIcon?: FormUiClass;
221
+ /** Dot in the indicator of the current section while it is pending. */
222
+ navigationIndicatorMarker?: FormUiClass;
223
+ navigationLabel?: FormUiClass;
224
+ navigationOptional?: FormUiClass;
225
+ navigationDirty?: FormUiClass;
226
+ /** Wrapper under the entries, whose padding insets the summary. */
227
+ navigationFooter?: FormUiClass;
228
+ /** The summary, with its top border: "3 sections left to complete". */
229
+ navigationSummary?: FormUiClass;
230
+ /** The bold "3 sections" of the summary. */
231
+ navigationSummaryCount?: FormUiClass;
232
+ sections?: FormUiClass;
233
+ /** Placeholder card shown while the schema context loads. */
234
+ sectionSkeleton?: FormUiClass;
235
+ section?: FormUiClass;
236
+ sectionHeader?: FormUiClass;
237
+ sectionTitle?: FormUiClass;
238
+ sectionDescription?: FormUiClass;
239
+ sectionOptional?: FormUiClass;
240
+ sectionActions?: FormUiClass;
241
+ sectionReset?: FormUiClass;
242
+ sectionBody?: FormUiClass;
243
+ }
186
244
  export interface FormUiPartConfig<TUi> {
187
245
  ui?: TUi;
188
246
  }
@@ -219,4 +277,6 @@ export interface FormUiConfig {
219
277
  modal?: FormUiPartConfig<FormOverlayUi>;
220
278
  drawer?: FormUiPartConfig<FormOverlayUi>;
221
279
  fullscreen?: FormUiPartConfig<FormOverlayUi>;
280
+ /** Form page rendered by `FormPage` and its parts. */
281
+ page?: FormUiPartConfig<FormPageUi>;
222
282
  }
@@ -0,0 +1,15 @@
1
+ import type { FormUiConfig, FormValidationMode, FormValue } from '../types/index.js';
2
+ /** Reads the schema `controls` object. */
3
+ export declare function getSchemaControls(schema: FormValue): any;
4
+ /** Resolves `controls.syncInput`: `true`, a path list, or no synchronization. */
5
+ export declare function getSchemaSyncInput(schema: FormValue): boolean | readonly string[];
6
+ /** Resolves `controls.validate`, validating everything by default. */
7
+ export declare function getSchemaValidationMode(schema: FormValue): FormValidationMode;
8
+ /** Resolves `controls.autoFocus`: a raw field path, `true` for the first field, or `false`. */
9
+ export declare function getSchemaAutoFocus(schema: FormValue): string | boolean;
10
+ /** True when `controls.dirtyCheck` enables dirty metadata and reset affordances. */
11
+ export declare function getSchemaDirtyCheck(schema: FormValue): boolean;
12
+ /** Reads `controls.confirmNavOnDirty` as authored. */
13
+ export declare function getSchemaDirtyNavigation(schema: FormValue): unknown;
14
+ /** Reads the schema-level `ui` overrides. */
15
+ export declare function getSchemaUi(schema: FormValue): FormUiConfig | undefined;
@@ -0,0 +1,38 @@
1
+ import { isRecord } from "./path.js";
2
+ import { isBoolean, isString, stringArray } from "./predicate.js";
3
+ export function getSchemaControls(schema) {
4
+ if (!isRecord(schema)) {
5
+ return;
6
+ }
7
+ const controls = Object.getOwnPropertyDescriptor(schema, "controls")?.value;
8
+ return isRecord(controls) ? controls : void 0;
9
+ }
10
+ function getSchemaControl(schema, name) {
11
+ const controls = getSchemaControls(schema);
12
+ return controls ? Object.getOwnPropertyDescriptor(controls, name)?.value : void 0;
13
+ }
14
+ export function getSchemaSyncInput(schema) {
15
+ const value = getSchemaControl(schema, "syncInput");
16
+ return isBoolean(value) ? value : stringArray(value);
17
+ }
18
+ export function getSchemaValidationMode(schema) {
19
+ const value = getSchemaControl(schema, "validate");
20
+ return value === false || value === "required" || value === "validators" ? value : true;
21
+ }
22
+ export function getSchemaAutoFocus(schema) {
23
+ const value = getSchemaControl(schema, "autoFocus");
24
+ return isString(value) || isBoolean(value) ? value : false;
25
+ }
26
+ export function getSchemaDirtyCheck(schema) {
27
+ return getSchemaControl(schema, "dirtyCheck") === true;
28
+ }
29
+ export function getSchemaDirtyNavigation(schema) {
30
+ return getSchemaControl(schema, "confirmNavOnDirty");
31
+ }
32
+ export function getSchemaUi(schema) {
33
+ if (!isRecord(schema)) {
34
+ return void 0;
35
+ }
36
+ const value = Object.getOwnPropertyDescriptor(schema, "ui")?.value;
37
+ return isRecord(value) ? value : void 0;
38
+ }
@@ -24,7 +24,7 @@ export async function focusFormFieldElement(fieldElement) {
24
24
  focusableElement.focus({ preventScroll: true });
25
25
  fieldElement.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" });
26
26
  await waitForFocusSettle();
27
- return document.activeElement === focusableElement;
27
+ return focusableElement.ownerDocument.activeElement === focusableElement;
28
28
  }
29
29
  export async function focusFirstInvalidFormField(errors) {
30
30
  for (const error of errors) {
@@ -8,7 +8,9 @@ export function resolveFormLayoutConfig(base, override) {
8
8
  return {
9
9
  columns: override?.columns ?? base?.columns ?? FORM_LAYOUT_DEFAULTS.columns,
10
10
  fieldSpan: override?.fieldSpan ?? base?.fieldSpan ?? FORM_LAYOUT_DEFAULTS.fieldSpan,
11
- gap: override?.gap ?? base?.gap ?? FORM_LAYOUT_DEFAULTS.gap
11
+ gap: override?.gap ?? base?.gap ?? FORM_LAYOUT_DEFAULTS.gap,
12
+ labelPosition: override?.labelPosition ?? base?.labelPosition,
13
+ labelWidth: override?.labelWidth ?? base?.labelWidth
12
14
  };
13
15
  }
14
16
  export function normalizeFormLayoutGap(value) {
@@ -0,0 +1,20 @@
1
+ import type { FormObject, FormPageSectionEntry, FormPageSectionState, FormRuntime, FormValue } from '../types/index.js';
2
+ /** Pairs each section of a page schema with the card `defineFormPageSchema` generated for it. */
3
+ export declare function getFormPageSections(schema: FormValue): readonly FormPageSectionEntry[];
4
+ /** Resolved heading of the page navigation. */
5
+ export declare function getFormPageNavigationTitle(schema: FormValue): string | undefined;
6
+ /** True while the section's `condition` lets it render. */
7
+ export declare function isFormPageSectionVisible(entry: FormPageSectionEntry, runtime: FormRuntime): boolean;
8
+ /**
9
+ * Live state of one visible section: what it still misses, whether it shows errors, and what
10
+ * changed since the baseline.
11
+ */
12
+ export declare function resolveFormPageSectionState(params: {
13
+ entry: FormPageSectionEntry;
14
+ index: number;
15
+ runtime: FormRuntime;
16
+ /** Input the form was opened with: a value it provides counts as filled in. */
17
+ input: FormObject | undefined;
18
+ /** False when the validation mode does not enforce required fields. */
19
+ requiredEnforced: boolean;
20
+ }): FormPageSectionState;
@@ -0,0 +1,107 @@
1
+ import { createFormFieldInstance } from "./field-instance.js";
2
+ import { getPathValue, isRecord } from "./path.js";
3
+ import { isBoolean, isFunction, isNumber, isString } from "./predicate.js";
4
+ import {
5
+ fieldPath,
6
+ getChildFields,
7
+ getSchemaFields,
8
+ isEmptyValue,
9
+ isFlatPassthroughField,
10
+ isObjectContainerField,
11
+ resolveRequired
12
+ } from "./state.js";
13
+ import { resolveFormText } from "./text.js";
14
+ export function getFormPageSections(schema) {
15
+ if (!isRecord(schema) || !Array.isArray(schema.sections)) {
16
+ return [];
17
+ }
18
+ const cards = getSchemaFields(schema);
19
+ return schema.sections.filter(isFormPageSection).flatMap((section) => {
20
+ const card = cards.find((field) => field.key === section.key);
21
+ return card ? [{ card, section }] : [];
22
+ });
23
+ }
24
+ export function getFormPageNavigationTitle(schema) {
25
+ if (!isRecord(schema) || !isRecord(schema.navigation)) {
26
+ return void 0;
27
+ }
28
+ const { title } = schema.navigation;
29
+ return isFormText(title) ? resolveFormText(title) : void 0;
30
+ }
31
+ export function isFormPageSectionVisible(entry, runtime) {
32
+ return !hasCondition(entry.card) || runtime.shouldRender(entry.card, [entry.card.key]);
33
+ }
34
+ export function resolveFormPageSectionState(params) {
35
+ const { entry, runtime } = params;
36
+ const leaves = collectVisibleLeaves(entry.section.fields, [], runtime);
37
+ const paths = leaves.map((leaf) => leaf.path.join("."));
38
+ const contains = (candidate) => paths.some((path) => isPathWithin(candidate, path));
39
+ const dirtyPaths = runtime.dirtyPaths.value.filter(contains);
40
+ const invalid = runtime.errors.value.some((error) => contains(error.path));
41
+ const required = params.requiredEnforced ? leaves.filter((leaf) => isRequiredLeaf(leaf, runtime)) : [];
42
+ const missing = required.filter((leaf) => isEmptyValue(runtime.getValue(leaf.path))).length;
43
+ const optional = entry.section.optional === true || required.length === 0;
44
+ const filled = !optional || leaves.some((leaf) => isProvided(leaf, runtime, dirtyPaths, params.input));
45
+ return {
46
+ description: resolveFormText(entry.section.description),
47
+ dirty: dirtyPaths.length > 0,
48
+ dirtyPaths,
49
+ index: params.index,
50
+ key: entry.section.key,
51
+ label: resolveFormText(entry.section.label) ?? entry.section.key,
52
+ missing,
53
+ optional,
54
+ status: invalid ? "invalid" : missing === 0 && filled ? "complete" : "pending"
55
+ };
56
+ }
57
+ function collectVisibleLeaves(fields, parentPath, runtime) {
58
+ return fields.flatMap((field) => {
59
+ if (field.ignore === true) {
60
+ return [];
61
+ }
62
+ const path = fieldPath(parentPath, field);
63
+ if (hasCondition(field) && !runtime.shouldRender(field, path)) {
64
+ return [];
65
+ }
66
+ if (createFormFieldInstance(field).state.is("stateless")) {
67
+ return [];
68
+ }
69
+ if (isFlatPassthroughField(field)) {
70
+ return collectVisibleLeaves(getChildFields(field), parentPath, runtime);
71
+ }
72
+ if (isObjectContainerField(field)) {
73
+ return collectVisibleLeaves(getChildFields(field), path, runtime);
74
+ }
75
+ return [{ field, path }];
76
+ });
77
+ }
78
+ function isRequiredLeaf(leaf, runtime) {
79
+ const required = Object.getOwnPropertyDescriptor(leaf.field, "required")?.value;
80
+ if (isBoolean(required)) {
81
+ return required;
82
+ }
83
+ const validation = Object.getOwnPropertyDescriptor(leaf.field, "validation")?.value;
84
+ if (!isFunction(required) && !isRecord(validation)) {
85
+ return false;
86
+ }
87
+ return resolveRequired(leaf.field, runtime.getFieldCallbackParams(leaf.path, leaf.field)) === true;
88
+ }
89
+ function isProvided(leaf, runtime, dirtyPaths, input) {
90
+ if (isEmptyValue(runtime.getValue(leaf.path))) {
91
+ return false;
92
+ }
93
+ const path = leaf.path.join(".");
94
+ return dirtyPaths.some((dirtyPath) => isPathWithin(dirtyPath, path)) || !isEmptyValue(getPathValue(input ?? {}, leaf.path));
95
+ }
96
+ function hasCondition(field) {
97
+ return isFunction(Object.getOwnPropertyDescriptor(field, "condition")?.value);
98
+ }
99
+ function isPathWithin(path, scope) {
100
+ return path === scope || path.startsWith(`${scope}.`);
101
+ }
102
+ function isFormPageSection(value) {
103
+ return isRecord(value) && isString(value.key) && isFormText(value.label) && Array.isArray(value.fields);
104
+ }
105
+ function isFormText(value) {
106
+ return isString(value) || isNumber(value) || isFunction(value);
107
+ }
@@ -30,4 +30,6 @@ export declare function getMatrixRows(field: FormField): any[];
30
30
  export declare function resolveRequired(field: FormField, params: FormFieldCallbackParams): any;
31
31
  export declare function resolveRequiredMessage(field: FormField, fallback?: string): string;
32
32
  export declare function isEmptyValue(value: FormValue): boolean;
33
+ /** Child fields of a container, with the fields of every tab for tabs. */
34
+ export declare function getChildFields(field: FormField): FormField[];
33
35
  export declare function getArrayItemFields(field: FormField, item: FormObject): FormField[];
@@ -588,7 +588,7 @@ function isFormField(value) {
588
588
  const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
589
589
  return isString(value.key) && isString(type) && isRegisteredFormFieldType(type);
590
590
  }
591
- function getChildFields(field) {
591
+ export function getChildFields(field) {
592
592
  const tabs = Object.getOwnPropertyDescriptor(field, "tabs")?.value;
593
593
  if (Array.isArray(tabs)) {
594
594
  return tabs.flatMap((tab) => {
@@ -39,6 +39,7 @@ function mergeFormUiPair(current, next) {
39
39
  group: mergePart(current.group, next.group),
40
40
  matrix: mergePart(current.matrix, next.matrix),
41
41
  modal: mergePart(current.modal, next.modal),
42
+ page: mergePart(current.page, next.page),
42
43
  root: mergePart(current.root, next.root),
43
44
  tree: mergePart(current.tree, next.tree),
44
45
  treeSelect: mergePart(current.treeSelect, next.treeSelect)