@marimo-team/islands 0.21.2-dev69 → 0.21.2-dev70

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/main.js CHANGED
@@ -31074,12 +31074,12 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
31074
31074
  }, r[9] = d, r[10] = h, r[11] = S, r[12] = c, r[13] = w) : w = r[13];
31075
31075
  let E = useEvent_default(w), O;
31076
31076
  r[14] !== d || r[15] !== c ? (O = (e2, r2) => {
31077
- e2.buttons !== 2 && d.handleCellMouseDown({
31077
+ e2.buttons !== 2 && (isInteractiveTarget(e2) || d.handleCellMouseDown({
31078
31078
  cell: r2,
31079
31079
  isShiftKey: e2.shiftKey,
31080
31080
  isCtrlKey: e2.ctrlKey,
31081
31081
  table: c
31082
- });
31082
+ }));
31083
31083
  }, r[14] = d, r[15] = c, r[16] = O) : O = r[16];
31084
31084
  let M = useEvent_default(O), I;
31085
31085
  r[17] === d ? I = r[18] : (I = () => {
@@ -31103,6 +31103,11 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
31103
31103
  clearSelection: d.clearSelection
31104
31104
  }, r[22] = d.clearSelection, r[23] = M, r[24] = q, r[25] = z, r[26] = E, r[27] = h, r[28] = v, r[29] = e9) : e9 = r[29], e9;
31105
31105
  };
31106
+ var INTERACTIVE_SELECTOR = 'input, button, select, textarea, a, label, [role="checkbox"], [role="button"], [contenteditable="true"], marimo-ui-element';
31107
+ function isInteractiveTarget(e) {
31108
+ let r = e.target;
31109
+ return r === e.currentTarget || !(r instanceof Element) ? false : r.closest(INTERACTIVE_SELECTOR) !== null;
31110
+ }
31106
31111
  var import_compiler_runtime$101 = require_compiler_runtime(), focusedCellAtom = atom((e) => e(cellSelectionStateAtom).focusedCell);
31107
31112
  function useScrollIntoViewOnFocus(e) {
31108
31113
  let r = (0, import_compiler_runtime$101.c)(2), c;
@@ -64761,7 +64766,7 @@ ${c}
64761
64766
  return Logger.warn("Failed to get version from mount config"), null;
64762
64767
  }
64763
64768
  }
64764
- const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.21.2-dev69"), showCodeInRunModeAtom = atom(true);
64769
+ const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.21.2-dev70"), showCodeInRunModeAtom = atom(true);
64765
64770
  atom(null);
64766
64771
  var VIRTUAL_FILE_REGEX = /\/@file\/([^\s"&'/]+)\.([\dA-Za-z]+)/g, VirtualFileTracker = class e {
64767
64772
  constructor() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.21.2-dev69",
3
+ "version": "0.21.2-dev70",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -0,0 +1,119 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { describe, expect, it } from "vitest";
4
+ import { isInteractiveTarget } from "../use-cell-range-selection";
5
+
6
+ function createMouseEvent(
7
+ target: HTMLElement,
8
+ currentTarget: HTMLElement,
9
+ ): React.MouseEvent {
10
+ return { target, currentTarget } as unknown as React.MouseEvent;
11
+ }
12
+
13
+ describe("isInteractiveTarget", () => {
14
+ it("returns false when target is the cell itself", () => {
15
+ const cell = document.createElement("td");
16
+ expect(isInteractiveTarget(createMouseEvent(cell, cell))).toBe(false);
17
+ });
18
+
19
+ it("returns false when clicking plain text inside a cell", () => {
20
+ const cell = document.createElement("td");
21
+ const span = document.createElement("span");
22
+ cell.append(span);
23
+ expect(isInteractiveTarget(createMouseEvent(span, cell))).toBe(false);
24
+ });
25
+
26
+ it.each([
27
+ "input",
28
+ "button",
29
+ "select",
30
+ "textarea",
31
+ ])("returns true when clicking a <%s>", (tag) => {
32
+ const cell = document.createElement("td");
33
+ const el = document.createElement(tag);
34
+ cell.append(el);
35
+ expect(isInteractiveTarget(createMouseEvent(el, cell))).toBe(true);
36
+ });
37
+
38
+ it("returns true when clicking an <a> link", () => {
39
+ const cell = document.createElement("td");
40
+ const a = document.createElement("a");
41
+ a.href = "#";
42
+ cell.append(a);
43
+ expect(isInteractiveTarget(createMouseEvent(a, cell))).toBe(true);
44
+ });
45
+
46
+ it("returns true when clicking a <label>", () => {
47
+ const cell = document.createElement("td");
48
+ const label = document.createElement("label");
49
+ cell.append(label);
50
+ expect(isInteractiveTarget(createMouseEvent(label, cell))).toBe(true);
51
+ });
52
+
53
+ it('returns true for element with role="checkbox"', () => {
54
+ const cell = document.createElement("td");
55
+ const div = document.createElement("div");
56
+ div.setAttribute("role", "checkbox");
57
+ cell.append(div);
58
+ expect(isInteractiveTarget(createMouseEvent(div, cell))).toBe(true);
59
+ });
60
+
61
+ it('returns true for element with role="button"', () => {
62
+ const cell = document.createElement("td");
63
+ const div = document.createElement("div");
64
+ div.setAttribute("role", "button");
65
+ cell.append(div);
66
+ expect(isInteractiveTarget(createMouseEvent(div, cell))).toBe(true);
67
+ });
68
+
69
+ it('returns true for contenteditable="true"', () => {
70
+ const cell = document.createElement("td");
71
+ const div = document.createElement("div");
72
+ div.setAttribute("contenteditable", "true");
73
+ cell.append(div);
74
+ expect(isInteractiveTarget(createMouseEvent(div, cell))).toBe(true);
75
+ });
76
+
77
+ it("returns true when clicking a child nested inside an interactive element", () => {
78
+ const cell = document.createElement("td");
79
+ const button = document.createElement("button");
80
+ const icon = document.createElement("span");
81
+ button.append(icon);
82
+ cell.append(button);
83
+ expect(isInteractiveTarget(createMouseEvent(icon, cell))).toBe(true);
84
+ });
85
+
86
+ it("returns true when clicking inside a marimo-ui-element", () => {
87
+ const cell = document.createElement("td");
88
+ const marimoEl = document.createElement("marimo-ui-element");
89
+ const inner = document.createElement("div");
90
+ marimoEl.append(inner);
91
+ cell.append(marimoEl);
92
+ expect(isInteractiveTarget(createMouseEvent(inner, cell))).toBe(true);
93
+ });
94
+
95
+ it("returns true when clicking the marimo-ui-element itself", () => {
96
+ const cell = document.createElement("td");
97
+ const marimoEl = document.createElement("marimo-ui-element");
98
+ cell.append(marimoEl);
99
+ expect(isInteractiveTarget(createMouseEvent(marimoEl, cell))).toBe(true);
100
+ });
101
+
102
+ it("returns false when clicking a non-interactive div", () => {
103
+ const cell = document.createElement("td");
104
+ const wrapper = document.createElement("div");
105
+ const text = document.createElement("span");
106
+ wrapper.append(text);
107
+ cell.append(wrapper);
108
+ expect(isInteractiveTarget(createMouseEvent(text, cell))).toBe(false);
109
+ });
110
+
111
+ it("returns false when target is a non-Element (e.g. Text node)", () => {
112
+ const cell = document.createElement("td");
113
+ const textNode = document.createTextNode("hello");
114
+ cell.append(textNode);
115
+ expect(isInteractiveTarget(createMouseEvent(textNode as never, cell))).toBe(
116
+ false,
117
+ );
118
+ });
119
+ });
@@ -91,6 +91,10 @@ export const useCellRangeSelection = <TData>({
91
91
  return;
92
92
  }
93
93
 
94
+ if (isInteractiveTarget(e)) {
95
+ return;
96
+ }
97
+
94
98
  actions.handleCellMouseDown({
95
99
  cell,
96
100
  isShiftKey: e.shiftKey,
@@ -122,3 +126,18 @@ export const useCellRangeSelection = <TData>({
122
126
  clearSelection: actions.clearSelection,
123
127
  };
124
128
  };
129
+
130
+ const INTERACTIVE_SELECTOR =
131
+ 'input, button, select, textarea, a, label, [role="checkbox"], [role="button"], [contenteditable="true"], marimo-ui-element';
132
+
133
+ /**
134
+ * Skip cell selection when the click target is inside an interactive element
135
+ * (e.g. a checkbox or button rendered as rich cell content).
136
+ */
137
+ export function isInteractiveTarget(e: React.MouseEvent): boolean {
138
+ const target = e.target;
139
+ if (target === e.currentTarget || !(target instanceof Element)) {
140
+ return false;
141
+ }
142
+ return target.closest(INTERACTIVE_SELECTOR) !== null;
143
+ }