@marimo-team/islands 0.22.6-dev9 → 0.23.1-dev13

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
@@ -57315,8 +57315,14 @@ ${c}
57315
57315
  }
57316
57316
  function hasPureLineTrace(e) {
57317
57317
  return e ? e.some((e2) => {
57318
- let r = e2.type;
57319
- return r === void 0 || LINE_CLICK_TRACE_TYPES.has(String(r)) ? isPureLineMode(e2.mode) : false;
57318
+ let r = e2;
57319
+ return r.type === void 0 || LINE_CLICK_TRACE_TYPES.has(String(r.type)) ? isPureLineMode(r.mode) : false;
57320
+ }) : false;
57321
+ }
57322
+ function hasAreaTrace(e) {
57323
+ return e ? e.some((e2) => {
57324
+ let r = e2;
57325
+ return r.type !== void 0 && !LINE_CLICK_TRACE_TYPES.has(String(r.type)) ? false : typeof r.fill == "string" && r.fill !== "" && r.fill !== "none" || r.stackgroup != null;
57320
57326
  }) : false;
57321
57327
  }
57322
57328
  function createDragmodeButton(e, r, c, d, f) {
@@ -57349,7 +57355,7 @@ ${c}
57349
57355
  function shouldHandleClickSelection(e) {
57350
57356
  return e.some((e2) => {
57351
57357
  let r = getTraceSource(e2).type;
57352
- return r === "bar" || r === "heatmap" || r === "histogram" || r === "waterfall" || isLinePoint(e2);
57358
+ return r === "bar" || r === "heatmap" || r === "histogram" || r === "waterfall" || r === "violin" || isLinePoint(e2);
57353
57359
  });
57354
57360
  }
57355
57361
  function extractIndices(e) {
@@ -57523,7 +57529,7 @@ ${c}
57523
57529
  }));
57524
57530
  }, r[7] = w, r[8] = f, r[9] = I) : I = r[9];
57525
57531
  let z = useEvent_default(I), G = useDeepCompareMemoize(h), q;
57526
- r[10] === y.data ? q = r[11] : (q = hasPureLineTrace(y.data), r[10] = y.data, r[11] = q);
57532
+ r[10] === y.data ? q = r[11] : (q = hasPureLineTrace(y.data) || hasAreaTrace(y.data), r[10] = y.data, r[11] = q);
57527
57533
  let Z7 = q, Q7, $7, e9;
57528
57534
  if (r[12] !== G || r[13] !== M || r[14] !== z || r[15] !== Z7) {
57529
57535
  let e2 = [
@@ -65645,7 +65651,7 @@ ${c}
65645
65651
  return Logger.warn("Failed to get version from mount config"), null;
65646
65652
  }
65647
65653
  }
65648
- const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.22.6-dev9"), showCodeInRunModeAtom = atom(true);
65654
+ const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.1-dev13"), showCodeInRunModeAtom = atom(true);
65649
65655
  atom(null);
65650
65656
  var VIRTUAL_FILE_REGEX = /\/@file\/([^\s"&'/]+)\.([\dA-Za-z]+)/g, VirtualFileTracker = class e {
65651
65657
  constructor() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.22.6-dev9",
3
+ "version": "0.23.1-dev13",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -19,6 +19,7 @@ import {
19
19
  extractPoints,
20
20
  extractSunburstPoints,
21
21
  extractTreemapPoints,
22
+ hasAreaTrace,
22
23
  hasPureLineTrace,
23
24
  lineSelectionButtons,
24
25
  type ModeBarButton,
@@ -113,7 +114,8 @@ export const PlotlyComponent = memo(
113
114
 
114
115
  const configMemo = useDeepCompareMemoize(config);
115
116
  const plotlyConfig = useMemo((): Partial<Plotly.Config> => {
116
- const hasPureLine = hasPureLineTrace(figure.data);
117
+ const hasLineOrAreaTrace =
118
+ hasPureLineTrace(figure.data) || hasAreaTrace(figure.data);
117
119
  const defaultButtons: ModeBarButton[] = [
118
120
  // Custom button to reset the state
119
121
  {
@@ -130,7 +132,7 @@ export const PlotlyComponent = memo(
130
132
  click: handleResetWithClear,
131
133
  },
132
134
  ];
133
- if (hasPureLine) {
135
+ if (hasLineOrAreaTrace) {
134
136
  defaultButtons.push(...lineSelectionButtons(handleSetDragmode));
135
137
  }
136
138
 
@@ -111,4 +111,54 @@ describe("PlotlyPlugin", () => {
111
111
  range: undefined,
112
112
  });
113
113
  });
114
+
115
+ it("clicking a violin element triggers onClick", async () => {
116
+ const setValue = vi.fn<Setter<unknown>>();
117
+
118
+ render(
119
+ <Suspense fallback={null}>
120
+ <PlotlyComponent
121
+ figure={{
122
+ data: [{ type: "violin" }],
123
+ layout: {},
124
+ frames: null,
125
+ }}
126
+ value={undefined}
127
+ setValue={setValue}
128
+ host={document.createElement("div")}
129
+ config={{}}
130
+ />
131
+ </Suspense>,
132
+ );
133
+
134
+ await waitFor(() => {
135
+ expect(capturedPlotProps).not.toBeNull();
136
+ });
137
+
138
+ act(() => {
139
+ capturedPlotProps?.onClick?.({
140
+ points: [
141
+ {
142
+ data: { type: "violin" },
143
+ x: "Group A",
144
+ y: 3,
145
+ pointIndex: 0,
146
+ pointNumber: 0,
147
+ curveNumber: 0,
148
+ },
149
+ ],
150
+ });
151
+ });
152
+
153
+ expect(setValue).toHaveBeenCalledTimes(1);
154
+ const updater = setValue.mock.calls[0][0] as (value: unknown) => unknown;
155
+ expect(updater({})).toEqual({
156
+ selections: [],
157
+ points: [
158
+ { x: "Group A", y: 3, curveNumber: 0, pointNumber: 0, pointIndex: 0 },
159
+ ],
160
+ indices: [0],
161
+ range: undefined,
162
+ });
163
+ });
114
164
  });
@@ -5,6 +5,7 @@ import { describe, expect, it, vi } from "vitest";
5
5
  import {
6
6
  extractIndices,
7
7
  extractPoints,
8
+ hasAreaTrace,
8
9
  hasPureLineTrace,
9
10
  lineSelectionButtons,
10
11
  type ModeBarButton,
@@ -101,6 +102,14 @@ describe("shouldHandleClickSelection", () => {
101
102
  expect(shouldHandleClickSelection([heatmapPoint])).toBe(true);
102
103
  });
103
104
 
105
+ it("accepts violin clicks", () => {
106
+ const violinPoint = createPlotDatum({
107
+ data: { type: "violin" },
108
+ });
109
+
110
+ expect(shouldHandleClickSelection([violinPoint])).toBe(true);
111
+ });
112
+
104
113
  it("accepts histogram clicks", () => {
105
114
  const histogramPoint = createPlotDatum({
106
115
  data: { type: "histogram" },
@@ -219,3 +228,67 @@ describe("extractPoints", () => {
219
228
  ]);
220
229
  });
221
230
  });
231
+
232
+ describe("hasAreaTrace", () => {
233
+ it("detects scatter trace with tozeroy fill", () => {
234
+ expect(
235
+ hasAreaTrace([createTrace({ type: "scatter", fill: "tozeroy" })]),
236
+ ).toBe(true);
237
+ });
238
+
239
+ it("detects scatter trace with tonexty fill", () => {
240
+ expect(
241
+ hasAreaTrace([createTrace({ type: "scatter", fill: "tonexty" })]),
242
+ ).toBe(true);
243
+ });
244
+
245
+ it("detects scatter trace with stackgroup (px.area pattern)", () => {
246
+ expect(
247
+ hasAreaTrace([
248
+ createTrace({ type: "scatter", mode: "lines", stackgroup: "one" }),
249
+ ]),
250
+ ).toBe(true);
251
+ });
252
+
253
+ it("detects area traces with mode=none (fill-only, no visible line)", () => {
254
+ expect(
255
+ hasAreaTrace([
256
+ createTrace({ type: "scatter", fill: "tozeroy", mode: "none" }),
257
+ ]),
258
+ ).toBe(true);
259
+ });
260
+
261
+ it("ignores scatter traces with no fill and no stackgroup", () => {
262
+ expect(
263
+ hasAreaTrace([
264
+ createTrace({ type: "scatter", mode: "lines" }),
265
+ createTrace({ type: "scatter", mode: "markers" }),
266
+ ]),
267
+ ).toBe(false);
268
+ });
269
+
270
+ it("ignores scatter traces with fill=none", () => {
271
+ expect(hasAreaTrace([createTrace({ type: "scatter", fill: "none" })])).toBe(
272
+ false,
273
+ );
274
+ });
275
+
276
+ it("ignores scatter traces with fill=empty string", () => {
277
+ expect(
278
+ hasAreaTrace([createTrace({ type: "scatter", fill: "" as "none" })]),
279
+ ).toBe(false);
280
+ });
281
+
282
+ it("ignores non-scatter traces", () => {
283
+ expect(
284
+ hasAreaTrace([
285
+ createTrace({ type: "bar" }),
286
+ createTrace({ type: "heatmap" }),
287
+ ]),
288
+ ).toBe(false);
289
+ });
290
+
291
+ it("returns false for undefined data", () => {
292
+ expect(hasAreaTrace(undefined)).toBe(false);
293
+ });
294
+ });
@@ -141,13 +141,44 @@ export function hasPureLineTrace(
141
141
  }
142
142
 
143
143
  return data.some((trace) => {
144
- const traceType = (trace as { type?: unknown }).type;
144
+ const t = trace as Record<string, unknown>;
145
145
  const isScatterLike =
146
- traceType === undefined || LINE_CLICK_TRACE_TYPES.has(String(traceType));
146
+ t.type === undefined || LINE_CLICK_TRACE_TYPES.has(String(t.type));
147
147
  if (!isScatterLike) {
148
148
  return false;
149
149
  }
150
- return isPureLineMode((trace as { mode?: unknown }).mode);
150
+ return isPureLineMode(t.mode);
151
+ });
152
+ }
153
+
154
+ /**
155
+ * Return true when any scatter/scattergl trace has a non-empty fill or a
156
+ * stackgroup, i.e. it is an area chart.
157
+ *
158
+ * Area traces built with `mode="none"` have no visible line or markers, so
159
+ * `hasPureLineTrace` returns false for them even though they need select/lasso
160
+ * buttons just as much as `mode="lines"` area charts. This function covers
161
+ * that gap and is OR-ed with `hasPureLineTrace` in the config builder.
162
+ */
163
+ export function hasAreaTrace(
164
+ data: readonly Plotly.Data[] | undefined,
165
+ ): boolean {
166
+ if (!data) {
167
+ return false;
168
+ }
169
+
170
+ return data.some((trace) => {
171
+ const t = trace as Record<string, unknown>;
172
+ // Only scatter/scattergl can be area traces.
173
+ if (t.type !== undefined && !LINE_CLICK_TRACE_TYPES.has(String(t.type))) {
174
+ return false;
175
+ }
176
+ // A trace is an area trace when fill is a non-empty string other than
177
+ // "none", OR it belongs to a stackgroup (px.area always sets stackgroup).
178
+ return (
179
+ (typeof t.fill === "string" && t.fill !== "" && t.fill !== "none") ||
180
+ t.stackgroup != null
181
+ );
151
182
  });
152
183
  }
153
184
 
@@ -228,6 +259,7 @@ export function shouldHandleClickSelection(
228
259
  type === "heatmap" ||
229
260
  type === "histogram" ||
230
261
  type === "waterfall" ||
262
+ type === "violin" ||
231
263
  isLinePoint(point)
232
264
  );
233
265
  });