@nextlyhq/ui 0.0.2-alpha.60 → 0.0.2-alpha.62
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 +35 -8
- package/dist/index.cjs +472 -221
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +276 -21
- package/dist/index.d.ts +276 -21
- package/dist/index.mjs +477 -221
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.scoped.css +1 -1
- package/dist/tailwind-preset.cjs.map +1 -1
- package/dist/tailwind-preset.mjs.map +1 -1
- package/dist/theme.css +132 -0
- package/package.json +6 -5
package/dist/index.mjs
CHANGED
|
@@ -998,15 +998,23 @@ var tabsListVariants = cva8(
|
|
|
998
998
|
defaultVariants: { variant: "default" }
|
|
999
999
|
}
|
|
1000
1000
|
);
|
|
1001
|
-
var TabsList = forwardRef15(({ className, variant, ...props }, ref) =>
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1001
|
+
var TabsList = forwardRef15(({ className, variant, scrollable = false, ...props }, ref) => {
|
|
1002
|
+
const list = /* @__PURE__ */ jsx20(
|
|
1003
|
+
List,
|
|
1004
|
+
{
|
|
1005
|
+
ref,
|
|
1006
|
+
"data-slot": "tabs-list",
|
|
1007
|
+
className: cn(
|
|
1008
|
+
tabsListVariants({ variant }),
|
|
1009
|
+
scrollable && "w-max min-w-full",
|
|
1010
|
+
className
|
|
1011
|
+
),
|
|
1012
|
+
...props
|
|
1013
|
+
}
|
|
1014
|
+
);
|
|
1015
|
+
if (!scrollable) return list;
|
|
1016
|
+
return /* @__PURE__ */ jsx20("div", { "data-slot": "tabs-list-scroller", className: "w-full overflow-x-auto", children: list });
|
|
1017
|
+
});
|
|
1010
1018
|
TabsList.displayName = List.displayName;
|
|
1011
1019
|
var TABS_TRIGGER_SIZES = {
|
|
1012
1020
|
default: "text-sm",
|
|
@@ -1756,7 +1764,11 @@ SheetDescription.displayName = DialogPrimitive2.Description.displayName;
|
|
|
1756
1764
|
|
|
1757
1765
|
// src/components/command.tsx
|
|
1758
1766
|
import * as DialogPrimitive3 from "@radix-ui/react-dialog";
|
|
1759
|
-
import {
|
|
1767
|
+
import {
|
|
1768
|
+
Command as CommandPrimitive,
|
|
1769
|
+
defaultFilter,
|
|
1770
|
+
useCommandState as useCommandStatePrimitive
|
|
1771
|
+
} from "cmdk";
|
|
1760
1772
|
import { Search } from "lucide-react";
|
|
1761
1773
|
import { forwardRef as forwardRef22 } from "react";
|
|
1762
1774
|
import { jsx as jsx27, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
@@ -1983,6 +1995,7 @@ var CommandShortcut = forwardRef22(
|
|
|
1983
1995
|
);
|
|
1984
1996
|
CommandShortcut.displayName = "CommandShortcut";
|
|
1985
1997
|
var commandDefaultFilter = defaultFilter;
|
|
1998
|
+
var useCommandHighlight = () => useCommandStatePrimitive((state) => state.value);
|
|
1986
1999
|
|
|
1987
2000
|
// src/components/spinner.tsx
|
|
1988
2001
|
import { cva as cva12 } from "class-variance-authority";
|
|
@@ -2257,7 +2270,7 @@ TableSkeleton.displayName = "TableSkeleton";
|
|
|
2257
2270
|
|
|
2258
2271
|
// src/components/color-picker.tsx
|
|
2259
2272
|
import { Pipette } from "lucide-react";
|
|
2260
|
-
import * as
|
|
2273
|
+
import * as React10 from "react";
|
|
2261
2274
|
|
|
2262
2275
|
// src/lib/color/convert.ts
|
|
2263
2276
|
var clamp01 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
|
|
@@ -2362,6 +2375,10 @@ function hueSliderValue(hue, max) {
|
|
|
2362
2375
|
return step > max ? max : step;
|
|
2363
2376
|
}
|
|
2364
2377
|
|
|
2378
|
+
// src/lib/isomorphic-layout-effect.ts
|
|
2379
|
+
import * as React9 from "react";
|
|
2380
|
+
var useIsomorphicLayoutEffect = typeof document === "undefined" ? React9.useEffect : React9.useLayoutEffect;
|
|
2381
|
+
|
|
2365
2382
|
// src/components/color-picker.tsx
|
|
2366
2383
|
import { Fragment as Fragment2, jsx as jsx34, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2367
2384
|
function toHsva(hex) {
|
|
@@ -2383,6 +2400,9 @@ var CHECKERBOARD = "repeating-conic-gradient(#c8c8c8 0% 25%, #ffffff 0% 50%)";
|
|
|
2383
2400
|
function eyeDropperSupported() {
|
|
2384
2401
|
return typeof window !== "undefined" && "EyeDropper" in window;
|
|
2385
2402
|
}
|
|
2403
|
+
function isNode(value) {
|
|
2404
|
+
return value !== null && typeof value.nodeType === "number";
|
|
2405
|
+
}
|
|
2386
2406
|
function ColorPicker({
|
|
2387
2407
|
color,
|
|
2388
2408
|
onColorChange,
|
|
@@ -2392,20 +2412,100 @@ function ColorPicker({
|
|
|
2392
2412
|
showAlpha = false,
|
|
2393
2413
|
className
|
|
2394
2414
|
}) {
|
|
2395
|
-
const fieldId =
|
|
2396
|
-
const
|
|
2397
|
-
const
|
|
2398
|
-
const
|
|
2415
|
+
const fieldId = React10.useId();
|
|
2416
|
+
const rootRef = React10.useRef(null);
|
|
2417
|
+
const insidePress = React10.useRef(false);
|
|
2418
|
+
const owedFinish = React10.useRef(false);
|
|
2419
|
+
const pendingTap = React10.useRef(null);
|
|
2420
|
+
const latestCommit = React10.useRef(() => void 0);
|
|
2421
|
+
const surfaceRef = React10.useRef(null);
|
|
2422
|
+
const [hsva, setHsva] = React10.useState(() => toHsva(color));
|
|
2423
|
+
const [draftHex, setDraftHex] = React10.useState(null);
|
|
2424
|
+
const draftRef = React10.useRef(null);
|
|
2399
2425
|
const rendered = toHexString(hsva, showAlpha);
|
|
2400
|
-
|
|
2426
|
+
useIsomorphicLayoutEffect(() => {
|
|
2401
2427
|
const incoming = parseHex(color);
|
|
2402
2428
|
if (incoming && toHex(incoming, showAlpha ? incoming.alpha : 1) !== rendered) {
|
|
2429
|
+
dropDraft();
|
|
2403
2430
|
setHsva((prev) => hsvaFrom(incoming, incoming.alpha, prev.h));
|
|
2404
2431
|
}
|
|
2405
2432
|
}, [color, rendered, showAlpha]);
|
|
2433
|
+
const dropDraft = () => {
|
|
2434
|
+
owedFinish.current = false;
|
|
2435
|
+
draftRef.current = null;
|
|
2436
|
+
setDraftHex(null);
|
|
2437
|
+
};
|
|
2438
|
+
const commitDraft = () => {
|
|
2439
|
+
owedFinish.current = false;
|
|
2440
|
+
const text = draftRef.current;
|
|
2441
|
+
draftRef.current = null;
|
|
2442
|
+
if (text === null) return;
|
|
2443
|
+
setDraftHex(null);
|
|
2444
|
+
const parsed = parseHex(text);
|
|
2445
|
+
if (!parsed) return;
|
|
2446
|
+
setHsva((prev) => hsvaFrom(parsed, parsed.alpha, prev.h));
|
|
2447
|
+
onColorChange(toHex(parsed, showAlpha ? parsed.alpha : 1));
|
|
2448
|
+
};
|
|
2449
|
+
useIsomorphicLayoutEffect(() => {
|
|
2450
|
+
const root = rootRef.current;
|
|
2451
|
+
if (root === null) return;
|
|
2452
|
+
latestCommit.current = commitDraft;
|
|
2453
|
+
const onPointerDown = (event) => {
|
|
2454
|
+
pendingTap.current?.();
|
|
2455
|
+
pendingTap.current = null;
|
|
2456
|
+
const path = typeof event.composedPath === "function" ? event.composedPath() : [];
|
|
2457
|
+
const inside = path.includes(root) || isNode(event.target) && root.contains(event.target);
|
|
2458
|
+
insidePress.current = true;
|
|
2459
|
+
if (inside) return;
|
|
2460
|
+
const pointerType = event.pointerType;
|
|
2461
|
+
if (pointerType === "touch") {
|
|
2462
|
+
const onClick = () => {
|
|
2463
|
+
owner.removeEventListener("click", onClick, true);
|
|
2464
|
+
pendingTap.current = null;
|
|
2465
|
+
latestCommit.current();
|
|
2466
|
+
};
|
|
2467
|
+
owner.addEventListener("click", onClick, true);
|
|
2468
|
+
pendingTap.current = () => {
|
|
2469
|
+
owner.removeEventListener("click", onClick, true);
|
|
2470
|
+
};
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
commitDraft();
|
|
2474
|
+
};
|
|
2475
|
+
const owner = root.ownerDocument;
|
|
2476
|
+
const onPointerCancel = () => {
|
|
2477
|
+
insidePress.current = false;
|
|
2478
|
+
pendingTap.current?.();
|
|
2479
|
+
pendingTap.current = null;
|
|
2480
|
+
};
|
|
2481
|
+
const onPointerUp = () => {
|
|
2482
|
+
insidePress.current = false;
|
|
2483
|
+
};
|
|
2484
|
+
const onClickResolve = () => {
|
|
2485
|
+
if (!owedFinish.current) return;
|
|
2486
|
+
latestCommit.current();
|
|
2487
|
+
};
|
|
2488
|
+
owner.addEventListener("pointerdown", onPointerDown, true);
|
|
2489
|
+
owner.addEventListener("pointercancel", onPointerCancel, true);
|
|
2490
|
+
owner.addEventListener("pointerup", onPointerUp, true);
|
|
2491
|
+
owner.addEventListener("click", onClickResolve, false);
|
|
2492
|
+
return () => {
|
|
2493
|
+
owner.removeEventListener("pointerdown", onPointerDown, true);
|
|
2494
|
+
owner.removeEventListener("pointercancel", onPointerCancel, true);
|
|
2495
|
+
owner.removeEventListener("pointerup", onPointerUp, true);
|
|
2496
|
+
owner.removeEventListener("click", onClickResolve, false);
|
|
2497
|
+
};
|
|
2498
|
+
});
|
|
2499
|
+
useIsomorphicLayoutEffect(
|
|
2500
|
+
() => () => {
|
|
2501
|
+
pendingTap.current?.();
|
|
2502
|
+
pendingTap.current = null;
|
|
2503
|
+
},
|
|
2504
|
+
[]
|
|
2505
|
+
);
|
|
2406
2506
|
const commit = (next) => {
|
|
2407
2507
|
setHsva(next);
|
|
2408
|
-
|
|
2508
|
+
dropDraft();
|
|
2409
2509
|
onColorChange(toHexString(next, showAlpha));
|
|
2410
2510
|
};
|
|
2411
2511
|
const trackPointer = (event) => {
|
|
@@ -2435,8 +2535,8 @@ function ColorPicker({
|
|
|
2435
2535
|
event.preventDefault();
|
|
2436
2536
|
nudge(move[0], move[1]);
|
|
2437
2537
|
};
|
|
2438
|
-
const [canPickFromScreen, setCanPickFromScreen] =
|
|
2439
|
-
|
|
2538
|
+
const [canPickFromScreen, setCanPickFromScreen] = React10.useState(false);
|
|
2539
|
+
React10.useEffect(() => {
|
|
2440
2540
|
setCanPickFromScreen(eyeDropperSupported());
|
|
2441
2541
|
}, []);
|
|
2442
2542
|
const handle = surfacePointFor(hsva.s, hsva.v);
|
|
@@ -2444,163 +2544,187 @@ function ColorPicker({
|
|
|
2444
2544
|
const pickFromScreen = async () => {
|
|
2445
2545
|
const ctor = window.EyeDropper;
|
|
2446
2546
|
if (!ctor) return;
|
|
2547
|
+
const owed = owedFinish.current;
|
|
2548
|
+
owedFinish.current = false;
|
|
2447
2549
|
let sampled;
|
|
2448
2550
|
try {
|
|
2449
2551
|
sampled = (await new ctor().open()).sRGBHex;
|
|
2450
2552
|
} catch {
|
|
2553
|
+
if (owed) commitDraft();
|
|
2451
2554
|
return;
|
|
2452
2555
|
}
|
|
2453
2556
|
const parsed = parseHex(sampled);
|
|
2454
2557
|
if (parsed) commit(hsvaFrom(parsed, hsva.a, hsva.h));
|
|
2455
2558
|
};
|
|
2456
|
-
return /* @__PURE__ */ jsxs13(
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
// viewer, so the reverse order lets the opaque white end of the
|
|
2469
|
-
// saturation ramp cover the black end of the value ramp: the
|
|
2470
|
-
// bottom-left corner displays white while selecting black.
|
|
2471
|
-
backgroundImage: "linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent)"
|
|
2472
|
-
},
|
|
2473
|
-
onKeyDown: handleSurfaceKey,
|
|
2474
|
-
onPointerDown: (event) => {
|
|
2475
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2476
|
-
trackPointer(event);
|
|
2477
|
-
},
|
|
2478
|
-
onPointerMove: (event) => {
|
|
2479
|
-
if (event.buttons === 1) trackPointer(event);
|
|
2480
|
-
},
|
|
2481
|
-
children: /* @__PURE__ */ jsx34(
|
|
2482
|
-
"span",
|
|
2483
|
-
{
|
|
2484
|
-
"aria-hidden": "true",
|
|
2485
|
-
className: "pointer-events-none absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm ring-1 ring-black/60",
|
|
2486
|
-
style: { left: `${handle.x * 100}%`, top: `${handle.y * 100}%` }
|
|
2487
|
-
}
|
|
2488
|
-
)
|
|
2489
|
-
}
|
|
2490
|
-
),
|
|
2491
|
-
/* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-hue`, children: "Hue" }),
|
|
2492
|
-
/* @__PURE__ */ jsx34(
|
|
2493
|
-
"input",
|
|
2494
|
-
{
|
|
2495
|
-
id: `${fieldId}-hue`,
|
|
2496
|
-
type: "range",
|
|
2497
|
-
min: 0,
|
|
2498
|
-
max: HUE_MAX,
|
|
2499
|
-
step: 1,
|
|
2500
|
-
value: hueSliderValue(hsva.h, HUE_MAX),
|
|
2501
|
-
onChange: (event) => commit({ ...hsva, h: hueAt(+event.target.value / (HUE_MAX + 1)) }),
|
|
2502
|
-
className: SLIDER,
|
|
2503
|
-
style: {
|
|
2504
|
-
backgroundImage: "linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)"
|
|
2559
|
+
return /* @__PURE__ */ jsxs13(
|
|
2560
|
+
"div",
|
|
2561
|
+
{
|
|
2562
|
+
ref: rootRef,
|
|
2563
|
+
className: cn("w-64 space-y-3", className),
|
|
2564
|
+
onBlur: (event) => {
|
|
2565
|
+
const next = event.relatedTarget;
|
|
2566
|
+
const root = rootRef.current;
|
|
2567
|
+
if (root !== null && isNode(next) && root.contains(next)) return;
|
|
2568
|
+
if (next === null && insidePress.current) {
|
|
2569
|
+
owedFinish.current = true;
|
|
2570
|
+
return;
|
|
2505
2571
|
}
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2572
|
+
commitDraft();
|
|
2573
|
+
},
|
|
2574
|
+
children: [
|
|
2575
|
+
/* @__PURE__ */ jsx34(
|
|
2576
|
+
"div",
|
|
2577
|
+
{
|
|
2578
|
+
ref: surfaceRef,
|
|
2579
|
+
role: "application",
|
|
2580
|
+
tabIndex: 0,
|
|
2581
|
+
"aria-label": `Saturation and brightness: ${Math.round(hsva.s * 100)}% saturation, ${Math.round(hsva.v * 100)}% brightness. Arrow keys adjust.`,
|
|
2582
|
+
className: "ring-offset-background focus-visible:ring-ring relative h-40 w-full cursor-crosshair touch-none rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
|
2583
|
+
style: {
|
|
2584
|
+
backgroundColor: hueOnly,
|
|
2585
|
+
// Value on TOP of saturation. CSS paints the first layer nearest the
|
|
2586
|
+
// viewer, so the reverse order lets the opaque white end of the
|
|
2587
|
+
// saturation ramp cover the black end of the value ramp: the
|
|
2588
|
+
// bottom-left corner displays white while selecting black.
|
|
2589
|
+
backgroundImage: "linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent)"
|
|
2590
|
+
},
|
|
2591
|
+
onKeyDown: handleSurfaceKey,
|
|
2592
|
+
onPointerDown: (event) => {
|
|
2593
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2594
|
+
trackPointer(event);
|
|
2595
|
+
},
|
|
2596
|
+
onPointerMove: (event) => {
|
|
2597
|
+
if (event.buttons === 1) trackPointer(event);
|
|
2598
|
+
},
|
|
2599
|
+
children: /* @__PURE__ */ jsx34(
|
|
2600
|
+
"span",
|
|
2601
|
+
{
|
|
2602
|
+
"aria-hidden": "true",
|
|
2603
|
+
className: "pointer-events-none absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm ring-1 ring-black/60",
|
|
2604
|
+
style: { left: `${handle.x * 100}%`, top: `${handle.y * 100}%` }
|
|
2605
|
+
}
|
|
2606
|
+
)
|
|
2528
2607
|
}
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
if (parsed) {
|
|
2545
|
-
setHsva(hsvaFrom(parsed, parsed.alpha, hsva.h));
|
|
2546
|
-
onColorChange(toHex(parsed, showAlpha ? parsed.alpha : 1));
|
|
2608
|
+
),
|
|
2609
|
+
/* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-hue`, children: "Hue" }),
|
|
2610
|
+
/* @__PURE__ */ jsx34(
|
|
2611
|
+
"input",
|
|
2612
|
+
{
|
|
2613
|
+
id: `${fieldId}-hue`,
|
|
2614
|
+
type: "range",
|
|
2615
|
+
min: 0,
|
|
2616
|
+
max: HUE_MAX,
|
|
2617
|
+
step: 1,
|
|
2618
|
+
value: hueSliderValue(hsva.h, HUE_MAX),
|
|
2619
|
+
onChange: (event) => commit({ ...hsva, h: hueAt(+event.target.value / (HUE_MAX + 1)) }),
|
|
2620
|
+
className: SLIDER,
|
|
2621
|
+
style: {
|
|
2622
|
+
backgroundImage: "linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)"
|
|
2547
2623
|
}
|
|
2548
|
-
},
|
|
2549
|
-
onBlur: () => setDraftHex(null)
|
|
2550
|
-
}
|
|
2551
|
-
),
|
|
2552
|
-
canPickFromScreen && /* @__PURE__ */ jsx34(
|
|
2553
|
-
Button,
|
|
2554
|
-
{
|
|
2555
|
-
type: "button",
|
|
2556
|
-
variant: "outline",
|
|
2557
|
-
size: "icon",
|
|
2558
|
-
"aria-label": "Pick a colour from the screen",
|
|
2559
|
-
onClick: () => void pickFromScreen(),
|
|
2560
|
-
children: /* @__PURE__ */ jsx34(Pipette, { className: "size-4" })
|
|
2561
|
-
}
|
|
2562
|
-
)
|
|
2563
|
-
] }),
|
|
2564
|
-
swatches.length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
|
|
2565
|
-
/* @__PURE__ */ jsx34("p", { className: "text-muted-foreground mb-1 text-xs", children: "Presets" }),
|
|
2566
|
-
/* @__PURE__ */ jsx34("div", { className: "flex flex-wrap gap-1", children: swatches.map((swatch) => /* @__PURE__ */ jsx34(
|
|
2567
|
-
"button",
|
|
2568
|
-
{
|
|
2569
|
-
type: "button",
|
|
2570
|
-
title: swatch.label,
|
|
2571
|
-
"aria-label": swatch.label,
|
|
2572
|
-
className: "size-6 rounded border shadow-sm",
|
|
2573
|
-
style: { backgroundColor: swatch.color },
|
|
2574
|
-
onClick: () => onSwatchSelect?.(swatch)
|
|
2575
|
-
},
|
|
2576
|
-
swatch.id
|
|
2577
|
-
)) })
|
|
2578
|
-
] }),
|
|
2579
|
-
recentColors.length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
|
|
2580
|
-
/* @__PURE__ */ jsx34("p", { className: "text-muted-foreground mb-1 text-xs", children: "Recent" }),
|
|
2581
|
-
/* @__PURE__ */ jsx34("div", { className: "flex flex-wrap gap-1", children: recentColors.map((recent) => /* @__PURE__ */ jsx34(
|
|
2582
|
-
"button",
|
|
2583
|
-
{
|
|
2584
|
-
type: "button",
|
|
2585
|
-
title: recent,
|
|
2586
|
-
"aria-label": recent,
|
|
2587
|
-
className: "size-6 rounded border shadow-sm",
|
|
2588
|
-
style: { backgroundColor: recent },
|
|
2589
|
-
onClick: () => {
|
|
2590
|
-
const parsed = parseHex(recent);
|
|
2591
|
-
if (parsed) commit(hsvaFrom(parsed, parsed.alpha, hsva.h));
|
|
2592
2624
|
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2625
|
+
),
|
|
2626
|
+
showAlpha && /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
2627
|
+
/* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-alpha`, children: "Opacity" }),
|
|
2628
|
+
/* @__PURE__ */ jsx34(
|
|
2629
|
+
"input",
|
|
2630
|
+
{
|
|
2631
|
+
id: `${fieldId}-alpha`,
|
|
2632
|
+
type: "range",
|
|
2633
|
+
min: 0,
|
|
2634
|
+
max: 100,
|
|
2635
|
+
step: 1,
|
|
2636
|
+
value: Math.round(hsva.a * 100),
|
|
2637
|
+
onChange: (event) => commit({ ...hsva, a: +event.target.value / 100 }),
|
|
2638
|
+
className: SLIDER,
|
|
2639
|
+
style: {
|
|
2640
|
+
// The ramp runs to the colour being edited, over a chequerboard,
|
|
2641
|
+
// so the track shows what the slider actually controls. Without
|
|
2642
|
+
// any background this rendered as a blank 12px strip whose only
|
|
2643
|
+
// label was screen-reader-only.
|
|
2644
|
+
backgroundImage: `linear-gradient(to right, transparent, ${toHexString({ ...hsva, a: 1 }, false)}), ${CHECKERBOARD}`,
|
|
2645
|
+
backgroundSize: "100% 100%, 8px 8px"
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
)
|
|
2649
|
+
] }),
|
|
2650
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
|
|
2651
|
+
/* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-hex`, children: "Hex colour" }),
|
|
2652
|
+
/* @__PURE__ */ jsx34(
|
|
2653
|
+
Input,
|
|
2654
|
+
{
|
|
2655
|
+
id: `${fieldId}-hex`,
|
|
2656
|
+
className: "font-mono",
|
|
2657
|
+
value: draftHex ?? rendered,
|
|
2658
|
+
onChange: (event) => {
|
|
2659
|
+
draftRef.current = event.target.value;
|
|
2660
|
+
setDraftHex(event.target.value);
|
|
2661
|
+
},
|
|
2662
|
+
onKeyDown: (event) => {
|
|
2663
|
+
if (event.key !== "Enter") return;
|
|
2664
|
+
if (event.nativeEvent.isComposing || event.keyCode === 229) return;
|
|
2665
|
+
event.preventDefault();
|
|
2666
|
+
commitDraft();
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
),
|
|
2670
|
+
canPickFromScreen && /* @__PURE__ */ jsx34(
|
|
2671
|
+
Button,
|
|
2672
|
+
{
|
|
2673
|
+
type: "button",
|
|
2674
|
+
variant: "outline",
|
|
2675
|
+
size: "icon",
|
|
2676
|
+
"aria-label": "Pick a colour from the screen",
|
|
2677
|
+
onClick: () => void pickFromScreen(),
|
|
2678
|
+
children: /* @__PURE__ */ jsx34(Pipette, { className: "size-4" })
|
|
2679
|
+
}
|
|
2680
|
+
)
|
|
2681
|
+
] }),
|
|
2682
|
+
swatches.length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
|
|
2683
|
+
/* @__PURE__ */ jsx34("p", { className: "text-muted-foreground mb-1 text-xs", children: "Presets" }),
|
|
2684
|
+
/* @__PURE__ */ jsx34("div", { className: "flex flex-wrap gap-1", children: swatches.map((swatch) => /* @__PURE__ */ jsx34(
|
|
2685
|
+
"button",
|
|
2686
|
+
{
|
|
2687
|
+
type: "button",
|
|
2688
|
+
title: swatch.label,
|
|
2689
|
+
"aria-label": swatch.label,
|
|
2690
|
+
className: "size-6 rounded border shadow-sm",
|
|
2691
|
+
style: { backgroundColor: swatch.color },
|
|
2692
|
+
onClick: () => {
|
|
2693
|
+
if (onSwatchSelect === void 0) return;
|
|
2694
|
+
dropDraft();
|
|
2695
|
+
onSwatchSelect(swatch);
|
|
2696
|
+
}
|
|
2697
|
+
},
|
|
2698
|
+
swatch.id
|
|
2699
|
+
)) })
|
|
2700
|
+
] }),
|
|
2701
|
+
recentColors.length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
|
|
2702
|
+
/* @__PURE__ */ jsx34("p", { className: "text-muted-foreground mb-1 text-xs", children: "Recent" }),
|
|
2703
|
+
/* @__PURE__ */ jsx34("div", { className: "flex flex-wrap gap-1", children: recentColors.map((recent) => /* @__PURE__ */ jsx34(
|
|
2704
|
+
"button",
|
|
2705
|
+
{
|
|
2706
|
+
type: "button",
|
|
2707
|
+
title: recent,
|
|
2708
|
+
"aria-label": recent,
|
|
2709
|
+
className: "size-6 rounded border shadow-sm",
|
|
2710
|
+
style: { backgroundColor: recent },
|
|
2711
|
+
onClick: () => {
|
|
2712
|
+
const parsed = parseHex(recent);
|
|
2713
|
+
if (parsed) commit(hsvaFrom(parsed, parsed.alpha, hsva.h));
|
|
2714
|
+
}
|
|
2715
|
+
},
|
|
2716
|
+
recent
|
|
2717
|
+
)) })
|
|
2718
|
+
] })
|
|
2719
|
+
]
|
|
2720
|
+
}
|
|
2721
|
+
);
|
|
2598
2722
|
}
|
|
2599
2723
|
|
|
2600
2724
|
// src/components/context-menu.tsx
|
|
2601
2725
|
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
|
|
2602
2726
|
import { Check as Check4, ChevronRight as ChevronRight2, Circle as Circle2 } from "lucide-react";
|
|
2603
|
-
import * as
|
|
2727
|
+
import * as React11 from "react";
|
|
2604
2728
|
import { jsx as jsx35, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2605
2729
|
var menuItemBase2 = "cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
|
|
2606
2730
|
var menuSurface = "z-50 max-h-[var(--radix-context-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 origin-[--radix-context-menu-content-transform-origin]";
|
|
@@ -2609,7 +2733,7 @@ var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
|
|
|
2609
2733
|
var ContextMenuGroup = ContextMenuPrimitive.Group;
|
|
2610
2734
|
var ContextMenuSub = ContextMenuPrimitive.Sub;
|
|
2611
2735
|
var ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
|
|
2612
|
-
var ContextMenuSubTrigger =
|
|
2736
|
+
var ContextMenuSubTrigger = React11.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
|
|
2613
2737
|
ContextMenuPrimitive.SubTrigger,
|
|
2614
2738
|
{
|
|
2615
2739
|
ref,
|
|
@@ -2627,7 +2751,7 @@ var ContextMenuSubTrigger = React10.forwardRef(({ className, inset, children, ..
|
|
|
2627
2751
|
}
|
|
2628
2752
|
));
|
|
2629
2753
|
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
|
|
2630
|
-
var ContextMenuSubContent =
|
|
2754
|
+
var ContextMenuSubContent = React11.forwardRef(({ className, ...props }, ref) => {
|
|
2631
2755
|
const portalContainer = usePortalContainer();
|
|
2632
2756
|
return /* @__PURE__ */ jsx35(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx35(
|
|
2633
2757
|
ContextMenuPrimitive.SubContent,
|
|
@@ -2639,7 +2763,7 @@ var ContextMenuSubContent = React10.forwardRef(({ className, ...props }, ref) =>
|
|
|
2639
2763
|
) });
|
|
2640
2764
|
});
|
|
2641
2765
|
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
|
|
2642
|
-
var ContextMenuContent =
|
|
2766
|
+
var ContextMenuContent = React11.forwardRef(({ className, ...props }, ref) => {
|
|
2643
2767
|
const portalContainer = usePortalContainer();
|
|
2644
2768
|
return /* @__PURE__ */ jsx35(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx35(
|
|
2645
2769
|
ContextMenuPrimitive.Content,
|
|
@@ -2651,7 +2775,7 @@ var ContextMenuContent = React10.forwardRef(({ className, ...props }, ref) => {
|
|
|
2651
2775
|
) });
|
|
2652
2776
|
});
|
|
2653
2777
|
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
|
|
2654
|
-
var ContextMenuItem =
|
|
2778
|
+
var ContextMenuItem = React11.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx35(
|
|
2655
2779
|
ContextMenuPrimitive.Item,
|
|
2656
2780
|
{
|
|
2657
2781
|
ref,
|
|
@@ -2665,7 +2789,7 @@ var ContextMenuItem = React10.forwardRef(({ className, inset, ...props }, ref) =
|
|
|
2665
2789
|
}
|
|
2666
2790
|
));
|
|
2667
2791
|
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
|
|
2668
|
-
var ContextMenuCheckboxItem =
|
|
2792
|
+
var ContextMenuCheckboxItem = React11.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs14(
|
|
2669
2793
|
ContextMenuPrimitive.CheckboxItem,
|
|
2670
2794
|
{
|
|
2671
2795
|
ref,
|
|
@@ -2683,7 +2807,7 @@ var ContextMenuCheckboxItem = React10.forwardRef(({ className, children, checked
|
|
|
2683
2807
|
}
|
|
2684
2808
|
));
|
|
2685
2809
|
ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
|
|
2686
|
-
var ContextMenuRadioItem =
|
|
2810
|
+
var ContextMenuRadioItem = React11.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
|
|
2687
2811
|
ContextMenuPrimitive.RadioItem,
|
|
2688
2812
|
{
|
|
2689
2813
|
ref,
|
|
@@ -2700,7 +2824,7 @@ var ContextMenuRadioItem = React10.forwardRef(({ className, children, ...props }
|
|
|
2700
2824
|
}
|
|
2701
2825
|
));
|
|
2702
2826
|
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
|
|
2703
|
-
var ContextMenuLabel =
|
|
2827
|
+
var ContextMenuLabel = React11.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx35(
|
|
2704
2828
|
ContextMenuPrimitive.Label,
|
|
2705
2829
|
{
|
|
2706
2830
|
ref,
|
|
@@ -2713,7 +2837,7 @@ var ContextMenuLabel = React10.forwardRef(({ className, inset, ...props }, ref)
|
|
|
2713
2837
|
}
|
|
2714
2838
|
));
|
|
2715
2839
|
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
|
|
2716
|
-
var ContextMenuSeparator =
|
|
2840
|
+
var ContextMenuSeparator = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx35(
|
|
2717
2841
|
ContextMenuPrimitive.Separator,
|
|
2718
2842
|
{
|
|
2719
2843
|
ref,
|
|
@@ -2786,7 +2910,7 @@ var ResizableHandle = ({
|
|
|
2786
2910
|
// src/components/tree-view.tsx
|
|
2787
2911
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
2788
2912
|
import { ChevronRight as ChevronRight3 } from "lucide-react";
|
|
2789
|
-
import * as
|
|
2913
|
+
import * as React12 from "react";
|
|
2790
2914
|
import { jsx as jsx37, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2791
2915
|
var ROW_HEIGHT = 28;
|
|
2792
2916
|
var INDENT_PER_LEVEL = 12;
|
|
@@ -2828,19 +2952,28 @@ function flatten(nodes, expanded) {
|
|
|
2828
2952
|
return rows;
|
|
2829
2953
|
}
|
|
2830
2954
|
function useControllable(controlled, fallback) {
|
|
2831
|
-
const [uncontrolled, setUncontrolled] =
|
|
2955
|
+
const [uncontrolled, setUncontrolled] = React12.useState(fallback);
|
|
2832
2956
|
return [
|
|
2833
2957
|
controlled === void 0 ? uncontrolled : controlled,
|
|
2834
2958
|
setUncontrolled
|
|
2835
2959
|
];
|
|
2836
2960
|
}
|
|
2837
|
-
|
|
2961
|
+
function treeSelectionMode(modifiers) {
|
|
2962
|
+
if (modifiers.shiftKey) return "extend";
|
|
2963
|
+
if (modifiers.metaKey || modifiers.ctrlKey) return "toggle";
|
|
2964
|
+
return "replace";
|
|
2965
|
+
}
|
|
2966
|
+
function isRowSelected(id, primary, selectedIds) {
|
|
2967
|
+
return selectedIds === void 0 ? primary === id : selectedIds.includes(id);
|
|
2968
|
+
}
|
|
2969
|
+
var TreeView = React12.forwardRef(
|
|
2838
2970
|
({
|
|
2839
2971
|
nodes,
|
|
2840
2972
|
expandedIds,
|
|
2841
2973
|
defaultExpandedIds,
|
|
2842
2974
|
onExpandedChange,
|
|
2843
2975
|
selectedId,
|
|
2976
|
+
selectedIds,
|
|
2844
2977
|
defaultSelectedId,
|
|
2845
2978
|
onSelectedChange,
|
|
2846
2979
|
className,
|
|
@@ -2849,8 +2982,8 @@ var TreeView = React11.forwardRef(
|
|
|
2849
2982
|
"aria-describedby": ariaDescribedBy,
|
|
2850
2983
|
...props
|
|
2851
2984
|
}, forwardedRef) => {
|
|
2852
|
-
const scrollRef =
|
|
2853
|
-
const attachScroll =
|
|
2985
|
+
const scrollRef = React12.useRef(null);
|
|
2986
|
+
const attachScroll = React12.useCallback(
|
|
2854
2987
|
(node) => {
|
|
2855
2988
|
scrollRef.current = node;
|
|
2856
2989
|
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
@@ -2864,7 +2997,7 @@ var TreeView = React11.forwardRef(
|
|
|
2864
2997
|
expandedIds === void 0 ? void 0 : [...expandedIds],
|
|
2865
2998
|
[...defaultExpandedIds ?? []]
|
|
2866
2999
|
);
|
|
2867
|
-
const expanded =
|
|
3000
|
+
const expanded = React12.useMemo(
|
|
2868
3001
|
() => new Set(expandedIds ?? expandedState),
|
|
2869
3002
|
[expandedIds, expandedState]
|
|
2870
3003
|
);
|
|
@@ -2872,11 +3005,11 @@ var TreeView = React11.forwardRef(
|
|
|
2872
3005
|
selectedId === void 0 ? void 0 : selectedId,
|
|
2873
3006
|
defaultSelectedId ?? null
|
|
2874
3007
|
);
|
|
2875
|
-
const rows =
|
|
3008
|
+
const rows = React12.useMemo(
|
|
2876
3009
|
() => flatten(nodes, expanded),
|
|
2877
3010
|
[nodes, expanded]
|
|
2878
3011
|
);
|
|
2879
|
-
const [activeId, setActiveId] =
|
|
3012
|
+
const [activeId, setActiveId] = React12.useState(null);
|
|
2880
3013
|
const activeIndex = Math.max(
|
|
2881
3014
|
0,
|
|
2882
3015
|
rows.findIndex((row) => row.node.id === (activeId ?? selected))
|
|
@@ -2898,9 +3031,9 @@ var TreeView = React11.forwardRef(
|
|
|
2898
3031
|
else next.delete(id);
|
|
2899
3032
|
commitExpanded(next);
|
|
2900
3033
|
};
|
|
2901
|
-
const choose = (id) => {
|
|
3034
|
+
const choose = (id, mode = "replace") => {
|
|
2902
3035
|
if (selectedId === void 0) setSelected(id);
|
|
2903
|
-
onSelectedChange?.(id);
|
|
3036
|
+
onSelectedChange?.(id, mode);
|
|
2904
3037
|
};
|
|
2905
3038
|
const focusRow = (index) => {
|
|
2906
3039
|
const row = rows[index];
|
|
@@ -2920,11 +3053,12 @@ var TreeView = React11.forwardRef(
|
|
|
2920
3053
|
}
|
|
2921
3054
|
return from;
|
|
2922
3055
|
};
|
|
2923
|
-
const typeahead =
|
|
3056
|
+
const typeahead = React12.useRef({ query: "", at: 0 });
|
|
2924
3057
|
const onKeyDown = (event) => {
|
|
2925
3058
|
const index = activeIndex;
|
|
2926
3059
|
const row = rows[index];
|
|
2927
3060
|
if (row === void 0) return;
|
|
3061
|
+
if (event.altKey) return;
|
|
2928
3062
|
switch (event.key) {
|
|
2929
3063
|
case "ArrowDown":
|
|
2930
3064
|
event.preventDefault();
|
|
@@ -2979,7 +3113,9 @@ var TreeView = React11.forwardRef(
|
|
|
2979
3113
|
case "Enter":
|
|
2980
3114
|
case " ":
|
|
2981
3115
|
event.preventDefault();
|
|
2982
|
-
if (row.node.disabled !== true)
|
|
3116
|
+
if (row.node.disabled !== true) {
|
|
3117
|
+
choose(row.node.id, treeSelectionMode(event));
|
|
3118
|
+
}
|
|
2983
3119
|
return;
|
|
2984
3120
|
case "*": {
|
|
2985
3121
|
event.preventDefault();
|
|
@@ -3027,6 +3163,7 @@ var TreeView = React11.forwardRef(
|
|
|
3027
3163
|
"div",
|
|
3028
3164
|
{
|
|
3029
3165
|
role: "tree",
|
|
3166
|
+
"aria-multiselectable": selectedIds === void 0 ? void 0 : true,
|
|
3030
3167
|
"aria-label": ariaLabel,
|
|
3031
3168
|
"aria-labelledby": ariaLabelledBy,
|
|
3032
3169
|
"aria-describedby": ariaDescribedBy,
|
|
@@ -3035,7 +3172,12 @@ var TreeView = React11.forwardRef(
|
|
|
3035
3172
|
children: virtualItems.map((item) => {
|
|
3036
3173
|
const row = rows[item.index];
|
|
3037
3174
|
if (row === void 0) return null;
|
|
3038
|
-
const isSelected =
|
|
3175
|
+
const isSelected = isRowSelected(
|
|
3176
|
+
row.node.id,
|
|
3177
|
+
selected,
|
|
3178
|
+
selectedIds
|
|
3179
|
+
);
|
|
3180
|
+
const isPrimary = selected === row.node.id;
|
|
3039
3181
|
return /* @__PURE__ */ jsxs16(
|
|
3040
3182
|
"div",
|
|
3041
3183
|
{
|
|
@@ -3049,16 +3191,21 @@ var TreeView = React11.forwardRef(
|
|
|
3049
3191
|
"aria-disabled": row.node.disabled === true ? true : void 0,
|
|
3050
3192
|
tabIndex: item.index === tabStopIndex ? 0 : -1,
|
|
3051
3193
|
onFocus: () => setActiveId(row.node.id),
|
|
3052
|
-
onClick: () => {
|
|
3194
|
+
onClick: (event) => {
|
|
3053
3195
|
if (row.node.disabled === true) return;
|
|
3054
3196
|
setActiveId(row.node.id);
|
|
3055
|
-
choose(row.node.id);
|
|
3197
|
+
choose(row.node.id, treeSelectionMode(event));
|
|
3056
3198
|
},
|
|
3057
3199
|
className: cn(
|
|
3058
3200
|
"absolute left-0 flex w-full select-none items-center gap-1 rounded-sm pr-2 text-sm outline-none",
|
|
3059
3201
|
"focus-visible:ring-1 focus-visible:ring-ring",
|
|
3060
3202
|
row.node.disabled === true ? "pointer-events-none opacity-50" : "cursor-pointer",
|
|
3061
|
-
isSelected ? "bg-muted text-foreground" : "hover:bg-muted/50"
|
|
3203
|
+
isSelected ? "bg-muted text-foreground" : "hover:bg-muted/50",
|
|
3204
|
+
// WEIGHT, not a second colour. Every row here is selected and
|
|
3205
|
+
// an action applies to all of them; what a reader needs is
|
|
3206
|
+
// which one the detail panel describes, and a second colour
|
|
3207
|
+
// would have to mean a second kind of selected.
|
|
3208
|
+
isSelected && isPrimary && "font-medium"
|
|
3062
3209
|
),
|
|
3063
3210
|
style: {
|
|
3064
3211
|
height: item.size,
|
|
@@ -3104,7 +3251,7 @@ TreeView.displayName = "TreeView";
|
|
|
3104
3251
|
|
|
3105
3252
|
// src/components/slider.tsx
|
|
3106
3253
|
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
3107
|
-
import * as
|
|
3254
|
+
import * as React13 from "react";
|
|
3108
3255
|
|
|
3109
3256
|
// src/lib/dev-warn.ts
|
|
3110
3257
|
var emitted = /* @__PURE__ */ new Set();
|
|
@@ -3130,7 +3277,7 @@ function thumbCount(value, defaultValue) {
|
|
|
3130
3277
|
function hasAccessibleName(value) {
|
|
3131
3278
|
return value !== void 0 && value.trim() !== "";
|
|
3132
3279
|
}
|
|
3133
|
-
var Slider =
|
|
3280
|
+
var Slider = React13.forwardRef(
|
|
3134
3281
|
({
|
|
3135
3282
|
className,
|
|
3136
3283
|
value,
|
|
@@ -3141,7 +3288,7 @@ var Slider = React12.forwardRef(
|
|
|
3141
3288
|
"aria-labelledby": ariaLabelledBy,
|
|
3142
3289
|
...props
|
|
3143
3290
|
}, ref) => {
|
|
3144
|
-
const initialUncontrolledCount =
|
|
3291
|
+
const initialUncontrolledCount = React13.useRef(
|
|
3145
3292
|
thumbCount(void 0, defaultValue)
|
|
3146
3293
|
).current;
|
|
3147
3294
|
const count = value?.length ?? initialUncontrolledCount;
|
|
@@ -3255,7 +3402,7 @@ var Slider = React12.forwardRef(
|
|
|
3255
3402
|
Slider.displayName = SliderPrimitive.Root.displayName;
|
|
3256
3403
|
|
|
3257
3404
|
// src/lib/shortcuts/react.tsx
|
|
3258
|
-
import * as
|
|
3405
|
+
import * as React14 from "react";
|
|
3259
3406
|
|
|
3260
3407
|
// src/lib/shortcuts/key-spec.ts
|
|
3261
3408
|
function normalizeKey(key) {
|
|
@@ -3784,9 +3931,8 @@ var FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
|
3784
3931
|
|
|
3785
3932
|
// src/lib/shortcuts/react.tsx
|
|
3786
3933
|
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
3787
|
-
var ShortcutContext =
|
|
3934
|
+
var ShortcutContext = React14.createContext(null);
|
|
3788
3935
|
var ownersByTarget = /* @__PURE__ */ new WeakMap();
|
|
3789
|
-
var useIsomorphicLayoutEffect = typeof document === "undefined" ? React13.useEffect : React13.useLayoutEffect;
|
|
3790
3936
|
function optionsFingerprint(options) {
|
|
3791
3937
|
return [
|
|
3792
3938
|
options.isApple ?? "auto",
|
|
@@ -3799,13 +3945,13 @@ function ShortcutProvider({
|
|
|
3799
3945
|
target,
|
|
3800
3946
|
...managerOptions
|
|
3801
3947
|
}) {
|
|
3802
|
-
const parent =
|
|
3948
|
+
const parent = React14.useContext(ShortcutContext);
|
|
3803
3949
|
const resolvedTarget = target === null ? null : target ?? (typeof document === "undefined" ? null : document);
|
|
3804
3950
|
const nestedOnSameTarget = parent !== null && parent.target === resolvedTarget;
|
|
3805
|
-
const optionsRef =
|
|
3806
|
-
const ownManagers =
|
|
3807
|
-
const ownDetached =
|
|
3808
|
-
const detached =
|
|
3951
|
+
const optionsRef = React14.useRef(managerOptions);
|
|
3952
|
+
const ownManagers = React14.useRef(/* @__PURE__ */ new WeakMap());
|
|
3953
|
+
const ownDetached = React14.useRef(null);
|
|
3954
|
+
const detached = React14.useMemo(() => {
|
|
3809
3955
|
if (resolvedTarget === null) {
|
|
3810
3956
|
ownDetached.current ??= createShortcutManager(optionsRef.current);
|
|
3811
3957
|
return ownDetached.current;
|
|
@@ -3861,7 +4007,7 @@ function ShortcutProvider({
|
|
|
3861
4007
|
};
|
|
3862
4008
|
}, [resolvedTarget, manager]);
|
|
3863
4009
|
const depth = nestedOnSameTarget && parent ? parent.depth : 0;
|
|
3864
|
-
const value =
|
|
4010
|
+
const value = React14.useMemo(
|
|
3865
4011
|
() => ({ manager, depth, target: resolvedTarget, options: fingerprint }),
|
|
3866
4012
|
[manager, depth, resolvedTarget, fingerprint]
|
|
3867
4013
|
);
|
|
@@ -3870,11 +4016,11 @@ function ShortcutProvider({
|
|
|
3870
4016
|
function ShortcutScope({
|
|
3871
4017
|
children
|
|
3872
4018
|
}) {
|
|
3873
|
-
const parent =
|
|
4019
|
+
const parent = React14.useContext(ShortcutContext);
|
|
3874
4020
|
if (!parent) {
|
|
3875
4021
|
throw new Error("ShortcutScope must be rendered inside a ShortcutProvider");
|
|
3876
4022
|
}
|
|
3877
|
-
const value =
|
|
4023
|
+
const value = React14.useMemo(
|
|
3878
4024
|
() => ({
|
|
3879
4025
|
manager: parent.manager,
|
|
3880
4026
|
depth: parent.depth + 1,
|
|
@@ -3888,13 +4034,13 @@ function ShortcutScope({
|
|
|
3888
4034
|
return /* @__PURE__ */ jsx39(ShortcutContext.Provider, { value, children });
|
|
3889
4035
|
}
|
|
3890
4036
|
function useShortcuts(bindings, options) {
|
|
3891
|
-
const context =
|
|
4037
|
+
const context = React14.useContext(ShortcutContext);
|
|
3892
4038
|
if (!context) {
|
|
3893
4039
|
throw new Error("useShortcuts must be called inside a ShortcutProvider");
|
|
3894
4040
|
}
|
|
3895
4041
|
const { manager, depth } = context;
|
|
3896
|
-
const registration =
|
|
3897
|
-
const latest =
|
|
4042
|
+
const registration = React14.useRef(null);
|
|
4043
|
+
const latest = React14.useRef({ bindings, options });
|
|
3898
4044
|
useIsomorphicLayoutEffect(() => {
|
|
3899
4045
|
registration.current = manager.register([], {
|
|
3900
4046
|
name: latest.current.options.name,
|
|
@@ -3917,7 +4063,7 @@ function useShortcuts(bindings, options) {
|
|
|
3917
4063
|
});
|
|
3918
4064
|
}
|
|
3919
4065
|
function useShortcutManager() {
|
|
3920
|
-
const context =
|
|
4066
|
+
const context = React14.useContext(ShortcutContext);
|
|
3921
4067
|
if (!context) {
|
|
3922
4068
|
throw new Error(
|
|
3923
4069
|
"useShortcutManager must be called inside a ShortcutProvider"
|
|
@@ -3927,7 +4073,7 @@ function useShortcutManager() {
|
|
|
3927
4073
|
}
|
|
3928
4074
|
function useActiveShortcuts() {
|
|
3929
4075
|
const manager = useShortcutManager();
|
|
3930
|
-
return
|
|
4076
|
+
return React14.useSyncExternalStore(
|
|
3931
4077
|
manager.subscribe,
|
|
3932
4078
|
manager.activeBindings,
|
|
3933
4079
|
manager.activeBindings
|
|
@@ -4054,29 +4200,12 @@ function FormSection({
|
|
|
4054
4200
|
),
|
|
4055
4201
|
description ? /* @__PURE__ */ jsx41("p", { className: "text-sm text-muted-foreground", children: description }) : null
|
|
4056
4202
|
] }),
|
|
4057
|
-
/* @__PURE__ */ jsx41(Card, { className: "overflow-hidden", children: /* @__PURE__ */ jsx41("div", { className: "divide-y divide-foreground/10 px-6", children }) })
|
|
4203
|
+
/* @__PURE__ */ jsx41(Card, { className: "overflow-hidden", children: /* @__PURE__ */ jsx41("div", { className: "nx-form-section-rows divide-y divide-foreground/10 px-6", children }) })
|
|
4058
4204
|
] });
|
|
4059
4205
|
}
|
|
4060
4206
|
|
|
4061
|
-
// src/components/form-
|
|
4062
|
-
import { cva as cva14 } from "class-variance-authority";
|
|
4207
|
+
// src/components/form-actions.tsx
|
|
4063
4208
|
import { jsx as jsx42, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4064
|
-
var measure = cva14("mx-auto w-full px-6 py-8", {
|
|
4065
|
-
variants: {
|
|
4066
|
-
width: {
|
|
4067
|
-
form: "max-w-[56rem]",
|
|
4068
|
-
wide: "max-w-[72rem]"
|
|
4069
|
-
}
|
|
4070
|
-
},
|
|
4071
|
-
defaultVariants: { width: "form" }
|
|
4072
|
-
});
|
|
4073
|
-
function FormLayout({
|
|
4074
|
-
width = "form",
|
|
4075
|
-
className,
|
|
4076
|
-
children
|
|
4077
|
-
}) {
|
|
4078
|
-
return /* @__PURE__ */ jsx42("div", { className: cn(measure({ width }), className), children });
|
|
4079
|
-
}
|
|
4080
4209
|
function FormActions({ dirty, className, children }) {
|
|
4081
4210
|
return /* @__PURE__ */ jsxs20(
|
|
4082
4211
|
"div",
|
|
@@ -4099,6 +4228,127 @@ function FormActions({ dirty, className, children }) {
|
|
|
4099
4228
|
}
|
|
4100
4229
|
);
|
|
4101
4230
|
}
|
|
4231
|
+
|
|
4232
|
+
// src/components/page-shell.tsx
|
|
4233
|
+
import {
|
|
4234
|
+
createContext as createContext5,
|
|
4235
|
+
forwardRef as forwardRef28,
|
|
4236
|
+
useCallback as useCallback2,
|
|
4237
|
+
useContext as useContext5,
|
|
4238
|
+
useEffect as useEffect4,
|
|
4239
|
+
useRef as useRef5
|
|
4240
|
+
} from "react";
|
|
4241
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
4242
|
+
function hasBareTextChild(shell) {
|
|
4243
|
+
return Array.from(shell.childNodes).some(
|
|
4244
|
+
(node) => node.nodeType === Node.TEXT_NODE && node.textContent?.trim() !== ""
|
|
4245
|
+
);
|
|
4246
|
+
}
|
|
4247
|
+
var InsideShell = createContext5(false);
|
|
4248
|
+
function hasDisplayContentsChild(shell) {
|
|
4249
|
+
return Array.from(shell.children).some(
|
|
4250
|
+
(child) => getComputedStyle(child).display === "contents"
|
|
4251
|
+
);
|
|
4252
|
+
}
|
|
4253
|
+
var SHELL_MEASURE = {
|
|
4254
|
+
form: "var(--nx-measure-form)",
|
|
4255
|
+
wide: "var(--nx-measure-wide)",
|
|
4256
|
+
full: "100%"
|
|
4257
|
+
};
|
|
4258
|
+
var PageShell = forwardRef28(
|
|
4259
|
+
({ width = "form", className, children, style, ...props }, ref) => {
|
|
4260
|
+
const shellRef = useRef5(null);
|
|
4261
|
+
const attachRef = useCallback2(
|
|
4262
|
+
(node) => {
|
|
4263
|
+
shellRef.current = node;
|
|
4264
|
+
if (typeof ref === "function") return ref(node);
|
|
4265
|
+
if (ref) ref.current = node;
|
|
4266
|
+
},
|
|
4267
|
+
[ref]
|
|
4268
|
+
);
|
|
4269
|
+
const nested = useContext5(InsideShell);
|
|
4270
|
+
useEffect4(() => {
|
|
4271
|
+
if (!isDevelopmentRuntime()) return;
|
|
4272
|
+
const shell = shellRef.current;
|
|
4273
|
+
if (!shell) return;
|
|
4274
|
+
devWarnOnce(
|
|
4275
|
+
!nested,
|
|
4276
|
+
"PageShell: an ancestor already renders a PageShell. The two grids each add a pair of gutter tracks, so this page's content is inset twice. Remove this shell, or move the outer one."
|
|
4277
|
+
);
|
|
4278
|
+
const check = () => {
|
|
4279
|
+
devWarnOnce(
|
|
4280
|
+
!hasBareTextChild(shell),
|
|
4281
|
+
"PageShell: a direct child renders as bare text. CSS Grid wraps it in an anonymous grid item, which no selector can reach, so it is placed in the gutter rather than the content column and sits outside the page's measure. Wrap it in an element \u2014 a `<p>`, or the section it belongs to."
|
|
4282
|
+
);
|
|
4283
|
+
devWarnOnce(
|
|
4284
|
+
!hasDisplayContentsChild(shell),
|
|
4285
|
+
"PageShell: a direct child has `display: contents`, so it generates no grid item and the content-column rule has nothing to apply to. Its own children are promoted into this grid, match no selector, and are placed from the gutter onward. Give the child a box, or move `display: contents` inside it."
|
|
4286
|
+
);
|
|
4287
|
+
};
|
|
4288
|
+
check();
|
|
4289
|
+
const observer = new MutationObserver(check);
|
|
4290
|
+
observer.observe(shell, { childList: true });
|
|
4291
|
+
return () => {
|
|
4292
|
+
observer.disconnect();
|
|
4293
|
+
};
|
|
4294
|
+
});
|
|
4295
|
+
const shellStyle = {
|
|
4296
|
+
...style,
|
|
4297
|
+
"--nx-shell-measure": SHELL_MEASURE[width]
|
|
4298
|
+
};
|
|
4299
|
+
return /* @__PURE__ */ jsx43(InsideShell.Provider, { value: true, children: /* @__PURE__ */ jsx43(
|
|
4300
|
+
"div",
|
|
4301
|
+
{
|
|
4302
|
+
ref: attachRef,
|
|
4303
|
+
"data-slot": "page-shell",
|
|
4304
|
+
style: shellStyle,
|
|
4305
|
+
className: cn("nx-page-shell py-8", className),
|
|
4306
|
+
...props,
|
|
4307
|
+
children
|
|
4308
|
+
}
|
|
4309
|
+
) });
|
|
4310
|
+
}
|
|
4311
|
+
);
|
|
4312
|
+
PageShell.displayName = "PageShell";
|
|
4313
|
+
var Bleed = forwardRef28(
|
|
4314
|
+
({ className, children, ...props }, ref) => /* @__PURE__ */ jsx43(
|
|
4315
|
+
"div",
|
|
4316
|
+
{
|
|
4317
|
+
ref,
|
|
4318
|
+
"data-slot": "bleed",
|
|
4319
|
+
className: cn("nx-bleed", className),
|
|
4320
|
+
...props,
|
|
4321
|
+
children
|
|
4322
|
+
}
|
|
4323
|
+
)
|
|
4324
|
+
);
|
|
4325
|
+
Bleed.displayName = "Bleed";
|
|
4326
|
+
|
|
4327
|
+
// src/components/page-header.tsx
|
|
4328
|
+
import { forwardRef as forwardRef29 } from "react";
|
|
4329
|
+
import { jsx as jsx44, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
4330
|
+
var PageHeader = forwardRef29(
|
|
4331
|
+
({ title, description, breadcrumbs, actions, className, ...props }, ref) => /* @__PURE__ */ jsxs21(
|
|
4332
|
+
"header",
|
|
4333
|
+
{
|
|
4334
|
+
ref,
|
|
4335
|
+
"data-slot": "page-header",
|
|
4336
|
+
className: cn("mb-8", className),
|
|
4337
|
+
...props,
|
|
4338
|
+
children: [
|
|
4339
|
+
breadcrumbs ? /* @__PURE__ */ jsx44("div", { className: "mb-6", children: breadcrumbs }) : null,
|
|
4340
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-col justify-between gap-4 sm:flex-row sm:items-center", children: [
|
|
4341
|
+
/* @__PURE__ */ jsxs21("div", { className: "space-y-1", children: [
|
|
4342
|
+
/* @__PURE__ */ jsx44("h1", { className: "text-xl font-semibold tracking-tight", children: title }),
|
|
4343
|
+
description ? /* @__PURE__ */ jsx44("p", { className: "mt-1 text-sm font-normal text-muted-foreground", children: description }) : null
|
|
4344
|
+
] }),
|
|
4345
|
+
actions ? /* @__PURE__ */ jsx44("div", { className: "flex items-center gap-3", children: actions }) : null
|
|
4346
|
+
] })
|
|
4347
|
+
]
|
|
4348
|
+
}
|
|
4349
|
+
)
|
|
4350
|
+
);
|
|
4351
|
+
PageHeader.displayName = "PageHeader";
|
|
4102
4352
|
export {
|
|
4103
4353
|
Accordion,
|
|
4104
4354
|
AccordionContent,
|
|
@@ -4122,6 +4372,7 @@ export {
|
|
|
4122
4372
|
AvatarFallback,
|
|
4123
4373
|
AvatarImage,
|
|
4124
4374
|
Badge,
|
|
4375
|
+
Bleed,
|
|
4125
4376
|
Button,
|
|
4126
4377
|
Card,
|
|
4127
4378
|
CardAction,
|
|
@@ -4186,11 +4437,12 @@ export {
|
|
|
4186
4437
|
FieldShell,
|
|
4187
4438
|
FormActions,
|
|
4188
4439
|
FormLabelWithTooltip,
|
|
4189
|
-
FormLayout,
|
|
4190
4440
|
FormSection,
|
|
4191
4441
|
Grid,
|
|
4192
4442
|
Input,
|
|
4193
4443
|
Label,
|
|
4444
|
+
PageHeader,
|
|
4445
|
+
PageShell,
|
|
4194
4446
|
Popover,
|
|
4195
4447
|
PopoverAnchor,
|
|
4196
4448
|
PopoverContent,
|
|
@@ -4202,6 +4454,7 @@ export {
|
|
|
4202
4454
|
ResizableHandle,
|
|
4203
4455
|
ResizablePanel,
|
|
4204
4456
|
ResizablePanelGroup,
|
|
4457
|
+
SHELL_MEASURE,
|
|
4205
4458
|
Select,
|
|
4206
4459
|
SelectContent,
|
|
4207
4460
|
SelectGroup,
|
|
@@ -4260,8 +4513,10 @@ export {
|
|
|
4260
4513
|
badgeVariants,
|
|
4261
4514
|
buttonVariants,
|
|
4262
4515
|
cardVariants,
|
|
4516
|
+
chordMatches,
|
|
4263
4517
|
commandDefaultFilter,
|
|
4264
4518
|
createShortcutManager,
|
|
4519
|
+
detectApplePlatform,
|
|
4265
4520
|
dialogContentVariants,
|
|
4266
4521
|
inputVariants,
|
|
4267
4522
|
parseKeys,
|
|
@@ -4271,6 +4526,7 @@ export {
|
|
|
4271
4526
|
spinnerVariants,
|
|
4272
4527
|
toast,
|
|
4273
4528
|
useActiveShortcuts,
|
|
4529
|
+
useCommandHighlight,
|
|
4274
4530
|
usePortalContainer,
|
|
4275
4531
|
useShortcutManager,
|
|
4276
4532
|
useShortcuts
|