@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,112 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { TwoPanelMenuBase } from "./TwoPanelMenu.js";
3
+ import { Columns, ChevronDown } from "lucide-react";
4
+ import { Button } from "../ui/button.js";
5
+ import { Checkbox } from "../ui/checkbox.js";
6
+ function CheckboxRightPanel({
7
+ group,
8
+ columnVisibility,
9
+ onColumnToggle,
10
+ onGroupToggleAll
11
+ }) {
12
+ const allVisible = group.items.every((item) => columnVisibility[item.id] !== false);
13
+ const noneVisible = group.items.every((item) => columnVisibility[item.id] === false);
14
+ const isIndeterminate = !allVisible && !noneVisible;
15
+ return /* @__PURE__ */ jsxs("div", { style: { padding: 4 }, children: [
16
+ /* @__PURE__ */ jsxs(
17
+ "label",
18
+ {
19
+ className: "flex w-full items-center gap-2.5 rounded-md px-2 py-2 text-left hover:bg-[var(--bg-hover)] cursor-pointer",
20
+ style: { fontSize: 12, fontWeight: 500, color: "var(--text-secondary)" },
21
+ children: [
22
+ /* @__PURE__ */ jsx(
23
+ Checkbox,
24
+ {
25
+ checked: isIndeterminate ? "indeterminate" : allVisible,
26
+ onCheckedChange: () => onGroupToggleAll(group.key, !allVisible),
27
+ className: "h-3.5 w-3.5 rounded-[3px]"
28
+ }
29
+ ),
30
+ /* @__PURE__ */ jsx("span", { children: "All" })
31
+ ]
32
+ }
33
+ ),
34
+ /* @__PURE__ */ jsx("div", { className: "border-t border-[var(--border-subtle)]", style: { margin: "0 8px 4px 8px" } }),
35
+ group.items.map((item) => {
36
+ const isChecked = columnVisibility[item.id] !== false;
37
+ return /* @__PURE__ */ jsxs(
38
+ "label",
39
+ {
40
+ className: `flex w-full items-center gap-2.5 rounded-md px-2 py-2 text-left hover:bg-[var(--bg-hover)] cursor-pointer ${item.disabled ? "pointer-events-none opacity-50" : ""}`,
41
+ style: { fontSize: 13 },
42
+ children: [
43
+ /* @__PURE__ */ jsx(
44
+ Checkbox,
45
+ {
46
+ checked: isChecked,
47
+ onCheckedChange: () => onColumnToggle(item.id),
48
+ disabled: item.disabled,
49
+ className: "h-3.5 w-3.5 rounded-[3px]"
50
+ }
51
+ ),
52
+ /* @__PURE__ */ jsx("span", { children: item.label })
53
+ ]
54
+ },
55
+ item.id
56
+ );
57
+ })
58
+ ] });
59
+ }
60
+ function GroupedColumnToggle({
61
+ columnGroups,
62
+ columnLabels,
63
+ columnVisibility,
64
+ onColumnToggle,
65
+ onGroupToggleAll,
66
+ open,
67
+ onOpenChange
68
+ }) {
69
+ const groups = columnGroups.map((cg) => ({
70
+ key: cg.key,
71
+ label: cg.label,
72
+ items: cg.columnIds.map((columnId) => ({
73
+ id: columnId,
74
+ label: columnLabels[columnId] ?? columnId,
75
+ checked: columnVisibility[columnId] !== false,
76
+ disabled: false
77
+ }))
78
+ }));
79
+ const activeCountPerGroup = {};
80
+ for (const cg of columnGroups) {
81
+ const hiddenCount = cg.columnIds.filter((id) => columnVisibility[id] === false).length;
82
+ activeCountPerGroup[cg.key] = hiddenCount;
83
+ }
84
+ const trigger = /* @__PURE__ */ jsxs(Button, { variant: "secondary", children: [
85
+ /* @__PURE__ */ jsx(Columns, { size: 14 }),
86
+ "Columns",
87
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 text-[var(--text-tertiary)]" })
88
+ ] });
89
+ return /* @__PURE__ */ jsx(
90
+ TwoPanelMenuBase,
91
+ {
92
+ groups,
93
+ activeCountPerGroup,
94
+ trigger,
95
+ width: 380,
96
+ open,
97
+ onOpenChange,
98
+ renderRightPanel: (group) => /* @__PURE__ */ jsx(
99
+ CheckboxRightPanel,
100
+ {
101
+ group,
102
+ columnVisibility,
103
+ onColumnToggle,
104
+ onGroupToggleAll
105
+ }
106
+ )
107
+ }
108
+ );
109
+ }
110
+ export {
111
+ GroupedColumnToggle
112
+ };
@@ -0,0 +1,74 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { MoreVertical } from "lucide-react";
3
+ import { Button } from "../ui/button.js";
4
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from "../ui/dropdown-menu.js";
5
+ import { cn } from "../../lib/utils.js";
6
+ function RowActionsMenu({
7
+ actions = [],
8
+ sections,
9
+ align = "end",
10
+ triggerClassName,
11
+ contentClassName
12
+ }) {
13
+ const resolvedSections = sections && sections.length > 0 ? sections : actions.length > 0 ? [{ label: "", actions }] : [];
14
+ const isGrouped = resolvedSections.some((section) => section.label);
15
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
16
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
17
+ Button,
18
+ {
19
+ variant: "ghost",
20
+ size: "icon",
21
+ "aria-label": "Row actions",
22
+ className: cn(
23
+ "h-7 w-7 rounded-sm p-0 opacity-0 transition-opacity group-hover:opacity-100 data-[state=open]:opacity-100",
24
+ triggerClassName
25
+ ),
26
+ onClick: (event) => event.stopPropagation(),
27
+ children: /* @__PURE__ */ jsx(MoreVertical, { className: "h-4 w-4" })
28
+ }
29
+ ) }),
30
+ /* @__PURE__ */ jsx(
31
+ DropdownMenuContent,
32
+ {
33
+ align,
34
+ className: cn(isGrouped ? "w-[320px] p-1.5" : "w-40", contentClassName),
35
+ children: resolvedSections.map((section, sectionIndex) => /* @__PURE__ */ jsxs("div", { children: [
36
+ section.label ? /* @__PURE__ */ jsx("div", { className: "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-[0.12em] text-[var(--text-tertiary)] first:pt-1", children: section.label }) : null,
37
+ section.actions.map((action) => /* @__PURE__ */ jsxs(
38
+ DropdownMenuItem,
39
+ {
40
+ disabled: action.disabled,
41
+ className: cn(
42
+ "gap-2.5 rounded-md px-2.5 py-2",
43
+ action.variant === "danger" && "text-[var(--tag-pink-text)]",
44
+ action.variant === "accent" && "text-[var(--text-primary)]"
45
+ ),
46
+ onClick: (event) => {
47
+ event.stopPropagation();
48
+ action.onClick(event);
49
+ },
50
+ children: [
51
+ /* @__PURE__ */ jsx(
52
+ action.icon,
53
+ {
54
+ className: cn(
55
+ "h-3.5 w-3.5 shrink-0 text-[var(--text-secondary)]",
56
+ action.variant === "danger" && "text-[var(--tag-pink-text)]",
57
+ action.variant === "accent" && "text-[var(--text-primary)]"
58
+ )
59
+ }
60
+ ),
61
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: action.label })
62
+ ]
63
+ },
64
+ `${section.label}-${action.label}`
65
+ )),
66
+ sectionIndex < resolvedSections.length - 1 ? /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-[var(--border-subtle)]" }) : null
67
+ ] }, section.label || sectionIndex))
68
+ }
69
+ )
70
+ ] });
71
+ }
72
+ export {
73
+ RowActionsMenu
74
+ };
@@ -0,0 +1,104 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { GripVertical, Expand } from "lucide-react";
3
+ import { cn } from "../../lib/utils.js";
4
+ import { Checkbox } from "../ui/checkbox.js";
5
+ function RowControlCell({
6
+ rowNumber,
7
+ selected,
8
+ onSelectToggle,
9
+ onExpandToggle,
10
+ ariaLabelSelect = "Select row",
11
+ ariaLabelExpand = "Expand row",
12
+ forceControlsVisible = false
13
+ }) {
14
+ const showCheckbox = selected || forceControlsVisible;
15
+ const showHoverAffordances = forceControlsVisible;
16
+ return /* @__PURE__ */ jsxs("div", { className: "relative flex h-full w-full items-center justify-center", children: [
17
+ /* @__PURE__ */ jsx(
18
+ "span",
19
+ {
20
+ className: cn(
21
+ "text-[11px] tabular-nums text-[var(--text-tertiary)] transition-opacity",
22
+ showCheckbox ? "opacity-0" : "opacity-100 group-hover:opacity-0"
23
+ ),
24
+ children: rowNumber
25
+ }
26
+ ),
27
+ /* @__PURE__ */ jsx(
28
+ "div",
29
+ {
30
+ className: cn(
31
+ "absolute inset-0 flex items-center justify-center transition-opacity",
32
+ showCheckbox ? "opacity-100" : "pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100"
33
+ ),
34
+ children: /* @__PURE__ */ jsx(
35
+ Checkbox,
36
+ {
37
+ checked: selected,
38
+ onCheckedChange: () => onSelectToggle(),
39
+ onClick: (e) => {
40
+ e.stopPropagation();
41
+ },
42
+ "aria-label": ariaLabelSelect
43
+ }
44
+ )
45
+ }
46
+ ),
47
+ /* @__PURE__ */ jsx(
48
+ "div",
49
+ {
50
+ className: cn(
51
+ "pointer-events-none absolute inset-y-0 left-0 flex w-5 items-center justify-center transition-opacity",
52
+ showHoverAffordances ? "opacity-100" : "opacity-0 group-hover:opacity-100"
53
+ ),
54
+ children: /* @__PURE__ */ jsx(
55
+ GripVertical,
56
+ {
57
+ className: "h-3.5 w-3.5 shrink-0 text-[var(--text-tertiary)]",
58
+ "aria-hidden": "true"
59
+ }
60
+ )
61
+ }
62
+ ),
63
+ onExpandToggle ? /* @__PURE__ */ jsx(
64
+ "div",
65
+ {
66
+ className: cn(
67
+ "absolute inset-y-0 right-0 flex w-5 items-center justify-center transition-opacity",
68
+ showHoverAffordances ? "opacity-100" : "pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100"
69
+ ),
70
+ children: /* @__PURE__ */ jsx(
71
+ "button",
72
+ {
73
+ type: "button",
74
+ className: "inline-flex h-5 w-5 items-center justify-center rounded border border-[var(--border-subtle)] text-[var(--text-tertiary)] hover:bg-[var(--bg-hover)]",
75
+ onClick: (e) => {
76
+ e.stopPropagation();
77
+ onExpandToggle(e);
78
+ },
79
+ "aria-label": ariaLabelExpand,
80
+ children: /* @__PURE__ */ jsx(Expand, { className: "h-3 w-3" })
81
+ }
82
+ )
83
+ }
84
+ ) : null
85
+ ] });
86
+ }
87
+ function RowControlHeader({
88
+ checked,
89
+ onToggle,
90
+ ariaLabel = "Select all rows on page"
91
+ }) {
92
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(
93
+ Checkbox,
94
+ {
95
+ checked,
96
+ onCheckedChange: () => onToggle(),
97
+ "aria-label": ariaLabel
98
+ }
99
+ ) });
100
+ }
101
+ export {
102
+ RowControlCell,
103
+ RowControlHeader
104
+ };
@@ -0,0 +1,102 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { ArrowUp, ArrowDown, ArrowUpDown } from "lucide-react";
3
+ import { cn } from "../../lib/utils.js";
4
+ function SortIcon({
5
+ sorted,
6
+ hoverClass
7
+ }) {
8
+ if (sorted === "asc") {
9
+ return /* @__PURE__ */ jsx(ArrowUp, { className: "h-3 w-3 shrink-0 text-[var(--text-primary)]" });
10
+ }
11
+ if (sorted === "desc") {
12
+ return /* @__PURE__ */ jsx(ArrowDown, { className: "h-3 w-3 shrink-0 text-[var(--text-primary)]" });
13
+ }
14
+ return /* @__PURE__ */ jsx(
15
+ ArrowUpDown,
16
+ {
17
+ className: cn(
18
+ "h-3 w-3 shrink-0 text-[var(--text-tertiary)] opacity-0 transition-opacity",
19
+ hoverClass
20
+ )
21
+ }
22
+ );
23
+ }
24
+ function SortableHeader({
25
+ label,
26
+ primaryLabel,
27
+ secondaryLabel,
28
+ mode,
29
+ sorted,
30
+ onClick,
31
+ primarySorted,
32
+ onPrimaryClick,
33
+ secondarySorted,
34
+ onSecondaryClick,
35
+ className
36
+ }) {
37
+ const resolvedPrimaryLabel = primaryLabel ?? label ?? "";
38
+ const resolvedMode = mode ?? (secondaryLabel ? "stacked" : "single");
39
+ const isStacked = resolvedMode === "stacked";
40
+ const isDualSort = isStacked && primarySorted !== void 0;
41
+ if (isDualSort) {
42
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-0.5", className), children: [
43
+ /* @__PURE__ */ jsxs(
44
+ "button",
45
+ {
46
+ type: "button",
47
+ className: "group/primary inline-flex cursor-pointer select-none items-center gap-1 text-left",
48
+ onClick: onPrimaryClick,
49
+ children: [
50
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--text-primary)]", children: resolvedPrimaryLabel }),
51
+ /* @__PURE__ */ jsx(
52
+ SortIcon,
53
+ {
54
+ sorted: primarySorted,
55
+ hoverClass: "group-hover/primary:opacity-100"
56
+ }
57
+ )
58
+ ]
59
+ }
60
+ ),
61
+ /* @__PURE__ */ jsxs(
62
+ "button",
63
+ {
64
+ type: "button",
65
+ className: "group/secondary inline-flex cursor-pointer select-none items-center gap-1 text-left",
66
+ onClick: onSecondaryClick,
67
+ children: [
68
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-[0.06em] text-[var(--text-tertiary)]", children: secondaryLabel }),
69
+ /* @__PURE__ */ jsx(
70
+ SortIcon,
71
+ {
72
+ sorted: secondarySorted,
73
+ hoverClass: "group-hover/secondary:opacity-100"
74
+ }
75
+ )
76
+ ]
77
+ }
78
+ )
79
+ ] });
80
+ }
81
+ return /* @__PURE__ */ jsxs(
82
+ "button",
83
+ {
84
+ type: "button",
85
+ className: cn(
86
+ "group/header inline-flex cursor-pointer select-none items-start gap-1.5 text-left",
87
+ className
88
+ ),
89
+ onClick,
90
+ children: [
91
+ isStacked ? /* @__PURE__ */ jsxs("span", { className: "flex flex-col leading-none", children: [
92
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--text-primary)]", children: resolvedPrimaryLabel }),
93
+ /* @__PURE__ */ jsx("span", { className: "mt-1 text-[10px] font-medium uppercase tracking-[0.06em] text-[var(--text-tertiary)]", children: secondaryLabel })
94
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-[var(--text-primary)]", children: resolvedPrimaryLabel }),
95
+ /* @__PURE__ */ jsx(SortIcon, { sorted, hoverClass: "group-hover/header:opacity-100" })
96
+ ]
97
+ }
98
+ );
99
+ }
100
+ export {
101
+ SortableHeader
102
+ };
@@ -0,0 +1,132 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { ChevronLeft, ChevronRight } from "lucide-react";
3
+ import { Button } from "../ui/button.js";
4
+ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "../ui/select.js";
5
+ const defaultRowsPerPageOptions = [15, 30, 60, 100];
6
+ function TableFooter(props) {
7
+ const {
8
+ selectedCount,
9
+ totalCount,
10
+ onSelectAll,
11
+ onClearSelection,
12
+ bulkActions
13
+ } = props;
14
+ const summaryLabel = selectedCount > 0 ? `Selected: ${selectedCount}` : `Total: ${totalCount}`;
15
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-[64px] shrink-0 flex-col gap-3 border-t border-[var(--border-subtle)] px-6 py-3 lg:flex-row lg:items-center lg:justify-between", children: [
16
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
17
+ /* @__PURE__ */ jsx(
18
+ "span",
19
+ {
20
+ className: selectedCount > 0 ? "text-[12px] font-semibold text-[var(--text-primary)]" : "text-[12px] font-medium text-[var(--text-secondary)]",
21
+ children: summaryLabel
22
+ }
23
+ ),
24
+ selectedCount > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
25
+ /* @__PURE__ */ jsxs(
26
+ Button,
27
+ {
28
+ variant: "ghost",
29
+ size: "sm",
30
+ className: "h-7 text-[12px]",
31
+ onClick: onSelectAll,
32
+ children: [
33
+ "Select All (",
34
+ totalCount,
35
+ ")"
36
+ ]
37
+ }
38
+ ),
39
+ /* @__PURE__ */ jsx(
40
+ Button,
41
+ {
42
+ variant: "ghost",
43
+ size: "sm",
44
+ className: "h-7 text-[12px]",
45
+ onClick: onClearSelection,
46
+ children: "Clear"
47
+ }
48
+ ),
49
+ bulkActions.map((action) => /* @__PURE__ */ jsx(
50
+ Button,
51
+ {
52
+ variant: "ghost",
53
+ size: "sm",
54
+ className: `h-7 text-[12px]${action.variant === "danger" ? " text-[var(--tag-pink-text)]" : ""}`,
55
+ onClick: action.onClick,
56
+ children: action.label
57
+ },
58
+ action.label
59
+ ))
60
+ ] }) : null
61
+ ] }),
62
+ renderPagination(props)
63
+ ] });
64
+ }
65
+ function renderPagination(props) {
66
+ if (props.paginationVariant === "perPage") {
67
+ const rowsPerPageOptions = props.rowsPerPageOptions ?? defaultRowsPerPageOptions;
68
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 lg:justify-end", children: [
69
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
70
+ /* @__PURE__ */ jsx("span", { className: "text-[12px] text-[var(--text-secondary)]", children: "Rows per page" }),
71
+ /* @__PURE__ */ jsxs(
72
+ Select,
73
+ {
74
+ value: String(props.rowsPerPage),
75
+ onValueChange: (value) => props.onRowsPerPageChange(Number(value)),
76
+ children: [
77
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-[var(--size-control-sm)] w-[var(--size-select-compact)]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
78
+ /* @__PURE__ */ jsx(SelectContent, { children: rowsPerPageOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: String(option), children: option }, option)) })
79
+ ]
80
+ }
81
+ )
82
+ ] }),
83
+ renderNumericPager(props)
84
+ ] });
85
+ }
86
+ if (props.paginationVariant !== "pages") {
87
+ return null;
88
+ }
89
+ return renderNumericPager(props);
90
+ }
91
+ function renderNumericPager(props) {
92
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 lg:justify-end", children: [
93
+ /* @__PURE__ */ jsx(
94
+ Button,
95
+ {
96
+ variant: "ghost",
97
+ size: "icon",
98
+ "aria-label": "Previous page",
99
+ className: "h-7 w-7",
100
+ disabled: props.currentPage === 1,
101
+ onClick: () => props.onPageChange(props.currentPage - 1),
102
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
103
+ }
104
+ ),
105
+ props.pageNumbers.map((pageNum) => /* @__PURE__ */ jsx(
106
+ Button,
107
+ {
108
+ variant: pageNum === props.currentPage ? "default" : "ghost",
109
+ size: "sm",
110
+ className: "h-7 w-7 p-0 text-[12px]",
111
+ onClick: () => props.onPageChange(pageNum),
112
+ children: pageNum
113
+ },
114
+ pageNum
115
+ )),
116
+ /* @__PURE__ */ jsx(
117
+ Button,
118
+ {
119
+ variant: "ghost",
120
+ size: "icon",
121
+ "aria-label": "Next page",
122
+ className: "h-7 w-7",
123
+ disabled: props.currentPage === props.totalPages,
124
+ onClick: () => props.onPageChange(props.currentPage + 1),
125
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
126
+ }
127
+ )
128
+ ] });
129
+ }
130
+ export {
131
+ TableFooter
132
+ };
@@ -0,0 +1,14 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils.js";
3
+ import { useScrollActivity } from "../../hooks/use-scroll-activity.js";
4
+ function TableLayout({ children, className }) {
5
+ return /* @__PURE__ */ jsx("div", { className: cn("relative flex flex-1 flex-col overflow-hidden", className), children });
6
+ }
7
+ function ScrollArea({ children, className }) {
8
+ const scrollRef = useScrollActivity();
9
+ return /* @__PURE__ */ jsx("div", { ref: scrollRef, className: cn("scrollbar-auto-hide flex-1 overflow-auto", className), children });
10
+ }
11
+ TableLayout.ScrollArea = ScrollArea;
12
+ export {
13
+ TableLayout
14
+ };
@@ -0,0 +1,16 @@
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 TimestampCell({ value }) {
8
+ const { date, time } = splitTimestamp(value);
9
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1 text-left font-mono", children: [
10
+ /* @__PURE__ */ jsx("div", { className: "text-[13px] font-medium text-[var(--text-primary)]", children: date }),
11
+ time ? /* @__PURE__ */ jsx("div", { className: "text-[12px] text-[var(--text-secondary)]", children: time }) : null
12
+ ] });
13
+ }
14
+ export {
15
+ TimestampCell
16
+ };
@@ -0,0 +1,64 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Popover, PopoverTrigger, PopoverContent } from "../ui/popover.js";
4
+ function CategoryRow({ group, activeCount, isSelected, onClick }) {
5
+ return /* @__PURE__ */ jsxs(
6
+ "button",
7
+ {
8
+ type: "button",
9
+ onClick,
10
+ className: `flex w-full cursor-pointer items-center justify-between gap-1 rounded-md px-3 py-2 text-left text-[13px] transition-colors hover:bg-[var(--bg-hover)] ${isSelected ? "bg-[var(--bg-secondary)] font-medium" : "font-normal"}`,
11
+ children: [
12
+ /* @__PURE__ */ jsx(
13
+ "span",
14
+ {
15
+ className: `truncate leading-[1.4] ${isSelected ? "text-[var(--text-primary)]" : "text-[var(--text-secondary)]"}`,
16
+ children: group.label
17
+ }
18
+ ),
19
+ activeCount > 0 && /* @__PURE__ */ jsx("span", { className: "inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-[var(--bg-tertiary)] px-1.5 text-[11px] font-semibold tabular-nums text-[var(--text-utility)]", children: activeCount })
20
+ ]
21
+ }
22
+ );
23
+ }
24
+ function TwoPanelMenuBase({
25
+ groups,
26
+ activeCountPerGroup = {},
27
+ trigger,
28
+ width = 380,
29
+ renderRightPanel,
30
+ open,
31
+ onOpenChange
32
+ }) {
33
+ const [selectedGroupKey, setSelectedGroupKey] = useState(groups[0]?.key ?? "");
34
+ const selectedGroup = groups.find((g) => g.key === selectedGroupKey) ?? groups[0];
35
+ const handleClose = () => onOpenChange?.(false);
36
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange, children: [
37
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: trigger }),
38
+ /* @__PURE__ */ jsxs(
39
+ PopoverContent,
40
+ {
41
+ align: "start",
42
+ sideOffset: 4,
43
+ className: "flex max-h-[60vh] overflow-hidden p-0",
44
+ style: { width: `${width}px` },
45
+ children: [
46
+ /* @__PURE__ */ jsx("div", { className: "w-44 shrink-0 overflow-y-auto bg-[var(--bg-surface-muted)] p-1.5", children: groups.map((group) => /* @__PURE__ */ jsx(
47
+ CategoryRow,
48
+ {
49
+ group,
50
+ activeCount: activeCountPerGroup[group.key] ?? 0,
51
+ isSelected: group.key === selectedGroupKey,
52
+ onClick: () => setSelectedGroupKey(group.key)
53
+ },
54
+ group.key
55
+ )) }),
56
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto bg-[var(--bg-surface)]", children: selectedGroup ? renderRightPanel(selectedGroup, handleClose) : null })
57
+ ]
58
+ }
59
+ )
60
+ ] });
61
+ }
62
+ export {
63
+ TwoPanelMenuBase
64
+ };
@@ -0,0 +1,25 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../../lib/utils.js";
4
+ const ViewChip = React.forwardRef(
5
+ ({ label, active, className, ...rest }, ref) => {
6
+ return /* @__PURE__ */ jsx(
7
+ "button",
8
+ {
9
+ ref,
10
+ type: "button",
11
+ ...rest,
12
+ className: cn(
13
+ "inline-flex items-center rounded-full border px-3 py-1 text-[13px] font-medium transition-colors focus:outline-none focus:ring-1 focus:ring-[var(--border-focus)]",
14
+ active ? "border-[var(--border-brand)] bg-[var(--bg-brand-subtle)] text-[var(--text-brand)]" : "border-[var(--border-subtle)] bg-transparent text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]",
15
+ className
16
+ ),
17
+ children: label
18
+ }
19
+ );
20
+ }
21
+ );
22
+ ViewChip.displayName = "ViewChip";
23
+ export {
24
+ ViewChip
25
+ };