@object-ui/core 17.7.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.
- package/CHANGELOG.md +650 -0
- package/README.md +127 -0
- package/dist/actions/ActionRunner.d.ts +192 -49
- package/dist/actions/ActionRunner.js +389 -102
- package/dist/actions/UndoManager.d.ts +8 -13
- package/dist/actions/actionKeys.d.ts +1 -1
- package/dist/actions/actionKeys.js +10 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/actions/navigationTarget.d.ts +41 -0
- package/dist/actions/navigationTarget.js +20 -0
- package/dist/actions/recordDelete.d.ts +59 -23
- package/dist/actions/recordDelete.js +40 -42
- package/dist/adapters/ApiDataSource.d.ts +8 -4
- package/dist/adapters/ApiDataSource.js +19 -7
- package/dist/adapters/resolveDataSource.d.ts +9 -6
- package/dist/adapters/resolveDataSource.js +9 -12
- package/dist/data-scope/ViewDataProvider.d.ts +7 -24
- package/dist/data-scope/ViewDataProvider.js +6 -53
- package/dist/evaluator/deadlineSettled.d.ts +40 -0
- package/dist/evaluator/deadlineSettled.js +45 -0
- package/dist/evaluator/fieldRules.js +6 -1
- package/dist/evaluator/index.d.ts +1 -0
- package/dist/evaluator/index.js +1 -0
- package/dist/evaluator/optionRules.d.ts +1 -1
- package/dist/evaluator/optionRules.js +1 -1
- package/dist/evaluator/subjectPermissions.d.ts +30 -1
- package/dist/evaluator/subjectPermissions.js +42 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/registry/Registry.d.ts +34 -13
- package/dist/registry/Registry.js +5 -22
- package/dist/utils/affordanceGrants.d.ts +371 -0
- package/dist/utils/affordanceGrants.js +252 -0
- package/dist/utils/chart-series.d.ts +34 -0
- package/dist/utils/chart-series.js +25 -2
- package/dist/utils/date-display.d.ts +42 -50
- package/dist/utils/date-display.js +192 -11
- package/dist/utils/expand-fields.d.ts +6 -4
- package/dist/utils/expand-fields.js +6 -4
- package/dist/utils/filter-converter.d.ts +6 -2
- package/dist/utils/filter-converter.js +6 -2
- package/dist/utils/normalize-list-view.d.ts +16 -12
- package/dist/utils/normalize-list-view.js +66 -67
- package/dist/utils/predicate-fields.js +6 -2
- package/dist/utils/record-source.d.ts +1 -1
- package/dist/utils/record-source.js +1 -1
- package/dist/utils/reference-keys.js +1 -1
- package/dist/validation/schema-validator.js +29 -5
- package/dist/validation/server-owned-value.d.ts +5 -1
- package/dist/validation/server-owned-value.js +5 -1
- package/package.json +4 -4
|
@@ -83,6 +83,11 @@ const isRecord = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
|
83
83
|
* firing control. ⛔ Do not read the three as legacy-only spellings awaiting
|
|
84
84
|
* retirement — the protocol declares them, so removing them here would leave
|
|
85
85
|
* objectui narrower than the protocol.
|
|
86
|
+
*
|
|
87
|
+
* ⛔ `inlineEdit` → `editInline` is NOT a row here, although it lands in the same
|
|
88
|
+
* block (objectui#5144). Every row of this table is deleted after it folds;
|
|
89
|
+
* `inlineEdit` must survive its fold, because it is also the MODE `ListView`
|
|
90
|
+
* opens the grid in. See {@link foldsInlineEditIntoEditInline}.
|
|
86
91
|
*/
|
|
87
92
|
const SHOW_FLAG_TO_USER_ACTION = {
|
|
88
93
|
showSearch: 'search',
|
|
@@ -93,6 +98,43 @@ const SHOW_FLAG_TO_USER_ACTION = {
|
|
|
93
98
|
showHideFields: 'hideFields',
|
|
94
99
|
showColor: 'rowColor',
|
|
95
100
|
};
|
|
101
|
+
/**
|
|
102
|
+
* Whether a view's `inlineEdit` folds into `userActions.editInline`
|
|
103
|
+
* (objectui#5144, the maintainer's B-fold).
|
|
104
|
+
*
|
|
105
|
+
* The spec declares `userActions.editInline` with `.default(true)` since the
|
|
106
|
+
* maintainer's v18 ruling (objectstack#22605): a list is editable in place by
|
|
107
|
+
* default, and `editInline: false` is the opt-out. It declares the view's
|
|
108
|
+
* `inlineEdit` as the same kind of permission ("allow inline editing"). Stored
|
|
109
|
+
* views carry `inlineEdit`, not `editInline`: authored views declare it, and
|
|
110
|
+
* the console's list toolbar used to write it. Folding it here puts both keys
|
|
111
|
+
* on one vocabulary, so `ListView` can read `editInline` with the spec default
|
|
112
|
+
* and a view's own `inlineEdit` still decides it when `editInline` is absent.
|
|
113
|
+
*
|
|
114
|
+
* The console's toolbar no longer writes `inlineEdit` (objectui#5144, ruling
|
|
115
|
+
* E). It persisted a user's edit mode into this permission key, so switching
|
|
116
|
+
* the toggle off stored `inlineEdit: false` and the fold then read the view as
|
|
117
|
+
* not offering inline editing. The toggle is session state now.
|
|
118
|
+
*
|
|
119
|
+
* Two rules, each the same as a fold above:
|
|
120
|
+
* - The value carries over: `inlineEdit: true` folds to `editInline: true`,
|
|
121
|
+
* and `inlineEdit: false` to `editInline: false`.
|
|
122
|
+
* - An explicit `userActions.editInline` wins. It is the spec key, so a
|
|
123
|
+
* stored `inlineEdit` only fills the gap.
|
|
124
|
+
*
|
|
125
|
+
* One departure, the `data` → `objectName` one: `inlineEdit` is KEPT. The other
|
|
126
|
+
* folds delete because the legacy key has one meaning and one home.
|
|
127
|
+
* `inlineEdit` has a second use. It is the spec's own `ListView.inlineEdit`,
|
|
128
|
+
* and `ListView` seeds the grid's edit MODE from it on each load. The toolbar
|
|
129
|
+
* toggle then flips that mode for the session. `editInline` decides whether
|
|
130
|
+
* the toggle is offered at all. Deleting `inlineEdit` would open every such
|
|
131
|
+
* view out of edit mode.
|
|
132
|
+
*/
|
|
133
|
+
function foldsInlineEditIntoEditInline(s) {
|
|
134
|
+
if (typeof s.inlineEdit !== 'boolean')
|
|
135
|
+
return false;
|
|
136
|
+
return !(isRecord(s.userActions) && typeof s.userActions.editInline === 'boolean');
|
|
137
|
+
}
|
|
96
138
|
/**
|
|
97
139
|
* Legacy `sharing.visibility` → the spec's `ViewSharing.type`. The spec models
|
|
98
140
|
* two ownership kinds; objectui's four-value audience enum collapses onto them:
|
|
@@ -240,32 +282,6 @@ function readListViewKind(value) {
|
|
|
240
282
|
warnUndrawableViewKind(value);
|
|
241
283
|
return undefined;
|
|
242
284
|
}
|
|
243
|
-
/**
|
|
244
|
-
* Per-view-type config aliases → the spec key each one aliases (#2890, the
|
|
245
|
-
* phase-3 carry-over).
|
|
246
|
-
*
|
|
247
|
-
* Phase 3 derived `kanban` / `gallery` / `timeline` from the spec configs but
|
|
248
|
-
* kept the pre-#2231 objectui spellings declared alongside the spec keys so
|
|
249
|
-
* stored view metadata would keep validating
|
|
250
|
-
* (`packages/types/src/zod/objectql.zod.ts`, each marked `@deprecated legacy
|
|
251
|
-
* alias for the spec's X`). Folding them here is what lets a read-site stop
|
|
252
|
-
* carrying its own `canonical || legacy` pair — the same move A1–A5 made for
|
|
253
|
-
* the top-level vocabulary.
|
|
254
|
-
*
|
|
255
|
-
* `calendar` is deliberately absent: its one local key, `defaultView`, is not
|
|
256
|
-
* an alias of anything. It has no spec counterpart at all, so it wants
|
|
257
|
-
* PROMOTION upstream, not a rename — folding it would delete an authored value
|
|
258
|
-
* with nowhere to put it.
|
|
259
|
-
*
|
|
260
|
-
* Note `kanban.columns` is the spec's "fields shown on each card", NOT the
|
|
261
|
-
* table columns that the same word names at the ListView top level. The fold
|
|
262
|
-
* is scoped to the nested config, so the two never meet.
|
|
263
|
-
*/
|
|
264
|
-
const PER_VIEW_CONFIG_ALIASES = {
|
|
265
|
-
kanban: { groupField: 'groupByField', cardFields: 'columns' },
|
|
266
|
-
gallery: { imageField: 'coverField' },
|
|
267
|
-
timeline: { dateField: 'startDateField' },
|
|
268
|
-
};
|
|
269
285
|
/**
|
|
270
286
|
* ObjectUI's `list-view` node historically used a different vocabulary from
|
|
271
287
|
* `@objectstack/spec` for the same concepts (`fields` where the spec says
|
|
@@ -307,6 +323,12 @@ const PER_VIEW_CONFIG_ALIASES = {
|
|
|
307
323
|
* stays absent, because the defaults are per-toggle (search/sort/filter/
|
|
308
324
|
* rowHeight/group default ON, hideFields/rowColor default OFF) and belong to
|
|
309
325
|
* the renderer, not to the vocabulary bridge.
|
|
326
|
+
* - the view's `inlineEdit` → `userActions.editInline` (objectui#5144), with
|
|
327
|
+
* the value carried over and an explicit `editInline` winning. `inlineEdit`
|
|
328
|
+
* stays on the result, because `ListView` seeds the grid's edit mode from
|
|
329
|
+
* it. See {@link foldsInlineEditIntoEditInline}. An absent pair stays
|
|
330
|
+
* absent here as well; `ListView` reads that as on, the spec's default
|
|
331
|
+
* (objectstack#22605).
|
|
310
332
|
* - `aria: { label, describedBy }` → the spec's `AriaProps`
|
|
311
333
|
* (`{ ariaLabel, ariaDescribedBy }`), and `sharing: { visibility, enabled }`
|
|
312
334
|
* → the spec's `ViewSharing` (`{ type }`) — #2890 scope A step 5. `aria.live`
|
|
@@ -329,8 +351,8 @@ const PER_VIEW_CONFIG_ALIASES = {
|
|
|
329
351
|
* · an already-present `objectName` WINS — this fold only fills a gap, it
|
|
330
352
|
* never re-points a binding that already resolves;
|
|
331
353
|
* · `data` is NOT deleted. Every other fold deletes because the legacy key
|
|
332
|
-
* has one meaning and one home; `data` has
|
|
333
|
-
*
|
|
354
|
+
* has one meaning and one home; `data` has more providers than
|
|
355
|
+
* `object`, `value` is read live in `ListView`, and the whole block is FORWARDED to child
|
|
334
356
|
* views (the gantt branch), whose own `getDataConfig` reads `data` before
|
|
335
357
|
* `objectName`. Deleting it for one provider would rewrite what a child
|
|
336
358
|
* resolves. Nothing in `ListView` reads `data.provider === 'object'`, so
|
|
@@ -353,16 +375,14 @@ const PER_VIEW_CONFIG_ALIASES = {
|
|
|
353
375
|
* breaking change with no inventory. Runs AFTER the `fields` → `columns` fold
|
|
354
376
|
* above, so a view that spells its column list the legacy way still gets its
|
|
355
377
|
* entries canonicalized.
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* `columns` reaches it. Every other reader of these four was already
|
|
365
|
-
* canonical-first and is unaffected.
|
|
378
|
+
*
|
|
379
|
+
* No longer folded: the four PER-VIEW-TYPE config aliases phase 3 carried over
|
|
380
|
+
* (`kanban.groupField` → `groupByField`, `kanban.cardFields` → `columns`,
|
|
381
|
+
* `gallery.imageField` → `coverField`, `timeline.dateField` →
|
|
382
|
+
* `startDateField`). objectui#6152 round 14 retired that fold with every
|
|
383
|
+
* renderer-side reader of the four: each list-view door refuses them by name
|
|
384
|
+
* (rounds 11 and 12), and a stored block that still carries one passes through
|
|
385
|
+
* here untouched and binds nothing downstream.
|
|
366
386
|
*/
|
|
367
387
|
export function normalizeListViewSchema(schema) {
|
|
368
388
|
if (!schema || typeof schema !== 'object')
|
|
@@ -380,6 +400,7 @@ export function normalizeListViewSchema(schema) {
|
|
|
380
400
|
const legacyFilters = s.filters;
|
|
381
401
|
const foldFilter = Array.isArray(legacyFilters);
|
|
382
402
|
const legacyFlags = Object.keys(SHOW_FLAG_TO_USER_ACTION).filter((k) => typeof s[k] === 'boolean');
|
|
403
|
+
const foldInlineEdit = foldsInlineEditIntoEditInline(s);
|
|
383
404
|
const foldDescription = typeof s.showDescription === 'boolean';
|
|
384
405
|
const aria = isRecord(s.aria) ? s.aria : undefined;
|
|
385
406
|
const foldAria = !!aria && Object.keys(ARIA_KEY_ALIASES).some((k) => aria[k] !== undefined);
|
|
@@ -409,22 +430,9 @@ export function normalizeListViewSchema(schema) {
|
|
|
409
430
|
: undefined;
|
|
410
431
|
const foldedColumns = normalizeColumnIdentities(columnsSource);
|
|
411
432
|
const foldColumnIdentity = foldedColumns !== columnsSource;
|
|
412
|
-
|
|
413
|
-
// the early return so an otherwise-canonical view carrying only a nested
|
|
414
|
-
// legacy key still folds — and so a view carrying none still returns by
|
|
415
|
-
// reference.
|
|
416
|
-
const perViewFolds = Object.entries(PER_VIEW_CONFIG_ALIASES)
|
|
417
|
-
.map(([viewKey, aliases]) => {
|
|
418
|
-
const cfg = isRecord(s[viewKey]) ? s[viewKey] : undefined;
|
|
419
|
-
if (!cfg)
|
|
420
|
-
return undefined;
|
|
421
|
-
const legacyKeys = Object.keys(aliases).filter((legacy) => cfg[legacy] !== undefined);
|
|
422
|
-
return legacyKeys.length ? { viewKey, aliases, cfg, legacyKeys } : undefined;
|
|
423
|
-
})
|
|
424
|
-
.filter((entry) => entry !== undefined);
|
|
425
|
-
if (!foldColumns && !foldRowHeight && !foldFilter && !legacyFlags.length &&
|
|
433
|
+
if (!foldColumns && !foldRowHeight && !foldFilter && !legacyFlags.length && !foldInlineEdit &&
|
|
426
434
|
!foldDescription && !foldAria && !foldSharing && !defaultViewKind &&
|
|
427
|
-
!foldColumnIdentity && !
|
|
435
|
+
!foldColumnIdentity && !foldObjectName) {
|
|
428
436
|
return schema;
|
|
429
437
|
}
|
|
430
438
|
const next = { ...s };
|
|
@@ -448,7 +456,7 @@ export function normalizeListViewSchema(schema) {
|
|
|
448
456
|
next.filter = legacyFilters;
|
|
449
457
|
delete next.filters;
|
|
450
458
|
}
|
|
451
|
-
if (legacyFlags.length) {
|
|
459
|
+
if (legacyFlags.length || foldInlineEdit) {
|
|
452
460
|
const ua = { ...(isRecord(next.userActions) ? next.userActions : {}) };
|
|
453
461
|
for (const flag of legacyFlags) {
|
|
454
462
|
const key = SHOW_FLAG_TO_USER_ACTION[flag];
|
|
@@ -456,6 +464,10 @@ export function normalizeListViewSchema(schema) {
|
|
|
456
464
|
ua[key] = s[flag];
|
|
457
465
|
delete next[flag];
|
|
458
466
|
}
|
|
467
|
+
// objectui#5144. Gap-fill only, and `inlineEdit` is not deleted: see
|
|
468
|
+
// `foldsInlineEditIntoEditInline`.
|
|
469
|
+
if (foldInlineEdit)
|
|
470
|
+
ua.editInline = s.inlineEdit;
|
|
459
471
|
next.userActions = ua;
|
|
460
472
|
}
|
|
461
473
|
if (foldDescription) {
|
|
@@ -498,19 +510,6 @@ export function normalizeListViewSchema(schema) {
|
|
|
498
510
|
delete nextSharing.enabled;
|
|
499
511
|
next.sharing = nextSharing;
|
|
500
512
|
}
|
|
501
|
-
for (const { viewKey, aliases, cfg, legacyKeys } of perViewFolds) {
|
|
502
|
-
const nextCfg = { ...cfg };
|
|
503
|
-
for (const legacy of legacyKeys) {
|
|
504
|
-
const canonical = aliases[legacy];
|
|
505
|
-
// Same one-directional shape as every fold above: the canonical key wins
|
|
506
|
-
// when both are present, and the legacy key is REMOVED so a missed
|
|
507
|
-
// read-site fails loudly instead of quietly taking the legacy path.
|
|
508
|
-
if (nextCfg[canonical] === undefined)
|
|
509
|
-
nextCfg[canonical] = cfg[legacy];
|
|
510
|
-
delete nextCfg[legacy];
|
|
511
|
-
}
|
|
512
|
-
next[viewKey] = nextCfg;
|
|
513
|
-
}
|
|
514
513
|
if (foldObjectName)
|
|
515
514
|
next.objectName = dataObjectName;
|
|
516
515
|
if (defaultViewKind)
|
|
@@ -105,7 +105,7 @@ const TARGET_ROW_TOKEN = /\{([a-z_][a-z0-9_]*)\}/gi;
|
|
|
105
105
|
/**
|
|
106
106
|
* The row key a `defaultFromRow` param seeds its value from — `field` wins,
|
|
107
107
|
* because row data is keyed by object field; `name` is the fallback. The same
|
|
108
|
-
* precedence `resolveActionParam` (`@object-ui/
|
|
108
|
+
* precedence `resolveActionParam` (`@object-ui/fields`) reads, which is the
|
|
109
109
|
* point: the projection must carry the key the runtime looks up, not the
|
|
110
110
|
* param's payload name. `remove_team_member` seeds `teamId` from `team_id`.
|
|
111
111
|
*/
|
|
@@ -125,7 +125,11 @@ function defaultFromRowKey(param) {
|
|
|
125
125
|
* Each source is the one a writer actually merges into the written set:
|
|
126
126
|
*
|
|
127
127
|
* - `patch`: the static field values of `operation: 'update'`, merged under the
|
|
128
|
-
* collected params (`ActionRunner`'s `executeUpdateOperation`)
|
|
128
|
+
* collected params (`ActionRunner`'s `executeUpdateOperation`). Every def
|
|
129
|
+
* this harvest reads is a definition its writer applies whole (a view's
|
|
130
|
+
* resolved row def, a `bulkActionDefs` entry, an object's action), never a
|
|
131
|
+
* page action row, so this is the declared `patch` the write applies: the
|
|
132
|
+
* one the runner's Undo snapshot reads too (objectui#13022);
|
|
129
133
|
* - each param's COLLECTED key, `name ?? field`: the key the param dialog
|
|
130
134
|
* stores its answer under (`paramName` in `app-shell`'s
|
|
131
135
|
* `resolveActionParams`). This is the opposite precedence to
|
|
@@ -45,7 +45,7 @@ import type { ViewData } from '@object-ui/types';
|
|
|
45
45
|
* The ladder's second rung wraps inline rows as `{ provider: 'value', items }`,
|
|
46
46
|
* which names no object at all. So for the object-NAME question the three-rung
|
|
47
47
|
* ladder reduces to two rungs — the resolved config's object when it names one,
|
|
48
|
-
* else the schema's own `objectName`, which is what a `value
|
|
48
|
+
* else the schema's own `objectName`, which is what a `value`-backed block
|
|
49
49
|
* still needs for metadata reads, i18n field labels and permission verdicts.
|
|
50
50
|
* Callers pass the ALREADY-RESOLVED config (their
|
|
51
51
|
* {@link resolveRecordSourceConfig} output, direct or through a local wrapper),
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
* The ladder's second rung wraps inline rows as `{ provider: 'value', items }`,
|
|
45
45
|
* which names no object at all. So for the object-NAME question the three-rung
|
|
46
46
|
* ladder reduces to two rungs — the resolved config's object when it names one,
|
|
47
|
-
* else the schema's own `objectName`, which is what a `value
|
|
47
|
+
* else the schema's own `objectName`, which is what a `value`-backed block
|
|
48
48
|
* still needs for metadata reads, i18n field labels and permission verdicts.
|
|
49
49
|
* Callers pass the ALREADY-RESOLVED config (their
|
|
50
50
|
* {@link resolveRecordSourceConfig} output, direct or through a local wrapper),
|
|
@@ -280,7 +280,7 @@ const warnedUnfoldableSpelling = new Set();
|
|
|
280
280
|
* ⚠️ Not NO reader, and the line never says so (objectui#7650). Some reads of a
|
|
281
281
|
* retired spelling were KEPT on purpose and still see a value this arm leaves
|
|
282
282
|
* alone. For the two `no-declared-twin` keys: `resolveActionParam` in
|
|
283
|
-
* `@object-ui/
|
|
283
|
+
* `@object-ui/fields` reads `id_field` and `title_format` (objectui#7435
|
|
284
284
|
* kept them; its pin `resolveActionParams.declaredLookupLegs-7435.test.ts`
|
|
285
285
|
* calls them the snake spellings that must keep working), and
|
|
286
286
|
* `resolveGroupByLabels` in `@object-ui/plugin-charts` reads
|
|
@@ -5,6 +5,7 @@
|
|
|
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 { nodeSlotValues, nodeSlotsFor } from '@object-ui/types';
|
|
8
9
|
import { hasDeclaredPredicate } from '../evaluator/declaredPredicate.js';
|
|
9
10
|
import { isUnevaluablePredicate } from '../evaluator/unevaluablePredicate.js';
|
|
10
11
|
/**
|
|
@@ -360,15 +361,21 @@ function validateFormSchema(schema, path = 'schema') {
|
|
|
360
361
|
}
|
|
361
362
|
return errors;
|
|
362
363
|
}
|
|
364
|
+
/** `schema.items[0].content[1]`: the child's path, spelled the way `children[0]` already is. */
|
|
365
|
+
function spellSlotPath(path, segments) {
|
|
366
|
+
return segments.reduce((spelled, segment) => (typeof segment === 'number' ? `${spelled}[${segment}]` : `${spelled}.${segment}`), path);
|
|
367
|
+
}
|
|
363
368
|
/**
|
|
364
|
-
* Validate child schemas recursively
|
|
369
|
+
* Validate child schemas recursively: what `children` holds on every node,
|
|
370
|
+
* and what the node slots declared for this node's type hold.
|
|
365
371
|
*/
|
|
366
372
|
function validateChildren(schema, path = 'schema') {
|
|
367
373
|
const errors = [];
|
|
368
|
-
// One spelling. This walker resolved `children || body` for ANY
|
|
369
|
-
// so it outlived every per-registration read of the dialect —
|
|
370
|
-
// retired it, and a recursive validator that still descended
|
|
371
|
-
// keep validating a child list no renderer puts
|
|
374
|
+
// One child-list spelling. This walker resolved `children || body` for ANY
|
|
375
|
+
// node type, so it outlived every per-registration read of the dialect —
|
|
376
|
+
// objectui#6771 retired it, and a recursive validator that still descended
|
|
377
|
+
// `body` on every node would keep validating a child list no renderer puts
|
|
378
|
+
// on the page.
|
|
372
379
|
const children = schema.children;
|
|
373
380
|
if (children) {
|
|
374
381
|
if (Array.isArray(children)) {
|
|
@@ -384,6 +391,23 @@ function validateChildren(schema, path = 'schema') {
|
|
|
384
391
|
errors.push(...childResult.errors, ...childResult.warnings);
|
|
385
392
|
}
|
|
386
393
|
}
|
|
394
|
+
// The node slots THIS type's renderer reads — a dialog's `trigger`, a tab
|
|
395
|
+
// item's `content`, a page's `regions[].components` — from the one
|
|
396
|
+
// declaration in `@object-ui/types` (`nodeSlotsFor`, objectui#11170), which
|
|
397
|
+
// the `objectui check` gate and the SDUI parser read too. Per type, never a
|
|
398
|
+
// second generic spelling: `page:card`'s retired `body` is walked because
|
|
399
|
+
// that renderer is measured still painting it; `body` on any other type is
|
|
400
|
+
// not, which is the objectui#6771 line above, kept.
|
|
401
|
+
if (typeof schema.type === 'string') {
|
|
402
|
+
for (const slot of nodeSlotsFor(schema.type)) {
|
|
403
|
+
for (const { segments, value } of nodeSlotValues(schema, slot.path)) {
|
|
404
|
+
if (!isSchemaNodeShape(value))
|
|
405
|
+
continue;
|
|
406
|
+
const childResult = validateSchema(value, spellSlotPath(path, segments));
|
|
407
|
+
errors.push(...childResult.errors, ...childResult.warnings);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
387
411
|
return errors;
|
|
388
412
|
}
|
|
389
413
|
/**
|
|
@@ -21,7 +21,11 @@
|
|
|
21
21
|
* 2. the create-mode static `required` rule (#4069) —
|
|
22
22
|
* `isRequiredInForm` in `@object-ui/plugin-form`;
|
|
23
23
|
* 3. the create-mode `requiredWhen` rule (#4085) —
|
|
24
|
-
* {@link isServerOwnedValue}, read by `resolveFieldRuleState
|
|
24
|
+
* {@link isServerOwnedValue}, read by `resolveFieldRuleState`;
|
|
25
|
+
* 4. the "Set automatically when saved." hint (objectui#12108) — the form
|
|
26
|
+
* renderer reads the same {@link isServerOwnedValue} answer it hands to
|
|
27
|
+
* `resolveFieldRuleState`, so the hint and the lowered `required` are
|
|
28
|
+
* one verdict.
|
|
25
29
|
*/
|
|
26
30
|
export declare function isRuntimeDefault(v: unknown): boolean;
|
|
27
31
|
/**
|
|
@@ -67,7 +67,11 @@ function isExpressionEnvelope(v) {
|
|
|
67
67
|
* 2. the create-mode static `required` rule (#4069) —
|
|
68
68
|
* `isRequiredInForm` in `@object-ui/plugin-form`;
|
|
69
69
|
* 3. the create-mode `requiredWhen` rule (#4085) —
|
|
70
|
-
* {@link isServerOwnedValue}, read by `resolveFieldRuleState
|
|
70
|
+
* {@link isServerOwnedValue}, read by `resolveFieldRuleState`;
|
|
71
|
+
* 4. the "Set automatically when saved." hint (objectui#12108) — the form
|
|
72
|
+
* renderer reads the same {@link isServerOwnedValue} answer it hands to
|
|
73
|
+
* `resolveFieldRuleState`, so the hint and the lowered `required` are
|
|
74
|
+
* one verdict.
|
|
71
75
|
*/
|
|
72
76
|
export function isRuntimeDefault(v) {
|
|
73
77
|
return isRuntimeDefaultToken(v) || isExpressionEnvelope(v);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@objectstack/formula": "^
|
|
29
|
-
"@objectstack/spec": "^
|
|
30
|
-
"@object-ui/types": "
|
|
28
|
+
"@objectstack/formula": "^18.0.0",
|
|
29
|
+
"@objectstack/spec": "^18.0.0",
|
|
30
|
+
"@object-ui/types": "18.0.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"typescript": "^6.0.3",
|