@particle-academy/react-fancy 2.3.4 → 2.4.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/dist/index.cjs +70 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +71 -15
- package/dist/index.js.map +1 -1
- package/docs/Select.md +31 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3292,10 +3292,14 @@ var NativeSelect = react.forwardRef(
|
|
|
3292
3292
|
suffixPosition,
|
|
3293
3293
|
onValueChange,
|
|
3294
3294
|
onChange,
|
|
3295
|
+
value,
|
|
3296
|
+
defaultValue,
|
|
3295
3297
|
...props
|
|
3296
3298
|
}, ref) => {
|
|
3297
3299
|
const autoId = react.useId();
|
|
3298
3300
|
const selectId = id ?? autoId;
|
|
3301
|
+
const isControlled = value !== void 0;
|
|
3302
|
+
const resolvedDefault = !isControlled && defaultValue === void 0 && placeholder ? "" : defaultValue;
|
|
3299
3303
|
const select = /* @__PURE__ */ jsxRuntime.jsx(
|
|
3300
3304
|
InputWrapper,
|
|
3301
3305
|
{
|
|
@@ -3327,6 +3331,7 @@ var NativeSelect = react.forwardRef(
|
|
|
3327
3331
|
onValueChange?.(e.target.value);
|
|
3328
3332
|
},
|
|
3329
3333
|
...props,
|
|
3334
|
+
...isControlled ? { value } : { defaultValue: resolvedDefault },
|
|
3330
3335
|
children: [
|
|
3331
3336
|
placeholder && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: placeholder }),
|
|
3332
3337
|
list.map(
|
|
@@ -3376,6 +3381,9 @@ var ListboxSelect = react.forwardRef(
|
|
|
3376
3381
|
onValueChange,
|
|
3377
3382
|
onValuesChange,
|
|
3378
3383
|
searchable = false,
|
|
3384
|
+
creatable = false,
|
|
3385
|
+
onCreate,
|
|
3386
|
+
createLabel = "Create",
|
|
3379
3387
|
selectedSuffix = "selected",
|
|
3380
3388
|
indicator = "check",
|
|
3381
3389
|
value: controlledSingleValue,
|
|
@@ -3383,9 +3391,11 @@ var ListboxSelect = react.forwardRef(
|
|
|
3383
3391
|
}, _ref) => {
|
|
3384
3392
|
const autoId = react.useId();
|
|
3385
3393
|
const selectId = id ?? autoId;
|
|
3394
|
+
const textInputEnabled = searchable || creatable;
|
|
3386
3395
|
const [open, setOpen] = react.useState(false);
|
|
3387
3396
|
const [search2, setSearch] = react.useState("");
|
|
3388
3397
|
const [activeIndex, setActiveIndex] = react.useState(-1);
|
|
3398
|
+
const [createdOptions, setCreatedOptions] = react.useState([]);
|
|
3389
3399
|
const [singleValue, setSingleValue] = react.useState(
|
|
3390
3400
|
controlledSingleValue ?? defaultSingleValue ?? ""
|
|
3391
3401
|
);
|
|
@@ -3402,7 +3412,6 @@ var ListboxSelect = react.forwardRef(
|
|
|
3402
3412
|
}, [controlledSingleValue]);
|
|
3403
3413
|
const anchorRef = react.useRef(null);
|
|
3404
3414
|
const listRef = react.useRef(null);
|
|
3405
|
-
const wrapperRef = react.useRef(null);
|
|
3406
3415
|
const searchRef = react.useRef(null);
|
|
3407
3416
|
const position = useFloatingPosition(anchorRef, listRef, {
|
|
3408
3417
|
placement: "bottom-start",
|
|
@@ -3414,18 +3423,24 @@ var ListboxSelect = react.forwardRef(
|
|
|
3414
3423
|
setSearch("");
|
|
3415
3424
|
setActiveIndex(-1);
|
|
3416
3425
|
}, []);
|
|
3417
|
-
useOutsideClick(
|
|
3426
|
+
useOutsideClick(listRef, close, open, anchorRef);
|
|
3418
3427
|
useEscapeKey(close, open);
|
|
3419
3428
|
react.useEffect(() => {
|
|
3420
|
-
if (open &&
|
|
3429
|
+
if (open && textInputEnabled) {
|
|
3421
3430
|
requestAnimationFrame(() => searchRef.current?.focus());
|
|
3422
3431
|
}
|
|
3423
|
-
}, [open,
|
|
3424
|
-
const
|
|
3425
|
-
|
|
3432
|
+
}, [open, textInputEnabled]);
|
|
3433
|
+
const resolvedOptions = react.useMemo(() => {
|
|
3434
|
+
const base = flattenOptions(list).map(resolveOption);
|
|
3435
|
+
const created = createdOptions.map(resolveOption);
|
|
3436
|
+
return [...base, ...created];
|
|
3437
|
+
}, [list, createdOptions]);
|
|
3426
3438
|
const filtered = search2 ? resolvedOptions.filter(
|
|
3427
3439
|
(o) => o.label.toLowerCase().includes(search2.toLowerCase())
|
|
3428
3440
|
) : resolvedOptions;
|
|
3441
|
+
const canCreate = creatable && search2.trim().length > 0 && !resolvedOptions.some(
|
|
3442
|
+
(o) => o.label.toLowerCase() === search2.trim().toLowerCase() || o.value === search2.trim()
|
|
3443
|
+
);
|
|
3429
3444
|
const isSelected = (value) => {
|
|
3430
3445
|
if (multiple) return currentMulti.includes(value);
|
|
3431
3446
|
return currentSingle === value;
|
|
@@ -3444,6 +3459,25 @@ var ListboxSelect = react.forwardRef(
|
|
|
3444
3459
|
},
|
|
3445
3460
|
[multiple, currentMulti, onValuesChange, onValueChange, close]
|
|
3446
3461
|
);
|
|
3462
|
+
const handleCreate = react.useCallback(() => {
|
|
3463
|
+
const label2 = search2.trim();
|
|
3464
|
+
if (!label2) return;
|
|
3465
|
+
const value = label2;
|
|
3466
|
+
const newOption = { value, label: label2 };
|
|
3467
|
+
setCreatedOptions((prev) => [...prev, newOption]);
|
|
3468
|
+
onCreate?.(label2);
|
|
3469
|
+
setSearch("");
|
|
3470
|
+
if (multiple) {
|
|
3471
|
+
const next = [...currentMulti, value];
|
|
3472
|
+
setMultiValues(next);
|
|
3473
|
+
onValuesChange?.(next);
|
|
3474
|
+
requestAnimationFrame(() => searchRef.current?.focus());
|
|
3475
|
+
} else {
|
|
3476
|
+
setSingleValue(value);
|
|
3477
|
+
onValueChange?.(value);
|
|
3478
|
+
close();
|
|
3479
|
+
}
|
|
3480
|
+
}, [search2, multiple, currentMulti, onCreate, onValuesChange, onValueChange, close]);
|
|
3447
3481
|
const getDisplayText = () => {
|
|
3448
3482
|
if (multiple) {
|
|
3449
3483
|
if (currentMulti.length === 0) return placeholder;
|
|
@@ -3472,10 +3506,15 @@ var ListboxSelect = react.forwardRef(
|
|
|
3472
3506
|
} else if (e.key === "ArrowUp") {
|
|
3473
3507
|
e.preventDefault();
|
|
3474
3508
|
setActiveIndex((i) => Math.max(i - 1, 0));
|
|
3475
|
-
} else if (e.key === "Enter"
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3509
|
+
} else if (e.key === "Enter") {
|
|
3510
|
+
if (activeIndex >= 0) {
|
|
3511
|
+
e.preventDefault();
|
|
3512
|
+
const item = filtered[activeIndex];
|
|
3513
|
+
if (item && !item.disabled) toggleOption(item.value);
|
|
3514
|
+
} else if (canCreate) {
|
|
3515
|
+
e.preventDefault();
|
|
3516
|
+
handleCreate();
|
|
3517
|
+
}
|
|
3479
3518
|
}
|
|
3480
3519
|
};
|
|
3481
3520
|
const trigger = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3535,7 +3574,7 @@ var ListboxSelect = react.forwardRef(
|
|
|
3535
3574
|
width: anchorRef.current?.offsetWidth
|
|
3536
3575
|
},
|
|
3537
3576
|
children: [
|
|
3538
|
-
|
|
3577
|
+
textInputEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 pb-1 pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3539
3578
|
"input",
|
|
3540
3579
|
{
|
|
3541
3580
|
ref: searchRef,
|
|
@@ -3546,11 +3585,28 @@ var ListboxSelect = react.forwardRef(
|
|
|
3546
3585
|
setActiveIndex(-1);
|
|
3547
3586
|
},
|
|
3548
3587
|
onKeyDown: handleKeyDown,
|
|
3549
|
-
placeholder: "Search
|
|
3588
|
+
placeholder: creatable && !searchable ? "Type to add\u2026" : "Search\u2026",
|
|
3550
3589
|
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"
|
|
3551
3590
|
}
|
|
3552
3591
|
) }),
|
|
3553
|
-
|
|
3592
|
+
canCreate && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3593
|
+
"button",
|
|
3594
|
+
{
|
|
3595
|
+
type: "button",
|
|
3596
|
+
onClick: handleCreate,
|
|
3597
|
+
className: "flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm text-blue-600 hover:bg-blue-50 dark:text-blue-400 dark:hover:bg-blue-500/10",
|
|
3598
|
+
children: [
|
|
3599
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "h-4 w-4 shrink-0", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 3a.75.75 0 01.75.75v5.5h5.5a.75.75 0 010 1.5h-5.5v5.5a.75.75 0 01-1.5 0v-5.5h-5.5a.75.75 0 010-1.5h5.5v-5.5A.75.75 0 0110 3z", clipRule: "evenodd" }) }),
|
|
3600
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "truncate", children: [
|
|
3601
|
+
createLabel,
|
|
3602
|
+
' "',
|
|
3603
|
+
search2.trim(),
|
|
3604
|
+
'"'
|
|
3605
|
+
] })
|
|
3606
|
+
]
|
|
3607
|
+
}
|
|
3608
|
+
),
|
|
3609
|
+
filtered.length === 0 && !canCreate ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-zinc-400", children: "No results found" }) : filtered.length === 0 ? null : filtered.map((option, i) => {
|
|
3554
3610
|
const selected = isSelected(option.value);
|
|
3555
3611
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3556
3612
|
"button",
|
|
@@ -3589,7 +3645,7 @@ var ListboxSelect = react.forwardRef(
|
|
|
3589
3645
|
]
|
|
3590
3646
|
}
|
|
3591
3647
|
) });
|
|
3592
|
-
const content = /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
3648
|
+
const content = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
3593
3649
|
trigger,
|
|
3594
3650
|
dropdown
|
|
3595
3651
|
] });
|