lilact 0.16.0 → 0.16.2

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.
Files changed (65) hide show
  1. package/README.md +5 -5
  2. package/bin/bundle.cjs +19 -16
  3. package/bin/copy-demo.js +1 -1
  4. package/dist/lilact.development.js +115 -117
  5. package/dist/lilact.development.js.map +3 -3
  6. package/dist/lilact.development.min.js +19 -19
  7. package/dist/lilact.development.min.js.map +3 -3
  8. package/dist/lilact.production.min.js +19 -19
  9. package/docs/functions/accessories.DragHandle.html +2 -2
  10. package/docs/functions/timers.timeoutPromise.html +1 -1
  11. package/docs/index.html +4 -4
  12. package/docs/static/demos/pane.jsx +2 -1
  13. package/docs/static/index.html +1 -1
  14. package/docs/static/lilact.development.js +115 -117
  15. package/docs/static/lilact.development.js.map +3 -3
  16. package/docs/static/lilact.development.min.js +19 -19
  17. package/docs/static/lilact.development.min.js.map +3 -3
  18. package/docs/static/lilact.production.min.js +19 -19
  19. package/docs/variables/accessories.SplitPane.html +2 -2
  20. package/{root → examples}/demos/pane.jsx +2 -1
  21. package/{root → examples}/index.html +1 -1
  22. package/{root → examples}/lilact.development.js +115 -117
  23. package/{root → examples}/lilact.development.js.map +3 -3
  24. package/examples/lilact.development.min.js +107 -0
  25. package/{root → examples}/lilact.development.min.js.map +3 -3
  26. package/examples/lilact.production.min.js +106 -0
  27. package/package.json +3 -3
  28. package/scripts/build.mjs +29 -0
  29. package/scripts/copy-dist-to-examples.mjs +42 -0
  30. package/scripts/esbuild-preprocessor-plugin.cjs +29 -4
  31. package/scripts/preprocess.mjs +29 -1
  32. package/src/accessories.jsx +152 -161
  33. package/src/jsx.js +13 -15
  34. package/typedoc.json +1 -1
  35. package/root/lilact.development.min.js +0 -107
  36. package/root/lilact.production.min.js +0 -106
  37. package/scripts/copy-dist-to-root.mjs +0 -13
  38. /package/{root → examples}/demos/actionstate.jsx +0 -0
  39. /package/{root → examples}/demos/capture.jsx +0 -0
  40. /package/{root → examples}/demos/context.jsx +0 -0
  41. /package/{root → examples}/demos/css-transition.jsx +0 -0
  42. /package/{root → examples}/demos/error-boundary.jsx +0 -0
  43. /package/{root → examples}/demos/error-callback.jsx +0 -0
  44. /package/{root → examples}/demos/error-component-stack.jsx +0 -0
  45. /package/{root → examples}/demos/error-init.jsx +0 -0
  46. /package/{root → examples}/demos/error-parser.jsx +0 -0
  47. /package/{root → examples}/demos/form-elements.jsx +0 -0
  48. /package/{root → examples}/demos/forwardref.jsx +0 -0
  49. /package/{root → examples}/demos/lazy.jsx +0 -0
  50. /package/{root → examples}/demos/modal.jsx +0 -0
  51. /package/{root → examples}/demos/proptypes.jsx +0 -0
  52. /package/{root → examples}/demos/reducer.jsx +0 -0
  53. /package/{root → examples}/demos/redux.jsx +0 -0
  54. /package/{root → examples}/demos/router.jsx +0 -0
  55. /package/{root → examples}/demos/stopwatch.jsx +0 -0
  56. /package/{root → examples}/demos/suspense.jsx +0 -0
  57. /package/{root → examples}/demos/switch-transition.jsx +0 -0
  58. /package/{root → examples}/demos/transition.jsx +0 -0
  59. /package/{root → examples}/demos/usedefered.jsx +0 -0
  60. /package/{root → examples}/demos/usetransition.jsx +0 -0
  61. /package/{root → examples}/icon.png +0 -0
  62. /package/{root → examples}/prismjs/LICENSE.md +0 -0
  63. /package/{root → examples}/prismjs/prism-jsx.min.js +0 -0
  64. /package/{root → examples}/prismjs/prism.min.css +0 -0
  65. /package/{root → examples}/prismjs/prism.min.js +0 -0
@@ -284,7 +284,7 @@ export class Suspense extends Component
284
284
  * @param {string} [props.className] Optional CSS class applied to the wrapper element.
285
285
  * A `.dragging` class will be also applied when dragging.
286
286
  *
287
- * @param {React.ReactNode} [props.children] Content rendered inside the handle.
287
+ * @param {Component} [props.children] Content rendered inside the handle.
288
288
  */
289
289
 
290
290
  export function DragHandle({
@@ -387,12 +387,6 @@ export function DragHandle({
387
387
  }
388
388
 
389
389
 
390
-
391
- const clamp = (n, min, max) => {
392
- if (!Number.isFinite(n)) return n;
393
- return Math.min(max, Math.max(min, n));
394
- };
395
-
396
390
  /**
397
391
  * A split-pane container with a draggable splitter, supporting both horizontal and vertical layouts.
398
392
  *
@@ -430,7 +424,7 @@ const clamp = (n, min, max) => {
430
424
  * @param leftPaneStyle - Optional styles applied to the left pane (or top pane in vertical mode).
431
425
  * @param rightPaneStyle - Optional styles applied to the right pane (or bottom pane in vertical mode).
432
426
  * @param splitterStyle - Optional styles applied to the splitter element.
433
- * @param children - React children to be rendered into the two pane containers.
427
+ * @param children - Children to be rendered into the two pane containers.
434
428
  *
435
429
  * @example
436
430
  * ```tsx
@@ -448,10 +442,11 @@ const clamp = (n, min, max) => {
448
442
  * </SplitPane>
449
443
  * ```
450
444
  */
445
+
451
446
  export const SplitPane = forwardRef(function SplitPane(
452
447
  {
453
448
  mode = "horizontal",
454
- position, // controlled: number | undefined/null
449
+ position,
455
450
  defaultPosition = 0.5,
456
451
  min = 0.1,
457
452
  max = 0.9,
@@ -459,198 +454,194 @@ export const SplitPane = forwardRef(function SplitPane(
459
454
  onSizeChange,
460
455
  style,
461
456
  className,
462
- leftPaneStyle,
463
- rightPaneStyle,
457
+ firstPaneStyle,
458
+ secondPaneStyle,
464
459
  splitterStyle,
465
460
  children,
466
461
  },
467
462
  ref
468
463
  ) {
469
- const containerRef = useRef(null);
470
- const panes = Children.toArray(children);
471
- const leftChild = panes[0] ?? null;
472
- const rightChild = panes[1] ?? null;
464
+ const initialMode = mode === "vertical" ? "vertical" : "horizontal";
465
+ const [internalMode, setInternalMode] = useState(initialMode);
473
466
 
474
- const isControlled = position != null;
467
+ const [internalPos, setInternalPos] = useState(clamp(defaultPosition, min, max));
468
+ const posResolved = position == null ? internalPos : clamp(position, min, max);
475
469
 
476
- const [internalMode, setInternalMode] = useState(mode);
477
-
478
- const [posUncontrolled, setPosUncontrolled] = useState(() =>
479
- clamp(
480
- position ?? defaultPosition,
481
- min,
482
- max
483
- )
484
- );
470
+ useEffect(() => {
471
+ if (position == null) return;
472
+ setInternalPos(clamp(position, min, max));
473
+ }, [position, min, max]);
485
474
 
486
475
  useEffect(() => {
487
- if (mode != null) setInternalMode(mode);
476
+ setInternalMode(mode === "vertical" ? "vertical" : "horizontal");
488
477
  }, [mode]);
489
478
 
490
- // keep internal position clamped if min/max change (uncontrolled only)
491
- useLayoutEffect(() => {
492
- if (isControlled) return;
493
- setPosUncontrolled((p) => clamp(p, min, max));
494
- }, [min, max, isControlled]);
495
-
496
- const posResolved = isControlled ? clamp(position, min, max) : posUncontrolled;
497
-
498
479
  const setPosition = (next) => {
499
480
  const clamped = clamp(next, min, max);
500
- if (!isControlled) setPosUncontrolled(clamped);
481
+ if (position == null) setInternalPos(clamped);
501
482
  onSizeChange?.(clamped);
502
483
  };
503
484
 
504
- const draggingRef = useRef(false);
505
- const pointerIdRef = useRef(null);
485
+ useImperativeHandle(ref, () => ({
486
+ setPosition,
487
+ setMode: (nextMode) => setInternalMode(nextMode === "vertical" ? "vertical" : "horizontal"),
488
+ getPosition: () => posResolved,
489
+ getMode: () => internalMode,
490
+ }));
491
+
492
+ const containerRef = useRef(null);
493
+ const sizeRef = useRef({ w: 0, h: 0 });
506
494
 
507
- const updateFromClient = (clientX, clientY) => {
495
+ useLayoutEffect(() => {
508
496
  const el = containerRef.current;
509
497
  if (!el) return;
510
498
 
499
+ const ro = new ResizeObserver(() => {
500
+ const rect = el.getBoundingClientRect();
501
+ sizeRef.current = { w: rect.width, h: rect.height };
502
+ });
503
+
504
+ ro.observe(el);
511
505
  const rect = el.getBoundingClientRect();
506
+ sizeRef.current = { w: rect.width, h: rect.height };
512
507
 
513
- if (internalMode === "horizontal") {
514
- const usable = rect.width;
515
- if (!Number.isFinite(usable) || usable <= 0) return; // no jump on init
516
- const raw = (clientX - rect.left) / usable;
517
- if (!Number.isFinite(raw)) return;
518
- setPosition(raw);
519
- } else {
520
- const usable = rect.height;
521
- if (!Number.isFinite(usable) || usable <= 0) return; // no jump on init
522
- const raw = (clientY - rect.top) / usable;
523
- if (!Number.isFinite(raw)) return;
524
- setPosition(raw);
525
- }
526
- };
508
+ return () => ro.disconnect();
509
+ }, []);
527
510
 
528
- // stable global listeners: only act while draggingRef.current === true
529
- useEffect(() => {
530
- const onMove = (e) => {
531
- if (!draggingRef.current) return;
532
- if (pointerIdRef.current != null && e.pointerId !== pointerIdRef.current) return;
533
- updateFromClient(e.clientX, e.clientY);
534
- };
535
-
536
- const stop = (e) => {
537
- if (!draggingRef.current) return;
538
- if (pointerIdRef.current != null && e.pointerId !== pointerIdRef.current) return;
539
- draggingRef.current = false;
540
- pointerIdRef.current = null;
541
- };
542
-
543
- window.addEventListener("pointermove", onMove, { passive: true });
544
- window.addEventListener("pointerup", stop, { passive: true });
545
- window.addEventListener("pointercancel", stop, { passive: true });
546
-
547
- return () => {
548
- window.removeEventListener("pointermove", onMove);
549
- window.removeEventListener("pointerup", stop);
550
- window.removeEventListener("pointercancel", stop);
551
- };
552
- }, [internalMode]); // updateFromClient uses internalMode
553
-
554
- const onPointerDown = (e) => {
555
- if (e.button != null && e.button !== 0) return;
556
- e.preventDefault();
557
-
558
- draggingRef.current = true;
559
- pointerIdRef.current = e.pointerId;
560
-
561
- try {
562
- e.currentTarget.setPointerCapture?.(e.pointerId);
563
- } catch {}
564
-
565
- updateFromClient(e.clientX, e.clientY); // first update only if rect is sane
566
- };
511
+ const startPosRef = useRef(posResolved);
512
+ const [dragging, setDragging] = useState(false);
567
513
 
568
- const onKeyDown = (e) => {
569
- const step = 0.02;
570
- let delta = 0;
514
+ const handleStart = () => {
515
+ setDragging(true);
516
+ startPosRef.current = posResolved;
517
+ };
571
518
 
519
+ // DragHandle in your description: onDelta(x, y, data)
520
+ const handleDelta = (x, y, _data) => {
521
+ const { w, h } = sizeRef.current;
572
522
  if (internalMode === "horizontal") {
573
- if (e.key === "ArrowLeft") delta = -step;
574
- if (e.key === "ArrowRight") delta = step;
523
+ setPosition(startPosRef.current + x / (w || 1));
575
524
  } else {
576
- if (e.key === "ArrowUp") delta = -step;
577
- if (e.key === "ArrowDown") delta = step;
578
- }
579
-
580
- if (delta !== 0) {
581
- e.preventDefault();
582
- setPosition(posResolved + delta);
525
+ setPosition(startPosRef.current + y / (h || 1));
583
526
  }
584
527
  };
585
528
 
586
- const sizes = useMemo(() => {
587
- const leftPct = `${posResolved * 100}%`;
588
- const rightCalc = `calc(${100 - posResolved * 100}% - ${splitterSize}px)`;
589
- return { leftPct, rightCalc };
590
- }, [posResolved, splitterSize]);
591
-
592
- const rootStyle = {
593
- display: "flex",
594
- width: "100%",
595
- height: "100%",
596
- overflow: "hidden",
597
- touchAction: "none",
598
- ...(style || {}),
599
- flexDirection: internalMode === "horizontal" ? "row" : "column",
600
- };
529
+ const handleEnd = () => setDragging(false);
601
530
 
602
- const leftPaneComputed =
603
- internalMode === "horizontal"
604
- ? { width: sizes.leftPct, flex: `0 0 ${sizes.leftPct}`, overflow: "auto", ...(leftPaneStyle || {}) }
605
- : { height: sizes.leftPct, flex: `0 0 ${sizes.leftPct}`, overflow: "auto", ...(leftPaneStyle || {}) };
531
+ const arr = Children.toArray(children);
532
+ const firstChild = arr[0];
533
+ const secondChild = arr[1];
606
534
 
607
- const rightPaneComputed =
608
- internalMode === "horizontal"
609
- ? { width: sizes.rightCalc, flex: "1 1 auto", overflow: "auto", ...(rightPaneStyle || {}) }
610
- : { height: sizes.rightCalc, flex: "1 1 auto", overflow: "auto", ...(rightPaneStyle || {}) };
535
+ const p = posResolved;
611
536
 
612
- const splitterComputed =
537
+ const pane1StyleAbs =
613
538
  internalMode === "horizontal"
614
- ? { width: `${splitterSize}px`, transform: "translateX(-50%)", height: '100%', flex: `0 0 ${splitterSize}px`, background: "rgba(0,0,0,0.08)", cursor: "col-resize", ...(splitterStyle || {}) }
615
- : { height: `${splitterSize}px`, transform: "translateY(-50%)", width: '100%', flex: `0 0 ${splitterSize}px`, background: "rgba(0,0,0,0.08)", cursor: "row-resize", ...(splitterStyle || {}) };
616
-
617
- const dividerVisualStyle =
539
+ ? {
540
+ position: "absolute",
541
+ top: 0,
542
+ bottom: 0,
543
+ left: 0,
544
+ width: `calc(${p} * (100% - ${splitterSize}px))`,
545
+ overflow: "auto",
546
+ ...(firstPaneStyle || {}),
547
+ }
548
+ : {
549
+ position: "absolute",
550
+ left: 0,
551
+ right: 0,
552
+ top: 0,
553
+ height: `calc(${p} * (100% - ${splitterSize}px))`,
554
+ overflow: "auto",
555
+ ...(firstPaneStyle || {}),
556
+ };
557
+
558
+ const pane2StyleAbs =
618
559
  internalMode === "horizontal"
619
- ? { height: "100%", width: "100%" }
620
- : { width: "100%", height: "100%" };
560
+ ? {
561
+ position: "absolute",
562
+ top: 0,
563
+ bottom: 0,
564
+ left: `calc(${p} * (100% - ${splitterSize}px) + ${splitterSize}px)`,
565
+ right: 0,
566
+ overflow: "auto",
567
+ ...(secondPaneStyle || {}),
568
+ }
569
+ : {
570
+ position: "absolute",
571
+ left: 0,
572
+ right: 0,
573
+ top: `calc(${p} * (100% - ${splitterSize}px) + ${splitterSize}px)`,
574
+ bottom: 0,
575
+ overflow: "auto",
576
+ ...(secondPaneStyle || {}),
577
+ };
578
+
579
+ // Basic visible default for splitter (so it doesn't "disappear" on mode switch).
580
+ // Also give zIndex + background and keep pointer events enabled.
581
+ const splitterBase = {
582
+ background: "rgba(0,0,0,0.08)",
583
+ boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.15)",
584
+ zIndex: 10,
585
+ };
621
586
 
622
- useImperativeHandle(ref, () => ({
623
- setPosition,
624
- setMode: (nextMode) => setInternalMode(nextMode === "vertical" ? "vertical" : "horizontal"),
625
- getPosition: () => posResolved,
626
- getMode: () => internalMode,
627
- }));
587
+ const splitterAbsStyle =
588
+ internalMode === "horizontal"
589
+ ? {
590
+ position: "absolute",
591
+ top: 0,
592
+ bottom: 0,
593
+ left: `calc(${p} * (100% - ${splitterSize}px))`,
594
+ width: splitterSize,
595
+ height: "100%",
596
+
597
+ cursor: dragging ? "col-resize" : "col-resize",
598
+ touchAction: "none",
599
+ pointerEvents: "auto",
600
+
601
+ ...splitterBase,
602
+ ...(splitterStyle || {}),
603
+ }
604
+ : {
605
+ position: "absolute",
606
+ left: 0,
607
+ right: 0,
608
+ top: `calc(${p} * (100% - ${splitterSize}px))`,
609
+ height: splitterSize,
610
+ width: "100%",
611
+
612
+ cursor: dragging ? "row-resize" : "row-resize",
613
+ touchAction: "none",
614
+ pointerEvents: "auto",
615
+
616
+ ...splitterBase,
617
+ ...(splitterStyle || {}),
618
+ };
628
619
 
629
620
  return (
630
- <div ref={containerRef} className={className} style={rootStyle}>
631
- <div style={leftPaneComputed}>{leftChild}</div>
632
-
633
- <div
634
- role="separator"
635
- aria-orientation={internalMode === "horizontal" ? "vertical" : "horizontal"}
636
- aria-valuemin={min}
637
- aria-valuemax={max}
638
- aria-valuenow={posResolved}
639
- tabIndex={0}
640
- onPointerDown={onPointerDown}
641
- onPointerCancel={() => {
642
- draggingRef.current = false;
643
- pointerIdRef.current = null;
644
- }}
645
- onKeyDown={onKeyDown}
646
- style={splitterComputed}
647
- >
648
- <div style={dividerVisualStyle} />
649
- </div>
650
-
651
- <div style={rightPaneComputed}>{rightChild}</div>
621
+ <div
622
+ ref={containerRef}
623
+ className={className}
624
+ style={{
625
+ position: "relative",
626
+ width: "100%",
627
+ height: "100%",
628
+ overflow: "hidden",
629
+ ...(style || {}),
630
+ }}
631
+ >
632
+ <div style={pane1StyleAbs}>{firstChild}</div>
633
+ <div style={pane2StyleAbs}>{secondChild}</div>
634
+
635
+ {/* Keep the DragHandle mounted across mode changes (only its absolute coordinates change). */}
636
+ <DragHandle
637
+ onStart={handleStart}
638
+ onDelta={handleDelta}
639
+ onEnd={handleEnd}
640
+ style={splitterAbsStyle}
641
+ />
652
642
  </div>
653
643
  );
654
644
  });
655
645
 
656
646
 
647
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
package/src/jsx.js CHANGED
@@ -583,25 +583,23 @@ function parseXML(code, index, container, look_behind=false)
583
583
  break;
584
584
 
585
585
  case '>':
586
- {
587
- const i = parseXMLContent(code, index, b);
586
+ const j = parseXMLContent(code, index, b);
588
587
 
589
- // not xml
590
- // todo: side effects must be checked
591
- if(i===null) return;
588
+ // not xml
589
+ // todo: side effects must be checked
590
+ if(j===null) return;
592
591
 
593
- if(i>index) index = i;
594
- else index++;
592
+ if(j>index) index = j;
593
+ else index++;
595
594
 
596
- if(b.end) {
597
- if(container) container.children.push(b);
598
- return b;
599
- }
600
- else {
601
- index++;
602
- }
603
- break;
595
+ if(b.end) {
596
+ if(container) container.children.push(b);
597
+ return b;
604
598
  }
599
+ else {
600
+ index++;
601
+ }
602
+ break;
605
603
 
606
604
  case ' ':
607
605
  case '\t':
package/typedoc.json CHANGED
@@ -15,7 +15,7 @@
15
15
  ".tmp/src/hooks.jsx",
16
16
  ".tmp/src/misc.jsx",
17
17
  ".tmp/src/run.jsx",
18
- //".tmp/src/jsxx.jsx",
18
+ //".tmp/src/jsx.jsx",
19
19
  ".tmp/src/redux.jsx",
20
20
  ".tmp/src/timers.jsx",
21
21
  ".tmp/src/transition.jsx",