@object-ui/plugin-charts 17.3.0 → 17.5.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 CHANGED
@@ -1,5 +1,342 @@
1
1
  # @object-ui/plugin-charts
2
2
 
3
+ ## 17.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5fac011: Publish `normalizeChartSchema` from the package entry.
8
+
9
+ `normalizeChartSchema` is the single place the author-facing chart schema is translated into the renderer's internal pipeline contract, and `ChartRenderer` calls it on every render. It was not reachable from the package's only entry point, so a consumer that wanted to assert what `AdvancedChartImpl` is actually handed had to restate the translation rather than run it. It is now exported from the entry, along with the `NormalizedChartSchema` type it returns.
10
+
11
+ Additive only: nothing is removed or renamed, and the module was already in the entry's eager import graph via `ChartRenderer`, so this publishes a name rather than shipping new bytes.
12
+
13
+ ### Patch Changes
14
+
15
+ - 5900ac5: Analytics surfaces now run resolved select-option labels through the locale bundle — the chart legend and the related list on one page stop disagreeing
16
+
17
+ A dashboard widget grouped by a `select` field rendered the option's authored English label while the related list beside it rendered the translation. The decisive evidence in objectui#4030 is the stored value `orion`: the chart read `Orion Engineered Carbons`, a string with no resemblance to the value and matching the object's `label` byte for byte. So the analytics path had already RESOLVED the option label — it simply never ran the result through the i18n bundle before display. (`domestic → Domestic` differs from its value by case alone, which is why the first diagnosis, "the report groups by stored value", was wrong.)
18
+
19
+ There is exactly one resolution channel and this change reuses it rather than adding a chart-side dialect: `fieldOptionLabel` from `useObjectLabel`, i.e. `{ns}.fieldOptions.<object>.<field>.<value>` — the convention `@objectstack/spec` names objectui as the reader of, and the one list, form, kanban and record-picker surfaces already translate select options through. The bundle is applied ONCE, at the output of the label net that landed in objectui#4053/#4263, on the shared option list every consumer reads: chart axis and legend, the table/pivot cells of a dotted dimension, that table's CSV export, per-category colours and the declared category order. `@object-ui/core` gains `localizeFieldOptions` (the pure mirror of `translateOptions`), an optional translator on `buildDimensionLabelMap`, and `resolveDimensionFieldMeta` — the same single relationship walk `resolveDimensionFieldOptions` performs, now keeping the object that OWNS the terminal field, because for `crm_account.industry` the bundle key is `crm_account`, not the dataset's base object.
20
+
21
+ Two properties the fix is shaped around. The rows reach this net keyed either way — by stored value when the server did not resolve the dimension, by the English label when it did (ADR-0021) — and the reported screen is the second case, so the map answers to both keys and lands on the same translated display. And identity is untouched: `relabelDimensions` still rewrites display only, so a drilled chart segment clicked as `欧励隆` filters by `orion`, bucket ids and pivot totals keep their raw keys, and an option with no bundle entry (or an `en` console) renders exactly the authored label it renders today.
22
+
23
+ The per-locale work moved from the metadata fetch into the render, so switching language now re-labels in place instead of waiting for a refetch.
24
+
25
+ Not covered, and unchanged here: a LOCAL select dimension on a table/pivot, whose label the server resolves and whose client-side net is deliberately off (objectui#4263), and a dashboard global filter's own field label, which has no object name in its metadata to key a bundle lookup with — tracked on objectui#4030.
26
+
27
+ - 3fc2971: A null-keyed group renders as an explicit bucket instead of silently vanishing from a chart (objectui#4466)
28
+
29
+ `buildChartSeries`' single-dimension branch passed rows through verbatim, so a row whose category VALUE is `null` reached recharts with a null category and drew no mark. The visible outcome was not an empty chart but a quietly wrong one: rows `[{user_id: null, event_count: 51}, {user_id: 'Dev Admin', event_count: 2}]` drew exactly ONE bar — the dominant group, 51 of 53 events, dropped while the y-axis scale still accommodated it, so the chart understated its own data and the axis proved the data had been there. With every group null it drew axes, gridlines and an axis title with zero marks and no empty state, which is the shipped first-boot state of the built-in System Overview board's "Events by User" (every seeded `sys_audit_log` row is written with `user_id = NULL`).
30
+
31
+ The mapping lives in the shared series layer, so dashboard widgets and standalone `ObjectChart` get one answer rather than a per-chart patch in the recharts wrapper. It resolves the two-answers disagreement the card names as well: an empty result set keeps the designed empty state, a non-empty result always draws bars — the null bucket included.
32
+
33
+ `@object-ui/core` gains `NULL_CATEGORY_LABEL` and `ChartSeriesOptions`; `buildChartSeries` and `findChartSeriesRow` each take an optional trailing `options`. Both additive — every existing call site compiles and behaves identically, and a result with no null category is still returned by array identity. The two helpers are a pair on purpose: the caller matches a clicked segment against rows that still carry the raw `null`, so `findChartSeriesRow` reads the bucket label back to that row and the newly-visible bar keeps its drill-through instead of resolving to `-1`.
34
+
35
+ The label goes through the i18n channel (`chart.nullCategory`, en `(None)` / zh `(未指定)`, all ten packs), passed down by the renderer: `@object-ui/core` is React-free and cannot read the locale bundle, so it takes the resolved string the same way `dimensionOptionTranslator` takes a resolver. Its English constant is the floor for a provider-less host, not the mechanism.
36
+
37
+ `hasNoCategoryKey` (framework#4033) is untouched and now documented against this: a row that does not carry the category key AT ALL is a different defect — a dimension grouped by but never projected — and keeps its explanatory placeholder. The bucket deliberately never ADDS the key to such a row, which is what keeps that guard's signal alive. Key absent → the placeholder; key present with a null value → the bucket.
38
+
39
+ - aca27fa: The multi-dimension pivot branch buckets a null first-dimension value instead of dropping its bar (objectui#4497)
40
+
41
+ `buildChartSeries`' pivot branch (2+ dimensions, single measure) bucketed rows by `String(xRaw ?? '')` but wrote the RAW value into the emitted row, so a null first-dimension value produced `{status: null, Low: 3}` and reached recharts with a null category — which draws no mark. Measured at the DOM: a two-group pivot drew ONE bar, and an all-null pivot drew axes and gridlines with zero bar rectangles and no empty state. That is the same mechanism objectui#4466 fixed one branch below, on the branch that card deliberately left pinned as-is until the pivot's own bucketing had been measured.
42
+
43
+ The pivot now maps a null/undefined first-dimension VALUE to the same bucket label the single-dimension branch uses — `ChartSeriesOptions.nullCategoryLabel`, defaulting to `NULL_CATEGORY_LABEL`. One doctrine, one predicate, two call sites; no new export, and every existing call site compiles and behaves identically.
44
+
45
+ The bucket KEY is untouched, which is what keeps this a display fix: `String(xRaw ?? '')` still decides which rows share a bar, so every existing grouping is byte-identical and only the label the bucket carries changes. Rows that lack the category key entirely are still not bucketed — that shape is a dimension grouped by but never projected (framework#4033), a different defect with a different answer.
46
+
47
+ Drill-through needed no change, which was measured rather than assumed: the pivot's emitted rows are AGGREGATED, so they are not index-aligned with `drillRawRows` and the one production caller (`DatasetWidget.handleChartDrill`) already drills by SEARCHING the raw rows through `findChartSeriesRow`. Those raw rows still carry their null, and objectui#4466's label-matching covers the multi-dimension arm as well as the single-dimension one, so the newly-visible bar resolves to the right record. Pinned at both levels so a regression in either half surfaces as the dead click it would be.
48
+
49
+ - 613b167: A dataset dimension on a dotted relationship path now renders its option labels instead of the raw stored enum
50
+
51
+ A `DatasetDimension` whose `field` is a relationship path (`crm_account.industry`) got no select-option resolution at all: the chart plotted `education`, `finance`, `manufacturing` — the database column, unresolved — while the **same underlying field** reached as a **local** dimension rendered `Education`, `Finance`, `Manufacturing` beside it on the same dashboard. Nothing errored, so the widget just quietly showed database enum values to end users; on a non-English deployment those are words that appear nowhere else in the UI, since every form and list shows the translated label.
52
+
53
+ The label lookup read options as `baseObject.fields[<path>]`, which only ever matches the local spelling. For a dotted path the options live on the **related** object, so the lookup missed and the renderer fell through to the stored value.
54
+
55
+ The object-resolution step of that one lookup now walks the path: each segment before the last must be a declared relationship (`lookup` / `master_detail`, target read from `reference` / `reference_to` / `referenceTo` / `reference_to_object`), and the terminal field's options are read off the object that actually owns it. This is the same lookup for both spellings rather than a dotted-path variant beside it — a single-segment path never enters the walk and resolves exactly as before, so the local and joined paths cannot drift apart. Multi-hop paths (`crm_account.owner.department`) resolve too, which is the shape the dataset designer already emits.
56
+
57
+ Hops ride the caller's existing `GET /meta/object/:name` channel — the same authenticated read that fetched the base object — so no new fetch layer is introduced, and objects are fetched once per resolution even when several dimensions share a prefix. Every failure stays best-effort: a segment that is not a relationship, a target that cannot be loaded, or a terminal field with no options yields no mapping and the raw value survives, exactly as it does today.
58
+
59
+ Applies to both surfaces that carried this lookup: dashboard dataset widgets (`DatasetWidget`) and the chart view's dataset path (`ObjectChart`).
60
+
61
+ Scope: this ends at "the label is in hand". Whether that label then passes through the i18n bundle is a separate gap tracked upstream as objectstack#5076.
62
+
63
+ - 0b49d60: Analytics: `ObjectChart` consumes the shared label-net helpers instead of a third copy
64
+
65
+ objectui#4389 (PR #4404) named two copies of the analytics label-net glue — the dashboard's `DatasetWidget` and plugin-report's dataset block — and retired both into `@object-ui/core` + `@object-ui/react`. There was a THIRD, which that card did not name and its PR deliberately left out of scope: `packages/plugin-charts/src/ObjectChart.tsx` carried its own `translatorFor` closure, its own `buildDimensionLabelMap` loop, and its own base-object-read-then-walk composition. The `translatorFor` copy was logically identical to the two that were deleted, down to the comment explaining the binding.
66
+
67
+ `ObjectChart` now calls core's `dimensionOptionTranslator`, `deriveDimensionLabelMaps` and `loadDimensionFieldMeta` directly. Nothing about what a label IS changes — those helpers are the same code the two retired copies were rewritten onto, so the part that was genuinely duplicated three times is now written once.
68
+
69
+ Behaviour is unchanged by construction: same two metadata reads in the same order on the dataset path, same one read on the aggregate path, same best-effort fallback (an unresolvable path yields no entry and the raw value survives), same locale-applying memo boundary. `plugin-charts`' 22 test files / 170 assertions pass unchanged and their files are byte-identical to before, which is the acceptance evidence for a pure swap.
70
+
71
+ The card's second, optional step — moving the DATASET path's metadata read onto `@object-ui/react`'s `useDatasetDimensionMeta` — was attempted and declined on measurement; the shape blocker is recorded on objectui#4405 and in the PR. The two bug-fix properties the family exists to state (the read rides the host's authenticated `apiFetch`, objectui#4121; the fetched metadata stays locale-free, objectui#4030 / PR #4324) therefore remain stated locally in this file, exactly as before, and are undisturbed by this change.
72
+
73
+ - bcd3e02: `ObjectChart`'s category option-color / dimension-label probe now rides the host's
74
+ authenticated fetch (`SchemaRendererContext.apiFetch`) instead of the bare global
75
+ `fetch`.
76
+
77
+ Both metadata reads the effect makes — `GET /api/v1/meta/dataset/{dataset}` and
78
+ `GET /api/v1/meta/object/{object}` — went out on the global `fetch`, so in a hosted
79
+ console they skipped whatever the host supplies on that channel (Authorization /
80
+ tenant headers, base-URL rewrite, draft-preview params). A bearer-token session
81
+ carries its credential in a header rather than a cookie, so `credentials: 'include'`
82
+ alone left these two reads unauthenticated. The effect is best-effort and swallows
83
+ every failure, which made the symptom silent: semantic option colors and dataset
84
+ dimension labels simply never applied, and the chart fell back to the positional
85
+ theme palette and raw stored values.
86
+
87
+ Standalone embeds are unaffected — with no provider (or a provider that supplies no
88
+ `apiFetch`) the probe still uses the global `fetch`, the same documented fallback
89
+ `useRecordEditable` and `provider: 'api'` view sources use.
90
+
91
+ - Updated dependencies [0e67b53]
92
+ - Updated dependencies [ceccdcf]
93
+ - Updated dependencies [d6e5124]
94
+ - Updated dependencies [debad27]
95
+ - Updated dependencies [dc2aa3e]
96
+ - Updated dependencies [ee66e2e]
97
+ - Updated dependencies [ee26e65]
98
+ - Updated dependencies [5900ac5]
99
+ - Updated dependencies [932cbcd]
100
+ - Updated dependencies [734d186]
101
+ - Updated dependencies [f650253]
102
+ - Updated dependencies [3d9769a]
103
+ - Updated dependencies [8f85f8b]
104
+ - Updated dependencies [d0c3b26]
105
+ - Updated dependencies [3fc2971]
106
+ - Updated dependencies [aca27fa]
107
+ - Updated dependencies [dde7283]
108
+ - Updated dependencies [f7c6430]
109
+ - Updated dependencies [4dadf0d]
110
+ - Updated dependencies [ae10a01]
111
+ - Updated dependencies [92876f0]
112
+ - Updated dependencies [f279deb]
113
+ - Updated dependencies [4b70d28]
114
+ - Updated dependencies [eb7f586]
115
+ - Updated dependencies [e901131]
116
+ - Updated dependencies [d9d3463]
117
+ - Updated dependencies [2a40f69]
118
+ - Updated dependencies [bec3e14]
119
+ - Updated dependencies [613b167]
120
+ - Updated dependencies [b4d3c22]
121
+ - Updated dependencies [1f9b905]
122
+ - Updated dependencies [cb13400]
123
+ - Updated dependencies [828549a]
124
+ - Updated dependencies [e1ade8f]
125
+ - Updated dependencies [bc64bfe]
126
+ - Updated dependencies [abb0f81]
127
+ - Updated dependencies [38ab505]
128
+ - Updated dependencies [3e19fe7]
129
+ - Updated dependencies [bb58d1d]
130
+ - Updated dependencies [5cc847c]
131
+ - Updated dependencies [fa21254]
132
+ - Updated dependencies [33c32bf]
133
+ - Updated dependencies [66fb4fa]
134
+ - Updated dependencies [b953a97]
135
+ - Updated dependencies [d7f3e30]
136
+ - Updated dependencies [6d641c9]
137
+ - Updated dependencies [7e4f0e5]
138
+ - Updated dependencies [a84385b]
139
+ - Updated dependencies [45e1949]
140
+ - Updated dependencies [92250d6]
141
+ - Updated dependencies [c1d939f]
142
+ - Updated dependencies [58bebf6]
143
+ - Updated dependencies [405e808]
144
+ - Updated dependencies [49ae9f4]
145
+ - Updated dependencies [a3ae404]
146
+ - Updated dependencies [bfdf3d4]
147
+ - Updated dependencies [bb68488]
148
+ - Updated dependencies [c0f9a4b]
149
+ - Updated dependencies [b1e42d0]
150
+ - Updated dependencies [2459a3e]
151
+ - Updated dependencies [ac853ce]
152
+ - Updated dependencies [fa51109]
153
+ - Updated dependencies [d6aa172]
154
+ - Updated dependencies [fe52a04]
155
+ - Updated dependencies [d46f9b8]
156
+ - Updated dependencies [3f5f87c]
157
+ - Updated dependencies [2fea4d2]
158
+ - Updated dependencies [f5e1143]
159
+ - Updated dependencies [7f1cb33]
160
+ - Updated dependencies [f148a64]
161
+ - Updated dependencies [bb68488]
162
+ - Updated dependencies [2e3b0c0]
163
+ - Updated dependencies [9461dd3]
164
+ - Updated dependencies [78fa331]
165
+ - Updated dependencies [47f551b]
166
+ - Updated dependencies [31ab1ac]
167
+ - Updated dependencies [0082db8]
168
+ - Updated dependencies [ab04728]
169
+ - Updated dependencies [5bf09fd]
170
+ - Updated dependencies [06915b0]
171
+ - Updated dependencies [ff84b05]
172
+ - @object-ui/i18n@17.5.0
173
+ - @object-ui/react@17.5.0
174
+ - @object-ui/components@17.5.0
175
+ - @object-ui/core@17.5.0
176
+ - @object-ui/types@17.5.0
177
+
178
+ ## 17.4.0
179
+
180
+ ### Patch Changes
181
+
182
+ - a7e39a8: `ChartContainer`'s min-size fallback survives a consumer-supplied `style` (objectstack#7026)
183
+
184
+ The container wrote `style={{ minHeight: 280, minWidth: 0, ...props.style }}` and
185
+ then spread `{...props}` on the line BELOW it. `props` is the rest of
186
+ `ComponentProps< "div" >` — only `id`, `className`, `children`, `config` and
187
+ `disableSettleRemount` are destructured out of it — so it still carried the
188
+ consumer's `style`, and a later JSX attribute of the same name replaces an earlier
189
+ one outright. Any caller that passed a `style` therefore replaced the whole object:
190
+ both `minHeight` and `minWidth` vanished, and the `...props.style` merge written
191
+ inside it never executed even once. It was dead code that read, to anyone auditing
192
+ the file, as if the fallback were guaranteed.
193
+
194
+ That fallback is not decorative. It exists so Recharts' `ResponsiveContainer`
195
+ always has a non-zero box to measure: a dashboard widget that overrides the
196
+ container's `h-[350px]` class and wraps the chart in flex/grid without an explicit
197
+ child height leaves the box at 0, Recharts measures `width/height = -1`, and the
198
+ chart renders invisibly — the exact failure the guard was added for.
199
+
200
+ `style` is now destructured out of the rest props and merged explicitly, so which
201
+ side wins is stated in code instead of being decided by JSX attribute order, and
202
+ `{...props}` can no longer reach `style` at all.
203
+
204
+ Precedence: **an author's explicit size wins.** Simply spreading `{...props}`
205
+ first and merging unconditionally would have traded this bug for its mirror image
206
+ — `minHeight: 280` injected next to an authored `height: 100` floors that 100 to
207
+ 280, silently overriding the author. So each half of the fallback applies only
208
+ when the consumer style declares neither of its own keys: `height`/`minHeight`
209
+ gate the height half, `width`/`minWidth` gate the width half, and a key present
210
+ but set to `undefined`/`null` counts as not declared. Every other consumer style
211
+ key passes through untouched.
212
+
213
+ Behaviour change surface, deliberately narrow. A caller that supplies no `style`
214
+ is byte-for-byte unchanged. A caller whose `style` declares a height — which today
215
+ is the only shape in the tree, `AdvancedChartImpl`'s `containerProps` forwarding
216
+ `ChartConfig.height` — keeps exactly the height it authored, also unchanged, and
217
+ additionally regains the `minWidth: 0` half. What changes is the case the issue
218
+ was filed for: a `style` carrying no size key (a margin, a padding, an
219
+ aspect-ratio, any future container-level presentation prop routed through the same
220
+ `containerProps` path) now keeps the min-size fallback instead of silently
221
+ stripping it.
222
+
223
+ Pinned in both directions, since a one-sided pin would have been satisfied by the
224
+ mirror-image fix: a non-size `style` keeps `min-height: 280` / `min-width: 0`
225
+ (red before this change), and an explicit `height: 100` renders as 100 with no
226
+ `min-height` floor (red under the unconditional-merge alternative).
227
+
228
+ - 4bc6c23: Converge dashboard widget `compareTo` on the executor's `{ kind, dimension? }` contract, and make the dataset path actually render a comparison
229
+
230
+ `CompareToConfig` was a three-branch union (`'previousPeriod' | 'previousYear' | { offset }`). `@objectstack/spec` collapsed it to the shape the analytics executor already implements — `DatasetCompareTo`, a plain strict object `{ kind: 'previousPeriod' | 'previousYear'; dimension?: string }` (objectstack#5011) — so this renderer now reads that one shape:
231
+
232
+ - `shiftFilterByCompareTo` / `compareToTrendLabelKey` dispatch on `compareTo.kind`. The `{ offset }` duration shift is gone: `{ offset: '1y' }` is `kind: 'previousYear'`, while `'7d'` / `'1M'` have no faithful target and are restated by the author on the widget's own `filter` plus `kind: 'previousPeriod'`. No trend label key is retired — the offset arm resolved to `vsPreviousPeriod`, which survives as the `previousPeriod` fallback.
233
+ - `DatasetWidget` no longer discards part of `compareTo`. It used to forward only the object form because the two string forms had no meaning downstream; with one shape there is nothing to discard, and a stale string is now invalid metadata rejected where it is authored rather than silently reinterpreted here.
234
+ - **The comparison now actually runs on the dataset path.** A widget states its window in its own `filter` (a date macro, or the dashboard date-range filter merged in), but the executor shifts a `timeDimensions` entry carrying a `dateRange` — so a dataset widget asking for a comparison got "compareTo needs a dated window to shift" and rendered none. When (and only when) a comparison is requested, the resolved filter's bounded date windows are lowered into `selection.timeDimensions[].dateRange` and moved out of `runtimeFilter` (a copy left behind would intersect the shifted window with the current one and empty every comparison column). Which dimension gets shifted stays the executor's decision: every window found is lowered under the name the author wrote, and zero or two candidates surfaces the executor's own error, listing them.
235
+ - The `<measure>__compare` columns that come back are now shown: a delta + window label on KPI widgets, a comparison column on tables, and a `variant: 'comparison'` overlay series on charts — the same treatment and the same `dashboard.trend.*` labels the inline object-provider widgets already use.
236
+
237
+ - 5bfaabd: `PageComponentSchema.dataSource` now reaches every object-bound block, not just
238
+ `list-view` — and `element:record_picker` stops discarding `view`
239
+ (objectstack#6953).
240
+
241
+ objectstack#5576 wired the spec's per-element data binding
242
+ (`dataSource: { object, view?, filter?, sort?, limit? }`) to `list-view` and left
243
+ the same declaration inert on every other page component. Two gaps remained, and
244
+ both were silent:
245
+
246
+ - **`element:record_picker` read four of the five keys and dropped `view`.** So
247
+ `dataSource: { object: 'account', view: 'hot' }` — the spec's own example —
248
+ built a picker over EVERY account instead of the rows the saved view selects.
249
+ Nothing threw and nothing rendered an error; the option list was simply wider
250
+ than what was authored, which also means a user could select a record the page
251
+ said was out of scope.
252
+ - **`object-grid` / `object-form` / `object-kanban` / `object-calendar` /
253
+ `object-chart` / `object-metric` / `record:related_list` read none of it.**
254
+ Each gates its fetch on its own `objectName`, and nothing mapped
255
+ `dataSource.object` onto it, so a page written the way the spec documents
256
+ rendered an empty grid / a field-less form / a board with no cards / an empty
257
+ month / an empty chart / a static metric number — with no request and no
258
+ diagnostic anywhere. Spec-valid metadata rendering nothing is the
259
+ objectstack#4413 shape.
260
+
261
+ Composition follows objectstack#5576's landed semantics unchanged on every block:
262
+ a named saved view supplies the baseline, a key written on the component itself
263
+ overrides it, an explicit binding key overrides both, `filter` AND-combines
264
+ ("additional filter criteria" — a binding can narrow a view, never widen it), and
265
+ a `view` name that does not resolve renders a configuration error instead of
266
+ degrading to the object's full scope.
267
+
268
+ - `@object-ui/react` — new `useElementDataSourceSchema(schema, mapping, dataSource?)`
269
+ and `ElementDataSourceGate` apply a resolved binding to the schema keys a given
270
+ block reads, plus `ElementDataSourceErrorPanel` / `ElementDataSourceLoadingPanel`
271
+ for the two non-final states. One precedence table for all blocks rather than
272
+ one copy per block — that copy is how "additional filter criteria" would have
273
+ become two dialects.
274
+ - A mapping names **only** keys its block genuinely reads. A composed value
275
+ written onto a key the block ignores would be accepted and dropped, which is
276
+ the defect being removed, one layer deeper — so a kanban's swimlane `columns`
277
+ never receive a view's field list, and a block with no row cap leaves `limit`
278
+ unmapped. The per-block coverage table, including two residual gaps that are
279
+ named rather than papered over, is in `content/docs/guide/data-source.md`.
280
+
281
+ No behaviour changes for a block that carries no `dataSource`: the binding-free
282
+ path returns the schema by reference, so nothing remounts and nothing refetches.
283
+
284
+ - Updated dependencies [794c497]
285
+ - Updated dependencies [993336f]
286
+ - Updated dependencies [f0a625a]
287
+ - Updated dependencies [b5980f4]
288
+ - Updated dependencies [8aad9fd]
289
+ - Updated dependencies [6719877]
290
+ - Updated dependencies [56ff091]
291
+ - Updated dependencies [7864f03]
292
+ - Updated dependencies [0cbdca8]
293
+ - Updated dependencies [d229dfa]
294
+ - Updated dependencies [ecae400]
295
+ - Updated dependencies [4bc6c23]
296
+ - Updated dependencies [d3e738a]
297
+ - Updated dependencies [c3b01a7]
298
+ - Updated dependencies [f5f8744]
299
+ - Updated dependencies [7ed3360]
300
+ - Updated dependencies [69becd2]
301
+ - Updated dependencies [5e52495]
302
+ - Updated dependencies [0fa5e4d]
303
+ - Updated dependencies [b750823]
304
+ - Updated dependencies [5bfaabd]
305
+ - Updated dependencies [e06810e]
306
+ - Updated dependencies [ab3ad4f]
307
+ - Updated dependencies [c2fd122]
308
+ - Updated dependencies [ac2139c]
309
+ - Updated dependencies [b14ab3a]
310
+ - Updated dependencies [e24d767]
311
+ - Updated dependencies [8c60819]
312
+ - Updated dependencies [aca561a]
313
+ - Updated dependencies [e64a52e]
314
+ - Updated dependencies [844d17f]
315
+ - Updated dependencies [48132f7]
316
+ - Updated dependencies [4dcd52a]
317
+ - Updated dependencies [42ae5c6]
318
+ - Updated dependencies [0ef9dfd]
319
+ - Updated dependencies [1d723e3]
320
+ - Updated dependencies [0109f54]
321
+ - Updated dependencies [7e5bb5d]
322
+ - Updated dependencies [fbc23e0]
323
+ - Updated dependencies [6d762da]
324
+ - Updated dependencies [e6fdbdc]
325
+ - Updated dependencies [54233b1]
326
+ - Updated dependencies [f9faa7d]
327
+ - Updated dependencies [97b63d7]
328
+ - Updated dependencies [6bb454a]
329
+ - Updated dependencies [523be48]
330
+ - Updated dependencies [7e2b7e9]
331
+ - Updated dependencies [33526fd]
332
+ - Updated dependencies [32413ec]
333
+ - Updated dependencies [c1e1e6b]
334
+ - @object-ui/components@17.4.0
335
+ - @object-ui/react@17.4.0
336
+ - @object-ui/core@17.4.0
337
+ - @object-ui/i18n@17.4.0
338
+ - @object-ui/types@17.4.0
339
+
3
340
  ## 17.3.0
4
341
 
5
342
  ### Minor Changes
@@ -872,6 +1209,7 @@
872
1209
  project `health`) painted its categories from the generic `--chart-1..5`
873
1210
  palette — the same gap the chart view (`object-chart`) had before #1932. It now
874
1211
  resolves the dimension field's option colors (using the dataset's base `object`
1212
+
875
1213
  - dimension→field map the query already returns) and threads them to the
876
1214
  renderer as a per-category `categoryColors` map, so health green/red/yellow
877
1215
  paints semantically.
@@ -1078,6 +1416,7 @@
1078
1416
  - 991b62d: Add `compareTo` field to dashboard widgets for period-over-period
1079
1417
  comparison. Supports `'previousPeriod'`, `'previousYear'`, and
1080
1418
  `{ offset: '7d' | '4w' | '1M' | '1y' }`.
1419
+
1081
1420
  - **Metric / gauge widgets** now compute a delta percentage when `compareTo`
1082
1421
  is set and surface it as a derived `trend` (auto-labelled via
1083
1422
  `dashboard.trend.vsLast*` i18n keys sniffed from the filter macros).
@@ -1562,6 +1901,7 @@
1562
1901
  Library builds (vite lib mode) now externalize every non-relative import instead of bundling third-party CJS dependencies into the published dist. This avoids inlined `require("react")` / `require("react-dom")` calls that cause `Calling \`require\` for "react" in an environment that doesn't expose the \`require\` function` runtime errors when consumer apps re-bundle the published dist.
1563
1902
 
1564
1903
  Specifically fixes:
1904
+
1565
1905
  - `@object-ui/plugin-dashboard` no longer inlines `react-grid-layout` (and its transitive `react-draggable` / `react-resizable` CJS bundles). `react-grid-layout` is now declared as a peer dependency so consumers install a single ESM-friendly copy.
1566
1906
  - `@object-ui/components`, `@object-ui/plugin-calendar`, `@object-ui/plugin-charts`, `@object-ui/plugin-designer` no longer inline `react-i18next` / `i18next` / `use-sync-external-store` CJS shims.
1567
1907
  - All plugin packages now use a unified `external: (id) => !/^[./]/.test(id) && !id.startsWith(__dirname)` rule, ensuring future additions of CJS deps are automatically externalized.
@@ -1795,6 +2135,7 @@
1795
2135
  - New plugin-object and ObjectQL SDK updates
1796
2136
 
1797
2137
  **Added:**
2138
+
1798
2139
  - New Plugin: @object-ui/plugin-object - ObjectQL plugin for automatic table and form generation
1799
2140
  - ObjectTable: Auto-generates tables from ObjectQL object schemas
1800
2141
  - ObjectForm: Auto-generates forms from ObjectQL object schemas with create/edit/view modes
@@ -1803,6 +2144,7 @@
1803
2144
  - ObjectQL Integration: Enhanced ObjectQLDataSource with getObjectSchema() method using MetadataApiClient
1804
2145
 
1805
2146
  **Changed:**
2147
+
1806
2148
  - Updated @objectql/sdk from ^1.8.3 to ^1.9.1
1807
2149
  - Updated @objectql/types from ^1.8.3 to ^1.9.1
1808
2150
 
@@ -1819,6 +2161,7 @@
1819
2161
  - Patch release: Add automated changeset workflow and CI/CD improvements
1820
2162
 
1821
2163
  This release includes infrastructure improvements:
2164
+
1822
2165
  - Added changeset-based version management
1823
2166
  - Enhanced CI/CD workflows with GitHub Actions
1824
2167
  - Improved documentation for contributing and releasing
package/README.md CHANGED
@@ -120,17 +120,6 @@ By using lazy loading, the main application bundle stays lean:
120
120
 
121
121
  This results in significantly faster initial page loads for applications that don't use charts on every page.
122
122
 
123
- <!-- release-metadata:v3.3.0 -->
124
-
125
- ## Compatibility
126
-
127
- - **React:** 18.x or 19.x
128
- - **Node.js:** ≥ 18
129
- - **TypeScript:** ≥ 5.0 (strict mode)
130
- - **`@objectstack/spec`:** ^3.3.0
131
- - **`@objectstack/client`:** ^3.3.0
132
- - **Tailwind CSS:** ≥ 3.4 (for packages with UI)
133
-
134
123
  ## Links
135
124
 
136
125
  - 📚 [Documentation](https://www.objectui.org/docs/plugins/plugin-charts)
@@ -39,7 +39,7 @@ export type ChartContainerConfig = {
39
39
  theme: Record<keyof typeof THEMES, string>;
40
40
  });
41
41
  };
42
- declare function ChartContainer({ id, className, children, config, disableSettleRemount, ...props }: React.ComponentProps<"div"> & {
42
+ declare function ChartContainer({ id, className, children, config, disableSettleRemount, style, ...props }: React.ComponentProps<"div"> & {
43
43
  config: ChartContainerConfig;
44
44
  children: React.ComponentProps<typeof ResponsiveContainer>["children"];
45
45
  /**
@@ -46,3 +46,16 @@ export declare function aggregateRecords(records: any[], aggregate: {
46
46
  export declare function resolveGroupByLabels(data: any[], groupByField: string, objectSchema: any, dataSource?: any, translateOption?: (value: string, fallbackLabel: string) => string): Promise<any[]>;
47
47
  export { extractRecords } from '@object-ui/core';
48
48
  export declare const ObjectChart: (props: any) => React.JSX.Element;
49
+ /**
50
+ * Registry shell for `object-chart` — maps the spec's
51
+ * `PageComponentSchema.dataSource` binding onto the keys {@link ObjectChart}
52
+ * reads (objectstack#6953).
53
+ *
54
+ * Nothing used to map `dataSource.object` onto `objectName`, and this block gates
55
+ * BOTH its fetch and its loading state on that key (`!schema.objectName &&
56
+ * !schema.dataset` returns early) — so a chart authored with the binding the
57
+ * spec documents rendered an empty frame with no error and no request. Lives
58
+ * here, beside the registration, rather than in `ChartContainerImpl` — the
59
+ * binding is a registry-boundary concern, not a rendering one.
60
+ */
61
+ export declare const ObjectChartBlock: (props: any) => React.JSX.Element;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import { ChartBarRenderer, ChartRenderer } from './ChartRenderer';
2
2
  export type { BarChartSchema } from './types';
3
3
  export { ChartBarRenderer, ChartRenderer };
4
- export { ObjectChart } from './ObjectChart';
4
+ export { ObjectChart, ObjectChartBlock } from './ObjectChart';
5
+ export { normalizeChartSchema } from './normalizeChartSchema';
6
+ export type { NormalizedChartSchema } from './normalizeChartSchema';
5
7
  export declare const chartComponents: {
6
8
  'bar-chart': import('react').FC<import('./ChartRenderer').ChartBarRendererProps>;
7
9
  chart: import('react').FC<import('./ChartRenderer').ChartRendererProps>;