@altertable/data-app 0.63.0 → 0.65.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.
Files changed (63) hide show
  1. package/AGENTS.md +3 -0
  2. package/CONTRIBUTING.md +4 -0
  3. package/README.md +1 -1
  4. package/dist/chunks/{contract-tkc552ze.js → contract-a061yj6r.js} +2 -2
  5. package/dist/chunks/contract-awa2d5b1.js +272 -0
  6. package/dist/chunks/contract-awa2d5b1.js.map +12 -0
  7. package/dist/chunks/{contract-zr3jd7mr.js → contract-g6hky7x6.js} +93 -72
  8. package/dist/chunks/contract-g6hky7x6.js.map +12 -0
  9. package/dist/chunks/{contract-8wdybxj7.js → contract-sm7j7k95.js} +110 -74
  10. package/dist/chunks/contract-sm7j7k95.js.map +14 -0
  11. package/dist/chunks/{contract-farfe948.js → contract-txjy0en2.js} +31 -31
  12. package/dist/chunks/contract-txjy0en2.js.map +10 -0
  13. package/dist/chunks/contract-wz59z8pq.js.map +2 -2
  14. package/dist/chunks/{contract-wd8qe3mt.js → contract-yxbjea23.js} +8 -6
  15. package/dist/chunks/contract-yxbjea23.js.map +12 -0
  16. package/dist/client/index.js +3 -3
  17. package/dist/core/appearance.js +4 -2
  18. package/dist/core/appearance.js.map +1 -1
  19. package/dist/core/contract.js +1 -1
  20. package/dist/embed/index.js +20 -10
  21. package/dist/embed/index.js.map +3 -3
  22. package/dist/react/embed/index.js +5 -2
  23. package/dist/react/embed/index.js.map +3 -3
  24. package/dist/react/index.js +726 -454
  25. package/dist/react/index.js.map +17 -14
  26. package/dist/types/client/iframe.d.ts +2 -0
  27. package/dist/types/client/index.d.ts +1 -0
  28. package/dist/types/client/logger.d.ts +6 -0
  29. package/dist/types/core/appearance.d.ts +12 -1
  30. package/dist/types/core/bridge-endpoint.d.ts +21 -0
  31. package/dist/types/core/bridge.d.ts +137 -16
  32. package/dist/types/core/config.d.ts +2 -1
  33. package/dist/types/core/logger.d.ts +12 -0
  34. package/dist/types/embed/host.d.ts +6 -2
  35. package/dist/types/embed/index.d.ts +1 -0
  36. package/dist/types/embed/source.d.ts +1 -1
  37. package/dist/types/react/embed/bridge.d.ts +1 -1
  38. package/dist/types/react/index.d.ts +1 -0
  39. package/dist/types/react/ui/AppToolbar.d.ts +3 -1
  40. package/dist/types/react/ui/DataApp.d.ts +6 -1
  41. package/dist/types/react/ui/ExportControl.d.ts +4 -0
  42. package/dist/types/react/ui/Toast.d.ts +8 -0
  43. package/dist/types/react/ui/csv-export.d.ts +19 -0
  44. package/dist/types/react/ui/icons.d.ts +1 -0
  45. package/dist/types/react/ui/useAppAppearance.d.ts +2 -2
  46. package/dist/worker.js +382 -79
  47. package/docs/app-authoring.md +30 -3
  48. package/docs/embed.md +1 -1
  49. package/docs/hosted-apps.md +2 -2
  50. package/docs/layout.md +31 -0
  51. package/docs/local-data-apps.md +1 -1
  52. package/docs/react.md +64 -2
  53. package/examples/starter-data-app/index.tsx +50 -32
  54. package/package.json +2 -1
  55. package/dist/chunks/contract-8q35dcyh.js +0 -9
  56. package/dist/chunks/contract-8q35dcyh.js.map +0 -10
  57. package/dist/chunks/contract-8wdybxj7.js.map +0 -13
  58. package/dist/chunks/contract-cxr9t12b.js +0 -18
  59. package/dist/chunks/contract-cxr9t12b.js.map +0 -10
  60. package/dist/chunks/contract-farfe948.js.map +0 -10
  61. package/dist/chunks/contract-wd8qe3mt.js.map +0 -11
  62. package/dist/chunks/contract-zr3jd7mr.js.map +0 -12
  63. /package/dist/chunks/{contract-tkc552ze.js.map → contract-a061yj6r.js.map} +0 -0
@@ -9,28 +9,26 @@ import {
9
9
  formatPercent2
10
10
  } from "../chunks/contract-mev09s5v.js";
11
11
  import {
12
- parseAppearance2,
12
+ normalizeAppearance2,
13
13
  applyAppearance2,
14
14
  createThemeController2
15
- } from "../chunks/contract-farfe948.js";
15
+ } from "../chunks/contract-txjy0en2.js";
16
16
  import {
17
+ invariant,
17
18
  dimensionMemberKey,
18
19
  dimensionFilter2,
19
20
  parseFacetOptions2,
20
21
  defineQueryNames2
21
- } from "../chunks/contract-wd8qe3mt.js";
22
+ } from "../chunks/contract-yxbjea23.js";
22
23
  import {
23
24
  createDataClient2,
24
25
  getDataAppNavigation2
25
- } from "../chunks/contract-tkc552ze.js";
26
+ } from "../chunks/contract-a061yj6r.js";
26
27
  import {
27
28
  DataAppError2,
28
29
  localFrameBridge,
29
30
  getDataAppTransport2
30
- } from "../chunks/contract-8wdybxj7.js";
31
- import {
32
- invariant
33
- } from "../chunks/contract-8q35dcyh.js";
31
+ } from "../chunks/contract-sm7j7k95.js";
34
32
 
35
33
  // src/react/injectStyles.ts
36
34
  function injectStyles({
@@ -334,6 +332,7 @@ function injectDataAppStyles(options = {}) {
334
332
  .altertable-grid > * {
335
333
  min-width: 0;
336
334
  min-height: 0;
335
+ margin: 0;
337
336
  }
338
337
 
339
338
  .altertable-grid[data-align="stretch"] {
@@ -377,19 +376,19 @@ function injectDataAppStyles(options = {}) {
377
376
  min-height: 0;
378
377
  }
379
378
 
380
- @container altertable-grid (width >= 408px) {
379
+ @container altertable-grid (width >= 414px) {
381
380
  .altertable-grid:not([data-columns="1"])[data-min-item-width="compact"] > .altertable-grid-item[data-span="2"] {
382
381
  grid-column: span 2;
383
382
  }
384
383
  }
385
384
 
386
- @container altertable-grid (width >= 504px) {
385
+ @container altertable-grid (width >= 510px) {
387
386
  .altertable-grid:not([data-columns="1"])[data-min-item-width="regular"] > .altertable-grid-item[data-span="2"] {
388
387
  grid-column: span 2;
389
388
  }
390
389
  }
391
390
 
392
- @container altertable-grid (width >= 664px) {
391
+ @container altertable-grid (width >= 670px) {
393
392
  .altertable-grid:not([data-columns="1"])[data-min-item-width="wide"] > .altertable-grid-item[data-span="2"] {
394
393
  grid-column: span 2;
395
394
  }
@@ -2405,6 +2404,10 @@ function injectDataAppStyles(options = {}) {
2405
2404
  min-width: 0;
2406
2405
  }
2407
2406
 
2407
+ .react-aria-TabPanel[data-inert] {
2408
+ display: none;
2409
+ }
2410
+
2408
2411
  .react-aria-TabPanel[data-focus-visible] {
2409
2412
  outline: var(--at-focus-outline, 1px solid #687078);
2410
2413
  outline-offset: var(--at-focus-ring-offset, 2px);
@@ -2690,9 +2693,16 @@ body, #root {
2690
2693
  }
2691
2694
 
2692
2695
  .altertable-app-body {
2696
+ display: grid;
2697
+ grid-template-columns: minmax(0, 1fr);
2698
+ gap: var(--at-layout-gap, 24px);
2693
2699
  min-width: 0;
2694
2700
  }
2695
2701
 
2702
+ .altertable-app-main > *, .altertable-app-body > * {
2703
+ margin: 0;
2704
+ }
2705
+
2696
2706
  .altertable-app-footer {
2697
2707
  margin-top: auto;
2698
2708
  }
@@ -3378,6 +3388,11 @@ button {
3378
3388
  justify-content: center;
3379
3389
  }
3380
3390
 
3391
+ .altertable-data-view-toast-region[data-position="top"] {
3392
+ top: max(20px, env(safe-area-inset-top));
3393
+ bottom: auto;
3394
+ }
3395
+
3381
3396
  .altertable-data-view-toast {
3382
3397
  display: flex;
3383
3398
  overflow: auto;
@@ -3403,7 +3418,7 @@ button {
3403
3418
  flex: none;
3404
3419
  }
3405
3420
 
3406
- .altertable-data-view-toast[data-state="stale-error"] > svg {
3421
+ .altertable-data-view-toast[data-state="error"] > svg {
3407
3422
  color: var(--at-danger, #b42318);
3408
3423
  }
3409
3424
 
@@ -3750,6 +3765,7 @@ button {
3750
3765
  /* src/react/ui/Stack.css */
3751
3766
  .altertable-stack {
3752
3767
  display: grid;
3768
+ grid-template-columns: minmax(0, 1fr);
3753
3769
  align-content: start;
3754
3770
  min-width: 0;
3755
3771
  }
@@ -3766,6 +3782,10 @@ button {
3766
3782
  gap: var(--at-layout-gap, 24px);
3767
3783
  }
3768
3784
 
3785
+ .altertable-stack > * {
3786
+ margin: 0;
3787
+ }
3788
+
3769
3789
  /* src/react/ui/Inspect.css */
3770
3790
  .altertable-inspect-trigger {
3771
3791
  display: inline-grid;
@@ -4749,6 +4769,31 @@ button {
4749
4769
  height: 16px;
4750
4770
  }
4751
4771
 
4772
+ /* src/react/ui/ExportControl.css */
4773
+ .altertable-export-popover {
4774
+ z-index: 1000;
4775
+ max-height: min(320px, var(--available-height));
4776
+ overflow: auto;
4777
+ border: 1px solid var(--at-border, #e3e6e8);
4778
+ border-radius: var(--at-radius-surface, 12px);
4779
+ background: var(--at-surface, #fff);
4780
+ color: var(--at-text, #202124);
4781
+ max-width: min(320px, 100vw - 32px);
4782
+ padding: 4px;
4783
+ box-shadow: 0 10px 32px #0000001f;
4784
+ }
4785
+
4786
+ .altertable-export-popover [role="menuitem"] {
4787
+ outline: none;
4788
+ border-radius: 6px;
4789
+ padding: 10px 12px;
4790
+ font-size: 13px;
4791
+ }
4792
+
4793
+ .altertable-export-popover [role="menuitem"][data-focused] {
4794
+ background: var(--at-border, #e3e6e8);
4795
+ }
4796
+
4752
4797
  /* src/react/styles.css */
4753
4798
 
4754
4799
  `,
@@ -4803,6 +4848,7 @@ function injectDataAppShellStyles(options = {}) {
4803
4848
  .altertable-grid > * {
4804
4849
  min-width: 0;
4805
4850
  min-height: 0;
4851
+ margin: 0;
4806
4852
  }
4807
4853
 
4808
4854
  .altertable-grid[data-align="stretch"] {
@@ -4846,19 +4892,19 @@ function injectDataAppShellStyles(options = {}) {
4846
4892
  min-height: 0;
4847
4893
  }
4848
4894
 
4849
- @container altertable-grid (width >= 408px) {
4895
+ @container altertable-grid (width >= 414px) {
4850
4896
  .altertable-grid:not([data-columns="1"])[data-min-item-width="compact"] > .altertable-grid-item[data-span="2"] {
4851
4897
  grid-column: span 2;
4852
4898
  }
4853
4899
  }
4854
4900
 
4855
- @container altertable-grid (width >= 504px) {
4901
+ @container altertable-grid (width >= 510px) {
4856
4902
  .altertable-grid:not([data-columns="1"])[data-min-item-width="regular"] > .altertable-grid-item[data-span="2"] {
4857
4903
  grid-column: span 2;
4858
4904
  }
4859
4905
  }
4860
4906
 
4861
- @container altertable-grid (width >= 664px) {
4907
+ @container altertable-grid (width >= 670px) {
4862
4908
  .altertable-grid:not([data-columns="1"])[data-min-item-width="wide"] > .altertable-grid-item[data-span="2"] {
4863
4909
  grid-column: span 2;
4864
4910
  }
@@ -5233,7 +5279,12 @@ function mountDataApp({
5233
5279
  document.documentElement.lang = navigator.language;
5234
5280
  document.title = dataAppTitle2(config);
5235
5281
  getDataAppNavigation2();
5236
- createRoot(root).render(/* @__PURE__ */ jsx(DataAppProvider, {
5282
+ createRoot(root, {
5283
+ onUncaughtError(error) {
5284
+ console.error(error);
5285
+ getDataAppTransport2()?.fail();
5286
+ }
5287
+ }).render(/* @__PURE__ */ jsx(DataAppProvider, {
5237
5288
  children: /* @__PURE__ */ jsx(Component, {})
5238
5289
  }));
5239
5290
  }
@@ -5320,6 +5371,7 @@ import {
5320
5371
  Clock3,
5321
5372
  Copy,
5322
5373
  FileCode2,
5374
+ Download,
5323
5375
  Info,
5324
5376
  LoaderCircle,
5325
5377
  Minus,
@@ -5346,6 +5398,7 @@ var brandedIcons = {
5346
5398
  info: Info,
5347
5399
  openDetails: ChevronRight,
5348
5400
  present: Presentation,
5401
+ export: Download,
5349
5402
  error: CircleAlert,
5350
5403
  close: X,
5351
5404
  previous: ArrowLeft,
@@ -5691,7 +5744,6 @@ function dateRangeVariable({
5691
5744
  };
5692
5745
  }
5693
5746
  };
5694
- invariant(!defaultValue.comparison, `Date variable ${key} comparison must be activated by the reader.`);
5695
5747
  invariant(variable.valid(defaultValue), `Date variable ${key} has a default outside its available data range.`);
5696
5748
  return variable;
5697
5749
  }
@@ -7464,7 +7516,6 @@ function createDataHooks(client) {
7464
7516
  };
7465
7517
  }
7466
7518
  function defineTimeView(definition) {
7467
- invariant(!definition.variables || !("period" in definition.variables), "The period input is owned by defineTimeView.");
7468
7519
  const period = dateRangeVariable({ ...definition.time, key: "period" });
7469
7520
  return defineDataView({
7470
7521
  operation: definition.operation,
@@ -7565,10 +7616,10 @@ import { useEffect as useEffect14, useRef as useRef6 } from "react";
7565
7616
  // src/react/ui/useAppAppearance.ts
7566
7617
  import { useLayoutEffect, useState as useState8, useSyncExternalStore as useSyncExternalStore2 } from "react";
7567
7618
  function useAppAppearance(appearance, hostTheme) {
7568
- const [controller] = useState8(() => createThemeController2(parseAppearance2(appearance).theme));
7619
+ const [controller] = useState8(() => createThemeController2(normalizeAppearance2(appearance).theme));
7569
7620
  const viewerPreference = useSyncExternalStore2(controller.subscribe, controller.getTheme, controller.getTheme);
7570
7621
  useLayoutEffect(() => applyAppearance2({
7571
- ...parseAppearance2(appearance),
7622
+ ...normalizeAppearance2(appearance),
7572
7623
  theme: hostTheme ?? viewerPreference
7573
7624
  }), [appearance, hostTheme, viewerPreference]);
7574
7625
  return hostTheme ? undefined : controller;
@@ -8461,15 +8512,81 @@ function AppScope({
8461
8512
  });
8462
8513
  }
8463
8514
 
8464
- // src/react/ui/LiveControl.tsx
8465
- import {
8466
- Button as AriaButton2,
8467
- ListBox as ListBox3,
8468
- ListBoxItem as ListBoxItem3,
8469
- Popover as Popover3,
8470
- Select as Select2,
8471
- SelectValue as SelectValue2
8472
- } from "react-aria-components";
8515
+ // src/react/ui/ExportControl.tsx
8516
+ import { useState as useState12 } from "react";
8517
+
8518
+ // src/react/ui/csv-export.ts
8519
+ import { strToU8, zipSync } from "fflate";
8520
+ function formatCsv({
8521
+ columns,
8522
+ rows
8523
+ }) {
8524
+ if (!columns.length)
8525
+ throw new Error("CSV export needs at least one column.");
8526
+ if (rows.some((row) => row.length !== columns.length))
8527
+ throw new Error("CSV rows must match the export columns.");
8528
+ function cell(value) {
8529
+ if (value === null || value === undefined)
8530
+ return "";
8531
+ let text = String(value);
8532
+ if (typeof value === "string" && /^[\s]*[=+\-@]|^[\t\r\n]/.test(text))
8533
+ text = `'${text}`;
8534
+ return /[",\r\n]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
8535
+ }
8536
+ return [columns, ...rows].map((row) => row.map(cell).join(",")).join(`\r
8537
+ `) + `\r
8538
+ `;
8539
+ }
8540
+ function filenameWithExtension(name, extension) {
8541
+ const filename = name.toLowerCase().endsWith(`.${extension}`) ? name : `${name.replace(/\.(?:csv|zip)$/i, "")}.${extension}`;
8542
+ if (!name.trim() || filename.length > 255 || /[\p{Cc}\\/]/u.test(filename))
8543
+ throw new Error("Export filenames must be nonempty names without paths.");
8544
+ return filename;
8545
+ }
8546
+ function createCsvDownload(data, selectedTable) {
8547
+ if (!data.tables.length)
8548
+ throw new Error("CSV export needs at least one dataset.");
8549
+ const names = data.tables.map((table) => filenameWithExtension(table.name, "csv"));
8550
+ if (new Set(names.map((name) => name.toLowerCase())).size !== names.length)
8551
+ throw new Error("CSV dataset names must be unique.");
8552
+ const table = selectedTable ?? (data.tables.length === 1 ? data.tables[0] : undefined);
8553
+ if (table)
8554
+ return {
8555
+ filename: filenameWithExtension(selectedTable ? table.name : data.filename, "csv"),
8556
+ blob: new Blob(["\uFEFF" + formatCsv(table)], {
8557
+ type: "text/csv;charset=utf-8"
8558
+ }),
8559
+ route: "export:csv"
8560
+ };
8561
+ const files = Object.fromEntries(data.tables.map((dataset, index) => [
8562
+ names[index],
8563
+ strToU8("\uFEFF" + formatCsv(dataset))
8564
+ ]));
8565
+ return {
8566
+ filename: filenameWithExtension(data.filename, "zip"),
8567
+ blob: new Blob([zipSync(files, { level: 1 })], { type: "application/zip" }),
8568
+ route: "export:zip"
8569
+ };
8570
+ }
8571
+ async function exportCsv(data, table) {
8572
+ const { filename, blob, route } = createCsvDownload(data, table);
8573
+ const transport = getDataAppTransport2();
8574
+ if (transport) {
8575
+ await transport.request({ route, payload: { filename, blob } });
8576
+ return;
8577
+ }
8578
+ const url = URL.createObjectURL(blob);
8579
+ const link = document.createElement("a");
8580
+ link.href = url;
8581
+ link.download = filename;
8582
+ document.body.append(link);
8583
+ try {
8584
+ link.click();
8585
+ } finally {
8586
+ link.remove();
8587
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
8588
+ }
8589
+ }
8473
8590
 
8474
8591
  // src/react/ui/IconButton.tsx
8475
8592
  import { jsx as jsx27, jsxs as jsxs18, Fragment as Fragment6 } from "react/jsx-runtime";
@@ -8521,8 +8638,129 @@ function IconButton({
8521
8638
  });
8522
8639
  }
8523
8640
 
8524
- // src/react/ui/LiveControl.tsx
8641
+ // src/react/ui/ExportControl.tsx
8642
+ import { Menu, MenuItem, MenuTrigger, Popover as Popover3 } from "react-aria-components";
8643
+
8644
+ // src/react/ui/Toast.tsx
8525
8645
  import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
8646
+ function Toast({
8647
+ state,
8648
+ children,
8649
+ onRetry,
8650
+ position = "bottom"
8651
+ }) {
8652
+ const failed = state === "error";
8653
+ const updating = state === "updating";
8654
+ return /* @__PURE__ */ jsx28("div", {
8655
+ className: "altertable-data-view-toast-region",
8656
+ "data-position": position,
8657
+ children: /* @__PURE__ */ jsxs19("div", {
8658
+ className: "altertable-data-view-toast",
8659
+ "data-state": state,
8660
+ role: failed ? "alert" : "status",
8661
+ children: [
8662
+ /* @__PURE__ */ jsx28(AppIcon, {
8663
+ name: failed ? "error" : updating ? "loading" : "live",
8664
+ size: 16,
8665
+ className: updating ? "altertable-data-view-toast-spinner" : undefined
8666
+ }),
8667
+ /* @__PURE__ */ jsx28("span", {
8668
+ children
8669
+ }),
8670
+ failed && onRetry && /* @__PURE__ */ jsx28(Button, {
8671
+ onClick: onRetry,
8672
+ children: "Try again"
8673
+ })
8674
+ ]
8675
+ })
8676
+ });
8677
+ }
8678
+
8679
+ // src/react/ui/ExportControl.tsx
8680
+ import { jsx as jsx29, jsxs as jsxs20, Fragment as Fragment7 } from "react/jsx-runtime";
8681
+ function ExportControl({ csv }) {
8682
+ const [open, setOpen] = useState12(false);
8683
+ const [status, setStatus] = useState12("idle");
8684
+ const [retryTableName, setRetryTableName] = useState12();
8685
+ async function download(table) {
8686
+ setOpen(false);
8687
+ setRetryTableName(table?.name);
8688
+ setStatus("pending");
8689
+ try {
8690
+ await exportCsv(csv, table);
8691
+ setStatus("idle");
8692
+ } catch {
8693
+ setStatus("error");
8694
+ }
8695
+ }
8696
+ return /* @__PURE__ */ jsxs20(Fragment7, {
8697
+ children: [
8698
+ status === "error" && /* @__PURE__ */ jsx29(Toast, {
8699
+ state: "error",
8700
+ position: "top",
8701
+ onRetry: () => void download(csv.tables.find((table) => table.name === retryTableName)),
8702
+ children: "Couldn’t export data."
8703
+ }),
8704
+ csv.tables.length === 1 ? /* @__PURE__ */ jsx29(IconButton, {
8705
+ icon: "export",
8706
+ variant: "elevated",
8707
+ label: "Export CSV",
8708
+ disabled: status === "pending",
8709
+ "aria-busy": status === "pending",
8710
+ onClick: () => void download()
8711
+ }) : /* @__PURE__ */ jsxs20(MenuTrigger, {
8712
+ isOpen: open,
8713
+ onOpenChange: setOpen,
8714
+ children: [
8715
+ /* @__PURE__ */ jsx29(PressButton, {
8716
+ variant: "elevated",
8717
+ size: "icon",
8718
+ "aria-label": "Export",
8719
+ isDisabled: status === "pending",
8720
+ "aria-busy": status === "pending",
8721
+ children: /* @__PURE__ */ jsx29(AppIcon, {
8722
+ name: "export"
8723
+ })
8724
+ }),
8725
+ /* @__PURE__ */ jsx29(Popover3, {
8726
+ placement: "bottom end",
8727
+ className: "altertable-export-popover",
8728
+ children: /* @__PURE__ */ jsxs20(Menu, {
8729
+ "aria-label": "Export data",
8730
+ children: [
8731
+ csv.tables.map((table, index) => /* @__PURE__ */ jsxs20(MenuItem, {
8732
+ id: index,
8733
+ onAction: () => void download(table),
8734
+ children: [
8735
+ "Export ",
8736
+ table.name,
8737
+ " (CSV)"
8738
+ ]
8739
+ }, index)),
8740
+ /* @__PURE__ */ jsx29(MenuItem, {
8741
+ id: "all",
8742
+ onAction: () => void download(),
8743
+ children: "Export all (ZIP)"
8744
+ })
8745
+ ]
8746
+ })
8747
+ })
8748
+ ]
8749
+ })
8750
+ ]
8751
+ });
8752
+ }
8753
+
8754
+ // src/react/ui/LiveControl.tsx
8755
+ import {
8756
+ Button as AriaButton2,
8757
+ ListBox as ListBox3,
8758
+ ListBoxItem as ListBoxItem3,
8759
+ Popover as Popover4,
8760
+ Select as Select2,
8761
+ SelectValue as SelectValue2
8762
+ } from "react-aria-components";
8763
+ import { jsx as jsx30, jsxs as jsxs21 } from "react/jsx-runtime";
8526
8764
  var intervals = [
8527
8765
  { seconds: 30, label: "Every 30 seconds", description: "every 30 seconds" },
8528
8766
  { seconds: 60, label: "Every minute", description: "every minute" },
@@ -8538,11 +8776,11 @@ function LiveControl({
8538
8776
  }) {
8539
8777
  const frequency = intervals.find((interval) => interval.seconds === intervalSeconds)?.description;
8540
8778
  invariant(frequency, "LiveControl requires a supported update interval.");
8541
- return /* @__PURE__ */ jsxs19("div", {
8779
+ return /* @__PURE__ */ jsxs21("div", {
8542
8780
  className: classNames("altertable-live-control", className),
8543
8781
  "data-active": enabled,
8544
8782
  children: [
8545
- /* @__PURE__ */ jsx28(IconButton, {
8783
+ /* @__PURE__ */ jsx30(IconButton, {
8546
8784
  ...props,
8547
8785
  icon: "live",
8548
8786
  variant: "ghost",
@@ -8550,7 +8788,7 @@ function LiveControl({
8550
8788
  "aria-pressed": enabled,
8551
8789
  onClick: () => onChange(!enabled)
8552
8790
  }),
8553
- /* @__PURE__ */ jsxs19(Select2, {
8791
+ /* @__PURE__ */ jsxs21(Select2, {
8554
8792
  "aria-label": `Live update frequency: ${frequency}`,
8555
8793
  selectedKey: String(intervalSeconds),
8556
8794
  onSelectionChange: (key) => {
@@ -8560,29 +8798,29 @@ function LiveControl({
8560
8798
  },
8561
8799
  className: "altertable-live-frequency",
8562
8800
  children: [
8563
- /* @__PURE__ */ jsxs19(AriaButton2, {
8801
+ /* @__PURE__ */ jsxs21(AriaButton2, {
8564
8802
  "aria-label": `Live update frequency: ${frequency}`,
8565
8803
  children: [
8566
- /* @__PURE__ */ jsx28(SelectValue2, {
8804
+ /* @__PURE__ */ jsx30(SelectValue2, {
8567
8805
  className: "altertable-visually-hidden"
8568
8806
  }),
8569
- /* @__PURE__ */ jsx28(AppIcon, {
8807
+ /* @__PURE__ */ jsx30(AppIcon, {
8570
8808
  name: "disclosure",
8571
8809
  size: 14
8572
8810
  })
8573
8811
  ]
8574
8812
  }),
8575
- /* @__PURE__ */ jsx28(Popover3, {
8813
+ /* @__PURE__ */ jsx30(Popover4, {
8576
8814
  placement: "bottom end",
8577
8815
  className: "altertable-live-frequency-popover",
8578
- children: /* @__PURE__ */ jsx28(ListBox3, {
8816
+ children: /* @__PURE__ */ jsx30(ListBox3, {
8579
8817
  "aria-label": "Live update frequency",
8580
- children: intervals.map((interval) => /* @__PURE__ */ jsxs19(ListBoxItem3, {
8818
+ children: intervals.map((interval) => /* @__PURE__ */ jsxs21(ListBoxItem3, {
8581
8819
  id: String(interval.seconds),
8582
8820
  textValue: interval.label,
8583
8821
  children: [
8584
8822
  interval.label,
8585
- /* @__PURE__ */ jsx28(AppIcon, {
8823
+ /* @__PURE__ */ jsx30(AppIcon, {
8586
8824
  name: "check",
8587
8825
  size: 15
8588
8826
  })
@@ -8602,7 +8840,7 @@ import {
8602
8840
  useEffectEvent as useEffectEvent2,
8603
8841
  useId as useId7,
8604
8842
  useRef as useRef5,
8605
- useState as useState12
8843
+ useState as useState13
8606
8844
  } from "react";
8607
8845
  import { useMergeRefs as useMergeRefs5 } from "@floating-ui/react";
8608
8846
 
@@ -8612,7 +8850,7 @@ import {
8612
8850
  useId as useId6,
8613
8851
  useSyncExternalStore as useSyncExternalStore3
8614
8852
  } from "react";
8615
- import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
8853
+ import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
8616
8854
  var themes = [
8617
8855
  { value: "light", label: "Light", icon: "lightTheme" },
8618
8856
  { value: "dark", label: "Dark", icon: "darkTheme" }
@@ -8641,19 +8879,19 @@ function ThemeSelector({
8641
8879
  }) {
8642
8880
  const selected = useResolvedTheme(theme);
8643
8881
  const name = useId6();
8644
- return /* @__PURE__ */ jsxs20("fieldset", {
8882
+ return /* @__PURE__ */ jsxs22("fieldset", {
8645
8883
  ...props,
8646
8884
  className: classNames("altertable-theme-selector", className),
8647
8885
  children: [
8648
- /* @__PURE__ */ jsx29("legend", {
8886
+ /* @__PURE__ */ jsx31("legend", {
8649
8887
  className: "altertable-theme-legend",
8650
8888
  children: "Color theme"
8651
8889
  }),
8652
- themes.map(({ value, label, icon }) => /* @__PURE__ */ jsx29(Tooltip, {
8890
+ themes.map(({ value, label, icon }) => /* @__PURE__ */ jsx31(Tooltip, {
8653
8891
  content: `${label} theme`,
8654
- children: /* @__PURE__ */ jsxs20("label", {
8892
+ children: /* @__PURE__ */ jsxs22("label", {
8655
8893
  children: [
8656
- /* @__PURE__ */ jsx29("input", {
8894
+ /* @__PURE__ */ jsx31("input", {
8657
8895
  type: "radio",
8658
8896
  name,
8659
8897
  value,
@@ -8661,7 +8899,7 @@ function ThemeSelector({
8661
8899
  "aria-label": `${label} theme`,
8662
8900
  onChange: () => theme.setTheme(value)
8663
8901
  }),
8664
- /* @__PURE__ */ jsx29(AppIcon, {
8902
+ /* @__PURE__ */ jsx31(AppIcon, {
8665
8903
  name: icon,
8666
8904
  size: 16
8667
8905
  })
@@ -8679,7 +8917,7 @@ function ThemeToggle({
8679
8917
  const selected = useResolvedTheme(theme);
8680
8918
  const next = selected === "dark" ? "light" : "dark";
8681
8919
  const icon = next === "dark" ? "darkTheme" : "lightTheme";
8682
- return /* @__PURE__ */ jsx29(IconButton, {
8920
+ return /* @__PURE__ */ jsx31(IconButton, {
8683
8921
  icon,
8684
8922
  variant: "ghost",
8685
8923
  label: `Switch to ${next} theme`,
@@ -8716,7 +8954,7 @@ function storySteps(findings, context) {
8716
8954
  }
8717
8955
 
8718
8956
  // src/react/ui/PresentStory.tsx
8719
- import { jsx as jsx30, jsxs as jsxs21, Fragment as Fragment7 } from "react/jsx-runtime";
8957
+ import { jsx as jsx32, jsxs as jsxs23, Fragment as Fragment8 } from "react/jsx-runtime";
8720
8958
  var stepKeys = {
8721
8959
  ArrowRight(index) {
8722
8960
  return index + 1;
@@ -8759,9 +8997,11 @@ function PresentStory({
8759
8997
  const dialog = useRef5(null);
8760
8998
  const trigger = useRef5(null);
8761
8999
  const headline = useRef5(null);
9000
+ const ownedFullscreenElement = useRef5(null);
9001
+ const isOpening = useRef5(false);
8762
9002
  const headlineId = useId7();
8763
9003
  const contextId = useId7();
8764
- const [stepId, setStepId] = useState12(steps[0]?.id);
9004
+ const [stepId, setStepId] = useState13(steps[0]?.id);
8765
9005
  const triggerRef = useMergeRefs5([trigger, ref]);
8766
9006
  const dialogRef = useMergeRefs5([dialog, dialogProps?.ref]);
8767
9007
  const index = Math.max(0, steps.findIndex((step) => step.id === stepId));
@@ -8789,18 +9029,62 @@ function PresentStory({
8789
9029
  if (dialog.current?.open)
8790
9030
  headline.current?.focus({ preventScroll: true });
8791
9031
  }, [stepId]);
9032
+ useEffect11(() => {
9033
+ const presentationDialog = dialog.current;
9034
+ if (!presentationDialog)
9035
+ return;
9036
+ const ownerDocument = presentationDialog.ownerDocument;
9037
+ function handleFullscreenChange() {
9038
+ const fullscreenElement = ownedFullscreenElement.current;
9039
+ if (!fullscreenElement || ownerDocument.fullscreenElement === fullscreenElement)
9040
+ return;
9041
+ ownedFullscreenElement.current = null;
9042
+ dialog.current?.close();
9043
+ }
9044
+ ownerDocument.addEventListener("fullscreenchange", handleFullscreenChange);
9045
+ return () => {
9046
+ ownerDocument.removeEventListener("fullscreenchange", handleFullscreenChange);
9047
+ exitPresentationFullscreen();
9048
+ };
9049
+ }, []);
9050
+ function exitPresentationFullscreen() {
9051
+ const fullscreenElement = ownedFullscreenElement.current;
9052
+ ownedFullscreenElement.current = null;
9053
+ if (!fullscreenElement)
9054
+ return;
9055
+ const ownerDocument = fullscreenElement.ownerDocument;
9056
+ if (ownerDocument.fullscreenElement === fullscreenElement)
9057
+ ownerDocument.exitFullscreen().catch(() => {});
9058
+ }
8792
9059
  function writePresentation(id, mode = "replace") {
8793
9060
  writeSearch({ present: id ? "1" : null, step: id ?? null }, mode);
8794
9061
  }
8795
- function open() {
8796
- if (unavailable)
9062
+ async function openPresentation() {
9063
+ const presentationDialog = dialog.current;
9064
+ const firstStep = steps[0];
9065
+ if (unavailable || isOpening.current || !presentationDialog || !firstStep)
9066
+ return;
9067
+ const ownerDocument = presentationDialog.ownerDocument;
9068
+ const fullscreenElement = ownerDocument.documentElement;
9069
+ isOpening.current = true;
9070
+ try {
9071
+ if (!ownerDocument.fullscreenElement && ownerDocument.fullscreenEnabled) {
9072
+ await fullscreenElement.requestFullscreen();
9073
+ ownedFullscreenElement.current = fullscreenElement;
9074
+ }
9075
+ } catch {} finally {
9076
+ isOpening.current = false;
9077
+ }
9078
+ if (!presentationDialog.isConnected) {
9079
+ exitPresentationFullscreen();
8797
9080
  return;
8798
- setStepId(steps[0].id);
8799
- dialog.current?.showModal();
9081
+ }
9082
+ setStepId(firstStep.id);
9083
+ presentationDialog.showModal();
8800
9084
  headline.current?.focus({ preventScroll: true });
8801
- writePresentation(steps[0].id, "push");
9085
+ writePresentation(firstStep.id, "push");
8802
9086
  }
8803
- useShortcut(shortcuts.playStory, open, !unavailable);
9087
+ useShortcut(shortcuts.playStory, openPresentation, !unavailable);
8804
9088
  function goTo(nextIndex) {
8805
9089
  const next = steps[nextIndex];
8806
9090
  if (!next)
@@ -8817,12 +9101,12 @@ function PresentStory({
8817
9101
  event.preventDefault();
8818
9102
  goTo(move(index, steps.length - 1));
8819
9103
  }
8820
- return /* @__PURE__ */ jsxs21(Fragment7, {
9104
+ return /* @__PURE__ */ jsxs23(Fragment8, {
8821
9105
  children: [
8822
- /* @__PURE__ */ jsx30("span", {
9106
+ /* @__PURE__ */ jsx32("span", {
8823
9107
  ...launcherProps,
8824
9108
  className: classNames("altertable-present-launch", launcherProps?.className),
8825
- children: /* @__PURE__ */ jsx30(IconButton, {
9109
+ children: /* @__PURE__ */ jsx32(IconButton, {
8826
9110
  ...props,
8827
9111
  ref: triggerRef,
8828
9112
  icon: "present",
@@ -8835,12 +9119,12 @@ function PresentStory({
8835
9119
  onClick: (event) => {
8836
9120
  onClick?.(event);
8837
9121
  if (!event.defaultPrevented)
8838
- open();
9122
+ openPresentation();
8839
9123
  },
8840
9124
  children
8841
9125
  })
8842
9126
  }),
8843
- /* @__PURE__ */ jsx30("dialog", {
9127
+ /* @__PURE__ */ jsx32("dialog", {
8844
9128
  ...dialogProps,
8845
9129
  ref: dialogRef,
8846
9130
  className: classNames("altertable-present-dialog", dialogProps?.className),
@@ -8849,6 +9133,7 @@ function PresentStory({
8849
9133
  onClose: (event) => {
8850
9134
  if (event.target !== event.currentTarget)
8851
9135
  return;
9136
+ exitPresentationFullscreen();
8852
9137
  if (searchParams().get("present") === "1")
8853
9138
  writePresentation();
8854
9139
  trigger.current?.focus({ preventScroll: true });
@@ -8859,21 +9144,21 @@ function PresentStory({
8859
9144
  if (!event.defaultPrevented)
8860
9145
  handleKeyDown(event);
8861
9146
  },
8862
- children: step && /* @__PURE__ */ jsxs21("div", {
9147
+ children: step && /* @__PURE__ */ jsxs23("div", {
8863
9148
  className: "altertable-present-shell",
8864
9149
  children: [
8865
- /* @__PURE__ */ jsxs21("header", {
9150
+ /* @__PURE__ */ jsxs23("header", {
8866
9151
  className: "altertable-present-header",
8867
9152
  children: [
8868
- /* @__PURE__ */ jsxs21("div", {
9153
+ /* @__PURE__ */ jsxs23("div", {
8869
9154
  className: "altertable-present-title",
8870
9155
  children: [
8871
- /* @__PURE__ */ jsx30("strong", {
9156
+ /* @__PURE__ */ jsx32("strong", {
8872
9157
  children: title
8873
9158
  }),
8874
- scope && /* @__PURE__ */ jsxs21(Fragment7, {
9159
+ scope && /* @__PURE__ */ jsxs23(Fragment8, {
8875
9160
  children: [
8876
- /* @__PURE__ */ jsx30("span", {
9161
+ /* @__PURE__ */ jsx32("span", {
8877
9162
  className: "altertable-present-connector",
8878
9163
  "aria-hidden": "true",
8879
9164
  children: "/"
@@ -8883,10 +9168,10 @@ function PresentStory({
8883
9168
  })
8884
9169
  ]
8885
9170
  }),
8886
- /* @__PURE__ */ jsxs21("div", {
9171
+ /* @__PURE__ */ jsxs23("div", {
8887
9172
  className: "altertable-present-actions",
8888
9173
  children: [
8889
- /* @__PURE__ */ jsxs21("span", {
9174
+ /* @__PURE__ */ jsxs23("span", {
8890
9175
  className: "altertable-present-count",
8891
9176
  "aria-label": `Finding ${index + 1} of ${steps.length}`,
8892
9177
  children: [
@@ -8895,15 +9180,15 @@ function PresentStory({
8895
9180
  steps.length
8896
9181
  ]
8897
9182
  }),
8898
- theme && /* @__PURE__ */ jsx30("span", {
9183
+ theme && /* @__PURE__ */ jsx32("span", {
8899
9184
  className: "altertable-present-theme",
8900
- children: /* @__PURE__ */ jsx30(ThemeToggle, {
9185
+ children: /* @__PURE__ */ jsx32(ThemeToggle, {
8901
9186
  theme,
8902
9187
  portalRoot: dialog
8903
9188
  })
8904
9189
  }),
8905
9190
  headerActions,
8906
- /* @__PURE__ */ jsx30(IconButton, {
9191
+ /* @__PURE__ */ jsx32(IconButton, {
8907
9192
  icon: "close",
8908
9193
  variant: "ghost",
8909
9194
  label: "Exit presentation",
@@ -8916,25 +9201,25 @@ function PresentStory({
8916
9201
  })
8917
9202
  ]
8918
9203
  }),
8919
- /* @__PURE__ */ jsxs21(GradientScroll, {
9204
+ /* @__PURE__ */ jsxs23(GradientScroll, {
8920
9205
  className: "altertable-present-main",
8921
9206
  children: [
8922
- /* @__PURE__ */ jsxs21("div", {
9207
+ /* @__PURE__ */ jsxs23("div", {
8923
9208
  className: "altertable-present-copy",
8924
9209
  children: [
8925
- /* @__PURE__ */ jsx30("h2", {
9210
+ /* @__PURE__ */ jsx32("h2", {
8926
9211
  id: headlineId,
8927
9212
  ref: headline,
8928
9213
  tabIndex: -1,
8929
9214
  children: step.headline
8930
9215
  }),
8931
- step.context && /* @__PURE__ */ jsx30("p", {
9216
+ step.context && /* @__PURE__ */ jsx32("p", {
8932
9217
  id: contextId,
8933
9218
  children: step.context
8934
9219
  }),
8935
- /* @__PURE__ */ jsx30("div", {
9220
+ /* @__PURE__ */ jsx32("div", {
8936
9221
  className: "altertable-present-explore",
8937
- children: /* @__PURE__ */ jsxs21(AboutData, {
9222
+ children: /* @__PURE__ */ jsxs23(AboutData, {
8938
9223
  shortcut: false,
8939
9224
  id: step.id,
8940
9225
  empty: step.empty ?? empty,
@@ -8953,7 +9238,7 @@ function PresentStory({
8953
9238
  variant: "outline",
8954
9239
  portalRoot: dialog,
8955
9240
  children: [
8956
- /* @__PURE__ */ jsx30(AppIcon, {
9241
+ /* @__PURE__ */ jsx32(AppIcon, {
8957
9242
  name: "explore"
8958
9243
  }),
8959
9244
  " Explore sources"
@@ -8962,18 +9247,18 @@ function PresentStory({
8962
9247
  })
8963
9248
  ]
8964
9249
  }),
8965
- /* @__PURE__ */ jsx30("div", {
9250
+ /* @__PURE__ */ jsx32("div", {
8966
9251
  className: "altertable-present-visual",
8967
9252
  "data-kind": step.visualKind,
8968
9253
  children: step.visual
8969
9254
  })
8970
9255
  ]
8971
9256
  }, step.id),
8972
- /* @__PURE__ */ jsxs21("nav", {
9257
+ /* @__PURE__ */ jsxs23("nav", {
8973
9258
  className: "altertable-present-nav",
8974
9259
  "aria-label": "Story findings",
8975
9260
  children: [
8976
- /* @__PURE__ */ jsx30(IconButton, {
9261
+ /* @__PURE__ */ jsx32(IconButton, {
8977
9262
  icon: "previous",
8978
9263
  variant: "ghost",
8979
9264
  label: "Previous step",
@@ -8984,13 +9269,13 @@ function PresentStory({
8984
9269
  onClick: () => goTo(index - 1),
8985
9270
  disabled: index === 0
8986
9271
  }),
8987
- /* @__PURE__ */ jsx30("div", {
9272
+ /* @__PURE__ */ jsx32("div", {
8988
9273
  className: "altertable-present-dots",
8989
- children: steps.map((item, itemIndex) => /* @__PURE__ */ jsx30(Tooltip, {
9274
+ children: steps.map((item, itemIndex) => /* @__PURE__ */ jsx32(Tooltip, {
8990
9275
  content: item.headline,
8991
9276
  placement: "top",
8992
9277
  portalRoot: dialog,
8993
- children: /* @__PURE__ */ jsx30("button", {
9278
+ children: /* @__PURE__ */ jsx32("button", {
8994
9279
  type: "button",
8995
9280
  "aria-label": `Finding ${itemIndex + 1}: ${item.headline}`,
8996
9281
  "aria-current": itemIndex === index ? "step" : undefined,
@@ -8998,7 +9283,7 @@ function PresentStory({
8998
9283
  })
8999
9284
  }, item.id))
9000
9285
  }),
9001
- /* @__PURE__ */ jsx30(IconButton, {
9286
+ /* @__PURE__ */ jsx32(IconButton, {
9002
9287
  icon: "next",
9003
9288
  variant: "ghost",
9004
9289
  label: "Next step",
@@ -9022,9 +9307,9 @@ function PresentStory({
9022
9307
  // src/react/ui/RefreshControl.tsx
9023
9308
  import {
9024
9309
  useEffect as useEffect12,
9025
- useState as useState13
9310
+ useState as useState14
9026
9311
  } from "react";
9027
- import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
9312
+ import { jsx as jsx33, jsxs as jsxs24 } from "react/jsx-runtime";
9028
9313
  function RefreshControl({
9029
9314
  refreshing,
9030
9315
  children,
@@ -9034,7 +9319,7 @@ function RefreshControl({
9034
9319
  className,
9035
9320
  ...props
9036
9321
  }) {
9037
- const [refreshDelay, setRefreshDelay] = useState13({
9322
+ const [refreshDelay, setRefreshDelay] = useState14({
9038
9323
  refreshing,
9039
9324
  elapsed: false
9040
9325
  });
@@ -9047,12 +9332,12 @@ function RefreshControl({
9047
9332
  return () => window.clearTimeout(timer);
9048
9333
  }, [refreshing]);
9049
9334
  const showProgress = refreshing && refreshDelay.refreshing && refreshDelay.elapsed;
9050
- return /* @__PURE__ */ jsxs22("div", {
9335
+ return /* @__PURE__ */ jsxs24("div", {
9051
9336
  ...props,
9052
9337
  className: classNames("altertable-refresh-control", className),
9053
9338
  "data-refreshing": showProgress ? "" : undefined,
9054
9339
  children: [
9055
- /* @__PURE__ */ jsx31("div", {
9340
+ /* @__PURE__ */ jsx33("div", {
9056
9341
  ...statusProps,
9057
9342
  className: classNames("altertable-refresh-status", statusProps?.className),
9058
9343
  "aria-live": "polite",
@@ -9065,7 +9350,7 @@ function RefreshControl({
9065
9350
  }
9066
9351
 
9067
9352
  // src/react/ui/AppToolbar.tsx
9068
- import { jsx as jsx32, jsxs as jsxs23 } from "react/jsx-runtime";
9353
+ import { jsx as jsx34, jsxs as jsxs25 } from "react/jsx-runtime";
9069
9354
  function AppToolbar({
9070
9355
  children,
9071
9356
  updatedAt,
@@ -9075,6 +9360,7 @@ function AppToolbar({
9075
9360
  live,
9076
9361
  aboutData,
9077
9362
  story,
9363
+ csvExport,
9078
9364
  end,
9079
9365
  controlsProps,
9080
9366
  className,
@@ -9096,27 +9382,27 @@ function AppToolbar({
9096
9382
  refresh.onRefresh();
9097
9383
  }
9098
9384
  useShortcut(shortcuts.refresh, runRefresh, !!refresh);
9099
- return /* @__PURE__ */ jsx32("div", {
9385
+ return /* @__PURE__ */ jsx34("div", {
9100
9386
  ...props,
9101
9387
  className: classNames("altertable-app-toolbar", className),
9102
9388
  role,
9103
9389
  "aria-label": ariaLabel,
9104
- children: /* @__PURE__ */ jsxs23("div", {
9390
+ children: /* @__PURE__ */ jsxs25("div", {
9105
9391
  ...controlsProps,
9106
9392
  className: classNames("altertable-app-toolbar-actions", controlsProps?.className),
9107
9393
  children: [
9108
9394
  children,
9109
- (initialLoading || updatedAt) && /* @__PURE__ */ jsx32("span", {
9395
+ (initialLoading || updatedAt) && /* @__PURE__ */ jsx34("span", {
9110
9396
  className: "altertable-app-toolbar-updated",
9111
- children: initialLoading ? /* @__PURE__ */ jsx32("output", {
9397
+ children: initialLoading ? /* @__PURE__ */ jsx34("output", {
9112
9398
  children: "Loading data"
9113
9399
  }) : updatedAt
9114
9400
  }),
9115
- refresh && /* @__PURE__ */ jsx32(RefreshControl, {
9401
+ refresh && /* @__PURE__ */ jsx34(RefreshControl, {
9116
9402
  refreshing: refresh.refreshing,
9117
9403
  label: requestState === "loading" ? "Loading data" : requestState === "updating" ? "Updating data" : refresh.label,
9118
9404
  statusProps: refresh.statusProps,
9119
- children: /* @__PURE__ */ jsxs23(IconButton, {
9405
+ children: /* @__PURE__ */ jsxs25(IconButton, {
9120
9406
  ...refresh.buttonProps,
9121
9407
  icon: "refresh",
9122
9408
  variant: "elevated",
@@ -9125,17 +9411,17 @@ function AppToolbar({
9125
9411
  tooltip: refresh.refreshing && refresh.onCancel ? "Cancel refresh" : refresh.tooltip,
9126
9412
  onClick: activateRefresh,
9127
9413
  children: [
9128
- /* @__PURE__ */ jsx32(AppIcon, {
9414
+ /* @__PURE__ */ jsx34(AppIcon, {
9129
9415
  name: "refresh",
9130
9416
  className: "altertable-refresh-idle",
9131
9417
  size: 17
9132
9418
  }),
9133
- /* @__PURE__ */ jsx32(AppIcon, {
9419
+ /* @__PURE__ */ jsx34(AppIcon, {
9134
9420
  name: "loading",
9135
9421
  className: "altertable-refresh-loading",
9136
9422
  size: 17
9137
9423
  }),
9138
- refresh.onCancel && /* @__PURE__ */ jsx32(AppIcon, {
9424
+ refresh.onCancel && /* @__PURE__ */ jsx34(AppIcon, {
9139
9425
  name: "stop",
9140
9426
  className: "altertable-refresh-cancel",
9141
9427
  size: 17,
@@ -9145,11 +9431,14 @@ function AppToolbar({
9145
9431
  ]
9146
9432
  })
9147
9433
  }),
9148
- live && /* @__PURE__ */ jsx32(LiveControl, {
9434
+ live && /* @__PURE__ */ jsx34(LiveControl, {
9149
9435
  ...live
9150
9436
  }),
9151
9437
  aboutData,
9152
- story && /* @__PURE__ */ jsx32(PresentStory, {
9438
+ !!csvExport?.tables.length && /* @__PURE__ */ jsx34(ExportControl, {
9439
+ csv: csvExport
9440
+ }),
9441
+ story && /* @__PURE__ */ jsx34(PresentStory, {
9153
9442
  ...story
9154
9443
  }),
9155
9444
  end
@@ -9159,7 +9448,7 @@ function AppToolbar({
9159
9448
  }
9160
9449
 
9161
9450
  // src/react/ui/VariableBar.tsx
9162
- import { jsx as jsx33 } from "react/jsx-runtime";
9451
+ import { jsx as jsx35 } from "react/jsx-runtime";
9163
9452
  function VariableBar({
9164
9453
  children,
9165
9454
  className,
@@ -9167,7 +9456,7 @@ function VariableBar({
9167
9456
  "aria-label": ariaLabel = "View variables",
9168
9457
  ...props
9169
9458
  }) {
9170
- return /* @__PURE__ */ jsx33("div", {
9459
+ return /* @__PURE__ */ jsx35("div", {
9171
9460
  ...props,
9172
9461
  className: classNames("altertable-variable-bar", className),
9173
9462
  role,
@@ -9177,15 +9466,15 @@ function VariableBar({
9177
9466
  }
9178
9467
 
9179
9468
  // src/react/ui/DataViewToast.tsx
9180
- import { useEffect as useEffect13, useState as useState14 } from "react";
9181
- import { jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
9469
+ import { useEffect as useEffect13, useState as useState15 } from "react";
9470
+ import { jsx as jsx36 } from "react/jsx-runtime";
9182
9471
  function DataViewToast({
9183
9472
  view,
9184
9473
  message,
9185
9474
  notice,
9186
9475
  onRetry
9187
9476
  }) {
9188
- const [delay, setDelay] = useState14({ kind: view.kind, elapsed: false });
9477
+ const [delay, setDelay] = useState15({ kind: view.kind, elapsed: false });
9189
9478
  if (delay.kind !== view.kind)
9190
9479
  setDelay({ kind: view.kind, elapsed: false });
9191
9480
  useEffect13(() => {
@@ -9202,34 +9491,16 @@ function DataViewToast({
9202
9491
  const failed = showStaleError;
9203
9492
  const showingUpdate = view.kind === "updating" && showUpdating;
9204
9493
  const detail = view.kind === "stale-error" || view.kind === "updating" ? view.message : undefined;
9205
- const icon = failed ? "error" : showingUpdate ? "loading" : "live";
9206
- const state = failed ? "stale-error" : showingUpdate ? "updating" : "notice";
9207
- return /* @__PURE__ */ jsx34("div", {
9208
- className: "altertable-data-view-toast-region",
9209
- children: /* @__PURE__ */ jsxs24("div", {
9210
- className: "altertable-data-view-toast",
9211
- "data-state": state,
9212
- role: failed ? "alert" : "status",
9213
- children: [
9214
- /* @__PURE__ */ jsx34(AppIcon, {
9215
- name: icon,
9216
- size: 16,
9217
- className: showingUpdate ? "altertable-data-view-toast-spinner" : undefined
9218
- }),
9219
- /* @__PURE__ */ jsx34("span", {
9220
- children: failed ? message ?? detail : showingUpdate ? message ?? detail : notice
9221
- }),
9222
- failed && onRetry && /* @__PURE__ */ jsx34(Button, {
9223
- onClick: onRetry,
9224
- children: "Try again"
9225
- })
9226
- ]
9227
- })
9494
+ const state = failed ? "error" : showingUpdate ? "updating" : "notice";
9495
+ return /* @__PURE__ */ jsx36(Toast, {
9496
+ state,
9497
+ onRetry,
9498
+ children: failed || showingUpdate ? message ?? detail : notice
9228
9499
  });
9229
9500
  }
9230
9501
 
9231
9502
  // src/react/ui/ContentSkeleton.tsx
9232
- import { jsx as jsx35, jsxs as jsxs25 } from "react/jsx-runtime";
9503
+ import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
9233
9504
  function ContentSkeleton({
9234
9505
  variant,
9235
9506
  rows = 4,
@@ -9237,29 +9508,29 @@ function ContentSkeleton({
9237
9508
  ...props
9238
9509
  }) {
9239
9510
  invariant(Number.isInteger(rows) && rows >= 0 && rows <= 100, "Skeleton rows must be between 0 and 100.");
9240
- return /* @__PURE__ */ jsxs25("div", {
9511
+ return /* @__PURE__ */ jsxs26("div", {
9241
9512
  ...props,
9242
9513
  "aria-hidden": "true",
9243
9514
  className: classNames(`altertable-${variant === "metric" ? "metric-widget" : "data-widget"}`, "altertable-content-skeleton", className),
9244
9515
  children: [
9245
- /* @__PURE__ */ jsx35(Skeleton, {
9516
+ /* @__PURE__ */ jsx37(Skeleton, {
9246
9517
  className: "altertable-content-skeleton-label"
9247
9518
  }),
9248
- /* @__PURE__ */ jsx35(Skeleton, {
9519
+ /* @__PURE__ */ jsx37(Skeleton, {
9249
9520
  className: variant === "metric" ? "altertable-content-skeleton-value" : variant === "ranking" ? "altertable-content-skeleton-subtitle" : "altertable-content-skeleton-chart"
9250
9521
  }),
9251
- variant === "panel" && /* @__PURE__ */ jsx35(Skeleton, {
9522
+ variant === "panel" && /* @__PURE__ */ jsx37(Skeleton, {
9252
9523
  className: "altertable-content-skeleton-foot"
9253
9524
  }),
9254
- variant === "ranking" && /* @__PURE__ */ jsx35("div", {
9525
+ variant === "ranking" && /* @__PURE__ */ jsx37("div", {
9255
9526
  className: "altertable-content-skeleton-rows",
9256
- children: Array.from({ length: rows }, (_, index) => index).map((row) => /* @__PURE__ */ jsxs25("div", {
9527
+ children: Array.from({ length: rows }, (_, index) => index).map((row) => /* @__PURE__ */ jsxs26("div", {
9257
9528
  className: "altertable-content-skeleton-row",
9258
9529
  children: [
9259
- /* @__PURE__ */ jsx35(Skeleton, {
9530
+ /* @__PURE__ */ jsx37(Skeleton, {
9260
9531
  className: "altertable-content-skeleton-row-label"
9261
9532
  }),
9262
- /* @__PURE__ */ jsx35(Skeleton, {
9533
+ /* @__PURE__ */ jsx37(Skeleton, {
9263
9534
  className: "altertable-content-skeleton-row-track"
9264
9535
  })
9265
9536
  ]
@@ -9270,7 +9541,7 @@ function ContentSkeleton({
9270
9541
  }
9271
9542
 
9272
9543
  // src/react/ui/DataBoundary.tsx
9273
- import { jsx as jsx36, jsxs as jsxs26 } from "react/jsx-runtime";
9544
+ import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
9274
9545
  function DataBoundary({
9275
9546
  view,
9276
9547
  loading,
@@ -9284,41 +9555,41 @@ function DataBoundary({
9284
9555
  ...props
9285
9556
  }) {
9286
9557
  if (view.kind === "loading" || view.kind === "empty" || view.kind === "error")
9287
- return /* @__PURE__ */ jsx36("div", {
9558
+ return /* @__PURE__ */ jsx38("div", {
9288
9559
  ...props,
9289
9560
  className: classNames("altertable-data-boundary", className),
9290
9561
  children: view.kind === "loading" ? loading : view.kind === "empty" ? empty : error(view.error)
9291
9562
  });
9292
9563
  const updating = view.kind === "updating";
9293
9564
  const hasStaleError = view.kind === "stale-error";
9294
- return /* @__PURE__ */ jsxs26("div", {
9565
+ return /* @__PURE__ */ jsxs27("div", {
9295
9566
  ...props,
9296
9567
  className: classNames("altertable-data-boundary", className),
9297
9568
  children: [
9298
- notice === "inline" && (updating || hasStaleError) && /* @__PURE__ */ jsxs26("div", {
9569
+ notice === "inline" && (updating || hasStaleError) && /* @__PURE__ */ jsxs27("div", {
9299
9570
  className: "altertable-data-boundary-notice",
9300
9571
  "data-state": view.kind,
9301
9572
  role: hasStaleError ? "alert" : "status",
9302
9573
  children: [
9303
- updating ? /* @__PURE__ */ jsx36(AppIcon, {
9574
+ updating ? /* @__PURE__ */ jsx38(AppIcon, {
9304
9575
  name: "loading",
9305
9576
  size: 16,
9306
9577
  className: "altertable-data-boundary-spinner"
9307
- }) : /* @__PURE__ */ jsx36(AppIcon, {
9578
+ }) : /* @__PURE__ */ jsx38(AppIcon, {
9308
9579
  name: "error",
9309
9580
  size: 16
9310
9581
  }),
9311
- /* @__PURE__ */ jsx36("span", {
9582
+ /* @__PURE__ */ jsx38("span", {
9312
9583
  className: "altertable-data-boundary-message",
9313
9584
  children: view.message
9314
9585
  }),
9315
- staleError && view.kind === "stale-error" && /* @__PURE__ */ jsx36("span", {
9586
+ staleError && view.kind === "stale-error" && /* @__PURE__ */ jsx38("span", {
9316
9587
  className: "altertable-data-boundary-action",
9317
9588
  children: staleError(view.error)
9318
9589
  })
9319
9590
  ]
9320
9591
  }),
9321
- /* @__PURE__ */ jsx36("div", {
9592
+ /* @__PURE__ */ jsx38("div", {
9322
9593
  className: "altertable-data-boundary-content",
9323
9594
  "data-updating": updating && dimOnUpdate || undefined,
9324
9595
  children: children(view.data, view.kind === "ready" ? view.input : view.displayedInput)
@@ -9328,7 +9599,7 @@ function DataBoundary({
9328
9599
  }
9329
9600
 
9330
9601
  // src/react/ui/StatusPanel.tsx
9331
- import { jsx as jsx37, jsxs as jsxs27 } from "react/jsx-runtime";
9602
+ import { jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
9332
9603
  function StatusPanel({
9333
9604
  status,
9334
9605
  title,
@@ -9340,32 +9611,32 @@ function StatusPanel({
9340
9611
  role,
9341
9612
  ...props
9342
9613
  }) {
9343
- return /* @__PURE__ */ jsxs27("div", {
9614
+ return /* @__PURE__ */ jsxs28("div", {
9344
9615
  ...props,
9345
9616
  className: classNames("altertable-status-panel", className),
9346
9617
  "data-status": status,
9347
9618
  role: role ?? (status === "error" ? "alert" : "status"),
9348
9619
  children: [
9349
- status === "error" && /* @__PURE__ */ jsx37(AppIcon, {
9620
+ status === "error" && /* @__PURE__ */ jsx39(AppIcon, {
9350
9621
  name: "error",
9351
9622
  size: 18
9352
9623
  }),
9353
- /* @__PURE__ */ jsxs27("div", {
9624
+ /* @__PURE__ */ jsxs28("div", {
9354
9625
  className: "altertable-status-copy",
9355
9626
  children: [
9356
- /* @__PURE__ */ jsx37("strong", {
9627
+ /* @__PURE__ */ jsx39("strong", {
9357
9628
  children: title
9358
9629
  }),
9359
- description && /* @__PURE__ */ jsx37("p", {
9630
+ description && /* @__PURE__ */ jsx39("p", {
9360
9631
  children: description
9361
9632
  }),
9362
- details && /* @__PURE__ */ jsx37("small", {
9633
+ details && /* @__PURE__ */ jsx39("small", {
9363
9634
  children: details
9364
9635
  }),
9365
9636
  children
9366
9637
  ]
9367
9638
  }),
9368
- action && /* @__PURE__ */ jsx37("div", {
9639
+ action && /* @__PURE__ */ jsx39("div", {
9369
9640
  className: "altertable-status-action",
9370
9641
  children: action
9371
9642
  })
@@ -9374,7 +9645,7 @@ function StatusPanel({
9374
9645
  }
9375
9646
 
9376
9647
  // src/react/ui/DataSection.tsx
9377
- import { jsx as jsx38 } from "react/jsx-runtime";
9648
+ import { jsx as jsx40 } from "react/jsx-runtime";
9378
9649
  function errorPresentation(cause) {
9379
9650
  const code = cause instanceof DataAppError2 ? cause.code : "request_failed";
9380
9651
  switch (code) {
@@ -9433,33 +9704,33 @@ function DataSection({
9433
9704
  dimOnUpdate = false,
9434
9705
  ...props
9435
9706
  }) {
9436
- return /* @__PURE__ */ jsx38(DataBoundary, {
9707
+ return /* @__PURE__ */ jsx40(DataBoundary, {
9437
9708
  ...props,
9438
9709
  view: result.view,
9439
9710
  role: label ? "region" : undefined,
9440
9711
  "aria-label": label,
9441
9712
  notice,
9442
9713
  dimOnUpdate,
9443
- loading: loading ?? /* @__PURE__ */ jsx38(ContentSkeleton, {
9714
+ loading: loading ?? /* @__PURE__ */ jsx40(ContentSkeleton, {
9444
9715
  variant: "panel"
9445
9716
  }),
9446
- empty: /* @__PURE__ */ jsx38(EmptyState, {
9717
+ empty: /* @__PURE__ */ jsx40(EmptyState, {
9447
9718
  ...empty
9448
9719
  }),
9449
9720
  error: (cause) => {
9450
9721
  const presentation = errorPresentation(cause);
9451
9722
  const retryAction = error?.onRetry ?? (presentation.retryable ? () => void result.refetch() : undefined);
9452
- return /* @__PURE__ */ jsx38(StatusPanel, {
9723
+ return /* @__PURE__ */ jsx40(StatusPanel, {
9453
9724
  status: "error",
9454
9725
  title: error?.title ?? presentation.title,
9455
9726
  description: error?.description ?? presentation.description,
9456
- action: retryAction && /* @__PURE__ */ jsx38(Button, {
9727
+ action: retryAction && /* @__PURE__ */ jsx40(Button, {
9457
9728
  onClick: retryAction,
9458
9729
  children: "Retry"
9459
9730
  })
9460
9731
  });
9461
9732
  },
9462
- staleError: () => /* @__PURE__ */ jsx38(Button, {
9733
+ staleError: () => /* @__PURE__ */ jsx40(Button, {
9463
9734
  onClick: error?.onRetry ?? (() => void result.refetch()),
9464
9735
  children: "Retry"
9465
9736
  }),
@@ -9468,7 +9739,7 @@ function DataSection({
9468
9739
  }
9469
9740
 
9470
9741
  // src/react/ui/DataApp.tsx
9471
- import { jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
9742
+ import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
9472
9743
  function DataApp(props) {
9473
9744
  const {
9474
9745
  config,
@@ -9492,12 +9763,14 @@ function DataApp(props) {
9492
9763
  console.warn("DataApp owns the page title. Use section headings (h2) in its body.");
9493
9764
  });
9494
9765
  const snapshot = request && displayedSnapshot(request.view);
9495
- const story = request && props.story && snapshot ? { findings: props.story(snapshot) } : undefined;
9496
- const scope = /* @__PURE__ */ jsx39(AppScope, {
9766
+ const findings = request && snapshot ? props.story(snapshot) : undefined;
9767
+ const story = findings?.length ? { findings } : undefined;
9768
+ const scope = /* @__PURE__ */ jsx41(AppScope, {
9497
9769
  organization: scopeLabels?.organization ?? config.scope.organization,
9498
9770
  environment: scopeLabels?.environment ?? config.scope.environment
9499
9771
  });
9500
- const toolbar = /* @__PURE__ */ jsx39(AppToolbar, {
9772
+ const toolbar = /* @__PURE__ */ jsx41(AppToolbar, {
9773
+ csvExport: request ? snapshot ? props.csvExport(snapshot) : undefined : props.csvExport,
9501
9774
  requestState: request?.view.kind,
9502
9775
  refresh: refresh ?? request?.refresh,
9503
9776
  story: story && {
@@ -9508,7 +9781,7 @@ function DataApp(props) {
9508
9781
  empty: aboutEmpty,
9509
9782
  theme: themeController
9510
9783
  },
9511
- aboutData: /* @__PURE__ */ jsx39(AboutData, {
9784
+ aboutData: /* @__PURE__ */ jsx41(AboutData, {
9512
9785
  id: "data",
9513
9786
  shortcut: true,
9514
9787
  dataContext,
@@ -9519,32 +9792,32 @@ function DataApp(props) {
9519
9792
  }),
9520
9793
  children: toolbarActions
9521
9794
  });
9522
- return /* @__PURE__ */ jsx39(InspectionContext, {
9795
+ return /* @__PURE__ */ jsx41(InspectionContext, {
9523
9796
  value: {
9524
9797
  dataContext,
9525
9798
  empty: aboutEmpty,
9526
9799
  queries: queries ?? request?.queries
9527
9800
  },
9528
- children: /* @__PURE__ */ jsxs28(AppLayout, {
9801
+ children: /* @__PURE__ */ jsxs29(AppLayout, {
9529
9802
  ...layoutProps,
9530
9803
  footer: isEmbedded ? null : layoutProps?.footer,
9531
- footerActions: footerActions ?? (themeController && /* @__PURE__ */ jsx39(ThemeToggle, {
9804
+ footerActions: footerActions ?? (themeController && /* @__PURE__ */ jsx41(ThemeToggle, {
9532
9805
  theme: themeController
9533
9806
  })),
9534
9807
  children: [
9535
- isEmbedded ? toolbar : /* @__PURE__ */ jsx39(AppHeader, {
9808
+ isEmbedded ? toolbar : /* @__PURE__ */ jsx41(AppHeader, {
9536
9809
  scope,
9537
9810
  title: config.title,
9538
9811
  description,
9539
9812
  toolbar
9540
9813
  }),
9541
- (request?.controls ?? props.variables) && /* @__PURE__ */ jsx39(VariableBar, {
9814
+ (request?.controls ?? props.variables) && /* @__PURE__ */ jsx41(VariableBar, {
9542
9815
  children: request?.controls ?? props.variables
9543
9816
  }),
9544
- /* @__PURE__ */ jsx39("div", {
9817
+ /* @__PURE__ */ jsx41("div", {
9545
9818
  ref: bodyRef,
9546
9819
  className: "altertable-app-body",
9547
- children: request ? /* @__PURE__ */ jsx39(DataSection, {
9820
+ children: request ? /* @__PURE__ */ jsx41(DataSection, {
9548
9821
  result: request,
9549
9822
  notice: "none",
9550
9823
  dimOnUpdate: false,
@@ -9554,7 +9827,7 @@ function DataApp(props) {
9554
9827
  children: (data, displayedInput) => props.children(data, displayedInput)
9555
9828
  }) : props.children
9556
9829
  }),
9557
- request && /* @__PURE__ */ jsx39(DataViewToast, {
9830
+ request && /* @__PURE__ */ jsx41(DataViewToast, {
9558
9831
  view: request.view,
9559
9832
  onRetry: () => void request.refetch()
9560
9833
  })
@@ -9563,7 +9836,7 @@ function DataApp(props) {
9563
9836
  });
9564
9837
  }
9565
9838
  // src/react/ui/GettingStarted.tsx
9566
- import { jsx as jsx40, jsxs as jsxs29 } from "react/jsx-runtime";
9839
+ import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
9567
9840
  var client = /* @__PURE__ */ createDataClient2();
9568
9841
  var { useDataQuery } = /* @__PURE__ */ createDataHooks(client);
9569
9842
  function GettingStarted({
@@ -9572,7 +9845,7 @@ function GettingStarted({
9572
9845
  }) {
9573
9846
  const connection = useDataQuery("connection", {});
9574
9847
  const state = connection.error ? "error" : connection.isFetching || !connection.data ? "checking" : "connected";
9575
- return /* @__PURE__ */ jsxs29(DataApp, {
9848
+ return /* @__PURE__ */ jsxs30(DataApp, {
9576
9849
  config,
9577
9850
  dataContext,
9578
9851
  description: "Check your lakehouse connection, then build a view around a real question.",
@@ -9586,98 +9859,98 @@ function GettingStarted({
9586
9859
  buttonProps: { "aria-label": "Check connection" }
9587
9860
  },
9588
9861
  children: [
9589
- /* @__PURE__ */ jsxs29("section", {
9862
+ /* @__PURE__ */ jsxs30("section", {
9590
9863
  className: "starter-connection",
9591
9864
  "data-state": state,
9592
9865
  role: state === "error" ? "alert" : "status",
9593
9866
  children: [
9594
- /* @__PURE__ */ jsx40("div", {
9867
+ /* @__PURE__ */ jsx42("div", {
9595
9868
  className: "starter-connection-icon",
9596
- children: /* @__PURE__ */ jsx40(AppIcon, {
9869
+ children: /* @__PURE__ */ jsx42(AppIcon, {
9597
9870
  name: state === "connected" ? "check" : state === "error" ? "error" : "loading",
9598
9871
  size: 24
9599
9872
  })
9600
9873
  }),
9601
- /* @__PURE__ */ jsxs29("div", {
9874
+ /* @__PURE__ */ jsxs30("div", {
9602
9875
  className: "starter-connection-copy",
9603
9876
  children: [
9604
- /* @__PURE__ */ jsx40("span", {
9877
+ /* @__PURE__ */ jsx42("span", {
9605
9878
  className: "starter-eyebrow",
9606
9879
  children: "Lakehouse connection"
9607
9880
  }),
9608
- /* @__PURE__ */ jsx40("h2", {
9881
+ /* @__PURE__ */ jsx42("h2", {
9609
9882
  children: state === "connected" ? "Connected" : state === "error" ? "Connection not verified" : "Checking connection…"
9610
9883
  }),
9611
- /* @__PURE__ */ jsx40("p", {
9884
+ /* @__PURE__ */ jsx42("p", {
9612
9885
  children: state === "connected" ? "A query completed successfully using this app’s current profile. You’re ready to build your first view." : state === "error" ? connection.data ? "An earlier query succeeded, but the latest check failed. Check the profile and try again." : "The query could not complete. Check the profile and lakehouse access, then try again." : "Running a lightweight query with this app’s current profile."
9613
9886
  }),
9614
- state === "connected" && /* @__PURE__ */ jsx40("small", {
9887
+ state === "connected" && /* @__PURE__ */ jsx42("small", {
9615
9888
  children: "This check does not verify access to every dataset."
9616
9889
  })
9617
9890
  ]
9618
9891
  }),
9619
- state === "error" && /* @__PURE__ */ jsx40(Button, {
9892
+ state === "error" && /* @__PURE__ */ jsx42(Button, {
9620
9893
  onClick: () => void connection.refetch(),
9621
9894
  children: "Try again"
9622
9895
  })
9623
9896
  ]
9624
9897
  }),
9625
- /* @__PURE__ */ jsxs29("section", {
9898
+ /* @__PURE__ */ jsxs30("section", {
9626
9899
  className: "starter-next",
9627
9900
  "aria-labelledby": "starter-next-title",
9628
9901
  children: [
9629
- /* @__PURE__ */ jsxs29("div", {
9902
+ /* @__PURE__ */ jsxs30("div", {
9630
9903
  className: "starter-next-heading",
9631
9904
  children: [
9632
- /* @__PURE__ */ jsx40("span", {
9905
+ /* @__PURE__ */ jsx42("span", {
9633
9906
  className: "starter-eyebrow",
9634
9907
  children: "Next steps"
9635
9908
  }),
9636
- /* @__PURE__ */ jsx40("h2", {
9909
+ /* @__PURE__ */ jsx42("h2", {
9637
9910
  id: "starter-next-title",
9638
9911
  children: "Turn this starter into a useful app"
9639
9912
  }),
9640
- /* @__PURE__ */ jsx40("p", {
9913
+ /* @__PURE__ */ jsx42("p", {
9641
9914
  children: "Start with one question your readers need answered."
9642
9915
  })
9643
9916
  ]
9644
9917
  }),
9645
- /* @__PURE__ */ jsxs29("ol", {
9918
+ /* @__PURE__ */ jsxs30("ol", {
9646
9919
  className: "starter-steps",
9647
9920
  children: [
9648
- /* @__PURE__ */ jsxs29("li", {
9921
+ /* @__PURE__ */ jsxs30("li", {
9649
9922
  children: [
9650
- /* @__PURE__ */ jsx40("strong", {
9923
+ /* @__PURE__ */ jsx42("strong", {
9651
9924
  children: "Choose a question"
9652
9925
  }),
9653
- /* @__PURE__ */ jsx40("p", {
9926
+ /* @__PURE__ */ jsx42("p", {
9654
9927
  children: "Decide what someone should learn or do after opening this app."
9655
9928
  })
9656
9929
  ]
9657
9930
  }),
9658
- /* @__PURE__ */ jsxs29("li", {
9931
+ /* @__PURE__ */ jsxs30("li", {
9659
9932
  children: [
9660
- /* @__PURE__ */ jsx40("strong", {
9933
+ /* @__PURE__ */ jsx42("strong", {
9661
9934
  children: "Find the right data"
9662
9935
  }),
9663
- /* @__PURE__ */ jsx40("p", {
9936
+ /* @__PURE__ */ jsx42("p", {
9664
9937
  children: "Inspect the relevant catalogs, tables, and columns before writing the query."
9665
9938
  })
9666
9939
  ]
9667
9940
  }),
9668
- /* @__PURE__ */ jsxs29("li", {
9941
+ /* @__PURE__ */ jsxs30("li", {
9669
9942
  children: [
9670
- /* @__PURE__ */ jsx40("strong", {
9943
+ /* @__PURE__ */ jsx42("strong", {
9671
9944
  children: "Build the first view"
9672
9945
  }),
9673
- /* @__PURE__ */ jsxs29("p", {
9946
+ /* @__PURE__ */ jsxs30("p", {
9674
9947
  children: [
9675
9948
  "Replace the connection check in ",
9676
- /* @__PURE__ */ jsx40("code", {
9949
+ /* @__PURE__ */ jsx42("code", {
9677
9950
  children: "src/operations.ts"
9678
9951
  }),
9679
9952
  ", then render its result in ",
9680
- /* @__PURE__ */ jsx40("code", {
9953
+ /* @__PURE__ */ jsx42("code", {
9681
9954
  children: "src/App.tsx"
9682
9955
  }),
9683
9956
  "."
@@ -9693,14 +9966,14 @@ function GettingStarted({
9693
9966
  });
9694
9967
  }
9695
9968
  // src/react/ui/Stack.tsx
9696
- import { jsx as jsx41 } from "react/jsx-runtime";
9969
+ import { jsx as jsx43 } from "react/jsx-runtime";
9697
9970
  function Stack({
9698
9971
  children,
9699
9972
  gap = "lg",
9700
9973
  className,
9701
9974
  ...props
9702
9975
  }) {
9703
- return /* @__PURE__ */ jsx41("div", {
9976
+ return /* @__PURE__ */ jsx43("div", {
9704
9977
  ...props,
9705
9978
  className: classNames("altertable-stack", className),
9706
9979
  "data-gap": gap,
@@ -9708,7 +9981,7 @@ function Stack({
9708
9981
  });
9709
9982
  }
9710
9983
  // src/react/ui/Grid.tsx
9711
- import { jsx as jsx42 } from "react/jsx-runtime";
9984
+ import { jsx as jsx44 } from "react/jsx-runtime";
9712
9985
  function Grid({
9713
9986
  children,
9714
9987
  columns = 1,
@@ -9718,7 +9991,7 @@ function Grid({
9718
9991
  className,
9719
9992
  ...props
9720
9993
  }) {
9721
- return /* @__PURE__ */ jsx42("div", {
9994
+ return /* @__PURE__ */ jsx44("div", {
9722
9995
  ...props,
9723
9996
  className: classNames("altertable-grid", className),
9724
9997
  "data-columns": columns,
@@ -9729,14 +10002,14 @@ function Grid({
9729
10002
  });
9730
10003
  }
9731
10004
  // src/react/ui/GridItem.tsx
9732
- import { jsx as jsx43 } from "react/jsx-runtime";
10005
+ import { jsx as jsx45 } from "react/jsx-runtime";
9733
10006
  function GridItem({
9734
10007
  children,
9735
10008
  span = 1,
9736
10009
  className,
9737
10010
  ...props
9738
10011
  }) {
9739
- return /* @__PURE__ */ jsx43("div", {
10012
+ return /* @__PURE__ */ jsx45("div", {
9740
10013
  ...props,
9741
10014
  className: classNames("altertable-grid-item", className),
9742
10015
  "data-span": span,
@@ -9745,24 +10018,24 @@ function GridItem({
9745
10018
  }
9746
10019
  // src/react/ui/DataWidget.tsx
9747
10020
  import { useId as useId8 } from "react";
9748
- import { jsx as jsx44, jsxs as jsxs30, Fragment as Fragment8 } from "react/jsx-runtime";
10021
+ import { jsx as jsx46, jsxs as jsxs31, Fragment as Fragment9 } from "react/jsx-runtime";
9749
10022
  function DataWidget(props) {
9750
10023
  if (props.reading) {
9751
10024
  const { reading, isEmpty, empty, skeleton, children, ...shell } = props;
9752
10025
  if (reading.loading)
9753
- return /* @__PURE__ */ jsx44(ContentSkeleton, {
10026
+ return /* @__PURE__ */ jsx46(ContentSkeleton, {
9754
10027
  variant: "panel",
9755
10028
  ...skeleton,
9756
10029
  className: shell.className
9757
10030
  });
9758
10031
  const noData = isEmpty(reading.value);
9759
- return /* @__PURE__ */ jsx44(DataWidgetContent, {
10032
+ return /* @__PURE__ */ jsx46(DataWidgetContent, {
9760
10033
  ...shell,
9761
10034
  empty: noData ? empty : undefined,
9762
10035
  children: noData ? null : children(reading.value)
9763
10036
  });
9764
10037
  }
9765
- return /* @__PURE__ */ jsx44(DataWidgetContent, {
10038
+ return /* @__PURE__ */ jsx46(DataWidgetContent, {
9766
10039
  ...props
9767
10040
  });
9768
10041
  }
@@ -9781,16 +10054,16 @@ function DataWidgetContent({
9781
10054
  ...props
9782
10055
  }) {
9783
10056
  const titleId = useId8();
9784
- const content = empty ? /* @__PURE__ */ jsx44(EmptyState, {
10057
+ const content = empty ? /* @__PURE__ */ jsx46(EmptyState, {
9785
10058
  ...empty
9786
10059
  }) : children;
9787
- const visual = /* @__PURE__ */ jsx44(WidgetContent, {
10060
+ const visual = /* @__PURE__ */ jsx46(WidgetContent, {
9788
10061
  bodyPadding: empty ? "flush" : bodyPadding,
9789
10062
  footer: empty ? undefined : footer,
9790
10063
  status,
9791
10064
  children: content
9792
10065
  });
9793
- const help = evidence && /* @__PURE__ */ jsxs30(AboutData, {
10066
+ const help = evidence && /* @__PURE__ */ jsxs31(AboutData, {
9794
10067
  id: evidence.id,
9795
10068
  references: {
9796
10069
  kind: "ids",
@@ -9803,7 +10076,7 @@ function DataWidgetContent({
9803
10076
  tooltip: "Explore this widget",
9804
10077
  shortcut: false,
9805
10078
  title,
9806
- headerActions: /* @__PURE__ */ jsx44(WidgetStatusControl, {
10079
+ headerActions: /* @__PURE__ */ jsx46(WidgetStatusControl, {
9807
10080
  status
9808
10081
  }),
9809
10082
  description,
@@ -9811,41 +10084,41 @@ function DataWidgetContent({
9811
10084
  visualKind: "widget",
9812
10085
  children: [
9813
10086
  title,
9814
- /* @__PURE__ */ jsx44(AppIcon, {
10087
+ /* @__PURE__ */ jsx46(AppIcon, {
9815
10088
  name: "openDetails"
9816
10089
  })
9817
10090
  ]
9818
10091
  });
9819
- return /* @__PURE__ */ jsxs30("section", {
10092
+ return /* @__PURE__ */ jsxs31("section", {
9820
10093
  ...props,
9821
10094
  className: classNames("altertable-data-widget", className),
9822
10095
  "aria-labelledby": props["aria-labelledby"] ?? titleId,
9823
10096
  children: [
9824
- /* @__PURE__ */ jsxs30("header", {
10097
+ /* @__PURE__ */ jsxs31("header", {
9825
10098
  className: "altertable-data-widget-header",
9826
10099
  children: [
9827
- /* @__PURE__ */ jsxs30("div", {
10100
+ /* @__PURE__ */ jsxs31("div", {
9828
10101
  children: [
9829
- /* @__PURE__ */ jsxs30("h2", {
10102
+ /* @__PURE__ */ jsxs31("h2", {
9830
10103
  id: titleId,
9831
10104
  "aria-label": typeof title === "string" ? title : undefined,
9832
10105
  children: [
9833
10106
  help ?? title,
9834
- count !== undefined && /* @__PURE__ */ jsx44("span", {
10107
+ count !== undefined && /* @__PURE__ */ jsx46("span", {
9835
10108
  className: "altertable-data-widget-count",
9836
10109
  children: formatCount2(count)
9837
10110
  })
9838
10111
  ]
9839
10112
  }),
9840
- description && /* @__PURE__ */ jsx44("p", {
10113
+ description && /* @__PURE__ */ jsx46("p", {
9841
10114
  children: description
9842
10115
  })
9843
10116
  ]
9844
10117
  }),
9845
- /* @__PURE__ */ jsxs30("div", {
10118
+ /* @__PURE__ */ jsxs31("div", {
9846
10119
  className: "altertable-data-widget-help",
9847
10120
  children: [
9848
- /* @__PURE__ */ jsx44(WidgetStatusControl, {
10121
+ /* @__PURE__ */ jsx46(WidgetStatusControl, {
9849
10122
  status
9850
10123
  }),
9851
10124
  action
@@ -9863,15 +10136,15 @@ function WidgetContent({
9863
10136
  status,
9864
10137
  children
9865
10138
  }) {
9866
- return /* @__PURE__ */ jsxs30(Fragment8, {
10139
+ return /* @__PURE__ */ jsxs31(Fragment9, {
9867
10140
  children: [
9868
- /* @__PURE__ */ jsx44("div", {
10141
+ /* @__PURE__ */ jsx46("div", {
9869
10142
  className: "altertable-data-widget-body",
9870
10143
  "data-padding": bodyPadding,
9871
10144
  "aria-busy": status?.kind === "updating" || undefined,
9872
10145
  children
9873
10146
  }),
9874
- footer && /* @__PURE__ */ jsx44("footer", {
10147
+ footer && /* @__PURE__ */ jsx46("footer", {
9875
10148
  className: "altertable-data-widget-footer",
9876
10149
  children: footer
9877
10150
  })
@@ -9879,39 +10152,39 @@ function WidgetContent({
9879
10152
  });
9880
10153
  }
9881
10154
  // src/react/ui/TextContent.tsx
9882
- import { jsx as jsx45 } from "react/jsx-runtime";
10155
+ import { jsx as jsx47 } from "react/jsx-runtime";
9883
10156
  function TextContent({ className, ...props }) {
9884
- return /* @__PURE__ */ jsx45("div", {
10157
+ return /* @__PURE__ */ jsx47("div", {
9885
10158
  ...props,
9886
10159
  className: classNames("altertable-text-content", className)
9887
10160
  });
9888
10161
  }
9889
10162
  // src/react/ui/TextWidget.tsx
9890
- import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
10163
+ import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
9891
10164
  function TextWidget(props) {
9892
10165
  const content = props.reading ? props.reading.loading ? null : props.children(props.reading.value) : props.children;
9893
10166
  const { reading, children: _, className, ...shell } = props;
9894
10167
  const loading = reading?.loading === true;
9895
- return /* @__PURE__ */ jsx46(DataWidget, {
10168
+ return /* @__PURE__ */ jsx48(DataWidget, {
9896
10169
  ...shell,
9897
10170
  className: classNames("altertable-text-widget", className),
9898
10171
  evidence: loading ? undefined : shell.evidence,
9899
10172
  "aria-busy": loading || shell["aria-busy"],
9900
- children: /* @__PURE__ */ jsx46(TextContent, {
9901
- children: loading ? /* @__PURE__ */ jsxs31("div", {
10173
+ children: /* @__PURE__ */ jsx48(TextContent, {
10174
+ children: loading ? /* @__PURE__ */ jsxs32("div", {
9902
10175
  className: "altertable-text-widget-skeleton",
9903
10176
  "aria-hidden": "true",
9904
10177
  children: [
9905
- /* @__PURE__ */ jsx46(Skeleton, {}),
9906
- /* @__PURE__ */ jsx46(Skeleton, {}),
9907
- /* @__PURE__ */ jsx46(Skeleton, {})
10178
+ /* @__PURE__ */ jsx48(Skeleton, {}),
10179
+ /* @__PURE__ */ jsx48(Skeleton, {}),
10180
+ /* @__PURE__ */ jsx48(Skeleton, {})
9908
10181
  ]
9909
10182
  }) : content
9910
10183
  })
9911
10184
  });
9912
10185
  }
9913
10186
  // src/react/ui/VisualizationWidget.tsx
9914
- import { useState as useState15 } from "react";
10187
+ import { useState as useState16 } from "react";
9915
10188
 
9916
10189
  // src/react/ui/widget-views.ts
9917
10190
  function validateWidgetViews(views, selected) {
@@ -9921,7 +10194,7 @@ function validateWidgetViews(views, selected) {
9921
10194
  }
9922
10195
 
9923
10196
  // src/react/ui/WidgetViewTabs.tsx
9924
- import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
10197
+ import { jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
9925
10198
  function WidgetViewTabs({
9926
10199
  label,
9927
10200
  views,
@@ -9931,24 +10204,24 @@ function WidgetViewTabs({
9931
10204
  ...props
9932
10205
  }) {
9933
10206
  validateWidgetViews(views, selectedKey);
9934
- return /* @__PURE__ */ jsx47("div", {
10207
+ return /* @__PURE__ */ jsx49("div", {
9935
10208
  ...props,
9936
10209
  className: classNames("altertable-widget-view-tabs", className),
9937
- children: /* @__PURE__ */ jsxs32(Tabs, {
10210
+ children: /* @__PURE__ */ jsxs33(Tabs, {
9938
10211
  selectedKey,
9939
10212
  onSelectionChange: (key) => onSelectionChange(String(key)),
9940
10213
  children: [
9941
- /* @__PURE__ */ jsx47(TabList, {
10214
+ /* @__PURE__ */ jsx49(TabList, {
9942
10215
  "aria-label": label,
9943
- children: views.map((view) => /* @__PURE__ */ jsx47(Tab, {
10216
+ children: views.map((view) => /* @__PURE__ */ jsx49(Tab, {
9944
10217
  id: view.id,
9945
10218
  children: view.label
9946
10219
  }, view.id))
9947
10220
  }),
9948
- /* @__PURE__ */ jsx47(TabPanels, {
9949
- children: views.map((view) => /* @__PURE__ */ jsx47(TabPanel, {
10221
+ /* @__PURE__ */ jsx49(TabPanels, {
10222
+ children: views.map((view) => /* @__PURE__ */ jsx49(TabPanel, {
9950
10223
  id: view.id,
9951
- children: view.isEmpty ? /* @__PURE__ */ jsx47(EmptyState, {
10224
+ children: view.isEmpty ? /* @__PURE__ */ jsx49(EmptyState, {
9952
10225
  ...view.empty
9953
10226
  }) : view.content
9954
10227
  }, view.id))
@@ -9959,22 +10232,22 @@ function WidgetViewTabs({
9959
10232
  }
9960
10233
 
9961
10234
  // src/react/ui/VisualizationWidget.tsx
9962
- import { jsx as jsx48 } from "react/jsx-runtime";
10235
+ import { jsx as jsx50 } from "react/jsx-runtime";
9963
10236
  function VisualizationWidget(props) {
9964
10237
  if ("views" in props && props.views)
9965
- return /* @__PURE__ */ jsx48(VisualizationWidgetWithViews, {
10238
+ return /* @__PURE__ */ jsx50(VisualizationWidgetWithViews, {
9966
10239
  ...props
9967
10240
  });
9968
10241
  if ("reading" in props) {
9969
10242
  const { reading, children, isEmpty, empty, skeleton, insight, ...shell } = props;
9970
- return /* @__PURE__ */ jsx48(DataWidget, {
10243
+ return /* @__PURE__ */ jsx50(DataWidget, {
9971
10244
  ...shell,
9972
10245
  reading,
9973
10246
  isEmpty,
9974
10247
  empty,
9975
10248
  skeleton,
9976
10249
  footer: insight,
9977
- children: (data) => /* @__PURE__ */ jsx48("div", {
10250
+ children: (data) => /* @__PURE__ */ jsx50("div", {
9978
10251
  className: "altertable-visualization-widget-content",
9979
10252
  children: children(data)
9980
10253
  })
@@ -9982,14 +10255,14 @@ function VisualizationWidget(props) {
9982
10255
  }
9983
10256
  const { visual, loading = false, insight, ...shell } = props;
9984
10257
  if (loading)
9985
- return /* @__PURE__ */ jsx48(ContentSkeleton, {
10258
+ return /* @__PURE__ */ jsx50(ContentSkeleton, {
9986
10259
  variant: "panel",
9987
10260
  className: shell.className
9988
10261
  });
9989
- return /* @__PURE__ */ jsx48(DataWidget, {
10262
+ return /* @__PURE__ */ jsx50(DataWidget, {
9990
10263
  ...shell,
9991
10264
  footer: insight,
9992
- children: /* @__PURE__ */ jsx48("div", {
10265
+ children: /* @__PURE__ */ jsx50("div", {
9993
10266
  className: "altertable-visualization-widget-content",
9994
10267
  children: visual
9995
10268
  })
@@ -10006,18 +10279,18 @@ function VisualizationWidgetWithViews({
10006
10279
  insight,
10007
10280
  ...shell
10008
10281
  }) {
10009
- const [selected, setSelected] = useState15(initialView ?? views[0]?.id ?? "");
10282
+ const [selected, setSelected] = useState16(initialView ?? views[0]?.id ?? "");
10010
10283
  validateWidgetViews(views, selected);
10011
- return /* @__PURE__ */ jsx48(DataWidget, {
10284
+ return /* @__PURE__ */ jsx50(DataWidget, {
10012
10285
  ...shell,
10013
10286
  reading,
10014
10287
  isEmpty,
10015
10288
  empty,
10016
10289
  skeleton,
10017
10290
  footer: insight,
10018
- children: (data) => /* @__PURE__ */ jsx48("div", {
10291
+ children: (data) => /* @__PURE__ */ jsx50("div", {
10019
10292
  className: "altertable-visualization-widget-content",
10020
- children: /* @__PURE__ */ jsx48(WidgetViewTabs, {
10293
+ children: /* @__PURE__ */ jsx50(WidgetViewTabs, {
10021
10294
  label: viewLabel,
10022
10295
  views: views.map((view) => ({
10023
10296
  id: view.id,
@@ -10033,14 +10306,14 @@ function VisualizationWidgetWithViews({
10033
10306
  });
10034
10307
  }
10035
10308
  // src/react/ui/TableWidget.tsx
10036
- import { useState as useState18 } from "react";
10309
+ import { useState as useState19 } from "react";
10037
10310
 
10038
10311
  // src/react/ui/DateTimeTooltip.tsx
10039
- import { useEffect as useEffect15, useState as useState17 } from "react";
10312
+ import { useEffect as useEffect15, useState as useState18 } from "react";
10040
10313
 
10041
10314
  // src/react/ui/HelpPopover.tsx
10042
10315
  import {
10043
- useState as useState16
10316
+ useState as useState17
10044
10317
  } from "react";
10045
10318
  import {
10046
10319
  autoUpdate as autoUpdate2,
@@ -10058,7 +10331,7 @@ import {
10058
10331
  useMergeRefs as useMergeRefs6,
10059
10332
  useRole
10060
10333
  } from "@floating-ui/react";
10061
- import { jsx as jsx49, jsxs as jsxs33, Fragment as Fragment9 } from "react/jsx-runtime";
10334
+ import { jsx as jsx51, jsxs as jsxs34, Fragment as Fragment10 } from "react/jsx-runtime";
10062
10335
  function HelpPopover({
10063
10336
  trigger,
10064
10337
  triggerLabel,
@@ -10073,8 +10346,8 @@ function HelpPopover({
10073
10346
  open: openProp,
10074
10347
  onOpenChange
10075
10348
  }) {
10076
- const [uncontrolledOpen, setUncontrolledOpen] = useState16(false);
10077
- const [dialogRoot, setDialogRoot] = useState16(null);
10349
+ const [uncontrolledOpen, setUncontrolledOpen] = useState17(false);
10350
+ const [dialogRoot, setDialogRoot] = useState17(null);
10078
10351
  const open = openProp ?? uncontrolledOpen;
10079
10352
  function setOpen(next) {
10080
10353
  onOpenChange?.(next);
@@ -10105,9 +10378,9 @@ function HelpPopover({
10105
10378
  (element) => setDialogRoot(element?.closest("dialog") ?? null)
10106
10379
  ]);
10107
10380
  const mergedPanelRef = useMergeRefs6([refs.setFloating, panelProps?.ref]);
10108
- return /* @__PURE__ */ jsxs33(Fragment9, {
10381
+ return /* @__PURE__ */ jsxs34(Fragment10, {
10109
10382
  children: [
10110
- /* @__PURE__ */ jsx49("button", {
10383
+ /* @__PURE__ */ jsx51("button", {
10111
10384
  ...getReferenceProps({
10112
10385
  ...triggerProps,
10113
10386
  "aria-label": triggerProps?.["aria-label"] ?? triggerLabel
@@ -10120,13 +10393,13 @@ function HelpPopover({
10120
10393
  "data-open": open,
10121
10394
  children: trigger
10122
10395
  }),
10123
- open && /* @__PURE__ */ jsx49(FloatingPortal2, {
10396
+ open && /* @__PURE__ */ jsx51(FloatingPortal2, {
10124
10397
  root: portalRoot ?? dialogRoot ?? undefined,
10125
- children: /* @__PURE__ */ jsx49(FloatingFocusManager, {
10398
+ children: /* @__PURE__ */ jsx51(FloatingFocusManager, {
10126
10399
  context,
10127
10400
  modal: false,
10128
10401
  initialFocus: -1,
10129
- children: /* @__PURE__ */ jsx49("section", {
10402
+ children: /* @__PURE__ */ jsx51("section", {
10130
10403
  ...getFloatingProps(panelProps ?? {}),
10131
10404
  ref: mergedPanelRef,
10132
10405
  className: classNames("altertable-help-popover", panelClassName, panelProps?.className),
@@ -10141,7 +10414,7 @@ function HelpPopover({
10141
10414
  }
10142
10415
 
10143
10416
  // src/react/ui/DateTimeTooltip.tsx
10144
- import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
10417
+ import { jsx as jsx52, jsxs as jsxs35 } from "react/jsx-runtime";
10145
10418
  function formattedDate(date, timeZone) {
10146
10419
  return new Intl.DateTimeFormat(undefined, {
10147
10420
  timeZone,
@@ -10163,7 +10436,7 @@ function DateTimeTooltip({
10163
10436
  panelClassName,
10164
10437
  ...props
10165
10438
  }) {
10166
- const [now, setNow] = useState17(Date.now);
10439
+ const [now, setNow] = useState18(Date.now);
10167
10440
  useEffect15(() => {
10168
10441
  const interval = window.setInterval(() => setNow(Date.now()), 30000);
10169
10442
  return () => window.clearInterval(interval);
@@ -10179,54 +10452,54 @@ function DateTimeTooltip({
10179
10452
  ...timeZone && timeZone !== browserTimeZone ? [{ label: `Browser · ${browserTimeZone}`, zone: browserTimeZone }] : []
10180
10453
  ];
10181
10454
  const timestamp = date.toISOString();
10182
- return /* @__PURE__ */ jsx50(HelpPopover, {
10455
+ return /* @__PURE__ */ jsx52(HelpPopover, {
10183
10456
  ...props,
10184
10457
  placement: props.placement ?? "bottom",
10185
10458
  triggerClassName,
10186
10459
  panelClassName: ["altertable-date-time-tooltip", panelClassName].filter(Boolean).join(" "),
10187
10460
  triggerLabel: "Show exact date and time",
10188
10461
  label: "Date and time details",
10189
- trigger: children ?? /* @__PURE__ */ jsx50("time", {
10462
+ trigger: children ?? /* @__PURE__ */ jsx52("time", {
10190
10463
  dateTime: timestamp,
10191
10464
  children: formattedDate(date, timeZone ?? browserTimeZone)
10192
10465
  }),
10193
- children: /* @__PURE__ */ jsxs34("div", {
10466
+ children: /* @__PURE__ */ jsxs35("div", {
10194
10467
  className: "altertable-date-time-rows",
10195
10468
  children: [
10196
- rows.map(({ label, zone }) => /* @__PURE__ */ jsxs34("span", {
10469
+ rows.map(({ label, zone }) => /* @__PURE__ */ jsxs35("span", {
10197
10470
  className: "altertable-date-time-row",
10198
10471
  children: [
10199
- /* @__PURE__ */ jsx50("span", {
10472
+ /* @__PURE__ */ jsx52("span", {
10200
10473
  className: "altertable-date-time-label",
10201
10474
  children: label
10202
10475
  }),
10203
- /* @__PURE__ */ jsx50("time", {
10476
+ /* @__PURE__ */ jsx52("time", {
10204
10477
  dateTime: timestamp,
10205
10478
  children: formattedDate(date, zone)
10206
10479
  })
10207
10480
  ]
10208
10481
  }, label)),
10209
- /* @__PURE__ */ jsxs34("span", {
10482
+ /* @__PURE__ */ jsxs35("span", {
10210
10483
  className: "altertable-date-time-row",
10211
10484
  children: [
10212
- /* @__PURE__ */ jsx50("span", {
10485
+ /* @__PURE__ */ jsx52("span", {
10213
10486
  className: "altertable-date-time-label",
10214
10487
  children: "Relative"
10215
10488
  }),
10216
- /* @__PURE__ */ jsx50("time", {
10489
+ /* @__PURE__ */ jsx52("time", {
10217
10490
  dateTime: timestamp,
10218
10491
  children: relativeDate(date, now)
10219
10492
  })
10220
10493
  ]
10221
10494
  }),
10222
- /* @__PURE__ */ jsxs34("span", {
10495
+ /* @__PURE__ */ jsxs35("span", {
10223
10496
  className: "altertable-date-time-row",
10224
10497
  children: [
10225
- /* @__PURE__ */ jsx50("span", {
10498
+ /* @__PURE__ */ jsx52("span", {
10226
10499
  className: "altertable-date-time-label",
10227
10500
  children: "Timestamp"
10228
10501
  }),
10229
- /* @__PURE__ */ jsx50("time", {
10502
+ /* @__PURE__ */ jsx52("time", {
10230
10503
  dateTime: timestamp,
10231
10504
  children: date.getTime()
10232
10505
  })
@@ -10238,16 +10511,16 @@ function DateTimeTooltip({
10238
10511
  }
10239
10512
 
10240
10513
  // src/react/ui/DataTable.tsx
10241
- import { jsx as jsx51, jsxs as jsxs35, Fragment as Fragment10 } from "react/jsx-runtime";
10514
+ import { jsx as jsx53, jsxs as jsxs36, Fragment as Fragment11 } from "react/jsx-runtime";
10242
10515
  function DataTable({
10243
10516
  className,
10244
10517
  ref,
10245
10518
  searchable,
10246
10519
  ...props
10247
10520
  }) {
10248
- return /* @__PURE__ */ jsxs35(Fragment10, {
10521
+ return /* @__PURE__ */ jsxs36(Fragment11, {
10249
10522
  children: [
10250
- searchable && (searchable.itemCount > 5 || searchable.value !== (searchable.resetValue ?? "")) && /* @__PURE__ */ jsx51(SearchField, {
10523
+ searchable && (searchable.itemCount > 5 || searchable.value !== (searchable.resetValue ?? "")) && /* @__PURE__ */ jsx53(SearchField, {
10251
10524
  label: searchable.label,
10252
10525
  placeholder: searchable.placeholder,
10253
10526
  value: searchable.value,
@@ -10256,9 +10529,9 @@ function DataTable({
10256
10529
  size: "compact",
10257
10530
  className: "altertable-data-table-search"
10258
10531
  }),
10259
- /* @__PURE__ */ jsx51("div", {
10532
+ /* @__PURE__ */ jsx53("div", {
10260
10533
  className: "altertable-data-table-scroll",
10261
- children: /* @__PURE__ */ jsx51("table", {
10534
+ children: /* @__PURE__ */ jsx53("table", {
10262
10535
  ...props,
10263
10536
  ref,
10264
10537
  className: classNames("altertable-data-table", className)
@@ -10274,7 +10547,7 @@ function DataTableShare({ value }) {
10274
10547
  minimumFractionDigits: 1,
10275
10548
  maximumFractionDigits: 1
10276
10549
  }).format(ratio);
10277
- return /* @__PURE__ */ jsx51("span", {
10550
+ return /* @__PURE__ */ jsx53("span", {
10278
10551
  className: "altertable-data-table-share",
10279
10552
  children: label
10280
10553
  });
@@ -10284,11 +10557,11 @@ function DataTableEmptyRow({
10284
10557
  title,
10285
10558
  description
10286
10559
  }) {
10287
- return /* @__PURE__ */ jsx51("tr", {
10560
+ return /* @__PURE__ */ jsx53("tr", {
10288
10561
  className: "altertable-data-table-empty-row",
10289
- children: /* @__PURE__ */ jsx51("td", {
10562
+ children: /* @__PURE__ */ jsx53("td", {
10290
10563
  colSpan,
10291
- children: /* @__PURE__ */ jsx51(EmptyState, {
10564
+ children: /* @__PURE__ */ jsx53(EmptyState, {
10292
10565
  title,
10293
10566
  description,
10294
10567
  variant: "table"
@@ -10303,15 +10576,15 @@ function DataTableTimestamp({
10303
10576
  }) {
10304
10577
  const date = value instanceof Date ? value : new Date(value);
10305
10578
  if (Number.isNaN(date.getTime()))
10306
- return /* @__PURE__ */ jsx51(Fragment10, {
10579
+ return /* @__PURE__ */ jsx53(Fragment11, {
10307
10580
  children: children ?? value.toString()
10308
10581
  });
10309
10582
  const timestamp = date.toISOString();
10310
- return /* @__PURE__ */ jsx51(DateTimeTooltip, {
10583
+ return /* @__PURE__ */ jsx53(DateTimeTooltip, {
10311
10584
  date,
10312
10585
  timeZone,
10313
10586
  triggerClassName: "altertable-data-table-timestamp",
10314
- children: /* @__PURE__ */ jsx51("time", {
10587
+ children: /* @__PURE__ */ jsx53("time", {
10315
10588
  dateTime: timestamp,
10316
10589
  children: children ?? timestamp
10317
10590
  })
@@ -10319,28 +10592,27 @@ function DataTableTimestamp({
10319
10592
  }
10320
10593
 
10321
10594
  // src/react/ui/TableWidget.tsx
10322
- import { jsx as jsx52, jsxs as jsxs36, Fragment as Fragment11 } from "react/jsx-runtime";
10595
+ import { jsx as jsx54, jsxs as jsxs37, Fragment as Fragment12 } from "react/jsx-runtime";
10323
10596
  function TableWidget(props) {
10324
10597
  const { pagination, limit, columns } = props;
10325
10598
  invariant(!pagination || Number.isSafeInteger(pagination.pageSize) && pagination.pageSize >= 1, "TableWidget pagination.pageSize must be a positive integer.");
10326
- invariant(limit === undefined || pagination === undefined, "TableWidget limit and pagination are mutually exclusive.");
10327
10599
  invariant(limit === undefined || Number.isSafeInteger(limit) && limit >= 1, "TableWidget limit must be a positive integer.");
10328
10600
  const columnIds = columns.map((column) => column.id);
10329
10601
  invariant(columnIds.length > 0 && columnIds.every((id) => !!id.trim()) && new Set(columnIds).size === columnIds.length, "TableWidget column IDs must be nonempty and unique.");
10330
10602
  if (props.reading) {
10331
10603
  const { reading, skeletonRows = 5, ...rest } = props;
10332
10604
  if (reading.loading)
10333
- return /* @__PURE__ */ jsx52(ContentSkeleton, {
10605
+ return /* @__PURE__ */ jsx54(ContentSkeleton, {
10334
10606
  variant: "ranking",
10335
10607
  rows: skeletonRows,
10336
10608
  className: rest.className
10337
10609
  });
10338
- return /* @__PURE__ */ jsx52(TableWidgetContent, {
10610
+ return /* @__PURE__ */ jsx54(TableWidgetContent, {
10339
10611
  ...rest,
10340
10612
  rows: reading.value
10341
10613
  });
10342
10614
  }
10343
- return /* @__PURE__ */ jsx52(TableWidgetContent, {
10615
+ return /* @__PURE__ */ jsx54(TableWidgetContent, {
10344
10616
  ...props
10345
10617
  });
10346
10618
  }
@@ -10364,7 +10636,7 @@ function TableWidgetContent({
10364
10636
  invariant(keys.every((key) => typeof key === "string" ? !!key.trim() : Number.isFinite(key)) && new Set(keys.map(String)).size === keys.length, "TableWidget row keys must be nonempty and unique.");
10365
10637
  const rowKeys = JSON.stringify(keys);
10366
10638
  const pageSize = pagination === false || limit !== undefined ? null : pagination?.pageSize ?? 10;
10367
- const [pageState, setPageState] = useState18({
10639
+ const [pageState, setPageState] = useState19({
10368
10640
  page: 0,
10369
10641
  rowKeys,
10370
10642
  searchValue: search?.value,
@@ -10390,29 +10662,29 @@ function TableWidgetContent({
10390
10662
  resetValue: search.resetValue,
10391
10663
  itemCount: rows.length
10392
10664
  };
10393
- const table = /* @__PURE__ */ jsx52(Fragment11, {
10394
- children: /* @__PURE__ */ jsxs36(DataTable, {
10665
+ const table = /* @__PURE__ */ jsx54(Fragment12, {
10666
+ children: /* @__PURE__ */ jsxs37(DataTable, {
10395
10667
  searchable,
10396
10668
  children: [
10397
- /* @__PURE__ */ jsx52("thead", {
10398
- children: /* @__PURE__ */ jsx52("tr", {
10399
- children: columns.map((column) => /* @__PURE__ */ jsx52("th", {
10669
+ /* @__PURE__ */ jsx54("thead", {
10670
+ children: /* @__PURE__ */ jsx54("tr", {
10671
+ children: columns.map((column) => /* @__PURE__ */ jsx54("th", {
10400
10672
  scope: "col",
10401
10673
  "data-type": column.type,
10402
10674
  children: column.header
10403
10675
  }, column.id))
10404
10676
  })
10405
10677
  }),
10406
- /* @__PURE__ */ jsx52("tbody", {
10407
- children: visible.length === 0 ? /* @__PURE__ */ jsx52(DataTableEmptyRow, {
10678
+ /* @__PURE__ */ jsx54("tbody", {
10679
+ children: visible.length === 0 ? /* @__PURE__ */ jsx54(DataTableEmptyRow, {
10408
10680
  colSpan: columns.length,
10409
10681
  ...empty
10410
- }) : visible.map((hit) => /* @__PURE__ */ jsx52("tr", {
10411
- children: columns.map((column, index) => index === 0 ? /* @__PURE__ */ jsx52("th", {
10682
+ }) : visible.map((hit) => /* @__PURE__ */ jsx54("tr", {
10683
+ children: columns.map((column, index) => index === 0 ? /* @__PURE__ */ jsx54("th", {
10412
10684
  scope: "row",
10413
10685
  "data-type": column.type,
10414
10686
  children: column.cell(hit.item, hit)
10415
- }, column.id) : /* @__PURE__ */ jsx52("td", {
10687
+ }, column.id) : /* @__PURE__ */ jsx54("td", {
10416
10688
  "data-type": column.type,
10417
10689
  children: column.cell(hit.item, hit)
10418
10690
  }, column.id))
@@ -10421,11 +10693,11 @@ function TableWidgetContent({
10421
10693
  ]
10422
10694
  })
10423
10695
  });
10424
- const pager = pageSize && pageCount > 1 && /* @__PURE__ */ jsxs36("nav", {
10696
+ const pager = pageSize && pageCount > 1 && /* @__PURE__ */ jsxs37("nav", {
10425
10697
  className: "altertable-table-pagination",
10426
10698
  "aria-label": "Table pages",
10427
10699
  children: [
10428
- /* @__PURE__ */ jsxs36("span", {
10700
+ /* @__PURE__ */ jsxs37("span", {
10429
10701
  className: "altertable-table-pagination-range",
10430
10702
  children: [
10431
10703
  formatCount2(start + 1),
@@ -10438,10 +10710,10 @@ function TableWidgetContent({
10438
10710
  pluralize2(hits.length, "result")
10439
10711
  ]
10440
10712
  }),
10441
- /* @__PURE__ */ jsxs36("span", {
10713
+ /* @__PURE__ */ jsxs37("span", {
10442
10714
  className: "altertable-table-pagination-controls",
10443
10715
  children: [
10444
- /* @__PURE__ */ jsxs36("span", {
10716
+ /* @__PURE__ */ jsxs37("span", {
10445
10717
  children: [
10446
10718
  "Page ",
10447
10719
  page + 1,
@@ -10449,9 +10721,9 @@ function TableWidgetContent({
10449
10721
  pageCount
10450
10722
  ]
10451
10723
  }),
10452
- /* @__PURE__ */ jsx52(Tooltip, {
10724
+ /* @__PURE__ */ jsx54(Tooltip, {
10453
10725
  content: "Previous page",
10454
- children: /* @__PURE__ */ jsx52(Button, {
10726
+ children: /* @__PURE__ */ jsx54(Button, {
10455
10727
  size: "icon-compact",
10456
10728
  "aria-label": "Previous page",
10457
10729
  disabled: page === 0,
@@ -10461,15 +10733,15 @@ function TableWidgetContent({
10461
10733
  searchValue: search?.value,
10462
10734
  pageSize
10463
10735
  }),
10464
- children: /* @__PURE__ */ jsx52(AppIcon, {
10736
+ children: /* @__PURE__ */ jsx54(AppIcon, {
10465
10737
  name: "previousMonth",
10466
10738
  size: 16
10467
10739
  })
10468
10740
  })
10469
10741
  }),
10470
- /* @__PURE__ */ jsx52(Tooltip, {
10742
+ /* @__PURE__ */ jsx54(Tooltip, {
10471
10743
  content: "Next page",
10472
- children: /* @__PURE__ */ jsx52(Button, {
10744
+ children: /* @__PURE__ */ jsx54(Button, {
10473
10745
  size: "icon-compact",
10474
10746
  "aria-label": "Next page",
10475
10747
  disabled: page >= pageCount - 1,
@@ -10479,7 +10751,7 @@ function TableWidgetContent({
10479
10751
  searchValue: search?.value,
10480
10752
  pageSize
10481
10753
  }),
10482
- children: /* @__PURE__ */ jsx52(AppIcon, {
10754
+ children: /* @__PURE__ */ jsx54(AppIcon, {
10483
10755
  name: "nextMonth",
10484
10756
  size: 16
10485
10757
  })
@@ -10489,20 +10761,20 @@ function TableWidgetContent({
10489
10761
  })
10490
10762
  ]
10491
10763
  });
10492
- return /* @__PURE__ */ jsx52(DataWidget, {
10764
+ return /* @__PURE__ */ jsx54(DataWidget, {
10493
10765
  ...props,
10494
10766
  title,
10495
10767
  count,
10496
10768
  description,
10497
10769
  action,
10498
10770
  evidence,
10499
- footer: (pager || insight) && /* @__PURE__ */ jsxs36(Fragment11, {
10771
+ footer: (pager || insight) && /* @__PURE__ */ jsxs37(Fragment12, {
10500
10772
  children: [
10501
10773
  pager,
10502
10774
  insight
10503
10775
  ]
10504
10776
  }),
10505
- children: /* @__PURE__ */ jsx52("div", {
10777
+ children: /* @__PURE__ */ jsx54("div", {
10506
10778
  className: "altertable-table-widget-content",
10507
10779
  children: table
10508
10780
  })
@@ -10516,7 +10788,7 @@ function chartColor(id) {
10516
10788
  return `var(--at-chart-${(hash >>> 0) % 8 + 1}, var(--at-accent, #4779dc))`;
10517
10789
  }
10518
10790
  // src/react/ui/Breakdown.tsx
10519
- import { jsx as jsx53, jsxs as jsxs37 } from "react/jsx-runtime";
10791
+ import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
10520
10792
  function Breakdown({
10521
10793
  total,
10522
10794
  items,
@@ -10526,18 +10798,18 @@ function Breakdown({
10526
10798
  }) {
10527
10799
  invariant(Number.isFinite(total) && total >= 0 && items.every((item) => Number.isFinite(item.value) && item.value >= 0) && items.reduce((sum, item) => sum + item.value, 0) <= total, "Breakdown items must be nonnegative parts of the observed total.");
10528
10800
  const dominant = total > 0 && items.some((item) => item.value / total >= 0.85);
10529
- return /* @__PURE__ */ jsxs37("div", {
10801
+ return /* @__PURE__ */ jsxs38("div", {
10530
10802
  ...props,
10531
10803
  className: classNames("altertable-breakdown", className),
10532
10804
  "data-dominant": dominant || undefined,
10533
10805
  children: [
10534
- /* @__PURE__ */ jsxs37("div", {
10806
+ /* @__PURE__ */ jsxs38("div", {
10535
10807
  className: "altertable-breakdown-summary",
10536
10808
  children: [
10537
- /* @__PURE__ */ jsx53("span", {
10809
+ /* @__PURE__ */ jsx55("span", {
10538
10810
  children: "Share of total"
10539
10811
  }),
10540
- /* @__PURE__ */ jsxs37("strong", {
10812
+ /* @__PURE__ */ jsxs38("strong", {
10541
10813
  children: [
10542
10814
  formatValue(total),
10543
10815
  " total"
@@ -10545,42 +10817,42 @@ function Breakdown({
10545
10817
  })
10546
10818
  ]
10547
10819
  }),
10548
- /* @__PURE__ */ jsx53("div", {
10820
+ /* @__PURE__ */ jsx55("div", {
10549
10821
  className: "altertable-breakdown-bar",
10550
10822
  "aria-hidden": "true",
10551
- children: items.map((item) => /* @__PURE__ */ jsx53("span", {
10823
+ children: items.map((item) => /* @__PURE__ */ jsx55("span", {
10552
10824
  style: {
10553
10825
  width: `${total ? item.value / total * 100 : 0}%`,
10554
10826
  backgroundColor: chartColor(item.id)
10555
10827
  }
10556
10828
  }, item.id))
10557
10829
  }),
10558
- /* @__PURE__ */ jsx53("dl", {
10830
+ /* @__PURE__ */ jsx55("dl", {
10559
10831
  className: "altertable-breakdown-list",
10560
10832
  children: items.map((item) => {
10561
10833
  const share = total ? item.value / total : 0;
10562
10834
  const color = {
10563
10835
  "--altertable-breakdown-color": chartColor(item.id)
10564
10836
  };
10565
- return /* @__PURE__ */ jsxs37("div", {
10837
+ return /* @__PURE__ */ jsxs38("div", {
10566
10838
  className: "altertable-breakdown-row",
10567
10839
  "data-empty": item.value === 0 || undefined,
10568
10840
  style: color,
10569
10841
  children: [
10570
- /* @__PURE__ */ jsxs37("dt", {
10842
+ /* @__PURE__ */ jsxs38("dt", {
10571
10843
  children: [
10572
- /* @__PURE__ */ jsx53("span", {
10844
+ /* @__PURE__ */ jsx55("span", {
10573
10845
  className: "altertable-breakdown-swatch",
10574
10846
  "aria-hidden": "true"
10575
10847
  }),
10576
10848
  item.label
10577
10849
  ]
10578
10850
  }),
10579
- /* @__PURE__ */ jsx53("dd", {
10851
+ /* @__PURE__ */ jsx55("dd", {
10580
10852
  className: "altertable-breakdown-value",
10581
10853
  children: formatValue(item.value)
10582
10854
  }),
10583
- /* @__PURE__ */ jsx53("dd", {
10855
+ /* @__PURE__ */ jsx55("dd", {
10584
10856
  className: "altertable-breakdown-share",
10585
10857
  children: formatPercent2(share)
10586
10858
  })
@@ -10592,7 +10864,7 @@ function Breakdown({
10592
10864
  });
10593
10865
  }
10594
10866
  // src/react/ui/Ranking.tsx
10595
- import { jsx as jsx54, jsxs as jsxs38 } from "react/jsx-runtime";
10867
+ import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
10596
10868
  function Ranking({
10597
10869
  items,
10598
10870
  formatValue = formatCount2,
@@ -10601,30 +10873,30 @@ function Ranking({
10601
10873
  }) {
10602
10874
  invariant(items.every((item) => Number.isFinite(item.value) && item.value >= 0), "Ranking values must be finite and nonnegative.");
10603
10875
  const max = Math.max(0, ...items.map((item) => item.value));
10604
- return /* @__PURE__ */ jsx54("ol", {
10876
+ return /* @__PURE__ */ jsx56("ol", {
10605
10877
  ...props,
10606
10878
  className: classNames("altertable-ranking", className),
10607
- children: items.map((item) => /* @__PURE__ */ jsxs38("li", {
10879
+ children: items.map((item) => /* @__PURE__ */ jsxs39("li", {
10608
10880
  children: [
10609
- /* @__PURE__ */ jsxs38("div", {
10881
+ /* @__PURE__ */ jsxs39("div", {
10610
10882
  className: "altertable-ranking-reading",
10611
10883
  children: [
10612
- /* @__PURE__ */ jsx54("span", {
10884
+ /* @__PURE__ */ jsx56("span", {
10613
10885
  children: item.label
10614
10886
  }),
10615
- /* @__PURE__ */ jsx54("strong", {
10887
+ /* @__PURE__ */ jsx56("strong", {
10616
10888
  children: formatValue(item.value)
10617
10889
  })
10618
10890
  ]
10619
10891
  }),
10620
- /* @__PURE__ */ jsx54("div", {
10892
+ /* @__PURE__ */ jsx56("div", {
10621
10893
  className: "altertable-ranking-track",
10622
10894
  "aria-hidden": "true",
10623
- children: /* @__PURE__ */ jsx54("span", {
10895
+ children: /* @__PURE__ */ jsx56("span", {
10624
10896
  style: { width: `${max ? item.value / max * 100 : 0}%` }
10625
10897
  })
10626
10898
  }),
10627
- item.detail != null && /* @__PURE__ */ jsx54("div", {
10899
+ item.detail != null && /* @__PURE__ */ jsx56("div", {
10628
10900
  className: "altertable-ranking-detail",
10629
10901
  children: item.detail
10630
10902
  })
@@ -10633,27 +10905,27 @@ function Ranking({
10633
10905
  });
10634
10906
  }
10635
10907
  // src/react/ui/WidgetDisclosure.tsx
10636
- import { jsx as jsx55, jsxs as jsxs39 } from "react/jsx-runtime";
10908
+ import { jsx as jsx57, jsxs as jsxs40 } from "react/jsx-runtime";
10637
10909
  function WidgetDisclosure({
10638
10910
  label,
10639
10911
  children,
10640
10912
  className,
10641
10913
  ...props
10642
10914
  }) {
10643
- return /* @__PURE__ */ jsxs39("details", {
10915
+ return /* @__PURE__ */ jsxs40("details", {
10644
10916
  ...props,
10645
10917
  className: classNames("altertable-widget-disclosure", className),
10646
10918
  children: [
10647
- /* @__PURE__ */ jsxs39("summary", {
10919
+ /* @__PURE__ */ jsxs40("summary", {
10648
10920
  children: [
10649
10921
  label,
10650
- /* @__PURE__ */ jsx55(AppIcon, {
10922
+ /* @__PURE__ */ jsx57(AppIcon, {
10651
10923
  name: "disclosure",
10652
10924
  size: 16
10653
10925
  })
10654
10926
  ]
10655
10927
  }),
10656
- /* @__PURE__ */ jsx55("div", {
10928
+ /* @__PURE__ */ jsx57("div", {
10657
10929
  className: "altertable-widget-disclosure-content",
10658
10930
  children
10659
10931
  })
@@ -10703,23 +10975,23 @@ function metricComparison(metric, reading) {
10703
10975
  }
10704
10976
 
10705
10977
  // src/react/ui/ComparisonVisual.tsx
10706
- import { jsx as jsx56, jsxs as jsxs40, Fragment as Fragment12 } from "react/jsx-runtime";
10978
+ import { jsx as jsx58, jsxs as jsxs41, Fragment as Fragment13 } from "react/jsx-runtime";
10707
10979
  function ComparisonVisual(props) {
10708
10980
  if ("metric" in props) {
10709
10981
  if (props.reading.loading)
10710
- return /* @__PURE__ */ jsx56(ContentSkeleton, {
10982
+ return /* @__PURE__ */ jsx58(ContentSkeleton, {
10711
10983
  variant: "panel"
10712
10984
  });
10713
10985
  const comparison = metricComparison(props.metric, props.reading);
10714
10986
  if (!comparison)
10715
10987
  return null;
10716
- return /* @__PURE__ */ jsx56(ComparisonContent, {
10988
+ return /* @__PURE__ */ jsx58(ComparisonContent, {
10717
10989
  ...comparison,
10718
10990
  label: props.metric.label,
10719
10991
  emphasis: props.emphasis
10720
10992
  });
10721
10993
  }
10722
- return /* @__PURE__ */ jsx56(ComparisonContent, {
10994
+ return /* @__PURE__ */ jsx58(ComparisonContent, {
10723
10995
  ...props
10724
10996
  });
10725
10997
  }
@@ -10736,64 +11008,64 @@ function ComparisonContent({
10736
11008
  previous,
10737
11009
  favorableDirection
10738
11010
  });
10739
- return /* @__PURE__ */ jsxs40("figure", {
11011
+ return /* @__PURE__ */ jsxs41("figure", {
10740
11012
  className: "altertable-comparison-visual",
10741
11013
  "data-emphasis": emphasis,
10742
11014
  "aria-label": `${label} comparison`,
10743
11015
  children: [
10744
- /* @__PURE__ */ jsx56("figcaption", {
11016
+ /* @__PURE__ */ jsx58("figcaption", {
10745
11017
  children: label
10746
11018
  }),
10747
- /* @__PURE__ */ jsxs40("div", {
11019
+ /* @__PURE__ */ jsxs41("div", {
10748
11020
  className: "altertable-comparison-row",
10749
11021
  "data-period": "current",
10750
11022
  children: [
10751
- /* @__PURE__ */ jsxs40("div", {
11023
+ /* @__PURE__ */ jsxs41("div", {
10752
11024
  children: [
10753
- /* @__PURE__ */ jsx56("span", {
11025
+ /* @__PURE__ */ jsx58("span", {
10754
11026
  children: current.periodLabel ?? "Current period"
10755
11027
  }),
10756
- /* @__PURE__ */ jsx56("strong", {
11028
+ /* @__PURE__ */ jsx58("strong", {
10757
11029
  children: current.formattedValue
10758
11030
  })
10759
11031
  ]
10760
11032
  }),
10761
- /* @__PURE__ */ jsx56("span", {
11033
+ /* @__PURE__ */ jsx58("span", {
10762
11034
  className: "altertable-comparison-track",
10763
- children: /* @__PURE__ */ jsx56("span", {
11035
+ children: /* @__PURE__ */ jsx58("span", {
10764
11036
  style: { width: `${current.value / max * 100}%` }
10765
11037
  })
10766
11038
  })
10767
11039
  ]
10768
11040
  }),
10769
- previous && /* @__PURE__ */ jsxs40("div", {
11041
+ previous && /* @__PURE__ */ jsxs41("div", {
10770
11042
  className: "altertable-comparison-row",
10771
11043
  "data-period": "previous",
10772
11044
  children: [
10773
- /* @__PURE__ */ jsxs40("div", {
11045
+ /* @__PURE__ */ jsxs41("div", {
10774
11046
  children: [
10775
- /* @__PURE__ */ jsx56("span", {
11047
+ /* @__PURE__ */ jsx58("span", {
10776
11048
  children: previous.periodLabel ?? "Previous period"
10777
11049
  }),
10778
- /* @__PURE__ */ jsx56("strong", {
11050
+ /* @__PURE__ */ jsx58("strong", {
10779
11051
  children: previous.formattedValue
10780
11052
  })
10781
11053
  ]
10782
11054
  }),
10783
- /* @__PURE__ */ jsx56("span", {
11055
+ /* @__PURE__ */ jsx58("span", {
10784
11056
  className: "altertable-comparison-track",
10785
- children: /* @__PURE__ */ jsx56("span", {
11057
+ children: /* @__PURE__ */ jsx58("span", {
10786
11058
  style: { width: `${(previous.value ?? 0) / max * 100}%` }
10787
11059
  })
10788
11060
  })
10789
11061
  ]
10790
11062
  }),
10791
- /* @__PURE__ */ jsx56("p", {
11063
+ /* @__PURE__ */ jsx58("p", {
10792
11064
  className: "altertable-comparison-change",
10793
11065
  "data-tone": tone,
10794
- children: percent === null ? "No comparable previous value" : /* @__PURE__ */ jsxs40(Fragment12, {
11066
+ children: percent === null ? "No comparable previous value" : /* @__PURE__ */ jsxs41(Fragment13, {
10795
11067
  children: [
10796
- /* @__PURE__ */ jsx56(AppIcon, {
11068
+ /* @__PURE__ */ jsx58(AppIcon, {
10797
11069
  name: icon,
10798
11070
  size: 17
10799
11071
  }),
@@ -10808,17 +11080,17 @@ function ComparisonContent({
10808
11080
  });
10809
11081
  }
10810
11082
  // src/react/ui/MetricWidget.tsx
10811
- import { jsx as jsx57, jsxs as jsxs41 } from "react/jsx-runtime";
11083
+ import { jsx as jsx59, jsxs as jsxs42 } from "react/jsx-runtime";
10812
11084
  function MetricWidget(props) {
10813
11085
  if ("metric" in props) {
10814
11086
  const { metric, reading, ...rest } = props;
10815
11087
  if (reading.loading)
10816
- return /* @__PURE__ */ jsx57(MetricWidgetContent, {
11088
+ return /* @__PURE__ */ jsx59(MetricWidgetContent, {
10817
11089
  ...rest,
10818
11090
  label: metric.label,
10819
11091
  loading: true
10820
11092
  });
10821
- return /* @__PURE__ */ jsx57(MetricWidgetContent, {
11093
+ return /* @__PURE__ */ jsx59(MetricWidgetContent, {
10822
11094
  ...rest,
10823
11095
  label: metric.label,
10824
11096
  value: reading.value.current,
@@ -10827,7 +11099,7 @@ function MetricWidget(props) {
10827
11099
  comparison: metricComparison(metric, reading)
10828
11100
  });
10829
11101
  }
10830
- return /* @__PURE__ */ jsx57(MetricWidgetContent, {
11102
+ return /* @__PURE__ */ jsx59(MetricWidgetContent, {
10831
11103
  ...props
10832
11104
  });
10833
11105
  }
@@ -10848,17 +11120,17 @@ function MetricWidgetContent({
10848
11120
  ...props
10849
11121
  }) {
10850
11122
  if (loading)
10851
- return /* @__PURE__ */ jsx57(ContentSkeleton, {
11123
+ return /* @__PURE__ */ jsx59(ContentSkeleton, {
10852
11124
  variant: "metric",
10853
11125
  className
10854
11126
  });
10855
11127
  const shownValue = format ? formatMetric2(value, format) : content;
10856
11128
  const change = comparison ? comparisonChange(comparison) : null;
10857
- const shownTrend = change?.percent != null ? /* @__PURE__ */ jsxs41("span", {
11129
+ const shownTrend = change?.percent != null ? /* @__PURE__ */ jsxs42("span", {
10858
11130
  className: "altertable-metric-change",
10859
11131
  "data-tone": change.tone,
10860
11132
  children: [
10861
- /* @__PURE__ */ jsx57(AppIcon, {
11133
+ /* @__PURE__ */ jsx59(AppIcon, {
10862
11134
  name: change.icon,
10863
11135
  size: 14
10864
11136
  }),
@@ -10867,33 +11139,33 @@ function MetricWidgetContent({
10867
11139
  " ",
10868
11140
  comparison?.previous?.periodLabel?.toLowerCase() ?? "previous period"
10869
11141
  ]
10870
- }) : comparison?.previous?.value === null ? /* @__PURE__ */ jsx57("span", {
11142
+ }) : comparison?.previous?.value === null ? /* @__PURE__ */ jsx59("span", {
10871
11143
  className: "altertable-metric-change",
10872
11144
  "data-tone": "neutral",
10873
11145
  children: "Previous period unavailable"
10874
11146
  }) : null;
10875
- const reading = /* @__PURE__ */ jsxs41("div", {
11147
+ const reading = /* @__PURE__ */ jsxs42("div", {
10876
11148
  className: "altertable-metric-reading",
10877
11149
  children: [
10878
- /* @__PURE__ */ jsx57("strong", {
11150
+ /* @__PURE__ */ jsx59("strong", {
10879
11151
  className: "altertable-metric-value",
10880
11152
  "data-unavailable": shownValue === "—" || undefined,
10881
11153
  children: shownValue
10882
11154
  }),
10883
- shownTrend && /* @__PURE__ */ jsx57("span", {
11155
+ shownTrend && /* @__PURE__ */ jsx59("span", {
10884
11156
  className: "altertable-metric-trend",
10885
11157
  children: shownTrend
10886
11158
  })
10887
11159
  ]
10888
11160
  });
10889
- const visualization = visual && /* @__PURE__ */ jsx57("div", {
11161
+ const visualization = visual && /* @__PURE__ */ jsx59("div", {
10890
11162
  className: "altertable-metric-visual",
10891
11163
  children: visual
10892
11164
  });
10893
- const feedback = /* @__PURE__ */ jsx57(WidgetStatusControl, {
11165
+ const feedback = /* @__PURE__ */ jsx59(WidgetStatusControl, {
10894
11166
  status
10895
11167
  });
10896
- const help = evidence ? /* @__PURE__ */ jsxs41(AboutData, {
11168
+ const help = evidence ? /* @__PURE__ */ jsxs42(AboutData, {
10897
11169
  "aria-label": `Explore ${label}`,
10898
11170
  variant: "ghost",
10899
11171
  className: "altertable-widget-heading-trigger",
@@ -10908,7 +11180,7 @@ function MetricWidgetContent({
10908
11180
  title: label,
10909
11181
  headerActions: feedback,
10910
11182
  description,
10911
- visual: /* @__PURE__ */ jsxs41("div", {
11183
+ visual: /* @__PURE__ */ jsxs42("div", {
10912
11184
  className: "altertable-metric-evidence",
10913
11185
  children: [
10914
11186
  reading,
@@ -10918,22 +11190,22 @@ function MetricWidgetContent({
10918
11190
  visualKind: "metric",
10919
11191
  children: [
10920
11192
  label,
10921
- /* @__PURE__ */ jsx57(AppIcon, {
11193
+ /* @__PURE__ */ jsx59(AppIcon, {
10922
11194
  name: "openDetails"
10923
11195
  })
10924
11196
  ]
10925
11197
  }) : null;
10926
- return /* @__PURE__ */ jsxs41("div", {
11198
+ return /* @__PURE__ */ jsxs42("div", {
10927
11199
  ...props,
10928
11200
  className: classNames("altertable-metric-widget", className),
10929
11201
  children: [
10930
- /* @__PURE__ */ jsxs41("div", {
11202
+ /* @__PURE__ */ jsxs42("div", {
10931
11203
  className: "altertable-metric-label",
10932
11204
  children: [
10933
- /* @__PURE__ */ jsx57("span", {
11205
+ /* @__PURE__ */ jsx59("span", {
10934
11206
  children: help ?? label
10935
11207
  }),
10936
- /* @__PURE__ */ jsxs41("div", {
11208
+ /* @__PURE__ */ jsxs42("div", {
10937
11209
  className: "altertable-metric-help",
10938
11210
  children: [
10939
11211
  feedback,
@@ -10943,12 +11215,12 @@ function MetricWidgetContent({
10943
11215
  ]
10944
11216
  }),
10945
11217
  reading,
10946
- description && /* @__PURE__ */ jsx57("small", {
11218
+ description && /* @__PURE__ */ jsx59("small", {
10947
11219
  className: "altertable-metric-description",
10948
11220
  children: description
10949
11221
  }),
10950
11222
  visualization,
10951
- insight && /* @__PURE__ */ jsx57("div", {
11223
+ insight && /* @__PURE__ */ jsx59("div", {
10952
11224
  className: "altertable-metric-insight",
10953
11225
  children: insight
10954
11226
  })
@@ -10956,8 +11228,8 @@ function MetricWidgetContent({
10956
11228
  });
10957
11229
  }
10958
11230
  // src/react/ui/SelectableBarChart.tsx
10959
- import { useLayoutEffect as useLayoutEffect2, useRef as useRef7, useState as useState19 } from "react";
10960
- import { jsx as jsx58, jsxs as jsxs42 } from "react/jsx-runtime";
11231
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef7, useState as useState20 } from "react";
11232
+ import { jsx as jsx60, jsxs as jsxs43 } from "react/jsx-runtime";
10961
11233
  function SelectableBarChart({
10962
11234
  items,
10963
11235
  selectedId,
@@ -10966,7 +11238,7 @@ function SelectableBarChart({
10966
11238
  ariaLabel,
10967
11239
  formatValue = (value) => new Intl.NumberFormat().format(value)
10968
11240
  }) {
10969
- const [previewId, setPreviewId] = useState19(null);
11241
+ const [previewId, setPreviewId] = useState20(null);
10970
11242
  const scrollport = useRef7(null);
10971
11243
  const buttons = useRef7([]);
10972
11244
  useLayoutEffect2(() => {
@@ -10988,20 +11260,20 @@ function SelectableBarChart({
10988
11260
  const next = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : Math.max(0, Math.min(items.length - 1, index + (event.key === "ArrowRight" ? 1 : -1)));
10989
11261
  buttons.current[next]?.focus();
10990
11262
  }
10991
- return /* @__PURE__ */ jsxs42("div", {
11263
+ return /* @__PURE__ */ jsxs43("div", {
10992
11264
  className: "altertable-selectable-bars",
10993
11265
  children: [
10994
- /* @__PURE__ */ jsxs42("div", {
11266
+ /* @__PURE__ */ jsxs43("div", {
10995
11267
  className: "altertable-selectable-bars-preview",
10996
11268
  "aria-live": "polite",
10997
11269
  children: [
10998
- preview ? /* @__PURE__ */ jsxs42("span", {
11270
+ preview ? /* @__PURE__ */ jsxs43("span", {
10999
11271
  children: [
11000
- /* @__PURE__ */ jsx58("small", {
11272
+ /* @__PURE__ */ jsx60("small", {
11001
11273
  children: previewId && previewId !== selectedId ? "Preview" : selected ? "Selected" : "Latest"
11002
11274
  }),
11003
11275
  " ",
11004
- /* @__PURE__ */ jsx58("strong", {
11276
+ /* @__PURE__ */ jsx60("strong", {
11005
11277
  children: preview.label
11006
11278
  }),
11007
11279
  " · ",
@@ -11009,21 +11281,21 @@ function SelectableBarChart({
11009
11281
  " ",
11010
11282
  unit
11011
11283
  ]
11012
- }) : /* @__PURE__ */ jsx58("span", {
11284
+ }) : /* @__PURE__ */ jsx60("span", {
11013
11285
  children: "No data"
11014
11286
  }),
11015
- selected && /* @__PURE__ */ jsx58("button", {
11287
+ selected && /* @__PURE__ */ jsx60("button", {
11016
11288
  type: "button",
11017
11289
  onClick: () => onSelectionChange(null),
11018
11290
  children: "Clear selection"
11019
11291
  })
11020
11292
  ]
11021
11293
  }),
11022
- /* @__PURE__ */ jsx58("div", {
11294
+ /* @__PURE__ */ jsx60("div", {
11023
11295
  className: "altertable-selectable-bars-scroll",
11024
11296
  ref: scrollport,
11025
11297
  "aria-label": ariaLabel,
11026
- children: items.map((item, index) => /* @__PURE__ */ jsxs42("button", {
11298
+ children: items.map((item, index) => /* @__PURE__ */ jsxs43("button", {
11027
11299
  ref: (node) => {
11028
11300
  buttons.current[index] = node;
11029
11301
  },
@@ -11038,23 +11310,23 @@ function SelectableBarChart({
11038
11310
  onBlur: () => setPreviewId(null),
11039
11311
  onKeyDown: (event) => onKeyDown(event, index),
11040
11312
  children: [
11041
- /* @__PURE__ */ jsx58("span", {
11313
+ /* @__PURE__ */ jsx60("span", {
11042
11314
  className: "altertable-selectable-bars-area",
11043
- children: /* @__PURE__ */ jsx58("span", {
11315
+ children: /* @__PURE__ */ jsx60("span", {
11044
11316
  className: "altertable-selectable-bars-bar",
11045
11317
  style: {
11046
11318
  height: `${Math.max(item.value > 0 ? 3 : 0, item.value / maximum * 100)}%`
11047
11319
  }
11048
11320
  })
11049
11321
  }),
11050
- /* @__PURE__ */ jsx58("span", {
11322
+ /* @__PURE__ */ jsx60("span", {
11051
11323
  className: "altertable-selectable-bars-label",
11052
11324
  children: item.label
11053
11325
  })
11054
11326
  ]
11055
11327
  }, item.id))
11056
11328
  }),
11057
- items.length > 0 && /* @__PURE__ */ jsx58("p", {
11329
+ items.length > 0 && /* @__PURE__ */ jsx60("p", {
11058
11330
  className: "altertable-selectable-bars-help",
11059
11331
  children: "Select a bar to inspect its day. Use arrow keys to move; press Escape to clear."
11060
11332
  })
@@ -11062,7 +11334,7 @@ function SelectableBarChart({
11062
11334
  });
11063
11335
  }
11064
11336
  // src/react/ui/DataAppSkeleton.tsx
11065
- import { jsx as jsx59, jsxs as jsxs43 } from "react/jsx-runtime";
11337
+ import { jsx as jsx61, jsxs as jsxs44 } from "react/jsx-runtime";
11066
11338
  var chartHeights = [40, 60, 50, 80, 60, 100, 80, 60];
11067
11339
  function DataAppSkeleton({
11068
11340
  header,
@@ -11070,60 +11342,60 @@ function DataAppSkeleton({
11070
11342
  className,
11071
11343
  ...props
11072
11344
  }) {
11073
- return /* @__PURE__ */ jsx59("output", {
11345
+ return /* @__PURE__ */ jsx61("output", {
11074
11346
  "aria-label": "Loading data app",
11075
11347
  ...props,
11076
11348
  "aria-busy": "true",
11077
11349
  className: classNames("altertable-data-app-skeleton", className),
11078
- children: /* @__PURE__ */ jsxs43("div", {
11350
+ children: /* @__PURE__ */ jsxs44("div", {
11079
11351
  className: "altertable-data-app-skeleton-content",
11080
11352
  children: [
11081
- header != null && header !== false && /* @__PURE__ */ jsx59("div", {
11353
+ header != null && header !== false && /* @__PURE__ */ jsx61("div", {
11082
11354
  className: "altertable-data-app-skeleton-header",
11083
11355
  children: header
11084
11356
  }),
11085
- /* @__PURE__ */ jsxs43("div", {
11357
+ /* @__PURE__ */ jsxs44("div", {
11086
11358
  className: "altertable-data-app-skeleton-body",
11087
11359
  "aria-hidden": "true",
11088
11360
  children: [
11089
- /* @__PURE__ */ jsx59(Grid, {
11361
+ /* @__PURE__ */ jsx61(Grid, {
11090
11362
  columns: 3,
11091
11363
  gap: "md",
11092
- children: [0, 1, 2].map((item) => /* @__PURE__ */ jsx59(MetricWidget, {
11364
+ children: [0, 1, 2].map((item) => /* @__PURE__ */ jsx61(MetricWidget, {
11093
11365
  label: "",
11094
11366
  loading: true
11095
11367
  }, item))
11096
11368
  }),
11097
- /* @__PURE__ */ jsx59(VisualizationWidget, {
11098
- title: /* @__PURE__ */ jsx59(Skeleton, {
11369
+ /* @__PURE__ */ jsx61(VisualizationWidget, {
11370
+ title: /* @__PURE__ */ jsx61(Skeleton, {
11099
11371
  className: "altertable-data-app-skeleton-widget-title"
11100
11372
  }),
11101
- visual: /* @__PURE__ */ jsx59("div", {
11373
+ visual: /* @__PURE__ */ jsx61("div", {
11102
11374
  className: "altertable-data-app-skeleton-chart",
11103
- children: chartHeights.map((height, index) => /* @__PURE__ */ jsx59(Skeleton, {
11375
+ children: chartHeights.map((height, index) => /* @__PURE__ */ jsx61(Skeleton, {
11104
11376
  style: { height: `${height}%` }
11105
11377
  }, index))
11106
11378
  })
11107
11379
  }),
11108
- /* @__PURE__ */ jsx59(DataWidget, {
11109
- title: /* @__PURE__ */ jsx59(Skeleton, {
11380
+ /* @__PURE__ */ jsx61(DataWidget, {
11381
+ title: /* @__PURE__ */ jsx61(Skeleton, {
11110
11382
  className: "altertable-data-app-skeleton-widget-title"
11111
11383
  }),
11112
- children: /* @__PURE__ */ jsx59("div", {
11384
+ children: /* @__PURE__ */ jsx61("div", {
11113
11385
  className: "altertable-data-app-skeleton-rows",
11114
- children: [0, 1, 2].map((row) => /* @__PURE__ */ jsxs43("div", {
11386
+ children: [0, 1, 2].map((row) => /* @__PURE__ */ jsxs44("div", {
11115
11387
  className: "altertable-data-app-skeleton-row",
11116
11388
  children: [
11117
- /* @__PURE__ */ jsx59(Skeleton, {}),
11118
- /* @__PURE__ */ jsx59(Skeleton, {}),
11119
- /* @__PURE__ */ jsx59(Skeleton, {})
11389
+ /* @__PURE__ */ jsx61(Skeleton, {}),
11390
+ /* @__PURE__ */ jsx61(Skeleton, {}),
11391
+ /* @__PURE__ */ jsx61(Skeleton, {})
11120
11392
  ]
11121
11393
  }, row))
11122
11394
  })
11123
11395
  })
11124
11396
  ]
11125
11397
  }),
11126
- footer != null && footer !== false && /* @__PURE__ */ jsx59("div", {
11398
+ footer != null && footer !== false && /* @__PURE__ */ jsx61("div", {
11127
11399
  className: "altertable-data-app-skeleton-footer",
11128
11400
  children: footer
11129
11401
  })
@@ -11132,7 +11404,7 @@ function DataAppSkeleton({
11132
11404
  });
11133
11405
  }
11134
11406
  // src/react/ui/RefreshRegion.tsx
11135
- import { jsx as jsx60 } from "react/jsx-runtime";
11407
+ import { jsx as jsx62 } from "react/jsx-runtime";
11136
11408
  function RefreshRegion({
11137
11409
  refreshing,
11138
11410
  dimOnUpdate = false,
@@ -11141,10 +11413,10 @@ function RefreshRegion({
11141
11413
  className,
11142
11414
  ...props
11143
11415
  }) {
11144
- return /* @__PURE__ */ jsx60("div", {
11416
+ return /* @__PURE__ */ jsx62("div", {
11145
11417
  ...props,
11146
11418
  className: classNames("altertable-refresh-region", className),
11147
- children: /* @__PURE__ */ jsx60("div", {
11419
+ children: /* @__PURE__ */ jsx62("div", {
11148
11420
  ...contentProps,
11149
11421
  className: classNames("altertable-refresh-content", contentProps?.className),
11150
11422
  "data-refreshing": refreshing && dimOnUpdate,
@@ -11154,8 +11426,8 @@ function RefreshRegion({
11154
11426
  });
11155
11427
  }
11156
11428
  // src/react/ui/UpdatedAt.tsx
11157
- import { useEffect as useEffect16, useState as useState20 } from "react";
11158
- import { jsx as jsx61, jsxs as jsxs44 } from "react/jsx-runtime";
11429
+ import { useEffect as useEffect16, useState as useState21 } from "react";
11430
+ import { jsx as jsx63, jsxs as jsxs45 } from "react/jsx-runtime";
11159
11431
  function UpdatedAt({
11160
11432
  timestamp,
11161
11433
  locale,
@@ -11164,7 +11436,7 @@ function UpdatedAt({
11164
11436
  triggerClassName,
11165
11437
  ...props
11166
11438
  }) {
11167
- const [now, setNow] = useState20(Date.now);
11439
+ const [now, setNow] = useState21(Date.now);
11168
11440
  useEffect16(() => {
11169
11441
  const interval = window.setInterval(() => setNow(Date.now()), 30000);
11170
11442
  return () => window.clearInterval(interval);
@@ -11179,11 +11451,11 @@ function UpdatedAt({
11179
11451
  else if (elapsedMinutes >= 1)
11180
11452
  age = relative.format(-elapsedMinutes, "minute");
11181
11453
  const date = new Date(timestamp);
11182
- return /* @__PURE__ */ jsx61(DateTimeTooltip, {
11454
+ return /* @__PURE__ */ jsx63(DateTimeTooltip, {
11183
11455
  ...props,
11184
11456
  date,
11185
11457
  triggerClassName: ["altertable-updated-at", triggerClassName].filter(Boolean).join(" "),
11186
- children: children ?? /* @__PURE__ */ jsxs44("time", {
11458
+ children: children ?? /* @__PURE__ */ jsxs45("time", {
11187
11459
  dateTime: date.toISOString(),
11188
11460
  children: [
11189
11461
  label,
@@ -11266,7 +11538,7 @@ function createDataContext(queryNames) {
11266
11538
  return bindDataContext;
11267
11539
  }
11268
11540
  // src/react/ui/data-identifiers.tsx
11269
- import { jsx as jsx62, jsxs as jsxs45 } from "react/jsx-runtime";
11541
+ import { jsx as jsx64, jsxs as jsxs46 } from "react/jsx-runtime";
11270
11542
  function qualifiedName(definition) {
11271
11543
  const table = definition.kind === "table" ? definition : definition.table;
11272
11544
  const path = [table.catalog, table.schema, table.name].join(".");
@@ -11302,23 +11574,23 @@ function defineDataIdentifiers({ tables, columns }) {
11302
11574
  const shown = display ?? (definition.kind === "table" ? "qualified" : "short");
11303
11575
  const table = definition.kind === "table" ? definition : definition.table;
11304
11576
  const prefix = definition.kind === "table" ? [table.catalog, table.schema] : [table.catalog, table.schema, table.name];
11305
- return /* @__PURE__ */ jsxs45("code", {
11577
+ return /* @__PURE__ */ jsxs46("code", {
11306
11578
  className: "altertable-data-identifier",
11307
11579
  "data-kind": definition.kind,
11308
11580
  title: qualified,
11309
11581
  "data-identifier-id": id,
11310
11582
  children: [
11311
- shown === "qualified" && /* @__PURE__ */ jsx62("span", {
11583
+ shown === "qualified" && /* @__PURE__ */ jsx64("span", {
11312
11584
  className: "altertable-data-identifier-path",
11313
- children: prefix.map((segment, index) => /* @__PURE__ */ jsxs45("span", {
11585
+ children: prefix.map((segment, index) => /* @__PURE__ */ jsxs46("span", {
11314
11586
  children: [
11315
11587
  segment,
11316
11588
  ".",
11317
- /* @__PURE__ */ jsx62("wbr", {})
11589
+ /* @__PURE__ */ jsx64("wbr", {})
11318
11590
  ]
11319
11591
  }, index))
11320
11592
  }),
11321
- /* @__PURE__ */ jsx62("span", {
11593
+ /* @__PURE__ */ jsx64("span", {
11322
11594
  className: "altertable-data-identifier-name",
11323
11595
  children: definition.name
11324
11596
  })
@@ -11331,7 +11603,7 @@ function defineDataIdentifiers({ tables, columns }) {
11331
11603
  };
11332
11604
  }
11333
11605
  // src/react/ui/GlossaryExplanation.tsx
11334
- import { jsx as jsx63 } from "react/jsx-runtime";
11606
+ import { jsx as jsx65 } from "react/jsx-runtime";
11335
11607
  function GlossaryExplanation({
11336
11608
  entry,
11337
11609
  empty,
@@ -11343,7 +11615,7 @@ function GlossaryExplanation({
11343
11615
  className,
11344
11616
  ...props
11345
11617
  }) {
11346
- return /* @__PURE__ */ jsx63(AboutData, {
11618
+ return /* @__PURE__ */ jsx65(AboutData, {
11347
11619
  ...props,
11348
11620
  shortcut: false,
11349
11621
  iconOnly: true,
@@ -11358,28 +11630,28 @@ function GlossaryExplanation({
11358
11630
  className: className ?? "altertable-inspect-trigger",
11359
11631
  tooltip: "Explore this term",
11360
11632
  "aria-label": props["aria-label"] ?? `Explore ${entry.term}`,
11361
- children: /* @__PURE__ */ jsx63(AppIcon, {
11633
+ children: /* @__PURE__ */ jsx65(AppIcon, {
11362
11634
  name: "openDetails"
11363
11635
  })
11364
11636
  });
11365
11637
  }
11366
11638
  // src/react/ui/GlossaryDefinition.tsx
11367
- import { jsx as jsx64, jsxs as jsxs46 } from "react/jsx-runtime";
11639
+ import { jsx as jsx66, jsxs as jsxs47 } from "react/jsx-runtime";
11368
11640
  function GlossaryDefinition({
11369
11641
  entry,
11370
11642
  children
11371
11643
  }) {
11372
- return /* @__PURE__ */ jsxs46(HelpPopover, {
11644
+ return /* @__PURE__ */ jsxs47(HelpPopover, {
11373
11645
  trigger: children ?? entry.term,
11374
11646
  triggerLabel: `Explain ${entry.term}`,
11375
11647
  label: entry.term,
11376
11648
  triggerClassName: "altertable-glossary-definition-trigger",
11377
11649
  panelClassName: "altertable-glossary-definition-popover",
11378
11650
  children: [
11379
- /* @__PURE__ */ jsx64("strong", {
11651
+ /* @__PURE__ */ jsx66("strong", {
11380
11652
  children: entry.term
11381
11653
  }),
11382
- /* @__PURE__ */ jsx64("div", {
11654
+ /* @__PURE__ */ jsx66("div", {
11383
11655
  children: entry.definition
11384
11656
  })
11385
11657
  ]
@@ -11479,4 +11751,4 @@ export {
11479
11751
  writeSearch
11480
11752
  };
11481
11753
 
11482
- //# debugId=103599A830311DAF64756E2164756E21
11754
+ //# debugId=A6B15262EAC6BE2D64756E2164756E21