@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.cjs CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  Badge: () => Badge,
35
35
  Breadcrumb: () => Breadcrumb,
36
36
  Button: () => Button,
37
+ COLOR_PALETTE: () => COLOR_PALETTE,
37
38
  Calendar: () => Calendar,
38
39
  Card: () => Card,
39
40
  CardContent: () => CardContent,
@@ -103,6 +104,7 @@ __export(index_exports, {
103
104
  Tabs: () => Tabs,
104
105
  TagInput: () => TagInput,
105
106
  Textarea: () => Textarea,
107
+ ThemeProvider: () => ThemeProvider,
106
108
  Timeline: () => Timeline,
107
109
  ToastProvider: () => ToastProvider,
108
110
  ToggleSwitch: () => ToggleSwitch,
@@ -111,6 +113,7 @@ __export(index_exports, {
111
113
  TreeView: () => TreeView,
112
114
  Widget: () => Widget,
113
115
  Wizard: () => Wizard,
116
+ useTheme: () => useTheme,
114
117
  useToast: () => useToast
115
118
  });
116
119
  module.exports = __toCommonJS(index_exports);
@@ -122,9 +125,25 @@ var import_lucide_react = require("lucide-react");
122
125
  // src/lib/utils.ts
123
126
  var import_clsx = require("clsx");
124
127
  var import_tailwind_merge = require("tailwind-merge");
128
+ var ReactDOM = __toESM(require("react-dom"), 1);
125
129
  function cn(...inputs) {
126
130
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
127
131
  }
132
+ function getPortalPosition(triggerEl, dropdownHeight = 300, preferredPlacement = "bottom") {
133
+ const r = triggerEl.getBoundingClientRect();
134
+ const spaceBelow = window.innerHeight - r.bottom;
135
+ const spaceAbove = r.top;
136
+ const placement = preferredPlacement === "bottom" && spaceBelow < dropdownHeight && spaceAbove > spaceBelow ? "top" : preferredPlacement;
137
+ return {
138
+ top: placement === "bottom" ? r.bottom + 4 : r.top - 4,
139
+ left: r.left,
140
+ width: r.width,
141
+ placement
142
+ };
143
+ }
144
+ function FloatingPortal({ children }) {
145
+ return ReactDOM.createPortal(children, document.body);
146
+ }
128
147
 
129
148
  // src/components/ui/accordion.tsx
130
149
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -917,6 +936,8 @@ function ColorPicker({
917
936
  const [opacity, setOpacity] = React7.useState(100);
918
937
  const [recent, setRecent] = React7.useState([]);
919
938
  const ref = React7.useRef(null);
939
+ const triggerRef = React7.useRef(null);
940
+ const [dropStyle, setDropStyle] = React7.useState({});
920
941
  const color = controlled ?? internal;
921
942
  React7.useEffect(() => {
922
943
  setHex(color);
@@ -928,6 +949,19 @@ function ColorPicker({
928
949
  document.addEventListener("mousedown", handler);
929
950
  return () => document.removeEventListener("mousedown", handler);
930
951
  }, []);
952
+ function openPicker() {
953
+ if (triggerRef.current) {
954
+ const pos = getPortalPosition(triggerRef.current, 280);
955
+ setDropStyle({
956
+ position: "fixed",
957
+ top: pos.placement === "bottom" ? pos.top : void 0,
958
+ bottom: pos.placement === "top" ? window.innerHeight - pos.top : void 0,
959
+ left: pos.left,
960
+ zIndex: 9999
961
+ });
962
+ }
963
+ setOpen(true);
964
+ }
931
965
  function apply(c) {
932
966
  if (!controlled) setInternal(c);
933
967
  onChange?.(c);
@@ -942,9 +976,10 @@ function ColorPicker({
942
976
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
943
977
  "button",
944
978
  {
979
+ ref: triggerRef,
945
980
  type: "button",
946
981
  disabled,
947
- onClick: () => setOpen((v) => !v),
982
+ onClick: () => open ? setOpen(false) : openPicker(),
948
983
  className: cn(
949
984
  "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",
950
985
  disabled && "opacity-50 cursor-not-allowed pointer-events-none"
@@ -955,7 +990,7 @@ function ColorPicker({
955
990
  ]
956
991
  }
957
992
  ),
958
- open && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "absolute z-50 mt-1 w-56 rounded-xl border border-border glass shadow-2xl p-3 space-y-3", children: [
993
+ open && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "w-56 rounded-xl border border-border glass shadow-2xl p-3 space-y-3", style: dropStyle, children: [
959
994
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
960
995
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
961
996
  "input",
@@ -1010,10 +1045,7 @@ function ColorPicker({
1010
1045
  apply(s);
1011
1046
  setHex(s);
1012
1047
  },
1013
- className: cn(
1014
- "h-6 w-6 rounded-md border transition-transform hover:scale-110",
1015
- color === s ? "border-primary ring-1 ring-primary" : "border-border/60"
1016
- ),
1048
+ 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"),
1017
1049
  style: { backgroundColor: s },
1018
1050
  title: s
1019
1051
  },
@@ -1037,7 +1069,7 @@ function ColorPicker({
1037
1069
  s
1038
1070
  )) })
1039
1071
  ] })
1040
- ] })
1072
+ ] }) })
1041
1073
  ] });
1042
1074
  }
1043
1075
 
@@ -1064,7 +1096,9 @@ function Combobox({
1064
1096
  const [open, setOpen] = React8.useState(false);
1065
1097
  const [query, setQuery] = React8.useState("");
1066
1098
  const ref = React8.useRef(null);
1099
+ const triggerRef = React8.useRef(null);
1067
1100
  const inputRef = React8.useRef(null);
1101
+ const [dropStyle, setDropStyle] = React8.useState({});
1068
1102
  const selected = controlled ?? internal;
1069
1103
  function update(val) {
1070
1104
  if (!controlled) setInternal(val);
@@ -1088,6 +1122,20 @@ function Combobox({
1088
1122
  e.stopPropagation();
1089
1123
  update(multiple ? [] : "");
1090
1124
  }
1125
+ const openDropdown = () => {
1126
+ if (triggerRef.current) {
1127
+ const pos = getPortalPosition(triggerRef.current, 300);
1128
+ setDropStyle({
1129
+ position: "fixed",
1130
+ top: pos.placement === "bottom" ? pos.top : void 0,
1131
+ bottom: pos.placement === "top" ? window.innerHeight - pos.top : void 0,
1132
+ left: pos.left,
1133
+ width: pos.width,
1134
+ zIndex: 9999
1135
+ });
1136
+ }
1137
+ setOpen(true);
1138
+ };
1091
1139
  React8.useEffect(() => {
1092
1140
  function handler(e) {
1093
1141
  if (ref.current && !ref.current.contains(e.target)) {
@@ -1101,13 +1149,10 @@ function Combobox({
1101
1149
  React8.useEffect(() => {
1102
1150
  if (open) setTimeout(() => inputRef.current?.focus(), 50);
1103
1151
  }, [open]);
1104
- const filtered = options.filter(
1105
- (o) => o.label.toLowerCase().includes(query.toLowerCase())
1106
- );
1152
+ const filtered = options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
1107
1153
  const groups = Array.from(new Set(filtered.map((o) => o.group ?? ""))).filter(Boolean);
1108
1154
  const ungrouped = filtered.filter((o) => !o.group);
1109
1155
  const showCreate = creatable && query && !options.find((o) => o.label.toLowerCase() === query.toLowerCase());
1110
- const selectedLabels = multiple ? selected.map((v) => options.find((o) => o.value === v)?.label ?? v) : options.find((o) => o.value === selected)?.label;
1111
1156
  const hasValue = multiple ? selected.length > 0 : !!selected;
1112
1157
  function renderOptions(opts) {
1113
1158
  return opts.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
@@ -1135,9 +1180,10 @@ function Combobox({
1135
1180
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1136
1181
  "button",
1137
1182
  {
1183
+ ref: triggerRef,
1138
1184
  type: "button",
1139
1185
  disabled,
1140
- onClick: () => setOpen((v) => !v),
1186
+ onClick: () => open ? setOpen(false) : openDropdown(),
1141
1187
  className: cn(
1142
1188
  "flex w-full items-center justify-between gap-2 rounded-xl border border-border bg-background px-3 py-2 text-sm transition-colors",
1143
1189
  "hover:border-primary/40 focus:outline-none focus:ring-2 focus:ring-ring",
@@ -1145,7 +1191,7 @@ function Combobox({
1145
1191
  disabled && "opacity-50 cursor-not-allowed pointer-events-none"
1146
1192
  ),
1147
1193
  children: [
1148
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: cn("flex-1 truncate text-left", !hasValue && "text-muted-foreground"), children: multiple ? selected.length > 0 ? `${selected.length} selected` : placeholder : selectedLabels || placeholder }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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 }),
1149
1195
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "flex items-center gap-1 shrink-0", children: [
1150
1196
  clearable && hasValue && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { onClick: clear, className: "text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.X, { className: "h-3.5 w-3.5" }) }),
1151
1197
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.ChevronDown, { className: cn("h-4 w-4 text-muted-foreground transition-transform", open && "rotate-180") })
@@ -1153,50 +1199,57 @@ function Combobox({
1153
1199
  ]
1154
1200
  }
1155
1201
  ),
1156
- open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "absolute z-50 mt-1 w-full rounded-xl border border-border glass shadow-2xl overflow-hidden", children: [
1157
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [
1158
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.Search, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
1159
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1160
- "input",
1161
- {
1162
- ref: inputRef,
1163
- value: query,
1164
- onChange: (e) => setQuery(e.target.value),
1165
- placeholder: searchPlaceholder,
1166
- className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
1167
- }
1168
- )
1169
- ] }),
1170
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "overflow-y-auto p-1", style: { maxHeight }, children: [
1171
- showCreate && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1172
- "button",
1173
- {
1174
- type: "button",
1175
- onClick: () => {
1176
- toggle(query);
1177
- setQuery("");
1178
- },
1179
- className: "flex w-full items-center gap-2 px-3 py-2 text-sm rounded-lg hover:bg-accent text-primary",
1180
- children: [
1181
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.Plus, { className: "h-3.5 w-3.5" }),
1182
- 'Create "',
1183
- query,
1184
- '"'
1185
- ]
1186
- }
1187
- ),
1188
- groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1189
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "px-3 py-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: group }),
1190
- renderOptions(filtered.filter((o) => o.group === group))
1191
- ] }, group)),
1192
- renderOptions(ungrouped),
1193
- filtered.length === 0 && !showCreate && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No results" })
1194
- ] }),
1195
- multiple && selected.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "border-t border-border px-3 py-2 flex flex-wrap gap-1", children: selected.map((v) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "inline-flex items-center gap-1 rounded-full bg-primary/15 text-primary text-xs px-2 py-0.5", children: [
1196
- options.find((o) => o.value === v)?.label ?? v,
1197
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => toggle(v), className: "opacity-60 hover:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.X, { className: "h-3 w-3" }) })
1198
- ] }, v)) })
1199
- ] })
1202
+ open && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1203
+ "div",
1204
+ {
1205
+ className: "rounded-xl border border-border glass shadow-2xl overflow-hidden",
1206
+ style: dropStyle,
1207
+ children: [
1208
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [
1209
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.Search, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
1210
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1211
+ "input",
1212
+ {
1213
+ ref: inputRef,
1214
+ value: query,
1215
+ onChange: (e) => setQuery(e.target.value),
1216
+ placeholder: searchPlaceholder,
1217
+ className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
1218
+ }
1219
+ )
1220
+ ] }),
1221
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "overflow-y-auto p-1", style: { maxHeight }, children: [
1222
+ showCreate && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1223
+ "button",
1224
+ {
1225
+ type: "button",
1226
+ onClick: () => {
1227
+ toggle(query);
1228
+ setQuery("");
1229
+ },
1230
+ className: "flex w-full items-center gap-2 px-3 py-2 text-sm rounded-lg hover:bg-accent text-primary",
1231
+ children: [
1232
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.Plus, { className: "h-3.5 w-3.5" }),
1233
+ 'Create "',
1234
+ query,
1235
+ '"'
1236
+ ]
1237
+ }
1238
+ ),
1239
+ groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1240
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "px-3 py-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: group }),
1241
+ renderOptions(filtered.filter((o) => o.group === group))
1242
+ ] }, group)),
1243
+ renderOptions(ungrouped),
1244
+ filtered.length === 0 && !showCreate && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No results" })
1245
+ ] }),
1246
+ multiple && selected.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "border-t border-border px-3 py-2 flex flex-wrap gap-1", children: selected.map((v) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "inline-flex items-center gap-1 rounded-full bg-primary/15 text-primary text-xs px-2 py-0.5", children: [
1247
+ options.find((o) => o.value === v)?.label ?? v,
1248
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: () => toggle(v), className: "opacity-60 hover:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.X, { className: "h-3 w-3" }) })
1249
+ ] }, v)) })
1250
+ ]
1251
+ }
1252
+ ) })
1200
1253
  ] });
1201
1254
  }
1202
1255
 
@@ -1656,12 +1709,12 @@ function DonutChart({ data, color, height, showValues, unit }) {
1656
1709
  const total = data.reduce((s, d) => s + d.value, 0) || 1;
1657
1710
  const cx = 80, cy = height / 2, r = Math.min(cx, cy) - 10, inner = r * 0.58;
1658
1711
  let angle = -Math.PI / 2;
1659
- const defaultColors2 = ["primary", "info", "success", "warning", "danger"];
1712
+ const defaultColors = ["primary", "info", "success", "warning", "danger"];
1660
1713
  const slices = data.map((d, i) => {
1661
1714
  const sweep = d.value / total * 2 * Math.PI;
1662
1715
  const start = angle;
1663
1716
  angle += sweep;
1664
- const c = d.color ?? defaultColors2[i % defaultColors2.length];
1717
+ const c = d.color ?? defaultColors[i % defaultColors.length];
1665
1718
  return { ...d, start, sweep, color: c };
1666
1719
  });
1667
1720
  const arc = (cx2, cy2, r2, start, end) => {
@@ -2153,6 +2206,20 @@ function parseValue(value, mode) {
2153
2206
  return null;
2154
2207
  }
2155
2208
  }
2209
+ function getAnchorStyle(anchorEl, wide = false) {
2210
+ if (!anchorEl) return { position: "fixed", top: 0, left: 0, zIndex: 9999 };
2211
+ const r = anchorEl.getBoundingClientRect();
2212
+ const spaceBelow = window.innerHeight - r.bottom;
2213
+ const dropH = wide ? 320 : 300;
2214
+ const placement = spaceBelow < dropH && r.top > spaceBelow ? "top" : "bottom";
2215
+ return {
2216
+ position: "fixed",
2217
+ top: placement === "bottom" ? r.bottom + 4 : void 0,
2218
+ bottom: placement === "top" ? window.innerHeight - r.top + 4 : void 0,
2219
+ left: r.left,
2220
+ zIndex: 9999
2221
+ };
2222
+ }
2156
2223
  function TimePicker({
2157
2224
  selected,
2158
2225
  disabledDateTimes,
@@ -2220,25 +2287,9 @@ function Calendar2({
2220
2287
  const isDisabled = (d) => disabledDates?.includes((0, import_date_fns.format)(d, "yyyy-MM-dd")) ?? false;
2221
2288
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "p-3 select-none", children: [
2222
2289
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [
2223
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2224
- "button",
2225
- {
2226
- type: "button",
2227
- onClick: onPrevMonth,
2228
- className: "p-1 rounded hover:bg-white/10 text-muted-foreground hover:text-foreground transition-colors",
2229
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react10.ChevronLeft, { size: 16 })
2230
- }
2231
- ),
2290
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", onClick: onPrevMonth, className: "p-1 rounded hover:bg-white/10 text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react10.ChevronLeft, { size: 16 }) }),
2232
2291
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-sm font-semibold text-foreground", children: (0, import_date_fns.format)(month, "MMMM yyyy") }),
2233
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2234
- "button",
2235
- {
2236
- type: "button",
2237
- onClick: onNextMonth,
2238
- className: "p-1 rounded hover:bg-white/10 text-muted-foreground hover:text-foreground transition-colors",
2239
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react10.ChevronRight, { size: 16 })
2240
- }
2241
- )
2292
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", onClick: onNextMonth, className: "p-1 rounded hover:bg-white/10 text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react10.ChevronRight, { size: 16 }) })
2242
2293
  ] }),
2243
2294
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "grid grid-cols-7 mb-1", children: DAYS2.map((d) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "text-center text-xs text-muted-foreground py-1", children: d }, d)) }),
2244
2295
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "grid grid-cols-7 gap-y-1", children: days.map((d, i) => {
@@ -2273,136 +2324,44 @@ function DatePickerPopup({
2273
2324
  disabledDates,
2274
2325
  disabledDateTimes,
2275
2326
  onChange,
2276
- onClose
2327
+ onClose,
2328
+ anchorEl
2277
2329
  }) {
2278
2330
  const parsed = parseValue(value, mode);
2279
2331
  const [month, setMonth] = React13.useState(parsed ?? /* @__PURE__ */ new Date());
2280
2332
  const [selected, setSelected] = React13.useState(parsed);
2281
- const ref = React13.useRef(null);
2333
+ const anchorStyle = getAnchorStyle(anchorEl ?? null, mode === "dateTime");
2282
2334
  const commit = (d) => {
2283
- if (mode === "date") {
2284
- onChange((0, import_date_fns.format)(d, "yyyy-MM-dd"));
2285
- } else if (mode === "dateTime") {
2286
- onChange((0, import_date_fns.format)(d, "yyyy-MM-dd'T'HH:mm"));
2287
- } else {
2288
- onChange((0, import_date_fns.format)(d, "HH:mm"));
2289
- }
2335
+ if (mode === "date") onChange((0, import_date_fns.format)(d, "yyyy-MM-dd"));
2336
+ else if (mode === "dateTime") onChange((0, import_date_fns.format)(d, "yyyy-MM-dd'T'HH:mm"));
2337
+ else onChange((0, import_date_fns.format)(d, "HH:mm"));
2290
2338
  setSelected(d);
2291
2339
  };
2292
2340
  const handleDayClick = (d) => {
2293
2341
  const base = selected ?? /* @__PURE__ */ new Date();
2294
- const merged = (0, import_date_fns.setMinutes)((0, import_date_fns.setHours)(d, (0, import_date_fns.getHours)(base)), (0, import_date_fns.getMinutes)(base));
2295
- commit(merged);
2342
+ commit((0, import_date_fns.setMinutes)((0, import_date_fns.setHours)(d, (0, import_date_fns.getHours)(base)), (0, import_date_fns.getMinutes)(base)));
2296
2343
  };
2297
2344
  const handleTimeChange = (h, m) => {
2298
- const base = selected ?? /* @__PURE__ */ new Date();
2299
- const merged = (0, import_date_fns.setMinutes)((0, import_date_fns.setHours)(base, h), m);
2300
- commit(merged);
2345
+ commit((0, import_date_fns.setMinutes)((0, import_date_fns.setHours)(selected ?? /* @__PURE__ */ new Date(), h), m));
2301
2346
  };
2302
2347
  const datePrefix = selected ? (0, import_date_fns.format)(selected, "yyyy-MM-dd") : void 0;
2303
- if (mode === "dateTime") {
2304
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2305
- "div",
2348
+ const footer = (label) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "border-t border-white/10 px-3 py-2 flex items-center justify-between", children: [
2349
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-xs text-muted-foreground", children: label }),
2350
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2351
+ "button",
2306
2352
  {
2307
- ref,
2308
- className: "absolute z-50 mt-1 rounded-xl border border-white/10 bg-card shadow-xl backdrop-blur-sm",
2309
- style: { top: "100%", left: 0 },
2310
- children: [
2311
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex", children: [
2312
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex-1 min-w-[240px]", children: [
2313
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs font-medium text-muted-foreground px-3 pt-3 pb-1", children: "Date" }),
2314
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2315
- Calendar2,
2316
- {
2317
- selected,
2318
- month,
2319
- disabledDates,
2320
- onDayClick: handleDayClick,
2321
- onPrevMonth: () => setMonth((m) => (0, import_date_fns.subMonths)(m, 1)),
2322
- onNextMonth: () => setMonth((m) => (0, import_date_fns.addMonths)(m, 1))
2323
- }
2324
- )
2325
- ] }),
2326
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "w-px bg-white/10 my-3" }),
2327
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex-1 min-w-[140px] flex flex-col", children: [
2328
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs font-medium text-muted-foreground px-3 pt-3 pb-1", children: "Time" }),
2329
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex gap-2 px-3 pb-3 flex-1", children: [
2330
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex-1", children: [
2331
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-muted-foreground mb-1 text-center", children: "HH" }),
2332
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "grid grid-cols-1 gap-1 max-h-52 overflow-y-auto", children: HOURS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2333
- "button",
2334
- {
2335
- type: "button",
2336
- disabled: MINUTES.every((m) => {
2337
- if (!disabledDateTimes || !datePrefix) return false;
2338
- return disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`);
2339
- }),
2340
- onClick: () => handleTimeChange(h, selected ? (0, import_date_fns.getMinutes)(selected) : 0),
2341
- className: cn(
2342
- "text-xs rounded py-1 transition-colors",
2343
- selected && (0, import_date_fns.getHours)(selected) === h ? "bg-primary text-primary-foreground" : "hover:bg-white/10 text-foreground",
2344
- MINUTES.every((m) => {
2345
- if (!disabledDateTimes || !datePrefix) return false;
2346
- return disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`);
2347
- }) && "opacity-30 cursor-not-allowed line-through"
2348
- ),
2349
- children: String(h).padStart(2, "0")
2350
- },
2351
- h
2352
- )) })
2353
- ] }),
2354
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "w-12", children: [
2355
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-muted-foreground mb-1 text-center", children: "MM" }),
2356
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "grid grid-cols-1 gap-1 max-h-52 overflow-y-auto", children: MINUTES.map((m) => {
2357
- const h = selected ? (0, import_date_fns.getHours)(selected) : 0;
2358
- const isDisabled = disabledDateTimes && datePrefix ? disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`) : false;
2359
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2360
- "button",
2361
- {
2362
- type: "button",
2363
- disabled: isDisabled,
2364
- onClick: () => handleTimeChange(h, m),
2365
- className: cn(
2366
- "text-xs rounded py-1 transition-colors",
2367
- selected && (0, import_date_fns.getMinutes)(selected) === m ? "bg-primary text-primary-foreground" : "hover:bg-white/10 text-foreground",
2368
- isDisabled && "opacity-30 cursor-not-allowed line-through"
2369
- ),
2370
- children: [
2371
- ":",
2372
- String(m).padStart(2, "0")
2373
- ]
2374
- },
2375
- m
2376
- );
2377
- }) })
2378
- ] })
2379
- ] })
2380
- ] })
2381
- ] }),
2382
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "border-t border-white/10 px-3 py-2 flex items-center justify-between", children: [
2383
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-xs text-muted-foreground", children: selected ? (0, import_date_fns.format)(selected, "MMM d, yyyy HH:mm") : "No date selected" }),
2384
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2385
- "button",
2386
- {
2387
- type: "button",
2388
- onClick: onClose,
2389
- className: "text-xs rounded-lg bg-primary text-primary-foreground px-3 py-1 hover:opacity-90 transition-opacity",
2390
- children: "Done"
2391
- }
2392
- )
2393
- ] })
2394
- ]
2353
+ type: "button",
2354
+ onClick: onClose,
2355
+ className: "text-xs rounded-lg bg-primary text-primary-foreground px-3 py-1 hover:opacity-90 transition-opacity",
2356
+ children: "Done"
2395
2357
  }
2396
- );
2397
- }
2398
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2399
- "div",
2400
- {
2401
- ref,
2402
- className: "absolute z-50 mt-1 rounded-xl border border-white/10 bg-card shadow-xl backdrop-blur-sm min-w-[260px]",
2403
- style: { top: "100%", left: 0 },
2404
- children: [
2405
- mode === "date" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2358
+ )
2359
+ ] });
2360
+ if (mode === "dateTime") {
2361
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "rounded-xl border border-white/10 bg-card shadow-xl backdrop-blur-sm", style: anchorStyle, children: [
2362
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex", children: [
2363
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex-1 min-w-[240px]", children: [
2364
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs font-medium text-muted-foreground px-3 pt-3 pb-1", children: "Date" }),
2406
2365
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2407
2366
  Calendar2,
2408
2367
  {
@@ -2413,46 +2372,91 @@ function DatePickerPopup({
2413
2372
  onPrevMonth: () => setMonth((m) => (0, import_date_fns.subMonths)(m, 1)),
2414
2373
  onNextMonth: () => setMonth((m) => (0, import_date_fns.addMonths)(m, 1))
2415
2374
  }
2416
- ),
2417
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "border-t border-white/10 px-3 py-2 flex items-center justify-between", children: [
2418
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-xs text-muted-foreground", children: selected ? (0, import_date_fns.format)(selected, "MMM d, yyyy") : "No date selected" }),
2419
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2420
- "button",
2421
- {
2422
- type: "button",
2423
- onClick: onClose,
2424
- className: "text-xs rounded-lg bg-primary text-primary-foreground px-3 py-1 hover:opacity-90 transition-opacity",
2425
- children: "Done"
2426
- }
2427
- )
2428
- ] })
2375
+ )
2429
2376
  ] }),
2430
- mode === "time" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2431
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2432
- TimePicker,
2433
- {
2434
- selected,
2435
- disabledDateTimes,
2436
- datePrefix,
2437
- onChange: handleTimeChange
2438
- }
2439
- ),
2440
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "border-t border-white/10 px-3 py-2 flex items-center justify-between", children: [
2441
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-xs text-muted-foreground", children: selected ? (0, import_date_fns.format)(selected, "HH:mm") : "No time selected" }),
2442
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2443
- "button",
2444
- {
2445
- type: "button",
2446
- onClick: onClose,
2447
- className: "text-xs rounded-lg bg-primary text-primary-foreground px-3 py-1 hover:opacity-90 transition-opacity",
2448
- children: "Done"
2449
- }
2450
- )
2377
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "w-px bg-white/10 my-3" }),
2378
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex-1 min-w-[140px] flex flex-col", children: [
2379
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs font-medium text-muted-foreground px-3 pt-3 pb-1", children: "Time" }),
2380
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex gap-2 px-3 pb-3 flex-1", children: [
2381
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex-1", children: [
2382
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-muted-foreground mb-1 text-center", children: "HH" }),
2383
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "grid grid-cols-1 gap-1 max-h-52 overflow-y-auto", children: HOURS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2384
+ "button",
2385
+ {
2386
+ type: "button",
2387
+ disabled: MINUTES.every((m) => {
2388
+ if (!disabledDateTimes || !datePrefix) return false;
2389
+ return disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`);
2390
+ }),
2391
+ onClick: () => handleTimeChange(h, selected ? (0, import_date_fns.getMinutes)(selected) : 0),
2392
+ className: cn(
2393
+ "text-xs rounded py-1 transition-colors",
2394
+ selected && (0, import_date_fns.getHours)(selected) === h ? "bg-primary text-primary-foreground" : "hover:bg-white/10 text-foreground"
2395
+ ),
2396
+ children: String(h).padStart(2, "0")
2397
+ },
2398
+ h
2399
+ )) })
2400
+ ] }),
2401
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "w-12", children: [
2402
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-muted-foreground mb-1 text-center", children: "MM" }),
2403
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "grid grid-cols-1 gap-1 max-h-52 overflow-y-auto", children: MINUTES.map((m) => {
2404
+ const h = selected ? (0, import_date_fns.getHours)(selected) : 0;
2405
+ const dis = disabledDateTimes && datePrefix ? disabledDateTimes.includes(`${datePrefix}T${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`) : false;
2406
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2407
+ "button",
2408
+ {
2409
+ type: "button",
2410
+ disabled: dis,
2411
+ onClick: () => handleTimeChange(h, m),
2412
+ className: cn(
2413
+ "text-xs rounded py-1 transition-colors",
2414
+ selected && (0, import_date_fns.getMinutes)(selected) === m ? "bg-primary text-primary-foreground" : "hover:bg-white/10 text-foreground",
2415
+ dis && "opacity-30 cursor-not-allowed line-through"
2416
+ ),
2417
+ children: [
2418
+ ":",
2419
+ String(m).padStart(2, "0")
2420
+ ]
2421
+ },
2422
+ m
2423
+ );
2424
+ }) })
2425
+ ] })
2451
2426
  ] })
2452
2427
  ] })
2453
- ]
2454
- }
2455
- );
2428
+ ] }),
2429
+ footer(selected ? (0, import_date_fns.format)(selected, "MMM d, yyyy HH:mm") : "No date selected")
2430
+ ] }) });
2431
+ }
2432
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "rounded-xl border border-white/10 bg-card shadow-xl backdrop-blur-sm min-w-[260px]", style: anchorStyle, children: [
2433
+ mode === "date" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2434
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2435
+ Calendar2,
2436
+ {
2437
+ selected,
2438
+ month,
2439
+ disabledDates,
2440
+ onDayClick: handleDayClick,
2441
+ onPrevMonth: () => setMonth((m) => (0, import_date_fns.subMonths)(m, 1)),
2442
+ onNextMonth: () => setMonth((m) => (0, import_date_fns.addMonths)(m, 1))
2443
+ }
2444
+ ),
2445
+ footer(selected ? (0, import_date_fns.format)(selected, "MMM d, yyyy") : "No date selected")
2446
+ ] }),
2447
+ mode === "time" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2448
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2449
+ TimePicker,
2450
+ {
2451
+ selected,
2452
+ disabledDateTimes,
2453
+ datePrefix,
2454
+ onChange: handleTimeChange
2455
+ }
2456
+ ),
2457
+ footer(selected ? (0, import_date_fns.format)(selected, "HH:mm") : "No time selected")
2458
+ ] })
2459
+ ] }) });
2456
2460
  }
2457
2461
 
2458
2462
  // src/components/ui/date-range-picker.tsx
@@ -2490,6 +2494,8 @@ function DateRangePicker({
2490
2494
  const [viewMonth, setViewMonth] = React14.useState(today.getMonth());
2491
2495
  const [viewYear, setViewYear] = React14.useState(today.getFullYear());
2492
2496
  const ref = React14.useRef(null);
2497
+ const triggerRef = React14.useRef(null);
2498
+ const [dropStyle, setDropStyle] = React14.useState({});
2493
2499
  const range2 = controlled ?? internal;
2494
2500
  React14.useEffect(() => {
2495
2501
  function handler(e) {
@@ -2502,6 +2508,19 @@ function DateRangePicker({
2502
2508
  if (!controlled) setInternal(r);
2503
2509
  onChange?.(r);
2504
2510
  }
2511
+ function openPicker() {
2512
+ if (triggerRef.current) {
2513
+ const pos = getPortalPosition(triggerRef.current, 340);
2514
+ setDropStyle({
2515
+ position: "fixed",
2516
+ top: pos.placement === "bottom" ? pos.top : void 0,
2517
+ bottom: pos.placement === "top" ? window.innerHeight - pos.top : void 0,
2518
+ left: pos.left,
2519
+ zIndex: 9999
2520
+ });
2521
+ }
2522
+ setOpen(true);
2523
+ }
2505
2524
  function selectDay(d) {
2506
2525
  if (selecting === "from") {
2507
2526
  update({ from: d, to: null });
@@ -2536,9 +2555,10 @@ function DateRangePicker({
2536
2555
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2537
2556
  "button",
2538
2557
  {
2558
+ ref: triggerRef,
2539
2559
  type: "button",
2540
2560
  disabled,
2541
- onClick: () => setOpen((v) => !v),
2561
+ onClick: () => open ? setOpen(false) : openPicker(),
2542
2562
  className: cn(
2543
2563
  "flex w-full items-center gap-2 rounded-xl border border-border bg-background px-3 py-2 text-sm transition-colors",
2544
2564
  "hover:border-primary/40 focus:outline-none focus:ring-2 focus:ring-ring",
@@ -2564,25 +2584,41 @@ function DateRangePicker({
2564
2584
  ]
2565
2585
  }
2566
2586
  ),
2567
- open && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "absolute z-50 mt-1 rounded-xl border border-border glass shadow-2xl p-4 w-72", children: [
2587
+ open && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "rounded-xl border border-border glass shadow-2xl p-4 w-72", style: dropStyle, children: [
2568
2588
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [
2569
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: () => {
2570
- if (viewMonth === 0) {
2571
- setViewMonth(11);
2572
- setViewYear((y) => y - 1);
2573
- } else setViewMonth((m) => m - 1);
2574
- }, className: "p-1 rounded-md hover:bg-accent transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react11.ChevronLeft, { className: "h-4 w-4" }) }),
2589
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2590
+ "button",
2591
+ {
2592
+ type: "button",
2593
+ onClick: () => {
2594
+ if (viewMonth === 0) {
2595
+ setViewMonth(11);
2596
+ setViewYear((y) => y - 1);
2597
+ } else setViewMonth((m) => m - 1);
2598
+ },
2599
+ className: "p-1 rounded-md hover:bg-accent transition-colors",
2600
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react11.ChevronLeft, { className: "h-4 w-4" })
2601
+ }
2602
+ ),
2575
2603
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "text-sm font-semibold", children: [
2576
2604
  MONTHS2[viewMonth],
2577
2605
  " ",
2578
2606
  viewYear
2579
2607
  ] }),
2580
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: () => {
2581
- if (viewMonth === 11) {
2582
- setViewMonth(0);
2583
- setViewYear((y) => y + 1);
2584
- } else setViewMonth((m) => m + 1);
2585
- }, className: "p-1 rounded-md hover:bg-accent transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react11.ChevronRight, { className: "h-4 w-4" }) })
2608
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2609
+ "button",
2610
+ {
2611
+ type: "button",
2612
+ onClick: () => {
2613
+ if (viewMonth === 11) {
2614
+ setViewMonth(0);
2615
+ setViewYear((y) => y + 1);
2616
+ } else setViewMonth((m) => m + 1);
2617
+ },
2618
+ className: "p-1 rounded-md hover:bg-accent transition-colors",
2619
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react11.ChevronRight, { className: "h-4 w-4" })
2620
+ }
2621
+ )
2586
2622
  ] }),
2587
2623
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "grid grid-cols-7 mb-1", children: DAYS3.map((d) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-center text-[10px] font-semibold text-muted-foreground py-1", children: d }, d)) }),
2588
2624
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "grid grid-cols-7 gap-y-0.5", children: days.map((d, i) => {
@@ -2617,7 +2653,7 @@ function DateRangePicker({
2617
2653
  );
2618
2654
  }) }),
2619
2655
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "mt-3 text-center text-xs text-muted-foreground", children: selecting === "from" ? "Select start date" : "Select end date" })
2620
- ] })
2656
+ ] }) })
2621
2657
  ] });
2622
2658
  }
2623
2659
 
@@ -2719,10 +2755,10 @@ function Drawer({
2719
2755
  var React16 = __toESM(require("react"), 1);
2720
2756
  var import_jsx_runtime19 = require("react/jsx-runtime");
2721
2757
  var widthMap = {
2722
- sm: "w-40",
2723
- md: "w-56",
2724
- lg: "w-72",
2725
- auto: "w-auto min-w-[10rem]"
2758
+ sm: 160,
2759
+ md: 224,
2760
+ lg: 288,
2761
+ auto: void 0
2726
2762
  };
2727
2763
  function Dropdown({
2728
2764
  trigger,
@@ -2736,25 +2772,40 @@ function Dropdown({
2736
2772
  className
2737
2773
  }) {
2738
2774
  const [isOpen, setIsOpen] = React16.useState(false);
2739
- const containerRef = React16.useRef(null);
2740
- const toggle = () => {
2775
+ const triggerRef = React16.useRef(null);
2776
+ const [dropStyle, setDropStyle] = React16.useState({});
2777
+ const open = () => {
2741
2778
  if (disabled) return;
2742
- const next = !isOpen;
2743
- setIsOpen(next);
2744
- onOpenChange?.(next);
2779
+ if (triggerRef.current) {
2780
+ const r = triggerRef.current.getBoundingClientRect();
2781
+ const pos = getPortalPosition(triggerRef.current, 320, placement);
2782
+ const w = widthMap[width];
2783
+ let left = r.left;
2784
+ if (align === "right") left = r.right - (w ?? r.width);
2785
+ if (align === "center") left = r.left + r.width / 2 - (w ?? r.width) / 2;
2786
+ setDropStyle({
2787
+ position: "fixed",
2788
+ top: pos.placement === "bottom" ? pos.top : void 0,
2789
+ bottom: pos.placement === "top" ? window.innerHeight - r.top + 4 : void 0,
2790
+ left,
2791
+ width: w,
2792
+ minWidth: w ? void 0 : "10rem",
2793
+ zIndex: 9999
2794
+ });
2795
+ }
2796
+ setIsOpen(true);
2797
+ onOpenChange?.(true);
2745
2798
  };
2746
2799
  const close = () => {
2747
2800
  setIsOpen(false);
2748
2801
  onOpenChange?.(false);
2749
2802
  };
2750
2803
  React16.useEffect(() => {
2751
- const handleClickOutside = (event) => {
2752
- if (containerRef.current && !containerRef.current.contains(event.target)) {
2753
- close();
2754
- }
2804
+ const handleClickOutside = (e) => {
2805
+ if (triggerRef.current && !triggerRef.current.contains(e.target)) close();
2755
2806
  };
2756
- const handleKeyDown = (event) => {
2757
- if (event.key === "Escape") close();
2807
+ const handleKeyDown = (e) => {
2808
+ if (e.key === "Escape") close();
2758
2809
  };
2759
2810
  document.addEventListener("mousedown", handleClickOutside);
2760
2811
  document.addEventListener("keydown", handleKeyDown);
@@ -2763,39 +2814,30 @@ function Dropdown({
2763
2814
  document.removeEventListener("keydown", handleKeyDown);
2764
2815
  };
2765
2816
  }, [isOpen]);
2766
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative inline-block text-left", ref: containerRef, children: [
2817
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative inline-block text-left", ref: triggerRef, children: [
2767
2818
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2768
2819
  "div",
2769
2820
  {
2770
- onClick: toggle,
2821
+ onClick: () => isOpen ? close() : open(),
2771
2822
  "aria-expanded": isOpen,
2772
2823
  "aria-haspopup": "true",
2773
2824
  className: cn(disabled && "opacity-50 cursor-not-allowed pointer-events-none"),
2774
2825
  children: trigger
2775
2826
  }
2776
2827
  ),
2777
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2828
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2778
2829
  "div",
2779
2830
  {
2780
2831
  className: cn(
2781
- "absolute z-50 rounded-xl border border-white/10 bg-background/90 backdrop-blur-2xl text-popover-foreground",
2832
+ "rounded-xl border border-white/10 bg-background/90 backdrop-blur-2xl text-popover-foreground",
2782
2833
  "shadow-[0_8px_32px_rgba(0,0,0,0.35)] ring-1 ring-white/5",
2783
2834
  "animate-in fade-in-0 zoom-in-95 duration-150",
2784
- widthMap[width],
2785
- placement === "top" ? "bottom-full mb-2" : "top-full mt-2",
2786
- align === "right" ? "right-0" : align === "center" ? "left-1/2 -translate-x-1/2" : "left-0",
2787
2835
  className
2788
2836
  ),
2789
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2790
- "div",
2791
- {
2792
- className: "py-1.5",
2793
- onClick: closeOnSelect ? close : void 0,
2794
- children
2795
- }
2796
- )
2837
+ style: dropStyle,
2838
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "py-1.5", onClick: closeOnSelect ? close : void 0, children })
2797
2839
  }
2798
- )
2840
+ ) })
2799
2841
  ] });
2800
2842
  }
2801
2843
  function DropdownItem({
@@ -2828,10 +2870,7 @@ function DropdownItem({
2828
2870
  function DropdownSeparator({ className }) {
2829
2871
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("my-1.5 h-px bg-white/8", className) });
2830
2872
  }
2831
- function DropdownLabel({
2832
- children,
2833
- className
2834
- }) {
2873
+ function DropdownLabel({ children, className }) {
2835
2874
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: cn("px-3.5 py-1.5 text-xs font-semibold uppercase tracking-wider text-muted-foreground/60", className), children });
2836
2875
  }
2837
2876
 
@@ -3693,6 +3732,7 @@ var Input = React18.forwardRef(
3693
3732
  value: internalValue,
3694
3733
  disabledDates,
3695
3734
  disabledDateTimes,
3735
+ anchorEl: containerRef.current,
3696
3736
  onChange: (v) => {
3697
3737
  setInternalValue(v);
3698
3738
  setValidationError(null);
@@ -4084,30 +4124,43 @@ function Select({
4084
4124
  const [search, setSearch] = React23.useState("");
4085
4125
  const [isSearching, setIsSearching] = React23.useState(false);
4086
4126
  const containerRef = React23.useRef(null);
4127
+ const triggerRef = React23.useRef(null);
4128
+ const [dropStyle, setDropStyle] = React23.useState({});
4087
4129
  const getKey = (opt) => String(Object.keys(opt)[0]);
4088
4130
  const getLabel = (opt) => Object.values(opt)[0];
4089
4131
  const selectedValues = React23.useMemo(() => {
4090
- if (multiple && Array.isArray(value)) {
4091
- return value;
4092
- } else if (typeof value === "string") {
4093
- return [value];
4094
- }
4132
+ if (multiple && Array.isArray(value)) return value;
4133
+ if (typeof value === "string") return [value];
4095
4134
  return [];
4096
4135
  }, [value, multiple]);
4097
- const selectedOptions = React23.useMemo(() => {
4098
- return options.filter((opt) => selectedValues.includes(getKey(opt)));
4099
- }, [options, selectedValues]);
4100
- const filteredOptions = searchable ? options.filter(
4101
- (opt) => getLabel(opt).toLowerCase().includes(search.toLowerCase())
4102
- ) : options;
4136
+ const selectedOptions = React23.useMemo(
4137
+ () => options.filter((opt) => selectedValues.includes(getKey(opt))),
4138
+ [options, selectedValues]
4139
+ );
4140
+ const filteredOptions = searchable ? options.filter((opt) => getLabel(opt).toLowerCase().includes(search.toLowerCase())) : options;
4141
+ const openDropdown = () => {
4142
+ if (disabled) return;
4143
+ if (triggerRef.current) {
4144
+ const pos = getPortalPosition(triggerRef.current, 260);
4145
+ setDropStyle({
4146
+ position: "fixed",
4147
+ top: pos.placement === "bottom" ? pos.top : void 0,
4148
+ bottom: pos.placement === "top" ? window.innerHeight - pos.top : void 0,
4149
+ left: pos.left,
4150
+ width: pos.width,
4151
+ zIndex: 9999
4152
+ });
4153
+ }
4154
+ setIsOpen(true);
4155
+ };
4103
4156
  React23.useEffect(() => {
4104
- const handleClickOutside = (event) => {
4105
- if (containerRef.current && !containerRef.current.contains(event.target)) {
4157
+ const handler = (e) => {
4158
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
4106
4159
  setIsOpen(false);
4107
4160
  }
4108
4161
  };
4109
- document.addEventListener("mousedown", handleClickOutside);
4110
- return () => document.removeEventListener("mousedown", handleClickOutside);
4162
+ document.addEventListener("mousedown", handler);
4163
+ return () => document.removeEventListener("mousedown", handler);
4111
4164
  }, []);
4112
4165
  const handleSelect = (optionValue) => {
4113
4166
  if (multiple) {
@@ -4121,10 +4174,7 @@ function Select({
4121
4174
  };
4122
4175
  const handleRemove = (optionValue, e) => {
4123
4176
  e.stopPropagation();
4124
- if (multiple) {
4125
- const newValues = selectedValues.filter((v) => v !== optionValue);
4126
- onChange?.(newValues);
4127
- }
4177
+ if (multiple) onChange?.(selectedValues.filter((v) => v !== optionValue));
4128
4178
  };
4129
4179
  const handleReorder = (fromIndex, toIndex) => {
4130
4180
  if (!multiple || !reorderable || !Array.isArray(value)) return;
@@ -4138,16 +4188,13 @@ function Select({
4138
4188
  e.dataTransfer.setData("text/plain", index.toString());
4139
4189
  };
4140
4190
  const handleDragOver = (e) => {
4141
- if (!reorderable) return;
4142
- e.preventDefault();
4191
+ if (reorderable) e.preventDefault();
4143
4192
  };
4144
4193
  const handleDrop = (e, toIndex) => {
4145
4194
  if (!reorderable) return;
4146
4195
  e.preventDefault();
4147
4196
  const fromIndex = parseInt(e.dataTransfer.getData("text/plain"));
4148
- if (fromIndex !== toIndex) {
4149
- handleReorder(fromIndex, toIndex);
4150
- }
4197
+ if (fromIndex !== toIndex) handleReorder(fromIndex, toIndex);
4151
4198
  };
4152
4199
  if (native) {
4153
4200
  if (multiple) {
@@ -4157,58 +4204,29 @@ function Select({
4157
4204
  "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",
4158
4205
  disabled && "opacity-50 pointer-events-none"
4159
4206
  ), children: [
4160
- selectedValues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-wrap gap-1 px-3 pt-2 pb-1 border-b border-slate-900/10", children: selectedOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
4161
- "span",
4162
- {
4163
- className: "inline-flex items-center gap-1 rounded-sm bg-primary/15 text-primary px-2 py-0.5 text-xs",
4164
- children: [
4165
- getLabel(opt),
4166
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
4167
- "button",
4168
- {
4169
- type: "button",
4170
- disabled,
4171
- onClick: () => onChange?.(selectedValues.filter((v) => v !== getKey(opt))),
4172
- className: "hover:text-destructive",
4173
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.X, { className: "h-3 w-3" })
4174
- }
4175
- )
4176
- ]
4177
- },
4178
- getKey(opt)
4179
- )) }),
4207
+ selectedValues.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-wrap gap-1 px-3 pt-2 pb-1 border-b border-slate-900/10", children: selectedOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "inline-flex items-center gap-1 rounded-sm bg-primary/15 text-primary px-2 py-0.5 text-xs", children: [
4208
+ getLabel(opt),
4209
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", disabled, onClick: () => onChange?.(selectedValues.filter((v) => v !== getKey(opt))), className: "hover:text-destructive", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.X, { className: "h-3 w-3" }) })
4210
+ ] }, getKey(opt))) }),
4180
4211
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "max-h-48 overflow-y-auto p-1", children: options.map((option) => {
4181
4212
  const checked = selectedValues.includes(getKey(option));
4182
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
4183
- "label",
4184
- {
4185
- className: cn(
4186
- "flex items-center gap-3 rounded-lg px-3 py-2 text-sm cursor-pointer transition-colors hover:bg-accent",
4187
- checked && "bg-primary/8 text-primary"
4188
- ),
4189
- children: [
4190
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: cn(
4191
- "flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
4192
- checked ? "bg-primary border-primary text-primary-foreground" : "border-slate-900/30 bg-background/50"
4193
- ), children: checked && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.Check, { className: "h-3 w-3" }) }),
4194
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
4195
- "input",
4196
- {
4197
- type: "checkbox",
4198
- className: "sr-only",
4199
- checked,
4200
- disabled,
4201
- onChange: () => {
4202
- const newValues = checked ? selectedValues.filter((v) => v !== getKey(option)) : [...selectedValues, getKey(option)];
4203
- onChange?.(newValues);
4204
- }
4205
- }
4206
- ),
4207
- getLabel(option)
4208
- ]
4209
- },
4210
- getKey(option)
4211
- );
4213
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("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: [
4214
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("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__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.Check, { className: "h-3 w-3" }) }),
4215
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
4216
+ "input",
4217
+ {
4218
+ type: "checkbox",
4219
+ className: "sr-only",
4220
+ checked,
4221
+ disabled,
4222
+ onChange: () => {
4223
+ const newValues = checked ? selectedValues.filter((v) => v !== getKey(option)) : [...selectedValues, getKey(option)];
4224
+ onChange?.(newValues);
4225
+ }
4226
+ }
4227
+ ),
4228
+ getLabel(option)
4229
+ ] }, getKey(option));
4212
4230
  }) })
4213
4231
  ] })
4214
4232
  ] });
@@ -4239,14 +4257,15 @@ function Select({
4239
4257
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
4240
4258
  "button",
4241
4259
  {
4260
+ ref: triggerRef,
4242
4261
  type: "button",
4243
4262
  className: cn(
4244
4263
  "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",
4245
4264
  multiple && selectedValues.length > 0 && "flex-wrap gap-1",
4246
- (suffixIcon || !suffixIcon) && "pr-10",
4265
+ "pr-10",
4247
4266
  disabled && "cursor-not-allowed opacity-50"
4248
4267
  ),
4249
- onClick: () => !disabled && setIsOpen(!isOpen),
4268
+ onClick: () => isOpen ? setIsOpen(false) : openDropdown(),
4250
4269
  disabled,
4251
4270
  children: multiple && selectedOptions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-wrap gap-1 flex-1 min-w-0", children: selectedOptions.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
4252
4271
  "span",
@@ -4255,22 +4274,11 @@ function Select({
4255
4274
  onDragStart: (e) => handleDragStart(e, index),
4256
4275
  onDragOver: handleDragOver,
4257
4276
  onDrop: (e) => handleDrop(e, index),
4258
- className: cn(
4259
- "inline-flex items-center gap-1 rounded-sm bg-primary/15 text-primary px-2 py-1 text-xs",
4260
- reorderable && "cursor-move"
4261
- ),
4277
+ className: cn("inline-flex items-center gap-1 rounded-sm bg-primary/15 text-primary px-2 py-1 text-xs", reorderable && "cursor-move"),
4262
4278
  children: [
4263
4279
  reorderable && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.GripVertical, { className: "h-3 w-3 opacity-50" }),
4264
4280
  getLabel(option),
4265
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
4266
- "button",
4267
- {
4268
- type: "button",
4269
- onClick: (e) => handleRemove(getKey(option), e),
4270
- className: "ml-1 hover:text-destructive",
4271
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.X, { className: "h-3 w-3" })
4272
- }
4273
- )
4281
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", onClick: (e) => handleRemove(getKey(option), e), className: "ml-1 hover:text-destructive", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.X, { className: "h-3 w-3" }) })
4274
4282
  ]
4275
4283
  },
4276
4284
  getKey(option)
@@ -4283,50 +4291,56 @@ function Select({
4283
4291
  {
4284
4292
  type: "button",
4285
4293
  disabled,
4286
- onClick: () => !disabled && setIsOpen(!isOpen),
4294
+ onClick: () => isOpen ? setIsOpen(false) : openDropdown(),
4287
4295
  className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors z-10 disabled:opacity-50",
4288
- "aria-label": "Open options",
4289
4296
  style: iconColor ? { color: iconColor } : void 0,
4290
4297
  children: suffixIcon
4291
4298
  }
4292
4299
  ),
4293
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("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: [
4294
- searchable && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "sticky top-0 z-10 flex items-center border-b border-white/10 bg-background/90 px-3 py-2", children: [
4295
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
4296
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
4297
- "input",
4298
- {
4299
- 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",
4300
- placeholder: searchingMessage,
4301
- value: search,
4302
- onChange: (e) => {
4303
- setSearch(e.target.value);
4304
- setIsSearching(true);
4305
- setTimeout(() => setIsSearching(false), 300);
4306
- },
4307
- onClick: (e) => e.stopPropagation()
4308
- }
4309
- )
4310
- ] }),
4311
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "p-1", children: isSearching ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "py-6 text-center text-sm text-muted-foreground", children: loadingMessage }) : filteredOptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "py-6 text-center text-sm text-muted-foreground", children: search ? noSearchResultsMessage : "No options available." }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
4312
- filteredOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
4313
- "div",
4314
- {
4315
- className: cn(
4316
- "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",
4317
- (multiple ? selectedValues.includes(getKey(option)) : value === getKey(option)) && "bg-accent text-accent-foreground"
4318
- ),
4319
- onClick: () => handleSelect(getKey(option)),
4320
- children: [
4321
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("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__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.Check, { className: "h-4 w-4" }) }),
4322
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "truncate", children: getLabel(option) })
4323
- ]
4324
- },
4325
- getKey(option)
4326
- )),
4327
- createOptionForm && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "border-t border-white/10 mt-1 pt-1", children: createOptionForm })
4328
- ] }) })
4329
- ] })
4300
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
4301
+ "div",
4302
+ {
4303
+ 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",
4304
+ style: dropStyle,
4305
+ children: [
4306
+ searchable && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "sticky top-0 z-10 flex items-center border-b border-white/10 bg-background/90 px-3 py-2", children: [
4307
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
4308
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
4309
+ "input",
4310
+ {
4311
+ className: "flex h-8 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground",
4312
+ placeholder: searchingMessage,
4313
+ value: search,
4314
+ onChange: (e) => {
4315
+ setSearch(e.target.value);
4316
+ setIsSearching(true);
4317
+ setTimeout(() => setIsSearching(false), 300);
4318
+ },
4319
+ onClick: (e) => e.stopPropagation()
4320
+ }
4321
+ )
4322
+ ] }),
4323
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "p-1", children: isSearching ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "py-6 text-center text-sm text-muted-foreground", children: loadingMessage }) : filteredOptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "py-6 text-center text-sm text-muted-foreground", children: search ? noSearchResultsMessage : "No options available." }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
4324
+ filteredOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
4325
+ "div",
4326
+ {
4327
+ className: cn(
4328
+ "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",
4329
+ (multiple ? selectedValues.includes(getKey(option)) : value === getKey(option)) && "bg-accent text-accent-foreground"
4330
+ ),
4331
+ onClick: () => handleSelect(getKey(option)),
4332
+ children: [
4333
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("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__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react16.Check, { className: "h-4 w-4" }) }),
4334
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "truncate", children: getLabel(option) })
4335
+ ]
4336
+ },
4337
+ getKey(option)
4338
+ )),
4339
+ createOptionForm && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "border-t border-white/10 mt-1 pt-1", children: createOptionForm })
4340
+ ] }) })
4341
+ ]
4342
+ }
4343
+ ) })
4330
4344
  ] })
4331
4345
  ] });
4332
4346
  }
@@ -5169,7 +5183,7 @@ var import_lucide_react20 = require("lucide-react");
5169
5183
 
5170
5184
  // src/components/ui/tooltip.tsx
5171
5185
  var React28 = __toESM(require("react"), 1);
5172
- var ReactDOM = __toESM(require("react-dom"), 1);
5186
+ var ReactDOM2 = __toESM(require("react-dom"), 1);
5173
5187
  var import_jsx_runtime33 = require("react/jsx-runtime");
5174
5188
  function Tooltip({
5175
5189
  content,
@@ -5224,7 +5238,7 @@ function Tooltip({
5224
5238
  onBlur: () => setVisible(false),
5225
5239
  children: [
5226
5240
  children,
5227
- visible && ReactDOM.createPortal(
5241
+ visible && ReactDOM2.createPortal(
5228
5242
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
5229
5243
  "div",
5230
5244
  {
@@ -5247,24 +5261,36 @@ function Tooltip({
5247
5261
 
5248
5262
  // src/components/theme-provider.tsx
5249
5263
  var import_react = require("react");
5264
+
5265
+ // src/components/conf/settingConfig.json
5266
+ var settingConfig_default = {
5267
+ theme: "dark",
5268
+ fontSize: "16px",
5269
+ fontFamily: '"Space Grotesk", "Inter", sans-serif',
5270
+ colors: {
5271
+ primary: "#8b5cf6",
5272
+ primaryHover: "#7c3aed",
5273
+ secondary: "#171717",
5274
+ secondaryHover: "#262626",
5275
+ info: "#3b82f6",
5276
+ infoHover: "#2563eb",
5277
+ warning: "#f59e0b",
5278
+ warningHover: "#d97706",
5279
+ danger: "#ef4444",
5280
+ dangerHover: "#dc2626"
5281
+ }
5282
+ };
5283
+
5284
+ // src/components/theme-provider.tsx
5250
5285
  var import_jsx_runtime34 = require("react/jsx-runtime");
5251
- var defaultColors = {
5252
- primary: "#8b5cf6",
5253
- primaryHover: "#7c3aed",
5254
- secondary: "#171717",
5255
- secondaryHover: "#262626",
5256
- info: "#3b82f6",
5257
- infoHover: "#2563eb",
5258
- warning: "#f59e0b",
5259
- warningHover: "#d97706",
5260
- danger: "#ef4444",
5261
- dangerHover: "#dc2626"
5286
+ var configDefaults = {
5287
+ theme: settingConfig_default.theme,
5288
+ fontSize: settingConfig_default.fontSize,
5289
+ fontFamily: settingConfig_default.fontFamily,
5290
+ colors: settingConfig_default.colors
5262
5291
  };
5263
5292
  var initialState = {
5264
- theme: "system",
5265
- colors: defaultColors,
5266
- fontSize: "16px",
5267
- fontFamily: '"Space Grotesk", "Inter", sans-serif',
5293
+ ...configDefaults,
5268
5294
  setTheme: () => null,
5269
5295
  setColors: () => null,
5270
5296
  setFontSize: () => null,
@@ -5274,26 +5300,60 @@ var initialState = {
5274
5300
  var ThemeProviderContext = (0, import_react.createContext)(initialState);
5275
5301
  var COLOR_PALETTE = [
5276
5302
  { base: "#6366f1", hover: "#4f46e5" },
5277
- // Indigo
5278
5303
  { base: "#8b5cf6", hover: "#7c3aed" },
5279
- // Violet
5280
5304
  { base: "#3b82f6", hover: "#2563eb" },
5281
- // Blue
5282
5305
  { base: "#10b981", hover: "#059669" },
5283
- // Emerald
5284
5306
  { base: "#22c55e", hover: "#16a34a" },
5285
- // Green
5286
5307
  { base: "#eab308", hover: "#ca8a04" },
5287
- // Yellow
5288
5308
  { base: "#f59e0b", hover: "#d97706" },
5289
- // Amber
5290
5309
  { base: "#f97316", hover: "#ea580c" },
5291
- // Orange
5292
5310
  { base: "#ef4444", hover: "#dc2626" },
5293
- // Red
5294
5311
  { base: "#ec4899", hover: "#db2777" }
5295
- // Pink
5296
5312
  ];
5313
+ function ThemeProvider({
5314
+ children,
5315
+ storageKey = "codego-ui-theme-settings",
5316
+ ...props
5317
+ }) {
5318
+ const [settings, setSettings] = (0, import_react.useState)(() => {
5319
+ try {
5320
+ const stored = localStorage.getItem(storageKey);
5321
+ if (stored) return { ...configDefaults, ...JSON.parse(stored) };
5322
+ } catch {
5323
+ }
5324
+ return configDefaults;
5325
+ });
5326
+ (0, import_react.useEffect)(() => {
5327
+ localStorage.setItem(storageKey, JSON.stringify(settings));
5328
+ }, [settings, storageKey]);
5329
+ (0, import_react.useEffect)(() => {
5330
+ const root = window.document.documentElement;
5331
+ root.classList.remove("light", "dark");
5332
+ const resolved = settings.theme === "system" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : settings.theme;
5333
+ root.classList.add(resolved);
5334
+ root.style.setProperty("--primary", settings.colors.primary);
5335
+ root.style.setProperty("--primary-hover", settings.colors.primaryHover);
5336
+ root.style.setProperty("--secondary", settings.colors.secondary);
5337
+ root.style.setProperty("--secondary-hover", settings.colors.secondaryHover);
5338
+ root.style.setProperty("--info", settings.colors.info);
5339
+ root.style.setProperty("--info-hover", settings.colors.infoHover);
5340
+ root.style.setProperty("--warning", settings.colors.warning);
5341
+ root.style.setProperty("--warning-hover", settings.colors.warningHover);
5342
+ root.style.setProperty("--danger", settings.colors.danger);
5343
+ root.style.setProperty("--danger-hover", settings.colors.dangerHover);
5344
+ root.style.setProperty("font-size", settings.fontSize);
5345
+ root.style.setProperty("--font-sans", settings.fontFamily);
5346
+ }, [settings]);
5347
+ const value = {
5348
+ ...settings,
5349
+ setTheme: (theme) => setSettings((s) => ({ ...s, theme })),
5350
+ setColors: (colors) => setSettings((s) => ({ ...s, colors: { ...s.colors, ...colors } })),
5351
+ setFontSize: (fontSize) => setSettings((s) => ({ ...s, fontSize })),
5352
+ setFontFamily: (fontFamily) => setSettings((s) => ({ ...s, fontFamily })),
5353
+ resetSettings: () => setSettings(configDefaults)
5354
+ };
5355
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ThemeProviderContext.Provider, { ...props, value, children });
5356
+ }
5297
5357
  var useTheme = () => {
5298
5358
  const context = (0, import_react.useContext)(ThemeProviderContext);
5299
5359
  if (context === void 0)
@@ -5453,16 +5513,28 @@ function PanelSidebarGroup({
5453
5513
  // src/components/ui/popover.tsx
5454
5514
  var React31 = __toESM(require("react"), 1);
5455
5515
  var import_jsx_runtime36 = require("react/jsx-runtime");
5456
- var PLACEMENT_CLASSES = {
5457
- "top": "bottom-full left-1/2 -translate-x-1/2 mb-2",
5458
- "bottom": "top-full left-1/2 -translate-x-1/2 mt-2",
5459
- "left": "right-full top-1/2 -translate-y-1/2 mr-2",
5460
- "right": "left-full top-1/2 -translate-y-1/2 ml-2",
5461
- "top-start": "bottom-full left-0 mb-2",
5462
- "top-end": "bottom-full right-0 mb-2",
5463
- "bottom-start": "top-full left-0 mt-2",
5464
- "bottom-end": "top-full right-0 mt-2"
5465
- };
5516
+ function calcStyle(triggerEl, placement) {
5517
+ const r = triggerEl.getBoundingClientRect();
5518
+ const GAP = 8;
5519
+ switch (placement) {
5520
+ case "bottom":
5521
+ return { top: r.bottom + GAP, left: r.left + r.width / 2, transform: "translateX(-50%)" };
5522
+ case "bottom-start":
5523
+ return { top: r.bottom + GAP, left: r.left };
5524
+ case "bottom-end":
5525
+ return { top: r.bottom + GAP, left: r.right, transform: "translateX(-100%)" };
5526
+ case "top":
5527
+ return { top: r.top - GAP, left: r.left + r.width / 2, transform: "translate(-50%, -100%)" };
5528
+ case "top-start":
5529
+ return { top: r.top - GAP, left: r.left, transform: "translateY(-100%)" };
5530
+ case "top-end":
5531
+ return { top: r.top - GAP, left: r.right, transform: "translate(-100%, -100%)" };
5532
+ case "left":
5533
+ return { top: r.top + r.height / 2, left: r.left - GAP, transform: "translate(-100%, -50%)" };
5534
+ case "right":
5535
+ return { top: r.top + r.height / 2, left: r.right + GAP, transform: "translateY(-50%)" };
5536
+ }
5537
+ }
5466
5538
  function Popover({
5467
5539
  trigger,
5468
5540
  content,
@@ -5474,11 +5546,18 @@ function Popover({
5474
5546
  }) {
5475
5547
  const [internal, setInternal] = React31.useState(false);
5476
5548
  const ref = React31.useRef(null);
5549
+ const [popStyle, setPopStyle] = React31.useState({});
5477
5550
  const open = controlled ?? internal;
5478
5551
  function setOpen(v) {
5479
5552
  if (controlled === void 0) setInternal(v);
5480
5553
  onOpenChange?.(v);
5481
5554
  }
5555
+ function openPopover() {
5556
+ if (ref.current) {
5557
+ setPopStyle({ position: "fixed", zIndex: 9999, ...calcStyle(ref.current, placement) });
5558
+ }
5559
+ setOpen(true);
5560
+ }
5482
5561
  React31.useEffect(() => {
5483
5562
  if (triggerOn !== "click") return;
5484
5563
  function handler(e) {
@@ -5487,14 +5566,17 @@ function Popover({
5487
5566
  document.addEventListener("mousedown", handler);
5488
5567
  return () => document.removeEventListener("mousedown", handler);
5489
5568
  }, [triggerOn]);
5490
- const hoverProps = triggerOn === "hover" ? { onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false) } : {};
5569
+ const hoverProps = triggerOn === "hover" ? { onMouseEnter: openPopover, onMouseLeave: () => setOpen(false) } : {};
5491
5570
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { ref, className: "relative inline-block", ...hoverProps, children: [
5492
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { onClick: () => triggerOn === "click" && setOpen(!open), children: trigger }),
5493
- open && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: cn(
5494
- "absolute z-50 min-w-max rounded-xl border border-border glass shadow-2xl",
5495
- PLACEMENT_CLASSES[placement],
5496
- className
5497
- ), children: content })
5571
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { onClick: () => triggerOn === "click" && (open ? setOpen(false) : openPopover()), children: trigger }),
5572
+ open && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
5573
+ "div",
5574
+ {
5575
+ className: cn("min-w-max rounded-xl border border-border glass shadow-2xl", className),
5576
+ style: popStyle,
5577
+ children: content
5578
+ }
5579
+ ) })
5498
5580
  ] });
5499
5581
  }
5500
5582
 
@@ -7956,6 +8038,7 @@ function Wizard({
7956
8038
  Badge,
7957
8039
  Breadcrumb,
7958
8040
  Button,
8041
+ COLOR_PALETTE,
7959
8042
  Calendar,
7960
8043
  Card,
7961
8044
  CardContent,
@@ -8025,6 +8108,7 @@ function Wizard({
8025
8108
  Tabs,
8026
8109
  TagInput,
8027
8110
  Textarea,
8111
+ ThemeProvider,
8028
8112
  Timeline,
8029
8113
  ToastProvider,
8030
8114
  ToggleSwitch,
@@ -8033,5 +8117,6 @@ function Wizard({
8033
8117
  TreeView,
8034
8118
  Widget,
8035
8119
  Wizard,
8120
+ useTheme,
8036
8121
  useToast
8037
8122
  });