@mediaradar/design-components 0.6.0 → 0.7.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 +392 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +256 -2
- package/dist/index.d.ts +256 -2
- package/dist/index.js +379 -8
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/scripts/tailwind-coverage.mjs +3 -0
package/README.md
CHANGED
|
@@ -5,9 +5,8 @@ components genuinely common across consuming apps (`insights-studio-prototype`,
|
|
|
5
5
|
`mr-clientapps-insights-studio`), published as a real npm package so there's
|
|
6
6
|
structurally only one implementation instead of two that can silently drift.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
at all. See `gh-design-system`'s open spike PR for the current state.
|
|
8
|
+
Published to npm and consumed by `insights-studio-prototype`. See
|
|
9
|
+
`CHANGELOG.md` for what each version contains.
|
|
11
10
|
|
|
12
11
|
---
|
|
13
12
|
|
|
@@ -24,6 +23,16 @@ components, for example), forcing it into a shared package is a downgrade
|
|
|
24
23
|
for whichever app had the better version, not an improvement. Leave it
|
|
25
24
|
where it is.
|
|
26
25
|
|
|
26
|
+
**Exception: generic design-system primitives** (decided 2026-09-25).
|
|
27
|
+
Basic building blocks like `Button`, `Toggle`, `AISpark` and `Freshness`
|
|
28
|
+
belong here even without an `mr-clientapps` duplicate. Two reasons: shared
|
|
29
|
+
components are built on them (`FilterDropdownFooter` and `NameListModal`
|
|
30
|
+
can't move without `Button`), and the component catalog and style guide
|
|
31
|
+
are moving to read from this package alone, so a primitive left behind
|
|
32
|
+
would drop out of both. Page- or data-specific components with no
|
|
33
|
+
duplicate (`EmbeddedFrame`, `ParkedSection`) still stay in their app, and
|
|
34
|
+
out of the catalog.
|
|
35
|
+
|
|
27
36
|
**The escape hatch — a genuine conflict discovered mid-migration.** Sometimes
|
|
28
37
|
a component looks like a good candidate until reconciliation actually starts,
|
|
29
38
|
and it turns out the two apps need behavior that's genuinely incompatible —
|
package/dist/index.cjs
CHANGED
|
@@ -24,17 +24,23 @@ __export(index_exports, {
|
|
|
24
24
|
AdvertiserQuickFilter: () => AdvertiserQuickFilter,
|
|
25
25
|
AdvertiserSearchPrompt: () => AdvertiserSearchPrompt,
|
|
26
26
|
BarChartPlaceholder: () => BarChartPlaceholder,
|
|
27
|
+
Button: () => Button,
|
|
27
28
|
Card: () => Card,
|
|
28
29
|
CheckBox: () => CheckBox,
|
|
30
|
+
ChipContent: () => ChipContent,
|
|
29
31
|
DEFAULT_SEARCH_MATCH: () => DEFAULT_SEARCH_MATCH,
|
|
30
32
|
DataScopeFilter: () => DataScopeFilter,
|
|
31
33
|
DateRangeFilter: () => DateRangeFilter,
|
|
34
|
+
FilterChipBar: () => FilterChipBar,
|
|
35
|
+
FilterDropdownFooter: () => FilterDropdownFooter,
|
|
32
36
|
InfoTip: () => InfoTip,
|
|
33
37
|
LineChartPlaceholder: () => LineChartPlaceholder,
|
|
34
38
|
NO_RESULTS_BODY: () => NO_RESULTS_BODY,
|
|
35
39
|
NO_RESULTS_TITLE: () => NO_RESULTS_TITLE,
|
|
40
|
+
NameListModal: () => NameListModal,
|
|
36
41
|
NoResultsEmptyState: () => NoResultsEmptyState,
|
|
37
42
|
PRIMARY_ACTION_CLASS: () => PRIMARY_ACTION_CLASS,
|
|
43
|
+
Pager: () => Pager,
|
|
38
44
|
PieChartPlaceholder: () => PieChartPlaceholder,
|
|
39
45
|
PublisherBreakdownList: () => PublisherBreakdownList,
|
|
40
46
|
QUIET_ACTION_CLASS: () => QUIET_ACTION_CLASS,
|
|
@@ -44,10 +50,16 @@ __export(index_exports, {
|
|
|
44
50
|
SelectFilter: () => SelectFilter,
|
|
45
51
|
SelectedSection: () => SelectedSection,
|
|
46
52
|
SelectionPicker: () => SelectionPicker,
|
|
53
|
+
SortButton: () => SortButton,
|
|
47
54
|
StackedColumnPlaceholder: () => StackedColumnPlaceholder,
|
|
48
55
|
Tooltip: () => Tooltip,
|
|
56
|
+
WorkspaceAvatar: () => WorkspaceAvatar,
|
|
49
57
|
WorkspaceSelectedCard: () => WorkspaceSelectedCard,
|
|
50
|
-
|
|
58
|
+
buttonVariants: () => buttonVariants,
|
|
59
|
+
chipTriggerClass: () => chipTriggerClass,
|
|
60
|
+
cycleSort: () => cycleSort,
|
|
61
|
+
noResultsBody: () => noResultsBody,
|
|
62
|
+
sortProp: () => sortProp
|
|
51
63
|
});
|
|
52
64
|
module.exports = __toCommonJS(index_exports);
|
|
53
65
|
|
|
@@ -1598,7 +1610,7 @@ function AxisFrame({
|
|
|
1598
1610
|
"div",
|
|
1599
1611
|
{
|
|
1600
1612
|
className: "absolute inset-x-0 border-t border-dashed",
|
|
1601
|
-
style: { top: `${pct}%`, borderColor: "var(--color-border-default)" }
|
|
1613
|
+
style: { top: `${pct}%`, borderColor: "var(--mr-color-border-default)" }
|
|
1602
1614
|
},
|
|
1603
1615
|
pct
|
|
1604
1616
|
)),
|
|
@@ -1671,7 +1683,7 @@ function LineChartPlaceholder({ height = 280 }) {
|
|
|
1671
1683
|
{
|
|
1672
1684
|
points: toPath(pts, 0, LINE_FORECAST_FROM + 1),
|
|
1673
1685
|
fill: "none",
|
|
1674
|
-
stroke: "var(--color-border-strong)",
|
|
1686
|
+
stroke: "var(--mr-color-border-strong)",
|
|
1675
1687
|
strokeWidth: "2",
|
|
1676
1688
|
vectorEffect: "non-scaling-stroke",
|
|
1677
1689
|
strokeLinecap: "round",
|
|
@@ -1683,7 +1695,7 @@ function LineChartPlaceholder({ height = 280 }) {
|
|
|
1683
1695
|
{
|
|
1684
1696
|
points: toPath(pts, LINE_FORECAST_FROM, pts.length),
|
|
1685
1697
|
fill: "none",
|
|
1686
|
-
stroke: "var(--color-border-strong)",
|
|
1698
|
+
stroke: "var(--mr-color-border-strong)",
|
|
1687
1699
|
strokeWidth: "2",
|
|
1688
1700
|
strokeDasharray: "5 4",
|
|
1689
1701
|
vectorEffect: "non-scaling-stroke",
|
|
@@ -1700,7 +1712,7 @@ function LineChartPlaceholder({ height = 280 }) {
|
|
|
1700
1712
|
style: {
|
|
1701
1713
|
left: `${i / (pts.length - 1) * 100}%`,
|
|
1702
1714
|
top: `${y}%`,
|
|
1703
|
-
backgroundColor: "var(--color-border-strong)"
|
|
1715
|
+
backgroundColor: "var(--mr-color-border-strong)"
|
|
1704
1716
|
}
|
|
1705
1717
|
},
|
|
1706
1718
|
`${s}-${i}`
|
|
@@ -1716,7 +1728,7 @@ function PieChartPlaceholder({ height = 220, legendRows = 8 }) {
|
|
|
1716
1728
|
const r = 45;
|
|
1717
1729
|
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
1730
|
/* @__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)" }),
|
|
1731
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "50", cy: "50", r, fill: "var(--mr-color-subtle)" }),
|
|
1720
1732
|
PIE_SEAMS.map((deg) => {
|
|
1721
1733
|
const rad = (deg - 90) * Math.PI / 180;
|
|
1722
1734
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
@@ -1726,7 +1738,7 @@ function PieChartPlaceholder({ height = 220, legendRows = 8 }) {
|
|
|
1726
1738
|
y1: "50",
|
|
1727
1739
|
x2: 50 + r * Math.cos(rad),
|
|
1728
1740
|
y2: 50 + r * Math.sin(rad),
|
|
1729
|
-
stroke: "var(--color-border-default)",
|
|
1741
|
+
stroke: "var(--mr-color-border-default)",
|
|
1730
1742
|
strokeWidth: "1"
|
|
1731
1743
|
},
|
|
1732
1744
|
deg
|
|
@@ -1758,7 +1770,7 @@ function StackedColumnPlaceholder({
|
|
|
1758
1770
|
height: `${pct}%`,
|
|
1759
1771
|
/* border-strong, not border-default: on a subtle fill the softer
|
|
1760
1772
|
seam disappears and the stack reads as one undivided block. */
|
|
1761
|
-
borderTop: i === 0 ? void 0 : "1px solid var(--color-border-strong)"
|
|
1773
|
+
borderTop: i === 0 ? void 0 : "1px solid var(--mr-color-border-strong)"
|
|
1762
1774
|
}
|
|
1763
1775
|
},
|
|
1764
1776
|
i
|
|
@@ -2605,23 +2617,388 @@ function PublisherBreakdownList({ rows, defaultVisibleCount = 10, padded = true,
|
|
|
2605
2617
|
] }))
|
|
2606
2618
|
] });
|
|
2607
2619
|
}
|
|
2620
|
+
|
|
2621
|
+
// src/Button.tsx
|
|
2622
|
+
var import_react13 = require("react");
|
|
2623
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
2624
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
2625
|
+
var import_lucide_react15 = require("lucide-react");
|
|
2626
|
+
|
|
2627
|
+
// src/cn.ts
|
|
2628
|
+
var import_clsx = require("clsx");
|
|
2629
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
2630
|
+
function cn(...inputs) {
|
|
2631
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
// src/Button.tsx
|
|
2635
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2636
|
+
var buttonVariants = (0, import_class_variance_authority.cva)(
|
|
2637
|
+
"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",
|
|
2638
|
+
{
|
|
2639
|
+
variants: {
|
|
2640
|
+
variant: {
|
|
2641
|
+
primary: "bg-brand-primaryAction text-brand-onprimary hover:brightness-110",
|
|
2642
|
+
secondary: "bg-surface text-text-primary border border-border-interactive hover:bg-subtle",
|
|
2643
|
+
ghost: "text-text-primary hover:bg-subtle",
|
|
2644
|
+
danger: "bg-status-danger text-status-onstatus hover:brightness-110",
|
|
2645
|
+
link: "text-text-link underline-offset-4 hover:underline px-0"
|
|
2646
|
+
},
|
|
2647
|
+
size: {
|
|
2648
|
+
sm: "h-8 px-3 text-sm",
|
|
2649
|
+
md: "h-10 px-4 text-sm",
|
|
2650
|
+
lg: "h-11 px-6 text-sm",
|
|
2651
|
+
icon: "h-9 w-9 p-0"
|
|
2652
|
+
}
|
|
2653
|
+
},
|
|
2654
|
+
defaultVariants: {
|
|
2655
|
+
variant: "primary",
|
|
2656
|
+
size: "md"
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
);
|
|
2660
|
+
var Button = (0, import_react13.forwardRef)(
|
|
2661
|
+
({ className, variant, size, asChild = false, loading = false, disabled, children, ...props }, ref) => {
|
|
2662
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
2663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
2664
|
+
Comp,
|
|
2665
|
+
{
|
|
2666
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
2667
|
+
ref,
|
|
2668
|
+
disabled: disabled || loading,
|
|
2669
|
+
"aria-busy": loading || void 0,
|
|
2670
|
+
...props,
|
|
2671
|
+
children: [
|
|
2672
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react15.Loader2, { className: "size-4 shrink-0 animate-spin", "aria-hidden": "true" }),
|
|
2673
|
+
children
|
|
2674
|
+
]
|
|
2675
|
+
}
|
|
2676
|
+
);
|
|
2677
|
+
}
|
|
2678
|
+
);
|
|
2679
|
+
Button.displayName = "Button";
|
|
2680
|
+
|
|
2681
|
+
// src/FilterDropdownFooter.tsx
|
|
2682
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2683
|
+
function FilterDropdownFooter({
|
|
2684
|
+
onClear,
|
|
2685
|
+
onApply,
|
|
2686
|
+
clearLabel = "Clear all",
|
|
2687
|
+
applyLabel = "Apply"
|
|
2688
|
+
}) {
|
|
2689
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
2690
|
+
"div",
|
|
2691
|
+
{
|
|
2692
|
+
className: cn(
|
|
2693
|
+
"flex items-center gap-2 border-t border-border-default p-2",
|
|
2694
|
+
onClear ? "justify-between" : "justify-end"
|
|
2695
|
+
),
|
|
2696
|
+
children: [
|
|
2697
|
+
onClear && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { type: "button", variant: "ghost", size: "sm", onClick: onClear, children: clearLabel }),
|
|
2698
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { type: "button", variant: "primary", size: "sm", onClick: onApply, children: applyLabel })
|
|
2699
|
+
]
|
|
2700
|
+
}
|
|
2701
|
+
);
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
// src/NameListModal.tsx
|
|
2705
|
+
var import_react14 = require("react");
|
|
2706
|
+
var import_react_dom5 = require("react-dom");
|
|
2707
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2708
|
+
function NameListModal({ title, initialName, submitLabel, onCancel, onSubmit }) {
|
|
2709
|
+
const [name, setName] = (0, import_react14.useState)(initialName);
|
|
2710
|
+
(0, import_react14.useEffect)(() => {
|
|
2711
|
+
const onKey = (e) => e.key === "Escape" && onCancel();
|
|
2712
|
+
window.addEventListener("keydown", onKey);
|
|
2713
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
2714
|
+
}, [onCancel]);
|
|
2715
|
+
return (0, import_react_dom5.createPortal)(
|
|
2716
|
+
// The scrim is a literal: @mediaradar/design-tokens has no scrim token yet.
|
|
2717
|
+
// Same light/dark values as insights-studio-prototype's local --color-scrim;
|
|
2718
|
+
// the dark one keys off data-theme, the attribute design-tokens' dark.css uses.
|
|
2719
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2720
|
+
"div",
|
|
2721
|
+
{
|
|
2722
|
+
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",
|
|
2723
|
+
onMouseDown: (e) => e.target === e.currentTarget && onCancel(),
|
|
2724
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
2725
|
+
"div",
|
|
2726
|
+
{
|
|
2727
|
+
role: "dialog",
|
|
2728
|
+
"aria-modal": "true",
|
|
2729
|
+
"aria-label": title,
|
|
2730
|
+
className: "w-full max-w-[420px] rounded-card border border-border-default bg-surface p-5 shadow-overlay",
|
|
2731
|
+
children: [
|
|
2732
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { className: "text-[16px] font-semibold text-text-primary", children: title }),
|
|
2733
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mt-4 flex flex-col gap-1.5", children: [
|
|
2734
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("label", { htmlFor: "account-list-name", className: "text-[12px] font-medium text-text-secondary", children: "List name" }),
|
|
2735
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2736
|
+
"input",
|
|
2737
|
+
{
|
|
2738
|
+
id: "account-list-name",
|
|
2739
|
+
autoFocus: true,
|
|
2740
|
+
value: name,
|
|
2741
|
+
onChange: (e) => setName(e.target.value),
|
|
2742
|
+
placeholder: "e.g. Q4 prospecting targets",
|
|
2743
|
+
className: "h-10 rounded-control border border-border-default bg-input px-3 text-sm outline-hidden focus:border-brand-primaryAction"
|
|
2744
|
+
}
|
|
2745
|
+
)
|
|
2746
|
+
] }),
|
|
2747
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mt-5 flex items-center justify-end gap-2", children: [
|
|
2748
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { variant: "secondary", onClick: onCancel, children: "Cancel" }),
|
|
2749
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { disabled: !name.trim(), onClick: () => onSubmit(name.trim()), children: submitLabel })
|
|
2750
|
+
] })
|
|
2751
|
+
]
|
|
2752
|
+
}
|
|
2753
|
+
)
|
|
2754
|
+
}
|
|
2755
|
+
),
|
|
2756
|
+
document.body
|
|
2757
|
+
);
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
// src/ChipTrigger.tsx
|
|
2761
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2762
|
+
function chipTriggerClass() {
|
|
2763
|
+
return cn(
|
|
2764
|
+
"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",
|
|
2765
|
+
// Sits on the input fill, with a stroke dark enough to still read as a
|
|
2766
|
+
// control against the warm canvas.
|
|
2767
|
+
"border-border-strong"
|
|
2768
|
+
);
|
|
2769
|
+
}
|
|
2770
|
+
function ChipContent({ caption, value, icon }) {
|
|
2771
|
+
const stack = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "flex flex-col gap-1 text-left leading-none", children: [
|
|
2772
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-[10px] uppercase tracking-wide text-text-tertiary", children: caption }),
|
|
2773
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-[12px] font-medium text-text-primary", children: value })
|
|
2774
|
+
] });
|
|
2775
|
+
if (icon) {
|
|
2776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
2777
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "shrink-0 text-text-tertiary", children: icon }),
|
|
2778
|
+
stack
|
|
2779
|
+
] });
|
|
2780
|
+
}
|
|
2781
|
+
return stack;
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
// src/FilterChipBar.tsx
|
|
2785
|
+
var import_lucide_react16 = require("lucide-react");
|
|
2786
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
2787
|
+
function FilterChipBar({ chips, onRemove, onClearAll, parkedKeys }) {
|
|
2788
|
+
if (chips.length === 0) return null;
|
|
2789
|
+
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: [
|
|
2790
|
+
chips.map((c) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2791
|
+
Chip,
|
|
2792
|
+
{
|
|
2793
|
+
label: c.label,
|
|
2794
|
+
groupLabel: c.groupLabel,
|
|
2795
|
+
parked: !!parkedKeys?.has(c.key),
|
|
2796
|
+
onRemove: () => onRemove(c)
|
|
2797
|
+
},
|
|
2798
|
+
c.key
|
|
2799
|
+
)),
|
|
2800
|
+
/* @__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" })
|
|
2801
|
+
] });
|
|
2802
|
+
}
|
|
2803
|
+
function Chip({
|
|
2804
|
+
label,
|
|
2805
|
+
groupLabel,
|
|
2806
|
+
parked,
|
|
2807
|
+
onRemove
|
|
2808
|
+
}) {
|
|
2809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "group relative inline-flex", children: [
|
|
2810
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2811
|
+
"span",
|
|
2812
|
+
{
|
|
2813
|
+
className: cn(
|
|
2814
|
+
"flex items-center gap-1 rounded-full px-2.5 py-1 text-[12px] font-medium ring-1 transition-colors",
|
|
2815
|
+
parked ? (
|
|
2816
|
+
// No fill, dashed edge, muted label: reads as "held, not acting on
|
|
2817
|
+
// anything" against the solid applied chips beside it.
|
|
2818
|
+
"border border-dashed border-border-default bg-transparent text-text-tertiary ring-transparent group-hover:text-text-secondary"
|
|
2819
|
+
) : "bg-subtle text-text-secondary ring-transparent group-hover:bg-border-default group-hover:text-text-primary group-hover:ring-border-interactive"
|
|
2820
|
+
),
|
|
2821
|
+
children: [
|
|
2822
|
+
parked && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.CircleSlash, { size: 11, "aria-hidden": "true", className: "shrink-0 text-text-tertiary" }),
|
|
2823
|
+
label,
|
|
2824
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2825
|
+
"button",
|
|
2826
|
+
{
|
|
2827
|
+
type: "button",
|
|
2828
|
+
onClick: onRemove,
|
|
2829
|
+
"aria-label": `Remove ${groupLabel}: ${label}`,
|
|
2830
|
+
className: "text-text-tertiary transition-colors hover:text-text-primary",
|
|
2831
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.X, { size: 12 })
|
|
2832
|
+
}
|
|
2833
|
+
)
|
|
2834
|
+
]
|
|
2835
|
+
}
|
|
2836
|
+
),
|
|
2837
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2838
|
+
"span",
|
|
2839
|
+
{
|
|
2840
|
+
role: "tooltip",
|
|
2841
|
+
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",
|
|
2842
|
+
children: parked ? "Not in this workspace" : groupLabel
|
|
2843
|
+
}
|
|
2844
|
+
)
|
|
2845
|
+
] });
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
// src/SortButton.tsx
|
|
2849
|
+
var import_lucide_react17 = require("lucide-react");
|
|
2850
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2851
|
+
function SortButton({ label, sortKey, sort, onSort, disabled = false }) {
|
|
2852
|
+
const active = !disabled && sort.key === sortKey;
|
|
2853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
2854
|
+
"button",
|
|
2855
|
+
{
|
|
2856
|
+
type: "button",
|
|
2857
|
+
disabled,
|
|
2858
|
+
onClick: () => onSort(sortKey),
|
|
2859
|
+
"aria-sort": active ? sort.dir === "asc" ? "ascending" : "descending" : "none",
|
|
2860
|
+
className: cn(
|
|
2861
|
+
// text-left overrides the UA default on <button>, which would centre a
|
|
2862
|
+
// label that wraps onto two lines, out of step with the column under it.
|
|
2863
|
+
"group inline-flex items-center gap-1 text-left uppercase tracking-wide transition-colors",
|
|
2864
|
+
!disabled && "hover:text-text-primary"
|
|
2865
|
+
),
|
|
2866
|
+
children: [
|
|
2867
|
+
label,
|
|
2868
|
+
!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)(
|
|
2869
|
+
import_lucide_react17.ArrowUpDown,
|
|
2870
|
+
{
|
|
2871
|
+
size: 12,
|
|
2872
|
+
className: "shrink-0 text-text-tertiary opacity-50 transition-opacity group-hover:opacity-100"
|
|
2873
|
+
}
|
|
2874
|
+
))
|
|
2875
|
+
]
|
|
2876
|
+
}
|
|
2877
|
+
);
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
// src/tableSort.ts
|
|
2881
|
+
function cycleSort(current, key, firstDir = "desc") {
|
|
2882
|
+
if (!current || current.key !== key) return { key, dir: firstDir };
|
|
2883
|
+
if (current.dir === firstDir) return { key, dir: firstDir === "desc" ? "asc" : "desc" };
|
|
2884
|
+
return null;
|
|
2885
|
+
}
|
|
2886
|
+
function sortProp(sort) {
|
|
2887
|
+
return sort ?? { key: null, dir: "desc" };
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
// src/Pager.tsx
|
|
2891
|
+
var import_lucide_react18 = require("lucide-react");
|
|
2892
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
2893
|
+
function pageWindow(current, total) {
|
|
2894
|
+
if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
|
|
2895
|
+
const keep = /* @__PURE__ */ new Set([1, total, current, current - 1, current + 1]);
|
|
2896
|
+
const pages = [...keep].filter((p) => p >= 1 && p <= total).sort((a, b) => a - b);
|
|
2897
|
+
const out = [];
|
|
2898
|
+
let prev = 0;
|
|
2899
|
+
for (const p of pages) {
|
|
2900
|
+
if (p - prev > 1) out.push(`gap-${p}`);
|
|
2901
|
+
out.push(p);
|
|
2902
|
+
prev = p;
|
|
2903
|
+
}
|
|
2904
|
+
return out;
|
|
2905
|
+
}
|
|
2906
|
+
function Pager({ page, totalPages, onPage }) {
|
|
2907
|
+
const btn = "flex h-8 min-w-8 items-center justify-center rounded-control px-2 text-[13px] transition-colors";
|
|
2908
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
2909
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2910
|
+
"button",
|
|
2911
|
+
{
|
|
2912
|
+
type: "button",
|
|
2913
|
+
onClick: () => onPage(page - 1),
|
|
2914
|
+
disabled: page === 1,
|
|
2915
|
+
"aria-label": "Previous page",
|
|
2916
|
+
className: cn(btn, "text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30"),
|
|
2917
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react18.ChevronLeft, { size: 16 })
|
|
2918
|
+
}
|
|
2919
|
+
),
|
|
2920
|
+
pageWindow(page, totalPages).map(
|
|
2921
|
+
(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)(
|
|
2922
|
+
"button",
|
|
2923
|
+
{
|
|
2924
|
+
type: "button",
|
|
2925
|
+
onClick: () => onPage(p),
|
|
2926
|
+
"aria-current": p === page ? "page" : void 0,
|
|
2927
|
+
className: cn(
|
|
2928
|
+
btn,
|
|
2929
|
+
p === page ? "bg-brand-primaryAction font-semibold text-brand-onprimary" : "text-text-secondary hover:bg-subtle hover:text-text-primary"
|
|
2930
|
+
),
|
|
2931
|
+
children: p
|
|
2932
|
+
},
|
|
2933
|
+
p
|
|
2934
|
+
)
|
|
2935
|
+
),
|
|
2936
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2937
|
+
"button",
|
|
2938
|
+
{
|
|
2939
|
+
type: "button",
|
|
2940
|
+
onClick: () => onPage(page + 1),
|
|
2941
|
+
disabled: page === totalPages,
|
|
2942
|
+
"aria-label": "Next page",
|
|
2943
|
+
className: cn(btn, "text-text-secondary hover:bg-subtle hover:text-text-primary disabled:pointer-events-none disabled:opacity-30"),
|
|
2944
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react18.ChevronRight, { size: 16 })
|
|
2945
|
+
}
|
|
2946
|
+
)
|
|
2947
|
+
] });
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
// src/WorkspaceAvatar.tsx
|
|
2951
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
2952
|
+
function workspaceInitials(name) {
|
|
2953
|
+
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
2954
|
+
if (words.length === 0) return "\xB7";
|
|
2955
|
+
if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
|
|
2956
|
+
return (words[0][0] + words[1][0]).toUpperCase();
|
|
2957
|
+
}
|
|
2958
|
+
var SIZES = {
|
|
2959
|
+
/** Matches a 15px lucide icon exactly, so a workspace name in a menu row
|
|
2960
|
+
* left-aligns with labels in icon-led rows above and below it. */
|
|
2961
|
+
xs: "h-[15px] w-[15px] rounded-[4px] text-[8px] tracking-tight",
|
|
2962
|
+
sm: "h-6 w-6 text-[10px]",
|
|
2963
|
+
md: "h-7 w-7 text-[11px]",
|
|
2964
|
+
lg: "h-11 w-11 text-[15px]"
|
|
2965
|
+
};
|
|
2966
|
+
function WorkspaceAvatar({ name, size = "md" }) {
|
|
2967
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2968
|
+
"span",
|
|
2969
|
+
{
|
|
2970
|
+
"aria-hidden": "true",
|
|
2971
|
+
className: cn(
|
|
2972
|
+
"flex shrink-0 items-center justify-center rounded-control bg-subtle font-semibold leading-none text-text-secondary",
|
|
2973
|
+
SIZES[size]
|
|
2974
|
+
),
|
|
2975
|
+
children: workspaceInitials(name ?? "All data")
|
|
2976
|
+
}
|
|
2977
|
+
);
|
|
2978
|
+
}
|
|
2608
2979
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2609
2980
|
0 && (module.exports = {
|
|
2610
2981
|
AdvertiserNoResults,
|
|
2611
2982
|
AdvertiserQuickFilter,
|
|
2612
2983
|
AdvertiserSearchPrompt,
|
|
2613
2984
|
BarChartPlaceholder,
|
|
2985
|
+
Button,
|
|
2614
2986
|
Card,
|
|
2615
2987
|
CheckBox,
|
|
2988
|
+
ChipContent,
|
|
2616
2989
|
DEFAULT_SEARCH_MATCH,
|
|
2617
2990
|
DataScopeFilter,
|
|
2618
2991
|
DateRangeFilter,
|
|
2992
|
+
FilterChipBar,
|
|
2993
|
+
FilterDropdownFooter,
|
|
2619
2994
|
InfoTip,
|
|
2620
2995
|
LineChartPlaceholder,
|
|
2621
2996
|
NO_RESULTS_BODY,
|
|
2622
2997
|
NO_RESULTS_TITLE,
|
|
2998
|
+
NameListModal,
|
|
2623
2999
|
NoResultsEmptyState,
|
|
2624
3000
|
PRIMARY_ACTION_CLASS,
|
|
3001
|
+
Pager,
|
|
2625
3002
|
PieChartPlaceholder,
|
|
2626
3003
|
PublisherBreakdownList,
|
|
2627
3004
|
QUIET_ACTION_CLASS,
|
|
@@ -2631,9 +3008,15 @@ function PublisherBreakdownList({ rows, defaultVisibleCount = 10, padded = true,
|
|
|
2631
3008
|
SelectFilter,
|
|
2632
3009
|
SelectedSection,
|
|
2633
3010
|
SelectionPicker,
|
|
3011
|
+
SortButton,
|
|
2634
3012
|
StackedColumnPlaceholder,
|
|
2635
3013
|
Tooltip,
|
|
3014
|
+
WorkspaceAvatar,
|
|
2636
3015
|
WorkspaceSelectedCard,
|
|
2637
|
-
|
|
3016
|
+
buttonVariants,
|
|
3017
|
+
chipTriggerClass,
|
|
3018
|
+
cycleSort,
|
|
3019
|
+
noResultsBody,
|
|
3020
|
+
sortProp
|
|
2638
3021
|
});
|
|
2639
3022
|
//# sourceMappingURL=index.cjs.map
|