@underverse-ui/underverse 1.0.8 → 1.0.10
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.cjs +187 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +256 -96
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6536,6 +6536,14 @@ var import_lucide_react17 = require("lucide-react");
|
|
|
6536
6536
|
var import_lucide_react15 = require("lucide-react");
|
|
6537
6537
|
var React24 = __toESM(require("react"), 1);
|
|
6538
6538
|
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
6539
|
+
var VIETNAM_HOLIDAYS = [
|
|
6540
|
+
{ date: "01-01", name: "T\u1EBFt D\u01B0\u01A1ng l\u1ECBch", recurring: true },
|
|
6541
|
+
{ date: "04-30", name: "Gi\u1EA3i ph\xF3ng mi\u1EC1n Nam", recurring: true },
|
|
6542
|
+
{ date: "05-01", name: "Qu\u1ED1c t\u1EBF Lao \u0111\u1ED9ng", recurring: true },
|
|
6543
|
+
{ date: "09-02", name: "Qu\u1ED1c kh\xE1nh", recurring: true },
|
|
6544
|
+
{ date: "03-10", name: "Gi\u1ED7 T\u1ED5 H\xF9ng V\u01B0\u01A1ng", recurring: true }
|
|
6545
|
+
// Lunar 10/3, simplified
|
|
6546
|
+
];
|
|
6539
6547
|
function startOfMonth(d) {
|
|
6540
6548
|
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
6541
6549
|
}
|
|
@@ -6565,6 +6573,20 @@ function startOfWeek(d, weekStartsOn) {
|
|
|
6565
6573
|
s.setDate(d.getDate() - diff);
|
|
6566
6574
|
return new Date(s.getFullYear(), s.getMonth(), s.getDate());
|
|
6567
6575
|
}
|
|
6576
|
+
function isHoliday(d, holidays) {
|
|
6577
|
+
const mm = String(d.getMonth() + 1).padStart(2, "0");
|
|
6578
|
+
const dd = String(d.getDate()).padStart(2, "0");
|
|
6579
|
+
const mmdd = `${mm}-${dd}`;
|
|
6580
|
+
for (const h of holidays) {
|
|
6581
|
+
if (h.recurring) {
|
|
6582
|
+
if (h.date === mmdd) return h;
|
|
6583
|
+
} else {
|
|
6584
|
+
const hDate = h.date instanceof Date ? h.date : new Date(h.date);
|
|
6585
|
+
if (isSameDay(d, hDate)) return h;
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
return void 0;
|
|
6589
|
+
}
|
|
6568
6590
|
function getMonthGrid(view, weekStartsOn) {
|
|
6569
6591
|
const start = startOfMonth(view);
|
|
6570
6592
|
const end = endOfMonth(view);
|
|
@@ -6614,8 +6636,13 @@ function Calendar2({
|
|
|
6614
6636
|
animate = false,
|
|
6615
6637
|
showEventBadges = false,
|
|
6616
6638
|
highlightWeekends = false,
|
|
6639
|
+
weekendTextColor = "text-destructive",
|
|
6640
|
+
highlightHolidays = false,
|
|
6641
|
+
holidayTextColor = "text-destructive",
|
|
6642
|
+
holidays = VIETNAM_HOLIDAYS,
|
|
6617
6643
|
cellMode = "compact",
|
|
6618
6644
|
maxEventsPerDay = 3,
|
|
6645
|
+
showEventCount = true,
|
|
6619
6646
|
onEventClick,
|
|
6620
6647
|
renderEvent,
|
|
6621
6648
|
enableEventSheet,
|
|
@@ -6802,6 +6829,8 @@ function Calendar2({
|
|
|
6802
6829
|
const dayEvents = byDay.get(k) || [];
|
|
6803
6830
|
const disabled = isDateDisabled(d);
|
|
6804
6831
|
const isWeekend = d.getDay() === 0 || d.getDay() === 6;
|
|
6832
|
+
const holidayMatch = isHoliday(d, holidays);
|
|
6833
|
+
const isHolidayDay = highlightHolidays && !!holidayMatch;
|
|
6805
6834
|
const customDay = renderDay?.({ date: d, isCurrentMonth: inMonth, isToday: isToday2, isSelected: selectedDay, events: dayEvents });
|
|
6806
6835
|
if (customDay) return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(React24.Fragment, { children: customDay }, `${monthLabel}-${idx}`);
|
|
6807
6836
|
if (cellMode === "events") {
|
|
@@ -6820,9 +6849,11 @@ function Calendar2({
|
|
|
6820
6849
|
!inMonth && "opacity-40",
|
|
6821
6850
|
disabled && "opacity-30 cursor-not-allowed",
|
|
6822
6851
|
highlightWeekends && isWeekend && "bg-destructive/5",
|
|
6852
|
+
isHolidayDay && "bg-destructive/5",
|
|
6823
6853
|
isToday2 && !selectedDay && "ring-2 ring-primary/40 border-primary/50",
|
|
6824
6854
|
selectedDay && "border-primary/60 bg-primary/5"
|
|
6825
6855
|
),
|
|
6856
|
+
title: holidayMatch?.name,
|
|
6826
6857
|
children: [
|
|
6827
6858
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center justify-between px-2.5 py-1.5", children: [
|
|
6828
6859
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
@@ -6831,6 +6862,8 @@ function Calendar2({
|
|
|
6831
6862
|
className: cn(
|
|
6832
6863
|
"font-semibold tabular-nums",
|
|
6833
6864
|
cellSz.day,
|
|
6865
|
+
highlightWeekends && isWeekend && weekendTextColor,
|
|
6866
|
+
isHolidayDay && holidayTextColor,
|
|
6834
6867
|
isToday2 && "text-primary",
|
|
6835
6868
|
selectedDay && "text-primary",
|
|
6836
6869
|
!inMonth && "text-muted-foreground/50"
|
|
@@ -6838,7 +6871,7 @@ function Calendar2({
|
|
|
6838
6871
|
children: d.getDate()
|
|
6839
6872
|
}
|
|
6840
6873
|
),
|
|
6841
|
-
dayEvents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-[10px] px-1.5 py-0.5 rounded-md bg-muted/60 text-muted-foreground font-medium", children: dayEvents.length })
|
|
6874
|
+
dayEvents.length > 0 && showEventCount && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-[10px] px-1.5 py-0.5 rounded-md bg-muted/60 text-muted-foreground font-medium", children: dayEvents.length })
|
|
6842
6875
|
] }),
|
|
6843
6876
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "space-y-1 px-2 pb-2", children: [
|
|
6844
6877
|
visibleEvents.map((e, i) => {
|
|
@@ -6851,7 +6884,7 @@ function Calendar2({
|
|
|
6851
6884
|
type: "button",
|
|
6852
6885
|
onClick: () => handleEventActivate(e, d, k, i),
|
|
6853
6886
|
className: cn(
|
|
6854
|
-
"group w-full text-left rounded-lg px-2.5 py-1.5",
|
|
6887
|
+
"group w-full text-left rounded-r-lg px-2.5 py-1.5",
|
|
6855
6888
|
"transition-all duration-150",
|
|
6856
6889
|
"hover:bg-accent/50 hover:shadow-sm hover:-translate-y-0.5",
|
|
6857
6890
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30",
|
|
@@ -6893,11 +6926,14 @@ function Calendar2({
|
|
|
6893
6926
|
!inMonth && "text-muted-foreground/50",
|
|
6894
6927
|
disabled && "opacity-40 cursor-not-allowed",
|
|
6895
6928
|
highlightWeekends && isWeekend && "bg-destructive/5",
|
|
6929
|
+
highlightWeekends && isWeekend && !selectedDay && weekendTextColor,
|
|
6930
|
+
isHolidayDay && "bg-destructive/5",
|
|
6931
|
+
isHolidayDay && !selectedDay && holidayTextColor,
|
|
6896
6932
|
isToday2 && !selectedDay && "ring-2 ring-primary/60 bg-primary/5 font-bold",
|
|
6897
6933
|
selectedDay && "bg-linear-to-br from-primary to-primary/90 text-primary-foreground shadow-md hover:shadow-lg hover:scale-105",
|
|
6898
6934
|
!selectedDay && !disabled && "hover:bg-accent hover:text-accent-foreground hover:scale-105 active:scale-95"
|
|
6899
6935
|
),
|
|
6900
|
-
title: d.toDateString(),
|
|
6936
|
+
title: holidayMatch?.name || d.toDateString(),
|
|
6901
6937
|
children: [
|
|
6902
6938
|
d.getDate(),
|
|
6903
6939
|
dayEvents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "absolute -bottom-1 inline-flex gap-0.5", children: dayEvents.slice(0, 3).map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
@@ -6981,6 +7017,8 @@ function Calendar2({
|
|
|
6981
7017
|
const dayEvents = byDay.get(k) || [];
|
|
6982
7018
|
const disabled = isDateDisabled(d);
|
|
6983
7019
|
const isWeekend = d.getDay() === 0 || d.getDay() === 6;
|
|
7020
|
+
const holidayMatch = isHoliday(d, holidays);
|
|
7021
|
+
const isHolidayDay = highlightHolidays && !!holidayMatch;
|
|
6984
7022
|
const customDay = renderDay?.({ date: d, isCurrentMonth: inMonth, isToday: isToday2, isSelected: selectedDay, events: dayEvents });
|
|
6985
7023
|
if (customDay) return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(React24.Fragment, { children: customDay }, `wd-${idx}`);
|
|
6986
7024
|
if (cellMode === "events") {
|
|
@@ -6998,9 +7036,11 @@ function Calendar2({
|
|
|
6998
7036
|
cellSz.cell,
|
|
6999
7037
|
disabled && "opacity-30 cursor-not-allowed",
|
|
7000
7038
|
highlightWeekends && isWeekend && "bg-destructive/5",
|
|
7039
|
+
isHolidayDay && "bg-destructive/5",
|
|
7001
7040
|
isToday2 && !selectedDay && "ring-2 ring-primary/40 border-primary/50",
|
|
7002
7041
|
selectedDay && "border-primary/60 bg-primary/5"
|
|
7003
7042
|
),
|
|
7043
|
+
title: holidayMatch?.name,
|
|
7004
7044
|
children: [
|
|
7005
7045
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-center justify-between px-2.5 py-1.5", children: [
|
|
7006
7046
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
@@ -7009,13 +7049,15 @@ function Calendar2({
|
|
|
7009
7049
|
className: cn(
|
|
7010
7050
|
"font-semibold tabular-nums",
|
|
7011
7051
|
cellSz.day,
|
|
7052
|
+
highlightWeekends && isWeekend && weekendTextColor,
|
|
7053
|
+
isHolidayDay && holidayTextColor,
|
|
7012
7054
|
isToday2 && "text-primary",
|
|
7013
7055
|
selectedDay && "text-primary"
|
|
7014
7056
|
),
|
|
7015
7057
|
children: d.getDate()
|
|
7016
7058
|
}
|
|
7017
7059
|
),
|
|
7018
|
-
dayEvents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-[10px] px-1.5 py-0.5 rounded-md bg-muted/60 text-muted-foreground font-medium", children: dayEvents.length })
|
|
7060
|
+
dayEvents.length > 0 && showEventCount && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "text-[10px] px-1.5 py-0.5 rounded-md bg-muted/60 text-muted-foreground font-medium", children: dayEvents.length })
|
|
7019
7061
|
] }),
|
|
7020
7062
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "space-y-1 px-2 pb-2", children: [
|
|
7021
7063
|
visibleEvents.map((e, i) => {
|
|
@@ -7028,7 +7070,7 @@ function Calendar2({
|
|
|
7028
7070
|
type: "button",
|
|
7029
7071
|
onClick: () => handleEventActivate(e, d, k, i),
|
|
7030
7072
|
className: cn(
|
|
7031
|
-
"group w-full text-left rounded-lg px-2.5 py-1.5",
|
|
7073
|
+
"group w-full text-left rounded-r-lg px-2.5 py-1.5",
|
|
7032
7074
|
"transition-all duration-150",
|
|
7033
7075
|
"hover:bg-accent/50 hover:shadow-sm hover:-translate-y-0.5",
|
|
7034
7076
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30",
|
|
@@ -7069,7 +7111,9 @@ function Calendar2({
|
|
|
7069
7111
|
highlightWeekends && isWeekend && "bg-accent/10",
|
|
7070
7112
|
isToday2 && !selectedDay && "ring-1 ring-primary/50",
|
|
7071
7113
|
selectedDay && "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
7072
|
-
!selectedDay && "hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground"
|
|
7114
|
+
!selectedDay && "hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
|
|
7115
|
+
!selectedDay && highlightHolidays && isHoliday(d, holidays) && holidayTextColor,
|
|
7116
|
+
!selectedDay && !(highlightHolidays && isHoliday(d, holidays)) && isWeekend && weekendTextColor
|
|
7073
7117
|
),
|
|
7074
7118
|
title: d.toDateString(),
|
|
7075
7119
|
children: [
|
|
@@ -12693,7 +12737,9 @@ var import_lucide_react24 = require("lucide-react");
|
|
|
12693
12737
|
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
12694
12738
|
var defaultLabels = {
|
|
12695
12739
|
emptyText: "No categories",
|
|
12696
|
-
selectedText: (count) => `${count} selected
|
|
12740
|
+
selectedText: (count) => `${count} selected`,
|
|
12741
|
+
searchPlaceholder: "Search...",
|
|
12742
|
+
noResultsText: "No results found"
|
|
12697
12743
|
};
|
|
12698
12744
|
function CategoryTreeSelect(props) {
|
|
12699
12745
|
const {
|
|
@@ -12702,6 +12748,7 @@ function CategoryTreeSelect(props) {
|
|
|
12702
12748
|
disabled,
|
|
12703
12749
|
viewOnly = false,
|
|
12704
12750
|
defaultExpanded = false,
|
|
12751
|
+
enableSearch,
|
|
12705
12752
|
labels,
|
|
12706
12753
|
inline = false,
|
|
12707
12754
|
onNodeClick,
|
|
@@ -12710,18 +12757,76 @@ function CategoryTreeSelect(props) {
|
|
|
12710
12757
|
} = props;
|
|
12711
12758
|
const [isOpen, setIsOpen] = (0, import_react18.useState)(false);
|
|
12712
12759
|
const [expandedNodes, setExpandedNodes] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
|
|
12760
|
+
const [query, setQuery] = (0, import_react18.useState)("");
|
|
12761
|
+
const searchInputRef = (0, import_react18.useRef)(null);
|
|
12713
12762
|
const mergedLabels = { ...defaultLabels, ...labels };
|
|
12714
12763
|
const valueArray = singleSelect ? props.value != null ? [props.value] : [] : props.value || [];
|
|
12715
|
-
const parentCategories =
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
|
|
12764
|
+
const { parentCategories, childrenMap, byId } = (0, import_react18.useMemo)(() => {
|
|
12765
|
+
const byId2 = /* @__PURE__ */ new Map();
|
|
12766
|
+
const childrenMap2 = /* @__PURE__ */ new Map();
|
|
12767
|
+
const parentCategories2 = [];
|
|
12768
|
+
for (const cat of categories) byId2.set(cat.id, cat);
|
|
12769
|
+
for (const cat of categories) {
|
|
12770
|
+
if (cat.parent_id == null) {
|
|
12771
|
+
parentCategories2.push(cat);
|
|
12772
|
+
continue;
|
|
12773
|
+
}
|
|
12774
|
+
if (!childrenMap2.has(cat.parent_id)) childrenMap2.set(cat.parent_id, []);
|
|
12775
|
+
childrenMap2.get(cat.parent_id).push(cat);
|
|
12776
|
+
}
|
|
12777
|
+
return { parentCategories: parentCategories2, childrenMap: childrenMap2, byId: byId2 };
|
|
12778
|
+
}, [categories]);
|
|
12779
|
+
const isSearchEnabled = (0, import_react18.useMemo)(() => enableSearch ?? categories.length > 10, [enableSearch, categories.length]);
|
|
12780
|
+
const normalizedQuery = (0, import_react18.useMemo)(() => query.trim().toLowerCase(), [query]);
|
|
12781
|
+
const isSearchMode = isSearchEnabled && normalizedQuery.length > 0;
|
|
12782
|
+
const visibleIds = (0, import_react18.useMemo)(() => {
|
|
12783
|
+
if (!isSearchMode) return null;
|
|
12784
|
+
const matches = categories.filter((c) => c.name.toLowerCase().includes(normalizedQuery));
|
|
12785
|
+
if (matches.length === 0) return /* @__PURE__ */ new Set();
|
|
12786
|
+
const visible = /* @__PURE__ */ new Set();
|
|
12787
|
+
const addAncestors = (cat) => {
|
|
12788
|
+
let cur = cat;
|
|
12789
|
+
let guard = 0;
|
|
12790
|
+
while (cur && cur.parent_id != null && guard++ < categories.length) {
|
|
12791
|
+
const pid = cur.parent_id;
|
|
12792
|
+
if (typeof pid !== "number") break;
|
|
12793
|
+
if (visible.has(pid)) {
|
|
12794
|
+
cur = byId.get(pid);
|
|
12795
|
+
continue;
|
|
12796
|
+
}
|
|
12797
|
+
visible.add(pid);
|
|
12798
|
+
cur = byId.get(pid);
|
|
12799
|
+
}
|
|
12800
|
+
};
|
|
12801
|
+
const addDescendants = (rootId) => {
|
|
12802
|
+
const stack = [rootId];
|
|
12803
|
+
let guard = 0;
|
|
12804
|
+
while (stack.length > 0 && guard++ < categories.length * 3) {
|
|
12805
|
+
const id = stack.pop();
|
|
12806
|
+
const children = childrenMap.get(id) ?? [];
|
|
12807
|
+
for (const child of children) {
|
|
12808
|
+
if (visible.has(child.id)) continue;
|
|
12809
|
+
visible.add(child.id);
|
|
12810
|
+
stack.push(child.id);
|
|
12811
|
+
}
|
|
12721
12812
|
}
|
|
12722
|
-
|
|
12813
|
+
};
|
|
12814
|
+
for (const m of matches) {
|
|
12815
|
+
visible.add(m.id);
|
|
12816
|
+
addAncestors(m);
|
|
12817
|
+
addDescendants(m.id);
|
|
12723
12818
|
}
|
|
12724
|
-
|
|
12819
|
+
return visible;
|
|
12820
|
+
}, [byId, categories, childrenMap, isSearchMode, normalizedQuery]);
|
|
12821
|
+
(0, import_react18.useEffect)(() => {
|
|
12822
|
+
if (!isOpen) setQuery("");
|
|
12823
|
+
}, [isOpen]);
|
|
12824
|
+
(0, import_react18.useEffect)(() => {
|
|
12825
|
+
if (!isOpen) return;
|
|
12826
|
+
if (!isSearchEnabled) return;
|
|
12827
|
+
const t = setTimeout(() => searchInputRef.current?.focus(), 50);
|
|
12828
|
+
return () => clearTimeout(t);
|
|
12829
|
+
}, [isOpen, isSearchEnabled]);
|
|
12725
12830
|
(0, import_react18.useEffect)(() => {
|
|
12726
12831
|
if ((viewOnly || inline) && defaultExpanded) {
|
|
12727
12832
|
const allParentIds = categories.filter((c) => childrenMap.has(c.id)).map((c) => c.id);
|
|
@@ -12729,6 +12834,7 @@ function CategoryTreeSelect(props) {
|
|
|
12729
12834
|
}
|
|
12730
12835
|
}, [viewOnly, inline, defaultExpanded, categories]);
|
|
12731
12836
|
const toggleExpand = (id) => {
|
|
12837
|
+
if (isSearchMode) return;
|
|
12732
12838
|
const newExpanded = new Set(expandedNodes);
|
|
12733
12839
|
if (newExpanded.has(id)) {
|
|
12734
12840
|
newExpanded.delete(id);
|
|
@@ -12769,9 +12875,10 @@ function CategoryTreeSelect(props) {
|
|
|
12769
12875
|
}
|
|
12770
12876
|
};
|
|
12771
12877
|
const renderCategory = (category, level = 0) => {
|
|
12772
|
-
const
|
|
12878
|
+
const allChildren = childrenMap.get(category.id) || [];
|
|
12879
|
+
const children = isSearchMode ? allChildren.filter((c) => visibleIds?.has(c.id)) : allChildren;
|
|
12773
12880
|
const hasChildren = children.length > 0;
|
|
12774
|
-
const isExpanded = expandedNodes.has(category.id);
|
|
12881
|
+
const isExpanded = hasChildren && (isSearchMode || expandedNodes.has(category.id));
|
|
12775
12882
|
const isSelected = valueArray.includes(category.id);
|
|
12776
12883
|
const isParent = level === 0;
|
|
12777
12884
|
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "animate-in fade-in-50 duration-200", style: { animationDelay: `${level * 30}ms` }, children: [
|
|
@@ -12801,8 +12908,10 @@ function CategoryTreeSelect(props) {
|
|
|
12801
12908
|
"p-1.5 rounded-lg transition-all duration-200",
|
|
12802
12909
|
"hover:scale-110 active:scale-95",
|
|
12803
12910
|
"focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50",
|
|
12804
|
-
isExpanded && "text-primary"
|
|
12911
|
+
isExpanded && "text-primary",
|
|
12912
|
+
isSearchMode && "opacity-60 cursor-not-allowed hover:scale-100 active:scale-100"
|
|
12805
12913
|
),
|
|
12914
|
+
disabled: isSearchMode,
|
|
12806
12915
|
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: cn("transition-transform duration-200", isExpanded && "rotate-90"), children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react24.ChevronRight, { className: "w-4 h-4" }) })
|
|
12807
12916
|
}
|
|
12808
12917
|
) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "w-7" }),
|
|
@@ -12826,15 +12935,60 @@ function CategoryTreeSelect(props) {
|
|
|
12826
12935
|
hasChildren && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: cn("ml-2 pl-2 border-l-2 border-dashed border-border/50", "animate-in slide-in-from-top-2 fade-in-50 duration-200"), children: children.map((child) => renderCategory(child, level + 1)) })
|
|
12827
12936
|
] }, category.id);
|
|
12828
12937
|
};
|
|
12829
|
-
const
|
|
12830
|
-
|
|
12831
|
-
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("
|
|
12832
|
-
|
|
12938
|
+
const renderSearch = () => {
|
|
12939
|
+
if (!isSearchEnabled) return null;
|
|
12940
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "sticky top-0 z-10 px-1 pt-1 pb-2 bg-popover/80 backdrop-blur-xl", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "relative", children: [
|
|
12941
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react24.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
12942
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
12943
|
+
"input",
|
|
12944
|
+
{
|
|
12945
|
+
ref: searchInputRef,
|
|
12946
|
+
value: query,
|
|
12947
|
+
onChange: (e) => setQuery(e.target.value),
|
|
12948
|
+
placeholder: mergedLabels.searchPlaceholder,
|
|
12949
|
+
className: cn(
|
|
12950
|
+
"w-full h-10 rounded-full px-10 pr-10 text-sm",
|
|
12951
|
+
"bg-background/70 border border-border/60",
|
|
12952
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:border-primary/40"
|
|
12953
|
+
)
|
|
12954
|
+
}
|
|
12955
|
+
),
|
|
12956
|
+
query.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
12957
|
+
"button",
|
|
12958
|
+
{
|
|
12959
|
+
type: "button",
|
|
12960
|
+
onClick: () => {
|
|
12961
|
+
setQuery("");
|
|
12962
|
+
searchInputRef.current?.focus();
|
|
12963
|
+
},
|
|
12964
|
+
className: cn(
|
|
12965
|
+
"absolute right-2 top-1/2 -translate-y-1/2 h-7 w-7 rounded-full",
|
|
12966
|
+
"flex items-center justify-center",
|
|
12967
|
+
"text-muted-foreground hover:text-foreground hover:bg-accent/40 transition-colors",
|
|
12968
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
|
|
12969
|
+
),
|
|
12970
|
+
"aria-label": "Clear search",
|
|
12971
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react24.X, { className: "h-4 w-4" })
|
|
12972
|
+
}
|
|
12973
|
+
)
|
|
12974
|
+
] }) });
|
|
12975
|
+
};
|
|
12976
|
+
const effectiveParentCategories = (0, import_react18.useMemo)(() => {
|
|
12977
|
+
if (!isSearchMode) return parentCategories;
|
|
12978
|
+
return parentCategories.filter((c) => visibleIds?.has(c.id));
|
|
12979
|
+
}, [isSearchMode, parentCategories, visibleIds]);
|
|
12980
|
+
const renderTreeContent = () => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "space-y-0.5", children: effectiveParentCategories.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
|
|
12981
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "w-12 h-12 rounded-2xl bg-muted/50 flex items-center justify-center mb-3", children: isSearchMode ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react24.SearchX, { className: "w-6 h-6 text-muted-foreground/50" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react24.Layers, { className: "w-6 h-6 text-muted-foreground/50" }) }),
|
|
12982
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-sm text-muted-foreground", children: isSearchMode ? mergedLabels.noResultsText : mergedLabels.emptyText })
|
|
12983
|
+
] }) : effectiveParentCategories.map((cat) => renderCategory(cat)) });
|
|
12833
12984
|
if (viewOnly) {
|
|
12834
|
-
return /* @__PURE__ */ (0, import_jsx_runtime43.
|
|
12985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cn("rounded-2xl border border-border/60 bg-card/50 backdrop-blur-sm p-3 shadow-sm", disabled && "opacity-50", className), children: [
|
|
12986
|
+
renderSearch(),
|
|
12987
|
+
renderTreeContent()
|
|
12988
|
+
] });
|
|
12835
12989
|
}
|
|
12836
12990
|
if (inline) {
|
|
12837
|
-
return /* @__PURE__ */ (0, import_jsx_runtime43.
|
|
12991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
12838
12992
|
"div",
|
|
12839
12993
|
{
|
|
12840
12994
|
className: cn(
|
|
@@ -12842,7 +12996,10 @@ function CategoryTreeSelect(props) {
|
|
|
12842
12996
|
disabled && "opacity-50 pointer-events-none",
|
|
12843
12997
|
className
|
|
12844
12998
|
),
|
|
12845
|
-
children:
|
|
12999
|
+
children: [
|
|
13000
|
+
renderSearch(),
|
|
13001
|
+
renderTreeContent()
|
|
13002
|
+
]
|
|
12846
13003
|
}
|
|
12847
13004
|
);
|
|
12848
13005
|
}
|
|
@@ -12899,7 +13056,7 @@ function CategoryTreeSelect(props) {
|
|
|
12899
13056
|
),
|
|
12900
13057
|
isOpen && !disabled && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
|
|
12901
13058
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "fixed inset-0 z-10", onClick: () => setIsOpen(false) }),
|
|
12902
|
-
/* @__PURE__ */ (0, import_jsx_runtime43.
|
|
13059
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
12903
13060
|
"div",
|
|
12904
13061
|
{
|
|
12905
13062
|
className: cn(
|
|
@@ -12909,7 +13066,10 @@ function CategoryTreeSelect(props) {
|
|
|
12909
13066
|
"p-2",
|
|
12910
13067
|
"animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-300"
|
|
12911
13068
|
),
|
|
12912
|
-
children:
|
|
13069
|
+
children: [
|
|
13070
|
+
renderSearch(),
|
|
13071
|
+
renderTreeContent()
|
|
13072
|
+
]
|
|
12913
13073
|
}
|
|
12914
13074
|
)
|
|
12915
13075
|
] })
|