@marimo-team/islands 0.19.7-dev35 → 0.19.7-dev37

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.
Files changed (33) hide show
  1. package/dist/{glide-data-editor-DHsjQhtP.js → glide-data-editor-C3T7HsLi.js} +1 -1
  2. package/dist/main.js +32 -21
  3. package/dist/style.css +1 -1
  4. package/dist/{types-DBsIRhMX.js → types-CzEZ3EWT.js} +1 -1
  5. package/package.json +1 -1
  6. package/src/components/data-table/TableActions.tsx +5 -3
  7. package/src/components/data-table/download-actions.tsx +7 -2
  8. package/src/components/data-table/pagination.tsx +4 -4
  9. package/src/components/debug/indicator.tsx +1 -1
  10. package/src/components/editor/actions/useNotebookActions.tsx +4 -2
  11. package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +1 -1
  12. package/src/components/editor/chrome/wrapper/app-chrome.tsx +6 -4
  13. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +178 -0
  14. package/src/components/editor/chrome/wrapper/footer.tsx +1 -1
  15. package/src/components/editor/chrome/wrapper/sidebar.tsx +1 -1
  16. package/src/components/editor/controls/Controls.tsx +2 -2
  17. package/src/components/editor/controls/notebook-menu-dropdown.tsx +1 -1
  18. package/src/components/editor/file-tree/file-explorer.tsx +1 -1
  19. package/src/components/editor/header/status.tsx +1 -1
  20. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +13 -4
  21. package/src/components/home/components.tsx +1 -1
  22. package/src/components/static-html/static-banner.tsx +1 -1
  23. package/src/components/ui/dropdown-menu.tsx +1 -1
  24. package/src/components/ui/table.tsx +1 -1
  25. package/src/core/export/__tests__/hooks.test.ts +60 -58
  26. package/src/core/export/hooks.ts +71 -31
  27. package/src/core/network/types.ts +4 -0
  28. package/src/css/app/print.css +0 -14
  29. package/src/utils/__tests__/async-capture-tracker.test.ts +353 -0
  30. package/src/utils/__tests__/download.test.tsx +5 -114
  31. package/src/utils/async-capture-tracker.ts +168 -0
  32. package/src/utils/download.ts +17 -57
  33. package/src/utils/html-to-image.ts +9 -12
@@ -5183,7 +5183,7 @@ var DropdownMenuContent = import_react.forwardRef((e4, t) => {
5183
5183
  let n = (0, import_compiler_runtime$3.c)(17), r, i, a, o;
5184
5184
  n[0] === e4 ? (r = n[1], i = n[2], a = n[3], o = n[4]) : ({ className: r, scrollable: a, sideOffset: o, ...i } = e4, n[0] = e4, n[1] = r, n[2] = i, n[3] = a, n[4] = o);
5185
5185
  let s = a === void 0 ? true : a, c = o === void 0 ? 4 : o, l;
5186
- n[5] !== r || n[6] !== s ? (l = cn(menuContentCommon(), "animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", s && "overflow-auto", r), n[5] = r, n[6] = s, n[7] = l) : l = n[7];
5186
+ n[5] !== r || n[6] !== s ? (l = cn(menuContentCommon(), "animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 print:hidden", s && "overflow-auto", r), n[5] = r, n[6] = s, n[7] = l) : l = n[7];
5187
5187
  let u = s ? `calc(var(--radix-dropdown-menu-content-available-height) - ${MAX_HEIGHT_OFFSET}px)` : void 0, d;
5188
5188
  n[8] !== i.style || n[9] !== u ? (d = {
5189
5189
  ...i.style,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.19.7-dev35",
3
+ "version": "0.19.7-dev37",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -107,13 +107,13 @@ export const TableActions = <TData,>({
107
107
  };
108
108
 
109
109
  return (
110
- <div className="flex items-center shrink-0 pt-1 no-print">
110
+ <div className="flex items-center shrink-0 pt-1">
111
111
  {onSearchQueryChange && enableSearch && (
112
112
  <Tooltip content="Search">
113
113
  <Button
114
114
  variant="text"
115
115
  size="xs"
116
- className="mb-0"
116
+ className="mb-0 print:hidden"
117
117
  onClick={() => setIsSearchEnabled(!isSearchEnabled)}
118
118
  >
119
119
  <SearchIcon className="w-4 h-4 text-muted-foreground" />
@@ -125,7 +125,7 @@ export const TableActions = <TData,>({
125
125
  <Button
126
126
  variant="text"
127
127
  size="xs"
128
- className="mb-0"
128
+ className="mb-0 print:hidden"
129
129
  onClick={toggleDisplayHeader}
130
130
  >
131
131
  <ChartSplineIcon className="w-4 h-4 text-muted-foreground" />
@@ -140,6 +140,7 @@ export const TableActions = <TData,>({
140
140
  variant="text"
141
141
  size="xs"
142
142
  onClick={() => togglePanel("row-viewer")}
143
+ className="print:hidden"
143
144
  >
144
145
  <PanelRightIcon
145
146
  className={cn(
@@ -156,6 +157,7 @@ export const TableActions = <TData,>({
156
157
  variant="text"
157
158
  size="xs"
158
159
  onClick={() => togglePanel("column-explorer")}
160
+ className="print:hidden"
159
161
  >
160
162
  <ChartColumnStacked
161
163
  className={cn(
@@ -87,7 +87,12 @@ export const DownloadAs: React.FC<DownloadActionProps> = (props) => {
87
87
  const { locale } = useLocale();
88
88
 
89
89
  const button = (
90
- <Button data-testid="download-as-button" size="xs" variant="link">
90
+ <Button
91
+ data-testid="download-as-button"
92
+ size="xs"
93
+ variant="link"
94
+ className="print:hidden"
95
+ >
91
96
  Download <ChevronDownIcon className="w-3 h-3 ml-1" />
92
97
  </Button>
93
98
  );
@@ -146,7 +151,7 @@ export const DownloadAs: React.FC<DownloadActionProps> = (props) => {
146
151
  return (
147
152
  <DropdownMenu modal={false}>
148
153
  <DropdownMenuTrigger asChild={true}>{button}</DropdownMenuTrigger>
149
- <DropdownMenuContent side="bottom" className="no-print">
154
+ <DropdownMenuContent side="bottom" className="print:hidden">
150
155
  {options.map((option) => (
151
156
  <DropdownMenuItem
152
157
  key={option.label}
@@ -67,7 +67,7 @@ export const DataTablePagination = <TData,>({
67
67
  size="xs"
68
68
  data-testid="select-all-button"
69
69
  variant="link"
70
- className="h-4"
70
+ className="h-4 print:hidden"
71
71
  onMouseDown={Events.preventFocus}
72
72
  onClick={() => {
73
73
  if (onSelectAllRowsChange) {
@@ -91,7 +91,7 @@ export const DataTablePagination = <TData,>({
91
91
  size="xs"
92
92
  data-testid="clear-selection-button"
93
93
  variant="link"
94
- className="h-4"
94
+ className="h-4 print:hidden"
95
95
  onMouseDown={Events.preventFocus}
96
96
  onClick={() => {
97
97
  if (!isCellSelection) {
@@ -139,7 +139,7 @@ export const DataTablePagination = <TData,>({
139
139
 
140
140
  const renderPageSizeSelector = () => {
141
141
  return (
142
- <div className="flex items-center gap-1 text-xs whitespace-nowrap mr-1">
142
+ <div className="flex items-center gap-1 text-xs whitespace-nowrap mr-1 print:hidden">
143
143
  <Select
144
144
  value={pageSize.toString()}
145
145
  onValueChange={(value) => table.setPageSize(Number(value))}
@@ -173,7 +173,7 @@ export const DataTablePagination = <TData,>({
173
173
  {showPageSizeSelector && renderPageSizeSelector()}
174
174
  </div>
175
175
 
176
- <div className="flex items-end space-x-2">
176
+ <div className="flex items-end space-x-2 print:hidden">
177
177
  <Button
178
178
  size="xs"
179
179
  variant="outline"
@@ -5,7 +5,7 @@ export const TailwindIndicator = () => {
5
5
  }
6
6
 
7
7
  return (
8
- <div className="fixed bottom-10 right-0 z-50 flex items-center justify-center bg-gray-800 py-[2px] px-1 font-mono text-[10px] text-white font-semibold">
8
+ <div className="fixed bottom-10 right-0 z-50 flex items-center justify-center bg-gray-800 py-[2px] px-1 font-mono text-[10px] text-white font-semibold print:hidden">
9
9
  <div className="block sm:hidden">xs</div>
10
10
  <div className="hidden sm:block md:hidden lg:hidden xl:hidden 2xl:hidden">
11
11
  sm
@@ -70,6 +70,7 @@ import { createShareableLink } from "@/core/wasm/share";
70
70
  import { isWasm } from "@/core/wasm/utils";
71
71
  import { copyToClipboard } from "@/utils/copy";
72
72
  import {
73
+ ADD_PRINTING_CLASS,
73
74
  downloadAsPDF,
74
75
  downloadBlob,
75
76
  downloadHTMLAsImage,
@@ -219,6 +220,8 @@ export function useNotebookActions() {
219
220
  await downloadHTMLAsImage({
220
221
  element: app,
221
222
  filename: document.title,
223
+ // Add body.printing ONLY when converting the whole notebook to a screenshot
224
+ prepare: ADD_PRINTING_CLASS,
222
225
  });
223
226
  },
224
227
  },
@@ -241,8 +244,7 @@ export function useNotebookActions() {
241
244
 
242
245
  const downloadPDF = async (progress: ProgressState) => {
243
246
  await updateCellOutputsWithScreenshots({
244
- takeScreenshots: () =>
245
- takeScreenshots({ progress, snappy: false }),
247
+ takeScreenshots: () => takeScreenshots({ progress }),
246
248
  updateCellOutputs,
247
249
  });
248
250
  await downloadAsPDF({
@@ -123,7 +123,7 @@ export const ContextAwarePanel: React.FC = () => {
123
123
  <>
124
124
  <PanelResizeHandle
125
125
  onDragging={handleDragging}
126
- className="resize-handle border-border z-20 no-print border-l"
126
+ className="resize-handle border-border z-20 print:hidden border-l"
127
127
  />
128
128
  <Panel defaultSize={20} minSize={15} maxSize={80}>
129
129
  {renderBody()}
@@ -37,6 +37,7 @@ import {
37
37
  type PanelType,
38
38
  } from "../types";
39
39
  import { BackendConnectionStatus } from "./footer-items/backend-status";
40
+ import { LspStatus } from "./footer-items/lsp-status";
40
41
  import { PanelsWrapper } from "./panels";
41
42
  import { PendingAICells } from "./pending-ai-cells";
42
43
  import { useAiPanelTab } from "./useAiPanel";
@@ -227,7 +228,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
227
228
  <PanelResizeHandle
228
229
  onDragging={handleDragging}
229
230
  className={cn(
230
- "border-border no-print z-10",
231
+ "border-border print:hidden z-10",
231
232
  isSidebarOpen ? "resize-handle" : "resize-handle-collapsed",
232
233
  "vertical",
233
234
  )}
@@ -238,7 +239,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
238
239
  <PanelResizeHandle
239
240
  onDragging={handleDragging}
240
241
  className={cn(
241
- "border-border no-print z-20",
242
+ "border-border print:hidden z-20",
242
243
  isDeveloperPanelOpen ? "resize-handle" : "resize-handle-collapsed",
243
244
  "horizontal",
244
245
  )}
@@ -382,7 +383,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
382
383
  collapsedSize={0}
383
384
  collapsible={true}
384
385
  className={cn(
385
- "dark:bg-(--slate-1) no-print print:hidden hide-on-fullscreen",
386
+ "dark:bg-(--slate-1) print:hidden hide-on-fullscreen",
386
387
  isSidebarOpen && "border-r border-l border-(--slate-7)",
387
388
  )}
388
389
  minSize={10}
@@ -427,7 +428,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
427
428
  collapsedSize={0}
428
429
  collapsible={true}
429
430
  className={cn(
430
- "dark:bg-(--slate-1) no-print print:hidden hide-on-fullscreen",
431
+ "dark:bg-(--slate-1) print:hidden hide-on-fullscreen",
431
432
  isDeveloperPanelOpen && "border-t",
432
433
  )}
433
434
  minSize={10}
@@ -490,6 +491,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
490
491
  />
491
492
  <div className="border-l border-border h-4 mx-1" />
492
493
  <BackendConnectionStatus />
494
+ <LspStatus />
493
495
  <div className="flex-1" />
494
496
  <Button
495
497
  size="xs"
@@ -0,0 +1,178 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { atom, useAtomValue, useSetAtom } from "jotai";
4
+ import { AlertCircleIcon, CheckCircle2Icon } from "lucide-react";
5
+ import type React from "react";
6
+ import { Spinner } from "@/components/icons/spinner";
7
+ import { Tooltip } from "@/components/ui/tooltip";
8
+ import { toast } from "@/components/ui/use-toast";
9
+ import { API } from "@/core/network/api";
10
+ import { connectionAtom } from "@/core/network/connection";
11
+ import type {
12
+ LspHealthResponse,
13
+ LspRestartRequest,
14
+ LspRestartResponse,
15
+ } from "@/core/network/types";
16
+ import { isAppConnected } from "@/core/websocket/connection-utils";
17
+ import { useAsyncData } from "@/hooks/useAsyncData";
18
+ import { useInterval } from "@/hooks/useInterval";
19
+
20
+ const CHECK_LSP_HEALTH_INTERVAL_MS = 60_000;
21
+
22
+ export const lspHealthAtom = atom<LspHealthResponse | null>(null);
23
+
24
+ export const LspStatus: React.FC = () => {
25
+ const connection = useAtomValue(connectionAtom).state;
26
+ const setLspHealth = useSetAtom(lspHealthAtom);
27
+
28
+ const { isFetching, data, refetch } = useAsyncData(async () => {
29
+ if (!isAppConnected(connection)) {
30
+ return null;
31
+ }
32
+
33
+ try {
34
+ const health = await API.get<LspHealthResponse>("/lsp/health");
35
+ setLspHealth(health);
36
+ return health;
37
+ } catch {
38
+ return null;
39
+ }
40
+ }, [connection]);
41
+
42
+ useInterval(refetch, {
43
+ delayMs: isAppConnected(connection) ? CHECK_LSP_HEALTH_INTERVAL_MS : null,
44
+ whenVisible: true,
45
+ });
46
+
47
+ const handleRestart = async () => {
48
+ try {
49
+ const result = await API.post<LspRestartRequest, LspRestartResponse>(
50
+ "/lsp/restart",
51
+ {},
52
+ );
53
+
54
+ if (result.success) {
55
+ toast({
56
+ title: "LSP Servers Restarted",
57
+ description:
58
+ result.restarted.length > 0
59
+ ? `Restarted: ${result.restarted.join(", ")}`
60
+ : "No servers needed restart",
61
+ });
62
+ } else {
63
+ toast({
64
+ variant: "danger",
65
+ title: "LSP Restart Failed",
66
+ description: Object.entries(result.errors ?? {})
67
+ .map(([k, v]) => `${k}: ${v}`)
68
+ .join("\n"),
69
+ });
70
+ }
71
+
72
+ // Refresh health status
73
+ refetch();
74
+ } catch (error) {
75
+ toast({
76
+ variant: "danger",
77
+ title: "LSP Restart Failed",
78
+ description: error instanceof Error ? error.message : "Unknown error",
79
+ });
80
+ }
81
+ };
82
+
83
+ // Don't show if no LSP servers are configured
84
+ if (!data || data.servers.length === 0) {
85
+ return null;
86
+ }
87
+
88
+ const getStatusIcon = () => {
89
+ if (isFetching) {
90
+ return <Spinner size="small" />;
91
+ }
92
+
93
+ if (!data) {
94
+ return <AlertCircleIcon className="w-4 h-4" />;
95
+ }
96
+
97
+ switch (data.status) {
98
+ case "healthy":
99
+ return <CheckCircle2Icon className="w-4 h-4 text-(--green-9)" />;
100
+ case "degraded":
101
+ return <AlertCircleIcon className="w-4 h-4 text-(--yellow-11)" />;
102
+ case "unhealthy":
103
+ return <AlertCircleIcon className="w-4 h-4 text-(--yellow-11)" />;
104
+ }
105
+ };
106
+
107
+ const getServerStatusDisplay = (
108
+ status: "starting" | "running" | "stopped" | "crashed" | "unresponsive",
109
+ lastPingMs: number | null | undefined,
110
+ ) => {
111
+ switch (status) {
112
+ case "running":
113
+ return `✓ OK${lastPingMs == null ? "" : ` (${lastPingMs.toFixed(0)}ms)`}`;
114
+ case "starting":
115
+ return "⋯ Starting";
116
+ case "stopped":
117
+ return "✗ Stopped";
118
+ case "crashed":
119
+ return "✗ Crashed";
120
+ case "unresponsive":
121
+ return "✗ Not responding";
122
+ }
123
+ };
124
+
125
+ const getServerStatusColor = (
126
+ status: "starting" | "running" | "stopped" | "crashed" | "unresponsive",
127
+ ) => {
128
+ switch (status) {
129
+ case "running":
130
+ return "text-(--green-9)";
131
+ case "starting":
132
+ return "text-(--yellow-11)";
133
+ default:
134
+ return "text-(--red-9)";
135
+ }
136
+ };
137
+
138
+ const tooltipContent = (
139
+ <div className="text-sm">
140
+ <b>LSP Status</b>
141
+ <div className="mt-1 text-xs space-y-1">
142
+ {data?.servers.map((server) => (
143
+ <div key={server.serverId} className="flex justify-between gap-2">
144
+ <span>{server.serverId}</span>
145
+ <span className={getServerStatusColor(server.status)}>
146
+ {getServerStatusDisplay(server.status, server.lastPingMs)}
147
+ </span>
148
+ </div>
149
+ ))}
150
+ </div>
151
+ {data?.status === "healthy" ? null : (
152
+ <div className="mt-2 text-xs text-muted-foreground">
153
+ Click to restart failed servers
154
+ </div>
155
+ )}
156
+ </div>
157
+ );
158
+
159
+ const handleClick = () => {
160
+ if (data?.status !== "healthy") {
161
+ void handleRestart();
162
+ }
163
+ };
164
+
165
+ return (
166
+ <Tooltip content={tooltipContent} data-testid="footer-lsp-status">
167
+ <button
168
+ type="button"
169
+ onClick={handleClick}
170
+ className="p-1 hover:bg-accent rounded flex items-center gap-1.5 text-xs text-muted-foreground"
171
+ data-testid="lsp-status"
172
+ >
173
+ {getStatusIcon()}
174
+ <span>LSP</span>
175
+ </button>
176
+ </Tooltip>
177
+ );
178
+ };
@@ -57,7 +57,7 @@ export const Footer: React.FC = () => {
57
57
  });
58
58
 
59
59
  return (
60
- <footer className="h-10 py-1 gap-1 bg-background flex items-center text-muted-foreground text-md pl-2 pr-1 border-t border-border select-none no-print text-sm z-50 print:hidden hide-on-fullscreen overflow-x-auto overflow-y-hidden scrollbar-thin">
60
+ <footer className="h-10 py-1 gap-1 bg-background flex items-center text-muted-foreground text-md pl-2 pr-1 border-t border-border select-none print:hidden text-sm z-50 hide-on-fullscreen overflow-x-auto overflow-y-hidden scrollbar-thin">
61
61
  <FooterItem
62
62
  className="h-full"
63
63
  tooltip={
@@ -115,7 +115,7 @@ export const Sidebar: React.FC = () => {
115
115
  ]);
116
116
 
117
117
  return (
118
- <div className="h-full pt-4 pb-1 px-1 flex flex-col items-start text-muted-foreground text-md select-none no-print text-sm z-50 dark:bg-background print:hidden hide-on-fullscreen">
118
+ <div className="h-full pt-4 pb-1 px-1 flex flex-col items-start text-muted-foreground text-md select-none text-sm z-50 dark:bg-background print:hidden hide-on-fullscreen">
119
119
  <ReorderableList<PanelDescriptor>
120
120
  value={sidebarItems}
121
121
  setValue={handleSetSidebarItems}
@@ -212,7 +212,7 @@ const StopControlButton = ({
212
212
  };
213
213
 
214
214
  const topRightControls =
215
- "absolute top-3 right-5 m-0 flex items-center gap-2 min-h-[28px] no-print pointer-events-auto z-30 print:hidden";
215
+ "absolute top-3 right-5 m-0 flex items-center gap-2 min-h-[28px] print:hidden pointer-events-auto z-30";
216
216
 
217
217
  const bottomRightControls =
218
- "absolute bottom-5 right-5 flex flex-col gap-2 items-center no-print pointer-events-auto z-30 print:hidden";
218
+ "absolute bottom-5 right-5 flex flex-col gap-2 items-center print:hidden pointer-events-auto z-30";
@@ -111,7 +111,7 @@ export const NotebookMenuDropdown: React.FC<Props> = ({
111
111
  <DropdownMenuTrigger asChild={true} disabled={disabled}>
112
112
  {button}
113
113
  </DropdownMenuTrigger>
114
- <DropdownMenuContent align="end" className="no-print w-[240px]">
114
+ <DropdownMenuContent align="end" className="print:hidden w-[240px]">
115
115
  {actions.map((action) => {
116
116
  if (action.hidden || action.redundant) {
117
117
  return null;
@@ -510,7 +510,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
510
510
  return (
511
511
  <DropdownMenuContent
512
512
  align="end"
513
- className="no-print w-[220px]"
513
+ className="print:hidden w-[220px]"
514
514
  onClick={(e) => e.stopPropagation()}
515
515
  onCloseAutoFocus={(e) => e.preventDefault()}
516
516
  >
@@ -34,7 +34,7 @@ export const StatusOverlay: React.FC<{
34
34
  );
35
35
  };
36
36
 
37
- const topLeftStatus = "no-print pointer-events-auto hover:cursor-pointer";
37
+ const topLeftStatus = "print:hidden pointer-events-auto hover:cursor-pointer";
38
38
 
39
39
  const DisconnectedIcon = () => (
40
40
  <Tooltip content="App disconnected">
@@ -41,7 +41,11 @@ import { downloadAsHTML } from "@/core/static/download-html";
41
41
  import { isStaticNotebook } from "@/core/static/static-state";
42
42
  import { isWasm } from "@/core/wasm/utils";
43
43
  import { cn } from "@/utils/cn";
44
- import { downloadBlob, downloadHTMLAsImage } from "@/utils/download";
44
+ import {
45
+ ADD_PRINTING_CLASS,
46
+ downloadBlob,
47
+ downloadHTMLAsImage,
48
+ } from "@/utils/download";
45
49
  import { Filenames } from "@/utils/filenames";
46
50
  import { FloatingOutline } from "../../chrome/panels/outline/floating-outline";
47
51
  import { cellDomProps } from "../../common";
@@ -185,7 +189,12 @@ const ActionButtons: React.FC<{
185
189
  if (!app) {
186
190
  return;
187
191
  }
188
- await downloadHTMLAsImage({ element: app, filename: document.title });
192
+ await downloadHTMLAsImage({
193
+ element: app,
194
+ filename: document.title,
195
+ // Add body.printing ONLY when converting the whole notebook to a screenshot
196
+ prepare: ADD_PRINTING_CLASS,
197
+ });
189
198
  };
190
199
 
191
200
  const handleDownloadAsHTML = async () => {
@@ -271,7 +280,7 @@ const ActionButtons: React.FC<{
271
280
  <div
272
281
  data-testid="notebook-actions-dropdown"
273
282
  className={cn(
274
- "right-0 top-0 z-50 m-4 no-print flex gap-2 print:hidden",
283
+ "right-0 top-0 z-50 m-4 print:hidden flex gap-2",
275
284
  // If the notebook is static, we have a banner at the top, so
276
285
  // we can't use fixed positioning. Ideally this is sticky, but the
277
286
  // current dom structure makes that difficult.
@@ -284,7 +293,7 @@ const ActionButtons: React.FC<{
284
293
  <MoreHorizontalIcon className="w-4 h-4" />
285
294
  </Button>
286
295
  </DropdownMenuTrigger>
287
- <DropdownMenuContent align="end" className="no-print w-[220px]">
296
+ <DropdownMenuContent align="end" className="print:hidden w-[220px]">
288
297
  {actions}
289
298
  </DropdownMenuContent>
290
299
  </DropdownMenu>
@@ -80,7 +80,7 @@ export const OpenTutorialDropDown: React.FC = () => {
80
80
  <CaretDownIcon className="w-3 h-3 ml-1" />
81
81
  </Button>
82
82
  </DropdownMenuTrigger>
83
- <DropdownMenuContent side="bottom" align="end" className="no-print">
83
+ <DropdownMenuContent side="bottom" align="end" className="print:hidden">
84
84
  {Objects.entries(TUTORIALS).map(
85
85
  ([tutorialId, [label, Icon, description]]) => (
86
86
  <DropdownMenuItem
@@ -36,7 +36,7 @@ export const StaticBanner: React.FC = () => {
36
36
 
37
37
  return (
38
38
  <div
39
- className="px-4 py-2 bg-(--sky-2) border-b border-(--sky-7) text-(--sky-11) flex justify-between items-center gap-4 no-print text-sm"
39
+ className="px-4 py-2 bg-(--sky-2) border-b border-(--sky-7) text-(--sky-11) flex justify-between items-center gap-4 print:hidden text-sm"
40
40
  data-testid="static-notebook-banner"
41
41
  >
42
42
  <span>
@@ -83,7 +83,7 @@ const DropdownMenuContent = React.forwardRef<
83
83
  sideOffset={sideOffset}
84
84
  className={cn(
85
85
  menuContentCommon(),
86
- "animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
86
+ "animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 print:hidden",
87
87
  scrollable && "overflow-auto",
88
88
  className,
89
89
  )}
@@ -7,7 +7,7 @@ const Table = React.forwardRef<
7
7
  HTMLTableElement,
8
8
  React.HTMLAttributes<HTMLTableElement>
9
9
  >(({ className, ...props }, ref) => (
10
- <div className="w-full overflow-auto scrollbar-thin flex-1">
10
+ <div className="w-full overflow-auto scrollbar-thin flex-1 print:overflow-hidden">
11
11
  <table
12
12
  ref={ref}
13
13
  className={cn("w-full caption-bottom text-sm", className)}