@marimo-team/islands 0.22.1-dev23 → 0.22.1-dev27

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 (68) hide show
  1. package/dist/main.js +3 -3
  2. package/package.json +6 -17
  3. package/src/__tests__/main.test.tsx +12 -14
  4. package/src/components/ai/ai-provider-icon.tsx +1 -2
  5. package/src/components/data-table/cell-selection/types.ts +3 -2
  6. package/src/components/data-table/charts/charts.tsx +2 -2
  7. package/src/components/data-table/column-formatting/types.ts +3 -2
  8. package/src/components/data-table/column-header.tsx +4 -2
  9. package/src/components/data-table/column-wrapping/types.ts +3 -2
  10. package/src/components/data-table/copy-column/types.ts +3 -2
  11. package/src/components/data-table/focus-row/types.ts +3 -2
  12. package/src/components/data-table/range-focus/__tests__/atoms.test.ts +11 -11
  13. package/src/components/data-table/range-focus/__tests__/use-cell-range-selection.test.ts +9 -11
  14. package/src/components/editor/__tests__/data-attributes.test.tsx +93 -94
  15. package/src/components/editor/actions/name-cell-input.tsx +4 -2
  16. package/src/components/editor/actions/useCellActionButton.tsx +4 -2
  17. package/src/components/editor/cell/CellStatus.tsx +4 -5
  18. package/src/components/editor/cell/cell-context-menu.tsx +4 -2
  19. package/src/components/editor/cell/code/cell-editor.tsx +2 -1
  20. package/src/components/editor/cell/toolbar.tsx +2 -1
  21. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +11 -12
  22. package/src/components/storage/__tests__/storage-snippets.test.ts +4 -6
  23. package/src/components/tracing/tracing.test.tsx +30 -30
  24. package/src/components/ui/badge.tsx +2 -1
  25. package/src/components/ui/button.tsx +2 -1
  26. package/src/components/ui/calendar.tsx +3 -2
  27. package/src/components/ui/combobox.tsx +2 -1
  28. package/src/components/ui/date-input.tsx +7 -6
  29. package/src/components/ui/date-picker.tsx +6 -4
  30. package/src/components/ui/field.tsx +1 -2
  31. package/src/components/ui/progress.tsx +3 -2
  32. package/src/components/ui/query-param-preserving-link.tsx +4 -2
  33. package/src/components/ui/sheet.tsx +2 -1
  34. package/src/components/ui/textarea.tsx +1 -2
  35. package/src/core/ai/context/providers/cell-output.ts +1 -2
  36. package/src/core/ai/tools/edit-notebook-tool.ts +4 -3
  37. package/src/core/ai/tools/run-cells-tool.ts +4 -3
  38. package/src/core/cells/__tests__/add-missing-import.test.ts +23 -22
  39. package/src/core/cells/__tests__/cell.test.ts +14 -13
  40. package/src/core/cells/logs.ts +1 -1
  41. package/src/core/codemirror/cells/__tests__/extensions.test.ts +15 -17
  42. package/src/core/codemirror/copilot/transport.ts +1 -2
  43. package/src/core/codemirror/language/languages/markdown.ts +1 -3
  44. package/src/core/codemirror/language/languages/python.ts +4 -0
  45. package/src/core/codemirror/language/languages/sql/completion-sources.tsx +4 -6
  46. package/src/core/codemirror/language/languages/sql/sql.ts +1 -3
  47. package/src/core/codemirror/reactive-references/__tests__/analyzer.test.ts +28 -42
  48. package/src/core/datasets/data-source-connections.ts +4 -2
  49. package/src/core/dom/__tests__/htmlUtils.test.ts +8 -14
  50. package/src/core/dom/__tests__/outline.test.ts +2 -3
  51. package/src/core/islands/__tests__/parse.test.ts +8 -7
  52. package/src/core/saving/__tests__/filename.test.ts +7 -6
  53. package/src/core/static/__tests__/download-html.test.ts +16 -15
  54. package/src/core/static/__tests__/files.test.ts +30 -28
  55. package/src/css/app/Cell.css +5 -2
  56. package/src/css/globals.css +40 -14
  57. package/src/plugins/impl/DataEditorPlugin.tsx +4 -2
  58. package/src/plugins/impl/FormPlugin.tsx +1 -2
  59. package/src/plugins/impl/data-frames/forms/__tests__/form.test.tsx +7 -9
  60. package/src/plugins/impl/vega/__tests__/make-selectable.test.ts +13 -14
  61. package/src/plugins/layout/ImageComparisonPlugin.tsx +1 -3
  62. package/src/plugins/stateless-plugin.ts +4 -2
  63. package/src/utils/__tests__/cell-urls.test.ts +24 -21
  64. package/src/utils/__tests__/filenames.test.ts +15 -14
  65. package/src/utils/__tests__/json-parser.test.ts +14 -21
  66. package/src/utils/__tests__/path.test.ts +34 -31
  67. package/src/utils/__tests__/urls.test.ts +19 -18
  68. package/src/utils/tracer.ts +1 -0
@@ -92,27 +92,30 @@ describe("cell-urls utilities", () => {
92
92
  });
93
93
 
94
94
  describe("edge case cell names with unicode and special characters", () => {
95
- it.each(
96
- EDGE_CASE_CELL_NAMES,
97
- )("should handle unicode cell names in createCellLink: %s", (cellName) => {
98
- const url = createCellLink(cellName);
99
- expect(url).toContain("scrollTo=");
100
- expect(url).toContain(encodeURIComponent(cellName));
101
- });
102
-
103
- it.each(
104
- EDGE_CASE_CELL_NAMES,
105
- )("should round-trip unicode cell names correctly: %s", (cellName) => {
106
- const url = createCellLink(cellName);
107
- const hash = url.split("#")[1];
108
- const extracted = extractCellNameFromHash(`#${hash}`);
109
- expect(extracted).toBe(cellName);
110
- });
95
+ it.each(EDGE_CASE_CELL_NAMES)(
96
+ "should handle unicode cell names in createCellLink: %s",
97
+ (cellName) => {
98
+ const url = createCellLink(cellName);
99
+ expect(url).toContain("scrollTo=");
100
+ expect(url).toContain(encodeURIComponent(cellName));
101
+ },
102
+ );
103
+
104
+ it.each(EDGE_CASE_CELL_NAMES)(
105
+ "should round-trip unicode cell names correctly: %s",
106
+ (cellName) => {
107
+ const url = createCellLink(cellName);
108
+ const hash = url.split("#")[1];
109
+ const extracted = extractCellNameFromHash(`#${hash}`);
110
+ expect(extracted).toBe(cellName);
111
+ },
112
+ );
111
113
 
112
- it.each(
113
- EDGE_CASE_CELL_NAMES,
114
- )("should allow linking to unicode cell names: %s", (cellName) => {
115
- expect(canLinkToCell(cellName)).toBe(true);
116
- });
114
+ it.each(EDGE_CASE_CELL_NAMES)(
115
+ "should allow linking to unicode cell names: %s",
116
+ (cellName) => {
117
+ expect(canLinkToCell(cellName)).toBe(true);
118
+ },
119
+ );
117
120
  });
118
121
  });
@@ -35,22 +35,23 @@ describe("Filenames", () => {
35
35
  expect(Filenames.withoutExtension("test.foo.txt")).toEqual("test.foo");
36
36
  });
37
37
 
38
- it.each(
39
- EDGE_CASE_FILENAMES,
40
- )("should handle edge case filenames: %s", (filename) => {
41
- // Test all filename operations with edge cases
42
- const withoutExt = Filenames.withoutExtension(filename);
38
+ it.each(EDGE_CASE_FILENAMES)(
39
+ "should handle edge case filenames: %s",
40
+ (filename) => {
41
+ // Test all filename operations with edge cases
42
+ const withoutExt = Filenames.withoutExtension(filename);
43
43
 
44
- expect(Filenames.toMarkdown(filename)).toEqual(`${withoutExt}.md`);
45
- expect(Filenames.toHTML(filename)).toEqual(`${withoutExt}.html`);
46
- expect(Filenames.toPNG(filename)).toEqual(`${withoutExt}.png`);
47
- expect(Filenames.toPY(filename)).toEqual(`${withoutExt}.py`);
48
- expect(Filenames.toIPYNB(filename)).toEqual(`${withoutExt}.ipynb`);
44
+ expect(Filenames.toMarkdown(filename)).toEqual(`${withoutExt}.md`);
45
+ expect(Filenames.toHTML(filename)).toEqual(`${withoutExt}.html`);
46
+ expect(Filenames.toPNG(filename)).toEqual(`${withoutExt}.png`);
47
+ expect(Filenames.toPY(filename)).toEqual(`${withoutExt}.py`);
48
+ expect(Filenames.toIPYNB(filename)).toEqual(`${withoutExt}.ipynb`);
49
49
 
50
- // Ensure operations preserve unicode and special characters in base name
51
- expect(withoutExt).not.toEqual("");
52
- expect(typeof withoutExt).toBe("string");
53
- });
50
+ // Ensure operations preserve unicode and special characters in base name
51
+ expect(withoutExt).not.toEqual("");
52
+ expect(typeof withoutExt).toBe("string");
53
+ },
54
+ );
54
55
  });
55
56
 
56
57
  describe("getImageExtension", () => {
@@ -184,9 +184,8 @@ it("can convert json to markdown - with URLs", () => {
184
184
  `);
185
185
 
186
186
  // Mixed content - URL and text in same cell
187
- expect(
188
- jsonToMarkdown([{ info: "Visit https://example.com for more" }]),
189
- ).toMatchInlineSnapshot(`
187
+ expect(jsonToMarkdown([{ info: "Visit https://example.com for more" }]))
188
+ .toMatchInlineSnapshot(`
190
189
  "| info |
191
190
  |---|
192
191
  | Visit [https://example.com](https://example.com) for more |"
@@ -203,9 +202,8 @@ it("can convert json to markdown - with URLs", () => {
203
202
  });
204
203
 
205
204
  it("can convert json to markdown - handles nulls and undefined", () => {
206
- expect(
207
- jsonToMarkdown([{ a: null, b: undefined, c: 1 }]),
208
- ).toMatchInlineSnapshot(`
205
+ expect(jsonToMarkdown([{ a: null, b: undefined, c: 1 }]))
206
+ .toMatchInlineSnapshot(`
209
207
  "| a | b | c |
210
208
  |---|---|---|
211
209
  | | | 1 |"
@@ -226,18 +224,16 @@ it("can convert json to markdown - handles nulls and undefined", () => {
226
224
 
227
225
  it("can convert json to markdown - handles special characters", () => {
228
226
  // Pipes need to be escaped since they're markdown table delimiters
229
- expect(
230
- jsonToMarkdown([{ a: "value|with|pipes", b: "normal" }]),
231
- ).toMatchInlineSnapshot(`
227
+ expect(jsonToMarkdown([{ a: "value|with|pipes", b: "normal" }]))
228
+ .toMatchInlineSnapshot(`
232
229
  "| a | b |
233
230
  |---|---|
234
231
  | value\\|with\\|pipes | normal |"
235
232
  `);
236
233
 
237
234
  // Newlines should be replaced with spaces
238
- expect(
239
- jsonToMarkdown([{ a: "line1\nline2", b: "normal" }]),
240
- ).toMatchInlineSnapshot(`
235
+ expect(jsonToMarkdown([{ a: "line1\nline2", b: "normal" }]))
236
+ .toMatchInlineSnapshot(`
241
237
  "| a | b |
242
238
  |---|---|
243
239
  | line1 line2 | normal |"
@@ -252,9 +248,8 @@ it("can convert json to markdown - handles special characters", () => {
252
248
  });
253
249
 
254
250
  it("can convert json to markdown - handles different data types", () => {
255
- expect(
256
- jsonToMarkdown([{ str: "text", num: 42, bool: true, nil: null }]),
257
- ).toMatchInlineSnapshot(`
251
+ expect(jsonToMarkdown([{ str: "text", num: 42, bool: true, nil: null }]))
252
+ .toMatchInlineSnapshot(`
258
253
  "| str | num | bool | nil |
259
254
  |---|---|---|---|
260
255
  | text | 42 | true | |"
@@ -282,9 +277,8 @@ it("can convert json to markdown - handles different data types", () => {
282
277
  | [1,2,3] |"
283
278
  `);
284
279
 
285
- expect(
286
- jsonToMarkdown([{ data: { nested: "value" } }]),
287
- ).toMatchInlineSnapshot(`
280
+ expect(jsonToMarkdown([{ data: { nested: "value" } }]))
281
+ .toMatchInlineSnapshot(`
288
282
  "| data |
289
283
  |---|
290
284
  | {"nested":"value"} |"
@@ -293,9 +287,8 @@ it("can convert json to markdown - handles different data types", () => {
293
287
 
294
288
  it("can convert json to markdown - handles existing markdown links", () => {
295
289
  // When input already contains a markdown link, it should be preserved as-is
296
- expect(
297
- jsonToMarkdown([{ link: "[Google](https://google.com)" }]),
298
- ).toMatchInlineSnapshot(`
290
+ expect(jsonToMarkdown([{ link: "[Google](https://google.com)" }]))
291
+ .toMatchInlineSnapshot(`
299
292
  "| link |
300
293
  |---|
301
294
  | [Google](https://google.com) |"
@@ -170,36 +170,39 @@ describe("PathBuilder", () => {
170
170
  });
171
171
 
172
172
  describe("edge case filenames", () => {
173
- it.each(
174
- EDGE_CASE_FILENAMES,
175
- )("should handle unicode and spaces in basename: %s", (filename) => {
176
- const basename = Paths.basename(filename);
177
- expect(basename).toBe(filename);
178
- expect(typeof basename).toBe("string");
179
- expect(basename).not.toBe("");
180
- });
181
-
182
- it.each(
183
- EDGE_CASE_FILENAMES,
184
- )("should handle unicode and spaces in dirname: %s", (filename) => {
185
- const fullPath = `/path/to/${filename}`;
186
- const dirname = Paths.dirname(fullPath);
187
- expect(dirname).toBe("/path/to");
188
- });
189
-
190
- it.each(
191
- EDGE_CASE_FILENAMES,
192
- )("should handle unicode and spaces in path operations: %s", (filename) => {
193
- const baseName = Paths.basename(filename);
194
- const extension = Paths.extension(filename);
195
-
196
- // Should preserve unicode characters in basename
197
- expect(baseName).toContain(filename.split(".")[0]);
198
-
199
- // Should correctly extract extension
200
- if (filename.includes(".")) {
201
- expect(extension).toBe(filename.split(".").pop());
202
- }
203
- });
173
+ it.each(EDGE_CASE_FILENAMES)(
174
+ "should handle unicode and spaces in basename: %s",
175
+ (filename) => {
176
+ const basename = Paths.basename(filename);
177
+ expect(basename).toBe(filename);
178
+ expect(typeof basename).toBe("string");
179
+ expect(basename).not.toBe("");
180
+ },
181
+ );
182
+
183
+ it.each(EDGE_CASE_FILENAMES)(
184
+ "should handle unicode and spaces in dirname: %s",
185
+ (filename) => {
186
+ const fullPath = `/path/to/${filename}`;
187
+ const dirname = Paths.dirname(fullPath);
188
+ expect(dirname).toBe("/path/to");
189
+ },
190
+ );
191
+
192
+ it.each(EDGE_CASE_FILENAMES)(
193
+ "should handle unicode and spaces in path operations: %s",
194
+ (filename) => {
195
+ const baseName = Paths.basename(filename);
196
+ const extension = Paths.extension(filename);
197
+
198
+ // Should preserve unicode characters in basename
199
+ expect(baseName).toContain(filename.split(".")[0]);
200
+
201
+ // Should correctly extract extension
202
+ if (filename.includes(".")) {
203
+ expect(extension).toBe(filename.split(".").pop());
204
+ }
205
+ },
206
+ );
204
207
  });
205
208
  });
@@ -14,24 +14,25 @@ describe("isUrl", () => {
14
14
  });
15
15
 
16
16
  describe("URL parameter handling with edge case filenames", () => {
17
- it.each(
18
- EDGE_CASE_FILENAMES,
19
- )("should handle unicode filenames in URL parameters: %s", (filename) => {
20
- // Test that updateQueryParams can handle unicode filenames
21
- updateQueryParams((params) => {
22
- params.set("file", filename);
23
- });
24
-
25
- // Verify URL encoding/decoding works with unicode
26
- const encoded = encodeURIComponent(filename);
27
- const decoded = decodeURIComponent(encoded);
28
- expect(decoded).toBe(filename);
29
-
30
- // Verify filename can be safely added to URL parameters
31
- const url = new URL("https://example.com");
32
- url.searchParams.set("file", filename);
33
- expect(url.searchParams.get("file")).toBe(filename);
34
- });
17
+ it.each(EDGE_CASE_FILENAMES)(
18
+ "should handle unicode filenames in URL parameters: %s",
19
+ (filename) => {
20
+ // Test that updateQueryParams can handle unicode filenames
21
+ updateQueryParams((params) => {
22
+ params.set("file", filename);
23
+ });
24
+
25
+ // Verify URL encoding/decoding works with unicode
26
+ const encoded = encodeURIComponent(filename);
27
+ const decoded = decodeURIComponent(encoded);
28
+ expect(decoded).toBe(filename);
29
+
30
+ // Verify filename can be safely added to URL parameters
31
+ const url = new URL("https://example.com");
32
+ url.searchParams.set("file", filename);
33
+ expect(url.searchParams.get("file")).toBe(filename);
34
+ },
35
+ );
35
36
 
36
37
  it("should preserve unicode in query string round-trip", () => {
37
38
  EDGE_CASE_FILENAMES.forEach((filename) => {
@@ -82,6 +82,7 @@ export class Tracer {
82
82
  }
83
83
 
84
84
  this.spans.forEach((span) => {
85
+ // oxlint-disable-next-line no-console -- intentional tracing output
85
86
  console.log(`Span: ${span.name}`);
86
87
  const childSpans = this.spans.filter(
87
88
  (s) =>