@underverse-ui/underverse 1.0.97 → 1.0.99

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
@@ -1815,8 +1815,9 @@ function useSmartTranslations(namespace) {
1815
1815
  return internalT;
1816
1816
  }
1817
1817
  return (key) => {
1818
- const primaryLocale = nextIntlBridge?.locale ?? internalLocale;
1819
- const fallbackLocale = environmentLocale && environmentLocale !== primaryLocale ? environmentLocale : null;
1818
+ const resolvedEnvironmentLocale = environmentLocale && environmentLocale !== internalLocale ? environmentLocale : null;
1819
+ const primaryLocale = nextIntlBridge?.locale ?? resolvedEnvironmentLocale ?? internalLocale;
1820
+ const fallbackLocale = resolvedEnvironmentLocale && resolvedEnvironmentLocale !== primaryLocale ? resolvedEnvironmentLocale : null;
1820
1821
  let translated = null;
1821
1822
  if (nextIntlBridge) {
1822
1823
  const nextIntlResult = nextIntlBridge.translate(namespace, key);
@@ -1848,10 +1849,20 @@ function useSmartLocale() {
1848
1849
  const forceInternal = React6.useContext(ForceInternalContext);
1849
1850
  const nextIntlBridge = useNextIntlBridge();
1850
1851
  const internalLocale = useUnderverseLocale();
1852
+ const [environmentLocale, setEnvironmentLocale] = React6.useState(null);
1853
+ React6.useEffect(() => {
1854
+ if (forceInternal) return;
1855
+ if (nextIntlBridge) return;
1856
+ if (internalLocale !== "en") return;
1857
+ const detected = getEnvironmentLocale(internalLocale);
1858
+ if (detected !== internalLocale) {
1859
+ setEnvironmentLocale(detected);
1860
+ }
1861
+ }, [forceInternal, internalLocale, nextIntlBridge]);
1851
1862
  if (forceInternal) {
1852
1863
  return internalLocale;
1853
1864
  }
1854
- return nextIntlBridge?.locale ?? internalLocale;
1865
+ return nextIntlBridge?.locale ?? environmentLocale ?? internalLocale;
1855
1866
  }
1856
1867
 
1857
1868
  // src/components/Input.tsx
@@ -7196,9 +7207,10 @@ var Combobox = ({
7196
7207
  {
7197
7208
  id: `combobox-item-${index}`,
7198
7209
  type: "button",
7210
+ role: "option",
7199
7211
  tabIndex: -1,
7200
7212
  disabled: itemDisabled,
7201
- "aria-pressed": isSelected,
7213
+ "aria-selected": isSelected,
7202
7214
  onClick: () => handleSelect(item),
7203
7215
  style: {
7204
7216
  animationDelay: open ? `${Math.min(index * 15, 150)}ms` : "0ms"
@@ -7303,40 +7315,50 @@ var Combobox = ({
7303
7315
  }
7304
7316
  )
7305
7317
  ] }) }),
7306
- /* @__PURE__ */ jsx29("div", { ref: optionsViewportRef, className: "overflow-y-auto overscroll-contain", style: { maxHeight }, children: /* @__PURE__ */ jsx29("div", { className: cn(size === "sm" ? "p-1" : size === "lg" ? "p-2" : "p-1.5"), children: loading2 ? /* @__PURE__ */ jsx29("div", { className: "px-3 py-10 text-center", children: /* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center gap-3 animate-in fade-in-0 zoom-in-95 duration-300", children: [
7307
- /* @__PURE__ */ jsx29("div", { className: "relative", children: /* @__PURE__ */ jsx29("div", { className: "w-10 h-10 rounded-full border-2 border-primary/20 border-t-primary animate-spin" }) }),
7308
- /* @__PURE__ */ jsx29("span", { className: "text-sm text-muted-foreground", children: loadingText })
7309
- ] }) }) : filteredOptions.length > 0 ? groupedOptions ? (
7310
- // Render grouped options with global index tracking
7311
- (() => {
7312
- let globalIndex = 0;
7313
- return Object.entries(groupedOptions).map(([group, items]) => /* @__PURE__ */ jsxs22("div", { className: cn(globalIndex > 0 && "mt-2 pt-2 border-t border-border/30"), children: [
7314
- /* @__PURE__ */ jsx29("div", { className: "px-3 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: group }),
7315
- /* @__PURE__ */ jsx29("ul", { className: "space-y-0.5", children: items.map((item) => {
7316
- const index = globalIndex++;
7317
- return renderOptionItem(item, index);
7318
- }) })
7319
- ] }, group));
7320
- })()
7321
- ) : (
7322
- // Render flat options
7323
- /* @__PURE__ */ jsx29("ul", { className: "space-y-0.5", children: filteredOptions.map((item, index) => renderOptionItem(item, index)) })
7324
- ) : /* @__PURE__ */ jsx29("div", { className: "px-3 py-10 text-center", children: /* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center gap-3 animate-in fade-in-0 zoom-in-95 duration-300", children: [
7325
- /* @__PURE__ */ jsx29("div", { className: "w-12 h-12 rounded-full bg-muted/50 flex items-center justify-center", children: /* @__PURE__ */ jsx29(SearchX, { className: "h-6 w-6 text-muted-foreground/60" }) }),
7326
- /* @__PURE__ */ jsxs22("div", { className: "space-y-1", children: [
7327
- /* @__PURE__ */ jsx29("span", { className: "block text-sm font-medium text-foreground", children: emptyText }),
7328
- query && /* @__PURE__ */ jsx29("span", { className: "block text-xs text-muted-foreground", children: "Try a different search term" })
7329
- ] }),
7330
- query && /* @__PURE__ */ jsx29(
7331
- "button",
7332
- {
7333
- type: "button",
7334
- onClick: () => setQuery(""),
7335
- className: "px-3 py-1.5 text-xs font-medium text-primary bg-primary/10 rounded-full hover:bg-primary/20 transition-colors",
7336
- children: "Clear search"
7337
- }
7338
- )
7339
- ] }) }) }) })
7318
+ /* @__PURE__ */ jsx29(
7319
+ "div",
7320
+ {
7321
+ ref: optionsViewportRef,
7322
+ role: "listbox",
7323
+ "aria-labelledby": labelId,
7324
+ className: "overflow-y-auto overscroll-contain",
7325
+ style: { maxHeight },
7326
+ children: /* @__PURE__ */ jsx29("div", { className: cn(size === "sm" ? "p-1" : size === "lg" ? "p-2" : "p-1.5"), children: loading2 ? /* @__PURE__ */ jsx29("div", { className: "px-3 py-10 text-center", children: /* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center gap-3 animate-in fade-in-0 zoom-in-95 duration-300", children: [
7327
+ /* @__PURE__ */ jsx29("div", { className: "relative", children: /* @__PURE__ */ jsx29("div", { className: "w-10 h-10 rounded-full border-2 border-primary/20 border-t-primary animate-spin" }) }),
7328
+ /* @__PURE__ */ jsx29("span", { className: "text-sm text-muted-foreground", children: loadingText })
7329
+ ] }) }) : filteredOptions.length > 0 ? groupedOptions ? (
7330
+ // Render grouped options with global index tracking
7331
+ (() => {
7332
+ let globalIndex = 0;
7333
+ return Object.entries(groupedOptions).map(([group, items]) => /* @__PURE__ */ jsxs22("div", { className: cn(globalIndex > 0 && "mt-2 pt-2 border-t border-border/30"), children: [
7334
+ /* @__PURE__ */ jsx29("div", { className: "px-3 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: group }),
7335
+ /* @__PURE__ */ jsx29("ul", { className: "space-y-0.5", children: items.map((item) => {
7336
+ const index = globalIndex++;
7337
+ return renderOptionItem(item, index);
7338
+ }) })
7339
+ ] }, group));
7340
+ })()
7341
+ ) : (
7342
+ // Render flat options
7343
+ /* @__PURE__ */ jsx29("ul", { className: "space-y-0.5", children: filteredOptions.map((item, index) => renderOptionItem(item, index)) })
7344
+ ) : /* @__PURE__ */ jsx29("div", { className: "px-3 py-10 text-center", children: /* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center gap-3 animate-in fade-in-0 zoom-in-95 duration-300", children: [
7345
+ /* @__PURE__ */ jsx29("div", { className: "w-12 h-12 rounded-full bg-muted/50 flex items-center justify-center", children: /* @__PURE__ */ jsx29(SearchX, { className: "h-6 w-6 text-muted-foreground/60" }) }),
7346
+ /* @__PURE__ */ jsxs22("div", { className: "space-y-1", children: [
7347
+ /* @__PURE__ */ jsx29("span", { className: "block text-sm font-medium text-foreground", children: emptyText }),
7348
+ query && /* @__PURE__ */ jsx29("span", { className: "block text-xs text-muted-foreground", children: "Try a different search term" })
7349
+ ] }),
7350
+ query && /* @__PURE__ */ jsx29(
7351
+ "button",
7352
+ {
7353
+ type: "button",
7354
+ onClick: () => setQuery(""),
7355
+ className: "px-3 py-1.5 text-xs font-medium text-primary bg-primary/10 rounded-full hover:bg-primary/20 transition-colors",
7356
+ children: "Clear search"
7357
+ }
7358
+ )
7359
+ ] }) }) })
7360
+ }
7361
+ )
7340
7362
  ]
7341
7363
  }
7342
7364
  );
@@ -16934,15 +16956,83 @@ var TREE_NODE_INDENT_REM = 1;
16934
16956
  var TREE_BRANCH_OFFSET_CLASS = "ml-1.5 pl-1.5";
16935
16957
  var TREE_NODE_GAP_CLASS = "gap-1.5";
16936
16958
  var TREE_EXPANDER_PLACEHOLDER_CLASS = "w-5";
16937
- function getInitialExpandedNodes(categories, defaultExpanded, viewOnly, inline) {
16938
- if (!(viewOnly || inline) || !defaultExpanded) return /* @__PURE__ */ new Set();
16939
- const parentIds = /* @__PURE__ */ new Set();
16940
- for (const category of categories) {
16941
- if (typeof category.parent_id === "number") {
16942
- parentIds.add(category.parent_id);
16959
+ function getAncestorPathIds(categories, targetId) {
16960
+ const byId = new Map(categories.map((category) => [category.id, category]));
16961
+ const expanded = /* @__PURE__ */ new Set();
16962
+ let current = byId.get(targetId);
16963
+ let guard = 0;
16964
+ while (current && guard++ < categories.length) {
16965
+ expanded.add(current.id);
16966
+ if (typeof current.parent_id !== "number") break;
16967
+ current = byId.get(current.parent_id);
16968
+ }
16969
+ return expanded;
16970
+ }
16971
+ function getInitialExpandedNodes(categories, {
16972
+ defaultExpanded,
16973
+ defaultExpandedIds,
16974
+ expandToId,
16975
+ viewOnly,
16976
+ inline
16977
+ }) {
16978
+ const expanded = /* @__PURE__ */ new Set();
16979
+ if ((viewOnly || inline) && defaultExpanded) {
16980
+ for (const category of categories) {
16981
+ if (typeof category.parent_id === "number") {
16982
+ expanded.add(category.parent_id);
16983
+ }
16984
+ }
16985
+ }
16986
+ for (const id of defaultExpandedIds ?? []) {
16987
+ if (typeof id === "number") {
16988
+ expanded.add(id);
16943
16989
  }
16944
16990
  }
16945
- return parentIds;
16991
+ if (typeof expandToId === "number") {
16992
+ for (const id of getAncestorPathIds(categories, expandToId)) {
16993
+ expanded.add(id);
16994
+ }
16995
+ }
16996
+ return expanded;
16997
+ }
16998
+ function getExpandedNodesState(expandedIds, uncontrolledExpandedNodes) {
16999
+ return expandedIds !== void 0 ? new Set(expandedIds) : uncontrolledExpandedNodes;
17000
+ }
17001
+ function collectAncestorIds(categories, categoryId) {
17002
+ const ancestorIds = getAncestorPathIds(categories, categoryId);
17003
+ ancestorIds.delete(categoryId);
17004
+ return ancestorIds;
17005
+ }
17006
+ function collectDescendantIds(childrenMap, categoryId) {
17007
+ const descendants = /* @__PURE__ */ new Set();
17008
+ const stack = [categoryId];
17009
+ while (stack.length > 0) {
17010
+ const currentId = stack.pop();
17011
+ for (const child of childrenMap.get(currentId) ?? []) {
17012
+ if (descendants.has(child.id)) continue;
17013
+ descendants.add(child.id);
17014
+ stack.push(child.id);
17015
+ }
17016
+ }
17017
+ return descendants;
17018
+ }
17019
+ function pruneAncestorSelection(categories, childrenMap, selected, fromCategoryId) {
17020
+ const byId = new Map(categories.map((category) => [category.id, category]));
17021
+ let current = byId.get(fromCategoryId);
17022
+ let guard = 0;
17023
+ while (current && typeof current.parent_id === "number" && guard++ < categories.length) {
17024
+ const parent = byId.get(current.parent_id);
17025
+ if (!parent) break;
17026
+ const descendantIds = collectDescendantIds(childrenMap, parent.id);
17027
+ const hasSelectedDescendant = Array.from(descendantIds).some((id) => selected.has(id));
17028
+ if (!hasSelectedDescendant) {
17029
+ selected.delete(parent.id);
17030
+ }
17031
+ current = parent;
17032
+ }
17033
+ }
17034
+ function toCategoryOrderSelection(categories, selected) {
17035
+ return categories.map((category) => category.id).filter((categoryId) => selected.has(categoryId));
16946
17036
  }
16947
17037
  function CategoryTreeSelect(props) {
16948
17038
  const tv = useSmartTranslations("ValidationInput");
@@ -16961,6 +17051,10 @@ function CategoryTreeSelect(props) {
16961
17051
  helperText,
16962
17052
  viewOnly = false,
16963
17053
  defaultExpanded = false,
17054
+ defaultExpandedIds,
17055
+ expandToId = null,
17056
+ expandedIds,
17057
+ onExpandedChange,
16964
17058
  enableSearch,
16965
17059
  labels,
16966
17060
  inline = false,
@@ -16971,7 +17065,9 @@ function CategoryTreeSelect(props) {
16971
17065
  singleSelect = false
16972
17066
  } = props;
16973
17067
  const [isOpen, setIsOpen] = useState31(false);
16974
- const [expandedNodes, setExpandedNodes] = useState31(() => getInitialExpandedNodes(categories, defaultExpanded, viewOnly, inline));
17068
+ const [expandedNodes, setExpandedNodes] = useState31(
17069
+ () => getInitialExpandedNodes(categories, { defaultExpanded, defaultExpandedIds, expandToId, viewOnly, inline })
17070
+ );
16975
17071
  const [query, setQuery] = useState31("");
16976
17072
  const [localRequiredError, setLocalRequiredError] = useState31();
16977
17073
  const searchInputRef = useRef19(null);
@@ -17008,6 +17104,7 @@ function CategoryTreeSelect(props) {
17008
17104
  const isSearchEnabled = useMemo19(() => enableSearch ?? categories.length > 10, [enableSearch, categories.length]);
17009
17105
  const normalizedQuery = useMemo19(() => query.trim().toLowerCase(), [query]);
17010
17106
  const isSearchMode = isSearchEnabled && normalizedQuery.length > 0;
17107
+ const effectiveExpandedNodes = useMemo19(() => getExpandedNodesState(expandedIds, expandedNodes), [expandedIds, expandedNodes]);
17011
17108
  const visibleIds = useMemo19(() => {
17012
17109
  if (!isSearchMode) return null;
17013
17110
  const matches = categories.filter((c) => c.name.toLowerCase().includes(normalizedQuery));
@@ -17060,13 +17157,16 @@ function CategoryTreeSelect(props) {
17060
17157
  }, [disabled, required, valueArray.length]);
17061
17158
  const toggleExpand = (id2) => {
17062
17159
  if (isSearchMode) return;
17063
- const newExpanded = new Set(expandedNodes);
17160
+ const newExpanded = new Set(effectiveExpandedNodes);
17064
17161
  if (newExpanded.has(id2)) {
17065
17162
  newExpanded.delete(id2);
17066
17163
  } else {
17067
17164
  newExpanded.add(id2);
17068
17165
  }
17069
- setExpandedNodes(newExpanded);
17166
+ if (expandedIds === void 0) {
17167
+ setExpandedNodes(newExpanded);
17168
+ }
17169
+ onExpandedChange?.(Array.from(newExpanded));
17070
17170
  };
17071
17171
  const handleSelect = (categoryId, category) => {
17072
17172
  if (viewOnly) return;
@@ -17094,21 +17194,23 @@ function CategoryTreeSelect(props) {
17094
17194
  const newSelected = new Set(valueArray);
17095
17195
  if (newSelected.has(categoryId)) {
17096
17196
  newSelected.delete(categoryId);
17097
- const children = childrenMap.get(categoryId) || [];
17098
- children.forEach((child) => newSelected.delete(child.id));
17197
+ for (const descendantId of collectDescendantIds(childrenMap, categoryId)) {
17198
+ newSelected.delete(descendantId);
17199
+ }
17200
+ pruneAncestorSelection(categories, childrenMap, newSelected, categoryId);
17099
17201
  } else {
17100
17202
  newSelected.add(categoryId);
17101
- if (category.parent_id) {
17102
- newSelected.add(category.parent_id);
17203
+ for (const ancestorId of collectAncestorIds(categories, categoryId)) {
17204
+ newSelected.add(ancestorId);
17103
17205
  }
17104
17206
  }
17105
- onChange(Array.from(newSelected));
17207
+ onChange(toCategoryOrderSelection(categories, newSelected));
17106
17208
  }
17107
17209
  };
17108
17210
  const renderCategory = (category, level = 0) => {
17109
17211
  const children = effectiveChildrenMap.get(category.id) || [];
17110
17212
  const hasChildren = children.length > 0;
17111
- const isExpanded = hasChildren && (isSearchMode || expandedNodes.has(category.id));
17213
+ const isExpanded = hasChildren && (isSearchMode || effectiveExpandedNodes.has(category.id));
17112
17214
  const isSelected = selectedIds.has(category.id);
17113
17215
  const isSelectable = !viewOnly && (!leafOnlySelect || !hasChildren);
17114
17216
  return /* @__PURE__ */ jsxs39(
@@ -17456,11 +17558,10 @@ function CategoryTreeSelect(props) {
17456
17558
  "shadow-2xl backdrop-blur-xl"
17457
17559
  ),
17458
17560
  trigger: /* @__PURE__ */ jsxs39(
17459
- "button",
17561
+ "div",
17460
17562
  {
17461
17563
  id: resolvedId,
17462
- type: "button",
17463
- disabled,
17564
+ tabIndex: disabled ? -1 : 0,
17464
17565
  role: "combobox",
17465
17566
  "aria-haspopup": "tree",
17466
17567
  "aria-expanded": isOpen,
@@ -17469,6 +17570,13 @@ function CategoryTreeSelect(props) {
17469
17570
  "aria-describedby": describedBy,
17470
17571
  "aria-required": required,
17471
17572
  "aria-invalid": !!effectiveError,
17573
+ onKeyDown: (event) => {
17574
+ if (disabled) return;
17575
+ if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown") {
17576
+ event.preventDefault();
17577
+ handleOpenChange(!isOpen);
17578
+ }
17579
+ },
17472
17580
  className: cn(
17473
17581
  "group flex w-full items-center justify-between rounded-full transition-all duration-200",
17474
17582
  "backdrop-blur-sm",
@@ -17507,13 +17615,11 @@ function CategoryTreeSelect(props) {
17507
17615
  ] }),
17508
17616
  /* @__PURE__ */ jsxs39("div", { className: "ml-2 flex shrink-0 items-center gap-1.5", children: [
17509
17617
  allowClear && selectedCount > 0 && !disabled && /* @__PURE__ */ jsx49(
17510
- "div",
17618
+ "button",
17511
17619
  {
17512
- role: "button",
17513
- tabIndex: 0,
17620
+ type: "button",
17514
17621
  "aria-label": "Clear selection",
17515
17622
  onClick: handleClear,
17516
- onKeyDown: (event) => (event.key === "Enter" || event.key === " ") && handleClear(event),
17517
17623
  className: cn(
17518
17624
  "opacity-0 group-hover:opacity-100 transition-all duration-200",
17519
17625
  "p-1 rounded-lg hover:bg-destructive/10 text-muted-foreground hover:text-destructive",
@@ -21236,6 +21342,18 @@ function DataTableBodyRows({
21236
21342
  import React54 from "react";
21237
21343
  import { Filter as FilterIcon } from "lucide-react";
21238
21344
  import { Fragment as Fragment22, jsx as jsx64, jsxs as jsxs53 } from "react/jsx-runtime";
21345
+ function getColumnLabel(title) {
21346
+ if (typeof title === "string" || typeof title === "number") {
21347
+ return String(title).replace(/\s+/g, " ").trim();
21348
+ }
21349
+ if (Array.isArray(title)) {
21350
+ return title.map((item) => getColumnLabel(item)).filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
21351
+ }
21352
+ if (React54.isValidElement(title)) {
21353
+ return getColumnLabel(title.props.children);
21354
+ }
21355
+ return "";
21356
+ }
21239
21357
  function DataTableHeader({
21240
21358
  headerRows,
21241
21359
  headerAlign,
@@ -21260,12 +21378,13 @@ function DataTableHeader({
21260
21378
  if (!col.filter) return null;
21261
21379
  const key = col.key;
21262
21380
  const commonProps = { className: "w-full", size };
21381
+ const columnLabel = getColumnLabel(col.title) || key;
21263
21382
  if (col.filter.type === "text") {
21264
21383
  return /* @__PURE__ */ jsx64(
21265
21384
  Input_default,
21266
21385
  {
21267
21386
  ...commonProps,
21268
- placeholder: col.filter.placeholder || `Search ${String(col.title)}`,
21387
+ placeholder: col.filter.placeholder || `Search ${columnLabel}`,
21269
21388
  value: filters[key] || "",
21270
21389
  onChange: (e) => {
21271
21390
  setCurPage(1);
@@ -21286,7 +21405,7 @@ function DataTableHeader({
21286
21405
  setCurPage(1);
21287
21406
  setFilters((prev) => ({ ...prev, [key]: value || void 0 }));
21288
21407
  },
21289
- placeholder: col.filter.placeholder || `Select ${String(col.title)}`
21408
+ placeholder: col.filter.placeholder || `Select ${columnLabel}`
21290
21409
  }
21291
21410
  );
21292
21411
  }
@@ -21295,7 +21414,7 @@ function DataTableHeader({
21295
21414
  DatePicker,
21296
21415
  {
21297
21416
  size,
21298
- placeholder: col.filter.placeholder || `Select ${String(col.title)}`,
21417
+ placeholder: col.filter.placeholder || `Select ${columnLabel}`,
21299
21418
  value: filters[key] || null,
21300
21419
  onChange: (date) => {
21301
21420
  setCurPage(1);
@@ -21327,16 +21446,19 @@ function DataTableHeader({
21327
21446
  }
21328
21447
  const isRightAlign = col.align === "right" || !col.align && headerAlign === "right";
21329
21448
  const isCenterAlign = col.align === "center" || !col.align && headerAlign === "center";
21449
+ const columnLabel = getColumnLabel(col.title) || col.key;
21330
21450
  const titleContent = /* @__PURE__ */ jsxs53("div", { className: "flex items-center gap-1", children: [
21331
21451
  /* @__PURE__ */ jsx64("span", { className: cn("font-medium whitespace-nowrap select-text", headerTitleClass), children: col.title }),
21332
21452
  col.sortable && /* @__PURE__ */ jsx64(
21333
21453
  Tooltip,
21334
21454
  {
21335
21455
  placement: "top",
21336
- content: /* @__PURE__ */ jsx64("span", { className: "text-xs font-medium", children: `Sort by ${String(col.title)}` }),
21456
+ content: /* @__PURE__ */ jsx64("span", { className: "text-xs font-medium", children: `Sort by ${columnLabel}` }),
21337
21457
  children: /* @__PURE__ */ jsx64(
21338
21458
  "button",
21339
21459
  {
21460
+ type: "button",
21461
+ title: `Sort by ${columnLabel}`,
21340
21462
  className: cn(
21341
21463
  "p-1 rounded-lg transition-all duration-200 hover:bg-accent",
21342
21464
  sort?.key === col.key ? "opacity-100 bg-accent" : "opacity-60 hover:opacity-100"
@@ -21349,7 +21471,7 @@ function DataTableHeader({
21349
21471
  return null;
21350
21472
  });
21351
21473
  },
21352
- "aria-label": "Sort",
21474
+ "aria-label": `Sort by ${columnLabel}`,
21353
21475
  children: /* @__PURE__ */ jsxs53("svg", { viewBox: "0 0 20 20", fill: "none", className: cn("inline-block", sortIconClass), children: [
21354
21476
  /* @__PURE__ */ jsx64(
21355
21477
  "path",
@@ -21387,15 +21509,17 @@ function DataTableHeader({
21387
21509
  Tooltip,
21388
21510
  {
21389
21511
  placement: "top",
21390
- content: /* @__PURE__ */ jsx64("span", { className: "text-xs font-medium", children: `Filter by ${String(col.title)}` }),
21512
+ content: /* @__PURE__ */ jsx64("span", { className: "text-xs font-medium", children: `Filter by ${columnLabel}` }),
21391
21513
  children: /* @__PURE__ */ jsx64(
21392
21514
  "button",
21393
21515
  {
21516
+ type: "button",
21517
+ title: `Filter by ${columnLabel}`,
21394
21518
  className: cn(
21395
21519
  "p-1.5 rounded-lg transition-all duration-200 hover:bg-accent",
21396
21520
  filters[col.key] ? "bg-accent text-primary" : "text-muted-foreground"
21397
21521
  ),
21398
- "aria-label": "Filter",
21522
+ "aria-label": `Filter by ${columnLabel}`,
21399
21523
  children: /* @__PURE__ */ jsx64(FilterIcon, { className: "w-4 h-4" })
21400
21524
  }
21401
21525
  )
@@ -22911,16 +23035,8 @@ function LanguageSwitcherHeadless({
22911
23035
  ] });
22912
23036
  }
22913
23037
 
22914
- // ../../lib/utils/cn.ts
22915
- import { clsx as clsx2 } from "clsx";
22916
- import { twMerge as twMerge2 } from "tailwind-merge";
22917
- function cn2(...inputs) {
22918
- return twMerge2(clsx2(...inputs));
22919
- }
22920
-
22921
- // ../../lib/constants/constants-ui/alert.ts
23038
+ // src/constants/alert.ts
22922
23039
  var VARIANT_STYLES_ALERT = {
22923
- // Use system colors for background + border; leave text colors to content
22924
23040
  default: "border border-border bg-card/60 backdrop-blur-sm",
22925
23041
  info: "border border-info/30 bg-info/10 backdrop-blur-sm",
22926
23042
  success: "border border-success/30 bg-success/10 backdrop-blur-sm",
@@ -22928,7 +23044,7 @@ var VARIANT_STYLES_ALERT = {
22928
23044
  error: "border border-destructive/30 bg-destructive/10 backdrop-blur-sm"
22929
23045
  };
22930
23046
 
22931
- // ../../lib/i18n/translation-adapter.tsx
23047
+ // src/contexts/translation-adapter.tsx
22932
23048
  import * as React65 from "react";
22933
23049
  import { jsx as jsx73 } from "react/jsx-runtime";
22934
23050
  function isUnresolvedTranslation2(value, namespace, key) {
@@ -31655,6 +31771,7 @@ var UEditor = React74.forwardRef(({
31655
31771
  const t = useSmartTranslations("UEditor");
31656
31772
  const effectivePlaceholder = placeholder ?? t("placeholder");
31657
31773
  const inFlightPrepareRef = useRef31(null);
31774
+ const lastAppliedContentRef = useRef31(content ?? "");
31658
31775
  const editorContentRef = useRef31(null);
31659
31776
  const tableColumnGuideRef = useRef31(null);
31660
31777
  const tableRowGuideRef = useRef31(null);
@@ -31957,10 +32074,12 @@ var UEditor = React74.forwardRef(({
31957
32074
  [content, editor, uploadImageForSave]
31958
32075
  );
31959
32076
  useEffect35(() => {
31960
- if (editor && content !== editor.getHTML()) {
31961
- if (editor.isEmpty && content) {
31962
- editor.commands.setContent(content);
31963
- }
32077
+ if (!editor) return;
32078
+ const nextContent = content ?? "";
32079
+ if (lastAppliedContentRef.current === nextContent) return;
32080
+ lastAppliedContentRef.current = nextContent;
32081
+ if (editor.getHTML() !== nextContent) {
32082
+ editor.commands.setContent(nextContent, { emitUpdate: false });
31964
32083
  }
31965
32084
  }, [content, editor]);
31966
32085
  useEffect35(() => {
@@ -32410,7 +32529,7 @@ export {
32410
32529
  VIETNAM_HOLIDAYS,
32411
32530
  VerticalTabs,
32412
32531
  Watermark_default as Watermark,
32413
- cn2 as cn,
32532
+ cn,
32414
32533
  cn as cnLocal,
32415
32534
  extractImageSrcsFromHtml,
32416
32535
  getAnimationStyles,