@richardmcquiston01/dashboard-widgets-toolkit 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/core.cjs +53 -0
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +29 -3
- package/dist/core.d.ts +29 -3
- package/dist/core.js +49 -1
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +53 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +49 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +94 -2
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +11 -2
- package/dist/react.d.ts +11 -2
- package/dist/react.js +95 -3
- package/dist/react.js.map +1 -1
- package/dist/{scale-WlRozDCf.d.cts → scale-Bhjc5Eqt.d.cts} +11 -1
- package/dist/{scale-WlRozDCf.d.ts → scale-Bhjc5Eqt.d.ts} +11 -1
- package/dist/styles.css +4 -0
- package/package.json +1 -1
package/dist/react.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { D as DashboardWidget, W as WidgetSize, G as GraphWidgetData, N as NiceDomain, L as Locale,
|
|
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';
|
|
3
3
|
|
|
4
4
|
interface WidgetCardProps {
|
|
5
5
|
readonly title: string;
|
|
@@ -17,6 +17,13 @@ interface WidgetCardProps {
|
|
|
17
17
|
readonly onRetry?: () => void;
|
|
18
18
|
readonly footer?: ReactNode;
|
|
19
19
|
readonly size?: WidgetSize;
|
|
20
|
+
/** Fill free space in the grid row (height, width or both). */
|
|
21
|
+
readonly fill?: WidgetFill;
|
|
22
|
+
/**
|
|
23
|
+
* Explicit grid column span, set by `Dashboard` and `WidgetGrid` to give a
|
|
24
|
+
* width-filling card the columns left over in its row.
|
|
25
|
+
*/
|
|
26
|
+
readonly columnSpan?: number;
|
|
20
27
|
/** 2 to 6; default 2. */
|
|
21
28
|
readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
|
|
22
29
|
readonly className?: string;
|
|
@@ -26,11 +33,13 @@ interface WidgetCardProps {
|
|
|
26
33
|
* The frame every widget sits in: title, optional description and actions,
|
|
27
34
|
* a minimise toggle, and loading, empty and error states.
|
|
28
35
|
*/
|
|
29
|
-
declare function WidgetCard({ title, description, actions, minimized, onToggleMinimized, status, emptyText, error, onRetry, footer, size, headingLevel, className, children, }: WidgetCardProps): ReactNode;
|
|
36
|
+
declare function WidgetCard({ title, description, actions, minimized, onToggleMinimized, status, emptyText, error, onRetry, footer, size, fill, columnSpan, headingLevel, className, children, }: WidgetCardProps): ReactNode;
|
|
30
37
|
/** The title to show: alert lists add their total, e.g. "Low stock (3)". */
|
|
31
38
|
declare function widgetTitle(widget: DashboardWidget): string;
|
|
32
39
|
interface ResolvedWidgetCardProps {
|
|
33
40
|
readonly widget: DashboardWidget;
|
|
41
|
+
/** See `WidgetCardProps.columnSpan`. */
|
|
42
|
+
readonly columnSpan?: number;
|
|
34
43
|
readonly actions?: ReactNode;
|
|
35
44
|
readonly minimized?: boolean;
|
|
36
45
|
readonly onToggleMinimized?: () => void;
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { D as DashboardWidget, W as WidgetSize, G as GraphWidgetData, N as NiceDomain, L as Locale,
|
|
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';
|
|
3
3
|
|
|
4
4
|
interface WidgetCardProps {
|
|
5
5
|
readonly title: string;
|
|
@@ -17,6 +17,13 @@ interface WidgetCardProps {
|
|
|
17
17
|
readonly onRetry?: () => void;
|
|
18
18
|
readonly footer?: ReactNode;
|
|
19
19
|
readonly size?: WidgetSize;
|
|
20
|
+
/** Fill free space in the grid row (height, width or both). */
|
|
21
|
+
readonly fill?: WidgetFill;
|
|
22
|
+
/**
|
|
23
|
+
* Explicit grid column span, set by `Dashboard` and `WidgetGrid` to give a
|
|
24
|
+
* width-filling card the columns left over in its row.
|
|
25
|
+
*/
|
|
26
|
+
readonly columnSpan?: number;
|
|
20
27
|
/** 2 to 6; default 2. */
|
|
21
28
|
readonly headingLevel?: 2 | 3 | 4 | 5 | 6;
|
|
22
29
|
readonly className?: string;
|
|
@@ -26,11 +33,13 @@ interface WidgetCardProps {
|
|
|
26
33
|
* The frame every widget sits in: title, optional description and actions,
|
|
27
34
|
* a minimise toggle, and loading, empty and error states.
|
|
28
35
|
*/
|
|
29
|
-
declare function WidgetCard({ title, description, actions, minimized, onToggleMinimized, status, emptyText, error, onRetry, footer, size, headingLevel, className, children, }: WidgetCardProps): ReactNode;
|
|
36
|
+
declare function WidgetCard({ title, description, actions, minimized, onToggleMinimized, status, emptyText, error, onRetry, footer, size, fill, columnSpan, headingLevel, className, children, }: WidgetCardProps): ReactNode;
|
|
30
37
|
/** The title to show: alert lists add their total, e.g. "Low stock (3)". */
|
|
31
38
|
declare function widgetTitle(widget: DashboardWidget): string;
|
|
32
39
|
interface ResolvedWidgetCardProps {
|
|
33
40
|
readonly widget: DashboardWidget;
|
|
41
|
+
/** See `WidgetCardProps.columnSpan`. */
|
|
42
|
+
readonly columnSpan?: number;
|
|
34
43
|
readonly actions?: ReactNode;
|
|
35
44
|
readonly minimized?: boolean;
|
|
36
45
|
readonly onToggleMinimized?: () => void;
|
package/dist/react.js
CHANGED
|
@@ -1,8 +1,52 @@
|
|
|
1
|
-
import { createContext, useContext, useId, useState } from 'react';
|
|
1
|
+
import { createContext, useContext, useId, useState, useRef, useEffect, useMemo } from 'react';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/react/card.tsx
|
|
5
5
|
|
|
6
|
+
// src/core/grid.ts
|
|
7
|
+
function fillsWidth(fill) {
|
|
8
|
+
return fill === "width" || fill === "both";
|
|
9
|
+
}
|
|
10
|
+
function fillsHeight(fill) {
|
|
11
|
+
return fill === "height" || fill === "both";
|
|
12
|
+
}
|
|
13
|
+
function baseColumnSpan(size, columns, largeSpan = 2) {
|
|
14
|
+
if (size === "full") return columns;
|
|
15
|
+
if (size === "large") return Math.min(largeSpan, columns);
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
function fillColumnSpans(items, columns, largeSpan = 2) {
|
|
19
|
+
const trackCount = Math.max(1, Math.floor(columns));
|
|
20
|
+
const spans = /* @__PURE__ */ new Map();
|
|
21
|
+
let row = [];
|
|
22
|
+
let used = 0;
|
|
23
|
+
function closeRow() {
|
|
24
|
+
const fillers = row.filter(({ item }) => fillsWidth(item.fill));
|
|
25
|
+
const leftover = trackCount - used;
|
|
26
|
+
if (fillers.length > 0) {
|
|
27
|
+
const share = Math.floor(leftover / fillers.length);
|
|
28
|
+
const remainder = leftover % fillers.length;
|
|
29
|
+
fillers.forEach(({ item, span }, index) => {
|
|
30
|
+
spans.set(item.key, span + share + (index < remainder ? 1 : 0));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
row = [];
|
|
34
|
+
used = 0;
|
|
35
|
+
}
|
|
36
|
+
for (const item of items) {
|
|
37
|
+
const span = baseColumnSpan(
|
|
38
|
+
item.defaultSize,
|
|
39
|
+
trackCount,
|
|
40
|
+
largeSpan
|
|
41
|
+
);
|
|
42
|
+
if (used + span > trackCount && row.length > 0) closeRow();
|
|
43
|
+
row.push({ item, span });
|
|
44
|
+
used += span;
|
|
45
|
+
}
|
|
46
|
+
closeRow();
|
|
47
|
+
return spans;
|
|
48
|
+
}
|
|
49
|
+
|
|
6
50
|
// src/core/format.ts
|
|
7
51
|
var DEFAULT_CURRENCY = "USD";
|
|
8
52
|
function localeArgument(locale) {
|
|
@@ -902,6 +946,8 @@ function WidgetCard({
|
|
|
902
946
|
onRetry,
|
|
903
947
|
footer,
|
|
904
948
|
size,
|
|
949
|
+
fill,
|
|
950
|
+
columnSpan,
|
|
905
951
|
headingLevel = 2,
|
|
906
952
|
className,
|
|
907
953
|
children
|
|
@@ -947,8 +993,11 @@ function WidgetCard({
|
|
|
947
993
|
`dwt-card--${status}`,
|
|
948
994
|
minimized && "dwt-card--minimized",
|
|
949
995
|
size !== void 0 && `dwt-card--size-${size}`,
|
|
996
|
+
fillsHeight(fill) && "dwt-card--fill-height",
|
|
997
|
+
fillsWidth(fill) && "dwt-card--fill-width",
|
|
950
998
|
className
|
|
951
999
|
),
|
|
1000
|
+
...columnSpan === void 0 ? {} : { style: { gridColumn: `span ${columnSpan}` } },
|
|
952
1001
|
children: [
|
|
953
1002
|
/* @__PURE__ */ jsxs("header", { className: slot("cardHeader", "dwt-card-header"), children: [
|
|
954
1003
|
/* @__PURE__ */ jsxs("div", { className: "dwt-card-heading", children: [
|
|
@@ -1012,6 +1061,7 @@ function ResolvedWidgetCard({
|
|
|
1012
1061
|
status: widget.status,
|
|
1013
1062
|
...definition.description === void 0 ? {} : { description: definition.description },
|
|
1014
1063
|
...definition.defaultSize === void 0 ? {} : { size: definition.defaultSize },
|
|
1064
|
+
...definition.fill === void 0 ? {} : { fill: definition.fill },
|
|
1015
1065
|
...widget.status === "empty" ? { emptyText: widget.emptyText } : {},
|
|
1016
1066
|
...widget.status === "error" ? { error: widget.error } : {},
|
|
1017
1067
|
children: widget.status === "ok" ? /* @__PURE__ */ jsx(WidgetContent, { data: widget.data }) : null
|
|
@@ -1105,6 +1155,41 @@ function restoreWidget(layout, key) {
|
|
|
1105
1155
|
function toggleMinimized(layout, key) {
|
|
1106
1156
|
return isMinimized(layout, key) ? restoreWidget(layout, key) : minimizeWidget(layout, key);
|
|
1107
1157
|
}
|
|
1158
|
+
var NARROW_VIEWPORT_QUERY = "(max-width: 640px)";
|
|
1159
|
+
function useFillSpans(definitions, gridRef) {
|
|
1160
|
+
const [metrics, setMetrics] = useState(void 0);
|
|
1161
|
+
const needsSpans = definitions.some(
|
|
1162
|
+
(definition) => fillsWidth(definition.fill)
|
|
1163
|
+
);
|
|
1164
|
+
useEffect(() => {
|
|
1165
|
+
const grid = gridRef.current;
|
|
1166
|
+
if (!needsSpans || grid === null || typeof ResizeObserver === "undefined") {
|
|
1167
|
+
setMetrics(void 0);
|
|
1168
|
+
return void 0;
|
|
1169
|
+
}
|
|
1170
|
+
function measure() {
|
|
1171
|
+
if (grid === null) return;
|
|
1172
|
+
const tracks = getComputedStyle(grid).gridTemplateColumns;
|
|
1173
|
+
const columns = tracks === "" || tracks === "none" ? 0 : tracks.trim().split(/\s+/).length;
|
|
1174
|
+
const largeSpan = window.matchMedia(NARROW_VIEWPORT_QUERY).matches ? 1 : 2;
|
|
1175
|
+
setMetrics(
|
|
1176
|
+
(previous) => columns === 0 ? void 0 : previous?.columns === columns && previous.largeSpan === largeSpan ? previous : { columns, largeSpan }
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
measure();
|
|
1180
|
+
const observer = new ResizeObserver(measure);
|
|
1181
|
+
observer.observe(grid);
|
|
1182
|
+
return () => observer.disconnect();
|
|
1183
|
+
}, [needsSpans, gridRef]);
|
|
1184
|
+
return useMemo(
|
|
1185
|
+
() => metrics === void 0 ? /* @__PURE__ */ new Map() : fillColumnSpans(definitions, metrics.columns, metrics.largeSpan),
|
|
1186
|
+
[definitions, metrics]
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
function spanProps(spans, key) {
|
|
1190
|
+
const columnSpan = spans.get(key);
|
|
1191
|
+
return columnSpan === void 0 ? {} : { columnSpan };
|
|
1192
|
+
}
|
|
1108
1193
|
function WidgetGrid({
|
|
1109
1194
|
widgets,
|
|
1110
1195
|
onRetry,
|
|
@@ -1112,10 +1197,14 @@ function WidgetGrid({
|
|
|
1112
1197
|
className
|
|
1113
1198
|
}) {
|
|
1114
1199
|
const slot = useSlotClassName();
|
|
1115
|
-
|
|
1200
|
+
const gridRef = useRef(null);
|
|
1201
|
+
const definitions = widgets.map((w) => w.definition);
|
|
1202
|
+
const spans = useFillSpans(definitions, gridRef);
|
|
1203
|
+
return /* @__PURE__ */ jsx("div", { ref: gridRef, className: slot("grid", "dwt-grid", className), children: widgets.map((widget) => /* @__PURE__ */ jsx(
|
|
1116
1204
|
ResolvedWidgetCard,
|
|
1117
1205
|
{
|
|
1118
1206
|
widget,
|
|
1207
|
+
...spanProps(spans, widget.definition.key),
|
|
1119
1208
|
...headingLevel === void 0 ? {} : { headingLevel },
|
|
1120
1209
|
...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(widget.definition.key) }
|
|
1121
1210
|
},
|
|
@@ -1139,6 +1228,8 @@ function DashboardInner({
|
|
|
1139
1228
|
const visible = visibleWidgets(definitions, layout);
|
|
1140
1229
|
const hidden = hiddenWidgets(definitions, layout);
|
|
1141
1230
|
const editable = onLayoutChange !== void 0;
|
|
1231
|
+
const gridRef = useRef(null);
|
|
1232
|
+
const spans = useFillSpans(visible, gridRef);
|
|
1142
1233
|
function change(next) {
|
|
1143
1234
|
if (next !== layout) onLayoutChange?.(next);
|
|
1144
1235
|
}
|
|
@@ -1160,7 +1251,7 @@ function DashboardInner({
|
|
|
1160
1251
|
definition.key
|
|
1161
1252
|
))
|
|
1162
1253
|
] }),
|
|
1163
|
-
visible.length === 0 ? /* @__PURE__ */ jsx("p", { className: slot("empty", "dwt-empty", "dwt-dashboard-empty"), children: definitions.length === 0 ? labels.noWidgets : labels.allHidden }) : /* @__PURE__ */ jsx("div", { className: slot("grid", "dwt-grid"), children: visible.map((definition, index) => {
|
|
1254
|
+
visible.length === 0 ? /* @__PURE__ */ jsx("p", { className: slot("empty", "dwt-empty", "dwt-dashboard-empty"), children: definitions.length === 0 ? labels.noWidgets : labels.allHidden }) : /* @__PURE__ */ jsx("div", { ref: gridRef, className: slot("grid", "dwt-grid"), children: visible.map((definition, index) => {
|
|
1164
1255
|
const widget = byKey.get(
|
|
1165
1256
|
definition.key
|
|
1166
1257
|
);
|
|
@@ -1208,6 +1299,7 @@ function DashboardInner({
|
|
|
1208
1299
|
ResolvedWidgetCard,
|
|
1209
1300
|
{
|
|
1210
1301
|
widget,
|
|
1302
|
+
...spanProps(spans, key),
|
|
1211
1303
|
minimized: isMinimized(layout, key),
|
|
1212
1304
|
...actions === void 0 ? {} : { actions },
|
|
1213
1305
|
...editable ? {
|