@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.
- package/agents/overview-surfaces.md +9 -2
- package/dist/components/command-palette/CommandPaletteDialog.svelte +1 -1
- package/dist/components/overview/OverviewGrid.svelte +8 -4
- package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -1
- package/dist/components/overview/WidgetOptionsForm.svelte +13 -2
- package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -1
- package/dist/components/overview/format.d.ts +3 -12
- package/dist/components/overview/format.d.ts.map +1 -1
- package/dist/components/overview/format.js +2 -45
- package/dist/components/overview/grid-types.d.ts +6 -11
- package/dist/components/overview/grid-types.d.ts.map +1 -1
- package/dist/components/overview/index.d.ts +1 -0
- package/dist/components/overview/index.d.ts.map +1 -1
- package/dist/components/overview/recipe-widgets.d.ts +6 -3
- package/dist/components/overview/recipe-widgets.d.ts.map +1 -1
- package/dist/components/overview/recipe-widgets.js +9 -0
- package/dist/components/overview/registry.d.ts +3 -0
- package/dist/components/overview/registry.d.ts.map +1 -1
- package/dist/components/overview/registry.js +25 -0
- package/dist/components/overview/server.d.ts +1 -1
- package/dist/components/overview/server.d.ts.map +1 -1
- package/dist/components/overview/server.js +1 -1
- package/dist/components/overview/types.d.ts +17 -0
- package/dist/components/overview/types.d.ts.map +1 -1
- package/dist/components/overview/widgets/ChartWidget.svelte +5 -265
- package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +1 -1
- package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/AdminShell.svelte +4 -4
- package/dist/components/workspace/admin-shell/ShellIconButton.svelte +2 -2
- package/dist/components/workspace/admin-shell/TenantNav.svelte +8 -8
- package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte +3 -3
- 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.
|
|
318
|
-
|
|
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
|
|
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 {
|
|
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;
|
|
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 {
|
|
27
|
-
|
|
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;
|
|
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
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
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":"
|
|
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
|
-
|
|
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 {
|
|
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
|
|
47
|
-
|
|
48
|
-
|
|
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,
|
|
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 {
|
|
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;
|
|
22
|
-
export
|
|
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,
|
|
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;
|
|
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 {
|
|
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
|
-
|
|
114
|
-
<
|
|
115
|
-
|
|
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 {
|
|
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":"
|
|
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
|
|
2310
|
-
block-size: max(2rem, var(--smrt-control-target-min
|
|
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
|
|
2336
|
-
block-size: max(2.75rem, var(--smrt-control-target-min
|
|
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
|
|
67
|
-
block-size: max(var(--smrt-control-height-small), var(--smrt-control-target-min
|
|
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
|
|
313
|
-
block-size: max(2rem, var(--smrt-control-target-min
|
|
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
|
|
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
|
|
347
|
-
block-size: max(2.25rem, var(--smrt-control-target-min
|
|
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
|
|
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
|
|
384
|
-
block-size: max(2.25rem, var(--smrt-control-target-min
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
209
|
-
"@happyvertical/smrt-mcp-apps": "0.
|
|
210
|
-
"@happyvertical/smrt-types": "0.
|
|
211
|
-
"@happyvertical/smrt-ui": "0.
|
|
212
|
-
"@happyvertical/smrt-web": "0.
|
|
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.
|
|
248
|
-
"@happyvertical/smrt-chat": "0.
|
|
249
|
-
"@happyvertical/smrt-content": "0.
|
|
250
|
-
"@happyvertical/smrt-core": "0.
|
|
251
|
-
"@happyvertical/smrt-reports": "0.
|
|
252
|
-
"@happyvertical/smrt-scanner": "0.
|
|
253
|
-
"@happyvertical/smrt-tenancy": "0.
|
|
254
|
-
"@happyvertical/smrt-users": "0.
|
|
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",
|