@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.
- package/LICENSE +21 -0
- package/README.md +262 -0
- package/dist/es/components/dashboard/ReportSummaryCard.js +67 -0
- package/dist/es/components/data-table/AppliedStateChips.js +113 -0
- package/dist/es/components/data-table/ColumnFilterPopover.js +548 -0
- package/dist/es/components/data-table/ColumnHeaderMenu.js +144 -0
- package/dist/es/components/data-table/CompoundFilterPopover.js +508 -0
- package/dist/es/components/data-table/CopyButton.js +35 -0
- package/dist/es/components/data-table/CopyableText.js +26 -0
- package/dist/es/components/data-table/DataTableShell.js +145 -0
- package/dist/es/components/data-table/DrawerActionGroup.js +59 -0
- package/dist/es/components/data-table/DrawerEntityCard.js +21 -0
- package/dist/es/components/data-table/DrawerField.js +10 -0
- package/dist/es/components/data-table/DrawerFlagItem.js +20 -0
- package/dist/es/components/data-table/DrawerSection.js +26 -0
- package/dist/es/components/data-table/DrawerShell.js +141 -0
- package/dist/es/components/data-table/DrawerSummaryCard.js +11 -0
- package/dist/es/components/data-table/EmptyState.js +14 -0
- package/dist/es/components/data-table/ExpiryTimestampCell.js +43 -0
- package/dist/es/components/data-table/FilterChip.js +47 -0
- package/dist/es/components/data-table/FilterFormPanel.js +357 -0
- package/dist/es/components/data-table/FilterFormToggle.js +77 -0
- package/dist/es/components/data-table/FilterPopoverFooter.js +19 -0
- package/dist/es/components/data-table/FilterToolbar.js +131 -0
- package/dist/es/components/data-table/FlatColumnToggle.js +46 -0
- package/dist/es/components/data-table/GapIndicator.js +29 -0
- package/dist/es/components/data-table/GroupedColumnToggle.js +112 -0
- package/dist/es/components/data-table/RowActionsMenu.js +74 -0
- package/dist/es/components/data-table/RowControlCell.js +104 -0
- package/dist/es/components/data-table/SortableHeader.js +102 -0
- package/dist/es/components/data-table/TableFooter.js +132 -0
- package/dist/es/components/data-table/TableLayout.js +14 -0
- package/dist/es/components/data-table/TimestampCell.js +16 -0
- package/dist/es/components/data-table/TwoPanelMenu.js +64 -0
- package/dist/es/components/data-table/ViewChip.js +25 -0
- package/dist/es/components/data-table/cells/AmountCell.js +127 -0
- package/dist/es/components/data-table/cells/ConfirmedAmountCell.js +115 -0
- package/dist/es/components/data-table/cells/CurrencyAmountCell.js +26 -0
- package/dist/es/components/data-table/cells/DualLineCell.js +59 -0
- package/dist/es/components/data-table/cells/EnumBadgeCell.js +9 -0
- package/dist/es/components/data-table/cells/MonoIdCell.js +31 -0
- package/dist/es/components/data-table/hooks/use-column-resize.js +39 -0
- package/dist/es/components/data-table/hooks/use-row-drag.js +40 -0
- package/dist/es/components/data-table/hooks/use-table-pagination.js +14 -0
- package/dist/es/components/data-table/hooks/use-table-sort.js +35 -0
- package/dist/es/components/data-table/managed-filters.js +34 -0
- package/dist/es/components/data-table/sticky-utils.js +25 -0
- package/dist/es/components/layout/AppShell.js +113 -0
- package/dist/es/components/layout/Sidebar.js +128 -0
- package/dist/es/components/layout/SidebarAccountMenu.js +129 -0
- package/dist/es/components/layout/SidebarUser.js +38 -0
- package/dist/es/components/layout/TopBar.js +25 -0
- package/dist/es/components/layout/app-shell-context.js +9 -0
- package/dist/es/components/ui/badge.js +31 -0
- package/dist/es/components/ui/button-footer.js +25 -0
- package/dist/es/components/ui/button.js +44 -0
- package/dist/es/components/ui/checkbox.js +24 -0
- package/dist/es/components/ui/combobox.js +179 -0
- package/dist/es/components/ui/dialog.js +80 -0
- package/dist/es/components/ui/dropdown-menu.js +66 -0
- package/dist/es/components/ui/input.js +24 -0
- package/dist/es/components/ui/popover.js +33 -0
- package/dist/es/components/ui/segmented-control.js +60 -0
- package/dist/es/components/ui/select.js +66 -0
- package/dist/es/components/ui/tabs.js +41 -0
- package/dist/es/components/ui/theme-switch.js +47 -0
- package/dist/es/constants/drawer.js +4 -0
- package/dist/es/context/drawer-expand-context.js +10 -0
- package/dist/es/context/portal-container-context.js +10 -0
- package/dist/es/hooks/table-orchestration-store.js +165 -0
- package/dist/es/hooks/use-scroll-activity.js +33 -0
- package/dist/es/hooks/useRowDragOverride.js +18 -0
- package/dist/es/hooks/useTableOrchestration.js +452 -0
- package/dist/es/index.js +199 -0
- package/dist/es/lib/column-gaps.js +23 -0
- package/dist/es/lib/filter-stats.js +67 -0
- package/dist/es/lib/format-enum.js +6 -0
- package/dist/es/lib/format-timestamp.js +37 -0
- package/dist/es/lib/style-scope.js +4 -0
- package/dist/es/lib/utils.js +8 -0
- package/dist/fonts.css +5 -0
- package/dist/preflight.css +502 -0
- package/dist/styles.css +1731 -0
- package/dist/tablewright.cjs +5473 -0
- package/dist/tablewright.css +1579 -0
- package/dist/tokens.css +150 -0
- package/dist/types/components/dashboard/ReportSummaryCard.d.ts +15 -0
- package/dist/types/components/data-table/AppliedStateChips.d.ts +28 -0
- package/dist/types/components/data-table/ColumnFilterPopover.d.ts +14 -0
- package/dist/types/components/data-table/ColumnHeaderMenu.d.ts +27 -0
- package/dist/types/components/data-table/CompoundFilterPopover.d.ts +14 -0
- package/dist/types/components/data-table/CopyButton.d.ts +8 -0
- package/dist/types/components/data-table/CopyableText.d.ts +10 -0
- package/dist/types/components/data-table/DataTableShell.d.ts +30 -0
- package/dist/types/components/data-table/DrawerActionGroup.d.ts +8 -0
- package/dist/types/components/data-table/DrawerEntityCard.d.ts +13 -0
- package/dist/types/components/data-table/DrawerField.d.ts +7 -0
- package/dist/types/components/data-table/DrawerFlagItem.d.ts +10 -0
- package/dist/types/components/data-table/DrawerSection.d.ts +8 -0
- package/dist/types/components/data-table/DrawerShell.d.ts +33 -0
- package/dist/types/components/data-table/DrawerSummaryCard.d.ts +7 -0
- package/dist/types/components/data-table/EmptyState.d.ts +6 -0
- package/dist/types/components/data-table/ExpiryTimestampCell.d.ts +6 -0
- package/dist/types/components/data-table/FilterChip.d.ts +8 -0
- package/dist/types/components/data-table/FilterFormPanel.d.ts +34 -0
- package/dist/types/components/data-table/FilterFormToggle.d.ts +18 -0
- package/dist/types/components/data-table/FilterPopoverFooter.d.ts +9 -0
- package/dist/types/components/data-table/FilterToolbar.d.ts +29 -0
- package/dist/types/components/data-table/FlatColumnToggle.d.ts +10 -0
- package/dist/types/components/data-table/GapIndicator.d.ts +11 -0
- package/dist/types/components/data-table/GroupedColumnToggle.d.ts +12 -0
- package/dist/types/components/data-table/RowActionsMenu.d.ts +10 -0
- package/dist/types/components/data-table/RowControlCell.d.ts +16 -0
- package/dist/types/components/data-table/SortableHeader.d.ts +16 -0
- package/dist/types/components/data-table/TableFooter.d.ts +31 -0
- package/dist/types/components/data-table/TableLayout.d.ts +12 -0
- package/dist/types/components/data-table/TimestampCell.d.ts +3 -0
- package/dist/types/components/data-table/TwoPanelMenu.d.ts +22 -0
- package/dist/types/components/data-table/ViewChip.d.ts +6 -0
- package/dist/types/components/data-table/cells/AmountCell.d.ts +11 -0
- package/dist/types/components/data-table/cells/ConfirmedAmountCell.d.ts +10 -0
- package/dist/types/components/data-table/cells/CurrencyAmountCell.d.ts +8 -0
- package/dist/types/components/data-table/cells/DualLineCell.d.ts +44 -0
- package/dist/types/components/data-table/cells/EnumBadgeCell.d.ts +9 -0
- package/dist/types/components/data-table/cells/MonoIdCell.d.ts +19 -0
- package/dist/types/components/data-table/filter-types.d.ts +79 -0
- package/dist/types/components/data-table/hooks/use-column-resize.d.ts +7 -0
- package/dist/types/components/data-table/hooks/use-row-drag.d.ts +14 -0
- package/dist/types/components/data-table/hooks/use-table-pagination.d.ts +10 -0
- package/dist/types/components/data-table/hooks/use-table-sort.d.ts +6 -0
- package/dist/types/components/data-table/managed-filters.d.ts +18 -0
- package/dist/types/components/data-table/sticky-utils.d.ts +4 -0
- package/dist/types/components/data-table/types.d.ts +35 -0
- package/dist/types/components/layout/AppShell.d.ts +23 -0
- package/dist/types/components/layout/Sidebar.d.ts +16 -0
- package/dist/types/components/layout/SidebarAccountMenu.d.ts +20 -0
- package/dist/types/components/layout/SidebarUser.d.ts +8 -0
- package/dist/types/components/layout/TopBar.d.ts +7 -0
- package/dist/types/components/layout/app-shell-context.d.ts +8 -0
- package/dist/types/components/layout/index.d.ts +10 -0
- package/dist/types/components/layout/types.d.ts +11 -0
- package/dist/types/components/ui/badge.d.ts +9 -0
- package/dist/types/components/ui/button-footer.d.ts +7 -0
- package/dist/types/components/ui/button.d.ts +11 -0
- package/dist/types/components/ui/checkbox.d.ts +4 -0
- package/dist/types/components/ui/combobox.d.ts +92 -0
- package/dist/types/components/ui/dialog.d.ts +15 -0
- package/dist/types/components/ui/dropdown-menu.d.ts +10 -0
- package/dist/types/components/ui/input.d.ts +6 -0
- package/dist/types/components/ui/popover.d.ts +7 -0
- package/dist/types/components/ui/segmented-control.d.ts +17 -0
- package/dist/types/components/ui/select.d.ts +8 -0
- package/dist/types/components/ui/tabs.d.ts +10 -0
- package/dist/types/components/ui/theme-switch.d.ts +12 -0
- package/dist/types/constants/drawer.d.ts +1 -0
- package/dist/types/context/drawer-expand-context.d.ts +7 -0
- package/dist/types/context/portal-container-context.d.ts +14 -0
- package/dist/types/hooks/table-orchestration-store.d.ts +75 -0
- package/dist/types/hooks/use-scroll-activity.d.ts +1 -0
- package/dist/types/hooks/useDemoTheme.d.ts +8 -0
- package/dist/types/hooks/useRowDragOverride.d.ts +6 -0
- package/dist/types/hooks/useTableOrchestration.d.ts +115 -0
- package/dist/types/index.d.ts +107 -0
- package/dist/types/lib/column-gaps.d.ts +3 -0
- package/dist/types/lib/filter-stats.d.ts +2 -0
- package/dist/types/lib/format-enum.d.ts +1 -0
- package/dist/types/lib/format-timestamp.d.ts +4 -0
- package/dist/types/lib/style-scope.d.ts +19 -0
- package/dist/types/lib/utils.d.ts +2 -0
- package/package.json +114 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { AlertTriangle } from "lucide-react";
|
|
3
|
+
import { CopyableText } from "../CopyableText.js";
|
|
4
|
+
const fmtIn = (v) => v.toLocaleString("en-US");
|
|
5
|
+
const fmtOut = (v) => v.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
6
|
+
function AmountCell({
|
|
7
|
+
inAmount,
|
|
8
|
+
inCurrency,
|
|
9
|
+
outAmount,
|
|
10
|
+
outCurrency,
|
|
11
|
+
inAmountConfirmed,
|
|
12
|
+
outAmountConfirmed,
|
|
13
|
+
mutedCurrency
|
|
14
|
+
}) {
|
|
15
|
+
const inMismatch = inAmountConfirmed !== void 0 && inAmountConfirmed > 0 && inAmountConfirmed !== inAmount;
|
|
16
|
+
const outMismatch = outAmountConfirmed !== void 0 && outAmountConfirmed > 0 && outAmountConfirmed !== outAmount;
|
|
17
|
+
const inCurrencyEl = mutedCurrency ? /* @__PURE__ */ jsx("span", { className: "text-[var(--text-secondary)] font-normal", children: inCurrency }) : inCurrency;
|
|
18
|
+
const outCurrencyEl = mutedCurrency ? /* @__PURE__ */ jsx("span", { className: "text-[var(--text-secondary)] font-normal", children: outCurrency }) : outCurrency;
|
|
19
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
20
|
+
inMismatch && inAmountConfirmed !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
21
|
+
/* @__PURE__ */ jsxs(
|
|
22
|
+
CopyableText,
|
|
23
|
+
{
|
|
24
|
+
value: String(inAmountConfirmed),
|
|
25
|
+
title: "Copy in amount confirmed",
|
|
26
|
+
className: "w-full",
|
|
27
|
+
textClassName: "text-[13px] font-semibold text-[var(--text-primary)]",
|
|
28
|
+
children: [
|
|
29
|
+
/* @__PURE__ */ jsx(
|
|
30
|
+
AlertTriangle,
|
|
31
|
+
{
|
|
32
|
+
className: "inline h-3 w-3 mr-0.5 text-[var(--tag-orange-text)]",
|
|
33
|
+
"aria-hidden": true
|
|
34
|
+
}
|
|
35
|
+
),
|
|
36
|
+
fmtIn(inAmountConfirmed),
|
|
37
|
+
" ",
|
|
38
|
+
inCurrencyEl
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
),
|
|
42
|
+
/* @__PURE__ */ jsxs(
|
|
43
|
+
CopyableText,
|
|
44
|
+
{
|
|
45
|
+
value: String(inAmount),
|
|
46
|
+
title: "Copy in amount",
|
|
47
|
+
className: "w-full",
|
|
48
|
+
textClassName: "text-[12px] font-mono text-[var(--text-secondary)] line-through",
|
|
49
|
+
children: [
|
|
50
|
+
fmtIn(inAmount),
|
|
51
|
+
" ",
|
|
52
|
+
inCurrencyEl
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
] }) : /* @__PURE__ */ jsxs(
|
|
57
|
+
CopyableText,
|
|
58
|
+
{
|
|
59
|
+
value: String(inAmount),
|
|
60
|
+
title: "Copy in amount",
|
|
61
|
+
className: "w-full",
|
|
62
|
+
textClassName: "text-[13px] font-semibold text-[var(--text-primary)]",
|
|
63
|
+
children: [
|
|
64
|
+
fmtIn(inAmount),
|
|
65
|
+
" ",
|
|
66
|
+
inCurrencyEl
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
outMismatch && outAmountConfirmed !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
71
|
+
/* @__PURE__ */ jsxs(
|
|
72
|
+
CopyableText,
|
|
73
|
+
{
|
|
74
|
+
value: String(outAmountConfirmed),
|
|
75
|
+
title: "Copy out amount confirmed",
|
|
76
|
+
className: "w-full",
|
|
77
|
+
textClassName: "text-[12px] font-mono text-[var(--text-primary)]",
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ jsx(
|
|
80
|
+
AlertTriangle,
|
|
81
|
+
{
|
|
82
|
+
className: "inline h-3 w-3 mr-0.5 text-[var(--tag-orange-text)]",
|
|
83
|
+
"aria-hidden": true
|
|
84
|
+
}
|
|
85
|
+
),
|
|
86
|
+
"→ ",
|
|
87
|
+
fmtOut(outAmountConfirmed),
|
|
88
|
+
" ",
|
|
89
|
+
outCurrencyEl
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
/* @__PURE__ */ jsxs(
|
|
94
|
+
CopyableText,
|
|
95
|
+
{
|
|
96
|
+
value: String(outAmount),
|
|
97
|
+
title: "Copy out amount",
|
|
98
|
+
className: "w-full",
|
|
99
|
+
textClassName: "text-[12px] font-mono text-[var(--text-secondary)] line-through",
|
|
100
|
+
children: [
|
|
101
|
+
"→ ",
|
|
102
|
+
fmtOut(outAmount),
|
|
103
|
+
" ",
|
|
104
|
+
outCurrencyEl
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
] }) : /* @__PURE__ */ jsxs(
|
|
109
|
+
CopyableText,
|
|
110
|
+
{
|
|
111
|
+
value: String(outAmount),
|
|
112
|
+
title: "Copy out amount",
|
|
113
|
+
className: "w-full",
|
|
114
|
+
textClassName: "text-[12px] font-mono text-[var(--text-secondary)]",
|
|
115
|
+
children: [
|
|
116
|
+
"→ ",
|
|
117
|
+
fmtOut(outAmount),
|
|
118
|
+
" ",
|
|
119
|
+
outCurrencyEl
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
] });
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
AmountCell
|
|
127
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { CircleDashed, Check, AlertTriangle } from "lucide-react";
|
|
3
|
+
import { CopyableText } from "../CopyableText.js";
|
|
4
|
+
const fmt = (v) => v.toLocaleString("en-US");
|
|
5
|
+
function ConfirmedAmountCell({
|
|
6
|
+
value,
|
|
7
|
+
currency,
|
|
8
|
+
confirmedValue,
|
|
9
|
+
copyTitle = "Copy",
|
|
10
|
+
confirmedCopyTitle = "Copy confirmed",
|
|
11
|
+
mutedCurrency
|
|
12
|
+
}) {
|
|
13
|
+
const primaryCurrency = mutedCurrency ? /* @__PURE__ */ jsx("span", { className: "text-[var(--text-secondary)] font-normal", children: currency }) : currency;
|
|
14
|
+
const secondaryCurrency = mutedCurrency ? /* @__PURE__ */ jsx("span", { className: "text-[var(--text-secondary)] font-normal", children: currency }) : currency;
|
|
15
|
+
if (confirmedValue === void 0 || confirmedValue === null) {
|
|
16
|
+
return /* @__PURE__ */ jsxs(
|
|
17
|
+
CopyableText,
|
|
18
|
+
{
|
|
19
|
+
value: String(value),
|
|
20
|
+
title: copyTitle,
|
|
21
|
+
className: "w-full",
|
|
22
|
+
textClassName: "text-[13px] font-semibold text-[var(--text-primary)]",
|
|
23
|
+
children: [
|
|
24
|
+
fmt(value),
|
|
25
|
+
" ",
|
|
26
|
+
primaryCurrency
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
if (confirmedValue === 0 && value > 0) {
|
|
32
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
33
|
+
/* @__PURE__ */ jsxs(
|
|
34
|
+
CopyableText,
|
|
35
|
+
{
|
|
36
|
+
value: String(value),
|
|
37
|
+
title: copyTitle,
|
|
38
|
+
className: "w-full",
|
|
39
|
+
textClassName: "text-[13px] font-semibold text-[var(--text-primary)]",
|
|
40
|
+
children: [
|
|
41
|
+
fmt(value),
|
|
42
|
+
" ",
|
|
43
|
+
primaryCurrency
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
),
|
|
47
|
+
/* @__PURE__ */ jsx(
|
|
48
|
+
"div",
|
|
49
|
+
{
|
|
50
|
+
className: "text-[11px] text-[var(--text-secondary)]",
|
|
51
|
+
title: "Not confirmed",
|
|
52
|
+
"aria-label": "Not confirmed",
|
|
53
|
+
children: /* @__PURE__ */ jsx(CircleDashed, { className: "inline h-3 w-3", "aria-hidden": true })
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
] });
|
|
57
|
+
}
|
|
58
|
+
if (confirmedValue === value) {
|
|
59
|
+
return /* @__PURE__ */ jsxs(
|
|
60
|
+
CopyableText,
|
|
61
|
+
{
|
|
62
|
+
value: String(value),
|
|
63
|
+
title: copyTitle,
|
|
64
|
+
className: "w-full",
|
|
65
|
+
textClassName: "text-[13px] font-semibold text-[var(--text-primary)]",
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ jsx(Check, { className: "inline h-3 w-3 mr-0.5 text-[var(--text-tertiary)]", "aria-hidden": true }),
|
|
68
|
+
fmt(value),
|
|
69
|
+
" ",
|
|
70
|
+
primaryCurrency
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
76
|
+
/* @__PURE__ */ jsxs(
|
|
77
|
+
CopyableText,
|
|
78
|
+
{
|
|
79
|
+
value: String(confirmedValue),
|
|
80
|
+
title: confirmedCopyTitle,
|
|
81
|
+
className: "w-full",
|
|
82
|
+
textClassName: "text-[13px] font-semibold text-[var(--text-primary)]",
|
|
83
|
+
children: [
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
AlertTriangle,
|
|
86
|
+
{
|
|
87
|
+
className: "inline h-3 w-3 mr-0.5 text-[var(--tag-orange-text)]",
|
|
88
|
+
"aria-hidden": true
|
|
89
|
+
}
|
|
90
|
+
),
|
|
91
|
+
fmt(confirmedValue),
|
|
92
|
+
" ",
|
|
93
|
+
primaryCurrency
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
),
|
|
97
|
+
/* @__PURE__ */ jsxs(
|
|
98
|
+
CopyableText,
|
|
99
|
+
{
|
|
100
|
+
value: String(value),
|
|
101
|
+
title: copyTitle,
|
|
102
|
+
className: "w-full",
|
|
103
|
+
textClassName: "text-[12px] font-mono text-[var(--text-secondary)] line-through",
|
|
104
|
+
children: [
|
|
105
|
+
fmt(value),
|
|
106
|
+
" ",
|
|
107
|
+
secondaryCurrency
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
113
|
+
export {
|
|
114
|
+
ConfirmedAmountCell
|
|
115
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { CopyableText } from "../CopyableText.js";
|
|
3
|
+
function CurrencyAmountCell({
|
|
4
|
+
value,
|
|
5
|
+
currency,
|
|
6
|
+
copyTitle = "Copy",
|
|
7
|
+
mutedCurrency
|
|
8
|
+
}) {
|
|
9
|
+
return /* @__PURE__ */ jsxs(
|
|
10
|
+
CopyableText,
|
|
11
|
+
{
|
|
12
|
+
value: String(value),
|
|
13
|
+
title: copyTitle,
|
|
14
|
+
className: "w-full",
|
|
15
|
+
textClassName: "text-[13px] font-semibold text-[var(--text-primary)]",
|
|
16
|
+
children: [
|
|
17
|
+
value.toLocaleString("en-US"),
|
|
18
|
+
" ",
|
|
19
|
+
mutedCurrency ? /* @__PURE__ */ jsx("span", { className: "text-[var(--text-secondary)] font-normal", children: currency }) : currency
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
CurrencyAmountCell
|
|
26
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { CopyableText } from "../CopyableText.js";
|
|
3
|
+
import { truncateMiddle } from "./MonoIdCell.js";
|
|
4
|
+
function applyMiddleTruncate(value, config) {
|
|
5
|
+
if (!config) return value;
|
|
6
|
+
const head = typeof config === "object" ? config.head ?? 6 : 6;
|
|
7
|
+
const tail = typeof config === "object" ? config.tail ?? 6 : 6;
|
|
8
|
+
return truncateMiddle(value, head, tail, head + tail + 2);
|
|
9
|
+
}
|
|
10
|
+
function DualLineCell({
|
|
11
|
+
primary,
|
|
12
|
+
secondary,
|
|
13
|
+
primaryCopyTitle = "Copy",
|
|
14
|
+
secondaryCopyTitle = "Copy",
|
|
15
|
+
primaryVariant = "default",
|
|
16
|
+
primaryLabel,
|
|
17
|
+
secondaryLabel,
|
|
18
|
+
equalWeight = false,
|
|
19
|
+
primaryTruncateMiddle,
|
|
20
|
+
secondaryTruncateMiddle
|
|
21
|
+
}) {
|
|
22
|
+
const primaryTextClass = primaryVariant === "mono" ? "font-mono text-[11px]" : "font-semibold text-[var(--text-primary)]";
|
|
23
|
+
const secondaryColour = equalWeight ? "text-[var(--text-primary)]" : "text-[var(--text-secondary)]";
|
|
24
|
+
const primaryDisplay = primaryVariant === "mono" ? applyMiddleTruncate(primary, primaryTruncateMiddle) : primary;
|
|
25
|
+
const secondaryDisplay = applyMiddleTruncate(secondary, secondaryTruncateMiddle);
|
|
26
|
+
const primaryContent = primaryLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
27
|
+
/* @__PURE__ */ jsx("span", { className: "mr-1 text-[10px] text-[var(--text-secondary)]", children: primaryLabel }),
|
|
28
|
+
/* @__PURE__ */ jsx("span", { title: primary, children: primaryDisplay })
|
|
29
|
+
] }) : /* @__PURE__ */ jsx("span", { title: primary, children: primaryDisplay });
|
|
30
|
+
const secondaryContent = secondaryLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
31
|
+
/* @__PURE__ */ jsx("span", { className: "mr-1 text-[10px] text-[var(--text-secondary)]", children: secondaryLabel }),
|
|
32
|
+
/* @__PURE__ */ jsx("span", { title: secondary, children: secondaryDisplay })
|
|
33
|
+
] }) : /* @__PURE__ */ jsx("span", { title: secondary, children: secondaryDisplay });
|
|
34
|
+
return /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1", children: [
|
|
35
|
+
/* @__PURE__ */ jsx(
|
|
36
|
+
CopyableText,
|
|
37
|
+
{
|
|
38
|
+
value: primary,
|
|
39
|
+
title: primaryCopyTitle,
|
|
40
|
+
className: "w-full",
|
|
41
|
+
textClassName: primaryTextClass,
|
|
42
|
+
children: primaryContent
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ jsx(
|
|
46
|
+
CopyableText,
|
|
47
|
+
{
|
|
48
|
+
value: secondary,
|
|
49
|
+
title: secondaryCopyTitle,
|
|
50
|
+
className: "w-full",
|
|
51
|
+
textClassName: `font-mono text-[11px] ${secondaryColour}`,
|
|
52
|
+
children: secondaryContent
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
] });
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
DualLineCell
|
|
59
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Badge } from "../../ui/badge.js";
|
|
3
|
+
import { formatEnumLabel } from "../../../lib/format-enum.js";
|
|
4
|
+
function EnumBadgeCell({ value, variantMap, label, className }) {
|
|
5
|
+
return /* @__PURE__ */ jsx(Badge, { variant: variantMap[value], className, children: label ?? formatEnumLabel(value) });
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
EnumBadgeCell
|
|
9
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { CopyableText } from "../CopyableText.js";
|
|
3
|
+
function truncateMiddle(value, head, tail, threshold) {
|
|
4
|
+
if (value.length < threshold) return value;
|
|
5
|
+
return `${value.slice(0, head)}…${value.slice(-tail)}`;
|
|
6
|
+
}
|
|
7
|
+
function MonoIdCell({
|
|
8
|
+
value,
|
|
9
|
+
copyTitle = "Copy",
|
|
10
|
+
truncate = true,
|
|
11
|
+
truncateHead = 6,
|
|
12
|
+
truncateTail = 6,
|
|
13
|
+
truncateThreshold
|
|
14
|
+
}) {
|
|
15
|
+
const threshold = truncateThreshold ?? truncateHead + truncateTail + 2;
|
|
16
|
+
const display = truncate ? truncateMiddle(value, truncateHead, truncateTail, threshold) : value;
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
18
|
+
CopyableText,
|
|
19
|
+
{
|
|
20
|
+
value,
|
|
21
|
+
title: copyTitle,
|
|
22
|
+
className: "w-full",
|
|
23
|
+
textClassName: "font-mono text-[11px]",
|
|
24
|
+
children: /* @__PURE__ */ jsx("span", { title: value, children: display })
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
MonoIdCell,
|
|
30
|
+
truncateMiddle
|
|
31
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useState, useRef, useCallback, useMemo } from "react";
|
|
2
|
+
function useColumnResize(defaults, initialWidths) {
|
|
3
|
+
const [widths, setWidths] = useState(() => {
|
|
4
|
+
const w = {};
|
|
5
|
+
for (const [id, m] of Object.entries(defaults)) w[id] = m.minW;
|
|
6
|
+
return initialWidths ? { ...w, ...initialWidths } : w;
|
|
7
|
+
});
|
|
8
|
+
const resizing = useRef(null);
|
|
9
|
+
const onPointerDown = useCallback(
|
|
10
|
+
(colId, e) => {
|
|
11
|
+
e.preventDefault();
|
|
12
|
+
e.stopPropagation();
|
|
13
|
+
resizing.current = { colId, startX: e.clientX, startW: widths[colId] ?? defaults[colId]?.minW ?? 100 };
|
|
14
|
+
const onMove = (ev) => {
|
|
15
|
+
if (!resizing.current) return;
|
|
16
|
+
const { colId: resizingColId, startX, startW } = resizing.current;
|
|
17
|
+
const diff = ev.clientX - startX;
|
|
18
|
+
const newW = Math.max(36, startW + diff);
|
|
19
|
+
setWidths((prev) => ({ ...prev, [resizingColId]: newW }));
|
|
20
|
+
};
|
|
21
|
+
const onUp = () => {
|
|
22
|
+
resizing.current = null;
|
|
23
|
+
document.removeEventListener("pointermove", onMove);
|
|
24
|
+
document.removeEventListener("pointerup", onUp);
|
|
25
|
+
};
|
|
26
|
+
document.addEventListener("pointermove", onMove);
|
|
27
|
+
document.addEventListener("pointerup", onUp);
|
|
28
|
+
},
|
|
29
|
+
[widths, defaults]
|
|
30
|
+
);
|
|
31
|
+
const totalWidth = useMemo(
|
|
32
|
+
() => Object.values(widths).reduce((s, w) => s + w, 0),
|
|
33
|
+
[widths]
|
|
34
|
+
);
|
|
35
|
+
return { widths, totalWidth, onPointerDown, setWidths };
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
useColumnResize
|
|
39
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
function useRowDrag(source, onReorder) {
|
|
3
|
+
const [dragRowIdx, setDragRowIdx] = useState(null);
|
|
4
|
+
const [dropTargetIdx, setDropTargetIdx] = useState(null);
|
|
5
|
+
function getDragProps(rowIndex) {
|
|
6
|
+
return {
|
|
7
|
+
draggable: true,
|
|
8
|
+
onDragStart: (e) => {
|
|
9
|
+
setDragRowIdx(rowIndex);
|
|
10
|
+
e.dataTransfer.effectAllowed = "move";
|
|
11
|
+
e.dataTransfer.setData("text/plain", "");
|
|
12
|
+
},
|
|
13
|
+
onDragOver: (e) => {
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
e.dataTransfer.dropEffect = "move";
|
|
16
|
+
setDropTargetIdx(rowIndex);
|
|
17
|
+
},
|
|
18
|
+
onDragLeave: () => setDropTargetIdx(null),
|
|
19
|
+
onDrop: (e) => {
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
if (dragRowIdx !== null && dragRowIdx !== rowIndex) {
|
|
22
|
+
const items = [...source];
|
|
23
|
+
const [moved] = items.splice(dragRowIdx, 1);
|
|
24
|
+
items.splice(rowIndex, 0, moved);
|
|
25
|
+
onReorder(items);
|
|
26
|
+
}
|
|
27
|
+
setDragRowIdx(null);
|
|
28
|
+
setDropTargetIdx(null);
|
|
29
|
+
},
|
|
30
|
+
onDragEnd: () => {
|
|
31
|
+
setDragRowIdx(null);
|
|
32
|
+
setDropTargetIdx(null);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return { dragRowIdx, dropTargetIdx, getDragProps };
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
useRowDrag
|
|
40
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "react";
|
|
2
|
+
function getVisiblePageNumbers(currentPage, totalPages, maxVisible = 5) {
|
|
3
|
+
const pages = [];
|
|
4
|
+
let start = Math.max(1, currentPage - Math.floor(maxVisible / 2));
|
|
5
|
+
const end = Math.min(totalPages, start + maxVisible - 1);
|
|
6
|
+
start = Math.max(1, end - maxVisible + 1);
|
|
7
|
+
for (let i = start; i <= end; i += 1) {
|
|
8
|
+
pages.push(i);
|
|
9
|
+
}
|
|
10
|
+
return pages;
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
getVisiblePageNumbers
|
|
14
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useState, useCallback } from "react";
|
|
2
|
+
function useTableSort(onSortChange) {
|
|
3
|
+
const [sortState, setSortState] = useState({});
|
|
4
|
+
const toggleSort = useCallback((columnId) => {
|
|
5
|
+
setSortState((prev) => {
|
|
6
|
+
const current = prev[columnId] ?? false;
|
|
7
|
+
const next = current === false ? "asc" : current === "asc" ? "desc" : false;
|
|
8
|
+
const reset = {};
|
|
9
|
+
for (const k of Object.keys(prev)) reset[k] = false;
|
|
10
|
+
reset[columnId] = next;
|
|
11
|
+
return reset;
|
|
12
|
+
});
|
|
13
|
+
onSortChange?.();
|
|
14
|
+
}, [onSortChange]);
|
|
15
|
+
const applySorting = useCallback(
|
|
16
|
+
(items, getSortValue) => {
|
|
17
|
+
const activeSortCol = Object.entries(sortState).find(([, dir2]) => dir2 !== false);
|
|
18
|
+
if (!activeSortCol) return items;
|
|
19
|
+
const [col, dir] = activeSortCol;
|
|
20
|
+
const sorted = [...items];
|
|
21
|
+
sorted.sort((a, b) => {
|
|
22
|
+
const va = getSortValue(a, col);
|
|
23
|
+
const vb = getSortValue(b, col);
|
|
24
|
+
const cmp = va < vb ? -1 : va > vb ? 1 : 0;
|
|
25
|
+
return dir === "asc" ? cmp : -cmp;
|
|
26
|
+
});
|
|
27
|
+
return sorted;
|
|
28
|
+
},
|
|
29
|
+
[sortState]
|
|
30
|
+
);
|
|
31
|
+
return { sortState, toggleSort, applySorting };
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
useTableSort
|
|
35
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function applyManagedChanges(orch, changes) {
|
|
2
|
+
const activeIds = new Set(orch.columnFilters.map((f) => f.columnId));
|
|
3
|
+
for (const change of changes) {
|
|
4
|
+
if (change.action === "remove") {
|
|
5
|
+
if (activeIds.has(change.columnId)) orch.handleRemoveColumnFilter(change.columnId);
|
|
6
|
+
continue;
|
|
7
|
+
}
|
|
8
|
+
orch.handleSetColumnFilter(change.columnId, change.value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function clearManagedFilters(orch, managedColumnIds) {
|
|
12
|
+
const activeIds = new Set(orch.columnFilters.map((f) => f.columnId));
|
|
13
|
+
for (const id of managedColumnIds) {
|
|
14
|
+
if (activeIds.has(id)) orch.handleRemoveColumnFilter(id);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function isFilterValueEmpty(v) {
|
|
18
|
+
if (v === void 0) return true;
|
|
19
|
+
if (Array.isArray(v)) return v.length === 0 || v.every((x) => x === "" || x == null);
|
|
20
|
+
if (typeof v === "string") return v.length === 0;
|
|
21
|
+
if (typeof v === "object" && v !== null) {
|
|
22
|
+
return Object.values(v).every((x) => isFilterValueEmpty(x));
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
function hasActiveManagedFilters(filters, managedFieldIds) {
|
|
27
|
+
const managed = new Set(managedFieldIds);
|
|
28
|
+
return filters.some((f) => managed.has(f.columnId) && !isFilterValueEmpty(f.value));
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
applyManagedChanges,
|
|
32
|
+
clearManagedFilters,
|
|
33
|
+
hasActiveManagedFilters
|
|
34
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function stickyStyle(meta, isHeader) {
|
|
2
|
+
if (isHeader) {
|
|
3
|
+
return {
|
|
4
|
+
position: "sticky",
|
|
5
|
+
top: 0,
|
|
6
|
+
zIndex: meta?.sticky ? 30 : 10,
|
|
7
|
+
...meta?.sticky ? { [meta.sticky]: meta.stickyOffset ?? 0 } : {}
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
if (!meta?.sticky) return void 0;
|
|
11
|
+
return {
|
|
12
|
+
position: "sticky",
|
|
13
|
+
[meta.sticky]: meta.stickyOffset ?? 0,
|
|
14
|
+
zIndex: 20
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function stickyBorderClass(meta) {
|
|
18
|
+
const edge = meta?.borderEdge !== void 0 ? meta.borderEdge : meta?.sticky === "left" ? "right" : meta?.sticky === "right" ? "left" : null;
|
|
19
|
+
if (!edge) return "";
|
|
20
|
+
return edge === "right" ? "[box-shadow:1px_0_0_0_var(--border-subtle)]" : "[box-shadow:-1px_0_0_0_var(--border-subtle)]";
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
stickyBorderClass,
|
|
24
|
+
stickyStyle
|
|
25
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import { AppShellContext } from "./app-shell-context.js";
|
|
5
|
+
import { Sidebar } from "./Sidebar.js";
|
|
6
|
+
import { TopBar } from "./TopBar.js";
|
|
7
|
+
const HOVER_DELAY = 200;
|
|
8
|
+
function AppShellRoot({
|
|
9
|
+
collapsed: controlledCollapsed,
|
|
10
|
+
defaultCollapsed = false,
|
|
11
|
+
onCollapsedChange: onCollapsedChangeProp,
|
|
12
|
+
children,
|
|
13
|
+
className
|
|
14
|
+
}) {
|
|
15
|
+
const isControlled = controlledCollapsed !== void 0;
|
|
16
|
+
const [internalCollapsed, setInternalCollapsed] = React.useState(defaultCollapsed);
|
|
17
|
+
const collapsed = isControlled ? controlledCollapsed : internalCollapsed;
|
|
18
|
+
const [hovering, setHovering] = React.useState(false);
|
|
19
|
+
const hoverTimerRef = React.useRef(
|
|
20
|
+
null
|
|
21
|
+
);
|
|
22
|
+
const onCollapsedChange = React.useCallback(
|
|
23
|
+
(next) => {
|
|
24
|
+
if (!isControlled) setInternalCollapsed(next);
|
|
25
|
+
onCollapsedChangeProp?.(next);
|
|
26
|
+
},
|
|
27
|
+
[isControlled, onCollapsedChangeProp]
|
|
28
|
+
);
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
function handleKeyDown(e) {
|
|
31
|
+
if (e.key === "b" && (e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
|
32
|
+
const tag = e.target?.tagName;
|
|
33
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
|
|
34
|
+
if (e.target?.isContentEditable) return;
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
onCollapsedChange(!collapsed);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
40
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
41
|
+
}, [collapsed, onCollapsedChange]);
|
|
42
|
+
const handleMouseEnter = React.useCallback(() => {
|
|
43
|
+
if (!collapsed) return;
|
|
44
|
+
hoverTimerRef.current = setTimeout(() => setHovering(true), HOVER_DELAY);
|
|
45
|
+
}, [collapsed]);
|
|
46
|
+
const handleMouseLeave = React.useCallback(() => {
|
|
47
|
+
if (hoverTimerRef.current) {
|
|
48
|
+
clearTimeout(hoverTimerRef.current);
|
|
49
|
+
hoverTimerRef.current = null;
|
|
50
|
+
}
|
|
51
|
+
setHovering(false);
|
|
52
|
+
}, []);
|
|
53
|
+
React.useEffect(() => {
|
|
54
|
+
if (!collapsed) setHovering(false);
|
|
55
|
+
}, [collapsed]);
|
|
56
|
+
const ctx = React.useMemo(
|
|
57
|
+
() => ({
|
|
58
|
+
collapsed,
|
|
59
|
+
hovering,
|
|
60
|
+
effectiveCollapsed: collapsed && !hovering,
|
|
61
|
+
onCollapsedChange
|
|
62
|
+
}),
|
|
63
|
+
[collapsed, hovering, onCollapsedChange]
|
|
64
|
+
);
|
|
65
|
+
return /* @__PURE__ */ jsx(AppShellContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx(
|
|
66
|
+
"div",
|
|
67
|
+
{
|
|
68
|
+
className: cn("flex h-full overflow-hidden bg-[var(--bg-body)]", className),
|
|
69
|
+
onMouseLeave: handleMouseLeave,
|
|
70
|
+
children: React.Children.map(children, (child) => {
|
|
71
|
+
if (!React.isValidElement(child)) return child;
|
|
72
|
+
if (child.type === AppShellSidebar) {
|
|
73
|
+
return /* @__PURE__ */ jsx(
|
|
74
|
+
"div",
|
|
75
|
+
{
|
|
76
|
+
onMouseEnter: handleMouseEnter,
|
|
77
|
+
onMouseLeave: handleMouseLeave,
|
|
78
|
+
className: "relative shrink-0",
|
|
79
|
+
style: {
|
|
80
|
+
width: collapsed ? "var(--size-sidebar-collapsed)" : "var(--size-sidebar-expanded)",
|
|
81
|
+
transitionProperty: "width",
|
|
82
|
+
transitionDuration: "var(--duration-sidebar)",
|
|
83
|
+
transitionTimingFunction: "ease-in-out"
|
|
84
|
+
},
|
|
85
|
+
children: child
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return child;
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
) });
|
|
93
|
+
}
|
|
94
|
+
function AppShellSidebar(props) {
|
|
95
|
+
return /* @__PURE__ */ jsx(Sidebar, { ...props });
|
|
96
|
+
}
|
|
97
|
+
function AppShellHeader(props) {
|
|
98
|
+
return /* @__PURE__ */ jsx(TopBar, { ...props });
|
|
99
|
+
}
|
|
100
|
+
function AppShellContent({
|
|
101
|
+
children,
|
|
102
|
+
className
|
|
103
|
+
}) {
|
|
104
|
+
return /* @__PURE__ */ jsx("div", { className: cn("min-h-0 flex-1 overflow-hidden", className), children });
|
|
105
|
+
}
|
|
106
|
+
const AppShell = Object.assign(AppShellRoot, {
|
|
107
|
+
Sidebar: AppShellSidebar,
|
|
108
|
+
Header: AppShellHeader,
|
|
109
|
+
Content: AppShellContent
|
|
110
|
+
});
|
|
111
|
+
export {
|
|
112
|
+
AppShell
|
|
113
|
+
};
|