@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.
@@ -3357,7 +3357,7 @@ function captureSubscriberTag(listener) {
3357
3357
  }
3358
3358
  return "unknown";
3359
3359
  }
3360
- function EventBusProvider({ children }) {
3360
+ function EventBusProvider({ children, isolated = false }) {
3361
3361
  const listenersRef = React98.useRef(/* @__PURE__ */ new Map());
3362
3362
  const anyListenersRef = React98.useRef(/* @__PURE__ */ new Set());
3363
3363
  const deprecationWarningShown = React98.useRef(false);
@@ -3473,11 +3473,12 @@ function EventBusProvider({ children }) {
3473
3473
  [emit, on, once, hasListeners, onAny, getSelectedEntity, clearSelectedEntity]
3474
3474
  );
3475
3475
  React98.useEffect(() => {
3476
+ if (isolated) return;
3476
3477
  setGlobalEventBus(contextValue);
3477
3478
  return () => {
3478
3479
  setGlobalEventBus(null);
3479
3480
  };
3480
- }, [contextValue]);
3481
+ }, [contextValue, isolated]);
3481
3482
  return /* @__PURE__ */ jsxRuntime.jsx(EventBusContext.Provider, { value: contextValue, children });
3482
3483
  }
3483
3484
  var busLog, subLog, EventBusContext, listenerTags;
@@ -14626,13 +14627,13 @@ var init_MapView = __esm({
14626
14627
  shadowSize: [41, 41]
14627
14628
  });
14628
14629
  L.Marker.prototype.options.icon = defaultIcon;
14629
- const { useEffect: useEffect89, useRef: useRef88, useCallback: useCallback130, useState: useState125 } = React98__namespace.default;
14630
+ const { useEffect: useEffect90, useRef: useRef89, useCallback: useCallback130, useState: useState125 } = React98__namespace.default;
14630
14631
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
14631
14632
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
14632
14633
  function MapUpdater({ centerLat, centerLng, zoom }) {
14633
14634
  const map = useMap();
14634
- const prevRef = useRef88({ centerLat, centerLng, zoom });
14635
- useEffect89(() => {
14635
+ const prevRef = useRef89({ centerLat, centerLng, zoom });
14636
+ useEffect90(() => {
14636
14637
  const prev = prevRef.current;
14637
14638
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
14638
14639
  map.setView([centerLat, centerLng], zoom);
@@ -14643,7 +14644,7 @@ var init_MapView = __esm({
14643
14644
  }
14644
14645
  function MapClickHandler({ onMapClick }) {
14645
14646
  const map = useMap();
14646
- useEffect89(() => {
14647
+ useEffect90(() => {
14647
14648
  if (!onMapClick) return;
14648
14649
  const handler = (e) => {
14649
14650
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -26158,6 +26159,21 @@ var init_DashboardLayout = __esm({
26158
26159
  };
26159
26160
  const [sidebarOpen, setSidebarOpen] = React98.useState(false);
26160
26161
  const [userMenuOpen, setUserMenuOpen] = React98.useState(false);
26162
+ const layoutRef = React98.useRef(null);
26163
+ const [isMobile, setIsMobile] = React98.useState(false);
26164
+ React98.useEffect(() => {
26165
+ const el = layoutRef.current;
26166
+ if (!el || typeof ResizeObserver === "undefined") return;
26167
+ const ro = new ResizeObserver((entries) => {
26168
+ const w = entries[0]?.contentRect.width ?? el.clientWidth;
26169
+ setIsMobile(w < 1024);
26170
+ });
26171
+ ro.observe(el);
26172
+ return () => ro.disconnect();
26173
+ }, []);
26174
+ React98.useEffect(() => {
26175
+ if (!isMobile && sidebarOpen) setSidebarOpen(false);
26176
+ }, [isMobile, sidebarOpen]);
26161
26177
  const location = reactRouterDom.useLocation();
26162
26178
  const ctxPagePath = useCurrentPagePath();
26163
26179
  const activePath = currentPath ?? ctxPagePath ?? location.pathname;
@@ -26170,15 +26186,15 @@ var init_DashboardLayout = __esm({
26170
26186
  const showBottomNav = layoutMode === "bottomnav";
26171
26187
  const isTopNav = layoutMode === "topnav";
26172
26188
  return /* @__PURE__ */ jsxRuntime.jsxs(
26173
- HStack,
26189
+ Box,
26174
26190
  {
26175
- gap: "none",
26176
- className: "@container/dashboard min-h-screen w-full bg-background dark:bg-background items-stretch",
26191
+ ref: layoutRef,
26192
+ className: "@container/dashboard min-h-screen w-full bg-background dark:bg-background flex flex-row items-stretch",
26177
26193
  children: [
26178
- showSidebar && sidebarOpen && /* @__PURE__ */ jsxRuntime.jsx(
26194
+ showSidebar && isMobile && sidebarOpen && /* @__PURE__ */ jsxRuntime.jsx(
26179
26195
  Box,
26180
26196
  {
26181
- className: "fixed inset-0 bg-foreground/50 dark:bg-foreground/70 z-20 @lg/dashboard:hidden",
26197
+ className: "fixed inset-0 bg-foreground/50 dark:bg-foreground/70 z-20",
26182
26198
  onClick: () => setSidebarOpen(false)
26183
26199
  }
26184
26200
  ),
@@ -26188,11 +26204,16 @@ var init_DashboardLayout = __esm({
26188
26204
  as: "aside",
26189
26205
  className: cn(
26190
26206
  "z-30 w-64 flex-shrink-0 bg-card dark:bg-card border-r border-border dark:border-border",
26191
- "fixed inset-y-0 left-0 @lg/dashboard:static @lg/dashboard:translate-x-0 @lg/dashboard:h-auto",
26192
- "transform transition-transform duration-200 ease-in-out",
26193
- "flex flex-col",
26194
- sidebarOpen ? "translate-x-0" : "-translate-x-full"
26207
+ "flex flex-col"
26195
26208
  ),
26209
+ style: isMobile ? {
26210
+ position: "fixed",
26211
+ top: 0,
26212
+ bottom: 0,
26213
+ left: 0,
26214
+ transform: sidebarOpen ? "translateX(0)" : "translateX(-100%)",
26215
+ transition: "transform 200ms ease-in-out"
26216
+ } : { position: "static", transform: "none" },
26196
26217
  children: [
26197
26218
  /* @__PURE__ */ jsxRuntime.jsxs(
26198
26219
  HStack,
@@ -26221,11 +26242,11 @@ var init_DashboardLayout = __esm({
26221
26242
  }
26222
26243
  )
26223
26244
  ] }),
26224
- /* @__PURE__ */ jsxRuntime.jsx(
26245
+ isMobile && /* @__PURE__ */ jsxRuntime.jsx(
26225
26246
  Button,
26226
26247
  {
26227
26248
  variant: "ghost",
26228
- className: "@lg/dashboard:hidden p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground",
26249
+ className: "p-2 rounded-md hover:bg-muted dark:hover:bg-muted text-muted-foreground dark:text-muted-foreground",
26229
26250
  onClick: () => setSidebarOpen(false),
26230
26251
  children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "x", className: "h-5 w-5" })
26231
26252
  }
@@ -26266,11 +26287,11 @@ var init_DashboardLayout = __esm({
26266
26287
  justify: "between",
26267
26288
  className: "h-full px-3 @sm/dashboard:px-4 gap-2 @sm/dashboard:gap-4",
26268
26289
  children: [
26269
- showSidebar && /* @__PURE__ */ jsxRuntime.jsx(
26290
+ showSidebar && isMobile && /* @__PURE__ */ jsxRuntime.jsx(
26270
26291
  Button,
26271
26292
  {
26272
26293
  variant: "ghost",
26273
- 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",
26294
+ 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",
26274
26295
  onClick: () => setSidebarOpen(true),
26275
26296
  "aria-label": "Open sidebar",
26276
26297
  children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "menu", className: "h-5 w-5" })
@@ -60028,13 +60049,14 @@ function OrbitalProvider({
60028
60049
  debug: debug2 = false,
60029
60050
  initialData,
60030
60051
  suspense = false,
60031
- verification
60052
+ verification,
60053
+ isolated = false
60032
60054
  }) {
60033
60055
  const suspenseConfig = React98.useMemo(
60034
60056
  () => ({ enabled: suspense }),
60035
60057
  [suspense]
60036
60058
  );
60037
- const inner = /* @__PURE__ */ jsxRuntime.jsx(EventBusProvider, { debug: debug2, children: /* @__PURE__ */ jsxRuntime.jsx(VerificationProvider, { enabled: verification, children: /* @__PURE__ */ jsxRuntime.jsx(SelectionProvider, { debug: debug2, children: /* @__PURE__ */ jsxRuntime.jsx(SuspenseConfigProvider, { config: suspenseConfig, children }) }) }) });
60059
+ const inner = /* @__PURE__ */ jsxRuntime.jsx(EventBusProvider, { debug: debug2, isolated, children: /* @__PURE__ */ jsxRuntime.jsx(VerificationProvider, { enabled: verification, children: /* @__PURE__ */ jsxRuntime.jsx(SelectionProvider, { debug: debug2, children: /* @__PURE__ */ jsxRuntime.jsx(SuspenseConfigProvider, { config: suspenseConfig, children }) }) }) });
60038
60060
  if (skipTheme) {
60039
60061
  return inner;
60040
60062
  }
@@ -62041,7 +62063,8 @@ function OrbPreview({
62041
62063
  className,
62042
62064
  serverUrl,
62043
62065
  transport,
62044
- initialPagePath
62066
+ initialPagePath,
62067
+ isolated = false
62045
62068
  }) {
62046
62069
  if (serverUrl && transport) {
62047
62070
  throw new Error("OrbPreview accepts serverUrl OR transport, not both");
@@ -62163,7 +62186,7 @@ function OrbPreview({
62163
62186
  style: { height },
62164
62187
  children: [
62165
62188
  localFallback && /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.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." }) }),
62166
- /* @__PURE__ */ jsxRuntime.jsx(OrbitalProvider, { initialData: effectiveMockData, skipTheme: true, verification: true, children: /* @__PURE__ */ jsxRuntime.jsx(UISlotProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
62189
+ /* @__PURE__ */ jsxRuntime.jsx(OrbitalProvider, { initialData: effectiveMockData, skipTheme: true, verification: true, isolated, children: /* @__PURE__ */ jsxRuntime.jsx(UISlotProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
62167
62190
  SchemaRunner,
62168
62191
  {
62169
62192
  schema: parsedSchema,
@@ -62236,7 +62259,8 @@ function BrowserPlayground({
62236
62259
  transport,
62237
62260
  initialPagePath,
62238
62261
  height,
62239
- className
62262
+ className,
62263
+ isolated: true
62240
62264
  }
62241
62265
  );
62242
62266
  }
@@ -62653,15 +62677,9 @@ function buildTransitionSchema(fullSchema, orbitalName, traitName, transitionEve
62653
62677
  return { ...fullSchema, name: `${fullSchema.name}__${orbitalName}__${traitName}__${transitionEvent}`, orbitals: [clonedOrbital] };
62654
62678
  }
62655
62679
  var SELECTION_STYLES = `
62656
- .orb-preview-live [data-pattern]:hover {
62657
- outline: 2px dashed var(--color-primary);
62658
- outline-offset: 1px;
62680
+ .orb-preview-live [data-pattern] {
62659
62681
  cursor: pointer;
62660
62682
  }
62661
- .orb-preview-live [data-pattern].pattern-selected {
62662
- outline: 2px solid var(--color-primary);
62663
- outline-offset: 1px;
62664
- }
62665
62683
  .orb-preview-live.drag-active [data-accepts-children="true"] {
62666
62684
  outline: 2px dashed var(--color-primary);
62667
62685
  outline-offset: -2px;
@@ -62678,15 +62696,73 @@ var SELECTION_STYLES = `
62678
62696
  pointer-events: none;
62679
62697
  }
62680
62698
  `;
62699
+ function absUnion(el) {
62700
+ const own = el.getBoundingClientRect();
62701
+ if (own.width > 0 || own.height > 0) {
62702
+ return { top: own.top, left: own.left, right: own.right, bottom: own.bottom };
62703
+ }
62704
+ let r2 = null;
62705
+ for (const child of Array.from(el.children)) {
62706
+ const box = absUnion(child);
62707
+ if (!box) continue;
62708
+ r2 = r2 ? {
62709
+ top: Math.min(r2.top, box.top),
62710
+ left: Math.min(r2.left, box.left),
62711
+ right: Math.max(r2.right, box.right),
62712
+ bottom: Math.max(r2.bottom, box.bottom)
62713
+ } : box;
62714
+ }
62715
+ return r2;
62716
+ }
62717
+ function rectRelativeTo(el, container, zoom) {
62718
+ const u = absUnion(el);
62719
+ if (!u) return null;
62720
+ const base = container.getBoundingClientRect();
62721
+ const z = zoom > 0 ? zoom : 1;
62722
+ return {
62723
+ top: (u.top - base.top) / z,
62724
+ left: (u.left - base.left) / z,
62725
+ width: (u.right - u.left) / z,
62726
+ height: (u.bottom - u.top) / z
62727
+ };
62728
+ }
62729
+ function buildFocus(el, orbitalName) {
62730
+ if (!orbitalName) return null;
62731
+ const path = el.getAttribute("data-orb-path") ?? el.getAttribute("data-pattern-path");
62732
+ const patternType = el.getAttribute("data-orb-pattern") ?? el.getAttribute("data-pattern");
62733
+ const trait = el.getAttribute("data-orb-trait") ?? el.getAttribute("data-source-trait");
62734
+ const focus = {
62735
+ level: "node",
62736
+ orbital: orbitalName,
62737
+ label: patternType ?? trait ?? "element"
62738
+ };
62739
+ if (path !== null) focus.path = path;
62740
+ if (trait !== null) focus.trait = trait;
62741
+ if (patternType !== null) focus.patternType = patternType;
62742
+ const transition = el.getAttribute("data-orb-transition");
62743
+ if (transition !== null) focus.transition = transition;
62744
+ const state = el.getAttribute("data-orb-state");
62745
+ if (state !== null) focus.state = state;
62746
+ const slot = el.getAttribute("data-orb-slot");
62747
+ if (slot !== null) focus.slot = slot;
62748
+ const entity = el.getAttribute("data-orb-entity");
62749
+ if (entity !== null) focus.entity = entity;
62750
+ return focus;
62751
+ }
62681
62752
  var OrbPreviewNodeInner = (props) => {
62682
62753
  const data = props.data;
62683
62754
  const screenSize = React98.useContext(ScreenSizeContext);
62684
62755
  const preset = SCREEN_SIZE_PRESETS[screenSize];
62685
62756
  const { select } = React98.useContext(PatternSelectionContext);
62757
+ const eventBus = useEventBus();
62758
+ const reactFlow = react.useReactFlow();
62686
62759
  const contentRef = React98.useRef(null);
62687
62760
  const [hovered, setHovered] = React98.useState(false);
62688
62761
  const handleMouseEnter = React98.useCallback(() => setHovered(true), []);
62689
62762
  const handleMouseLeave = React98.useCallback(() => setHovered(false), []);
62763
+ const [selectedRect, setSelectedRect] = React98.useState(null);
62764
+ const [hoverRect, setHoverRect] = React98.useState(null);
62765
+ const lastHoverElRef = React98.useRef(null);
62690
62766
  const role = data.stateRole ?? "default";
62691
62767
  const colors = ROLE_COLORS[role] ?? ROLE_COLORS.default;
62692
62768
  const eventSources = data.eventSources ?? [];
@@ -62719,13 +62795,15 @@ var OrbPreviewNodeInner = (props) => {
62719
62795
  e.stopPropagation();
62720
62796
  const target = e.target;
62721
62797
  const patternEl = target.closest("[data-pattern]");
62722
- contentRef.current?.querySelectorAll(".pattern-selected").forEach((el) => {
62798
+ const container = contentRef.current;
62799
+ container?.querySelectorAll(".pattern-selected").forEach((el) => {
62723
62800
  el.classList.remove("pattern-selected");
62724
62801
  });
62725
- if (patternEl) {
62802
+ const zoom = reactFlow.getViewport().zoom;
62803
+ if (patternEl && container) {
62726
62804
  patternEl.classList.add("pattern-selected");
62727
- const nodeRect = contentRef.current?.getBoundingClientRect();
62728
- const elRect = patternEl.getBoundingClientRect();
62805
+ const rect = rectRelativeTo(patternEl, container, zoom);
62806
+ setSelectedRect(rect);
62729
62807
  select({
62730
62808
  patternType: patternEl.getAttribute("data-pattern") ?? "unknown",
62731
62809
  // `data-pattern-path` is the SExpr tree path (`children.0.…`) emitted by
@@ -62736,18 +62814,33 @@ var OrbPreviewNodeInner = (props) => {
62736
62814
  patternId: patternEl.getAttribute("data-pattern-path") ?? void 0,
62737
62815
  sourceTrait: patternEl.getAttribute("data-source-trait") ?? void 0,
62738
62816
  nodeData: data,
62739
- rect: nodeRect ? {
62740
- top: elRect.top - nodeRect.top,
62741
- left: elRect.left - nodeRect.left,
62742
- width: elRect.width,
62743
- height: elRect.height
62744
- } : void 0
62817
+ rect: rect ?? void 0
62745
62818
  });
62819
+ const focus = buildFocus(patternEl, data.orbitalName);
62820
+ if (focus) eventBus.emit("UI:ELEMENT_SELECTED", { focus: { ...focus } });
62746
62821
  } else {
62822
+ setSelectedRect(null);
62747
62823
  select(null);
62748
- }
62749
- }, [data, select]);
62750
- const eventBus = useEventBus();
62824
+ eventBus.emit("UI:ELEMENT_SELECTED", { focus: null });
62825
+ }
62826
+ }, [data, select, eventBus, reactFlow]);
62827
+ const handleContentMouseMove = React98.useCallback((e) => {
62828
+ const container = contentRef.current;
62829
+ if (!container) return;
62830
+ const el = e.target.closest("[data-pattern]");
62831
+ if (el === lastHoverElRef.current) return;
62832
+ lastHoverElRef.current = el;
62833
+ setHoverRect(el ? rectRelativeTo(el, container, reactFlow.getViewport().zoom) : null);
62834
+ }, [reactFlow]);
62835
+ const handleContentMouseLeave = React98.useCallback(() => {
62836
+ lastHoverElRef.current = null;
62837
+ setHoverRect(null);
62838
+ }, []);
62839
+ React98.useEffect(() => {
62840
+ setSelectedRect(null);
62841
+ setHoverRect(null);
62842
+ lastHoverElRef.current = null;
62843
+ }, [orbitalSchema]);
62751
62844
  const [dragActive, setDragActive] = React98.useState(false);
62752
62845
  React98.useEffect(() => {
62753
62846
  const unsub1 = eventBus.on("UI:DRAG_START", (e) => {
@@ -62966,26 +63059,66 @@ var OrbPreviewNodeInner = (props) => {
62966
63059
  src.event
62967
63060
  )) })
62968
63061
  ] }),
62969
- /* @__PURE__ */ jsxRuntime.jsx(
63062
+ /* @__PURE__ */ jsxRuntime.jsxs(
62970
63063
  Box,
62971
63064
  {
62972
63065
  ref: setContentRef,
62973
- className: `orb-preview-live nodrag${dragActive || l2IsOver ? " drag-active" : ""}`,
63066
+ className: `orb-preview-live nodrag relative${dragActive || l2IsOver ? " drag-active" : ""}`,
62974
63067
  onClick: handleContentClick,
62975
- children: orbitalSchema ? (
62976
- // L1 and L2 both auto-grow with content. L2's `buildTransitionSchema`
62977
- // rewrites portal slots (modal/drawer/overlay/center) to `main`, so
62978
- // the rendered pattern lands inline in the main slot and contributes
62979
- // to the card's height — same height model as L1 orbital cards.
62980
- /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsxRuntime.jsx(
62981
- BrowserPlayground,
63068
+ onMouseMove: handleContentMouseMove,
63069
+ onMouseLeave: handleContentMouseLeave,
63070
+ children: [
63071
+ hoverRect && /* @__PURE__ */ jsxRuntime.jsx(
63072
+ "div",
62982
63073
  {
62983
- schema: orbitalSchema,
62984
- mode: "mock",
62985
- height: "auto"
63074
+ "aria-hidden": true,
63075
+ style: {
63076
+ position: "absolute",
63077
+ pointerEvents: "none",
63078
+ top: hoverRect.top,
63079
+ left: hoverRect.left,
63080
+ width: hoverRect.width,
63081
+ height: hoverRect.height,
63082
+ outline: "2px dashed var(--color-primary)",
63083
+ outlineOffset: "1px",
63084
+ borderRadius: "2px",
63085
+ zIndex: 20
63086
+ }
62986
63087
  }
62987
- ) })
62988
- ) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center justify-center", style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground", children: "No preview available" }) })
63088
+ ),
63089
+ selectedRect && /* @__PURE__ */ jsxRuntime.jsx(
63090
+ "div",
63091
+ {
63092
+ "aria-hidden": true,
63093
+ style: {
63094
+ position: "absolute",
63095
+ pointerEvents: "none",
63096
+ top: selectedRect.top,
63097
+ left: selectedRect.left,
63098
+ width: selectedRect.width,
63099
+ height: selectedRect.height,
63100
+ outline: "2px solid var(--color-primary)",
63101
+ outlineOffset: "1px",
63102
+ borderRadius: "2px",
63103
+ zIndex: 21
63104
+ }
63105
+ }
63106
+ ),
63107
+ orbitalSchema ? (
63108
+ // L1 and L2 both auto-grow with content. L2's `buildTransitionSchema`
63109
+ // rewrites portal slots (modal/drawer/overlay/center) to `main`, so
63110
+ // the rendered pattern lands inline in the main slot and contributes
63111
+ // to the card's height — same height model as L1 orbital cards.
63112
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsxRuntime.jsx(
63113
+ BrowserPlayground,
63114
+ {
63115
+ schema: orbitalSchema,
63116
+ mode: "mock",
63117
+ height: "auto"
63118
+ }
63119
+ ) })
63120
+ ) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center justify-center", style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground", children: "No preview available" }) })
63121
+ ]
62989
63122
  }
62990
63123
  ),
62991
63124
  /* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "target", position: react.Position.Left, style: TARGET_HANDLE_STYLE }),