@marimo-team/islands 0.21.2-dev42 → 0.21.2-dev44

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.21.2-dev42",
3
+ "version": "0.21.2-dev44",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -3,50 +3,15 @@
3
3
  /*
4
4
  This allows you to create a basic tooltip using the data-tooltip attribute
5
5
  e.g. <span data-tooltip="Hello, World!">Hover me</span>
6
+
7
+ The tooltip content is rendered via the React Tooltip component (Radix UI portal),
8
+ which prevents clipping inside containers with overflow:hidden.
9
+ See: RenderHTML.tsx -> wrapTooltipTargets
6
10
  */
7
11
 
8
12
  .markdown {
9
13
  [data-tooltip] {
10
- position: relative;
11
14
  cursor: pointer;
12
15
  text-decoration: underline dotted;
13
16
  }
14
-
15
- [data-tooltip]::before,
16
- [data-tooltip]::after {
17
- visibility: hidden;
18
- opacity: 0;
19
- pointer-events: none;
20
- transition: all 0.2s ease;
21
- position: absolute;
22
- z-index: 1000;
23
- left: 50%;
24
- transform: translateX(-50%);
25
- }
26
-
27
- [data-tooltip]::before {
28
- content: attr(data-tooltip);
29
- bottom: calc(100% + 10px);
30
- padding: 5px 10px;
31
- width: max-content;
32
- max-width: 300px;
33
- border-radius: 6px;
34
- background-color: ;
35
- text-align: center;
36
- line-height: 1.4;
37
- white-space: pre-wrap;
38
-
39
- @apply bg-background text-foreground shadow-md border text-base;
40
- }
41
-
42
- [data-tooltip]:hover::before,
43
- [data-tooltip]:hover::after {
44
- visibility: visible;
45
- opacity: 1;
46
- }
47
-
48
- [data-tooltip]:hover::before {
49
- /* stylelint-disable-next-line unit-allowed-list */
50
- transform: translateX(-50%) translateY(10px);
51
- }
52
17
  }
@@ -14,6 +14,7 @@ import React, {
14
14
  } from "react";
15
15
  import { CopyClipboardIcon } from "@/components/icons/copy-icon";
16
16
  import { QueryParamPreservingLink } from "@/components/ui/query-param-preserving-link";
17
+ import { Tooltip } from "@/components/ui/tooltip";
17
18
  import { DocHoverTarget } from "@/core/documentation/DocHoverTarget";
18
19
  import { sanitizeHtml, useSanitizeHtml } from "./sanitize";
19
20
 
@@ -160,6 +161,21 @@ const wrapDocHoverTargets: TransformFn = (
160
161
  }
161
162
  };
162
163
 
164
+ // Wrap elements with data-tooltip attribute in a Tooltip component.
165
+ // This renders the tooltip in a portal (top layer), fixing clipping inside
166
+ // containers with overflow:hidden (e.g. grid cells).
167
+ const wrapTooltipTargets: TransformFn = (
168
+ reactNode: ReactNode,
169
+ domNode: DOMNode,
170
+ ): JSX.Element | undefined => {
171
+ if (domNode instanceof Element && domNode.attribs?.["data-tooltip"]) {
172
+ const tooltipContent = domNode.attribs["data-tooltip"];
173
+ return (
174
+ <Tooltip content={tooltipContent}>{reactNode as JSX.Element}</Tooltip>
175
+ );
176
+ }
177
+ };
178
+
163
179
  const CopyableCode = ({ children }: { children: ReactNode }) => {
164
180
  const ref = useRef<HTMLDivElement>(null);
165
181
  return (
@@ -239,6 +255,7 @@ function parseHtml({
239
255
  addCopyButtonToCodehilite,
240
256
  preserveQueryParamsInAnchorLinks,
241
257
  wrapDocHoverTargets,
258
+ wrapTooltipTargets,
242
259
  removeWrappingBodyTags,
243
260
  removeWrappingHtmlTags,
244
261
  ];
@@ -197,6 +197,51 @@ describe("parseHtml", () => {
197
197
  });
198
198
  });
199
199
 
200
+ describe("wrapTooltipTargets", () => {
201
+ test("data-tooltip wraps element in Tooltip component", () => {
202
+ const html = '<span data-tooltip="Hello world">Hover me</span>';
203
+ expect(parseHtml({ html })).toMatchInlineSnapshot(`
204
+ <Tooltip
205
+ content="Hello world"
206
+ >
207
+ <span
208
+ data-tooltip="Hello world"
209
+ >
210
+ Hover me
211
+ </span>
212
+ </Tooltip>
213
+ `);
214
+ });
215
+
216
+ test("element without data-tooltip is not wrapped", () => {
217
+ const html = "<span>No tooltip</span>";
218
+ expect(parseHtml({ html })).toMatchInlineSnapshot(`
219
+ <span>
220
+ No tooltip
221
+ </span>
222
+ `);
223
+ });
224
+
225
+ test("data-tooltip on nested element wraps only that element", () => {
226
+ const html = '<p>Outer <span data-tooltip="tip">inner</span> text</p>';
227
+ expect(parseHtml({ html })).toMatchInlineSnapshot(`
228
+ <p>
229
+ Outer
230
+ <Tooltip
231
+ content="tip"
232
+ >
233
+ <span
234
+ data-tooltip="tip"
235
+ >
236
+ inner
237
+ </span>
238
+ </Tooltip>
239
+ text
240
+ </p>
241
+ `);
242
+ });
243
+ });
244
+
200
245
  describe("parseHtml with < nad >", () => {
201
246
  const html =
202
247
  'thread <unnamed> panicked at "assertion failed: `(left == right)`"';