@object-ui/core 17.3.0 → 17.6.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 (99) hide show
  1. package/CHANGELOG.md +2018 -0
  2. package/README.md +38 -34
  3. package/dist/actions/ActionEngine.d.ts +43 -26
  4. package/dist/actions/ActionEngine.js +67 -54
  5. package/dist/actions/ActionRunner.d.ts +281 -31
  6. package/dist/actions/ActionRunner.js +458 -36
  7. package/dist/actions/actionKeys.d.ts +163 -27
  8. package/dist/actions/actionKeys.js +238 -27
  9. package/dist/actions/actionResponse.js +1 -1
  10. package/dist/actions/index.d.ts +1 -0
  11. package/dist/actions/index.js +1 -0
  12. package/dist/actions/recordIdParam.d.ts +77 -0
  13. package/dist/actions/recordIdParam.js +37 -0
  14. package/dist/actions/serverActionHandler.d.ts +1 -1
  15. package/dist/actions/serverActionHandler.js +1 -1
  16. package/dist/data-scope/ViewDataProvider.d.ts +37 -12
  17. package/dist/data-scope/ViewDataProvider.js +83 -5
  18. package/dist/data-scope/element-data-source.d.ts +113 -0
  19. package/dist/data-scope/element-data-source.js +216 -0
  20. package/dist/data-scope/index.d.ts +2 -1
  21. package/dist/data-scope/index.js +1 -0
  22. package/dist/evaluator/ExpressionEvaluator.d.ts +42 -1
  23. package/dist/evaluator/ExpressionEvaluator.js +42 -1
  24. package/dist/evaluator/SafeExpressionParser.js +0 -4
  25. package/dist/evaluator/declaredPredicate.d.ts +119 -0
  26. package/dist/evaluator/declaredPredicate.js +152 -0
  27. package/dist/evaluator/fieldRules.d.ts +35 -0
  28. package/dist/evaluator/fieldRules.js +79 -20
  29. package/dist/evaluator/index.d.ts +2 -0
  30. package/dist/evaluator/index.js +2 -0
  31. package/dist/evaluator/listConditional.d.ts +54 -4
  32. package/dist/evaluator/listConditional.js +125 -19
  33. package/dist/evaluator/optionRules.d.ts +55 -0
  34. package/dist/evaluator/optionRules.js +60 -0
  35. package/dist/evaluator/predicateInput.d.ts +51 -3
  36. package/dist/evaluator/predicateInput.js +62 -5
  37. package/dist/evaluator/rowPredicateCanon.d.ts +67 -0
  38. package/dist/evaluator/rowPredicateCanon.js +208 -0
  39. package/dist/index.d.ts +8 -1
  40. package/dist/index.js +31 -1
  41. package/dist/protocols/DndProtocol.d.ts +42 -1
  42. package/dist/protocols/KeyboardProtocol.d.ts +31 -1
  43. package/dist/protocols/SharingProtocol.d.ts +11 -1
  44. package/dist/registry/Registry.d.ts +62 -16
  45. package/dist/theme/ThemeEngine.d.ts +0 -8
  46. package/dist/theme/ThemeEngine.js +22 -103
  47. package/dist/theme/index.d.ts +1 -1
  48. package/dist/theme/index.js +7 -1
  49. package/dist/types/index.d.ts +125 -12
  50. package/dist/utils/chart-presentation.d.ts +205 -0
  51. package/dist/utils/chart-presentation.js +280 -0
  52. package/dist/utils/chart-series.d.ts +390 -23
  53. package/dist/utils/chart-series.js +776 -32
  54. package/dist/utils/column-identity.d.ts +43 -0
  55. package/dist/utils/column-identity.js +47 -1
  56. package/dist/utils/compare-to.d.ts +40 -13
  57. package/dist/utils/compare-to.js +4 -32
  58. package/dist/utils/dashboard-filters.d.ts +54 -8
  59. package/dist/utils/dashboard-filters.js +261 -12
  60. package/dist/utils/dataset-format.d.ts +73 -14
  61. package/dist/utils/dataset-format.js +142 -9
  62. package/dist/utils/dataset-pivot.d.ts +28 -7
  63. package/dist/utils/dataset-pivot.js +27 -6
  64. package/dist/utils/debug.js +7 -0
  65. package/dist/utils/dom-props.d.ts +137 -0
  66. package/dist/utils/dom-props.js +153 -0
  67. package/dist/utils/expand-fields.d.ts +97 -7
  68. package/dist/utils/expand-fields.js +97 -7
  69. package/dist/utils/filter-tokens.js +0 -1
  70. package/dist/utils/freeze-schema.d.ts +38 -1
  71. package/dist/utils/freeze-schema.js +10 -0
  72. package/dist/utils/humanize-label.d.ts +60 -0
  73. package/dist/utils/humanize-label.js +62 -0
  74. package/dist/utils/managedBy.d.ts +27 -2
  75. package/dist/utils/normalize-list-view.d.ts +36 -6
  76. package/dist/utils/normalize-list-view.js +93 -9
  77. package/dist/utils/number-display.d.ts +155 -0
  78. package/dist/utils/number-display.js +71 -0
  79. package/dist/utils/predicate-fields.d.ts +29 -4
  80. package/dist/utils/predicate-fields.js +44 -4
  81. package/dist/utils/resolve-view-id.d.ts +31 -0
  82. package/dist/utils/resolve-view-id.js +45 -0
  83. package/dist/utils/retired-field-types.d.ts +90 -0
  84. package/dist/utils/retired-field-types.js +124 -0
  85. package/dist/utils/sort-query.d.ts +57 -0
  86. package/dist/utils/sort-query.js +35 -0
  87. package/dist/utils/unmaterialized-fields.d.ts +52 -0
  88. package/dist/utils/unmaterialized-fields.js +57 -0
  89. package/dist/validation/index.d.ts +1 -0
  90. package/dist/validation/index.js +1 -0
  91. package/dist/validation/schema-validator.js +105 -0
  92. package/dist/validation/server-owned-value.d.ts +62 -0
  93. package/dist/validation/server-owned-value.js +99 -0
  94. package/dist/validation/validators/object-validation-engine.js +0 -2
  95. package/package.json +5 -5
  96. package/dist/__benchmarks__/core.bench.d.ts +0 -8
  97. package/dist/__benchmarks__/core.bench.js +0 -53
  98. package/dist/utils/merge-views-into-objects.d.ts +0 -19
  99. package/dist/utils/merge-views-into-objects.js +0 -39
@@ -0,0 +1,208 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * The row-predicate spelling CANON, and the Phase-1 deprecation warning for the
10
+ * two spellings that are not it (objectui#5330).
11
+ *
12
+ * ## The canon (maintainer ruling, 2026-08-20 — option B)
13
+ *
14
+ * A row predicate — `visible` / `disabled` / `enabled` on an action renderer, a
15
+ * row scope, a `record:alert` — binds the row THREE ways today: canonical
16
+ * `record.status`, bare shorthand `status`, and legacy `data.status`
17
+ * (objectui#4075 / PR #4079 bound all four action renderers all three ways to
18
+ * restore consistency, deliberately without deciding which of them is
19
+ * CONTRACT). This module is where that decision now lives:
20
+ *
21
+ * > **The canon is `record.*`.** The bare shorthand and `data.*` are
22
+ * > client-side tolerances in a deprecation window, kept because stored
23
+ * > metadata carries them, warned about here, and removable only after a
24
+ * > stored-metadata survey sizes the window (⛔ no removal before the survey).
25
+ *
26
+ * It mirrors the objectstack#7917 option-② precedent for the identical shape (a
27
+ * renderer tolerance quietly becoming a second de-facto contract — AGENTS.md
28
+ * #0.1), whose objectui half is `utils/dashboard-filters.ts`' bare-string
29
+ * `options` shorthand: same three phases, same reason the warning is not
30
+ * decoration (ADR-0078 — nothing silently inert; a tolerance nothing ever
31
+ * reports can never be retired, because nothing would ever show that the last
32
+ * document carrying it is gone).
33
+ *
34
+ * ## The canon states the SERVER's accept set, not this client's
35
+ *
36
+ * The ruling made that the dev's first measurement, because a canon that only
37
+ * describes the renderer would be the very thing it exists to end. Measured
38
+ * against `@objectstack/formula@17.1.0` — the engine the server evaluates with,
39
+ * and the one `fieldRules.ts` already delegates to:
40
+ *
41
+ * | spelling | server runtime (`buildScope` + `celEngine`) | server authoring oracle |
42
+ * |---|---|---|
43
+ * | `record.status` | ✅ `{ ok: true, value: true }` | ✅ accepted |
44
+ * | bare `status` | ❌ `Unknown variable: status` | ❌ refused (`'status'`) |
45
+ * | `data.status` | ❌ `Unknown variable: data` | ⚠️ **silently accepted** |
46
+ *
47
+ * `buildScope({ record })` mounts exactly `['record']` — `data` is never bound
48
+ * and the row's fields are never flattened to top level. So **the server
49
+ * accepts `record.*` and nothing else**; both other spellings fault there. The
50
+ * three-way binding is a client tolerance with no server counterpart, which is
51
+ * precisely why it is the client's job to warn.
52
+ *
53
+ * ⚠️ The `data.*` row is the dangerous one and the reason this warning exists
54
+ * at all. `data` IS in `@objectstack/formula`'s `SCOPE_ROOTS`, so the server's
55
+ * bare-identifier oracle waves `data.status` through — that list is a
56
+ * deliberately generous "never faults" LINT BASELINE, not the runtime accept
57
+ * set. A `data.*` row predicate therefore passes every authoring gate the
58
+ * platform has and then binds nothing at runtime: it is not an error, it is a
59
+ * constant `false`, and a `visible` that is constantly false is a button that
60
+ * silently never appears. That is the #4075 fail-closed family's exact
61
+ * signature, and this client is the only layer positioned to catch it.
62
+ *
63
+ * ## `data.*` is DEPRECATED HERE, not everywhere — the canon is layer-scoped
64
+ *
65
+ * `data` is the CANONICAL root one layer over, in a metadata-editing form (the
66
+ * row under edit): objectstack's `CANONICAL_ROOT_BY_LAYER` reads
67
+ * `{ runtime: 'record', metadata: 'data' }` (ADR-0089 D3), and objectui's own
68
+ * `app-shell` metadata-admin `SchemaForm` binds `{ data: row }` on purpose. So
69
+ * `data.*` is not a legacy alias to be deprecated platform-wide — it is a
70
+ * WRONG-LAYER paste on a runtime record surface, and only that is what this
71
+ * module reports. Stating the deprecation unqualified would contradict
72
+ * ADR-0089 D3 and break the metadata-editing layer's own contract.
73
+ *
74
+ * ## Why the detection reuses the server's oracle instead of a regex
75
+ *
76
+ * `collectCelRootIdentifiers` and `firstUndeclaredReference` are
77
+ * `@objectstack/formula` exports — the same two oracles objectstack's
78
+ * `visibility-bare-identifier` gate uses. Reading roots off the canonical AST
79
+ * rather than pattern-matching the source is what keeps this from inventing a
80
+ * second dialect judgement client-side: a string this module cannot parse is
81
+ * NOT this module's verdict to give (syntax belongs to the gates that own it),
82
+ * and it stands down rather than guessing.
83
+ */
84
+ import { collectCelRootIdentifiers, firstUndeclaredReference } from '@objectstack/formula';
85
+ /** The one canonical row-predicate root. */
86
+ export const ROW_PREDICATE_CANONICAL_ROOT = 'record';
87
+ /**
88
+ * The metadata-editing-form root (ADR-0089 D3). Canonical on THAT layer, and a
89
+ * wrong-layer paste on a runtime record surface — see the module note.
90
+ */
91
+ const METADATA_LAYER_ROOT = 'data';
92
+ /**
93
+ * Detect a non-canonical spelling in ONE row predicate, or `null` when the
94
+ * predicate is already canonical (or is not this module's verdict to give).
95
+ *
96
+ * Deliberately conservative in both arms — every condition below can only
97
+ * REMOVE a finding, never invent one, because a false deprecation warning sends
98
+ * an author to rewrite a predicate that was correct:
99
+ *
100
+ * - **Unparseable source** → `null`. Syntax is another gate's verdict.
101
+ * - **Bare shorthand** is reported only when the undeclared identifier is an own
102
+ * key of THIS row. That is what makes it unambiguously the #4075 shorthand
103
+ * rather than a host-scope global this module cannot see (a deployment key
104
+ * that is simply not in `SCOPE_ROOTS` would otherwise read as a bare field).
105
+ * - **`data.*`** is reported only when the caller confirms `data` names the row
106
+ * (`dataNamesRow`). A surface whose `data` is the host scope's own — a
107
+ * `rowless` dialog, a metadata-editing form — is a legitimate `data.*` site
108
+ * and is left alone.
109
+ *
110
+ * Only the FIRST finding is returned, and the bare-shorthand arm is checked
111
+ * first: it is the arm the server refuses outright (`visibility-bare-identifier`
112
+ * is an `error` there, while a mis-layered root is a `warning`), so when a
113
+ * predicate manages both it is the one the author must fix to have anything
114
+ * evaluate at all.
115
+ *
116
+ * @param source The predicate's CEL text. Callers must have already
117
+ * routed legacy `${…}`-dialect strings elsewhere — in that
118
+ * dialect `data.*` is the NORMAL spelling, and reporting it
119
+ * here would be a false positive on every legacy predicate.
120
+ * @param row The row the predicate is bound against.
121
+ * @param dataNamesRow Whether `data` is bound to that same row on this surface.
122
+ */
123
+ export function detectNonCanonicalRowSpelling(source, row, dataNamesRow) {
124
+ if (typeof source !== 'string' || !source.trim())
125
+ return null;
126
+ const roots = collectCelRootIdentifiers(source);
127
+ // Not parseable through the canonical front end — not our verdict.
128
+ if (!roots || roots.ok !== true)
129
+ return null;
130
+ // (1) Bare shorthand — the arm the server refuses outright.
131
+ const bare = firstUndeclaredReference(source);
132
+ if (typeof bare === 'string' &&
133
+ row != null &&
134
+ typeof row === 'object' &&
135
+ Object.prototype.hasOwnProperty.call(row, bare)) {
136
+ return {
137
+ kind: 'bare-shorthand',
138
+ identifier: bare,
139
+ canonical: `${ROW_PREDICATE_CANONICAL_ROOT}.${bare}`,
140
+ };
141
+ }
142
+ // (2) Wrong-layer `data.*` root — silent at runtime on the server.
143
+ if (dataNamesRow && Array.isArray(roots.roots) && roots.roots.includes(METADATA_LAYER_ROOT)) {
144
+ return {
145
+ kind: 'metadata-layer-root',
146
+ identifier: METADATA_LAYER_ROOT,
147
+ canonical: ROW_PREDICATE_CANONICAL_ROOT,
148
+ };
149
+ }
150
+ return null;
151
+ }
152
+ /**
153
+ * Dev-mode gate, matching `utils/dashboard-filters.ts` and `actions/actionKeys.ts`
154
+ * — a deprecation warning that floods a production console is a warning that
155
+ * gets muted.
156
+ */
157
+ const isDev = () => globalThis.process?.env
158
+ ?.NODE_ENV !== 'production';
159
+ /**
160
+ * Warn-once memo, keyed by the `(label, predicate source)` pair — the same
161
+ * identity `warnEvalError` uses, and JSON-encoded for the same reason: the
162
+ * separator that boundary once used was a raw U+0000, which made the file
163
+ * carrying it binary to grep (objectstack#5450). Keying on the source alone
164
+ * would report the first surface carrying a shorthand `status` predicate and
165
+ * stay silent about every other one; the label is what sends the author to the
166
+ * right screen.
167
+ *
168
+ * Module scope, not per-call: these predicates are re-evaluated on every row of
169
+ * every render, so per-call state would warn once per frame — the flood the
170
+ * dedupe exists to prevent.
171
+ */
172
+ const warnedSpellings = new Set();
173
+ /** Reset the row-predicate spelling warn-once memo. Exported for tests. */
174
+ export function resetRowPredicateCanonWarnings() {
175
+ warnedSpellings.clear();
176
+ }
177
+ /**
178
+ * Report a non-canonical row-predicate spelling once, in dev.
179
+ *
180
+ * Phase 1 of the objectui#5330 window: the binding is UNCHANGED and every
181
+ * spelling still resolves — this only says so out loud, so the stored
182
+ * population stops growing and a later survey has something to count. It is a
183
+ * warning and deliberately not a refusal: turning it into one would move the
184
+ * accept/reject set, which this card is explicitly not entitled to do.
185
+ */
186
+ export function warnNonCanonicalRowSpelling(source, row, dataNamesRow, label) {
187
+ if (!isDev())
188
+ return;
189
+ const finding = detectNonCanonicalRowSpelling(source, row, dataNamesRow);
190
+ if (!finding)
191
+ return;
192
+ const key = JSON.stringify([label ?? '', source, finding.kind]);
193
+ if (warnedSpellings.has(key))
194
+ return;
195
+ warnedSpellings.add(key);
196
+ const where = label ? ` (${label})` : '';
197
+ const detail = finding.kind === 'bare-shorthand'
198
+ ? `it references the bare field ${JSON.stringify(finding.identifier)}; ` +
199
+ `the server refuses that spelling outright ("Unknown variable: ${finding.identifier}")`
200
+ : 'it is rooted at `data.`, which is the metadata-editing-form root — on a ' +
201
+ 'record surface the server binds no `data` at all, so the predicate is a ' +
202
+ 'constant false there rather than an error';
203
+ console.warn(`[object-ui] A row predicate${where} uses a DEPRECATED spelling: ` +
204
+ `${JSON.stringify(source)} — ${detail}. The canon is \`record.*\` ` +
205
+ `(objectui#5330, ruled 2026-08-20): write \`${finding.canonical}\`. ` +
206
+ 'This still evaluates here for now; the tolerance retires after a ' +
207
+ 'stored-metadata survey.');
208
+ }
package/dist/index.d.ts CHANGED
@@ -13,12 +13,17 @@ export * from './registry/PluginScopeImpl.js';
13
13
  export * from './registry/WidgetRegistry.js';
14
14
  export * from './validation/index.js';
15
15
  export * from './builder/schema-builder.js';
16
+ export * from './utils/dom-props.js';
16
17
  export * from './utils/filter-converter.js';
17
18
  export * from './utils/managedBy.js';
18
19
  export * from './utils/extract-records.js';
19
20
  export * from './utils/expand-fields.js';
21
+ export * from './utils/retired-field-types.js';
22
+ export * from './utils/unmaterialized-fields.js';
20
23
  export * from './utils/column-identity.js';
21
24
  export * from './utils/sort-values.js';
25
+ export * from './utils/sort-query.js';
26
+ export * from './utils/resolve-view-id.js';
22
27
  export * from './evaluator/index.js';
23
28
  export * from './actions/index.js';
24
29
  export * from './query/index.js';
@@ -28,7 +33,6 @@ export * from './data-scope/index.js';
28
33
  export * from './errors/index.js';
29
34
  export * from './utils/debug.js';
30
35
  export * from './utils/debug-collector.js';
31
- export * from './utils/merge-views-into-objects.js';
32
36
  export * from './utils/freeze-schema.js';
33
37
  export * from './protocols/index.js';
34
38
  export * from './styling/scoped-styles.js';
@@ -47,6 +51,8 @@ export * from './utils/dashboard-filters.js';
47
51
  export * from './utils/merge-filters.js';
48
52
  export * from './utils/compare-to.js';
49
53
  export * from './utils/chart-series.js';
54
+ export * from './utils/chart-presentation.js';
55
+ export * from './utils/number-display.js';
50
56
  export * from './utils/dataset-format.js';
51
57
  export * from './utils/dataset-pivot.js';
52
58
  export * from './utils/record-title.js';
@@ -55,3 +61,4 @@ export * from './utils/reference-keys.js';
55
61
  export * from './utils/predicate-record.js';
56
62
  export * from './utils/predicate-fields.js';
57
63
  export * from './utils/normalize-list-view.js';
64
+ export * from './utils/humanize-label.js';
package/dist/index.js CHANGED
@@ -12,12 +12,27 @@ export * from './registry/PluginScopeImpl.js';
12
12
  export * from './registry/WidgetRegistry.js';
13
13
  export * from './validation/index.js';
14
14
  export * from './builder/schema-builder.js';
15
+ // The DOM pass-through whitelist of the SDUI widget prop contract
16
+ // (objectui#4425 phase 2): a registered widget's host element receives only
17
+ // what `toDomProps` passes — everything else is consumed or dropped.
18
+ // `@object-ui/fields` executes the SAME mechanism against its own declared key
19
+ // list (`pickDomProps`), so there is one judge, not two.
20
+ export * from './utils/dom-props.js';
15
21
  export * from './utils/filter-converter.js';
16
22
  export * from './utils/managedBy.js';
17
23
  export * from './utils/extract-records.js';
18
24
  export * from './utils/expand-fields.js';
25
+ // The RETIREMENT gate (objectui#4914, maintainer ruling B). Homed here rather
26
+ // than in `@object-ui/fields` because `@object-ui/components` is one of its six
27
+ // consumers and `fields` depends on `components` — see the module's docblock
28
+ // for why a second copy was not an option. `@object-ui/fields` re-exports every
29
+ // name, so its published surface is unchanged.
30
+ export * from './utils/retired-field-types.js';
31
+ export * from './utils/unmaterialized-fields.js';
19
32
  export * from './utils/column-identity.js';
20
33
  export * from './utils/sort-values.js';
34
+ export * from './utils/sort-query.js';
35
+ export * from './utils/resolve-view-id.js';
21
36
  export * from './evaluator/index.js';
22
37
  export * from './actions/index.js';
23
38
  export * from './query/index.js';
@@ -27,7 +42,6 @@ export * from './data-scope/index.js';
27
42
  export * from './errors/index.js';
28
43
  export * from './utils/debug.js';
29
44
  export * from './utils/debug-collector.js';
30
- export * from './utils/merge-views-into-objects.js';
31
45
  export * from './utils/freeze-schema.js';
32
46
  export * from './protocols/index.js';
33
47
  export * from './styling/scoped-styles.js';
@@ -49,6 +63,16 @@ export * from './utils/dashboard-filters.js';
49
63
  export * from './utils/merge-filters.js';
50
64
  export * from './utils/compare-to.js';
51
65
  export * from './utils/chart-series.js';
66
+ // The AUTHORED half of a dataset-bound chart (objectui#4229's data/presentation
67
+ // split), shared by the dashboard widget and the report's embedded chart so the
68
+ // same spec keys are lowered identically on both (objectui#4877).
69
+ export * from './utils/chart-presentation.js';
70
+ // The ONE number-display formatter (objectui#4033) — grouping policy, display
71
+ // locale and the percent convention. It lived in `@object-ui/i18n` until
72
+ // objectui#4576; it is pure, and living above `core` was what kept
73
+ // `dataset-format` below from reaching it (so the two drifted). `@object-ui/i18n`
74
+ // re-exports these names unchanged, so both import paths name the same symbol.
75
+ export * from './utils/number-display.js';
52
76
  export * from './utils/dataset-format.js';
53
77
  // Pivot lookup-key encoders, shared by every cross-tab renderer so the
54
78
  // dashboard widget and the report renderer key their buckets identically
@@ -66,3 +90,9 @@ export * from './utils/predicate-record.js';
66
90
  // which the column-derived `$select` never asked the server for.
67
91
  export * from './utils/predicate-fields.js';
68
92
  export * from './utils/normalize-list-view.js';
93
+ // The single home for the VALUE fallback prettifier (a stored value becomes a
94
+ // display string when nothing resolves it). `@object-ui/fields` and
95
+ // `@object-ui/plugin-charts` each carried a byte-identical private copy;
96
+ // both now re-export this one (objectui#5444). Its docstring also records why
97
+ // it stays distinct from `humanizeFieldKey`, the KEY fallback.
98
+ export * from './utils/humanize-label.js';
@@ -14,7 +14,48 @@
14
14
  * @module protocols/DndProtocol
15
15
  * @packageDocumentation
16
16
  */
17
- import type { DndConfig, DragItem, DropZone, DragConstraint } from '@object-ui/types';
17
+ /** How a drag is initiated. */
18
+ export type DragHandle = 'element' | 'handle' | 'grip_icon';
19
+ /** The `dropEffect` advertised to assistive technology and DnD libraries. */
20
+ export type DropEffect = 'none' | 'link' | 'move' | 'copy';
21
+ /** Movement constraints applied to a drag. */
22
+ export interface DragConstraint {
23
+ axis: 'x' | 'y' | 'both';
24
+ bounds: 'none' | 'parent' | 'viewport';
25
+ grid?: [number, number];
26
+ }
27
+ /** A draggable item's declaration. */
28
+ export interface DragItem {
29
+ type: string;
30
+ label?: string;
31
+ handle: DragHandle;
32
+ constraint?: DragConstraint;
33
+ preview: 'custom' | 'none' | 'element';
34
+ disabled: boolean;
35
+ ariaLabel?: string;
36
+ ariaDescribedBy?: string;
37
+ role?: string;
38
+ }
39
+ /** A drop target's declaration. */
40
+ export interface DropZone {
41
+ label?: string;
42
+ accept: string[];
43
+ maxItems?: number;
44
+ highlightOnDragOver: boolean;
45
+ dropEffect: DropEffect;
46
+ ariaLabel?: string;
47
+ ariaDescribedBy?: string;
48
+ role?: string;
49
+ }
50
+ /** Top-level drag-and-drop configuration. */
51
+ export interface DndConfig {
52
+ enabled: boolean;
53
+ dragItem?: DragItem;
54
+ dropZone?: DropZone;
55
+ sortable: boolean;
56
+ autoScroll: boolean;
57
+ touchDelay: number;
58
+ }
18
59
  /** Fully resolved DnD configuration with all defaults applied. */
19
60
  export interface ResolvedDndConfig {
20
61
  enabled: boolean;
@@ -15,7 +15,37 @@
15
15
  * @module protocols/KeyboardProtocol
16
16
  * @packageDocumentation
17
17
  */
18
- import type { KeyboardNavigationConfig, KeyboardShortcut, FocusTrapConfig } from '@object-ui/types';
18
+ /** A single keyboard shortcut binding. */
19
+ export interface KeyboardShortcut {
20
+ key: string;
21
+ action: string;
22
+ description?: string;
23
+ scope: 'global' | 'form' | 'modal' | 'view' | 'list';
24
+ }
25
+ /** Focus trap declaration for a modal-like region. */
26
+ export interface FocusTrapConfig {
27
+ enabled: boolean;
28
+ initialFocus?: string;
29
+ returnFocus: boolean;
30
+ escapeDeactivates: boolean;
31
+ }
32
+ /** Focus management declaration. */
33
+ export interface FocusManagement {
34
+ tabOrder: 'manual' | 'auto';
35
+ skipLinks: boolean;
36
+ focusVisible: boolean;
37
+ focusTrap?: FocusTrapConfig;
38
+ arrowNavigation: boolean;
39
+ }
40
+ /** Top-level keyboard navigation configuration. */
41
+ export interface KeyboardNavigationConfig {
42
+ shortcuts?: KeyboardShortcut[];
43
+ focusManagement?: FocusManagement;
44
+ rovingTabindex: boolean;
45
+ ariaLabel?: string;
46
+ ariaDescribedBy?: string;
47
+ role?: string;
48
+ }
19
49
  /** Fully resolved keyboard navigation configuration. */
20
50
  export interface ResolvedKeyboardConfig {
21
51
  shortcuts: KeyboardShortcut[];
@@ -15,7 +15,17 @@
15
15
  * @module protocols/SharingProtocol
16
16
  * @packageDocumentation
17
17
  */
18
- import type { SharingConfig, EmbedConfig } from '@object-ui/types';
18
+ import type { SharingConfig } from '@object-ui/types';
19
+ /** An iframe embed declaration. */
20
+ export interface EmbedConfig {
21
+ enabled: boolean;
22
+ allowedOrigins?: string[];
23
+ width?: string;
24
+ height?: string;
25
+ showHeader?: boolean;
26
+ showNavigation?: boolean;
27
+ responsive?: boolean;
28
+ }
19
29
  /** Fully resolved sharing configuration. */
20
30
  export interface ResolvedSharingConfig {
21
31
  enabled: boolean;
@@ -5,22 +5,30 @@
5
5
  * This source code is licensed under the MIT license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
- import type { SchemaNode } from '../types/index.js';
8
+ import type { ComponentInput } from '@object-ui/types';
9
9
  export type ComponentRenderer<T = any> = T;
10
- export type ComponentInput = {
11
- name: string;
12
- type: 'string' | 'number' | 'boolean' | 'enum' | 'array' | 'object' | 'color' | 'date' | 'code' | 'file' | 'slot';
13
- label?: string;
14
- defaultValue?: any;
15
- required?: boolean;
16
- enum?: string[] | {
17
- label: string;
18
- value: any;
19
- }[];
20
- description?: string;
21
- advanced?: boolean;
22
- inputType?: string;
23
- };
10
+ /**
11
+ * What a registration DECLARES about one authorable prop.
12
+ *
13
+ * This is the declaration the component registrations themselves import, so it
14
+ * is the one an author's manifest is ultimately built from — and it is now
15
+ * RE-EXPORTED from `@object-ui/types` rather than restated here
16
+ * (objectui#4972), the disposition objectui#4580 ruled for the identical
17
+ * shape: *a structural copy would reproduce the defect the moment either side
18
+ * moved.* This package already depends on `@object-ui/types`, so the edge
19
+ * exists and adds no cycle, and `src/types/index.ts` re-exports `SchemaNode`
20
+ * from there the same way.
21
+ *
22
+ * The copy this replaces had ALREADY moved, which is why the card is not
23
+ * hypothetical: it carried nine keys while `base.ts` carried thirteen, so
24
+ * `min` / `max` / `step` / `placeholder` were missing from *the copy every
25
+ * registration actually imports*. Those four keys were therefore unwritable at
26
+ * any real registration — a plain TS error — while `ComponentInputSchema` (the
27
+ * zod schema) and `ComponentMeta.inputs` both accepted them. The publication
28
+ * face advertised four keys the authoring face rejected; the divergence was
29
+ * dormant only because no registration had tried to write one yet.
30
+ */
31
+ export type { ComponentInput } from '@object-ui/types';
24
32
  export type ComponentMeta = {
25
33
  label?: string;
26
34
  icon?: string;
@@ -43,9 +51,47 @@ export type ComponentMeta = {
43
51
  * registry.register('form', FormView, { namespace: 'view', skipFallback: true });
44
52
  */
45
53
  skipFallback?: boolean;
54
+ /**
55
+ * How a HOST must associate its own visible label with what this component
56
+ * renders (objectui#3961, extended by objectui#4857). Read by the form
57
+ * renderer; absent ⇒ `'control'`. This closed three-value vocabulary is the
58
+ * single repo-wide answer to "how does a host learn what a widget will
59
+ * render" (maintainer ruling of 2026-08-17, joint with objectui#4871) — no
60
+ * host may keep a local variant of it.
61
+ *
62
+ * - `'control'` — the component's outermost rendered element is a LABELABLE
63
+ * HTML element (`input` / `textarea` / `select` / `button` / …), so the host
64
+ * associates its label the plain way: `<label for>` → the id the host handed
65
+ * down. This is the default and covers every single-control widget.
66
+ * - `'group'` — it is NOT labelable: either a real composite (several inputs
67
+ * under one container, e.g. `address`) or a single control that is not a
68
+ * labelable element (a `div[role="button"]` dropzone, e.g. `file`). A
69
+ * `<label for>` pointing at such an element is inert in HTML — it activates
70
+ * nothing and contributes no accessible name (`HTMLLabelElement.control` is
71
+ * `null`) — so the host must instead give its label an `id` and hand the
72
+ * component `aria-labelledby`, which associates by IDREF and works on any
73
+ * element. The COMPONENT consumes those keys on its own surface.
74
+ * - `'display'` — the rendered surface is a pure display in EVERY state:
75
+ * there is no focusable control and the component itself spreads nothing
76
+ * (computed / system-generated values such as `formula` / `summary` /
77
+ * `auto_number` / `vector`). The host must not emit a `<label for>` at all
78
+ * — no labelable element will ever exist for it to reach, in the editable
79
+ * state as much as the readonly one — and instead wraps the component's
80
+ * output in the host's own container carrying the field id,
81
+ * `aria-labelledby`, `aria-describedby` and `role="group"` (the
82
+ * objectui#4788 channel, driven by this declaration rather than by
83
+ * `readonly` alone). Unlike `'group'`, the WIDGET is not expected to
84
+ * consume anything: the host's wrapper is the named surface.
85
+ *
86
+ * This is a DECLARATION, not a guess: the host cannot infer it from the DOM a
87
+ * widget happens to render, and a widget that fails to declare it falls back
88
+ * to the `'control'` path where the dangling/inert `for` is caught by the
89
+ * label-association tests (objectui#3952) instead of silently producing an
90
+ * unlabelled group.
91
+ */
92
+ labelling?: 'control' | 'group' | 'display';
46
93
  inputs?: ComponentInput[];
47
94
  defaultProps?: Record<string, any>;
48
- defaultChildren?: SchemaNode[];
49
95
  examples?: Record<string, any>;
50
96
  isContainer?: boolean;
51
97
  resizable?: boolean;
@@ -43,14 +43,6 @@ export declare function generateBorderRadiusVars(borderRadius: NonNullable<Theme
43
43
  * Generate CSS custom properties from a Theme's shadow config.
44
44
  */
45
45
  export declare function generateShadowVars(shadows: NonNullable<Theme['shadows']>): Record<string, string>;
46
- /**
47
- * Generate CSS custom properties from a Theme's animation config.
48
- */
49
- export declare function generateAnimationVars(animation: NonNullable<Theme['animation']>): Record<string, string>;
50
- /**
51
- * Generate CSS custom properties from a Theme's z-index config.
52
- */
53
- export declare function generateZIndexVars(zIndex: NonNullable<Theme['zIndex']>): Record<string, string>;
54
46
  /**
55
47
  * Generate ALL CSS custom properties from a complete Theme.
56
48
  * This is the main entry point for theme → CSS conversion.