@mediaradar/design-components 0.6.0 → 0.8.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/README.md +12 -3
- package/dist/index.cjs +1013 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +486 -2
- package/dist/index.d.ts +486 -2
- package/dist/index.js +992 -8
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/scripts/tailwind-coverage.mjs +3 -0
package/dist/index.cjs
CHANGED
|
@@ -20,21 +20,31 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AISpark: () => AISpark,
|
|
23
24
|
AdvertiserNoResults: () => AdvertiserNoResults,
|
|
24
25
|
AdvertiserQuickFilter: () => AdvertiserQuickFilter,
|
|
25
26
|
AdvertiserSearchPrompt: () => AdvertiserSearchPrompt,
|
|
26
27
|
BarChartPlaceholder: () => BarChartPlaceholder,
|
|
28
|
+
Button: () => Button,
|
|
27
29
|
Card: () => Card,
|
|
28
30
|
CheckBox: () => CheckBox,
|
|
31
|
+
ChipContent: () => ChipContent,
|
|
29
32
|
DEFAULT_SEARCH_MATCH: () => DEFAULT_SEARCH_MATCH,
|
|
30
33
|
DataScopeFilter: () => DataScopeFilter,
|
|
31
34
|
DateRangeFilter: () => DateRangeFilter,
|
|
35
|
+
DateRangePicker: () => DateRangePicker,
|
|
36
|
+
FilterChipBar: () => FilterChipBar,
|
|
37
|
+
FilterDropdownFooter: () => FilterDropdownFooter,
|
|
38
|
+
Freshness: () => Freshness,
|
|
32
39
|
InfoTip: () => InfoTip,
|
|
33
40
|
LineChartPlaceholder: () => LineChartPlaceholder,
|
|
41
|
+
MultiSelectFilter: () => MultiSelectFilter,
|
|
34
42
|
NO_RESULTS_BODY: () => NO_RESULTS_BODY,
|
|
35
43
|
NO_RESULTS_TITLE: () => NO_RESULTS_TITLE,
|
|
44
|
+
NameListModal: () => NameListModal,
|
|
36
45
|
NoResultsEmptyState: () => NoResultsEmptyState,
|
|
37
46
|
PRIMARY_ACTION_CLASS: () => PRIMARY_ACTION_CLASS,
|
|
47
|
+
Pager: () => Pager,
|
|
38
48
|
PieChartPlaceholder: () => PieChartPlaceholder,
|
|
39
49
|
PublisherBreakdownList: () => PublisherBreakdownList,
|
|
40
50
|
QUIET_ACTION_CLASS: () => QUIET_ACTION_CLASS,
|
|
@@ -44,10 +54,20 @@ __export(index_exports, {
|
|
|
44
54
|
SelectFilter: () => SelectFilter,
|
|
45
55
|
SelectedSection: () => SelectedSection,
|
|
46
56
|
SelectionPicker: () => SelectionPicker,
|
|
57
|
+
SortButton: () => SortButton,
|
|
47
58
|
StackedColumnPlaceholder: () => StackedColumnPlaceholder,
|
|
59
|
+
TablePagination: () => TablePagination,
|
|
60
|
+
Tag: () => Tag,
|
|
61
|
+
Toggle: () => Toggle,
|
|
48
62
|
Tooltip: () => Tooltip,
|
|
63
|
+
WorkspaceAvatar: () => WorkspaceAvatar,
|
|
49
64
|
WorkspaceSelectedCard: () => WorkspaceSelectedCard,
|
|
50
|
-
|
|
65
|
+
buttonVariants: () => buttonVariants,
|
|
66
|
+
chipTriggerClass: () => chipTriggerClass,
|
|
67
|
+
cycleSort: () => cycleSort,
|
|
68
|
+
noResultsBody: () => noResultsBody,
|
|
69
|
+
resolveRange: () => resolveRange,
|
|
70
|
+
sortProp: () => sortProp
|
|
51
71
|
});
|
|
52
72
|
module.exports = __toCommonJS(index_exports);
|
|
53
73
|
|
|
@@ -1598,7 +1618,7 @@ function AxisFrame({
|
|
|
1598
1618
|
"div",
|
|
1599
1619
|
{
|
|
1600
1620
|
className: "absolute inset-x-0 border-t border-dashed",
|
|
1601
|
-
style: { top: `${pct}%`, borderColor: "var(--color-border-default)" }
|
|
1621
|
+
style: { top: `${pct}%`, borderColor: "var(--mr-color-border-default)" }
|
|
1602
1622
|
},
|
|
1603
1623
|
pct
|
|
1604
1624
|
)),
|
|
@@ -1671,7 +1691,7 @@ function LineChartPlaceholder({ height = 280 }) {
|
|
|
1671
1691
|
{
|
|
1672
1692
|
points: toPath(pts, 0, LINE_FORECAST_FROM + 1),
|
|
1673
1693
|
fill: "none",
|
|
1674
|
-
stroke: "var(--color-border-strong)",
|
|
1694
|
+
stroke: "var(--mr-color-border-strong)",
|
|
1675
1695
|
strokeWidth: "2",
|
|
1676
1696
|
vectorEffect: "non-scaling-stroke",
|
|
1677
1697
|
strokeLinecap: "round",
|
|
@@ -1683,7 +1703,7 @@ function LineChartPlaceholder({ height = 280 }) {
|
|
|
1683
1703
|
{
|
|
1684
1704
|
points: toPath(pts, LINE_FORECAST_FROM, pts.length),
|
|
1685
1705
|
fill: "none",
|
|
1686
|
-
stroke: "var(--color-border-strong)",
|
|
1706
|
+
stroke: "var(--mr-color-border-strong)",
|
|
1687
1707
|
strokeWidth: "2",
|
|
1688
1708
|
strokeDasharray: "5 4",
|
|
1689
1709
|
vectorEffect: "non-scaling-stroke",
|
|
@@ -1700,7 +1720,7 @@ function LineChartPlaceholder({ height = 280 }) {
|
|
|
1700
1720
|
style: {
|
|
1701
1721
|
left: `${i / (pts.length - 1) * 100}%`,
|
|
1702
1722
|
top: `${y}%`,
|
|
1703
|
-
backgroundColor: "var(--color-border-strong)"
|
|
1723
|
+
backgroundColor: "var(--mr-color-border-strong)"
|
|
1704
1724
|
}
|
|
1705
1725
|
},
|
|
1706
1726
|
`${s}-${i}`
|
|
@@ -1716,7 +1736,7 @@ function PieChartPlaceholder({ height = 220, legendRows = 8 }) {
|
|
|
1716
1736
|
const r = 45;
|
|
1717
1737
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex w-full items-center gap-3", style: { height }, role: "presentation", "aria-hidden": "true", children: [
|
|
1718
1738
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex h-full items-center justify-center", style: { width: "60%" }, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { viewBox: "0 0 100 100", className: "h-full", style: { aspectRatio: "1 / 1" }, children: [
|
|
1719
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "50", cy: "50", r, fill: "var(--color-subtle)" }),
|
|
1739
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "50", cy: "50", r, fill: "var(--mr-color-subtle)" }),
|
|
1720
1740
|
PIE_SEAMS.map((deg) => {
|
|
1721
1741
|
const rad = (deg - 90) * Math.PI / 180;
|
|
1722
1742
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
@@ -1726,7 +1746,7 @@ function PieChartPlaceholder({ height = 220, legendRows = 8 }) {
|
|
|
1726
1746
|
y1: "50",
|
|
1727
1747
|
x2: 50 + r * Math.cos(rad),
|
|
1728
1748
|
y2: 50 + r * Math.sin(rad),
|
|
1729
|
-
stroke: "var(--color-border-default)",
|
|
1749
|
+
stroke: "var(--mr-color-border-default)",
|
|
1730
1750
|
strokeWidth: "1"
|
|
1731
1751
|
},
|
|
1732
1752
|
deg
|
|
@@ -1758,7 +1778,7 @@ function StackedColumnPlaceholder({
|
|
|
1758
1778
|
height: `${pct}%`,
|
|
1759
1779
|
/* border-strong, not border-default: on a subtle fill the softer
|
|
1760
1780
|
seam disappears and the stack reads as one undivided block. */
|
|
1761
|
-
borderTop: i === 0 ? void 0 : "1px solid var(--color-border-strong)"
|
|
1781
|
+
borderTop: i === 0 ? void 0 : "1px solid var(--mr-color-border-strong)"
|
|
1762
1782
|
}
|
|
1763
1783
|
},
|
|
1764
1784
|
i
|
|
@@ -2605,23 +2625,997 @@ function PublisherBreakdownList({ rows, defaultVisibleCount = 10, padded = true,
|
|
|
2605
2625
|
] }))
|
|
2606
2626
|
] });
|
|
2607
2627
|
}
|
|
2628
|
+
|
|
2629
|
+
// src/Button.tsx
|
|
2630
|
+
var import_react13 = require("react");
|
|
2631
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
2632
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
2633
|
+
var import_lucide_react15 = require("lucide-react");
|
|
2634
|
+
|
|
2635
|
+
// src/cn.ts
|
|
2636
|
+
var import_clsx = require("clsx");
|
|
2637
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
2638
|
+
function cn(...inputs) {
|
|
2639
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
// src/Button.tsx
|
|
2643
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2644
|
+
var buttonVariants = (0, import_class_variance_authority.cva)(
|
|
2645
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-control font-medium transition-all duration-(--mr-motion-duration-interactive) ease-interactive disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-hidden focus-visible:ring-0",
|
|
2646
|
+
{
|
|
2647
|
+
variants: {
|
|
2648
|
+
variant: {
|
|
2649
|
+
primary: "bg-brand-primaryAction text-brand-onprimary hover:brightness-110",
|
|
2650
|
+
secondary: "bg-surface text-text-primary border border-border-interactive hover:bg-subtle",
|
|
2651
|
+
ghost: "text-text-primary hover:bg-subtle",
|
|
2652
|
+
danger: "bg-status-danger text-status-onstatus hover:brightness-110",
|
|
2653
|
+
link: "text-text-link underline-offset-4 hover:underline px-0"
|
|
2654
|
+
},
|
|
2655
|
+
size: {
|
|
2656
|
+
sm: "h-8 px-3 text-sm",
|
|
2657
|
+
md: "h-10 px-4 text-sm",
|
|
2658
|
+
lg: "h-11 px-6 text-sm",
|
|
2659
|
+
icon: "h-9 w-9 p-0"
|
|
2660
|
+
}
|
|
2661
|
+
},
|
|
2662
|
+
defaultVariants: {
|
|
2663
|
+
variant: "primary",
|
|
2664
|
+
size: "md"
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
);
|
|
2668
|
+
var Button = (0, import_react13.forwardRef)(
|
|
2669
|
+
({ className, variant, size, asChild = false, loading = false, disabled, children, ...props }, ref) => {
|
|
2670
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
2671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
2672
|
+
Comp,
|
|
2673
|
+
{
|
|
2674
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
2675
|
+
ref,
|
|
2676
|
+
disabled: disabled || loading,
|
|
2677
|
+
"aria-busy": loading || void 0,
|
|
2678
|
+
...props,
|
|
2679
|
+
children: [
|
|
2680
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react15.Loader2, { className: "size-4 shrink-0 animate-spin", "aria-hidden": "true" }),
|
|
2681
|
+
children
|
|
2682
|
+
]
|
|
2683
|
+
}
|
|
2684
|
+
);
|
|
2685
|
+
}
|
|
2686
|
+
);
|
|
2687
|
+
Button.displayName = "Button";
|
|
2688
|
+
|
|
2689
|
+
// src/FilterDropdownFooter.tsx
|
|
2690
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2691
|
+
function FilterDropdownFooter({
|
|
2692
|
+
onClear,
|
|
2693
|
+
onApply,
|
|
2694
|
+
clearLabel = "Clear all",
|
|
2695
|
+
applyLabel = "Apply"
|
|
2696
|
+
}) {
|
|
2697
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
2698
|
+
"div",
|
|
2699
|
+
{
|
|
2700
|
+
className: cn(
|
|
2701
|
+
"flex items-center gap-2 border-t border-border-default p-2",
|
|
2702
|
+
onClear ? "justify-between" : "justify-end"
|
|
2703
|
+
),
|
|
2704
|
+
children: [
|
|
2705
|
+
onClear && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { type: "button", variant: "ghost", size: "sm", onClick: onClear, children: clearLabel }),
|
|
2706
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { type: "button", variant: "primary", size: "sm", onClick: onApply, children: applyLabel })
|
|
2707
|
+
]
|
|
2708
|
+
}
|
|
2709
|
+
);
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
// src/NameListModal.tsx
|
|
2713
|
+
var import_react14 = require("react");
|
|
2714
|
+
var import_react_dom5 = require("react-dom");
|
|
2715
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2716
|
+
function NameListModal({ title, initialName, submitLabel, onCancel, onSubmit }) {
|
|
2717
|
+
const [name, setName] = (0, import_react14.useState)(initialName);
|
|
2718
|
+
(0, import_react14.useEffect)(() => {
|
|
2719
|
+
const onKey = (e) => e.key === "Escape" && onCancel();
|
|
2720
|
+
window.addEventListener("keydown", onKey);
|
|
2721
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
2722
|
+
}, [onCancel]);
|
|
2723
|
+
return (0, import_react_dom5.createPortal)(
|
|
2724
|
+
// The scrim is a literal: @mediaradar/design-tokens has no scrim token yet.
|
|
2725
|
+
// Same light/dark values as insights-studio-prototype's local --color-scrim;
|
|
2726
|
+
// the dark one keys off data-theme, the attribute design-tokens' dark.css uses.
|
|
2727
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2728
|
+
"div",
|
|
2729
|
+
{
|
|
2730
|
+
className: "fixed inset-0 z-70 flex items-center justify-center bg-[rgba(20,17,13,0.55)] in-data-[theme=dark]:bg-[rgba(0,0,0,0.65)] px-4",
|
|
2731
|
+
onMouseDown: (e) => e.target === e.currentTarget && onCancel(),
|
|
2732
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
2733
|
+
"div",
|
|
2734
|
+
{
|
|
2735
|
+
role: "dialog",
|
|
2736
|
+
"aria-modal": "true",
|
|
2737
|
+
"aria-label": title,
|
|
2738
|
+
className: "w-full max-w-[420px] rounded-card border border-border-default bg-surface p-5 shadow-overlay",
|
|
2739
|
+
children: [
|
|
2740
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { className: "text-[16px] font-semibold text-text-primary", children: title }),
|
|
2741
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mt-4 flex flex-col gap-1.5", children: [
|
|
2742
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("label", { htmlFor: "account-list-name", className: "text-[12px] font-medium text-text-secondary", children: "List name" }),
|
|
2743
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2744
|
+
"input",
|
|
2745
|
+
{
|
|
2746
|
+
id: "account-list-name",
|
|
2747
|
+
autoFocus: true,
|
|
2748
|
+
value: name,
|
|
2749
|
+
onChange: (e) => setName(e.target.value),
|
|
2750
|
+
placeholder: "e.g. Q4 prospecting targets",
|
|
2751
|
+
className: "h-10 rounded-control border border-border-default bg-input px-3 text-sm outline-hidden focus:border-brand-primaryAction"
|
|
2752
|
+
}
|
|
2753
|
+
)
|
|
2754
|
+
] }),
|
|
2755
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mt-5 flex items-center justify-end gap-2", children: [
|
|
2756
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { variant: "secondary", onClick: onCancel, children: "Cancel" }),
|
|
2757
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { disabled: !name.trim(), onClick: () => onSubmit(name.trim()), children: submitLabel })
|
|
2758
|
+
] })
|
|
2759
|
+
]
|
|
2760
|
+
}
|
|
2761
|
+
)
|
|
2762
|
+
}
|
|
2763
|
+
),
|
|
2764
|
+
document.body
|
|
2765
|
+
);
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
// src/ChipTrigger.tsx
|
|
2769
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2770
|
+
function chipTriggerClass() {
|
|
2771
|
+
return cn(
|
|
2772
|
+
"flex h-11 items-center gap-2 rounded-control border bg-input px-2.5 text-text-secondary transition-colors hover:bg-subtle hover:text-text-primary focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-border-focus",
|
|
2773
|
+
// Sits on the input fill, with a stroke dark enough to still read as a
|
|
2774
|
+
// control against the warm canvas.
|
|
2775
|
+
"border-border-strong"
|
|
2776
|
+
);
|
|
2777
|
+
}
|
|
2778
|
+
function ChipContent({ caption, value, icon }) {
|
|
2779
|
+
const stack = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "flex flex-col gap-1 text-left leading-none", children: [
|
|
2780
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-[10px] uppercase tracking-wide text-text-tertiary", children: caption }),
|
|
2781
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-[12px] font-medium text-text-primary", children: value })
|
|
2782
|
+
] });
|
|
2783
|
+
if (icon) {
|
|
2784
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
2785
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "shrink-0 text-text-tertiary", children: icon }),
|
|
2786
|
+
stack
|
|
2787
|
+
] });
|
|
2788
|
+
}
|
|
2789
|
+
return stack;
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
// src/FilterChipBar.tsx
|
|
2793
|
+
var import_lucide_react16 = require("lucide-react");
|
|
2794
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
2795
|
+
function FilterChipBar({ chips, onRemove, onClearAll, parkedKeys }) {
|
|
2796
|
+
if (chips.length === 0) return null;
|
|
2797
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5 border-t border-border-default pt-2.5", children: [
|
|
2798
|
+
chips.map((c) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2799
|
+
Chip,
|
|
2800
|
+
{
|
|
2801
|
+
label: c.label,
|
|
2802
|
+
groupLabel: c.groupLabel,
|
|
2803
|
+
parked: !!parkedKeys?.has(c.key),
|
|
2804
|
+
onRemove: () => onRemove(c)
|
|
2805
|
+
},
|
|
2806
|
+
c.key
|
|
2807
|
+
)),
|
|
2808
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", onClick: onClearAll, className: "ml-1 text-[12px] font-medium text-text-link hover:underline", children: "Clear all" })
|
|
2809
|
+
] });
|
|
2810
|
+
}
|
|
2811
|
+
function Chip({
|
|
2812
|
+
label,
|
|
2813
|
+
groupLabel,
|
|
2814
|
+
parked,
|
|
2815
|
+
onRemove
|
|
2816
|
+
}) {
|
|
2817
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "group relative inline-flex", children: [
|
|
2818
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2819
|
+
"span",
|
|
2820
|
+
{
|
|
2821
|
+
className: cn(
|
|
2822
|
+
"flex items-center gap-1 rounded-full px-2.5 py-1 text-[12px] font-medium ring-1 transition-colors",
|
|
2823
|
+
parked ? (
|
|
2824
|
+
// No fill, dashed edge, muted label: reads as "held, not acting on
|
|
2825
|
+
// anything" against the solid applied chips beside it.
|
|
2826
|
+
"border border-dashed border-border-default bg-transparent text-text-tertiary ring-transparent group-hover:text-text-secondary"
|
|
2827
|
+
) : "bg-subtle text-text-secondary ring-transparent group-hover:bg-border-default group-hover:text-text-primary group-hover:ring-border-interactive"
|
|
2828
|
+
),
|
|
2829
|
+
children: [
|
|
2830
|
+
parked && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.CircleSlash, { size: 11, "aria-hidden": "true", className: "shrink-0 text-text-tertiary" }),
|
|
2831
|
+
label,
|
|
2832
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2833
|
+
"button",
|
|
2834
|
+
{
|
|
2835
|
+
type: "button",
|
|
2836
|
+
onClick: onRemove,
|
|
2837
|
+
"aria-label": `Remove ${groupLabel}: ${label}`,
|
|
2838
|
+
className: "text-text-tertiary transition-colors hover:text-text-primary",
|
|
2839
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.X, { size: 12 })
|
|
2840
|
+
}
|
|
2841
|
+
)
|
|
2842
|
+
]
|
|
2843
|
+
}
|
|
2844
|
+
),
|
|
2845
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2846
|
+
"span",
|
|
2847
|
+
{
|
|
2848
|
+
role: "tooltip",
|
|
2849
|
+
className: "pointer-events-none absolute bottom-full left-1/2 z-20 mb-1.5 -translate-x-1/2 whitespace-nowrap rounded-md bg-text-primary px-2 py-1 text-[11px] font-medium text-surface opacity-0 shadow-raised transition-opacity duration-150 group-hover:opacity-100",
|
|
2850
|
+
children: parked ? "Not in this workspace" : groupLabel
|
|
2851
|
+
}
|
|
2852
|
+
)
|
|
2853
|
+
] });
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
// src/SortButton.tsx
|
|
2857
|
+
var import_lucide_react17 = require("lucide-react");
|
|
2858
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2859
|
+
function SortButton({ label, sortKey, sort, onSort, disabled = false }) {
|
|
2860
|
+
const active = !disabled && sort.key === sortKey;
|
|
2861
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
2862
|
+
"button",
|
|
2863
|
+
{
|
|
2864
|
+
type: "button",
|
|
2865
|
+
disabled,
|
|
2866
|
+
onClick: () => onSort(sortKey),
|
|
2867
|
+
"aria-sort": active ? sort.dir === "asc" ? "ascending" : "descending" : "none",
|
|
2868
|
+
className: cn(
|
|
2869
|
+
// text-left overrides the UA default on <button>, which would centre a
|
|
2870
|
+
// label that wraps onto two lines, out of step with the column under it.
|
|
2871
|
+
"group inline-flex items-center gap-1 text-left uppercase tracking-wide transition-colors",
|
|
2872
|
+
!disabled && "hover:text-text-primary"
|
|
2873
|
+
),
|
|
2874
|
+
children: [
|
|
2875
|
+
label,
|
|
2876
|
+
!disabled && (active ? sort.dir === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react17.ArrowUp, { size: 12, className: "shrink-0 text-brand-primaryAction" }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react17.ArrowDown, { size: 12, className: "shrink-0 text-brand-primaryAction" }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2877
|
+
import_lucide_react17.ArrowUpDown,
|
|
2878
|
+
{
|
|
2879
|
+
size: 12,
|
|
2880
|
+
className: "shrink-0 text-text-tertiary opacity-50 transition-opacity group-hover:opacity-100"
|
|
2881
|
+
}
|
|
2882
|
+
))
|
|
2883
|
+
]
|
|
2884
|
+
}
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
// src/tableSort.ts
|
|
2889
|
+
function cycleSort(current, key, firstDir = "desc") {
|
|
2890
|
+
if (!current || current.key !== key) return { key, dir: firstDir };
|
|
2891
|
+
if (current.dir === firstDir) return { key, dir: firstDir === "desc" ? "asc" : "desc" };
|
|
2892
|
+
return null;
|
|
2893
|
+
}
|
|
2894
|
+
function sortProp(sort) {
|
|
2895
|
+
return sort ?? { key: null, dir: "desc" };
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
// src/Pager.tsx
|
|
2899
|
+
var import_lucide_react18 = require("lucide-react");
|
|
2900
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
2901
|
+
function pageWindow(current, total) {
|
|
2902
|
+
if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
|
|
2903
|
+
const keep = /* @__PURE__ */ new Set([1, total, current, current - 1, current + 1]);
|
|
2904
|
+
const pages = [...keep].filter((p) => p >= 1 && p <= total).sort((a, b) => a - b);
|
|
2905
|
+
const out = [];
|
|
2906
|
+
let prev = 0;
|
|
2907
|
+
for (const p of pages) {
|
|
2908
|
+
if (p - prev > 1) out.push(`gap-${p}`);
|
|
2909
|
+
out.push(p);
|
|
2910
|
+
prev = p;
|
|
2911
|
+
}
|
|
2912
|
+
return out;
|
|
2913
|
+
}
|
|
2914
|
+
function Pager({ page, totalPages, onPage }) {
|
|
2915
|
+
const btn = "flex h-8 min-w-8 items-center justify-center rounded-control px-2 text-[13px] transition-colors";
|
|
2916
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
2917
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2918
|
+
"button",
|
|
2919
|
+
{
|
|
2920
|
+
type: "button",
|
|
2921
|
+
onClick: () => onPage(page - 1),
|
|
2922
|
+
disabled: page === 1,
|
|
2923
|
+
"aria-label": "Previous page",
|
|
2924
|
+
className: cn(btn, "text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30"),
|
|
2925
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react18.ChevronLeft, { size: 16 })
|
|
2926
|
+
}
|
|
2927
|
+
),
|
|
2928
|
+
pageWindow(page, totalPages).map(
|
|
2929
|
+
(p) => typeof p === "string" ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "px-1 text-[13px] text-text-tertiary", children: "\u2026" }, p) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2930
|
+
"button",
|
|
2931
|
+
{
|
|
2932
|
+
type: "button",
|
|
2933
|
+
onClick: () => onPage(p),
|
|
2934
|
+
"aria-current": p === page ? "page" : void 0,
|
|
2935
|
+
className: cn(
|
|
2936
|
+
btn,
|
|
2937
|
+
p === page ? "bg-brand-primaryAction font-semibold text-brand-onprimary" : "text-text-secondary hover:bg-subtle hover:text-text-primary"
|
|
2938
|
+
),
|
|
2939
|
+
children: p
|
|
2940
|
+
},
|
|
2941
|
+
p
|
|
2942
|
+
)
|
|
2943
|
+
),
|
|
2944
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2945
|
+
"button",
|
|
2946
|
+
{
|
|
2947
|
+
type: "button",
|
|
2948
|
+
onClick: () => onPage(page + 1),
|
|
2949
|
+
disabled: page === totalPages,
|
|
2950
|
+
"aria-label": "Next page",
|
|
2951
|
+
className: cn(btn, "text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30"),
|
|
2952
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react18.ChevronRight, { size: 16 })
|
|
2953
|
+
}
|
|
2954
|
+
)
|
|
2955
|
+
] });
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
// src/WorkspaceAvatar.tsx
|
|
2959
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
2960
|
+
function workspaceInitials(name) {
|
|
2961
|
+
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
2962
|
+
if (words.length === 0) return "\xB7";
|
|
2963
|
+
if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
|
|
2964
|
+
return (words[0][0] + words[1][0]).toUpperCase();
|
|
2965
|
+
}
|
|
2966
|
+
var SIZES = {
|
|
2967
|
+
/** Matches a 15px lucide icon exactly, so a workspace name in a menu row
|
|
2968
|
+
* left-aligns with labels in icon-led rows above and below it. */
|
|
2969
|
+
xs: "h-[15px] w-[15px] rounded-[4px] text-[8px] tracking-tight",
|
|
2970
|
+
sm: "h-6 w-6 text-[10px]",
|
|
2971
|
+
md: "h-7 w-7 text-[11px]",
|
|
2972
|
+
lg: "h-11 w-11 text-[15px]"
|
|
2973
|
+
};
|
|
2974
|
+
function WorkspaceAvatar({ name, size = "md" }) {
|
|
2975
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2976
|
+
"span",
|
|
2977
|
+
{
|
|
2978
|
+
"aria-hidden": "true",
|
|
2979
|
+
className: cn(
|
|
2980
|
+
"flex shrink-0 items-center justify-center rounded-control bg-subtle font-semibold leading-none text-text-secondary",
|
|
2981
|
+
SIZES[size]
|
|
2982
|
+
),
|
|
2983
|
+
children: workspaceInitials(name ?? "All data")
|
|
2984
|
+
}
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2988
|
+
// src/Tag.tsx
|
|
2989
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
2990
|
+
function Tag({ children, className }) {
|
|
2991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2992
|
+
"span",
|
|
2993
|
+
{
|
|
2994
|
+
className: cn(
|
|
2995
|
+
"inline-flex items-center whitespace-nowrap rounded-full bg-subtle px-2 py-0.5 text-[11px] font-medium text-text-secondary",
|
|
2996
|
+
className
|
|
2997
|
+
),
|
|
2998
|
+
children
|
|
2999
|
+
}
|
|
3000
|
+
);
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
// src/TablePagination.tsx
|
|
3004
|
+
var import_lucide_react19 = require("lucide-react");
|
|
3005
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
3006
|
+
function TablePagination({
|
|
3007
|
+
page,
|
|
3008
|
+
perPage,
|
|
3009
|
+
totalItems,
|
|
3010
|
+
onPageChange,
|
|
3011
|
+
onPerPageChange,
|
|
3012
|
+
perPageOptions = [25, 50, 100],
|
|
3013
|
+
itemLabel = "results",
|
|
3014
|
+
className
|
|
3015
|
+
}) {
|
|
3016
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / perPage));
|
|
3017
|
+
const current = Math.min(page, totalPages);
|
|
3018
|
+
const rangeStart = totalItems === 0 ? 0 : (current - 1) * perPage + 1;
|
|
3019
|
+
const rangeEnd = Math.min(current * perPage, totalItems);
|
|
3020
|
+
const btn = "flex h-8 min-w-8 items-center justify-center rounded-control px-2 text-[13px] transition-colors";
|
|
3021
|
+
const stepBtn = cn(
|
|
3022
|
+
btn,
|
|
3023
|
+
"text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30"
|
|
3024
|
+
);
|
|
3025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: cn("flex flex-wrap items-center justify-between gap-x-4 gap-y-2", className), children: [
|
|
3026
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("label", { className: "flex items-center gap-2 text-[13px] text-text-secondary", children: [
|
|
3027
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "relative", children: [
|
|
3028
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3029
|
+
"select",
|
|
3030
|
+
{
|
|
3031
|
+
value: perPage,
|
|
3032
|
+
onChange: (e) => onPerPageChange(Number(e.target.value)),
|
|
3033
|
+
"aria-label": "Items per page",
|
|
3034
|
+
className: "appearance-none rounded-control border border-border-default bg-input py-1 pl-2.5 pr-7 text-[13px] font-medium text-text-primary focus:outline focus:outline-2 focus:outline-border-focus",
|
|
3035
|
+
children: perPageOptions.map((n) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("option", { value: n, children: n }, n))
|
|
3036
|
+
}
|
|
3037
|
+
),
|
|
3038
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3039
|
+
import_lucide_react19.ChevronDown,
|
|
3040
|
+
{
|
|
3041
|
+
size: 13,
|
|
3042
|
+
"aria-hidden": "true",
|
|
3043
|
+
className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-text-secondary"
|
|
3044
|
+
}
|
|
3045
|
+
)
|
|
3046
|
+
] }),
|
|
3047
|
+
"items per page"
|
|
3048
|
+
] }),
|
|
3049
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("nav", { className: "flex items-center gap-1", "aria-label": "Pagination", children: [
|
|
3050
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3051
|
+
"button",
|
|
3052
|
+
{
|
|
3053
|
+
type: "button",
|
|
3054
|
+
onClick: () => onPageChange(1),
|
|
3055
|
+
disabled: current === 1,
|
|
3056
|
+
"aria-label": "First page",
|
|
3057
|
+
className: stepBtn,
|
|
3058
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react19.ChevronFirst, { size: 16, "aria-hidden": "true" })
|
|
3059
|
+
}
|
|
3060
|
+
),
|
|
3061
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3062
|
+
"button",
|
|
3063
|
+
{
|
|
3064
|
+
type: "button",
|
|
3065
|
+
onClick: () => onPageChange(current - 1),
|
|
3066
|
+
disabled: current === 1,
|
|
3067
|
+
"aria-label": "Previous page",
|
|
3068
|
+
className: stepBtn,
|
|
3069
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react19.ChevronLeft, { size: 16, "aria-hidden": "true" })
|
|
3070
|
+
}
|
|
3071
|
+
),
|
|
3072
|
+
pageWindow(current, totalPages).map(
|
|
3073
|
+
(p) => typeof p === "string" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "px-1 text-[13px] text-text-tertiary", children: "\u2026" }, p) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3074
|
+
"button",
|
|
3075
|
+
{
|
|
3076
|
+
type: "button",
|
|
3077
|
+
onClick: () => onPageChange(p),
|
|
3078
|
+
"aria-current": p === current ? "page" : void 0,
|
|
3079
|
+
className: cn(
|
|
3080
|
+
btn,
|
|
3081
|
+
p === current ? "bg-brand-primaryAction font-semibold text-brand-onprimary" : "text-text-secondary hover:bg-subtle hover:text-text-primary"
|
|
3082
|
+
),
|
|
3083
|
+
children: p
|
|
3084
|
+
},
|
|
3085
|
+
p
|
|
3086
|
+
)
|
|
3087
|
+
),
|
|
3088
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3089
|
+
"button",
|
|
3090
|
+
{
|
|
3091
|
+
type: "button",
|
|
3092
|
+
onClick: () => onPageChange(current + 1),
|
|
3093
|
+
disabled: current === totalPages,
|
|
3094
|
+
"aria-label": "Next page",
|
|
3095
|
+
className: stepBtn,
|
|
3096
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react19.ChevronRight, { size: 16, "aria-hidden": "true" })
|
|
3097
|
+
}
|
|
3098
|
+
),
|
|
3099
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3100
|
+
"button",
|
|
3101
|
+
{
|
|
3102
|
+
type: "button",
|
|
3103
|
+
onClick: () => onPageChange(totalPages),
|
|
3104
|
+
disabled: current === totalPages,
|
|
3105
|
+
"aria-label": "Last page",
|
|
3106
|
+
className: stepBtn,
|
|
3107
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react19.ChevronLast, { size: 16, "aria-hidden": "true" })
|
|
3108
|
+
}
|
|
3109
|
+
)
|
|
3110
|
+
] }),
|
|
3111
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "text-[13px] text-text-tertiary tabular-nums", children: [
|
|
3112
|
+
rangeStart.toLocaleString(),
|
|
3113
|
+
" \u2013 ",
|
|
3114
|
+
rangeEnd.toLocaleString(),
|
|
3115
|
+
" of ",
|
|
3116
|
+
totalItems.toLocaleString(),
|
|
3117
|
+
" ",
|
|
3118
|
+
itemLabel
|
|
3119
|
+
] })
|
|
3120
|
+
] });
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
// src/DateRangePicker.tsx
|
|
3124
|
+
var import_react15 = require("react");
|
|
3125
|
+
var import_lucide_react20 = require("lucide-react");
|
|
3126
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
3127
|
+
var MONTH_ABBR = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
3128
|
+
var PRESETS = ["Rolling 3 months", "Rolling 6 months", "Rolling 12 months"];
|
|
3129
|
+
var startOfToday = () => {
|
|
3130
|
+
const d = /* @__PURE__ */ new Date();
|
|
3131
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
3132
|
+
};
|
|
3133
|
+
var fmtDate = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
3134
|
+
function resolveRange(label, today = startOfToday()) {
|
|
3135
|
+
const end = today;
|
|
3136
|
+
const mMonths = label.match(/Rolling (\d+) months/);
|
|
3137
|
+
if (mMonths) {
|
|
3138
|
+
return [new Date(end.getFullYear(), end.getMonth() - Number(mMonths[1]), 1), end];
|
|
3139
|
+
}
|
|
3140
|
+
const mQuarters = label.match(/Rolling (\d+) quarters/);
|
|
3141
|
+
if (mQuarters) {
|
|
3142
|
+
return [new Date(end.getFullYear(), end.getMonth() - Number(mQuarters[1]) * 3, 1), end];
|
|
3143
|
+
}
|
|
3144
|
+
const mYears = label.match(/Rolling (\d+) years/);
|
|
3145
|
+
if (mYears) {
|
|
3146
|
+
return [new Date(end.getFullYear() - Number(mYears[1]), end.getMonth(), 1), end];
|
|
3147
|
+
}
|
|
3148
|
+
const mCustom = label.match(/([A-Za-z]{3})\s+(\d{4}).*?([A-Za-z]{3})\s+(\d{4})/);
|
|
3149
|
+
if (mCustom) {
|
|
3150
|
+
const s = new Date(Number(mCustom[2]), MONTH_ABBR.indexOf(mCustom[1]), 1);
|
|
3151
|
+
const e = new Date(Number(mCustom[4]), MONTH_ABBR.indexOf(mCustom[3]) + 1, 0);
|
|
3152
|
+
return [s, e];
|
|
3153
|
+
}
|
|
3154
|
+
return [new Date(end.getFullYear(), end.getMonth() - 6, 1), end];
|
|
3155
|
+
}
|
|
3156
|
+
function spanLabel(label, today) {
|
|
3157
|
+
const [s, e] = resolveRange(label, today);
|
|
3158
|
+
return `${fmtDate(s)} \u2013 ${fmtDate(e)}`;
|
|
3159
|
+
}
|
|
3160
|
+
function MiniSelect({ value, onChange, options }) {
|
|
3161
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3162
|
+
"select",
|
|
3163
|
+
{
|
|
3164
|
+
value: String(value),
|
|
3165
|
+
onChange: (e) => {
|
|
3166
|
+
const opt = options.find((o) => String(o.value) === e.target.value);
|
|
3167
|
+
if (opt) onChange(opt.value);
|
|
3168
|
+
},
|
|
3169
|
+
className: "rounded-control border border-border-default bg-input px-1.5 py-1 text-[12px] text-text-primary outline-hidden focus:border-border-focus",
|
|
3170
|
+
children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("option", { value: String(o.value), children: o.label }, String(o.value)))
|
|
3171
|
+
}
|
|
3172
|
+
);
|
|
3173
|
+
}
|
|
3174
|
+
function DateRangePicker({
|
|
3175
|
+
defaultValue = "Rolling 6 months",
|
|
3176
|
+
align = "left",
|
|
3177
|
+
presets = PRESETS,
|
|
3178
|
+
onChange,
|
|
3179
|
+
onRangeChange,
|
|
3180
|
+
showFooter = false,
|
|
3181
|
+
today,
|
|
3182
|
+
years
|
|
3183
|
+
}) {
|
|
3184
|
+
const end = (0, import_react15.useMemo)(() => today ?? startOfToday(), [today]);
|
|
3185
|
+
const yearOptions = years ?? [3, 2, 1, 0].map((n) => end.getFullYear() - n);
|
|
3186
|
+
const [open, setOpen] = (0, import_react15.useState)(false);
|
|
3187
|
+
const [value, setValue] = (0, import_react15.useState)(defaultValue);
|
|
3188
|
+
const [draft, setDraft] = (0, import_react15.useState)(defaultValue);
|
|
3189
|
+
const ref = (0, import_react15.useRef)(null);
|
|
3190
|
+
const [fromMo, setFromMo] = (0, import_react15.useState)(end.getMonth());
|
|
3191
|
+
const [fromYr, setFromYr] = (0, import_react15.useState)(end.getFullYear() - 1);
|
|
3192
|
+
const [toMo, setToMo] = (0, import_react15.useState)(end.getMonth());
|
|
3193
|
+
const [toYr, setToYr] = (0, import_react15.useState)(end.getFullYear());
|
|
3194
|
+
(0, import_react15.useEffect)(() => {
|
|
3195
|
+
const [s, e] = resolveRange(value, end);
|
|
3196
|
+
onRangeChange?.(s, e);
|
|
3197
|
+
}, [value]);
|
|
3198
|
+
const toggleOpen = () => {
|
|
3199
|
+
if (!open) setDraft(value);
|
|
3200
|
+
setOpen((o) => !o);
|
|
3201
|
+
};
|
|
3202
|
+
(0, import_react15.useEffect)(() => {
|
|
3203
|
+
if (!open) return;
|
|
3204
|
+
const onDown = (e) => {
|
|
3205
|
+
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
3206
|
+
};
|
|
3207
|
+
const onKey = (e) => e.key === "Escape" && setOpen(false);
|
|
3208
|
+
window.addEventListener("mousedown", onDown);
|
|
3209
|
+
window.addEventListener("keydown", onKey);
|
|
3210
|
+
return () => {
|
|
3211
|
+
window.removeEventListener("mousedown", onDown);
|
|
3212
|
+
window.removeEventListener("keydown", onKey);
|
|
3213
|
+
};
|
|
3214
|
+
}, [open]);
|
|
3215
|
+
const commit = (label) => {
|
|
3216
|
+
setValue(label);
|
|
3217
|
+
onChange?.(label);
|
|
3218
|
+
setOpen(false);
|
|
3219
|
+
};
|
|
3220
|
+
const span = toYr * 12 + toMo - (fromYr * 12 + fromMo) + 1;
|
|
3221
|
+
const valid = span >= 1;
|
|
3222
|
+
const applyCustom = () => {
|
|
3223
|
+
if (!valid) return;
|
|
3224
|
+
const label = `${MONTH_ABBR[fromMo]} ${fromYr} \u2013 ${MONTH_ABBR[toMo]} ${toYr}`;
|
|
3225
|
+
if (showFooter) setDraft(label);
|
|
3226
|
+
else commit(label);
|
|
3227
|
+
};
|
|
3228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "relative", ref, children: [
|
|
3229
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
3230
|
+
"button",
|
|
3231
|
+
{
|
|
3232
|
+
type: "button",
|
|
3233
|
+
onClick: toggleOpen,
|
|
3234
|
+
"aria-expanded": open,
|
|
3235
|
+
"aria-haspopup": "listbox",
|
|
3236
|
+
className: chipTriggerClass(),
|
|
3237
|
+
children: [
|
|
3238
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "flex flex-col gap-1 text-left leading-none", children: [
|
|
3239
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-[10px] text-text-tertiary", children: spanLabel(value, end) }),
|
|
3240
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-[12px] font-medium text-text-primary", children: value })
|
|
3241
|
+
] }),
|
|
3242
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react20.ChevronDown, { size: 14, "aria-hidden": "true", className: cn("shrink-0 text-text-secondary transition-transform", open && "rotate-180") })
|
|
3243
|
+
]
|
|
3244
|
+
}
|
|
3245
|
+
),
|
|
3246
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: cn("absolute top-[calc(100%+8px)] z-30 w-[280px] overflow-hidden rounded-card border border-border-default bg-surface py-1 shadow-overlay", align === "right" ? "right-0" : "left-0"), children: [
|
|
3247
|
+
presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3248
|
+
"button",
|
|
3249
|
+
{
|
|
3250
|
+
type: "button",
|
|
3251
|
+
onClick: () => showFooter ? setDraft(p) : commit(p),
|
|
3252
|
+
className: cn("block w-full px-3 py-2 text-left text-[13px] transition-colors hover:bg-subtle", (showFooter ? draft : value) === p ? "font-semibold text-brand-primaryAction" : "text-text-secondary"),
|
|
3253
|
+
children: p
|
|
3254
|
+
},
|
|
3255
|
+
p
|
|
3256
|
+
)),
|
|
3257
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "mt-1 border-t border-border-default px-3 pb-2 pt-2", children: [
|
|
3258
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "text-[13px] font-semibold text-text-primary", children: "Custom Range" }),
|
|
3259
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "mt-2 flex flex-col gap-2", children: [
|
|
3260
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("label", { className: "flex items-center justify-between gap-2 text-[12px] text-text-secondary", children: [
|
|
3261
|
+
"From",
|
|
3262
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "flex gap-1", children: [
|
|
3263
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: fromMo, onChange: setFromMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3264
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: fromYr, onChange: setFromYr, options: yearOptions.map((y) => ({ label: String(y), value: y })) })
|
|
3265
|
+
] })
|
|
3266
|
+
] }),
|
|
3267
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("label", { className: "flex items-center justify-between gap-2 text-[12px] text-text-secondary", children: [
|
|
3268
|
+
"To",
|
|
3269
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "flex gap-1", children: [
|
|
3270
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: toMo, onChange: setToMo, options: MONTH_ABBR.map((mm, i) => ({ label: mm, value: i })) }),
|
|
3271
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MiniSelect, { value: toYr, onChange: setToYr, options: yearOptions.map((y) => ({ label: String(y), value: y })) })
|
|
3272
|
+
] })
|
|
3273
|
+
] }),
|
|
3274
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3275
|
+
"button",
|
|
3276
|
+
{
|
|
3277
|
+
type: "button",
|
|
3278
|
+
onClick: applyCustom,
|
|
3279
|
+
disabled: !valid,
|
|
3280
|
+
className: "self-start text-[13px] font-semibold text-brand-primaryAction transition-opacity hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-40",
|
|
3281
|
+
children: showFooter ? "Use custom range" : "Apply"
|
|
3282
|
+
}
|
|
3283
|
+
)
|
|
3284
|
+
] })
|
|
3285
|
+
] }),
|
|
3286
|
+
showFooter && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(FilterDropdownFooter, { onApply: () => commit(draft) })
|
|
3287
|
+
] })
|
|
3288
|
+
] });
|
|
3289
|
+
}
|
|
3290
|
+
|
|
3291
|
+
// src/MultiSelectFilter.tsx
|
|
3292
|
+
var import_react16 = require("react");
|
|
3293
|
+
var import_lucide_react21 = require("lucide-react");
|
|
3294
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
3295
|
+
function MultiSelectFilter({
|
|
3296
|
+
caption,
|
|
3297
|
+
options = [],
|
|
3298
|
+
groups,
|
|
3299
|
+
selected,
|
|
3300
|
+
onChange,
|
|
3301
|
+
allLabel = "All",
|
|
3302
|
+
searchable = false,
|
|
3303
|
+
searchPlaceholder,
|
|
3304
|
+
align = "left",
|
|
3305
|
+
fullIsAll = false,
|
|
3306
|
+
min = 0,
|
|
3307
|
+
icon,
|
|
3308
|
+
showFooter = false,
|
|
3309
|
+
clearValue = [],
|
|
3310
|
+
menuWidthClass = "w-60",
|
|
3311
|
+
plainParent = false,
|
|
3312
|
+
fullWidth = false
|
|
3313
|
+
}) {
|
|
3314
|
+
const groupLeaves = (g) => g.children.length ? g.children : [{ id: g.id, label: g.label }];
|
|
3315
|
+
const leafOptions = groups ? groups.flatMap(groupLeaves) : options;
|
|
3316
|
+
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
3317
|
+
const [q, setQ] = (0, import_react16.useState)("");
|
|
3318
|
+
const [draft, setDraft] = (0, import_react16.useState)(selected);
|
|
3319
|
+
const ref = (0, import_react16.useRef)(null);
|
|
3320
|
+
const close = (0, import_react16.useCallback)(() => {
|
|
3321
|
+
setOpen(false);
|
|
3322
|
+
setQ("");
|
|
3323
|
+
if (showFooter) return;
|
|
3324
|
+
if (draft.length !== selected.length || draft.some((id) => !selected.includes(id))) {
|
|
3325
|
+
onChange(draft);
|
|
3326
|
+
}
|
|
3327
|
+
}, [draft, selected, onChange, showFooter]);
|
|
3328
|
+
const openTray = () => {
|
|
3329
|
+
setDraft(selected);
|
|
3330
|
+
setOpen(true);
|
|
3331
|
+
};
|
|
3332
|
+
const apply = () => {
|
|
3333
|
+
onChange(draft);
|
|
3334
|
+
setOpen(false);
|
|
3335
|
+
setQ("");
|
|
3336
|
+
};
|
|
3337
|
+
(0, import_react16.useEffect)(() => {
|
|
3338
|
+
if (!open) return;
|
|
3339
|
+
const onKey = (e) => e.key === "Escape" && close();
|
|
3340
|
+
const onClick = (e) => {
|
|
3341
|
+
if (ref.current && !ref.current.contains(e.target)) close();
|
|
3342
|
+
};
|
|
3343
|
+
window.addEventListener("keydown", onKey);
|
|
3344
|
+
window.addEventListener("mousedown", onClick);
|
|
3345
|
+
return () => {
|
|
3346
|
+
window.removeEventListener("keydown", onKey);
|
|
3347
|
+
window.removeEventListener("mousedown", onClick);
|
|
3348
|
+
};
|
|
3349
|
+
}, [open, close]);
|
|
3350
|
+
const toggle = (id) => setDraft((cur) => {
|
|
3351
|
+
const next = cur.includes(id) ? cur.filter((x) => x !== id) : [...cur, id];
|
|
3352
|
+
if (next.length < min) return cur;
|
|
3353
|
+
return next;
|
|
3354
|
+
});
|
|
3355
|
+
const toggleGroup = (g) => setDraft((cur) => {
|
|
3356
|
+
const ids = groupLeaves(g).map((c) => c.id);
|
|
3357
|
+
const allSel = ids.every((id) => cur.includes(id));
|
|
3358
|
+
const next = allSel ? cur.filter((id) => !ids.includes(id)) : [.../* @__PURE__ */ new Set([...cur, ...ids])];
|
|
3359
|
+
if (next.length < min) return cur;
|
|
3360
|
+
return next;
|
|
3361
|
+
});
|
|
3362
|
+
const groupState = (g) => {
|
|
3363
|
+
const ids = groupLeaves(g).map((c) => c.id);
|
|
3364
|
+
const sel = ids.filter((id) => draft.includes(id)).length;
|
|
3365
|
+
return sel === 0 ? "none" : sel === ids.length ? "all" : "some";
|
|
3366
|
+
};
|
|
3367
|
+
const shown = open && !showFooter ? draft : selected;
|
|
3368
|
+
const isAll = shown.length === 0 || fullIsAll && shown.length === leafOptions.length;
|
|
3369
|
+
const value = isAll ? allLabel : shown.length === 1 ? leafOptions.find((o) => o.id === shown[0])?.label ?? `${shown.length} selected` : `${shown.length} selected`;
|
|
3370
|
+
const ql = q.trim().toLowerCase();
|
|
3371
|
+
const items = options.filter((o) => !ql || o.label.toLowerCase().includes(ql));
|
|
3372
|
+
const visibleGroups = groups ? groups.map((g) => {
|
|
3373
|
+
if (!ql || g.label.toLowerCase().includes(ql)) return g;
|
|
3374
|
+
const kids = g.children.filter((c) => c.label.toLowerCase().includes(ql));
|
|
3375
|
+
return kids.length ? { ...g, children: kids } : null;
|
|
3376
|
+
}).filter((g) => g !== null) : [];
|
|
3377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: cn("relative", fullWidth && "w-full"), ref, children: [
|
|
3378
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3379
|
+
"button",
|
|
3380
|
+
{
|
|
3381
|
+
type: "button",
|
|
3382
|
+
onClick: () => open ? close() : openTray(),
|
|
3383
|
+
"aria-expanded": open,
|
|
3384
|
+
className: cn(chipTriggerClass(), fullWidth && "w-full justify-between"),
|
|
3385
|
+
children: [
|
|
3386
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChipContent, { caption, value, icon }),
|
|
3387
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3388
|
+
import_lucide_react21.ChevronDown,
|
|
3389
|
+
{
|
|
3390
|
+
size: 14,
|
|
3391
|
+
"aria-hidden": "true",
|
|
3392
|
+
className: cn("shrink-0 text-text-secondary transition-transform", open && "rotate-180")
|
|
3393
|
+
}
|
|
3394
|
+
)
|
|
3395
|
+
]
|
|
3396
|
+
}
|
|
3397
|
+
),
|
|
3398
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3399
|
+
"div",
|
|
3400
|
+
{
|
|
3401
|
+
className: cn(
|
|
3402
|
+
"absolute top-[calc(100%+8px)] z-30 flex flex-col overflow-hidden rounded-card border border-border-default bg-surface shadow-overlay",
|
|
3403
|
+
menuWidthClass,
|
|
3404
|
+
align === "right" ? "right-0" : "left-0"
|
|
3405
|
+
),
|
|
3406
|
+
role: "dialog",
|
|
3407
|
+
"aria-label": caption,
|
|
3408
|
+
children: [
|
|
3409
|
+
searchable && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "border-b border-border-default p-2", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex h-9 items-center gap-2 rounded-control border border-border-default bg-input px-2.5", children: [
|
|
3410
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react21.Search, { size: 14, className: "text-text-secondary", "aria-hidden": "true" }),
|
|
3411
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3412
|
+
"input",
|
|
3413
|
+
{
|
|
3414
|
+
type: "text",
|
|
3415
|
+
value: q,
|
|
3416
|
+
onChange: (e) => setQ(e.target.value),
|
|
3417
|
+
placeholder: searchPlaceholder ?? `Search ${caption.toLowerCase()}`,
|
|
3418
|
+
className: "h-full flex-1 bg-transparent text-[13px] outline-hidden placeholder:text-text-tertiary"
|
|
3419
|
+
}
|
|
3420
|
+
),
|
|
3421
|
+
q && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("button", { type: "button", onClick: () => setQ(""), "aria-label": "Clear search", className: "text-text-tertiary hover:text-text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react21.X, { size: 13 }) })
|
|
3422
|
+
] }) }),
|
|
3423
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "max-h-[280px] overflow-y-auto p-1", children: [
|
|
3424
|
+
groups ? visibleGroups.map((g) => {
|
|
3425
|
+
const state = groupState(g);
|
|
3426
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { children: [
|
|
3427
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3428
|
+
"button",
|
|
3429
|
+
{
|
|
3430
|
+
type: "button",
|
|
3431
|
+
onClick: () => toggleGroup(g),
|
|
3432
|
+
className: "flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle",
|
|
3433
|
+
children: [
|
|
3434
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TriCheck, { state }),
|
|
3435
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: cn("flex-1 text-[14px] text-text-primary", !plainParent && "font-semibold"), children: g.label })
|
|
3436
|
+
]
|
|
3437
|
+
}
|
|
3438
|
+
),
|
|
3439
|
+
g.children.map((c) => {
|
|
3440
|
+
const checked = draft.includes(c.id);
|
|
3441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3442
|
+
"button",
|
|
3443
|
+
{
|
|
3444
|
+
type: "button",
|
|
3445
|
+
onClick: () => toggle(c.id),
|
|
3446
|
+
className: "flex w-full items-center gap-2.5 rounded-control py-2 pl-9 pr-2 text-left transition-colors hover:bg-subtle",
|
|
3447
|
+
children: [
|
|
3448
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TriCheck, { state: checked ? "all" : "none" }),
|
|
3449
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "flex-1 text-[14px] text-text-primary", children: c.label })
|
|
3450
|
+
]
|
|
3451
|
+
},
|
|
3452
|
+
c.id
|
|
3453
|
+
);
|
|
3454
|
+
})
|
|
3455
|
+
] }, g.id);
|
|
3456
|
+
}) : items.map((o) => {
|
|
3457
|
+
const checked = draft.includes(o.id);
|
|
3458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3459
|
+
"button",
|
|
3460
|
+
{
|
|
3461
|
+
type: "button",
|
|
3462
|
+
onClick: () => toggle(o.id),
|
|
3463
|
+
className: "flex w-full items-center gap-2.5 rounded-control px-2 py-2 text-left transition-colors hover:bg-subtle",
|
|
3464
|
+
children: [
|
|
3465
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3466
|
+
"span",
|
|
3467
|
+
{
|
|
3468
|
+
className: cn(
|
|
3469
|
+
"flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors",
|
|
3470
|
+
checked ? "border-transparent bg-brand-primaryAction text-brand-onprimary" : "border-border-interactive bg-input"
|
|
3471
|
+
),
|
|
3472
|
+
children: checked && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react21.Check, { size: 13, strokeWidth: 3 })
|
|
3473
|
+
}
|
|
3474
|
+
),
|
|
3475
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "flex-1 text-[14px] text-text-primary", children: o.label })
|
|
3476
|
+
]
|
|
3477
|
+
},
|
|
3478
|
+
o.id
|
|
3479
|
+
);
|
|
3480
|
+
}),
|
|
3481
|
+
(groups && !visibleGroups.length || !groups && !items.length) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "py-6 text-center text-[13px] text-text-tertiary", children: "No matches." })
|
|
3482
|
+
] }),
|
|
3483
|
+
showFooter ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(FilterDropdownFooter, { onClear: () => setDraft(clearValue), onApply: apply }) : min === 0 && draft.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "border-t border-border-default p-2", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3484
|
+
"button",
|
|
3485
|
+
{
|
|
3486
|
+
type: "button",
|
|
3487
|
+
onClick: () => setDraft([]),
|
|
3488
|
+
className: "text-[12px] font-medium text-text-link hover:underline",
|
|
3489
|
+
children: [
|
|
3490
|
+
"Clear ",
|
|
3491
|
+
caption.toLowerCase()
|
|
3492
|
+
]
|
|
3493
|
+
}
|
|
3494
|
+
) })
|
|
3495
|
+
]
|
|
3496
|
+
}
|
|
3497
|
+
)
|
|
3498
|
+
] });
|
|
3499
|
+
}
|
|
3500
|
+
function TriCheck({ state }) {
|
|
3501
|
+
const filled = state !== "none";
|
|
3502
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3503
|
+
"span",
|
|
3504
|
+
{
|
|
3505
|
+
className: cn(
|
|
3506
|
+
"flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border transition-colors",
|
|
3507
|
+
filled ? "border-transparent bg-brand-primaryAction text-brand-onprimary" : "border-border-interactive bg-input"
|
|
3508
|
+
),
|
|
3509
|
+
children: [
|
|
3510
|
+
state === "all" && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react21.Check, { size: 13, strokeWidth: 3 }),
|
|
3511
|
+
state === "some" && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react21.Minus, { size: 13, strokeWidth: 3 })
|
|
3512
|
+
]
|
|
3513
|
+
}
|
|
3514
|
+
);
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3517
|
+
// src/Toggle.tsx
|
|
3518
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
3519
|
+
var SIZES2 = {
|
|
3520
|
+
sm: { track: "h-5 w-9", knob: "h-4 w-4", on: "translate-x-[18px]" },
|
|
3521
|
+
md: { track: "h-6 w-11", knob: "h-5 w-5", on: "translate-x-[22px]" }
|
|
3522
|
+
};
|
|
3523
|
+
function Toggle({ checked, onChange, label, size = "md", disabled, className }) {
|
|
3524
|
+
const s = SIZES2[size];
|
|
3525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
3526
|
+
"button",
|
|
3527
|
+
{
|
|
3528
|
+
type: "button",
|
|
3529
|
+
role: "switch",
|
|
3530
|
+
"aria-checked": checked,
|
|
3531
|
+
"aria-label": label,
|
|
3532
|
+
disabled,
|
|
3533
|
+
onClick: () => onChange(!checked),
|
|
3534
|
+
className: cn(
|
|
3535
|
+
"relative inline-flex shrink-0 items-center rounded-full transition-colors focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus",
|
|
3536
|
+
s.track,
|
|
3537
|
+
checked ? "bg-brand-primaryAction" : "bg-border-interactive",
|
|
3538
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
3539
|
+
className
|
|
3540
|
+
),
|
|
3541
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
3542
|
+
"span",
|
|
3543
|
+
{
|
|
3544
|
+
className: cn(
|
|
3545
|
+
"inline-block transform rounded-full bg-surface shadow-raised transition-transform",
|
|
3546
|
+
s.knob,
|
|
3547
|
+
checked ? s.on : "translate-x-0.5"
|
|
3548
|
+
)
|
|
3549
|
+
}
|
|
3550
|
+
)
|
|
3551
|
+
}
|
|
3552
|
+
);
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3555
|
+
// src/AISpark.tsx
|
|
3556
|
+
var import_react17 = require("react");
|
|
3557
|
+
var import_lucide_react22 = require("lucide-react");
|
|
3558
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
3559
|
+
function AISpark({ size = 16, className }) {
|
|
3560
|
+
const id = (0, import_react17.useId)();
|
|
3561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
3562
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("svg", { width: "0", height: "0", "aria-hidden": "true", style: { position: "absolute" }, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("linearGradient", { id, x1: "0", y1: "0", x2: "1", y2: "1", children: [
|
|
3563
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("stop", { offset: "0%", stopColor: "var(--mr-color-brand-primary)" }),
|
|
3564
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("stop", { offset: "100%", className: "[stop-color:#9474ff] in-data-[theme=dark]:[stop-color:#a488ff]" })
|
|
3565
|
+
] }) }) }),
|
|
3566
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react22.Sparkles, { size, stroke: `url(#${id})`, className, "aria-hidden": "true" })
|
|
3567
|
+
] });
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
// src/Freshness.tsx
|
|
3571
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
3572
|
+
var dotColor = {
|
|
3573
|
+
fresh: "bg-status-success",
|
|
3574
|
+
recent: "bg-status-warning",
|
|
3575
|
+
stale: "bg-text-tertiary"
|
|
3576
|
+
};
|
|
3577
|
+
var srLabel = {
|
|
3578
|
+
fresh: "Fresh (under 4 hours)",
|
|
3579
|
+
recent: "Recent (today)",
|
|
3580
|
+
stale: "Older than a day"
|
|
3581
|
+
};
|
|
3582
|
+
function Freshness({ level }) {
|
|
3583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
3584
|
+
"span",
|
|
3585
|
+
{
|
|
3586
|
+
className: cn("inline-block h-1.5 w-1.5 shrink-0 rounded-full", dotColor[level]),
|
|
3587
|
+
role: "img",
|
|
3588
|
+
"aria-label": srLabel[level]
|
|
3589
|
+
}
|
|
3590
|
+
);
|
|
3591
|
+
}
|
|
2608
3592
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2609
3593
|
0 && (module.exports = {
|
|
3594
|
+
AISpark,
|
|
2610
3595
|
AdvertiserNoResults,
|
|
2611
3596
|
AdvertiserQuickFilter,
|
|
2612
3597
|
AdvertiserSearchPrompt,
|
|
2613
3598
|
BarChartPlaceholder,
|
|
3599
|
+
Button,
|
|
2614
3600
|
Card,
|
|
2615
3601
|
CheckBox,
|
|
3602
|
+
ChipContent,
|
|
2616
3603
|
DEFAULT_SEARCH_MATCH,
|
|
2617
3604
|
DataScopeFilter,
|
|
2618
3605
|
DateRangeFilter,
|
|
3606
|
+
DateRangePicker,
|
|
3607
|
+
FilterChipBar,
|
|
3608
|
+
FilterDropdownFooter,
|
|
3609
|
+
Freshness,
|
|
2619
3610
|
InfoTip,
|
|
2620
3611
|
LineChartPlaceholder,
|
|
3612
|
+
MultiSelectFilter,
|
|
2621
3613
|
NO_RESULTS_BODY,
|
|
2622
3614
|
NO_RESULTS_TITLE,
|
|
3615
|
+
NameListModal,
|
|
2623
3616
|
NoResultsEmptyState,
|
|
2624
3617
|
PRIMARY_ACTION_CLASS,
|
|
3618
|
+
Pager,
|
|
2625
3619
|
PieChartPlaceholder,
|
|
2626
3620
|
PublisherBreakdownList,
|
|
2627
3621
|
QUIET_ACTION_CLASS,
|
|
@@ -2631,9 +3625,19 @@ function PublisherBreakdownList({ rows, defaultVisibleCount = 10, padded = true,
|
|
|
2631
3625
|
SelectFilter,
|
|
2632
3626
|
SelectedSection,
|
|
2633
3627
|
SelectionPicker,
|
|
3628
|
+
SortButton,
|
|
2634
3629
|
StackedColumnPlaceholder,
|
|
3630
|
+
TablePagination,
|
|
3631
|
+
Tag,
|
|
3632
|
+
Toggle,
|
|
2635
3633
|
Tooltip,
|
|
3634
|
+
WorkspaceAvatar,
|
|
2636
3635
|
WorkspaceSelectedCard,
|
|
2637
|
-
|
|
3636
|
+
buttonVariants,
|
|
3637
|
+
chipTriggerClass,
|
|
3638
|
+
cycleSort,
|
|
3639
|
+
noResultsBody,
|
|
3640
|
+
resolveRange,
|
|
3641
|
+
sortProp
|
|
2638
3642
|
});
|
|
2639
3643
|
//# sourceMappingURL=index.cjs.map
|