@marimo-team/islands 0.24.1-dev115 → 0.24.1-dev119
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/{ConnectedDataExplorerComponent-3vyrwCHu.js → ConnectedDataExplorerComponent-qIKbwYin.js} +10 -10
- package/dist/{ErrorBoundary-QF0xsxMw.js → ErrorBoundary-CR-ZQN_c.js} +2 -2
- package/dist/{any-language-editor-B2e3EkTe.js → any-language-editor-CpTnK43-.js} +3 -3
- package/dist/assets/__vite-browser-external-BdKGjRZ4.js +1 -0
- package/dist/assets/{worker-C3TCEtlU.js → worker-DlIBfp9S.js} +2 -2
- package/dist/{chat-ui-BgGHMO2G.js → chat-ui-DttQ-5Ut.js} +15 -15
- package/dist/{check-C_-c2CXl.js → check-CHig47QV.js} +1 -1
- package/dist/{common-Cdx64lyR.js → common-B2pVJVWJ.js} +7590 -7548
- package/dist/{copy-D4GHy7GA.js → copy-CD7S58CY.js} +1 -1
- package/dist/{dist-mymH-A_x.js → dist-3_o3T78I.js} +14 -14
- package/dist/{dropdown-menu-Div6gwlw.js → dropdown-menu-DhCfcscX.js} +123 -123
- package/dist/{error-banner-DmgOcFS3.js → error-banner-WDhUzJyg.js} +202 -202
- package/dist/{esm-CmFEQJjP.js → esm-CesmlDrs.js} +1 -1
- package/dist/{extends-CGTKDWHv.js → extends-BPB6_lTK.js} +3 -3
- package/dist/{formats-DuRRWVwb.js → formats-CJMVUfb3.js} +1 -1
- package/dist/{glide-data-editor-ekJ5GwaZ.js → glide-data-editor-sPZ8fUFn.js} +7 -7
- package/dist/{glide-utils-Dwc8Eh8G.js → glide-utils-NShAPPtn.js} +2 -2
- package/dist/{html-to-image-u8Ik6EnK.js → html-to-image-BTYnN4ev.js} +3378 -3378
- package/dist/{label-DdGS_CZZ.js → label-lwzzBHUW.js} +1 -1
- package/dist/main.js +793 -793
- package/dist/{mermaid-Bt45Zzl4.js → mermaid-BsHdQeQf.js} +3 -3
- package/dist/{process-output-DQiqt-_U.js → process-output-CsALk6tp.js} +3 -3
- package/dist/{reveal-component-tQ-rgxcQ.js → reveal-component-CiaqFa0B.js} +8 -8
- package/dist/{schemas-BjeOpZLk.js → schemas-DzK6U94N.js} +1379 -1363
- package/dist/{select-DotAQ4jp.js → select-3qHpFKF9.js} +286 -286
- package/dist/{spec-BesaYkGC.js → spec-CutWdqo3.js} +4 -4
- package/dist/style.css +1 -1
- package/dist/{toDate-CrAIOASL.js → toDate-D-Rx3ux5.js} +2 -2
- package/dist/{tooltip-COXZxyl7.js → tooltip-Dt77sBeT.js} +87 -87
- package/dist/{useAsyncData-x0_tWDWI.js → useAsyncData-CH6-CgJF.js} +1 -1
- package/dist/{useDateFormatter-B3V__WqX.js → useDateFormatter-Cp9Jdxls.js} +2 -2
- package/dist/{useDeepCompareMemoize-KaRHJEEU.js → useDeepCompareMemoize-JC87C_jO.js} +1 -1
- package/dist/{useLifecycle-x0OriHo-.js → useLifecycle-B4RGlyf0.js} +2 -2
- package/dist/{useTheme-Bm9_FyqO.js → useTheme-CVJ0UOf2.js} +2 -1
- package/dist/{vega-component-nD2oP6WN.js → vega-component-D-IXRnlx.js} +7 -7
- package/package.json +1 -1
- package/src/components/ai/ai-provider-icon.tsx +2 -2
- package/src/components/ai/ai-utils.ts +1 -1
- package/src/components/app-config/ai-config.tsx +33 -37
- package/src/components/app-config/user-config-form.tsx +1 -1
- package/src/components/data-table/renderers.tsx +2 -6
- package/src/components/editor/Output.tsx +40 -0
- package/src/components/editor/__tests__/Output.test.tsx +85 -2
- package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +832 -0
- package/src/components/editor/file-tree/__tests__/file-viewer.test.tsx +27 -0
- package/src/components/editor/file-tree/__tests__/requesting-tree.test.ts +130 -0
- package/src/components/editor/file-tree/file-browser-row.tsx +82 -0
- package/src/components/editor/file-tree/file-explorer.tsx +377 -159
- package/src/components/editor/file-tree/file-operations.tsx +1 -1
- package/src/components/editor/file-tree/file-search-results.tsx +142 -0
- package/src/components/editor/file-tree/file-tree-row.tsx +40 -0
- package/src/components/editor/file-tree/file-viewer.tsx +2 -1
- package/src/components/editor/file-tree/requesting-tree.tsx +162 -32
- package/src/components/editor/file-tree/use-file-search.ts +142 -0
- package/src/components/editor/file-tree/use-hover-expand.ts +34 -0
- package/src/components/ui/__tests__/fullscreen.test.tsx +88 -0
- package/src/components/ui/fullscreen.tsx +43 -1
- package/src/components/ui/links.tsx +2 -1
- package/src/core/ai/ids/__tests__/ids.test.ts +0 -8
- package/src/core/ai/ids/ids.ts +1 -1
- package/src/core/config/config-schema.ts +1 -0
- package/src/core/network/__tests__/requests-toasting.test.tsx +14 -0
- package/src/core/network/requests-toasting.tsx +1 -1
- package/src/hooks/useEventListener.ts +1 -1
- package/dist/assets/__vite-browser-external-Cf4O9gnt.js +0 -1
|
@@ -18,10 +18,12 @@ import {
|
|
|
18
18
|
ChevronsDownUpIcon,
|
|
19
19
|
ChevronsUpDownIcon,
|
|
20
20
|
ExpandIcon,
|
|
21
|
+
ShrinkIcon,
|
|
21
22
|
} from "lucide-react";
|
|
22
23
|
import { tooltipHandler } from "@/components/charts/tooltip";
|
|
23
24
|
import { useExpandedOutput } from "@/core/cells/outputs";
|
|
24
25
|
import { viewStateAtom } from "@/core/mode";
|
|
26
|
+
import { useEventListener } from "@/hooks/useEventListener";
|
|
25
27
|
import { useIframeCapabilities } from "@/hooks/useIframeCapabilities";
|
|
26
28
|
import { useOverflowDetection } from "@/hooks/useOverflowDetection";
|
|
27
29
|
import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
@@ -31,11 +33,13 @@ import { getContainerWidth } from "@/plugins/impl/vega/utils";
|
|
|
31
33
|
import { useTheme } from "@/theme/useTheme";
|
|
32
34
|
import { Events } from "@/utils/events";
|
|
33
35
|
import { invariant } from "@/utils/invariant";
|
|
36
|
+
import { Logger } from "@/utils/Logger";
|
|
34
37
|
import { processMimeBundle } from "@/utils/mime-types";
|
|
35
38
|
import { Objects } from "@/utils/objects";
|
|
36
39
|
import { LazyVegaEmbed } from "../charts/lazy";
|
|
37
40
|
import { ChartLoadingState } from "../data-table/charts/components/chart-states";
|
|
38
41
|
import { Button } from "../ui/button";
|
|
42
|
+
import { useIsFullScreen } from "../ui/fullscreen";
|
|
39
43
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
|
|
40
44
|
import { Tooltip } from "../ui/tooltip";
|
|
41
45
|
import { CsvViewer } from "./file-tree/renderers";
|
|
@@ -408,6 +412,12 @@ const Div = React.forwardRef<
|
|
|
408
412
|
>((props, ref) => <div ref={ref} {...props} />);
|
|
409
413
|
Div.displayName = "Div";
|
|
410
414
|
|
|
415
|
+
function exitFullscreen() {
|
|
416
|
+
document.exitFullscreen().catch((error) => {
|
|
417
|
+
Logger.warn("Failed to exit fullscreen", error);
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
411
421
|
/**
|
|
412
422
|
* Detects if there is overflow in the output area and adds a button to optionally expand
|
|
413
423
|
*/
|
|
@@ -425,6 +435,16 @@ const ExpandableOutput = React.memo(
|
|
|
425
435
|
const [isExpanded, setIsExpanded] = useExpandedOutput(cellId);
|
|
426
436
|
const isOverflowing = useOverflowDetection(containerRef);
|
|
427
437
|
const { hasFullscreen } = useIframeCapabilities();
|
|
438
|
+
const isFullscreen = useIsFullScreen(containerRef);
|
|
439
|
+
|
|
440
|
+
// Not every host exits fullscreen on Escape by itself. A null target keeps
|
|
441
|
+
// the listener off every output that is not fullscreen.
|
|
442
|
+
useEventListener(isFullscreen ? document : null, "keydown", (event) => {
|
|
443
|
+
if (event.key !== "Escape" || !document.fullscreenElement) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
exitFullscreen();
|
|
447
|
+
});
|
|
428
448
|
|
|
429
449
|
return (
|
|
430
450
|
<>
|
|
@@ -488,6 +508,26 @@ const ExpandableOutput = React.memo(
|
|
|
488
508
|
isExpanded || forceExpand ? { maxHeight: "none" } : undefined
|
|
489
509
|
}
|
|
490
510
|
>
|
|
511
|
+
{/* Fullscreen paints this element only, and the action buttons sit
|
|
512
|
+
outside it. A host does not always draw an exit overlay, so the
|
|
513
|
+
output carries its own exit control. */}
|
|
514
|
+
{isFullscreen && (
|
|
515
|
+
<Tooltip content="Exit fullscreen" side="left">
|
|
516
|
+
<Button
|
|
517
|
+
data-testid="exit-fullscreen-output-button"
|
|
518
|
+
aria-label="Exit fullscreen"
|
|
519
|
+
className="absolute right-2 top-2 z-2 p-1 bg-background/90 border border-border hover:bg-muted print:hidden"
|
|
520
|
+
onClick={exitFullscreen}
|
|
521
|
+
size="xs"
|
|
522
|
+
variant="text"
|
|
523
|
+
>
|
|
524
|
+
<ShrinkIcon
|
|
525
|
+
className="size-4 opacity-60 hover:opacity-80"
|
|
526
|
+
strokeWidth={1.25}
|
|
527
|
+
/>
|
|
528
|
+
</Button>
|
|
529
|
+
</Tooltip>
|
|
530
|
+
)}
|
|
491
531
|
{children}
|
|
492
532
|
</div>
|
|
493
533
|
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { act, fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
4
|
import { cellId } from "@/__tests__/branded";
|
|
5
5
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
6
6
|
import { OutputArea, OutputRenderer } from "../Output";
|
|
@@ -158,3 +158,86 @@ describe("OutputRenderer image and SVG rendering", () => {
|
|
|
158
158
|
expect(imgElement).toHaveAttribute("src", base64PngDataUrl);
|
|
159
159
|
});
|
|
160
160
|
});
|
|
161
|
+
|
|
162
|
+
describe("OutputArea fullscreen exit control", () => {
|
|
163
|
+
let fullscreenElement: Element | null = null;
|
|
164
|
+
const exitFullscreen = vi.fn(() => Promise.resolve());
|
|
165
|
+
|
|
166
|
+
beforeEach(() => {
|
|
167
|
+
fullscreenElement = null;
|
|
168
|
+
exitFullscreen.mockClear();
|
|
169
|
+
Object.defineProperty(document, "fullscreenElement", {
|
|
170
|
+
configurable: true,
|
|
171
|
+
get: () => fullscreenElement,
|
|
172
|
+
});
|
|
173
|
+
Object.defineProperty(document, "exitFullscreen", {
|
|
174
|
+
configurable: true,
|
|
175
|
+
value: exitFullscreen,
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Drop the stubs so that the real document properties come back.
|
|
180
|
+
afterEach(() => {
|
|
181
|
+
Reflect.deleteProperty(document, "fullscreenElement");
|
|
182
|
+
Reflect.deleteProperty(document, "exitFullscreen");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const renderOutput = () =>
|
|
186
|
+
render(
|
|
187
|
+
<TooltipProvider>
|
|
188
|
+
<OutputArea
|
|
189
|
+
output={{
|
|
190
|
+
channel: "output",
|
|
191
|
+
data: "Hello World",
|
|
192
|
+
mimetype: "text/plain",
|
|
193
|
+
}}
|
|
194
|
+
cellId={cellId("test")}
|
|
195
|
+
stale={false}
|
|
196
|
+
loading={false}
|
|
197
|
+
allowExpand={true}
|
|
198
|
+
/>
|
|
199
|
+
</TooltipProvider>,
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const enterFullscreen = (container: HTMLElement) => {
|
|
203
|
+
fullscreenElement = container.querySelector('[data-cell-role="output"]');
|
|
204
|
+
act(() => {
|
|
205
|
+
document.dispatchEvent(new Event("fullscreenchange"));
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
it("hides the exit button outside fullscreen", () => {
|
|
210
|
+
renderOutput();
|
|
211
|
+
expect(
|
|
212
|
+
screen.queryByTestId("exit-fullscreen-output-button"),
|
|
213
|
+
).not.toBeInTheDocument();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("shows the exit button when the output is the fullscreen element", () => {
|
|
217
|
+
const { container } = renderOutput();
|
|
218
|
+
enterFullscreen(container);
|
|
219
|
+
expect(
|
|
220
|
+
screen.getByTestId("exit-fullscreen-output-button"),
|
|
221
|
+
).toBeInTheDocument();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("exits fullscreen on click", () => {
|
|
225
|
+
const { container } = renderOutput();
|
|
226
|
+
enterFullscreen(container);
|
|
227
|
+
fireEvent.click(screen.getByTestId("exit-fullscreen-output-button"));
|
|
228
|
+
expect(exitFullscreen).toHaveBeenCalledTimes(1);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("exits fullscreen on Escape", () => {
|
|
232
|
+
const { container } = renderOutput();
|
|
233
|
+
enterFullscreen(container);
|
|
234
|
+
fireEvent.keyDown(document, { key: "Escape" });
|
|
235
|
+
expect(exitFullscreen).toHaveBeenCalledTimes(1);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("ignores Escape outside fullscreen", () => {
|
|
239
|
+
renderOutput();
|
|
240
|
+
fireEvent.keyDown(document, { key: "Escape" });
|
|
241
|
+
expect(exitFullscreen).not.toHaveBeenCalled();
|
|
242
|
+
});
|
|
243
|
+
});
|