@richardmcquiston01/dashboard-widgets-toolkit 0.1.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.
@@ -0,0 +1,550 @@
1
+ /*
2
+ * @richardmcquiston01/dashboard-widgets-toolkit: optional styles.
3
+ *
4
+ * Everything is driven by --dwt-* custom properties, set at zero
5
+ * specificity with :where(), so an app overrides any of them (or any
6
+ * .dwt-* rule) without !important. Dark mode follows the OS setting unless
7
+ * the page sets data-theme="light"; data-theme="dark" or a "dark" class on
8
+ * <html> forces it.
9
+ *
10
+ * Chart colours are the dataviz reference palette: eight categorical slots
11
+ * validated for colour-vision deficiency, each stepped separately for the
12
+ * dark surface (not an automatic flip).
13
+ */
14
+
15
+ :where(.dwt-dashboard, .dwt-card) {
16
+ color-scheme: light;
17
+ --dwt-font: system-ui, -apple-system, 'Segoe UI', sans-serif;
18
+ --dwt-surface: #fcfcfb;
19
+ --dwt-page: #f9f9f7;
20
+ --dwt-text: #0b0b0b;
21
+ --dwt-text-secondary: #52514e;
22
+ --dwt-text-muted: #6b6a66;
23
+ --dwt-border: rgba(11, 11, 11, 0.1);
24
+ --dwt-grid: #e1e0d9;
25
+ --dwt-baseline: #c3c2b7;
26
+ --dwt-crosshair: #898781;
27
+ --dwt-link: #1c5cab;
28
+ --dwt-good: #006300;
29
+ --dwt-bad: #d03b3b;
30
+ --dwt-meter-track: #cde2fb;
31
+ --dwt-bar-track: #f0efec;
32
+ --dwt-button-hover: rgba(11, 11, 11, 0.06);
33
+ --dwt-focus: #2a78d6;
34
+ --dwt-series-1: #2a78d6;
35
+ --dwt-series-2: #eb6834;
36
+ --dwt-series-3: #1baf7a;
37
+ --dwt-series-4: #eda100;
38
+ --dwt-series-5: #e87ba4;
39
+ --dwt-series-6: #008300;
40
+ --dwt-series-7: #4a3aa7;
41
+ --dwt-series-8: #e34948;
42
+ --dwt-radius: 8px;
43
+ --dwt-gap: 16px;
44
+ --dwt-padding: 16px;
45
+ --dwt-min-column: 280px;
46
+ }
47
+
48
+ @media (prefers-color-scheme: dark) {
49
+ :root:where(:not([data-theme='light'])) :where(.dwt-dashboard, .dwt-card) {
50
+ color-scheme: dark;
51
+ --dwt-surface: #1a1a19;
52
+ --dwt-page: #0d0d0d;
53
+ --dwt-text: #ffffff;
54
+ --dwt-text-secondary: #c3c2b7;
55
+ --dwt-text-muted: #a3a29b;
56
+ --dwt-border: rgba(255, 255, 255, 0.1);
57
+ --dwt-grid: #2c2c2a;
58
+ --dwt-baseline: #383835;
59
+ --dwt-crosshair: #898781;
60
+ --dwt-link: #86b6ef;
61
+ --dwt-good: #0ca30c;
62
+ --dwt-bad: #e66767;
63
+ --dwt-meter-track: #104281;
64
+ --dwt-bar-track: #383835;
65
+ --dwt-button-hover: rgba(255, 255, 255, 0.08);
66
+ --dwt-focus: #3987e5;
67
+ --dwt-series-1: #3987e5;
68
+ --dwt-series-2: #d95926;
69
+ --dwt-series-3: #199e70;
70
+ --dwt-series-4: #c98500;
71
+ --dwt-series-5: #d55181;
72
+ --dwt-series-6: #008300;
73
+ --dwt-series-7: #9085e9;
74
+ --dwt-series-8: #e66767;
75
+ }
76
+ }
77
+
78
+ :root:where([data-theme='dark'], .dark) :where(.dwt-dashboard, .dwt-card) {
79
+ color-scheme: dark;
80
+ --dwt-surface: #1a1a19;
81
+ --dwt-page: #0d0d0d;
82
+ --dwt-text: #ffffff;
83
+ --dwt-text-secondary: #c3c2b7;
84
+ --dwt-text-muted: #a3a29b;
85
+ --dwt-border: rgba(255, 255, 255, 0.1);
86
+ --dwt-grid: #2c2c2a;
87
+ --dwt-baseline: #383835;
88
+ --dwt-crosshair: #898781;
89
+ --dwt-link: #86b6ef;
90
+ --dwt-good: #0ca30c;
91
+ --dwt-bad: #e66767;
92
+ --dwt-meter-track: #104281;
93
+ --dwt-bar-track: #383835;
94
+ --dwt-button-hover: rgba(255, 255, 255, 0.08);
95
+ --dwt-focus: #3987e5;
96
+ --dwt-series-1: #3987e5;
97
+ --dwt-series-2: #d95926;
98
+ --dwt-series-3: #199e70;
99
+ --dwt-series-4: #c98500;
100
+ --dwt-series-5: #d55181;
101
+ --dwt-series-6: #008300;
102
+ --dwt-series-7: #9085e9;
103
+ --dwt-series-8: #e66767;
104
+ }
105
+
106
+ /* Layout ---------------------------------------------------------------- */
107
+
108
+ :where(.dwt-dashboard) {
109
+ font-family: var(--dwt-font);
110
+ color: var(--dwt-text);
111
+ }
112
+
113
+ :where(.dwt-grid) {
114
+ display: grid;
115
+ gap: var(--dwt-gap);
116
+ grid-template-columns: repeat(
117
+ auto-fill,
118
+ minmax(min(100%, var(--dwt-min-column)), 1fr)
119
+ );
120
+ align-items: start;
121
+ }
122
+
123
+ :where(.dwt-card--size-large) {
124
+ grid-column: span 2;
125
+ }
126
+
127
+ :where(.dwt-card--size-full) {
128
+ grid-column: 1 / -1;
129
+ }
130
+
131
+ @media (max-width: 640px) {
132
+ :where(.dwt-card--size-large) {
133
+ grid-column: auto;
134
+ }
135
+ }
136
+
137
+ :where(.dwt-hidden-bar) {
138
+ display: flex;
139
+ flex-wrap: wrap;
140
+ align-items: center;
141
+ gap: 8px;
142
+ margin-bottom: 12px;
143
+ font-size: 0.875rem;
144
+ }
145
+
146
+ :where(.dwt-hidden-label) {
147
+ color: var(--dwt-text-secondary);
148
+ }
149
+
150
+ /* Card ------------------------------------------------------------------ */
151
+
152
+ :where(.dwt-card) {
153
+ display: flex;
154
+ flex-direction: column;
155
+ min-width: 0;
156
+ padding: var(--dwt-padding);
157
+ background: var(--dwt-surface);
158
+ color: var(--dwt-text);
159
+ border: 1px solid var(--dwt-border);
160
+ border-radius: var(--dwt-radius);
161
+ font-family: var(--dwt-font);
162
+ }
163
+
164
+ :where(.dwt-card-header) {
165
+ display: flex;
166
+ align-items: flex-start;
167
+ justify-content: space-between;
168
+ gap: 8px;
169
+ }
170
+
171
+ :where(.dwt-card-heading) {
172
+ min-width: 0;
173
+ }
174
+
175
+ :where(.dwt-card-title) {
176
+ margin: 0;
177
+ font-size: 0.875rem;
178
+ font-weight: 600;
179
+ line-height: 1.4;
180
+ }
181
+
182
+ :where(.dwt-card-description) {
183
+ margin: 2px 0 0;
184
+ color: var(--dwt-text-secondary);
185
+ font-size: 0.75rem;
186
+ }
187
+
188
+ :where(.dwt-card-actions) {
189
+ display: flex;
190
+ flex-shrink: 0;
191
+ gap: 2px;
192
+ }
193
+
194
+ :where(.dwt-card-body) {
195
+ flex: 1;
196
+ margin-top: 12px;
197
+ font-size: 0.875rem;
198
+ }
199
+
200
+ :where(.dwt-card--minimized .dwt-card-body) {
201
+ display: none;
202
+ }
203
+
204
+ :where(.dwt-card-footer) {
205
+ margin-top: 12px;
206
+ }
207
+
208
+ :where(.dwt-button) {
209
+ font: inherit;
210
+ font-size: 0.8125rem;
211
+ color: inherit;
212
+ background: transparent;
213
+ border: 1px solid var(--dwt-border);
214
+ border-radius: 6px;
215
+ padding: 2px 8px;
216
+ cursor: pointer;
217
+ }
218
+
219
+ :where(.dwt-button:hover:not(:disabled)) {
220
+ background: var(--dwt-button-hover);
221
+ }
222
+
223
+ :where(.dwt-button:disabled) {
224
+ opacity: 0.4;
225
+ cursor: default;
226
+ }
227
+
228
+ :where(.dwt-icon-button) {
229
+ border-color: transparent;
230
+ min-width: 28px;
231
+ min-height: 28px;
232
+ padding: 2px 6px;
233
+ }
234
+
235
+ :where(
236
+ .dwt-button:focus-visible,
237
+ .dwt-chart-svg:focus-visible,
238
+ .dwt-link:focus-visible,
239
+ .dwt-table-twin summary:focus-visible
240
+ ) {
241
+ outline: 2px solid var(--dwt-focus);
242
+ outline-offset: 2px;
243
+ }
244
+
245
+ :where(.dwt-status, .dwt-empty, .dwt-note) {
246
+ margin: 0;
247
+ color: var(--dwt-text-secondary);
248
+ }
249
+
250
+ :where(.dwt-note) {
251
+ margin-top: 8px;
252
+ font-size: 0.75rem;
253
+ }
254
+
255
+ :where(.dwt-error) {
256
+ display: flex;
257
+ align-items: center;
258
+ justify-content: space-between;
259
+ gap: 8px;
260
+ }
261
+
262
+ :where(.dwt-error-message) {
263
+ margin: 0;
264
+ color: var(--dwt-text-secondary);
265
+ }
266
+
267
+ :where(.dwt-link, .dwt-alert-title:is(a)) {
268
+ color: var(--dwt-link);
269
+ text-decoration: none;
270
+ }
271
+
272
+ :where(.dwt-link:hover, a.dwt-alert-title:hover) {
273
+ text-decoration: underline;
274
+ }
275
+
276
+ /* Figures (TEXT, KPI, GAUGE) --------------------------------------------- */
277
+
278
+ :where(.dwt-figure) {
279
+ margin: 0;
280
+ font-size: 1.75rem;
281
+ font-weight: 600;
282
+ line-height: 1.2;
283
+ }
284
+
285
+ :where(.dwt-figure-label) {
286
+ margin: 0;
287
+ color: var(--dwt-text-secondary);
288
+ font-size: 0.8125rem;
289
+ }
290
+
291
+ :where(.dwt-kpi-meta) {
292
+ display: flex;
293
+ flex-wrap: wrap;
294
+ gap: 4px 8px;
295
+ margin: 4px 0 0;
296
+ font-size: 0.75rem;
297
+ }
298
+
299
+ :where(.dwt-delta) {
300
+ font-weight: 600;
301
+ color: var(--dwt-text-secondary);
302
+ }
303
+
304
+ :where(.dwt-delta--good) {
305
+ color: var(--dwt-good);
306
+ }
307
+
308
+ :where(.dwt-delta--bad) {
309
+ color: var(--dwt-bad);
310
+ }
311
+
312
+ :where(.dwt-delta-arrow) {
313
+ font-size: 0.625rem;
314
+ }
315
+
316
+ :where(.dwt-delta-comparison, .dwt-hint) {
317
+ font-weight: 400;
318
+ color: var(--dwt-text-secondary);
319
+ }
320
+
321
+ :where(.dwt-meter) {
322
+ height: 12px;
323
+ border-radius: 999px;
324
+ overflow: hidden;
325
+ }
326
+
327
+ :where(.dwt-meter-fill) {
328
+ height: 100%;
329
+ border-radius: 999px;
330
+ }
331
+
332
+ :where(.dwt-gauge-caption) {
333
+ margin: 8px 0 0;
334
+ }
335
+
336
+ :where(.dwt-gauge-value) {
337
+ font-weight: 600;
338
+ }
339
+
340
+ /* Tables ---------------------------------------------------------------- */
341
+
342
+ :where(.dwt-table-wrap) {
343
+ overflow-x: auto;
344
+ }
345
+
346
+ :where(.dwt-table) {
347
+ width: 100%;
348
+ border-collapse: collapse;
349
+ font-size: 0.8125rem;
350
+ }
351
+
352
+ :where(.dwt-table th, .dwt-table td) {
353
+ padding: 4px 8px 4px 0;
354
+ text-align: left;
355
+ border-bottom: 1px solid var(--dwt-grid);
356
+ }
357
+
358
+ :where(.dwt-table thead th) {
359
+ color: var(--dwt-text-secondary);
360
+ font-weight: 600;
361
+ }
362
+
363
+ :where(.dwt-table tbody th) {
364
+ font-weight: 400;
365
+ }
366
+
367
+ :where(.dwt-table .dwt-numeric) {
368
+ text-align: right;
369
+ font-variant-numeric: tabular-nums;
370
+ }
371
+
372
+ /* Lists ----------------------------------------------------------------- */
373
+
374
+ :where(.dwt-bar-list, .dwt-alert-list, .dwt-legend, .dwt-tooltip-rows) {
375
+ list-style: none;
376
+ margin: 0;
377
+ padding: 0;
378
+ }
379
+
380
+ :where(.dwt-bar-row) {
381
+ display: grid;
382
+ grid-template-columns: minmax(0, 1fr) auto;
383
+ gap: 2px 8px;
384
+ margin-bottom: 8px;
385
+ }
386
+
387
+ :where(.dwt-bar-label) {
388
+ overflow: hidden;
389
+ text-overflow: ellipsis;
390
+ white-space: nowrap;
391
+ }
392
+
393
+ :where(.dwt-bar-value) {
394
+ color: var(--dwt-text-secondary);
395
+ font-size: 0.75rem;
396
+ font-variant-numeric: tabular-nums;
397
+ white-space: nowrap;
398
+ }
399
+
400
+ :where(.dwt-bar-track) {
401
+ grid-column: 1 / -1;
402
+ display: block;
403
+ height: 8px;
404
+ border-radius: 999px;
405
+ overflow: hidden;
406
+ }
407
+
408
+ :where(.dwt-bar-fill) {
409
+ display: block;
410
+ height: 100%;
411
+ border-radius: 999px;
412
+ }
413
+
414
+ :where(.dwt-alert-row) {
415
+ display: flex;
416
+ align-items: center;
417
+ gap: 12px;
418
+ padding: 8px 0;
419
+ border-top: 1px solid var(--dwt-grid);
420
+ }
421
+
422
+ :where(.dwt-alert-row:first-child) {
423
+ border-top: 0;
424
+ }
425
+
426
+ :where(.dwt-thumbnail) {
427
+ flex-shrink: 0;
428
+ width: 36px;
429
+ height: 36px;
430
+ border-radius: 4px;
431
+ object-fit: cover;
432
+ background: var(--dwt-bar-track);
433
+ }
434
+
435
+ :where(.dwt-alert-main) {
436
+ display: flex;
437
+ flex: 1;
438
+ flex-direction: column;
439
+ min-width: 0;
440
+ }
441
+
442
+ :where(.dwt-alert-title) {
443
+ overflow: hidden;
444
+ text-overflow: ellipsis;
445
+ white-space: nowrap;
446
+ font-weight: 500;
447
+ }
448
+
449
+ :where(.dwt-alert-detail) {
450
+ color: var(--dwt-text-secondary);
451
+ font-size: 0.75rem;
452
+ }
453
+
454
+ :where(.dwt-alert-value) {
455
+ flex-shrink: 0;
456
+ color: var(--dwt-text-secondary);
457
+ font-size: 0.75rem;
458
+ white-space: nowrap;
459
+ }
460
+
461
+ /* Charts ---------------------------------------------------------------- */
462
+
463
+ :where(.dwt-chart) {
464
+ margin: 0;
465
+ }
466
+
467
+ :where(.dwt-legend) {
468
+ display: flex;
469
+ flex-wrap: wrap;
470
+ gap: 4px 12px;
471
+ margin-bottom: 8px;
472
+ font-size: 0.75rem;
473
+ color: var(--dwt-text-secondary);
474
+ }
475
+
476
+ :where(.dwt-legend-item) {
477
+ display: inline-flex;
478
+ align-items: center;
479
+ gap: 4px;
480
+ }
481
+
482
+ :where(.dwt-chart-frame) {
483
+ position: relative;
484
+ }
485
+
486
+ :where(.dwt-chart-svg) {
487
+ display: block;
488
+ width: 100%;
489
+ height: auto;
490
+ overflow: visible;
491
+ font-family: var(--dwt-font);
492
+ }
493
+
494
+ :where(.dwt-axis-label) {
495
+ font-variant-numeric: tabular-nums;
496
+ }
497
+
498
+ :where(.dwt-tooltip) {
499
+ position: absolute;
500
+ top: 0;
501
+ transform: translateX(-50%);
502
+ pointer-events: none;
503
+ padding: 4px 8px;
504
+ background: var(--dwt-surface);
505
+ border: 1px solid var(--dwt-border);
506
+ border-radius: 6px;
507
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
508
+ font-size: 0.75rem;
509
+ white-space: nowrap;
510
+ }
511
+
512
+ :where(.dwt-tooltip-label) {
513
+ margin: 0 0 2px;
514
+ color: var(--dwt-text-secondary);
515
+ }
516
+
517
+ :where(.dwt-tooltip-row) {
518
+ display: flex;
519
+ align-items: center;
520
+ gap: 6px;
521
+ }
522
+
523
+ :where(.dwt-tooltip-value) {
524
+ color: var(--dwt-text);
525
+ font-variant-numeric: tabular-nums;
526
+ }
527
+
528
+ :where(.dwt-tooltip-series) {
529
+ color: var(--dwt-text-secondary);
530
+ }
531
+
532
+ :where(.dwt-table-twin) {
533
+ margin-top: 8px;
534
+ }
535
+
536
+ :where(.dwt-table-twin summary) {
537
+ cursor: pointer;
538
+ color: var(--dwt-text-secondary);
539
+ font-size: 0.75rem;
540
+ }
541
+
542
+ :where(.dwt-table-twin .dwt-table) {
543
+ margin-top: 8px;
544
+ }
545
+
546
+ @media (forced-colors: active) {
547
+ :where(.dwt-meter, .dwt-bar-track) {
548
+ border: 1px solid CanvasText;
549
+ }
550
+ }
package/package.json ADDED
@@ -0,0 +1,121 @@
1
+ {
2
+ "name": "@richardmcquiston01/dashboard-widgets-toolkit",
3
+ "version": "0.1.0",
4
+ "description": "Framework-agnostic dashboard widget toolkit: typed widget definitions and data payloads (KPI, gauge, table, bar list, alert list, chart), user layout (order, hide, minimise), and React renderers. Bring your own data providers.",
5
+ "keywords": [
6
+ "dashboard",
7
+ "widgets",
8
+ "kpi",
9
+ "gauge",
10
+ "chart",
11
+ "svg",
12
+ "layout",
13
+ "react",
14
+ "typescript",
15
+ "accessibility"
16
+ ],
17
+ "license": "Apache-2.0",
18
+ "author": "Richard McQuiston (https://richardmcquiston.com/)",
19
+ "homepage": "https://github.com/RichardMcQuiston01/dashboard-widgets-toolkit#readme",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/RichardMcQuiston01/dashboard-widgets-toolkit.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/RichardMcQuiston01/dashboard-widgets-toolkit/issues"
26
+ },
27
+ "type": "module",
28
+ "sideEffects": [
29
+ "*.css"
30
+ ],
31
+ "main": "./dist/index.cjs",
32
+ "module": "./dist/index.js",
33
+ "types": "./dist/index.d.ts",
34
+ "typesVersions": {
35
+ "*": {
36
+ "core": [
37
+ "./dist/core.d.cts"
38
+ ],
39
+ "react": [
40
+ "./dist/react.d.cts"
41
+ ]
42
+ }
43
+ },
44
+ "exports": {
45
+ ".": {
46
+ "import": {
47
+ "types": "./dist/index.d.ts",
48
+ "default": "./dist/index.js"
49
+ },
50
+ "require": {
51
+ "types": "./dist/index.d.cts",
52
+ "default": "./dist/index.cjs"
53
+ }
54
+ },
55
+ "./core": {
56
+ "import": {
57
+ "types": "./dist/core.d.ts",
58
+ "default": "./dist/core.js"
59
+ },
60
+ "require": {
61
+ "types": "./dist/core.d.cts",
62
+ "default": "./dist/core.cjs"
63
+ }
64
+ },
65
+ "./react": {
66
+ "import": {
67
+ "types": "./dist/react.d.ts",
68
+ "default": "./dist/react.js"
69
+ },
70
+ "require": {
71
+ "types": "./dist/react.d.cts",
72
+ "default": "./dist/react.cjs"
73
+ }
74
+ },
75
+ "./styles.css": "./dist/styles.css",
76
+ "./package.json": "./package.json"
77
+ },
78
+ "files": [
79
+ "dist"
80
+ ],
81
+ "engines": {
82
+ "node": ">=18",
83
+ "bun": ">=1.3"
84
+ },
85
+ "publishConfig": {
86
+ "access": "public"
87
+ },
88
+ "scripts": {
89
+ "build": "tsup",
90
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.react.json --noEmit && tsc -p tsconfig.test.json --noEmit",
91
+ "test": "bun test test",
92
+ "lint": "eslint .",
93
+ "format": "prettier --write .",
94
+ "format:check": "prettier --check .",
95
+ "changeset": "changeset",
96
+ "version-packages": "changeset version"
97
+ },
98
+ "peerDependencies": {
99
+ "react": ">=18"
100
+ },
101
+ "peerDependenciesMeta": {
102
+ "react": {
103
+ "optional": true
104
+ }
105
+ },
106
+ "devDependencies": {
107
+ "@changesets/cli": "^3.0.3",
108
+ "@eslint/js": "^10.0.1",
109
+ "@types/node": "^22.20.5",
110
+ "@types/react": "^19.3.0",
111
+ "@types/react-dom": "^19.3.0",
112
+ "eslint": "^10.12.0",
113
+ "globals": "^17.13.0",
114
+ "prettier": "^3.9.9",
115
+ "react": "^19.3.0",
116
+ "react-dom": "^19.3.0",
117
+ "tsup": "^8.5.1",
118
+ "typescript": "~6.0.2",
119
+ "typescript-eslint": "^8.71.1"
120
+ }
121
+ }