@object-ui/plugin-dashboard 17.2.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/README.md CHANGED
@@ -219,21 +219,36 @@ into each bound widget's inline query (`AND`-combined with the widget's own
219
219
  "field": "region", // default binding target
220
220
  "label": "Region",
221
221
  "type": "select", // text | select | date | number | lookup
222
- "options": ["EMEA", "APAC", "AMER"]
222
+ // Canonical @objectstack/spec pair form — the only form the platform
223
+ // accepts at publish. The bare-string shorthand (["EMEA", …]) is
224
+ // deprecated: still lifted at runtime, now warns (objectui#4356).
225
+ "options": [
226
+ { "value": "EMEA", "label": "EMEA" },
227
+ { "value": "APAC", "label": "APAC" },
228
+ { "value": "AMER", "label": "AMER" }
229
+ ]
223
230
  // or dynamic: "optionsFrom": { "object": "accounts", "valueField": "region" }
224
231
  }
225
232
  ],
226
233
  "widgets": [
234
+ // Widgets bind a semantic-layer dataset (ADR-0021) and select its
235
+ // dimensions/measures by name. The pre-ADR-0021 top-level `object` +
236
+ // `categoryField`/`valueField`/`aggregate` shape was REMOVED — a widget
237
+ // still carrying it renders "This widget uses a retired data format.
238
+ // Edit it to bind a dataset." instead of a chart. A renderer-internal
239
+ // query lives under `options.data` as `{ provider: 'object', object,
240
+ // aggregate }`; an `options.data` array is fixed demo data.
241
+ //
227
242
  // Default binding: the filter's own `field` (dateRange → created_at).
228
- { "id": "w1", "type": "bar", "object": "invoices", "aggregate": "count" },
243
+ { "id": "w1", "type": "bar", "dataset": "invoices", "dimensions": ["status"], "values": ["count"] },
229
244
  // Explicit binding: map each filter to THIS widget's own field.
230
245
  {
231
- "id": "w2", "type": "line", "object": "accounts", "aggregate": "count",
246
+ "id": "w2", "type": "line", "dataset": "accounts", "dimensions": ["signed_month"], "values": ["count"],
232
247
  "filterBindings": { "dateRange": "signed_at", "region": "sales_region" }
233
248
  },
234
249
  // Opt out of a filter with `false`.
235
250
  {
236
- "id": "w3", "type": "metric", "object": "invoices", "aggregate": "count",
251
+ "id": "w3", "type": "metric", "dataset": "invoices", "values": ["count"],
237
252
  "filterBindings": { "region": false }
238
253
  }
239
254
  ]
@@ -267,6 +282,39 @@ Notes:
267
282
  warning instead of emitting a query that matches nothing. Explicit
268
283
  `filterBindings` strings are always honoured as written.
269
284
 
285
+ ## Widget accent colour (`colorVariant`)
286
+
287
+ A KPI widget can declare a semantic accent. The vocabulary is
288
+ `@objectstack/spec`'s `WidgetColorVariantSchema` enum — `default`, `blue`,
289
+ `teal`, `orange`, `purple`, `success`, `warning`, `danger` — the same eight
290
+ tokens the designer's swatch picker offers:
291
+
292
+ ```typescript
293
+ {
294
+ id: 'kpi_at_risk',
295
+ type: 'metric',
296
+ title: 'At-Risk Projects',
297
+ dataset: 'project_health',
298
+ values: ['project_count'],
299
+ filter: { health: 'red' },
300
+ colorVariant: 'danger', // tints the value; card chrome stays neutral
301
+ }
302
+ ```
303
+
304
+ Where the accent lands depends on the layout, not on the token:
305
+
306
+ | Layout | Accent |
307
+ | --- | --- |
308
+ | Card chrome (`MetricWidget`, inline `object-metric`) | the icon chip's background + foreground |
309
+ | Chrome-less (`MetricWidget variant: 'bare'`, and every dataset-bound `metric`) | the big number's text colour |
310
+
311
+ Both read one shared table (`src/colorVariants.ts`), so the same declaration
312
+ reads the same on either surface. `default` — and omitting the key — means "no
313
+ accent"; the widget renders in the ambient foreground colour. A token outside
314
+ the enum gets no accent and is not aliased to a nearby colour: it is invalid
315
+ metadata, rejected where it is authored and published rather than reinterpreted
316
+ here.
317
+
270
318
  ## TypeScript Support
271
319
 
272
320
  ```typescript
@@ -386,17 +434,6 @@ file system, …) per the protocol-agnostic architecture rule.
386
434
  > dashboards. If you still want a browser-local cache for a demo, do it
387
435
  > in the parent inside `onSchemaChange`.
388
436
 
389
- <!-- release-metadata:v3.3.0 -->
390
-
391
- ## Compatibility
392
-
393
- - **React:** 18.x or 19.x
394
- - **Node.js:** ≥ 18
395
- - **TypeScript:** ≥ 5.0 (strict mode)
396
- - **`@objectstack/spec`:** ^3.3.0
397
- - **`@objectstack/client`:** ^3.3.0
398
- - **Tailwind CSS:** ≥ 3.4 (for packages with UI)
399
-
400
437
  ## Links
401
438
 
402
439
  - 📚 [Documentation](https://www.objectui.org/docs/plugins/plugin-dashboard)
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardFilterBar.d.ts","sourceRoot":"","sources":["../src/DashboardFilterBar.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;GAQG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AAiB5D,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,iBAAiB,CAAC;AAOzB,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2ND,wBAAgB,kBAAkB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,uBAAuB,4BAyCrH"}
1
+ {"version":3,"file":"DashboardFilterBar.d.ts","sourceRoot":"","sources":["../src/DashboardFilterBar.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;GAQG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AAiB5D,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,iBAAiB,CAAC;AAoCzB,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkSD,wBAAgB,kBAAkB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,uBAAuB,4BAyCrH"}
@@ -4,6 +4,33 @@ import * as React from 'react';
4
4
  export interface DashboardGridLayoutProps {
5
5
  schema: DashboardComponentSchema;
6
6
  className?: string;
7
+ /**
8
+ * Data-source adapter for the widgets this grid renders, handed to
9
+ * `DatasetWidget` for ADR-0021 dataset-bound widgets (objectui#4614).
10
+ *
11
+ * Typed `unknown`, not `any`. The sibling declares `dataSource?: any`
12
+ * (`DashboardRenderer.tsx:198`) for a reason that is explicitly historical —
13
+ * "that is precisely what it resolved to before", via the index signature that
14
+ * used to answer for it — and this is a NEW declaration with no prior
15
+ * resolution to preserve. `unknown` is what the consumer itself declares
16
+ * (`DatasetWidget.tsx:655`, `dataSource: unknown`), so the value is forwarded
17
+ * to exactly the type that receives it, and no call site is held to anything
18
+ * new: every value is assignable to `unknown`. Narrowing it further to a real
19
+ * adapter type is a separate change with its own consumer sweep, on both
20
+ * surfaces at once.
21
+ *
22
+ * Optional, and the omitted case is a SUPPORTED one rather than an oversight:
23
+ * `dashboard-grid`'s SDUI registration declares only `title` / `className`
24
+ * inputs, so schema-driven hosts render this component with no adapter at all.
25
+ * A dataset-bound widget arriving that way renders `DatasetWidget`'s own
26
+ * no-capability diagnostic — a visible state, never a blank tile.
27
+ *
28
+ * `SchemaRenderer` forwards this as a React prop (its `...props` spread, last:
29
+ * `SchemaRenderer.tsx:632`). It cannot be shadowed by the spec's per-element
30
+ * `dataSource` BINDING, which is stripped from the schema before that spread
31
+ * for exactly this reason (`SchemaRenderer.tsx:564-575`, objectstack#5576).
32
+ */
33
+ dataSource?: unknown;
7
34
  /**
8
35
  * Fires on every drag/resize tick with the raw react-grid-layout payload.
9
36
  * Useful for live previews; NOT a persistence hook.
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardGridLayout.d.ts","sourceRoot":"","sources":["../src/DashboardGridLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAA2C,KAAK,UAAU,IAAI,SAAS,EAAuC,MAAM,mBAAmB,CAAC;AAC/I,OAAO,kCAAkC,CAAC;AAI1C,OAAO,KAAK,EAAE,wBAAwB,EAAyB,MAAM,kBAAkB,CAAC;AA4BxF,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,wBAAwB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;IAC/C;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC5D,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,wBAAwB,EAChC,MAAM,EAAE,SAAS,EAAE,GAClB,wBAAwB,CAa1B;AAcD,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA6UlE,CAAC"}
1
+ {"version":3,"file":"DashboardGridLayout.d.ts","sourceRoot":"","sources":["../src/DashboardGridLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAA2C,KAAK,UAAU,IAAI,SAAS,EAAuC,MAAM,mBAAmB,CAAC;AAC/I,OAAO,kCAAkC,CAAC;AAK1C,OAAO,KAAK,EAAc,wBAAwB,EAAyB,MAAM,kBAAkB,CAAC;AA8BpG,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,wBAAwB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;IAC/C;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC5D,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,wBAAwB,EAChC,MAAM,EAAE,SAAS,EAAE,GAClB,wBAAwB,CAa1B;AAcD,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA+blE,CAAC"}
@@ -1,8 +1,51 @@
1
1
  import { DashboardComponentSchema, DashboardWidgetSchema } from '@object-ui/types';
2
- import { ActionDef, ActionResult, ActionContext, ModalHandler } from '@object-ui/core';
3
- export interface DashboardRendererProps {
2
+ import { ActionDef, ActionResult, ActionContext, ModalHandler, SduiDomPassThroughKey } from '@object-ui/core';
3
+ import { HTMLAttributes } from 'react';
4
+ /**
5
+ * The dashboard renderer's props.
6
+ *
7
+ * ## Why there is no `[key: string]: any` here (objectui#4528)
8
+ *
9
+ * There used to be one, and it erased this entire interface. A string index
10
+ * signature puts `string` into `keyof Props`, so `'ref' extends keyof Props` is
11
+ * always true and React's `PropsWithoutRef` takes its `Omit` branch — and
12
+ * `Omit` over a type carrying a string index signature keeps ONLY the index
13
+ * signature. Every declared property above was dropped from the resolved type:
14
+ * `keyof React.ComponentProps< typeof DashboardRenderer >` measured as
15
+ * `string | number`, and `onWidgetClick` measured as `any` at every JSX call
16
+ * site, while this interface went on declaring
17
+ * `(widgetId: string | null) => void`. The declaration was right and no
18
+ * consumer was held to it — a prop typo or a wrong-arity handler type-checked.
19
+ *
20
+ * The same trap, in `packages/components`, is objectui#4422 / PR #4438; this is
21
+ * the sweep of the two packages that issue left unswept.
22
+ *
23
+ * ## How the DOM pass-through survives without it
24
+ *
25
+ * `SchemaRenderer` hands this component the authored node's own keys, so the
26
+ * render function still collects an open rest object — but what may reach the
27
+ * element is decided by `toDomProps`' WHITELIST (objectui#4432), not by this
28
+ * type. The keys that whitelist forwards are therefore declared here BY NAME,
29
+ * derived from the whitelist constant itself so the two cannot drift, which is
30
+ * exactly what `@object-ui/core`'s `dom-props` doctrine asks for: "Deliberate
31
+ * DOM pass-through beyond this set stays available the objectui#4435 way —
32
+ * DECLARE it and forward it by name. Do not reopen the spread."
33
+ */
34
+ export interface DashboardRendererProps extends Pick<HTMLAttributes<HTMLDivElement>, SduiDomPassThroughKey> {
4
35
  schema: DashboardComponentSchema;
5
36
  className?: string;
37
+ /**
38
+ * Data-source adapter for the widgets this dashboard renders.
39
+ *
40
+ * Destructured by the render function and handed to `DatasetWidget` /
41
+ * `SchemaRenderer`, and passed by both in-repo hosts (`DashboardView`,
42
+ * `DashboardPreview`) — but never declared until objectui#4528, because the
43
+ * index signature above was answering for it. Typed `any` deliberately: that
44
+ * is precisely what it resolved to before, so declaring it changes what is
45
+ * DECLARED without changing what any call site is held to. Narrowing it to a
46
+ * real adapter type is a separate change with its own consumer sweep.
47
+ */
48
+ dataSource?: any;
6
49
  /** Callback invoked when dashboard refresh is triggered (manual or auto) */
7
50
  onRefresh?: () => void;
8
51
  /** Total record count to display */
@@ -37,7 +80,6 @@ export interface DashboardRendererProps {
37
80
  * title/subtitle so we don't display them twice.
38
81
  */
39
82
  hideHeaderText?: boolean;
40
- [key: string]: any;
41
83
  }
42
84
  /**
43
85
  * DashboardRenderer — the public dashboard renderer.
@@ -54,5 +96,5 @@ export interface DashboardRendererProps {
54
96
  * stay readable inside widget subtrees, and only a same-named filter shadows
55
97
  * the outer variable.
56
98
  */
57
- export declare const DashboardRenderer: import('react').ForwardRefExoticComponent<Omit<DashboardRendererProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
99
+ export declare const DashboardRenderer: import('react').ForwardRefExoticComponent<DashboardRendererProps & import('react').RefAttributes<HTMLDivElement>>;
58
100
  //# sourceMappingURL=DashboardRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardRenderer.d.ts","sourceRoot":"","sources":["../src/DashboardRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAGxF,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAsJ5F,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,wBAAwB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,WAAW,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACrE,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,uDAAuD;IACvD,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,IAAI,CAAC;IAC9D,mGAAmG;IACnG,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,wGAAwG;IACxG,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC,CAAC;IACrH;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAyuBD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,gIAiB7B,CAAC"}
1
+ {"version":3,"file":"DashboardRenderer.d.ts","sourceRoot":"","sources":["../src/DashboardRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAc,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAGpG,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAUnH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAmI5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,sBACf,SAAQ,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,qBAAqB,CAAC;IACnE,MAAM,EAAE,wBAAwB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,WAAW,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACrE,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,uDAAuD;IACvD,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,IAAI,CAAC;IAC9D,mGAAmG;IACnG,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,wGAAwG;IACxG,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC,CAAC;IACrH;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAg3BD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,mHAiB7B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardWithConfig.d.ts","sourceRoot":"","sources":["../src/DashboardWithConfig.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,wBAAwB,EAAyB,MAAM,kBAAkB,CAAC;AAKxF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAMnE,MAAM,WAAW,wBAAwB;IACvC,qCAAqC;IACrC,MAAM,EAAE,wBAAwB,CAAC;IACjC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,6DAA6D;IAC7D,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IACpD,iEAAiE;IACjE,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IACvE,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,yBAAyB,EAAE,CAAC;IACvC,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,WAAW,EACX,iBAAyB,EACzB,SAAS,EACT,QAAQ,EACR,eAAe,GAChB,EAAE,wBAAwB,qBAyJ1B"}
1
+ {"version":3,"file":"DashboardWithConfig.d.ts","sourceRoot":"","sources":["../src/DashboardWithConfig.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,wBAAwB,EAAyB,MAAM,kBAAkB,CAAC;AAKxF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAMnE,MAAM,WAAW,wBAAwB;IACvC,qCAAqC;IACrC,MAAM,EAAE,wBAAwB,CAAC;IACjC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,6DAA6D;IAC7D,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IACpD,iEAAiE;IACjE,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IACvE,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,yBAAyB,EAAE,CAAC;IACvC,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,WAAW,EACX,iBAAyB,EACzB,SAAS,EACT,QAAQ,EACR,eAAe,GAChB,EAAE,wBAAwB,qBAuK1B"}
@@ -1,19 +1,44 @@
1
- import { buildDatasetDrillFilter } from '@object-ui/core';
1
+ import { buildDatasetDrillFilter, pivotCellKey, ChartSeriesBinding } from '@object-ui/core';
2
2
  /**
3
3
  * Build the record-list filter for a drilled row. Re-exported for back-compat;
4
4
  * the implementation now lives in `@object-ui/core` (`buildDatasetDrillFilter`)
5
5
  * so the dashboard and the report renderer drill identically.
6
6
  */
7
7
  export declare const buildDrillFilter: typeof buildDatasetDrillFilter;
8
+ /**
9
+ * The pivot key encoders, re-exported for back-compat; the implementations now
10
+ * live in `@object-ui/core` (`pivotBucketId` / `pivotCellKey`) so this widget
11
+ * and the report renderer's cross-tab key their buckets identically. See that
12
+ * module for why both are `JSON.stringify` rather than a delimiter character,
13
+ * and why an empty value encodes as JSON `null` rather than a placeholder
14
+ * string (objectui#4056).
15
+ *
16
+ * Every consumer of a bucket id — the cell index below, the row-total lookup
17
+ * AND the column-total lookup in the cross-tab renderer — must build its key
18
+ * with these, over values normalized by `pivotDimensionValue`; a second,
19
+ * hand-rolled encoding of the same id is what made the old bug invisible.
20
+ *
21
+ * `pivotRowId` is the historical name of the axis-neutral encoder, kept as an
22
+ * alias so this package's published surface does not change.
23
+ */
24
+ declare const pivotRowId: (dimensionValues: Array<string | null>) => string;
25
+ export { pivotRowId, pivotCellKey };
8
26
  /**
9
27
  * Pivot flat dataset rows into a cross-tab: `rowDims` go DOWN, `colDim` spreads
10
28
  * ACROSS. Returns ordered row/column headers (display labels from the rows) and
11
- * a map from a `${rowId} ${colId}` cell key to the FLAT row index holding
12
- * that combination's measure values. No re-aggregation — the dataset already
13
- * grouped by every dimension, so each cell maps to exactly one row (the index
14
- * is also what drill-through uses to read `drillRawRows`).
29
+ * a map from a `pivotCellKey(rowId, colId)` cell key to the FLAT row index
30
+ * holding that combination's measure values. No re-aggregation — the dataset
31
+ * already grouped by every dimension, so each cell maps to exactly one row (the
32
+ * index is also what drill-through uses to read `drillRawRows`).
33
+ *
34
+ * `locale` is the display-locale tag the header LABELS are formatted in
35
+ * (objectui#4566) — this is a plain exported function, not a component, so it
36
+ * cannot read `useDisplayLocale()` itself. It affects `rowHeaders`/`colHeaders`
37
+ * only; the `id`s are opaque keys built by `pivotBucketId` from the RAW values
38
+ * and are deliberately untouched by it, so a locale change can never re-key a
39
+ * cell (which would break the `cellIndex` lookup and drill-through with it).
15
40
  */
16
- export declare function buildPivot(rows: Array<Record<string, unknown>>, rowDims: string[], colDim: string): {
41
+ export declare function buildPivot(rows: Array<Record<string, unknown>>, rowDims: string[], colDim: string, locale?: string): {
17
42
  rowHeaders: Array<{
18
43
  id: string;
19
44
  labels: string[];
@@ -26,6 +51,161 @@ export declare function buildPivot(rows: Array<Record<string, unknown>>, rowDims
26
51
  };
27
52
  /** Serialize a 2D array (first row = headers) to CSV text. */
28
53
  export declare function toCsv(rows: Array<Array<string | number | null | undefined>>): string;
54
+ /** A `DatasetSelection.timeDimensions` entry stating a bounded window. */
55
+ export interface DatasetTimeWindow {
56
+ dimension: string;
57
+ dateRange: [string, string];
58
+ }
59
+ /**
60
+ * Split a RESOLVED runtime filter into the bounded date windows it states and
61
+ * the rest of the filter (objectui#3337 point 5).
62
+ *
63
+ * The executor shifts exactly one thing for a `compareTo`: a `timeDimensions`
64
+ * entry carrying a `dateRange`. A widget states its window in its own `filter`
65
+ * instead (a date macro, or the dashboard's date-range filter merged in by
66
+ * `DashboardRenderer`), which is why forwarding a structured `compareTo` alone
67
+ * still came back "compareTo needs a dated window to shift".
68
+ *
69
+ * Windows are **moved, not copied**: the comparison pass re-runs with the
70
+ * shifted `timeDimensions` but the SAME `runtimeFilter`, so a copy left behind
71
+ * would intersect the shifted window with the current one and every
72
+ * `<measure>__compare` column would come back empty.
73
+ *
74
+ * Only CONJUNCTIVE positions are walked — the top level and `$and` members. A
75
+ * window inside `$or` / `$not` is not a window the whole query runs in, so it
76
+ * stays in the filter untouched.
77
+ *
78
+ * **Which dimension gets shifted is not decided here.** Every window found is
79
+ * lowered under the name the author wrote. Zero of them, or two, is the
80
+ * executor's error to raise — it names the candidates (`resolveCompareDimension`).
81
+ * Guessing one renderer-side would trade a loud error for a quietly wrong
82
+ * window, which is the failure class objectstack#5011 set out to end.
83
+ */
84
+ export declare function extractDateWindows(filter: unknown): {
85
+ windows: DatasetTimeWindow[];
86
+ rest: Record<string, unknown> | undefined;
87
+ };
88
+ /**
89
+ * Lower a dashboard widget's declared `chartConfig` (spec `ChartConfigSchema` —
90
+ * the same shape a report block and a react `<ObjectChart>` parse) onto the
91
+ * chart schema this widget hands to the renderer.
92
+ *
93
+ * ## Why this is a whitelist and not a spread
94
+ *
95
+ * Until #3135 NONE of `chartConfig` reached the renderer: this widget read
96
+ * `options` and nothing else, so an author who wrote `showLegend: false` still
97
+ * got a legend and one who wrote `true` only got one because "on" is the
98
+ * renderer's default. #3135 lowered that single flag and left the rest declared
99
+ * and inert. objectstack#7016 lowers the rest of the keys that are actually
100
+ * DELIVERED, admitting a key only when both of these hold:
101
+ *
102
+ * 1. **The chart block draws it end to end on this path.** `{ type: 'chart' }`
103
+ * resolves to `ChartRenderer` → `AdvancedChartImpl`, which draws
104
+ * `title`/`subtitle` in its ChartFrame, turns `description` into the chart
105
+ * container's `role="img"` + `aria-label`, applies `height` as that
106
+ * container's inline height, reads `colors` as the positional palette,
107
+ * prints `showDataLabels` as a Recharts `LabelList`, draws `annotations` as
108
+ * ReferenceLine/ReferenceArea and honours `interaction` as the tooltip
109
+ * toggle plus `Brush`. Forwarding a key the renderer ignores would only
110
+ * move declared-but-not-delivered one layer down, which is the failure this
111
+ * change exists to remove.
112
+ * 2. **It does not fight the dataset derivation.** `type` stays out: the
113
+ * widget's own `type` already picks the family through `CHART_TYPE_MAP`,
114
+ * which is the dataset path's chart-family channel.
115
+ *
116
+ * ## Where `xAxis` / `yAxis` / `series` go — the ruled split (#4229)
117
+ *
118
+ * Those three used to be refused here under the same criterion 2, on the
119
+ * grounds that they are "DERIVED from the dataset selection". That belief was
120
+ * **half right, and the half it got wrong silently dropped authored intent**:
121
+ * a widget authoring the spec's own combo shape — `series[].type` plus
122
+ * `series[].yAxis: 'left'|'right'` and two `yAxis` entries — rendered as
123
+ * grouped bars on one axis, because the per-series mark and the axis binding
124
+ * never left this function (#4229, measured in the DOM: 2 bars / 0 lines / 1
125
+ * axis where 1 bar + 1 line + 2 axes were authored).
126
+ *
127
+ * The ruling: **the dataset owns DATA, the author owns PRESENTATION.**
128
+ *
129
+ * - **Data (derived, never forwarded)** — series MEMBERSHIP (which columns
130
+ * become series, which rows, which buckets) and the column each binding
131
+ * reads. Concretely: `buildChartSeries`'s `dataKey`s, `xAxisKey`, and the
132
+ * spec's two binding keys `series[].name` and `ChartAxis.field`.
133
+ * - **Presentation (authored, merged forward)** — everything else on those
134
+ * same objects: `series[].type` (the per-series mark), `series[].yAxis`
135
+ * (which axis it binds to), `label`/`color`/`stack`/`variant`/`dashArray`/
136
+ * `opacity`, and the axis definitions' `title`/`format`/`min`/`max`/
137
+ * `stepSize`/`showGridLines`/`position`/`logarithmic`.
138
+ *
139
+ * This is #2880's S2 rule — dual axes are `yAxis[].position` plus
140
+ * `series[].yAxis`, and a combo assigns its axes by EXPLICIT binding first,
141
+ * falling back to the per-series-type guess only where the author bound
142
+ * nothing — extended from `ObjectChart` (where PR #2883 landed it) to the
143
+ * dataset path, which never carried it over. {@link mergeAuthoredPresentation}
144
+ * is the ONE place that merge happens; see it for the match rule and for why
145
+ * membership is safe.
146
+ *
147
+ * `aria` is the one declared key with **no reader at all** on this path:
148
+ * `AdvancedChartImpl` has no `aria` prop, and `SchemaRenderer`'s ARIA injection
149
+ * reads the FLAT `ariaLabel`/`ariaDescribedBy`/`role`, never a nested `aria`
150
+ * object. It is therefore left unforwarded on purpose (criterion 1) and
151
+ * reported back to objectstack#5175's narrowing half rather than papered over
152
+ * with a dashboard-only flattening that would also collide with the accessible
153
+ * name `description` already sets.
154
+ *
155
+ * @param raw the widget's `chartConfig` as authored (anything, incl. absent)
156
+ * @param fieldCategoryColors per-category colours resolved from the category
157
+ * dimension's own select/lookup option colours, merged UNDER an explicit
158
+ * author map (see the `colors` note below)
159
+ * @returns only the keys that resolved, so the caller can spread it over the
160
+ * derived chart schema and every undeclared key keeps the renderer's default
161
+ */
162
+ export declare function chartConfigPresentation(raw: unknown, fieldCategoryColors?: Record<string, string> | null): Record<string, unknown>;
163
+ /** Authored spec `ChartSeries` presentation, in the renderer's internal spelling. */
164
+ export interface AuthoredSeriesPresentation {
165
+ label?: string;
166
+ /** Spec `ChartSeries.type`, narrowed — see {@link seriesPresentation}. */
167
+ chartType?: 'bar' | 'line' | 'area';
168
+ yAxis?: 'left' | 'right';
169
+ color?: string;
170
+ stack?: string;
171
+ variant?: 'primary' | 'comparison';
172
+ dashArray?: string;
173
+ opacity?: number;
174
+ }
175
+ /** A derived series binding with the author's presentation merged onto it. */
176
+ export type MergedChartSeries = ChartSeriesBinding & AuthoredSeriesPresentation;
177
+ /**
178
+ * Merge the authored `chartConfig`'s PRESENTATION onto the series and axes the
179
+ * dataset selection derived — the one place that happens (#4229).
180
+ *
181
+ * The match rule is **by name/key**: an authored `series[].name` is paired with
182
+ * the derived binding whose `dataKey` it equals, and the pairing decides
183
+ * nothing but presentation:
184
+ *
185
+ * - an authored entry naming a measure that is NOT in the dataset selection is
186
+ * **ignored** — membership belongs to the dataset, so an author cannot add,
187
+ * remove or re-point a series from `chartConfig`;
188
+ * - a derived series with no authored entry keeps the family default, so every
189
+ * dashboard that never wrote `chartConfig.series` renders byte-for-byte as
190
+ * before;
191
+ * - where both exist the **explicit binding wins** (#2880 S2), which is the
192
+ * whole point: `type: 'line'` + `yAxis: 'right'` is how the spec says "this
193
+ * measure is a line on the secondary axis".
194
+ *
195
+ * Matching on `name` only is deliberate: `name` is the spec's authorable key
196
+ * for a series (`dataKey` is a declared ALIAS of it, resolved where the
197
+ * metadata is parsed), so reading a second spelling here would fossilize a
198
+ * dialect this renderer has no business accepting (AGENTS.md #0.1).
199
+ *
200
+ * @param derived the bindings `buildChartSeries` produced from the selection
201
+ * @param raw the widget's `chartConfig` as authored (anything, incl. absent)
202
+ * @returns the merged series, plus the presentation-only axes to spread onto
203
+ * the chart schema (absent when the author declared none)
204
+ */
205
+ export declare function mergeAuthoredPresentation(derived: ChartSeriesBinding[], raw: unknown): {
206
+ series: MergedChartSeries[];
207
+ axes: Record<string, unknown>;
208
+ };
29
209
  export declare function DatasetWidget({ widget, dataSource }: {
30
210
  widget: any;
31
211
  dataSource: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"DatasetWidget.d.ts","sourceRoot":"","sources":["../src/DatasetWidget.tsx"],"names":[],"mappings":"AA8BA,OAAO,EAUL,uBAAuB,EAGxB,MAAM,iBAAiB,CAAC;AAezB;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,gCAA0B,CAAC;AAExD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,OAAO,EAAE,MAAM,EAAE,EACjB,MAAM,EAAE,MAAM,GACb;IACD,UAAU,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACpD,UAAU,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CAcA;AASD,8DAA8D;AAC9D,wBAAgB,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,GAAG,MAAM,CAEpF;AAmDD,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,+BAgezF"}
1
+ {"version":3,"file":"DatasetWidget.d.ts","sourceRoot":"","sources":["../src/DatasetWidget.tsx"],"names":[],"mappings":"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"}
@@ -1,17 +1,36 @@
1
1
  import { default as React } from 'react';
2
- export interface MetricCardProps {
3
- title?: string | {
4
- key?: string;
5
- defaultValue?: string;
6
- };
2
+ import { I18nLabel } from '@object-ui/types';
3
+ import { SchemaHostProps } from './schemaHostProps';
4
+ /**
5
+ * DOM PASS-THROUGH (objectui#4426) — see `MetricWidget.tsx`'s interface header
6
+ * for the full argument; this is the same widening on the same spread, onto the
7
+ * same Shadcn `Card` (`div`).
8
+ *
9
+ * `title` is the one key `Omit`-ed, and the omission is the accurate contract
10
+ * rather than a workaround. HTML's `title` is a tooltip string; this card's
11
+ * `title` is its HEADING, in the `I18nLabel` vocabulary — an incompatible type,
12
+ * and one the component destructures out and renders into `CardTitle`, so no
13
+ * `title` attribute has ever reached this element. Declaring the inherited DOM
14
+ * `title` here would be the "declared but not delivered" failure this repo
15
+ * treats as first-class (objectui#3290, objectui#3222): it would type-check,
16
+ * read as a supported tooltip, and silently do nothing. `MetricWidget` has no
17
+ * such collision — its heading is `label` — so it extends the DOM attributes
18
+ * whole. The repo's spelling for this carve-out is `ComboboxProps`
19
+ * (`extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "value" | "onChange">`),
20
+ * omitted there for the same reason: the component's own contract owns the name.
21
+ */
22
+ export interface MetricCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
23
+ /**
24
+ * Card heading, in @objectstack/spec's `I18nLabel` vocabulary — a plain
25
+ * string or an inline per-locale map. See `MetricWidget.label` for why the
26
+ * retired `{ key, defaultValue }` form is no longer accepted (objectui#4032).
27
+ */
28
+ title?: string | I18nLabel;
7
29
  value: string | number;
8
30
  icon?: string;
9
31
  trend?: 'up' | 'down' | 'neutral';
10
32
  trendValue?: string;
11
- description?: string | {
12
- key?: string;
13
- defaultValue?: string;
14
- };
33
+ description?: string | I18nLabel;
15
34
  className?: string;
16
35
  /** When true, the card is in a loading state (fetching data from server). */
17
36
  loading?: boolean;
@@ -22,5 +41,5 @@ export interface MetricCardProps {
22
41
  * MetricCard - Standalone metric card component for dashboard KPIs
23
42
  * Displays a metric value with optional icon, trend indicator, and description
24
43
  */
25
- export declare const MetricCard: React.FC<MetricCardProps>;
44
+ export declare const MetricCard: React.FC<MetricCardProps & SchemaHostProps>;
26
45
  //# sourceMappingURL=MetricCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MetricCard.d.ts","sourceRoot":"","sources":["../src/MetricCard.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA+DhD,CAAC"}
1
+ {"version":3,"file":"MetricCard.d.ts","sourceRoot":"","sources":["../src/MetricCard.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAC1F;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,GAAG,eAAe,CA6ElE,CAAC"}
@@ -1,25 +1,74 @@
1
1
  import { default as React } from 'react';
2
- export type MetricColorVariant = 'default' | 'blue' | 'teal' | 'orange' | 'purple' | 'success' | 'warning' | 'danger';
3
- export interface MetricWidgetProps {
4
- label: string | {
5
- key?: string;
6
- defaultValue?: string;
7
- };
2
+ import { I18nLabel } from '@object-ui/types';
3
+ import { MetricColorVariant } from './colorVariants';
4
+ import { SchemaHostProps } from './schemaHostProps';
5
+ /**
6
+ * The variant vocabulary and its two class tables now live in
7
+ * `./colorVariants` — the dataset-bound KPI (`DatasetWidget`, objectui#3359)
8
+ * paints the SAME accents, and two copies of a palette is how a
9
+ * declared-but-unenforced key becomes two disagreeing declarations. Re-exported
10
+ * here because this module was the type's original home.
11
+ */
12
+ export type { MetricColorVariant };
13
+ /**
14
+ * DOM PASS-THROUGH (objectui#4426). `MetricWidget` ends its prop list with a
15
+ * `...domProps` spread onto the Shadcn `Card` — a `div` — so `id`, `role`,
16
+ * `aria-*`, `data-*`, `tabIndex`, `title` and the DOM event handlers reach the
17
+ * element. objectui#4357 (PR #4428) deliberately KEPT that spread: it is the
18
+ * component's only accessibility passthrough, and removing it would delete the
19
+ * only way a host can put an `id` or an `aria-label` on a KPI card.
20
+ *
21
+ * Until now the type refused what the runtime accepted. A TypeScript consumer
22
+ * importing the component directly could not write `<MetricWidget id="revenue"
23
+ * role="region" aria-label="Revenue KPI" … />` without a cast, while a JS
24
+ * consumer and every SDUI author going through `SchemaRenderer` (untyped at
25
+ * that boundary) got the passthrough for free. This `extends` is that
26
+ * declaration — the mirror image of #4357, closing the same question from the
27
+ * other side: renderer metadata was reaching the DOM because the spread is
28
+ * open; DOM attributes were unreachable because the type was closed.
29
+ *
30
+ * Measured convention, not an invented spelling: an exported `*Props` interface
31
+ * that spreads onto a host element extends `React.HTMLAttributes<HTMLDivElement>`
32
+ * here — `PageHeaderComponentProps` (whose own doc says "it extends
33
+ * `HTMLAttributes` so every DOM prop rides along"), `ChatbotProps`,
34
+ * `ChatbotEnhancedProps`, `TypingIndicatorProps`, `RefreshIndicatorProps`,
35
+ * `FieldProps`, and shadcn's own `BadgeProps`.
36
+ *
37
+ * What this does NOT declare, deliberately: the schema-shaped keys
38
+ * `SchemaRenderer` injects (`schema` / `bind` / `events` / `props` /
39
+ * `ariaLabel` / `ariaDescribedBy` / `dataSource`). None of them is an HTML
40
+ * attribute name, all seven are destructured out and never reach the DOM, and
41
+ * declaring them here would re-assert as a public contract exactly what #4357
42
+ * stripped. They stay in `SchemaHostProps`, intersected in at the component's
43
+ * own signature — the renderer's private door, not the consumer's front door.
44
+ * The narrower `FieldWidgetDomProps` shape (objectui#3221) is the other spelling
45
+ * in this repo, but it exists to be bound key-by-key to a runtime whitelist
46
+ * (`toDomProps`) in both directions; this component has no such whitelist, and
47
+ * inventing a half of one here would declare a set the spread does not enforce.
48
+ * Whether plugin widgets should get that whitelist is objectui#4425.
49
+ */
50
+ export interface MetricWidgetProps extends React.HTMLAttributes<HTMLDivElement> {
51
+ /**
52
+ * The KPI's heading, in @objectstack/spec's `I18nLabel` vocabulary — a plain
53
+ * string or an inline per-locale map (`{ en: 'Revenue', 'zh-CN': '收入' }`).
54
+ *
55
+ * Was `string | { key?, defaultValue? }` — the key-reference form
56
+ * objectstack#5055 RETIRED. It is not accepted here any more because the spec
57
+ * rejects it at authoring time, and because reading it was never the point:
58
+ * the private resolver behind it ended `defaultValue || key` and never
59
+ * consulted a bundle, so the escape hatch was declared and inert
60
+ * (objectui#4032).
61
+ */
62
+ label: string | I18nLabel;
8
63
  value: string | number;
9
64
  trend?: {
10
65
  value: number;
11
- label?: string | {
12
- key?: string;
13
- defaultValue?: string;
14
- };
66
+ label?: string | I18nLabel;
15
67
  direction?: 'up' | 'down' | 'neutral';
16
68
  };
17
69
  icon?: React.ReactNode | string;
18
70
  className?: string;
19
- description?: string | {
20
- key?: string;
21
- defaultValue?: string;
22
- };
71
+ description?: string | I18nLabel;
23
72
  /** When true, the widget is in a loading state (fetching data from server). */
24
73
  loading?: boolean;
25
74
  /** Error message from a failed data fetch. When set, the widget shows an error state. */
@@ -30,11 +79,27 @@ export interface MetricWidgetProps {
30
79
  format?: string;
31
80
  /** ISO currency code (e.g. `'USD'`); enables currency formatting on numeric values. */
32
81
  currency?: string;
33
- /** Static prefix appended in front of the formatted value (e.g. `'$'`, `'¥'`). */
82
+ /**
83
+ * Static prefix appended in front of the formatted value (e.g. `'$'`, `'¥'`).
84
+ *
85
+ * Same name, same `string` type as the inherited RDFa `prefix` attribute, and
86
+ * this declaration wins: the component reads it and destructures it out, so
87
+ * it never reaches the DOM. That is the accurate contract — it was already
88
+ * true before this interface declared its passthrough.
89
+ */
34
90
  prefix?: string;
35
91
  /** Static suffix appended after the formatted value (e.g. `' /mo'`). */
36
92
  suffix?: string;
37
- /** When set, the entire card becomes clickable and emits this handler. */
93
+ /**
94
+ * When set, the entire card becomes clickable and emits this handler.
95
+ *
96
+ * Deliberately NARROWER than the inherited `MouseEventHandler<HTMLDivElement>`:
97
+ * the KPI card treats a click as "the tile was activated" and wires the same
98
+ * handler to Enter/Space, where there is no mouse event to hand over. A
99
+ * zero-arg function is assignable to the inherited signature, so consumers
100
+ * already passing `(e) => …` keep compiling; this only stops the component
101
+ * from promising an event object its keyboard path cannot produce.
102
+ */
38
103
  onClick?: () => void;
39
104
  /**
40
105
  * Layout variant. `'card'` (default) is the bordered KPI card; `'bare'` drops
@@ -43,5 +108,5 @@ export interface MetricWidgetProps {
43
108
  */
44
109
  variant?: 'card' | 'bare';
45
110
  }
46
- export declare const MetricWidget: ({ label, value, trend, icon, className, description, loading, error, colorVariant, format, currency, prefix, suffix, onClick, variant, ...props }: MetricWidgetProps) => React.JSX.Element;
111
+ export declare const MetricWidget: ({ label, value, trend, icon, className, description, loading, error, colorVariant, format, currency, prefix, suffix, onClick, variant, schema: _schema, bind: _bind, events: _events, props: _propsBag, ariaLabel: _ariaLabel, ariaDescribedBy: _ariaDescribedBy, dataSource: _dataSource, ...domProps }: MetricWidgetProps & SchemaHostProps) => React.JSX.Element;
47
112
  //# sourceMappingURL=MetricWidget.d.ts.map