@almadar/ui 5.15.0 → 5.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.
package/dist/avl/index.js CHANGED
@@ -4,7 +4,7 @@ import * as React98 from 'react';
4
4
  import React98__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
5
5
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
6
6
  import ELK from 'elkjs/lib/elk.bundled.js';
7
- import { MarkerType, Handle, Position, getBezierPath, EdgeLabelRenderer, BaseEdge, ReactFlowProvider, useNodesState, useEdgesState, useReactFlow, ReactFlow, Controls, Background, BackgroundVariant } from '@xyflow/react';
7
+ import { MarkerType, useReactFlow, Handle, Position, getBezierPath, EdgeLabelRenderer, BaseEdge, ReactFlowProvider, useNodesState, useEdgesState, ReactFlow, Controls, Background, BackgroundVariant } from '@xyflow/react';
8
8
  import * as LucideIcons2 from 'lucide-react';
9
9
  import { Loader2, X, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, AlertTriangle, Trash2, ZoomOut, ZoomIn, Download, RotateCcw, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, ArrowUp, ArrowDown, MoreVertical, AlertCircle, Circle, Clock, CheckCircle2, CheckCircle, XCircle, Play, Pause, SkipForward, Bug, Send, ChevronUp, ChevronDown, Wrench, Tag, User, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
10
10
  import * as PhosphorIcons from '@phosphor-icons/react';
@@ -3308,7 +3308,7 @@ function captureSubscriberTag(listener) {
3308
3308
  }
3309
3309
  return "unknown";
3310
3310
  }
3311
- function EventBusProvider({ children }) {
3311
+ function EventBusProvider({ children, isolated = false }) {
3312
3312
  const listenersRef = useRef(/* @__PURE__ */ new Map());
3313
3313
  const anyListenersRef = useRef(/* @__PURE__ */ new Set());
3314
3314
  const deprecationWarningShown = useRef(false);
@@ -3424,11 +3424,12 @@ function EventBusProvider({ children }) {
3424
3424
  [emit, on, once, hasListeners, onAny, getSelectedEntity, clearSelectedEntity]
3425
3425
  );
3426
3426
  useEffect(() => {
3427
+ if (isolated) return;
3427
3428
  setGlobalEventBus(contextValue);
3428
3429
  return () => {
3429
3430
  setGlobalEventBus(null);
3430
3431
  };
3431
- }, [contextValue]);
3432
+ }, [contextValue, isolated]);
3432
3433
  return /* @__PURE__ */ jsx(EventBusContext.Provider, { value: contextValue, children });
3433
3434
  }
3434
3435
  var busLog, subLog, EventBusContext, listenerTags;
@@ -14577,13 +14578,13 @@ var init_MapView = __esm({
14577
14578
  shadowSize: [41, 41]
14578
14579
  });
14579
14580
  L.Marker.prototype.options.icon = defaultIcon;
14580
- const { useEffect: useEffect89, useRef: useRef88, useCallback: useCallback130, useState: useState125 } = React98__default;
14581
+ const { useEffect: useEffect90, useRef: useRef89, useCallback: useCallback130, useState: useState125 } = React98__default;
14581
14582
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
14582
14583
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
14583
14584
  function MapUpdater({ centerLat, centerLng, zoom }) {
14584
14585
  const map = useMap();
14585
- const prevRef = useRef88({ centerLat, centerLng, zoom });
14586
- useEffect89(() => {
14586
+ const prevRef = useRef89({ centerLat, centerLng, zoom });
14587
+ useEffect90(() => {
14587
14588
  const prev = prevRef.current;
14588
14589
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
14589
14590
  map.setView([centerLat, centerLng], zoom);
@@ -14594,7 +14595,7 @@ var init_MapView = __esm({
14594
14595
  }
14595
14596
  function MapClickHandler({ onMapClick }) {
14596
14597
  const map = useMap();
14597
- useEffect89(() => {
14598
+ useEffect90(() => {
14598
14599
  if (!onMapClick) return;
14599
14600
  const handler = (e) => {
14600
14601
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -26109,6 +26110,21 @@ var init_DashboardLayout = __esm({
26109
26110
  };
26110
26111
  const [sidebarOpen, setSidebarOpen] = useState(false);
26111
26112
  const [userMenuOpen, setUserMenuOpen] = useState(false);
26113
+ const layoutRef = useRef(null);
26114
+ const [isMobile, setIsMobile] = useState(false);
26115
+ useEffect(() => {
26116
+ const el = layoutRef.current;
26117
+ if (!el || typeof ResizeObserver === "undefined") return;
26118
+ const ro = new ResizeObserver((entries) => {
26119
+ const w = entries[0]?.contentRect.width ?? el.clientWidth;
26120
+ setIsMobile(w < 1024);
26121
+ });
26122
+ ro.observe(el);
26123
+ return () => ro.disconnect();
26124
+ }, []);
26125
+ useEffect(() => {
26126
+ if (!isMobile && sidebarOpen) setSidebarOpen(false);
26127
+ }, [isMobile, sidebarOpen]);
26112
26128
  const location = useLocation();
26113
26129
  const ctxPagePath = useCurrentPagePath();
26114
26130
  const activePath = currentPath ?? ctxPagePath ?? location.pathname;
@@ -26121,15 +26137,15 @@ var init_DashboardLayout = __esm({
26121
26137
  const showBottomNav = layoutMode === "bottomnav";
26122
26138
  const isTopNav = layoutMode === "topnav";
26123
26139
  return /* @__PURE__ */ jsxs(
26124
- HStack,
26140
+ Box,
26125
26141
  {
26126
- gap: "none",
26127
- className: "@container/dashboard min-h-screen w-full bg-background dark:bg-background items-stretch",
26142
+ ref: layoutRef,
26143
+ className: "@container/dashboard min-h-screen w-full bg-background dark:bg-background flex flex-row items-stretch",
26128
26144
  children: [
26129
- showSidebar && sidebarOpen && /* @__PURE__ */ jsx(
26145
+ showSidebar && isMobile && sidebarOpen && /* @__PURE__ */ jsx(
26130
26146
  Box,
26131
26147
  {
26132
- className: "fixed inset-0 bg-foreground/50 dark:bg-foreground/70 z-20 @lg/dashboard:hidden",
26148
+ className: "fixed inset-0 bg-foreground/50 dark:bg-foreground/70 z-20",
26133
26149
  onClick: () => setSidebarOpen(false)
26134
26150
  }
26135
26151
  ),
@@ -26139,11 +26155,16 @@ var init_DashboardLayout = __esm({
26139
26155
  as: "aside",
26140
26156
  className: cn(
26141
26157
  "z-30 w-64 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
26142
- "fixed inset-y-0 left-0 @lg/dashboard:static @lg/dashboard:translate-x-0 @lg/dashboard:h-auto",
26143
- "transform transition-transform duration-200 ease-in-out",
26144
- "flex flex-col",
26145
- sidebarOpen ? "translate-x-0" : "-translate-x-full"
26158
+ "flex flex-col"
26146
26159
  ),
26160
+ style: isMobile ? {
26161
+ position: "fixed",
26162
+ top: 0,
26163
+ bottom: 0,
26164
+ left: 0,
26165
+ transform: sidebarOpen ? "translateX(0)" : "translateX(-100%)",
26166
+ transition: "transform 200ms ease-in-out"
26167
+ } : { position: "static", transform: "none" },
26147
26168
  children: [
26148
26169
  /* @__PURE__ */ jsxs(
26149
26170
  HStack,
@@ -26172,11 +26193,11 @@ var init_DashboardLayout = __esm({
26172
26193
  }
26173
26194
  )
26174
26195
  ] }),
26175
- /* @__PURE__ */ jsx(
26196
+ isMobile && /* @__PURE__ */ jsx(
26176
26197
  Button,
26177
26198
  {
26178
26199
  variant: "ghost",
26179
- className: "@lg/dashboard:hidden p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground",
26200
+ className: "p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground",
26180
26201
  onClick: () => setSidebarOpen(false),
26181
26202
  children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-5 w-5" })
26182
26203
  }
@@ -26217,11 +26238,11 @@ var init_DashboardLayout = __esm({
26217
26238
  justify: "between",
26218
26239
  className: "h-full px-3 @sm/dashboard:px-4 gap-2 @sm/dashboard:gap-4",
26219
26240
  children: [
26220
- showSidebar && /* @__PURE__ */ jsx(
26241
+ showSidebar && isMobile && /* @__PURE__ */ jsx(
26221
26242
  Button,
26222
26243
  {
26223
26244
  variant: "ghost",
26224
- className: "@lg/dashboard:hidden p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground touch-manipulation min-h-[44px] min-w-[44px] flex items-center justify-center",
26245
+ className: "p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground touch-manipulation min-h-[44px] min-w-[44px] flex items-center justify-center",
26225
26246
  onClick: () => setSidebarOpen(true),
26226
26247
  "aria-label": "Open sidebar",
26227
26248
  children: /* @__PURE__ */ jsx(Icon, { name: "menu", className: "h-5 w-5" })
@@ -59979,13 +60000,14 @@ function OrbitalProvider({
59979
60000
  debug: debug2 = false,
59980
60001
  initialData,
59981
60002
  suspense = false,
59982
- verification
60003
+ verification,
60004
+ isolated = false
59983
60005
  }) {
59984
60006
  const suspenseConfig = useMemo(
59985
60007
  () => ({ enabled: suspense }),
59986
60008
  [suspense]
59987
60009
  );
59988
- const inner = /* @__PURE__ */ jsx(EventBusProvider, { debug: debug2, children: /* @__PURE__ */ jsx(VerificationProvider, { enabled: verification, children: /* @__PURE__ */ jsx(SelectionProvider, { debug: debug2, children: /* @__PURE__ */ jsx(SuspenseConfigProvider, { config: suspenseConfig, children }) }) }) });
60010
+ const inner = /* @__PURE__ */ jsx(EventBusProvider, { debug: debug2, isolated, children: /* @__PURE__ */ jsx(VerificationProvider, { enabled: verification, children: /* @__PURE__ */ jsx(SelectionProvider, { debug: debug2, children: /* @__PURE__ */ jsx(SuspenseConfigProvider, { config: suspenseConfig, children }) }) }) });
59989
60011
  if (skipTheme) {
59990
60012
  return inner;
59991
60013
  }
@@ -61992,7 +62014,8 @@ function OrbPreview({
61992
62014
  className,
61993
62015
  serverUrl,
61994
62016
  transport,
61995
- initialPagePath
62017
+ initialPagePath,
62018
+ isolated = false
61996
62019
  }) {
61997
62020
  if (serverUrl && transport) {
61998
62021
  throw new Error("OrbPreview accepts serverUrl OR transport, not both");
@@ -62114,7 +62137,7 @@ function OrbPreview({
62114
62137
  style: { height },
62115
62138
  children: [
62116
62139
  localFallback && /* @__PURE__ */ jsx(Box, { className: "px-3 py-2 bg-[var(--color-warning)] bg-opacity-10 border-b border-[var(--color-warning)] flex items-center gap-2", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-warning-foreground)] flex-1", children: "Preview server unreachable \u2014 running locally. Server-side state and persistence are disabled." }) }),
62117
- /* @__PURE__ */ jsx(OrbitalProvider, { initialData: effectiveMockData, skipTheme: true, verification: true, children: /* @__PURE__ */ jsx(UISlotProvider, { children: /* @__PURE__ */ jsx(
62140
+ /* @__PURE__ */ jsx(OrbitalProvider, { initialData: effectiveMockData, skipTheme: true, verification: true, isolated, children: /* @__PURE__ */ jsx(UISlotProvider, { children: /* @__PURE__ */ jsx(
62118
62141
  SchemaRunner,
62119
62142
  {
62120
62143
  schema: parsedSchema,
@@ -62187,7 +62210,8 @@ function BrowserPlayground({
62187
62210
  transport,
62188
62211
  initialPagePath,
62189
62212
  height,
62190
- className
62213
+ className,
62214
+ isolated: true
62191
62215
  }
62192
62216
  );
62193
62217
  }
@@ -62604,15 +62628,9 @@ function buildTransitionSchema(fullSchema, orbitalName, traitName, transitionEve
62604
62628
  return { ...fullSchema, name: `${fullSchema.name}__${orbitalName}__${traitName}__${transitionEvent}`, orbitals: [clonedOrbital] };
62605
62629
  }
62606
62630
  var SELECTION_STYLES = `
62607
- .orb-preview-live [data-pattern]:hover {
62608
- outline: 2px dashed var(--color-primary);
62609
- outline-offset: 1px;
62631
+ .orb-preview-live [data-pattern] {
62610
62632
  cursor: pointer;
62611
62633
  }
62612
- .orb-preview-live [data-pattern].pattern-selected {
62613
- outline: 2px solid var(--color-primary);
62614
- outline-offset: 1px;
62615
- }
62616
62634
  .orb-preview-live.drag-active [data-accepts-children="true"] {
62617
62635
  outline: 2px dashed var(--color-primary);
62618
62636
  outline-offset: -2px;
@@ -62629,15 +62647,73 @@ var SELECTION_STYLES = `
62629
62647
  pointer-events: none;
62630
62648
  }
62631
62649
  `;
62650
+ function absUnion(el) {
62651
+ const own = el.getBoundingClientRect();
62652
+ if (own.width > 0 || own.height > 0) {
62653
+ return { top: own.top, left: own.left, right: own.right, bottom: own.bottom };
62654
+ }
62655
+ let r2 = null;
62656
+ for (const child of Array.from(el.children)) {
62657
+ const box = absUnion(child);
62658
+ if (!box) continue;
62659
+ r2 = r2 ? {
62660
+ top: Math.min(r2.top, box.top),
62661
+ left: Math.min(r2.left, box.left),
62662
+ right: Math.max(r2.right, box.right),
62663
+ bottom: Math.max(r2.bottom, box.bottom)
62664
+ } : box;
62665
+ }
62666
+ return r2;
62667
+ }
62668
+ function rectRelativeTo(el, container, zoom) {
62669
+ const u = absUnion(el);
62670
+ if (!u) return null;
62671
+ const base = container.getBoundingClientRect();
62672
+ const z = zoom > 0 ? zoom : 1;
62673
+ return {
62674
+ top: (u.top - base.top) / z,
62675
+ left: (u.left - base.left) / z,
62676
+ width: (u.right - u.left) / z,
62677
+ height: (u.bottom - u.top) / z
62678
+ };
62679
+ }
62680
+ function buildFocus(el, orbitalName) {
62681
+ if (!orbitalName) return null;
62682
+ const path = el.getAttribute("data-orb-path") ?? el.getAttribute("data-pattern-path");
62683
+ const patternType = el.getAttribute("data-orb-pattern") ?? el.getAttribute("data-pattern");
62684
+ const trait = el.getAttribute("data-orb-trait") ?? el.getAttribute("data-source-trait");
62685
+ const focus = {
62686
+ level: "node",
62687
+ orbital: orbitalName,
62688
+ label: patternType ?? trait ?? "element"
62689
+ };
62690
+ if (path !== null) focus.path = path;
62691
+ if (trait !== null) focus.trait = trait;
62692
+ if (patternType !== null) focus.patternType = patternType;
62693
+ const transition = el.getAttribute("data-orb-transition");
62694
+ if (transition !== null) focus.transition = transition;
62695
+ const state = el.getAttribute("data-orb-state");
62696
+ if (state !== null) focus.state = state;
62697
+ const slot = el.getAttribute("data-orb-slot");
62698
+ if (slot !== null) focus.slot = slot;
62699
+ const entity = el.getAttribute("data-orb-entity");
62700
+ if (entity !== null) focus.entity = entity;
62701
+ return focus;
62702
+ }
62632
62703
  var OrbPreviewNodeInner = (props) => {
62633
62704
  const data = props.data;
62634
62705
  const screenSize = useContext(ScreenSizeContext);
62635
62706
  const preset = SCREEN_SIZE_PRESETS[screenSize];
62636
62707
  const { select } = useContext(PatternSelectionContext);
62708
+ const eventBus = useEventBus();
62709
+ const reactFlow = useReactFlow();
62637
62710
  const contentRef = useRef(null);
62638
62711
  const [hovered, setHovered] = useState(false);
62639
62712
  const handleMouseEnter = useCallback(() => setHovered(true), []);
62640
62713
  const handleMouseLeave = useCallback(() => setHovered(false), []);
62714
+ const [selectedRect, setSelectedRect] = useState(null);
62715
+ const [hoverRect, setHoverRect] = useState(null);
62716
+ const lastHoverElRef = useRef(null);
62641
62717
  const role = data.stateRole ?? "default";
62642
62718
  const colors = ROLE_COLORS[role] ?? ROLE_COLORS.default;
62643
62719
  const eventSources = data.eventSources ?? [];
@@ -62670,13 +62746,15 @@ var OrbPreviewNodeInner = (props) => {
62670
62746
  e.stopPropagation();
62671
62747
  const target = e.target;
62672
62748
  const patternEl = target.closest("[data-pattern]");
62673
- contentRef.current?.querySelectorAll(".pattern-selected").forEach((el) => {
62749
+ const container = contentRef.current;
62750
+ container?.querySelectorAll(".pattern-selected").forEach((el) => {
62674
62751
  el.classList.remove("pattern-selected");
62675
62752
  });
62676
- if (patternEl) {
62753
+ const zoom = reactFlow.getViewport().zoom;
62754
+ if (patternEl && container) {
62677
62755
  patternEl.classList.add("pattern-selected");
62678
- const nodeRect = contentRef.current?.getBoundingClientRect();
62679
- const elRect = patternEl.getBoundingClientRect();
62756
+ const rect = rectRelativeTo(patternEl, container, zoom);
62757
+ setSelectedRect(rect);
62680
62758
  select({
62681
62759
  patternType: patternEl.getAttribute("data-pattern") ?? "unknown",
62682
62760
  // `data-pattern-path` is the SExpr tree path (`children.0.…`) emitted by
@@ -62687,18 +62765,33 @@ var OrbPreviewNodeInner = (props) => {
62687
62765
  patternId: patternEl.getAttribute("data-pattern-path") ?? void 0,
62688
62766
  sourceTrait: patternEl.getAttribute("data-source-trait") ?? void 0,
62689
62767
  nodeData: data,
62690
- rect: nodeRect ? {
62691
- top: elRect.top - nodeRect.top,
62692
- left: elRect.left - nodeRect.left,
62693
- width: elRect.width,
62694
- height: elRect.height
62695
- } : void 0
62768
+ rect: rect ?? void 0
62696
62769
  });
62770
+ const focus = buildFocus(patternEl, data.orbitalName);
62771
+ if (focus) eventBus.emit("UI:ELEMENT_SELECTED", { focus: { ...focus } });
62697
62772
  } else {
62773
+ setSelectedRect(null);
62698
62774
  select(null);
62699
- }
62700
- }, [data, select]);
62701
- const eventBus = useEventBus();
62775
+ eventBus.emit("UI:ELEMENT_SELECTED", { focus: null });
62776
+ }
62777
+ }, [data, select, eventBus, reactFlow]);
62778
+ const handleContentMouseMove = useCallback((e) => {
62779
+ const container = contentRef.current;
62780
+ if (!container) return;
62781
+ const el = e.target.closest("[data-pattern]");
62782
+ if (el === lastHoverElRef.current) return;
62783
+ lastHoverElRef.current = el;
62784
+ setHoverRect(el ? rectRelativeTo(el, container, reactFlow.getViewport().zoom) : null);
62785
+ }, [reactFlow]);
62786
+ const handleContentMouseLeave = useCallback(() => {
62787
+ lastHoverElRef.current = null;
62788
+ setHoverRect(null);
62789
+ }, []);
62790
+ useEffect(() => {
62791
+ setSelectedRect(null);
62792
+ setHoverRect(null);
62793
+ lastHoverElRef.current = null;
62794
+ }, [orbitalSchema]);
62702
62795
  const [dragActive, setDragActive] = useState(false);
62703
62796
  useEffect(() => {
62704
62797
  const unsub1 = eventBus.on("UI:DRAG_START", (e) => {
@@ -62917,26 +63010,66 @@ var OrbPreviewNodeInner = (props) => {
62917
63010
  src.event
62918
63011
  )) })
62919
63012
  ] }),
62920
- /* @__PURE__ */ jsx(
63013
+ /* @__PURE__ */ jsxs(
62921
63014
  Box,
62922
63015
  {
62923
63016
  ref: setContentRef,
62924
- className: `orb-preview-live nodrag${dragActive || l2IsOver ? " drag-active" : ""}`,
63017
+ className: `orb-preview-live nodrag relative${dragActive || l2IsOver ? " drag-active" : ""}`,
62925
63018
  onClick: handleContentClick,
62926
- children: orbitalSchema ? (
62927
- // L1 and L2 both auto-grow with content. L2's `buildTransitionSchema`
62928
- // rewrites portal slots (modal/drawer/overlay/center) to `main`, so
62929
- // the rendered pattern lands inline in the main slot and contributes
62930
- // to the card's height — same height model as L1 orbital cards.
62931
- /* @__PURE__ */ jsx(Box, { style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsx(
62932
- BrowserPlayground,
63019
+ onMouseMove: handleContentMouseMove,
63020
+ onMouseLeave: handleContentMouseLeave,
63021
+ children: [
63022
+ hoverRect && /* @__PURE__ */ jsx(
63023
+ "div",
62933
63024
  {
62934
- schema: orbitalSchema,
62935
- mode: "mock",
62936
- height: "auto"
63025
+ "aria-hidden": true,
63026
+ style: {
63027
+ position: "absolute",
63028
+ pointerEvents: "none",
63029
+ top: hoverRect.top,
63030
+ left: hoverRect.left,
63031
+ width: hoverRect.width,
63032
+ height: hoverRect.height,
63033
+ outline: "2px dashed var(--color-primary)",
63034
+ outlineOffset: "1px",
63035
+ borderRadius: "2px",
63036
+ zIndex: 20
63037
+ }
62937
63038
  }
62938
- ) })
62939
- ) : /* @__PURE__ */ jsx(Box, { className: "flex items-center justify-center", style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground", children: "No preview available" }) })
63039
+ ),
63040
+ selectedRect && /* @__PURE__ */ jsx(
63041
+ "div",
63042
+ {
63043
+ "aria-hidden": true,
63044
+ style: {
63045
+ position: "absolute",
63046
+ pointerEvents: "none",
63047
+ top: selectedRect.top,
63048
+ left: selectedRect.left,
63049
+ width: selectedRect.width,
63050
+ height: selectedRect.height,
63051
+ outline: "2px solid var(--color-primary)",
63052
+ outlineOffset: "1px",
63053
+ borderRadius: "2px",
63054
+ zIndex: 21
63055
+ }
63056
+ }
63057
+ ),
63058
+ orbitalSchema ? (
63059
+ // L1 and L2 both auto-grow with content. L2's `buildTransitionSchema`
63060
+ // rewrites portal slots (modal/drawer/overlay/center) to `main`, so
63061
+ // the rendered pattern lands inline in the main slot and contributes
63062
+ // to the card's height — same height model as L1 orbital cards.
63063
+ /* @__PURE__ */ jsx(Box, { style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsx(
63064
+ BrowserPlayground,
63065
+ {
63066
+ schema: orbitalSchema,
63067
+ mode: "mock",
63068
+ height: "auto"
63069
+ }
63070
+ ) })
63071
+ ) : /* @__PURE__ */ jsx(Box, { className: "flex items-center justify-center", style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground", children: "No preview available" }) })
63072
+ ]
62940
63073
  }
62941
63074
  ),
62942
63075
  /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Left, style: TARGET_HANDLE_STYLE }),
@@ -8679,13 +8679,13 @@ var init_MapView = __esm({
8679
8679
  shadowSize: [41, 41]
8680
8680
  });
8681
8681
  L.Marker.prototype.options.icon = defaultIcon;
8682
- const { useEffect: useEffect73, useRef: useRef67, useCallback: useCallback129, useState: useState112 } = React80__namespace.default;
8682
+ const { useEffect: useEffect74, useRef: useRef68, useCallback: useCallback129, useState: useState112 } = React80__namespace.default;
8683
8683
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
8684
8684
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
8685
8685
  function MapUpdater({ centerLat, centerLng, zoom }) {
8686
8686
  const map = useMap();
8687
- const prevRef = useRef67({ centerLat, centerLng, zoom });
8688
- useEffect73(() => {
8687
+ const prevRef = useRef68({ centerLat, centerLng, zoom });
8688
+ useEffect74(() => {
8689
8689
  const prev = prevRef.current;
8690
8690
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
8691
8691
  map.setView([centerLat, centerLng], zoom);
@@ -8696,7 +8696,7 @@ var init_MapView = __esm({
8696
8696
  }
8697
8697
  function MapClickHandler({ onMapClick }) {
8698
8698
  const map = useMap();
8699
- useEffect73(() => {
8699
+ useEffect74(() => {
8700
8700
  if (!onMapClick) return;
8701
8701
  const handler = (e) => {
8702
8702
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -21317,6 +21317,21 @@ var init_DashboardLayout = __esm({
21317
21317
  };
21318
21318
  const [sidebarOpen, setSidebarOpen] = React80.useState(false);
21319
21319
  const [userMenuOpen, setUserMenuOpen] = React80.useState(false);
21320
+ const layoutRef = React80.useRef(null);
21321
+ const [isMobile, setIsMobile] = React80.useState(false);
21322
+ React80.useEffect(() => {
21323
+ const el = layoutRef.current;
21324
+ if (!el || typeof ResizeObserver === "undefined") return;
21325
+ const ro = new ResizeObserver((entries) => {
21326
+ const w = entries[0]?.contentRect.width ?? el.clientWidth;
21327
+ setIsMobile(w < 1024);
21328
+ });
21329
+ ro.observe(el);
21330
+ return () => ro.disconnect();
21331
+ }, []);
21332
+ React80.useEffect(() => {
21333
+ if (!isMobile && sidebarOpen) setSidebarOpen(false);
21334
+ }, [isMobile, sidebarOpen]);
21320
21335
  const location = reactRouterDom.useLocation();
21321
21336
  const ctxPagePath = useCurrentPagePath();
21322
21337
  const activePath = currentPath ?? ctxPagePath ?? location.pathname;
@@ -21333,15 +21348,15 @@ var init_DashboardLayout = __esm({
21333
21348
  const showBottomNav = layoutMode === "bottomnav";
21334
21349
  const isTopNav = layoutMode === "topnav";
21335
21350
  return /* @__PURE__ */ jsxRuntime.jsxs(
21336
- exports.HStack,
21351
+ exports.Box,
21337
21352
  {
21338
- gap: "none",
21339
- className: "@container/dashboard min-h-screen w-full bg-background dark:bg-background items-stretch",
21353
+ ref: layoutRef,
21354
+ className: "@container/dashboard min-h-screen w-full bg-background dark:bg-background flex flex-row items-stretch",
21340
21355
  children: [
21341
- showSidebar && sidebarOpen && /* @__PURE__ */ jsxRuntime.jsx(
21356
+ showSidebar && isMobile && sidebarOpen && /* @__PURE__ */ jsxRuntime.jsx(
21342
21357
  exports.Box,
21343
21358
  {
21344
- className: "fixed inset-0 bg-foreground/50 dark:bg-foreground/70 z-20 @lg/dashboard:hidden",
21359
+ className: "fixed inset-0 bg-foreground/50 dark:bg-foreground/70 z-20",
21345
21360
  onClick: () => setSidebarOpen(false)
21346
21361
  }
21347
21362
  ),
@@ -21351,11 +21366,16 @@ var init_DashboardLayout = __esm({
21351
21366
  as: "aside",
21352
21367
  className: cn(
21353
21368
  "z-30 w-64 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
21354
- "fixed inset-y-0 left-0 @lg/dashboard:static @lg/dashboard:translate-x-0 @lg/dashboard:h-auto",
21355
- "transform transition-transform duration-200 ease-in-out",
21356
- "flex flex-col",
21357
- sidebarOpen ? "translate-x-0" : "-translate-x-full"
21369
+ "flex flex-col"
21358
21370
  ),
21371
+ style: isMobile ? {
21372
+ position: "fixed",
21373
+ top: 0,
21374
+ bottom: 0,
21375
+ left: 0,
21376
+ transform: sidebarOpen ? "translateX(0)" : "translateX(-100%)",
21377
+ transition: "transform 200ms ease-in-out"
21378
+ } : { position: "static", transform: "none" },
21359
21379
  children: [
21360
21380
  /* @__PURE__ */ jsxRuntime.jsxs(
21361
21381
  exports.HStack,
@@ -21384,11 +21404,11 @@ var init_DashboardLayout = __esm({
21384
21404
  }
21385
21405
  )
21386
21406
  ] }),
21387
- /* @__PURE__ */ jsxRuntime.jsx(
21407
+ isMobile && /* @__PURE__ */ jsxRuntime.jsx(
21388
21408
  exports.Button,
21389
21409
  {
21390
21410
  variant: "ghost",
21391
- className: "@lg/dashboard:hidden p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground",
21411
+ className: "p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground",
21392
21412
  onClick: () => setSidebarOpen(false),
21393
21413
  children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "x", className: "h-5 w-5" })
21394
21414
  }
@@ -21429,11 +21449,11 @@ var init_DashboardLayout = __esm({
21429
21449
  justify: "between",
21430
21450
  className: "h-full px-3 @sm/dashboard:px-4 gap-2 @sm/dashboard:gap-4",
21431
21451
  children: [
21432
- showSidebar && /* @__PURE__ */ jsxRuntime.jsx(
21452
+ showSidebar && isMobile && /* @__PURE__ */ jsxRuntime.jsx(
21433
21453
  exports.Button,
21434
21454
  {
21435
21455
  variant: "ghost",
21436
- className: "@lg/dashboard:hidden p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground touch-manipulation min-h-[44px] min-w-[44px] flex items-center justify-center",
21456
+ className: "p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground touch-manipulation min-h-[44px] min-w-[44px] flex items-center justify-center",
21437
21457
  onClick: () => setSidebarOpen(true),
21438
21458
  "aria-label": "Open sidebar",
21439
21459
  children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "menu", className: "h-5 w-5" })
@@ -8630,13 +8630,13 @@ var init_MapView = __esm({
8630
8630
  shadowSize: [41, 41]
8631
8631
  });
8632
8632
  L.Marker.prototype.options.icon = defaultIcon;
8633
- const { useEffect: useEffect73, useRef: useRef67, useCallback: useCallback129, useState: useState112 } = React80__default;
8633
+ const { useEffect: useEffect74, useRef: useRef68, useCallback: useCallback129, useState: useState112 } = React80__default;
8634
8634
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
8635
8635
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
8636
8636
  function MapUpdater({ centerLat, centerLng, zoom }) {
8637
8637
  const map = useMap();
8638
- const prevRef = useRef67({ centerLat, centerLng, zoom });
8639
- useEffect73(() => {
8638
+ const prevRef = useRef68({ centerLat, centerLng, zoom });
8639
+ useEffect74(() => {
8640
8640
  const prev = prevRef.current;
8641
8641
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
8642
8642
  map.setView([centerLat, centerLng], zoom);
@@ -8647,7 +8647,7 @@ var init_MapView = __esm({
8647
8647
  }
8648
8648
  function MapClickHandler({ onMapClick }) {
8649
8649
  const map = useMap();
8650
- useEffect73(() => {
8650
+ useEffect74(() => {
8651
8651
  if (!onMapClick) return;
8652
8652
  const handler = (e) => {
8653
8653
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -21268,6 +21268,21 @@ var init_DashboardLayout = __esm({
21268
21268
  };
21269
21269
  const [sidebarOpen, setSidebarOpen] = useState(false);
21270
21270
  const [userMenuOpen, setUserMenuOpen] = useState(false);
21271
+ const layoutRef = useRef(null);
21272
+ const [isMobile, setIsMobile] = useState(false);
21273
+ useEffect(() => {
21274
+ const el = layoutRef.current;
21275
+ if (!el || typeof ResizeObserver === "undefined") return;
21276
+ const ro = new ResizeObserver((entries) => {
21277
+ const w = entries[0]?.contentRect.width ?? el.clientWidth;
21278
+ setIsMobile(w < 1024);
21279
+ });
21280
+ ro.observe(el);
21281
+ return () => ro.disconnect();
21282
+ }, []);
21283
+ useEffect(() => {
21284
+ if (!isMobile && sidebarOpen) setSidebarOpen(false);
21285
+ }, [isMobile, sidebarOpen]);
21271
21286
  const location = useLocation();
21272
21287
  const ctxPagePath = useCurrentPagePath();
21273
21288
  const activePath = currentPath ?? ctxPagePath ?? location.pathname;
@@ -21284,15 +21299,15 @@ var init_DashboardLayout = __esm({
21284
21299
  const showBottomNav = layoutMode === "bottomnav";
21285
21300
  const isTopNav = layoutMode === "topnav";
21286
21301
  return /* @__PURE__ */ jsxs(
21287
- HStack,
21302
+ Box,
21288
21303
  {
21289
- gap: "none",
21290
- className: "@container/dashboard min-h-screen w-full bg-background dark:bg-background items-stretch",
21304
+ ref: layoutRef,
21305
+ className: "@container/dashboard min-h-screen w-full bg-background dark:bg-background flex flex-row items-stretch",
21291
21306
  children: [
21292
- showSidebar && sidebarOpen && /* @__PURE__ */ jsx(
21307
+ showSidebar && isMobile && sidebarOpen && /* @__PURE__ */ jsx(
21293
21308
  Box,
21294
21309
  {
21295
- className: "fixed inset-0 bg-foreground/50 dark:bg-foreground/70 z-20 @lg/dashboard:hidden",
21310
+ className: "fixed inset-0 bg-foreground/50 dark:bg-foreground/70 z-20",
21296
21311
  onClick: () => setSidebarOpen(false)
21297
21312
  }
21298
21313
  ),
@@ -21302,11 +21317,16 @@ var init_DashboardLayout = __esm({
21302
21317
  as: "aside",
21303
21318
  className: cn(
21304
21319
  "z-30 w-64 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
21305
- "fixed inset-y-0 left-0 @lg/dashboard:static @lg/dashboard:translate-x-0 @lg/dashboard:h-auto",
21306
- "transform transition-transform duration-200 ease-in-out",
21307
- "flex flex-col",
21308
- sidebarOpen ? "translate-x-0" : "-translate-x-full"
21320
+ "flex flex-col"
21309
21321
  ),
21322
+ style: isMobile ? {
21323
+ position: "fixed",
21324
+ top: 0,
21325
+ bottom: 0,
21326
+ left: 0,
21327
+ transform: sidebarOpen ? "translateX(0)" : "translateX(-100%)",
21328
+ transition: "transform 200ms ease-in-out"
21329
+ } : { position: "static", transform: "none" },
21310
21330
  children: [
21311
21331
  /* @__PURE__ */ jsxs(
21312
21332
  HStack,
@@ -21335,11 +21355,11 @@ var init_DashboardLayout = __esm({
21335
21355
  }
21336
21356
  )
21337
21357
  ] }),
21338
- /* @__PURE__ */ jsx(
21358
+ isMobile && /* @__PURE__ */ jsx(
21339
21359
  Button,
21340
21360
  {
21341
21361
  variant: "ghost",
21342
- className: "@lg/dashboard:hidden p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground",
21362
+ className: "p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground",
21343
21363
  onClick: () => setSidebarOpen(false),
21344
21364
  children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-5 w-5" })
21345
21365
  }
@@ -21380,11 +21400,11 @@ var init_DashboardLayout = __esm({
21380
21400
  justify: "between",
21381
21401
  className: "h-full px-3 @sm/dashboard:px-4 gap-2 @sm/dashboard:gap-4",
21382
21402
  children: [
21383
- showSidebar && /* @__PURE__ */ jsx(
21403
+ showSidebar && isMobile && /* @__PURE__ */ jsx(
21384
21404
  Button,
21385
21405
  {
21386
21406
  variant: "ghost",
21387
- className: "@lg/dashboard:hidden p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground touch-manipulation min-h-[44px] min-w-[44px] flex items-center justify-center",
21407
+ className: "p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground touch-manipulation min-h-[44px] min-w-[44px] flex items-center justify-center",
21388
21408
  onClick: () => setSidebarOpen(true),
21389
21409
  "aria-label": "Open sidebar",
21390
21410
  children: /* @__PURE__ */ jsx(Icon, { name: "menu", className: "h-5 w-5" })