@richardmcquiston01/dashboard-widgets-toolkit 0.2.0 → 0.4.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/dist/react.d.cts CHANGED
@@ -1,14 +1,20 @@
1
- import { ReactNode } from 'react';
2
- import { D as DashboardWidget, W as WidgetSize, a as WidgetFill, G as GraphWidgetData, N as NiceDomain, L as Locale, b as DashboardLayout, A as AlertListWidgetData, B as BarListWidgetData, c as GaugeWidgetData, K as KpiWidgetData, T as TableWidgetData, d as TextWidgetData, e as WidgetData } from './scale-Bhjc5Eqt.cjs';
1
+ import { ReactNode, RefObject } from 'react';
2
+ import { D as DashboardWidget, W as WidgetSize, a as WidgetFill, G as GraphWidgetData, N as NiceDomain, b as WidgetDefinition, c as DetailProviderOptions, d as DetailData, e as DetailQuery, L as Locale, f as DashboardLayout, A as AlertListWidgetData, B as BarListWidgetData, g as GaugeWidgetData, K as KpiWidgetData, T as TableWidgetData, h as TextWidgetData, i as WidgetData, R as ResolveOptions, j as WidgetContext, k as WidgetProviders } from './scale-dWDGE1zW.cjs';
3
3
 
4
4
  interface WidgetCardProps {
5
5
  readonly title: string;
6
6
  readonly description?: string;
7
- /** Extra controls in the header (move, hide...), before the minimise toggle. */
7
+ /** Extra controls in the header (move, hide...), before the minimize toggle. */
8
8
  readonly actions?: ReactNode;
9
9
  readonly minimized?: boolean;
10
- /** Shows the minimise/expand toggle when given. */
10
+ /** Shows the minimize/expand toggle when given. */
11
11
  readonly onToggleMinimized?: () => void;
12
+ /**
13
+ * Opens the widget's detail view. Adds a "View" icon button to the header
14
+ * actions and makes the title clickable (for mouse and touch; the button is
15
+ * the accessible control).
16
+ */
17
+ readonly onView?: () => void;
12
18
  /** Default 'ok', which renders `children`. */
13
19
  readonly status?: 'ok' | 'loading' | 'empty' | 'error';
14
20
  readonly emptyText?: string;
@@ -24,6 +30,13 @@ interface WidgetCardProps {
24
30
  * width-filling card the columns left over in its row.
25
31
  */
26
32
  readonly columnSpan?: number;
33
+ /** 12-column width (see `WidgetDefinition.width`); sets `--dwt-width`. */
34
+ readonly width?: number;
35
+ /**
36
+ * The widget's key, rendered as `data-widget-key` so `useWidgets` can tell
37
+ * which card scrolled into view. `ResolvedWidgetCard` sets it for you.
38
+ */
39
+ readonly widgetKey?: string;
27
40
  /** 2 to 6; default 2. */
28
41
  readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
29
42
  readonly className?: string;
@@ -31,18 +44,22 @@ interface WidgetCardProps {
31
44
  }
32
45
  /**
33
46
  * The frame every widget sits in: title, optional description and actions,
34
- * a minimise toggle, and loading, empty and error states.
47
+ * a minimize toggle, and loading, empty and error states.
35
48
  */
36
- declare function WidgetCard({ title, description, actions, minimized, onToggleMinimized, status, emptyText, error, onRetry, footer, size, fill, columnSpan, headingLevel, className, children, }: WidgetCardProps): ReactNode;
49
+ declare function WidgetCard({ title, description, actions, minimized, onToggleMinimized, onView, status, emptyText, error, onRetry, footer, size, fill, columnSpan, width, widgetKey, headingLevel, className, children, }: WidgetCardProps): ReactNode;
37
50
  /** The title to show: alert lists add their total, e.g. "Low stock (3)". */
38
51
  declare function widgetTitle(widget: DashboardWidget): string;
39
52
  interface ResolvedWidgetCardProps {
40
53
  readonly widget: DashboardWidget;
41
54
  /** See `WidgetCardProps.columnSpan`. */
42
55
  readonly columnSpan?: number;
56
+ /** 12-column width (see `WidgetDefinition.width`); sets `--dwt-width`. */
57
+ readonly width?: number;
43
58
  readonly actions?: ReactNode;
44
59
  readonly minimized?: boolean;
45
60
  readonly onToggleMinimized?: () => void;
61
+ /** See `WidgetCardProps.onView`. */
62
+ readonly onView?: () => void;
46
63
  readonly onRetry?: () => void;
47
64
  readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
48
65
  readonly className?: string;
@@ -68,8 +85,65 @@ declare function GraphWidget({ data, title, }: {
68
85
  readonly title?: string;
69
86
  }): ReactNode;
70
87
 
88
+ /**
89
+ * Loads a widget's full detail data. Close over your own context (a Prisma
90
+ * client, a fetch) here; the package never fetches. See `DetailProvider`.
91
+ */
92
+ type DetailLoader = (definition: WidgetDefinition, options: DetailProviderOptions) => DetailData | Promise<DetailData>;
93
+ interface WidgetDetailProps {
94
+ /** Table caption: the widget's title. */
95
+ readonly title: string;
96
+ /** The rows to show. Absent while `status` is `loading` or `error`. */
97
+ readonly data?: DetailData;
98
+ /** Controlled: you own the query, so you can keep it in the URL. */
99
+ readonly query: DetailQuery;
100
+ readonly onQueryChange: (query: DetailQuery) => void;
101
+ /** Default `ok`. */
102
+ readonly status?: 'ok' | 'loading' | 'error';
103
+ readonly error?: string;
104
+ readonly onRetry?: () => void;
105
+ /** Heading level of the title, 2 to 6. Default 2. */
106
+ readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
107
+ /** Id of the heading, so a dialog can label itself with it. */
108
+ readonly headingId?: string;
109
+ readonly className?: string;
110
+ }
111
+ /**
112
+ * The detail view of a widget: search and column filters, a sortable table
113
+ * and paging, over data you give it (client mode: it filters, sorts and pages
114
+ * in memory with `queryRows`). Controlled by `query`. Use it on its own as a
115
+ * page, or inside `WidgetDetailDialog`.
116
+ */
117
+ declare function WidgetDetail({ title, data, query, onQueryChange, status, error, onRetry, headingLevel, headingId, className, }: WidgetDetailProps): ReactNode;
118
+ interface WidgetDetailDialogProps {
119
+ readonly title: string;
120
+ readonly open: boolean;
121
+ /** Called on Esc, the Close button and a click on the backdrop. */
122
+ readonly onClose: () => void;
123
+ readonly children: ReactNode;
124
+ }
125
+ /**
126
+ * A native modal `<dialog>`: focus is trapped, Esc closes it, the page behind
127
+ * is inert, and focus returns to the control that opened it.
128
+ */
129
+ declare function WidgetDetailDialog({ title, open, onClose, children, }: WidgetDetailDialogProps): ReactNode;
130
+ interface DetailLoadState {
131
+ readonly status: 'loading' | 'ok' | 'error';
132
+ readonly data?: DetailData;
133
+ readonly error?: string;
134
+ }
135
+ /**
136
+ * Loads a widget's detail data while `enabled`: calls `load` with an abort
137
+ * signal (aborted on close, retry or unmount), validates the result and
138
+ * reports loading, ok or error. `reload` runs it again.
139
+ */
140
+ declare function useDetailData(definition: WidgetDefinition, load: DetailLoader | undefined, enabled: boolean): {
141
+ readonly state: DetailLoadState;
142
+ readonly reload: () => void;
143
+ };
144
+
71
145
  /** Every element that carries a stable `dwt-*` class, for `classNames`. */
72
- type DashboardClassSlot = 'dashboard' | 'hiddenBar' | 'grid' | 'card' | 'cardHeader' | 'cardTitle' | 'cardDescription' | 'cardActions' | 'cardBody' | 'cardFooter' | 'button' | 'status' | 'empty' | 'error' | 'text' | 'kpi' | 'gauge' | 'table' | 'barList' | 'alertList' | 'chart' | 'legend' | 'tooltip' | 'tableTwin';
146
+ type DashboardClassSlot = 'dashboard' | 'hiddenBar' | 'grid' | 'card' | 'cardHeader' | 'cardTitle' | 'cardDescription' | 'cardActions' | 'cardBody' | 'cardFooter' | 'button' | 'status' | 'empty' | 'error' | 'text' | 'kpi' | 'gauge' | 'table' | 'barList' | 'alertList' | 'chart' | 'legend' | 'tooltip' | 'tableTwin' | 'detail';
73
147
  /**
74
148
  * Extra classes per slot, appended to the `dwt-*` class (never replacing
75
149
  * it), e.g. `{ card: 'rounded-lg shadow-sm' }` for Tailwind.
@@ -87,6 +161,22 @@ interface DashboardLabels {
87
161
  readonly moveEarlier: (title: string) => string;
88
162
  readonly moveLater: (title: string) => string;
89
163
  readonly hiddenWidgets: string;
164
+ readonly minimizedWidgets: string;
165
+ /** Added to the accessible name of links that open in a new tab. */
166
+ readonly opensInNewTab: string;
167
+ /** The card's View button, opening the detail view. */
168
+ readonly view: (title: string) => string;
169
+ readonly close: string;
170
+ readonly search: string;
171
+ readonly filterBy: (column: string) => string;
172
+ readonly sortBy: (column: string) => string;
173
+ readonly noResults: string;
174
+ /** e.g. "Showing 1–25 of 312 results". */
175
+ readonly showingRows: (from: number, to: number, total: number) => string;
176
+ readonly previousPage: string;
177
+ readonly nextPage: string;
178
+ readonly pageOf: (page: number, pageCount: number) => string;
179
+ readonly pagination: string;
90
180
  readonly allHidden: string;
91
181
  readonly noWidgets: string;
92
182
  readonly andMore: (count: number) => string;
@@ -131,28 +221,40 @@ interface DashboardProps extends WidgetSettings {
131
221
  /** The viewer's saved layout. Default: none saved. */
132
222
  readonly layout?: DashboardLayout;
133
223
  /**
134
- * Called with the next layout after a move, hide, show, minimise or
224
+ * Called with the next layout after a move, hide, show, minimize or
135
225
  * restore; persist it. Without it the layout is read-only (no controls).
136
226
  */
137
227
  readonly onLayoutChange?: (layout: DashboardLayout) => void;
138
228
  readonly onRetry?: (key: string) => void;
229
+ /**
230
+ * Loads the full data for a widget's detail view (widgets whose definition
231
+ * sets `detail`). Close over your own context. Without it, TABLE widgets
232
+ * with no footer and BAR_LIST widgets show their card data; other widgets
233
+ * get no View button.
234
+ */
235
+ readonly loadDetail?: DetailLoader;
236
+ /**
237
+ * Called with the widget key when the viewer opens a detail view, instead
238
+ * of the built-in dialog: navigate to your own page.
239
+ */
240
+ readonly onOpenDetail?: (key: string) => void;
139
241
  readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
140
242
  readonly className?: string;
141
243
  }
142
244
  /**
143
245
  * A full dashboard: widgets ordered by the viewer's layout, with move,
144
- * hide/show and minimise controls when `onLayoutChange` is given. Settings
246
+ * hide/show and minimize controls when `onLayoutChange` is given. Settings
145
247
  * (locale, link target, classNames, labels) apply to every widget inside.
146
248
  */
147
249
  declare function Dashboard({ locale, linkTarget, classNames, labels, ...props }: DashboardProps): ReactNode;
148
250
 
149
251
  /**
150
- * Default colours, used as `var(--dwt-*, fallback)` so charts read correctly
252
+ * Default colors, used as `var(--dwt-*, fallback)` so charts read correctly
151
253
  * without the stylesheet. `styles.css` redefines them for dark mode, and an
152
254
  * app can override any of them with its own CSS custom properties.
153
255
  *
154
256
  * The categorical order is the dataviz reference palette, validated for
155
- * colour-vision deficiency on adjacent pairs in light and dark modes. Slots
257
+ * color-vision deficiency on adjacent pairs in light and dark modes. Slots
156
258
  * are assigned in this fixed order, never cycled, and follow the series
157
259
  * (its position in the payload), never its rank.
158
260
  */
@@ -180,7 +282,7 @@ declare function TextWidget({ data, }: {
180
282
  }): ReactNode;
181
283
  /**
182
284
  * KPI: a stat tile. The change against the previous period carries an arrow
183
- * and signed text as well as colour, so it never relies on colour alone.
285
+ * and signed text as well as color, so it never relies on color alone.
184
286
  */
185
287
  declare function KpiWidget({ data, }: {
186
288
  readonly data: KpiWidgetData;
@@ -194,7 +296,7 @@ declare function TableWidget({ data, }: {
194
296
  readonly data: TableWidgetData;
195
297
  }): ReactNode;
196
298
  /**
197
- * BAR_LIST: labelled horizontal bars. One series, so one colour (slot 1)
299
+ * BAR_LIST: labelled horizontal bars. One series, so one color (slot 1)
198
300
  * for every bar; the value text sits beside the bar, never inside it.
199
301
  */
200
302
  declare function BarListWidget({ data, }: {
@@ -209,4 +311,43 @@ declare function WidgetContent({ data, }: {
209
311
  readonly data: WidgetData;
210
312
  }): ReactNode;
211
313
 
212
- export { AlertListWidget, BarListWidget, DEFAULT_LABELS, DEFAULT_SERIES_COLORS, Dashboard, type DashboardClassNames, type DashboardClassSlot, type DashboardLabels, type DashboardProps, GaugeWidget, GraphWidget, KpiWidget, ResolvedWidgetCard, type ResolvedWidgetCardProps, TableWidget, TextWidget, Thumbnail, WidgetCard, type WidgetCardProps, WidgetContent, WidgetGrid, type WidgetGridProps, WidgetLink, type WidgetSettings, WidgetSettingsProvider, barPath, buildChartModel, describeChart, joinClassNames, seriesColor, useWidgetSettings, widgetTitle };
314
+ interface UseWidgetsOptions extends ResolveOptions {
315
+ /**
316
+ * When each widget's provider starts. `'mount'` (default): right after the
317
+ * first render, so the page and the dashboard shell appear first and each
318
+ * card fills in as its data arrives. `'visible'`: only once the card is
319
+ * near the viewport (attach `gridRef` to an element around the cards).
320
+ */
321
+ readonly loadWhen?: 'mount' | 'visible';
322
+ /** `IntersectionObserver` margin for `loadWhen: 'visible'`. Default `'200px'`. */
323
+ readonly rootMargin?: string;
324
+ /**
325
+ * Reload started widgets every this many ms. Ticks are skipped while the
326
+ * tab is hidden, and a widget still loading is not restarted.
327
+ */
328
+ readonly refreshMs?: number;
329
+ }
330
+ interface UseWidgetsResult {
331
+ /** Pass to `Dashboard` or `WidgetGrid`: placeholders first, then results. */
332
+ readonly widgets: readonly DashboardWidget[];
333
+ /** Reload one widget (for example from the error card's Retry) or all. */
334
+ readonly refresh: (key?: string) => void;
335
+ /**
336
+ * For `loadWhen: 'visible'`: attach to any element that contains the cards,
337
+ * for example a wrapper `<div ref={gridRef}>` around `Dashboard`.
338
+ */
339
+ readonly gridRef: RefObject<HTMLDivElement | null>;
340
+ }
341
+ /**
342
+ * Loads widget data after the page has rendered and returns widgets for
343
+ * `Dashboard`. The first render never waits for data (so server rendering
344
+ * and first paint are unaffected); every widget starts as `loading`, loads
345
+ * independently, and replaces its placeholder when its own data arrives.
346
+ *
347
+ * Keep `definitions`, `providers`, `context` and `options.cache` referentially
348
+ * stable (module constants or `useMemo`): a changed value restarts loading,
349
+ * aborting whatever is in flight.
350
+ */
351
+ declare function useWidgets<C extends WidgetContext>(definitions: readonly WidgetDefinition[], providers: WidgetProviders<C>, context: C, options?: UseWidgetsOptions): UseWidgetsResult;
352
+
353
+ export { AlertListWidget, BarListWidget, DEFAULT_LABELS, DEFAULT_SERIES_COLORS, Dashboard, type DashboardClassNames, type DashboardClassSlot, type DashboardLabels, type DashboardProps, type DetailLoadState, type DetailLoader, GaugeWidget, GraphWidget, KpiWidget, ResolvedWidgetCard, type ResolvedWidgetCardProps, TableWidget, TextWidget, Thumbnail, type UseWidgetsOptions, type UseWidgetsResult, WidgetCard, type WidgetCardProps, WidgetContent, WidgetDetail, WidgetDetailDialog, type WidgetDetailDialogProps, type WidgetDetailProps, WidgetGrid, type WidgetGridProps, WidgetLink, type WidgetSettings, WidgetSettingsProvider, barPath, buildChartModel, describeChart, joinClassNames, seriesColor, useDetailData, useWidgetSettings, useWidgets, widgetTitle };
package/dist/react.d.ts CHANGED
@@ -1,14 +1,20 @@
1
- import { ReactNode } from 'react';
2
- import { D as DashboardWidget, W as WidgetSize, a as WidgetFill, G as GraphWidgetData, N as NiceDomain, L as Locale, b as DashboardLayout, A as AlertListWidgetData, B as BarListWidgetData, c as GaugeWidgetData, K as KpiWidgetData, T as TableWidgetData, d as TextWidgetData, e as WidgetData } from './scale-Bhjc5Eqt.js';
1
+ import { ReactNode, RefObject } from 'react';
2
+ import { D as DashboardWidget, W as WidgetSize, a as WidgetFill, G as GraphWidgetData, N as NiceDomain, b as WidgetDefinition, c as DetailProviderOptions, d as DetailData, e as DetailQuery, L as Locale, f as DashboardLayout, A as AlertListWidgetData, B as BarListWidgetData, g as GaugeWidgetData, K as KpiWidgetData, T as TableWidgetData, h as TextWidgetData, i as WidgetData, R as ResolveOptions, j as WidgetContext, k as WidgetProviders } from './scale-dWDGE1zW.js';
3
3
 
4
4
  interface WidgetCardProps {
5
5
  readonly title: string;
6
6
  readonly description?: string;
7
- /** Extra controls in the header (move, hide...), before the minimise toggle. */
7
+ /** Extra controls in the header (move, hide...), before the minimize toggle. */
8
8
  readonly actions?: ReactNode;
9
9
  readonly minimized?: boolean;
10
- /** Shows the minimise/expand toggle when given. */
10
+ /** Shows the minimize/expand toggle when given. */
11
11
  readonly onToggleMinimized?: () => void;
12
+ /**
13
+ * Opens the widget's detail view. Adds a "View" icon button to the header
14
+ * actions and makes the title clickable (for mouse and touch; the button is
15
+ * the accessible control).
16
+ */
17
+ readonly onView?: () => void;
12
18
  /** Default 'ok', which renders `children`. */
13
19
  readonly status?: 'ok' | 'loading' | 'empty' | 'error';
14
20
  readonly emptyText?: string;
@@ -24,6 +30,13 @@ interface WidgetCardProps {
24
30
  * width-filling card the columns left over in its row.
25
31
  */
26
32
  readonly columnSpan?: number;
33
+ /** 12-column width (see `WidgetDefinition.width`); sets `--dwt-width`. */
34
+ readonly width?: number;
35
+ /**
36
+ * The widget's key, rendered as `data-widget-key` so `useWidgets` can tell
37
+ * which card scrolled into view. `ResolvedWidgetCard` sets it for you.
38
+ */
39
+ readonly widgetKey?: string;
27
40
  /** 2 to 6; default 2. */
28
41
  readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
29
42
  readonly className?: string;
@@ -31,18 +44,22 @@ interface WidgetCardProps {
31
44
  }
32
45
  /**
33
46
  * The frame every widget sits in: title, optional description and actions,
34
- * a minimise toggle, and loading, empty and error states.
47
+ * a minimize toggle, and loading, empty and error states.
35
48
  */
36
- declare function WidgetCard({ title, description, actions, minimized, onToggleMinimized, status, emptyText, error, onRetry, footer, size, fill, columnSpan, headingLevel, className, children, }: WidgetCardProps): ReactNode;
49
+ declare function WidgetCard({ title, description, actions, minimized, onToggleMinimized, onView, status, emptyText, error, onRetry, footer, size, fill, columnSpan, width, widgetKey, headingLevel, className, children, }: WidgetCardProps): ReactNode;
37
50
  /** The title to show: alert lists add their total, e.g. "Low stock (3)". */
38
51
  declare function widgetTitle(widget: DashboardWidget): string;
39
52
  interface ResolvedWidgetCardProps {
40
53
  readonly widget: DashboardWidget;
41
54
  /** See `WidgetCardProps.columnSpan`. */
42
55
  readonly columnSpan?: number;
56
+ /** 12-column width (see `WidgetDefinition.width`); sets `--dwt-width`. */
57
+ readonly width?: number;
43
58
  readonly actions?: ReactNode;
44
59
  readonly minimized?: boolean;
45
60
  readonly onToggleMinimized?: () => void;
61
+ /** See `WidgetCardProps.onView`. */
62
+ readonly onView?: () => void;
46
63
  readonly onRetry?: () => void;
47
64
  readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
48
65
  readonly className?: string;
@@ -68,8 +85,65 @@ declare function GraphWidget({ data, title, }: {
68
85
  readonly title?: string;
69
86
  }): ReactNode;
70
87
 
88
+ /**
89
+ * Loads a widget's full detail data. Close over your own context (a Prisma
90
+ * client, a fetch) here; the package never fetches. See `DetailProvider`.
91
+ */
92
+ type DetailLoader = (definition: WidgetDefinition, options: DetailProviderOptions) => DetailData | Promise<DetailData>;
93
+ interface WidgetDetailProps {
94
+ /** Table caption: the widget's title. */
95
+ readonly title: string;
96
+ /** The rows to show. Absent while `status` is `loading` or `error`. */
97
+ readonly data?: DetailData;
98
+ /** Controlled: you own the query, so you can keep it in the URL. */
99
+ readonly query: DetailQuery;
100
+ readonly onQueryChange: (query: DetailQuery) => void;
101
+ /** Default `ok`. */
102
+ readonly status?: 'ok' | 'loading' | 'error';
103
+ readonly error?: string;
104
+ readonly onRetry?: () => void;
105
+ /** Heading level of the title, 2 to 6. Default 2. */
106
+ readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
107
+ /** Id of the heading, so a dialog can label itself with it. */
108
+ readonly headingId?: string;
109
+ readonly className?: string;
110
+ }
111
+ /**
112
+ * The detail view of a widget: search and column filters, a sortable table
113
+ * and paging, over data you give it (client mode: it filters, sorts and pages
114
+ * in memory with `queryRows`). Controlled by `query`. Use it on its own as a
115
+ * page, or inside `WidgetDetailDialog`.
116
+ */
117
+ declare function WidgetDetail({ title, data, query, onQueryChange, status, error, onRetry, headingLevel, headingId, className, }: WidgetDetailProps): ReactNode;
118
+ interface WidgetDetailDialogProps {
119
+ readonly title: string;
120
+ readonly open: boolean;
121
+ /** Called on Esc, the Close button and a click on the backdrop. */
122
+ readonly onClose: () => void;
123
+ readonly children: ReactNode;
124
+ }
125
+ /**
126
+ * A native modal `<dialog>`: focus is trapped, Esc closes it, the page behind
127
+ * is inert, and focus returns to the control that opened it.
128
+ */
129
+ declare function WidgetDetailDialog({ title, open, onClose, children, }: WidgetDetailDialogProps): ReactNode;
130
+ interface DetailLoadState {
131
+ readonly status: 'loading' | 'ok' | 'error';
132
+ readonly data?: DetailData;
133
+ readonly error?: string;
134
+ }
135
+ /**
136
+ * Loads a widget's detail data while `enabled`: calls `load` with an abort
137
+ * signal (aborted on close, retry or unmount), validates the result and
138
+ * reports loading, ok or error. `reload` runs it again.
139
+ */
140
+ declare function useDetailData(definition: WidgetDefinition, load: DetailLoader | undefined, enabled: boolean): {
141
+ readonly state: DetailLoadState;
142
+ readonly reload: () => void;
143
+ };
144
+
71
145
  /** Every element that carries a stable `dwt-*` class, for `classNames`. */
72
- type DashboardClassSlot = 'dashboard' | 'hiddenBar' | 'grid' | 'card' | 'cardHeader' | 'cardTitle' | 'cardDescription' | 'cardActions' | 'cardBody' | 'cardFooter' | 'button' | 'status' | 'empty' | 'error' | 'text' | 'kpi' | 'gauge' | 'table' | 'barList' | 'alertList' | 'chart' | 'legend' | 'tooltip' | 'tableTwin';
146
+ type DashboardClassSlot = 'dashboard' | 'hiddenBar' | 'grid' | 'card' | 'cardHeader' | 'cardTitle' | 'cardDescription' | 'cardActions' | 'cardBody' | 'cardFooter' | 'button' | 'status' | 'empty' | 'error' | 'text' | 'kpi' | 'gauge' | 'table' | 'barList' | 'alertList' | 'chart' | 'legend' | 'tooltip' | 'tableTwin' | 'detail';
73
147
  /**
74
148
  * Extra classes per slot, appended to the `dwt-*` class (never replacing
75
149
  * it), e.g. `{ card: 'rounded-lg shadow-sm' }` for Tailwind.
@@ -87,6 +161,22 @@ interface DashboardLabels {
87
161
  readonly moveEarlier: (title: string) => string;
88
162
  readonly moveLater: (title: string) => string;
89
163
  readonly hiddenWidgets: string;
164
+ readonly minimizedWidgets: string;
165
+ /** Added to the accessible name of links that open in a new tab. */
166
+ readonly opensInNewTab: string;
167
+ /** The card's View button, opening the detail view. */
168
+ readonly view: (title: string) => string;
169
+ readonly close: string;
170
+ readonly search: string;
171
+ readonly filterBy: (column: string) => string;
172
+ readonly sortBy: (column: string) => string;
173
+ readonly noResults: string;
174
+ /** e.g. "Showing 1–25 of 312 results". */
175
+ readonly showingRows: (from: number, to: number, total: number) => string;
176
+ readonly previousPage: string;
177
+ readonly nextPage: string;
178
+ readonly pageOf: (page: number, pageCount: number) => string;
179
+ readonly pagination: string;
90
180
  readonly allHidden: string;
91
181
  readonly noWidgets: string;
92
182
  readonly andMore: (count: number) => string;
@@ -131,28 +221,40 @@ interface DashboardProps extends WidgetSettings {
131
221
  /** The viewer's saved layout. Default: none saved. */
132
222
  readonly layout?: DashboardLayout;
133
223
  /**
134
- * Called with the next layout after a move, hide, show, minimise or
224
+ * Called with the next layout after a move, hide, show, minimize or
135
225
  * restore; persist it. Without it the layout is read-only (no controls).
136
226
  */
137
227
  readonly onLayoutChange?: (layout: DashboardLayout) => void;
138
228
  readonly onRetry?: (key: string) => void;
229
+ /**
230
+ * Loads the full data for a widget's detail view (widgets whose definition
231
+ * sets `detail`). Close over your own context. Without it, TABLE widgets
232
+ * with no footer and BAR_LIST widgets show their card data; other widgets
233
+ * get no View button.
234
+ */
235
+ readonly loadDetail?: DetailLoader;
236
+ /**
237
+ * Called with the widget key when the viewer opens a detail view, instead
238
+ * of the built-in dialog: navigate to your own page.
239
+ */
240
+ readonly onOpenDetail?: (key: string) => void;
139
241
  readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
140
242
  readonly className?: string;
141
243
  }
142
244
  /**
143
245
  * A full dashboard: widgets ordered by the viewer's layout, with move,
144
- * hide/show and minimise controls when `onLayoutChange` is given. Settings
246
+ * hide/show and minimize controls when `onLayoutChange` is given. Settings
145
247
  * (locale, link target, classNames, labels) apply to every widget inside.
146
248
  */
147
249
  declare function Dashboard({ locale, linkTarget, classNames, labels, ...props }: DashboardProps): ReactNode;
148
250
 
149
251
  /**
150
- * Default colours, used as `var(--dwt-*, fallback)` so charts read correctly
252
+ * Default colors, used as `var(--dwt-*, fallback)` so charts read correctly
151
253
  * without the stylesheet. `styles.css` redefines them for dark mode, and an
152
254
  * app can override any of them with its own CSS custom properties.
153
255
  *
154
256
  * The categorical order is the dataviz reference palette, validated for
155
- * colour-vision deficiency on adjacent pairs in light and dark modes. Slots
257
+ * color-vision deficiency on adjacent pairs in light and dark modes. Slots
156
258
  * are assigned in this fixed order, never cycled, and follow the series
157
259
  * (its position in the payload), never its rank.
158
260
  */
@@ -180,7 +282,7 @@ declare function TextWidget({ data, }: {
180
282
  }): ReactNode;
181
283
  /**
182
284
  * KPI: a stat tile. The change against the previous period carries an arrow
183
- * and signed text as well as colour, so it never relies on colour alone.
285
+ * and signed text as well as color, so it never relies on color alone.
184
286
  */
185
287
  declare function KpiWidget({ data, }: {
186
288
  readonly data: KpiWidgetData;
@@ -194,7 +296,7 @@ declare function TableWidget({ data, }: {
194
296
  readonly data: TableWidgetData;
195
297
  }): ReactNode;
196
298
  /**
197
- * BAR_LIST: labelled horizontal bars. One series, so one colour (slot 1)
299
+ * BAR_LIST: labelled horizontal bars. One series, so one color (slot 1)
198
300
  * for every bar; the value text sits beside the bar, never inside it.
199
301
  */
200
302
  declare function BarListWidget({ data, }: {
@@ -209,4 +311,43 @@ declare function WidgetContent({ data, }: {
209
311
  readonly data: WidgetData;
210
312
  }): ReactNode;
211
313
 
212
- export { AlertListWidget, BarListWidget, DEFAULT_LABELS, DEFAULT_SERIES_COLORS, Dashboard, type DashboardClassNames, type DashboardClassSlot, type DashboardLabels, type DashboardProps, GaugeWidget, GraphWidget, KpiWidget, ResolvedWidgetCard, type ResolvedWidgetCardProps, TableWidget, TextWidget, Thumbnail, WidgetCard, type WidgetCardProps, WidgetContent, WidgetGrid, type WidgetGridProps, WidgetLink, type WidgetSettings, WidgetSettingsProvider, barPath, buildChartModel, describeChart, joinClassNames, seriesColor, useWidgetSettings, widgetTitle };
314
+ interface UseWidgetsOptions extends ResolveOptions {
315
+ /**
316
+ * When each widget's provider starts. `'mount'` (default): right after the
317
+ * first render, so the page and the dashboard shell appear first and each
318
+ * card fills in as its data arrives. `'visible'`: only once the card is
319
+ * near the viewport (attach `gridRef` to an element around the cards).
320
+ */
321
+ readonly loadWhen?: 'mount' | 'visible';
322
+ /** `IntersectionObserver` margin for `loadWhen: 'visible'`. Default `'200px'`. */
323
+ readonly rootMargin?: string;
324
+ /**
325
+ * Reload started widgets every this many ms. Ticks are skipped while the
326
+ * tab is hidden, and a widget still loading is not restarted.
327
+ */
328
+ readonly refreshMs?: number;
329
+ }
330
+ interface UseWidgetsResult {
331
+ /** Pass to `Dashboard` or `WidgetGrid`: placeholders first, then results. */
332
+ readonly widgets: readonly DashboardWidget[];
333
+ /** Reload one widget (for example from the error card's Retry) or all. */
334
+ readonly refresh: (key?: string) => void;
335
+ /**
336
+ * For `loadWhen: 'visible'`: attach to any element that contains the cards,
337
+ * for example a wrapper `<div ref={gridRef}>` around `Dashboard`.
338
+ */
339
+ readonly gridRef: RefObject<HTMLDivElement | null>;
340
+ }
341
+ /**
342
+ * Loads widget data after the page has rendered and returns widgets for
343
+ * `Dashboard`. The first render never waits for data (so server rendering
344
+ * and first paint are unaffected); every widget starts as `loading`, loads
345
+ * independently, and replaces its placeholder when its own data arrives.
346
+ *
347
+ * Keep `definitions`, `providers`, `context` and `options.cache` referentially
348
+ * stable (module constants or `useMemo`): a changed value restarts loading,
349
+ * aborting whatever is in flight.
350
+ */
351
+ declare function useWidgets<C extends WidgetContext>(definitions: readonly WidgetDefinition[], providers: WidgetProviders<C>, context: C, options?: UseWidgetsOptions): UseWidgetsResult;
352
+
353
+ export { AlertListWidget, BarListWidget, DEFAULT_LABELS, DEFAULT_SERIES_COLORS, Dashboard, type DashboardClassNames, type DashboardClassSlot, type DashboardLabels, type DashboardProps, type DetailLoadState, type DetailLoader, GaugeWidget, GraphWidget, KpiWidget, ResolvedWidgetCard, type ResolvedWidgetCardProps, TableWidget, TextWidget, Thumbnail, type UseWidgetsOptions, type UseWidgetsResult, WidgetCard, type WidgetCardProps, WidgetContent, WidgetDetail, WidgetDetailDialog, type WidgetDetailDialogProps, type WidgetDetailProps, WidgetGrid, type WidgetGridProps, WidgetLink, type WidgetSettings, WidgetSettingsProvider, barPath, buildChartModel, describeChart, joinClassNames, seriesColor, useDetailData, useWidgetSettings, useWidgets, widgetTitle };