@object-ui/plugin-form 17.6.0 → 18.0.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 (72) hide show
  1. package/CHANGELOG.md +4991 -0
  2. package/README.md +522 -80
  3. package/dist/DrawerForm.d.ts +42 -3
  4. package/dist/DrawerForm.d.ts.map +1 -1
  5. package/dist/EmbeddableForm.d.ts.map +1 -1
  6. package/dist/FormAnalytics.d.ts.map +1 -1
  7. package/dist/LineItemsPanel.d.ts +6 -3
  8. package/dist/LineItemsPanel.d.ts.map +1 -1
  9. package/dist/MasterDetailForm.d.ts +79 -38
  10. package/dist/MasterDetailForm.d.ts.map +1 -1
  11. package/dist/ModalForm.d.ts +60 -5
  12. package/dist/ModalForm.d.ts.map +1 -1
  13. package/dist/ObjectForm.d.ts.map +1 -1
  14. package/dist/SplitForm.d.ts +49 -3
  15. package/dist/SplitForm.d.ts.map +1 -1
  16. package/dist/TabbedForm.d.ts +75 -5
  17. package/dist/TabbedForm.d.ts.map +1 -1
  18. package/dist/WizardForm.d.ts +145 -38
  19. package/dist/WizardForm.d.ts.map +1 -1
  20. package/dist/autoLayout.d.ts +113 -8
  21. package/dist/autoLayout.d.ts.map +1 -1
  22. package/dist/closedAffordanceNotice.d.ts +14 -0
  23. package/dist/closedAffordanceNotice.d.ts.map +1 -0
  24. package/dist/customFieldsMerge.d.ts +29 -0
  25. package/dist/customFieldsMerge.d.ts.map +1 -0
  26. package/dist/deriveMasterDetail.d.ts +82 -29
  27. package/dist/deriveMasterDetail.d.ts.map +1 -1
  28. package/dist/fieldGroups.d.ts +189 -0
  29. package/dist/fieldGroups.d.ts.map +1 -1
  30. package/dist/fieldWriteGate.d.ts +136 -0
  31. package/dist/fieldWriteGate.d.ts.map +1 -0
  32. package/dist/flatFields.d.ts +11 -2
  33. package/dist/flatFields.d.ts.map +1 -1
  34. package/dist/formChrome.d.ts +55 -0
  35. package/dist/formChrome.d.ts.map +1 -0
  36. package/dist/index.d.ts +149 -26
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +3984 -2332
  39. package/dist/index.umd.cjs +1 -1
  40. package/dist/initialFieldFocus.d.ts +23 -0
  41. package/dist/initialFieldFocus.d.ts.map +1 -0
  42. package/dist/initialRecord.d.ts +72 -0
  43. package/dist/initialRecord.d.ts.map +1 -0
  44. package/dist/loadFailure.d.ts +28 -0
  45. package/dist/loadFailure.d.ts.map +1 -0
  46. package/dist/masterDetailTx.d.ts.map +1 -1
  47. package/dist/occSave.d.ts +6 -1
  48. package/dist/occSave.d.ts.map +1 -1
  49. package/dist/recordInvalidation.d.ts +33 -0
  50. package/dist/recordInvalidation.d.ts.map +1 -0
  51. package/dist/recordReadGate.d.ts +34 -0
  52. package/dist/recordReadGate.d.ts.map +1 -0
  53. package/dist/sanitize.d.ts +272 -5
  54. package/dist/sanitize.d.ts.map +1 -1
  55. package/dist/schemaDefaults.d.ts +104 -9
  56. package/dist/schemaDefaults.d.ts.map +1 -1
  57. package/dist/sectionFields.d.ts +67 -2
  58. package/dist/sectionFields.d.ts.map +1 -1
  59. package/dist/sectionGroups.d.ts +62 -0
  60. package/dist/sectionGroups.d.ts.map +1 -0
  61. package/dist/sectionPredicateDiagnostic.d.ts +38 -0
  62. package/dist/sectionPredicateDiagnostic.d.ts.map +1 -0
  63. package/dist/submitTarget.d.ts +136 -0
  64. package/dist/submitTarget.d.ts.map +1 -0
  65. package/dist/successBehavior.d.ts +44 -25
  66. package/dist/successBehavior.d.ts.map +1 -1
  67. package/dist/thankYouRedirectCountdown.d.ts +1 -1
  68. package/dist/uploadGate.d.ts +35 -0
  69. package/dist/uploadGate.d.ts.map +1 -0
  70. package/dist/writePayload.d.ts +87 -0
  71. package/dist/writePayload.d.ts.map +1 -0
  72. package/package.json +13 -12
@@ -0,0 +1,35 @@
1
+ import { default as React } from 'react';
2
+ import { useUploadingScope } from '@object-ui/fields';
3
+ export interface UploadGate {
4
+ /** True while at least one upload inside this form is still in flight. */
5
+ uploading: boolean;
6
+ /** Mount around the form body so its upload widgets report in. */
7
+ scope: ReturnType<typeof useUploadingScope>;
8
+ /** The Save button's label while `uploading`. */
9
+ busyLabel: string;
10
+ /** Why Save is unavailable — shown, and used as the refusal message. */
11
+ reason: string;
12
+ }
13
+ /**
14
+ * Own the gate for one record form. The host renders its form body inside
15
+ * {@link UploadGateProvider} with the returned `scope`.
16
+ */
17
+ export declare function useUploadGate(): UploadGate;
18
+ /** Re-exported under this package's own name so hosts import one module. */
19
+ export declare function UploadGateProvider({ gate, children, }: {
20
+ gate: UploadGate;
21
+ children: React.ReactNode;
22
+ }): React.ReactElement;
23
+ /**
24
+ * The visible reason. Rendered beside the action row, not as a toast: the
25
+ * explanation has to be readable at the moment the user looks at the control
26
+ * that will not respond, and a toast is gone by then.
27
+ *
28
+ * `role="status"` (polite) rather than `alert`: nothing has gone wrong, an
29
+ * upload is simply still running, and an assertive live region would interrupt
30
+ * a screen-reader user mid-sentence every time a file is picked.
31
+ */
32
+ export declare function UploadInFlightNotice({ gate }: {
33
+ gate: UploadGate;
34
+ }): React.ReactElement | null;
35
+ //# sourceMappingURL=uploadGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploadGate.d.ts","sourceRoot":"","sources":["../src/uploadGate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAA0B,MAAM,mBAAmB,CAAC;AAgD9E,MAAM,WAAW,UAAU;IACzB,0EAA0E;IAC1E,SAAS,EAAE,OAAO,CAAC;IACnB,kEAAkE;IAClE,KAAK,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;IAC5C,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAS1C;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,GAAG,KAAK,CAAC,YAAY,CAErB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAO9F"}
@@ -0,0 +1,87 @@
1
+ import { LoadedRecordSnapshot } from './sanitize.js';
2
+ import { FieldWriteGate } from './fieldWriteGate.js';
3
+ /** The facts of a form schema the outbound sequence reads. */
4
+ export interface FormWriteTarget {
5
+ mode?: string;
6
+ objectName: string;
7
+ recordId?: string | number | null;
8
+ /** Inline field definitions (`object-form.customFields`). */
9
+ customFields?: readonly unknown[] | null;
10
+ }
11
+ /** Where the outbound sequence gets its answers from. */
12
+ export interface FormWriteSources {
13
+ /** The object definition the form loaded, or `null` when it has none. */
14
+ objectSchema: {
15
+ fields?: Record<string, Record<string, unknown> | undefined>;
16
+ } | null | undefined;
17
+ /** The caller's field-level write verdict — {@link FieldWriteGate}. */
18
+ canEdit: FieldWriteGate | undefined;
19
+ /** The record this form read for the record it edits (objectui#10156). */
20
+ snapshot: LoadedRecordSnapshot | null | undefined;
21
+ /**
22
+ * On a create, the values the form OPENED with — its `seedCreateValues`
23
+ * result (objectui#12359). An owner the user picked against it is written,
24
+ * and one the form was seeded with and the user left alone is not. Ignored
25
+ * on an edit.
26
+ *
27
+ * Required, so a layout cannot forget it and silently drop a pick again —
28
+ * which is how every create writer behaved before. `null` says there is no
29
+ * opening value to judge against: no pick can then be told from a seed, so
30
+ * the owner stays off the wire.
31
+ */
32
+ createBaseline: Record<string, unknown> | null;
33
+ }
34
+ export interface FormWritePayloads {
35
+ /**
36
+ * Every value the form may write, as the form now holds it: stripped of what
37
+ * a form never writes and, on a create, of the fields the producer owns. On
38
+ * a create it also carries an owner the user picked (objectui#12359), since
39
+ * a create writes `payload` itself.
40
+ */
41
+ payload: Record<string, unknown>;
42
+ /**
43
+ * What the save sends — on BOTH routes, the host `submitHandler` and the
44
+ * form's own create / OCC-guarded update. On an edit, the fields of
45
+ * {@link FormWritePayloads.payload} that differ from the record the form
46
+ * read; otherwise `payload` itself.
47
+ */
48
+ writePayload: Record<string, unknown>;
49
+ }
50
+ /**
51
+ * The ONE outbound sequence of a record form: what a save writes, built from
52
+ * the values the form collected (objectui#10563).
53
+ *
54
+ * 1. `sanitizeFormData` drops what a form never writes — server-owned columns
55
+ * (objectui#10108), computed / formula / read-only columns, keys the object
56
+ * does not declare, and every field the caller's field-level security
57
+ * refuses (`canEdit`, `80c54122e`).
58
+ * 2. On a create, `createOwnerPayload` adds back an owner the user picked
59
+ * against {@link FormWriteSources.createBaseline} (objectui#12359), and then
60
+ * `omitServerResolvedDefaults` drops an empty field whose runtime default
61
+ * the producer resolves (#4069).
62
+ * 3. On an edit, `dirtyEditPayload` keeps only the fields that differ from the
63
+ * record the form read (objectui#10156), and sends the whole of step 1's
64
+ * result when it cannot settle that. It is handed the values too, so an
65
+ * owner the user changed is written while an untouched one is not
66
+ * (objectui#12205): on an edit only `writePayload` can carry it, never
67
+ * `payload`.
68
+ *
69
+ * ## Why it is one function
70
+ *
71
+ * `ObjectForm` routes a record save through several layouts, and each layout
72
+ * owns its save handler. When the sequence was spelled inline in each handler,
73
+ * three of them — `TabbedForm`, `SplitForm` and `WizardForm` (which also renders
74
+ * a simple form's mobile `stepper`) — carried none of it and wrote every value
75
+ * they held, `id`, `owner_id`, the formula columns and the field-level-refused
76
+ * ones included. ⛔ Do not spell any step of it beside a call to this function.
77
+ *
78
+ * ## The inline-members rule
79
+ *
80
+ * With a non-empty `customFields` the object definition is NOT handed to steps
81
+ * 1 and 2: an inline member may name a field the object never declares (it is
82
+ * appended after the generated set, objectui#9778), and the unknown-key strip
83
+ * would drop the value the author asked for. The server-owned roster and the
84
+ * field-level verdict still apply, because neither needs a definition.
85
+ */
86
+ export declare function formWritePayload(values: Record<string, unknown>, form: FormWriteTarget, { objectSchema, canEdit, snapshot, createBaseline }: FormWriteSources): FormWritePayloads;
87
+ //# sourceMappingURL=writePayload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writePayload.d.ts","sourceRoot":"","sources":["../src/writePayload.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,8DAA8D;AAC9D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAAC;CAC1C;AAED,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,YAAY,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IAClG,uEAAuE;IACvE,OAAO,EAAE,cAAc,GAAG,SAAS,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD;;;;;;;;;;OAUG;IACH,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,eAAe,EACrB,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,gBAAgB,GACpE,iBAAiB,CAmBnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-form",
3
- "version": "17.6.0",
3
+ "version": "18.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Form plugin for Object UI",
@@ -15,15 +15,15 @@
15
15
  }
16
16
  },
17
17
  "dependencies": {
18
- "@objectstack/spec": "^17.0.0",
19
- "lucide-react": "^1.31.0",
20
- "@object-ui/components": "17.6.0",
21
- "@object-ui/core": "17.6.0",
22
- "@object-ui/fields": "17.6.0",
23
- "@object-ui/i18n": "17.6.0",
24
- "@object-ui/permissions": "17.6.0",
25
- "@object-ui/react": "17.6.0",
26
- "@object-ui/types": "17.6.0"
18
+ "@objectstack/spec": "^18.0.0",
19
+ "lucide-react": "^1.43.0",
20
+ "@object-ui/components": "18.0.0",
21
+ "@object-ui/core": "18.0.0",
22
+ "@object-ui/fields": "18.0.0",
23
+ "@object-ui/i18n": "18.0.0",
24
+ "@object-ui/permissions": "18.0.0",
25
+ "@object-ui/react": "18.0.0",
26
+ "@object-ui/types": "18.0.0"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "react": "^18.0.0 || ^19.0.0",
@@ -35,7 +35,8 @@
35
35
  "typescript": "^6.0.3",
36
36
  "vite": "^8.2.1",
37
37
  "vite-plugin-dts": "^5.0.3",
38
- "@object-ui/data-objectstack": "17.6.0"
38
+ "@object-ui/data-objectstack": "18.0.0",
39
+ "@object-ui/test-support": "17.4.0"
39
40
  },
40
41
  "keywords": [
41
42
  "objectui",
@@ -71,7 +72,7 @@
71
72
  ],
72
73
  "scripts": {
73
74
  "build": "vite build",
74
- "test": "vitest run",
75
+ "test": "vitest run --root ../.. packages/plugin-form/",
75
76
  "type-check": "tsc --noEmit && tsc -p tsconfig.test.json",
76
77
  "lint": "eslint ."
77
78
  }