@happyvertical/smrt-svelte 0.55.24 → 0.56.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 (32) hide show
  1. package/agents/overview-surfaces.md +9 -2
  2. package/dist/components/command-palette/CommandPaletteDialog.svelte +1 -1
  3. package/dist/components/overview/OverviewGrid.svelte +8 -4
  4. package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -1
  5. package/dist/components/overview/WidgetOptionsForm.svelte +13 -2
  6. package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -1
  7. package/dist/components/overview/format.d.ts +3 -12
  8. package/dist/components/overview/format.d.ts.map +1 -1
  9. package/dist/components/overview/format.js +2 -45
  10. package/dist/components/overview/grid-types.d.ts +6 -11
  11. package/dist/components/overview/grid-types.d.ts.map +1 -1
  12. package/dist/components/overview/index.d.ts +1 -0
  13. package/dist/components/overview/index.d.ts.map +1 -1
  14. package/dist/components/overview/recipe-widgets.d.ts +6 -3
  15. package/dist/components/overview/recipe-widgets.d.ts.map +1 -1
  16. package/dist/components/overview/recipe-widgets.js +9 -0
  17. package/dist/components/overview/registry.d.ts +3 -0
  18. package/dist/components/overview/registry.d.ts.map +1 -1
  19. package/dist/components/overview/registry.js +25 -0
  20. package/dist/components/overview/server.d.ts +1 -1
  21. package/dist/components/overview/server.d.ts.map +1 -1
  22. package/dist/components/overview/server.js +1 -1
  23. package/dist/components/overview/types.d.ts +17 -0
  24. package/dist/components/overview/types.d.ts.map +1 -1
  25. package/dist/components/overview/widgets/ChartWidget.svelte +5 -265
  26. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +1 -1
  27. package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -1
  28. package/dist/components/workspace/admin-shell/AdminShell.svelte +4 -4
  29. package/dist/components/workspace/admin-shell/ShellIconButton.svelte +2 -2
  30. package/dist/components/workspace/admin-shell/TenantNav.svelte +8 -8
  31. package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte +3 -3
  32. package/package.json +14 -14
@@ -22,6 +22,11 @@ assistant operations with Undo ("Assistant operations").
22
22
  | `./overview/server` (`server.ts`) | Svelte-free: types, `validateWidgetOptions`, the model (`resolveOverview`, `checkOverviewOverride`, `applyOverviewOverride`, `diffOverview`, `sanitizeOverview`, ...), `WidgetRegistry` / `registerWidget`, `loadOverview`, the operations (`planOverviewOperations`, `describeOverview`) and `createOverviewAssistantSurface`. Safe in a `+page.server.ts` or a save endpoint. |
23
23
  | `./overview` (`index.ts`) | Everything above plus `OverviewGrid`, `createOverview` (controller), `WidgetOptionsForm`, the core widgets and `registerCoreWidgets`, `shortcutsFromNav`, `formatWidgetValue`, `parseMarkdown` / `safeHref`, `createOverviewAssistant` / `useOverviewAssistantTools` / `OverviewAssistantUndo`. |
24
24
 
25
+ `ChartWidget` delegates to `@happyvertical/smrt-ui/charts` so domain packages
26
+ can reuse the same renderer without depending on this integration package.
27
+ `formatWidgetValue` remains a compatibility re-export of the Svelte-free
28
+ `@happyvertical/smrt-ui/charts/format` entry. Existing translation keys stay stable.
29
+
25
30
  ## Data model (`types.ts`, `model.ts`)
26
31
 
27
32
  A saved overview is data, never code:
@@ -306,6 +311,7 @@ turns the manifest's widget surfaces into `registry.register(...)` calls:
306
311
  | `type`, `label`, `description`, `icon`, `version` | `type`, `title`, `description`, `icon`, `version` |
307
312
  | `options` | `options` (plain JSON; `registry.register` re-validates the schema) |
308
313
  | `export` | `loadComponent` (lazy; the export may be a component or a `{ default }` module) |
314
+ | `optionsEditor` | `loadOptionsEditor` (lazy; lets dependent choices use a package-owned editor without importing UI on the server) |
309
315
  | `data.load` | `load` (resolved on first use; a missing or non-function loader is that widget's error tile) |
310
316
  | `migrate` | `migrate`, **resolved eagerly** because the registry's `migrate` is synchronous |
311
317
  | `allowedIn`, `defaultSpan`, `minSpan`, `maxSpan` | same names |
@@ -314,8 +320,9 @@ turns the manifest's widget surfaces into `registry.register(...)` calls:
314
320
  - **The module resolver is injected.** `resolveExport(specifier, exportName)` is
315
321
  the host's: a static map of dynamic imports in a bundled app, a stub in tests.
316
322
  Nothing is imported when the manifest is read, and the registration itself
317
- imports nothing except `migrate` exports. Relative or absolute specifiers
318
- are refused.
323
+ imports nothing except `migrate` exports. UI hosts resolve lazy components
324
+ with `resolveWidgetComponents(...)` and custom editors with
325
+ `resolveWidgetOptionsEditors(...)`. Relative or absolute specifiers are refused.
319
326
  - **Never throws for a bad surface.** The result is `{ registered, skipped,
320
327
  dispose }`; a skip carries `reason` `duplicate_type` (a core widget or another
321
328
  recipe owns the type; `replace` overrides), `invalid` (the registry refused the
@@ -306,7 +306,7 @@ const inputLabel = $derived(label ?? t(M['ui.command_palette.input_label']));
306
306
  display: flex;
307
307
  align-items: center;
308
308
  gap: 0.75rem;
309
- min-block-size: max(2.5rem, var(--smrt-control-target-min, 0px));
309
+ min-block-size: max(2.5rem, var(--smrt-control-target-min));
310
310
  padding: 0.375rem 0.75rem;
311
311
  border-radius: var(--smrt-radius-medium, 0.5rem);
312
312
  color: var(--smrt-color-on-surface);
@@ -33,12 +33,17 @@ import type { OverviewOpResult } from './controller.svelte.js';
33
33
  import type { OverviewGridProps } from './grid-types.js';
34
34
  import { spanFromKey, spanFromPointer } from './resize.js';
35
35
  import { defaultWidgetOptions } from './schema.js';
36
- import type { OverviewOptions, OverviewWidget } from './types.js';
36
+ import type {
37
+ OverviewOptions,
38
+ OverviewWidget,
39
+ WidgetOptionIssue,
40
+ } from './types.js';
37
41
  import WidgetOptionsForm from './WidgetOptionsForm.svelte';
38
42
 
39
43
  let {
40
44
  controller,
41
45
  components,
46
+ optionEditors,
42
47
  editing: editingProp,
43
48
  label,
44
49
  headingLevel = 2,
@@ -299,9 +304,7 @@ function chooseType(type: string): void {
299
304
  }
300
305
  }
301
306
 
302
- function saveOptions(
303
- options: OverviewOptions,
304
- ): { key: string; code: string }[] | null {
307
+ function saveOptions(options: OverviewOptions): WidgetOptionIssue[] | null {
305
308
  const current = configure;
306
309
  if (!current) return null;
307
310
  const result: OverviewOpResult =
@@ -531,6 +534,7 @@ const headingTag = $derived(`h${headingLevel}`);
531
534
  definition={configureDef}
532
535
  initial={configure.initial}
533
536
  {models}
537
+ optionsEditor={optionEditors?.get(configure.type) ?? configureDef.optionsEditor}
534
538
  onsave={saveOptions}
535
539
  oncancel={() => (configure = null)}
536
540
  />
@@ -1 +1 @@
1
- {"version":3,"file":"OverviewGrid.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/overview/OverviewGrid.svelte.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AA6bzD,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"OverviewGrid.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/overview/OverviewGrid.svelte.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAgczD,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -23,8 +23,14 @@ import { M } from '../../i18n/strings.overview.js';
23
23
  import type { WidgetOptionsFormProps } from './grid-types.js';
24
24
  import type { OverviewOptions, WidgetOptionField } from './types.js';
25
25
 
26
- let { definition, initial, models, onsave, oncancel }: WidgetOptionsFormProps =
27
- $props();
26
+ let {
27
+ definition,
28
+ initial,
29
+ models,
30
+ onsave,
31
+ oncancel,
32
+ optionsEditor,
33
+ }: WidgetOptionsFormProps = $props();
28
34
 
29
35
  const { t } = useI18n();
30
36
 
@@ -108,8 +114,12 @@ const optionalChoice = (field: WidgetOptionField): boolean =>
108
114
  const modelValues = $derived(
109
115
  new Set((models ?? []).map((model) => model.value)),
110
116
  );
117
+ const CustomEditor = $derived(optionsEditor ?? definition.optionsEditor);
111
118
  </script>
112
119
 
120
+ {#if CustomEditor}
121
+ <CustomEditor {definition} {initial} {models} {onsave} {oncancel} />
122
+ {:else}
113
123
  <Form onsubmit={submit} novalidate>
114
124
  {#if failed}
115
125
  <Alert variant="error">{t(M['ui.overview.options_failed'])}</Alert>
@@ -184,6 +194,7 @@ const modelValues = $derived(
184
194
  </Button>
185
195
  </FormActionBar>
186
196
  </Form>
197
+ {/if}
187
198
 
188
199
  <style>
189
200
  @layer smrt.reset, smrt.structure, smrt.theme;
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetOptionsForm.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/overview/WidgetOptionsForm.svelte.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AA8J9D,QAAA,MAAM,iBAAiB,4DAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"WidgetOptionsForm.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/overview/WidgetOptionsForm.svelte.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAyK9D,QAAA,MAAM,iBAAiB,4DAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -1,13 +1,4 @@
1
- export type WidgetValueFormat = 'integer' | 'decimal' | 'percent' | 'money';
2
- export interface FormatWidgetValueOptions {
3
- format?: WidgetValueFormat;
4
- /** ISO 4217 code for `money` (default USD). */
5
- currency?: string;
6
- locale: string;
7
- }
8
- /**
9
- * Format a metric value. `money` takes integer minor units, `percent` takes a
10
- * fraction (0.25 is 25%). Non-finite input renders as an en dash.
11
- */
12
- export declare function formatWidgetValue(value: unknown, { format, currency, locale }: FormatWidgetValueOptions): string;
1
+ /** Shared number formatting; money values are integer minor units. */
2
+ export type { FormatWidgetValueOptions, WidgetValueFormat, } from '@happyvertical/smrt-ui/charts/format';
3
+ export { formatWidgetValue } from '@happyvertical/smrt-ui/charts/format';
13
4
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/components/overview/format.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE5E,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAYD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,EAAE,MAAkB,EAAE,QAAgB,EAAE,MAAM,EAAE,EAAE,wBAAwB,GACzE,MAAM,CA4BR"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/components/overview/format.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,YAAY,EACV,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC"}
@@ -1,45 +1,2 @@
1
- /**
2
- * Number formatting for overview widgets (#3727). Deterministic for a given
3
- * locale so a server render and the client hydrate to the same text. Money is
4
- * integer minor units end to end (never a decimal in data).
5
- */
6
- import { currencyMinorDigits } from '../screens/values.js';
7
- const EN_DASH = '–';
8
- function safeLocale(locale) {
9
- try {
10
- return Intl.getCanonicalLocales(locale)[0] ?? 'en';
11
- }
12
- catch {
13
- return 'en';
14
- }
15
- }
16
- /**
17
- * Format a metric value. `money` takes integer minor units, `percent` takes a
18
- * fraction (0.25 is 25%). Non-finite input renders as an en dash.
19
- */
20
- export function formatWidgetValue(value, { format = 'integer', currency = 'USD', locale }) {
21
- if (typeof value !== 'number' || !Number.isFinite(value))
22
- return EN_DASH;
23
- const tag = safeLocale(locale);
24
- switch (format) {
25
- case 'money': {
26
- const code = /^[A-Za-z]{3}$/.test(currency)
27
- ? currency.toUpperCase()
28
- : 'USD';
29
- const digits = currencyMinorDigits(code);
30
- return new Intl.NumberFormat(tag, {
31
- style: 'currency',
32
- currency: code,
33
- }).format(value / 10 ** digits);
34
- }
35
- case 'percent':
36
- return new Intl.NumberFormat(tag, {
37
- style: 'percent',
38
- maximumFractionDigits: 1,
39
- }).format(value);
40
- case 'decimal':
41
- return new Intl.NumberFormat(tag, { maximumFractionDigits: 2 }).format(value);
42
- default:
43
- return new Intl.NumberFormat(tag, { maximumFractionDigits: 0 }).format(value);
44
- }
45
- }
1
+ /** Shared number formatting; money values are integer minor units. */
2
+ export { formatWidgetValue } from '@happyvertical/smrt-ui/charts/format';
@@ -1,6 +1,6 @@
1
1
  import type { Component, Snippet } from 'svelte';
2
2
  import type { OverviewController } from './controller.svelte.js';
3
- import type { OverviewOptions, OverviewWidget, RegisteredWidget, WidgetComponentProps } from './types.js';
3
+ import type { OverviewWidget, WidgetComponentProps, WidgetOptionsEditorProps } from './types.js';
4
4
  /** A model the option editor offers for `model` fields. */
5
5
  export interface OverviewModelChoice {
6
6
  value: string;
@@ -16,6 +16,8 @@ export interface OverviewGridProps {
16
16
  * unavailable.
17
17
  */
18
18
  components?: ReadonlyMap<string, Component<WidgetComponentProps>>;
19
+ /** Resolved custom option editors (see `resolveWidgetOptionsEditors`). */
20
+ optionEditors?: ReadonlyMap<string, Component<WidgetOptionsEditorProps>>;
19
21
  /**
20
22
  * Edit mode. Omit to follow the shell's layout editor (the pencil), so a
21
23
  * grid inside `AppShell` edits with the rest of the page.
@@ -43,14 +45,7 @@ export interface OverviewFormIssue {
43
45
  code: string;
44
46
  }
45
47
  /** Props of `WidgetOptionsForm`. */
46
- export interface WidgetOptionsFormProps {
47
- /** The widget type being configured. */
48
- definition: RegisteredWidget;
49
- /** Current options (an existing widget) or starting values. */
50
- initial: OverviewOptions;
51
- models?: readonly OverviewModelChoice[];
52
- /** Saves; returns issues to show, or `null` when it worked. */
53
- onsave: (options: OverviewOptions) => OverviewFormIssue[] | null;
54
- oncancel: () => void;
55
- }
48
+ export type WidgetOptionsFormProps = WidgetOptionsEditorProps & {
49
+ optionsEditor?: Component<WidgetOptionsEditorProps>;
50
+ };
56
51
  //# sourceMappingURL=grid-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"grid-types.d.ts","sourceRoot":"","sources":["../../../src/components/overview/grid-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAEpB,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,UAAU,EAAE,kBAAkB,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAClE;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,iEAAiE;IACjE,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACxC,0DAA0D;IAC1D,aAAa,CAAC,EAAE,SAAS,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,uDAAuD;AACvD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oCAAoC;AACpC,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,+DAA+D;IAC/D,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACxC,+DAA+D;IAC/D,MAAM,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,iBAAiB,EAAE,GAAG,IAAI,CAAC;IACjE,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB"}
1
+ {"version":3,"file":"grid-types.d.ts","sourceRoot":"","sources":["../../../src/components/overview/grid-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAEpB,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,UAAU,EAAE,kBAAkB,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAClE,0EAA0E;IAC1E,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,wBAAwB,CAAC,CAAC,CAAC;IACzE;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,iEAAiE;IACjE,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACxC,0DAA0D;IAC1D,aAAa,CAAC,EAAE,SAAS,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,uDAAuD;AACvD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oCAAoC;AACpC,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,GAAG;IAC9D,aAAa,CAAC,EAAE,SAAS,CAAC,wBAAwB,CAAC,CAAC;CACrD,CAAC"}
@@ -15,6 +15,7 @@ export { default as OverviewAssistantUndo } from './OverviewAssistantUndo.svelte
15
15
  export { default as OverviewGrid } from './OverviewGrid.svelte';
16
16
  export { spanFromKey, spanFromPointer } from './resize.js';
17
17
  export * from './server.js';
18
+ export type { WidgetOptionsEditorProps } from './types.js';
18
19
  export { default as WidgetOptionsForm } from './WidgetOptionsForm.svelte';
19
20
  export { default as ChartWidget } from './widgets/ChartWidget.svelte';
20
21
  export { type CoreWidgetLoaders, createChartWidget, createMetricWidget, createNoteWidget, createRecordListWidget, createShortcutsWidget, registerCoreWidgets, } from './widgets/core.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/overview/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,wBAAwB,EAC7B,iBAAiB,EACjB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,aAAa,EACb,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EACL,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/overview/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,wBAAwB,EAC7B,iBAAiB,EACjB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,aAAa,EACb,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,cAAc,aAAa,CAAC;AAC5B,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EACL,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,kCAAkC,CAAC"}
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * Svelte-free apart from type imports, so a server load can call it.
12
12
  */
13
- import type { RecipeDefinition, RecipeExportRef } from '@happyvertical/smrt-types';
13
+ import type { RecipeExportRef, RecipeSurface } from '@happyvertical/smrt-types';
14
14
  import type { WidgetRegistry } from './registry.js';
15
15
  /**
16
16
  * Resolves one export of a module: `resolveExport('@acme/shop/svelte',
@@ -18,8 +18,11 @@ import type { WidgetRegistry } from './registry.js';
18
18
  * stub); it may reject or return `undefined` for something it does not know.
19
19
  */
20
20
  export type RecipeExportResolver = (specifier: string, exportName: string) => unknown | Promise<unknown>;
21
- /** The part of a recipe this helper reads; a manifest `RecipeDefinition` fits. */
22
- export type RecipeWidgetSource = Pick<RecipeDefinition, 'id'> & Partial<Pick<RecipeDefinition, 'surfaces'>>;
21
+ /** The part of a recipe this helper reads; manifests and readonly recipe statics fit. */
22
+ export interface RecipeWidgetSource {
23
+ id: string;
24
+ surfaces?: readonly RecipeSurface[];
25
+ }
23
26
  export interface RegisterRecipeWidgetsOptions {
24
27
  /** Replace a type that is already registered instead of skipping it. */
25
28
  replace?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"recipe-widgets.d.ts","sourceRoot":"","sources":["../../../src/components/overview/recipe-widgets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAEhB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAWpD;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,KACf,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,kFAAkF;AAClF,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAC3D,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC,CAAC;AAE9C,MAAM,WAAW,4BAA4B;IAC3C,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;CACzC;AAED,MAAM,MAAM,sBAAsB;AAChC,wEAAwE;AACtE,gBAAgB;AAClB,2DAA2D;GACzD,SAAS;AACX,4EAA4E;GAC1E,YAAY,CAAC;AAEjB,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,sBAAsB,CAAC;IAC/B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,sDAAsD;IACtD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,wDAAwD;IACxD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,eAAe,GAAG,MAAM,GAC5B;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUlD;AAqFD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EACrC,aAAa,EAAE,oBAAoB,EACnC,OAAO,GAAE,4BAAiC,GACzC,OAAO,CAAC,wBAAwB,CAAC,CAyDnC"}
1
+ {"version":3,"file":"recipe-widgets.d.ts","sourceRoot":"","sources":["../../../src/components/overview/recipe-widgets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EAEd,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAWpD;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,KACf,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,yFAAyF;AACzF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,4BAA4B;IAC3C,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;CACzC;AAED,MAAM,MAAM,sBAAsB;AAChC,wEAAwE;AACtE,gBAAgB;AAClB,2DAA2D;GACzD,SAAS;AACX,4EAA4E;GAC1E,YAAY,CAAC;AAEjB,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,sBAAsB,CAAC;IAC/B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,sDAAsD;IACtD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,wDAAwD;IACxD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,eAAe,GAAG,MAAM,GAC5B;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUlD;AAkGD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EACrC,aAAa,EAAE,oBAAoB,EACnC,OAAO,GAAE,4BAAiC,GACzC,OAAO,CAAC,wBAAwB,CAAC,CAyDnC"}
@@ -39,6 +39,9 @@ function isModuleWithDefault(value) {
39
39
  }
40
40
  function toDefinition(surface, resolveExport, migrate) {
41
41
  const component = once(() => resolveRef(surface.export, resolveExport));
42
+ const optionsEditor = surface.optionsEditor
43
+ ? once(() => resolveRef(surface.optionsEditor, resolveExport))
44
+ : undefined;
42
45
  const loadFn = surface.data?.load
43
46
  ? once(() => resolveRef(surface.data?.load, resolveExport))
44
47
  : undefined;
@@ -67,6 +70,12 @@ function toDefinition(surface, resolveExport, migrate) {
67
70
  def.maxSpan = surface.maxSpan;
68
71
  if (migrate)
69
72
  def.migrate = migrate;
73
+ if (optionsEditor) {
74
+ def.loadOptionsEditor = async () => {
75
+ const value = await optionsEditor();
76
+ return (isModuleWithDefault(value) ? value.default : value);
77
+ };
78
+ }
70
79
  if (loadFn) {
71
80
  const load = async (options, ctx) => {
72
81
  const fn = await loadFn();
@@ -34,6 +34,7 @@ export declare function registerWidget<Data>(def: WidgetDefinition<Data>, option
34
34
  }): () => void;
35
35
  /** A resolved component for each widget type that has one. */
36
36
  export type WidgetComponents = Map<string, Component<WidgetComponentProps>>;
37
+ export type WidgetOptionsEditors = Map<string, Component<import('./types.js').WidgetOptionsEditorProps>>;
37
38
  /**
38
39
  * Resolve the components for `types`: eager components as is, lazy ones by
39
40
  * awaiting `loadComponent`. Call it in a universal page load (or before
@@ -42,4 +43,6 @@ export type WidgetComponents = Map<string, Component<WidgetComponentProps>>;
42
43
  * renders as unavailable.
43
44
  */
44
45
  export declare function resolveWidgetComponents(types: Iterable<string>, registry?: WidgetRegistry): Promise<WidgetComponents>;
46
+ /** Resolve custom recipe option editors only in a browser or universal UI host. */
47
+ export declare function resolveWidgetOptionsEditors(types: Iterable<string>, registry?: WidgetRegistry): Promise<WidgetOptionsEditors>;
45
48
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/components/overview/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAIL,KAAK,gBAAgB,EAGrB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAyCpB,wCAAwC;AACxC,qBAAa,cAAc;;IAGzB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EACX,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAC3B,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAO,GAClC,MAAM,IAAI;IAab,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAI/C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,8CAA8C;IAC9C,KAAK,IAAI,MAAM,EAAE;IAIjB,IAAI,IAAI,gBAAgB,EAAE;CAG3B;AAED,4EAA4E;AAC5E,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AAED,6EAA6E;AAC7E,eAAO,MAAM,qBAAqB,EAAE,cAAuC,CAAC;AAE5E,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EACjC,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAC3B,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9B,MAAM,IAAI,CAEZ;AAED,8DAA8D;AAC9D,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAQ5E;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,QAAQ,GAAE,cAAsC,GAC/C,OAAO,CAAC,gBAAgB,CAAC,CAyB3B"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/components/overview/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAIL,KAAK,gBAAgB,EAGrB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAyCpB,wCAAwC;AACxC,qBAAa,cAAc;;IAGzB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EACX,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAC3B,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAO,GAClC,MAAM,IAAI;IAab,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAI/C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,8CAA8C;IAC9C,KAAK,IAAI,MAAM,EAAE;IAIjB,IAAI,IAAI,gBAAgB,EAAE;CAG3B;AAED,4EAA4E;AAC5E,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AAED,6EAA6E;AAC7E,eAAO,MAAM,qBAAqB,EAAE,cAAuC,CAAC;AAE5E,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EACjC,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAC3B,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9B,MAAM,IAAI,CAEZ;AAED,8DAA8D;AAC9D,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAC5E,MAAM,MAAM,oBAAoB,GAAG,GAAG,CACpC,MAAM,EACN,SAAS,CAAC,OAAO,YAAY,EAAE,wBAAwB,CAAC,CACzD,CAAC;AAQF;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,QAAQ,GAAE,cAAsC,GAC/C,OAAO,CAAC,gBAAgB,CAAC,CAyB3B;AAED,mFAAmF;AACnF,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,QAAQ,GAAE,cAAsC,GAC/C,OAAO,CAAC,oBAAoB,CAAC,CA2B/B"}
@@ -110,3 +110,28 @@ export async function resolveWidgetComponents(types, registry = defaultWidgetReg
110
110
  }));
111
111
  return out;
112
112
  }
113
+ /** Resolve custom recipe option editors only in a browser or universal UI host. */
114
+ export async function resolveWidgetOptionsEditors(types, registry = defaultWidgetRegistry) {
115
+ const out = new Map();
116
+ await Promise.all([...new Set(types)].map(async (type) => {
117
+ const def = registry.get(type);
118
+ if (!def)
119
+ return;
120
+ if (def.optionsEditor) {
121
+ out.set(type, def.optionsEditor);
122
+ return;
123
+ }
124
+ if (!def.loadOptionsEditor)
125
+ return;
126
+ try {
127
+ const loaded = await def.loadOptionsEditor();
128
+ out.set(type, (typeof loaded === 'object' && loaded !== null && 'default' in loaded
129
+ ? loaded.default
130
+ : loaded));
131
+ }
132
+ catch {
133
+ // The descriptor-driven editor remains available as a safe fallback.
134
+ }
135
+ }));
136
+ return out;
137
+ }
@@ -11,7 +11,7 @@ export { applyOverviewOverride, checkOverviewOverride, defineOverview, diffOverv
11
11
  export { allowedWidgetTypes, type DescribeOverviewInput, describeOverview, OVERVIEW_MAX_OPERATIONS, OVERVIEW_OPERATION_KINDS, OVERVIEW_OPERATION_SCHEMA, type OverviewAddOperation, type OverviewConfigureOperation, type OverviewDescription, type OverviewMoveOperation, type OverviewOperation, type OverviewOperationIssue, type OverviewOperationIssueCode, type OverviewOperationKind, type OverviewOperationResult, type OverviewOptionDescription, type OverviewPlan, type OverviewRemoveOperation, type OverviewResizeOperation, type OverviewWidgetTypeDescription, type PlanOverviewOperationsInput, planOverviewOperations, } from './operations.js';
12
12
  export { parseRecipeExportRef, type RecipeExportResolver, type RecipeWidgetRegistration, type RecipeWidgetSkip, type RecipeWidgetSkipReason, type RecipeWidgetSource, type RegisterRecipeWidgetsOptions, registerRecipeWidgets, } from './recipe-widgets.js';
13
13
  export { RECORD_OVERVIEW_ALLOWED, RECORD_OVERVIEW_LIMIT, RECORD_OVERVIEW_MAX_METRICS, RECORD_OVERVIEW_PANEL_SPAN, type RecordOverviewOptions, recordOverview, recordOverviewId, } from './record.js';
14
- export { createWidgetRegistry, defaultWidgetRegistry, registerWidget, resolveWidgetComponents, type WidgetComponents, WidgetRegistry, } from './registry.js';
14
+ export { createWidgetRegistry, defaultWidgetRegistry, registerWidget, resolveWidgetComponents, resolveWidgetOptionsEditors, type WidgetComponents, type WidgetOptionsEditors, WidgetRegistry, } from './registry.js';
15
15
  export { assertWidgetOptionFields, defaultWidgetOptions, IDENTIFIER_PATTERN, MODEL_PATTERN, optionsEqual, validateWidgetOptions, } from './schema.js';
16
16
  export * from './types.js';
17
17
  export { type LineItemsTotals, type LineTotalKey, type LineTotalLine, type LineTotalsMismatch, type LineTotalsResult, lineItemTotals, sumLineAmounts, } from './widgets/line-totals.js';
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/components/overview/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,8BAA8B,EAC9B,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,EAC7B,KAAK,+BAA+B,GACrC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,mBAAmB,EACxB,YAAY,EACZ,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,KAAK,qBAAqB,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,eAAe,EACf,KAAK,eAAe,EACpB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,KAAK,qBAAqB,EAC1B,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,4BAA4B,EACjC,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,EAC1B,KAAK,qBAAqB,EAC1B,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,cAAc,EACd,cAAc,GACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,cAAc,EACd,WAAW,EACX,UAAU,GACX,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/components/overview/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,8BAA8B,EAC9B,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,EAC7B,KAAK,+BAA+B,GACrC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,mBAAmB,EACxB,YAAY,EACZ,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,KAAK,qBAAqB,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,eAAe,EACf,KAAK,eAAe,EACpB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,KAAK,qBAAqB,EAC1B,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,4BAA4B,EACjC,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,EAC1B,KAAK,qBAAqB,EAC1B,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,uBAAuB,EACvB,2BAA2B,EAC3B,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,cAAc,EACd,cAAc,GACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,cAAc,EACd,WAAW,EACX,UAAU,GACX,MAAM,2BAA2B,CAAC"}
@@ -11,7 +11,7 @@ export { applyOverviewOverride, checkOverviewOverride, defineOverview, diffOverv
11
11
  export { allowedWidgetTypes, describeOverview, OVERVIEW_MAX_OPERATIONS, OVERVIEW_OPERATION_KINDS, OVERVIEW_OPERATION_SCHEMA, planOverviewOperations, } from './operations.js';
12
12
  export { parseRecipeExportRef, registerRecipeWidgets, } from './recipe-widgets.js';
13
13
  export { RECORD_OVERVIEW_ALLOWED, RECORD_OVERVIEW_LIMIT, RECORD_OVERVIEW_MAX_METRICS, RECORD_OVERVIEW_PANEL_SPAN, recordOverview, recordOverviewId, } from './record.js';
14
- export { createWidgetRegistry, defaultWidgetRegistry, registerWidget, resolveWidgetComponents, WidgetRegistry, } from './registry.js';
14
+ export { createWidgetRegistry, defaultWidgetRegistry, registerWidget, resolveWidgetComponents, resolveWidgetOptionsEditors, WidgetRegistry, } from './registry.js';
15
15
  export { assertWidgetOptionFields, defaultWidgetOptions, IDENTIFIER_PATTERN, MODEL_PATTERN, optionsEqual, validateWidgetOptions, } from './schema.js';
16
16
  export * from './types.js';
17
17
  export { lineItemTotals, sumLineAmounts, } from './widgets/line-totals.js';
@@ -196,6 +196,17 @@ export type WidgetMigrate = (options: Record<string, unknown>, fromVersion: numb
196
196
  export type WidgetComponentModule<Data> = Component<WidgetComponentProps<Data>> | {
197
197
  default: Component<WidgetComponentProps<Data>>;
198
198
  };
199
+ /** Props for a custom widget option editor. Saving still passes through the registry schema. */
200
+ export interface WidgetOptionsEditorProps {
201
+ definition: RegisteredWidget;
202
+ initial: OverviewOptions;
203
+ models?: readonly {
204
+ value: string;
205
+ label: string;
206
+ }[];
207
+ onsave: (options: OverviewOptions) => WidgetOptionIssue[] | null;
208
+ oncancel: () => void;
209
+ }
199
210
  /** What `registerWidget` takes. */
200
211
  export interface WidgetDefinition<Data = unknown> {
201
212
  /** Lowercase kebab id, e.g. `metric`. */
@@ -217,6 +228,12 @@ export interface WidgetDefinition<Data = unknown> {
217
228
  * resolves these before rendering with `resolveWidgetComponents`.
218
229
  */
219
230
  loadComponent?: () => Promise<WidgetComponentModule<Data>>;
231
+ /** Custom editor for dependent or remotely loaded option choices. */
232
+ optionsEditor?: Component<WidgetOptionsEditorProps>;
233
+ /** Resolves a custom editor lazily from a recipe export. */
234
+ loadOptionsEditor?: () => Promise<Component<WidgetOptionsEditorProps> | {
235
+ default: Component<WidgetOptionsEditorProps>;
236
+ }>;
220
237
  /** Server loader; absent for widgets that render from options alone. */
221
238
  load?: WidgetLoad<Data>;
222
239
  /** Overview ids this widget may appear in; omit for any. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/overview/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/overview/types.ts"],"names":[],"mappings":"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"}
@@ -1,272 +1,12 @@
1
1
  <script lang="ts">
2
- /**
3
- * Chart widget (#3727, #3888): bars, a line, a plain table, a donut or a single
4
- * headline value over labelled values, drawn from the loaded data. Every chart
5
- * carries its numbers as text (bar values inline, a visible table for `table`,
6
- * a visually hidden table for the line and the donut, the value itself for
7
- * `stat`) so it is readable without sight.
8
- */
9
- import { useI18n } from '@happyvertical/smrt-ui/i18n';
10
- import { M } from '../../../i18n/strings.overview.js';
11
- import { formatWidgetValue } from '../format.js';
2
+ import { Chart } from '@happyvertical/smrt-ui/charts';
12
3
  import type { WidgetComponentProps } from '../types.js';
13
- import { type ChartWidgetData, isRecord } from './data.js';
4
+ import type { ChartWidgetData } from './data.js';
14
5
 
15
6
  let { options, data, title, locale }: WidgetComponentProps<ChartWidgetData> =
16
7
  $props();
17
-
18
- const { t } = useI18n();
19
- const MAX_POINTS = 60;
20
-
21
- const chart = $derived(isRecord(data) ? data : null);
22
- const points = $derived.by(() => {
23
- if (!chart || !Array.isArray(chart.points)) return [];
24
- const out: { label: string; value: number }[] = [];
25
- for (const point of chart.points.slice(0, MAX_POINTS)) {
26
- if (
27
- isRecord(point) &&
28
- typeof point.label === 'string' &&
29
- typeof point.value === 'number' &&
30
- Number.isFinite(point.value)
31
- ) {
32
- out.push({ label: point.label, value: point.value });
33
- }
34
- }
35
- return out;
36
- });
37
- const STYLES = ['bar', 'line', 'table', 'pie', 'stat'] as const;
38
- const style = $derived(
39
- STYLES.find((candidate) => candidate === options.style) ?? 'bar',
40
- );
41
- const fmt = (value: number): string =>
42
- formatWidgetValue(value, {
43
- format: chart?.format ?? 'integer',
44
- currency: chart?.currency,
45
- locale,
46
- });
47
- const max = $derived(Math.max(0, ...points.map((point) => point.value)));
48
- const min = $derived(Math.min(0, ...points.map((point) => point.value)));
49
- const span = $derived(max - min || 1);
50
- const polyline = $derived(
51
- points
52
- .map((point, index) => {
53
- const x = points.length === 1 ? 50 : (index / (points.length - 1)) * 100;
54
- const y = 36 - ((point.value - min) / span) * 32;
55
- return `${x.toFixed(2)},${y.toFixed(2)}`;
56
- })
57
- .join(' '),
58
- );
59
-
60
- // Donut: slices are percentages of the positive total on a circle whose
61
- // path length is 100, so a segment's dash length is its share.
62
- const total = $derived(
63
- points.reduce((sum, point) => sum + Math.max(0, point.value), 0),
64
- );
65
- const slices = $derived.by(() => {
66
- let offset = 0;
67
- return points.map((point, index) => {
68
- const share = total > 0 ? (Math.max(0, point.value) / total) * 100 : 0;
69
- const slice = { ...point, index, share, offset };
70
- offset += share;
71
- return slice;
72
- });
73
- });
74
- const percent = (share: number): string =>
75
- formatWidgetValue(share / 100, { format: 'percent', locale });
76
-
77
- // Stat: the latest value, and its change against the one before.
78
- const latest = $derived(points.at(-1));
79
- const delta = $derived.by((): number | null => {
80
- if (
81
- chart &&
82
- typeof chart.delta === 'number' &&
83
- Number.isFinite(chart.delta)
84
- ) {
85
- return chart.delta;
86
- }
87
- const previous = points.at(-2);
88
- if (!latest || !previous || previous.value === 0) return null;
89
- return ((latest.value - previous.value) / Math.abs(previous.value)) * 100;
90
- });
91
- const deltaText = $derived(
92
- delta === null || delta === 0
93
- ? ''
94
- : t(
95
- M[
96
- delta > 0
97
- ? 'ui.overview.metric.change_up'
98
- : 'ui.overview.metric.change_down'
99
- ],
100
- {
101
- value: formatWidgetValue(Math.abs(delta) / 100, {
102
- format: 'percent',
103
- locale,
104
- }),
105
- },
106
- ),
107
- );
108
- const summary = $derived(
109
- `${title}. ${t(M['ui.overview.chart.summary'], { count: points.length })}`,
110
- );
111
8
  </script>
112
9
 
113
- {#snippet dataTable(hidden: boolean)}
114
- <table class={hidden ? 'smrt-chart__table' : 'smrt-chart__data'}>
115
- <caption>{t(M['ui.overview.chart.table'])}</caption>
116
- <thead>
117
- <tr>
118
- <th scope="col">{t(M['ui.overview.chart.label_column'])}</th>
119
- <th scope="col">{t(M['ui.overview.chart.value_column'])}</th>
120
- </tr>
121
- </thead>
122
- <tbody>
123
- {#each points as point, index (index)}
124
- <tr><th scope="row">{point.label}</th><td>{fmt(point.value)}</td></tr>
125
- {/each}
126
- </tbody>
127
- </table>
128
- {/snippet}
129
-
130
- {#if points.length === 0}
131
- <p class="smrt-chart__empty" data-smrt-component="ChartWidget">{t(M['ui.overview.no_data'])}</p>
132
- {:else if style === 'table'}
133
- <div class="smrt-chart smrt-chart--table" data-smrt-component="ChartWidget">
134
- {@render dataTable(false)}
135
- </div>
136
- {:else if style === 'stat'}
137
- {#if latest}
138
- <div class="smrt-chart smrt-chart--stat" data-smrt-component="ChartWidget">
139
- <p class="smrt-chart__headline">{fmt(latest.value)}</p>
140
- <p class="smrt-chart__caption">{latest.label}</p>
141
- {#if deltaText}
142
- <p class="smrt-chart__delta" data-direction={(delta ?? 0) > 0 ? 'up' : 'down'}>
143
- <span aria-hidden="true">{(delta ?? 0) > 0 ? '▲' : '▼'}</span>
144
- {deltaText}
145
- </p>
146
- {/if}
147
- </div>
148
- {/if}
149
- {:else if style === 'pie'}
150
- {#if total > 0}
151
- <div class="smrt-chart smrt-chart--pie" data-smrt-component="ChartWidget">
152
- <svg class="smrt-chart__donut" viewBox="0 0 42 42" role="img" aria-label={summary}>
153
- {#each slices as slice (slice.index)}
154
- {#if slice.share > 0}
155
- <circle
156
- class="smrt-chart__slice"
157
- data-slot={slice.index % 8}
158
- cx="21"
159
- cy="21"
160
- r="15.9155"
161
- fill="none"
162
- stroke-width="6"
163
- pathLength="100"
164
- stroke-dasharray="{slice.share} {100 - slice.share}"
165
- stroke-dashoffset={-slice.offset}
166
- transform="rotate(-90 21 21)"
167
- />
168
- {/if}
169
- {/each}
170
- </svg>
171
- <ul class="smrt-chart__legend" aria-hidden="true">
172
- {#each slices as slice (slice.index)}
173
- <li class="smrt-chart__legend-item">
174
- <span class="smrt-chart__swatch" data-slot={slice.index % 8}></span>
175
- <span class="smrt-chart__label">{slice.label}</span>
176
- <span class="smrt-chart__value">{fmt(slice.value)} · {percent(slice.share)}</span>
177
- </li>
178
- {/each}
179
- </ul>
180
- {@render dataTable(true)}
181
- </div>
182
- {:else}
183
- <p class="smrt-chart__empty" data-smrt-component="ChartWidget">{t(M['ui.overview.no_data'])}</p>
184
- {/if}
185
- {:else if style === 'line'}
186
- <div class="smrt-chart" data-smrt-component="ChartWidget">
187
- <svg class="smrt-chart__line" viewBox="0 0 100 40" preserveAspectRatio="none" role="img" aria-label={summary}>
188
- <polyline points={polyline} fill="none" stroke="currentColor" stroke-width="2" vector-effect="non-scaling-stroke" />
189
- </svg>
190
- <p class="smrt-chart__axis" aria-hidden="true">
191
- <span>{points[0].label}</span>
192
- <span>{points[points.length - 1].label}</span>
193
- </p>
194
- {@render dataTable(true)}
195
- </div>
196
- {:else}
197
- <ul class="smrt-chart__bars" aria-label={summary} data-smrt-component="ChartWidget">
198
- {#each points as point, index (index)}
199
- <li class="smrt-chart__row">
200
- <span class="smrt-chart__label">{point.label}</span>
201
- <span class="smrt-chart__track" aria-hidden="true">
202
- <span class="smrt-chart__bar" style:inline-size="{max > 0 ? (Math.max(0, point.value) / max) * 100 : 0}%"></span>
203
- </span>
204
- <span class="smrt-chart__value">{fmt(point.value)}</span>
205
- </li>
206
- {/each}
207
- </ul>
208
- {/if}
209
-
210
- <style>
211
- @layer smrt.reset, smrt.structure, smrt.theme;
212
- @layer smrt.theme {
213
- .smrt-chart { display: grid; gap: var(--smrt-spacing-1); color: var(--smrt-color-primary); }
214
- .smrt-chart__line { inline-size: 100%; block-size: 7rem; overflow: visible; }
215
- .smrt-chart__axis { display: flex; justify-content: space-between; margin: 0; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-label-large-size, 0.75rem); }
216
- .smrt-chart__bars { display: grid; gap: var(--smrt-spacing-2); margin: 0; padding: 0; list-style: none; }
217
- .smrt-chart__row { display: grid; grid-template-columns: minmax(4rem, 30%) minmax(0, 1fr) auto; align-items: center; gap: var(--smrt-spacing-2); font-size: var(--smrt-typography-body-medium-size, 0.875rem); color: var(--smrt-color-on-surface); }
218
- .smrt-chart__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
219
- .smrt-chart__track { display: block; block-size: 0.625rem; border-radius: var(--smrt-radius-full); background: var(--smrt-color-surface-container-high); overflow: hidden; }
220
- .smrt-chart__bar { display: block; block-size: 100%; border-radius: inherit; background: var(--smrt-color-primary); }
221
- .smrt-chart__value { font-variant-numeric: tabular-nums; color: var(--smrt-color-on-surface-variant); }
222
- .smrt-chart__empty { margin: 0; color: var(--smrt-color-on-surface-variant); }
223
- .smrt-chart--table { color: var(--smrt-color-on-surface); }
224
- .smrt-chart__data { inline-size: 100%; border-collapse: collapse; font-size: var(--smrt-typography-body-medium-size, 0.875rem); }
225
- .smrt-chart__data caption { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
226
- .smrt-chart__data th, .smrt-chart__data td { padding: var(--smrt-spacing-1) var(--smrt-spacing-2); border-block-end: var(--smrt-hairline); text-align: start; }
227
- .smrt-chart__data thead th { background: var(--smrt-surface-sunken); color: var(--smrt-color-on-surface-variant); font-weight: var(--smrt-typography-weight-medium, 500); }
228
- .smrt-chart__data tbody th { font-weight: inherit; overflow-wrap: anywhere; }
229
- .smrt-chart__data td, .smrt-chart__data thead th:last-child { text-align: end; font-variant-numeric: tabular-nums; }
230
- .smrt-chart--stat { gap: var(--smrt-spacing-1); color: var(--smrt-color-on-surface); }
231
- .smrt-chart__headline { margin: 0; font-size: var(--smrt-typography-display-small-size, 2rem); font-weight: var(--smrt-typography-weight-medium, 500); line-height: 1.1; font-variant-numeric: tabular-nums; }
232
- .smrt-chart__caption { margin: 0; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-body-medium-size, 0.875rem); }
233
- .smrt-chart__delta { margin: 0; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-label-large-size, 0.875rem); }
234
- .smrt-chart--pie { grid-template-columns: minmax(6rem, 10rem) minmax(0, 1fr); align-items: center; gap: var(--smrt-spacing-4); }
235
- .smrt-chart__donut { inline-size: 100%; block-size: auto; }
236
- .smrt-chart__slice[data-slot='0'], .smrt-chart__swatch[data-slot='0'] { stroke: var(--smrt-color-primary); background: var(--smrt-color-primary); }
237
- .smrt-chart__slice[data-slot='1'], .smrt-chart__swatch[data-slot='1'] { stroke: var(--smrt-color-secondary); background: var(--smrt-color-secondary); }
238
- .smrt-chart__slice[data-slot='2'], .smrt-chart__swatch[data-slot='2'] { stroke: var(--smrt-color-tertiary); background: var(--smrt-color-tertiary); }
239
- .smrt-chart__slice[data-slot='3'], .smrt-chart__swatch[data-slot='3'] { stroke: var(--smrt-color-info); background: var(--smrt-color-info); }
240
- .smrt-chart__slice[data-slot='4'], .smrt-chart__swatch[data-slot='4'] { stroke: var(--smrt-color-primary-container); background: var(--smrt-color-primary-container); }
241
- .smrt-chart__slice[data-slot='5'], .smrt-chart__swatch[data-slot='5'] { stroke: var(--smrt-color-secondary-container); background: var(--smrt-color-secondary-container); }
242
- .smrt-chart__slice[data-slot='6'], .smrt-chart__swatch[data-slot='6'] { stroke: var(--smrt-color-tertiary-container); background: var(--smrt-color-tertiary-container); }
243
- .smrt-chart__slice[data-slot='7'], .smrt-chart__swatch[data-slot='7'] { stroke: var(--smrt-color-info-container); background: var(--smrt-color-info-container); }
244
- .smrt-chart__legend { display: grid; gap: var(--smrt-spacing-1); margin: 0; padding: 0; list-style: none; color: var(--smrt-color-on-surface); font-size: var(--smrt-typography-body-medium-size, 0.875rem); }
245
- .smrt-chart__legend-item { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--smrt-spacing-2); }
246
- .smrt-chart__swatch { inline-size: 0.75rem; block-size: 0.75rem; border-radius: var(--smrt-radius-small); }
247
- .smrt-chart__legend .smrt-chart__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
248
- @media (prefers-reduced-motion: no-preference) {
249
- .smrt-chart__slice { transition: stroke-dasharray var(--smrt-duration-normal) var(--smrt-easing-standard), stroke-dashoffset var(--smrt-duration-normal) var(--smrt-easing-standard); }
250
- .smrt-chart__bar { transition: inline-size var(--smrt-duration-normal) var(--smrt-easing-standard); }
251
- }
252
- .smrt-chart__table { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
253
- /* Forced colors (#3908): selected and open states keep a non-colour indicator. */
254
- @media (forced-colors: active) {
255
- /* Series keys: system colours cycle by slot (the user's own palette), so
256
- slices and legend swatches stay distinguishable without author colours.
257
- The legend always carries label, value and share as text. */
258
- .smrt-chart__slice[data-slot='0'], .smrt-chart__swatch[data-slot='0'] { stroke: CanvasText; background: CanvasText; }
259
- .smrt-chart__slice[data-slot='1'], .smrt-chart__swatch[data-slot='1'] { stroke: Highlight; background: Highlight; }
260
- .smrt-chart__slice[data-slot='2'], .smrt-chart__swatch[data-slot='2'] { stroke: LinkText; background: LinkText; }
261
- .smrt-chart__slice[data-slot='3'], .smrt-chart__swatch[data-slot='3'] { stroke: VisitedText; background: VisitedText; }
262
- .smrt-chart__slice[data-slot='4'], .smrt-chart__swatch[data-slot='4'] { stroke: ActiveText; background: ActiveText; }
263
- .smrt-chart__slice[data-slot='5'], .smrt-chart__swatch[data-slot='5'] { stroke: GrayText; background: GrayText; }
264
- .smrt-chart__slice[data-slot='6'], .smrt-chart__swatch[data-slot='6'] { stroke: ButtonText; background: ButtonText; }
265
- .smrt-chart__slice[data-slot='7'], .smrt-chart__swatch[data-slot='7'] { stroke: MarkText; background: MarkText; }
266
- .smrt-chart__swatch { border: var(--smrt-hairline-strong); }
267
- .smrt-chart__slice { stroke-linecap: butt; }
268
- .smrt-chart__track { background: Canvas; border: var(--smrt-hairline-strong); }
269
- .smrt-chart__bar { background: Highlight; }
270
- }
271
- }
272
- </style>
10
+ <div data-smrt-component="ChartWidget">
11
+ <Chart data={data ?? null} style={String(options.style ?? 'bar')} {title} {locale} />
12
+ </div>
@@ -1,5 +1,5 @@
1
1
  import type { WidgetComponentProps } from '../types.js';
2
- import { type ChartWidgetData } from './data.js';
2
+ import type { ChartWidgetData } from './data.js';
3
3
  declare const ChartWidget: import("svelte").Component<WidgetComponentProps<ChartWidgetData>, {}, "">;
4
4
  type ChartWidget = ReturnType<typeof ChartWidget>;
5
5
  export default ChartWidget;
@@ -1 +1 @@
1
- {"version":3,"file":"ChartWidget.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/overview/widgets/ChartWidget.svelte.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,KAAK,eAAe,EAAY,MAAM,WAAW,CAAC;AAqM3D,QAAA,MAAM,WAAW,2EAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"ChartWidget.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/overview/widgets/ChartWidget.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAiBjD,QAAA,MAAM,WAAW,2EAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -2306,8 +2306,8 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2306
2306
  flex: 0 0 auto;
2307
2307
  margin-block-start: auto;
2308
2308
  align-self: flex-end;
2309
- inline-size: max(2rem, var(--smrt-control-target-min, 0px));
2310
- block-size: max(2rem, var(--smrt-control-target-min, 0px));
2309
+ inline-size: max(2rem, var(--smrt-control-target-min));
2310
+ block-size: max(2rem, var(--smrt-control-target-min));
2311
2311
  padding: 0;
2312
2312
  border-radius: var(--smrt-control-radius);
2313
2313
  color: var(--smrt-color-on-surface-variant);
@@ -2332,8 +2332,8 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2332
2332
 
2333
2333
  :global(.smrt-admin-shell__edge-toggle--left[data-smrt-component="Button"]) {
2334
2334
  flex: 0 0 auto;
2335
- inline-size: max(2.75rem, var(--smrt-control-target-min, 0px));
2336
- block-size: max(2.75rem, var(--smrt-control-target-min, 0px));
2335
+ inline-size: max(2.75rem, var(--smrt-control-target-min));
2336
+ block-size: max(2.75rem, var(--smrt-control-target-min));
2337
2337
  padding: 0;
2338
2338
  color: var(--smrt-color-on-surface-variant);
2339
2339
  }
@@ -63,8 +63,8 @@ let {
63
63
  display: inline-grid;
64
64
  place-items: center;
65
65
  box-sizing: border-box;
66
- inline-size: max(var(--smrt-control-height-small), var(--smrt-control-target-min, 0px));
67
- block-size: max(var(--smrt-control-height-small), var(--smrt-control-target-min, 0px));
66
+ inline-size: max(var(--smrt-control-height-small), var(--smrt-control-target-min));
67
+ block-size: max(var(--smrt-control-height-small), var(--smrt-control-target-min));
68
68
  padding: 0;
69
69
  border: 0;
70
70
  border-radius: var(--smrt-control-radius);
@@ -309,8 +309,8 @@ function fallbackIcon(label: string): string {
309
309
  display: inline-grid;
310
310
  grid-template-columns: minmax(0, 1fr);
311
311
  place-items: center;
312
- inline-size: max(2rem, var(--smrt-control-target-min, 0px));
313
- block-size: max(2rem, var(--smrt-control-target-min, 0px));
312
+ inline-size: max(2rem, var(--smrt-control-target-min));
313
+ block-size: max(2rem, var(--smrt-control-target-min));
314
314
  padding: 0;
315
315
  color: var(--smrt-color-on-surface-variant);
316
316
  }
@@ -321,7 +321,7 @@ function fallbackIcon(label: string): string {
321
321
 
322
322
  .smrt-tenant-nav__heading {
323
323
  box-sizing: border-box;
324
- min-block-size: var(--smrt-control-target-min, 0px);
324
+ min-block-size: var(--smrt-control-target-min);
325
325
  padding: var(--smrt-spacing-2) var(--smrt-spacing-3);
326
326
  color: var(--smrt-color-on-surface-variant);
327
327
  font-size: var(--smrt-typography-label-large-size);
@@ -343,8 +343,8 @@ function fallbackIcon(label: string): string {
343
343
  display: grid;
344
344
  place-items: center;
345
345
  list-style: none;
346
- inline-size: max(2.25rem, var(--smrt-control-target-min, 0px));
347
- block-size: max(2.25rem, var(--smrt-control-target-min, 0px));
346
+ inline-size: max(2.25rem, var(--smrt-control-target-min));
347
+ block-size: max(2.25rem, var(--smrt-control-target-min));
348
348
  padding: 0;
349
349
  }
350
350
  .smrt-tenant-nav--collapsed .smrt-tenant-nav__heading::-webkit-details-marker { display: none; }
@@ -357,7 +357,7 @@ function fallbackIcon(label: string): string {
357
357
  .smrt-tenant-nav[data-density='comfortable'] { --smrt-control-target-min: 0px; }
358
358
  .smrt-tenant-nav a {
359
359
  box-sizing: border-box;
360
- min-block-size: var(--smrt-control-target-min, 0px);
360
+ min-block-size: var(--smrt-control-target-min);
361
361
  display: grid;
362
362
  /* Icon, label, then one auto column per trailing mark (badge, dot). */
363
363
  grid-template-columns: auto minmax(0, 1fr);
@@ -380,8 +380,8 @@ function fallbackIcon(label: string): string {
380
380
  .smrt-tenant-nav--collapsed a {
381
381
  grid-template-columns: minmax(0, 1fr);
382
382
  place-items: center;
383
- inline-size: max(2.25rem, var(--smrt-control-target-min, 0px));
384
- block-size: max(2.25rem, var(--smrt-control-target-min, 0px));
383
+ inline-size: max(2.25rem, var(--smrt-control-target-min));
384
+ block-size: max(2.25rem, var(--smrt-control-target-min));
385
385
  padding: 0;
386
386
  }
387
387
 
@@ -357,7 +357,7 @@ $effect(() => {
357
357
  box-sizing: border-box;
358
358
  width: 100%;
359
359
  min-width: 0;
360
- min-height: max(2.75rem, var(--smrt-control-target-min, 0px));
360
+ min-height: max(2.75rem, var(--smrt-control-target-min));
361
361
  padding: var(--smrt-spacing-2);
362
362
  position: relative;
363
363
  border: var(--smrt-hairline);
@@ -403,7 +403,7 @@ $effect(() => {
403
403
  display: grid;
404
404
  place-items: center;
405
405
  grid-template-columns: minmax(0, 1fr);
406
- min-width: max(2.75rem, var(--smrt-control-target-min, 0px));
406
+ min-width: max(2.75rem, var(--smrt-control-target-min));
407
407
  padding: var(--smrt-spacing-1);
408
408
  border-color: transparent;
409
409
  border-radius: var(--smrt-radius-full);
@@ -467,7 +467,7 @@ $effect(() => {
467
467
  display: flex;
468
468
  align-items: center;
469
469
  box-sizing: border-box;
470
- min-block-size: max(2.75rem, var(--smrt-control-target-min, 0px));
470
+ min-block-size: max(2.75rem, var(--smrt-control-target-min));
471
471
  padding: var(--smrt-spacing-2) var(--smrt-spacing-3);
472
472
  border: none;
473
473
  border-radius: var(--smrt-control-radius-small);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-svelte",
3
- "version": "0.55.24",
3
+ "version": "0.56.0",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Svelte 5 components for SMRT user management - auth, users, tenants, roles, permissions, groups",
6
6
  "type": "module",
@@ -205,11 +205,11 @@
205
205
  },
206
206
  "dependencies": {
207
207
  "@happyvertical/logger": "^0.103.6",
208
- "@happyvertical/smrt-languages": "0.55.24",
209
- "@happyvertical/smrt-mcp-apps": "0.55.24",
210
- "@happyvertical/smrt-types": "0.55.24",
211
- "@happyvertical/smrt-ui": "0.55.24",
212
- "@happyvertical/smrt-web": "0.55.24",
208
+ "@happyvertical/smrt-languages": "0.56.0",
209
+ "@happyvertical/smrt-mcp-apps": "0.56.0",
210
+ "@happyvertical/smrt-types": "0.56.0",
211
+ "@happyvertical/smrt-ui": "0.56.0",
212
+ "@happyvertical/smrt-web": "0.56.0",
213
213
  "@tanstack/db": "^0.6.14",
214
214
  "@tanstack/svelte-db": "^0.1.91",
215
215
  "esm-env": "^1.2.2"
@@ -244,14 +244,14 @@
244
244
  }
245
245
  },
246
246
  "devDependencies": {
247
- "@happyvertical/smrt-agents": "0.55.24",
248
- "@happyvertical/smrt-chat": "0.55.24",
249
- "@happyvertical/smrt-content": "0.55.24",
250
- "@happyvertical/smrt-core": "0.55.24",
251
- "@happyvertical/smrt-reports": "0.55.24",
252
- "@happyvertical/smrt-scanner": "0.55.24",
253
- "@happyvertical/smrt-tenancy": "0.55.24",
254
- "@happyvertical/smrt-users": "0.55.24",
247
+ "@happyvertical/smrt-agents": "0.56.0",
248
+ "@happyvertical/smrt-chat": "0.56.0",
249
+ "@happyvertical/smrt-content": "0.56.0",
250
+ "@happyvertical/smrt-core": "0.56.0",
251
+ "@happyvertical/smrt-reports": "0.56.0",
252
+ "@happyvertical/smrt-scanner": "0.56.0",
253
+ "@happyvertical/smrt-tenancy": "0.56.0",
254
+ "@happyvertical/smrt-users": "0.56.0",
255
255
  "@happyvertical/speech": "^0.103.6",
256
256
  "@sveltejs/package": "^2.5.8",
257
257
  "@sveltejs/vite-plugin-svelte": "^7.3.0",