@mediaradar/design-components 0.20.0 → 0.21.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/dist/index.js CHANGED
@@ -233,7 +233,7 @@ function AdvertiserQuickFilter({
233
233
  "aria-label": caption,
234
234
  "data-testid": testIdPrefix && `${testIdPrefix}-popover`,
235
235
  children: [
236
- /* @__PURE__ */ jsx3("div", { className: "border-b border-border-default p-2", children: /* @__PURE__ */ jsxs3("div", { className: "flex h-9 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 focus-within:border-border-focus focus-within:ring-2 focus-within:ring-border-focus/30", children: [
236
+ /* @__PURE__ */ jsx3("div", { className: "border-b border-border-default p-2", children: /* @__PURE__ */ jsxs3("div", { className: "flex h-8 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 focus-within:outline-2 focus-within:outline-offset-1 focus-within:outline-border-focus", children: [
237
237
  /* @__PURE__ */ jsx3(Search2, { size: 14, className: "shrink-0 text-text-secondary", "aria-hidden": "true" }),
238
238
  /* @__PURE__ */ jsx3(
239
239
  "input",
@@ -910,8 +910,9 @@ function NavBtn({ children, onClick, ...rest }) {
910
910
 
911
911
  // src/SearchBar.tsx
912
912
  import { useEffect as useEffect4, useId as useId2, useRef as useRef4, useState as useState4 } from "react";
913
- import { AlertCircle, Check as Check3, ChevronDown as ChevronDown3, Search as Search3 } from "lucide-react";
913
+ import { AlertCircle, Check as Check3, ChevronDown as ChevronDown3, Search as Search3, X as X2 } from "lucide-react";
914
914
  import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
915
+ var HEIGHT = { sm: "h-8", md: "h-10", lg: "h-11" };
915
916
  var DEFAULT_SEARCH_MATCH = { mode: "anyWord", wordJoin: "Or" };
916
917
  var MODE_LABEL = {
917
918
  anyWord: "Any Word",
@@ -927,6 +928,7 @@ function SearchBar({
927
928
  value,
928
929
  onChange,
929
930
  variant = "default",
931
+ size = "lg",
930
932
  matchValue,
931
933
  onMatchChange,
932
934
  className,
@@ -934,6 +936,7 @@ function SearchBar({
934
936
  }) {
935
937
  const [open, setOpen] = useState4(false);
936
938
  const ref = useRef4(null);
939
+ const input = useRef4(null);
937
940
  useEffect4(() => {
938
941
  if (!open) return;
939
942
  const onKey = (e) => e.key === "Escape" && setOpen(false);
@@ -952,7 +955,8 @@ function SearchBar({
952
955
  "div",
953
956
  {
954
957
  className: cx2(
955
- "flex h-11 min-w-[200px] flex-1 items-stretch rounded-control border border-border-strong bg-input",
958
+ "flex min-w-[200px] flex-1 items-stretch rounded-control border border-border-strong bg-input focus-within:outline-2 focus-within:outline-offset-1 focus-within:outline-border-focus",
959
+ HEIGHT[size],
956
960
  className
957
961
  ),
958
962
  children: [
@@ -961,16 +965,31 @@ function SearchBar({
961
965
  /* @__PURE__ */ jsx8(
962
966
  "input",
963
967
  {
968
+ ref: input,
964
969
  type: "text",
965
970
  value,
966
971
  onChange: (e) => onChange?.(e.target.value),
967
972
  placeholder,
968
973
  "aria-label": placeholder,
969
974
  "data-testid": testIdPrefix && `${testIdPrefix}-search`,
970
- className: "min-w-0 flex-1 bg-transparent text-[13px] text-text-primary outline-hidden placeholder:text-text-tertiary"
975
+ className: "min-w-0 flex-1 bg-transparent text-dense text-text-primary outline-hidden placeholder:text-text-tertiary"
971
976
  }
972
977
  )
973
978
  ] }),
979
+ value && onChange && /* @__PURE__ */ jsx8(
980
+ "button",
981
+ {
982
+ type: "button",
983
+ onClick: () => {
984
+ onChange("");
985
+ input.current?.focus();
986
+ },
987
+ "aria-label": "Clear search",
988
+ "data-testid": testIdPrefix && `${testIdPrefix}-clear`,
989
+ className: "mr-1.5 flex size-6 shrink-0 items-center justify-center self-center rounded-control text-text-tertiary hover:bg-subtle hover:text-text-primary focus-visible:outline-2 focus-visible:outline-border-focus",
990
+ children: /* @__PURE__ */ jsx8(X2, { size: 14, "aria-hidden": "true" })
991
+ }
992
+ ),
974
993
  showMatch && // border-border-default, not the bare `border-border` both source
975
994
  // implementations used -- confirmed by actually compiling against
976
995
  // @mediaradar/design-tokens' real published theme.css (not assumed):
@@ -1609,7 +1628,7 @@ function NoResultsEmptyState({
1609
1628
 
1610
1629
  // src/WorkspaceSelectedCard.tsx
1611
1630
  import { useEffect as useEffect7, useRef as useRef8, useState as useState7 } from "react";
1612
- import { ChevronDown as ChevronDown6, X as X2 } from "lucide-react";
1631
+ import { ChevronDown as ChevronDown6, X as X3 } from "lucide-react";
1613
1632
  import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1614
1633
  function cx5(...parts) {
1615
1634
  return parts.filter(Boolean).join(" ");
@@ -1673,7 +1692,7 @@ function SummaryGroupItem({
1673
1692
  "aria-label": `Remove ${item.name}`,
1674
1693
  onClick: () => group.onRemove(item.id),
1675
1694
  className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-control text-text-secondary hover:bg-subtle hover:text-text-danger",
1676
- children: /* @__PURE__ */ jsx14(X2, { size: 12, "aria-hidden": "true" })
1695
+ children: /* @__PURE__ */ jsx14(X3, { size: 12, "aria-hidden": "true" })
1677
1696
  }
1678
1697
  )
1679
1698
  ]
@@ -2322,7 +2341,7 @@ function SelectionPicker({
2322
2341
  }) }),
2323
2342
  source === "search" && /* @__PURE__ */ jsxs22("div", { className: "flex min-w-0 flex-col gap-3", children: [
2324
2343
  /* @__PURE__ */ jsxs22("div", { className: "flex flex-wrap items-center gap-2", children: [
2325
- /* @__PURE__ */ jsxs22("div", { className: "flex h-9 min-w-[200px] flex-1 items-center gap-2 rounded-control border border-border-strong bg-input px-3", children: [
2344
+ /* @__PURE__ */ jsxs22("div", { className: "flex h-8 min-w-[200px] flex-1 items-center gap-2 rounded-control border border-border-strong bg-input px-3 focus-within:outline-2 focus-within:outline-offset-1 focus-within:outline-border-focus", children: [
2326
2345
  /* @__PURE__ */ jsx24(Search4, { size: 15, className: "text-text-secondary", "aria-hidden": "true" }),
2327
2346
  /* @__PURE__ */ jsx24(
2328
2347
  "input",
@@ -2636,7 +2655,7 @@ function FilterDropdown({
2636
2655
  onClick: () => setOpen((v) => !v),
2637
2656
  "aria-expanded": open,
2638
2657
  "data-testid": testIdPrefix && `${testIdPrefix}-filter-${filterSlug}`,
2639
- className: "inline-flex h-9 items-center gap-1.5 whitespace-nowrap rounded-control border border-border-strong bg-input px-3 text-[13px] font-medium text-text-secondary transition-colors hover:bg-subtle",
2658
+ className: "inline-flex h-8 items-center gap-1.5 whitespace-nowrap rounded-control border border-border-strong bg-input px-3 text-[13px] font-medium text-text-secondary transition-colors hover:bg-subtle",
2640
2659
  children: [
2641
2660
  label,
2642
2661
  /* @__PURE__ */ jsx24(ChevronDown8, { size: 13, "aria-hidden": "true", className: cx8("transition-transform", open && "rotate-180") })
@@ -2842,7 +2861,10 @@ var buttonVariants = cva(
2842
2861
  size: {
2843
2862
  xs: "h-6 px-2 text-xs",
2844
2863
  sm: "h-8 px-3 text-sm",
2845
- md: "h-10 px-4 text-sm"
2864
+ md: "h-10 px-4 text-sm",
2865
+ // 44, the filter row's height, so a button at the end of a row of
2866
+ // filter dropdowns lines up with them. One control scale: 32 / 40 / 44.
2867
+ lg: "h-11 px-5 text-sm"
2846
2868
  },
2847
2869
  // Shape is orthogonal to size. As a fourth SIZE, `icon` could only ever
2848
2870
  // be one dimension, so an icon button never lined up with the labelled
@@ -2857,6 +2879,7 @@ var buttonVariants = cva(
2857
2879
  { size: "xs", iconOnly: true, class: "w-6" },
2858
2880
  { size: "sm", iconOnly: true, class: "w-8" },
2859
2881
  { size: "md", iconOnly: true, class: "w-10" },
2882
+ { size: "lg", iconOnly: true, class: "w-11" },
2860
2883
  // A boxed button is a target you aim at, so its label carries the weight
2861
2884
  // of one. `link` sits inline in a sentence, where semibold reads as
2862
2885
  // emphasis on the words rather than as a control.
@@ -2970,7 +2993,7 @@ function NameListModal({
2970
2993
  /* @__PURE__ */ jsx28(
2971
2994
  "div",
2972
2995
  {
2973
- className: "fixed inset-0 z-70 flex items-center justify-center bg-scrim px-4",
2996
+ className: "fixed inset-0 z-modal flex items-center justify-center bg-scrim px-4",
2974
2997
  onMouseDown: (e) => e.target === e.currentTarget && onCancel(),
2975
2998
  children: /* @__PURE__ */ jsxs26(
2976
2999
  "div",
@@ -2980,7 +3003,7 @@ function NameListModal({
2980
3003
  "aria-modal": "true",
2981
3004
  "aria-labelledby": titleId,
2982
3005
  onKeyDown: trapTab,
2983
- className: "w-full max-w-[420px] rounded-card border border-border-default bg-surface p-5 shadow-overlay",
3006
+ className: "w-full max-w-110 rounded-card border border-border-default bg-surface p-5 shadow-overlay",
2984
3007
  children: [
2985
3008
  /* @__PURE__ */ jsx28("h2", { id: titleId, className: "text-[16px] font-semibold text-text-primary", children: title }),
2986
3009
  /* @__PURE__ */ jsxs26("div", { className: "mt-4 flex flex-col gap-1.5", children: [
@@ -2993,7 +3016,7 @@ function NameListModal({
2993
3016
  value: name,
2994
3017
  onChange: (e) => setName(e.target.value),
2995
3018
  placeholder,
2996
- className: "h-10 rounded-control border border-border-strong bg-input px-3 text-sm outline-hidden focus:border-brand-primaryAction"
3019
+ className: "h-10 rounded-control border border-border-strong bg-input px-3 text-dense focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-border-focus"
2997
3020
  }
2998
3021
  )
2999
3022
  ] }),
@@ -3039,7 +3062,7 @@ function ChipContent({ caption, value, icon }) {
3039
3062
  }
3040
3063
 
3041
3064
  // src/FilterChipBar.tsx
3042
- import { CircleSlash, X as X3 } from "lucide-react";
3065
+ import { CircleSlash, X as X4 } from "lucide-react";
3043
3066
  import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
3044
3067
  function FilterChipBar({ chips, onRemove, onClearAll, parkedKeys }) {
3045
3068
  if (chips.length === 0) return null;
@@ -3085,7 +3108,7 @@ function Chip({
3085
3108
  onClick: onRemove,
3086
3109
  "aria-label": `Remove ${groupLabel}: ${label}`,
3087
3110
  className: "text-text-tertiary transition-colors hover:text-text-primary",
3088
- children: /* @__PURE__ */ jsx30(X3, { size: 12 })
3111
+ children: /* @__PURE__ */ jsx30(X4, { size: 12 })
3089
3112
  }
3090
3113
  )
3091
3114
  ]
@@ -3538,7 +3561,7 @@ function MiniSelect({ value, onChange, options }) {
3538
3561
  const opt = options.find((o) => String(o.value) === e.target.value);
3539
3562
  if (opt) onChange(opt.value);
3540
3563
  },
3541
- className: "rounded-control border border-border-strong bg-input px-1.5 py-1 text-[12px] text-text-primary outline-hidden focus:border-border-focus",
3564
+ className: "rounded-control border border-border-strong bg-input px-1.5 py-1 text-[12px] text-text-primary focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-border-focus",
3542
3565
  children: options.map((o) => /* @__PURE__ */ jsx37("option", { value: String(o.value), children: o.label }, String(o.value)))
3543
3566
  }
3544
3567
  );
@@ -3667,7 +3690,7 @@ function DateRangePicker({
3667
3690
 
3668
3691
  // src/MultiSelectFilter.tsx
3669
3692
  import { useCallback as useCallback4, useEffect as useEffect13, useRef as useRef14, useState as useState14 } from "react";
3670
- import { ChevronDown as ChevronDown11, Check as Check8, Minus as Minus2, Search as Search5, X as X4 } from "lucide-react";
3693
+ import { ChevronDown as ChevronDown11, Check as Check8, Minus as Minus2, Search as Search5, X as X5 } from "lucide-react";
3671
3694
  import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
3672
3695
  function MultiSelectFilter({
3673
3696
  caption,
@@ -3791,7 +3814,7 @@ function MultiSelectFilter({
3791
3814
  role: "dialog",
3792
3815
  "aria-label": caption,
3793
3816
  children: [
3794
- searchable && /* @__PURE__ */ jsx38("div", { className: "border-b border-border-default p-2", children: /* @__PURE__ */ jsxs34("div", { className: "flex h-9 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5", children: [
3817
+ searchable && /* @__PURE__ */ jsx38("div", { className: "border-b border-border-default p-2", children: /* @__PURE__ */ jsxs34("div", { className: "flex h-8 items-center gap-2 rounded-control border border-border-strong bg-input px-2.5 focus-within:outline-2 focus-within:outline-offset-1 focus-within:outline-border-focus", children: [
3795
3818
  /* @__PURE__ */ jsx38(Search5, { size: 14, className: "text-text-secondary", "aria-hidden": "true" }),
3796
3819
  /* @__PURE__ */ jsx38(
3797
3820
  "input",
@@ -3803,7 +3826,7 @@ function MultiSelectFilter({
3803
3826
  className: "h-full flex-1 bg-transparent text-[13px] outline-hidden placeholder:text-text-tertiary"
3804
3827
  }
3805
3828
  ),
3806
- q && /* @__PURE__ */ jsx38("button", { type: "button", onClick: () => setQ(""), "aria-label": "Clear search", className: "text-text-tertiary hover:text-text-primary", children: /* @__PURE__ */ jsx38(X4, { size: 13 }) })
3829
+ q && /* @__PURE__ */ jsx38("button", { type: "button", onClick: () => setQ(""), "aria-label": "Clear search", className: "text-text-tertiary hover:text-text-primary", children: /* @__PURE__ */ jsx38(X5, { size: 13 }) })
3807
3830
  ] }) }),
3808
3831
  /* @__PURE__ */ jsxs34("div", { className: "max-h-[280px] overflow-y-auto p-1", children: [
3809
3832
  groups ? visibleGroups.map((g) => {
@@ -4001,16 +4024,294 @@ function SectionHeading({ title, description, actions, as: Tag2 = "h2", id, clas
4001
4024
  }
4002
4025
 
4003
4026
  // src/PageHeader.tsx
4027
+ import { ArrowLeft } from "lucide-react";
4004
4028
  import { jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
4005
- function PageHeader({ title, description, actions, className }) {
4029
+ function PageHeader({ title, description, actions, back, className }) {
4006
4030
  return /* @__PURE__ */ jsxs37("header", { className: cn("flex flex-wrap items-center justify-between gap-x-6 gap-y-3", className), children: [
4007
4031
  /* @__PURE__ */ jsxs37("div", { className: "min-w-0", children: [
4032
+ back && /* @__PURE__ */ jsxs37(
4033
+ "a",
4034
+ {
4035
+ href: back.href ?? "#",
4036
+ onClick: back.onClick,
4037
+ className: "mb-1.5 inline-flex items-center gap-1.5 rounded-control text-micro font-semibold uppercase tracking-wider text-text-tertiary hover:text-text-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus",
4038
+ children: [
4039
+ /* @__PURE__ */ jsx43(ArrowLeft, { size: 13, "aria-hidden": "true" }),
4040
+ back.label
4041
+ ]
4042
+ }
4043
+ ),
4008
4044
  /* @__PURE__ */ jsx43("h1", { className: "text-xl font-semibold tracking-tight text-text-primary", children: title }),
4009
4045
  description && /* @__PURE__ */ jsx43("p", { className: "mt-0.5 max-w-2xl text-sm text-text-secondary", children: description })
4010
4046
  ] }),
4011
4047
  actions && /* @__PURE__ */ jsx43("div", { className: "flex shrink-0 items-center gap-2", children: actions })
4012
4048
  ] });
4013
4049
  }
4050
+
4051
+ // src/Modal.tsx
4052
+ import { useEffect as useEffect14, useId as useId6, useRef as useRef15 } from "react";
4053
+ import { createPortal as createPortal7 } from "react-dom";
4054
+ import { X as X6 } from "lucide-react";
4055
+ import { jsx as jsx44, jsxs as jsxs38 } from "react/jsx-runtime";
4056
+ var WIDTH = {
4057
+ sm: "max-w-110",
4058
+ md: "max-w-160",
4059
+ lg: "max-w-220"
4060
+ };
4061
+ var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
4062
+ function Modal({ open, onClose, title, description, size = "md", footer, children, className }) {
4063
+ const titleId = useId6();
4064
+ const descId = useId6();
4065
+ const panel = useRef15(null);
4066
+ const close = useRef15(onClose);
4067
+ close.current = onClose;
4068
+ useEffect14(() => {
4069
+ if (!open) return;
4070
+ const opener = document.activeElement;
4071
+ const first = panel.current?.querySelector(`[data-modal-body] :is(${FOCUSABLE})`) ?? panel.current?.querySelector(`[data-modal-footer] :is(${FOCUSABLE})`);
4072
+ (first ?? panel.current)?.focus();
4073
+ const overflow = document.body.style.overflow;
4074
+ document.body.style.overflow = "hidden";
4075
+ const onKey = (e) => {
4076
+ if (e.key === "Escape") {
4077
+ e.stopPropagation();
4078
+ close.current();
4079
+ return;
4080
+ }
4081
+ if (e.key !== "Tab" || !panel.current) return;
4082
+ const items = Array.from(panel.current.querySelectorAll(FOCUSABLE));
4083
+ if (items.length === 0) return;
4084
+ const [head, tail] = [items[0], items[items.length - 1]];
4085
+ if (e.shiftKey && document.activeElement === head) {
4086
+ e.preventDefault();
4087
+ tail.focus();
4088
+ } else if (!e.shiftKey && document.activeElement === tail) {
4089
+ e.preventDefault();
4090
+ head.focus();
4091
+ }
4092
+ };
4093
+ document.addEventListener("keydown", onKey);
4094
+ return () => {
4095
+ document.removeEventListener("keydown", onKey);
4096
+ document.body.style.overflow = overflow;
4097
+ opener?.focus?.();
4098
+ };
4099
+ }, [open]);
4100
+ if (!open || typeof document === "undefined") return null;
4101
+ return createPortal7(
4102
+ /* @__PURE__ */ jsx44(
4103
+ "div",
4104
+ {
4105
+ className: "fixed inset-0 z-modal flex items-center justify-center bg-scrim px-4 py-6",
4106
+ onMouseDown: (e) => e.target === e.currentTarget && onClose(),
4107
+ children: /* @__PURE__ */ jsxs38(
4108
+ "div",
4109
+ {
4110
+ ref: panel,
4111
+ role: "dialog",
4112
+ "aria-modal": "true",
4113
+ "aria-labelledby": titleId,
4114
+ "aria-describedby": description ? descId : void 0,
4115
+ tabIndex: -1,
4116
+ className: cn(
4117
+ "flex max-h-full w-full flex-col rounded-card border border-border-default bg-surface shadow-overlay outline-hidden",
4118
+ WIDTH[size],
4119
+ className
4120
+ ),
4121
+ children: [
4122
+ /* @__PURE__ */ jsxs38("div", { className: "flex items-start gap-3 px-5 pt-5 pb-3", children: [
4123
+ /* @__PURE__ */ jsxs38("div", { className: "min-w-0 flex-1", children: [
4124
+ /* @__PURE__ */ jsx44("h2", { id: titleId, className: "text-base font-semibold text-text-primary", children: title }),
4125
+ description && /* @__PURE__ */ jsx44("p", { id: descId, className: "mt-0.5 text-sm text-text-secondary", children: description })
4126
+ ] }),
4127
+ /* @__PURE__ */ jsx44(
4128
+ "button",
4129
+ {
4130
+ type: "button",
4131
+ onClick: onClose,
4132
+ "aria-label": "Close",
4133
+ className: "-mr-1.5 -mt-1 flex size-8 shrink-0 items-center justify-center rounded-control text-text-tertiary hover:bg-subtle hover:text-text-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus",
4134
+ children: /* @__PURE__ */ jsx44(X6, { size: 16, "aria-hidden": "true" })
4135
+ }
4136
+ )
4137
+ ] }),
4138
+ children && /* @__PURE__ */ jsx44("div", { "data-modal-body": true, className: "min-h-0 flex-1 overflow-y-auto px-5 pb-5 text-sm text-text-primary", children }),
4139
+ footer && /* @__PURE__ */ jsx44("div", { "data-modal-footer": true, className: "flex items-center justify-end gap-2 border-t border-border-default px-5 py-3", children: footer })
4140
+ ]
4141
+ }
4142
+ )
4143
+ }
4144
+ ),
4145
+ document.body
4146
+ );
4147
+ }
4148
+
4149
+ // src/EmptyState.tsx
4150
+ import { jsx as jsx45, jsxs as jsxs39 } from "react/jsx-runtime";
4151
+ function EmptyState({ icon, title, description, action, size = "sm", className }) {
4152
+ const md = size === "md";
4153
+ return /* @__PURE__ */ jsxs39(
4154
+ "div",
4155
+ {
4156
+ className: cn(
4157
+ "flex flex-col items-center text-center",
4158
+ md ? "gap-2 px-6 py-16" : "gap-1.5 px-4 py-8",
4159
+ className
4160
+ ),
4161
+ children: [
4162
+ icon && /* @__PURE__ */ jsx45(
4163
+ "span",
4164
+ {
4165
+ "aria-hidden": "true",
4166
+ className: cn(
4167
+ "flex items-center justify-center text-text-tertiary",
4168
+ md && "mb-1 size-11 rounded-full bg-subtle"
4169
+ ),
4170
+ children: icon
4171
+ }
4172
+ ),
4173
+ /* @__PURE__ */ jsx45("p", { className: cn("font-semibold text-text-primary", md ? "text-base" : "text-sm"), children: title }),
4174
+ description && /* @__PURE__ */ jsx45("p", { className: cn("max-w-sm text-text-secondary", md ? "text-sm" : "text-xs"), children: description }),
4175
+ action && /* @__PURE__ */ jsx45("div", { className: md ? "mt-3" : "mt-2", children: action })
4176
+ ]
4177
+ }
4178
+ );
4179
+ }
4180
+
4181
+ // src/Tabs.tsx
4182
+ import { useRef as useRef16 } from "react";
4183
+ import { jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
4184
+ function arrowKeys(e, row) {
4185
+ if (!row || !["ArrowLeft", "ArrowRight", "Home", "End"].includes(e.key)) return;
4186
+ const items = Array.from(row.querySelectorAll("button:not([disabled])"));
4187
+ const at = items.indexOf(document.activeElement);
4188
+ const next = e.key === "Home" ? 0 : e.key === "End" ? items.length - 1 : (at + (e.key === "ArrowRight" ? 1 : -1) + items.length) % items.length;
4189
+ e.preventDefault();
4190
+ items[next]?.focus();
4191
+ items[next]?.click();
4192
+ }
4193
+ function Tabs({ items, value, onChange, idPrefix = "tabs", className, ...rest }) {
4194
+ const row = useRef16(null);
4195
+ return /* @__PURE__ */ jsx46(
4196
+ "div",
4197
+ {
4198
+ ref: row,
4199
+ role: "tablist",
4200
+ "aria-label": rest["aria-label"],
4201
+ onKeyDown: (e) => arrowKeys(e, row.current),
4202
+ className: cn("flex gap-6 border-b border-border-default", className),
4203
+ children: items.map((item) => {
4204
+ const on = item.value === value;
4205
+ return /* @__PURE__ */ jsxs40(
4206
+ "button",
4207
+ {
4208
+ type: "button",
4209
+ role: "tab",
4210
+ id: `${idPrefix}-tab-${item.value}`,
4211
+ "aria-controls": `${idPrefix}-panel-${item.value}`,
4212
+ "aria-selected": on,
4213
+ tabIndex: on ? 0 : -1,
4214
+ disabled: item.disabled,
4215
+ onClick: () => onChange(item.value),
4216
+ className: cn(
4217
+ "-mb-px flex items-center gap-1.5 rounded-control border-b-2 pt-1 pb-2.5 text-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus disabled:opacity-50",
4218
+ on ? "border-brand-primaryAction font-semibold text-text-primary" : "border-transparent text-text-secondary hover:text-text-primary"
4219
+ ),
4220
+ children: [
4221
+ item.label,
4222
+ item.count !== void 0 && /* @__PURE__ */ jsx46("span", { className: "text-xs text-text-tertiary", children: item.count })
4223
+ ]
4224
+ },
4225
+ item.value
4226
+ );
4227
+ })
4228
+ }
4229
+ );
4230
+ }
4231
+ function SegmentedControl({
4232
+ options,
4233
+ value,
4234
+ onChange,
4235
+ size = "sm",
4236
+ className,
4237
+ ...rest
4238
+ }) {
4239
+ const row = useRef16(null);
4240
+ return /* @__PURE__ */ jsx46(
4241
+ "div",
4242
+ {
4243
+ ref: row,
4244
+ role: "radiogroup",
4245
+ "aria-label": rest["aria-label"],
4246
+ onKeyDown: (e) => arrowKeys(e, row.current),
4247
+ className: cn("inline-flex w-fit items-stretch gap-0.5 rounded-full bg-subtle p-1", size === "md" ? "h-10" : "h-8", className),
4248
+ children: options.map((o) => {
4249
+ const on = o.value === value;
4250
+ return /* @__PURE__ */ jsx46(
4251
+ "button",
4252
+ {
4253
+ type: "button",
4254
+ role: "radio",
4255
+ "aria-checked": on,
4256
+ tabIndex: on ? 0 : -1,
4257
+ onClick: () => onChange(o.value),
4258
+ className: cn(
4259
+ "rounded-full px-3 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-border-focus",
4260
+ size === "md" ? "text-sm" : "text-xs",
4261
+ on ? "bg-surface font-semibold text-text-primary shadow-raised" : "text-text-secondary hover:text-text-primary"
4262
+ ),
4263
+ children: o.label
4264
+ },
4265
+ o.value
4266
+ );
4267
+ })
4268
+ }
4269
+ );
4270
+ }
4271
+
4272
+ // src/TextField.tsx
4273
+ import { forwardRef as forwardRef3, useId as useId7 } from "react";
4274
+ import { jsx as jsx47, jsxs as jsxs41 } from "react/jsx-runtime";
4275
+ var HEIGHT2 = { sm: "h-8", md: "h-10", lg: "h-11" };
4276
+ var TextField = forwardRef3(
4277
+ ({ label, hint, error, size = "md", icon, className, id, disabled, ...props }, ref) => {
4278
+ const auto = useId7();
4279
+ const fieldId = id ?? auto;
4280
+ const noteId = `${fieldId}-note`;
4281
+ const note = error ?? hint;
4282
+ return /* @__PURE__ */ jsxs41("div", { className: cn("flex flex-col gap-1.5", className), children: [
4283
+ label && /* @__PURE__ */ jsx47("label", { htmlFor: fieldId, className: "text-xs font-medium text-text-secondary", children: label }),
4284
+ /* @__PURE__ */ jsxs41(
4285
+ "div",
4286
+ {
4287
+ className: cn(
4288
+ "flex items-center gap-2 rounded-control border bg-input px-3 focus-within:outline-2 focus-within:outline-offset-1 focus-within:outline-border-focus",
4289
+ HEIGHT2[size],
4290
+ error ? "border-status-danger" : "border-border-strong",
4291
+ disabled && "opacity-50"
4292
+ ),
4293
+ children: [
4294
+ icon && /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "flex shrink-0 text-text-tertiary", children: icon }),
4295
+ /* @__PURE__ */ jsx47(
4296
+ "input",
4297
+ {
4298
+ ref,
4299
+ id: fieldId,
4300
+ disabled,
4301
+ "aria-invalid": error ? true : void 0,
4302
+ "aria-describedby": note ? noteId : void 0,
4303
+ className: "min-w-0 flex-1 bg-transparent text-dense text-text-primary outline-hidden placeholder:text-text-tertiary",
4304
+ ...props
4305
+ }
4306
+ )
4307
+ ]
4308
+ }
4309
+ ),
4310
+ note && /* @__PURE__ */ jsx47("p", { id: noteId, className: cn("text-xs", error ? "text-text-danger" : "text-text-tertiary"), children: note })
4311
+ ] });
4312
+ }
4313
+ );
4314
+ TextField.displayName = "TextField";
4014
4315
  export {
4015
4316
  AISpark,
4016
4317
  AdvertiserNoResults,
@@ -4028,11 +4329,13 @@ export {
4028
4329
  DateRangeFilter,
4029
4330
  DateRangePicker,
4030
4331
  Delta,
4332
+ EmptyState,
4031
4333
  FilterChipBar,
4032
4334
  FilterDropdownFooter,
4033
4335
  Freshness,
4034
4336
  InfoTip,
4035
4337
  LineChartPlaceholder,
4338
+ Modal,
4036
4339
  MultiSelectFilter,
4037
4340
  NO_RESULTS_BODY,
4038
4341
  NO_RESULTS_TITLE,
@@ -4047,6 +4350,7 @@ export {
4047
4350
  SearchBar,
4048
4351
  SectionHeading,
4049
4352
  SectionRail,
4353
+ SegmentedControl,
4050
4354
  SelectAllVisible,
4051
4355
  SelectFilter,
4052
4356
  SelectedSection,
@@ -4054,7 +4358,9 @@ export {
4054
4358
  SortButton,
4055
4359
  StackedColumnPlaceholder,
4056
4360
  TablePagination,
4361
+ Tabs,
4057
4362
  Tag,
4363
+ TextField,
4058
4364
  Toast,
4059
4365
  Toggle,
4060
4366
  Tooltip,