@richardmcquiston01/dashboard-widgets-toolkit 0.8.0 → 0.9.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.js CHANGED
@@ -522,6 +522,19 @@ var DEFAULT_LABELS = {
522
522
  moveLater: (title) => `Move ${title} later`,
523
523
  hiddenWidgets: "Hidden:",
524
524
  minimizedWidgets: "Minimized:",
525
+ customize: "Customize",
526
+ done: "Done",
527
+ reset: "Reset layout",
528
+ revertChanges: "Revert changes",
529
+ confirmReset: "Reset the layout to the default?",
530
+ confirmRevert: "Revert to how this looked before you started editing?",
531
+ confirmYes: "Yes",
532
+ confirmNo: "No",
533
+ editingOn: "Editing dashboard. Use the buttons on each card to reorder or hide it.",
534
+ editingOff: "Finished editing.",
535
+ dashboardControls: "Dashboard controls",
536
+ locked: (title) => `${title} is locked`,
537
+ lockedForViewers: (title) => `${title} is locked for viewers`,
525
538
  opensInNewTab: "(opens in a new tab)",
526
539
  view: (title) => `View ${title}`,
527
540
  close: "Close",
@@ -1392,6 +1405,7 @@ function WidgetCard({
1392
1405
  columnSpan,
1393
1406
  width,
1394
1407
  widgetKey,
1408
+ editing = false,
1395
1409
  headingLevel = 2,
1396
1410
  className,
1397
1411
  children
@@ -1436,6 +1450,7 @@ function WidgetCard({
1436
1450
  "dwt-card",
1437
1451
  `dwt-card--${status}`,
1438
1452
  minimized && "dwt-card--minimized",
1453
+ editing && "dwt-card--editing",
1439
1454
  size !== void 0 && `dwt-card--size-${size}`,
1440
1455
  fillsHeight(fill) && "dwt-card--fill-height",
1441
1456
  fillsWidth(fill) && "dwt-card--fill-width",
@@ -2137,6 +2152,57 @@ function DetailHost({
2137
2152
  }
2138
2153
  ) });
2139
2154
  }
2155
+ function InlineConfirm({
2156
+ message,
2157
+ onAnswer
2158
+ }) {
2159
+ const slot = useSlotClassName();
2160
+ const { labels } = useWidgetSettings();
2161
+ const noRef = useRef(null);
2162
+ useEffect(() => {
2163
+ noRef.current?.focus();
2164
+ }, []);
2165
+ return /* @__PURE__ */ jsxs(
2166
+ "span",
2167
+ {
2168
+ role: "group",
2169
+ "aria-label": message,
2170
+ className: "dwt-confirm",
2171
+ onKeyDown: (event) => {
2172
+ if (event.key === "Escape") {
2173
+ event.stopPropagation();
2174
+ onAnswer(false);
2175
+ }
2176
+ },
2177
+ children: [
2178
+ /* @__PURE__ */ jsx("span", { role: "alert", className: "dwt-confirm-message", children: message }),
2179
+ /* @__PURE__ */ jsx(
2180
+ "button",
2181
+ {
2182
+ type: "button",
2183
+ className: slot("button", "dwt-button", "dwt-icon-button"),
2184
+ "aria-label": labels.confirmYes,
2185
+ title: labels.confirmYes,
2186
+ onClick: () => onAnswer(true),
2187
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2713" })
2188
+ }
2189
+ ),
2190
+ /* @__PURE__ */ jsx(
2191
+ "button",
2192
+ {
2193
+ ref: noRef,
2194
+ type: "button",
2195
+ className: slot("button", "dwt-button", "dwt-icon-button"),
2196
+ "aria-label": labels.confirmNo,
2197
+ title: labels.confirmNo,
2198
+ onClick: () => onAnswer(false),
2199
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2715" })
2200
+ }
2201
+ )
2202
+ ]
2203
+ }
2204
+ );
2205
+ }
2140
2206
  function withoutLock(definition) {
2141
2207
  if (definition.locked === void 0) return definition;
2142
2208
  const copy = { ...definition };
@@ -2148,6 +2214,12 @@ function DashboardInner({
2148
2214
  layout: savedLayout = EMPTY_LAYOUT,
2149
2215
  onLayoutChange,
2150
2216
  overrideLocks = false,
2217
+ editMode = "always",
2218
+ editing: editingProp,
2219
+ defaultEditing = false,
2220
+ onEditingChange,
2221
+ defaultLayout,
2222
+ toolbar = true,
2151
2223
  onRetry,
2152
2224
  loadDetail,
2153
2225
  onOpenDetail,
@@ -2166,6 +2238,25 @@ function DashboardInner({
2166
2238
  const visible = visibleWidgets(definitions, layout);
2167
2239
  const hidden = hiddenWidgets(definitions, layout);
2168
2240
  const editable = onLayoutChange !== void 0;
2241
+ const toggleMode = editMode === "toggle";
2242
+ const [editingState, setEditingState] = useState(defaultEditing);
2243
+ const editing = editingProp ?? editingState;
2244
+ const controlsShown = editable && (!toggleMode || editing);
2245
+ const [snapshot, setSnapshot] = useState(
2246
+ void 0
2247
+ );
2248
+ if (toggleMode && editable && editing) {
2249
+ if (snapshot === void 0) setSnapshot(savedLayout);
2250
+ } else if (snapshot !== void 0) {
2251
+ setSnapshot(void 0);
2252
+ }
2253
+ const [confirming, setConfirming] = useState(
2254
+ void 0
2255
+ );
2256
+ const pending = editing ? confirming : void 0;
2257
+ const [announcement, setAnnouncement] = useState("");
2258
+ const toggleRef = useRef(null);
2259
+ const resetRef = useRef(null);
2169
2260
  const minimized = editable ? visible.filter((definition) => isMinimized(layout, definition.key)) : [];
2170
2261
  const shown = editable ? visible.filter((definition) => !isMinimized(layout, definition.key)) : visible;
2171
2262
  const [detailKey, setDetailKey] = useState(void 0);
@@ -2179,142 +2270,267 @@ function DashboardInner({
2179
2270
  function change(next) {
2180
2271
  if (next !== layout) onLayoutChange?.(next);
2181
2272
  }
2182
- return /* @__PURE__ */ jsxs("div", { className: slot("dashboard", "dwt-dashboard", className), children: [
2183
- editable && hidden.length > 0 && /* @__PURE__ */ jsxs("div", { className: slot("hiddenBar", "dwt-hidden-bar"), children: [
2184
- /* @__PURE__ */ jsx("span", { className: "dwt-hidden-label", children: labels.hiddenWidgets }),
2185
- hidden.map((definition) => /* @__PURE__ */ jsxs(
2186
- "button",
2187
- {
2188
- type: "button",
2189
- className: slot("button", "dwt-button", "dwt-show-button"),
2190
- "aria-label": labels.show(definition.title),
2191
- onClick: () => change(showWidget(layout, definition.key)),
2192
- children: [
2193
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "+ " }),
2194
- definition.title
2195
- ]
2196
- },
2197
- definition.key
2198
- ))
2199
- ] }),
2200
- minimized.length > 0 && /* @__PURE__ */ jsxs(
2201
- "div",
2202
- {
2203
- className: slot("hiddenBar", "dwt-hidden-bar", "dwt-minimized-bar"),
2204
- children: [
2205
- /* @__PURE__ */ jsx("span", { className: "dwt-hidden-label", children: labels.minimizedWidgets }),
2206
- minimized.map((definition) => /* @__PURE__ */ jsxs(
2273
+ function setEditing(next) {
2274
+ if (editingProp === void 0) setEditingState(next);
2275
+ onEditingChange?.(next);
2276
+ setAnnouncement(next ? labels.editingOn : labels.editingOff);
2277
+ setConfirming(void 0);
2278
+ }
2279
+ function answerConfirmation(yes) {
2280
+ const which = pending;
2281
+ setConfirming(void 0);
2282
+ if (yes && which === "reset") {
2283
+ change(enforceLocks(definitions, defaultLayout ?? EMPTY_LAYOUT));
2284
+ } else if (yes && which === "revert" && snapshot !== void 0) {
2285
+ change(snapshot);
2286
+ }
2287
+ (which === "revert" ? toggleRef : resetRef).current?.focus();
2288
+ }
2289
+ return /* @__PURE__ */ jsxs(
2290
+ "div",
2291
+ {
2292
+ className: slot(
2293
+ "dashboard",
2294
+ "dwt-dashboard",
2295
+ toggleMode && controlsShown && "dwt-dashboard--editing",
2296
+ className
2297
+ ),
2298
+ children: [
2299
+ editable && toggleMode && toolbar && /* @__PURE__ */ jsxs(
2300
+ "div",
2301
+ {
2302
+ role: "group",
2303
+ "aria-label": labels.dashboardControls,
2304
+ className: slot("toolbar", "dwt-toolbar"),
2305
+ children: [
2306
+ /* @__PURE__ */ jsx(
2307
+ "button",
2308
+ {
2309
+ ref: toggleRef,
2310
+ type: "button",
2311
+ "aria-pressed": editing,
2312
+ className: slot("button", "dwt-button", "dwt-toolbar-toggle"),
2313
+ onClick: () => setEditing(!editing),
2314
+ children: editing ? labels.done : labels.customize
2315
+ }
2316
+ ),
2317
+ editing && /* @__PURE__ */ jsxs(Fragment, { children: [
2318
+ /* @__PURE__ */ jsx(
2319
+ "button",
2320
+ {
2321
+ ref: resetRef,
2322
+ type: "button",
2323
+ className: slot("button", "dwt-button"),
2324
+ onClick: () => setConfirming("reset"),
2325
+ children: labels.reset
2326
+ }
2327
+ ),
2328
+ /* @__PURE__ */ jsx(
2329
+ "button",
2330
+ {
2331
+ type: "button",
2332
+ className: slot("button", "dwt-button"),
2333
+ disabled: snapshot === void 0 || savedLayout === snapshot,
2334
+ onClick: () => setConfirming("revert"),
2335
+ children: labels.revertChanges
2336
+ }
2337
+ )
2338
+ ] }),
2339
+ pending !== void 0 && /* @__PURE__ */ jsx(
2340
+ InlineConfirm,
2341
+ {
2342
+ message: pending === "reset" ? labels.confirmReset : labels.confirmRevert,
2343
+ onAnswer: answerConfirmation
2344
+ }
2345
+ ),
2346
+ /* @__PURE__ */ jsx("span", { className: "dwt-visually-hidden", "aria-live": "polite", children: announcement })
2347
+ ]
2348
+ }
2349
+ ),
2350
+ controlsShown && hidden.length > 0 && /* @__PURE__ */ jsxs("div", { className: slot("hiddenBar", "dwt-hidden-bar"), children: [
2351
+ /* @__PURE__ */ jsx("span", { className: "dwt-hidden-label", children: labels.hiddenWidgets }),
2352
+ hidden.map((definition) => /* @__PURE__ */ jsxs(
2207
2353
  "button",
2208
2354
  {
2209
2355
  type: "button",
2210
2356
  className: slot("button", "dwt-button", "dwt-show-button"),
2211
- "aria-label": labels.expand(definition.title),
2212
- onClick: () => change(toggleMinimized(layout, definition.key)),
2357
+ "aria-label": labels.show(definition.title),
2358
+ onClick: () => change(showWidget(layout, definition.key)),
2213
2359
  children: [
2214
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u25B8 " }),
2360
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "+ " }),
2215
2361
  definition.title
2216
2362
  ]
2217
2363
  },
2218
2364
  definition.key
2219
2365
  ))
2220
- ]
2221
- }
2222
- ),
2223
- visible.length === 0 ? /* @__PURE__ */ jsx("p", { className: slot("empty", "dwt-empty", "dwt-dashboard-empty"), children: definitions.length === 0 ? labels.noWidgets : labels.allHidden }) : shown.length === 0 ? null : /* @__PURE__ */ jsx(
2224
- "div",
2225
- {
2226
- ref: gridRef,
2227
- className: slot("grid", "dwt-grid", twelve && "dwt-grid--twelve"),
2228
- children: shown.map((definition, index) => {
2229
- const widget = byKey.get(
2230
- definition.key
2231
- );
2232
- if (widget === void 0) return null;
2233
- const key = definition.key;
2234
- const title = definition.title;
2235
- const lock = resolveWidgetLock(definition);
2236
- const canMoveEarlier = !lock.move && moveWidgetBy(definitions, layout, key, -1) !== layout;
2237
- const canMoveLater = !lock.move && moveWidgetBy(definitions, layout, key, 1) !== layout;
2238
- const actions = editable ? /* @__PURE__ */ jsxs(Fragment, { children: [
2239
- !lock.move && /* @__PURE__ */ jsxs(Fragment, { children: [
2240
- /* @__PURE__ */ jsx(
2366
+ ] }),
2367
+ minimized.length > 0 && /* @__PURE__ */ jsxs(
2368
+ "div",
2369
+ {
2370
+ className: slot("hiddenBar", "dwt-hidden-bar", "dwt-minimized-bar"),
2371
+ children: [
2372
+ /* @__PURE__ */ jsx("span", { className: "dwt-hidden-label", children: labels.minimizedWidgets }),
2373
+ minimized.map((definition) => /* @__PURE__ */ jsxs(
2241
2374
  "button",
2242
2375
  {
2243
2376
  type: "button",
2244
- className: slot(
2377
+ className: slot("button", "dwt-button", "dwt-show-button"),
2378
+ "aria-label": labels.expand(definition.title),
2379
+ onClick: () => change(toggleMinimized(layout, definition.key)),
2380
+ children: [
2381
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u25B8 " }),
2382
+ definition.title
2383
+ ]
2384
+ },
2385
+ definition.key
2386
+ ))
2387
+ ]
2388
+ }
2389
+ ),
2390
+ visible.length === 0 ? /* @__PURE__ */ jsx("p", { className: slot("empty", "dwt-empty", "dwt-dashboard-empty"), children: definitions.length === 0 ? labels.noWidgets : labels.allHidden }) : shown.length === 0 ? null : /* @__PURE__ */ jsx(
2391
+ "div",
2392
+ {
2393
+ ref: gridRef,
2394
+ className: slot("grid", "dwt-grid", twelve && "dwt-grid--twelve"),
2395
+ children: shown.map((definition, index) => {
2396
+ const widget = byKey.get(
2397
+ definition.key
2398
+ );
2399
+ if (widget === void 0) return null;
2400
+ const key = definition.key;
2401
+ const title = definition.title;
2402
+ const lock = resolveWidgetLock(definition);
2403
+ const ownLock = resolveWidgetLock(
2404
+ widget.definition
2405
+ );
2406
+ const isLocked = ownLock.move || ownLock.hide || ownLock.minimize;
2407
+ const lockLabel = overrideLocks ? labels.lockedForViewers(title) : labels.locked(title);
2408
+ const canMoveEarlier = !lock.move && moveWidgetBy(definitions, layout, key, -1) !== layout;
2409
+ const canMoveLater = !lock.move && moveWidgetBy(definitions, layout, key, 1) !== layout;
2410
+ const actions = controlsShown ? /* @__PURE__ */ jsxs(Fragment, { children: [
2411
+ isLocked && /* @__PURE__ */ jsx(
2412
+ "span",
2413
+ {
2414
+ role: "img",
2415
+ className: "dwt-lock",
2416
+ "aria-label": lockLabel,
2417
+ title: lockLabel,
2418
+ children: /* @__PURE__ */ jsxs(
2419
+ "svg",
2420
+ {
2421
+ viewBox: "0 0 16 16",
2422
+ width: "14",
2423
+ height: "14",
2424
+ "aria-hidden": "true",
2425
+ focusable: "false",
2426
+ children: [
2427
+ /* @__PURE__ */ jsx(
2428
+ "rect",
2429
+ {
2430
+ x: "3",
2431
+ y: "7",
2432
+ width: "10",
2433
+ height: "7",
2434
+ rx: "1.5",
2435
+ fill: "currentColor"
2436
+ }
2437
+ ),
2438
+ /* @__PURE__ */ jsx(
2439
+ "path",
2440
+ {
2441
+ d: "M5.5 7V5a2.5 2.5 0 0 1 5 0v2",
2442
+ fill: "none",
2443
+ stroke: "currentColor",
2444
+ strokeWidth: "1.4"
2445
+ }
2446
+ )
2447
+ ]
2448
+ }
2449
+ )
2450
+ }
2451
+ ),
2452
+ !lock.move && /* @__PURE__ */ jsxs(Fragment, { children: [
2453
+ /* @__PURE__ */ jsx(
2245
2454
  "button",
2246
- "dwt-button",
2247
- "dwt-icon-button"
2455
+ {
2456
+ type: "button",
2457
+ className: slot(
2458
+ "button",
2459
+ "dwt-button",
2460
+ "dwt-icon-button"
2461
+ ),
2462
+ "aria-label": labels.moveEarlier(title),
2463
+ title: labels.moveEarlier(title),
2464
+ disabled: index === 0 || !canMoveEarlier,
2465
+ onClick: () => change(moveWidgetBy(definitions, layout, key, -1)),
2466
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2191" })
2467
+ }
2248
2468
  ),
2249
- "aria-label": labels.moveEarlier(title),
2250
- title: labels.moveEarlier(title),
2251
- disabled: index === 0 || !canMoveEarlier,
2252
- onClick: () => change(moveWidgetBy(definitions, layout, key, -1)),
2253
- children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2191" })
2254
- }
2255
- ),
2256
- /* @__PURE__ */ jsx(
2257
- "button",
2258
- {
2259
- type: "button",
2260
- className: slot(
2469
+ /* @__PURE__ */ jsx(
2261
2470
  "button",
2262
- "dwt-button",
2263
- "dwt-icon-button"
2264
- ),
2265
- "aria-label": labels.moveLater(title),
2266
- title: labels.moveLater(title),
2267
- disabled: index === shown.length - 1 || !canMoveLater,
2268
- onClick: () => change(moveWidgetBy(definitions, layout, key, 1)),
2269
- children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2193" })
2270
- }
2271
- )
2272
- ] }),
2273
- !lock.hide && /* @__PURE__ */ jsx(
2274
- "button",
2275
- {
2276
- type: "button",
2277
- className: slot("button", "dwt-button", "dwt-icon-button"),
2278
- "aria-label": labels.hide(title),
2279
- title: labels.hide(title),
2280
- onClick: () => change(hideWidget(layout, key)),
2281
- children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xD7" })
2282
- }
2283
- )
2284
- ] }) : void 0;
2285
- const viewable = resolveDetailOptions(definition) !== void 0 && (onOpenDetail !== void 0 || loadDetail !== void 0 || widget.status === "ok" && deriveDetailData(widget.data) !== void 0);
2286
- return /* @__PURE__ */ jsx(
2287
- ResolvedWidgetCard,
2288
- {
2289
- widget,
2290
- ...viewable ? {
2291
- onView: () => onOpenDetail === void 0 ? setDetailKey(key) : onOpenDetail(key)
2292
- } : {},
2293
- ...spanProps(spans, key),
2294
- ...widthProps(twelve, definition),
2295
- minimized: isMinimized(layout, key),
2296
- ...actions === void 0 ? {} : { actions },
2297
- ...editable && !lock.minimize ? {
2298
- onToggleMinimized: () => change(toggleMinimized(layout, key))
2299
- } : {},
2300
- ...headingLevel === void 0 ? {} : { headingLevel },
2301
- ...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(key) }
2302
- },
2303
- key
2304
- );
2305
- })
2306
- }
2307
- ),
2308
- detailKey !== void 0 && byKey.get(detailKey) !== void 0 && /* @__PURE__ */ jsx(
2309
- DetailHost,
2310
- {
2311
- widget: byKey.get(detailKey),
2312
- loadDetail,
2313
- onClose: () => setDetailKey(void 0)
2314
- },
2315
- detailKey
2316
- )
2317
- ] });
2471
+ {
2472
+ type: "button",
2473
+ className: slot(
2474
+ "button",
2475
+ "dwt-button",
2476
+ "dwt-icon-button"
2477
+ ),
2478
+ "aria-label": labels.moveLater(title),
2479
+ title: labels.moveLater(title),
2480
+ disabled: index === shown.length - 1 || !canMoveLater,
2481
+ onClick: () => change(moveWidgetBy(definitions, layout, key, 1)),
2482
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2193" })
2483
+ }
2484
+ )
2485
+ ] }),
2486
+ !lock.hide && /* @__PURE__ */ jsx(
2487
+ "button",
2488
+ {
2489
+ type: "button",
2490
+ className: slot("button", "dwt-button", "dwt-icon-button"),
2491
+ "aria-label": labels.hide(title),
2492
+ title: labels.hide(title),
2493
+ onClick: () => change(hideWidget(layout, key)),
2494
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xD7" })
2495
+ }
2496
+ )
2497
+ ] }) : void 0;
2498
+ const viewable = resolveDetailOptions(definition) !== void 0 && (onOpenDetail !== void 0 || loadDetail !== void 0 || widget.status === "ok" && deriveDetailData(widget.data) !== void 0);
2499
+ return /* @__PURE__ */ jsx(
2500
+ ResolvedWidgetCard,
2501
+ {
2502
+ widget,
2503
+ ...viewable ? {
2504
+ onView: () => onOpenDetail === void 0 ? setDetailKey(key) : onOpenDetail(key)
2505
+ } : {},
2506
+ ...spanProps(spans, key),
2507
+ ...widthProps(twelve, definition),
2508
+ minimized: isMinimized(layout, key),
2509
+ editing: toggleMode && controlsShown,
2510
+ ...actions === void 0 ? {} : { actions },
2511
+ ...editable && !lock.minimize ? {
2512
+ onToggleMinimized: () => change(toggleMinimized(layout, key))
2513
+ } : {},
2514
+ ...headingLevel === void 0 ? {} : { headingLevel },
2515
+ ...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(key) }
2516
+ },
2517
+ key
2518
+ );
2519
+ })
2520
+ }
2521
+ ),
2522
+ detailKey !== void 0 && byKey.get(detailKey) !== void 0 && /* @__PURE__ */ jsx(
2523
+ DetailHost,
2524
+ {
2525
+ widget: byKey.get(detailKey),
2526
+ loadDetail,
2527
+ onClose: () => setDetailKey(void 0)
2528
+ },
2529
+ detailKey
2530
+ )
2531
+ ]
2532
+ }
2533
+ );
2318
2534
  }
2319
2535
  function Dashboard({
2320
2536
  locale,