@particle-academy/react-fancy 1.6.1 → 1.7.0
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/README.md +14 -2
- package/dist/index.cjs +496 -197
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -3
- package/dist/index.d.ts +36 -3
- package/dist/index.js +497 -198
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1924,10 +1924,157 @@ var Textarea = react.forwardRef(
|
|
|
1924
1924
|
}
|
|
1925
1925
|
);
|
|
1926
1926
|
Textarea.displayName = "Textarea";
|
|
1927
|
+
function Portal({ children, container }) {
|
|
1928
|
+
if (typeof document === "undefined") return null;
|
|
1929
|
+
const target = container ?? document.body;
|
|
1930
|
+
return reactDom.createPortal(
|
|
1931
|
+
/* @__PURE__ */ jsxRuntime.jsx(PortalDarkWrapper, { children }),
|
|
1932
|
+
target
|
|
1933
|
+
);
|
|
1934
|
+
}
|
|
1935
|
+
function PortalDarkWrapper({ children }) {
|
|
1936
|
+
const ref = react.useRef(null);
|
|
1937
|
+
react.useEffect(() => {
|
|
1938
|
+
const root = document.documentElement;
|
|
1939
|
+
const wrapper = ref.current;
|
|
1940
|
+
if (!wrapper) return;
|
|
1941
|
+
const sync = () => {
|
|
1942
|
+
const isDark = root.classList.contains("dark") || root.getAttribute("data-theme") === "dark";
|
|
1943
|
+
wrapper.classList.toggle("dark", isDark);
|
|
1944
|
+
};
|
|
1945
|
+
sync();
|
|
1946
|
+
const observer = new MutationObserver(sync);
|
|
1947
|
+
observer.observe(root, {
|
|
1948
|
+
attributes: true,
|
|
1949
|
+
attributeFilter: ["class", "data-theme"]
|
|
1950
|
+
});
|
|
1951
|
+
return () => observer.disconnect();
|
|
1952
|
+
}, []);
|
|
1953
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, "data-react-fancy-portal": "", style: { display: "contents" }, children });
|
|
1954
|
+
}
|
|
1955
|
+
function getPosition(anchor, floating, placement, offset) {
|
|
1956
|
+
let x = 0;
|
|
1957
|
+
let y = 0;
|
|
1958
|
+
const base = placement.split("-")[0];
|
|
1959
|
+
const align = placement.split("-")[1];
|
|
1960
|
+
switch (base) {
|
|
1961
|
+
case "top":
|
|
1962
|
+
x = anchor.left + anchor.width / 2 - floating.width / 2;
|
|
1963
|
+
y = anchor.top - floating.height - offset;
|
|
1964
|
+
break;
|
|
1965
|
+
case "bottom":
|
|
1966
|
+
x = anchor.left + anchor.width / 2 - floating.width / 2;
|
|
1967
|
+
y = anchor.bottom + offset;
|
|
1968
|
+
break;
|
|
1969
|
+
case "left":
|
|
1970
|
+
x = anchor.left - floating.width - offset;
|
|
1971
|
+
y = anchor.top + anchor.height / 2 - floating.height / 2;
|
|
1972
|
+
break;
|
|
1973
|
+
case "right":
|
|
1974
|
+
x = anchor.right + offset;
|
|
1975
|
+
y = anchor.top + anchor.height / 2 - floating.height / 2;
|
|
1976
|
+
break;
|
|
1977
|
+
}
|
|
1978
|
+
if (base === "top" || base === "bottom") {
|
|
1979
|
+
if (align === "start") x = anchor.left;
|
|
1980
|
+
else if (align === "end") x = anchor.right - floating.width;
|
|
1981
|
+
}
|
|
1982
|
+
if (base === "left" || base === "right") {
|
|
1983
|
+
if (align === "start") y = anchor.top;
|
|
1984
|
+
else if (align === "end") y = anchor.bottom - floating.height;
|
|
1985
|
+
}
|
|
1986
|
+
let finalPlacement = placement;
|
|
1987
|
+
const vw = window.innerWidth;
|
|
1988
|
+
const vh = window.innerHeight;
|
|
1989
|
+
if (base === "bottom" && y + floating.height > vh) {
|
|
1990
|
+
y = anchor.top - floating.height - offset;
|
|
1991
|
+
finalPlacement = placement.replace("bottom", "top");
|
|
1992
|
+
} else if (base === "top" && y < 0) {
|
|
1993
|
+
y = anchor.bottom + offset;
|
|
1994
|
+
finalPlacement = placement.replace("top", "bottom");
|
|
1995
|
+
}
|
|
1996
|
+
x = Math.max(4, Math.min(x, vw - floating.width - 4));
|
|
1997
|
+
y = Math.max(4, Math.min(y, vh - floating.height - 4));
|
|
1998
|
+
return { x, y, placement: finalPlacement };
|
|
1999
|
+
}
|
|
2000
|
+
function useFloatingPosition(anchorRef, floatingRef, options = {}) {
|
|
2001
|
+
const { placement = "bottom", offset = 8, enabled = true } = options;
|
|
2002
|
+
const [position, setPosition] = react.useState({
|
|
2003
|
+
x: -9999,
|
|
2004
|
+
y: -9999,
|
|
2005
|
+
placement
|
|
2006
|
+
});
|
|
2007
|
+
const update = react.useCallback(() => {
|
|
2008
|
+
const anchor = anchorRef.current;
|
|
2009
|
+
const floating = floatingRef.current;
|
|
2010
|
+
if (!anchor || !floating) return;
|
|
2011
|
+
const anchorRect = anchor.getBoundingClientRect();
|
|
2012
|
+
const floatingRect = floating.getBoundingClientRect();
|
|
2013
|
+
setPosition(getPosition(anchorRect, floatingRect, placement, offset));
|
|
2014
|
+
}, [anchorRef, floatingRef, placement, offset]);
|
|
2015
|
+
react.useLayoutEffect(() => {
|
|
2016
|
+
if (!enabled) return;
|
|
2017
|
+
update();
|
|
2018
|
+
const raf = requestAnimationFrame(() => {
|
|
2019
|
+
update();
|
|
2020
|
+
});
|
|
2021
|
+
return () => cancelAnimationFrame(raf);
|
|
2022
|
+
}, [update, enabled]);
|
|
2023
|
+
react.useEffect(() => {
|
|
2024
|
+
if (!enabled) return;
|
|
2025
|
+
window.addEventListener("scroll", update, true);
|
|
2026
|
+
window.addEventListener("resize", update);
|
|
2027
|
+
return () => {
|
|
2028
|
+
window.removeEventListener("scroll", update, true);
|
|
2029
|
+
window.removeEventListener("resize", update);
|
|
2030
|
+
};
|
|
2031
|
+
}, [update, enabled]);
|
|
2032
|
+
return position;
|
|
2033
|
+
}
|
|
2034
|
+
function useOutsideClick(ref, handler, enabled = true, ignoreRef) {
|
|
2035
|
+
react.useEffect(() => {
|
|
2036
|
+
if (!enabled) return;
|
|
2037
|
+
const listener = (event) => {
|
|
2038
|
+
const el = ref.current;
|
|
2039
|
+
if (!el || el.contains(event.target)) return;
|
|
2040
|
+
if (ignoreRef?.current?.contains(event.target)) return;
|
|
2041
|
+
handler(event);
|
|
2042
|
+
};
|
|
2043
|
+
document.addEventListener("mousedown", listener);
|
|
2044
|
+
document.addEventListener("touchstart", listener);
|
|
2045
|
+
return () => {
|
|
2046
|
+
document.removeEventListener("mousedown", listener);
|
|
2047
|
+
document.removeEventListener("touchstart", listener);
|
|
2048
|
+
};
|
|
2049
|
+
}, [ref, handler, enabled, ignoreRef]);
|
|
2050
|
+
}
|
|
2051
|
+
function useEscapeKey(handler, enabled = true) {
|
|
2052
|
+
react.useEffect(() => {
|
|
2053
|
+
if (!enabled) return;
|
|
2054
|
+
const listener = (event) => {
|
|
2055
|
+
if (event.key === "Escape") {
|
|
2056
|
+
handler();
|
|
2057
|
+
}
|
|
2058
|
+
};
|
|
2059
|
+
document.addEventListener("keydown", listener);
|
|
2060
|
+
return () => document.removeEventListener("keydown", listener);
|
|
2061
|
+
}, [handler, enabled]);
|
|
2062
|
+
}
|
|
1927
2063
|
function isOptionGroup(item) {
|
|
1928
2064
|
return typeof item === "object" && "options" in item;
|
|
1929
2065
|
}
|
|
1930
|
-
function
|
|
2066
|
+
function flattenOptions(list) {
|
|
2067
|
+
const flat = [];
|
|
2068
|
+
for (const item of list) {
|
|
2069
|
+
if (isOptionGroup(item)) {
|
|
2070
|
+
flat.push(...item.options);
|
|
2071
|
+
} else {
|
|
2072
|
+
flat.push(item);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
return flat;
|
|
2076
|
+
}
|
|
2077
|
+
function renderNativeOption(option, index) {
|
|
1931
2078
|
const resolved = resolveOption(option);
|
|
1932
2079
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1933
2080
|
"option",
|
|
@@ -1939,7 +2086,7 @@ function renderOption(option, index) {
|
|
|
1939
2086
|
`${resolved.value}-${index}`
|
|
1940
2087
|
);
|
|
1941
2088
|
}
|
|
1942
|
-
var
|
|
2089
|
+
var NativeSelect = react.forwardRef(
|
|
1943
2090
|
({
|
|
1944
2091
|
size = "md",
|
|
1945
2092
|
dirty,
|
|
@@ -1997,8 +2144,8 @@ var Select = react.forwardRef(
|
|
|
1997
2144
|
placeholder && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: placeholder }),
|
|
1998
2145
|
list.map(
|
|
1999
2146
|
(item, index) => isOptionGroup(item) ? /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: item.label, children: item.options.map(
|
|
2000
|
-
(opt, optIndex) =>
|
|
2001
|
-
) }, `group-${index}`) :
|
|
2147
|
+
(opt, optIndex) => renderNativeOption(opt, optIndex)
|
|
2148
|
+
) }, `group-${index}`) : renderNativeOption(item, index)
|
|
2002
2149
|
)
|
|
2003
2150
|
]
|
|
2004
2151
|
}
|
|
@@ -2022,6 +2169,270 @@ var Select = react.forwardRef(
|
|
|
2022
2169
|
return select;
|
|
2023
2170
|
}
|
|
2024
2171
|
);
|
|
2172
|
+
NativeSelect.displayName = "NativeSelect";
|
|
2173
|
+
var ListboxSelect = react.forwardRef(
|
|
2174
|
+
({
|
|
2175
|
+
size = "md",
|
|
2176
|
+
dirty,
|
|
2177
|
+
error,
|
|
2178
|
+
label,
|
|
2179
|
+
description,
|
|
2180
|
+
required,
|
|
2181
|
+
disabled,
|
|
2182
|
+
className,
|
|
2183
|
+
id,
|
|
2184
|
+
list,
|
|
2185
|
+
placeholder = "Select...",
|
|
2186
|
+
multiple = false,
|
|
2187
|
+
values: controlledValues,
|
|
2188
|
+
defaultValues,
|
|
2189
|
+
onValueChange,
|
|
2190
|
+
onValuesChange,
|
|
2191
|
+
searchable = false,
|
|
2192
|
+
selectedSuffix = "selected",
|
|
2193
|
+
indicator = "check",
|
|
2194
|
+
value: controlledSingleValue,
|
|
2195
|
+
defaultValue: defaultSingleValue
|
|
2196
|
+
}, _ref) => {
|
|
2197
|
+
const autoId = react.useId();
|
|
2198
|
+
const selectId = id ?? autoId;
|
|
2199
|
+
const [open, setOpen] = react.useState(false);
|
|
2200
|
+
const [search2, setSearch] = react.useState("");
|
|
2201
|
+
const [activeIndex, setActiveIndex] = react.useState(-1);
|
|
2202
|
+
const [singleValue, setSingleValue] = react.useState(
|
|
2203
|
+
controlledSingleValue ?? defaultSingleValue ?? ""
|
|
2204
|
+
);
|
|
2205
|
+
const currentSingle = controlledSingleValue ?? singleValue;
|
|
2206
|
+
const [multiValues, setMultiValues] = react.useState(
|
|
2207
|
+
controlledValues ?? defaultValues ?? []
|
|
2208
|
+
);
|
|
2209
|
+
const currentMulti = controlledValues ?? multiValues;
|
|
2210
|
+
react.useEffect(() => {
|
|
2211
|
+
if (controlledValues) setMultiValues(controlledValues);
|
|
2212
|
+
}, [controlledValues]);
|
|
2213
|
+
react.useEffect(() => {
|
|
2214
|
+
if (controlledSingleValue !== void 0) setSingleValue(controlledSingleValue);
|
|
2215
|
+
}, [controlledSingleValue]);
|
|
2216
|
+
const anchorRef = react.useRef(null);
|
|
2217
|
+
const listRef = react.useRef(null);
|
|
2218
|
+
const wrapperRef = react.useRef(null);
|
|
2219
|
+
const searchRef = react.useRef(null);
|
|
2220
|
+
const position = useFloatingPosition(anchorRef, listRef, {
|
|
2221
|
+
placement: "bottom-start",
|
|
2222
|
+
offset: 4,
|
|
2223
|
+
enabled: open
|
|
2224
|
+
});
|
|
2225
|
+
const close = react.useCallback(() => {
|
|
2226
|
+
setOpen(false);
|
|
2227
|
+
setSearch("");
|
|
2228
|
+
setActiveIndex(-1);
|
|
2229
|
+
}, []);
|
|
2230
|
+
useOutsideClick(wrapperRef, close, open);
|
|
2231
|
+
useEscapeKey(close, open);
|
|
2232
|
+
react.useEffect(() => {
|
|
2233
|
+
if (open && searchable) {
|
|
2234
|
+
requestAnimationFrame(() => searchRef.current?.focus());
|
|
2235
|
+
}
|
|
2236
|
+
}, [open, searchable]);
|
|
2237
|
+
const allOptions = flattenOptions(list);
|
|
2238
|
+
const resolvedOptions = allOptions.map(resolveOption);
|
|
2239
|
+
const filtered = search2 ? resolvedOptions.filter(
|
|
2240
|
+
(o) => o.label.toLowerCase().includes(search2.toLowerCase())
|
|
2241
|
+
) : resolvedOptions;
|
|
2242
|
+
const isSelected = (value) => {
|
|
2243
|
+
if (multiple) return currentMulti.includes(value);
|
|
2244
|
+
return currentSingle === value;
|
|
2245
|
+
};
|
|
2246
|
+
const toggleOption = react.useCallback(
|
|
2247
|
+
(value) => {
|
|
2248
|
+
if (multiple) {
|
|
2249
|
+
const next = currentMulti.includes(value) ? currentMulti.filter((v) => v !== value) : [...currentMulti, value];
|
|
2250
|
+
setMultiValues(next);
|
|
2251
|
+
onValuesChange?.(next);
|
|
2252
|
+
} else {
|
|
2253
|
+
setSingleValue(value);
|
|
2254
|
+
onValueChange?.(value);
|
|
2255
|
+
close();
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
[multiple, currentMulti, onValuesChange, onValueChange, close]
|
|
2259
|
+
);
|
|
2260
|
+
const getDisplayText = () => {
|
|
2261
|
+
if (multiple) {
|
|
2262
|
+
if (currentMulti.length === 0) return placeholder;
|
|
2263
|
+
if (currentMulti.length === 1) {
|
|
2264
|
+
const opt2 = resolvedOptions.find((o) => o.value === currentMulti[0]);
|
|
2265
|
+
return opt2?.label ?? currentMulti[0];
|
|
2266
|
+
}
|
|
2267
|
+
return `${currentMulti.length} ${selectedSuffix}`;
|
|
2268
|
+
}
|
|
2269
|
+
if (!currentSingle) return placeholder;
|
|
2270
|
+
const opt = resolvedOptions.find((o) => o.value === currentSingle);
|
|
2271
|
+
return opt?.label ?? currentSingle;
|
|
2272
|
+
};
|
|
2273
|
+
const hasValue = multiple ? currentMulti.length > 0 : !!currentSingle;
|
|
2274
|
+
const handleKeyDown = (e) => {
|
|
2275
|
+
if (!open) {
|
|
2276
|
+
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
|
|
2277
|
+
e.preventDefault();
|
|
2278
|
+
setOpen(true);
|
|
2279
|
+
}
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
if (e.key === "ArrowDown") {
|
|
2283
|
+
e.preventDefault();
|
|
2284
|
+
setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
|
|
2285
|
+
} else if (e.key === "ArrowUp") {
|
|
2286
|
+
e.preventDefault();
|
|
2287
|
+
setActiveIndex((i) => Math.max(i - 1, 0));
|
|
2288
|
+
} else if (e.key === "Enter" && activeIndex >= 0) {
|
|
2289
|
+
e.preventDefault();
|
|
2290
|
+
const item = filtered[activeIndex];
|
|
2291
|
+
if (item && !item.disabled) toggleOption(item.value);
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
const trigger = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2295
|
+
"button",
|
|
2296
|
+
{
|
|
2297
|
+
ref: anchorRef,
|
|
2298
|
+
type: "button",
|
|
2299
|
+
id: selectId,
|
|
2300
|
+
disabled,
|
|
2301
|
+
onClick: () => setOpen((o) => !o),
|
|
2302
|
+
onKeyDown: handleKeyDown,
|
|
2303
|
+
role: "combobox",
|
|
2304
|
+
"aria-expanded": open,
|
|
2305
|
+
"aria-haspopup": "listbox",
|
|
2306
|
+
"data-react-fancy-select": "",
|
|
2307
|
+
"data-variant": "listbox",
|
|
2308
|
+
className: cn(
|
|
2309
|
+
inputBaseClasses,
|
|
2310
|
+
inputSizeClasses[size],
|
|
2311
|
+
dirtyClasses(dirty),
|
|
2312
|
+
errorClasses(error),
|
|
2313
|
+
"flex w-full cursor-pointer items-center justify-between gap-2 text-left",
|
|
2314
|
+
!hasValue && "text-zinc-400 dark:text-zinc-500",
|
|
2315
|
+
className
|
|
2316
|
+
),
|
|
2317
|
+
children: [
|
|
2318
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: getDisplayText() }),
|
|
2319
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2320
|
+
"svg",
|
|
2321
|
+
{
|
|
2322
|
+
className: cn("h-4 w-4 shrink-0 text-zinc-400 transition-transform", open && "rotate-180"),
|
|
2323
|
+
viewBox: "0 0 20 20",
|
|
2324
|
+
fill: "currentColor",
|
|
2325
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2326
|
+
"path",
|
|
2327
|
+
{
|
|
2328
|
+
fillRule: "evenodd",
|
|
2329
|
+
d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
|
|
2330
|
+
clipRule: "evenodd"
|
|
2331
|
+
}
|
|
2332
|
+
)
|
|
2333
|
+
}
|
|
2334
|
+
)
|
|
2335
|
+
]
|
|
2336
|
+
}
|
|
2337
|
+
);
|
|
2338
|
+
const dropdown = open && /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2339
|
+
"div",
|
|
2340
|
+
{
|
|
2341
|
+
ref: listRef,
|
|
2342
|
+
role: "listbox",
|
|
2343
|
+
"aria-multiselectable": multiple || void 0,
|
|
2344
|
+
className: "fixed z-50 max-h-60 min-w-[8rem] overflow-y-auto rounded-xl border border-zinc-200 bg-white p-1 shadow-lg dark:border-zinc-700 dark:bg-zinc-900 dark:shadow-zinc-950/50 fancy-scale-in",
|
|
2345
|
+
style: {
|
|
2346
|
+
left: position.x,
|
|
2347
|
+
top: position.y,
|
|
2348
|
+
width: anchorRef.current?.offsetWidth
|
|
2349
|
+
},
|
|
2350
|
+
children: [
|
|
2351
|
+
searchable && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 pb-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2352
|
+
"input",
|
|
2353
|
+
{
|
|
2354
|
+
ref: searchRef,
|
|
2355
|
+
type: "text",
|
|
2356
|
+
value: search2,
|
|
2357
|
+
onChange: (e) => {
|
|
2358
|
+
setSearch(e.target.value);
|
|
2359
|
+
setActiveIndex(-1);
|
|
2360
|
+
},
|
|
2361
|
+
onKeyDown: handleKeyDown,
|
|
2362
|
+
placeholder: "Search...",
|
|
2363
|
+
className: "w-full rounded-md border-0 bg-zinc-100 px-2.5 py-1.5 text-sm text-zinc-900 placeholder:text-zinc-400 outline-none dark:bg-zinc-800 dark:text-zinc-100 dark:placeholder:text-zinc-500"
|
|
2364
|
+
}
|
|
2365
|
+
) }),
|
|
2366
|
+
filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-zinc-400", children: "No results found" }) : filtered.map((option, i) => {
|
|
2367
|
+
const selected = isSelected(option.value);
|
|
2368
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2369
|
+
"button",
|
|
2370
|
+
{
|
|
2371
|
+
type: "button",
|
|
2372
|
+
role: "option",
|
|
2373
|
+
"aria-selected": selected,
|
|
2374
|
+
disabled: option.disabled,
|
|
2375
|
+
onClick: () => toggleOption(option.value),
|
|
2376
|
+
className: cn(
|
|
2377
|
+
"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm transition-colors",
|
|
2378
|
+
i === activeIndex ? "bg-zinc-100 dark:bg-zinc-800" : "hover:bg-zinc-50 dark:hover:bg-zinc-800/50",
|
|
2379
|
+
selected ? "text-zinc-900 dark:text-zinc-100" : "text-zinc-700 dark:text-zinc-300",
|
|
2380
|
+
option.disabled && "cursor-not-allowed opacity-50"
|
|
2381
|
+
),
|
|
2382
|
+
children: [
|
|
2383
|
+
indicator === "checkbox" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2384
|
+
"span",
|
|
2385
|
+
{
|
|
2386
|
+
className: cn(
|
|
2387
|
+
"flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
|
|
2388
|
+
selected ? "border-blue-500 bg-blue-500 text-white dark:border-blue-400 dark:bg-blue-400" : "border-zinc-300 dark:border-zinc-600"
|
|
2389
|
+
),
|
|
2390
|
+
children: selected && /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "h-3 w-3", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "2.5 6 5 8.5 9.5 3.5" }) })
|
|
2391
|
+
}
|
|
2392
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: selected && /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "h-4 w-4 text-blue-500 dark:text-blue-400", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z", clipRule: "evenodd" }) }) }),
|
|
2393
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
2394
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate", children: option.label }),
|
|
2395
|
+
option.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-xs text-zinc-400 dark:text-zinc-500", children: option.description })
|
|
2396
|
+
] })
|
|
2397
|
+
]
|
|
2398
|
+
},
|
|
2399
|
+
option.value
|
|
2400
|
+
);
|
|
2401
|
+
})
|
|
2402
|
+
]
|
|
2403
|
+
}
|
|
2404
|
+
) });
|
|
2405
|
+
const content = /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapperRef, className: "relative", children: [
|
|
2406
|
+
trigger,
|
|
2407
|
+
dropdown
|
|
2408
|
+
] });
|
|
2409
|
+
if (label || error || description) {
|
|
2410
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2411
|
+
Field,
|
|
2412
|
+
{
|
|
2413
|
+
label,
|
|
2414
|
+
description,
|
|
2415
|
+
error,
|
|
2416
|
+
required,
|
|
2417
|
+
htmlFor: selectId,
|
|
2418
|
+
size,
|
|
2419
|
+
children: content
|
|
2420
|
+
}
|
|
2421
|
+
);
|
|
2422
|
+
}
|
|
2423
|
+
return content;
|
|
2424
|
+
}
|
|
2425
|
+
);
|
|
2426
|
+
ListboxSelect.displayName = "ListboxSelect";
|
|
2427
|
+
var Select = react.forwardRef(
|
|
2428
|
+
(props, ref) => {
|
|
2429
|
+
const variant = props.variant ?? (props.multiple ? "listbox" : "native");
|
|
2430
|
+
if (variant === "listbox") {
|
|
2431
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ListboxSelect, { ...props, ref });
|
|
2432
|
+
}
|
|
2433
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NativeSelect, { ...props, ref });
|
|
2434
|
+
}
|
|
2435
|
+
);
|
|
2025
2436
|
Select.displayName = "Select";
|
|
2026
2437
|
function useControllableState(controlledValue, defaultValue, onChange) {
|
|
2027
2438
|
const [uncontrolledValue, setUncontrolledValue] = react.useState(defaultValue);
|
|
@@ -3690,34 +4101,6 @@ var Table = Object.assign(TableRoot, {
|
|
|
3690
4101
|
Tray: TableTray,
|
|
3691
4102
|
RowTray: TableRowTray
|
|
3692
4103
|
});
|
|
3693
|
-
function Portal({ children, container }) {
|
|
3694
|
-
if (typeof document === "undefined") return null;
|
|
3695
|
-
const target = container ?? document.body;
|
|
3696
|
-
return reactDom.createPortal(
|
|
3697
|
-
/* @__PURE__ */ jsxRuntime.jsx(PortalDarkWrapper, { children }),
|
|
3698
|
-
target
|
|
3699
|
-
);
|
|
3700
|
-
}
|
|
3701
|
-
function PortalDarkWrapper({ children }) {
|
|
3702
|
-
const ref = react.useRef(null);
|
|
3703
|
-
react.useEffect(() => {
|
|
3704
|
-
const root = document.documentElement;
|
|
3705
|
-
const wrapper = ref.current;
|
|
3706
|
-
if (!wrapper) return;
|
|
3707
|
-
const sync = () => {
|
|
3708
|
-
const isDark = root.classList.contains("dark") || root.getAttribute("data-theme") === "dark";
|
|
3709
|
-
wrapper.classList.toggle("dark", isDark);
|
|
3710
|
-
};
|
|
3711
|
-
sync();
|
|
3712
|
-
const observer = new MutationObserver(sync);
|
|
3713
|
-
observer.observe(root, {
|
|
3714
|
-
attributes: true,
|
|
3715
|
-
attributeFilter: ["class", "data-theme"]
|
|
3716
|
-
});
|
|
3717
|
-
return () => observer.disconnect();
|
|
3718
|
-
}, []);
|
|
3719
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, "data-react-fancy-portal": "", style: { display: "contents" }, children });
|
|
3720
|
-
}
|
|
3721
4104
|
var sizeClasses3 = {
|
|
3722
4105
|
xs: "text-xs",
|
|
3723
4106
|
sm: "text-sm",
|
|
@@ -4759,85 +5142,6 @@ var Timeline = Object.assign(TimelineRoot, {
|
|
|
4759
5142
|
Item: TimelineItem,
|
|
4760
5143
|
Block: TimelineBlock
|
|
4761
5144
|
});
|
|
4762
|
-
function getPosition(anchor, floating, placement, offset) {
|
|
4763
|
-
let x = 0;
|
|
4764
|
-
let y = 0;
|
|
4765
|
-
const base = placement.split("-")[0];
|
|
4766
|
-
const align = placement.split("-")[1];
|
|
4767
|
-
switch (base) {
|
|
4768
|
-
case "top":
|
|
4769
|
-
x = anchor.left + anchor.width / 2 - floating.width / 2;
|
|
4770
|
-
y = anchor.top - floating.height - offset;
|
|
4771
|
-
break;
|
|
4772
|
-
case "bottom":
|
|
4773
|
-
x = anchor.left + anchor.width / 2 - floating.width / 2;
|
|
4774
|
-
y = anchor.bottom + offset;
|
|
4775
|
-
break;
|
|
4776
|
-
case "left":
|
|
4777
|
-
x = anchor.left - floating.width - offset;
|
|
4778
|
-
y = anchor.top + anchor.height / 2 - floating.height / 2;
|
|
4779
|
-
break;
|
|
4780
|
-
case "right":
|
|
4781
|
-
x = anchor.right + offset;
|
|
4782
|
-
y = anchor.top + anchor.height / 2 - floating.height / 2;
|
|
4783
|
-
break;
|
|
4784
|
-
}
|
|
4785
|
-
if (base === "top" || base === "bottom") {
|
|
4786
|
-
if (align === "start") x = anchor.left;
|
|
4787
|
-
else if (align === "end") x = anchor.right - floating.width;
|
|
4788
|
-
}
|
|
4789
|
-
if (base === "left" || base === "right") {
|
|
4790
|
-
if (align === "start") y = anchor.top;
|
|
4791
|
-
else if (align === "end") y = anchor.bottom - floating.height;
|
|
4792
|
-
}
|
|
4793
|
-
let finalPlacement = placement;
|
|
4794
|
-
const vw = window.innerWidth;
|
|
4795
|
-
const vh = window.innerHeight;
|
|
4796
|
-
if (base === "bottom" && y + floating.height > vh) {
|
|
4797
|
-
y = anchor.top - floating.height - offset;
|
|
4798
|
-
finalPlacement = placement.replace("bottom", "top");
|
|
4799
|
-
} else if (base === "top" && y < 0) {
|
|
4800
|
-
y = anchor.bottom + offset;
|
|
4801
|
-
finalPlacement = placement.replace("top", "bottom");
|
|
4802
|
-
}
|
|
4803
|
-
x = Math.max(4, Math.min(x, vw - floating.width - 4));
|
|
4804
|
-
y = Math.max(4, Math.min(y, vh - floating.height - 4));
|
|
4805
|
-
return { x, y, placement: finalPlacement };
|
|
4806
|
-
}
|
|
4807
|
-
function useFloatingPosition(anchorRef, floatingRef, options = {}) {
|
|
4808
|
-
const { placement = "bottom", offset = 8, enabled = true } = options;
|
|
4809
|
-
const [position, setPosition] = react.useState({
|
|
4810
|
-
x: -9999,
|
|
4811
|
-
y: -9999,
|
|
4812
|
-
placement
|
|
4813
|
-
});
|
|
4814
|
-
const update = react.useCallback(() => {
|
|
4815
|
-
const anchor = anchorRef.current;
|
|
4816
|
-
const floating = floatingRef.current;
|
|
4817
|
-
if (!anchor || !floating) return;
|
|
4818
|
-
const anchorRect = anchor.getBoundingClientRect();
|
|
4819
|
-
const floatingRect = floating.getBoundingClientRect();
|
|
4820
|
-
setPosition(getPosition(anchorRect, floatingRect, placement, offset));
|
|
4821
|
-
}, [anchorRef, floatingRef, placement, offset]);
|
|
4822
|
-
react.useLayoutEffect(() => {
|
|
4823
|
-
if (!enabled) return;
|
|
4824
|
-
update();
|
|
4825
|
-
const raf = requestAnimationFrame(() => {
|
|
4826
|
-
update();
|
|
4827
|
-
});
|
|
4828
|
-
return () => cancelAnimationFrame(raf);
|
|
4829
|
-
}, [update, enabled]);
|
|
4830
|
-
react.useEffect(() => {
|
|
4831
|
-
if (!enabled) return;
|
|
4832
|
-
window.addEventListener("scroll", update, true);
|
|
4833
|
-
window.addEventListener("resize", update);
|
|
4834
|
-
return () => {
|
|
4835
|
-
window.removeEventListener("scroll", update, true);
|
|
4836
|
-
window.removeEventListener("resize", update);
|
|
4837
|
-
};
|
|
4838
|
-
}, [update, enabled]);
|
|
4839
|
-
return position;
|
|
4840
|
-
}
|
|
4841
5145
|
var Tooltip = react.forwardRef(
|
|
4842
5146
|
function Tooltip2({ children, content, placement = "top", delay = 200, offset = 8, className }, _ref) {
|
|
4843
5147
|
const [open, setOpen] = react.useState(false);
|
|
@@ -4905,78 +5209,26 @@ function usePopover() {
|
|
|
4905
5209
|
}
|
|
4906
5210
|
return ctx;
|
|
4907
5211
|
}
|
|
4908
|
-
function PopoverTrigger({ children }) {
|
|
4909
|
-
const { setOpen, open, anchorRef } = usePopover();
|
|
4910
|
-
return
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
const el = ref.current;
|
|
4923
|
-
if (!el || el.contains(event.target)) return;
|
|
4924
|
-
if (ignoreRef?.current?.contains(event.target)) return;
|
|
4925
|
-
handler(event);
|
|
4926
|
-
};
|
|
4927
|
-
document.addEventListener("mousedown", listener);
|
|
4928
|
-
document.addEventListener("touchstart", listener);
|
|
4929
|
-
return () => {
|
|
4930
|
-
document.removeEventListener("mousedown", listener);
|
|
4931
|
-
document.removeEventListener("touchstart", listener);
|
|
4932
|
-
};
|
|
4933
|
-
}, [ref, handler, enabled, ignoreRef]);
|
|
4934
|
-
}
|
|
4935
|
-
function useEscapeKey(handler, enabled = true) {
|
|
4936
|
-
react.useEffect(() => {
|
|
4937
|
-
if (!enabled) return;
|
|
4938
|
-
const listener = (event) => {
|
|
4939
|
-
if (event.key === "Escape") {
|
|
4940
|
-
handler();
|
|
4941
|
-
}
|
|
4942
|
-
};
|
|
4943
|
-
document.addEventListener("keydown", listener);
|
|
4944
|
-
return () => document.removeEventListener("keydown", listener);
|
|
4945
|
-
}, [handler, enabled]);
|
|
4946
|
-
}
|
|
4947
|
-
function useAnimation({
|
|
4948
|
-
open,
|
|
4949
|
-
enterClass,
|
|
4950
|
-
exitClass
|
|
4951
|
-
}) {
|
|
4952
|
-
const [mounted, setMounted] = react.useState(open);
|
|
4953
|
-
const [animClass, setAnimClass] = react.useState(open ? enterClass : "");
|
|
4954
|
-
const ref = react.useRef(null);
|
|
4955
|
-
react.useEffect(() => {
|
|
4956
|
-
if (open) {
|
|
4957
|
-
setMounted(true);
|
|
4958
|
-
setAnimClass(enterClass);
|
|
4959
|
-
} else if (mounted) {
|
|
4960
|
-
setAnimClass(exitClass);
|
|
4961
|
-
}
|
|
4962
|
-
}, [open, enterClass, exitClass, mounted]);
|
|
4963
|
-
const handleAnimationEnd = react.useCallback(() => {
|
|
4964
|
-
if (!open) {
|
|
4965
|
-
setMounted(false);
|
|
4966
|
-
setAnimClass("");
|
|
5212
|
+
function PopoverTrigger({ children, className }) {
|
|
5213
|
+
const { setOpen, open, anchorRef, hover, onHoverEnter, onHoverLeave } = usePopover();
|
|
5214
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5215
|
+
"span",
|
|
5216
|
+
{
|
|
5217
|
+
ref: anchorRef,
|
|
5218
|
+
"data-react-fancy-popover-trigger": "",
|
|
5219
|
+
className: cn("inline-flex", className),
|
|
5220
|
+
onClick: hover ? void 0 : () => setOpen(!open),
|
|
5221
|
+
onMouseEnter: hover ? onHoverEnter : void 0,
|
|
5222
|
+
onMouseLeave: hover ? onHoverLeave : void 0,
|
|
5223
|
+
"aria-expanded": open,
|
|
5224
|
+
"aria-haspopup": true,
|
|
5225
|
+
children
|
|
4967
5226
|
}
|
|
4968
|
-
|
|
4969
|
-
react.useEffect(() => {
|
|
4970
|
-
const el = ref.current;
|
|
4971
|
-
if (!el) return;
|
|
4972
|
-
el.addEventListener("animationend", handleAnimationEnd);
|
|
4973
|
-
return () => el.removeEventListener("animationend", handleAnimationEnd);
|
|
4974
|
-
}, [handleAnimationEnd, mounted]);
|
|
4975
|
-
return { mounted, className: animClass, ref };
|
|
5227
|
+
);
|
|
4976
5228
|
}
|
|
5229
|
+
PopoverTrigger.displayName = "PopoverTrigger";
|
|
4977
5230
|
function PopoverContent({ children, className }) {
|
|
4978
|
-
const { open, setOpen, anchorRef, placement, offset } = usePopover();
|
|
4979
|
-
const floatingRef = react.useRef(null);
|
|
5231
|
+
const { open, setOpen, anchorRef, floatingRef, placement, offset, hover, onHoverEnter, onHoverLeave } = usePopover();
|
|
4980
5232
|
const outsideRef = react.useRef(null);
|
|
4981
5233
|
const position = useFloatingPosition(anchorRef, floatingRef, {
|
|
4982
5234
|
placement,
|
|
@@ -4984,29 +5236,26 @@ function PopoverContent({ children, className }) {
|
|
|
4984
5236
|
enabled: open
|
|
4985
5237
|
});
|
|
4986
5238
|
const close = react.useCallback(() => setOpen(false), [setOpen]);
|
|
4987
|
-
useOutsideClick(outsideRef, close, open, anchorRef);
|
|
5239
|
+
useOutsideClick(outsideRef, close, open && !hover, anchorRef);
|
|
4988
5240
|
useEscapeKey(close, open);
|
|
4989
|
-
const
|
|
4990
|
-
|
|
4991
|
-
enterClass: "fancy-scale-in",
|
|
4992
|
-
exitClass: "fancy-fade-out"
|
|
4993
|
-
});
|
|
4994
|
-
if (!mounted) return null;
|
|
5241
|
+
const positioned = position.x !== -9999 && position.y !== -9999;
|
|
5242
|
+
if (!open) return null;
|
|
4995
5243
|
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4996
5244
|
"div",
|
|
4997
5245
|
{
|
|
4998
5246
|
ref: (node) => {
|
|
4999
5247
|
outsideRef.current = node;
|
|
5000
5248
|
floatingRef.current = node;
|
|
5001
|
-
animRef.current = node;
|
|
5002
5249
|
},
|
|
5003
5250
|
"data-react-fancy-popover": "",
|
|
5004
5251
|
className: cn(
|
|
5005
5252
|
"fixed z-50 rounded-xl border border-zinc-200 bg-white p-4 text-zinc-700 shadow-lg dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-200 dark:shadow-zinc-950/50",
|
|
5006
|
-
|
|
5253
|
+
positioned ? "fancy-scale-in" : "invisible",
|
|
5007
5254
|
className
|
|
5008
5255
|
),
|
|
5009
5256
|
style: { left: position.x, top: position.y },
|
|
5257
|
+
onMouseEnter: hover ? onHoverEnter : void 0,
|
|
5258
|
+
onMouseLeave: hover ? onHoverLeave : void 0,
|
|
5010
5259
|
children
|
|
5011
5260
|
}
|
|
5012
5261
|
) });
|
|
@@ -5018,17 +5267,37 @@ function PopoverRoot({
|
|
|
5018
5267
|
defaultOpen = false,
|
|
5019
5268
|
onOpenChange,
|
|
5020
5269
|
placement = "bottom",
|
|
5021
|
-
offset = 8
|
|
5270
|
+
offset = 8,
|
|
5271
|
+
hover = false,
|
|
5272
|
+
hoverDelay = 200,
|
|
5273
|
+
hoverCloseDelay = 300
|
|
5022
5274
|
}) {
|
|
5023
|
-
const [
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
onOpenChange
|
|
5027
|
-
);
|
|
5275
|
+
const [internalOpen, setInternalOpen] = react.useState(defaultOpen);
|
|
5276
|
+
const isControlled = controlledOpen !== void 0;
|
|
5277
|
+
const open = isControlled ? controlledOpen : internalOpen;
|
|
5028
5278
|
const anchorRef = react.useRef(null);
|
|
5279
|
+
const floatingRef = react.useRef(null);
|
|
5280
|
+
const hoverTimeoutRef = react.useRef(void 0);
|
|
5281
|
+
const setOpen = react.useCallback(
|
|
5282
|
+
(next) => {
|
|
5283
|
+
if (!isControlled) setInternalOpen(next);
|
|
5284
|
+
onOpenChange?.(next);
|
|
5285
|
+
},
|
|
5286
|
+
[isControlled, onOpenChange]
|
|
5287
|
+
);
|
|
5288
|
+
const onHoverEnter = react.useCallback(() => {
|
|
5289
|
+
if (!hover) return;
|
|
5290
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
5291
|
+
hoverTimeoutRef.current = setTimeout(() => setOpen(true), hoverDelay);
|
|
5292
|
+
}, [hover, hoverDelay, setOpen]);
|
|
5293
|
+
const onHoverLeave = react.useCallback(() => {
|
|
5294
|
+
if (!hover) return;
|
|
5295
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
5296
|
+
hoverTimeoutRef.current = setTimeout(() => setOpen(false), hoverCloseDelay);
|
|
5297
|
+
}, [hover, hoverCloseDelay, setOpen]);
|
|
5029
5298
|
const ctx = react.useMemo(
|
|
5030
|
-
() => ({ open, setOpen, anchorRef, placement, offset }),
|
|
5031
|
-
[open, setOpen,
|
|
5299
|
+
() => ({ open, setOpen, anchorRef, floatingRef, placement, offset, hover, onHoverEnter, onHoverLeave }),
|
|
5300
|
+
[open, setOpen, placement, offset, hover, onHoverEnter, onHoverLeave]
|
|
5032
5301
|
);
|
|
5033
5302
|
return /* @__PURE__ */ jsxRuntime.jsx(PopoverContext.Provider, { value: ctx, children });
|
|
5034
5303
|
}
|
|
@@ -5056,6 +5325,36 @@ function DropdownTrigger({ children }) {
|
|
|
5056
5325
|
});
|
|
5057
5326
|
}
|
|
5058
5327
|
DropdownTrigger.displayName = "DropdownTrigger";
|
|
5328
|
+
function useAnimation({
|
|
5329
|
+
open,
|
|
5330
|
+
enterClass,
|
|
5331
|
+
exitClass
|
|
5332
|
+
}) {
|
|
5333
|
+
const [mounted, setMounted] = react.useState(open);
|
|
5334
|
+
const [animClass, setAnimClass] = react.useState(open ? enterClass : "");
|
|
5335
|
+
const ref = react.useRef(null);
|
|
5336
|
+
react.useEffect(() => {
|
|
5337
|
+
if (open) {
|
|
5338
|
+
setMounted(true);
|
|
5339
|
+
setAnimClass(enterClass);
|
|
5340
|
+
} else if (mounted) {
|
|
5341
|
+
setAnimClass(exitClass);
|
|
5342
|
+
}
|
|
5343
|
+
}, [open, enterClass, exitClass, mounted]);
|
|
5344
|
+
const handleAnimationEnd = react.useCallback(() => {
|
|
5345
|
+
if (!open) {
|
|
5346
|
+
setMounted(false);
|
|
5347
|
+
setAnimClass("");
|
|
5348
|
+
}
|
|
5349
|
+
}, [open]);
|
|
5350
|
+
react.useEffect(() => {
|
|
5351
|
+
const el = ref.current;
|
|
5352
|
+
if (!el) return;
|
|
5353
|
+
el.addEventListener("animationend", handleAnimationEnd);
|
|
5354
|
+
return () => el.removeEventListener("animationend", handleAnimationEnd);
|
|
5355
|
+
}, [handleAnimationEnd, mounted]);
|
|
5356
|
+
return { mounted, className: animClass, ref };
|
|
5357
|
+
}
|
|
5059
5358
|
function DropdownItems({ children, className }) {
|
|
5060
5359
|
const { open, setOpen, anchorRef, activeIndex, setActiveIndex, placement, offset } = useDropdown();
|
|
5061
5360
|
const floatingRef = react.useRef(null);
|