nuxt-ui-tools 1.3.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 (68) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +8 -1
  3. package/dist/runtime/form/components/actions/form-actions.vue +13 -127
  4. package/dist/runtime/form/components/page/form-page-actions.d.vue.ts +3 -0
  5. package/dist/runtime/form/components/page/form-page-actions.vue +40 -0
  6. package/dist/runtime/form/components/page/form-page-actions.vue.d.ts +3 -0
  7. package/dist/runtime/form/components/page/form-page-header.d.vue.ts +24 -0
  8. package/dist/runtime/form/components/page/form-page-header.vue +99 -0
  9. package/dist/runtime/form/components/page/form-page-header.vue.d.ts +24 -0
  10. package/dist/runtime/form/components/page/form-page-navigation.d.vue.ts +34 -0
  11. package/dist/runtime/form/components/page/form-page-navigation.vue +229 -0
  12. package/dist/runtime/form/components/page/form-page-navigation.vue.d.ts +34 -0
  13. package/dist/runtime/form/components/page/form-page-section.d.vue.ts +19 -0
  14. package/dist/runtime/form/components/page/form-page-section.vue +114 -0
  15. package/dist/runtime/form/components/page/form-page-section.vue.d.ts +19 -0
  16. package/dist/runtime/form/components/page/form-page-sections.d.vue.ts +21 -0
  17. package/dist/runtime/form/components/page/form-page-sections.vue +75 -0
  18. package/dist/runtime/form/components/page/form-page-sections.vue.d.ts +21 -0
  19. package/dist/runtime/form/components/page/form-page.d.vue.ts +80 -0
  20. package/dist/runtime/form/components/page/form-page.vue +91 -0
  21. package/dist/runtime/form/components/page/form-page.vue.d.ts +80 -0
  22. package/dist/runtime/form/components/renderer/form-field-shell.vue +7 -11
  23. package/dist/runtime/form/components/root/form.vue +25 -194
  24. package/dist/runtime/form/composables/use-form-action-buttons.d.ts +32 -0
  25. package/dist/runtime/form/composables/use-form-action-buttons.js +89 -0
  26. package/dist/runtime/form/composables/use-form-actions.d.ts +8 -5
  27. package/dist/runtime/form/composables/use-form-actions.js +1 -1
  28. package/dist/runtime/form/composables/use-form-page-scroll.d.ts +22 -0
  29. package/dist/runtime/form/composables/use-form-page-scroll.js +178 -0
  30. package/dist/runtime/form/composables/use-form-page.d.ts +114 -0
  31. package/dist/runtime/form/composables/use-form-page.js +83 -0
  32. package/dist/runtime/form/composables/use-form-root.d.ts +34 -0
  33. package/dist/runtime/form/composables/use-form-root.js +171 -0
  34. package/dist/runtime/form/composables/use-form-runtime.js +13 -4
  35. package/dist/runtime/form/composables/use-form.js +2 -22
  36. package/dist/runtime/form/fields/checkbox-card/component.vue +28 -19
  37. package/dist/runtime/form/fields/checkbox-card/types.d.ts +2 -5
  38. package/dist/runtime/form/fields/choice-card/choice-card-label.d.vue.ts +17 -0
  39. package/dist/runtime/form/fields/choice-card/choice-card-label.vue +50 -0
  40. package/dist/runtime/form/fields/choice-card/choice-card-label.vue.d.ts +17 -0
  41. package/dist/runtime/form/fields/choice-card/types.d.ts +31 -0
  42. package/dist/runtime/form/fields/choice-card/types.js +0 -0
  43. package/dist/runtime/form/fields/choice-card/use-choice-card.d.ts +22 -0
  44. package/dist/runtime/form/fields/choice-card/use-choice-card.js +52 -0
  45. package/dist/runtime/form/fields/radio-card/component.vue +17 -18
  46. package/dist/runtime/form/fields/radio-card/types.d.ts +2 -4
  47. package/dist/runtime/form/index.d.ts +1 -1
  48. package/dist/runtime/form/index.js +7 -1
  49. package/dist/runtime/form/schema/index.d.ts +1 -1
  50. package/dist/runtime/form/schema/index.js +1 -0
  51. package/dist/runtime/form/schema/page.d.ts +50 -0
  52. package/dist/runtime/form/schema/page.js +25 -0
  53. package/dist/runtime/form/types/index.d.ts +1 -0
  54. package/dist/runtime/form/types/page.d.ts +172 -0
  55. package/dist/runtime/form/types/page.js +0 -0
  56. package/dist/runtime/form/types/ui.d.ts +60 -0
  57. package/dist/runtime/form/utils/controls.d.ts +15 -0
  58. package/dist/runtime/form/utils/controls.js +38 -0
  59. package/dist/runtime/form/utils/layout.js +3 -1
  60. package/dist/runtime/form/utils/page.d.ts +20 -0
  61. package/dist/runtime/form/utils/page.js +107 -0
  62. package/dist/runtime/form/utils/state.d.ts +2 -0
  63. package/dist/runtime/form/utils/state.js +1 -1
  64. package/dist/runtime/form/utils/ui.js +1 -0
  65. package/dist/runtime/i18n/locales/en.js +18 -0
  66. package/dist/runtime/i18n/locales/fr.js +18 -0
  67. package/dist/runtime/i18n/types.d.ts +29 -0
  68. package/package.json +1 -1
@@ -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)
@@ -101,6 +101,24 @@ export default defineUiToolsLocale({
101
101
  resetButton: "Reset",
102
102
  submitButton: "Submit"
103
103
  },
104
+ page: {
105
+ complete: "Everything is ready.",
106
+ modifiedOne: "{count} modified.",
107
+ modifiedOther: "{count} modified.",
108
+ navigation: "Form sections",
109
+ optional: "optional",
110
+ remaining: "{count} left to complete.",
111
+ resetSection: "Reset",
112
+ sectionsOne: "{count} section",
113
+ sectionsOther: "{count} sections",
114
+ status: {
115
+ complete: "Complete",
116
+ invalid: "Has errors",
117
+ pending: "To complete"
118
+ },
119
+ unmodified: "No unsaved changes.",
120
+ unsavedChanges: "Unsaved changes"
121
+ },
104
122
  fields: {
105
123
  array: {
106
124
  addItem: "Add item",
@@ -101,6 +101,24 @@ export default defineUiToolsLocale({
101
101
  resetButton: "R\xE9initialiser",
102
102
  submitButton: "Soumettre"
103
103
  },
104
+ page: {
105
+ complete: "Tout est pr\xEAt.",
106
+ modifiedOne: "{count} modifi\xE9e.",
107
+ modifiedOther: "{count} modifi\xE9es.",
108
+ navigation: "Sections du formulaire",
109
+ optional: "optionnel",
110
+ remaining: "{count} \xE0 compl\xE9ter.",
111
+ resetSection: "R\xE9initialiser",
112
+ sectionsOne: "{count} section",
113
+ sectionsOther: "{count} sections",
114
+ status: {
115
+ complete: "Compl\xE8te",
116
+ invalid: "Contient des erreurs",
117
+ pending: "\xC0 compl\xE9ter"
118
+ },
119
+ unmodified: "Aucune modification en cours.",
120
+ unsavedChanges: "Modifications non enregistr\xE9es"
121
+ },
104
122
  fields: {
105
123
  array: {
106
124
  addItem: "Ajouter un \xE9l\xE9ment",
@@ -275,6 +275,35 @@ export interface UiToolsFormMessages {
275
275
  cancelButton: string;
276
276
  resetButton: string;
277
277
  };
278
+ /** Form page chrome. Counts use `Intl.PluralRules`: `One` for "one", `Other` otherwise. */
279
+ page: {
280
+ /** Accessible name of the section navigation when the schema gives it no title. */
281
+ navigation: string;
282
+ /** Marks an optional section, in the navigation and on its card. */
283
+ optional: string;
284
+ /** Badge under the page title and name of a section's dirty marker. */
285
+ unsavedChanges: string;
286
+ /** Button of a modified section that puts its values back. */
287
+ resetSection: string;
288
+ /** Bold count inserted in `remaining` and `modified`: "{count} sections". */
289
+ sectionsOne: string;
290
+ sectionsOther: string;
291
+ /** Navigation summary while required sections are incomplete: "{count} to complete." */
292
+ remaining: string;
293
+ /** Navigation summary once every required section is complete. */
294
+ complete: string;
295
+ /** Navigation summary of a form with dirty checking: "{count} modified." */
296
+ modifiedOne: string;
297
+ modifiedOther: string;
298
+ /** Navigation summary of a form with dirty checking and no change. */
299
+ unmodified: string;
300
+ /** Accessible status of a navigation entry. */
301
+ status: {
302
+ complete: string;
303
+ pending: string;
304
+ invalid: string;
305
+ };
306
+ };
278
307
  states: {
279
308
  contextError: {
280
309
  title: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-ui-tools",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Nuxt module and runtime toolkit for UI-heavy Nuxt applications",
5
5
  "homepage": "https://github.com/ChronicStone/nuxt-ui-tools#readme",
6
6
  "bugs": "https://github.com/ChronicStone/nuxt-ui-tools/issues",