doodleui-react 0.1.1 → 0.3.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.js CHANGED
@@ -1,11 +1,19 @@
1
1
  "use client";
2
- import { createContext, forwardRef, useState, useId, useRef, useLayoutEffect, useContext, useCallback, useMemo } from 'react';
2
+ import { createContext, forwardRef, useRef, useState, useId, useLayoutEffect, useContext, Children, isValidElement, cloneElement, useEffect, useSyncExternalStore, useCallback, useMemo } from 'react';
3
3
  import rough from 'roughjs';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
6
6
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
7
7
  import * as Dialog from '@radix-ui/react-dialog';
8
+ import { motion, AnimatePresence } from 'framer-motion';
8
9
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
10
+ import * as SelectPrimitive from '@radix-ui/react-select';
11
+ import * as SwitchPrimitive from '@radix-ui/react-switch';
12
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
13
+ import * as ToastPrimitive from '@radix-ui/react-toast';
14
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
15
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
16
+ import * as SliderPrimitive from '@radix-ui/react-slider';
9
17
 
10
18
  // src/types.ts
11
19
  function toRoughOptions(props) {
@@ -41,6 +49,11 @@ var SKETCH_COLORS = {
41
49
  };
42
50
 
43
51
  // src/utils.ts
52
+ function assignRef(ref, value) {
53
+ if (!ref) return;
54
+ if (typeof ref === "function") ref(value);
55
+ else ref.current = value;
56
+ }
44
57
  function randomSeed() {
45
58
  return Math.floor(Math.random() * 2 ** 31);
46
59
  }
@@ -60,6 +73,13 @@ function cn(...parts) {
60
73
  const value = parts.filter(Boolean).join(" ");
61
74
  return value.length > 0 ? value : void 0;
62
75
  }
76
+ function deriveSeed(base, key) {
77
+ let hash = 0;
78
+ for (let i = 0; i < key.length; i += 1) {
79
+ hash = hash * 31 + key.charCodeAt(i) | 0;
80
+ }
81
+ return (base + (hash >>> 0)) % 2 ** 31;
82
+ }
63
83
  var SketchSeedContext = createContext(null);
64
84
  function SketchSeedProvider({
65
85
  children,
@@ -234,6 +254,177 @@ function RoughSvg({
234
254
  }
235
255
  );
236
256
  }
257
+ var DoodleUIContext = createContext(null);
258
+ function DoodleUIProvider({
259
+ children,
260
+ animate = true,
261
+ forceAnimate = false
262
+ }) {
263
+ const value = useMemo(
264
+ () => ({ animate, forceAnimate }),
265
+ [animate, forceAnimate]
266
+ );
267
+ return /* @__PURE__ */ jsx(DoodleUIContext.Provider, { value, children });
268
+ }
269
+ function useDoodleUI() {
270
+ return useContext(DoodleUIContext) ?? { animate: true, forceAnimate: false };
271
+ }
272
+
273
+ // src/animations/resolveAnimate.ts
274
+ function resolveAnimate({
275
+ animate,
276
+ providerAnimate = true,
277
+ forceAnimate = false,
278
+ prefersReducedMotion = false
279
+ }) {
280
+ if (prefersReducedMotion && !forceAnimate) return false;
281
+ if (animate !== void 0) return animate;
282
+ return providerAnimate;
283
+ }
284
+ function subscribe(onStoreChange) {
285
+ const media = window.matchMedia("(prefers-reduced-motion: reduce)");
286
+ media.addEventListener("change", onStoreChange);
287
+ return () => media.removeEventListener("change", onStoreChange);
288
+ }
289
+ function getSnapshot() {
290
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
291
+ }
292
+ function getServerSnapshot() {
293
+ return false;
294
+ }
295
+ function usePrefersReducedMotion() {
296
+ return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
297
+ }
298
+
299
+ // src/animations/useAnimate.ts
300
+ function useAnimate(animate) {
301
+ const { animate: providerAnimate, forceAnimate } = useDoodleUI();
302
+ const prefersReducedMotion = usePrefersReducedMotion();
303
+ return resolveAnimate({
304
+ animate,
305
+ providerAnimate,
306
+ forceAnimate,
307
+ prefersReducedMotion
308
+ });
309
+ }
310
+ function useTweenNumber(target, enabled, duration = 400) {
311
+ const [value, setValue] = useState(target);
312
+ const valueRef = useRef(target);
313
+ valueRef.current = value;
314
+ useEffect(() => {
315
+ if (!enabled) {
316
+ valueRef.current = target;
317
+ setValue(target);
318
+ return;
319
+ }
320
+ const from = valueRef.current;
321
+ if (from === target) return;
322
+ const start = performance.now();
323
+ let frame = 0;
324
+ const tick = (now) => {
325
+ const t = Math.min(1, (now - start) / duration);
326
+ const eased = 1 - (1 - t) ** 3;
327
+ const next = from + (target - from) * eased;
328
+ valueRef.current = next;
329
+ setValue(next);
330
+ if (t < 1) frame = requestAnimationFrame(tick);
331
+ };
332
+ frame = requestAnimationFrame(tick);
333
+ return () => cancelAnimationFrame(frame);
334
+ }, [target, enabled, duration]);
335
+ return enabled ? value : target;
336
+ }
337
+ var DRAW_IN_DURATION_MS = 400;
338
+ var DRAW_IN_ALERT_MS = 200;
339
+ var DRAW_IN_TOOLTIP_MS = 180;
340
+ var DRAW_IN_MARK_MS = 240;
341
+ var TABLE_STAGGER_MS = 40;
342
+ var DRAW_IN_EASING = "ease-out";
343
+ var running = /* @__PURE__ */ new WeakMap();
344
+ function collectStrokePaths(root) {
345
+ const groups = root.querySelectorAll("g");
346
+ if (groups.length > 0) {
347
+ const paths = [];
348
+ groups.forEach((group) => {
349
+ const children = group.querySelectorAll(":scope > path");
350
+ if (children.length === 0) return;
351
+ paths.push(children[children.length - 1]);
352
+ });
353
+ return paths;
354
+ }
355
+ return Array.from(root.querySelectorAll("path"));
356
+ }
357
+ function getStrokePaths(target) {
358
+ if (target instanceof SVGPathElement) return [target];
359
+ if (target instanceof SVGSVGElement) return collectStrokePaths(target);
360
+ const svgs = target.querySelectorAll("svg");
361
+ if (svgs.length > 0) {
362
+ return Array.from(svgs).flatMap((svg) => collectStrokePaths(svg));
363
+ }
364
+ return collectStrokePaths(target);
365
+ }
366
+ function clearDash(path) {
367
+ path.style.strokeDasharray = "";
368
+ path.style.strokeDashoffset = "";
369
+ }
370
+ function cancelDrawIn(target) {
371
+ if (!target) return;
372
+ const animations = running.get(target);
373
+ animations?.forEach((animation) => animation.cancel());
374
+ running.delete(target);
375
+ getStrokePaths(target).forEach(clearDash);
376
+ }
377
+ function drawIn(target, duration = DRAW_IN_DURATION_MS, delay = 0) {
378
+ cancelDrawIn(target);
379
+ const paths = getStrokePaths(target);
380
+ const animations = [];
381
+ for (const path of paths) {
382
+ let length = 0;
383
+ try {
384
+ length = path.getTotalLength();
385
+ } catch {
386
+ continue;
387
+ }
388
+ if (length <= 0) continue;
389
+ path.style.strokeDasharray = `${length}`;
390
+ path.style.strokeDashoffset = `${length}`;
391
+ const animation = path.animate(
392
+ [{ strokeDashoffset: String(length) }, { strokeDashoffset: "0" }],
393
+ { duration, delay, easing: DRAW_IN_EASING, fill: "forwards" }
394
+ );
395
+ animation.finished.then(() => {
396
+ clearDash(path);
397
+ }).catch(() => {
398
+ });
399
+ animations.push(animation);
400
+ }
401
+ running.set(target, animations);
402
+ }
403
+ function useDrawIn(pathRef, duration = DRAW_IN_DURATION_MS, enabled = true, replayKey, delay = 0) {
404
+ useLayoutEffect(() => {
405
+ const target = pathRef.current;
406
+ if (!target) return;
407
+ if (!enabled) {
408
+ cancelDrawIn(target);
409
+ return;
410
+ }
411
+ const apply = () => drawIn(target, duration, delay);
412
+ if (getStrokePaths(target).length > 0) {
413
+ apply();
414
+ return () => cancelDrawIn(target);
415
+ }
416
+ const observer = new MutationObserver(() => {
417
+ if (getStrokePaths(target).length === 0) return;
418
+ observer.disconnect();
419
+ apply();
420
+ });
421
+ observer.observe(target, { childList: true, subtree: true });
422
+ return () => {
423
+ observer.disconnect();
424
+ cancelDrawIn(target);
425
+ };
426
+ }, [pathRef, duration, enabled, replayKey, delay]);
427
+ }
237
428
  var SketchBox = forwardRef(
238
429
  function SketchBox2({
239
430
  children,
@@ -252,12 +443,21 @@ var SketchBox = forwardRef(
252
443
  strokeWidth,
253
444
  inset,
254
445
  path,
446
+ animate,
447
+ drawInDuration = DRAW_IN_DURATION_MS,
448
+ drawInKey,
255
449
  ...rest
256
450
  }, ref) {
451
+ const rootRef = useRef(null);
452
+ const shouldAnimate = useAnimate(animate);
453
+ useDrawIn(rootRef, drawInDuration, shouldAnimate, drawInKey);
257
454
  return /* @__PURE__ */ jsxs(
258
455
  "div",
259
456
  {
260
- ref,
457
+ ref: (node) => {
458
+ rootRef.current = node;
459
+ assignRef(ref, node);
460
+ },
261
461
  className: cn(className),
262
462
  style: { position: "relative", ...style },
263
463
  ...rest,
@@ -315,6 +515,10 @@ var SIZE_STYLES = {
315
515
  md: { fontSize: 15, padding: "8px 16px", minHeight: 38 },
316
516
  lg: { fontSize: 17, padding: "11px 22px", minHeight: 46 }
317
517
  };
518
+ function assignRef2(ref, value) {
519
+ if (typeof ref === "function") ref(value);
520
+ else if (ref) ref.current = value;
521
+ }
318
522
  var Button = forwardRef(
319
523
  function Button2({
320
524
  children,
@@ -329,18 +533,28 @@ var Button = forwardRef(
329
533
  fillStyle,
330
534
  strokeWidth,
331
535
  disabled,
536
+ animate,
332
537
  onMouseEnter,
333
538
  onMouseLeave,
334
539
  ...rest
335
540
  }, ref) {
541
+ const rootRef = useRef(null);
336
542
  const [hovered, setHovered] = useState(false);
543
+ const shouldAnimate = useAnimate(animate);
544
+ const resolvedSeed = useResolvedSeed(seed);
545
+ const hoverSeed = deriveSeed(resolvedSeed, "hover");
546
+ const sketchSeed = shouldAnimate && hovered && !disabled ? hoverSeed : resolvedSeed;
337
547
  const ink = sketchColor ?? SKETCH_COLORS.ink;
338
548
  const fill = variant === "primary" ? SKETCH_COLORS.accentFill : variant === "secondary" ? SKETCH_COLORS.secondaryFill : void 0;
339
549
  const stroke = variant === "ghost" && !hovered ? "transparent" : variant === "primary" ? sketchColor ?? SKETCH_COLORS.accent : ink;
550
+ useDrawIn(rootRef, DRAW_IN_DURATION_MS, shouldAnimate, sketchSeed);
340
551
  return /* @__PURE__ */ jsxs(
341
552
  "button",
342
553
  {
343
- ref,
554
+ ref: (node) => {
555
+ rootRef.current = node;
556
+ assignRef2(ref, node);
557
+ },
344
558
  type: "button",
345
559
  className: cn(className),
346
560
  disabled,
@@ -376,12 +590,12 @@ var Button = forwardRef(
376
590
  {
377
591
  shape: "rectangle",
378
592
  roughness,
379
- seed,
593
+ seed: sketchSeed,
380
594
  sketchColor: stroke,
381
595
  bowing,
382
596
  fillStyle: fillStyle ?? "hachure",
383
597
  fill,
384
- strokeWidth: hovered ? (strokeWidth ?? 1.75) + 0.4 : strokeWidth
598
+ strokeWidth: !shouldAnimate && hovered ? (strokeWidth ?? 1.75) + 0.4 : strokeWidth
385
599
  }
386
600
  ),
387
601
  /* @__PURE__ */ jsx("span", { style: { position: "relative", zIndex: 1 }, children })
@@ -403,11 +617,18 @@ var Input = forwardRef(function Input2({
403
617
  id,
404
618
  onFocus,
405
619
  onBlur,
620
+ animate,
406
621
  ...rest
407
622
  }, ref) {
408
623
  const [focused, setFocused] = useState(false);
624
+ const fieldRef = useRef(null);
625
+ const shouldAnimate = useAnimate(animate);
626
+ const resolvedSeed = useResolvedSeed(seed);
627
+ const focusSeed = deriveSeed(resolvedSeed, "focus");
628
+ const sketchSeed = shouldAnimate && focused ? focusSeed : resolvedSeed;
409
629
  const ink = sketchColor ?? SKETCH_COLORS.ink;
410
630
  const inputId = id;
631
+ useDrawIn(fieldRef, DRAW_IN_DURATION_MS, shouldAnimate, sketchSeed);
411
632
  return /* @__PURE__ */ jsxs(
412
633
  "label",
413
634
  {
@@ -431,17 +652,17 @@ var Input = forwardRef(function Input2({
431
652
  children: label
432
653
  }
433
654
  ) : null,
434
- /* @__PURE__ */ jsxs("span", { style: { position: "relative", display: "block" }, children: [
655
+ /* @__PURE__ */ jsxs("span", { ref: fieldRef, style: { position: "relative", display: "block" }, children: [
435
656
  /* @__PURE__ */ jsx(
436
657
  RoughSvg,
437
658
  {
438
659
  shape: "rectangle",
439
660
  roughness,
440
- seed,
661
+ seed: sketchSeed,
441
662
  sketchColor: focused ? SKETCH_COLORS.accent : ink,
442
663
  bowing,
443
664
  fillStyle,
444
- strokeWidth: focused ? (strokeWidth ?? 1.75) + 0.35 : strokeWidth
665
+ strokeWidth: focused && !shouldAnimate ? (strokeWidth ?? 1.75) + 0.35 : focused ? (strokeWidth ?? 1.75) + 0.2 : strokeWidth
445
666
  }
446
667
  ),
447
668
  /* @__PURE__ */ jsx(
@@ -495,10 +716,17 @@ var Textarea = forwardRef(
495
716
  rows = 4,
496
717
  onFocus,
497
718
  onBlur,
719
+ animate,
498
720
  ...rest
499
721
  }, ref) {
500
722
  const [focused, setFocused] = useState(false);
723
+ const fieldRef = useRef(null);
724
+ const shouldAnimate = useAnimate(animate);
725
+ const resolvedSeed = useResolvedSeed(seed);
726
+ const focusSeed = deriveSeed(resolvedSeed, "focus");
727
+ const sketchSeed = shouldAnimate && focused ? focusSeed : resolvedSeed;
501
728
  const ink = sketchColor ?? SKETCH_COLORS.ink;
729
+ useDrawIn(fieldRef, DRAW_IN_DURATION_MS, shouldAnimate, sketchSeed);
502
730
  return /* @__PURE__ */ jsxs(
503
731
  "label",
504
732
  {
@@ -522,17 +750,17 @@ var Textarea = forwardRef(
522
750
  children: label
523
751
  }
524
752
  ) : null,
525
- /* @__PURE__ */ jsxs("span", { style: { position: "relative", display: "block" }, children: [
753
+ /* @__PURE__ */ jsxs("span", { ref: fieldRef, style: { position: "relative", display: "block" }, children: [
526
754
  /* @__PURE__ */ jsx(
527
755
  RoughSvg,
528
756
  {
529
757
  shape: "rectangle",
530
758
  roughness,
531
- seed,
759
+ seed: sketchSeed,
532
760
  sketchColor: focused ? SKETCH_COLORS.accent : ink,
533
761
  bowing,
534
762
  fillStyle,
535
- strokeWidth: focused ? (strokeWidth ?? 1.75) + 0.35 : strokeWidth
763
+ strokeWidth: focused && !shouldAnimate ? (strokeWidth ?? 1.75) + 0.35 : focused ? (strokeWidth ?? 1.75) + 0.2 : strokeWidth
536
764
  }
537
765
  ),
538
766
  /* @__PURE__ */ jsx(
@@ -577,6 +805,36 @@ var Textarea = forwardRef(
577
805
  );
578
806
  var BOX = 20;
579
807
  var CHECK_PATH = "M 4.5 10.5 L 8.5 14.5 L 15.5 5.5";
808
+ function CheckMark({
809
+ roughness,
810
+ seed,
811
+ bowing,
812
+ strokeWidth,
813
+ shouldAnimate
814
+ }) {
815
+ const ref = useRef(null);
816
+ useDrawIn(ref, DRAW_IN_MARK_MS, shouldAnimate);
817
+ return /* @__PURE__ */ jsx(
818
+ "span",
819
+ {
820
+ ref,
821
+ style: { position: "absolute", inset: 0, pointerEvents: "none" },
822
+ children: /* @__PURE__ */ jsx(
823
+ RoughSvg,
824
+ {
825
+ shape: "path",
826
+ path: CHECK_PATH,
827
+ roughness: (roughness ?? 1.5) * 0.7,
828
+ seed,
829
+ sketchColor: SKETCH_COLORS.accent,
830
+ bowing,
831
+ strokeWidth: (strokeWidth ?? 1.6) + 0.4,
832
+ inset: 0
833
+ }
834
+ )
835
+ }
836
+ );
837
+ }
580
838
  var Checkbox = forwardRef(
581
839
  function Checkbox2({
582
840
  className,
@@ -592,11 +850,15 @@ var Checkbox = forwardRef(
592
850
  defaultChecked,
593
851
  onCheckedChange,
594
852
  id,
853
+ animate,
595
854
  ...rest
596
855
  }, ref) {
597
856
  const ink = sketchColor ?? SKETCH_COLORS.ink;
598
857
  const generatedId = useId();
599
858
  const inputId = id ?? generatedId;
859
+ const boxRef = useRef(null);
860
+ const shouldAnimate = useAnimate(animate);
861
+ useDrawIn(boxRef, DRAW_IN_DURATION_MS, shouldAnimate);
600
862
  return /* @__PURE__ */ jsxs(
601
863
  "span",
602
864
  {
@@ -631,16 +893,23 @@ var Checkbox = forwardRef(
631
893
  ...rest,
632
894
  children: [
633
895
  /* @__PURE__ */ jsx(
634
- RoughSvg,
896
+ "span",
635
897
  {
636
- shape: "rectangle",
637
- roughness,
638
- seed,
639
- sketchColor: ink,
640
- bowing,
641
- fillStyle,
642
- strokeWidth: strokeWidth ?? 1.6,
643
- inset: 1.5
898
+ ref: boxRef,
899
+ style: { position: "absolute", inset: 0, pointerEvents: "none" },
900
+ children: /* @__PURE__ */ jsx(
901
+ RoughSvg,
902
+ {
903
+ shape: "rectangle",
904
+ roughness,
905
+ seed,
906
+ sketchColor: ink,
907
+ bowing,
908
+ fillStyle,
909
+ strokeWidth: strokeWidth ?? 1.6,
910
+ inset: 1.5
911
+ }
912
+ )
644
913
  }
645
914
  ),
646
915
  /* @__PURE__ */ jsx(
@@ -652,16 +921,13 @@ var Checkbox = forwardRef(
652
921
  display: "block"
653
922
  },
654
923
  children: /* @__PURE__ */ jsx(
655
- RoughSvg,
924
+ CheckMark,
656
925
  {
657
- shape: "path",
658
- path: CHECK_PATH,
659
- roughness: (roughness ?? 1.5) * 0.7,
926
+ roughness,
660
927
  seed,
661
- sketchColor: SKETCH_COLORS.accent,
662
928
  bowing,
663
- strokeWidth: (strokeWidth ?? 1.6) + 0.4,
664
- inset: 0
929
+ strokeWidth,
930
+ shouldAnimate
665
931
  }
666
932
  )
667
933
  }
@@ -702,6 +968,53 @@ var RadioGroup = forwardRef(
702
968
  }
703
969
  );
704
970
  var SIZE = 20;
971
+ function RadioDot({
972
+ roughness,
973
+ seed,
974
+ bowing,
975
+ shouldAnimate
976
+ }) {
977
+ const ref = useRef(null);
978
+ useDrawIn(ref, DRAW_IN_MARK_MS, shouldAnimate);
979
+ useLayoutEffect(() => {
980
+ const node = ref.current;
981
+ if (!node || !shouldAnimate) return;
982
+ const animation = node.animate(
983
+ [
984
+ { transform: "scale(0.35)", opacity: 0 },
985
+ { transform: "scale(1)", opacity: 1 }
986
+ ],
987
+ { duration: 180, easing: "ease-out", fill: "forwards" }
988
+ );
989
+ return () => animation.cancel();
990
+ }, [shouldAnimate]);
991
+ return /* @__PURE__ */ jsx(
992
+ "span",
993
+ {
994
+ ref,
995
+ style: {
996
+ position: "absolute",
997
+ inset: 0,
998
+ pointerEvents: "none",
999
+ display: "block"
1000
+ },
1001
+ children: /* @__PURE__ */ jsx(
1002
+ RoughSvg,
1003
+ {
1004
+ shape: "ellipse",
1005
+ roughness: (roughness ?? 1.5) + 0.2,
1006
+ seed,
1007
+ sketchColor: SKETCH_COLORS.accent,
1008
+ fill: SKETCH_COLORS.accent,
1009
+ fillStyle: "solid",
1010
+ bowing,
1011
+ strokeWidth: 1,
1012
+ inset: 6
1013
+ }
1014
+ )
1015
+ }
1016
+ );
1017
+ }
705
1018
  var Radio = forwardRef(function Radio2({
706
1019
  className,
707
1020
  style,
@@ -713,11 +1026,15 @@ var Radio = forwardRef(function Radio2({
713
1026
  fillStyle,
714
1027
  strokeWidth,
715
1028
  id,
1029
+ animate,
716
1030
  ...rest
717
1031
  }, ref) {
718
1032
  const ink = sketchColor ?? SKETCH_COLORS.ink;
719
1033
  const generatedId = useId();
720
1034
  const inputId = id ?? generatedId;
1035
+ const ringRef = useRef(null);
1036
+ const shouldAnimate = useAnimate(animate);
1037
+ useDrawIn(ringRef, DRAW_IN_DURATION_MS, shouldAnimate);
721
1038
  return /* @__PURE__ */ jsxs(
722
1039
  "span",
723
1040
  {
@@ -750,16 +1067,23 @@ var Radio = forwardRef(function Radio2({
750
1067
  ...rest,
751
1068
  children: [
752
1069
  /* @__PURE__ */ jsx(
753
- RoughSvg,
1070
+ "span",
754
1071
  {
755
- shape: "ellipse",
756
- roughness,
757
- seed,
758
- sketchColor: ink,
759
- bowing,
760
- fillStyle,
761
- strokeWidth: strokeWidth ?? 1.6,
762
- inset: 1.5
1072
+ ref: ringRef,
1073
+ style: { position: "absolute", inset: 0, pointerEvents: "none" },
1074
+ children: /* @__PURE__ */ jsx(
1075
+ RoughSvg,
1076
+ {
1077
+ shape: "ellipse",
1078
+ roughness,
1079
+ seed,
1080
+ sketchColor: ink,
1081
+ bowing,
1082
+ fillStyle,
1083
+ strokeWidth: strokeWidth ?? 1.6,
1084
+ inset: 1.5
1085
+ }
1086
+ )
763
1087
  }
764
1088
  ),
765
1089
  /* @__PURE__ */ jsx(
@@ -771,17 +1095,12 @@ var Radio = forwardRef(function Radio2({
771
1095
  display: "block"
772
1096
  },
773
1097
  children: /* @__PURE__ */ jsx(
774
- RoughSvg,
1098
+ RadioDot,
775
1099
  {
776
- shape: "ellipse",
777
- roughness: (roughness ?? 1.5) + 0.2,
1100
+ roughness,
778
1101
  seed,
779
- sketchColor: SKETCH_COLORS.accent,
780
- fill: SKETCH_COLORS.accent,
781
- fillStyle: "solid",
782
1102
  bowing,
783
- strokeWidth: 1,
784
- inset: 6
1103
+ shouldAnimate
785
1104
  }
786
1105
  )
787
1106
  }
@@ -815,6 +1134,7 @@ var Card = forwardRef(function Card2({
815
1134
  bowing,
816
1135
  fillStyle,
817
1136
  strokeWidth,
1137
+ animate,
818
1138
  ...rest
819
1139
  }, ref) {
820
1140
  const boxProps = {
@@ -825,7 +1145,8 @@ var Card = forwardRef(function Card2({
825
1145
  sketchColor: sketchColor ?? SKETCH_COLORS.ink,
826
1146
  bowing,
827
1147
  fillStyle,
828
- strokeWidth
1148
+ strokeWidth,
1149
+ animate
829
1150
  };
830
1151
  return /* @__PURE__ */ jsxs(
831
1152
  SketchBox,
@@ -865,6 +1186,7 @@ var Badge = forwardRef(function Badge2({
865
1186
  bowing,
866
1187
  fillStyle,
867
1188
  strokeWidth,
1189
+ animate,
868
1190
  ...rest
869
1191
  }, ref) {
870
1192
  const ink = variant === "accent" ? sketchColor ?? SKETCH_COLORS.accent : sketchColor ?? SKETCH_COLORS.ink;
@@ -892,6 +1214,7 @@ var Badge = forwardRef(function Badge2({
892
1214
  sketchColor: ink,
893
1215
  bowing,
894
1216
  strokeWidth: strokeWidth ?? 1.4,
1217
+ animate,
895
1218
  ...rest,
896
1219
  children: /* @__PURE__ */ jsx("span", { ref, children })
897
1220
  }
@@ -922,6 +1245,7 @@ var Alert = forwardRef(function Alert2({
922
1245
  fillStyle,
923
1246
  strokeWidth,
924
1247
  role = "status",
1248
+ animate,
925
1249
  ...rest
926
1250
  }, ref) {
927
1251
  const color = sketchColor ?? VARIANT_COLOR[variant];
@@ -940,6 +1264,8 @@ var Alert = forwardRef(function Alert2({
940
1264
  fillStyle: fillStyle ?? "hachure",
941
1265
  fill: VARIANT_FILL[variant],
942
1266
  strokeWidth,
1267
+ animate,
1268
+ drawInDuration: DRAW_IN_ALERT_MS,
943
1269
  ...rest,
944
1270
  children: [
945
1271
  title ? /* @__PURE__ */ jsx(
@@ -972,15 +1298,27 @@ function Modal({
972
1298
  sketchColor,
973
1299
  bowing,
974
1300
  fillStyle,
975
- strokeWidth
1301
+ strokeWidth,
1302
+ animate
976
1303
  }) {
977
1304
  const ink = sketchColor ?? SKETCH_COLORS.ink;
978
- return /* @__PURE__ */ jsxs(Dialog.Root, { open, defaultOpen, onOpenChange, children: [
1305
+ const [uncontrolled, setUncontrolled] = useState(defaultOpen === true);
1306
+ const isOpen = open ?? uncontrolled;
1307
+ const shouldAnimate = useAnimate(animate);
1308
+ function handleOpenChange(next) {
1309
+ setUncontrolled(next);
1310
+ onOpenChange?.(next);
1311
+ }
1312
+ return /* @__PURE__ */ jsxs(Dialog.Root, { open: isOpen, onOpenChange: handleOpenChange, children: [
979
1313
  trigger ? /* @__PURE__ */ jsx(Dialog.Trigger, { asChild: true, children: trigger }) : null,
980
- /* @__PURE__ */ jsxs(Dialog.Portal, { children: [
981
- /* @__PURE__ */ jsx(
982
- Dialog.Overlay,
1314
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen ? /* @__PURE__ */ jsxs(Dialog.Portal, { forceMount: true, children: [
1315
+ /* @__PURE__ */ jsx(Dialog.Overlay, { asChild: true, forceMount: true, children: /* @__PURE__ */ jsx(
1316
+ motion.div,
983
1317
  {
1318
+ initial: shouldAnimate ? { opacity: 0 } : false,
1319
+ animate: { opacity: 1 },
1320
+ exit: shouldAnimate ? { opacity: 0 } : void 0,
1321
+ transition: shouldAnimate ? { duration: 0.2, ease: "easeOut" } : { duration: 0 },
984
1322
  style: {
985
1323
  position: "fixed",
986
1324
  inset: 0,
@@ -988,92 +1326,121 @@ function Modal({
988
1326
  zIndex: 70
989
1327
  }
990
1328
  }
991
- ),
1329
+ ) }),
992
1330
  /* @__PURE__ */ jsx(
993
- Dialog.Content,
1331
+ "div",
994
1332
  {
995
- className: cn(className),
996
1333
  style: {
997
1334
  position: "fixed",
998
- left: "50%",
999
- top: "50%",
1000
- transform: "translate(-50%, -50%)",
1335
+ inset: 0,
1001
1336
  zIndex: 80,
1002
- width: "min(480px, calc(100vw - 32px))",
1003
- outline: "none"
1337
+ display: "flex",
1338
+ alignItems: "center",
1339
+ justifyContent: "center",
1340
+ pointerEvents: "none",
1341
+ padding: 16
1004
1342
  },
1005
- children: /* @__PURE__ */ jsxs(
1006
- SketchBox,
1343
+ children: /* @__PURE__ */ jsx(Dialog.Content, { asChild: true, forceMount: true, children: /* @__PURE__ */ jsx(
1344
+ motion.div,
1007
1345
  {
1008
- roughness,
1009
- seed,
1010
- sketchColor: ink,
1011
- bowing,
1012
- fillStyle: fillStyle ?? "solid",
1013
- fill: "#f7f6f2",
1014
- strokeWidth: strokeWidth ?? 2,
1015
- shadow: true,
1016
- contentStyle: { padding: "20px 22px 18px" },
1017
- children: [
1018
- /* @__PURE__ */ jsxs(
1019
- "div",
1020
- {
1021
- style: {
1022
- display: "flex",
1023
- alignItems: "flex-start",
1024
- justifyContent: "space-between",
1025
- gap: 12,
1026
- marginBottom: title ? 10 : 0
1027
- },
1028
- children: [
1029
- title ? /* @__PURE__ */ jsx(
1030
- Dialog.Title,
1031
- {
1032
- style: {
1033
- margin: 0,
1034
- fontSize: 18,
1035
- fontWeight: doodleUiFontWeight(700),
1036
- fontFamily: doodleUiFontFamily,
1037
- color: ink
1038
- },
1039
- children: title
1040
- }
1041
- ) : /* @__PURE__ */ jsx(Dialog.Title, { style: { position: "absolute", width: 1, height: 1, overflow: "hidden", clip: "rect(0 0 0 0)" }, children: "Dialog" }),
1042
- /* @__PURE__ */ jsx(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx(
1043
- Button,
1044
- {
1045
- variant: "ghost",
1046
- size: "sm",
1047
- roughness,
1048
- seed,
1049
- sketchColor: ink,
1050
- "aria-label": "Close",
1051
- children: "Close"
1052
- }
1053
- ) })
1054
- ]
1055
- }
1056
- ),
1057
- description ? /* @__PURE__ */ jsx(
1058
- Dialog.Description,
1059
- {
1060
- style: {
1061
- margin: "0 0 14px",
1062
- fontSize: 14,
1063
- lineHeight: 1.5,
1064
- color: ink,
1065
- opacity: 0.8
1066
- },
1067
- children: description
1068
- }
1069
- ) : null,
1070
- /* @__PURE__ */ jsx("div", { children })
1071
- ]
1346
+ className: cn(className),
1347
+ initial: shouldAnimate ? { opacity: 0, scale: 0.96, y: 10 } : false,
1348
+ animate: { opacity: 1, scale: 1, y: 0 },
1349
+ exit: shouldAnimate ? { opacity: 0, scale: 0.96, y: 8 } : void 0,
1350
+ transition: shouldAnimate ? { duration: 0.22, ease: "easeOut" } : { duration: 0 },
1351
+ style: {
1352
+ width: "min(480px, calc(100vw - 32px))",
1353
+ outline: "none",
1354
+ pointerEvents: "auto"
1355
+ },
1356
+ children: /* @__PURE__ */ jsxs(
1357
+ SketchBox,
1358
+ {
1359
+ roughness,
1360
+ seed,
1361
+ sketchColor: ink,
1362
+ bowing,
1363
+ fillStyle: fillStyle ?? "solid",
1364
+ fill: "#f7f6f2",
1365
+ strokeWidth: strokeWidth ?? 2,
1366
+ shadow: true,
1367
+ animate,
1368
+ contentStyle: { padding: "20px 22px 18px" },
1369
+ children: [
1370
+ /* @__PURE__ */ jsxs(
1371
+ "div",
1372
+ {
1373
+ style: {
1374
+ display: "flex",
1375
+ alignItems: "flex-start",
1376
+ justifyContent: "space-between",
1377
+ gap: 12,
1378
+ marginBottom: title ? 10 : 0
1379
+ },
1380
+ children: [
1381
+ title ? /* @__PURE__ */ jsx(
1382
+ Dialog.Title,
1383
+ {
1384
+ style: {
1385
+ margin: 0,
1386
+ fontSize: 18,
1387
+ fontWeight: doodleUiFontWeight(700),
1388
+ fontFamily: doodleUiFontFamily,
1389
+ color: ink
1390
+ },
1391
+ children: title
1392
+ }
1393
+ ) : /* @__PURE__ */ jsx(
1394
+ Dialog.Title,
1395
+ {
1396
+ style: {
1397
+ position: "absolute",
1398
+ width: 1,
1399
+ height: 1,
1400
+ overflow: "hidden",
1401
+ clip: "rect(0 0 0 0)"
1402
+ },
1403
+ children: "Dialog"
1404
+ }
1405
+ ),
1406
+ /* @__PURE__ */ jsx(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx(
1407
+ Button,
1408
+ {
1409
+ variant: "ghost",
1410
+ size: "sm",
1411
+ roughness,
1412
+ seed,
1413
+ sketchColor: ink,
1414
+ animate,
1415
+ "aria-label": "Close",
1416
+ children: "Close"
1417
+ }
1418
+ ) })
1419
+ ]
1420
+ }
1421
+ ),
1422
+ description ? /* @__PURE__ */ jsx(
1423
+ Dialog.Description,
1424
+ {
1425
+ style: {
1426
+ margin: "0 0 14px",
1427
+ fontSize: 14,
1428
+ lineHeight: 1.5,
1429
+ color: ink,
1430
+ opacity: 0.8
1431
+ },
1432
+ children: description
1433
+ }
1434
+ ) : null,
1435
+ /* @__PURE__ */ jsx("div", { children })
1436
+ ]
1437
+ }
1438
+ )
1072
1439
  }
1073
- )
1440
+ ) })
1074
1441
  }
1075
1442
  )
1076
- ] })
1443
+ ] }) : null })
1077
1444
  ] });
1078
1445
  }
1079
1446
  var ModalRoot = Dialog.Root;
@@ -1091,13 +1458,20 @@ var Divider = forwardRef(
1091
1458
  sketchColor,
1092
1459
  bowing,
1093
1460
  strokeWidth,
1461
+ animate,
1094
1462
  ...rest
1095
1463
  }, ref) {
1464
+ const rootRef = useRef(null);
1465
+ const shouldAnimate = useAnimate(animate);
1096
1466
  const horizontal = orientation === "horizontal";
1467
+ useDrawIn(rootRef, DRAW_IN_DURATION_MS, shouldAnimate);
1097
1468
  return /* @__PURE__ */ jsx(
1098
1469
  "div",
1099
1470
  {
1100
- ref,
1471
+ ref: (node) => {
1472
+ rootRef.current = node;
1473
+ assignRef(ref, node);
1474
+ },
1101
1475
  role: "separator",
1102
1476
  "aria-orientation": orientation,
1103
1477
  className: cn(className),
@@ -1137,15 +1511,27 @@ var Progress = forwardRef(
1137
1511
  bowing,
1138
1512
  fillStyle,
1139
1513
  strokeWidth,
1514
+ animate,
1140
1515
  ...rest
1141
1516
  }, ref) {
1517
+ const rootRef = useRef(null);
1518
+ const trackRef = useRef(null);
1142
1519
  const ink = sketchColor ?? SKETCH_COLORS.accent;
1143
1520
  const clamped = Math.min(max, Math.max(0, value));
1144
1521
  const percent = max === 0 ? 0 : clamped / max * 100;
1522
+ const shouldAnimate = useAnimate(animate);
1523
+ const displayed = useTweenNumber(percent, shouldAnimate, 420);
1524
+ const resolvedSeed = useResolvedSeed(seed);
1525
+ const fillSeed = shouldAnimate ? deriveSeed(resolvedSeed, `fill-${Math.round(displayed / 6)}`) : resolvedSeed;
1526
+ const fillRoughness = (roughness ?? 1.5) + 0.4 + displayed / 100 * 0.7;
1527
+ useDrawIn(trackRef, DRAW_IN_DURATION_MS, shouldAnimate);
1145
1528
  return /* @__PURE__ */ jsxs(
1146
1529
  "div",
1147
1530
  {
1148
- ref,
1531
+ ref: (node) => {
1532
+ rootRef.current = node;
1533
+ assignRef(ref, node);
1534
+ },
1149
1535
  role: "progressbar",
1150
1536
  "aria-valuemin": 0,
1151
1537
  "aria-valuemax": max,
@@ -1160,18 +1546,25 @@ var Progress = forwardRef(
1160
1546
  ...rest,
1161
1547
  children: [
1162
1548
  /* @__PURE__ */ jsx(
1163
- RoughSvg,
1549
+ "span",
1164
1550
  {
1165
- shape: "rectangle",
1166
- roughness,
1167
- seed,
1168
- sketchColor: SKETCH_COLORS.ink,
1169
- bowing,
1170
- strokeWidth: strokeWidth ?? 1.5,
1171
- inset: 2
1551
+ ref: trackRef,
1552
+ style: { position: "absolute", inset: 0, pointerEvents: "none" },
1553
+ children: /* @__PURE__ */ jsx(
1554
+ RoughSvg,
1555
+ {
1556
+ shape: "rectangle",
1557
+ roughness,
1558
+ seed: resolvedSeed,
1559
+ sketchColor: SKETCH_COLORS.ink,
1560
+ bowing,
1561
+ strokeWidth: strokeWidth ?? 1.5,
1562
+ inset: 2
1563
+ }
1564
+ )
1172
1565
  }
1173
1566
  ),
1174
- percent > 0 ? /* @__PURE__ */ jsx(
1567
+ displayed > 0 ? /* @__PURE__ */ jsx(
1175
1568
  "div",
1176
1569
  {
1177
1570
  style: {
@@ -1179,16 +1572,16 @@ var Progress = forwardRef(
1179
1572
  left: 5,
1180
1573
  top: 4,
1181
1574
  bottom: 4,
1182
- width: `calc(${percent}% - 10px)`,
1183
- minWidth: percent > 0 ? 8 : 0,
1575
+ width: `calc(${displayed}% - 10px)`,
1576
+ minWidth: displayed > 0 ? 8 : 0,
1184
1577
  overflow: "hidden"
1185
1578
  },
1186
1579
  children: /* @__PURE__ */ jsx(
1187
1580
  RoughSvg,
1188
1581
  {
1189
1582
  shape: "rectangle",
1190
- roughness: (roughness ?? 1.5) + 0.55,
1191
- seed,
1583
+ roughness: fillRoughness,
1584
+ seed: fillSeed,
1192
1585
  sketchColor: ink,
1193
1586
  fill: ink,
1194
1587
  fillStyle: fillStyle ?? "hachure",
@@ -1216,7 +1609,8 @@ function Tooltip({
1216
1609
  sketchColor,
1217
1610
  bowing,
1218
1611
  fillStyle,
1219
- strokeWidth
1612
+ strokeWidth,
1613
+ animate
1220
1614
  }) {
1221
1615
  const ink = sketchColor ?? SKETCH_COLORS.ink;
1222
1616
  return /* @__PURE__ */ jsxs(TooltipPrimitive.Root, { delayDuration, children: [
@@ -1238,6 +1632,8 @@ function Tooltip({
1238
1632
  fillStyle: fillStyle ?? "solid",
1239
1633
  fill: "#f7f6f2",
1240
1634
  strokeWidth: strokeWidth ?? 1.4,
1635
+ animate,
1636
+ drawInDuration: DRAW_IN_TOOLTIP_MS,
1241
1637
  contentStyle: {
1242
1638
  padding: "6px 10px",
1243
1639
  fontSize: 13,
@@ -1253,7 +1649,2055 @@ function Tooltip({
1253
1649
  ) })
1254
1650
  ] });
1255
1651
  }
1652
+ var CHEVRON_PATH = "M 4 6 L 10 12 L 16 6";
1653
+ var UNDERLINE_INSET = 4;
1654
+ var SelectSketchContext = createContext(
1655
+ null
1656
+ );
1657
+ function useSelectSketch() {
1658
+ const ctx = useContext(SelectSketchContext);
1659
+ if (!ctx) {
1660
+ throw new Error("Select parts must be used inside <Select>.");
1661
+ }
1662
+ return ctx;
1663
+ }
1664
+ function Select({
1665
+ options,
1666
+ placeholder = "Select\u2026",
1667
+ className,
1668
+ style,
1669
+ roughness,
1670
+ seed,
1671
+ sketchColor,
1672
+ bowing,
1673
+ fillStyle,
1674
+ strokeWidth,
1675
+ value,
1676
+ defaultValue,
1677
+ onValueChange,
1678
+ animate,
1679
+ "aria-label": ariaLabel,
1680
+ ...rest
1681
+ }) {
1682
+ const [uncontrolled, setUncontrolled] = useState(defaultValue);
1683
+ const selectedValue = value ?? uncontrolled;
1684
+ const selectedLabel = options.find((option) => option.value === selectedValue)?.label;
1685
+ const resolvedSeed = useResolvedSeed(seed);
1686
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
1687
+ return /* @__PURE__ */ jsx(
1688
+ SelectSketchContext.Provider,
1689
+ {
1690
+ value: {
1691
+ roughness,
1692
+ seed: resolvedSeed,
1693
+ sketchColor,
1694
+ bowing,
1695
+ fillStyle,
1696
+ strokeWidth,
1697
+ resolvedSeed,
1698
+ ink,
1699
+ selectedValue,
1700
+ selectedLabel,
1701
+ placeholder,
1702
+ animate
1703
+ },
1704
+ children: /* @__PURE__ */ jsxs(
1705
+ SelectPrimitive.Root,
1706
+ {
1707
+ value,
1708
+ defaultValue,
1709
+ onValueChange: (next) => {
1710
+ setUncontrolled(next);
1711
+ onValueChange?.(next);
1712
+ },
1713
+ ...rest,
1714
+ children: [
1715
+ /* @__PURE__ */ jsx(
1716
+ SelectTrigger,
1717
+ {
1718
+ className,
1719
+ style,
1720
+ placeholder,
1721
+ "aria-label": ariaLabel
1722
+ }
1723
+ ),
1724
+ /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(
1725
+ SelectItem,
1726
+ {
1727
+ value: option.value,
1728
+ disabled: option.disabled,
1729
+ children: option.label
1730
+ },
1731
+ option.value
1732
+ )) })
1733
+ ]
1734
+ }
1735
+ )
1736
+ }
1737
+ );
1738
+ }
1739
+ var SelectTrigger = forwardRef(
1740
+ function SelectTrigger2({ className, style, placeholder, children, ...rest }, ref) {
1741
+ const sketch = useSelectSketch();
1742
+ const [openish, setOpenish] = useState(false);
1743
+ const rootRef = useRef(null);
1744
+ const shouldAnimate = useAnimate(sketch.animate);
1745
+ useDrawIn(rootRef, DRAW_IN_DURATION_MS, shouldAnimate);
1746
+ return /* @__PURE__ */ jsxs(
1747
+ SelectPrimitive.Trigger,
1748
+ {
1749
+ ref: (node) => {
1750
+ rootRef.current = node;
1751
+ assignRef(ref, node);
1752
+ },
1753
+ className: cn(className),
1754
+ onPointerDown: () => setOpenish(true),
1755
+ onBlur: () => setOpenish(false),
1756
+ style: {
1757
+ position: "relative",
1758
+ display: "inline-flex",
1759
+ alignItems: "center",
1760
+ justifyContent: "space-between",
1761
+ gap: 12,
1762
+ minWidth: 180,
1763
+ minHeight: 38,
1764
+ padding: "8px 12px",
1765
+ border: "none",
1766
+ background: "transparent",
1767
+ cursor: "pointer",
1768
+ color: sketch.ink,
1769
+ fontFamily: doodleUiFontFamily,
1770
+ fontSize: 15,
1771
+ lineHeight: 1.2,
1772
+ outline: "none",
1773
+ textAlign: "left",
1774
+ ...style
1775
+ },
1776
+ ...rest,
1777
+ children: [
1778
+ /* @__PURE__ */ jsx(
1779
+ RoughSvg,
1780
+ {
1781
+ shape: "rectangle",
1782
+ roughness: sketch.roughness,
1783
+ seed: sketch.resolvedSeed,
1784
+ sketchColor: openish ? SKETCH_COLORS.accent : sketch.ink,
1785
+ bowing: sketch.bowing,
1786
+ fillStyle: sketch.fillStyle,
1787
+ strokeWidth: openish ? (sketch.strokeWidth ?? 1.75) + 0.35 : sketch.strokeWidth
1788
+ }
1789
+ ),
1790
+ /* @__PURE__ */ jsx(
1791
+ "span",
1792
+ {
1793
+ style: {
1794
+ position: "relative",
1795
+ zIndex: 1,
1796
+ flex: 1,
1797
+ overflow: "hidden",
1798
+ textOverflow: "ellipsis",
1799
+ whiteSpace: "nowrap"
1800
+ },
1801
+ children: children ?? sketch.selectedLabel ?? placeholder
1802
+ }
1803
+ ),
1804
+ /* @__PURE__ */ jsx(
1805
+ SelectPrimitive.Icon,
1806
+ {
1807
+ style: {
1808
+ position: "relative",
1809
+ zIndex: 1,
1810
+ width: 18,
1811
+ height: 18,
1812
+ flexShrink: 0
1813
+ },
1814
+ children: /* @__PURE__ */ jsx(
1815
+ RoughSvg,
1816
+ {
1817
+ shape: "path",
1818
+ path: CHEVRON_PATH,
1819
+ roughness: (sketch.roughness ?? 1.5) * 0.7,
1820
+ seed: sketch.resolvedSeed,
1821
+ sketchColor: sketch.ink,
1822
+ bowing: sketch.bowing,
1823
+ strokeWidth: (sketch.strokeWidth ?? 1.6) + 0.2,
1824
+ inset: 0
1825
+ }
1826
+ )
1827
+ }
1828
+ )
1829
+ ]
1830
+ }
1831
+ );
1832
+ }
1833
+ );
1834
+ var SelectContent = forwardRef(
1835
+ function SelectContent2({ className, style, children, ...rest }, ref) {
1836
+ const sketch = useSelectSketch();
1837
+ return /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx(
1838
+ SelectPrimitive.Content,
1839
+ {
1840
+ ref,
1841
+ position: "popper",
1842
+ sideOffset: 6,
1843
+ className: cn(className),
1844
+ style: {
1845
+ zIndex: 80,
1846
+ outline: "none",
1847
+ minWidth: "var(--radix-select-trigger-width)",
1848
+ ...style
1849
+ },
1850
+ ...rest,
1851
+ children: /* @__PURE__ */ jsx(
1852
+ SketchBox,
1853
+ {
1854
+ roughness: sketch.roughness,
1855
+ seed: sketch.resolvedSeed,
1856
+ sketchColor: sketch.ink,
1857
+ bowing: sketch.bowing,
1858
+ fillStyle: sketch.fillStyle ?? "solid",
1859
+ fill: "#f7f6f2",
1860
+ strokeWidth: sketch.strokeWidth ?? 1.5,
1861
+ animate: sketch.animate,
1862
+ contentStyle: { padding: "6px 4px" },
1863
+ children: /* @__PURE__ */ jsx(SelectPrimitive.Viewport, { children })
1864
+ }
1865
+ )
1866
+ }
1867
+ ) });
1868
+ }
1869
+ );
1870
+ var SelectItem = forwardRef(
1871
+ function SelectItem2({ className, style, children, value, ...rest }, ref) {
1872
+ const sketch = useSelectSketch();
1873
+ const [highlighted, setHighlighted] = useState(false);
1874
+ const selected = sketch.selectedValue === value;
1875
+ const mark = highlighted || selected;
1876
+ return /* @__PURE__ */ jsxs(
1877
+ SelectPrimitive.Item,
1878
+ {
1879
+ ref,
1880
+ value,
1881
+ className: cn(className),
1882
+ onPointerMove: () => setHighlighted(true),
1883
+ onPointerLeave: () => setHighlighted(false),
1884
+ onFocus: () => setHighlighted(true),
1885
+ onBlur: () => setHighlighted(false),
1886
+ style: {
1887
+ position: "relative",
1888
+ display: "flex",
1889
+ alignItems: "center",
1890
+ padding: "7px 12px",
1891
+ fontFamily: doodleUiFontFamily,
1892
+ fontSize: 14,
1893
+ color: sketch.ink,
1894
+ outline: "none",
1895
+ cursor: "pointer",
1896
+ userSelect: "none",
1897
+ fontWeight: selected ? doodleUiFontWeight(650) : doodleUiFontWeight(400),
1898
+ ...style
1899
+ },
1900
+ ...rest,
1901
+ children: [
1902
+ mark ? /* @__PURE__ */ jsx(
1903
+ RoughSvg,
1904
+ {
1905
+ shape: "line",
1906
+ roughness: (sketch.roughness ?? 1.5) + 0.4,
1907
+ seed: sketch.resolvedSeed,
1908
+ sketchColor: selected ? SKETCH_COLORS.accent : sketch.ink,
1909
+ bowing: sketch.bowing ?? 1.6,
1910
+ strokeWidth: selected ? 1.8 : 1.3,
1911
+ inset: UNDERLINE_INSET,
1912
+ style: { opacity: selected ? 0.9 : 0.45 }
1913
+ }
1914
+ ) : null,
1915
+ /* @__PURE__ */ jsx(
1916
+ SelectPrimitive.ItemText,
1917
+ {
1918
+ style: { position: "relative", zIndex: 1 },
1919
+ children
1920
+ }
1921
+ )
1922
+ ]
1923
+ }
1924
+ );
1925
+ }
1926
+ );
1927
+ var SelectRoot = SelectPrimitive.Root;
1928
+ var SelectValue = SelectPrimitive.Value;
1929
+ var SelectGroup = SelectPrimitive.Group;
1930
+ var SelectLabel = SelectPrimitive.Label;
1931
+ var SelectSeparator = SelectPrimitive.Separator;
1932
+ var TRACK_W = 44;
1933
+ var TRACK_H = 24;
1934
+ var THUMB = 18;
1935
+ var THUMB_OFF = 3;
1936
+ var THUMB_ON = TRACK_W - THUMB - 3;
1937
+ var Switch = forwardRef(
1938
+ function Switch2({
1939
+ className,
1940
+ style,
1941
+ label,
1942
+ roughness,
1943
+ seed,
1944
+ sketchColor,
1945
+ bowing,
1946
+ fillStyle,
1947
+ strokeWidth,
1948
+ checked,
1949
+ defaultChecked,
1950
+ onCheckedChange,
1951
+ id,
1952
+ animate,
1953
+ ...rest
1954
+ }, ref) {
1955
+ const [uncontrolled, setUncontrolled] = useState(defaultChecked === true);
1956
+ const isOn = checked ?? uncontrolled;
1957
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
1958
+ const resolvedSeed = useResolvedSeed(seed);
1959
+ const shouldAnimate = useAnimate(animate);
1960
+ const trackRef = useRef(null);
1961
+ const trackSeed = shouldAnimate ? deriveSeed(resolvedSeed, isOn ? "on" : "off") : resolvedSeed;
1962
+ useDrawIn(trackRef, DRAW_IN_DURATION_MS, shouldAnimate, trackSeed);
1963
+ return /* @__PURE__ */ jsxs(
1964
+ "span",
1965
+ {
1966
+ className: cn(className),
1967
+ style: {
1968
+ display: "inline-flex",
1969
+ alignItems: "center",
1970
+ gap: 8,
1971
+ cursor: "pointer",
1972
+ userSelect: "none",
1973
+ ...style
1974
+ },
1975
+ children: [
1976
+ /* @__PURE__ */ jsxs(
1977
+ SwitchPrimitive.Root,
1978
+ {
1979
+ ref,
1980
+ id,
1981
+ checked,
1982
+ defaultChecked,
1983
+ onCheckedChange: (next) => {
1984
+ setUncontrolled(next);
1985
+ onCheckedChange?.(next);
1986
+ },
1987
+ style: {
1988
+ position: "relative",
1989
+ width: TRACK_W,
1990
+ height: TRACK_H,
1991
+ padding: 0,
1992
+ border: "none",
1993
+ background: "transparent",
1994
+ flexShrink: 0,
1995
+ cursor: "pointer",
1996
+ outline: "none"
1997
+ },
1998
+ ...rest,
1999
+ children: [
2000
+ /* @__PURE__ */ jsx(
2001
+ "span",
2002
+ {
2003
+ ref: trackRef,
2004
+ style: { position: "absolute", inset: 0, pointerEvents: "none" },
2005
+ children: /* @__PURE__ */ jsx(
2006
+ RoughSvg,
2007
+ {
2008
+ shape: "rectangle",
2009
+ roughness,
2010
+ seed: trackSeed,
2011
+ sketchColor: isOn ? SKETCH_COLORS.accent : ink,
2012
+ bowing: bowing ?? 1.4,
2013
+ fillStyle: fillStyle ?? (isOn ? "hachure" : void 0),
2014
+ fill: isOn ? SKETCH_COLORS.accentFill : void 0,
2015
+ strokeWidth: strokeWidth ?? 1.6,
2016
+ inset: 1.5
2017
+ }
2018
+ )
2019
+ }
2020
+ ),
2021
+ /* @__PURE__ */ jsx(SwitchPrimitive.Thumb, { asChild: true, children: /* @__PURE__ */ jsx(
2022
+ motion.span,
2023
+ {
2024
+ initial: false,
2025
+ animate: { x: isOn ? THUMB_ON : THUMB_OFF },
2026
+ transition: shouldAnimate ? { type: "spring", stiffness: 420, damping: 30 } : { duration: 0 },
2027
+ style: {
2028
+ position: "absolute",
2029
+ top: (TRACK_H - THUMB) / 2,
2030
+ left: 0,
2031
+ width: THUMB,
2032
+ height: THUMB,
2033
+ display: "block",
2034
+ zIndex: 1
2035
+ },
2036
+ children: /* @__PURE__ */ jsx(
2037
+ RoughSvg,
2038
+ {
2039
+ shape: "ellipse",
2040
+ roughness: (roughness ?? 1.5) * 0.85,
2041
+ seed: deriveSeed(resolvedSeed, "thumb"),
2042
+ sketchColor: isOn ? SKETCH_COLORS.accent : ink,
2043
+ fill: "#f7f6f2",
2044
+ fillStyle: "solid",
2045
+ bowing,
2046
+ strokeWidth: (strokeWidth ?? 1.5) + 0.2,
2047
+ inset: 1
2048
+ }
2049
+ )
2050
+ }
2051
+ ) })
2052
+ ]
2053
+ }
2054
+ ),
2055
+ label ? /* @__PURE__ */ jsx(
2056
+ "label",
2057
+ {
2058
+ htmlFor: id,
2059
+ style: {
2060
+ fontSize: 15,
2061
+ cursor: "pointer",
2062
+ fontFamily: doodleUiFontFamily
2063
+ },
2064
+ children: label
2065
+ }
2066
+ ) : null
2067
+ ]
2068
+ }
2069
+ );
2070
+ }
2071
+ );
2072
+ var TabsSketchContext = createContext(null);
2073
+ function useTabsSketch() {
2074
+ const ctx = useContext(TabsSketchContext);
2075
+ if (!ctx) {
2076
+ throw new Error("Tab parts must be used inside <Tabs>.");
2077
+ }
2078
+ return ctx;
2079
+ }
2080
+ var Tabs = forwardRef(function Tabs2({
2081
+ className,
2082
+ style,
2083
+ children,
2084
+ value,
2085
+ defaultValue,
2086
+ onValueChange,
2087
+ roughness,
2088
+ seed,
2089
+ sketchColor,
2090
+ bowing,
2091
+ fillStyle,
2092
+ strokeWidth,
2093
+ animate,
2094
+ ...rest
2095
+ }, ref) {
2096
+ const [uncontrolled, setUncontrolled] = useState(defaultValue);
2097
+ const current = value ?? uncontrolled;
2098
+ const resolvedSeed = useResolvedSeed(seed);
2099
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
2100
+ const shouldAnimate = useAnimate(animate);
2101
+ return /* @__PURE__ */ jsx(
2102
+ TabsSketchContext.Provider,
2103
+ {
2104
+ value: {
2105
+ roughness,
2106
+ seed: resolvedSeed,
2107
+ sketchColor,
2108
+ bowing,
2109
+ fillStyle,
2110
+ strokeWidth,
2111
+ resolvedSeed,
2112
+ ink,
2113
+ current,
2114
+ shouldAnimate
2115
+ },
2116
+ children: /* @__PURE__ */ jsx(
2117
+ TabsPrimitive.Root,
2118
+ {
2119
+ ref,
2120
+ className: cn(className),
2121
+ style,
2122
+ value: current,
2123
+ defaultValue,
2124
+ onValueChange: (next) => {
2125
+ setUncontrolled(next);
2126
+ onValueChange?.(next);
2127
+ },
2128
+ ...rest,
2129
+ children
2130
+ }
2131
+ )
2132
+ }
2133
+ );
2134
+ });
2135
+ function TabUnderline({
2136
+ box,
2137
+ seed,
2138
+ sketch
2139
+ }) {
2140
+ const ref = useRef(null);
2141
+ useDrawIn(ref, DRAW_IN_MARK_MS, sketch.shouldAnimate, seed);
2142
+ return /* @__PURE__ */ jsx(
2143
+ "span",
2144
+ {
2145
+ ref,
2146
+ "aria-hidden": "true",
2147
+ style: {
2148
+ position: "absolute",
2149
+ left: box.left,
2150
+ top: box.top,
2151
+ width: box.width,
2152
+ height: 10,
2153
+ pointerEvents: "none",
2154
+ transition: sketch.shouldAnimate ? "left 220ms ease, width 220ms ease, top 220ms ease" : void 0
2155
+ },
2156
+ children: /* @__PURE__ */ jsx(
2157
+ RoughSvg,
2158
+ {
2159
+ shape: "line",
2160
+ roughness: (sketch.roughness ?? 1.5) + 0.35,
2161
+ seed,
2162
+ sketchColor: SKETCH_COLORS.accent,
2163
+ bowing: sketch.bowing ?? 1.8,
2164
+ strokeWidth: (sketch.strokeWidth ?? 1.75) + 0.4,
2165
+ inset: 2
2166
+ }
2167
+ )
2168
+ }
2169
+ );
2170
+ }
2171
+ var TabList = forwardRef(
2172
+ function TabList2({ className, style, children, ...rest }, ref) {
2173
+ const sketch = useTabsSketch();
2174
+ const listRef = useRef(null);
2175
+ const [underline, setUnderline] = useState(null);
2176
+ useLayoutEffect(() => {
2177
+ const list = listRef.current;
2178
+ if (!list) return;
2179
+ const measure = () => {
2180
+ const active = list.querySelector('[data-state="active"]');
2181
+ if (!active) {
2182
+ setUnderline(null);
2183
+ return;
2184
+ }
2185
+ setUnderline({
2186
+ left: active.offsetLeft + 8,
2187
+ top: active.offsetTop + active.offsetHeight - 10,
2188
+ width: Math.max(12, active.offsetWidth - 16)
2189
+ });
2190
+ };
2191
+ measure();
2192
+ const observer = new ResizeObserver(measure);
2193
+ observer.observe(list);
2194
+ return () => observer.disconnect();
2195
+ }, [sketch.current, children]);
2196
+ return /* @__PURE__ */ jsxs(
2197
+ TabsPrimitive.List,
2198
+ {
2199
+ ref: (node) => {
2200
+ listRef.current = node;
2201
+ assignRef(ref, node);
2202
+ },
2203
+ className: cn(className),
2204
+ style: {
2205
+ display: "flex",
2206
+ flexWrap: "wrap",
2207
+ gap: 4,
2208
+ position: "relative",
2209
+ ...style
2210
+ },
2211
+ ...rest,
2212
+ children: [
2213
+ children,
2214
+ underline && sketch.current ? /* @__PURE__ */ jsx(
2215
+ TabUnderline,
2216
+ {
2217
+ box: underline,
2218
+ seed: deriveSeed(sketch.resolvedSeed, sketch.current),
2219
+ sketch
2220
+ }
2221
+ ) : null
2222
+ ]
2223
+ }
2224
+ );
2225
+ }
2226
+ );
2227
+ var Tab = forwardRef(function Tab2({ className, style, children, value, ...rest }, ref) {
2228
+ const sketch = useTabsSketch();
2229
+ const active = sketch.current === value;
2230
+ return /* @__PURE__ */ jsx(
2231
+ TabsPrimitive.Trigger,
2232
+ {
2233
+ ref,
2234
+ value,
2235
+ className: cn(className),
2236
+ style: {
2237
+ position: "relative",
2238
+ border: "none",
2239
+ background: "transparent",
2240
+ cursor: "pointer",
2241
+ padding: "8px 14px 12px",
2242
+ fontFamily: doodleUiFontFamily,
2243
+ fontSize: 15,
2244
+ fontWeight: active ? doodleUiFontWeight(650) : doodleUiFontWeight(400),
2245
+ color: sketch.ink,
2246
+ outline: "none",
2247
+ ...style
2248
+ },
2249
+ ...rest,
2250
+ children: /* @__PURE__ */ jsx("span", { style: { position: "relative", zIndex: 1 }, children })
2251
+ }
2252
+ );
2253
+ });
2254
+ var TabPanel = forwardRef(
2255
+ function TabPanel2({ className, style, children, ...rest }, ref) {
2256
+ const sketch = useTabsSketch();
2257
+ return /* @__PURE__ */ jsx(
2258
+ TabsPrimitive.Content,
2259
+ {
2260
+ ref,
2261
+ className: cn(className),
2262
+ style: {
2263
+ paddingTop: 14,
2264
+ fontFamily: doodleUiFontFamily,
2265
+ color: sketch.ink,
2266
+ fontSize: 15,
2267
+ lineHeight: 1.5,
2268
+ outline: "none",
2269
+ ...style
2270
+ },
2271
+ ...rest,
2272
+ children
2273
+ }
2274
+ );
2275
+ }
2276
+ );
2277
+ var TableSketchContext = createContext(null);
2278
+ function useTableSketch() {
2279
+ const ctx = useContext(TableSketchContext);
2280
+ if (!ctx) {
2281
+ throw new Error("Table parts must be used inside <Table>.");
2282
+ }
2283
+ return ctx;
2284
+ }
2285
+ function TableRule({
2286
+ line,
2287
+ headerUnderline,
2288
+ roughness,
2289
+ resolvedSeed,
2290
+ ink,
2291
+ bowing,
2292
+ strokeWidth,
2293
+ shouldAnimate
2294
+ }) {
2295
+ const ref = useRef(null);
2296
+ const delay = shouldAnimate ? Math.min(line.index, 6) * TABLE_STAGGER_MS : 0;
2297
+ useDrawIn(ref, DRAW_IN_DURATION_MS, shouldAnimate, void 0, delay);
2298
+ if (line.header && !headerUnderline) return null;
2299
+ return /* @__PURE__ */ jsx(
2300
+ "div",
2301
+ {
2302
+ ref,
2303
+ style: {
2304
+ position: "absolute",
2305
+ left: 0,
2306
+ width: line.width,
2307
+ top: line.y - 6,
2308
+ height: 12
2309
+ },
2310
+ children: /* @__PURE__ */ jsx(
2311
+ RoughSvg,
2312
+ {
2313
+ shape: "line",
2314
+ roughness: line.header ? (roughness ?? 1.5) + 0.2 : roughness ?? 1.7,
2315
+ seed: deriveSeed(resolvedSeed, line.key),
2316
+ sketchColor: ink,
2317
+ bowing: bowing ?? (line.header ? 1.4 : 2),
2318
+ strokeWidth: line.header ? (strokeWidth ?? 1.75) + 0.35 : strokeWidth ?? 1.35,
2319
+ inset: 6
2320
+ }
2321
+ )
2322
+ }
2323
+ );
2324
+ }
2325
+ var Table = forwardRef(function Table2({
2326
+ className,
2327
+ style,
2328
+ children,
2329
+ headerUnderline = true,
2330
+ roughness,
2331
+ seed,
2332
+ sketchColor,
2333
+ bowing,
2334
+ fillStyle,
2335
+ strokeWidth,
2336
+ animate,
2337
+ ...rest
2338
+ }, ref) {
2339
+ const wrapperRef = useRef(null);
2340
+ const tableRef = useRef(null);
2341
+ const [lines, setLines] = useState([]);
2342
+ const resolvedSeed = useResolvedSeed(seed);
2343
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
2344
+ const shouldAnimate = useAnimate(animate);
2345
+ useLayoutEffect(() => {
2346
+ const wrapper = wrapperRef.current;
2347
+ const table = tableRef.current;
2348
+ if (!wrapper || !table) return;
2349
+ const measure = () => {
2350
+ const rows = Array.from(table.querySelectorAll("tr"));
2351
+ const next = [];
2352
+ rows.forEach((row, index) => {
2353
+ const isLast = index === rows.length - 1;
2354
+ const isHeader = row.parentElement?.tagName === "THEAD";
2355
+ if (isLast && !isHeader) return;
2356
+ next.push({
2357
+ y: row.offsetTop + row.offsetHeight,
2358
+ width: table.offsetWidth,
2359
+ key: isHeader ? `header-${index}` : `row-${index}`,
2360
+ header: Boolean(isHeader),
2361
+ index
2362
+ });
2363
+ });
2364
+ setLines(next);
2365
+ };
2366
+ measure();
2367
+ const observer = new ResizeObserver(measure);
2368
+ observer.observe(table);
2369
+ observer.observe(wrapper);
2370
+ return () => observer.disconnect();
2371
+ }, [children]);
2372
+ return /* @__PURE__ */ jsx(
2373
+ TableSketchContext.Provider,
2374
+ {
2375
+ value: {
2376
+ roughness,
2377
+ seed: resolvedSeed,
2378
+ sketchColor,
2379
+ bowing,
2380
+ fillStyle,
2381
+ strokeWidth,
2382
+ resolvedSeed,
2383
+ ink,
2384
+ shouldAnimate
2385
+ },
2386
+ children: /* @__PURE__ */ jsxs(
2387
+ "div",
2388
+ {
2389
+ ref: wrapperRef,
2390
+ className: cn(className),
2391
+ style: { position: "relative", width: "100%", ...style },
2392
+ children: [
2393
+ /* @__PURE__ */ jsx(
2394
+ "div",
2395
+ {
2396
+ "aria-hidden": "true",
2397
+ style: {
2398
+ position: "absolute",
2399
+ inset: 0,
2400
+ pointerEvents: "none",
2401
+ zIndex: 1,
2402
+ overflow: "visible"
2403
+ },
2404
+ children: lines.map((line) => /* @__PURE__ */ jsx(
2405
+ TableRule,
2406
+ {
2407
+ line,
2408
+ headerUnderline,
2409
+ roughness,
2410
+ resolvedSeed,
2411
+ ink,
2412
+ bowing,
2413
+ strokeWidth,
2414
+ shouldAnimate
2415
+ },
2416
+ line.key
2417
+ ))
2418
+ }
2419
+ ),
2420
+ /* @__PURE__ */ jsx(
2421
+ "table",
2422
+ {
2423
+ ref: (node) => {
2424
+ tableRef.current = node;
2425
+ assignRef(ref, node);
2426
+ },
2427
+ style: {
2428
+ width: "100%",
2429
+ borderCollapse: "collapse",
2430
+ position: "relative",
2431
+ zIndex: 0,
2432
+ fontFamily: doodleUiFontFamily,
2433
+ color: ink
2434
+ },
2435
+ ...rest,
2436
+ children
2437
+ }
2438
+ )
2439
+ ]
2440
+ }
2441
+ )
2442
+ }
2443
+ );
2444
+ });
2445
+ var TableHead = forwardRef(function TableHead2({ className, style, ...rest }, ref) {
2446
+ return /* @__PURE__ */ jsx(
2447
+ "thead",
2448
+ {
2449
+ ref,
2450
+ className: cn(className),
2451
+ style,
2452
+ ...rest
2453
+ }
2454
+ );
2455
+ });
2456
+ var TableBody = forwardRef(function TableBody2({ className, style, ...rest }, ref) {
2457
+ return /* @__PURE__ */ jsx(
2458
+ "tbody",
2459
+ {
2460
+ ref,
2461
+ className: cn(className),
2462
+ style,
2463
+ ...rest
2464
+ }
2465
+ );
2466
+ });
2467
+ var TableRow = forwardRef(function TableRow2({ className, style, ...rest }, ref) {
2468
+ return /* @__PURE__ */ jsx(
2469
+ "tr",
2470
+ {
2471
+ ref,
2472
+ className: cn(className),
2473
+ style,
2474
+ ...rest
2475
+ }
2476
+ );
2477
+ });
2478
+ var TableHeaderCell = forwardRef(function TableHeaderCell2({ className, style, children, ...rest }, ref) {
2479
+ useTableSketch();
2480
+ return /* @__PURE__ */ jsx(
2481
+ "th",
2482
+ {
2483
+ ref,
2484
+ className: cn(className),
2485
+ style: {
2486
+ textAlign: "left",
2487
+ fontWeight: doodleUiFontWeight(650),
2488
+ fontSize: 13,
2489
+ padding: "10px 12px",
2490
+ ...style
2491
+ },
2492
+ ...rest,
2493
+ children
2494
+ }
2495
+ );
2496
+ });
2497
+ var TableCell = forwardRef(
2498
+ function TableCell2({ className, style, children, ...rest }, ref) {
2499
+ useTableSketch();
2500
+ return /* @__PURE__ */ jsx(
2501
+ "td",
2502
+ {
2503
+ ref,
2504
+ className: cn(className),
2505
+ style: {
2506
+ fontSize: 14,
2507
+ padding: "10px 12px",
2508
+ ...style
2509
+ },
2510
+ ...rest,
2511
+ children
2512
+ }
2513
+ );
2514
+ }
2515
+ );
2516
+ var VARIANT_COLOR2 = {
2517
+ info: SKETCH_COLORS.info,
2518
+ warning: SKETCH_COLORS.warning,
2519
+ error: SKETCH_COLORS.error,
2520
+ success: SKETCH_COLORS.success
2521
+ };
2522
+ var VARIANT_FILL2 = {
2523
+ info: "#d2deec",
2524
+ warning: "#f3e2c0",
2525
+ error: "#f3d0cc",
2526
+ success: "#d3e8dc"
2527
+ };
2528
+ var POSITION_STYLE = {
2529
+ "top-left": { top: 16, left: 16 },
2530
+ "top-right": { top: 16, right: 16 },
2531
+ "bottom-left": { bottom: 16, left: 16 },
2532
+ "bottom-right": { bottom: 16, right: 16 }
2533
+ };
2534
+ var ToastPositionContext = createContext("bottom-right");
2535
+ function ToastProvider({
2536
+ children,
2537
+ position = "bottom-right",
2538
+ duration = 4e3,
2539
+ swipeDirection = "right",
2540
+ label
2541
+ }) {
2542
+ return /* @__PURE__ */ jsx(ToastPositionContext.Provider, { value: position, children: /* @__PURE__ */ jsxs(
2543
+ ToastPrimitive.Provider,
2544
+ {
2545
+ duration,
2546
+ swipeDirection,
2547
+ label,
2548
+ children: [
2549
+ children,
2550
+ /* @__PURE__ */ jsx(
2551
+ ToastPrimitive.Viewport,
2552
+ {
2553
+ style: {
2554
+ position: "fixed",
2555
+ zIndex: 90,
2556
+ display: "flex",
2557
+ flexDirection: "column",
2558
+ gap: 10,
2559
+ width: "min(360px, calc(100vw - 32px))",
2560
+ margin: 0,
2561
+ padding: 0,
2562
+ listStyle: "none",
2563
+ outline: "none",
2564
+ ...POSITION_STYLE[position]
2565
+ }
2566
+ }
2567
+ )
2568
+ ]
2569
+ }
2570
+ ) });
2571
+ }
2572
+ function Toast({
2573
+ open,
2574
+ defaultOpen,
2575
+ onOpenChange,
2576
+ title,
2577
+ children,
2578
+ variant = "info",
2579
+ duration,
2580
+ className,
2581
+ style,
2582
+ roughness,
2583
+ seed,
2584
+ sketchColor,
2585
+ bowing,
2586
+ fillStyle,
2587
+ strokeWidth,
2588
+ animate
2589
+ }) {
2590
+ const position = useContext(ToastPositionContext);
2591
+ const fromTop = position.startsWith("top");
2592
+ const [uncontrolled, setUncontrolled] = useState(defaultOpen ?? false);
2593
+ const isOpen = open ?? uncontrolled;
2594
+ const shouldAnimate = useAnimate(animate);
2595
+ const color = sketchColor ?? VARIANT_COLOR2[variant];
2596
+ const offset = fromTop ? -14 : 14;
2597
+ function handleOpenChange(next) {
2598
+ setUncontrolled(next);
2599
+ onOpenChange?.(next);
2600
+ }
2601
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen ? /* @__PURE__ */ jsx(
2602
+ ToastPrimitive.Root,
2603
+ {
2604
+ open: isOpen,
2605
+ onOpenChange: handleOpenChange,
2606
+ duration,
2607
+ forceMount: true,
2608
+ asChild: true,
2609
+ children: /* @__PURE__ */ jsx(
2610
+ motion.li,
2611
+ {
2612
+ className: cn(className),
2613
+ initial: shouldAnimate ? { y: offset, opacity: 0, rotate: -1.4 } : false,
2614
+ animate: shouldAnimate ? { y: 0, opacity: 1, rotate: [-1.2, 0.9, -0.35, 0] } : { y: 0, opacity: 1, rotate: 0 },
2615
+ exit: shouldAnimate ? { y: offset, opacity: 0, rotate: 1.2 } : { opacity: 0 },
2616
+ transition: shouldAnimate ? { duration: 0.38, ease: "easeOut" } : { duration: 0 },
2617
+ style: {
2618
+ listStyle: "none",
2619
+ outline: "none",
2620
+ ...style
2621
+ },
2622
+ children: /* @__PURE__ */ jsxs(
2623
+ SketchBox,
2624
+ {
2625
+ roughness,
2626
+ seed,
2627
+ sketchColor: color,
2628
+ bowing,
2629
+ fillStyle: fillStyle ?? "hachure",
2630
+ fill: VARIANT_FILL2[variant],
2631
+ strokeWidth: strokeWidth ?? 1.7,
2632
+ shadow: true,
2633
+ animate,
2634
+ contentStyle: { padding: "12px 16px" },
2635
+ children: [
2636
+ title ? /* @__PURE__ */ jsx(
2637
+ ToastPrimitive.Title,
2638
+ {
2639
+ style: {
2640
+ margin: 0,
2641
+ fontWeight: doodleUiFontWeight(700),
2642
+ fontSize: 15,
2643
+ fontFamily: doodleUiFontFamily,
2644
+ color,
2645
+ marginBottom: children ? 4 : 0
2646
+ },
2647
+ children: title
2648
+ }
2649
+ ) : null,
2650
+ children ? /* @__PURE__ */ jsx(
2651
+ ToastPrimitive.Description,
2652
+ {
2653
+ style: {
2654
+ margin: 0,
2655
+ fontSize: 14,
2656
+ lineHeight: 1.5,
2657
+ fontFamily: doodleUiFontFamily,
2658
+ color: SKETCH_COLORS.ink
2659
+ },
2660
+ children
2661
+ }
2662
+ ) : null
2663
+ ]
2664
+ }
2665
+ )
2666
+ }
2667
+ )
2668
+ }
2669
+ ) : null });
2670
+ }
2671
+ var ToastRoot = ToastPrimitive.Root;
2672
+ var ToastTitle = ToastPrimitive.Title;
2673
+ var ToastDescription = ToastPrimitive.Description;
2674
+ var ToastClose = ToastPrimitive.Close;
2675
+ var ToastAction = ToastPrimitive.Action;
2676
+ var ToastViewport = ToastPrimitive.Viewport;
2677
+ var CHEVRON_PATH2 = "M 6 4 L 12 10 L 6 16";
2678
+ var AccordionSketchContext = createContext(null);
2679
+ function useAccordionSketch() {
2680
+ const ctx = useContext(AccordionSketchContext);
2681
+ if (!ctx) {
2682
+ throw new Error("Accordion parts must be used inside <Accordion>.");
2683
+ }
2684
+ return ctx;
2685
+ }
2686
+ var AccordionItemContext = createContext("");
2687
+ var Accordion = forwardRef(
2688
+ function Accordion2({
2689
+ className,
2690
+ style,
2691
+ children,
2692
+ type = "single",
2693
+ collapsible = true,
2694
+ value,
2695
+ defaultValue,
2696
+ onValueChange,
2697
+ disabled,
2698
+ roughness,
2699
+ seed,
2700
+ sketchColor,
2701
+ bowing,
2702
+ fillStyle,
2703
+ strokeWidth
2704
+ }, ref) {
2705
+ const resolvedSeed = useResolvedSeed(seed);
2706
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
2707
+ const [uncontrolled, setUncontrolled] = useState(defaultValue ?? (type === "multiple" ? [] : void 0));
2708
+ const openValue = value ?? uncontrolled;
2709
+ const sketchValue = {
2710
+ roughness,
2711
+ seed: resolvedSeed,
2712
+ sketchColor,
2713
+ bowing,
2714
+ fillStyle,
2715
+ strokeWidth,
2716
+ resolvedSeed,
2717
+ ink,
2718
+ openValue
2719
+ };
2720
+ function handleChange(next) {
2721
+ setUncontrolled(next);
2722
+ onValueChange?.(next);
2723
+ }
2724
+ const root = type === "multiple" ? /* @__PURE__ */ jsx(
2725
+ AccordionPrimitive.Root,
2726
+ {
2727
+ ref,
2728
+ type: "multiple",
2729
+ disabled,
2730
+ className: cn(className),
2731
+ style,
2732
+ value: openValue,
2733
+ defaultValue,
2734
+ onValueChange: handleChange,
2735
+ children
2736
+ }
2737
+ ) : /* @__PURE__ */ jsx(
2738
+ AccordionPrimitive.Root,
2739
+ {
2740
+ ref,
2741
+ type: "single",
2742
+ collapsible,
2743
+ disabled,
2744
+ className: cn(className),
2745
+ style,
2746
+ value: openValue,
2747
+ defaultValue,
2748
+ onValueChange: handleChange,
2749
+ children
2750
+ }
2751
+ );
2752
+ return /* @__PURE__ */ jsx(AccordionSketchContext.Provider, { value: sketchValue, children: root });
2753
+ }
2754
+ );
2755
+ var AccordionItem = forwardRef(
2756
+ function AccordionItem2({ className, style, children, value, ...rest }, ref) {
2757
+ const sketch = useAccordionSketch();
2758
+ return /* @__PURE__ */ jsx(AccordionItemContext.Provider, { value, children: /* @__PURE__ */ jsxs(
2759
+ AccordionPrimitive.Item,
2760
+ {
2761
+ ref,
2762
+ value,
2763
+ className: cn(className),
2764
+ style: { position: "relative", ...style },
2765
+ ...rest,
2766
+ children: [
2767
+ /* @__PURE__ */ jsx(
2768
+ "div",
2769
+ {
2770
+ style: {
2771
+ position: "absolute",
2772
+ left: 0,
2773
+ right: 0,
2774
+ top: -6,
2775
+ height: 12,
2776
+ pointerEvents: "none"
2777
+ },
2778
+ children: /* @__PURE__ */ jsx(
2779
+ RoughSvg,
2780
+ {
2781
+ shape: "line",
2782
+ roughness: (sketch.roughness ?? 1.5) + 0.25,
2783
+ seed: deriveSeed(sketch.resolvedSeed, `div-${value}`),
2784
+ sketchColor: sketch.ink,
2785
+ bowing: sketch.bowing ?? 1.8,
2786
+ strokeWidth: sketch.strokeWidth ?? 1.4,
2787
+ inset: 2
2788
+ }
2789
+ )
2790
+ }
2791
+ ),
2792
+ children
2793
+ ]
2794
+ }
2795
+ ) });
2796
+ }
2797
+ );
2798
+ var AccordionTrigger = forwardRef(function AccordionTrigger2({ className, style, children, ...rest }, ref) {
2799
+ const sketch = useAccordionSketch();
2800
+ const itemValue = useContext(AccordionItemContext);
2801
+ const open = Array.isArray(sketch.openValue) ? sketch.openValue.includes(itemValue) : sketch.openValue === itemValue;
2802
+ return /* @__PURE__ */ jsx(AccordionPrimitive.Header, { asChild: true, children: /* @__PURE__ */ jsx("h3", { style: { margin: 0 }, children: /* @__PURE__ */ jsxs(
2803
+ AccordionPrimitive.Trigger,
2804
+ {
2805
+ ref,
2806
+ className: cn(className),
2807
+ style: {
2808
+ display: "flex",
2809
+ width: "100%",
2810
+ alignItems: "center",
2811
+ justifyContent: "space-between",
2812
+ gap: 12,
2813
+ padding: "12px 4px",
2814
+ border: "none",
2815
+ background: "transparent",
2816
+ cursor: "pointer",
2817
+ fontFamily: doodleUiFontFamily,
2818
+ fontSize: 15,
2819
+ fontWeight: doodleUiFontWeight(600),
2820
+ color: sketch.ink,
2821
+ textAlign: "left",
2822
+ outline: "none",
2823
+ ...style
2824
+ },
2825
+ ...rest,
2826
+ children: [
2827
+ /* @__PURE__ */ jsx("span", { children }),
2828
+ /* @__PURE__ */ jsx(
2829
+ "span",
2830
+ {
2831
+ style: {
2832
+ position: "relative",
2833
+ width: 18,
2834
+ height: 18,
2835
+ flexShrink: 0,
2836
+ transform: open ? "rotate(90deg)" : "rotate(0deg)",
2837
+ transition: "transform 180ms ease"
2838
+ },
2839
+ children: /* @__PURE__ */ jsx(
2840
+ RoughSvg,
2841
+ {
2842
+ shape: "path",
2843
+ path: CHEVRON_PATH2,
2844
+ roughness: (sketch.roughness ?? 1.5) * 0.7,
2845
+ seed: deriveSeed(sketch.resolvedSeed, `chevron-${itemValue}`),
2846
+ sketchColor: sketch.ink,
2847
+ bowing: sketch.bowing,
2848
+ strokeWidth: (sketch.strokeWidth ?? 1.6) + 0.2,
2849
+ inset: 0
2850
+ }
2851
+ )
2852
+ }
2853
+ )
2854
+ ]
2855
+ }
2856
+ ) }) });
2857
+ });
2858
+ var AccordionContent = forwardRef(function AccordionContent2({ className, style, children, ...rest }, ref) {
2859
+ const sketch = useAccordionSketch();
2860
+ return /* @__PURE__ */ jsx(
2861
+ AccordionPrimitive.Content,
2862
+ {
2863
+ ref,
2864
+ className: cn(className),
2865
+ style: {
2866
+ padding: "0 4px 14px",
2867
+ fontFamily: doodleUiFontFamily,
2868
+ fontSize: 14,
2869
+ lineHeight: 1.5,
2870
+ color: sketch.ink,
2871
+ ...style
2872
+ },
2873
+ ...rest,
2874
+ children
2875
+ }
2876
+ );
2877
+ });
2878
+ var STATUS_COLOR = {
2879
+ online: SKETCH_COLORS.success,
2880
+ offline: "#8a8680",
2881
+ busy: SKETCH_COLORS.accent
2882
+ };
2883
+ var Avatar = forwardRef(
2884
+ function Avatar2({
2885
+ className,
2886
+ style,
2887
+ src,
2888
+ alt,
2889
+ fallback,
2890
+ size = 40,
2891
+ shape = "circle",
2892
+ status,
2893
+ roughness,
2894
+ seed,
2895
+ sketchColor,
2896
+ bowing,
2897
+ fillStyle,
2898
+ strokeWidth,
2899
+ ...rest
2900
+ }, ref) {
2901
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
2902
+ const resolvedSeed = useResolvedSeed(seed);
2903
+ const roughShape = shape === "circle" ? "ellipse" : "rectangle";
2904
+ const badge = 12;
2905
+ const rootStyle = {
2906
+ position: "relative",
2907
+ display: "inline-flex",
2908
+ width: size,
2909
+ height: size,
2910
+ flexShrink: 0,
2911
+ verticalAlign: "middle",
2912
+ ...style
2913
+ };
2914
+ return /* @__PURE__ */ jsxs(
2915
+ AvatarPrimitive.Root,
2916
+ {
2917
+ ref,
2918
+ className: cn(className),
2919
+ style: rootStyle,
2920
+ ...rest,
2921
+ children: [
2922
+ /* @__PURE__ */ jsx(
2923
+ RoughSvg,
2924
+ {
2925
+ shape: roughShape,
2926
+ roughness,
2927
+ seed: resolvedSeed,
2928
+ sketchColor: ink,
2929
+ bowing,
2930
+ fillStyle: fillStyle ?? "solid",
2931
+ fill: "#f7f6f2",
2932
+ strokeWidth: strokeWidth ?? 1.6,
2933
+ inset: 1.5
2934
+ }
2935
+ ),
2936
+ /* @__PURE__ */ jsxs(
2937
+ "span",
2938
+ {
2939
+ style: {
2940
+ position: "absolute",
2941
+ inset: 4,
2942
+ overflow: "hidden",
2943
+ borderRadius: shape === "circle" ? "50%" : 4,
2944
+ zIndex: 1,
2945
+ display: "flex",
2946
+ alignItems: "center",
2947
+ justifyContent: "center"
2948
+ },
2949
+ children: [
2950
+ src ? /* @__PURE__ */ jsx(
2951
+ AvatarPrimitive.Image,
2952
+ {
2953
+ src,
2954
+ alt,
2955
+ style: {
2956
+ width: "100%",
2957
+ height: "100%",
2958
+ objectFit: "cover"
2959
+ }
2960
+ }
2961
+ ) : null,
2962
+ /* @__PURE__ */ jsx(
2963
+ AvatarPrimitive.Fallback,
2964
+ {
2965
+ delayMs: src ? 400 : 0,
2966
+ style: {
2967
+ width: "100%",
2968
+ height: "100%",
2969
+ display: "flex",
2970
+ alignItems: "center",
2971
+ justifyContent: "center",
2972
+ fontFamily: doodleUiFontFamily,
2973
+ fontWeight: doodleUiFontWeight(650),
2974
+ fontSize: Math.max(12, size * 0.36),
2975
+ color: ink,
2976
+ background: SKETCH_COLORS.secondaryFill
2977
+ },
2978
+ children: fallback
2979
+ }
2980
+ )
2981
+ ]
2982
+ }
2983
+ ),
2984
+ status ? /* @__PURE__ */ jsx(
2985
+ "span",
2986
+ {
2987
+ style: {
2988
+ position: "absolute",
2989
+ width: badge,
2990
+ height: badge,
2991
+ right: -1,
2992
+ bottom: -1,
2993
+ zIndex: 2
2994
+ },
2995
+ children: /* @__PURE__ */ jsx(
2996
+ RoughSvg,
2997
+ {
2998
+ shape: "ellipse",
2999
+ roughness: (roughness ?? 1.5) * 0.8,
3000
+ seed: deriveSeed(resolvedSeed, "status"),
3001
+ sketchColor: STATUS_COLOR[status],
3002
+ fill: STATUS_COLOR[status],
3003
+ fillStyle: "solid",
3004
+ bowing,
3005
+ strokeWidth: 1,
3006
+ inset: 0.5
3007
+ }
3008
+ )
3009
+ }
3010
+ ) : null
3011
+ ]
3012
+ }
3013
+ );
3014
+ }
3015
+ );
3016
+ var Slider = forwardRef(function Slider2({
3017
+ className,
3018
+ style,
3019
+ roughness,
3020
+ seed,
3021
+ sketchColor,
3022
+ bowing,
3023
+ fillStyle,
3024
+ strokeWidth,
3025
+ thumbShape = "circle",
3026
+ ...rest
3027
+ }, ref) {
3028
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
3029
+ const resolvedSeed = useResolvedSeed(seed);
3030
+ return /* @__PURE__ */ jsxs(
3031
+ SliderPrimitive.Root,
3032
+ {
3033
+ ref,
3034
+ className: cn(className),
3035
+ style: {
3036
+ position: "relative",
3037
+ display: "flex",
3038
+ alignItems: "center",
3039
+ width: "100%",
3040
+ height: 28,
3041
+ userSelect: "none",
3042
+ touchAction: "none",
3043
+ ...style
3044
+ },
3045
+ ...rest,
3046
+ children: [
3047
+ /* @__PURE__ */ jsxs(
3048
+ SliderPrimitive.Track,
3049
+ {
3050
+ style: {
3051
+ position: "relative",
3052
+ flex: 1,
3053
+ height: 16
3054
+ },
3055
+ children: [
3056
+ /* @__PURE__ */ jsx(
3057
+ RoughSvg,
3058
+ {
3059
+ shape: "line",
3060
+ roughness: roughness ?? 1.8,
3061
+ seed: resolvedSeed,
3062
+ sketchColor: ink,
3063
+ bowing: bowing ?? 2,
3064
+ strokeWidth: strokeWidth ?? 1.6,
3065
+ inset: 4
3066
+ }
3067
+ ),
3068
+ /* @__PURE__ */ jsx(
3069
+ SliderPrimitive.Range,
3070
+ {
3071
+ style: {
3072
+ position: "absolute",
3073
+ left: 0,
3074
+ height: "100%"
3075
+ },
3076
+ children: /* @__PURE__ */ jsx(
3077
+ RoughSvg,
3078
+ {
3079
+ shape: "line",
3080
+ roughness: (roughness ?? 1.5) + 0.4,
3081
+ seed: deriveSeed(resolvedSeed, "range"),
3082
+ sketchColor: SKETCH_COLORS.accent,
3083
+ bowing: bowing ?? 1.6,
3084
+ strokeWidth: (strokeWidth ?? 1.6) + 0.6,
3085
+ inset: 4
3086
+ }
3087
+ )
3088
+ }
3089
+ )
3090
+ ]
3091
+ }
3092
+ ),
3093
+ /* @__PURE__ */ jsx(
3094
+ SliderPrimitive.Thumb,
3095
+ {
3096
+ style: {
3097
+ display: "block",
3098
+ width: 20,
3099
+ height: 20,
3100
+ position: "relative",
3101
+ outline: "none",
3102
+ cursor: "grab"
3103
+ },
3104
+ children: /* @__PURE__ */ jsx(
3105
+ RoughSvg,
3106
+ {
3107
+ shape: thumbShape === "square" ? "rectangle" : "ellipse",
3108
+ roughness: (roughness ?? 1.5) * 0.85,
3109
+ seed: deriveSeed(resolvedSeed, "thumb"),
3110
+ sketchColor: SKETCH_COLORS.accent,
3111
+ fill: "#f7f6f2",
3112
+ fillStyle: fillStyle ?? "solid",
3113
+ bowing,
3114
+ strokeWidth: (strokeWidth ?? 1.5) + 0.3,
3115
+ inset: 1
3116
+ }
3117
+ )
3118
+ }
3119
+ )
3120
+ ]
3121
+ }
3122
+ );
3123
+ });
3124
+ var PREV_PATH = "M 12 4 L 6 10 L 12 16";
3125
+ var NEXT_PATH = "M 6 4 L 12 10 L 6 16";
3126
+ function pageItems(page, count) {
3127
+ if (count <= 7) {
3128
+ return Array.from({ length: count }, (_, i) => i + 1);
3129
+ }
3130
+ const items = [1];
3131
+ const start = Math.max(2, page - 1);
3132
+ const end = Math.min(count - 1, page + 1);
3133
+ if (start > 2) items.push("ellipsis");
3134
+ for (let n = start; n <= end; n += 1) items.push(n);
3135
+ if (end < count - 1) items.push("ellipsis");
3136
+ items.push(count);
3137
+ return items;
3138
+ }
3139
+ var Pagination = forwardRef(
3140
+ function Pagination2({
3141
+ className,
3142
+ style,
3143
+ page,
3144
+ count,
3145
+ onPageChange,
3146
+ roughness,
3147
+ seed,
3148
+ sketchColor,
3149
+ bowing,
3150
+ strokeWidth,
3151
+ ...rest
3152
+ }, ref) {
3153
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
3154
+ const resolvedSeed = useResolvedSeed(seed);
3155
+ const items = pageItems(page, count);
3156
+ return /* @__PURE__ */ jsxs(
3157
+ "nav",
3158
+ {
3159
+ ref,
3160
+ className: cn(className),
3161
+ "aria-label": "Pagination",
3162
+ style: {
3163
+ display: "inline-flex",
3164
+ alignItems: "center",
3165
+ gap: 4,
3166
+ ...style
3167
+ },
3168
+ ...rest,
3169
+ children: [
3170
+ /* @__PURE__ */ jsx(
3171
+ PageButton,
3172
+ {
3173
+ "aria-label": "Previous page",
3174
+ disabled: page <= 1,
3175
+ onClick: () => onPageChange?.(Math.max(1, page - 1)),
3176
+ roughness,
3177
+ seed: deriveSeed(resolvedSeed, "prev"),
3178
+ ink,
3179
+ bowing,
3180
+ strokeWidth,
3181
+ children: /* @__PURE__ */ jsx("span", { style: { position: "relative", width: 16, height: 16, display: "block" }, children: /* @__PURE__ */ jsx(
3182
+ RoughSvg,
3183
+ {
3184
+ shape: "path",
3185
+ path: PREV_PATH,
3186
+ roughness: (roughness ?? 1.5) * 0.7,
3187
+ seed: deriveSeed(resolvedSeed, "prev-arrow"),
3188
+ sketchColor: ink,
3189
+ strokeWidth: (strokeWidth ?? 1.5) + 0.2,
3190
+ inset: 0
3191
+ }
3192
+ ) })
3193
+ }
3194
+ ),
3195
+ items.map(
3196
+ (item, index) => item === "ellipsis" ? /* @__PURE__ */ jsx(
3197
+ "span",
3198
+ {
3199
+ style: {
3200
+ width: 28,
3201
+ textAlign: "center",
3202
+ fontFamily: doodleUiFontFamily,
3203
+ color: ink
3204
+ },
3205
+ children: "\u2026"
3206
+ },
3207
+ `e-${index}`
3208
+ ) : /* @__PURE__ */ jsx(
3209
+ PageButton,
3210
+ {
3211
+ "aria-label": `Page ${item}`,
3212
+ "aria-current": item === page ? "page" : void 0,
3213
+ active: item === page,
3214
+ onClick: () => onPageChange?.(item),
3215
+ roughness,
3216
+ seed: deriveSeed(resolvedSeed, `page-${item}`),
3217
+ ink,
3218
+ bowing,
3219
+ strokeWidth,
3220
+ children: item
3221
+ },
3222
+ item
3223
+ )
3224
+ ),
3225
+ /* @__PURE__ */ jsx(
3226
+ PageButton,
3227
+ {
3228
+ "aria-label": "Next page",
3229
+ disabled: page >= count,
3230
+ onClick: () => onPageChange?.(Math.min(count, page + 1)),
3231
+ roughness,
3232
+ seed: deriveSeed(resolvedSeed, "next"),
3233
+ ink,
3234
+ bowing,
3235
+ strokeWidth,
3236
+ children: /* @__PURE__ */ jsx("span", { style: { position: "relative", width: 16, height: 16, display: "block" }, children: /* @__PURE__ */ jsx(
3237
+ RoughSvg,
3238
+ {
3239
+ shape: "path",
3240
+ path: NEXT_PATH,
3241
+ roughness: (roughness ?? 1.5) * 0.7,
3242
+ seed: deriveSeed(resolvedSeed, "next-arrow"),
3243
+ sketchColor: ink,
3244
+ strokeWidth: (strokeWidth ?? 1.5) + 0.2,
3245
+ inset: 0
3246
+ }
3247
+ ) })
3248
+ }
3249
+ )
3250
+ ]
3251
+ }
3252
+ );
3253
+ }
3254
+ );
3255
+ function PageButton({
3256
+ children,
3257
+ className,
3258
+ style,
3259
+ active,
3260
+ disabled,
3261
+ roughness,
3262
+ seed,
3263
+ ink,
3264
+ bowing,
3265
+ strokeWidth,
3266
+ ...rest
3267
+ }) {
3268
+ return /* @__PURE__ */ jsxs(
3269
+ "button",
3270
+ {
3271
+ type: "button",
3272
+ disabled,
3273
+ className: cn(className),
3274
+ style: {
3275
+ position: "relative",
3276
+ width: 36,
3277
+ height: 36,
3278
+ padding: 0,
3279
+ border: "none",
3280
+ background: "transparent",
3281
+ cursor: disabled ? "not-allowed" : "pointer",
3282
+ color: ink,
3283
+ fontFamily: doodleUiFontFamily,
3284
+ fontWeight: active ? doodleUiFontWeight(700) : doodleUiFontWeight(400),
3285
+ fontSize: 14,
3286
+ outline: "none",
3287
+ opacity: disabled ? 0.4 : 1,
3288
+ ...style
3289
+ },
3290
+ ...rest,
3291
+ children: [
3292
+ /* @__PURE__ */ jsx(
3293
+ RoughSvg,
3294
+ {
3295
+ shape: "ellipse",
3296
+ roughness,
3297
+ seed,
3298
+ sketchColor: active ? SKETCH_COLORS.accent : ink,
3299
+ bowing,
3300
+ fill: active ? SKETCH_COLORS.accentFill : void 0,
3301
+ fillStyle: active ? "hachure" : void 0,
3302
+ strokeWidth: active ? (strokeWidth ?? 1.6) + 0.3 : strokeWidth ?? 1.4,
3303
+ inset: 1.5
3304
+ }
3305
+ ),
3306
+ active ? /* @__PURE__ */ jsx(
3307
+ RoughSvg,
3308
+ {
3309
+ shape: "ellipse",
3310
+ roughness: (roughness ?? 1.5) + 0.45,
3311
+ seed,
3312
+ sketchColor: SKETCH_COLORS.accent,
3313
+ bowing: bowing ?? 1.6,
3314
+ strokeWidth: 1.1,
3315
+ inset: -1.5,
3316
+ style: { opacity: 0.7 }
3317
+ }
3318
+ ) : null,
3319
+ /* @__PURE__ */ jsx("span", { style: { position: "relative", zIndex: 1 }, children })
3320
+ ]
3321
+ }
3322
+ );
3323
+ }
3324
+ var SLASH_PATH = "M 10 3 L 6 15";
3325
+ var CHEVRON_PATH3 = "M 5 4 L 11 9 L 5 14";
3326
+ var BreadcrumbSketchContext = createContext(null);
3327
+ function useBreadcrumbSketch() {
3328
+ const ctx = useContext(BreadcrumbSketchContext);
3329
+ if (!ctx) {
3330
+ throw new Error("BreadcrumbItem must be used inside <Breadcrumb>.");
3331
+ }
3332
+ return ctx;
3333
+ }
3334
+ var Breadcrumb = forwardRef(
3335
+ function Breadcrumb2({
3336
+ className,
3337
+ style,
3338
+ children,
3339
+ separator = "slash",
3340
+ roughness,
3341
+ seed,
3342
+ sketchColor,
3343
+ bowing,
3344
+ strokeWidth,
3345
+ ...rest
3346
+ }, ref) {
3347
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
3348
+ const resolvedSeed = useResolvedSeed(seed);
3349
+ const items = Children.toArray(children).filter(isValidElement);
3350
+ return /* @__PURE__ */ jsx(
3351
+ BreadcrumbSketchContext.Provider,
3352
+ {
3353
+ value: {
3354
+ roughness,
3355
+ seed: resolvedSeed,
3356
+ sketchColor,
3357
+ bowing,
3358
+ strokeWidth,
3359
+ resolvedSeed,
3360
+ ink,
3361
+ separator
3362
+ },
3363
+ children: /* @__PURE__ */ jsx(
3364
+ "nav",
3365
+ {
3366
+ ref,
3367
+ className: cn(className),
3368
+ "aria-label": "Breadcrumb",
3369
+ style,
3370
+ ...rest,
3371
+ children: /* @__PURE__ */ jsx(
3372
+ "ol",
3373
+ {
3374
+ style: {
3375
+ display: "flex",
3376
+ flexWrap: "wrap",
3377
+ alignItems: "center",
3378
+ gap: 4,
3379
+ listStyle: "none",
3380
+ margin: 0,
3381
+ padding: 0,
3382
+ fontFamily: doodleUiFontFamily,
3383
+ color: ink,
3384
+ fontSize: 14
3385
+ },
3386
+ children: items.map((child, index) => /* @__PURE__ */ jsxs(
3387
+ "li",
3388
+ {
3389
+ style: { display: "inline-flex", alignItems: "center", gap: 4 },
3390
+ children: [
3391
+ cloneElement(child, {
3392
+ index
3393
+ }),
3394
+ index < items.length - 1 ? /* @__PURE__ */ jsx(
3395
+ SeparatorMark,
3396
+ {
3397
+ index,
3398
+ separator,
3399
+ resolvedSeed,
3400
+ roughness,
3401
+ ink,
3402
+ bowing,
3403
+ strokeWidth
3404
+ }
3405
+ ) : null
3406
+ ]
3407
+ },
3408
+ index
3409
+ ))
3410
+ }
3411
+ )
3412
+ }
3413
+ )
3414
+ }
3415
+ );
3416
+ }
3417
+ );
3418
+ function SeparatorMark({
3419
+ index,
3420
+ separator,
3421
+ resolvedSeed,
3422
+ roughness,
3423
+ ink,
3424
+ bowing,
3425
+ strokeWidth
3426
+ }) {
3427
+ return /* @__PURE__ */ jsx(
3428
+ "span",
3429
+ {
3430
+ "aria-hidden": "true",
3431
+ style: { position: "relative", width: 16, height: 18, display: "inline-block" },
3432
+ children: /* @__PURE__ */ jsx(
3433
+ RoughSvg,
3434
+ {
3435
+ shape: "path",
3436
+ path: separator === "chevron" ? CHEVRON_PATH3 : SLASH_PATH,
3437
+ roughness: (roughness ?? 1.5) * 0.85,
3438
+ seed: deriveSeed(resolvedSeed, `sep-${index}`),
3439
+ sketchColor: ink,
3440
+ bowing: bowing ?? 1.6,
3441
+ strokeWidth: strokeWidth ?? 1.4,
3442
+ inset: 0
3443
+ }
3444
+ )
3445
+ }
3446
+ );
3447
+ }
3448
+ var BreadcrumbItem = forwardRef(
3449
+ function BreadcrumbItem2({ className, style, href, current, children, index: _index, ...rest }, ref) {
3450
+ const sketch = useBreadcrumbSketch();
3451
+ const contentStyle = {
3452
+ color: current ? sketch.ink : sketch.ink,
3453
+ opacity: current ? 1 : 0.75,
3454
+ textDecoration: "none",
3455
+ fontFamily: doodleUiFontFamily,
3456
+ ...style
3457
+ };
3458
+ if (href && !current) {
3459
+ return /* @__PURE__ */ jsx(
3460
+ "a",
3461
+ {
3462
+ href,
3463
+ className: cn(className),
3464
+ style: contentStyle,
3465
+ ...rest,
3466
+ children
3467
+ }
3468
+ );
3469
+ }
3470
+ return /* @__PURE__ */ jsx(
3471
+ "span",
3472
+ {
3473
+ ref,
3474
+ className: cn(className),
3475
+ "aria-current": current ? "page" : void 0,
3476
+ style: contentStyle,
3477
+ ...rest,
3478
+ children
3479
+ }
3480
+ );
3481
+ }
3482
+ );
3483
+ var Skeleton = forwardRef(
3484
+ function Skeleton2({
3485
+ className,
3486
+ style,
3487
+ variant = "rect",
3488
+ pulse = true,
3489
+ width,
3490
+ height,
3491
+ roughness,
3492
+ seed,
3493
+ sketchColor,
3494
+ bowing,
3495
+ fillStyle,
3496
+ strokeWidth,
3497
+ ...rest
3498
+ }, ref) {
3499
+ const base = useResolvedSeed(seed);
3500
+ const [tick, setTick] = useState(0);
3501
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
3502
+ useEffect(() => {
3503
+ if (!pulse) return;
3504
+ const id = window.setInterval(() => {
3505
+ setTick((current) => current + 1);
3506
+ }, 900);
3507
+ return () => window.clearInterval(id);
3508
+ }, [pulse]);
3509
+ const resolved = pulse ? deriveSeed(base, `pulse-${tick}`) : base;
3510
+ const shape = variant === "circle" ? "ellipse" : "rectangle";
3511
+ const defaultHeight = variant === "text" ? 14 : variant === "circle" ? 40 : 80;
3512
+ const defaultWidth = variant === "circle" ? 40 : "100%";
3513
+ return /* @__PURE__ */ jsx(
3514
+ "div",
3515
+ {
3516
+ ref,
3517
+ "aria-hidden": "true",
3518
+ className: cn(className),
3519
+ style: {
3520
+ position: "relative",
3521
+ width: width ?? defaultWidth,
3522
+ height: height ?? defaultHeight,
3523
+ maxWidth: "100%",
3524
+ ...style
3525
+ },
3526
+ ...rest,
3527
+ children: /* @__PURE__ */ jsx(
3528
+ RoughSvg,
3529
+ {
3530
+ shape,
3531
+ roughness: (roughness ?? 1.5) + 0.4,
3532
+ seed: resolved,
3533
+ sketchColor: ink,
3534
+ fill: ink,
3535
+ fillStyle: fillStyle ?? "hachure",
3536
+ bowing: bowing ?? 1.6,
3537
+ strokeWidth: strokeWidth ?? 1.1,
3538
+ inset: 2,
3539
+ style: { opacity: 0.28 }
3540
+ }
3541
+ )
3542
+ }
3543
+ );
3544
+ }
3545
+ );
3546
+ function normalizeSteps(steps) {
3547
+ return steps.map(
3548
+ (step) => step !== null && typeof step === "object" && "label" in step ? step : { label: step }
3549
+ );
3550
+ }
3551
+ var Stepper = forwardRef(
3552
+ function Stepper2({
3553
+ className,
3554
+ style,
3555
+ steps,
3556
+ current = 0,
3557
+ orientation = "horizontal",
3558
+ roughness,
3559
+ seed,
3560
+ sketchColor,
3561
+ bowing,
3562
+ fillStyle,
3563
+ strokeWidth,
3564
+ ...rest
3565
+ }, ref) {
3566
+ const ink = sketchColor ?? SKETCH_COLORS.ink;
3567
+ const resolvedSeed = useResolvedSeed(seed);
3568
+ const items = normalizeSteps(steps);
3569
+ const horizontal = orientation === "horizontal";
3570
+ return /* @__PURE__ */ jsx(
3571
+ "div",
3572
+ {
3573
+ ref,
3574
+ role: "list",
3575
+ className: cn(className),
3576
+ style: {
3577
+ display: "flex",
3578
+ flexDirection: horizontal ? "row" : "column",
3579
+ alignItems: horizontal ? "flex-start" : "stretch",
3580
+ ...style
3581
+ },
3582
+ ...rest,
3583
+ children: items.map((step, index) => {
3584
+ const complete = index < current;
3585
+ const active = index === current;
3586
+ const markerColor = complete || active ? SKETCH_COLORS.accent : ink;
3587
+ return /* @__PURE__ */ jsxs(
3588
+ "div",
3589
+ {
3590
+ role: "listitem",
3591
+ "aria-current": active ? "step" : void 0,
3592
+ style: {
3593
+ display: "flex",
3594
+ flex: horizontal ? 1 : void 0,
3595
+ flexDirection: horizontal ? "column" : "row",
3596
+ alignItems: horizontal ? "center" : "flex-start",
3597
+ minWidth: 0
3598
+ },
3599
+ children: [
3600
+ /* @__PURE__ */ jsxs(
3601
+ "div",
3602
+ {
3603
+ style: {
3604
+ display: "flex",
3605
+ flexDirection: horizontal ? "row" : "column",
3606
+ alignItems: "center",
3607
+ width: horizontal ? "100%" : void 0
3608
+ },
3609
+ children: [
3610
+ /* @__PURE__ */ jsxs(
3611
+ "span",
3612
+ {
3613
+ style: {
3614
+ position: "relative",
3615
+ width: 28,
3616
+ height: 28,
3617
+ flexShrink: 0,
3618
+ display: "inline-flex",
3619
+ alignItems: "center",
3620
+ justifyContent: "center",
3621
+ fontFamily: doodleUiFontFamily,
3622
+ fontWeight: doodleUiFontWeight(700),
3623
+ fontSize: 13,
3624
+ color: markerColor
3625
+ },
3626
+ children: [
3627
+ /* @__PURE__ */ jsx(
3628
+ RoughSvg,
3629
+ {
3630
+ shape: "ellipse",
3631
+ roughness,
3632
+ seed: deriveSeed(resolvedSeed, `step-${index}`),
3633
+ sketchColor: markerColor,
3634
+ fill: complete ? SKETCH_COLORS.accentFill : active ? "#f7f6f2" : void 0,
3635
+ fillStyle: complete || active ? fillStyle ?? "hachure" : void 0,
3636
+ bowing,
3637
+ strokeWidth: active ? (strokeWidth ?? 1.6) + 0.4 : strokeWidth ?? 1.5,
3638
+ inset: 1.5
3639
+ }
3640
+ ),
3641
+ /* @__PURE__ */ jsx("span", { style: { position: "relative", zIndex: 1 }, children: complete ? "\u2713" : index + 1 })
3642
+ ]
3643
+ }
3644
+ ),
3645
+ index < items.length - 1 ? /* @__PURE__ */ jsx(
3646
+ "span",
3647
+ {
3648
+ style: {
3649
+ position: "relative",
3650
+ flex: 1,
3651
+ width: horizontal ? void 0 : 12,
3652
+ height: horizontal ? 12 : 28,
3653
+ minWidth: horizontal ? 16 : 12,
3654
+ alignSelf: "center"
3655
+ },
3656
+ children: /* @__PURE__ */ jsx(
3657
+ RoughSvg,
3658
+ {
3659
+ shape: horizontal ? "line" : "line-vertical",
3660
+ roughness: (roughness ?? 1.5) + 0.3,
3661
+ seed: deriveSeed(resolvedSeed, `connector-${index}`),
3662
+ sketchColor: complete ? SKETCH_COLORS.accent : ink,
3663
+ bowing: bowing ?? 2,
3664
+ strokeWidth: strokeWidth ?? 1.4,
3665
+ inset: 2
3666
+ }
3667
+ )
3668
+ }
3669
+ ) : null
3670
+ ]
3671
+ }
3672
+ ),
3673
+ /* @__PURE__ */ jsxs(
3674
+ "div",
3675
+ {
3676
+ style: {
3677
+ marginTop: horizontal ? 8 : 0,
3678
+ marginLeft: horizontal ? 0 : 10,
3679
+ paddingBottom: horizontal ? 0 : 8,
3680
+ textAlign: horizontal ? "center" : "left",
3681
+ fontFamily: doodleUiFontFamily,
3682
+ fontSize: 13,
3683
+ color: ink
3684
+ },
3685
+ children: [
3686
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: doodleUiFontWeight(600) }, children: step.label }),
3687
+ step.description ? /* @__PURE__ */ jsx("div", { style: { opacity: 0.7, fontSize: 12, marginTop: 2 }, children: step.description }) : null
3688
+ ]
3689
+ }
3690
+ )
3691
+ ]
3692
+ },
3693
+ index
3694
+ );
3695
+ })
3696
+ }
3697
+ );
3698
+ }
3699
+ );
1256
3700
 
1257
- export { Alert, Badge, Button, Card, Checkbox, DEFAULT_BOWING, DEFAULT_INK, DEFAULT_ROUGHNESS, DEFAULT_STROKE_WIDTH, Divider, Input, Modal, ModalClose, ModalDescription, ModalRoot, ModalTitle, ModalTrigger, Progress, Radio, RadioGroup, RoughSvg, SKETCH_COLORS, SketchBox, SketchSeedProvider, Textarea, Tooltip, TooltipProvider, toRoughOptions, useResolvedSeed, useSketchSeed };
3701
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, Avatar, Badge, Breadcrumb, BreadcrumbItem, Button, Card, Checkbox, DEFAULT_BOWING, DEFAULT_INK, DEFAULT_ROUGHNESS, DEFAULT_STROKE_WIDTH, DRAW_IN_ALERT_MS, DRAW_IN_DURATION_MS, DRAW_IN_MARK_MS, DRAW_IN_TOOLTIP_MS, Divider, DoodleUIProvider, Input, Modal, ModalClose, ModalDescription, ModalRoot, ModalTitle, ModalTrigger, Pagination, Progress, Radio, RadioGroup, RoughSvg, SKETCH_COLORS, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectRoot, SelectSeparator, SelectTrigger, SelectValue, Skeleton, SketchBox, SketchSeedProvider, Slider, Stepper, Switch, TABLE_STAGGER_MS, Tab, TabList, TabPanel, Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, Tabs, Textarea, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastRoot, ToastTitle, ToastViewport, Tooltip, TooltipProvider, deriveSeed, toRoughOptions, useAnimate, useDoodleUI, useDrawIn, useResolvedSeed, useSketchSeed };
1258
3702
  //# sourceMappingURL=index.js.map
1259
3703
  //# sourceMappingURL=index.js.map