@juv/codego-react-ui 1.1.2 → 1.1.5

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
@@ -5,9 +5,25 @@ import { ChevronDown } from "lucide-react";
5
5
  // src/lib/utils.ts
6
6
  import { clsx } from "clsx";
7
7
  import { twMerge } from "tailwind-merge";
8
+ import * as ReactDOM from "react-dom";
8
9
  function cn(...inputs) {
9
10
  return twMerge(clsx(inputs));
10
11
  }
12
+ function getPortalPosition(triggerEl, dropdownHeight = 300, preferredPlacement = "bottom") {
13
+ const r = triggerEl.getBoundingClientRect();
14
+ const spaceBelow = window.innerHeight - r.bottom;
15
+ const spaceAbove = r.top;
16
+ const placement = preferredPlacement === "bottom" && spaceBelow < dropdownHeight && spaceAbove > spaceBelow ? "top" : preferredPlacement;
17
+ return {
18
+ top: placement === "bottom" ? r.bottom + 4 : r.top - 4,
19
+ left: r.left,
20
+ width: r.width,
21
+ placement
22
+ };
23
+ }
24
+ function FloatingPortal({ children }) {
25
+ return ReactDOM.createPortal(children, document.body);
26
+ }
11
27
 
12
28
  // src/components/ui/accordion.tsx
13
29
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -800,6 +816,8 @@ function ColorPicker({
800
816
  const [opacity, setOpacity] = React7.useState(100);
801
817
  const [recent, setRecent] = React7.useState([]);
802
818
  const ref = React7.useRef(null);
819
+ const triggerRef = React7.useRef(null);
820
+ const [dropStyle, setDropStyle] = React7.useState({});
803
821
  const color = controlled ?? internal;
804
822
  React7.useEffect(() => {
805
823
  setHex(color);
@@ -811,6 +829,19 @@ function ColorPicker({
811
829
  document.addEventListener("mousedown", handler);
812
830
  return () => document.removeEventListener("mousedown", handler);
813
831
  }, []);
832
+ function openPicker() {
833
+ if (triggerRef.current) {
834
+ const pos = getPortalPosition(triggerRef.current, 280);
835
+ setDropStyle({
836
+ position: "fixed",
837
+ top: pos.placement === "bottom" ? pos.top : void 0,
838
+ bottom: pos.placement === "top" ? window.innerHeight - pos.top : void 0,
839
+ left: pos.left,
840
+ zIndex: 9999
841
+ });
842
+ }
843
+ setOpen(true);
844
+ }
814
845
  function apply(c) {
815
846
  if (!controlled) setInternal(c);
816
847
  onChange?.(c);
@@ -825,9 +856,10 @@ function ColorPicker({
825
856
  /* @__PURE__ */ jsxs8(
826
857
  "button",
827
858
  {
859
+ ref: triggerRef,
828
860
  type: "button",
829
861
  disabled,
830
- onClick: () => setOpen((v) => !v),
862
+ onClick: () => open ? setOpen(false) : openPicker(),
831
863
  className: cn(
832
864
  "flex items-center gap-2 h-9 px-3 rounded-xl border border-border bg-background text-sm transition-colors hover:border-primary/40 focus:outline-none focus:ring-2 focus:ring-ring",
833
865
  disabled && "opacity-50 cursor-not-allowed pointer-events-none"
@@ -838,7 +870,7 @@ function ColorPicker({
838
870
  ]
839
871
  }
840
872
  ),
841
- open && /* @__PURE__ */ jsxs8("div", { className: "absolute z-50 mt-1 w-56 rounded-xl border border-border glass shadow-2xl p-3 space-y-3", children: [
873
+ open && /* @__PURE__ */ jsx9(FloatingPortal, { children: /* @__PURE__ */ jsxs8("div", { className: "w-56 rounded-xl border border-border glass shadow-2xl p-3 space-y-3", style: dropStyle, children: [
842
874
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
843
875
  /* @__PURE__ */ jsx9(
844
876
  "input",
@@ -893,10 +925,7 @@ function ColorPicker({
893
925
  apply(s);
894
926
  setHex(s);
895
927
  },
896
- className: cn(
897
- "h-6 w-6 rounded-md border transition-transform hover:scale-110",
898
- color === s ? "border-primary ring-1 ring-primary" : "border-border/60"
899
- ),
928
+ className: cn("h-6 w-6 rounded-md border transition-transform hover:scale-110", color === s ? "border-primary ring-1 ring-primary" : "border-border/60"),
900
929
  style: { backgroundColor: s },
901
930
  title: s
902
931
  },
@@ -920,7 +949,7 @@ function ColorPicker({
920
949
  s
921
950
  )) })
922
951
  ] })
923
- ] })
952
+ ] }) })
924
953
  ] });
925
954
  }
926
955
 
@@ -947,7 +976,9 @@ function Combobox({
947
976
  const [open, setOpen] = React8.useState(false);
948
977
  const [query, setQuery] = React8.useState("");
949
978
  const ref = React8.useRef(null);
979
+ const triggerRef = React8.useRef(null);
950
980
  const inputRef = React8.useRef(null);
981
+ const [dropStyle, setDropStyle] = React8.useState({});
951
982
  const selected = controlled ?? internal;
952
983
  function update(val) {
953
984
  if (!controlled) setInternal(val);
@@ -971,6 +1002,20 @@ function Combobox({
971
1002
  e.stopPropagation();
972
1003
  update(multiple ? [] : "");
973
1004
  }
1005
+ const openDropdown = () => {
1006
+ if (triggerRef.current) {
1007
+ const pos = getPortalPosition(triggerRef.current, 300);
1008
+ setDropStyle({
1009
+ position: "fixed",
1010
+ top: pos.placement === "bottom" ? pos.top : void 0,
1011
+ bottom: pos.placement === "top" ? window.innerHeight - pos.top : void 0,
1012
+ left: pos.left,
1013
+ width: pos.width,
1014
+ zIndex: 9999
1015
+ });
1016
+ }
1017
+ setOpen(true);
1018
+ };
974
1019
  React8.useEffect(() => {
975
1020
  function handler(e) {
976
1021
  if (ref.current && !ref.current.contains(e.target)) {
@@ -984,13 +1029,10 @@ function Combobox({
984
1029
  React8.useEffect(() => {
985
1030
  if (open) setTimeout(() => inputRef.current?.focus(), 50);
986
1031
  }, [open]);
987
- const filtered = options.filter(
988
- (o) => o.label.toLowerCase().includes(query.toLowerCase())
989
- );
1032
+ const filtered = options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
990
1033
  const groups = Array.from(new Set(filtered.map((o) => o.group ?? ""))).filter(Boolean);
991
1034
  const ungrouped = filtered.filter((o) => !o.group);
992
1035
  const showCreate = creatable && query && !options.find((o) => o.label.toLowerCase() === query.toLowerCase());
993
- const selectedLabels = multiple ? selected.map((v) => options.find((o) => o.value === v)?.label ?? v) : options.find((o) => o.value === selected)?.label;
994
1036
  const hasValue = multiple ? selected.length > 0 : !!selected;
995
1037
  function renderOptions(opts) {
996
1038
  return opts.map((opt) => /* @__PURE__ */ jsxs9(
@@ -1018,9 +1060,10 @@ function Combobox({
1018
1060
  /* @__PURE__ */ jsxs9(
1019
1061
  "button",
1020
1062
  {
1063
+ ref: triggerRef,
1021
1064
  type: "button",
1022
1065
  disabled,
1023
- onClick: () => setOpen((v) => !v),
1066
+ onClick: () => open ? setOpen(false) : openDropdown(),
1024
1067
  className: cn(
1025
1068
  "flex w-full items-center justify-between gap-2 rounded-xl border border-border bg-background px-3 py-2 text-sm transition-colors",
1026
1069
  "hover:border-primary/40 focus:outline-none focus:ring-2 focus:ring-ring",
@@ -1028,7 +1071,7 @@ function Combobox({
1028
1071
  disabled && "opacity-50 cursor-not-allowed pointer-events-none"
1029
1072
  ),
1030
1073
  children: [
1031
- /* @__PURE__ */ jsx10("span", { className: cn("flex-1 truncate text-left", !hasValue && "text-muted-foreground"), children: multiple ? selected.length > 0 ? `${selected.length} selected` : placeholder : selectedLabels || placeholder }),
1074
+ /* @__PURE__ */ jsx10("span", { className: cn("flex-1 truncate text-left", !hasValue && "text-muted-foreground"), children: multiple ? selected.length > 0 ? `${selected.length} selected` : placeholder : options.find((o) => o.value === selected)?.label || placeholder }),
1032
1075
  /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-1 shrink-0", children: [
1033
1076
  clearable && hasValue && /* @__PURE__ */ jsx10("span", { onClick: clear, className: "text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ jsx10(X2, { className: "h-3.5 w-3.5" }) }),
1034
1077
  /* @__PURE__ */ jsx10(ChevronDown2, { className: cn("h-4 w-4 text-muted-foreground transition-transform", open && "rotate-180") })
@@ -1036,50 +1079,57 @@ function Combobox({
1036
1079
  ]
1037
1080
  }
1038
1081
  ),
1039
- open && /* @__PURE__ */ jsxs9("div", { className: "absolute z-50 mt-1 w-full rounded-xl border border-border glass shadow-2xl overflow-hidden", children: [
1040
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [
1041
- /* @__PURE__ */ jsx10(Search, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
1042
- /* @__PURE__ */ jsx10(
1043
- "input",
1044
- {
1045
- ref: inputRef,
1046
- value: query,
1047
- onChange: (e) => setQuery(e.target.value),
1048
- placeholder: searchPlaceholder,
1049
- className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
1050
- }
1051
- )
1052
- ] }),
1053
- /* @__PURE__ */ jsxs9("div", { className: "overflow-y-auto p-1", style: { maxHeight }, children: [
1054
- showCreate && /* @__PURE__ */ jsxs9(
1055
- "button",
1056
- {
1057
- type: "button",
1058
- onClick: () => {
1059
- toggle(query);
1060
- setQuery("");
1061
- },
1062
- className: "flex w-full items-center gap-2 px-3 py-2 text-sm rounded-lg hover:bg-accent text-primary",
1063
- children: [
1064
- /* @__PURE__ */ jsx10(Plus, { className: "h-3.5 w-3.5" }),
1065
- 'Create "',
1066
- query,
1067
- '"'
1068
- ]
1069
- }
1070
- ),
1071
- groups.map((group) => /* @__PURE__ */ jsxs9("div", { children: [
1072
- /* @__PURE__ */ jsx10("p", { className: "px-3 py-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: group }),
1073
- renderOptions(filtered.filter((o) => o.group === group))
1074
- ] }, group)),
1075
- renderOptions(ungrouped),
1076
- filtered.length === 0 && !showCreate && /* @__PURE__ */ jsx10("p", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No results" })
1077
- ] }),
1078
- multiple && selected.length > 0 && /* @__PURE__ */ jsx10("div", { className: "border-t border-border px-3 py-2 flex flex-wrap gap-1", children: selected.map((v) => /* @__PURE__ */ jsxs9("span", { className: "inline-flex items-center gap-1 rounded-full bg-primary/15 text-primary text-xs px-2 py-0.5", children: [
1079
- options.find((o) => o.value === v)?.label ?? v,
1080
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => toggle(v), className: "opacity-60 hover:opacity-100", children: /* @__PURE__ */ jsx10(X2, { className: "h-3 w-3" }) })
1081
- ] }, v)) })
1082
- ] })
1082
+ open && /* @__PURE__ */ jsx10(FloatingPortal, { children: /* @__PURE__ */ jsxs9(
1083
+ "div",
1084
+ {
1085
+ className: "rounded-xl border border-border glass shadow-2xl overflow-hidden",
1086
+ style: dropStyle,
1087
+ children: [
1088
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [
1089
+ /* @__PURE__ */ jsx10(Search, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
1090
+ /* @__PURE__ */ jsx10(
1091
+ "input",
1092
+ {
1093
+ ref: inputRef,
1094
+ value: query,
1095
+ onChange: (e) => setQuery(e.target.value),
1096
+ placeholder: searchPlaceholder,
1097
+ className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
1098
+ }
1099
+ )
1100
+ ] }),
1101
+ /* @__PURE__ */ jsxs9("div", { className: "overflow-y-auto p-1", style: { maxHeight }, children: [
1102
+ showCreate && /* @__PURE__ */ jsxs9(
1103
+ "button",
1104
+ {
1105
+ type: "button",
1106
+ onClick: () => {
1107
+ toggle(query);
1108
+ setQuery("");
1109
+ },
1110
+ className: "flex w-full items-center gap-2 px-3 py-2 text-sm rounded-lg hover:bg-accent text-primary",
1111
+ children: [
1112
+ /* @__PURE__ */ jsx10(Plus, { className: "h-3.5 w-3.5" }),
1113
+ 'Create "',
1114
+ query,
1115
+ '"'
1116
+ ]
1117
+ }
1118
+ ),
1119
+ groups.map((group) => /* @__PURE__ */ jsxs9("div", { children: [
1120
+ /* @__PURE__ */ jsx10("p", { className: "px-3 py-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: group }),
1121
+ renderOptions(filtered.filter((o) => o.group === group))
1122
+ ] }, group)),
1123
+ renderOptions(ungrouped),
1124
+ filtered.length === 0 && !showCreate && /* @__PURE__ */ jsx10("p", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No results" })
1125
+ ] }),
1126
+ multiple && selected.length > 0 && /* @__PURE__ */ jsx10("div", { className: "border-t border-border px-3 py-2 flex flex-wrap gap-1", children: selected.map((v) => /* @__PURE__ */ jsxs9("span", { className: "inline-flex items-center gap-1 rounded-full bg-primary/15 text-primary text-xs px-2 py-0.5", children: [
1127
+ options.find((o) => o.value === v)?.label ?? v,
1128
+ /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => toggle(v), className: "opacity-60 hover:opacity-100", children: /* @__PURE__ */ jsx10(X2, { className: "h-3 w-3" }) })
1129
+ ] }, v)) })
1130
+ ]
1131
+ }
1132
+ ) })
1083
1133
  ] });
1084
1134
  }
1085
1135
 
@@ -1539,12 +1589,12 @@ function DonutChart({ data, color, height, showValues, unit }) {
1539
1589
  const total = data.reduce((s, d) => s + d.value, 0) || 1;
1540
1590
  const cx = 80, cy = height / 2, r = Math.min(cx, cy) - 10, inner = r * 0.58;
1541
1591
  let angle = -Math.PI / 2;
1542
- const defaultColors2 = ["primary", "info", "success", "warning", "danger"];
1592
+ const defaultColors = ["primary", "info", "success", "warning", "danger"];
1543
1593
  const slices = data.map((d, i) => {
1544
1594
  const sweep = d.value / total * 2 * Math.PI;
1545
1595
  const start = angle;
1546
1596
  angle += sweep;
1547
- const c = d.color ?? defaultColors2[i % defaultColors2.length];
1597
+ const c = d.color ?? defaultColors[i % defaultColors.length];
1548
1598
  return { ...d, start, sweep, color: c };
1549
1599
  });
1550
1600
  const arc = (cx2, cy2, r2, start, end) => {
@@ -2053,6 +2103,20 @@ function parseValue(value, mode) {
2053
2103
  return null;
2054
2104
  }
2055
2105
  }
2106
+ function getAnchorStyle(anchorEl, wide = false) {
2107
+ if (!anchorEl) return { position: "fixed", top: 0, left: 0, zIndex: 9999 };
2108
+ const r = anchorEl.getBoundingClientRect();
2109
+ const spaceBelow = window.innerHeight - r.bottom;
2110
+ const dropH = wide ? 320 : 300;
2111
+ const placement = spaceBelow < dropH && r.top > spaceBelow ? "top" : "bottom";
2112
+ return {
2113
+ position: "fixed",
2114
+ top: placement === "bottom" ? r.bottom + 4 : void 0,
2115
+ bottom: placement === "top" ? window.innerHeight - r.top + 4 : void 0,
2116
+ left: r.left,
2117
+ zIndex: 9999
2118
+ };
2119
+ }
2056
2120
  function TimePicker({
2057
2121
  selected,
2058
2122
  disabledDateTimes,
@@ -2120,25 +2184,9 @@ function Calendar2({
2120
2184
  const isDisabled = (d) => disabledDates?.includes(format(d, "yyyy-MM-dd")) ?? false;
2121
2185
  return /* @__PURE__ */ jsxs15("div", { className: "p-3 select-none", children: [
2122
2186
  /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between mb-3", children: [
2123
- /* @__PURE__ */ jsx16(
2124
- "button",
2125
- {
2126
- type: "button",
2127
- onClick: onPrevMonth,
2128
- className: "p-1 rounded hover:bg-white/10 text-muted-foreground hover:text-foreground transition-colors",
2129
- children: /* @__PURE__ */ jsx16(ChevronLeft3, { size: 16 })
2130
- }
2131
- ),
2187
+ /* @__PURE__ */ jsx16("button", { type: "button", onClick: onPrevMonth, className: "p-1 rounded hover:bg-white/10 text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ jsx16(ChevronLeft3, { size: 16 }) }),
2132
2188
  /* @__PURE__ */ jsx16("span", { className: "text-sm font-semibold text-foreground", children: format(month, "MMMM yyyy") }),
2133
- /* @__PURE__ */ jsx16(
2134
- "button",
2135
- {
2136
- type: "button",
2137
- onClick: onNextMonth,
2138
- className: "p-1 rounded hover:bg-white/10 text-muted-foreground hover:text-foreground transition-colors",
2139
- children: /* @__PURE__ */ jsx16(ChevronRight5, { size: 16 })
2140
- }
2141
- )
2189
+ /* @__PURE__ */ jsx16("button", { type: "button", onClick: onNextMonth, className: "p-1 rounded hover:bg-white/10 text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ jsx16(ChevronRight5, { size: 16 }) })
2142
2190
  ] }),
2143
2191
  /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-7 mb-1", children: DAYS2.map((d) => /* @__PURE__ */ jsx16("div", { className: "text-center text-xs text-muted-foreground py-1", children: d }, d)) }),
2144
2192
  /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-7 gap-y-1", children: days.map((d, i) => {
@@ -2173,136 +2221,44 @@ function DatePickerPopup({
2173
2221
  disabledDates,
2174
2222
  disabledDateTimes,
2175
2223
  onChange,
2176
- onClose
2224
+ onClose,
2225
+ anchorEl
2177
2226
  }) {
2178
2227
  const parsed = parseValue(value, mode);
2179
2228
  const [month, setMonth] = React13.useState(parsed ?? /* @__PURE__ */ new Date());
2180
2229
  const [selected, setSelected] = React13.useState(parsed);
2181
- const ref = React13.useRef(null);
2230
+ const anchorStyle = getAnchorStyle(anchorEl ?? null, mode === "dateTime");
2182
2231
  const commit = (d) => {
2183
- if (mode === "date") {
2184
- onChange(format(d, "yyyy-MM-dd"));
2185
- } else if (mode === "dateTime") {
2186
- onChange(format(d, "yyyy-MM-dd'T'HH:mm"));
2187
- } else {
2188
- onChange(format(d, "HH:mm"));
2189
- }
2232
+ if (mode === "date") onChange(format(d, "yyyy-MM-dd"));
2233
+ else if (mode === "dateTime") onChange(format(d, "yyyy-MM-dd'T'HH:mm"));
2234
+ else onChange(format(d, "HH:mm"));
2190
2235
  setSelected(d);
2191
2236
  };
2192
2237
  const handleDayClick = (d) => {
2193
2238
  const base = selected ?? /* @__PURE__ */ new Date();
2194
- const merged = setMinutes(setHours(d, getHours(base)), getMinutes(base));
2195
- commit(merged);
2239
+ commit(setMinutes(setHours(d, getHours(base)), getMinutes(base)));
2196
2240
  };
2197
2241
  const handleTimeChange = (h, m) => {
2198
- const base = selected ?? /* @__PURE__ */ new Date();
2199
- const merged = setMinutes(setHours(base, h), m);
2200
- commit(merged);
2242
+ commit(setMinutes(setHours(selected ?? /* @__PURE__ */ new Date(), h), m));
2201
2243
  };
2202
2244
  const datePrefix = selected ? format(selected, "yyyy-MM-dd") : void 0;
2203
- if (mode === "dateTime") {
2204
- return /* @__PURE__ */ jsxs15(
2205
- "div",
2245
+ const footer = (label) => /* @__PURE__ */ jsxs15("div", { className: "border-t border-white/10 px-3 py-2 flex items-center justify-between", children: [
2246
+ /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground", children: label }),
2247
+ /* @__PURE__ */ jsx16(
2248
+ "button",
2206
2249
  {
2207
- ref,
2208
- className: "absolute z-50 mt-1 rounded-xl border border-white/10 bg-card shadow-xl backdrop-blur-sm",
2209
- style: { top: "100%", left: 0 },
2210
- children: [
2211
- /* @__PURE__ */ jsxs15("div", { className: "flex", children: [
2212
- /* @__PURE__ */ jsxs15("div", { className: "flex-1 min-w-[240px]", children: [
2213
- /* @__PURE__ */ jsx16("p", { className: "text-xs font-medium text-muted-foreground px-3 pt-3 pb-1", children: "Date" }),
2214
- /* @__PURE__ */ jsx16(
2215
- Calendar2,
2216
- {
2217
- selected,
2218
- month,
2219
- disabledDates,
2220
- onDayClick: handleDayClick,
2221
- onPrevMonth: () => setMonth((m) => subMonths(m, 1)),
2222
- onNextMonth: () => setMonth((m) => addMonths(m, 1))
2223
- }
2224
- )
2225
- ] }),
2226
- /* @__PURE__ */ jsx16("div", { className: "w-px bg-white/10 my-3" }),
2227
- /* @__PURE__ */ jsxs15("div", { className: "flex-1 min-w-[140px] flex flex-col", children: [
2228
- /* @__PURE__ */ jsx16("p", { className: "text-xs font-medium text-muted-foreground px-3 pt-3 pb-1", children: "Time" }),
2229
- /* @__PURE__ */ jsxs15("div", { className: "flex gap-2 px-3 pb-3 flex-1", children: [
2230
- /* @__PURE__ */ jsxs15("div", { className: "flex-1", children: [
2231
- /* @__PURE__ */ jsx16("p", { className: "text-xs text-muted-foreground mb-1 text-center", children: "HH" }),
2232
- /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-1 gap-1 max-h-52 overflow-y-auto", children: HOURS.map((h) => /* @__PURE__ */ jsx16(
2233
- "button",
2234
- {
2235
- type: "button",
2236
- disabled: MINUTES.every((m) => {
2237
- if (!disabledDateTimes || !datePrefix) return false;
2238
- return disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`);
2239
- }),
2240
- onClick: () => handleTimeChange(h, selected ? getMinutes(selected) : 0),
2241
- className: cn(
2242
- "text-xs rounded py-1 transition-colors",
2243
- selected && getHours(selected) === h ? "bg-primary text-primary-foreground" : "hover:bg-white/10 text-foreground",
2244
- MINUTES.every((m) => {
2245
- if (!disabledDateTimes || !datePrefix) return false;
2246
- return disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`);
2247
- }) && "opacity-30 cursor-not-allowed line-through"
2248
- ),
2249
- children: String(h).padStart(2, "0")
2250
- },
2251
- h
2252
- )) })
2253
- ] }),
2254
- /* @__PURE__ */ jsxs15("div", { className: "w-12", children: [
2255
- /* @__PURE__ */ jsx16("p", { className: "text-xs text-muted-foreground mb-1 text-center", children: "MM" }),
2256
- /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-1 gap-1 max-h-52 overflow-y-auto", children: MINUTES.map((m) => {
2257
- const h = selected ? getHours(selected) : 0;
2258
- const isDisabled = disabledDateTimes && datePrefix ? disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`) : false;
2259
- return /* @__PURE__ */ jsxs15(
2260
- "button",
2261
- {
2262
- type: "button",
2263
- disabled: isDisabled,
2264
- onClick: () => handleTimeChange(h, m),
2265
- className: cn(
2266
- "text-xs rounded py-1 transition-colors",
2267
- selected && getMinutes(selected) === m ? "bg-primary text-primary-foreground" : "hover:bg-white/10 text-foreground",
2268
- isDisabled && "opacity-30 cursor-not-allowed line-through"
2269
- ),
2270
- children: [
2271
- ":",
2272
- String(m).padStart(2, "0")
2273
- ]
2274
- },
2275
- m
2276
- );
2277
- }) })
2278
- ] })
2279
- ] })
2280
- ] })
2281
- ] }),
2282
- /* @__PURE__ */ jsxs15("div", { className: "border-t border-white/10 px-3 py-2 flex items-center justify-between", children: [
2283
- /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground", children: selected ? format(selected, "MMM d, yyyy HH:mm") : "No date selected" }),
2284
- /* @__PURE__ */ jsx16(
2285
- "button",
2286
- {
2287
- type: "button",
2288
- onClick: onClose,
2289
- className: "text-xs rounded-lg bg-primary text-primary-foreground px-3 py-1 hover:opacity-90 transition-opacity",
2290
- children: "Done"
2291
- }
2292
- )
2293
- ] })
2294
- ]
2250
+ type: "button",
2251
+ onClick: onClose,
2252
+ className: "text-xs rounded-lg bg-primary text-primary-foreground px-3 py-1 hover:opacity-90 transition-opacity",
2253
+ children: "Done"
2295
2254
  }
2296
- );
2297
- }
2298
- return /* @__PURE__ */ jsxs15(
2299
- "div",
2300
- {
2301
- ref,
2302
- className: "absolute z-50 mt-1 rounded-xl border border-white/10 bg-card shadow-xl backdrop-blur-sm min-w-[260px]",
2303
- style: { top: "100%", left: 0 },
2304
- children: [
2305
- mode === "date" && /* @__PURE__ */ jsxs15(Fragment3, { children: [
2255
+ )
2256
+ ] });
2257
+ if (mode === "dateTime") {
2258
+ return /* @__PURE__ */ jsx16(FloatingPortal, { children: /* @__PURE__ */ jsxs15("div", { className: "rounded-xl border border-white/10 bg-card shadow-xl backdrop-blur-sm", style: anchorStyle, children: [
2259
+ /* @__PURE__ */ jsxs15("div", { className: "flex", children: [
2260
+ /* @__PURE__ */ jsxs15("div", { className: "flex-1 min-w-[240px]", children: [
2261
+ /* @__PURE__ */ jsx16("p", { className: "text-xs font-medium text-muted-foreground px-3 pt-3 pb-1", children: "Date" }),
2306
2262
  /* @__PURE__ */ jsx16(
2307
2263
  Calendar2,
2308
2264
  {
@@ -2313,46 +2269,91 @@ function DatePickerPopup({
2313
2269
  onPrevMonth: () => setMonth((m) => subMonths(m, 1)),
2314
2270
  onNextMonth: () => setMonth((m) => addMonths(m, 1))
2315
2271
  }
2316
- ),
2317
- /* @__PURE__ */ jsxs15("div", { className: "border-t border-white/10 px-3 py-2 flex items-center justify-between", children: [
2318
- /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground", children: selected ? format(selected, "MMM d, yyyy") : "No date selected" }),
2319
- /* @__PURE__ */ jsx16(
2320
- "button",
2321
- {
2322
- type: "button",
2323
- onClick: onClose,
2324
- className: "text-xs rounded-lg bg-primary text-primary-foreground px-3 py-1 hover:opacity-90 transition-opacity",
2325
- children: "Done"
2326
- }
2327
- )
2328
- ] })
2272
+ )
2329
2273
  ] }),
2330
- mode === "time" && /* @__PURE__ */ jsxs15(Fragment3, { children: [
2331
- /* @__PURE__ */ jsx16(
2332
- TimePicker,
2333
- {
2334
- selected,
2335
- disabledDateTimes,
2336
- datePrefix,
2337
- onChange: handleTimeChange
2338
- }
2339
- ),
2340
- /* @__PURE__ */ jsxs15("div", { className: "border-t border-white/10 px-3 py-2 flex items-center justify-between", children: [
2341
- /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground", children: selected ? format(selected, "HH:mm") : "No time selected" }),
2342
- /* @__PURE__ */ jsx16(
2343
- "button",
2344
- {
2345
- type: "button",
2346
- onClick: onClose,
2347
- className: "text-xs rounded-lg bg-primary text-primary-foreground px-3 py-1 hover:opacity-90 transition-opacity",
2348
- children: "Done"
2349
- }
2350
- )
2274
+ /* @__PURE__ */ jsx16("div", { className: "w-px bg-white/10 my-3" }),
2275
+ /* @__PURE__ */ jsxs15("div", { className: "flex-1 min-w-[140px] flex flex-col", children: [
2276
+ /* @__PURE__ */ jsx16("p", { className: "text-xs font-medium text-muted-foreground px-3 pt-3 pb-1", children: "Time" }),
2277
+ /* @__PURE__ */ jsxs15("div", { className: "flex gap-2 px-3 pb-3 flex-1", children: [
2278
+ /* @__PURE__ */ jsxs15("div", { className: "flex-1", children: [
2279
+ /* @__PURE__ */ jsx16("p", { className: "text-xs text-muted-foreground mb-1 text-center", children: "HH" }),
2280
+ /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-1 gap-1 max-h-52 overflow-y-auto", children: HOURS.map((h) => /* @__PURE__ */ jsx16(
2281
+ "button",
2282
+ {
2283
+ type: "button",
2284
+ disabled: MINUTES.every((m) => {
2285
+ if (!disabledDateTimes || !datePrefix) return false;
2286
+ return disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`);
2287
+ }),
2288
+ onClick: () => handleTimeChange(h, selected ? getMinutes(selected) : 0),
2289
+ className: cn(
2290
+ "text-xs rounded py-1 transition-colors",
2291
+ selected && getHours(selected) === h ? "bg-primary text-primary-foreground" : "hover:bg-white/10 text-foreground"
2292
+ ),
2293
+ children: String(h).padStart(2, "0")
2294
+ },
2295
+ h
2296
+ )) })
2297
+ ] }),
2298
+ /* @__PURE__ */ jsxs15("div", { className: "w-12", children: [
2299
+ /* @__PURE__ */ jsx16("p", { className: "text-xs text-muted-foreground mb-1 text-center", children: "MM" }),
2300
+ /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-1 gap-1 max-h-52 overflow-y-auto", children: MINUTES.map((m) => {
2301
+ const h = selected ? getHours(selected) : 0;
2302
+ const dis = disabledDateTimes && datePrefix ? disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`) : false;
2303
+ return /* @__PURE__ */ jsxs15(
2304
+ "button",
2305
+ {
2306
+ type: "button",
2307
+ disabled: dis,
2308
+ onClick: () => handleTimeChange(h, m),
2309
+ className: cn(
2310
+ "text-xs rounded py-1 transition-colors",
2311
+ selected && getMinutes(selected) === m ? "bg-primary text-primary-foreground" : "hover:bg-white/10 text-foreground",
2312
+ dis && "opacity-30 cursor-not-allowed line-through"
2313
+ ),
2314
+ children: [
2315
+ ":",
2316
+ String(m).padStart(2, "0")
2317
+ ]
2318
+ },
2319
+ m
2320
+ );
2321
+ }) })
2322
+ ] })
2351
2323
  ] })
2352
2324
  ] })
2353
- ]
2354
- }
2355
- );
2325
+ ] }),
2326
+ footer(selected ? format(selected, "MMM d, yyyy HH:mm") : "No date selected")
2327
+ ] }) });
2328
+ }
2329
+ return /* @__PURE__ */ jsx16(FloatingPortal, { children: /* @__PURE__ */ jsxs15("div", { className: "rounded-xl border border-white/10 bg-card shadow-xl backdrop-blur-sm min-w-[260px]", style: anchorStyle, children: [
2330
+ mode === "date" && /* @__PURE__ */ jsxs15(Fragment3, { children: [
2331
+ /* @__PURE__ */ jsx16(
2332
+ Calendar2,
2333
+ {
2334
+ selected,
2335
+ month,
2336
+ disabledDates,
2337
+ onDayClick: handleDayClick,
2338
+ onPrevMonth: () => setMonth((m) => subMonths(m, 1)),
2339
+ onNextMonth: () => setMonth((m) => addMonths(m, 1))
2340
+ }
2341
+ ),
2342
+ footer(selected ? format(selected, "MMM d, yyyy") : "No date selected")
2343
+ ] }),
2344
+ mode === "time" && /* @__PURE__ */ jsxs15(Fragment3, { children: [
2345
+ /* @__PURE__ */ jsx16(
2346
+ TimePicker,
2347
+ {
2348
+ selected,
2349
+ disabledDateTimes,
2350
+ datePrefix,
2351
+ onChange: handleTimeChange
2352
+ }
2353
+ ),
2354
+ footer(selected ? format(selected, "HH:mm") : "No time selected")
2355
+ ] })
2356
+ ] }) });
2356
2357
  }
2357
2358
 
2358
2359
  // src/components/ui/date-range-picker.tsx
@@ -2390,6 +2391,8 @@ function DateRangePicker({
2390
2391
  const [viewMonth, setViewMonth] = React14.useState(today.getMonth());
2391
2392
  const [viewYear, setViewYear] = React14.useState(today.getFullYear());
2392
2393
  const ref = React14.useRef(null);
2394
+ const triggerRef = React14.useRef(null);
2395
+ const [dropStyle, setDropStyle] = React14.useState({});
2393
2396
  const range2 = controlled ?? internal;
2394
2397
  React14.useEffect(() => {
2395
2398
  function handler(e) {
@@ -2402,6 +2405,19 @@ function DateRangePicker({
2402
2405
  if (!controlled) setInternal(r);
2403
2406
  onChange?.(r);
2404
2407
  }
2408
+ function openPicker() {
2409
+ if (triggerRef.current) {
2410
+ const pos = getPortalPosition(triggerRef.current, 340);
2411
+ setDropStyle({
2412
+ position: "fixed",
2413
+ top: pos.placement === "bottom" ? pos.top : void 0,
2414
+ bottom: pos.placement === "top" ? window.innerHeight - pos.top : void 0,
2415
+ left: pos.left,
2416
+ zIndex: 9999
2417
+ });
2418
+ }
2419
+ setOpen(true);
2420
+ }
2405
2421
  function selectDay(d) {
2406
2422
  if (selecting === "from") {
2407
2423
  update({ from: d, to: null });
@@ -2436,9 +2452,10 @@ function DateRangePicker({
2436
2452
  /* @__PURE__ */ jsxs16(
2437
2453
  "button",
2438
2454
  {
2455
+ ref: triggerRef,
2439
2456
  type: "button",
2440
2457
  disabled,
2441
- onClick: () => setOpen((v) => !v),
2458
+ onClick: () => open ? setOpen(false) : openPicker(),
2442
2459
  className: cn(
2443
2460
  "flex w-full items-center gap-2 rounded-xl border border-border bg-background px-3 py-2 text-sm transition-colors",
2444
2461
  "hover:border-primary/40 focus:outline-none focus:ring-2 focus:ring-ring",
@@ -2464,25 +2481,41 @@ function DateRangePicker({
2464
2481
  ]
2465
2482
  }
2466
2483
  ),
2467
- open && /* @__PURE__ */ jsxs16("div", { className: "absolute z-50 mt-1 rounded-xl border border-border glass shadow-2xl p-4 w-72", children: [
2484
+ open && /* @__PURE__ */ jsx17(FloatingPortal, { children: /* @__PURE__ */ jsxs16("div", { className: "rounded-xl border border-border glass shadow-2xl p-4 w-72", style: dropStyle, children: [
2468
2485
  /* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-between mb-3", children: [
2469
- /* @__PURE__ */ jsx17("button", { type: "button", onClick: () => {
2470
- if (viewMonth === 0) {
2471
- setViewMonth(11);
2472
- setViewYear((y) => y - 1);
2473
- } else setViewMonth((m) => m - 1);
2474
- }, className: "p-1 rounded-md hover:bg-accent transition-colors", children: /* @__PURE__ */ jsx17(ChevronLeft4, { className: "h-4 w-4" }) }),
2486
+ /* @__PURE__ */ jsx17(
2487
+ "button",
2488
+ {
2489
+ type: "button",
2490
+ onClick: () => {
2491
+ if (viewMonth === 0) {
2492
+ setViewMonth(11);
2493
+ setViewYear((y) => y - 1);
2494
+ } else setViewMonth((m) => m - 1);
2495
+ },
2496
+ className: "p-1 rounded-md hover:bg-accent transition-colors",
2497
+ children: /* @__PURE__ */ jsx17(ChevronLeft4, { className: "h-4 w-4" })
2498
+ }
2499
+ ),
2475
2500
  /* @__PURE__ */ jsxs16("span", { className: "text-sm font-semibold", children: [
2476
2501
  MONTHS2[viewMonth],
2477
2502
  " ",
2478
2503
  viewYear
2479
2504
  ] }),
2480
- /* @__PURE__ */ jsx17("button", { type: "button", onClick: () => {
2481
- if (viewMonth === 11) {
2482
- setViewMonth(0);
2483
- setViewYear((y) => y + 1);
2484
- } else setViewMonth((m) => m + 1);
2485
- }, className: "p-1 rounded-md hover:bg-accent transition-colors", children: /* @__PURE__ */ jsx17(ChevronRight6, { className: "h-4 w-4" }) })
2505
+ /* @__PURE__ */ jsx17(
2506
+ "button",
2507
+ {
2508
+ type: "button",
2509
+ onClick: () => {
2510
+ if (viewMonth === 11) {
2511
+ setViewMonth(0);
2512
+ setViewYear((y) => y + 1);
2513
+ } else setViewMonth((m) => m + 1);
2514
+ },
2515
+ className: "p-1 rounded-md hover:bg-accent transition-colors",
2516
+ children: /* @__PURE__ */ jsx17(ChevronRight6, { className: "h-4 w-4" })
2517
+ }
2518
+ )
2486
2519
  ] }),
2487
2520
  /* @__PURE__ */ jsx17("div", { className: "grid grid-cols-7 mb-1", children: DAYS3.map((d) => /* @__PURE__ */ jsx17("div", { className: "text-center text-[10px] font-semibold text-muted-foreground py-1", children: d }, d)) }),
2488
2521
  /* @__PURE__ */ jsx17("div", { className: "grid grid-cols-7 gap-y-0.5", children: days.map((d, i) => {
@@ -2517,7 +2550,7 @@ function DateRangePicker({
2517
2550
  );
2518
2551
  }) }),
2519
2552
  /* @__PURE__ */ jsx17("p", { className: "mt-3 text-center text-xs text-muted-foreground", children: selecting === "from" ? "Select start date" : "Select end date" })
2520
- ] })
2553
+ ] }) })
2521
2554
  ] });
2522
2555
  }
2523
2556
 
@@ -2619,10 +2652,10 @@ function Drawer({
2619
2652
  import * as React16 from "react";
2620
2653
  import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
2621
2654
  var widthMap = {
2622
- sm: "w-40",
2623
- md: "w-56",
2624
- lg: "w-72",
2625
- auto: "w-auto min-w-[10rem]"
2655
+ sm: 160,
2656
+ md: 224,
2657
+ lg: 288,
2658
+ auto: void 0
2626
2659
  };
2627
2660
  function Dropdown({
2628
2661
  trigger,
@@ -2636,25 +2669,40 @@ function Dropdown({
2636
2669
  className
2637
2670
  }) {
2638
2671
  const [isOpen, setIsOpen] = React16.useState(false);
2639
- const containerRef = React16.useRef(null);
2640
- const toggle = () => {
2672
+ const triggerRef = React16.useRef(null);
2673
+ const [dropStyle, setDropStyle] = React16.useState({});
2674
+ const open = () => {
2641
2675
  if (disabled) return;
2642
- const next = !isOpen;
2643
- setIsOpen(next);
2644
- onOpenChange?.(next);
2676
+ if (triggerRef.current) {
2677
+ const r = triggerRef.current.getBoundingClientRect();
2678
+ const pos = getPortalPosition(triggerRef.current, 320, placement);
2679
+ const w = widthMap[width];
2680
+ let left = r.left;
2681
+ if (align === "right") left = r.right - (w ?? r.width);
2682
+ if (align === "center") left = r.left + r.width / 2 - (w ?? r.width) / 2;
2683
+ setDropStyle({
2684
+ position: "fixed",
2685
+ top: pos.placement === "bottom" ? pos.top : void 0,
2686
+ bottom: pos.placement === "top" ? window.innerHeight - r.top + 4 : void 0,
2687
+ left,
2688
+ width: w,
2689
+ minWidth: w ? void 0 : "10rem",
2690
+ zIndex: 9999
2691
+ });
2692
+ }
2693
+ setIsOpen(true);
2694
+ onOpenChange?.(true);
2645
2695
  };
2646
2696
  const close = () => {
2647
2697
  setIsOpen(false);
2648
2698
  onOpenChange?.(false);
2649
2699
  };
2650
2700
  React16.useEffect(() => {
2651
- const handleClickOutside = (event) => {
2652
- if (containerRef.current && !containerRef.current.contains(event.target)) {
2653
- close();
2654
- }
2701
+ const handleClickOutside = (e) => {
2702
+ if (triggerRef.current && !triggerRef.current.contains(e.target)) close();
2655
2703
  };
2656
- const handleKeyDown = (event) => {
2657
- if (event.key === "Escape") close();
2704
+ const handleKeyDown = (e) => {
2705
+ if (e.key === "Escape") close();
2658
2706
  };
2659
2707
  document.addEventListener("mousedown", handleClickOutside);
2660
2708
  document.addEventListener("keydown", handleKeyDown);
@@ -2663,39 +2711,30 @@ function Dropdown({
2663
2711
  document.removeEventListener("keydown", handleKeyDown);
2664
2712
  };
2665
2713
  }, [isOpen]);
2666
- return /* @__PURE__ */ jsxs18("div", { className: "relative inline-block text-left", ref: containerRef, children: [
2714
+ return /* @__PURE__ */ jsxs18("div", { className: "relative inline-block text-left", ref: triggerRef, children: [
2667
2715
  /* @__PURE__ */ jsx19(
2668
2716
  "div",
2669
2717
  {
2670
- onClick: toggle,
2718
+ onClick: () => isOpen ? close() : open(),
2671
2719
  "aria-expanded": isOpen,
2672
2720
  "aria-haspopup": "true",
2673
2721
  className: cn(disabled && "opacity-50 cursor-not-allowed pointer-events-none"),
2674
2722
  children: trigger
2675
2723
  }
2676
2724
  ),
2677
- isOpen && /* @__PURE__ */ jsx19(
2725
+ isOpen && /* @__PURE__ */ jsx19(FloatingPortal, { children: /* @__PURE__ */ jsx19(
2678
2726
  "div",
2679
2727
  {
2680
2728
  className: cn(
2681
- "absolute z-50 rounded-xl border border-white/10 bg-background/90 backdrop-blur-2xl text-popover-foreground",
2729
+ "rounded-xl border border-white/10 bg-background/90 backdrop-blur-2xl text-popover-foreground",
2682
2730
  "shadow-[0_8px_32px_rgba(0,0,0,0.35)] ring-1 ring-white/5",
2683
2731
  "animate-in fade-in-0 zoom-in-95 duration-150",
2684
- widthMap[width],
2685
- placement === "top" ? "bottom-full mb-2" : "top-full mt-2",
2686
- align === "right" ? "right-0" : align === "center" ? "left-1/2 -translate-x-1/2" : "left-0",
2687
2732
  className
2688
2733
  ),
2689
- children: /* @__PURE__ */ jsx19(
2690
- "div",
2691
- {
2692
- className: "py-1.5",
2693
- onClick: closeOnSelect ? close : void 0,
2694
- children
2695
- }
2696
- )
2734
+ style: dropStyle,
2735
+ children: /* @__PURE__ */ jsx19("div", { className: "py-1.5", onClick: closeOnSelect ? close : void 0, children })
2697
2736
  }
2698
- )
2737
+ ) })
2699
2738
  ] });
2700
2739
  }
2701
2740
  function DropdownItem({
@@ -2728,10 +2767,7 @@ function DropdownItem({
2728
2767
  function DropdownSeparator({ className }) {
2729
2768
  return /* @__PURE__ */ jsx19("div", { className: cn("my-1.5 h-px bg-white/8", className) });
2730
2769
  }
2731
- function DropdownLabel({
2732
- children,
2733
- className
2734
- }) {
2770
+ function DropdownLabel({ children, className }) {
2735
2771
  return /* @__PURE__ */ jsx19("p", { className: cn("px-3.5 py-1.5 text-xs font-semibold uppercase tracking-wider text-muted-foreground/60", className), children });
2736
2772
  }
2737
2773
 
@@ -3593,6 +3629,7 @@ var Input = React18.forwardRef(
3593
3629
  value: internalValue,
3594
3630
  disabledDates,
3595
3631
  disabledDateTimes,
3632
+ anchorEl: containerRef.current,
3596
3633
  onChange: (v) => {
3597
3634
  setInternalValue(v);
3598
3635
  setValidationError(null);
@@ -3984,30 +4021,43 @@ function Select({
3984
4021
  const [search, setSearch] = React23.useState("");
3985
4022
  const [isSearching, setIsSearching] = React23.useState(false);
3986
4023
  const containerRef = React23.useRef(null);
4024
+ const triggerRef = React23.useRef(null);
4025
+ const [dropStyle, setDropStyle] = React23.useState({});
3987
4026
  const getKey = (opt) => String(Object.keys(opt)[0]);
3988
4027
  const getLabel = (opt) => Object.values(opt)[0];
3989
4028
  const selectedValues = React23.useMemo(() => {
3990
- if (multiple && Array.isArray(value)) {
3991
- return value;
3992
- } else if (typeof value === "string") {
3993
- return [value];
3994
- }
4029
+ if (multiple && Array.isArray(value)) return value;
4030
+ if (typeof value === "string") return [value];
3995
4031
  return [];
3996
4032
  }, [value, multiple]);
3997
- const selectedOptions = React23.useMemo(() => {
3998
- return options.filter((opt) => selectedValues.includes(getKey(opt)));
3999
- }, [options, selectedValues]);
4000
- const filteredOptions = searchable ? options.filter(
4001
- (opt) => getLabel(opt).toLowerCase().includes(search.toLowerCase())
4002
- ) : options;
4033
+ const selectedOptions = React23.useMemo(
4034
+ () => options.filter((opt) => selectedValues.includes(getKey(opt))),
4035
+ [options, selectedValues]
4036
+ );
4037
+ const filteredOptions = searchable ? options.filter((opt) => getLabel(opt).toLowerCase().includes(search.toLowerCase())) : options;
4038
+ const openDropdown = () => {
4039
+ if (disabled) return;
4040
+ if (triggerRef.current) {
4041
+ const pos = getPortalPosition(triggerRef.current, 260);
4042
+ setDropStyle({
4043
+ position: "fixed",
4044
+ top: pos.placement === "bottom" ? pos.top : void 0,
4045
+ bottom: pos.placement === "top" ? window.innerHeight - pos.top : void 0,
4046
+ left: pos.left,
4047
+ width: pos.width,
4048
+ zIndex: 9999
4049
+ });
4050
+ }
4051
+ setIsOpen(true);
4052
+ };
4003
4053
  React23.useEffect(() => {
4004
- const handleClickOutside = (event) => {
4005
- if (containerRef.current && !containerRef.current.contains(event.target)) {
4054
+ const handler = (e) => {
4055
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
4006
4056
  setIsOpen(false);
4007
4057
  }
4008
4058
  };
4009
- document.addEventListener("mousedown", handleClickOutside);
4010
- return () => document.removeEventListener("mousedown", handleClickOutside);
4059
+ document.addEventListener("mousedown", handler);
4060
+ return () => document.removeEventListener("mousedown", handler);
4011
4061
  }, []);
4012
4062
  const handleSelect = (optionValue) => {
4013
4063
  if (multiple) {
@@ -4021,10 +4071,7 @@ function Select({
4021
4071
  };
4022
4072
  const handleRemove = (optionValue, e) => {
4023
4073
  e.stopPropagation();
4024
- if (multiple) {
4025
- const newValues = selectedValues.filter((v) => v !== optionValue);
4026
- onChange?.(newValues);
4027
- }
4074
+ if (multiple) onChange?.(selectedValues.filter((v) => v !== optionValue));
4028
4075
  };
4029
4076
  const handleReorder = (fromIndex, toIndex) => {
4030
4077
  if (!multiple || !reorderable || !Array.isArray(value)) return;
@@ -4038,16 +4085,13 @@ function Select({
4038
4085
  e.dataTransfer.setData("text/plain", index.toString());
4039
4086
  };
4040
4087
  const handleDragOver = (e) => {
4041
- if (!reorderable) return;
4042
- e.preventDefault();
4088
+ if (reorderable) e.preventDefault();
4043
4089
  };
4044
4090
  const handleDrop = (e, toIndex) => {
4045
4091
  if (!reorderable) return;
4046
4092
  e.preventDefault();
4047
4093
  const fromIndex = parseInt(e.dataTransfer.getData("text/plain"));
4048
- if (fromIndex !== toIndex) {
4049
- handleReorder(fromIndex, toIndex);
4050
- }
4094
+ if (fromIndex !== toIndex) handleReorder(fromIndex, toIndex);
4051
4095
  };
4052
4096
  if (native) {
4053
4097
  if (multiple) {
@@ -4057,58 +4101,29 @@ function Select({
4057
4101
  "w-full rounded-xl border border-slate-900/30 bg-background/50 backdrop-blur-sm overflow-hidden ring-offset-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
4058
4102
  disabled && "opacity-50 pointer-events-none"
4059
4103
  ), children: [
4060
- selectedValues.length > 0 && /* @__PURE__ */ jsx28("div", { className: "flex flex-wrap gap-1 px-3 pt-2 pb-1 border-b border-slate-900/10", children: selectedOptions.map((opt) => /* @__PURE__ */ jsxs24(
4061
- "span",
4062
- {
4063
- className: "inline-flex items-center gap-1 rounded-sm bg-primary/15 text-primary px-2 py-0.5 text-xs",
4064
- children: [
4065
- getLabel(opt),
4066
- /* @__PURE__ */ jsx28(
4067
- "button",
4068
- {
4069
- type: "button",
4070
- disabled,
4071
- onClick: () => onChange?.(selectedValues.filter((v) => v !== getKey(opt))),
4072
- className: "hover:text-destructive",
4073
- children: /* @__PURE__ */ jsx28(X7, { className: "h-3 w-3" })
4074
- }
4075
- )
4076
- ]
4077
- },
4078
- getKey(opt)
4079
- )) }),
4104
+ selectedValues.length > 0 && /* @__PURE__ */ jsx28("div", { className: "flex flex-wrap gap-1 px-3 pt-2 pb-1 border-b border-slate-900/10", children: selectedOptions.map((opt) => /* @__PURE__ */ jsxs24("span", { className: "inline-flex items-center gap-1 rounded-sm bg-primary/15 text-primary px-2 py-0.5 text-xs", children: [
4105
+ getLabel(opt),
4106
+ /* @__PURE__ */ jsx28("button", { type: "button", disabled, onClick: () => onChange?.(selectedValues.filter((v) => v !== getKey(opt))), className: "hover:text-destructive", children: /* @__PURE__ */ jsx28(X7, { className: "h-3 w-3" }) })
4107
+ ] }, getKey(opt))) }),
4080
4108
  /* @__PURE__ */ jsx28("div", { className: "max-h-48 overflow-y-auto p-1", children: options.map((option) => {
4081
4109
  const checked = selectedValues.includes(getKey(option));
4082
- return /* @__PURE__ */ jsxs24(
4083
- "label",
4084
- {
4085
- className: cn(
4086
- "flex items-center gap-3 rounded-lg px-3 py-2 text-sm cursor-pointer transition-colors hover:bg-accent",
4087
- checked && "bg-primary/8 text-primary"
4088
- ),
4089
- children: [
4090
- /* @__PURE__ */ jsx28("span", { className: cn(
4091
- "flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
4092
- checked ? "bg-primary border-primary text-primary-foreground" : "border-slate-900/30 bg-background/50"
4093
- ), children: checked && /* @__PURE__ */ jsx28(Check5, { className: "h-3 w-3" }) }),
4094
- /* @__PURE__ */ jsx28(
4095
- "input",
4096
- {
4097
- type: "checkbox",
4098
- className: "sr-only",
4099
- checked,
4100
- disabled,
4101
- onChange: () => {
4102
- const newValues = checked ? selectedValues.filter((v) => v !== getKey(option)) : [...selectedValues, getKey(option)];
4103
- onChange?.(newValues);
4104
- }
4105
- }
4106
- ),
4107
- getLabel(option)
4108
- ]
4109
- },
4110
- getKey(option)
4111
- );
4110
+ return /* @__PURE__ */ jsxs24("label", { className: cn("flex items-center gap-3 rounded-lg px-3 py-2 text-sm cursor-pointer transition-colors hover:bg-accent", checked && "bg-primary/8 text-primary"), children: [
4111
+ /* @__PURE__ */ jsx28("span", { className: cn("flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors", checked ? "bg-primary border-primary text-primary-foreground" : "border-slate-900/30 bg-background/50"), children: checked && /* @__PURE__ */ jsx28(Check5, { className: "h-3 w-3" }) }),
4112
+ /* @__PURE__ */ jsx28(
4113
+ "input",
4114
+ {
4115
+ type: "checkbox",
4116
+ className: "sr-only",
4117
+ checked,
4118
+ disabled,
4119
+ onChange: () => {
4120
+ const newValues = checked ? selectedValues.filter((v) => v !== getKey(option)) : [...selectedValues, getKey(option)];
4121
+ onChange?.(newValues);
4122
+ }
4123
+ }
4124
+ ),
4125
+ getLabel(option)
4126
+ ] }, getKey(option));
4112
4127
  }) })
4113
4128
  ] })
4114
4129
  ] });
@@ -4139,14 +4154,15 @@ function Select({
4139
4154
  /* @__PURE__ */ jsx28(
4140
4155
  "button",
4141
4156
  {
4157
+ ref: triggerRef,
4142
4158
  type: "button",
4143
4159
  className: cn(
4144
4160
  "relative flex w-full items-center min-h-[2.5rem] rounded-xl border border-slate-900/30 bg-background/50 backdrop-blur-sm px-4 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors hover:bg-background/80",
4145
4161
  multiple && selectedValues.length > 0 && "flex-wrap gap-1",
4146
- (suffixIcon || !suffixIcon) && "pr-10",
4162
+ "pr-10",
4147
4163
  disabled && "cursor-not-allowed opacity-50"
4148
4164
  ),
4149
- onClick: () => !disabled && setIsOpen(!isOpen),
4165
+ onClick: () => isOpen ? setIsOpen(false) : openDropdown(),
4150
4166
  disabled,
4151
4167
  children: multiple && selectedOptions.length > 0 ? /* @__PURE__ */ jsx28("div", { className: "flex flex-wrap gap-1 flex-1 min-w-0", children: selectedOptions.map((option, index) => /* @__PURE__ */ jsxs24(
4152
4168
  "span",
@@ -4155,22 +4171,11 @@ function Select({
4155
4171
  onDragStart: (e) => handleDragStart(e, index),
4156
4172
  onDragOver: handleDragOver,
4157
4173
  onDrop: (e) => handleDrop(e, index),
4158
- className: cn(
4159
- "inline-flex items-center gap-1 rounded-sm bg-primary/15 text-primary px-2 py-1 text-xs",
4160
- reorderable && "cursor-move"
4161
- ),
4174
+ className: cn("inline-flex items-center gap-1 rounded-sm bg-primary/15 text-primary px-2 py-1 text-xs", reorderable && "cursor-move"),
4162
4175
  children: [
4163
4176
  reorderable && /* @__PURE__ */ jsx28(GripVertical3, { className: "h-3 w-3 opacity-50" }),
4164
4177
  getLabel(option),
4165
- /* @__PURE__ */ jsx28(
4166
- "button",
4167
- {
4168
- type: "button",
4169
- onClick: (e) => handleRemove(getKey(option), e),
4170
- className: "ml-1 hover:text-destructive",
4171
- children: /* @__PURE__ */ jsx28(X7, { className: "h-3 w-3" })
4172
- }
4173
- )
4178
+ /* @__PURE__ */ jsx28("button", { type: "button", onClick: (e) => handleRemove(getKey(option), e), className: "ml-1 hover:text-destructive", children: /* @__PURE__ */ jsx28(X7, { className: "h-3 w-3" }) })
4174
4179
  ]
4175
4180
  },
4176
4181
  getKey(option)
@@ -4183,50 +4188,56 @@ function Select({
4183
4188
  {
4184
4189
  type: "button",
4185
4190
  disabled,
4186
- onClick: () => !disabled && setIsOpen(!isOpen),
4191
+ onClick: () => isOpen ? setIsOpen(false) : openDropdown(),
4187
4192
  className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors z-10 disabled:opacity-50",
4188
- "aria-label": "Open options",
4189
4193
  style: iconColor ? { color: iconColor } : void 0,
4190
4194
  children: suffixIcon
4191
4195
  }
4192
4196
  ),
4193
- isOpen && /* @__PURE__ */ jsxs24("div", { className: "absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border border-white/10 bg-background/80 backdrop-blur-xl text-popover-foreground shadow-lg animate-in fade-in-80", children: [
4194
- searchable && /* @__PURE__ */ jsxs24("div", { className: "sticky top-0 z-10 flex items-center border-b border-white/10 bg-background/90 px-3 py-2", children: [
4195
- /* @__PURE__ */ jsx28(Search4, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
4196
- /* @__PURE__ */ jsx28(
4197
- "input",
4198
- {
4199
- className: "flex h-8 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
4200
- placeholder: searchingMessage,
4201
- value: search,
4202
- onChange: (e) => {
4203
- setSearch(e.target.value);
4204
- setIsSearching(true);
4205
- setTimeout(() => setIsSearching(false), 300);
4206
- },
4207
- onClick: (e) => e.stopPropagation()
4208
- }
4209
- )
4210
- ] }),
4211
- /* @__PURE__ */ jsx28("div", { className: "p-1", children: isSearching ? /* @__PURE__ */ jsx28("div", { className: "py-6 text-center text-sm text-muted-foreground", children: loadingMessage }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx28("div", { className: "py-6 text-center text-sm text-muted-foreground", children: search ? noSearchResultsMessage : "No options available." }) : /* @__PURE__ */ jsxs24(Fragment5, { children: [
4212
- filteredOptions.map((option) => /* @__PURE__ */ jsxs24(
4213
- "div",
4214
- {
4215
- className: cn(
4216
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-accent hover:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
4217
- (multiple ? selectedValues.includes(getKey(option)) : value === getKey(option)) && "bg-accent text-accent-foreground"
4218
- ),
4219
- onClick: () => handleSelect(getKey(option)),
4220
- children: [
4221
- /* @__PURE__ */ jsx28("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: (multiple ? selectedValues.includes(getKey(option)) : value === getKey(option)) && /* @__PURE__ */ jsx28(Check5, { className: "h-4 w-4" }) }),
4222
- /* @__PURE__ */ jsx28("span", { className: "truncate", children: getLabel(option) })
4223
- ]
4224
- },
4225
- getKey(option)
4226
- )),
4227
- createOptionForm && /* @__PURE__ */ jsx28("div", { className: "border-t border-white/10 mt-1 pt-1", children: createOptionForm })
4228
- ] }) })
4229
- ] })
4197
+ isOpen && /* @__PURE__ */ jsx28(FloatingPortal, { children: /* @__PURE__ */ jsxs24(
4198
+ "div",
4199
+ {
4200
+ className: "max-h-60 overflow-auto rounded-md border border-white/10 bg-background/80 backdrop-blur-xl text-popover-foreground shadow-lg animate-in fade-in-80",
4201
+ style: dropStyle,
4202
+ children: [
4203
+ searchable && /* @__PURE__ */ jsxs24("div", { className: "sticky top-0 z-10 flex items-center border-b border-white/10 bg-background/90 px-3 py-2", children: [
4204
+ /* @__PURE__ */ jsx28(Search4, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
4205
+ /* @__PURE__ */ jsx28(
4206
+ "input",
4207
+ {
4208
+ className: "flex h-8 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground",
4209
+ placeholder: searchingMessage,
4210
+ value: search,
4211
+ onChange: (e) => {
4212
+ setSearch(e.target.value);
4213
+ setIsSearching(true);
4214
+ setTimeout(() => setIsSearching(false), 300);
4215
+ },
4216
+ onClick: (e) => e.stopPropagation()
4217
+ }
4218
+ )
4219
+ ] }),
4220
+ /* @__PURE__ */ jsx28("div", { className: "p-1", children: isSearching ? /* @__PURE__ */ jsx28("div", { className: "py-6 text-center text-sm text-muted-foreground", children: loadingMessage }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx28("div", { className: "py-6 text-center text-sm text-muted-foreground", children: search ? noSearchResultsMessage : "No options available." }) : /* @__PURE__ */ jsxs24(Fragment5, { children: [
4221
+ filteredOptions.map((option) => /* @__PURE__ */ jsxs24(
4222
+ "div",
4223
+ {
4224
+ className: cn(
4225
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-accent hover:text-accent-foreground",
4226
+ (multiple ? selectedValues.includes(getKey(option)) : value === getKey(option)) && "bg-accent text-accent-foreground"
4227
+ ),
4228
+ onClick: () => handleSelect(getKey(option)),
4229
+ children: [
4230
+ /* @__PURE__ */ jsx28("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: (multiple ? selectedValues.includes(getKey(option)) : value === getKey(option)) && /* @__PURE__ */ jsx28(Check5, { className: "h-4 w-4" }) }),
4231
+ /* @__PURE__ */ jsx28("span", { className: "truncate", children: getLabel(option) })
4232
+ ]
4233
+ },
4234
+ getKey(option)
4235
+ )),
4236
+ createOptionForm && /* @__PURE__ */ jsx28("div", { className: "border-t border-white/10 mt-1 pt-1", children: createOptionForm })
4237
+ ] }) })
4238
+ ]
4239
+ }
4240
+ ) })
4230
4241
  ] })
4231
4242
  ] });
4232
4243
  }
@@ -5069,7 +5080,7 @@ import { PanelLeftClose, PanelLeftOpen, Sun as Sun2, Moon } from "lucide-react";
5069
5080
 
5070
5081
  // src/components/ui/tooltip.tsx
5071
5082
  import * as React28 from "react";
5072
- import * as ReactDOM from "react-dom";
5083
+ import * as ReactDOM2 from "react-dom";
5073
5084
  import { Fragment as Fragment7, jsx as jsx33, jsxs as jsxs29 } from "react/jsx-runtime";
5074
5085
  function Tooltip({
5075
5086
  content,
@@ -5124,7 +5135,7 @@ function Tooltip({
5124
5135
  onBlur: () => setVisible(false),
5125
5136
  children: [
5126
5137
  children,
5127
- visible && ReactDOM.createPortal(
5138
+ visible && ReactDOM2.createPortal(
5128
5139
  /* @__PURE__ */ jsx33(
5129
5140
  "div",
5130
5141
  {
@@ -5147,24 +5158,36 @@ function Tooltip({
5147
5158
 
5148
5159
  // src/components/theme-provider.tsx
5149
5160
  import { createContext as createContext2, useContext as useContext2, useEffect as useEffect18, useState as useState23 } from "react";
5161
+
5162
+ // src/components/conf/settingConfig.json
5163
+ var settingConfig_default = {
5164
+ theme: "dark",
5165
+ fontSize: "16px",
5166
+ fontFamily: '"Space Grotesk", "Inter", sans-serif',
5167
+ colors: {
5168
+ primary: "#8b5cf6",
5169
+ primaryHover: "#7c3aed",
5170
+ secondary: "#171717",
5171
+ secondaryHover: "#262626",
5172
+ info: "#3b82f6",
5173
+ infoHover: "#2563eb",
5174
+ warning: "#f59e0b",
5175
+ warningHover: "#d97706",
5176
+ danger: "#ef4444",
5177
+ dangerHover: "#dc2626"
5178
+ }
5179
+ };
5180
+
5181
+ // src/components/theme-provider.tsx
5150
5182
  import { jsx as jsx34 } from "react/jsx-runtime";
5151
- var defaultColors = {
5152
- primary: "#8b5cf6",
5153
- primaryHover: "#7c3aed",
5154
- secondary: "#171717",
5155
- secondaryHover: "#262626",
5156
- info: "#3b82f6",
5157
- infoHover: "#2563eb",
5158
- warning: "#f59e0b",
5159
- warningHover: "#d97706",
5160
- danger: "#ef4444",
5161
- dangerHover: "#dc2626"
5183
+ var configDefaults = {
5184
+ theme: settingConfig_default.theme,
5185
+ fontSize: settingConfig_default.fontSize,
5186
+ fontFamily: settingConfig_default.fontFamily,
5187
+ colors: settingConfig_default.colors
5162
5188
  };
5163
5189
  var initialState = {
5164
- theme: "system",
5165
- colors: defaultColors,
5166
- fontSize: "16px",
5167
- fontFamily: '"Space Grotesk", "Inter", sans-serif',
5190
+ ...configDefaults,
5168
5191
  setTheme: () => null,
5169
5192
  setColors: () => null,
5170
5193
  setFontSize: () => null,
@@ -5174,26 +5197,60 @@ var initialState = {
5174
5197
  var ThemeProviderContext = createContext2(initialState);
5175
5198
  var COLOR_PALETTE = [
5176
5199
  { base: "#6366f1", hover: "#4f46e5" },
5177
- // Indigo
5178
5200
  { base: "#8b5cf6", hover: "#7c3aed" },
5179
- // Violet
5180
5201
  { base: "#3b82f6", hover: "#2563eb" },
5181
- // Blue
5182
5202
  { base: "#10b981", hover: "#059669" },
5183
- // Emerald
5184
5203
  { base: "#22c55e", hover: "#16a34a" },
5185
- // Green
5186
5204
  { base: "#eab308", hover: "#ca8a04" },
5187
- // Yellow
5188
5205
  { base: "#f59e0b", hover: "#d97706" },
5189
- // Amber
5190
5206
  { base: "#f97316", hover: "#ea580c" },
5191
- // Orange
5192
5207
  { base: "#ef4444", hover: "#dc2626" },
5193
- // Red
5194
5208
  { base: "#ec4899", hover: "#db2777" }
5195
- // Pink
5196
5209
  ];
5210
+ function ThemeProvider({
5211
+ children,
5212
+ storageKey = "codego-ui-theme-settings",
5213
+ ...props
5214
+ }) {
5215
+ const [settings, setSettings] = useState23(() => {
5216
+ try {
5217
+ const stored = localStorage.getItem(storageKey);
5218
+ if (stored) return { ...configDefaults, ...JSON.parse(stored) };
5219
+ } catch {
5220
+ }
5221
+ return configDefaults;
5222
+ });
5223
+ useEffect18(() => {
5224
+ localStorage.setItem(storageKey, JSON.stringify(settings));
5225
+ }, [settings, storageKey]);
5226
+ useEffect18(() => {
5227
+ const root = window.document.documentElement;
5228
+ root.classList.remove("light", "dark");
5229
+ const resolved = settings.theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : settings.theme;
5230
+ root.classList.add(resolved);
5231
+ root.style.setProperty("--primary", settings.colors.primary);
5232
+ root.style.setProperty("--primary-hover", settings.colors.primaryHover);
5233
+ root.style.setProperty("--secondary", settings.colors.secondary);
5234
+ root.style.setProperty("--secondary-hover", settings.colors.secondaryHover);
5235
+ root.style.setProperty("--info", settings.colors.info);
5236
+ root.style.setProperty("--info-hover", settings.colors.infoHover);
5237
+ root.style.setProperty("--warning", settings.colors.warning);
5238
+ root.style.setProperty("--warning-hover", settings.colors.warningHover);
5239
+ root.style.setProperty("--danger", settings.colors.danger);
5240
+ root.style.setProperty("--danger-hover", settings.colors.dangerHover);
5241
+ root.style.setProperty("font-size", settings.fontSize);
5242
+ root.style.setProperty("--font-sans", settings.fontFamily);
5243
+ }, [settings]);
5244
+ const value = {
5245
+ ...settings,
5246
+ setTheme: (theme) => setSettings((s) => ({ ...s, theme })),
5247
+ setColors: (colors) => setSettings((s) => ({ ...s, colors: { ...s.colors, ...colors } })),
5248
+ setFontSize: (fontSize) => setSettings((s) => ({ ...s, fontSize })),
5249
+ setFontFamily: (fontFamily) => setSettings((s) => ({ ...s, fontFamily })),
5250
+ resetSettings: () => setSettings(configDefaults)
5251
+ };
5252
+ return /* @__PURE__ */ jsx34(ThemeProviderContext.Provider, { ...props, value, children });
5253
+ }
5197
5254
  var useTheme = () => {
5198
5255
  const context = useContext2(ThemeProviderContext);
5199
5256
  if (context === void 0)
@@ -5353,16 +5410,28 @@ function PanelSidebarGroup({
5353
5410
  // src/components/ui/popover.tsx
5354
5411
  import * as React31 from "react";
5355
5412
  import { jsx as jsx36, jsxs as jsxs31 } from "react/jsx-runtime";
5356
- var PLACEMENT_CLASSES = {
5357
- "top": "bottom-full left-1/2 -translate-x-1/2 mb-2",
5358
- "bottom": "top-full left-1/2 -translate-x-1/2 mt-2",
5359
- "left": "right-full top-1/2 -translate-y-1/2 mr-2",
5360
- "right": "left-full top-1/2 -translate-y-1/2 ml-2",
5361
- "top-start": "bottom-full left-0 mb-2",
5362
- "top-end": "bottom-full right-0 mb-2",
5363
- "bottom-start": "top-full left-0 mt-2",
5364
- "bottom-end": "top-full right-0 mt-2"
5365
- };
5413
+ function calcStyle(triggerEl, placement) {
5414
+ const r = triggerEl.getBoundingClientRect();
5415
+ const GAP = 8;
5416
+ switch (placement) {
5417
+ case "bottom":
5418
+ return { top: r.bottom + GAP, left: r.left + r.width / 2, transform: "translateX(-50%)" };
5419
+ case "bottom-start":
5420
+ return { top: r.bottom + GAP, left: r.left };
5421
+ case "bottom-end":
5422
+ return { top: r.bottom + GAP, left: r.right, transform: "translateX(-100%)" };
5423
+ case "top":
5424
+ return { top: r.top - GAP, left: r.left + r.width / 2, transform: "translate(-50%, -100%)" };
5425
+ case "top-start":
5426
+ return { top: r.top - GAP, left: r.left, transform: "translateY(-100%)" };
5427
+ case "top-end":
5428
+ return { top: r.top - GAP, left: r.right, transform: "translate(-100%, -100%)" };
5429
+ case "left":
5430
+ return { top: r.top + r.height / 2, left: r.left - GAP, transform: "translate(-100%, -50%)" };
5431
+ case "right":
5432
+ return { top: r.top + r.height / 2, left: r.right + GAP, transform: "translateY(-50%)" };
5433
+ }
5434
+ }
5366
5435
  function Popover({
5367
5436
  trigger,
5368
5437
  content,
@@ -5374,11 +5443,18 @@ function Popover({
5374
5443
  }) {
5375
5444
  const [internal, setInternal] = React31.useState(false);
5376
5445
  const ref = React31.useRef(null);
5446
+ const [popStyle, setPopStyle] = React31.useState({});
5377
5447
  const open = controlled ?? internal;
5378
5448
  function setOpen(v) {
5379
5449
  if (controlled === void 0) setInternal(v);
5380
5450
  onOpenChange?.(v);
5381
5451
  }
5452
+ function openPopover() {
5453
+ if (ref.current) {
5454
+ setPopStyle({ position: "fixed", zIndex: 9999, ...calcStyle(ref.current, placement) });
5455
+ }
5456
+ setOpen(true);
5457
+ }
5382
5458
  React31.useEffect(() => {
5383
5459
  if (triggerOn !== "click") return;
5384
5460
  function handler(e) {
@@ -5387,14 +5463,17 @@ function Popover({
5387
5463
  document.addEventListener("mousedown", handler);
5388
5464
  return () => document.removeEventListener("mousedown", handler);
5389
5465
  }, [triggerOn]);
5390
- const hoverProps = triggerOn === "hover" ? { onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false) } : {};
5466
+ const hoverProps = triggerOn === "hover" ? { onMouseEnter: openPopover, onMouseLeave: () => setOpen(false) } : {};
5391
5467
  return /* @__PURE__ */ jsxs31("div", { ref, className: "relative inline-block", ...hoverProps, children: [
5392
- /* @__PURE__ */ jsx36("div", { onClick: () => triggerOn === "click" && setOpen(!open), children: trigger }),
5393
- open && /* @__PURE__ */ jsx36("div", { className: cn(
5394
- "absolute z-50 min-w-max rounded-xl border border-border glass shadow-2xl",
5395
- PLACEMENT_CLASSES[placement],
5396
- className
5397
- ), children: content })
5468
+ /* @__PURE__ */ jsx36("div", { onClick: () => triggerOn === "click" && (open ? setOpen(false) : openPopover()), children: trigger }),
5469
+ open && /* @__PURE__ */ jsx36(FloatingPortal, { children: /* @__PURE__ */ jsx36(
5470
+ "div",
5471
+ {
5472
+ className: cn("min-w-max rounded-xl border border-border glass shadow-2xl", className),
5473
+ style: popStyle,
5474
+ children: content
5475
+ }
5476
+ ) })
5398
5477
  ] });
5399
5478
  }
5400
5479
 
@@ -5681,7 +5760,7 @@ function RadioGroup({
5681
5760
  }
5682
5761
 
5683
5762
  // src/components/ui/repeater.tsx
5684
- import { Plus as Plus4, Trash2 as Trash22, GripVertical as GripVertical4 } from "lucide-react";
5763
+ import { Plus as Plus3, Trash2 as Trash22, GripVertical as GripVertical4 } from "lucide-react";
5685
5764
  import { jsx as jsx40, jsxs as jsxs35 } from "react/jsx-runtime";
5686
5765
  function Repeater({
5687
5766
  items,
@@ -5726,7 +5805,7 @@ function Repeater({
5726
5805
  onClick: onAdd,
5727
5806
  className: "group flex w-full items-center justify-center gap-2 rounded-xl border border-dashed border-border py-3 text-sm font-medium text-muted-foreground transition-all duration-200 hover:border-primary/50 hover:bg-primary/5 hover:text-primary",
5728
5807
  children: [
5729
- /* @__PURE__ */ jsx40("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-muted group-hover:bg-primary/10 transition-colors", children: /* @__PURE__ */ jsx40(Plus4, { className: "h-3 w-3" }) }),
5808
+ /* @__PURE__ */ jsx40("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-muted group-hover:bg-primary/10 transition-colors", children: /* @__PURE__ */ jsx40(Plus3, { className: "h-3 w-3" }) }),
5730
5809
  addButtonText
5731
5810
  ]
5732
5811
  }
@@ -7855,6 +7934,7 @@ export {
7855
7934
  Badge,
7856
7935
  Breadcrumb,
7857
7936
  Button,
7937
+ COLOR_PALETTE,
7858
7938
  Calendar,
7859
7939
  Card,
7860
7940
  CardContent,
@@ -7924,6 +8004,7 @@ export {
7924
8004
  Tabs,
7925
8005
  TagInput,
7926
8006
  Textarea,
8007
+ ThemeProvider,
7927
8008
  Timeline,
7928
8009
  ToastProvider,
7929
8010
  ToggleSwitch,
@@ -7932,5 +8013,6 @@ export {
7932
8013
  TreeView,
7933
8014
  Widget,
7934
8015
  Wizard,
8016
+ useTheme,
7935
8017
  useToast
7936
8018
  };