@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.
@@ -10,8 +10,8 @@ var LucideIcons2 = require('lucide-react');
10
10
  var PhosphorIcons = require('@phosphor-icons/react');
11
11
  var TablerIcons = require('@tabler/icons-react');
12
12
  var FaIcons = require('react-icons/fa');
13
- var evaluator = require('@almadar/evaluator');
14
13
  var reactDom = require('react-dom');
14
+ var evaluator = require('@almadar/evaluator');
15
15
  var reactRouterDom = require('react-router-dom');
16
16
  var ReactMarkdown = require('react-markdown');
17
17
  var remarkGfm = require('remark-gfm');
@@ -6856,7 +6856,7 @@ var init_Modal = __esm({
6856
6856
  document.body.style.overflow = "";
6857
6857
  };
6858
6858
  }, [isOpen]);
6859
- if (!isOpen) return null;
6859
+ if (!isOpen || typeof document === "undefined") return null;
6860
6860
  const handleClose = () => {
6861
6861
  if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
6862
6862
  onClose();
@@ -6866,124 +6866,127 @@ var init_Modal = __esm({
6866
6866
  handleClose();
6867
6867
  }
6868
6868
  };
6869
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6870
- /* @__PURE__ */ jsxRuntime.jsx(
6871
- Overlay,
6872
- {
6873
- isVisible: isOpen,
6874
- onClick: handleOverlayClick,
6875
- className: "z-40"
6876
- }
6877
- ),
6878
- /* @__PURE__ */ jsxRuntime.jsx(
6879
- Box,
6880
- {
6881
- className: cn(
6882
- "fixed inset-0 z-50 pointer-events-none",
6883
- "flex items-start justify-center px-4 pb-4 pt-[10vh]",
6884
- "max-sm:items-stretch max-sm:p-0 max-sm:pt-0"
6885
- ),
6886
- children: /* @__PURE__ */ jsxRuntime.jsxs(
6887
- Dialog,
6888
- {
6889
- ref: modalRef,
6890
- open: true,
6891
- className: cn(
6892
- // Reset browser-default dialog chrome — we own styling. `static`
6893
- // overrides the user-agent `position: absolute` so the parent
6894
- // flex container's `justify-center` actually centers the dialog
6895
- // (without this, the dialog drops out of flex flow and `m-0`
6896
- // kills the user-agent's `margin: auto` centering, pinning the
6897
- // dialog to top-left).
6898
- "static m-0 p-0 border-0 bg-transparent",
6899
- // Pre-existing dialog frame
6900
- "pointer-events-auto w-full flex flex-col bg-surface border shadow-elevation-dialog rounded-container",
6901
- // Desktop sizing + viewport-aware floor.
6902
- sizeClasses2[size],
6903
- minWidthClasses[size],
6904
- "max-h-[80vh]",
6905
- // Mobile: take the entire screen. Override desktop max-w cap,
6906
- // full height, no rounded corners, no min-width.
6907
- "max-sm:max-w-none max-sm:max-h-none max-sm:w-full max-sm:h-full max-sm:rounded-none",
6908
- lookStyles[look],
6909
- className
6910
- ),
6911
- style: dragY > 0 ? {
6912
- transform: `translateY(${dragY}px)`,
6913
- transition: isDragging.current ? "none" : "transform 200ms ease-out"
6914
- } : void 0,
6915
- ...title && { "aria-labelledby": "modal-title" },
6916
- children: [
6917
- /* @__PURE__ */ jsxRuntime.jsx(
6918
- Box,
6919
- {
6920
- className: "hidden max-sm:flex justify-center py-2 cursor-grab active:cursor-grabbing touch-none",
6921
- onPointerDown: (e) => {
6922
- if (!swipeDownToClose) return;
6923
- dragStartY.current = e.clientY;
6924
- isDragging.current = true;
6925
- e.target.setPointerCapture(e.pointerId);
6926
- },
6927
- onPointerMove: (e) => {
6928
- if (!isDragging.current) return;
6929
- const dy = Math.max(0, e.clientY - dragStartY.current);
6930
- setDragY(dy);
6931
- },
6932
- onPointerUp: () => {
6933
- if (!isDragging.current) return;
6934
- isDragging.current = false;
6935
- if (dragY > 100) {
6936
- handleClose();
6937
- }
6938
- setDragY(0);
6939
- },
6940
- onPointerCancel: () => {
6941
- isDragging.current = false;
6942
- setDragY(0);
6943
- },
6944
- children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-10 h-1 rounded-full bg-border" })
6945
- }
6869
+ return reactDom.createPortal(
6870
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6871
+ /* @__PURE__ */ jsxRuntime.jsx(
6872
+ Overlay,
6873
+ {
6874
+ isVisible: isOpen,
6875
+ onClick: handleOverlayClick,
6876
+ className: "z-[1000]"
6877
+ }
6878
+ ),
6879
+ /* @__PURE__ */ jsxRuntime.jsx(
6880
+ Box,
6881
+ {
6882
+ className: cn(
6883
+ "fixed inset-0 z-[1001] pointer-events-none",
6884
+ "flex items-start justify-center px-4 pb-4 pt-[10vh]",
6885
+ "max-sm:items-stretch max-sm:p-0 max-sm:pt-0"
6886
+ ),
6887
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
6888
+ Dialog,
6889
+ {
6890
+ ref: modalRef,
6891
+ open: true,
6892
+ className: cn(
6893
+ // Reset browser-default dialog chrome we own styling. `static`
6894
+ // overrides the user-agent `position: absolute` so the parent
6895
+ // flex container's `justify-center` actually centers the dialog
6896
+ // (without this, the dialog drops out of flex flow and `m-0`
6897
+ // kills the user-agent's `margin: auto` centering, pinning the
6898
+ // dialog to top-left).
6899
+ "static m-0 p-0 border-0 bg-transparent",
6900
+ // Pre-existing dialog frame
6901
+ "pointer-events-auto w-full flex flex-col bg-surface border shadow-elevation-dialog rounded-container",
6902
+ // Desktop sizing + viewport-aware floor.
6903
+ sizeClasses2[size],
6904
+ minWidthClasses[size],
6905
+ "max-h-[80vh]",
6906
+ // Mobile: take the entire screen. Override desktop max-w cap,
6907
+ // full height, no rounded corners, no min-width.
6908
+ "max-sm:max-w-none max-sm:max-h-none max-sm:w-full max-sm:h-full max-sm:rounded-none",
6909
+ lookStyles[look],
6910
+ className
6946
6911
  ),
6947
- (title || showCloseButton) && /* @__PURE__ */ jsxRuntime.jsxs(
6948
- Box,
6949
- {
6950
- className: cn(
6951
- "px-6 py-4 flex items-center justify-between",
6952
- "border-b-[length:var(--border-width)] border-border"
6953
- ),
6954
- children: [
6955
- title && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", as: "h2", id: "modal-title", children: title }),
6956
- showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(
6957
- Button,
6958
- {
6959
- variant: "ghost",
6960
- size: "sm",
6961
- icon: "x",
6962
- onClick: handleClose,
6963
- "data-event": "CLOSE",
6964
- "aria-label": "Close modal"
6912
+ style: dragY > 0 ? {
6913
+ transform: `translateY(${dragY}px)`,
6914
+ transition: isDragging.current ? "none" : "transform 200ms ease-out"
6915
+ } : void 0,
6916
+ ...title && { "aria-labelledby": "modal-title" },
6917
+ children: [
6918
+ /* @__PURE__ */ jsxRuntime.jsx(
6919
+ Box,
6920
+ {
6921
+ className: "hidden max-sm:flex justify-center py-2 cursor-grab active:cursor-grabbing touch-none",
6922
+ onPointerDown: (e) => {
6923
+ if (!swipeDownToClose) return;
6924
+ dragStartY.current = e.clientY;
6925
+ isDragging.current = true;
6926
+ e.target.setPointerCapture(e.pointerId);
6927
+ },
6928
+ onPointerMove: (e) => {
6929
+ if (!isDragging.current) return;
6930
+ const dy = Math.max(0, e.clientY - dragStartY.current);
6931
+ setDragY(dy);
6932
+ },
6933
+ onPointerUp: () => {
6934
+ if (!isDragging.current) return;
6935
+ isDragging.current = false;
6936
+ if (dragY > 100) {
6937
+ handleClose();
6965
6938
  }
6966
- )
6967
- ]
6968
- }
6969
- ),
6970
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 overflow-y-auto p-6", children }),
6971
- footer && /* @__PURE__ */ jsxRuntime.jsx(
6972
- Box,
6973
- {
6974
- className: cn(
6975
- "px-6 py-4 bg-muted",
6976
- "border-t-[length:var(--border-width)] border-border"
6977
- ),
6978
- children: footer
6979
- }
6980
- )
6981
- ]
6982
- }
6983
- )
6984
- }
6985
- )
6986
- ] });
6939
+ setDragY(0);
6940
+ },
6941
+ onPointerCancel: () => {
6942
+ isDragging.current = false;
6943
+ setDragY(0);
6944
+ },
6945
+ children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-10 h-1 rounded-full bg-border" })
6946
+ }
6947
+ ),
6948
+ (title || showCloseButton) && /* @__PURE__ */ jsxRuntime.jsxs(
6949
+ Box,
6950
+ {
6951
+ className: cn(
6952
+ "px-6 py-4 flex items-center justify-between",
6953
+ "border-b-[length:var(--border-width)] border-border"
6954
+ ),
6955
+ children: [
6956
+ title && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", as: "h2", id: "modal-title", children: title }),
6957
+ showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(
6958
+ Button,
6959
+ {
6960
+ variant: "ghost",
6961
+ size: "sm",
6962
+ icon: "x",
6963
+ onClick: handleClose,
6964
+ "data-event": "CLOSE",
6965
+ "aria-label": "Close modal"
6966
+ }
6967
+ )
6968
+ ]
6969
+ }
6970
+ ),
6971
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 overflow-y-auto p-6", children }),
6972
+ footer && /* @__PURE__ */ jsxRuntime.jsx(
6973
+ Box,
6974
+ {
6975
+ className: cn(
6976
+ "px-6 py-4 bg-muted",
6977
+ "border-t-[length:var(--border-width)] border-border"
6978
+ ),
6979
+ children: footer
6980
+ }
6981
+ )
6982
+ ]
6983
+ }
6984
+ )
6985
+ }
6986
+ )
6987
+ ] }),
6988
+ document.body
6989
+ );
6987
6990
  };
6988
6991
  Modal.displayName = "Modal";
6989
6992
  }
@@ -17552,7 +17555,7 @@ var init_CodeBlock = __esm({
17552
17555
  };
17553
17556
  };
17554
17557
  }, [errorLines]);
17555
- const isFoldable = foldableProp ?? (language === "orb" || language === "json");
17558
+ const isFoldable = foldableProp ?? true;
17556
17559
  const [collapsed, setCollapsed] = React98.useState(() => /* @__PURE__ */ new Set());
17557
17560
  const foldRegions = React98.useMemo(
17558
17561
  () => isFoldable ? computeFoldRegions(code) : [],
@@ -17575,6 +17578,8 @@ var init_CodeBlock = __esm({
17575
17578
  collapsedRef.current = collapsed;
17576
17579
  const foldStartMapRef = React98.useRef(foldStartMap);
17577
17580
  foldStartMapRef.current = foldStartMap;
17581
+ const hiddenLinesRef = React98.useRef(hiddenLines);
17582
+ hiddenLinesRef.current = hiddenLines;
17578
17583
  const toggleFold = React98.useCallback((lineNum) => {
17579
17584
  setCollapsed((prev) => {
17580
17585
  const next = new Set(prev);
@@ -17687,6 +17692,60 @@ var init_CodeBlock = __esm({
17687
17692
  eventBus.emit("UI:COPY_CODE", { language, success: false });
17688
17693
  }
17689
17694
  };
17695
+ const handleSelectionCopy = React98.useCallback((e) => {
17696
+ if (hiddenLinesRef.current.size === 0) return;
17697
+ const sel = typeof window !== "undefined" ? window.getSelection() : null;
17698
+ if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
17699
+ const lineOf = (node) => {
17700
+ const start = node instanceof HTMLElement ? node : node?.parentElement ?? null;
17701
+ const lineEl = start?.closest("[data-line]");
17702
+ if (!lineEl) return null;
17703
+ const n = parseInt(lineEl.getAttribute("data-line") ?? "", 10);
17704
+ return Number.isNaN(n) ? null : n;
17705
+ };
17706
+ const range = sel.getRangeAt(0);
17707
+ let a = lineOf(range.startContainer);
17708
+ let b = lineOf(range.endContainer);
17709
+ if (a === null || b === null) {
17710
+ const container = codeRef.current;
17711
+ if (!container) return;
17712
+ let min = Infinity, max = -Infinity;
17713
+ container.querySelectorAll("[data-line]").forEach((el) => {
17714
+ if (!sel.containsNode(el, true)) return;
17715
+ const n = parseInt(el.getAttribute("data-line") ?? "", 10);
17716
+ if (!Number.isNaN(n)) {
17717
+ min = Math.min(min, n);
17718
+ max = Math.max(max, n);
17719
+ }
17720
+ });
17721
+ if (min === Infinity) return;
17722
+ a = a ?? min;
17723
+ b = b ?? max;
17724
+ }
17725
+ if (a > b) [a, b] = [b, a];
17726
+ let touchesFold = false;
17727
+ for (let i = a; i <= b; i++) {
17728
+ if (hiddenLinesRef.current.has(i) || foldStartMapRef.current.has(i) && collapsedRef.current.has(i)) {
17729
+ touchesFold = true;
17730
+ break;
17731
+ }
17732
+ }
17733
+ if (!touchesFold) return;
17734
+ let endLine = b;
17735
+ let changed = true;
17736
+ while (changed) {
17737
+ changed = false;
17738
+ foldStartMapRef.current.forEach((region, start) => {
17739
+ if (start >= a && start <= endLine && collapsedRef.current.has(start) && region.end > endLine) {
17740
+ endLine = region.end;
17741
+ changed = true;
17742
+ }
17743
+ });
17744
+ }
17745
+ const full = code.split("\n").slice(a, endLine + 1).join("\n");
17746
+ e.clipboardData.setData("text/plain", full);
17747
+ e.preventDefault();
17748
+ }, [code]);
17690
17749
  const hasHeader = showLanguageBadge || showCopyButton;
17691
17750
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: `relative group ${className || ""}`, style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
17692
17751
  hasHeader && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -17837,6 +17896,7 @@ var init_CodeBlock = __esm({
17837
17896
  "div",
17838
17897
  {
17839
17898
  ref: scrollRef,
17899
+ onCopy: handleSelectionCopy,
17840
17900
  style: {
17841
17901
  flex: 1,
17842
17902
  minHeight: 0,