@almadar/ui 5.13.2 → 5.14.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/avl/index.js CHANGED
@@ -10,8 +10,8 @@ import { Loader2, X, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil
10
10
  import * as PhosphorIcons from '@phosphor-icons/react';
11
11
  import * as TablerIcons from '@tabler/icons-react';
12
12
  import * as FaIcons from 'react-icons/fa';
13
- import { evaluate, createMinimalContext } from '@almadar/evaluator';
14
13
  import { createPortal } from 'react-dom';
14
+ import { evaluate, createMinimalContext } from '@almadar/evaluator';
15
15
  import { Link, Outlet, useLocation } from 'react-router-dom';
16
16
  import ReactMarkdown from 'react-markdown';
17
17
  import remarkGfm from 'remark-gfm';
@@ -6807,7 +6807,7 @@ var init_Modal = __esm({
6807
6807
  document.body.style.overflow = "";
6808
6808
  };
6809
6809
  }, [isOpen]);
6810
- if (!isOpen) return null;
6810
+ if (!isOpen || typeof document === "undefined") return null;
6811
6811
  const handleClose = () => {
6812
6812
  if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
6813
6813
  onClose();
@@ -6817,124 +6817,127 @@ var init_Modal = __esm({
6817
6817
  handleClose();
6818
6818
  }
6819
6819
  };
6820
- return /* @__PURE__ */ jsxs(Fragment, { children: [
6821
- /* @__PURE__ */ jsx(
6822
- Overlay,
6823
- {
6824
- isVisible: isOpen,
6825
- onClick: handleOverlayClick,
6826
- className: "z-40"
6827
- }
6828
- ),
6829
- /* @__PURE__ */ jsx(
6830
- Box,
6831
- {
6832
- className: cn(
6833
- "fixed inset-0 z-50 pointer-events-none",
6834
- "flex items-start justify-center px-4 pb-4 pt-[10vh]",
6835
- "max-sm:items-stretch max-sm:p-0 max-sm:pt-0"
6836
- ),
6837
- children: /* @__PURE__ */ jsxs(
6838
- Dialog,
6839
- {
6840
- ref: modalRef,
6841
- open: true,
6842
- className: cn(
6843
- // Reset browser-default dialog chrome — we own styling. `static`
6844
- // overrides the user-agent `position: absolute` so the parent
6845
- // flex container's `justify-center` actually centers the dialog
6846
- // (without this, the dialog drops out of flex flow and `m-0`
6847
- // kills the user-agent's `margin: auto` centering, pinning the
6848
- // dialog to top-left).
6849
- "static m-0 p-0 border-0 bg-transparent",
6850
- // Pre-existing dialog frame
6851
- "pointer-events-auto w-full flex flex-col bg-surface border shadow-elevation-dialog rounded-container",
6852
- // Desktop sizing + viewport-aware floor.
6853
- sizeClasses2[size],
6854
- minWidthClasses[size],
6855
- "max-h-[80vh]",
6856
- // Mobile: take the entire screen. Override desktop max-w cap,
6857
- // full height, no rounded corners, no min-width.
6858
- "max-sm:max-w-none max-sm:max-h-none max-sm:w-full max-sm:h-full max-sm:rounded-none",
6859
- lookStyles[look],
6860
- className
6861
- ),
6862
- style: dragY > 0 ? {
6863
- transform: `translateY(${dragY}px)`,
6864
- transition: isDragging.current ? "none" : "transform 200ms ease-out"
6865
- } : void 0,
6866
- ...title && { "aria-labelledby": "modal-title" },
6867
- children: [
6868
- /* @__PURE__ */ jsx(
6869
- Box,
6870
- {
6871
- className: "hidden max-sm:flex justify-center py-2 cursor-grab active:cursor-grabbing touch-none",
6872
- onPointerDown: (e) => {
6873
- if (!swipeDownToClose) return;
6874
- dragStartY.current = e.clientY;
6875
- isDragging.current = true;
6876
- e.target.setPointerCapture(e.pointerId);
6877
- },
6878
- onPointerMove: (e) => {
6879
- if (!isDragging.current) return;
6880
- const dy = Math.max(0, e.clientY - dragStartY.current);
6881
- setDragY(dy);
6882
- },
6883
- onPointerUp: () => {
6884
- if (!isDragging.current) return;
6885
- isDragging.current = false;
6886
- if (dragY > 100) {
6887
- handleClose();
6888
- }
6889
- setDragY(0);
6890
- },
6891
- onPointerCancel: () => {
6892
- isDragging.current = false;
6893
- setDragY(0);
6894
- },
6895
- children: /* @__PURE__ */ jsx(Box, { className: "w-10 h-1 rounded-full bg-border" })
6896
- }
6820
+ return createPortal(
6821
+ /* @__PURE__ */ jsxs(Fragment, { children: [
6822
+ /* @__PURE__ */ jsx(
6823
+ Overlay,
6824
+ {
6825
+ isVisible: isOpen,
6826
+ onClick: handleOverlayClick,
6827
+ className: "z-[1000]"
6828
+ }
6829
+ ),
6830
+ /* @__PURE__ */ jsx(
6831
+ Box,
6832
+ {
6833
+ className: cn(
6834
+ "fixed inset-0 z-[1001] pointer-events-none",
6835
+ "flex items-start justify-center px-4 pb-4 pt-[10vh]",
6836
+ "max-sm:items-stretch max-sm:p-0 max-sm:pt-0"
6837
+ ),
6838
+ children: /* @__PURE__ */ jsxs(
6839
+ Dialog,
6840
+ {
6841
+ ref: modalRef,
6842
+ open: true,
6843
+ className: cn(
6844
+ // Reset browser-default dialog chrome we own styling. `static`
6845
+ // overrides the user-agent `position: absolute` so the parent
6846
+ // flex container's `justify-center` actually centers the dialog
6847
+ // (without this, the dialog drops out of flex flow and `m-0`
6848
+ // kills the user-agent's `margin: auto` centering, pinning the
6849
+ // dialog to top-left).
6850
+ "static m-0 p-0 border-0 bg-transparent",
6851
+ // Pre-existing dialog frame
6852
+ "pointer-events-auto w-full flex flex-col bg-surface border shadow-elevation-dialog rounded-container",
6853
+ // Desktop sizing + viewport-aware floor.
6854
+ sizeClasses2[size],
6855
+ minWidthClasses[size],
6856
+ "max-h-[80vh]",
6857
+ // Mobile: take the entire screen. Override desktop max-w cap,
6858
+ // full height, no rounded corners, no min-width.
6859
+ "max-sm:max-w-none max-sm:max-h-none max-sm:w-full max-sm:h-full max-sm:rounded-none",
6860
+ lookStyles[look],
6861
+ className
6897
6862
  ),
6898
- (title || showCloseButton) && /* @__PURE__ */ jsxs(
6899
- Box,
6900
- {
6901
- className: cn(
6902
- "px-6 py-4 flex items-center justify-between",
6903
- "border-b-[length:var(--border-width)] border-border"
6904
- ),
6905
- children: [
6906
- title && /* @__PURE__ */ jsx(Typography, { variant: "h4", as: "h2", id: "modal-title", children: title }),
6907
- showCloseButton && /* @__PURE__ */ jsx(
6908
- Button,
6909
- {
6910
- variant: "ghost",
6911
- size: "sm",
6912
- icon: "x",
6913
- onClick: handleClose,
6914
- "data-event": "CLOSE",
6915
- "aria-label": "Close modal"
6863
+ style: dragY > 0 ? {
6864
+ transform: `translateY(${dragY}px)`,
6865
+ transition: isDragging.current ? "none" : "transform 200ms ease-out"
6866
+ } : void 0,
6867
+ ...title && { "aria-labelledby": "modal-title" },
6868
+ children: [
6869
+ /* @__PURE__ */ jsx(
6870
+ Box,
6871
+ {
6872
+ className: "hidden max-sm:flex justify-center py-2 cursor-grab active:cursor-grabbing touch-none",
6873
+ onPointerDown: (e) => {
6874
+ if (!swipeDownToClose) return;
6875
+ dragStartY.current = e.clientY;
6876
+ isDragging.current = true;
6877
+ e.target.setPointerCapture(e.pointerId);
6878
+ },
6879
+ onPointerMove: (e) => {
6880
+ if (!isDragging.current) return;
6881
+ const dy = Math.max(0, e.clientY - dragStartY.current);
6882
+ setDragY(dy);
6883
+ },
6884
+ onPointerUp: () => {
6885
+ if (!isDragging.current) return;
6886
+ isDragging.current = false;
6887
+ if (dragY > 100) {
6888
+ handleClose();
6916
6889
  }
6917
- )
6918
- ]
6919
- }
6920
- ),
6921
- /* @__PURE__ */ jsx(Box, { className: "flex-1 overflow-y-auto p-6", children }),
6922
- footer && /* @__PURE__ */ jsx(
6923
- Box,
6924
- {
6925
- className: cn(
6926
- "px-6 py-4 bg-muted",
6927
- "border-t-[length:var(--border-width)] border-border"
6928
- ),
6929
- children: footer
6930
- }
6931
- )
6932
- ]
6933
- }
6934
- )
6935
- }
6936
- )
6937
- ] });
6890
+ setDragY(0);
6891
+ },
6892
+ onPointerCancel: () => {
6893
+ isDragging.current = false;
6894
+ setDragY(0);
6895
+ },
6896
+ children: /* @__PURE__ */ jsx(Box, { className: "w-10 h-1 rounded-full bg-border" })
6897
+ }
6898
+ ),
6899
+ (title || showCloseButton) && /* @__PURE__ */ jsxs(
6900
+ Box,
6901
+ {
6902
+ className: cn(
6903
+ "px-6 py-4 flex items-center justify-between",
6904
+ "border-b-[length:var(--border-width)] border-border"
6905
+ ),
6906
+ children: [
6907
+ title && /* @__PURE__ */ jsx(Typography, { variant: "h4", as: "h2", id: "modal-title", children: title }),
6908
+ showCloseButton && /* @__PURE__ */ jsx(
6909
+ Button,
6910
+ {
6911
+ variant: "ghost",
6912
+ size: "sm",
6913
+ icon: "x",
6914
+ onClick: handleClose,
6915
+ "data-event": "CLOSE",
6916
+ "aria-label": "Close modal"
6917
+ }
6918
+ )
6919
+ ]
6920
+ }
6921
+ ),
6922
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 overflow-y-auto p-6", children }),
6923
+ footer && /* @__PURE__ */ jsx(
6924
+ Box,
6925
+ {
6926
+ className: cn(
6927
+ "px-6 py-4 bg-muted",
6928
+ "border-t-[length:var(--border-width)] border-border"
6929
+ ),
6930
+ children: footer
6931
+ }
6932
+ )
6933
+ ]
6934
+ }
6935
+ )
6936
+ }
6937
+ )
6938
+ ] }),
6939
+ document.body
6940
+ );
6938
6941
  };
6939
6942
  Modal.displayName = "Modal";
6940
6943
  }
@@ -17503,7 +17506,7 @@ var init_CodeBlock = __esm({
17503
17506
  };
17504
17507
  };
17505
17508
  }, [errorLines]);
17506
- const isFoldable = foldableProp ?? (language === "orb" || language === "json");
17509
+ const isFoldable = foldableProp ?? true;
17507
17510
  const [collapsed, setCollapsed] = useState(() => /* @__PURE__ */ new Set());
17508
17511
  const foldRegions = useMemo(
17509
17512
  () => isFoldable ? computeFoldRegions(code) : [],
@@ -17526,6 +17529,8 @@ var init_CodeBlock = __esm({
17526
17529
  collapsedRef.current = collapsed;
17527
17530
  const foldStartMapRef = useRef(foldStartMap);
17528
17531
  foldStartMapRef.current = foldStartMap;
17532
+ const hiddenLinesRef = useRef(hiddenLines);
17533
+ hiddenLinesRef.current = hiddenLines;
17529
17534
  const toggleFold = useCallback((lineNum) => {
17530
17535
  setCollapsed((prev) => {
17531
17536
  const next = new Set(prev);
@@ -17638,6 +17643,60 @@ var init_CodeBlock = __esm({
17638
17643
  eventBus.emit("UI:COPY_CODE", { language, success: false });
17639
17644
  }
17640
17645
  };
17646
+ const handleSelectionCopy = useCallback((e) => {
17647
+ if (hiddenLinesRef.current.size === 0) return;
17648
+ const sel = typeof window !== "undefined" ? window.getSelection() : null;
17649
+ if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
17650
+ const lineOf = (node) => {
17651
+ const start = node instanceof HTMLElement ? node : node?.parentElement ?? null;
17652
+ const lineEl = start?.closest("[data-line]");
17653
+ if (!lineEl) return null;
17654
+ const n = parseInt(lineEl.getAttribute("data-line") ?? "", 10);
17655
+ return Number.isNaN(n) ? null : n;
17656
+ };
17657
+ const range = sel.getRangeAt(0);
17658
+ let a = lineOf(range.startContainer);
17659
+ let b = lineOf(range.endContainer);
17660
+ if (a === null || b === null) {
17661
+ const container = codeRef.current;
17662
+ if (!container) return;
17663
+ let min = Infinity, max = -Infinity;
17664
+ container.querySelectorAll("[data-line]").forEach((el) => {
17665
+ if (!sel.containsNode(el, true)) return;
17666
+ const n = parseInt(el.getAttribute("data-line") ?? "", 10);
17667
+ if (!Number.isNaN(n)) {
17668
+ min = Math.min(min, n);
17669
+ max = Math.max(max, n);
17670
+ }
17671
+ });
17672
+ if (min === Infinity) return;
17673
+ a = a ?? min;
17674
+ b = b ?? max;
17675
+ }
17676
+ if (a > b) [a, b] = [b, a];
17677
+ let touchesFold = false;
17678
+ for (let i = a; i <= b; i++) {
17679
+ if (hiddenLinesRef.current.has(i) || foldStartMapRef.current.has(i) && collapsedRef.current.has(i)) {
17680
+ touchesFold = true;
17681
+ break;
17682
+ }
17683
+ }
17684
+ if (!touchesFold) return;
17685
+ let endLine = b;
17686
+ let changed = true;
17687
+ while (changed) {
17688
+ changed = false;
17689
+ foldStartMapRef.current.forEach((region, start) => {
17690
+ if (start >= a && start <= endLine && collapsedRef.current.has(start) && region.end > endLine) {
17691
+ endLine = region.end;
17692
+ changed = true;
17693
+ }
17694
+ });
17695
+ }
17696
+ const full = code.split("\n").slice(a, endLine + 1).join("\n");
17697
+ e.clipboardData.setData("text/plain", full);
17698
+ e.preventDefault();
17699
+ }, [code]);
17641
17700
  const hasHeader = showLanguageBadge || showCopyButton;
17642
17701
  return /* @__PURE__ */ jsxs(Box, { className: `relative group ${className || ""}`, style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
17643
17702
  hasHeader && /* @__PURE__ */ jsxs(
@@ -17788,6 +17847,7 @@ var init_CodeBlock = __esm({
17788
17847
  "div",
17789
17848
  {
17790
17849
  ref: scrollRef,
17850
+ onCopy: handleSelectionCopy,
17791
17851
  style: {
17792
17852
  flex: 1,
17793
17853
  minHeight: 0,