@squadbase/vantage 0.6.2-dev1.42c4e48 → 0.6.2-dev1.9365dcd

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 (148) hide show
  1. package/dist/{build-MFWRPYKW.js → build-X5NVCQKT.js} +4 -4
  2. package/dist/{build-MFWRPYKW.js.map → build-X5NVCQKT.js.map} +1 -1
  3. package/dist/{chunk-IBGOCWJB.js → chunk-2ICNHUG6.js} +186 -82
  4. package/dist/chunk-2ICNHUG6.js.map +1 -0
  5. package/dist/{chunk-5ZOP4SQR.js → chunk-2N72FKLB.js} +12 -7
  6. package/dist/chunk-2N72FKLB.js.map +1 -0
  7. package/dist/chunk-HKSVYMYJ.js +7919 -0
  8. package/dist/chunk-HKSVYMYJ.js.map +1 -0
  9. package/dist/{chunk-PXRX5PEC.js → chunk-PDOBHMUQ.js} +3 -3
  10. package/dist/chunk-PDOBHMUQ.js.map +1 -0
  11. package/dist/{chunk-A2UUGASH.js → chunk-U736PVHY.js} +2 -2
  12. package/dist/chunk-U736PVHY.js.map +1 -0
  13. package/dist/{chunk-QEWCYW3I.js → chunk-WAMZWZJB.js} +13 -3
  14. package/dist/chunk-WAMZWZJB.js.map +1 -0
  15. package/dist/{chunk-OB6UBJXF.js → chunk-XPQSTZUU.js} +125 -35
  16. package/dist/chunk-XPQSTZUU.js.map +1 -0
  17. package/dist/cli.js +3 -3
  18. package/dist/components/index.d.ts +1832 -100
  19. package/dist/components/index.js +4 -4
  20. package/dist/{dev-DCTOHQ6W.js → dev-4XEDTELV.js} +4 -4
  21. package/dist/{dev-DCTOHQ6W.js.map → dev-4XEDTELV.js.map} +1 -1
  22. package/dist/doc/index.js +2 -2
  23. package/dist/doc/index.js.map +1 -1
  24. package/dist/markdown/index.js +1 -1
  25. package/dist/markdown/index.js.map +1 -1
  26. package/dist/slide/index.js +2 -2
  27. package/dist/slide/index.js.map +1 -1
  28. package/dist/table/index.js +6 -6
  29. package/dist/table/index.js.map +1 -1
  30. package/dist/ui/index.d.ts +4 -1
  31. package/dist/ui/index.js +21 -111
  32. package/dist/ui/index.js.map +1 -1
  33. package/dist/{upgrade-DBBE6GIR.js → upgrade-JHXZBGQS.js} +3 -3
  34. package/dist/{upgrade-DBBE6GIR.js.map → upgrade-JHXZBGQS.js.map} +1 -1
  35. package/dist/vite/index.js +2 -2
  36. package/docs/en/components.md +29 -15
  37. package/docs/en/parts/data-table.md +22 -0
  38. package/docs/en/parts/delta.md +50 -0
  39. package/docs/en/parts/format.md +43 -0
  40. package/docs/en/parts/kpi-card.md +57 -0
  41. package/docs/en/parts/metric-value.md +3 -2
  42. package/docs/en/parts/sparkline.md +1 -1
  43. package/docs/en/parts/trend-indicator.md +17 -1
  44. package/docs/en/ui-and-theming.md +1 -1
  45. package/docs/index.json +92 -32
  46. package/docs/ja/components.md +27 -15
  47. package/docs/ja/parts/data-table.md +22 -0
  48. package/docs/ja/parts/delta.md +50 -0
  49. package/docs/ja/parts/format.md +44 -0
  50. package/docs/ja/parts/kpi-card.md +55 -0
  51. package/docs/ja/parts/metric-value.md +3 -2
  52. package/docs/ja/parts/sparkline.md +1 -1
  53. package/docs/ja/parts/trend-indicator.md +17 -1
  54. package/docs/ja/ui-and-theming.md +2 -2
  55. package/package.json +26 -24
  56. package/registry/ui/accordion.tsx +4 -2
  57. package/registry/ui/alert-dialog.tsx +3 -3
  58. package/registry/ui/alert.tsx +3 -1
  59. package/registry/ui/app-shell.tsx +7 -1
  60. package/registry/ui/area-chart.tsx +2817 -157
  61. package/registry/ui/attention-list.tsx +303 -0
  62. package/registry/ui/avatar.tsx +1 -1
  63. package/registry/ui/badge.tsx +3 -1
  64. package/registry/ui/bar-chart.tsx +2816 -157
  65. package/registry/ui/bar-list.tsx +3507 -93
  66. package/registry/ui/box-plot-chart.tsx +3880 -0
  67. package/registry/ui/breadcrumb.tsx +3 -1
  68. package/registry/ui/button.tsx +3 -1
  69. package/registry/ui/calendar.tsx +3 -1
  70. package/registry/ui/card.tsx +4 -2
  71. package/registry/ui/category-bar.tsx +998 -16
  72. package/registry/ui/chart-frame.tsx +1366 -0
  73. package/registry/ui/checkbox.tsx +3 -1
  74. package/registry/ui/collapsible.tsx +3 -1
  75. package/registry/ui/combobox.tsx +2 -2
  76. package/registry/ui/command.tsx +3 -1
  77. package/registry/ui/dashboard-card.tsx +71 -28
  78. package/registry/ui/data-table.tsx +678 -56
  79. package/registry/ui/date-range-picker.tsx +245 -64
  80. package/registry/ui/delta.tsx +188 -0
  81. package/registry/ui/dialog.tsx +5 -3
  82. package/registry/ui/donut-chart.tsx +2893 -173
  83. package/registry/ui/drawer.tsx +1 -1
  84. package/registry/ui/dropdown-menu.tsx +5 -3
  85. package/registry/ui/echart.tsx +483 -46
  86. package/registry/ui/field.tsx +1 -1
  87. package/registry/ui/filter-bar.tsx +33 -6
  88. package/registry/ui/funnel-steps.tsx +3344 -49
  89. package/registry/ui/heatmap.tsx +1760 -0
  90. package/registry/ui/histogram-chart.tsx +3960 -0
  91. package/registry/ui/hover-card.tsx +2 -2
  92. package/registry/ui/input-group.tsx +3 -1
  93. package/registry/ui/input.tsx +3 -1
  94. package/registry/ui/kbd.tsx +3 -1
  95. package/registry/ui/kpi-card.tsx +699 -0
  96. package/registry/ui/label.tsx +3 -1
  97. package/registry/ui/legend.tsx +3536 -0
  98. package/registry/ui/line-chart.tsx +2817 -151
  99. package/registry/ui/metric-value.tsx +9 -1
  100. package/registry/ui/multi-select.tsx +11 -5
  101. package/registry/ui/page-shell.tsx +106 -51
  102. package/registry/ui/pagination.tsx +3 -1
  103. package/registry/ui/paired-chart.tsx +3801 -0
  104. package/registry/ui/placeholder.tsx +8 -2
  105. package/registry/ui/popover.tsx +4 -2
  106. package/registry/ui/progress-circle.tsx +607 -12
  107. package/registry/ui/progress.tsx +3 -1
  108. package/registry/ui/radio-group.tsx +1 -1
  109. package/registry/ui/sample-data.tsx +86 -0
  110. package/registry/ui/scatter-chart.tsx +4186 -0
  111. package/registry/ui/scroll-area.tsx +3 -2
  112. package/registry/ui/searchable-select.tsx +8 -3
  113. package/registry/ui/section-header.tsx +5 -3
  114. package/registry/ui/segmented-control.tsx +7 -2
  115. package/registry/ui/select.tsx +4 -2
  116. package/registry/ui/separator.tsx +3 -1
  117. package/registry/ui/sheet.tsx +4 -2
  118. package/registry/ui/sidebar.tsx +4 -2
  119. package/registry/ui/skeleton.tsx +4 -2
  120. package/registry/ui/slider.tsx +3 -1
  121. package/registry/ui/sparkline.tsx +84 -9
  122. package/registry/ui/spinner.tsx +3 -1
  123. package/registry/ui/states.tsx +34 -5
  124. package/registry/ui/status-badge.tsx +81 -39
  125. package/registry/ui/switch.tsx +3 -1
  126. package/registry/ui/table.tsx +4 -2
  127. package/registry/ui/tabs.tsx +5 -3
  128. package/registry/ui/textarea.tsx +3 -1
  129. package/registry/ui/toast.tsx +2 -2
  130. package/registry/ui/toggle-group.tsx +3 -1
  131. package/registry/ui/toggle.tsx +3 -1
  132. package/registry/ui/tooltip.tsx +4 -2
  133. package/registry/ui/tracker.tsx +624 -17
  134. package/registry/ui/trend-indicator.tsx +13 -1
  135. package/registry/ui/updated-at.tsx +122 -0
  136. package/registry/ui/waterfall-chart.tsx +4222 -0
  137. package/skills/vantage-design/SKILL.md +10 -2
  138. package/templates/AGENTS.md +13 -1
  139. package/templates/agents/page.md +10 -0
  140. package/theme.css +241 -147
  141. package/dist/chunk-5ZOP4SQR.js.map +0 -1
  142. package/dist/chunk-A2UUGASH.js.map +0 -1
  143. package/dist/chunk-AG6RZ2RR.js +0 -3208
  144. package/dist/chunk-AG6RZ2RR.js.map +0 -1
  145. package/dist/chunk-IBGOCWJB.js.map +0 -1
  146. package/dist/chunk-OB6UBJXF.js.map +0 -1
  147. package/dist/chunk-PXRX5PEC.js.map +0 -1
  148. package/dist/chunk-QEWCYW3I.js.map +0 -1
@@ -1,11 +1,11 @@
1
1
  import { FILE_PAGE_MAX_ROWS, FILE_PAGE_MAX_BYTES } from '../chunk-C2CX6GLX.js';
2
2
  import { useQuery } from '../chunk-V3LF7BE7.js';
3
3
  import '../chunk-XQUSGIDG.js';
4
- import { Loading, ErrorState } from '../chunk-5ZOP4SQR.js';
5
- import { PageShell, PageShellHeader, PageShellHeading, PageShellTitle, PageShellMeta, PageShellActions, PageShellContent } from '../chunk-AG6RZ2RR.js';
6
- import '../chunk-OB6UBJXF.js';
7
- import { Button } from '../chunk-PXRX5PEC.js';
8
- import { cn } from '../chunk-A2UUGASH.js';
4
+ import { Loading, ErrorState } from '../chunk-2N72FKLB.js';
5
+ import { PageShell, PageShellHeader, PageShellHeading, PageShellTitle, PageShellMeta, PageShellActions, PageShellContent } from '../chunk-HKSVYMYJ.js';
6
+ import '../chunk-XPQSTZUU.js';
7
+ import { Button } from '../chunk-PDOBHMUQ.js';
8
+ import { cn } from '../chunk-U736PVHY.js';
9
9
  import { useRef, useState, useMemo, useLayoutEffect, useEffect, useCallback } from 'react';
10
10
  import { DownloadIcon } from 'lucide-react';
11
11
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -167,7 +167,7 @@ var COL_PADDING = 18;
167
167
  var OVERSCAN_ROWS = 8;
168
168
  var OVERSCAN_COLS = 2;
169
169
  var WIDTH_SAMPLE_ROWS = 200;
170
- var CELL_FONT = '13px ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif';
170
+ var CELL_FONT = '13px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", Meiryo, ui-sans-serif, system-ui, sans-serif';
171
171
  function columnLabel(index) {
172
172
  let label = "";
173
173
  for (let n = index; n >= 0; n = Math.floor(n / 26) - 1) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/table/infer.ts","../../src/table/parse.ts","../../src/table/sheet-grid.tsx","../../src/table/table-viewer.tsx","../../src/table/file-page-view.tsx"],"names":["useState","useLayoutEffect","useRef","jsxs","jsx"],"mappings":";;;;;;;;;;;;;;;AAUA,IAAM,gBAAA,GAAmB,GAAA;AAGzB,IAAM,eAAA,GAAkB,GAAA;AAExB,SAAS,QAAQ,KAAA,EAAyB;AACxC,EAAA,OAAO,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,EAAA;AAC5D;AAQA,IAAM,QAAA,GAAW,oDAAA;AAEjB,SAAS,SAAS,KAAA,EAA4B;AAC5C,EAAA,IAAI,KAAA,YAAiB,MAAM,OAAO,MAAA;AAClC,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,QAAA,CAAS,KAAK,GAAG,OAAO,QAAA;AAChE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,SAAS,IAAA,CAAK,KAAK,GAAG,OAAO,MAAA;AAC9D,EAAA,OAAO,MAAA;AACT;AASA,SAAS,SAAA,CAAU,MAAA,EAAmB,KAAA,EAAe,IAAA,EAAkC;AACrF,EAAA,MAAM,UAAyB,EAAC;AAEhC,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,KAAA,EAAO,KAAA,EAAA,EAAS;AAC1C,IAAA,MAAM,GAAA,GAAM,OAAO,KAAK,CAAA;AACxB,IAAA,MAAM,KAAA,GAAQ,QAAQ,GAAG,CAAA,GAAI,KAAK,MAAA,CAAO,GAAG,EAAE,IAAA,EAAK;AAEnD,IAAA,IAAI,OAAA,GAAU,CAAA;AACd,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,KAAA,IAAS,GAAA,GAAM,GAAG,GAAA,GAAM,IAAA,CAAK,IAAI,IAAA,CAAK,MAAA,EAAQ,gBAAgB,CAAA,EAAG,GAAA,EAAA,EAAO;AACtE,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAG,CAAA,GAAI,KAAK,CAAA;AAC9B,MAAA,IAAI,OAAA,CAAQ,IAAI,CAAA,EAAG;AACnB,MAAA,MAAA,EAAA;AACA,MAAA,MAAM,IAAA,GAAO,SAAS,IAAI,CAAA;AAC1B,MAAA,IAAI,SAAS,QAAA,EAAU,OAAA,EAAA;AAAA,WAAA,IACd,SAAS,MAAA,EAAQ,KAAA,EAAA;AAAA,IAC5B;AACA,IAAA,IAAI,MAAA,GAAqB,MAAA;AACzB,IAAA,IAAI,SAAS,CAAA,EAAG;AACd,MAAA,IAAI,OAAA,GAAU,MAAA,IAAU,eAAA,EAAiB,MAAA,GAAS,QAAA;AAAA,WAAA,IACzC,KAAA,GAAQ,MAAA,IAAU,eAAA,EAAiB,MAAA,GAAS,MAAA;AAAA,IACvD;AAMA,IAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,GAAA,EAAK,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,KAAA,EAAO,QAAQ,CAAA;AAAA,EAClD;AACA,EAAA,OAAO,OAAA;AACT;AAOO,SAAS,OAAA,CAAQ,MAAc,IAAA,EAA+B;AACnE,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,IAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,EAAC,EAAG,IAAA,EAAM,EAAC,EAAG,SAAA,EAAW,CAAA,EAAG,SAAA,EAAW,KAAA,EAAM;AAAA,EACvE;AACA,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,CAAC,CAAA,IAAK,EAAC;AAC3B,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AACzB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,CAAC,GAAA,EAAK,GAAA,KAAQ,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,GAAA,CAAI,MAAM,CAAA,EAAG,CAAC,CAAA;AACpE,EAAA,MAAM,SAAA,GAAY,KAAK,MAAA,GAAS,kBAAA;AAChC,EAAA,MAAM,OAAO,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,kBAAkB,CAAA,GAAI,IAAA;AAC7D,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,OAAA,EAAS,SAAA,CAAU,MAAA,EAAQ,KAAA,EAAO,IAAI,CAAA;AAAA;AAAA;AAAA,IAGtC,MAAM,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,KAAQ,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,KAAA,EAAM,EAAG,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA,IAAK,IAAI,CAAC,CAAA;AAAA,IAC/E,WAAW,IAAA,CAAK,MAAA;AAAA,IAChB;AAAA,GACF;AACF;AAEA,IAAM,YAAA,GAAe,IAAI,IAAA,CAAK,YAAA,EAAa;AAU3C,IAAM,UAAA,GAAa,EAAE,QAAA,EAAU,KAAA,EAAM;AAM9B,SAAS,UAAA,CAAW,OAAgB,MAAA,EAA4B;AACrE,EAAA,IAAI,OAAA,CAAQ,KAAK,CAAA,EAAG,OAAO,EAAA;AAG3B,EAAA,IAAI,MAAA,KAAW,MAAA,IAAU,OAAO,KAAA,KAAU,UAAU,OAAO,KAAA;AAC3D,EAAA,IAAI,MAAA,KAAW,UAAU,KAAA,YAAiB,IAAA,SAAa,KAAA,CAAM,kBAAA,CAAmB,QAAW,UAAU,CAAA;AACrG,EAAA,IAAI,MAAA,KAAW,YAAY,OAAO,KAAA,KAAU,UAAU,OAAO,YAAA,CAAa,OAAO,KAAK,CAAA;AACtF,EAAA,IAAI,iBAAiB,IAAA,EAAM,OAAO,KAAA,CAAM,cAAA,CAAe,QAAW,UAAU,CAAA;AAC5E,EAAA,IAAI,OAAO,KAAA,KAAU,SAAA,EAAW,OAAO,QAAQ,MAAA,GAAS,OAAA;AACxD,EAAA,OAAO,OAAO,KAAK,CAAA;AACrB;;;AC9GO,IAAM,aAAA,GAAN,cAA4B,KAAA,CAAM;AAAA,EACvC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,eAAA;AAAA,EACd;AACF;AAEA,SAAS,UAAU,KAAA,EAAuB;AACxC,EAAA,OAAO,IAAI,KAAA,GAAQ,IAAA,GAAO,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAA,CAAA;AAC5C;AASA,SAAS,UAAU,MAAA,EAA6B;AAC9C,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,MAAM,CAAA;AACnC,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,CAAC,CAAA,KAAM,GAAA,IAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,GAAA,IAAQ,KAAA,CAAM,CAAC,CAAA,KAAM,GAAA;AACtE,EAAA,MAAM,IAAA,GAAO,MAAA,GAAS,KAAA,CAAM,QAAA,CAAS,CAAC,CAAA,GAAI,KAAA;AAC1C,EAAA,MAAM,OAAO,IAAI,WAAA,CAAY,OAAO,CAAA,CAAE,OAAO,IAAI,CAAA;AACjD,EAAA,MAAM,gBAAgB,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,IAAK,EAAC,EAAG,MAAA;AAC9C,EAAA,IAAI,YAAA,GAAe,KAAK,YAAA,GAAe,IAAA,CAAK,IAAI,IAAA,CAAK,MAAA,EAAQ,CAAC,CAAA,GAAI,IAAA,EAAQ;AACxE,IAAA,IAAI;AACF,MAAA,OAAO,IAAI,WAAA,CAAY,WAAW,CAAA,CAAE,OAAO,IAAI,CAAA;AAAA,IACjD,CAAA,CAAA,MAAQ;AAAA,IAGR;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAEA,eAAe,SAAS,MAAA,EAAwC;AAC9D,EAAA,MAAM,EAAE,OAAA,EAAS,IAAA,EAAK,GAAI,MAAM,OAAO,WAAW,CAAA;AAClD,EAAA,MAAM,IAAA,GAAO,UAAU,MAAM,CAAA;AAG7B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAiB,IAAA,EAAM;AAAA,IACzC,MAAA,EAAQ,KAAA;AAAA,IACR,aAAA,EAAe,IAAA;AAAA,IACf,cAAA,EAAgB;AAAA,GACjB,CAAA;AACD,EAAA,OAAO,EAAE,QAAQ,CAAC,OAAA,CAAQ,UAAU,MAAA,CAAO,IAAI,CAAC,CAAA,EAAE;AACpD;AAEA,eAAe,UAAU,MAAA,EAAwC;AAG/D,EAAA,MAAM,EAAE,OAAA,EAAS,YAAA,EAAa,GAAI,MAAM,OAAO,yBAAyB,CAAA;AACxE,EAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,MAAM,CAAA;AACxC,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU,QAAQ,KAAA,CAAM,KAAA,EAAO,KAAA,CAAM,IAAmB,CAAC;AAAA,GAC/E;AACF;AAOA,eAAsB,YAAA,CAAa,KAAa,IAAA,EAAiC;AAC/E,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAG,CAAA;AAChC,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,IAAI,aAAA,CAAc,CAAA,8BAAA,EAAiC,QAAA,CAAS,MAAM,CAAA,EAAA,CAAI,CAAA;AAAA,IAC9E;AACA,IAAA,MAAA,GAAS,MAAM,SAAS,WAAA,EAAY;AAAA,EACtC,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,GAAA,YAAe,eAAe,MAAM,GAAA;AACxC,IAAA,MAAM,IAAI,aAAA,CAAc,CAAA,yBAAA,EAA6B,GAAA,CAAc,OAAO,CAAA,CAAE,CAAA;AAAA,EAC9E;AAEA,EAAA,IAAI,MAAA,CAAO,aAAa,mBAAA,EAAqB;AAC3C,IAAA,MAAM,IAAI,aAAA;AAAA,MACR,CAAA,aAAA,EAAgB,SAAA,CAAU,MAAA,CAAO,UAAU,CAAC,CAAA,WAAA,EAAc,SAAA;AAAA,QACxD;AAAA,OACD,CAAA,0GAAA;AAAA,KACH;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,QAAQ,IAAA;AAAM,MACZ,KAAK,KAAA;AACH,QAAA,OAAO,MAAM,SAAS,MAAM,CAAA;AAAA,MAC9B,KAAK,MAAA;AACH,QAAA,OAAO,MAAM,UAAU,MAAM,CAAA;AAAA,MAC/B;AAGE,QAAA,MAAM,IAAI,aAAA,CAAc,CAAA,gBAAA,EAAmB,IAAI,CAAA,QAAA,CAAU,CAAA;AAAA;AAC7D,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,GAAA,YAAe,eAAe,MAAM,GAAA;AACxC,IAAA,MAAM,IAAI,aAAA;AAAA,MACR,CAAA,qFAAA,EAAwF,IAAI,CAAA,QAAA,EACzF,GAAA,CAAc,OACjB,CAAA,CAAA;AAAA,KACF;AAAA,EACF;AACF;ACtFA,IAAM,UAAA,GAAa,EAAA;AAEnB,IAAM,WAAA,GAAc,EAAA;AACpB,IAAM,gBAAA,GAAmB,EAAA;AACzB,IAAM,aAAA,GAAgB,EAAA;AACtB,IAAM,aAAA,GAAgB,GAAA;AAEtB,IAAM,gBAAA,GAAmB,GAAA;AAEzB,IAAM,WAAA,GAAc,EAAA;AACpB,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAM,aAAA,GAAgB,CAAA;AAEtB,IAAM,iBAAA,GAAoB,GAAA;AAE1B,IAAM,SAAA,GACJ,oKAAA;AAGK,SAAS,YAAY,KAAA,EAAuB;AACjD,EAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,EAAA,KAAA,IAAS,CAAA,GAAI,KAAA,EAAO,CAAA,IAAK,CAAA,EAAG,CAAA,GAAI,KAAK,KAAA,CAAM,CAAA,GAAI,EAAE,CAAA,GAAI,CAAA,EAAG;AACtD,IAAA,KAAA,GAAQ,MAAA,CAAO,YAAA,CAAa,EAAA,GAAM,CAAA,GAAI,EAAG,CAAA,GAAI,KAAA;AAAA,EAC/C;AACA,EAAA,OAAO,KAAA;AACT;AAQA,SAAS,cAAc,KAAA,EAA6B;AAClD,EAAA,MAAM,OAAA,GACJ,OAAO,QAAA,KAAa,WAAA,GAAc,IAAA,GAAO,SAAS,aAAA,CAAc,QAAQ,CAAA,CAAE,UAAA,CAAW,IAAI,CAAA;AAC3F,EAAA,IAAI,OAAA,UAAiB,IAAA,GAAO,SAAA;AAG5B,EAAA,MAAM,OAAA,GAAU,CAAC,IAAA,KAAkB,OAAA,GAAU,OAAA,CAAQ,YAAY,IAAI,CAAA,CAAE,KAAA,GAAQ,IAAA,CAAK,MAAA,GAAS,GAAA;AAC7F,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,KAAK,KAAA,CAAM,IAAA,CAAK,MAAA,GAAS,iBAAiB,CAAC,CAAA;AAE3E,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,QAAQ,KAAA,KAAU;AAC1C,IAAA,IAAI,GAAA,GAAM,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAA;AAC9B,IAAA,KAAA,IAAS,MAAM,CAAA,EAAG,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,EAAQ,OAAO,MAAA,EAAQ;AACxD,MAAA,MAAM,IAAA,GAAO,WAAW,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA,GAAI,KAAK,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA;AAC/D,MAAA,IAAI,IAAA,KAAS,IAAI,GAAA,GAAM,IAAA,CAAK,IAAI,GAAA,EAAK,OAAA,CAAQ,IAAI,CAAC,CAAA;AAAA,IACpD;AACA,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,aAAA,EAAe,IAAA,CAAK,GAAA,CAAI,aAAA,EAAe,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,GAAI,WAAW,CAAC,CAAA;AAAA,EACtF,CAAC,CAAA;AACH;AAGA,SAAS,eAAe,MAAA,EAA4B;AAClD,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,CAAA;AAClB,EAAA,KAAA,MAAW,KAAA,IAAS,QAAQ,OAAA,CAAQ,IAAA,CAAK,QAAQ,OAAA,CAAQ,MAAA,GAAS,CAAC,CAAA,GAAK,KAAK,CAAA;AAC7E,EAAA,OAAO,OAAA;AACT;AAGA,SAAS,QAAA,CAAS,SAAmB,CAAA,EAAmB;AACtD,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,IAAA,GAAO,QAAQ,MAAA,GAAS,CAAA;AAC5B,EAAA,OAAO,MAAM,IAAA,EAAM;AACjB,IAAA,MAAM,GAAA,GAAO,GAAA,GAAM,IAAA,GAAO,CAAA,IAAM,CAAA;AAChC,IAAA,IAAI,OAAA,CAAQ,GAAG,CAAA,IAAM,CAAA,EAAG,GAAA,GAAM,GAAA;AAAA,gBAClB,GAAA,GAAM,CAAA;AAAA,EACpB;AACA,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAG,CAAA;AACxB;AAiBO,SAAS,SAAA,CAAU,EAAE,KAAA,EAAO,SAAA,EAAU,EAAmB;AAC9D,EAAA,MAAM,SAAA,GAAY,OAAuB,IAAI,CAAA;AAC7C,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,QAAA,CAAS,EAAE,GAAA,EAAK,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,CAAA;AACxD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,QAAA,CAAS,EAAE,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAG,CAAA;AAChE,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,QAAA,CAAoB,EAAE,GAAA,EAAK,CAAA,EAAG,GAAA,EAAK,CAAA,EAAG,CAAA;AAEtE,EAAA,MAAM,UAAA,GAAa,QAAQ,MAAM,aAAA,CAAc,KAAK,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAC9D,EAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,MAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA;AAI5B,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,gBAAA,EAAkB,MAAA,CAAO,WAAW,CAAC,CAAA,CAAE,MAAA,GAAS,CAAA,GAAI,EAAE,CAAA;AAKnF,EAAA,MAAM,SAAA,GAAY,WAAW,MAAA,CAAO,CAAC,KAAK,KAAA,KAAU,GAAA,GAAM,OAAO,CAAC,CAAA;AAClE,EAAA,MAAM,aAAa,IAAA,CAAK,GAAA;AAAA,IACtB,CAAA;AAAA,IACA,KAAK,IAAA,CAAA,CAAM,QAAA,CAAS,KAAA,GAAQ,WAAA,GAAc,aAAa,gBAAgB;AAAA,GACzE;AACA,EAAA,MAAM,aAAa,IAAA,CAAK,GAAA;AAAA,IACtB,CAAA;AAAA,IACA,IAAA,CAAK,MAAM,QAAA,CAAS,MAAA,GAAS,eAAe,QAAA,GAAW,CAAA,IAAK,cAAc,UAAU;AAAA,GACtF;AACA,EAAA,MAAM,WAAW,QAAA,GAAW,UAAA;AAC5B,EAAA,MAAM,WAAW,QAAA,GAAW,UAAA;AAE5B,EAAA,MAAM,MAAA,GAAS,OAAA;AAAA,IACb,MAAM,CAAC,GAAG,UAAA,EAAY,GAAG,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,UAAA,EAAW,EAAG,MAAM,gBAAgB,CAAC,CAAA;AAAA,IACnF,CAAC,YAAY,UAAU;AAAA,GACzB;AACA,EAAA,MAAM,OAAA,GAAU,QAAQ,MAAM,cAAA,CAAe,MAAM,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAC9D,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,OAAA,CAAQ,MAAA,GAAS,CAAC,CAAA,IAAK,CAAA;AAElD,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAC1B,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,EAAE,KAAA,EAAO,QAAQ,WAAA,EAAa,MAAA,EAAQ,OAAA,CAAQ,YAAA,EAAc,CAAA;AAC9F,IAAA,OAAA,EAAQ;AACR,IAAA,MAAM,QAAA,GAAW,IAAI,cAAA,CAAe,OAAO,CAAA;AAC3C,IAAA,QAAA,CAAS,QAAQ,OAAO,CAAA;AACxB,IAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,EACnC,CAAA,EAAG,EAAE,CAAA;AAIL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,WAAA,CAAY,EAAE,GAAA,EAAK,CAAA,EAAG,GAAA,EAAK,GAAG,CAAA;AAC9B,IAAA,SAAA,CAAU,SAAS,QAAA,CAAS,EAAE,KAAK,CAAA,EAAG,IAAA,EAAM,GAAG,CAAA;AAAA,EACjD,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAIV,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,MAAM,MAAA,CAAO,GAAA,GAAM,UAAU,CAAA,GAAI,aAAa,CAAA;AAChF,EAAA,MAAM,UAAU,IAAA,CAAK,GAAA;AAAA,IACnB,QAAA;AAAA,IACA,IAAA,CAAK,MAAM,MAAA,CAAO,GAAA,GAAM,SAAS,MAAA,GAAS,WAAA,GAAc,UAAA,IAAc,UAAU,CAAA,GAC9E;AAAA,GACJ;AACA,EAAA,MAAM,QAAA,GAAW,KAAK,GAAA,CAAI,CAAA,EAAG,SAAS,OAAA,EAAS,MAAA,CAAO,IAAI,CAAA,GAAI,aAAa,CAAA;AAC3E,EAAA,MAAM,UAAU,IAAA,CAAK,GAAA;AAAA,IACnB,QAAA;AAAA,IACA,SAAS,OAAA,EAAS,MAAA,CAAO,OAAO,QAAA,CAAS,KAAK,IAAI,CAAA,GAAI;AAAA,GACxD;AACA,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,QAAQ,CAAA,IAAK,CAAA;AACvC,EAAA,MAAM,SAAA,GAAY,UAAA,IAAc,OAAA,CAAQ,OAAO,CAAA,IAAK,UAAA,CAAA;AACpD,EAAA,MAAM,cAAc,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,KAAK,GAAA,CAAI,CAAA,EAAG,OAAA,GAAU,QAAQ,GAAE,EAAG,CAAC,CAAA,EAAG,CAAA,KAAM,WAAW,CAAC,CAAA;AAGlG,EAAA,MAAM,MAAA,GAAS,WAAA;AAAA,IACb,CAAC,IAAA,KAAoB;AACnB,MAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAC1B,MAAA,IAAI,CAAC,OAAA,EAAS;AACd,MAAA,IAAI,IAAA,CAAK,MAAM,CAAA,EAAG;AAChB,QAAA,MAAM,GAAA,GAAM,WAAA,GAAc,UAAA,GAAA,CAAc,IAAA,CAAK,MAAM,CAAA,IAAK,UAAA;AACxD,QAAA,MAAM,SAAS,WAAA,GAAc,UAAA;AAC7B,QAAA,IAAI,MAAM,OAAA,CAAQ,SAAA,GAAY,MAAA,EAAQ,OAAA,CAAQ,YAAY,GAAA,GAAM,MAAA;AAAA,aAAA,IACvD,GAAA,GAAM,UAAA,GAAa,OAAA,CAAQ,SAAA,GAAY,QAAQ,YAAA,EAAc;AACpE,UAAA,OAAA,CAAQ,SAAA,GAAY,GAAA,GAAM,UAAA,GAAa,OAAA,CAAQ,YAAA;AAAA,QACjD;AAAA,MACF;AACA,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA,IAAK,CAAA;AAClC,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,IAAK,CAAA;AAClC,MAAA,IAAI,IAAA,GAAO,OAAA,CAAQ,UAAA,GAAa,CAAA,UAAW,UAAA,GAAa,IAAA;AAAA,WAAA,IAC/C,OAAO,KAAA,GAAQ,WAAA,GAAc,OAAA,CAAQ,UAAA,GAAa,QAAQ,WAAA,EAAa;AAC9E,QAAA,OAAA,CAAQ,UAAA,GAAa,IAAA,GAAO,KAAA,GAAQ,WAAA,GAAc,OAAA,CAAQ,WAAA;AAAA,MAC5D;AAAA,IACF,CAAA;AAAA,IACA,CAAC,WAAA,EAAa,OAAA,EAAS,MAAM;AAAA,GAC/B;AAEA,EAAA,MAAM,QAAA,GAAW,WAAA;AAAA,IACf,CAAC,KAAa,GAAA,KAAwB;AACpC,MAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAChC,MAAA,IAAI,CAAC,QAAQ,OAAO,EAAA;AACpB,MAAA,IAAI,GAAA,KAAQ,CAAA,EAAG,OAAO,MAAA,CAAO,KAAA;AAC7B,MAAA,OAAO,UAAA,CAAW,MAAM,IAAA,CAAK,GAAA,GAAM,CAAC,CAAA,GAAI,GAAG,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA;AAAA,IAC7D,CAAA;AAAA,IACA,CAAC,KAAK;AAAA,GACR;AAEA,EAAA,MAAM,SAAA,GAAY,WAAA;AAAA,IAChB,CAAC,KAAA,KAAyC;AAQxC,MAAA,MAAM,IAAA,GAAO,CAAC,IAAA,EAAc,IAAA,EAAc,YAAY,KAAA,KAAU;AAC9D,QAAA,MAAM,IAAA,GAAO;AAAA,UACX,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,IAAA,CAAK,IAAI,CAAA,EAAG,QAAA,CAAS,GAAA,GAAM,IAAI,CAAC,CAAA;AAAA,UACxD,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,QAAA,GAAW,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,QAAA,CAAS,GAAA,GAAM,IAAI,CAAC;AAAA,SAC9D;AACA,QAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,KAAQ,SAAS,GAAA,IAAO,IAAA,CAAK,QAAQ,QAAA,CAAS,GAAA;AACjE,QAAA,IAAI,KAAA,IAAS,CAAC,SAAA,EAAW,KAAA,CAAM,cAAA,EAAe;AAC9C,QAAA,IAAI,CAAC,KAAA,EAAO;AACZ,QAAA,WAAA,CAAY,IAAI,CAAA;AAChB,QAAA,MAAA,CAAO,IAAI,CAAA;AAAA,MACb,CAAA;AACA,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,MAAM,QAAA,CAAS,MAAA,GAAS,UAAU,CAAA,GAAI,CAAC,CAAA;AAErE,MAAA,QAAQ,MAAM,GAAA;AAAK,QACjB,KAAK,WAAA;AACH,UAAA,OAAO,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,QAClB,KAAK,SAAA;AACH,UAAA,OAAO,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,QACnB,KAAK,KAAA;AACH,UAAA,OAAO,KAAK,CAAA,EAAG,KAAA,CAAM,QAAA,GAAW,EAAA,GAAK,GAAG,IAAI,CAAA;AAAA,QAC9C,KAAK,YAAA;AACH,UAAA,OAAO,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,QAClB,KAAK,WAAA;AACH,UAAA,OAAO,IAAA,CAAK,GAAG,EAAE,CAAA;AAAA,QACnB,KAAK,UAAA;AACH,UAAA,OAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,QACrB,KAAK,QAAA;AACH,UAAA,OAAO,IAAA,CAAK,CAAC,IAAA,EAAM,CAAC,CAAA;AAAA,QACtB,KAAK,MAAA;AACH,UAAA,OAAO,IAAA,CAAK,MAAM,OAAA,IAAW,KAAA,CAAM,UAAU,CAAC,QAAA,GAAW,CAAA,EAAG,CAAC,QAAQ,CAAA;AAAA,QACvE,KAAK,KAAA;AACH,UAAA,OAAO,KAAK,KAAA,CAAM,OAAA,IAAW,MAAM,OAAA,GAAU,QAAA,GAAW,GAAG,QAAQ,CAAA;AAAA,QACrE,KAAK,GAAA;AAAA,QACL,KAAK,GAAA;AAGH,UAAA,IAAI,KAAA,CAAM,OAAA,IAAW,KAAA,CAAM,OAAA,EAAS;AAGlC,YAAA,SAAA,CAAU,SAAA,EAAW,SAAA,CAAU,QAAA,CAAS,QAAA,CAAS,GAAA,EAAK,SAAS,GAAG,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,YAAC,CAAC,CAAA;AAAA,UACrF;AACA,UAAA;AAAA,QACF;AACE,UAAA;AAAA;AACJ,IACF,CAAA;AAAA,IACA,CAAC,QAAA,EAAU,QAAA,EAAU,UAAU,MAAA,EAAQ,QAAA,EAAU,SAAS,MAAM;AAAA,GAClE;AAEA,EAAA,IAAI,aAAa,CAAA,EAAG;AAClB,IAAA,2BAAQ,GAAA,EAAA,EAAE,SAAA,EAAW,GAAG,mCAAA,EAAqC,SAAS,GAAG,QAAA,EAAA,sBAAA,EAAoB,CAAA;AAAA,EAC/F;AAEA,EAAA,MAAM,MAAA,GAAS,CAAC,GAAA,EAAa,GAAA,KAAgB;AAC3C,IAAA,WAAA,CAAY,EAAE,GAAA,EAAK,GAAA,EAAK,CAAA;AACxB,IAAA,SAAA,CAAU,OAAA,EAAS,KAAA,CAAM,EAAE,aAAA,EAAe,MAAM,CAAA;AAAA,EAClD,CAAA;AAEA,EAAA,MAAM,WAA0B,EAAE,MAAA,EAAQ,UAAA,EAAY,KAAA,EAAO,cAAc,UAAA,EAAW;AAEtF,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,SAAA;AAAA,MACL,IAAA,EAAK,MAAA;AAAA,MACL,cAAY,KAAA,CAAM,IAAA;AAAA,MAClB,iBAAe,QAAA,GAAW,CAAA;AAAA,MAC1B,eAAA,EAAe,QAAA;AAAA,MACf,QAAA,EAAU,CAAA;AAAA,MACV,QAAA,EAAU,CAAC,KAAA,KACT,SAAA,CAAU,EAAE,GAAA,EAAK,KAAA,CAAM,aAAA,CAAc,SAAA,EAAW,IAAA,EAAM,KAAA,CAAM,aAAA,CAAc,YAAY,CAAA;AAAA,MAExF,SAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACT,gHAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEA,QAAA,kBAAA,IAAA,CAAC,SAAI,IAAA,EAAK,UAAA,EAAW,OAAO,EAAE,KAAA,EAAO,WAAA,GAAc,UAAA,EAAW,EAE5D,QAAA,EAAA;AAAA,wBAAA,IAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,wBAAA;AAAA,YACV,KAAA,EAAO,EAAE,GAAG,QAAA,EAAU,QAAQ,WAAA,EAAY;AAAA,YAC1C,IAAA,EAAK,KAAA;AAAA,YAEL,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,sEAAA;AAAA,kBACV,KAAA,EAAO,EAAE,KAAA,EAAO,WAAA,EAAa,QAAQ,WAAA;AAAY;AAAA,eACnD;AAAA,8BACA,GAAA,CAAC,SAAI,SAAA,EAAU,0CAAA,EAA2C,OAAO,EAAE,KAAA,EAAO,WAAU,EAAG,CAAA;AAAA,cACtF,WAAA,CAAY,GAAA,CAAI,CAAC,GAAA,qBAChB,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBAEC,IAAA,EAAM,GAAA,GAAM,QAAA,GAAW,cAAA,GAAiB,cAAA;AAAA,kBACxC,eAAA,EAAe,GAAA,GAAM,QAAA,GAAW,GAAA,GAAM,CAAA,GAAI,MAAA;AAAA,kBAC1C,WAAA,EAAa,MAAM,QAAA,GAAW,MAAM,OAAO,QAAA,CAAS,GAAA,EAAK,GAAG,CAAA,GAAI,MAAA;AAAA,kBAChE,SAAA,EAAW,EAAA;AAAA,oBACT,sHAAA;AAAA,oBACA,QAAA,CAAS,GAAA,KAAQ,GAAA,IAAO,GAAA,GAAM,QAAA,IAAY;AAAA,mBAC5C;AAAA,kBACA,OAAO,EAAE,KAAA,EAAO,OAAO,GAAG,CAAA,EAAG,QAAQ,WAAA,EAAY;AAAA,kBAEhD,sBAAY,GAAG;AAAA,iBAAA;AAAA,gBAVX;AAAA,eAYR,CAAA;AAAA,8BACD,GAAA,CAAC,SAAI,SAAA,EAAU,0CAAA,EAA2C,OAAO,EAAE,KAAA,EAAO,WAAU,EAAG;AAAA;AAAA;AAAA,SACzF;AAAA,wBAMA,IAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,gCAAA;AAAA,YACV,KAAA,EAAO,EAAE,GAAG,QAAA,EAAU,KAAK,WAAA,EAAY;AAAA,YACvC,IAAA,EAAK,KAAA;AAAA,YAEL,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,SAAA;AAAA,gBAAA;AAAA,kBACC,KAAA,EAAM,GAAA;AAAA,kBACN,KAAA,EAAO,WAAA;AAAA,kBACP,MAAA,EAAQ,SAAS,GAAA,KAAQ,CAAA;AAAA,kBACzB,QAAA,EAAU,MAAM,MAAA,CAAO,CAAA,EAAG,SAAS,GAAG;AAAA;AAAA,eACxC;AAAA,8BACA,GAAA,CAAC,SAAI,SAAA,EAAU,wCAAA,EAAyC,OAAO,EAAE,KAAA,EAAO,WAAU,EAAG,CAAA;AAAA,cACpF,WAAA,CAAY,GAAA,CAAI,CAAC,GAAA,qBAChB,GAAA;AAAA,gBAAC,IAAA;AAAA,gBAAA;AAAA,kBAEC,KAAA,EAAO,OAAO,GAAG,CAAA;AAAA,kBAGjB,MAAA,EAAO,MAAA;AAAA,kBACP,IAAA,EAAM,KAAA,CAAM,OAAA,CAAQ,GAAG,GAAG,KAAA,IAAS,EAAA;AAAA,kBACnC,MAAA,EAAM,IAAA;AAAA,kBACN,QAAA,EAAU,QAAA,CAAS,GAAA,KAAQ,CAAA,IAAK,SAAS,GAAA,KAAQ,GAAA;AAAA,kBACjD,UAAU,GAAA,GAAM,QAAA,GAAW,MAAM,MAAA,CAAO,CAAA,EAAG,GAAG,CAAA,GAAI,MAAA;AAAA,kBAClD,QAAA,EAAU,GAAA,GAAM,QAAA,GAAW,GAAA,GAAM;AAAA,iBAAA;AAAA,gBAT5B;AAAA,eAWR,CAAA;AAAA,8BACD,GAAA,CAAC,SAAI,SAAA,EAAU,wCAAA,EAAyC,OAAO,EAAE,KAAA,EAAO,WAAU,EAAG;AAAA;AAAA;AAAA,SACvF;AAAA,wBAGA,GAAA,CAAC,KAAA,EAAA,EAAI,IAAA,EAAK,cAAA,EAAe,SAAA,EAAU,YAAW,KAAA,EAAO,EAAE,MAAA,EAAQ,QAAA,GAAW,UAAA,EAAW,EAClF,gBAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,GAAU,QAAQ,CAAA,EAAE,EAAG,CAAC,CAAA,EAAG,MAAA,KAAW;AACtE,UAAA,MAAM,MAAM,QAAA,GAAW,MAAA;AACvB,UAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA;AAC5B,UAAA,uBACE,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cAEC,IAAA,EAAK,KAAA;AAAA,cACL,eAAA,EAAe,GAAA,GAAM,QAAA,GAAW,GAAA,GAAM,CAAA,GAAI,MAAA;AAAA,cAC1C,SAAA,EAAU,eAAA;AAAA,cACV,OAAO,EAAE,GAAG,QAAA,EAAU,GAAA,EAAK,MAAM,UAAA,EAAW;AAAA,cAE5C,QAAA,EAAA;AAAA,gCAAA,GAAA;AAAA,kBAAC,SAAA;AAAA,kBAAA;AAAA,oBACC,KAAA,EAAO,MAAA,CAAO,GAAA,GAAM,CAAC,CAAA;AAAA,oBACrB,KAAA,EAAO,WAAA;AAAA,oBACP,MAAA,EAAQ,QAAA,CAAS,GAAA,KAAQ,GAAA,GAAM,CAAA;AAAA,oBAC/B,QAAA,EAAU,MAAM,QAAA,GAAW,MAAM,OAAO,GAAA,GAAM,CAAA,EAAG,QAAA,CAAS,GAAG,CAAA,GAAI;AAAA;AAAA,iBACnE;AAAA,gCACA,GAAA,CAAC,SAAI,SAAA,EAAU,UAAA,EAAW,OAAO,EAAE,KAAA,EAAO,WAAU,EAAG,CAAA;AAAA,gBACtD,WAAA,CAAY,GAAA,CAAI,CAAC,GAAA,KAAQ;AACxB,kBAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAChC,kBAAA,uBACE,GAAA;AAAA,oBAAC,IAAA;AAAA,oBAAA;AAAA,sBAEC,KAAA,EAAO,OAAO,GAAG,CAAA;AAAA,sBACjB,MAAA,EAAQ,QAAQ,MAAA,IAAU,MAAA;AAAA,sBAC1B,IAAA,EAAM,SAAS,UAAA,CAAW,KAAA,GAAQ,GAAG,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA,GAAI,EAAA;AAAA,sBACzD,UAAU,QAAA,CAAS,GAAA,KAAQ,GAAA,GAAM,CAAA,IAAK,SAAS,GAAA,KAAQ,GAAA;AAAA,sBACvD,QAAA,EACE,GAAA,GAAM,QAAA,IAAY,GAAA,GAAM,QAAA,GAAW,MAAM,MAAA,CAAO,GAAA,GAAM,CAAA,EAAG,GAAG,CAAA,GAAI,MAAA;AAAA,sBAElE,QAAA,EAAU,GAAA,GAAM,QAAA,GAAW,GAAA,GAAM;AAAA,qBAAA;AAAA,oBAR5B;AAAA,mBASP;AAAA,gBAEJ,CAAC,CAAA;AAAA,gCACD,GAAA,CAAC,SAAI,SAAA,EAAU,UAAA,EAAW,OAAO,EAAE,KAAA,EAAO,WAAU,EAAG;AAAA;AAAA,aAAA;AAAA,YA7BlD;AAAA,WA8BP;AAAA,QAEJ,CAAC,CAAA,EACH;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;AACA,SAAA,CAAU,WAAA,GAAc,WAAA;AAExB,SAAS,SAAA,CAAU;AAAA,EACjB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,WAAW,WAAA,GAAc,cAAA;AAAA,MAC/B,WAAA,EAAa,QAAA;AAAA,MACb,SAAA,EAAW,EAAA;AAAA;AAAA;AAAA,QAGT,gJAAA;AAAA,QACA,MAAA,IAAU;AAAA,OACZ;AAAA,MACA,KAAA,EAAO,EAAE,KAAA,EAAM;AAAA,MAEd,QAAA,EAAA;AAAA;AAAA,GACH;AAEJ;AAEA,SAAS,IAAA,CAAK;AAAA,EACZ,KAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAQG;AACD,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,WAAW,UAAA,GAAa,cAAA;AAAA,MAC9B,eAAA,EAAe,QAAA,KAAa,MAAA,GAAY,MAAA,GAAY,QAAA,GAAW,CAAA;AAAA,MAC/D,eAAA,EAAe,WAAW,QAAA,GAAW,MAAA;AAAA,MACrC,WAAA,EAAa,QAAA;AAAA,MAIb,OAAO,IAAA,IAAQ,MAAA;AAAA,MACf,SAAA,EAAW,EAAA;AAAA,QACT,0EAAA;AAAA,QACA,MAAA,IAAU,oCAAA;AAAA;AAAA,QAEV,MAAA,KAAW,SAAS,eAAA,GAAkB,0BAAA;AAAA,QACtC,YAAY,QAAA,IAAY;AAAA,OAC1B;AAAA,MACA,KAAA,EAAO,EAAE,KAAA,EAAM;AAAA,MAEf,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,QAAA,EAAA,IAAA,EAAK;AAAA;AAAA,GACnC;AAEJ;ACndA,IAAM,UAAA,GAAa,GAAA;AAEnB,IAAM,cAAA,GAAiB,CAAA;AA0BvB,SAAS,WAAW,OAAA,EAA8B;AAChD,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,IAAS,IAAA,GAAO,QAAQ,aAAA,EAAe,IAAA,IAAQ,SAAS,QAAA,CAAS,IAAA,EAAM,IAAA,GAAO,IAAA,CAAK,aAAA,EAAe;AAChG,IAAA,MAAM,KAAA,GAAQ,iBAAiB,IAAI,CAAA;AACnC,IAAA,KAAA,IACE,UAAA,CAAW,KAAA,CAAM,aAAa,CAAA,GAAI,UAAA,CAAW,MAAM,iBAAiB,CAAA,GAAI,UAAA,CAAW,KAAA,CAAM,YAAY,CAAA;AAAA,EACzG;AACA,EAAA,OAAO,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAA;AAC1C;AAOA,SAAS,aAAA,CAAc,KAAoC,OAAA,EAA0B;AACnF,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,SAAS,UAAU,CAAA;AAE/C,EAAAC,gBAAgB,MAAM;AACpB,IAAA,MAAM,UAAU,GAAA,CAAI,OAAA;AACpB,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,EAAS;AAC1B,IAAA,MAAM,UAAU,MAAM;AAKpB,MAAA,MAAM,IAAA,GAAO,QAAQ,qBAAA,EAAsB;AAC3C,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,GAAM,MAAA,CAAO,OAAA;AAC9B,MAAA,MAAM,OAAO,IAAA,CAAK,GAAA;AAAA,QAChB,UAAA;AAAA,QACA,MAAA,CAAO,cAAc,GAAA,GAAM,IAAA,CAAK,IAAI,UAAA,CAAW,OAAO,GAAG,cAAc;AAAA,OACzE;AAGA,MAAA,SAAA,CAAU,CAAC,YAAa,IAAA,CAAK,GAAA,CAAI,UAAU,IAAI,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO,OAAQ,CAAA;AAAA,IACxE,CAAA;AACA,IAAA,OAAA,EAAQ;AACR,IAAA,MAAM,QAAA,GAAW,IAAI,cAAA,CAAe,OAAO,CAAA;AAC3C,IAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,IAAI,CAAA;AAC9B,IAAA,MAAA,CAAO,gBAAA,CAAiB,UAAU,OAAO,CAAA;AACzC,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,UAAA,EAAW;AACpB,MAAA,MAAA,CAAO,mBAAA,CAAoB,UAAU,OAAO,CAAA;AAAA,IAC9C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,GAAG,CAAC,CAAA;AAEjB,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,MAAA,CAAO,OAAe,IAAA,EAAsB;AACnD,EAAA,OAAO,CAAA,EAAG,KAAA,CAAM,cAAA,EAAgB,CAAA,CAAA,EAAI,IAAI,CAAA,EAAG,KAAA,KAAU,CAAA,GAAI,EAAA,GAAK,GAAG,CAAA,CAAA;AACnE;AAGO,SAAS,WAAA,CAAY;AAAA,EAC1B,KAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA,GAAc,CAAA;AAAA,EACd,aAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,QAAA,GAAWC,OAAuB,IAAI,CAAA;AAC5C,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,QAAA,EAAU,MAAA,KAAW,MAAS,CAAA;AAC3D,EAAA,MAAM,IAAA,GAAO,UAAA,IAAc,UAAA,CAAW,MAAA,GAAS,IAAI,UAAA,GAAa,IAAA;AAEhE,EAAA,uBACEC,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,QAAA;AAAA,MACL,SAAA,EAAW,EAAA;AAAA,QACT,6EAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,KAAA,EAAO,EAAE,MAAA,EAAQ,MAAA,IAAU,MAAA,EAAO;AAAA,MAElC,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC,SAAI,SAAA,EAAU,gBAAA,EACb,0BAAAA,GAAAA,CAAC,SAAA,EAAA,EAAU,OAAc,CAAA,EAC3B,CAAA;AAAA,wBAIAD,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sEAAA,EACZ,QAAA,EAAA;AAAA,UAAA,IAAA,mBACCC,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+CAAA,EAAgD,IAAA,EAAK,SAAA,EACjE,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,IAAA,EAAM,KAAA,qBACfA,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cAEC,IAAA,EAAK,QAAA;AAAA,cACL,IAAA,EAAK,KAAA;AAAA,cACL,iBAAe,KAAA,KAAU,WAAA;AAAA,cACzB,OAAA,EAAS,MAAM,aAAA,GAAgB,KAAK,CAAA;AAAA,cACpC,SAAA,EAAW,EAAA;AAAA,gBACT,sEAAA;AAAA,gBACA,KAAA,KAAU,cACN,0DAAA,GACA;AAAA,eACN;AAAA,cAEC,QAAA,EAAA;AAAA,aAAA;AAAA,YAZI;AAAA,WAcR,GACH,CAAA,GACE,IAAA;AAAA,0BAEJD,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4EAAA,EACZ,QAAA,EAAA;AAAA,YAAA,KAAA,CAAM,SAAA,mBACLA,IAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,6BAAA,EAA8B,QAAA,EAAA;AAAA,cAAA,QAAA;AAAA,cACrC,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,cAAA,EAAe;AAAA,cAAE,MAAA;AAAA,cAAK,KAAA,CAAM,UAAU,cAAA,EAAe;AAAA,cAAE;AAAA,aAAA,EAElF,CAAA,GACE,IAAA;AAAA,4BACJA,KAAC,MAAA,EAAA,EACE,QAAA,EAAA;AAAA,cAAA,MAAA,CAAO,KAAA,CAAM,WAAW,KAAK,CAAA;AAAA,cAAE,QAAA;AAAA,cAAI,MAAA,CAAO,KAAA,CAAM,OAAA,CAAQ,MAAA,EAAQ,QAAQ;AAAA,aAAA,EAC3E;AAAA,WAAA,EACF;AAAA,SAAA,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;AACA,WAAA,CAAY,WAAA,GAAc,aAAA;ACnInB,SAAS,aAAa,EAAE,IAAA,EAAM,GAAA,EAAK,QAAA,EAAU,OAAM,EAAsB;AAC9E,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIH,SAAS,CAAC,CAAA;AAKtC,EAAA,MAAM,WAAW,QAAA,CAAS;AAAA,IACxB,QAAA,EAAU,CAAC,mBAAA,EAAqB,GAAG,CAAA;AAAA,IACnC,OAAA,EAAS,MAAM,YAAA,CAAa,GAAA,EAAK,IAAI,CAAA;AAAA,IACrC,SAAA,EAAW;AAAA,GACZ,CAAA;AAED,EAAA,MAAM,QAAA;AAAA;AAAA;AAAA;AAAA,oBAIJG,IAAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAQ,SAAA;AAAA,QACR,IAAA,EAAK,IAAA;AAAA,QACL,YAAA,EAAc,KAAA;AAAA,QACd,wBAAQC,GAAAA,CAAC,OAAE,IAAA,EAAM,GAAA,EAAK,UAAU,QAAA,EAAU,CAAA;AAAA,QAE1C,QAAA,EAAA;AAAA,0BAAAA,GAAAA,CAAC,YAAA,EAAA,EAAa,aAAA,EAAY,MAAA,EAAO,CAAA;AAAA,UAAE;AAAA;AAAA;AAAA;AAErC,GAAA;AAGF,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,EAAM,MAAA,IAAU,EAAC;AACzC,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,CAAC,CAAC,CAAC,CAAA;AAErE,EAAA,uBACED,KAAC,SAAA,EAAA,EAGC,QAAA,EAAA;AAAA,oBAAAA,IAAAA,CAAC,eAAA,EAAA,EAAgB,SAAA,EAAU,MAAA,EACzB,QAAA,EAAA;AAAA,sBAAAA,KAAC,gBAAA,EAAA,EACC,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC,cAAA,EAAA,EAAgB,QAAA,EAAA,KAAA,IAAS,QAAA,EAAS,CAAA;AAAA,wBACnCA,GAAAA,CAAC,aAAA,EAAA,EAAe,QAAA,EAAA,QAAA,EAAS;AAAA,OAAA,EAC3B,CAAA;AAAA,sBACAA,GAAAA,CAAC,gBAAA,EAAA,EAAkB,QAAA,EAAA,QAAA,EAAS;AAAA,KAAA,EAC9B,CAAA;AAAA,oBAEAD,KAAC,gBAAA,EAAA,EACE,QAAA,EAAA;AAAA,MAAA,QAAA,CAAS,SAAA,mBAAYC,GAAAA,CAAC,OAAA,EAAA,EAAQ,OAAO,CAAA,QAAA,EAAW,QAAQ,UAAK,CAAA,GAAK,IAAA;AAAA,MAIlE,QAAA,CAAS,0BACRA,GAAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,qBAAqB,QAAQ,CAAA,CAAA;AAAA,UACpC,OAAA,EAAU,SAAS,KAAA,CAAgB,OAAA;AAAA,UACnC,MAAA,EAAQ;AAAA;AAAA,OACV,GACE,IAAA;AAAA,MAEH,wBACCA,GAAAA;AAAA,QAAC,WAAA;AAAA,QAAA;AAAA,UACC,KAAA;AAAA,UACA,YAAY,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,IAAI,CAAA;AAAA,UACpC,WAAA,EAAa,MAAA;AAAA,UACb,aAAA,EAAe;AAAA;AAAA,OACjB,GACE;AAAA,KAAA,EACN;AAAA,GAAA,EACF,CAAA;AAEJ;AACA,YAAA,CAAa,WAAA,GAAc,cAAA","file":"index.js","sourcesContent":["/**\n * Turning raw rows into a readable table: which row is the header, what each\n * column holds, and how a cell should read. Deliberately shallow — the goal is\n * \"legible as a spreadsheet\", not a reimplementation of one. Formulas, charts\n * and cell formatting are dropped; their values are what survive.\n */\nimport { FILE_PAGE_MAX_ROWS } from \"../core/constants\"\nimport type { CellFormat, TableColumn, TableSheet } from \"./types\"\n\n/** Rows sampled when deciding a column's format. */\nconst TYPE_SAMPLE_ROWS = 500\n\n/** Share of non-empty sampled values that must agree before a type is claimed. */\nconst TYPE_CONFIDENCE = 0.9\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined || value === \"\"\n}\n\n/**\n * `YYYY-MM-DD`, optionally with a time. XLSX hands back real `Date`s, but CSV\n * carries dates as text — recognising the ISO shape is what lets a date column\n * from a CSV align (and sort) like one. The string itself is left alone; only\n * the alignment follows from this.\n */\nconst ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}(?:[T ]\\d{2}:\\d{2}(?::\\d{2})?)?$/\n\nfunction classify(value: unknown): CellFormat {\n if (value instanceof Date) return \"date\"\n if (typeof value === \"number\" && Number.isFinite(value)) return \"number\"\n if (typeof value === \"string\" && ISO_DATE.test(value)) return \"date\"\n return \"text\"\n}\n\n/**\n * Header labels are kept exactly as the file wrote them — blank stays blank,\n * and two columns titled \"Amount\" stay two columns titled \"Amount\". The viewer\n * draws this row as the file's row 1, so anything invented here (`Column 3`,\n * `Amount (2)`) would be text the reader cannot find in their own file.\n * Uniqueness lives in `key`, which is positional.\n */\nfunction toColumns(header: unknown[], width: number, body: unknown[][]): TableColumn[] {\n const columns: TableColumn[] = []\n\n for (let index = 0; index < width; index++) {\n const raw = header[index]\n const label = isEmpty(raw) ? \"\" : String(raw).trim()\n\n let numbers = 0\n let dates = 0\n let filled = 0\n for (let row = 0; row < Math.min(body.length, TYPE_SAMPLE_ROWS); row++) {\n const cell = body[row]?.[index]\n if (isEmpty(cell)) continue\n filled++\n const kind = classify(cell)\n if (kind === \"number\") numbers++\n else if (kind === \"date\") dates++\n }\n let format: CellFormat = \"text\"\n if (filled > 0) {\n if (numbers / filled >= TYPE_CONFIDENCE) format = \"number\"\n else if (dates / filled >= TYPE_CONFIDENCE) format = \"date\"\n }\n\n // The key is positional rather than derived from the label: two columns\n // titled \"Amount\" must stay distinguishable, and a label can be any text.\n // Nothing in the viewer reads it — it is there for callers rendering their\n // own table from `toSheet`.\n columns.push({ key: `c${index}`, label, format })\n }\n return columns\n}\n\n/**\n * Build a sheet from raw rows. The first row is the header — the near-universal\n * spreadsheet convention, and guessing otherwise (scoring rows for\n * \"headerness\") misfires on data that happens to start with text.\n */\nexport function toSheet(name: string, rows: unknown[][]): TableSheet {\n if (rows.length === 0) {\n return { name, columns: [], rows: [], totalRows: 0, truncated: false }\n }\n const header = rows[0] ?? []\n const body = rows.slice(1)\n const width = rows.reduce((max, row) => Math.max(max, row.length), 0)\n const truncated = body.length > FILE_PAGE_MAX_ROWS\n const kept = truncated ? body.slice(0, FILE_PAGE_MAX_ROWS) : body\n return {\n name,\n columns: toColumns(header, width, kept),\n // Pad short rows so every row has a value at every column index; ragged\n // rows are common in hand-edited CSV and would otherwise read as holes.\n rows: kept.map((row) => Array.from({ length: width }, (_, i) => row[i] ?? null)),\n totalRows: body.length,\n truncated,\n }\n}\n\nconst numberFormat = new Intl.NumberFormat()\n\n/**\n * XLSX dates have no time zone: read-excel-file turns the serial number into\n * a `Date` whose UTC fields hold the wall-clock value the file shows\n * (2026-06-02 → 2026-06-02T00:00:00Z). Formatting in the browser's zone would\n * move it — a day early west of UTC, an evening time into the next day east\n * of it — so it is always read in UTC. The raw `Date` is left as is, so\n * comparing two of them still orders them as the file does.\n */\nconst WALL_CLOCK = { timeZone: \"UTC\" } as const\n\n/**\n * Cell text. The raw value stays in the row so sorting compares numbers as\n * numbers and dates as dates; only the display passes through here.\n */\nexport function formatCell(value: unknown, format: CellFormat): string {\n if (isEmpty(value)) return \"\"\n // A date that arrived as text is shown exactly as the file wrote it: the\n // point of the viewer is to read the file, not to restate it.\n if (format === \"date\" && typeof value === \"string\") return value\n if (format === \"date\" && value instanceof Date) return value.toLocaleDateString(undefined, WALL_CLOCK)\n if (format === \"number\" && typeof value === \"number\") return numberFormat.format(value)\n if (value instanceof Date) return value.toLocaleString(undefined, WALL_CLOCK)\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\"\n return String(value)\n}\n","/**\n * Reading a data file in the browser. Both parsers are loaded through\n * `await import()` so an app without a data-file page never ships them, and an\n * app with one only pays when such a page is opened.\n *\n * Parsing happens on the client rather than at generate time because Vantage\n * has an SPA mode (no `server/`), so there is no server to parse on — and\n * because it makes dev, `build` and `preview` run the same code over the same\n * bytes, which is what \"the same URL returns the same thing\" rests on.\n */\nimport { FILE_PAGE_MAX_BYTES } from \"../core/constants\"\nimport { toSheet } from \"./infer\"\nimport type { Workbook } from \"./types\"\n\n/** Thrown for every failure a file page can show; the page renders the message. */\nexport class FilePageError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"FilePageError\"\n }\n}\n\nfunction megabytes(bytes: number): string {\n return `${(bytes / 1024 / 1024).toFixed(1)} MB`\n}\n\n/**\n * Decode CSV bytes. A Japanese spreadsheet exported from Excel is usually\n * CP932, not UTF-8, and decoding it as UTF-8 turns every non-ASCII character\n * into U+FFFD. Rather than ask the user to declare an encoding, decode as\n * UTF-8 and fall back when the result is visibly full of replacement\n * characters — a real UTF-8 file has none.\n */\nfunction decodeCsv(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n const hasBom = bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf\n const body = hasBom ? bytes.subarray(3) : bytes\n const utf8 = new TextDecoder(\"utf-8\").decode(body)\n const replacements = (utf8.match(/�/g) ?? []).length\n if (replacements > 0 && replacements / Math.max(utf8.length, 1) > 0.0005) {\n try {\n return new TextDecoder(\"shift-jis\").decode(body)\n } catch {\n // Some engines ship without the legacy decoder; the UTF-8 read is still\n // the best available answer.\n }\n }\n return utf8\n}\n\nasync function parseCsv(buffer: ArrayBuffer): Promise<Workbook> {\n const { default: Papa } = await import(\"papaparse\")\n const text = decodeCsv(buffer)\n // `header: false` on purpose: lifting the header row is done in `infer.ts`,\n // which puts CSV and XLSX on one code path instead of two.\n const result = Papa.parse<unknown[]>(text, {\n header: false,\n dynamicTyping: true,\n skipEmptyLines: \"greedy\",\n })\n return { sheets: [toSheet(\"Sheet1\", result.data)] }\n}\n\nasync function parseXlsx(buffer: ArrayBuffer): Promise<Workbook> {\n // The browser build specifically: the package has no root export, and the\n // node build reaches for `fs`.\n const { default: readXlsxFile } = await import(\"read-excel-file/browser\")\n const sheets = await readXlsxFile(buffer)\n return {\n sheets: sheets.map((sheet) => toSheet(sheet.sheet, sheet.data as unknown[][])),\n }\n}\n\n/**\n * Fetch and parse the file behind a file page. Every failure — network, size,\n * a corrupt workbook, an extension with no parser — surfaces as a rejected\n * promise so the page can render it in place instead of taking the app down.\n */\nexport async function loadWorkbook(src: string, kind: string): Promise<Workbook> {\n let buffer: ArrayBuffer\n try {\n const response = await fetch(src)\n if (!response.ok) {\n throw new FilePageError(`Could not load the file (HTTP ${response.status}).`)\n }\n buffer = await response.arrayBuffer()\n } catch (err) {\n if (err instanceof FilePageError) throw err\n throw new FilePageError(`Could not load the file: ${(err as Error).message}`)\n }\n\n if (buffer.byteLength > FILE_PAGE_MAX_BYTES) {\n throw new FilePageError(\n `This file is ${megabytes(buffer.byteLength)}, over the ${megabytes(\n FILE_PAGE_MAX_BYTES,\n )} limit for a data-file page. Download it, or serve the data from server/api/ and render it with DataTable.`,\n )\n }\n\n try {\n switch (kind) {\n case \"csv\":\n return await parseCsv(buffer)\n case \"xlsx\":\n return await parseXlsx(buffer)\n default:\n // Reached when an extension is added to FILE_PAGE_EXTENSIONS without a\n // parser here. Naming it beats rendering an empty table.\n throw new FilePageError(`No viewer for \".${kind}\" files.`)\n }\n } catch (err) {\n if (err instanceof FilePageError) throw err\n throw new FilePageError(\n `This file could not be read. It may be corrupt, password-protected, or not really a .${kind} file. (${\n (err as Error).message\n })`,\n )\n }\n}\n","/**\n * The spreadsheet grid. A data file page should read the way the file reads in\n * Excel or Sheets — column letters across the top, row numbers down the side,\n * a ruled canvas of fixed-height rows that runs past the data, and a selected\n * cell. That is why this is a grid and not a styled `DataTable`: the card, the\n * pagination and the sort affordances all say \"web table\", and none of them\n * exist in a spreadsheet.\n *\n * It is a viewer, not an editor. No toolbar, no formula bar, no editing; the\n * only interactions are moving the selection and copying a cell.\n *\n * Rows and columns are windowed. That is not an optimisation to revisit later:\n * a file page is capped at 200,000 rows, and mounting them would be hundreds of\n * thousands of DOM nodes. Fixed row height makes the window arithmetic exact,\n * so no virtualiser dependency is needed — `first = scrollTop / ROW_HEIGHT`.\n */\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n} from \"react\"\n\nimport { cn } from \"../ui/cn\"\nimport { formatCell } from \"./infer\"\nimport type { CellFormat, TableSheet } from \"./types\"\n\n/** Row height, matching a spreadsheet's default line rather than a web table's. */\nconst ROW_HEIGHT = 22\n/** Height of the A / B / C band. */\nconst HEAD_HEIGHT = 22\nconst MIN_GUTTER_WIDTH = 44\nconst MIN_COL_WIDTH = 56\nconst MAX_COL_WIDTH = 420\n/** Width of the empty columns that carry the ruling past the data. */\nconst FILLER_COL_WIDTH = 100\n/** Horizontal padding plus borders, added to the measured text width. */\nconst COL_PADDING = 18\nconst OVERSCAN_ROWS = 8\nconst OVERSCAN_COLS = 2\n/** Rows sampled when sizing a column. */\nconst WIDTH_SAMPLE_ROWS = 200\n/** Must match the cell font below, or measured widths will not fit the text. */\nconst CELL_FONT =\n '13px ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, \"Hiragino Sans\", \"Hiragino Kaku Gothic ProN\", \"Noto Sans JP\", \"Yu Gothic UI\", Meiryo, sans-serif'\n\n/** `0 → A`, `25 → Z`, `26 → AA` — spreadsheet column names. */\nexport function columnLabel(index: number): string {\n let label = \"\"\n for (let n = index; n >= 0; n = Math.floor(n / 26) - 1) {\n label = String.fromCharCode(65 + (n % 26)) + label\n }\n return label\n}\n\n/**\n * Size each column to its content, the way a spreadsheet does on import.\n * Measured with the canvas text metrics of the font the cells use, over a\n * sample spread across the whole sheet — sampling the first N rows only would\n * size a column on its header and miss the long values further down.\n */\nfunction measureWidths(sheet: TableSheet): number[] {\n const context =\n typeof document === \"undefined\" ? null : document.createElement(\"canvas\").getContext(\"2d\")\n if (context) context.font = CELL_FONT\n // Without a canvas (SSR, or a browser that refuses the context) fall back to\n // an average character width: the grid still lays out, just less snugly.\n const widthOf = (text: string) => (context ? context.measureText(text).width : text.length * 7.2)\n const stride = Math.max(1, Math.ceil(sheet.rows.length / WIDTH_SAMPLE_ROWS))\n\n return sheet.columns.map((column, index) => {\n let max = widthOf(column.label)\n for (let row = 0; row < sheet.rows.length; row += stride) {\n const text = formatCell(sheet.rows[row]?.[index], column.format)\n if (text !== \"\") max = Math.max(max, widthOf(text))\n }\n return Math.min(MAX_COL_WIDTH, Math.max(MIN_COL_WIDTH, Math.ceil(max) + COL_PADDING))\n })\n}\n\n/** Running x of each column, so windowing and scrolling are lookups. */\nfunction runningOffsets(widths: number[]): number[] {\n const offsets = [0]\n for (const width of widths) offsets.push(offsets[offsets.length - 1]! + width)\n return offsets\n}\n\n/** Index of the last offset at or before `x`. */\nfunction columnAt(offsets: number[], x: number): number {\n let low = 0\n let high = offsets.length - 2\n while (low < high) {\n const mid = (low + high + 1) >> 1\n if (offsets[mid]! <= x) low = mid\n else high = mid - 1\n }\n return Math.max(0, low)\n}\n\ninterface Selection {\n /** `0` is the header row (the file's row 1); `n` is body row `n - 1`. */\n row: number\n col: number\n}\n\nexport interface SheetGridProps {\n sheet: TableSheet\n className?: string\n}\n\n/**\n * One sheet as a grid. Fills its container, so give the parent a height —\n * `TableViewer` is the component that does that for a page.\n */\nexport function SheetGrid({ sheet, className }: SheetGridProps) {\n const scrollRef = useRef<HTMLDivElement>(null)\n const [scroll, setScroll] = useState({ top: 0, left: 0 })\n const [viewport, setViewport] = useState({ width: 0, height: 0 })\n const [selected, setSelected] = useState<Selection>({ row: 0, col: 0 })\n\n const dataWidths = useMemo(() => measureWidths(sheet), [sheet])\n const dataCols = sheet.columns.length\n const dataRows = sheet.rows.length\n\n // Wide enough for the largest row number: the gutter must not resize as the\n // window scrolls into five-digit rows.\n const gutterWidth = Math.max(MIN_GUTTER_WIDTH, String(dataRows + 1).length * 8 + 16)\n\n // Past the data the canvas keeps going, ruled and empty, as it does in every\n // spreadsheet. Enough of it to cover the viewport — beyond that nobody can\n // tell whether the sheet ends at column F or column XFD.\n const dataWidth = dataWidths.reduce((sum, width) => sum + width, 0)\n const fillerCols = Math.max(\n 0,\n Math.ceil((viewport.width - gutterWidth - dataWidth) / FILLER_COL_WIDTH),\n )\n const fillerRows = Math.max(\n 0,\n Math.ceil((viewport.height - HEAD_HEIGHT - (dataRows + 1) * ROW_HEIGHT) / ROW_HEIGHT),\n )\n const colCount = dataCols + fillerCols\n const rowCount = dataRows + fillerRows\n\n const widths = useMemo(\n () => [...dataWidths, ...Array.from({ length: fillerCols }, () => FILLER_COL_WIDTH)],\n [dataWidths, fillerCols],\n )\n const offsets = useMemo(() => runningOffsets(widths), [widths])\n const totalWidth = offsets[offsets.length - 1] ?? 0\n\n useLayoutEffect(() => {\n const element = scrollRef.current\n if (!element) return\n const measure = () => setViewport({ width: element.clientWidth, height: element.clientHeight })\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(element)\n return () => observer.disconnect()\n }, [])\n\n // Selection is positional, so a new sheet must not keep pointing at a cell\n // that no longer exists.\n useEffect(() => {\n setSelected({ row: 0, col: 0 })\n scrollRef.current?.scrollTo({ top: 0, left: 0 })\n }, [sheet])\n\n // Body rows live below the two frozen bands, so the first visible one falls\n // straight out of scrollTop.\n const firstRow = Math.max(0, Math.floor(scroll.top / ROW_HEIGHT) - OVERSCAN_ROWS)\n const lastRow = Math.min(\n rowCount,\n Math.ceil((scroll.top + viewport.height - HEAD_HEIGHT - ROW_HEIGHT) / ROW_HEIGHT) +\n OVERSCAN_ROWS,\n )\n const firstCol = Math.max(0, columnAt(offsets, scroll.left) - OVERSCAN_COLS)\n const lastCol = Math.min(\n colCount,\n columnAt(offsets, scroll.left + viewport.width) + 1 + OVERSCAN_COLS,\n )\n const leadWidth = offsets[firstCol] ?? 0\n const tailWidth = totalWidth - (offsets[lastCol] ?? totalWidth)\n const visibleCols = Array.from({ length: Math.max(0, lastCol - firstCol) }, (_, i) => firstCol + i)\n\n /** Bring a cell inside the scrollport, allowing for the frozen bands. */\n const reveal = useCallback(\n (next: Selection) => {\n const element = scrollRef.current\n if (!element) return\n if (next.row > 0) {\n const top = HEAD_HEIGHT + ROW_HEIGHT + (next.row - 1) * ROW_HEIGHT\n const frozen = HEAD_HEIGHT + ROW_HEIGHT\n if (top - element.scrollTop < frozen) element.scrollTop = top - frozen\n else if (top + ROW_HEIGHT - element.scrollTop > element.clientHeight) {\n element.scrollTop = top + ROW_HEIGHT - element.clientHeight\n }\n }\n const left = offsets[next.col] ?? 0\n const width = widths[next.col] ?? 0\n if (left - element.scrollLeft < 0) element.scrollLeft = left\n else if (left + width + gutterWidth - element.scrollLeft > element.clientWidth) {\n element.scrollLeft = left + width + gutterWidth - element.clientWidth\n }\n },\n [gutterWidth, offsets, widths],\n )\n\n const cellText = useCallback(\n (row: number, col: number): string => {\n const column = sheet.columns[col]\n if (!column) return \"\"\n if (row === 0) return column.label\n return formatCell(sheet.rows[row - 1]?.[col], column.format)\n },\n [sheet],\n )\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n // The selection stays on the data. The empty canvas past it is ruling,\n // not cells anyone needs to land on.\n //\n // `escapable` is what keeps this from being a keyboard trap: the grid is\n // focusable, so if Tab were always swallowed there would be no way out of\n // it. Tab that cannot move the selection any further is left to the\n // browser, which moves focus on to the sheet tabs.\n const step = (rows: number, cols: number, escapable = false) => {\n const next = {\n row: Math.min(dataRows, Math.max(0, selected.row + rows)),\n col: Math.min(dataCols - 1, Math.max(0, selected.col + cols)),\n }\n const moved = next.row !== selected.row || next.col !== selected.col\n if (moved || !escapable) event.preventDefault()\n if (!moved) return\n setSelected(next)\n reveal(next)\n }\n const page = Math.max(1, Math.floor(viewport.height / ROW_HEIGHT) - 1)\n\n switch (event.key) {\n case \"ArrowDown\":\n return step(1, 0)\n case \"ArrowUp\":\n return step(-1, 0)\n case \"Tab\":\n return step(0, event.shiftKey ? -1 : 1, true)\n case \"ArrowRight\":\n return step(0, 1)\n case \"ArrowLeft\":\n return step(0, -1)\n case \"PageDown\":\n return step(page, 0)\n case \"PageUp\":\n return step(-page, 0)\n case \"Home\":\n return step(event.ctrlKey || event.metaKey ? -dataRows : 0, -dataCols)\n case \"End\":\n return step(event.ctrlKey || event.metaKey ? dataRows : 0, dataCols)\n case \"c\":\n case \"C\":\n // The one thing a reader wants out of a viewer: the value, in full,\n // even when the column is too narrow to show it.\n if (event.metaKey || event.ctrlKey) {\n // A refused or unavailable clipboard is not worth an unhandled\n // rejection in the app's error reporting.\n navigator.clipboard?.writeText(cellText(selected.row, selected.col)).catch(() => {})\n }\n return\n default:\n return\n }\n },\n [cellText, dataCols, dataRows, reveal, selected, viewport.height],\n )\n\n if (dataCols === 0) {\n return <p className={cn(\"p-4 text-sm text-muted-foreground\", className)}>This sheet is empty.</p>\n }\n\n const select = (row: number, col: number) => {\n setSelected({ row, col })\n scrollRef.current?.focus({ preventScroll: true })\n }\n\n const rowStyle: CSSProperties = { height: ROW_HEIGHT, width: gutterWidth + totalWidth }\n\n return (\n <div\n ref={scrollRef}\n role=\"grid\"\n aria-label={sheet.name}\n aria-rowcount={dataRows + 1}\n aria-colcount={dataCols}\n tabIndex={0}\n onScroll={(event) =>\n setScroll({ top: event.currentTarget.scrollTop, left: event.currentTarget.scrollLeft })\n }\n onKeyDown={onKeyDown}\n className={cn(\n \"relative h-full overflow-auto bg-background text-[13px] outline-none select-none [overscroll-behavior:contain]\",\n className,\n )}\n >\n <div role=\"rowgroup\" style={{ width: gutterWidth + totalWidth }}>\n {/* A / B / C. Sticky on both axes, so the corner stays put. */}\n <div\n className=\"sticky top-0 z-40 flex\"\n style={{ ...rowStyle, height: HEAD_HEIGHT }}\n role=\"row\"\n >\n <div\n className=\"sticky left-0 z-10 shrink-0 border-r border-b border-border bg-muted\"\n style={{ width: gutterWidth, height: HEAD_HEIGHT }}\n />\n <div className=\"shrink-0 border-b border-border bg-muted\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => (\n <div\n key={col}\n role={col < dataCols ? \"columnheader\" : \"presentation\"}\n aria-colindex={col < dataCols ? col + 1 : undefined}\n onMouseDown={col < dataCols ? () => select(selected.row, col) : undefined}\n className={cn(\n \"flex shrink-0 items-center justify-center border-r border-b border-border bg-muted text-[11px] text-muted-foreground\",\n selected.col === col && col < dataCols && \"bg-accent font-medium text-foreground\",\n )}\n style={{ width: widths[col], height: HEAD_HEIGHT }}\n >\n {columnLabel(col)}\n </div>\n ))}\n <div className=\"shrink-0 border-b border-border bg-muted\" style={{ width: tailWidth }} />\n </div>\n\n {/* The file's row 1. Frozen under the letters, because a data file's\n first row is its header and reading row 40,000 without it is\n guesswork — the first thing anyone does to a sheet by hand. */}\n {/* Opaque: body rows scroll underneath this one. */}\n <div\n className=\"sticky z-30 flex bg-background\"\n style={{ ...rowStyle, top: HEAD_HEIGHT }}\n role=\"row\"\n >\n <RowHeader\n label=\"1\"\n width={gutterWidth}\n active={selected.row === 0}\n onSelect={() => select(0, selected.col)}\n />\n <div className=\"shrink-0 border-b border-foreground/25\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => (\n <Cell\n key={col}\n width={widths[col]!}\n // A header label is text, and a spreadsheet aligns a cell by what\n // is in it — so it reads left even over a column of numbers.\n format=\"text\"\n text={sheet.columns[col]?.label ?? \"\"}\n header\n selected={selected.row === 0 && selected.col === col}\n onSelect={col < dataCols ? () => select(0, col) : undefined}\n colIndex={col < dataCols ? col : undefined}\n />\n ))}\n <div className=\"shrink-0 border-b border-foreground/25\" style={{ width: tailWidth }} />\n </div>\n\n {/* `presentation` so the rows below stay owned by the rowgroup above. */}\n <div role=\"presentation\" className=\"relative\" style={{ height: rowCount * ROW_HEIGHT }}>\n {Array.from({ length: Math.max(0, lastRow - firstRow) }, (_, offset) => {\n const row = firstRow + offset\n const cells = sheet.rows[row]\n return (\n <div\n key={row}\n role=\"row\"\n aria-rowindex={row < dataRows ? row + 2 : undefined}\n className=\"absolute flex\"\n style={{ ...rowStyle, top: row * ROW_HEIGHT }}\n >\n <RowHeader\n label={String(row + 2)}\n width={gutterWidth}\n active={selected.row === row + 1}\n onSelect={row < dataRows ? () => select(row + 1, selected.col) : undefined}\n />\n <div className=\"shrink-0\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => {\n const column = sheet.columns[col]\n return (\n <Cell\n key={col}\n width={widths[col]!}\n format={column?.format ?? \"text\"}\n text={column ? formatCell(cells?.[col], column.format) : \"\"}\n selected={selected.row === row + 1 && selected.col === col}\n onSelect={\n row < dataRows && col < dataCols ? () => select(row + 1, col) : undefined\n }\n colIndex={col < dataCols ? col : undefined}\n />\n )\n })}\n <div className=\"shrink-0\" style={{ width: tailWidth }} />\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\nSheetGrid.displayName = \"SheetGrid\"\n\nfunction RowHeader({\n label,\n width,\n active,\n onSelect,\n}: {\n label: string\n width: number\n active: boolean\n onSelect?: () => void\n}) {\n return (\n <div\n role={onSelect ? \"rowheader\" : \"presentation\"}\n onMouseDown={onSelect}\n className={cn(\n // Above a selected cell (`z-10`): scrolling a selected column under the\n // gutter must not paint its outline over the row number.\n \"sticky left-0 z-20 flex h-full shrink-0 items-center justify-center border-r border-b border-border bg-muted text-[11px] text-muted-foreground\",\n active && \"bg-accent font-medium text-foreground\",\n )}\n style={{ width }}\n >\n {label}\n </div>\n )\n}\n\nfunction Cell({\n width,\n format,\n text,\n header,\n selected,\n onSelect,\n colIndex,\n}: {\n width: number\n format: CellFormat\n text: string\n header?: boolean\n selected: boolean\n onSelect?: () => void\n colIndex?: number\n}) {\n return (\n <div\n role={onSelect ? \"gridcell\" : \"presentation\"}\n aria-colindex={colIndex === undefined ? undefined : colIndex + 1}\n aria-selected={onSelect ? selected : undefined}\n onMouseDown={onSelect}\n // Columns are sized to their content but capped, so a long value still\n // gets clipped — the title is how the rest of it stays reachable\n // without a formula bar.\n title={text || undefined}\n className={cn(\n \"flex h-full shrink-0 items-center border-r border-b border-border px-1.5\",\n header && \"border-b-foreground/25 font-medium\",\n // Numbers and dates read right-aligned, as they do in a spreadsheet.\n format === \"text\" ? \"justify-start\" : \"justify-end tabular-nums\",\n selected && onSelect && \"relative z-10 outline-2 -outline-offset-2 outline-primary\",\n )}\n style={{ width }}\n >\n <span className=\"truncate\">{text}</span>\n </div>\n )\n}\n","/**\n * One sheet, framed the way a spreadsheet application frames one: the grid\n * fills the window, and a status bar sits under it with the sheet tabs on the\n * left and the shape of the sheet on the right.\n *\n * The frame is what makes the grid usable — a grid needs a definite height to\n * scroll inside, and a Vantage page has no guaranteed one (layouts belong to\n * the app). So it measures the space left below itself in the viewport rather\n * than asking the app to arrange for a height.\n */\nimport { useLayoutEffect, useRef, useState, type RefObject } from \"react\"\n\nimport { cn } from \"../ui/cn\"\nimport { SheetGrid } from \"./sheet-grid\"\nimport type { TableSheet } from \"./types\"\n\n/** Never collapse below this, however little viewport is left. */\nconst MIN_HEIGHT = 320\n/** Breathing room under the frame when the layout leaves none of its own. */\nconst MIN_BOTTOM_GAP = 8\n\nexport interface TableViewerProps {\n /** The sheet to render. */\n sheet: TableSheet\n /** Every sheet's name. Given more than one, a tab strip is rendered. */\n sheetNames?: string[]\n activeSheet?: number\n onSheetChange?: (index: number) => void\n /**\n * Fixed height for the frame. Without it the viewer fills the rest of the\n * viewport, which is right for a file page and wrong for a table embedded in\n * a dashboard among other cards.\n */\n height?: number | string\n className?: string\n}\n\n/**\n * What the layout keeps under the frame: every ancestor's bottom padding,\n * border and margin. It has to come out of the height, or the page ends up\n * scrollable by exactly that much (a page shell nested in a layout shell means\n * two lots of padding). Read from the box model rather than from the document\n * height, which a `min-h-screen` layout pins to the viewport and would make\n * this feed back on its own result.\n */\nfunction spaceBelow(element: HTMLElement): number {\n let total = 0\n for (let node = element.parentElement; node && node !== document.body; node = node.parentElement) {\n const style = getComputedStyle(node)\n total +=\n parseFloat(style.paddingBottom) + parseFloat(style.borderBottomWidth) + parseFloat(style.marginBottom)\n }\n return Number.isFinite(total) ? total : 0\n}\n\n/**\n * Fill the rest of the viewport. Measured rather than expressed in CSS: the\n * frame's distance from the top of the window depends on whatever the app's\n * layout put above it, which no `calc()` here can know.\n */\nfunction useFillHeight(ref: RefObject<HTMLElement | null>, enabled: boolean): number {\n const [height, setHeight] = useState(MIN_HEIGHT)\n\n useLayoutEffect(() => {\n const element = ref.current\n if (!element || !enabled) return\n const measure = () => {\n // Document-relative, not viewport-relative: `rect.top` alone shrinks as\n // the page scrolls, so a measurement taken while scrolled (a mobile URL\n // bar collapsing fires `resize`) would make the frame taller than the\n // viewport and add page scroll that never goes away.\n const rect = element.getBoundingClientRect()\n const top = rect.top + window.scrollY\n const next = Math.max(\n MIN_HEIGHT,\n window.innerHeight - top - Math.max(spaceBelow(element), MIN_BOTTOM_GAP),\n )\n // Only a real change: the frame's own height feeds back into the\n // document height, and rounding noise would loop.\n setHeight((current) => (Math.abs(current - next) > 1 ? next : current))\n }\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(document.body)\n window.addEventListener(\"resize\", measure)\n return () => {\n observer.disconnect()\n window.removeEventListener(\"resize\", measure)\n }\n }, [enabled, ref])\n\n return height\n}\n\nfunction plural(count: number, noun: string): string {\n return `${count.toLocaleString()} ${noun}${count === 1 ? \"\" : \"s\"}`\n}\n\n/** Render one parsed sheet. Exported so an app can drive it with its own data. */\nexport function TableViewer({\n sheet,\n sheetNames,\n activeSheet = 0,\n onSheetChange,\n height,\n className,\n}: TableViewerProps) {\n const frameRef = useRef<HTMLDivElement>(null)\n const filled = useFillHeight(frameRef, height === undefined)\n const tabs = sheetNames && sheetNames.length > 1 ? sheetNames : null\n\n return (\n <div\n ref={frameRef}\n className={cn(\n \"flex flex-col overflow-hidden rounded-md border border-border bg-background\",\n className,\n )}\n style={{ height: height ?? filled }}\n >\n <div className=\"min-h-0 flex-1\">\n <SheetGrid sheet={sheet} />\n </div>\n\n {/* The status bar: sheet tabs and the shape of the sheet, where a\n spreadsheet puts them. */}\n <div className=\"flex items-center gap-4 border-t border-border bg-muted/60 px-2 py-1\">\n {tabs ? (\n <div className=\"flex min-w-0 items-end gap-px overflow-x-auto\" role=\"tablist\">\n {tabs.map((name, index) => (\n <button\n key={name}\n type=\"button\"\n role=\"tab\"\n aria-selected={index === activeSheet}\n onClick={() => onSheetChange?.(index)}\n className={cn(\n \"shrink-0 rounded-t-sm border-t-2 px-3 py-1 text-xs whitespace-nowrap\",\n index === activeSheet\n ? \"border-primary bg-background font-medium text-foreground\"\n : \"border-transparent text-muted-foreground hover:text-foreground\",\n )}\n >\n {name}\n </button>\n ))}\n </div>\n ) : null}\n\n <div className=\"ml-auto flex shrink-0 items-center gap-3 text-[11px] text-muted-foreground\">\n {sheet.truncated ? (\n <span className=\"font-medium text-foreground\">\n First {sheet.rows.length.toLocaleString()} of {sheet.totalRows.toLocaleString()} rows —\n download the file for the rest\n </span>\n ) : null}\n <span>\n {plural(sheet.totalRows, \"row\")} × {plural(sheet.columns.length, \"column\")}\n </span>\n </div>\n </div>\n </div>\n )\n}\nTableViewer.displayName = \"TableViewer\"\n","/**\n * The page a `.csv` or `.xlsx` under `src/` becomes. Generated wrappers in\n * `.vantage/file-pages/` mount this; apps can mount it themselves to take over\n * the title or to render a file kept out of routing with an `_` prefix.\n */\nimport { useState } from \"react\"\nimport { DownloadIcon } from \"lucide-react\"\nimport {\n PageShell,\n PageShellActions,\n PageShellContent,\n PageShellHeader,\n PageShellHeading,\n PageShellMeta,\n PageShellTitle,\n} from \"../components\"\nimport { useQuery } from \"../query\"\nimport { Button } from \"../ui/button\"\nimport { Loading, ErrorState } from \"../ui/states\"\nimport { loadWorkbook } from \"./parse\"\nimport { TableViewer } from \"./table-viewer\"\n\nexport interface FilePageViewProps {\n /** Extension without the dot, e.g. `\"xlsx\"`. */\n kind: string\n /** URL of the file, produced by Vite's asset pipeline. */\n src: string\n /** Original file name, used for the heading fallback and the download. */\n fileName: string\n /** Title derived from the file name at generate time. */\n title?: string\n}\n\nexport function FilePageView({ kind, src, fileName, title }: FilePageViewProps) {\n const [active, setActive] = useState(0)\n\n // The framework's QueryClient is already above this in the tree, so the\n // parsed workbook is cached across navigations for free and the retry and\n // networkMode policies are the managed ones — no second provider.\n const workbook = useQuery({\n queryKey: [\"vantage:file-page\", src],\n queryFn: () => loadWorkbook(src, kind),\n staleTime: Infinity,\n })\n\n const download = (\n // `nativeButton={false}` because this renders an `<a>`: Base UI needs to\n // know it is not driving a real button, or it warns and keeps button\n // semantics that would fight the link's.\n <Button\n variant=\"outline\"\n size=\"sm\"\n nativeButton={false}\n render={<a href={src} download={fileName} />}\n >\n <DownloadIcon aria-hidden=\"true\" />\n Download\n </Button>\n )\n\n const sheets = workbook.data?.sheets ?? []\n const sheet = sheets[Math.min(active, Math.max(sheets.length - 1, 0))]\n\n return (\n <PageShell>\n {/* A slim band: the grid below wants the vertical room, and a data file\n has no description to carry. */}\n <PageShellHeader className=\"py-6\">\n <PageShellHeading>\n <PageShellTitle>{title ?? fileName}</PageShellTitle>\n <PageShellMeta>{fileName}</PageShellMeta>\n </PageShellHeading>\n <PageShellActions>{download}</PageShellActions>\n </PageShellHeader>\n\n <PageShellContent>\n {workbook.isPending ? <Loading label={`Reading ${fileName}…`} /> : null}\n\n {/* Every failure path lands here, inside the page. A data file the\n browser cannot read must not take the rest of the app down. */}\n {workbook.isError ? (\n <ErrorState\n title={`Could not display ${fileName}`}\n message={(workbook.error as Error).message}\n action={download}\n />\n ) : null}\n\n {sheet ? (\n <TableViewer\n sheet={sheet}\n sheetNames={sheets.map((s) => s.name)}\n activeSheet={active}\n onSheetChange={setActive}\n />\n ) : null}\n </PageShellContent>\n </PageShell>\n )\n}\nFilePageView.displayName = \"FilePageView\"\n"]}
1
+ {"version":3,"sources":["../../src/table/infer.ts","../../src/table/parse.ts","../../src/table/sheet-grid.tsx","../../src/table/table-viewer.tsx","../../src/table/file-page-view.tsx"],"names":["useState","useLayoutEffect","useRef","jsxs","jsx"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Turning raw rows into a readable table: which row is the header, what each\n * column holds, and how a cell should read. Deliberately shallow — the goal is\n * \"legible as a spreadsheet\", not a reimplementation of one. Formulas, charts\n * and cell formatting are dropped; their values are what survive.\n */\nimport { FILE_PAGE_MAX_ROWS } from \"../core/constants\"\nimport type { CellFormat, TableColumn, TableSheet } from \"./types\"\n\n/** Rows sampled when deciding a column's format. */\nconst TYPE_SAMPLE_ROWS = 500\n\n/** Share of non-empty sampled values that must agree before a type is claimed. */\nconst TYPE_CONFIDENCE = 0.9\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined || value === \"\"\n}\n\n/**\n * `YYYY-MM-DD`, optionally with a time. XLSX hands back real `Date`s, but CSV\n * carries dates as text — recognising the ISO shape is what lets a date column\n * from a CSV align (and sort) like one. The string itself is left alone; only\n * the alignment follows from this.\n */\nconst ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}(?:[T ]\\d{2}:\\d{2}(?::\\d{2})?)?$/\n\nfunction classify(value: unknown): CellFormat {\n if (value instanceof Date) return \"date\"\n if (typeof value === \"number\" && Number.isFinite(value)) return \"number\"\n if (typeof value === \"string\" && ISO_DATE.test(value)) return \"date\"\n return \"text\"\n}\n\n/**\n * Header labels are kept exactly as the file wrote them — blank stays blank,\n * and two columns titled \"Amount\" stay two columns titled \"Amount\". The viewer\n * draws this row as the file's row 1, so anything invented here (`Column 3`,\n * `Amount (2)`) would be text the reader cannot find in their own file.\n * Uniqueness lives in `key`, which is positional.\n */\nfunction toColumns(header: unknown[], width: number, body: unknown[][]): TableColumn[] {\n const columns: TableColumn[] = []\n\n for (let index = 0; index < width; index++) {\n const raw = header[index]\n const label = isEmpty(raw) ? \"\" : String(raw).trim()\n\n let numbers = 0\n let dates = 0\n let filled = 0\n for (let row = 0; row < Math.min(body.length, TYPE_SAMPLE_ROWS); row++) {\n const cell = body[row]?.[index]\n if (isEmpty(cell)) continue\n filled++\n const kind = classify(cell)\n if (kind === \"number\") numbers++\n else if (kind === \"date\") dates++\n }\n let format: CellFormat = \"text\"\n if (filled > 0) {\n if (numbers / filled >= TYPE_CONFIDENCE) format = \"number\"\n else if (dates / filled >= TYPE_CONFIDENCE) format = \"date\"\n }\n\n // The key is positional rather than derived from the label: two columns\n // titled \"Amount\" must stay distinguishable, and a label can be any text.\n // Nothing in the viewer reads it — it is there for callers rendering their\n // own table from `toSheet`.\n columns.push({ key: `c${index}`, label, format })\n }\n return columns\n}\n\n/**\n * Build a sheet from raw rows. The first row is the header — the near-universal\n * spreadsheet convention, and guessing otherwise (scoring rows for\n * \"headerness\") misfires on data that happens to start with text.\n */\nexport function toSheet(name: string, rows: unknown[][]): TableSheet {\n if (rows.length === 0) {\n return { name, columns: [], rows: [], totalRows: 0, truncated: false }\n }\n const header = rows[0] ?? []\n const body = rows.slice(1)\n const width = rows.reduce((max, row) => Math.max(max, row.length), 0)\n const truncated = body.length > FILE_PAGE_MAX_ROWS\n const kept = truncated ? body.slice(0, FILE_PAGE_MAX_ROWS) : body\n return {\n name,\n columns: toColumns(header, width, kept),\n // Pad short rows so every row has a value at every column index; ragged\n // rows are common in hand-edited CSV and would otherwise read as holes.\n rows: kept.map((row) => Array.from({ length: width }, (_, i) => row[i] ?? null)),\n totalRows: body.length,\n truncated,\n }\n}\n\nconst numberFormat = new Intl.NumberFormat()\n\n/**\n * XLSX dates have no time zone: read-excel-file turns the serial number into\n * a `Date` whose UTC fields hold the wall-clock value the file shows\n * (2026-06-02 → 2026-06-02T00:00:00Z). Formatting in the browser's zone would\n * move it — a day early west of UTC, an evening time into the next day east\n * of it — so it is always read in UTC. The raw `Date` is left as is, so\n * comparing two of them still orders them as the file does.\n */\nconst WALL_CLOCK = { timeZone: \"UTC\" } as const\n\n/**\n * Cell text. The raw value stays in the row so sorting compares numbers as\n * numbers and dates as dates; only the display passes through here.\n */\nexport function formatCell(value: unknown, format: CellFormat): string {\n if (isEmpty(value)) return \"\"\n // A date that arrived as text is shown exactly as the file wrote it: the\n // point of the viewer is to read the file, not to restate it.\n if (format === \"date\" && typeof value === \"string\") return value\n if (format === \"date\" && value instanceof Date) return value.toLocaleDateString(undefined, WALL_CLOCK)\n if (format === \"number\" && typeof value === \"number\") return numberFormat.format(value)\n if (value instanceof Date) return value.toLocaleString(undefined, WALL_CLOCK)\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\"\n return String(value)\n}\n","/**\n * Reading a data file in the browser. Both parsers are loaded through\n * `await import()` so an app without a data-file page never ships them, and an\n * app with one only pays when such a page is opened.\n *\n * Parsing happens on the client rather than at generate time because Vantage\n * has an SPA mode (no `server/`), so there is no server to parse on — and\n * because it makes dev, `build` and `preview` run the same code over the same\n * bytes, which is what \"the same URL returns the same thing\" rests on.\n */\nimport { FILE_PAGE_MAX_BYTES } from \"../core/constants\"\nimport { toSheet } from \"./infer\"\nimport type { Workbook } from \"./types\"\n\n/** Thrown for every failure a file page can show; the page renders the message. */\nexport class FilePageError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"FilePageError\"\n }\n}\n\nfunction megabytes(bytes: number): string {\n return `${(bytes / 1024 / 1024).toFixed(1)} MB`\n}\n\n/**\n * Decode CSV bytes. A Japanese spreadsheet exported from Excel is usually\n * CP932, not UTF-8, and decoding it as UTF-8 turns every non-ASCII character\n * into U+FFFD. Rather than ask the user to declare an encoding, decode as\n * UTF-8 and fall back when the result is visibly full of replacement\n * characters — a real UTF-8 file has none.\n */\nfunction decodeCsv(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n const hasBom = bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf\n const body = hasBom ? bytes.subarray(3) : bytes\n const utf8 = new TextDecoder(\"utf-8\").decode(body)\n const replacements = (utf8.match(/�/g) ?? []).length\n if (replacements > 0 && replacements / Math.max(utf8.length, 1) > 0.0005) {\n try {\n return new TextDecoder(\"shift-jis\").decode(body)\n } catch {\n // Some engines ship without the legacy decoder; the UTF-8 read is still\n // the best available answer.\n }\n }\n return utf8\n}\n\nasync function parseCsv(buffer: ArrayBuffer): Promise<Workbook> {\n const { default: Papa } = await import(\"papaparse\")\n const text = decodeCsv(buffer)\n // `header: false` on purpose: lifting the header row is done in `infer.ts`,\n // which puts CSV and XLSX on one code path instead of two.\n const result = Papa.parse<unknown[]>(text, {\n header: false,\n dynamicTyping: true,\n skipEmptyLines: \"greedy\",\n })\n return { sheets: [toSheet(\"Sheet1\", result.data)] }\n}\n\nasync function parseXlsx(buffer: ArrayBuffer): Promise<Workbook> {\n // The browser build specifically: the package has no root export, and the\n // node build reaches for `fs`.\n const { default: readXlsxFile } = await import(\"read-excel-file/browser\")\n const sheets = await readXlsxFile(buffer)\n return {\n sheets: sheets.map((sheet) => toSheet(sheet.sheet, sheet.data as unknown[][])),\n }\n}\n\n/**\n * Fetch and parse the file behind a file page. Every failure — network, size,\n * a corrupt workbook, an extension with no parser — surfaces as a rejected\n * promise so the page can render it in place instead of taking the app down.\n */\nexport async function loadWorkbook(src: string, kind: string): Promise<Workbook> {\n let buffer: ArrayBuffer\n try {\n const response = await fetch(src)\n if (!response.ok) {\n throw new FilePageError(`Could not load the file (HTTP ${response.status}).`)\n }\n buffer = await response.arrayBuffer()\n } catch (err) {\n if (err instanceof FilePageError) throw err\n throw new FilePageError(`Could not load the file: ${(err as Error).message}`)\n }\n\n if (buffer.byteLength > FILE_PAGE_MAX_BYTES) {\n throw new FilePageError(\n `This file is ${megabytes(buffer.byteLength)}, over the ${megabytes(\n FILE_PAGE_MAX_BYTES,\n )} limit for a data-file page. Download it, or serve the data from server/api/ and render it with DataTable.`,\n )\n }\n\n try {\n switch (kind) {\n case \"csv\":\n return await parseCsv(buffer)\n case \"xlsx\":\n return await parseXlsx(buffer)\n default:\n // Reached when an extension is added to FILE_PAGE_EXTENSIONS without a\n // parser here. Naming it beats rendering an empty table.\n throw new FilePageError(`No viewer for \".${kind}\" files.`)\n }\n } catch (err) {\n if (err instanceof FilePageError) throw err\n throw new FilePageError(\n `This file could not be read. It may be corrupt, password-protected, or not really a .${kind} file. (${\n (err as Error).message\n })`,\n )\n }\n}\n","/**\n * The spreadsheet grid. A data file page should read the way the file reads in\n * Excel or Sheets — column letters across the top, row numbers down the side,\n * a ruled canvas of fixed-height rows that runs past the data, and a selected\n * cell. That is why this is a grid and not a styled `DataTable`: the card, the\n * pagination and the sort affordances all say \"web table\", and none of them\n * exist in a spreadsheet.\n *\n * It is a viewer, not an editor. No toolbar, no formula bar, no editing; the\n * only interactions are moving the selection and copying a cell.\n *\n * Rows and columns are windowed. That is not an optimisation to revisit later:\n * a file page is capped at 200,000 rows, and mounting them would be hundreds of\n * thousands of DOM nodes. Fixed row height makes the window arithmetic exact,\n * so no virtualiser dependency is needed — `first = scrollTop / ROW_HEIGHT`.\n */\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n} from \"react\"\n\nimport { cn } from \"@squadbase/squadkit/lib/utils\"\nimport { formatCell } from \"./infer\"\nimport type { CellFormat, TableSheet } from \"./types\"\n\n/** Row height, matching a spreadsheet's default line rather than a web table's. */\nconst ROW_HEIGHT = 22\n/** Height of the A / B / C band. */\nconst HEAD_HEIGHT = 22\nconst MIN_GUTTER_WIDTH = 44\nconst MIN_COL_WIDTH = 56\nconst MAX_COL_WIDTH = 420\n/** Width of the empty columns that carry the ruling past the data. */\nconst FILLER_COL_WIDTH = 100\n/** Horizontal padding plus borders, added to the measured text width. */\nconst COL_PADDING = 18\nconst OVERSCAN_ROWS = 8\nconst OVERSCAN_COLS = 2\n/** Rows sampled when sizing a column. */\nconst WIDTH_SAMPLE_ROWS = 200\n/** Must match the cell font below, or measured widths will not fit the text. */\nconst CELL_FONT =\n '13px -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Hiragino Sans\", \"Hiragino Kaku Gothic ProN\", \"Noto Sans JP\", Meiryo, ui-sans-serif, system-ui, sans-serif'\n\n/** `0 → A`, `25 → Z`, `26 → AA` — spreadsheet column names. */\nexport function columnLabel(index: number): string {\n let label = \"\"\n for (let n = index; n >= 0; n = Math.floor(n / 26) - 1) {\n label = String.fromCharCode(65 + (n % 26)) + label\n }\n return label\n}\n\n/**\n * Size each column to its content, the way a spreadsheet does on import.\n * Measured with the canvas text metrics of the font the cells use, over a\n * sample spread across the whole sheet — sampling the first N rows only would\n * size a column on its header and miss the long values further down.\n */\nfunction measureWidths(sheet: TableSheet): number[] {\n const context =\n typeof document === \"undefined\" ? null : document.createElement(\"canvas\").getContext(\"2d\")\n if (context) context.font = CELL_FONT\n // Without a canvas (SSR, or a browser that refuses the context) fall back to\n // an average character width: the grid still lays out, just less snugly.\n const widthOf = (text: string) => (context ? context.measureText(text).width : text.length * 7.2)\n const stride = Math.max(1, Math.ceil(sheet.rows.length / WIDTH_SAMPLE_ROWS))\n\n return sheet.columns.map((column, index) => {\n let max = widthOf(column.label)\n for (let row = 0; row < sheet.rows.length; row += stride) {\n const text = formatCell(sheet.rows[row]?.[index], column.format)\n if (text !== \"\") max = Math.max(max, widthOf(text))\n }\n return Math.min(MAX_COL_WIDTH, Math.max(MIN_COL_WIDTH, Math.ceil(max) + COL_PADDING))\n })\n}\n\n/** Running x of each column, so windowing and scrolling are lookups. */\nfunction runningOffsets(widths: number[]): number[] {\n const offsets = [0]\n for (const width of widths) offsets.push(offsets[offsets.length - 1]! + width)\n return offsets\n}\n\n/** Index of the last offset at or before `x`. */\nfunction columnAt(offsets: number[], x: number): number {\n let low = 0\n let high = offsets.length - 2\n while (low < high) {\n const mid = (low + high + 1) >> 1\n if (offsets[mid]! <= x) low = mid\n else high = mid - 1\n }\n return Math.max(0, low)\n}\n\ninterface Selection {\n /** `0` is the header row (the file's row 1); `n` is body row `n - 1`. */\n row: number\n col: number\n}\n\nexport interface SheetGridProps {\n sheet: TableSheet\n className?: string\n}\n\n/**\n * One sheet as a grid. Fills its container, so give the parent a height —\n * `TableViewer` is the component that does that for a page.\n */\nexport function SheetGrid({ sheet, className }: SheetGridProps) {\n const scrollRef = useRef<HTMLDivElement>(null)\n const [scroll, setScroll] = useState({ top: 0, left: 0 })\n const [viewport, setViewport] = useState({ width: 0, height: 0 })\n const [selected, setSelected] = useState<Selection>({ row: 0, col: 0 })\n\n const dataWidths = useMemo(() => measureWidths(sheet), [sheet])\n const dataCols = sheet.columns.length\n const dataRows = sheet.rows.length\n\n // Wide enough for the largest row number: the gutter must not resize as the\n // window scrolls into five-digit rows.\n const gutterWidth = Math.max(MIN_GUTTER_WIDTH, String(dataRows + 1).length * 8 + 16)\n\n // Past the data the canvas keeps going, ruled and empty, as it does in every\n // spreadsheet. Enough of it to cover the viewport — beyond that nobody can\n // tell whether the sheet ends at column F or column XFD.\n const dataWidth = dataWidths.reduce((sum, width) => sum + width, 0)\n const fillerCols = Math.max(\n 0,\n Math.ceil((viewport.width - gutterWidth - dataWidth) / FILLER_COL_WIDTH),\n )\n const fillerRows = Math.max(\n 0,\n Math.ceil((viewport.height - HEAD_HEIGHT - (dataRows + 1) * ROW_HEIGHT) / ROW_HEIGHT),\n )\n const colCount = dataCols + fillerCols\n const rowCount = dataRows + fillerRows\n\n const widths = useMemo(\n () => [...dataWidths, ...Array.from({ length: fillerCols }, () => FILLER_COL_WIDTH)],\n [dataWidths, fillerCols],\n )\n const offsets = useMemo(() => runningOffsets(widths), [widths])\n const totalWidth = offsets[offsets.length - 1] ?? 0\n\n useLayoutEffect(() => {\n const element = scrollRef.current\n if (!element) return\n const measure = () => setViewport({ width: element.clientWidth, height: element.clientHeight })\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(element)\n return () => observer.disconnect()\n }, [])\n\n // Selection is positional, so a new sheet must not keep pointing at a cell\n // that no longer exists.\n useEffect(() => {\n setSelected({ row: 0, col: 0 })\n scrollRef.current?.scrollTo({ top: 0, left: 0 })\n }, [sheet])\n\n // Body rows live below the two frozen bands, so the first visible one falls\n // straight out of scrollTop.\n const firstRow = Math.max(0, Math.floor(scroll.top / ROW_HEIGHT) - OVERSCAN_ROWS)\n const lastRow = Math.min(\n rowCount,\n Math.ceil((scroll.top + viewport.height - HEAD_HEIGHT - ROW_HEIGHT) / ROW_HEIGHT) +\n OVERSCAN_ROWS,\n )\n const firstCol = Math.max(0, columnAt(offsets, scroll.left) - OVERSCAN_COLS)\n const lastCol = Math.min(\n colCount,\n columnAt(offsets, scroll.left + viewport.width) + 1 + OVERSCAN_COLS,\n )\n const leadWidth = offsets[firstCol] ?? 0\n const tailWidth = totalWidth - (offsets[lastCol] ?? totalWidth)\n const visibleCols = Array.from({ length: Math.max(0, lastCol - firstCol) }, (_, i) => firstCol + i)\n\n /** Bring a cell inside the scrollport, allowing for the frozen bands. */\n const reveal = useCallback(\n (next: Selection) => {\n const element = scrollRef.current\n if (!element) return\n if (next.row > 0) {\n const top = HEAD_HEIGHT + ROW_HEIGHT + (next.row - 1) * ROW_HEIGHT\n const frozen = HEAD_HEIGHT + ROW_HEIGHT\n if (top - element.scrollTop < frozen) element.scrollTop = top - frozen\n else if (top + ROW_HEIGHT - element.scrollTop > element.clientHeight) {\n element.scrollTop = top + ROW_HEIGHT - element.clientHeight\n }\n }\n const left = offsets[next.col] ?? 0\n const width = widths[next.col] ?? 0\n if (left - element.scrollLeft < 0) element.scrollLeft = left\n else if (left + width + gutterWidth - element.scrollLeft > element.clientWidth) {\n element.scrollLeft = left + width + gutterWidth - element.clientWidth\n }\n },\n [gutterWidth, offsets, widths],\n )\n\n const cellText = useCallback(\n (row: number, col: number): string => {\n const column = sheet.columns[col]\n if (!column) return \"\"\n if (row === 0) return column.label\n return formatCell(sheet.rows[row - 1]?.[col], column.format)\n },\n [sheet],\n )\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n // The selection stays on the data. The empty canvas past it is ruling,\n // not cells anyone needs to land on.\n //\n // `escapable` is what keeps this from being a keyboard trap: the grid is\n // focusable, so if Tab were always swallowed there would be no way out of\n // it. Tab that cannot move the selection any further is left to the\n // browser, which moves focus on to the sheet tabs.\n const step = (rows: number, cols: number, escapable = false) => {\n const next = {\n row: Math.min(dataRows, Math.max(0, selected.row + rows)),\n col: Math.min(dataCols - 1, Math.max(0, selected.col + cols)),\n }\n const moved = next.row !== selected.row || next.col !== selected.col\n if (moved || !escapable) event.preventDefault()\n if (!moved) return\n setSelected(next)\n reveal(next)\n }\n const page = Math.max(1, Math.floor(viewport.height / ROW_HEIGHT) - 1)\n\n switch (event.key) {\n case \"ArrowDown\":\n return step(1, 0)\n case \"ArrowUp\":\n return step(-1, 0)\n case \"Tab\":\n return step(0, event.shiftKey ? -1 : 1, true)\n case \"ArrowRight\":\n return step(0, 1)\n case \"ArrowLeft\":\n return step(0, -1)\n case \"PageDown\":\n return step(page, 0)\n case \"PageUp\":\n return step(-page, 0)\n case \"Home\":\n return step(event.ctrlKey || event.metaKey ? -dataRows : 0, -dataCols)\n case \"End\":\n return step(event.ctrlKey || event.metaKey ? dataRows : 0, dataCols)\n case \"c\":\n case \"C\":\n // The one thing a reader wants out of a viewer: the value, in full,\n // even when the column is too narrow to show it.\n if (event.metaKey || event.ctrlKey) {\n // A refused or unavailable clipboard is not worth an unhandled\n // rejection in the app's error reporting.\n navigator.clipboard?.writeText(cellText(selected.row, selected.col)).catch(() => {})\n }\n return\n default:\n return\n }\n },\n [cellText, dataCols, dataRows, reveal, selected, viewport.height],\n )\n\n if (dataCols === 0) {\n return <p className={cn(\"p-4 text-sm text-muted-foreground\", className)}>This sheet is empty.</p>\n }\n\n const select = (row: number, col: number) => {\n setSelected({ row, col })\n scrollRef.current?.focus({ preventScroll: true })\n }\n\n const rowStyle: CSSProperties = { height: ROW_HEIGHT, width: gutterWidth + totalWidth }\n\n return (\n <div\n ref={scrollRef}\n role=\"grid\"\n aria-label={sheet.name}\n aria-rowcount={dataRows + 1}\n aria-colcount={dataCols}\n tabIndex={0}\n onScroll={(event) =>\n setScroll({ top: event.currentTarget.scrollTop, left: event.currentTarget.scrollLeft })\n }\n onKeyDown={onKeyDown}\n className={cn(\n \"relative h-full overflow-auto bg-background text-[13px] outline-none select-none [overscroll-behavior:contain]\",\n className,\n )}\n >\n <div role=\"rowgroup\" style={{ width: gutterWidth + totalWidth }}>\n {/* A / B / C. Sticky on both axes, so the corner stays put. */}\n <div\n className=\"sticky top-0 z-40 flex\"\n style={{ ...rowStyle, height: HEAD_HEIGHT }}\n role=\"row\"\n >\n <div\n className=\"sticky left-0 z-10 shrink-0 border-r border-b border-border bg-muted\"\n style={{ width: gutterWidth, height: HEAD_HEIGHT }}\n />\n <div className=\"shrink-0 border-b border-border bg-muted\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => (\n <div\n key={col}\n role={col < dataCols ? \"columnheader\" : \"presentation\"}\n aria-colindex={col < dataCols ? col + 1 : undefined}\n onMouseDown={col < dataCols ? () => select(selected.row, col) : undefined}\n className={cn(\n \"flex shrink-0 items-center justify-center border-r border-b border-border bg-muted text-[11px] text-muted-foreground\",\n selected.col === col && col < dataCols && \"bg-accent font-medium text-foreground\",\n )}\n style={{ width: widths[col], height: HEAD_HEIGHT }}\n >\n {columnLabel(col)}\n </div>\n ))}\n <div className=\"shrink-0 border-b border-border bg-muted\" style={{ width: tailWidth }} />\n </div>\n\n {/* The file's row 1. Frozen under the letters, because a data file's\n first row is its header and reading row 40,000 without it is\n guesswork — the first thing anyone does to a sheet by hand. */}\n {/* Opaque: body rows scroll underneath this one. */}\n <div\n className=\"sticky z-30 flex bg-background\"\n style={{ ...rowStyle, top: HEAD_HEIGHT }}\n role=\"row\"\n >\n <RowHeader\n label=\"1\"\n width={gutterWidth}\n active={selected.row === 0}\n onSelect={() => select(0, selected.col)}\n />\n <div className=\"shrink-0 border-b border-foreground/25\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => (\n <Cell\n key={col}\n width={widths[col]!}\n // A header label is text, and a spreadsheet aligns a cell by what\n // is in it — so it reads left even over a column of numbers.\n format=\"text\"\n text={sheet.columns[col]?.label ?? \"\"}\n header\n selected={selected.row === 0 && selected.col === col}\n onSelect={col < dataCols ? () => select(0, col) : undefined}\n colIndex={col < dataCols ? col : undefined}\n />\n ))}\n <div className=\"shrink-0 border-b border-foreground/25\" style={{ width: tailWidth }} />\n </div>\n\n {/* `presentation` so the rows below stay owned by the rowgroup above. */}\n <div role=\"presentation\" className=\"relative\" style={{ height: rowCount * ROW_HEIGHT }}>\n {Array.from({ length: Math.max(0, lastRow - firstRow) }, (_, offset) => {\n const row = firstRow + offset\n const cells = sheet.rows[row]\n return (\n <div\n key={row}\n role=\"row\"\n aria-rowindex={row < dataRows ? row + 2 : undefined}\n className=\"absolute flex\"\n style={{ ...rowStyle, top: row * ROW_HEIGHT }}\n >\n <RowHeader\n label={String(row + 2)}\n width={gutterWidth}\n active={selected.row === row + 1}\n onSelect={row < dataRows ? () => select(row + 1, selected.col) : undefined}\n />\n <div className=\"shrink-0\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => {\n const column = sheet.columns[col]\n return (\n <Cell\n key={col}\n width={widths[col]!}\n format={column?.format ?? \"text\"}\n text={column ? formatCell(cells?.[col], column.format) : \"\"}\n selected={selected.row === row + 1 && selected.col === col}\n onSelect={\n row < dataRows && col < dataCols ? () => select(row + 1, col) : undefined\n }\n colIndex={col < dataCols ? col : undefined}\n />\n )\n })}\n <div className=\"shrink-0\" style={{ width: tailWidth }} />\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\nSheetGrid.displayName = \"SheetGrid\"\n\nfunction RowHeader({\n label,\n width,\n active,\n onSelect,\n}: {\n label: string\n width: number\n active: boolean\n onSelect?: () => void\n}) {\n return (\n <div\n role={onSelect ? \"rowheader\" : \"presentation\"}\n onMouseDown={onSelect}\n className={cn(\n // Above a selected cell (`z-10`): scrolling a selected column under the\n // gutter must not paint its outline over the row number.\n \"sticky left-0 z-20 flex h-full shrink-0 items-center justify-center border-r border-b border-border bg-muted text-[11px] text-muted-foreground\",\n active && \"bg-accent font-medium text-foreground\",\n )}\n style={{ width }}\n >\n {label}\n </div>\n )\n}\n\nfunction Cell({\n width,\n format,\n text,\n header,\n selected,\n onSelect,\n colIndex,\n}: {\n width: number\n format: CellFormat\n text: string\n header?: boolean\n selected: boolean\n onSelect?: () => void\n colIndex?: number\n}) {\n return (\n <div\n role={onSelect ? \"gridcell\" : \"presentation\"}\n aria-colindex={colIndex === undefined ? undefined : colIndex + 1}\n aria-selected={onSelect ? selected : undefined}\n onMouseDown={onSelect}\n // Columns are sized to their content but capped, so a long value still\n // gets clipped — the title is how the rest of it stays reachable\n // without a formula bar.\n title={text || undefined}\n className={cn(\n \"flex h-full shrink-0 items-center border-r border-b border-border px-1.5\",\n header && \"border-b-foreground/25 font-medium\",\n // Numbers and dates read right-aligned, as they do in a spreadsheet.\n format === \"text\" ? \"justify-start\" : \"justify-end tabular-nums\",\n selected && onSelect && \"relative z-10 outline-2 -outline-offset-2 outline-primary\",\n )}\n style={{ width }}\n >\n <span className=\"truncate\">{text}</span>\n </div>\n )\n}\n","/**\n * One sheet, framed the way a spreadsheet application frames one: the grid\n * fills the window, and a status bar sits under it with the sheet tabs on the\n * left and the shape of the sheet on the right.\n *\n * The frame is what makes the grid usable — a grid needs a definite height to\n * scroll inside, and a Vantage page has no guaranteed one (layouts belong to\n * the app). So it measures the space left below itself in the viewport rather\n * than asking the app to arrange for a height.\n */\nimport { useLayoutEffect, useRef, useState, type RefObject } from \"react\"\n\nimport { cn } from \"@squadbase/squadkit/lib/utils\"\nimport { SheetGrid } from \"./sheet-grid\"\nimport type { TableSheet } from \"./types\"\n\n/** Never collapse below this, however little viewport is left. */\nconst MIN_HEIGHT = 320\n/** Breathing room under the frame when the layout leaves none of its own. */\nconst MIN_BOTTOM_GAP = 8\n\nexport interface TableViewerProps {\n /** The sheet to render. */\n sheet: TableSheet\n /** Every sheet's name. Given more than one, a tab strip is rendered. */\n sheetNames?: string[]\n activeSheet?: number\n onSheetChange?: (index: number) => void\n /**\n * Fixed height for the frame. Without it the viewer fills the rest of the\n * viewport, which is right for a file page and wrong for a table embedded in\n * a dashboard among other cards.\n */\n height?: number | string\n className?: string\n}\n\n/**\n * What the layout keeps under the frame: every ancestor's bottom padding,\n * border and margin. It has to come out of the height, or the page ends up\n * scrollable by exactly that much (a page shell nested in a layout shell means\n * two lots of padding). Read from the box model rather than from the document\n * height, which a `min-h-screen` layout pins to the viewport and would make\n * this feed back on its own result.\n */\nfunction spaceBelow(element: HTMLElement): number {\n let total = 0\n for (let node = element.parentElement; node && node !== document.body; node = node.parentElement) {\n const style = getComputedStyle(node)\n total +=\n parseFloat(style.paddingBottom) + parseFloat(style.borderBottomWidth) + parseFloat(style.marginBottom)\n }\n return Number.isFinite(total) ? total : 0\n}\n\n/**\n * Fill the rest of the viewport. Measured rather than expressed in CSS: the\n * frame's distance from the top of the window depends on whatever the app's\n * layout put above it, which no `calc()` here can know.\n */\nfunction useFillHeight(ref: RefObject<HTMLElement | null>, enabled: boolean): number {\n const [height, setHeight] = useState(MIN_HEIGHT)\n\n useLayoutEffect(() => {\n const element = ref.current\n if (!element || !enabled) return\n const measure = () => {\n // Document-relative, not viewport-relative: `rect.top` alone shrinks as\n // the page scrolls, so a measurement taken while scrolled (a mobile URL\n // bar collapsing fires `resize`) would make the frame taller than the\n // viewport and add page scroll that never goes away.\n const rect = element.getBoundingClientRect()\n const top = rect.top + window.scrollY\n const next = Math.max(\n MIN_HEIGHT,\n window.innerHeight - top - Math.max(spaceBelow(element), MIN_BOTTOM_GAP),\n )\n // Only a real change: the frame's own height feeds back into the\n // document height, and rounding noise would loop.\n setHeight((current) => (Math.abs(current - next) > 1 ? next : current))\n }\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(document.body)\n window.addEventListener(\"resize\", measure)\n return () => {\n observer.disconnect()\n window.removeEventListener(\"resize\", measure)\n }\n }, [enabled, ref])\n\n return height\n}\n\nfunction plural(count: number, noun: string): string {\n return `${count.toLocaleString()} ${noun}${count === 1 ? \"\" : \"s\"}`\n}\n\n/** Render one parsed sheet. Exported so an app can drive it with its own data. */\nexport function TableViewer({\n sheet,\n sheetNames,\n activeSheet = 0,\n onSheetChange,\n height,\n className,\n}: TableViewerProps) {\n const frameRef = useRef<HTMLDivElement>(null)\n const filled = useFillHeight(frameRef, height === undefined)\n const tabs = sheetNames && sheetNames.length > 1 ? sheetNames : null\n\n return (\n <div\n ref={frameRef}\n className={cn(\n \"flex flex-col overflow-hidden rounded-md border border-border bg-background\",\n className,\n )}\n style={{ height: height ?? filled }}\n >\n <div className=\"min-h-0 flex-1\">\n <SheetGrid sheet={sheet} />\n </div>\n\n {/* The status bar: sheet tabs and the shape of the sheet, where a\n spreadsheet puts them. */}\n <div className=\"flex items-center gap-4 border-t border-border bg-muted/60 px-2 py-1\">\n {tabs ? (\n <div className=\"flex min-w-0 items-end gap-px overflow-x-auto\" role=\"tablist\">\n {tabs.map((name, index) => (\n <button\n key={name}\n type=\"button\"\n role=\"tab\"\n aria-selected={index === activeSheet}\n onClick={() => onSheetChange?.(index)}\n className={cn(\n \"shrink-0 rounded-t-sm border-t-2 px-3 py-1 text-xs whitespace-nowrap\",\n index === activeSheet\n ? \"border-primary bg-background font-medium text-foreground\"\n : \"border-transparent text-muted-foreground hover:text-foreground\",\n )}\n >\n {name}\n </button>\n ))}\n </div>\n ) : null}\n\n <div className=\"ml-auto flex shrink-0 items-center gap-3 text-[11px] text-muted-foreground\">\n {sheet.truncated ? (\n <span className=\"font-medium text-foreground\">\n First {sheet.rows.length.toLocaleString()} of {sheet.totalRows.toLocaleString()} rows —\n download the file for the rest\n </span>\n ) : null}\n <span>\n {plural(sheet.totalRows, \"row\")} × {plural(sheet.columns.length, \"column\")}\n </span>\n </div>\n </div>\n </div>\n )\n}\nTableViewer.displayName = \"TableViewer\"\n","/**\n * The page a `.csv` or `.xlsx` under `src/` becomes. Generated wrappers in\n * `.vantage/file-pages/` mount this; apps can mount it themselves to take over\n * the title or to render a file kept out of routing with an `_` prefix.\n */\nimport { useState } from \"react\"\nimport { DownloadIcon } from \"lucide-react\"\nimport {\n PageShell,\n PageShellActions,\n PageShellContent,\n PageShellHeader,\n PageShellHeading,\n PageShellMeta,\n PageShellTitle,\n} from \"../components\"\nimport { useQuery } from \"../query\"\nimport { Button } from \"@squadbase/squadkit/ui/button\"\nimport { Loading, ErrorState } from \"@squadbase/squadkit/ui/states\"\nimport { loadWorkbook } from \"./parse\"\nimport { TableViewer } from \"./table-viewer\"\n\nexport interface FilePageViewProps {\n /** Extension without the dot, e.g. `\"xlsx\"`. */\n kind: string\n /** URL of the file, produced by Vite's asset pipeline. */\n src: string\n /** Original file name, used for the heading fallback and the download. */\n fileName: string\n /** Title derived from the file name at generate time. */\n title?: string\n}\n\nexport function FilePageView({ kind, src, fileName, title }: FilePageViewProps) {\n const [active, setActive] = useState(0)\n\n // The framework's QueryClient is already above this in the tree, so the\n // parsed workbook is cached across navigations for free and the retry and\n // networkMode policies are the managed ones — no second provider.\n const workbook = useQuery({\n queryKey: [\"vantage:file-page\", src],\n queryFn: () => loadWorkbook(src, kind),\n staleTime: Infinity,\n })\n\n const download = (\n // `nativeButton={false}` because this renders an `<a>`: Base UI needs to\n // know it is not driving a real button, or it warns and keeps button\n // semantics that would fight the link's.\n <Button\n variant=\"outline\"\n size=\"sm\"\n nativeButton={false}\n render={<a href={src} download={fileName} />}\n >\n <DownloadIcon aria-hidden=\"true\" />\n Download\n </Button>\n )\n\n const sheets = workbook.data?.sheets ?? []\n const sheet = sheets[Math.min(active, Math.max(sheets.length - 1, 0))]\n\n return (\n <PageShell>\n {/* A slim band: the grid below wants the vertical room, and a data file\n has no description to carry. */}\n <PageShellHeader className=\"py-6\">\n <PageShellHeading>\n <PageShellTitle>{title ?? fileName}</PageShellTitle>\n <PageShellMeta>{fileName}</PageShellMeta>\n </PageShellHeading>\n <PageShellActions>{download}</PageShellActions>\n </PageShellHeader>\n\n <PageShellContent>\n {workbook.isPending ? <Loading label={`Reading ${fileName}…`} /> : null}\n\n {/* Every failure path lands here, inside the page. A data file the\n browser cannot read must not take the rest of the app down. */}\n {workbook.isError ? (\n <ErrorState\n title={`Could not display ${fileName}`}\n message={(workbook.error as Error).message}\n action={download}\n />\n ) : null}\n\n {sheet ? (\n <TableViewer\n sheet={sheet}\n sheetNames={sheets.map((s) => s.name)}\n activeSheet={active}\n onSheetChange={setActive}\n />\n ) : null}\n </PageShellContent>\n </PageShell>\n )\n}\nFilePageView.displayName = \"FilePageView\"\n"]}
@@ -453,9 +453,12 @@ declare function Empty({ title, description, icon, action, className, }: {
453
453
  action?: ReactNode;
454
454
  className?: string;
455
455
  }): React$1.JSX.Element;
456
- declare function ErrorState({ title, message, action, className, }: {
456
+ declare function ErrorState({ title, message, details, action, className, }: {
457
457
  title?: string;
458
+ /** What happened and what to do next, in plain words. */
458
459
  message?: ReactNode;
460
+ /** Technical detail (error message, status code), folded behind "詳細を表示". */
461
+ details?: ReactNode;
459
462
  action?: ReactNode;
460
463
  className?: string;
461
464
  }): React$1.JSX.Element;
package/dist/ui/index.js CHANGED
@@ -1,14 +1,14 @@
1
- export { Empty, ErrorState, Loading } from '../chunk-5ZOP4SQR.js';
2
- import { InputGroup, InputGroupInput, InputGroupAddon, InputGroupButton, Separator } from '../chunk-OB6UBJXF.js';
3
- export { Badge, Calendar, CalendarDayButton, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, toggleVariants, useIsMobile, useSidebar } from '../chunk-OB6UBJXF.js';
4
- import { Button } from '../chunk-PXRX5PEC.js';
5
- export { Button, buttonVariants } from '../chunk-PXRX5PEC.js';
6
- import { cn } from '../chunk-A2UUGASH.js';
7
- export { cn } from '../chunk-A2UUGASH.js';
1
+ export { Empty, ErrorState, Loading } from '../chunk-2N72FKLB.js';
2
+ import { InputGroup, InputGroupInput, InputGroupAddon, InputGroupButton, Separator } from '../chunk-XPQSTZUU.js';
3
+ export { Badge, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, toggleVariants, useIsMobile, useSidebar } from '../chunk-XPQSTZUU.js';
4
+ import { Button } from '../chunk-PDOBHMUQ.js';
5
+ export { Button, buttonVariants } from '../chunk-PDOBHMUQ.js';
6
+ import { cn } from '../chunk-U736PVHY.js';
7
+ export { cn } from '../chunk-U736PVHY.js';
8
8
  import { Accordion as Accordion$1 } from '@base-ui/react/accordion';
9
9
  import { ChevronDownIcon, ChevronUpIcon, ChevronRightIcon, MoreHorizontalIcon, CheckIcon, XIcon, ChevronLeftIcon, Loader2Icon, CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon } from 'lucide-react';
10
10
  import { jsx, jsxs } from 'react/jsx-runtime';
11
- import * as React7 from 'react';
11
+ import * as React6 from 'react';
12
12
  import { useMemo } from 'react';
13
13
  import { cva } from 'class-variance-authority';
14
14
  import { AlertDialog as AlertDialog$1 } from '@base-ui/react/alert-dialog';
@@ -79,7 +79,7 @@ function AccordionContent({
79
79
  Accordion$1.Panel,
80
80
  {
81
81
  "data-slot": "accordion-content",
82
- className: "overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up",
82
+ className: "overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up motion-reduce:animate-none",
83
83
  ...props,
84
84
  children: /* @__PURE__ */ jsx(
85
85
  "div",
@@ -180,7 +180,7 @@ function AlertDialogOverlay({
180
180
  {
181
181
  "data-slot": "alert-dialog-overlay",
182
182
  className: cn(
183
- "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
183
+ "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in motion-reduce:animate-none! data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
184
184
  className
185
185
  ),
186
186
  ...props
@@ -200,7 +200,7 @@ function AlertDialogContent({
200
200
  "data-slot": "alert-dialog-content",
201
201
  "data-size": size,
202
202
  className: cn(
203
- "group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
203
+ "group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in motion-reduce:animate-none! data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
204
204
  className
205
205
  ),
206
206
  ...props
@@ -514,96 +514,6 @@ function BreadcrumbEllipsis({
514
514
  }
515
515
  );
516
516
  }
517
- function Card({
518
- className,
519
- size = "default",
520
- ...props
521
- }) {
522
- return /* @__PURE__ */ jsx(
523
- "div",
524
- {
525
- "data-slot": "card",
526
- "data-size": size,
527
- className: cn(
528
- "group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
529
- className
530
- ),
531
- ...props
532
- }
533
- );
534
- }
535
- function CardHeader({ className, ...props }) {
536
- return /* @__PURE__ */ jsx(
537
- "div",
538
- {
539
- "data-slot": "card-header",
540
- className: cn(
541
- "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
542
- className
543
- ),
544
- ...props
545
- }
546
- );
547
- }
548
- function CardTitle({ className, ...props }) {
549
- return /* @__PURE__ */ jsx(
550
- "div",
551
- {
552
- "data-slot": "card-title",
553
- className: cn(
554
- "cn-font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
555
- className
556
- ),
557
- ...props
558
- }
559
- );
560
- }
561
- function CardDescription({ className, ...props }) {
562
- return /* @__PURE__ */ jsx(
563
- "div",
564
- {
565
- "data-slot": "card-description",
566
- className: cn("text-sm text-muted-foreground", className),
567
- ...props
568
- }
569
- );
570
- }
571
- function CardAction({ className, ...props }) {
572
- return /* @__PURE__ */ jsx(
573
- "div",
574
- {
575
- "data-slot": "card-action",
576
- className: cn(
577
- "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
578
- className
579
- ),
580
- ...props
581
- }
582
- );
583
- }
584
- function CardContent({ className, ...props }) {
585
- return /* @__PURE__ */ jsx(
586
- "div",
587
- {
588
- "data-slot": "card-content",
589
- className: cn("px-(--card-spacing)", className),
590
- ...props
591
- }
592
- );
593
- }
594
- function CardFooter({ className, ...props }) {
595
- return /* @__PURE__ */ jsx(
596
- "div",
597
- {
598
- "data-slot": "card-footer",
599
- className: cn(
600
- "flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)",
601
- className
602
- ),
603
- ...props
604
- }
605
- );
606
- }
607
517
  var Combobox = Combobox$1.Root;
608
518
  function ComboboxValue({ ...props }) {
609
519
  return /* @__PURE__ */ jsx(Combobox$1.Value, { "data-slot": "combobox-value", ...props });
@@ -705,7 +615,7 @@ function ComboboxContent({
705
615
  "data-slot": "combobox-content",
706
616
  "data-chips": !!anchor,
707
617
  className: cn(
708
- "cn-menu-target cn-menu-translucent group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[chips=true]:min-w-(--anchor-width) data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:border-input/30 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:shadow-none data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
618
+ "cn-menu-target cn-menu-translucent group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[chips=true]:min-w-(--anchor-width) data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:border-input/30 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:shadow-none data-open:animate-in motion-reduce:animate-none! data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
709
619
  className
710
620
  ),
711
621
  ...props
@@ -876,11 +786,11 @@ function ComboboxChipsInput({
876
786
  );
877
787
  }
878
788
  function useComboboxAnchor() {
879
- return React7.useRef(null);
789
+ return React6.useRef(null);
880
790
  }
881
- var DrawerContext = React7.createContext(null);
791
+ var DrawerContext = React6.createContext(null);
882
792
  function useDrawer() {
883
- const context = React7.useContext(DrawerContext);
793
+ const context = React6.useContext(DrawerContext);
884
794
  if (!context) {
885
795
  throw new Error("useDrawer must be used within a Drawer.");
886
796
  }
@@ -894,7 +804,7 @@ function Drawer({
894
804
  ...props
895
805
  }) {
896
806
  const hasSnapPoints = snapPoints != null && snapPoints.length > 0;
897
- const contextValue = React7.useMemo(
807
+ const contextValue = React6.useMemo(
898
808
  () => ({ hasSnapPoints, modal, showSwipeHandle, swipeDirection }),
899
809
  [hasSnapPoints, modal, showSwipeHandle, swipeDirection]
900
810
  );
@@ -1307,7 +1217,7 @@ function HoverCardContent({
1307
1217
  {
1308
1218
  "data-slot": "hover-card-content",
1309
1219
  className: cn(
1310
- "z-50 w-64 origin-(--transform-origin) rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
1220
+ "z-50 w-64 origin-(--transform-origin) rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in motion-reduce:animate-none! data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
1311
1221
  className
1312
1222
  ),
1313
1223
  ...props
@@ -1746,7 +1656,7 @@ function TabsTrigger({ className, ...props }) {
1746
1656
  {
1747
1657
  "data-slot": "tabs-trigger",
1748
1658
  className: cn(
1749
- "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1659
+ "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-[color,background-color,border-color,box-shadow] group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1750
1660
  "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
1751
1661
  "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
1752
1662
  "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
@@ -1761,7 +1671,7 @@ function TabsContent({ className, ...props }) {
1761
1671
  Tabs$1.Panel,
1762
1672
  {
1763
1673
  "data-slot": "tabs-content",
1764
- className: cn("flex-1 text-sm outline-none", className),
1674
+ className: cn("flex-1 text-sm outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50", className),
1765
1675
  ...props
1766
1676
  }
1767
1677
  );
@@ -1794,7 +1704,7 @@ function Toast({ className, ...props }) {
1794
1704
  className: cn(
1795
1705
  "group/toast pointer-events-auto absolute right-0 bottom-0 z-[calc(1000-var(--toast-index))] w-full origin-bottom rounded-2xl border bg-popover text-popover-foreground shadow-lg will-change-transform outline-none select-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
1796
1706
  "[--gap:0.75rem] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))]",
1797
- "h-(--height) [transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] [transition:transform_500ms_cubic-bezier(0.22,1,0.36,1),opacity_500ms,height_150ms]",
1707
+ "h-(--height) [transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] [transition:transform_400ms_cubic-bezier(0.22,1,0.36,1),opacity_400ms,height_150ms] data-ending-style:[transition-duration:200ms] motion-reduce:[transition:opacity_150ms]",
1798
1708
  "after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']",
1799
1709
  "data-expanded:h-(--toast-height) data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]",
1800
1710
  "data-limited:opacity-0 data-starting-style:[transform:translateY(150%)]",
@@ -1971,6 +1881,6 @@ function Toaster({
1971
1881
  var createToastManager = Toast$1.createToastManager;
1972
1882
  var useToastManager = Toast$1.useToastManager;
1973
1883
 
1974
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerSwipeHandle, DrawerTitle, DrawerTrigger, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, HoverCard, HoverCardContent, HoverCardTrigger, Kbd, KbdGroup, Label, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, Slider, Spinner, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Toast, ToastAction, ToastClose, ToastContent, ToastDescription, ToastPortal, ToastProvider, ToastTitle, ToastViewport, Toaster, createToastManager, tabsListVariants, toast, useComboboxAnchor, useToastManager };
1884
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerSwipeHandle, DrawerTitle, DrawerTrigger, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, HoverCard, HoverCardContent, HoverCardTrigger, Kbd, KbdGroup, Label, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, Slider, Spinner, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Toast, ToastAction, ToastClose, ToastContent, ToastDescription, ToastPortal, ToastProvider, ToastTitle, ToastViewport, Toaster, createToastManager, tabsListVariants, toast, useComboboxAnchor, useToastManager };
1975
1885
  //# sourceMappingURL=index.js.map
1976
1886
  //# sourceMappingURL=index.js.map