@marimo-team/islands 0.23.15-dev62 → 0.23.15-dev64

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.
@@ -9,7 +9,7 @@ import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
9
9
  import { dt as kioskModeAtom, ht as outputIsStale } from "./html-to-image-DDENewl2.js";
10
10
  import "./chunk-5FQGJX7Z-B9WoXK1R.js";
11
11
  import { u as createLucideIcon } from "./dist-B96tMAst.js";
12
- import { a as DEFAULT_DECK_VERTICAL_ALIGN, c as SlideSidebar, cn as Expand, ct as Panel, dn as Code, i as DEFAULT_DECK_TRANSITION, l as Slide, lt as PanelGroup, o as DEFAULT_SLIDE_TYPE, sn as EyeOff, t as useNotebookCodeAvailable, ut as PanelResizeHandle } from "./code-visibility-D7Oaafvl.js";
12
+ import { a as DEFAULT_DECK_VERTICAL_ALIGN, c as SlideSidebar, cn as Expand, ct as Panel, dn as Code, i as DEFAULT_DECK_TRANSITION, l as Slide, lt as PanelGroup, o as DEFAULT_SLIDE_TYPE, sn as EyeOff, t as useNotebookCodeAvailable, ut as PanelResizeHandle } from "./code-visibility-YsJOxF8J.js";
13
13
  import { X as useDebouncedCallback } from "./input-DStQIuqD.js";
14
14
  import "./toDate-B3IRfHhw.js";
15
15
  import "./react-dom-BTJzcVJ9.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.15-dev62",
3
+ "version": "0.23.15-dev64",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import type { JSX, PropsWithChildren } from "react";
3
3
  import React from "react";
4
+ import { createPortal } from "react-dom";
4
5
  import { z } from "zod";
5
6
  import {
6
7
  NavigationMenu,
@@ -9,9 +10,11 @@ import {
9
10
  NavigationMenuLink,
10
11
  NavigationMenuList,
11
12
  NavigationMenuTrigger,
13
+ NavigationMenuViewport,
12
14
  navigationMenuTriggerStyle,
13
15
  } from "@/components/ui/navigation";
14
16
  import { Tooltip } from "@/components/ui/tooltip";
17
+ import { useResizeObserver } from "@/hooks/useResizeObserver";
15
18
  import { renderHTML } from "@/plugins/core/RenderHTML";
16
19
  import { cn } from "@/utils/cn";
17
20
  import { appendQueryParams } from "@/utils/urls";
@@ -21,6 +24,7 @@ import type {
21
24
  } from "../stateless-plugin";
22
25
  import "./navigation-menu.css";
23
26
  import { KnownQueryParams } from "@/core/constants";
27
+ import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui";
24
28
 
25
29
  interface MenuItem {
26
30
  label: string;
@@ -45,6 +49,118 @@ interface Data {
45
49
  orientation: "horizontal" | "vertical";
46
50
  }
47
51
 
52
+ interface PortalPosition {
53
+ left: number;
54
+ top: number;
55
+ }
56
+
57
+ interface HorizontalMenuGroupProps {
58
+ item: MenuItemGroup;
59
+ preserveQueryParams: (href: string) => string;
60
+ target: (href: string) => string;
61
+ }
62
+
63
+ const HorizontalMenuGroup = ({
64
+ item,
65
+ preserveQueryParams,
66
+ target,
67
+ }: HorizontalMenuGroupProps): JSX.Element => {
68
+ const triggerRef = React.useRef<React.ComponentRef<
69
+ typeof NavigationMenuTrigger
70
+ > | null>(null);
71
+
72
+ return (
73
+ <NavigationMenuPrimitive.Root
74
+ className="relative z-10 max-w-max flex-1 items-center justify-center"
75
+ orientation="horizontal"
76
+ >
77
+ <NavigationMenuList>
78
+ <NavigationMenuItem>
79
+ <NavigationMenuTrigger ref={triggerRef}>
80
+ {renderHTML({ html: item.label })}
81
+ </NavigationMenuTrigger>
82
+ <NavigationMenuContent className="w-auto">
83
+ <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
84
+ {item.items.map((subItem) => (
85
+ <ListItem
86
+ key={subItem.label}
87
+ label={subItem.label}
88
+ href={preserveQueryParams(subItem.href)}
89
+ target={target(subItem.href)}
90
+ >
91
+ {subItem.description &&
92
+ renderHTML({ html: subItem.description })}
93
+ </ListItem>
94
+ ))}
95
+ </ul>
96
+ </NavigationMenuContent>
97
+ </NavigationMenuItem>
98
+ </NavigationMenuList>
99
+ <NavigationMenuViewportPortal anchorRef={triggerRef}>
100
+ <NavigationMenuViewport />
101
+ </NavigationMenuViewportPortal>
102
+ </NavigationMenuPrimitive.Root>
103
+ );
104
+ };
105
+
106
+ const NavigationMenuViewportPortal = ({
107
+ anchorRef,
108
+ children,
109
+ }: PropsWithChildren<{
110
+ anchorRef: React.RefObject<HTMLElement | null>;
111
+ }>): React.ReactElement | null => {
112
+ const [position, setPosition] = React.useState<PortalPosition | null>(null);
113
+
114
+ const updatePosition = React.useCallback(() => {
115
+ if (!anchorRef.current) {
116
+ return;
117
+ }
118
+
119
+ const rect = anchorRef.current.getBoundingClientRect();
120
+ setPosition({
121
+ left: rect.left,
122
+ top: rect.bottom,
123
+ });
124
+ }, [anchorRef]);
125
+
126
+ React.useLayoutEffect(() => {
127
+ updatePosition();
128
+ }, [updatePosition]);
129
+
130
+ useResizeObserver({
131
+ ref: anchorRef,
132
+ onResize: updatePosition,
133
+ });
134
+
135
+ React.useEffect(() => {
136
+ if (typeof window === "undefined") {
137
+ return;
138
+ }
139
+
140
+ window.addEventListener("resize", updatePosition);
141
+ document.addEventListener("scroll", updatePosition, { capture: true });
142
+
143
+ return () => {
144
+ window.removeEventListener("resize", updatePosition);
145
+ document.removeEventListener("scroll", updatePosition, { capture: true });
146
+ };
147
+ }, [updatePosition]);
148
+
149
+ if (!position || typeof document === "undefined") {
150
+ return null;
151
+ }
152
+
153
+ return createPortal(
154
+ <div
155
+ className="fixed z-50"
156
+ style={{ left: position.left, top: position.top }}
157
+ >
158
+ {children}
159
+ </div>,
160
+ document.body,
161
+ );
162
+ };
163
+
48
164
  export class NavigationMenuPlugin implements IStatelessPlugin<Data> {
49
165
  tagName = "marimo-nav-menu";
50
166
 
@@ -109,30 +225,12 @@ const NavMenuComponent = ({
109
225
  const renderMenuItem = (item: MenuItem | MenuItemGroup) => {
110
226
  if ("items" in item) {
111
227
  return orientation === "horizontal" ? (
112
- <NavigationMenu orientation="horizontal" key={item.label}>
113
- <NavigationMenuList>
114
- <NavigationMenuItem>
115
- <NavigationMenuTrigger>
116
- {renderHTML({ html: item.label })}
117
- </NavigationMenuTrigger>
118
- <NavigationMenuContent>
119
- <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
120
- {item.items.map((subItem) => (
121
- <ListItem
122
- key={subItem.label}
123
- label={subItem.label}
124
- href={preserveQueryParams(subItem.href)}
125
- target={target(subItem.href)}
126
- >
127
- {subItem.description &&
128
- renderHTML({ html: subItem.description })}
129
- </ListItem>
130
- ))}
131
- </ul>
132
- </NavigationMenuContent>
133
- </NavigationMenuItem>
134
- </NavigationMenuList>
135
- </NavigationMenu>
228
+ <HorizontalMenuGroup
229
+ key={item.label}
230
+ item={item}
231
+ preserveQueryParams={preserveQueryParams}
232
+ target={target}
233
+ />
136
234
  ) : (
137
235
  <NavigationMenuItem key={item.label}>
138
236
  <div
@@ -196,32 +294,30 @@ const NavMenuComponent = ({
196
294
  };
197
295
 
198
296
  const ListItem = React.forwardRef<
199
- React.ElementRef<"a">,
297
+ React.ComponentRef<"a">,
200
298
  React.ComponentPropsWithoutRef<"a"> & {
201
299
  label: string;
202
300
  }
203
301
  >(({ className, label, children, ...props }, ref) => {
204
302
  return (
205
303
  <li>
206
- <NavigationMenuLink asChild={true}>
207
- <a
208
- ref={ref}
209
- className={cn(
210
- "block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-hidden transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
211
- className,
212
- )}
213
- {...props}
214
- >
215
- <div className="text-base font-medium leading-none">
216
- {renderHTML({ html: label })}
217
- </div>
218
- {children && (
219
- <p className="line-clamp-2 text-sm leading-snug text-muted-foreground">
220
- {children}
221
- </p>
222
- )}
223
- </a>
224
- </NavigationMenuLink>
304
+ <a
305
+ ref={ref}
306
+ className={cn(
307
+ "block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-hidden transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
308
+ className,
309
+ )}
310
+ {...props}
311
+ >
312
+ <div className="text-base font-medium leading-none">
313
+ {renderHTML({ html: label })}
314
+ </div>
315
+ {children && (
316
+ <p className="line-clamp-2 text-sm leading-snug text-muted-foreground">
317
+ {children}
318
+ </p>
319
+ )}
320
+ </a>
225
321
  </li>
226
322
  );
227
323
  });