@undevy-org/tablewright 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -0
  3. package/dist/es/components/dashboard/ReportSummaryCard.js +67 -0
  4. package/dist/es/components/data-table/AppliedStateChips.js +113 -0
  5. package/dist/es/components/data-table/ColumnFilterPopover.js +548 -0
  6. package/dist/es/components/data-table/ColumnHeaderMenu.js +144 -0
  7. package/dist/es/components/data-table/CompoundFilterPopover.js +508 -0
  8. package/dist/es/components/data-table/CopyButton.js +35 -0
  9. package/dist/es/components/data-table/CopyableText.js +26 -0
  10. package/dist/es/components/data-table/DataTableShell.js +145 -0
  11. package/dist/es/components/data-table/DrawerActionGroup.js +59 -0
  12. package/dist/es/components/data-table/DrawerEntityCard.js +21 -0
  13. package/dist/es/components/data-table/DrawerField.js +10 -0
  14. package/dist/es/components/data-table/DrawerFlagItem.js +20 -0
  15. package/dist/es/components/data-table/DrawerSection.js +26 -0
  16. package/dist/es/components/data-table/DrawerShell.js +141 -0
  17. package/dist/es/components/data-table/DrawerSummaryCard.js +11 -0
  18. package/dist/es/components/data-table/EmptyState.js +14 -0
  19. package/dist/es/components/data-table/ExpiryTimestampCell.js +43 -0
  20. package/dist/es/components/data-table/FilterChip.js +47 -0
  21. package/dist/es/components/data-table/FilterFormPanel.js +357 -0
  22. package/dist/es/components/data-table/FilterFormToggle.js +77 -0
  23. package/dist/es/components/data-table/FilterPopoverFooter.js +19 -0
  24. package/dist/es/components/data-table/FilterToolbar.js +131 -0
  25. package/dist/es/components/data-table/FlatColumnToggle.js +46 -0
  26. package/dist/es/components/data-table/GapIndicator.js +29 -0
  27. package/dist/es/components/data-table/GroupedColumnToggle.js +112 -0
  28. package/dist/es/components/data-table/RowActionsMenu.js +74 -0
  29. package/dist/es/components/data-table/RowControlCell.js +104 -0
  30. package/dist/es/components/data-table/SortableHeader.js +102 -0
  31. package/dist/es/components/data-table/TableFooter.js +132 -0
  32. package/dist/es/components/data-table/TableLayout.js +14 -0
  33. package/dist/es/components/data-table/TimestampCell.js +16 -0
  34. package/dist/es/components/data-table/TwoPanelMenu.js +64 -0
  35. package/dist/es/components/data-table/ViewChip.js +25 -0
  36. package/dist/es/components/data-table/cells/AmountCell.js +127 -0
  37. package/dist/es/components/data-table/cells/ConfirmedAmountCell.js +115 -0
  38. package/dist/es/components/data-table/cells/CurrencyAmountCell.js +26 -0
  39. package/dist/es/components/data-table/cells/DualLineCell.js +59 -0
  40. package/dist/es/components/data-table/cells/EnumBadgeCell.js +9 -0
  41. package/dist/es/components/data-table/cells/MonoIdCell.js +31 -0
  42. package/dist/es/components/data-table/hooks/use-column-resize.js +39 -0
  43. package/dist/es/components/data-table/hooks/use-row-drag.js +40 -0
  44. package/dist/es/components/data-table/hooks/use-table-pagination.js +14 -0
  45. package/dist/es/components/data-table/hooks/use-table-sort.js +35 -0
  46. package/dist/es/components/data-table/managed-filters.js +34 -0
  47. package/dist/es/components/data-table/sticky-utils.js +25 -0
  48. package/dist/es/components/layout/AppShell.js +113 -0
  49. package/dist/es/components/layout/Sidebar.js +128 -0
  50. package/dist/es/components/layout/SidebarAccountMenu.js +129 -0
  51. package/dist/es/components/layout/SidebarUser.js +38 -0
  52. package/dist/es/components/layout/TopBar.js +25 -0
  53. package/dist/es/components/layout/app-shell-context.js +9 -0
  54. package/dist/es/components/ui/badge.js +31 -0
  55. package/dist/es/components/ui/button-footer.js +25 -0
  56. package/dist/es/components/ui/button.js +44 -0
  57. package/dist/es/components/ui/checkbox.js +24 -0
  58. package/dist/es/components/ui/combobox.js +179 -0
  59. package/dist/es/components/ui/dialog.js +80 -0
  60. package/dist/es/components/ui/dropdown-menu.js +66 -0
  61. package/dist/es/components/ui/input.js +24 -0
  62. package/dist/es/components/ui/popover.js +33 -0
  63. package/dist/es/components/ui/segmented-control.js +60 -0
  64. package/dist/es/components/ui/select.js +66 -0
  65. package/dist/es/components/ui/tabs.js +41 -0
  66. package/dist/es/components/ui/theme-switch.js +47 -0
  67. package/dist/es/constants/drawer.js +4 -0
  68. package/dist/es/context/drawer-expand-context.js +10 -0
  69. package/dist/es/context/portal-container-context.js +10 -0
  70. package/dist/es/hooks/table-orchestration-store.js +165 -0
  71. package/dist/es/hooks/use-scroll-activity.js +33 -0
  72. package/dist/es/hooks/useRowDragOverride.js +18 -0
  73. package/dist/es/hooks/useTableOrchestration.js +452 -0
  74. package/dist/es/index.js +199 -0
  75. package/dist/es/lib/column-gaps.js +23 -0
  76. package/dist/es/lib/filter-stats.js +67 -0
  77. package/dist/es/lib/format-enum.js +6 -0
  78. package/dist/es/lib/format-timestamp.js +37 -0
  79. package/dist/es/lib/style-scope.js +4 -0
  80. package/dist/es/lib/utils.js +8 -0
  81. package/dist/fonts.css +5 -0
  82. package/dist/preflight.css +502 -0
  83. package/dist/styles.css +1731 -0
  84. package/dist/tablewright.cjs +5473 -0
  85. package/dist/tablewright.css +1579 -0
  86. package/dist/tokens.css +150 -0
  87. package/dist/types/components/dashboard/ReportSummaryCard.d.ts +15 -0
  88. package/dist/types/components/data-table/AppliedStateChips.d.ts +28 -0
  89. package/dist/types/components/data-table/ColumnFilterPopover.d.ts +14 -0
  90. package/dist/types/components/data-table/ColumnHeaderMenu.d.ts +27 -0
  91. package/dist/types/components/data-table/CompoundFilterPopover.d.ts +14 -0
  92. package/dist/types/components/data-table/CopyButton.d.ts +8 -0
  93. package/dist/types/components/data-table/CopyableText.d.ts +10 -0
  94. package/dist/types/components/data-table/DataTableShell.d.ts +30 -0
  95. package/dist/types/components/data-table/DrawerActionGroup.d.ts +8 -0
  96. package/dist/types/components/data-table/DrawerEntityCard.d.ts +13 -0
  97. package/dist/types/components/data-table/DrawerField.d.ts +7 -0
  98. package/dist/types/components/data-table/DrawerFlagItem.d.ts +10 -0
  99. package/dist/types/components/data-table/DrawerSection.d.ts +8 -0
  100. package/dist/types/components/data-table/DrawerShell.d.ts +33 -0
  101. package/dist/types/components/data-table/DrawerSummaryCard.d.ts +7 -0
  102. package/dist/types/components/data-table/EmptyState.d.ts +6 -0
  103. package/dist/types/components/data-table/ExpiryTimestampCell.d.ts +6 -0
  104. package/dist/types/components/data-table/FilterChip.d.ts +8 -0
  105. package/dist/types/components/data-table/FilterFormPanel.d.ts +34 -0
  106. package/dist/types/components/data-table/FilterFormToggle.d.ts +18 -0
  107. package/dist/types/components/data-table/FilterPopoverFooter.d.ts +9 -0
  108. package/dist/types/components/data-table/FilterToolbar.d.ts +29 -0
  109. package/dist/types/components/data-table/FlatColumnToggle.d.ts +10 -0
  110. package/dist/types/components/data-table/GapIndicator.d.ts +11 -0
  111. package/dist/types/components/data-table/GroupedColumnToggle.d.ts +12 -0
  112. package/dist/types/components/data-table/RowActionsMenu.d.ts +10 -0
  113. package/dist/types/components/data-table/RowControlCell.d.ts +16 -0
  114. package/dist/types/components/data-table/SortableHeader.d.ts +16 -0
  115. package/dist/types/components/data-table/TableFooter.d.ts +31 -0
  116. package/dist/types/components/data-table/TableLayout.d.ts +12 -0
  117. package/dist/types/components/data-table/TimestampCell.d.ts +3 -0
  118. package/dist/types/components/data-table/TwoPanelMenu.d.ts +22 -0
  119. package/dist/types/components/data-table/ViewChip.d.ts +6 -0
  120. package/dist/types/components/data-table/cells/AmountCell.d.ts +11 -0
  121. package/dist/types/components/data-table/cells/ConfirmedAmountCell.d.ts +10 -0
  122. package/dist/types/components/data-table/cells/CurrencyAmountCell.d.ts +8 -0
  123. package/dist/types/components/data-table/cells/DualLineCell.d.ts +44 -0
  124. package/dist/types/components/data-table/cells/EnumBadgeCell.d.ts +9 -0
  125. package/dist/types/components/data-table/cells/MonoIdCell.d.ts +19 -0
  126. package/dist/types/components/data-table/filter-types.d.ts +79 -0
  127. package/dist/types/components/data-table/hooks/use-column-resize.d.ts +7 -0
  128. package/dist/types/components/data-table/hooks/use-row-drag.d.ts +14 -0
  129. package/dist/types/components/data-table/hooks/use-table-pagination.d.ts +10 -0
  130. package/dist/types/components/data-table/hooks/use-table-sort.d.ts +6 -0
  131. package/dist/types/components/data-table/managed-filters.d.ts +18 -0
  132. package/dist/types/components/data-table/sticky-utils.d.ts +4 -0
  133. package/dist/types/components/data-table/types.d.ts +35 -0
  134. package/dist/types/components/layout/AppShell.d.ts +23 -0
  135. package/dist/types/components/layout/Sidebar.d.ts +16 -0
  136. package/dist/types/components/layout/SidebarAccountMenu.d.ts +20 -0
  137. package/dist/types/components/layout/SidebarUser.d.ts +8 -0
  138. package/dist/types/components/layout/TopBar.d.ts +7 -0
  139. package/dist/types/components/layout/app-shell-context.d.ts +8 -0
  140. package/dist/types/components/layout/index.d.ts +10 -0
  141. package/dist/types/components/layout/types.d.ts +11 -0
  142. package/dist/types/components/ui/badge.d.ts +9 -0
  143. package/dist/types/components/ui/button-footer.d.ts +7 -0
  144. package/dist/types/components/ui/button.d.ts +11 -0
  145. package/dist/types/components/ui/checkbox.d.ts +4 -0
  146. package/dist/types/components/ui/combobox.d.ts +92 -0
  147. package/dist/types/components/ui/dialog.d.ts +15 -0
  148. package/dist/types/components/ui/dropdown-menu.d.ts +10 -0
  149. package/dist/types/components/ui/input.d.ts +6 -0
  150. package/dist/types/components/ui/popover.d.ts +7 -0
  151. package/dist/types/components/ui/segmented-control.d.ts +17 -0
  152. package/dist/types/components/ui/select.d.ts +8 -0
  153. package/dist/types/components/ui/tabs.d.ts +10 -0
  154. package/dist/types/components/ui/theme-switch.d.ts +12 -0
  155. package/dist/types/constants/drawer.d.ts +1 -0
  156. package/dist/types/context/drawer-expand-context.d.ts +7 -0
  157. package/dist/types/context/portal-container-context.d.ts +14 -0
  158. package/dist/types/hooks/table-orchestration-store.d.ts +75 -0
  159. package/dist/types/hooks/use-scroll-activity.d.ts +1 -0
  160. package/dist/types/hooks/useDemoTheme.d.ts +8 -0
  161. package/dist/types/hooks/useRowDragOverride.d.ts +6 -0
  162. package/dist/types/hooks/useTableOrchestration.d.ts +115 -0
  163. package/dist/types/index.d.ts +107 -0
  164. package/dist/types/lib/column-gaps.d.ts +3 -0
  165. package/dist/types/lib/filter-stats.d.ts +2 -0
  166. package/dist/types/lib/format-enum.d.ts +1 -0
  167. package/dist/types/lib/format-timestamp.d.ts +4 -0
  168. package/dist/types/lib/style-scope.d.ts +19 -0
  169. package/dist/types/lib/utils.d.ts +2 -0
  170. package/package.json +114 -0
@@ -0,0 +1,26 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { CopyButton } from "./CopyButton.js";
3
+ import { cn } from "../../lib/utils.js";
4
+ function CopyableText({
5
+ value,
6
+ children,
7
+ className,
8
+ textClassName,
9
+ buttonClassName,
10
+ title = "Copy value"
11
+ }) {
12
+ return /* @__PURE__ */ jsxs("span", { className: cn("group/copy inline-flex min-w-0 items-center gap-1", className), children: [
13
+ /* @__PURE__ */ jsx("span", { className: cn("min-w-0 truncate", textClassName), children: children ?? value }),
14
+ /* @__PURE__ */ jsx(
15
+ CopyButton,
16
+ {
17
+ text: value,
18
+ title,
19
+ className: cn("group-hover/copy:opacity-100 group-focus-within/copy:opacity-100", buttonClassName)
20
+ }
21
+ )
22
+ ] });
23
+ }
24
+ export {
25
+ CopyableText
26
+ };
@@ -0,0 +1,145 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { flexRender } from "@tanstack/react-table";
3
+ import { cn } from "../../lib/utils.js";
4
+ import { DrawerShell } from "./DrawerShell.js";
5
+ import { EmptyState } from "./EmptyState.js";
6
+ import { TableLayout } from "./TableLayout.js";
7
+ import { stickyStyle, stickyBorderClass } from "./sticky-utils.js";
8
+ function DataTableShell({
9
+ table,
10
+ dense,
11
+ emptyMessage,
12
+ columnMeta,
13
+ columnWidths,
14
+ onColumnResizeStart,
15
+ onRowClick,
16
+ getRowIsActive,
17
+ rowDrag,
18
+ footer,
19
+ drawer,
20
+ className
21
+ }) {
22
+ const visibleTableWidth = table.getVisibleLeafColumns().reduce(
23
+ (sum, column) => sum + (columnWidths[column.id] ?? columnMeta[column.id]?.minW ?? 120),
24
+ 0
25
+ );
26
+ return /* @__PURE__ */ jsxs(TableLayout, { className: cn("min-h-0", className), children: [
27
+ /* @__PURE__ */ jsx(TableLayout.ScrollArea, { className: "[scrollbar-gutter:stable]", children: /* @__PURE__ */ jsxs(
28
+ "table",
29
+ {
30
+ className: "w-full border-collapse",
31
+ style: { tableLayout: "fixed", minWidth: `${visibleTableWidth}px` },
32
+ children: [
33
+ /* @__PURE__ */ jsx("thead", { className: "sticky top-0 z-10 bg-[var(--bg-surface)]", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx("tr", { children: headerGroup.headers.map((header) => {
34
+ const columnId = header.column.id;
35
+ const meta = columnMeta[columnId];
36
+ const isActionsColumn = meta?.sticky === "right";
37
+ const isControlColumn = meta?.variant === "control";
38
+ return /* @__PURE__ */ jsxs(
39
+ "th",
40
+ {
41
+ className: cn(
42
+ "group/th relative border-b border-[var(--border-subtle)] bg-[var(--bg-surface)] px-4 text-left text-[12px] font-medium text-[var(--text-secondary)]",
43
+ dense ? "py-1.5" : "py-3",
44
+ isActionsColumn && "px-3 text-right",
45
+ isControlColumn && "px-1 text-center",
46
+ stickyBorderClass(meta)
47
+ ),
48
+ style: {
49
+ width: columnWidths[columnId],
50
+ minWidth: meta?.minW ?? 36,
51
+ ...stickyStyle(meta, true)
52
+ },
53
+ children: [
54
+ header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()),
55
+ header.column.columnDef.enableResizing !== false ? /* @__PURE__ */ jsx(
56
+ "div",
57
+ {
58
+ className: "absolute bottom-0 right-0 top-0 w-px cursor-col-resize bg-[var(--border-subtle)] opacity-30 transition-[opacity,width,background-color] duration-150 group-hover/th:w-[4px] group-hover/th:bg-[var(--border-focus)] group-hover/th:opacity-50 hover:!opacity-100",
59
+ onPointerDown: (event) => onColumnResizeStart(columnId, event)
60
+ }
61
+ ) : null
62
+ ]
63
+ },
64
+ header.id
65
+ );
66
+ }) }, headerGroup.id)) }),
67
+ /* @__PURE__ */ jsxs("tbody", { children: [
68
+ table.getRowModel().rows.map((row) => {
69
+ const isActive = getRowIsActive?.(row.original) ?? false;
70
+ const dragProps = rowDrag?.getDragProps(row.index);
71
+ const isDragged = rowDrag?.dragRowIdx === row.index;
72
+ const isDropTarget = rowDrag != null && rowDrag.dropTargetIdx === row.index && rowDrag.dragRowIdx !== null && rowDrag.dragRowIdx !== row.index;
73
+ return /* @__PURE__ */ jsx(
74
+ "tr",
75
+ {
76
+ ...dragProps,
77
+ onClick: onRowClick ? () => onRowClick(row.original) : void 0,
78
+ className: cn(
79
+ "group border-b border-[var(--border-subtle)] transition-colors",
80
+ onRowClick && "cursor-pointer hover:bg-[var(--bg-hover)]",
81
+ isActive && "bg-[var(--bg-hover)]",
82
+ rowDrag && "cursor-grab active:cursor-grabbing",
83
+ isDragged && "opacity-40",
84
+ isDropTarget && "border-t-2 border-t-[var(--border-focus)]"
85
+ ),
86
+ children: row.getVisibleCells().map((cell, cellIndex) => {
87
+ const meta = columnMeta[cell.column.id];
88
+ const isActionsColumn = meta?.sticky === "right";
89
+ const isControlColumn = meta?.variant === "control";
90
+ return /* @__PURE__ */ jsx(
91
+ "td",
92
+ {
93
+ className: cn(
94
+ "overflow-hidden px-4 text-[var(--text-primary)]",
95
+ dense ? "py-1 text-xs leading-tight" : "py-4 text-sm",
96
+ meta?.sticky && (isActive ? "bg-[var(--bg-hover)]" : "bg-[var(--bg-surface)] group-hover:bg-[var(--bg-hover)]"),
97
+ isActionsColumn && "px-3 align-middle text-right",
98
+ isControlColumn && "px-1 text-center",
99
+ cellIndex === 0 && isActive && "relative before:absolute before:bottom-0 before:left-0 before:top-0 before:w-[3px] before:bg-[var(--accent-primary)] before:content-['']",
100
+ stickyBorderClass(meta)
101
+ ),
102
+ style: {
103
+ width: columnWidths[cell.column.id],
104
+ minWidth: meta?.minW ?? 36,
105
+ maxWidth: columnWidths[cell.column.id],
106
+ ...stickyStyle(meta, false)
107
+ },
108
+ children: flexRender(cell.column.columnDef.cell, cell.getContext())
109
+ },
110
+ cell.id
111
+ );
112
+ })
113
+ },
114
+ row.id
115
+ );
116
+ }),
117
+ table.getRowModel().rows.length === 0 ? /* @__PURE__ */ jsx(
118
+ EmptyState,
119
+ {
120
+ message: emptyMessage,
121
+ colSpan: table.getVisibleLeafColumns().length
122
+ }
123
+ ) : null
124
+ ] })
125
+ ]
126
+ }
127
+ ) }),
128
+ footer,
129
+ drawer ? /* @__PURE__ */ jsx(
130
+ DrawerShell,
131
+ {
132
+ open: drawer.open,
133
+ onClose: drawer.onClose,
134
+ title: drawer.title,
135
+ subtitle: drawer.subtitle,
136
+ headerExtra: drawer.headerExtra,
137
+ mode: drawer.mode,
138
+ children: drawer.content
139
+ }
140
+ ) : null
141
+ ] });
142
+ }
143
+ export {
144
+ DataTableShell
145
+ };
@@ -0,0 +1,59 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils.js";
3
+ function DrawerActionGroup({ sections, variant, columns }) {
4
+ if (variant === "flat") {
5
+ const actions = sections.flatMap((s) => s.actions);
6
+ return /* @__PURE__ */ jsx("div", { className: cn("grid gap-2", (columns ?? 2) === 4 ? "grid-cols-4" : "grid-cols-2"), children: actions.map((action) => /* @__PURE__ */ jsxs(
7
+ "button",
8
+ {
9
+ type: "button",
10
+ onClick: (e) => {
11
+ e.stopPropagation();
12
+ action.onClick(e);
13
+ },
14
+ disabled: action.disabled,
15
+ className: "flex items-center gap-2 rounded-lg border border-[var(--border-subtle)] bg-[var(--bg-surface)] px-3 py-2 text-[13px] font-medium text-[var(--text-primary)] transition-colors hover:bg-[var(--bg-hover)] disabled:cursor-not-allowed disabled:opacity-40",
16
+ children: [
17
+ /* @__PURE__ */ jsx(action.icon, { className: "h-4 w-4 shrink-0 text-[var(--text-secondary)]" }),
18
+ action.label
19
+ ]
20
+ },
21
+ action.label
22
+ )) });
23
+ }
24
+ return /* @__PURE__ */ jsx("div", { className: "space-y-3", children: sections.map((section) => /* @__PURE__ */ jsxs(
25
+ "div",
26
+ {
27
+ className: "rounded-xl border border-[var(--border-subtle)] bg-[var(--bg-secondary)] p-3",
28
+ children: [
29
+ /* @__PURE__ */ jsx("div", { className: "mb-2 text-[10px] font-semibold uppercase tracking-[0.12em] text-[var(--text-tertiary)]", children: section.label }),
30
+ /* @__PURE__ */ jsx("div", { className: cn("grid gap-2", (columns ?? 2) === 4 ? "grid-cols-4" : "grid-cols-2"), children: section.actions.map((action) => /* @__PURE__ */ jsxs(
31
+ "button",
32
+ {
33
+ type: "button",
34
+ onClick: (e) => {
35
+ e.stopPropagation();
36
+ action.onClick(e);
37
+ },
38
+ disabled: action.disabled,
39
+ className: "flex items-center gap-2 rounded-lg border border-[var(--border-subtle)] bg-[var(--bg-surface)] px-3 py-2 text-[13px] font-medium text-[var(--text-primary)] transition-colors hover:bg-[var(--bg-hover)] disabled:cursor-not-allowed disabled:opacity-40",
40
+ children: [
41
+ /* @__PURE__ */ jsx(
42
+ action.icon,
43
+ {
44
+ className: action.variant === "danger" ? "h-4 w-4 shrink-0 text-[var(--tag-pink-text)]" : action.variant === "accent" ? "h-4 w-4 shrink-0 text-[var(--text-primary)]" : "h-4 w-4 shrink-0 text-[var(--text-secondary)]"
45
+ }
46
+ ),
47
+ /* @__PURE__ */ jsx("span", { children: action.label })
48
+ ]
49
+ },
50
+ action.label
51
+ )) })
52
+ ]
53
+ },
54
+ section.label
55
+ )) });
56
+ }
57
+ export {
58
+ DrawerActionGroup
59
+ };
@@ -0,0 +1,21 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { CopyableText } from "./CopyableText.js";
3
+ function DrawerEntityCard({ name, id, children }) {
4
+ const headerLayout = id ? "grid grid-cols-2 gap-x-4 items-center" : "flex";
5
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-[var(--bg-hover)] p-3.5", children: [
6
+ /* @__PURE__ */ jsxs("div", { className: `mb-2.5 border-b border-[var(--border-subtle)] pb-2 ${headerLayout}`, children: [
7
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-[var(--text-primary)]", children: name }),
8
+ id ? /* @__PURE__ */ jsx(
9
+ CopyableText,
10
+ {
11
+ value: id,
12
+ textClassName: "font-mono text-[11px] text-[var(--text-secondary)]"
13
+ }
14
+ ) : null
15
+ ] }),
16
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-x-4", children })
17
+ ] });
18
+ }
19
+ export {
20
+ DrawerEntityCard
21
+ };
@@ -0,0 +1,10 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ function DrawerField({ label, value, children }) {
3
+ return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[120px_1fr] items-center text-[13px]", children: [
4
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--text-secondary)]", children: label }),
5
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 overflow-hidden text-[var(--text-primary)]", children: children ?? value })
6
+ ] });
7
+ }
8
+ export {
9
+ DrawerField
10
+ };
@@ -0,0 +1,20 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ function DrawerFlagGrid({ children }) {
3
+ return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-x-4 gap-y-3", children });
4
+ }
5
+ function DrawerFlagItem({ label, value }) {
6
+ return /* @__PURE__ */ jsxs("div", { children: [
7
+ /* @__PURE__ */ jsx("div", { className: "mb-0.5 text-[11px] text-[var(--text-secondary)]", children: label }),
8
+ /* @__PURE__ */ jsx(
9
+ "div",
10
+ {
11
+ className: value ? "text-[13px] font-semibold text-[var(--tag-green-text)]" : "text-[13px] font-semibold text-[var(--text-primary)]",
12
+ children: value ? "Yes" : "No"
13
+ }
14
+ )
15
+ ] });
16
+ }
17
+ export {
18
+ DrawerFlagGrid,
19
+ DrawerFlagItem
20
+ };
@@ -0,0 +1,26 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils.js";
3
+ function DrawerSection({ title, children, className, card = false }) {
4
+ if (card) {
5
+ return /* @__PURE__ */ jsxs(
6
+ "div",
7
+ {
8
+ className: cn(
9
+ "rounded-lg border border-[var(--border-subtle)] bg-[var(--bg-surface)] p-4",
10
+ className
11
+ ),
12
+ children: [
13
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-[10px] font-semibold uppercase tracking-wider text-[var(--text-tertiary)]", children: title }),
14
+ children
15
+ ]
16
+ }
17
+ );
18
+ }
19
+ return /* @__PURE__ */ jsxs("section", { className: className ?? "mb-8", children: [
20
+ /* @__PURE__ */ jsx("h3", { className: "mb-4 text-[11px] font-semibold uppercase tracking-[0.05em] text-[var(--text-secondary)]", children: title }),
21
+ /* @__PURE__ */ jsx("div", { className: "grid gap-4", children })
22
+ ] });
23
+ }
24
+ export {
25
+ DrawerSection
26
+ };
@@ -0,0 +1,141 @@
1
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
+ import { useState, useRef, useEffect } from "react";
3
+ import { Minimize2, Maximize2, X } from "lucide-react";
4
+ import { Button } from "../ui/button.js";
5
+ import { cn } from "../../lib/utils.js";
6
+ import { useScrollActivity } from "../../hooks/use-scroll-activity.js";
7
+ import { DrawerExpandContext } from "../../context/drawer-expand-context.js";
8
+ function DrawerShell({
9
+ open,
10
+ onClose,
11
+ title,
12
+ subtitle,
13
+ headerExtra,
14
+ children,
15
+ footer,
16
+ dismissible = false,
17
+ mode = "side"
18
+ }) {
19
+ const [expandedState, setExpandedState] = useState(false);
20
+ const bodyScrollRef = useScrollActivity();
21
+ const isExpanded = mode === "modal" ? true : mode === "side" ? false : expandedState;
22
+ const canToggle = mode === "side+modal";
23
+ const handleClose = () => {
24
+ setExpandedState(false);
25
+ onClose();
26
+ };
27
+ const closeRef = useRef(handleClose);
28
+ useEffect(() => {
29
+ closeRef.current = handleClose;
30
+ });
31
+ useEffect(() => {
32
+ if (!open || !dismissible) return;
33
+ const onKeyDown = (event) => {
34
+ if (event.key !== "Escape" || event.defaultPrevented) return;
35
+ const target = event.target;
36
+ if (target?.closest?.("[role=dialog],[role=menu]")) return;
37
+ closeRef.current();
38
+ };
39
+ window.addEventListener("keydown", onKeyDown);
40
+ return () => window.removeEventListener("keydown", onKeyDown);
41
+ }, [open, dismissible]);
42
+ const header = /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-start justify-between border-b border-[var(--border-subtle)] px-6 py-6", children: [
43
+ /* @__PURE__ */ jsxs("div", { children: [
44
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
45
+ title ? /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-[var(--text-primary)]", children: title }) : null,
46
+ headerExtra
47
+ ] }),
48
+ subtitle && /* @__PURE__ */ jsx("div", { className: "mt-1 text-[11px] text-[var(--text-secondary)]", children: subtitle })
49
+ ] }),
50
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
51
+ canToggle && (isExpanded ? /* @__PURE__ */ jsx(
52
+ Button,
53
+ {
54
+ variant: "ghost",
55
+ size: "icon",
56
+ className: "h-8 w-8 rounded-sm",
57
+ onClick: () => setExpandedState(false),
58
+ title: "Collapse to panel",
59
+ children: /* @__PURE__ */ jsx(Minimize2, { className: "h-4 w-4" })
60
+ }
61
+ ) : /* @__PURE__ */ jsx(
62
+ Button,
63
+ {
64
+ variant: "ghost",
65
+ size: "icon",
66
+ className: "h-8 w-8 rounded-sm",
67
+ onClick: () => setExpandedState(true),
68
+ title: "Expand to full view",
69
+ children: /* @__PURE__ */ jsx(Maximize2, { className: "h-4 w-4" })
70
+ }
71
+ )),
72
+ /* @__PURE__ */ jsx(
73
+ Button,
74
+ {
75
+ variant: "ghost",
76
+ size: "icon",
77
+ "aria-label": "Close",
78
+ className: "h-8 w-8 rounded-sm",
79
+ onClick: handleClose,
80
+ children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
81
+ }
82
+ )
83
+ ] })
84
+ ] });
85
+ const body = /* @__PURE__ */ jsx(
86
+ "div",
87
+ {
88
+ ref: bodyScrollRef,
89
+ className: "scrollbar-auto-hide min-h-0 flex-1 overflow-y-auto px-6 py-6",
90
+ children
91
+ }
92
+ );
93
+ const pinnedFooter = footer ? /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t border-[var(--border-subtle)] px-6 py-4", children: footer }) : null;
94
+ return /* @__PURE__ */ jsxs(DrawerExpandContext.Provider, { value: isExpanded, children: [
95
+ !isExpanded && /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ dismissible && /* @__PURE__ */ jsx(
97
+ "div",
98
+ {
99
+ className: cn(
100
+ "absolute inset-0 z-30 bg-[var(--overlay-scrim,rgba(15,23,42,0.28))] transition-opacity duration-300",
101
+ open ? "opacity-100" : "pointer-events-none opacity-0"
102
+ ),
103
+ onClick: handleClose,
104
+ "aria-hidden": true
105
+ }
106
+ ),
107
+ /* @__PURE__ */ jsxs(
108
+ "aside",
109
+ {
110
+ "aria-label": "Details panel",
111
+ className: cn(
112
+ "absolute inset-y-0 right-0 z-40 flex w-[var(--size-drawer)] flex-col border-l border-[var(--border-subtle)] bg-[var(--bg-surface)] transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]",
113
+ open ? "translate-x-0 [box-shadow:var(--shadow-drawer)]" : "translate-x-full shadow-none"
114
+ ),
115
+ children: [
116
+ header,
117
+ body,
118
+ pinnedFooter
119
+ ]
120
+ }
121
+ )
122
+ ] }),
123
+ isExpanded && open && /* @__PURE__ */ jsxs(Fragment, { children: [
124
+ /* @__PURE__ */ jsx(
125
+ "div",
126
+ {
127
+ className: "fixed inset-0 z-50 bg-black/50 animate-in fade-in-0 duration-200",
128
+ onClick: handleClose
129
+ }
130
+ ),
131
+ /* @__PURE__ */ jsxs("div", { className: "fixed left-1/2 top-[10vh] z-50 flex h-[80vh] w-[min(75vw,1400px)] -translate-x-1/2 flex-col overflow-hidden rounded-xl border border-[var(--border-subtle)] bg-[var(--bg-surface)] shadow-2xl animate-in fade-in-0 zoom-in-95 duration-200", children: [
132
+ header,
133
+ body,
134
+ pinnedFooter
135
+ ] })
136
+ ] })
137
+ ] });
138
+ }
139
+ export {
140
+ DrawerShell
141
+ };
@@ -0,0 +1,11 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ function DrawerSummaryCard({ label, value, sub }) {
3
+ return /* @__PURE__ */ jsxs("div", { className: "bg-[var(--bg-hover)] rounded-lg p-3", children: [
4
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--text-secondary)] mb-1", children: label }),
5
+ /* @__PURE__ */ jsx("div", { className: "text-lg font-semibold text-[var(--text-primary)]", children: value }),
6
+ sub !== void 0 && /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--text-secondary)] mt-0.5", children: sub })
7
+ ] });
8
+ }
9
+ export {
10
+ DrawerSummaryCard
11
+ };
@@ -0,0 +1,14 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ function EmptyState({ message, colSpan }) {
3
+ return /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
4
+ "td",
5
+ {
6
+ colSpan,
7
+ className: "px-6 py-16 text-center text-[13px] text-[var(--text-secondary)]",
8
+ children: message
9
+ }
10
+ ) });
11
+ }
12
+ export {
13
+ EmptyState
14
+ };
@@ -0,0 +1,43 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ function splitTimestamp(value) {
3
+ if (!value) return { date: "—", time: "" };
4
+ const [date, time] = value.split(" ");
5
+ return { date: date ?? "—", time: time ?? "" };
6
+ }
7
+ function getUrgency(timestampMs) {
8
+ const diff = timestampMs - Date.now();
9
+ if (diff <= 0) return "expired";
10
+ if (diff < 5 * 60 * 1e3) return "danger";
11
+ if (diff < 30 * 60 * 1e3) return "warning";
12
+ return "ok";
13
+ }
14
+ function formatRelative(timestampMs) {
15
+ const diff = timestampMs - Date.now();
16
+ if (diff <= -864e5) return null;
17
+ if (diff <= 0) return "Expired";
18
+ const totalMinutes = Math.ceil(diff / 6e4);
19
+ if (totalMinutes < 60) return `in ${totalMinutes} min`;
20
+ const hours = Math.floor(totalMinutes / 60);
21
+ return `in ${hours} h`;
22
+ }
23
+ const urgencyClass = {
24
+ expired: "text-red-600",
25
+ danger: "text-red-600",
26
+ warning: "text-[var(--tag-orange-text)]",
27
+ ok: "text-[var(--text-secondary)]"
28
+ };
29
+ function ExpiryTimestampCell({ value, timestampMs }) {
30
+ const { date, time } = splitTimestamp(value);
31
+ const showUrgency = timestampMs !== void 0 && timestampMs > 0;
32
+ const ts = timestampMs ?? 0;
33
+ const urgency = showUrgency ? getUrgency(ts) : "ok";
34
+ const relativeLabel = showUrgency ? formatRelative(ts) : null;
35
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1 text-left font-mono", children: [
36
+ /* @__PURE__ */ jsx("div", { className: "text-[13px] font-medium text-[var(--text-primary)]", children: date }),
37
+ time ? /* @__PURE__ */ jsx("div", { className: "text-[12px] text-[var(--text-secondary)]", children: time }) : null,
38
+ relativeLabel && /* @__PURE__ */ jsx("div", { className: `text-[11px] ${urgencyClass[urgency]}`, children: relativeLabel })
39
+ ] });
40
+ }
41
+ export {
42
+ ExpiryTimestampCell
43
+ };
@@ -0,0 +1,47 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { X } from "lucide-react";
4
+ import { cn } from "../../lib/utils.js";
5
+ const FilterChip = React.forwardRef(
6
+ ({ label, value, onRemove, active, children, className, ...rest }, ref) => {
7
+ return /* @__PURE__ */ jsxs(
8
+ "div",
9
+ {
10
+ ref,
11
+ ...rest,
12
+ className: cn(
13
+ "flex h-[var(--size-control-md)] items-center rounded-md border border-[var(--border-subtle)] text-[13px] transition-colors",
14
+ active ? "bg-[var(--bg-secondary)]" : "bg-[var(--bg-surface)]",
15
+ className
16
+ ),
17
+ children: [
18
+ /* @__PURE__ */ jsx("div", { className: "flex h-full items-center pl-2.5 pr-1.5 cursor-pointer", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
19
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--text-secondary)]", children: label }),
20
+ value && /* @__PURE__ */ jsxs(Fragment, { children: [
21
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--text-tertiary)]", children: ":" }),
22
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--text-primary)] font-medium", children: value })
23
+ ] }),
24
+ children
25
+ ] }) }),
26
+ /* @__PURE__ */ jsx("div", { className: "h-full flex items-center pr-1.5", children: /* @__PURE__ */ jsx(
27
+ "button",
28
+ {
29
+ type: "button",
30
+ onClick: (e) => {
31
+ e.stopPropagation();
32
+ onRemove();
33
+ },
34
+ className: "flex h-5 w-5 items-center justify-center rounded-sm text-[var(--text-tertiary)] hover:bg-[var(--bg-hover)] hover:text-[var(--text-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--border-focus)]",
35
+ "aria-label": `Remove ${label} filter`,
36
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
37
+ }
38
+ ) })
39
+ ]
40
+ }
41
+ );
42
+ }
43
+ );
44
+ FilterChip.displayName = "FilterChip";
45
+ export {
46
+ FilterChip
47
+ };