@marimo-team/islands 0.23.16-dev2 → 0.23.16-dev21

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 (75) hide show
  1. package/dist/{ConnectedDataExplorerComponent-CJaUI-S-.js → ConnectedDataExplorerComponent-f9vLjQiF.js} +13 -13
  2. package/dist/{ErrorBoundary-DXlxsrTF.js → ErrorBoundary-DhLqwSWA.js} +3 -3
  3. package/dist/{any-language-editor-P9tjkj4n.js → any-language-editor-DifE-fl7.js} +5 -5
  4. package/dist/{button-BcSml68y.js → button-BSm8IXRU.js} +2 -4
  5. package/dist/{capabilities-BYLFYTYv.js → capabilities-C6OQ5YBO.js} +1 -1
  6. package/dist/{chat-ui-BdSDiVjk.js → chat-ui-BMBk8I78.js} +3129 -3129
  7. package/dist/{check-Cs-KV5XY.js → check-DP7U0H0G.js} +1 -1
  8. package/dist/{code-visibility-mgBayy67.js → code-visibility-Dt0oSVz1.js} +778 -755
  9. package/dist/{copy-Cs3yt6Vt.js → copy-DNq8q3zw.js} +2 -2
  10. package/dist/{dist-B96tMAst.js → dist-DIlxLFXG.js} +2 -2
  11. package/dist/{error-banner-DR7o3CbX.js → error-banner-B_GQfxxD.js} +2 -2
  12. package/dist/{esm-k8PIvuZW.js → esm-DzZVaNH4.js} +1 -1
  13. package/dist/{extends-Cq2JYHKy.js → extends-w2_S44bV.js} +4 -4
  14. package/dist/{formats-BFhkZJwd.js → formats-Dwq1THhr.js} +3 -3
  15. package/dist/{glide-data-editor--CaN-f27.js → glide-data-editor-B9K6-MJe.js} +9 -9
  16. package/dist/{html-to-image-DDENewl2.js → html-to-image-27MFfyOf.js} +4121 -2739
  17. package/dist/{input-DStQIuqD.js → input-C5K4VBvB.js} +7 -7
  18. package/dist/{label-DIk0QoFe.js → label-DjoYwqmj.js} +2 -2
  19. package/dist/{loader-CTHCI-qe.js → loader-DX-IDS7n.js} +1 -1
  20. package/dist/main.js +915 -923
  21. package/dist/{mermaid-CdSvixW2.js → mermaid-hv6IckVw.js} +5 -5
  22. package/dist/{node-sql-parser-DLl_zNw0.js → node-sql-parser-v1Vi-Fft.js} +16867 -16665
  23. package/dist/{process-output-2QPcgBQg.js → process-output-BpssYna4.js} +3 -3
  24. package/dist/{reveal-component-BDdfO6U_.js → reveal-component-BW-0eLEt.js} +702 -628
  25. package/dist/{spec-CnaxwDqy.js → spec-CQKL_D3i.js} +4 -4
  26. package/dist/{strings-BYAhZnQi.js → strings-DIy9NAmg.js} +4 -4
  27. package/dist/style.css +1 -1
  28. package/dist/{swiper-component-DE94711u.js → swiper-component-CEdAYjb7.js} +2 -2
  29. package/dist/toDate-CqhBWjvO.js +713 -0
  30. package/dist/{tooltip-B-qh7UPB.js → tooltip-f-qR0iUx.js} +3 -3
  31. package/dist/{types-DQl7jVYK.js → types-DicH9Oi0.js} +1 -1
  32. package/dist/{useAsyncData-CvO8WUy3.js → useAsyncData-CYOQb1EW.js} +1 -1
  33. package/dist/{useDateFormatter-BSoGim-G.js → useDateFormatter-Bt2qr_XS.js} +2 -2
  34. package/dist/{useDeepCompareMemoize-J3MKRdA4.js → useDeepCompareMemoize-CSHQeQEI.js} +1 -1
  35. package/dist/{useIframeCapabilities-POcFXHbw.js → useIframeCapabilities-kA09ykNq.js} +1 -1
  36. package/dist/{useLifecycle-DqPxHgAN.js → useLifecycle-CMJGqBaY.js} +3 -3
  37. package/dist/{useTheme-XMq9mNf_.js → useTheme-DYfby65G.js} +2 -2
  38. package/dist/{vega-component-CrFoZT1S.js → vega-component-C7nO5zcf.js} +10 -10
  39. package/dist/{zod-D0yOqoGe.js → zod-BUcyXSdR.js} +1 -1
  40. package/package.json +2 -2
  41. package/src/components/data-table/column-formatting/feature.ts +2 -1
  42. package/src/components/editor/connections/storage/__tests__/__snapshots__/as-code.test.ts.snap +50 -0
  43. package/src/components/editor/connections/storage/__tests__/as-code.test.ts +87 -8
  44. package/src/components/editor/connections/storage/as-code.ts +40 -21
  45. package/src/components/editor/connections/storage/schemas.ts +83 -42
  46. package/src/components/editor/file-tree/__tests__/file-render-mode.test.ts +27 -0
  47. package/src/components/editor/file-tree/__tests__/file-viewer.test.tsx +150 -0
  48. package/src/components/editor/file-tree/file-preview-metadata.tsx +51 -0
  49. package/src/components/editor/file-tree/file-render-mode.ts +32 -0
  50. package/src/components/editor/file-tree/file-viewer.tsx +76 -50
  51. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +198 -0
  52. package/src/components/slides/reveal-component.tsx +3 -2
  53. package/src/components/slides/slide-scroll-hint.tsx +161 -0
  54. package/src/components/ui/input.tsx +1 -1
  55. package/src/core/codemirror/keymaps/__tests__/keymaps.test.ts +31 -2
  56. package/src/core/codemirror/keymaps/keymaps.ts +12 -0
  57. package/src/core/codemirror/language/__tests__/sql.test.ts +443 -61
  58. package/src/core/codemirror/language/languages/sql/completion-store.ts +5 -1
  59. package/src/core/codemirror/language/languages/sql/sql.ts +210 -3
  60. package/src/core/hotkeys/hotkeys.ts +0 -2
  61. package/src/core/i18n/__tests__/locale-provider.test.tsx +54 -118
  62. package/src/core/i18n/__tests__/locale.test.ts +113 -0
  63. package/src/core/i18n/locale-provider.tsx +1 -19
  64. package/src/core/i18n/locale.ts +71 -0
  65. package/src/core/islands/__tests__/bridge.test.ts +107 -0
  66. package/src/core/islands/bridge.ts +15 -0
  67. package/src/core/mode.ts +10 -0
  68. package/src/core/network/__tests__/connection.test.ts +45 -0
  69. package/src/core/network/__tests__/requests-network.test.ts +13 -0
  70. package/src/core/network/connection.ts +15 -0
  71. package/src/core/network/requests-network.ts +6 -3
  72. package/src/core/network/types.ts +3 -1
  73. package/src/plugins/impl/FormPlugin.tsx +1 -1
  74. package/src/plugins/impl/__tests__/FormPlugin.test.tsx +162 -0
  75. package/dist/toDate-B3IRfHhw.js +0 -692
@@ -0,0 +1,161 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { ChevronDownIcon } from "lucide-react";
4
+ import {
5
+ type ReactNode,
6
+ type RefObject,
7
+ useEffect,
8
+ useRef,
9
+ useState,
10
+ } from "react";
11
+ import { cn } from "@/utils/cn";
12
+
13
+ /** Pixels of scroll before the hint is considered dismissed. */
14
+ const TOP_THRESHOLD_PX = 8;
15
+ /** Ignore sub-pixel overflow from rounding / borders. */
16
+ const OVERFLOW_TOLERANCE_PX = 1;
17
+
18
+ /**
19
+ * Whether a scroll container should show a "more content below" affordance.
20
+ * Visible only when content overflows and the viewport is still near the top.
21
+ */
22
+ export function shouldShowScrollHint(options: {
23
+ scrollHeight: number;
24
+ clientHeight: number;
25
+ scrollTop: number;
26
+ }): boolean {
27
+ const { scrollHeight, clientHeight, scrollTop } = options;
28
+ const overflowing = scrollHeight > clientHeight + OVERFLOW_TOLERANCE_PX;
29
+ const atTop = scrollTop <= TOP_THRESHOLD_PX;
30
+ return overflowing && atTop;
31
+ }
32
+
33
+ /**
34
+ * Measure only up to the first unrevealed fragment so
35
+ * the hint reflects currently revealed content, not future fragment steps.
36
+ */
37
+ function measureRevealedHeight(el: HTMLElement): number {
38
+ const firstUnrevealed = el.querySelector<HTMLElement>(
39
+ ".fragment:not(.visible)",
40
+ );
41
+ if (!firstUnrevealed) {
42
+ return el.scrollHeight;
43
+ }
44
+ const fragmentTop = firstUnrevealed.getBoundingClientRect().top;
45
+ return fragmentTop - el.getBoundingClientRect().top + el.scrollTop;
46
+ }
47
+
48
+ /**
49
+ * Tracks whether a scroll container is overflowing at the top, so we can
50
+ * surface a scroll affordance.
51
+ */
52
+ function useScrollHint(
53
+ scrollRef: RefObject<HTMLElement | null>,
54
+ contentRef: RefObject<HTMLElement | null>,
55
+ ): boolean {
56
+ const [showHint, setShowHint] = useState(false);
57
+
58
+ useEffect(() => {
59
+ const el = scrollRef.current;
60
+ const content = contentRef.current;
61
+ if (!el || !content) {
62
+ return;
63
+ }
64
+
65
+ let frame = 0;
66
+ const update = () => {
67
+ cancelAnimationFrame(frame);
68
+ frame = requestAnimationFrame(() => {
69
+ setShowHint(
70
+ shouldShowScrollHint({
71
+ scrollHeight: measureRevealedHeight(el),
72
+ clientHeight: el.clientHeight,
73
+ scrollTop: el.scrollTop,
74
+ }),
75
+ );
76
+ });
77
+ };
78
+
79
+ update();
80
+
81
+ const resizeObserver = new ResizeObserver(update);
82
+ resizeObserver.observe(el);
83
+ resizeObserver.observe(content);
84
+
85
+ // Fragments reveal via class changes (opacity/visibility, no layout shift),
86
+ // which the ResizeObserver can't see, so re-check on class mutations. Only
87
+ // attach on slides that have fragments to avoid reacting to unrelated class
88
+ // churn (e.g. animating widgets) on the common non-fragment slide.
89
+ const fragmentObserver = content.querySelector(".fragment")
90
+ ? new MutationObserver(update)
91
+ : null;
92
+ fragmentObserver?.observe(content, {
93
+ subtree: true,
94
+ attributes: true,
95
+ attributeFilter: ["class"],
96
+ });
97
+
98
+ el.addEventListener("scroll", update, { passive: true });
99
+
100
+ return () => {
101
+ cancelAnimationFrame(frame);
102
+ resizeObserver.disconnect();
103
+ fragmentObserver?.disconnect();
104
+ el.removeEventListener("scroll", update);
105
+ };
106
+ }, [scrollRef, contentRef]);
107
+
108
+ return showHint;
109
+ }
110
+
111
+ const ScrollHintOverlay = ({ className }: { className?: string }) => {
112
+ return (
113
+ <div
114
+ className={cn(
115
+ "pointer-events-none absolute inset-x-0 bottom-0 z-10 flex flex-col items-center",
116
+ "animate-in fade-in-0 duration-200",
117
+ className,
118
+ )}
119
+ data-testid="slide-scroll-hint"
120
+ aria-hidden={true}
121
+ >
122
+ <div className="h-16 w-full bg-linear-to-t from-background via-background/80 to-transparent" />
123
+ <div className="absolute bottom-3 flex items-center gap-1 rounded-full border border-border/60 bg-background/90 px-2.5 py-1 text-xs text-muted-foreground shadow-sm backdrop-blur-sm">
124
+ <ChevronDownIcon className="h-3.5 w-3.5" />
125
+ <span>Scroll for more</span>
126
+ </div>
127
+ </div>
128
+ );
129
+ };
130
+
131
+ /**
132
+ * Full-height scroll container for a slide. Shows a dismissible "Scroll for
133
+ * more" cue when content overflows the frame (easy to miss in fullscreen when
134
+ * OS overlay scrollbars are hidden).
135
+ */
136
+ export const SlideScrollContainer = ({
137
+ children,
138
+ className,
139
+ }: {
140
+ children: ReactNode;
141
+ className?: string;
142
+ }) => {
143
+ const scrollRef = useRef<HTMLDivElement>(null);
144
+ const contentRef = useRef<HTMLDivElement>(null);
145
+ const showHint = useScrollHint(scrollRef, contentRef);
146
+
147
+ return (
148
+ <div className={cn("relative h-full w-full", className)}>
149
+ <div
150
+ ref={scrollRef}
151
+ className="h-full w-full overflow-auto"
152
+ data-testid="slide-scroll-container"
153
+ >
154
+ <div ref={contentRef} className="flex w-full min-h-full">
155
+ {children}
156
+ </div>
157
+ </div>
158
+ {showHint && <ScrollHintOverlay />}
159
+ </div>
160
+ );
161
+ };
@@ -195,7 +195,7 @@ export const OnBlurredInput = React.forwardRef<
195
195
  onChange={(event) => setInternalValue(event.target.value)}
196
196
  onBlur={() => setValue(internalValue || "")}
197
197
  onKeyDown={(event) => {
198
- if (event.key !== "Enter") {
198
+ if (event.key !== "Enter" || event.shiftKey) {
199
199
  return;
200
200
  }
201
201
  setValue(internalValue || "");
@@ -1,8 +1,15 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import { defaultKeymap as originalDefaultKeymap } from "@codemirror/commands";
3
+ import {
4
+ copyLineDown,
5
+ copyLineUp,
6
+ defaultKeymap as originalDefaultKeymap,
7
+ } from "@codemirror/commands";
4
8
  import { describe, expect, it } from "vitest";
5
- import { HotkeyProvider } from "@/core/hotkeys/hotkeys";
9
+ import {
10
+ HotkeyProvider,
11
+ OverridingHotkeyProvider,
12
+ } from "@/core/hotkeys/hotkeys";
6
13
  import { visibleForTesting } from "../keymaps";
7
14
 
8
15
  const { defaultKeymap, defaultVimKeymap, overrideKeymap, OVERRIDDEN_COMMANDS } =
@@ -40,4 +47,26 @@ describe("keymaps", () => {
40
47
  expect(keys.some((k) => k.run === command)).toBe(true);
41
48
  }
42
49
  });
50
+
51
+ it.each([
52
+ ["cell.copyLineUp", copyLineUp, "Alt-Shift-ArrowUp"],
53
+ ["cell.copyLineDown", copyLineDown, "Alt-Shift-ArrowDown"],
54
+ ] as const)(
55
+ "%s is bound to the configured hotkey, not CodeMirror's default",
56
+ (action, command, defaultKey) => {
57
+ // Without an override, the binding matches CodeMirror's default key.
58
+ expect(
59
+ overrideKeymap(HotkeyProvider.create()).find((k) => k.run === command)
60
+ ?.key,
61
+ ).toBe(defaultKey);
62
+
63
+ // With an override, the binding follows the user's configured key.
64
+ // This is what `editable: true` on these hotkeys promises.
65
+ expect(
66
+ overrideKeymap(
67
+ new OverridingHotkeyProvider({ [action]: "Ctrl-d" }),
68
+ ).find((k) => k.run === command)?.key,
69
+ ).toBe("Ctrl-d");
70
+ },
71
+ );
43
72
  });
@@ -1,6 +1,8 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import {
4
+ copyLineDown,
5
+ copyLineUp,
4
6
  cursorCharLeft,
5
7
  cursorCharRight,
6
8
  cursorLineDown,
@@ -94,6 +96,8 @@ export function keymapBundle(
94
96
  const OVERRIDDEN_COMMANDS = new Set<Command | undefined>([
95
97
  toggleComment,
96
98
  toggleBlockComment,
99
+ copyLineUp,
100
+ copyLineDown,
97
101
  ]);
98
102
 
99
103
  const defaultKeymap = once(() => {
@@ -111,6 +115,14 @@ const overrideKeymap = (keymap: HotkeyProvider): readonly KeyBinding[] => {
111
115
  key: keymap.getHotkey("cell.toggleBlockComment").key,
112
116
  run: toggleBlockComment,
113
117
  },
118
+ {
119
+ key: keymap.getHotkey("cell.copyLineUp").key,
120
+ run: copyLineUp,
121
+ },
122
+ {
123
+ key: keymap.getHotkey("cell.copyLineDown").key,
124
+ run: copyLineDown,
125
+ },
114
126
  ];
115
127
  };
116
128