@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.
Files changed (52) hide show
  1. package/CHANGELOG.md +650 -0
  2. package/README.md +127 -0
  3. package/dist/actions/ActionRunner.d.ts +192 -49
  4. package/dist/actions/ActionRunner.js +389 -102
  5. package/dist/actions/UndoManager.d.ts +8 -13
  6. package/dist/actions/actionKeys.d.ts +1 -1
  7. package/dist/actions/actionKeys.js +10 -0
  8. package/dist/actions/index.d.ts +1 -0
  9. package/dist/actions/index.js +1 -0
  10. package/dist/actions/navigationTarget.d.ts +41 -0
  11. package/dist/actions/navigationTarget.js +20 -0
  12. package/dist/actions/recordDelete.d.ts +59 -23
  13. package/dist/actions/recordDelete.js +40 -42
  14. package/dist/adapters/ApiDataSource.d.ts +8 -4
  15. package/dist/adapters/ApiDataSource.js +19 -7
  16. package/dist/adapters/resolveDataSource.d.ts +9 -6
  17. package/dist/adapters/resolveDataSource.js +9 -12
  18. package/dist/data-scope/ViewDataProvider.d.ts +7 -24
  19. package/dist/data-scope/ViewDataProvider.js +6 -53
  20. package/dist/evaluator/deadlineSettled.d.ts +40 -0
  21. package/dist/evaluator/deadlineSettled.js +45 -0
  22. package/dist/evaluator/fieldRules.js +6 -1
  23. package/dist/evaluator/index.d.ts +1 -0
  24. package/dist/evaluator/index.js +1 -0
  25. package/dist/evaluator/optionRules.d.ts +1 -1
  26. package/dist/evaluator/optionRules.js +1 -1
  27. package/dist/evaluator/subjectPermissions.d.ts +30 -1
  28. package/dist/evaluator/subjectPermissions.js +42 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +3 -0
  31. package/dist/registry/Registry.d.ts +34 -13
  32. package/dist/registry/Registry.js +5 -22
  33. package/dist/utils/affordanceGrants.d.ts +371 -0
  34. package/dist/utils/affordanceGrants.js +252 -0
  35. package/dist/utils/chart-series.d.ts +34 -0
  36. package/dist/utils/chart-series.js +25 -2
  37. package/dist/utils/date-display.d.ts +42 -50
  38. package/dist/utils/date-display.js +192 -11
  39. package/dist/utils/expand-fields.d.ts +6 -4
  40. package/dist/utils/expand-fields.js +6 -4
  41. package/dist/utils/filter-converter.d.ts +6 -2
  42. package/dist/utils/filter-converter.js +6 -2
  43. package/dist/utils/normalize-list-view.d.ts +16 -12
  44. package/dist/utils/normalize-list-view.js +66 -67
  45. package/dist/utils/predicate-fields.js +6 -2
  46. package/dist/utils/record-source.d.ts +1 -1
  47. package/dist/utils/record-source.js +1 -1
  48. package/dist/utils/reference-keys.js +1 -1
  49. package/dist/validation/schema-validator.js +29 -5
  50. package/dist/validation/server-owned-value.d.ts +5 -1
  51. package/dist/validation/server-owned-value.js +5 -1
  52. 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 four providers, `api`/`value`
333
- * are read live in `ListView`, and the whole block is FORWARDED to child
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
- * - the four PER-VIEW-TYPE config aliases phase 3 carried over
357
- * ({@link PER_VIEW_CONFIG_ALIASES}): `kanban.groupField` → `groupByField`,
358
- * `kanban.cardFields` → `columns`, `gallery.imageField` → `coverField`,
359
- * `timeline.dateField` → `startDateField`. One read-site changes behaviour
360
- * as a result, and it is a CORRECTION of the same inverted precedence A2
361
- * fixed for `densityMode`: `ListView`'s kanban adapter resolves
362
- * `cardFields || columns`, i.e. legacy over canonical, so a config carrying
363
- * BOTH used to render the legacy value. After the fold the canonical
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
- // Per-view-type config aliases (#2890 phase-3 carry-over). Collected before
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 && !perViewFolds.length && !foldObjectName) {
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/app-shell`) reads, which is the
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`/`api`-backed block
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`/`api`-backed block
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/app-shell` reads `id_field` and `title_format` (objectui#7435
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 node type,
369
- // so it outlived every per-registration read of the dialect — objectui#6771
370
- // retired it, and a recursive validator that still descended `body` would
371
- // keep validating a child list no renderer puts on the page.
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": "17.7.0",
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": "^17.5.0",
29
- "@objectstack/spec": "^17.6.0",
30
- "@object-ui/types": "17.7.0"
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",