@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
@@ -116,41 +116,33 @@ export function generateColorVars(colors) {
116
116
  /**
117
117
  * Generate CSS custom properties from a Theme's typography config.
118
118
  */
119
+ // ----------------------------------------------------------------------------
120
+ // RETIRED THEME BLOCKS — @objectstack/spec 17.0.0-rc.3 (objectstack#5021 option
121
+ // 2, PR objectstack#5289), objectui#3361.
122
+ //
123
+ // `theme.animation`, `theme.zIndex` and five typography groups
124
+ // (`fontSize` / `fontWeight` / `lineHeight` / `letterSpacing`, plus
125
+ // `fontFamily.heading` / `fontFamily.mono`) became TOMBSTONES: the schema now
126
+ // rejects them by name and their prescription points at `theme.customVars`, the
127
+ // declared — and since #5021 the only — door for a custom property. A
128
+ // `--z-modal` or a `--duration-fast` is authored there now, emitted verbatim as
129
+ // `--<key>: <value>`.
130
+ //
131
+ // The emission code below them was therefore structurally dead: no author can
132
+ // produce the input that would reach it. It is removed rather than left behind
133
+ // a cast, because the tombstoned keys type as `never` and any cast that made
134
+ // them compile would fossilize a shape the contract has withdrawn (AGENTS.md
135
+ // #0.1). LIVE emission — `colors`, `borderRadius`, `shadows`,
136
+ // `typography.fontFamily.base` (→ `--font-sans`) and `customVars` — is
137
+ // untouched, byte for byte.
138
+ // ----------------------------------------------------------------------------
119
139
  export function generateTypographyVars(typography) {
120
140
  const vars = {};
141
+ // `fontFamily.base` is the only surviving typography input — see the RETIRED
142
+ // THEME BLOCKS note above for where the other five groups went.
121
143
  if (typography.fontFamily?.base) {
122
144
  vars['--font-sans'] = typography.fontFamily.base;
123
145
  }
124
- if (typography.fontFamily?.heading) {
125
- vars['--font-heading'] = typography.fontFamily.heading;
126
- }
127
- if (typography.fontFamily?.mono) {
128
- vars['--font-mono'] = typography.fontFamily.mono;
129
- }
130
- if (typography.fontSize) {
131
- for (const [key, value] of Object.entries(typography.fontSize)) {
132
- if (value)
133
- vars[`--font-size-${key}`] = value;
134
- }
135
- }
136
- if (typography.fontWeight) {
137
- for (const [key, value] of Object.entries(typography.fontWeight)) {
138
- if (value != null)
139
- vars[`--font-weight-${key}`] = String(value);
140
- }
141
- }
142
- if (typography.lineHeight) {
143
- for (const [key, value] of Object.entries(typography.lineHeight)) {
144
- if (value)
145
- vars[`--line-height-${key}`] = value;
146
- }
147
- }
148
- if (typography.letterSpacing) {
149
- for (const [key, value] of Object.entries(typography.letterSpacing)) {
150
- if (value)
151
- vars[`--letter-spacing-${key}`] = value;
152
- }
153
- }
154
146
  return vars;
155
147
  }
156
148
  /**
@@ -197,36 +189,6 @@ export function generateShadowVars(shadows) {
197
189
  }
198
190
  return vars;
199
191
  }
200
- /**
201
- * Generate CSS custom properties from a Theme's animation config.
202
- */
203
- export function generateAnimationVars(animation) {
204
- const vars = {};
205
- if (animation.duration) {
206
- for (const [key, value] of Object.entries(animation.duration)) {
207
- if (value)
208
- vars[`--duration-${key}`] = value;
209
- }
210
- }
211
- if (animation.timing) {
212
- for (const [key, value] of Object.entries(animation.timing)) {
213
- if (value)
214
- vars[`--timing-${key}`] = value;
215
- }
216
- }
217
- return vars;
218
- }
219
- /**
220
- * Generate CSS custom properties from a Theme's z-index config.
221
- */
222
- export function generateZIndexVars(zIndex) {
223
- const vars = {};
224
- for (const [key, value] of Object.entries(zIndex)) {
225
- if (value != null)
226
- vars[`--z-${key}`] = String(value);
227
- }
228
- return vars;
229
- }
230
192
  /**
231
193
  * Generate ALL CSS custom properties from a complete Theme.
232
194
  * This is the main entry point for theme → CSS conversion.
@@ -247,14 +209,6 @@ export function generateThemeVars(theme) {
247
209
  if (theme.shadows) {
248
210
  Object.assign(vars, generateShadowVars(theme.shadows));
249
211
  }
250
- // Animation
251
- if (theme.animation) {
252
- Object.assign(vars, generateAnimationVars(theme.animation));
253
- }
254
- // Z-Index
255
- if (theme.zIndex) {
256
- Object.assign(vars, generateZIndexVars(theme.zIndex));
257
- }
258
212
  // Custom CSS variables (passthrough)
259
213
  if (theme.customVars) {
260
214
  for (const [key, value] of Object.entries(theme.customVars)) {
@@ -290,22 +244,6 @@ export function mergeThemes(parent, child) {
290
244
  ...parent.typography?.fontFamily,
291
245
  ...child.typography?.fontFamily,
292
246
  },
293
- fontSize: {
294
- ...parent.typography?.fontSize,
295
- ...child.typography?.fontSize,
296
- },
297
- fontWeight: {
298
- ...parent.typography?.fontWeight,
299
- ...child.typography?.fontWeight,
300
- },
301
- lineHeight: {
302
- ...parent.typography?.lineHeight,
303
- ...child.typography?.lineHeight,
304
- },
305
- letterSpacing: {
306
- ...parent.typography?.letterSpacing,
307
- ...child.typography?.letterSpacing,
308
- },
309
247
  }
310
248
  : undefined,
311
249
  // Deep-merge border radius
@@ -316,25 +254,6 @@ export function mergeThemes(parent, child) {
316
254
  shadows: child.shadows || parent.shadows
317
255
  ? { ...parent.shadows, ...child.shadows }
318
256
  : undefined,
319
- // Deep-merge animation
320
- animation: child.animation || parent.animation
321
- ? {
322
- ...parent.animation,
323
- ...child.animation,
324
- duration: {
325
- ...parent.animation?.duration,
326
- ...child.animation?.duration,
327
- },
328
- timing: {
329
- ...parent.animation?.timing,
330
- ...child.animation?.timing,
331
- },
332
- }
333
- : undefined,
334
- // Deep-merge zIndex
335
- zIndex: child.zIndex || parent.zIndex
336
- ? { ...parent.zIndex, ...child.zIndex }
337
- : undefined,
338
257
  // Deep-merge customVars
339
258
  customVars: child.customVars || parent.customVars
340
259
  ? { ...parent.customVars, ...child.customVars }
@@ -5,4 +5,4 @@
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
- export { hexToHSL, toCSSColor, generateColorVars, generateTypographyVars, generateBorderRadiusVars, generateShadowVars, generateAnimationVars, generateZIndexVars, generateThemeVars, mergeThemes, resolveThemeInheritance, resolveMode, contrastRatio, meetsContrastLevel, } from './ThemeEngine';
8
+ export { hexToHSL, toCSSColor, generateColorVars, generateTypographyVars, generateBorderRadiusVars, generateShadowVars, generateThemeVars, mergeThemes, resolveThemeInheritance, resolveMode, contrastRatio, meetsContrastLevel, } from './ThemeEngine.js';
@@ -5,4 +5,10 @@
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
- export { hexToHSL, toCSSColor, generateColorVars, generateTypographyVars, generateBorderRadiusVars, generateShadowVars, generateAnimationVars, generateZIndexVars, generateThemeVars, mergeThemes, resolveThemeInheritance, resolveMode, contrastRatio, meetsContrastLevel, } from './ThemeEngine';
8
+ export { hexToHSL, toCSSColor, generateColorVars, generateTypographyVars, generateBorderRadiusVars, generateShadowVars,
9
+ // `generateAnimationVars` / `generateZIndexVars` removed with the
10
+ // `theme.animation` / `theme.zIndex` tombstones in @objectstack/spec
11
+ // 17.0.0-rc.3 (objectstack#5021) — see ThemeEngine's RETIRED THEME BLOCKS
12
+ // note. `theme.customVars` is the declared door for a `--duration-*` or
13
+ // `--z-*` now.
14
+ generateThemeVars, mergeThemes, resolveThemeInheritance, resolveMode, contrastRatio, meetsContrastLevel, } from './ThemeEngine.js';
@@ -5,15 +5,128 @@
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
- export interface SchemaNode {
9
- type: string;
10
- id?: string;
11
- className?: string;
12
- data?: any;
13
- body?: SchemaNode | SchemaNode[];
14
- [key: string]: any;
15
- }
16
- export interface ComponentRendererProps {
17
- schema: SchemaNode;
18
- [key: string]: any;
19
- }
8
+ /**
9
+ * One `SchemaNode` (objectui#4580).
10
+ *
11
+ * This package used to hand-declare `interface SchemaNode { type: string; …
12
+ * [key: string]: any }` here, while `@object-ui/types` exported
13
+ * `type SchemaNode = BaseSchema | string | number | boolean | null | undefined`
14
+ * — two different types under one name, from two packages the same consumers
15
+ * import together. Which declaration a call site got depended on which package
16
+ * it happened to import from, and #4548's option-A canary measured **19 of 35**
17
+ * errors as exactly that collision:
18
+ *
19
+ * ```
20
+ * Type 'import(".../packages/types/dist/base").SchemaNode' is not assignable to
21
+ * type 'import(".../packages/core/dist/types/index").SchemaNode'
22
+ * ```
23
+ *
24
+ * PR #4578 sidestepped it — `SchemaRenderer` states its own component-level
25
+ * union rather than picking a side — and left the reconciliation to this card.
26
+ *
27
+ * **`@object-ui/types`' union wins**, per #4580's ruling 1: it is the spec of
28
+ * record (its own doc comment names `'Plain string'` a valid node), and it is
29
+ * the side the measured collisions resolve toward. The declaration is RE-EXPORTED
30
+ * rather than restated, so there is exactly one declaration left to disagree
31
+ * with — a structural copy would reproduce the defect the moment either side
32
+ * moved. This package already depends on `@object-ui/types`, so the edge exists
33
+ * and adds no cycle.
34
+ *
35
+ * ## The entry-surface sentence that used to close this block is WITHDRAWN
36
+ *
37
+ * It read: *core's own entry surface is unchanged (`dist/index.d.ts` is
38
+ * byte-identical across the change — measured, both rounds)*. The reading was
39
+ * real, and it certified nothing (objectui#5673).
40
+ *
41
+ * `core/dist/index.d.ts` is emitted from a barrel that only FORWARDS this
42
+ * symbol, and forwarding never restates a shape — not `export *`, and not the
43
+ * `export type { SchemaNode, … } from './types/index.js'` line that names it.
44
+ * Only the module that DECLARES the symbol can move. So that file is
45
+ * byte-identical under any change to a re-exported declaration's shape, naming
46
+ * the symbol or not, and a gauge that cannot fail for the change class it is
47
+ * quoted against has discharged nothing.
48
+ *
49
+ * ## The gauge that can fail — and how to prove it can, before believing it
50
+ *
51
+ * 1. Watch the emitted `.d.ts` of the module that DECLARES the symbol. For
52
+ * `SchemaNode` that is `@object-ui/types`' `dist/base.d.ts`, in another
53
+ * package — not core's entry, and not core's own `dist/types/index.d.ts`
54
+ * either, which forwards exactly as the entry does. For the shape claim
55
+ * itself, resolve the symbol through the TypeScript CHECKER from
56
+ * `core/dist/index.d.ts`.
57
+ * 2. Build both legs from a cleared `dist/` AND a cleared
58
+ * `tsconfig.tsbuildinfo` — the build info lives outside `dist/`, so
59
+ * composite `tsc` skips emit if it survives and two stale trees compare
60
+ * equal for free.
61
+ * 3. CALIBRATE: inject a probe key into the declaring module, rebuild, and
62
+ * require the hash you are watching to MOVE; drop the probe, rebuild, and
63
+ * require it to come back to its original value. A probe that leaves your
64
+ * hash unmoved means the gauge is not wired to this symbol — that is what
65
+ * failure looks like here, and no "byte-identical" sentence may be written
66
+ * from a gauge that just failed it.
67
+ *
68
+ * Run against this file's own claim — probe: one additive optional key on
69
+ * `BaseSchema`, the shape `SchemaNode` publishes — `@object-ui/types`'
70
+ * `dist/base.d.ts` moved and came back, while `core/dist/index.d.ts` and
71
+ * `core/dist/types/index.d.ts` held one hash across all three legs. The
72
+ * withdrawn sentence was watching the two files that cannot move.
73
+ *
74
+ * The collision is only observable from a package that resolves BOTH through
75
+ * `node_modules`; the pin therefore lives in `@object-ui/react`
76
+ * (`src/__tests__/SchemaNode.reconciliation.test.ts`), not here.
77
+ */
78
+ export type { SchemaNode } from '@object-ui/types';
79
+ /**
80
+ * One `ComponentRendererProps` (objectui#4594).
81
+ *
82
+ * This package used to hand-declare `interface ComponentRendererProps
83
+ * { schema: SchemaNode; [key: string]: any }` here — two lines below `SchemaNode`
84
+ * and against `@object-ui/types`' generic
85
+ * `ComponentRendererProps< TSchema extends BaseSchema = BaseSchema >`. Same name,
86
+ * two packages the same consumers import together: the second such pair in this
87
+ * one file, and the third across this fault line after `SchemaNode` (#4580) and
88
+ * `ComponentInput` (#4972).
89
+ *
90
+ * **`@object-ui/types`' generic declaration wins**, and is RE-EXPORTED rather
91
+ * than restated, so there is exactly one declaration left to disagree with — a
92
+ * structural copy would reproduce the defect the moment either side moved.
93
+ *
94
+ * Reconciled now, at **zero consumers** — re-verified on the merged ref rather
95
+ * than inherited from the card: repo-wide, `ComponentRendererProps` occurred only
96
+ * at the two declarations, each package's own entry re-export, and one line of
97
+ * `packages/components/CHANGELOG.md` recording that nothing used it. Zero
98
+ * consumers is why this is cheap today and would not stay cheap: the day someone
99
+ * imports it, which declaration they get decides whether a primitive node is
100
+ * admissible.
101
+ *
102
+ * ## What the re-export moves, and how that was measured
103
+ *
104
+ * It is NOT surface-neutral, and the gauge that would have said so is vacuous.
105
+ * `core/dist/index.d.ts` is emitted from a barrel that only FORWARDS this
106
+ * symbol — its `export type { … }` line names it, and naming is not restating
107
+ * — so that file is byte-identical under ANY change to a re-exported
108
+ * declaration's shape and cannot fail for this change class (objectui#5673,
109
+ * where the `SchemaNode` block above withdraws the same reading and carries the
110
+ * probe calibration that tells a live gauge from this one).
111
+ *
112
+ * Measured instead by resolving the symbol through the TypeScript CHECKER from
113
+ * `core/dist/index.d.ts`, over a `dist/` + `tsconfig.tsbuildinfo` clean rebuild
114
+ * on both legs (the build info lives outside `dist/`, so composite `tsc` skips
115
+ * emit if it survives and two stale trees compare equal for free):
116
+ *
117
+ * ```
118
+ * before ComponentRendererProps schema: BaseSchema | string | number | boolean | null | undefined
119
+ * after ComponentRendererProps<TSchema> schema: TSchema (TSchema extends BaseSchema = BaseSchema)
120
+ * ```
121
+ *
122
+ * So `schema` NARROWS back to the object form — core's copy had silently widened
123
+ * when #4608 made `SchemaNode` a re-export of types' union, which is the interim
124
+ * state this card closes — and the type gains a parameter. Nothing downstream
125
+ * can observe either move, because nothing imports it.
126
+ *
127
+ * The collision is only observable from a package that resolves BOTH through
128
+ * `node_modules`; the pin therefore lives in `@object-ui/react`
129
+ * (`src/__tests__/ComponentRendererProps.reconciliation.test.ts`), not here —
130
+ * same position, same reason, as `SchemaNode`'s pin above.
131
+ */
132
+ export type { ComponentRendererProps } from '@object-ui/types';
@@ -0,0 +1,205 @@
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
+ * chart-presentation — the AUTHORED half of a dataset-bound chart, lowered onto
10
+ * the bindings {@link buildChartSeries} derived from the dataset selection.
11
+ *
12
+ * `chart-series.ts` beside this file owns the DATA half: which columns become
13
+ * series, which rows, which buckets. This file owns everything the author gets
14
+ * to say about how that data LOOKS — the ruled data/presentation split of
15
+ * objectui#4229, stated once:
16
+ *
17
+ * - **Data (derived, never forwarded)** — series MEMBERSHIP and the column each
18
+ * binding reads. Concretely `buildChartSeries`' `dataKey`s, `xAxisKey`, and
19
+ * the spec's two binding keys `ChartSeries.name` and `ChartAxis.field`.
20
+ * - **Presentation (authored, merged forward)** — everything else on those same
21
+ * objects: `series[].type` (the per-series mark), `series[].yAxis` (which
22
+ * axis it binds to), `label`/`color`/`stack`/`variant`/`dashArray`/`opacity`,
23
+ * the axis definitions' `title`/`format`/`min`/`max`/`stepSize`/
24
+ * `showGridLines`/`position`/`logarithmic`, and the chart chrome
25
+ * (`showLegend`, `showDataLabels`, `colors`, `annotations`, …).
26
+ *
27
+ * ## Why it lives in `@object-ui/core` rather than in one plugin
28
+ *
29
+ * It was written for `plugin-dashboard`'s `DatasetWidget` (#3135 → objectstack#7016
30
+ * → #4229) and lifted here by objectui#4877, when `plugin-report`'s embedded
31
+ * report chart turned out to need the SAME merge over the same spec shapes: the
32
+ * report was forwarding six keys and dropping every authored chrome key the
33
+ * schema declares, and re-deriving this beside the dashboard's copy is exactly
34
+ * the duplication objectui#4389 filed as a defect (two longhand copies of the
35
+ * analytics label net, one per plugin, drifting apart).
36
+ *
37
+ * Everything here is a pure data transform over plain records, so it sits below
38
+ * both plugins with no React and no i18n — the same layering `chart-series.ts`
39
+ * already has (see {@link OptionLabelTranslator} there for why an i18n-resolved
40
+ * string always arrives as an ARGUMENT rather than being read here).
41
+ *
42
+ * ## Two entry points, because the two surfaces declare axes differently
43
+ *
44
+ * A dashboard widget's `chartConfig` spells its axes as spec `ChartAxis`
45
+ * OBJECTS. A report's `chart.xAxis` / `chart.yAxis` are bare dimension/measure
46
+ * NAME strings — on that surface the axes are pure DATA (they ARE the selection)
47
+ * and carry no presentation at all. So:
48
+ *
49
+ * - {@link mergeAuthoredPresentation} is the object-axis entry point: series
50
+ * merge + axis presentation, for a caller whose axes are `ChartAxis` objects.
51
+ * - {@link mergeAuthoredSeries} is the series merge ALONE, for a caller whose
52
+ * axes are names. That split is structural, not a guard: handing a bare
53
+ * string to {@link mergeAuthoredPresentation} would run it through
54
+ * `axisPresentation`, which reads nothing off a string and would synthesise a
55
+ * `yAxis: [{}]` entry — a y-axis declaring nothing but its own existence,
56
+ * which is precisely how the COUNT of entries turns on a secondary axis. A
57
+ * surface that cannot author axis presentation should not be able to reach
58
+ * the code that reads it.
59
+ */
60
+ import type { ChartSeriesBinding } from './chart-series.js';
61
+ /** Authored spec `ChartSeries` presentation, in the renderer's internal spelling. */
62
+ export interface AuthoredSeriesPresentation {
63
+ label?: string;
64
+ /** Spec `ChartSeries.type`, narrowed — see {@link seriesPresentation}. */
65
+ chartType?: 'bar' | 'line' | 'area';
66
+ yAxis?: 'left' | 'right';
67
+ color?: string;
68
+ stack?: string;
69
+ variant?: 'primary' | 'comparison';
70
+ dashArray?: string;
71
+ opacity?: number;
72
+ }
73
+ /** A derived series binding with the author's presentation merged onto it. */
74
+ export type MergedChartSeries = ChartSeriesBinding & AuthoredSeriesPresentation;
75
+ /**
76
+ * One authored `ChartSeries`, minus its `name` — i.e. everything about it that
77
+ * is presentation rather than membership.
78
+ *
79
+ * `type` is narrowed to the three families that COMPOSE on one cartesian plot,
80
+ * because this array reaches the renderer already speaking the internal shape
81
+ * (`ChartRenderer` forwards a `dataKey`-shaped array untouched, so
82
+ * `normalizeChartSchema`'s own identical narrowing never sees it). Without the
83
+ * narrowing a `type: 'pie'` would not merely be inert — it would count as a
84
+ * family disagreement in `effectiveChartFamily`, flip the whole chart into a
85
+ * combo, and then draw that series as a bar anyway.
86
+ */
87
+ export declare function seriesPresentation(raw: Record<string, unknown>): AuthoredSeriesPresentation;
88
+ /**
89
+ * One authored `ChartAxis`, minus its `field` — the axis's presentation.
90
+ *
91
+ * `field` is the one DATA key on an axis (it names the plotted column), and
92
+ * dropping it here is what keeps membership with the dataset **structurally**
93
+ * rather than by a guard: `normalizeChartSchema` synthesises series out of
94
+ * `yAxis[].field` when a chart declares no series, so a forwarded `field`
95
+ * would be a live membership channel on an empty selection. With it gone the
96
+ * axis carries scale and chrome only, and the count of entries — which is what
97
+ * turns on the secondary axis (`yAxes.length > 1`) — survives, including for
98
+ * an entry that declares nothing but its own existence.
99
+ *
100
+ * Keys the renderer does not read on a given axis are dropped by
101
+ * `normalizeChartSchema`, the ONE normalization layer (#2880 S1): today it
102
+ * keeps `format`/`title`/`showGridLines` on the x-axis and the full set on the
103
+ * y-axes. That narrowing is deliberately NOT mirrored here — a second copy
104
+ * would drift from the renderer's real capability the moment it grew.
105
+ */
106
+ export declare function axisPresentation(raw: unknown): Record<string, unknown>;
107
+ /**
108
+ * Merge an authored `series[]` array's PRESENTATION onto the bindings the
109
+ * dataset selection derived — the series half of #4229's split, and the whole
110
+ * of it for a surface whose axes are names rather than objects (see the file
111
+ * header).
112
+ *
113
+ * The match rule is **by name/key**: an authored `series[].name` is paired with
114
+ * the derived binding whose `dataKey` it equals, and the pairing decides
115
+ * nothing but presentation:
116
+ *
117
+ * - an authored entry naming a measure that is NOT in the dataset selection is
118
+ * **ignored** — membership belongs to the dataset, so an author cannot add,
119
+ * remove or re-point a series from the chart config;
120
+ * - a derived series with no authored entry keeps the family default, so every
121
+ * surface that never wrote `series` renders byte-for-byte as before;
122
+ * - where both exist the **explicit binding wins** (#2880 S2), which is the
123
+ * whole point: `type: 'line'` + `yAxis: 'right'` is how the spec says "this
124
+ * measure is a line on the secondary axis".
125
+ *
126
+ * Matching on `name` only is deliberate: `name` is the spec's authorable key
127
+ * for a series (`dataKey` is a declared ALIAS of it, resolved where the
128
+ * metadata is parsed), so reading a second spelling here would fossilize a
129
+ * dialect this renderer has no business accepting (AGENTS.md #0.1).
130
+ *
131
+ * The FIRST entry naming a measure wins; a later duplicate cannot silently
132
+ * reconfigure a series the author already described.
133
+ *
134
+ * @param derived the bindings {@link buildChartSeries} produced from the selection
135
+ * @param authoredSeries the authored `series` array (anything, incl. absent)
136
+ */
137
+ export declare function mergeAuthoredSeries(derived: ChartSeriesBinding[], authoredSeries: unknown): MergedChartSeries[];
138
+ /**
139
+ * Merge an authored chart config's PRESENTATION onto the series and axes the
140
+ * dataset selection derived — the one place that happens for a surface whose
141
+ * axes are spec `ChartAxis` OBJECTS (#4229).
142
+ *
143
+ * The series half is {@link mergeAuthoredSeries}; see it for the match rule and
144
+ * for why membership is safe. The axes half reads `xAxis` / `yAxis` through
145
+ * {@link axisPresentation}, which is why a surface spelling those as bare NAME
146
+ * strings must call `mergeAuthoredSeries` directly instead (file header).
147
+ *
148
+ * @param derived the bindings {@link buildChartSeries} produced from the selection
149
+ * @param raw the authored chart config (anything, incl. absent)
150
+ * @returns the merged series, plus the presentation-only axes to spread onto
151
+ * the chart schema (absent when the author declared none)
152
+ */
153
+ export declare function mergeAuthoredPresentation(derived: ChartSeriesBinding[], raw: unknown): {
154
+ series: MergedChartSeries[];
155
+ axes: Record<string, unknown>;
156
+ };
157
+ /**
158
+ * Lower an authored chart config's CHROME (spec `ChartConfigSchema` /
159
+ * `ReportChartSchema` — the same keys on both) onto the chart schema a
160
+ * dataset-bound surface hands the renderer.
161
+ *
162
+ * ## Why this is a whitelist and not a spread
163
+ *
164
+ * Until #3135 NONE of a dashboard widget's `chartConfig` reached the renderer:
165
+ * the widget read `options` and nothing else, so an author who wrote
166
+ * `showLegend: false` still got a legend and one who wrote `true` only got one
167
+ * because "on" is the renderer's default. #3135 lowered that single flag and
168
+ * left the rest declared and inert. objectstack#7016 lowered the rest of the
169
+ * keys that are actually DELIVERED, admitting a key only when both of these
170
+ * hold:
171
+ *
172
+ * 1. **The chart block draws it end to end.** `{ type: 'chart' }` resolves to
173
+ * `ChartRenderer` → `AdvancedChartImpl`, which draws `title`/`subtitle` in
174
+ * its ChartFrame, turns `description` into the chart container's
175
+ * `role="img"` + `aria-label`, applies `height` as that container's inline
176
+ * height, reads `colors` as the positional palette, prints
177
+ * `showDataLabels` as a Recharts `LabelList`, draws `annotations` as
178
+ * ReferenceLine/ReferenceArea and honours `interaction` as the tooltip
179
+ * toggle plus `Brush`. Forwarding a key the renderer ignores would only
180
+ * move declared-but-not-delivered one layer down, which is the failure this
181
+ * exists to remove.
182
+ * 2. **It does not fight the dataset derivation.** `type` stays out: the
183
+ * calling surface's own type already picks the chart family, which is the
184
+ * dataset path's chart-family channel.
185
+ *
186
+ * `aria` is the one declared key with **no reader at all**: `AdvancedChartImpl`
187
+ * has no `aria` prop, and `SchemaRenderer`'s ARIA injection reads the FLAT
188
+ * `ariaLabel`/`ariaDescribedBy`/`role`, never a nested `aria` object. It is
189
+ * therefore left unforwarded on purpose (criterion 1) rather than papered over
190
+ * with a caller-side flattening that would also collide with the accessible
191
+ * name `description` already sets — reported back to objectstack#5175's
192
+ * narrowing half instead.
193
+ *
194
+ * `title` IS emitted here. A caller that paints the title itself (the report
195
+ * renderer's own `h3` above the chart) must drop it from the result, or the
196
+ * chart draws a second one.
197
+ *
198
+ * @param raw the authored chart config (anything, incl. absent)
199
+ * @param fieldCategoryColors per-category colours resolved from the category
200
+ * dimension's own select/lookup option colours, merged UNDER an explicit
201
+ * author map (see the `colors` note below)
202
+ * @returns only the keys that resolved, so the caller can spread it over the
203
+ * derived chart schema and every undeclared key keeps the renderer's default
204
+ */
205
+ export declare function chartConfigPresentation(raw: unknown, fieldCategoryColors?: Record<string, string> | null): Record<string, unknown>;