@undevy-org/tablewright 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/es/components/data-table/AppliedStateChips.js +15 -6
  2. package/dist/es/components/data-table/ColumnFilterPopover.js +42 -29
  3. package/dist/es/components/data-table/CompoundFilterPopover.js +38 -22
  4. package/dist/es/components/data-table/DrawerShell.js +2 -0
  5. package/dist/es/components/data-table/FilterFormPanel.js +36 -18
  6. package/dist/es/components/data-table/FilterPopoverFooter.js +12 -4
  7. package/dist/es/components/data-table/TableLayout.js +10 -1
  8. package/dist/es/components/layout/Sidebar.js +8 -1
  9. package/dist/es/components/layout/SidebarAccountMenu.js +3 -2
  10. package/dist/es/components/layout/SidebarUser.js +2 -1
  11. package/dist/es/lib/collapsed-nav-link-a11y.js +6 -0
  12. package/dist/es/lib/decorative-avatar-alt.js +6 -0
  13. package/dist/es/lib/scroll-region-tab-index.js +4 -0
  14. package/dist/styles.css +3 -0
  15. package/dist/tablewright.cjs +175 -89
  16. package/dist/tablewright.css +3 -0
  17. package/dist/types/components/data-table/AppliedStateChips.d.ts +13 -1
  18. package/dist/types/components/data-table/ColumnFilterPopover.d.ts +22 -1
  19. package/dist/types/components/data-table/CompoundFilterPopover.d.ts +19 -1
  20. package/dist/types/components/data-table/FilterFormPanel.d.ts +17 -1
  21. package/dist/types/components/data-table/FilterPopoverFooter.d.ts +8 -1
  22. package/dist/types/components/layout/Sidebar.d.ts +1 -0
  23. package/dist/types/index.d.ts +5 -1
  24. package/dist/types/lib/collapsed-nav-link-a11y.d.ts +2 -0
  25. package/dist/types/lib/decorative-avatar-alt.d.ts +2 -0
  26. package/dist/types/lib/scroll-region-tab-index.d.ts +2 -0
  27. package/package.json +7 -2
@@ -682,6 +682,7 @@ function CopyableText({
682
682
  )
683
683
  ] });
684
684
  }
685
+ const SCROLL_REGION_TAB_INDEX = 0;
685
686
  function useScrollActivity(idleMs = 700) {
686
687
  const nodeRef = React.useRef(null);
687
688
  const [nodeVersion, setNodeVersion] = React.useState(0);
@@ -797,6 +798,7 @@ function DrawerShell({
797
798
  "div",
798
799
  {
799
800
  ref: bodyScrollRef,
801
+ tabIndex: SCROLL_REGION_TAB_INDEX,
800
802
  className: "scrollbar-auto-hide min-h-0 flex-1 overflow-y-auto px-6 py-6",
801
803
  children
802
804
  }
@@ -862,7 +864,15 @@ function TableLayout({ children, className }) {
862
864
  }
863
865
  function ScrollArea({ children, className }) {
864
866
  const scrollRef = useScrollActivity();
865
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: scrollRef, className: cn("scrollbar-auto-hide flex-1 overflow-auto", className), children });
867
+ return /* @__PURE__ */ jsxRuntime.jsx(
868
+ "div",
869
+ {
870
+ ref: scrollRef,
871
+ tabIndex: SCROLL_REGION_TAB_INDEX,
872
+ className: cn("scrollbar-auto-hide flex-1 overflow-auto", className),
873
+ children
874
+ }
875
+ );
866
876
  }
867
877
  TableLayout.ScrollArea = ScrollArea;
868
878
  function stickyStyle(meta, isHeader) {
@@ -1200,16 +1210,24 @@ const ViewChip = React__namespace.forwardRef(
1200
1210
  }
1201
1211
  );
1202
1212
  ViewChip.displayName = "ViewChip";
1213
+ const DEFAULT_LABELS$5 = {
1214
+ apply: "Apply",
1215
+ clear: "Clear"
1216
+ };
1203
1217
  function FilterPopoverFooter({
1204
1218
  onApply,
1205
1219
  onClear,
1206
- applyLabel = "Apply",
1207
- clearLabel = "Clear",
1220
+ labels: labelOverrides,
1221
+ applyLabel,
1222
+ clearLabel,
1208
1223
  className
1209
1224
  }) {
1225
+ const labels = { ...DEFAULT_LABELS$5, ...labelOverrides };
1226
+ const apply = applyLabel ?? labels.apply;
1227
+ const clear = clearLabel ?? labels.clear;
1210
1228
  return /* @__PURE__ */ jsxRuntime.jsxs(ButtonFooter, { className: cn("px-3 py-2.5", className), children: [
1211
- onClear && /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: onClear, children: clearLabel }),
1212
- /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", size: "sm", onClick: onApply, children: applyLabel })
1229
+ onClear && /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: onClear, children: clear }),
1230
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", size: "sm", onClick: onApply, children: apply })
1213
1231
  ] });
1214
1232
  }
1215
1233
  function Root({
@@ -1837,6 +1855,9 @@ const AppShellContext = React.createContext(null);
1837
1855
  function useAppShell() {
1838
1856
  return React.useContext(AppShellContext);
1839
1857
  }
1858
+ function collapsedNavLinkAriaLabel(showExpanded, label) {
1859
+ return showExpanded ? void 0 : label;
1860
+ }
1840
1861
  function isItemActive(href, activeKey) {
1841
1862
  if (href === "" || href === "/") return activeKey === "" || activeKey === "/";
1842
1863
  return activeKey === href || activeKey.startsWith(href + "/");
@@ -1909,10 +1930,15 @@ const Sidebar = React__namespace.forwardRef(
1909
1930
  ),
1910
1931
  showExpanded && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[13px]", children: item.label })
1911
1932
  ] });
1933
+ const collapsedLinkLabel = collapsedNavLinkAriaLabel(
1934
+ showExpanded,
1935
+ item.label
1936
+ );
1912
1937
  if (renderLink) {
1913
1938
  return /* @__PURE__ */ jsxRuntime.jsx(React__namespace.Fragment, { children: renderLink(item.href, {
1914
1939
  className: itemClassName,
1915
- children
1940
+ children,
1941
+ ...collapsedLinkLabel ? { "aria-label": collapsedLinkLabel } : {}
1916
1942
  }) }, item.key);
1917
1943
  }
1918
1944
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1920,6 +1946,7 @@ const Sidebar = React__namespace.forwardRef(
1920
1946
  {
1921
1947
  href: item.href,
1922
1948
  className: itemClassName,
1949
+ "aria-label": collapsedLinkLabel,
1923
1950
  children
1924
1951
  },
1925
1952
  item.key
@@ -2080,6 +2107,9 @@ const AppShell = Object.assign(AppShellRoot, {
2080
2107
  Header: AppShellHeader,
2081
2108
  Content: AppShellContent
2082
2109
  });
2110
+ function decorativeAvatarAlt(adjacentNameVisible, name) {
2111
+ return adjacentNameVisible ? "" : name;
2112
+ }
2083
2113
  function getInitials$1(name) {
2084
2114
  return name.split(" ").map((w) => w[0]).slice(0, 2).join("").toUpperCase();
2085
2115
  }
@@ -2101,7 +2131,7 @@ const SidebarUser = React__namespace.forwardRef(
2101
2131
  "img",
2102
2132
  {
2103
2133
  src: avatarUrl,
2104
- alt: name,
2134
+ alt: decorativeAvatarAlt(!effectiveCollapsed, name),
2105
2135
  className: "h-8 w-8 shrink-0 rounded-full object-cover"
2106
2136
  }
2107
2137
  ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--bg-tertiary)] text-[11px] font-semibold text-[var(--text-secondary)]", children: getInitials$1(name) }),
@@ -2133,7 +2163,7 @@ function SidebarAccountMenu({
2133
2163
  "img",
2134
2164
  {
2135
2165
  src: avatarUrl,
2136
- alt: name,
2166
+ alt: decorativeAvatarAlt(!effectiveCollapsed, name),
2137
2167
  className: "h-7 w-7 shrink-0 rounded-full object-cover"
2138
2168
  }
2139
2169
  ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-[var(--bg-tertiary)] text-[11px] font-semibold text-[var(--text-secondary)]", children: getInitials(name) });
@@ -2169,7 +2199,7 @@ function SidebarAccountMenu({
2169
2199
  "img",
2170
2200
  {
2171
2201
  src: avatarUrl,
2172
- alt: name,
2202
+ alt: decorativeAvatarAlt(true, name),
2173
2203
  className: "h-8 w-8 shrink-0 rounded-full object-cover"
2174
2204
  }
2175
2205
  ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--bg-tertiary)] text-[11px] font-semibold text-[var(--text-secondary)]", children: getInitials(name) }),
@@ -2366,7 +2396,7 @@ function ExpiryTimestampCell({ value, timestampMs }) {
2366
2396
  relativeLabel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `text-[11px] ${urgencyClass[urgency]}`, children: relativeLabel })
2367
2397
  ] });
2368
2398
  }
2369
- const DEFAULT_LABELS$3 = {
2399
+ const DEFAULT_LABELS$4 = {
2370
2400
  sort: "Sort",
2371
2401
  sortByColumn: (label) => `Sort by ${label}`,
2372
2402
  ascending: "Ascending",
@@ -2428,7 +2458,7 @@ function ColumnHeaderMenu({
2428
2458
  menuWidth = "w-[200px]"
2429
2459
  }) {
2430
2460
  const [open, setOpen] = React.useState(false);
2431
- const labels = { ...DEFAULT_LABELS$3, ...labelOverrides };
2461
+ const labels = { ...DEFAULT_LABELS$4, ...labelOverrides };
2432
2462
  const isStacked = !!primaryLabel;
2433
2463
  const isSingleSortable = !!label && !!onSort;
2434
2464
  const isSortable = isStacked || isSingleSortable;
@@ -2732,7 +2762,7 @@ function isFilterValueEmpty(value) {
2732
2762
  if (Array.isArray(value)) return value.length === 0;
2733
2763
  return Object.values(value).every((x) => typeof x !== "number" && isFilterValueEmpty(x));
2734
2764
  }
2735
- const DEFAULT_LABELS$2 = {
2765
+ const DEFAULT_LABELS$3 = {
2736
2766
  searchPlaceholder: "Search...",
2737
2767
  addValuePlaceholder: "Add value...",
2738
2768
  noData: "no data",
@@ -2744,6 +2774,9 @@ const DEFAULT_LABELS$2 = {
2744
2774
  chipTo: "to",
2745
2775
  chipMin: "min",
2746
2776
  chipMax: "max",
2777
+ contains: "Contains",
2778
+ orBadge: "OR",
2779
+ numberInputPlaceholder: "0",
2747
2780
  valuesCount: (n) => `${n} values`,
2748
2781
  selectedCount: (n) => `${n} selected`
2749
2782
  };
@@ -2774,8 +2807,11 @@ function ColumnFilterPopover({
2774
2807
  chipClassName,
2775
2808
  stats,
2776
2809
  requestOpen,
2777
- onRequestOpenHandled
2810
+ onRequestOpenHandled,
2811
+ labels: labelOverrides,
2812
+ footerLabels
2778
2813
  }) {
2814
+ const labels = { ...DEFAULT_LABELS$3, ...labelOverrides };
2779
2815
  const [isOpen, setIsOpen] = React.useState(false);
2780
2816
  const onRequestOpenHandledRef = React.useRef(onRequestOpenHandled);
2781
2817
  React.useEffect(() => {
@@ -2912,7 +2948,7 @@ function ColumnFilterPopover({
2912
2948
  if (!textStats || textStats.type !== "text") {
2913
2949
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-wrap", children: [
2914
2950
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-[var(--text-tertiary)] whitespace-nowrap min-w-[54px]", children: label }),
2915
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-[var(--bg-secondary)] px-1.5 py-0.5 text-[11px] text-[var(--text-tertiary)] italic", children: DEFAULT_LABELS$2.noData })
2951
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-[var(--bg-secondary)] px-1.5 py-0.5 text-[11px] text-[var(--text-tertiary)] italic", children: labels.noData })
2916
2952
  ] });
2917
2953
  }
2918
2954
  const { samples, totalUnique } = textStats;
@@ -2942,8 +2978,8 @@ function ColumnFilterPopover({
2942
2978
  const filtText = filteredStats?.type === "text" ? filteredStats : null;
2943
2979
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 w-64 space-y-3", children: [
2944
2980
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: [
2945
- "Contains",
2946
- draftTags.length >= 2 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-[10px] font-semibold text-[var(--tag-blue-text)] bg-[var(--tag-blue-bg)] rounded px-1 py-0.5 uppercase", children: "OR" })
2981
+ labels.contains,
2982
+ draftTags.length >= 2 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-[10px] font-semibold text-[var(--tag-blue-text)] bg-[var(--tag-blue-bg)] rounded px-1 py-0.5 uppercase", children: labels.orBadge })
2947
2983
  ] }),
2948
2984
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1 rounded-md border border-[var(--border-subtle)] bg-[var(--bg-surface)] px-2 py-1.5 focus-within:border-[var(--border-focus)]", children: [
2949
2985
  draftTags.map((tag) => /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2970,7 +3006,7 @@ function ColumnFilterPopover({
2970
3006
  {
2971
3007
  autoFocus: true,
2972
3008
  className: "flex-1 min-w-[60px] bg-transparent text-sm text-[var(--text-primary)] outline-none placeholder:text-[var(--text-tertiary)]",
2973
- placeholder: draftTags.length === 0 ? DEFAULT_LABELS$2.searchPlaceholder : DEFAULT_LABELS$2.addValuePlaceholder,
3009
+ placeholder: draftTags.length === 0 ? labels.searchPlaceholder : labels.addValuePlaceholder,
2974
3010
  value: draftInput,
2975
3011
  onChange: (e) => setDraftInput(e.target.value),
2976
3012
  onKeyDown: handleTextKeyDown
@@ -2978,8 +3014,8 @@ function ColumnFilterPopover({
2978
3014
  )
2979
3015
  ] }),
2980
3016
  allText && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[var(--border-subtle)] pt-2 space-y-2", children: [
2981
- renderTextRow(DEFAULT_LABELS$2.statsTextAllPrefix, allText),
2982
- filteredStats !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderTextRow(DEFAULT_LABELS$2.statsTextFilteredPrefix, filtText) })
3017
+ renderTextRow(labels.statsTextAllPrefix, allText),
3018
+ filteredStats !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderTextRow(labels.statsTextFilteredPrefix, filtText) })
2983
3019
  ] })
2984
3020
  ] });
2985
3021
  }
@@ -3018,7 +3054,7 @@ function ColumnFilterPopover({
3018
3054
  if (!dateStats || dateStats.type !== "date") {
3019
3055
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-wrap", children: [
3020
3056
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-[var(--text-tertiary)] whitespace-nowrap min-w-[54px]", children: label }),
3021
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-[var(--bg-secondary)] px-1.5 py-0.5 text-[11px] text-[var(--text-tertiary)] italic", children: DEFAULT_LABELS$2.noData })
3057
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-[var(--bg-secondary)] px-1.5 py-0.5 text-[11px] text-[var(--text-tertiary)] italic", children: labels.noData })
3022
3058
  ] });
3023
3059
  }
3024
3060
  const { min, max } = dateStats;
@@ -3046,7 +3082,7 @@ function ColumnFilterPopover({
3046
3082
  className: chipCls(draftDate.from === min),
3047
3083
  onClick: () => setDraftDate((prev) => ({ ...prev, from: min })),
3048
3084
  children: [
3049
- DEFAULT_LABELS$2.chipFrom,
3085
+ labels.chipFrom,
3050
3086
  " ",
3051
3087
  formatChipDate(min)
3052
3088
  ]
@@ -3059,7 +3095,7 @@ function ColumnFilterPopover({
3059
3095
  className: chipCls(draftDate.to === max),
3060
3096
  onClick: () => setDraftDate((prev) => ({ ...prev, to: max })),
3061
3097
  children: [
3062
- DEFAULT_LABELS$2.chipTo,
3098
+ labels.chipTo,
3063
3099
  " ",
3064
3100
  formatChipDate(max)
3065
3101
  ]
@@ -3071,7 +3107,7 @@ function ColumnFilterPopover({
3071
3107
  const filtDate = filteredStats?.type === "date" ? filteredStats : null;
3072
3108
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 w-64 space-y-4", children: [
3073
3109
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
3074
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: DEFAULT_LABELS$2.chipFrom }),
3110
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: labels.chipFrom }),
3075
3111
  /* @__PURE__ */ jsxRuntime.jsx(
3076
3112
  Input,
3077
3113
  {
@@ -3082,7 +3118,7 @@ function ColumnFilterPopover({
3082
3118
  )
3083
3119
  ] }),
3084
3120
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
3085
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: DEFAULT_LABELS$2.chipTo }),
3121
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: labels.chipTo }),
3086
3122
  /* @__PURE__ */ jsxRuntime.jsx(
3087
3123
  Input,
3088
3124
  {
@@ -3093,8 +3129,8 @@ function ColumnFilterPopover({
3093
3129
  )
3094
3130
  ] }),
3095
3131
  allDate && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[var(--border-subtle)] pt-2 space-y-2", children: [
3096
- renderDateRow(DEFAULT_LABELS$2.statsAllPrefix, allDate),
3097
- filteredStats !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderDateRow(DEFAULT_LABELS$2.statsFilteredPrefix, filtDate) })
3132
+ renderDateRow(labels.statsAllPrefix, allDate),
3133
+ filteredStats !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderDateRow(labels.statsFilteredPrefix, filtDate) })
3098
3134
  ] })
3099
3135
  ] });
3100
3136
  }
@@ -3103,7 +3139,7 @@ function ColumnFilterPopover({
3103
3139
  if (!numStats || numStats.type !== "number-range") {
3104
3140
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-wrap", children: [
3105
3141
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-[var(--text-tertiary)] whitespace-nowrap min-w-[54px]", children: label }),
3106
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-[var(--bg-secondary)] px-1.5 py-0.5 text-[11px] text-[var(--text-tertiary)] italic", children: DEFAULT_LABELS$2.noData })
3142
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-[var(--bg-secondary)] px-1.5 py-0.5 text-[11px] text-[var(--text-tertiary)] italic", children: labels.noData })
3107
3143
  ] });
3108
3144
  }
3109
3145
  const { min, max } = numStats;
@@ -3134,7 +3170,7 @@ function ColumnFilterPopover({
3134
3170
  className: chipCls(draftNumberFrom === String(min)),
3135
3171
  onClick: () => setDraftNumberFrom(String(min)),
3136
3172
  children: [
3137
- DEFAULT_LABELS$2.chipMin,
3173
+ labels.chipMin,
3138
3174
  " ",
3139
3175
  min
3140
3176
  ]
@@ -3147,7 +3183,7 @@ function ColumnFilterPopover({
3147
3183
  className: chipCls(draftNumberTo === String(max)),
3148
3184
  onClick: () => setDraftNumberTo(String(max)),
3149
3185
  children: [
3150
- DEFAULT_LABELS$2.chipMax,
3186
+ labels.chipMax,
3151
3187
  " ",
3152
3188
  max
3153
3189
  ]
@@ -3159,13 +3195,13 @@ function ColumnFilterPopover({
3159
3195
  const filtNum = filteredStats?.type === "number-range" ? filteredStats : null;
3160
3196
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 w-64 space-y-4", children: [
3161
3197
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
3162
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: DEFAULT_LABELS$2.chipMin }),
3198
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: labels.chipMin }),
3163
3199
  /* @__PURE__ */ jsxRuntime.jsx(
3164
3200
  Input,
3165
3201
  {
3166
3202
  type: "number",
3167
3203
  autoFocus: true,
3168
- placeholder: allNum ? String(allNum.min) : "0",
3204
+ placeholder: allNum ? String(allNum.min) : labels.numberInputPlaceholder,
3169
3205
  value: draftNumberFrom,
3170
3206
  onChange: (e) => setDraftNumberFrom(e.target.value),
3171
3207
  onKeyDown: (e) => {
@@ -3178,12 +3214,12 @@ function ColumnFilterPopover({
3178
3214
  )
3179
3215
  ] }),
3180
3216
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
3181
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: DEFAULT_LABELS$2.chipMax }),
3217
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-[var(--text-tertiary)] uppercase tracking-wider block", children: labels.chipMax }),
3182
3218
  /* @__PURE__ */ jsxRuntime.jsx(
3183
3219
  Input,
3184
3220
  {
3185
3221
  type: "number",
3186
- placeholder: allNum ? String(allNum.max) : "0",
3222
+ placeholder: allNum ? String(allNum.max) : labels.numberInputPlaceholder,
3187
3223
  value: draftNumberTo,
3188
3224
  onChange: (e) => setDraftNumberTo(e.target.value),
3189
3225
  onKeyDown: (e) => {
@@ -3196,8 +3232,8 @@ function ColumnFilterPopover({
3196
3232
  )
3197
3233
  ] }),
3198
3234
  allNum && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[var(--border-subtle)] pt-2 space-y-2", children: [
3199
- renderNumRow(DEFAULT_LABELS$2.statsAllPrefix, allNum),
3200
- filteredStats !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderNumRow(DEFAULT_LABELS$2.statsFilteredPrefix, filtNum) })
3235
+ renderNumRow(labels.statsAllPrefix, allNum),
3236
+ filteredStats !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderNumRow(labels.statsFilteredPrefix, filtNum) })
3201
3237
  ] })
3202
3238
  ] });
3203
3239
  }
@@ -3214,21 +3250,21 @@ function ColumnFilterPopover({
3214
3250
  }
3215
3251
  if (value.length === 2) {
3216
3252
  const joined = value.join(", ");
3217
- return joined.length > 24 ? `${value.length} values` : joined;
3253
+ return joined.length > 24 ? labels.valuesCount(value.length) : joined;
3218
3254
  }
3219
- return DEFAULT_LABELS$2.valuesCount(value.length);
3255
+ return labels.valuesCount(value.length);
3220
3256
  }
3221
3257
  if (config.type === "enum" && Array.isArray(value)) {
3222
3258
  if (value.length === 1) {
3223
3259
  return config.options?.find((o) => o.value === value[0])?.label ?? value[0];
3224
3260
  }
3225
- return DEFAULT_LABELS$2.selectedCount(value.length);
3261
+ return labels.selectedCount(value.length);
3226
3262
  }
3227
3263
  if (config.type === "date") {
3228
3264
  const { from, to } = getDateRange(value);
3229
3265
  if (from && to) return `${from} — ${to}`;
3230
- if (from) return `${DEFAULT_LABELS$2.chipFrom} ${from}`;
3231
- if (to) return `${DEFAULT_LABELS$2.chipTo} ${to}`;
3266
+ if (from) return `${labels.chipFrom} ${from}`;
3267
+ if (to) return `${labels.chipTo} ${to}`;
3232
3268
  }
3233
3269
  if (config.type === "number-range") {
3234
3270
  const { from, to } = getNumberRange(value);
@@ -3257,20 +3293,33 @@ function ColumnFilterPopover({
3257
3293
  className: "w-auto p-0 [box-shadow:var(--shadow-menu)] border-[var(--border-subtle)] flex flex-col max-h-[min(var(--radix-popover-content-available-height),520px)] overflow-hidden",
3258
3294
  children: [
3259
3295
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto overscroll-contain", children: renderContent() }),
3260
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 bg-[var(--bg-surface)]", children: /* @__PURE__ */ jsxRuntime.jsx(FilterPopoverFooter, { onApply: handleApply, onClear: handleClear }) })
3296
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 bg-[var(--bg-surface)]", children: /* @__PURE__ */ jsxRuntime.jsx(
3297
+ FilterPopoverFooter,
3298
+ {
3299
+ onApply: handleApply,
3300
+ onClear: handleClear,
3301
+ labels: footerLabels
3302
+ }
3303
+ ) })
3261
3304
  ]
3262
3305
  }
3263
3306
  )
3264
3307
  ] });
3265
3308
  }
3266
- const DEFAULT_LABELS$1 = {
3309
+ const DEFAULT_LABELS$2 = {
3267
3310
  searchPlaceholder: "Search...",
3268
3311
  addPlaceholder: "Add...",
3269
3312
  contains: "Contains",
3313
+ orBadge: "OR",
3270
3314
  chipMin: "min",
3271
3315
  chipMax: "max",
3272
3316
  statsAllPrefix: "All:",
3273
- statsFilteredPrefix: "Filt:"
3317
+ statsFilteredPrefix: "Filt:",
3318
+ numberInputPlaceholder: "0",
3319
+ resetSectionTitle: (subLabel) => `Reset ${subLabel}`,
3320
+ filtersCount: (n) => `${n} filters`,
3321
+ subValuesCount: (n) => `${n} values`,
3322
+ subSelectedCount: (n) => `${n} selected`
3274
3323
  };
3275
3324
  function initDraft(sub, compound) {
3276
3325
  const val = compound[sub.key];
@@ -3305,7 +3354,7 @@ function draftToValue(draft) {
3305
3354
  const all = trimmed.length > 0 && !draft.tags.includes(trimmed) ? [...draft.tags, trimmed] : [...draft.tags];
3306
3355
  return all.length > 0 ? all : void 0;
3307
3356
  }
3308
- function formatSubDisplay(sub, val) {
3357
+ function formatSubDisplay(sub, val, labels) {
3309
3358
  if (isFilterValueEmpty(val)) return null;
3310
3359
  if (sub.type === "number-range") {
3311
3360
  const { from, to } = getNumberRange(val);
@@ -3319,14 +3368,14 @@ function formatSubDisplay(sub, val) {
3319
3368
  const label = sub.options?.find((o) => o.value === val[0])?.label ?? val[0];
3320
3369
  return `${sub.label}: ${label}`;
3321
3370
  }
3322
- return `${sub.label}: ${val.length} selected`;
3371
+ return `${sub.label}: ${labels.subSelectedCount(val.length)}`;
3323
3372
  }
3324
3373
  if (Array.isArray(val) && val.length > 0) {
3325
3374
  if (val.length === 1) {
3326
3375
  const display = val[0].length > 15 ? `${val[0].slice(0, 15)}…` : val[0];
3327
3376
  return `${sub.label}: ${display}`;
3328
3377
  }
3329
- return `${sub.label}: ${val.length} values`;
3378
+ return `${sub.label}: ${labels.subValuesCount(val.length)}`;
3330
3379
  }
3331
3380
  return null;
3332
3381
  }
@@ -3339,8 +3388,11 @@ function CompoundFilterPopover({
3339
3388
  chipClassName,
3340
3389
  columnFilterStats,
3341
3390
  requestOpen,
3342
- onRequestOpenHandled
3391
+ onRequestOpenHandled,
3392
+ labels: labelOverrides,
3393
+ footerLabels
3343
3394
  }) {
3395
+ const labels = { ...DEFAULT_LABELS$2, ...labelOverrides };
3344
3396
  const subFilters = config.subFilters ?? [];
3345
3397
  const compound = getCompoundValue(filter.value);
3346
3398
  const [isOpen, setIsOpen] = React.useState(false);
@@ -3416,12 +3468,12 @@ function CompoundFilterPopover({
3416
3468
  if (isFilterValueEmpty(compound)) return void 0;
3417
3469
  const parts = [];
3418
3470
  for (const sub of subFilters) {
3419
- const display = formatSubDisplay(sub, compound[sub.key]);
3471
+ const display = formatSubDisplay(sub, compound[sub.key], labels);
3420
3472
  if (display) parts.push(display);
3421
3473
  }
3422
3474
  if (parts.length === 0) return void 0;
3423
3475
  const joined = parts.join(" & ");
3424
- return joined.length > 30 ? `${parts.length} filters` : joined;
3476
+ return joined.length > 30 ? labels.filtersCount(parts.length) : joined;
3425
3477
  };
3426
3478
  const updateDraft = (key, updater) => {
3427
3479
  setDrafts((prev) => ({ ...prev, [key]: updater(prev[key]) }));
@@ -3444,7 +3496,7 @@ function CompoundFilterPopover({
3444
3496
  className: chipCls(draft.from === String(min)),
3445
3497
  onClick: () => updateDraft(sub.key, (d) => ({ ...d, from: String(min) })),
3446
3498
  children: [
3447
- DEFAULT_LABELS$1.chipMin,
3499
+ labels.chipMin,
3448
3500
  " ",
3449
3501
  min.toLocaleString()
3450
3502
  ]
@@ -3457,7 +3509,7 @@ function CompoundFilterPopover({
3457
3509
  className: chipCls(draft.to === String(max)),
3458
3510
  onClick: () => updateDraft(sub.key, (d) => ({ ...d, to: String(max) })),
3459
3511
  children: [
3460
- DEFAULT_LABELS$1.chipMax,
3512
+ labels.chipMax,
3461
3513
  " ",
3462
3514
  max.toLocaleString()
3463
3515
  ]
@@ -3468,13 +3520,13 @@ function CompoundFilterPopover({
3468
3520
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3469
3521
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
3470
3522
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-1", children: [
3471
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.1em] text-[var(--text-tertiary)] block", children: DEFAULT_LABELS$1.chipMin }),
3523
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.1em] text-[var(--text-tertiary)] block", children: labels.chipMin }),
3472
3524
  /* @__PURE__ */ jsxRuntime.jsx(
3473
3525
  Input,
3474
3526
  {
3475
3527
  type: "number",
3476
3528
  autoFocus: subFilters.indexOf(sub) === 0,
3477
- placeholder: allNum ? String(allNum.min) : "0",
3529
+ placeholder: allNum ? String(allNum.min) : labels.numberInputPlaceholder,
3478
3530
  value: draft.from,
3479
3531
  onChange: (e) => updateDraft(sub.key, (prev) => ({
3480
3532
  ...prev,
@@ -3490,12 +3542,12 @@ function CompoundFilterPopover({
3490
3542
  )
3491
3543
  ] }),
3492
3544
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-1", children: [
3493
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.1em] text-[var(--text-tertiary)] block", children: DEFAULT_LABELS$1.chipMax }),
3545
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-[0.1em] text-[var(--text-tertiary)] block", children: labels.chipMax }),
3494
3546
  /* @__PURE__ */ jsxRuntime.jsx(
3495
3547
  Input,
3496
3548
  {
3497
3549
  type: "number",
3498
- placeholder: allNum ? String(allNum.max) : "0",
3550
+ placeholder: allNum ? String(allNum.max) : labels.numberInputPlaceholder,
3499
3551
  value: draft.to,
3500
3552
  onChange: (e) => updateDraft(sub.key, (prev) => ({
3501
3553
  ...prev,
@@ -3512,8 +3564,8 @@ function CompoundFilterPopover({
3512
3564
  ] })
3513
3565
  ] }),
3514
3566
  allNum && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[var(--border-subtle)] mt-3 pt-2 space-y-2", children: [
3515
- renderNumRow(DEFAULT_LABELS$1.statsAllPrefix, allNum),
3516
- filtNum && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderNumRow(DEFAULT_LABELS$1.statsFilteredPrefix, filtNum) })
3567
+ renderNumRow(labels.statsAllPrefix, allNum),
3568
+ filtNum && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderNumRow(labels.statsFilteredPrefix, filtNum) })
3517
3569
  ] })
3518
3570
  ] });
3519
3571
  };
@@ -3610,8 +3662,8 @@ function CompoundFilterPopover({
3610
3662
  };
3611
3663
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3612
3664
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] font-semibold uppercase tracking-[0.1em] text-[var(--text-tertiary)] block mb-2", children: [
3613
- DEFAULT_LABELS$1.contains,
3614
- draft.tags.length >= 2 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-[10px] font-semibold text-[var(--tag-blue-text)] bg-[var(--tag-blue-bg)] rounded px-1 py-0.5 uppercase", children: "OR" })
3665
+ labels.contains,
3666
+ draft.tags.length >= 2 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-[10px] font-semibold text-[var(--tag-blue-text)] bg-[var(--tag-blue-bg)] rounded px-1 py-0.5 uppercase", children: labels.orBadge })
3615
3667
  ] }),
3616
3668
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1 rounded-md border border-[var(--border-subtle)] bg-[var(--bg-surface)] px-2 py-1.5 focus-within:border-[var(--border-focus)]", children: [
3617
3669
  draft.tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3641,7 +3693,7 @@ function CompoundFilterPopover({
3641
3693
  {
3642
3694
  autoFocus: subFilters.indexOf(sub) === 0,
3643
3695
  className: "flex-1 min-w-[50px] bg-transparent text-sm text-[var(--text-primary)] outline-none placeholder:text-[var(--text-tertiary)]",
3644
- placeholder: draft.tags.length === 0 ? DEFAULT_LABELS$1.searchPlaceholder : DEFAULT_LABELS$1.addPlaceholder,
3696
+ placeholder: draft.tags.length === 0 ? labels.searchPlaceholder : labels.addPlaceholder,
3645
3697
  value: draft.input,
3646
3698
  onChange: (e) => updateDraft(sub.key, (prev) => ({ ...prev, input: e.target.value })),
3647
3699
  onKeyDown: handleTextKeyDown
@@ -3649,8 +3701,8 @@ function CompoundFilterPopover({
3649
3701
  )
3650
3702
  ] }),
3651
3703
  allText && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[var(--border-subtle)] mt-3 pt-2 space-y-2", children: [
3652
- renderTextRow(DEFAULT_LABELS$1.statsAllPrefix, allText),
3653
- filtText && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderTextRow(DEFAULT_LABELS$1.statsFilteredPrefix, filtText) })
3704
+ renderTextRow(labels.statsAllPrefix, allText),
3705
+ filtText && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[var(--border-subtle)] pt-1.5", children: renderTextRow(labels.statsFilteredPrefix, filtText) })
3654
3706
  ] })
3655
3707
  ] });
3656
3708
  };
@@ -3732,7 +3784,7 @@ function CompoundFilterPopover({
3732
3784
  type: "button",
3733
3785
  className: "text-[11px] text-[var(--text-tertiary)] hover:text-[var(--text-secondary)] transition-colors",
3734
3786
  onClick: () => handleResetSection(sub.key),
3735
- title: `Reset ${sub.label}`,
3787
+ title: labels.resetSectionTitle(sub.label),
3736
3788
  children: "✕"
3737
3789
  }
3738
3790
  )
@@ -3744,13 +3796,20 @@ function CompoundFilterPopover({
3744
3796
  },
3745
3797
  sub.key
3746
3798
  )) }),
3747
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 bg-[var(--bg-surface)]", children: /* @__PURE__ */ jsxRuntime.jsx(FilterPopoverFooter, { onApply: handleApply, onClear: handleClearAll }) })
3799
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 bg-[var(--bg-surface)]", children: /* @__PURE__ */ jsxRuntime.jsx(
3800
+ FilterPopoverFooter,
3801
+ {
3802
+ onApply: handleApply,
3803
+ onClear: handleClearAll,
3804
+ labels: footerLabels
3805
+ }
3806
+ ) })
3748
3807
  ]
3749
3808
  }
3750
3809
  )
3751
3810
  ] });
3752
3811
  }
3753
- const DEFAULT_LABELS = {
3812
+ const DEFAULT_LABELS$1 = {
3754
3813
  clearAll: "Clear all",
3755
3814
  columns: "Columns",
3756
3815
  hiddenCount: (n) => `${n} hidden`
@@ -3772,8 +3831,13 @@ function AppliedStateChips({
3772
3831
  onClearAll,
3773
3832
  columnFilterStats,
3774
3833
  requestOpenFilterId,
3775
- onRequestOpenHandled
3834
+ onRequestOpenHandled,
3835
+ labels: labelOverrides,
3836
+ columnFilterLabels,
3837
+ compoundFilterLabels,
3838
+ filterPopoverFooterLabels
3776
3839
  }) {
3840
+ const labels = { ...DEFAULT_LABELS$1, ...labelOverrides };
3777
3841
  const hasFilters = filters.length > 0;
3778
3842
  const hasSort = currentSort !== null;
3779
3843
  const hasHiddenColumns = hiddenColumnsCount > 0;
@@ -3784,13 +3848,13 @@ function AppliedStateChips({
3784
3848
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2 pb-3", children: [
3785
3849
  /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: onClearAll, className: "shrink-0", children: [
3786
3850
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 14 }),
3787
- DEFAULT_LABELS.clearAll
3851
+ labels.clearAll
3788
3852
  ] }),
3789
3853
  hasHiddenColumns && /* @__PURE__ */ jsxRuntime.jsx(
3790
3854
  FilterChip,
3791
3855
  {
3792
- label: DEFAULT_LABELS.columns,
3793
- value: DEFAULT_LABELS.hiddenCount(hiddenColumnsCount),
3856
+ label: labels.columns,
3857
+ value: labels.hiddenCount(hiddenColumnsCount),
3794
3858
  onRemove: onResetColumns,
3795
3859
  onClick: onOpenColumnsMenu,
3796
3860
  className: "cursor-pointer"
@@ -3813,7 +3877,9 @@ function AppliedStateChips({
3813
3877
  chipClassName: isEmpty ? "border-dashed" : void 0,
3814
3878
  columnFilterStats,
3815
3879
  requestOpen: filter.columnId === requestOpenFilterId,
3816
- onRequestOpenHandled
3880
+ onRequestOpenHandled,
3881
+ labels: compoundFilterLabels,
3882
+ footerLabels: filterPopoverFooterLabels
3817
3883
  },
3818
3884
  filter.columnId
3819
3885
  );
@@ -3829,7 +3895,9 @@ function AppliedStateChips({
3829
3895
  chipClassName: isEmpty ? "border-dashed" : void 0,
3830
3896
  stats: columnFilterStats?.[filter.columnId],
3831
3897
  requestOpen: filter.columnId === requestOpenFilterId,
3832
- onRequestOpenHandled
3898
+ onRequestOpenHandled,
3899
+ labels: columnFilterLabels,
3900
+ footerLabels: filterPopoverFooterLabels
3833
3901
  },
3834
3902
  filter.columnId
3835
3903
  );
@@ -3864,6 +3932,21 @@ function hasActiveManagedFilters(filters, managedFieldIds) {
3864
3932
  const managed = new Set(managedFieldIds);
3865
3933
  return filters.some((f) => managed.has(f.columnId) && !isFilterValueEmpty(f.value));
3866
3934
  }
3935
+ const DEFAULT_LABELS = {
3936
+ closeFiltersAriaLabel: "Close filters",
3937
+ closeFiltersTitle: "Close filters",
3938
+ apply: "Apply",
3939
+ clear: "Clear",
3940
+ anyPlaceholder: "Any",
3941
+ rangeFromPlaceholder: "From",
3942
+ rangeToPlaceholder: "To",
3943
+ fieldRangeFromAriaLabel: (fieldLabel) => `${fieldLabel} — from`,
3944
+ fieldRangeToAriaLabel: (fieldLabel) => `${fieldLabel} — to`,
3945
+ compoundSubRangeFromAriaLabel: (subLabel) => `${subLabel} — from`,
3946
+ compoundSubRangeToAriaLabel: (subLabel) => `${subLabel} — to`,
3947
+ compoundSubRangeFromPlaceholder: (subLabel) => `${subLabel} from`,
3948
+ compoundSubRangeToPlaceholder: (subLabel) => `${subLabel} to`
3949
+ };
3867
3950
  function deriveInitialState(fields, filters) {
3868
3951
  const byId = new Map(filters.map((f) => [f.columnId, f.value]));
3869
3952
  const next = {};
@@ -3880,8 +3963,10 @@ function FilterFormPanel({
3880
3963
  className,
3881
3964
  id,
3882
3965
  onClose,
3883
- hiddenSubFilterKeys
3966
+ hiddenSubFilterKeys,
3967
+ labels: labelOverrides
3884
3968
  }) {
3969
+ const labels = { ...DEFAULT_LABELS, ...labelOverrides };
3885
3970
  const hiddenSubSet = React.useMemo(() => new Set(hiddenSubFilterKeys ?? []), [hiddenSubFilterKeys]);
3886
3971
  const renderableFields = React.useMemo(
3887
3972
  () => fields.filter((id2) => {
@@ -3956,8 +4041,8 @@ function FilterFormPanel({
3956
4041
  type: "button",
3957
4042
  variant: "ghost",
3958
4043
  size: "icon",
3959
- "aria-label": "Close filters",
3960
- title: "Close filters",
4044
+ "aria-label": labels.closeFiltersAriaLabel,
4045
+ title: labels.closeFiltersTitle,
3961
4046
  onClick: onClose,
3962
4047
  className: "h-7 w-7",
3963
4048
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
@@ -3974,7 +4059,8 @@ function FilterFormPanel({
3974
4059
  value: state[fieldId],
3975
4060
  onChange: (v) => setField(fieldId, v),
3976
4061
  fieldId,
3977
- hiddenSubSet
4062
+ hiddenSubSet,
4063
+ labels
3978
4064
  },
3979
4065
  fieldId
3980
4066
  );
@@ -3988,16 +4074,16 @@ function FilterFormPanel({
3988
4074
  size: "sm",
3989
4075
  onClick: handleClear,
3990
4076
  disabled: isClearDisabled,
3991
- children: "Clear"
4077
+ children: labels.clear
3992
4078
  }
3993
4079
  ),
3994
- /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", size: "sm", children: "Apply" })
4080
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", size: "sm", children: labels.apply })
3995
4081
  ] }) })
3996
4082
  ]
3997
4083
  }
3998
4084
  );
3999
4085
  }
4000
- function Field({ config, value, onChange, fieldId, hiddenSubSet }) {
4086
+ function Field({ config, value, onChange, fieldId, hiddenSubSet, labels }) {
4001
4087
  if (config.type === "text") {
4002
4088
  const text = Array.isArray(value) ? value[0] ?? "" : "";
4003
4089
  return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
@@ -4026,7 +4112,7 @@ function Field({ config, value, onChange, fieldId, hiddenSubSet }) {
4026
4112
  value: selected || null,
4027
4113
  onChange: (v) => onChange(v ? [v] : void 0),
4028
4114
  options: config.options ?? [],
4029
- placeholder: "Any",
4115
+ placeholder: labels.anyPlaceholder,
4030
4116
  triggerAriaLabel: config.label,
4031
4117
  triggerClassName: "h-9 min-w-0"
4032
4118
  }
@@ -4047,7 +4133,7 @@ function Field({ config, value, onChange, fieldId, hiddenSubSet }) {
4047
4133
  Input,
4048
4134
  {
4049
4135
  type: "date",
4050
- "aria-label": `${config.label} — from`,
4136
+ "aria-label": labels.fieldRangeFromAriaLabel(config.label),
4051
4137
  value: range.from ?? "",
4052
4138
  onChange: update("from"),
4053
4139
  className: "h-9 min-w-0 flex-1"
@@ -4057,7 +4143,7 @@ function Field({ config, value, onChange, fieldId, hiddenSubSet }) {
4057
4143
  Input,
4058
4144
  {
4059
4145
  type: "date",
4060
- "aria-label": `${config.label} — to`,
4146
+ "aria-label": labels.fieldRangeToAriaLabel(config.label),
4061
4147
  value: range.to ?? "",
4062
4148
  onChange: update("to"),
4063
4149
  className: "h-9 min-w-0 flex-1"
@@ -4081,10 +4167,10 @@ function Field({ config, value, onChange, fieldId, hiddenSubSet }) {
4081
4167
  Input,
4082
4168
  {
4083
4169
  type: "number",
4084
- "aria-label": `${config.label} — from`,
4170
+ "aria-label": labels.fieldRangeFromAriaLabel(config.label),
4085
4171
  value: range.from ?? "",
4086
4172
  onChange: update("from"),
4087
- placeholder: "From",
4173
+ placeholder: labels.rangeFromPlaceholder,
4088
4174
  className: "h-9 min-w-0 flex-1"
4089
4175
  }
4090
4176
  ),
@@ -4092,10 +4178,10 @@ function Field({ config, value, onChange, fieldId, hiddenSubSet }) {
4092
4178
  Input,
4093
4179
  {
4094
4180
  type: "number",
4095
- "aria-label": `${config.label} — to`,
4181
+ "aria-label": labels.fieldRangeToAriaLabel(config.label),
4096
4182
  value: range.to ?? "",
4097
4183
  onChange: update("to"),
4098
- placeholder: "To",
4184
+ placeholder: labels.rangeToPlaceholder,
4099
4185
  className: "h-9 min-w-0 flex-1"
4100
4186
  }
4101
4187
  )
@@ -4175,10 +4261,10 @@ function Field({ config, value, onChange, fieldId, hiddenSubSet }) {
4175
4261
  Input,
4176
4262
  {
4177
4263
  type: "number",
4178
- "aria-label": `${sub.label} — from`,
4264
+ "aria-label": labels.compoundSubRangeFromAriaLabel(sub.label),
4179
4265
  value: range.from ?? "",
4180
4266
  onChange: updateRange("from"),
4181
- placeholder: `${sub.label} from`,
4267
+ placeholder: labels.compoundSubRangeFromPlaceholder(sub.label),
4182
4268
  className: "h-9 min-w-0 flex-1"
4183
4269
  }
4184
4270
  ),
@@ -4186,10 +4272,10 @@ function Field({ config, value, onChange, fieldId, hiddenSubSet }) {
4186
4272
  Input,
4187
4273
  {
4188
4274
  type: "number",
4189
- "aria-label": `${sub.label} — to`,
4275
+ "aria-label": labels.compoundSubRangeToAriaLabel(sub.label),
4190
4276
  value: range.to ?? "",
4191
4277
  onChange: updateRange("to"),
4192
- placeholder: `${sub.label} to`,
4278
+ placeholder: labels.compoundSubRangeToPlaceholder(sub.label),
4193
4279
  className: "h-9 min-w-0 flex-1"
4194
4280
  }
4195
4281
  )