@marimo-team/islands 0.23.14-dev16 → 0.23.14-dev17

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.
@@ -9,7 +9,7 @@ import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
9
9
  import { lt as kioskModeAtom } from "./html-to-image-DcTkcjmm.js";
10
10
  import "./chunk-5FQGJX7Z-BbqSm5gU.js";
11
11
  import { u as createLucideIcon } from "./dist--2Bqjvs0.js";
12
- import { a as DEFAULT_SLIDE_TYPE, an as EyeOff, c as Slide, ct as PanelResizeHandle, i as DEFAULT_DECK_TRANSITION, ln as Code, on as Expand, ot as Panel, s as SlideSidebar, st as PanelGroup, t as useNotebookCodeAvailable } from "./code-visibility-Dc1Ap0mZ.js";
12
+ import { a as DEFAULT_SLIDE_TYPE, c as Slide, ct as PanelGroup, i as DEFAULT_DECK_TRANSITION, lt as PanelResizeHandle, on as EyeOff, s as SlideSidebar, sn as Expand, st as Panel, t as useNotebookCodeAvailable, un as Code } from "./code-visibility-Cb6UrZYv.js";
13
13
  import { X as useDebouncedCallback } from "./input-BSdZp5Ng.js";
14
14
  import "./toDate-D1Z7ZXWh.js";
15
15
  import "./react-dom-BTJzcVJ9.js";
@@ -7245,12 +7245,12 @@ function _temp(e5) {
7245
7245
  };
7246
7246
  }
7247
7247
  var SubslideView = (e5) => {
7248
- let t = (0, import_compiler_runtime.c)(24), { subslide: n, resolveShowCode: r, isEditable: i, slideConfigs: a } = e5, o, s, c, l, u, f;
7248
+ let t = (0, import_compiler_runtime.c)(24), { subslide: n, resolveShowCode: r, isEditable: i, slideConfigs: a } = e5, o, s, c, l, u, ro;
7249
7249
  if (t[0] !== i || t[1] !== r || t[2] !== a || t[3] !== n) {
7250
7250
  let { slideLevel: e6, cumulativeByBlock: io2 } = buildSubslideNotes(n, a);
7251
7251
  s = e6;
7252
7252
  let p2 = n.blocks.some((e7) => e7.cells.some((e8) => r(e8.id)));
7253
- o = w, f = "h-full w-full overflow-auto flex", c = p2 ? "mo-slide-content flex flex-col gap-3" : "mo-slide-content", t[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (l = { margin: "auto 20px" }, t[10] = l) : l = t[10], u = n.blocks.map((e7, t2) => {
7253
+ o = w, ro = "h-full w-full overflow-auto flex", c = p2 ? "mo-slide-content flex flex-col gap-3" : "mo-slide-content", t[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (l = { margin: "auto 20px" }, t[10] = l) : l = t[10], u = n.blocks.map((e7, t2) => {
7254
7254
  let n2 = e7.cells.map((e8) => r(e8.id) ? i ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SlideCellView, { cell: e8 }, e8.id) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SlideCellReadOnlyView, { cell: e8 }, e8.id) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Slide, {
7255
7255
  cellId: e8.id,
7256
7256
  status: e8.status,
@@ -7264,8 +7264,8 @@ var SubslideView = (e5) => {
7264
7264
  }, t2);
7265
7265
  }
7266
7266
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Fragment, { children: n2 }, t2);
7267
- }), t[0] = i, t[1] = r, t[2] = a, t[3] = n, t[4] = o, t[5] = s, t[6] = c, t[7] = l, t[8] = u, t[9] = f;
7268
- } else o = t[4], s = t[5], c = t[6], l = t[7], u = t[8], f = t[9];
7267
+ }), t[0] = i, t[1] = r, t[2] = a, t[3] = n, t[4] = o, t[5] = s, t[6] = c, t[7] = l, t[8] = u, t[9] = ro;
7268
+ } else o = t[4], s = t[5], c = t[6], l = t[7], u = t[8], ro = t[9];
7269
7269
  let io;
7270
7270
  t[11] !== c || t[12] !== l || t[13] !== u ? (io = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7271
7271
  className: c,
@@ -7273,10 +7273,10 @@ var SubslideView = (e5) => {
7273
7273
  children: u
7274
7274
  }), t[11] = c, t[12] = l, t[13] = u, t[14] = io) : io = t[14];
7275
7275
  let p;
7276
- t[15] !== f || t[16] !== io ? (p = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7277
- className: f,
7276
+ t[15] !== ro || t[16] !== io ? (p = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7277
+ className: ro,
7278
7278
  children: io
7279
- }), t[15] = f, t[16] = io, t[17] = p) : p = t[17];
7279
+ }), t[15] = ro, t[16] = io, t[17] = p) : p = t[17];
7280
7280
  let ao;
7281
7281
  t[18] === s ? ao = t[19] : (ao = s && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NotesAside, { text: s }), t[18] = s, t[19] = ao);
7282
7282
  let oo;
@@ -7302,7 +7302,7 @@ var ParkedPreviewContent = (e5) => {
7302
7302
  status: n.status,
7303
7303
  output: n.output
7304
7304
  }), t[3] = n.id, t[4] = n.output, t[5] = n.status, t[6] = o) : o = t[6], o;
7305
- }, reveal_component_default = ({ slideCells: e5, layout: o, setLayout: s, noOutputIds: l, activeIndex: u, onSlideChange: ro, mode: p, configWidth: fo, isEditable: po = false }) => {
7305
+ }, reveal_component_default = ({ slideCells: e5, layout: o, setLayout: s, noOutputIds: l, activeIndex: u, onSlideChange: f, mode: io, configWidth: fo, isEditable: po = false }) => {
7306
7306
  var _a2, _b2;
7307
7307
  let yo = (0, import_react.useRef)(null), bo = (0, import_react.useRef)(null), { width: So, height: Co } = useSlideDimensions(yo), wo = useFullScreenElement() != null, To = useAtomValue(kioskModeAtom), Eo = (0, import_react.useMemo)(() => To ? [] : [ce], [To]), [Do, Oo] = (0, import_react.useState)(() => /* @__PURE__ */ new Set()), ko = useNotebookCodeAvailable(e5), Ao = !isIslands() && ko, jo = u == null ? void 0 : e5[u], Mo = jo ?? e5.at(0), { parkedPreviewCell: No, isHeldEdit: Po, isNoOutputPreview: Fo, heldEditCellId: Io, heldShowsCode: Lo, toggleHeldShowsCode: Ro } = useParkedPreview({
7308
7308
  activeCell: jo,
@@ -7391,14 +7391,14 @@ var ParkedPreviewContent = (e5) => {
7391
7391
  let e6 = bo.current;
7392
7392
  if (!e6) return;
7393
7393
  let t = resolveActiveCellIndex(Go, e6.getIndices());
7394
- t != null && (ro == null ? void 0 : ro(t));
7394
+ t != null && (f == null ? void 0 : f(t));
7395
7395
  }), $o = useEvent_default((t) => {
7396
7396
  if (!No || u == null || Events.fromInput(t)) return;
7397
7397
  let n = classifyNavKey(t);
7398
7398
  if (n === 0) return;
7399
7399
  t.preventDefault(), t.stopPropagation();
7400
7400
  let i = u + n;
7401
- i < 0 || i >= e5.length || (ro == null ? void 0 : ro(i));
7401
+ i < 0 || i >= e5.length || (f == null ? void 0 : f(i));
7402
7402
  }), ns = useEvent_default(() => {
7403
7403
  Qo(), triggerResize(bo.current);
7404
7404
  });
@@ -7494,7 +7494,7 @@ var ParkedPreviewContent = (e5) => {
7494
7494
  ]
7495
7495
  })
7496
7496
  });
7497
- return p === "read" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7497
+ return io === "read" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7498
7498
  className: "flex-1 min-w-0 flex flex-row gap-3",
7499
7499
  children: os
7500
7500
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.14-dev16",
3
+ "version": "0.23.14-dev17",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -126,3 +126,28 @@ describe("ColumnExplorerPanel header counts", () => {
126
126
  expect(screen.queryByText(/hidden/)).not.toBeInTheDocument();
127
127
  });
128
128
  });
129
+
130
+ describe("ColumnExplorerPanel visibility actions", () => {
131
+ const showAll = () => screen.getByRole("button", { name: /Show all/ });
132
+ const hideAll = () => screen.getByRole("button", { name: /Hide all/ });
133
+
134
+ it("disables 'Show all' when every column is visible", () => {
135
+ renderPanel();
136
+ expect(showAll()).toBeDisabled();
137
+ expect(hideAll()).toBeEnabled();
138
+ });
139
+
140
+ it("disables 'Hide all' when every column is hidden", () => {
141
+ renderPanel({
142
+ initiallyHidden: ["customer_name", "cust_age", "order_total"],
143
+ });
144
+ expect(showAll()).toBeEnabled();
145
+ expect(hideAll()).toBeDisabled();
146
+ });
147
+
148
+ it("enables both actions when some columns are hidden", () => {
149
+ renderPanel({ initiallyHidden: ["cust_age"] });
150
+ expect(showAll()).toBeEnabled();
151
+ expect(hideAll()).toBeEnabled();
152
+ });
153
+ });
@@ -21,10 +21,17 @@ beforeAll(() => {
21
21
 
22
22
  type Row = Record<string, unknown>;
23
23
 
24
+ // Select, index, and nameless columns are non-hideable in production
25
+ // (see columns.tsx), so the harness mirrors that to keep visibility counts
26
+ // aligned with the real table.
24
27
  const TEST_COLUMNS: ColumnDef<Row>[] = [
25
- { id: SELECT_COLUMN_ID, accessorKey: SELECT_COLUMN_ID },
26
- { id: INDEX_COLUMN_NAME, accessorKey: INDEX_COLUMN_NAME },
27
- { id: "__m_column__0", accessorKey: "__m_column__0" },
28
+ { id: SELECT_COLUMN_ID, accessorKey: SELECT_COLUMN_ID, enableHiding: false },
29
+ {
30
+ id: INDEX_COLUMN_NAME,
31
+ accessorKey: INDEX_COLUMN_NAME,
32
+ enableHiding: false,
33
+ },
34
+ { id: "__m_column__0", accessorKey: "__m_column__0", enableHiding: false },
28
35
  {
29
36
  id: "customer_name",
30
37
  accessorKey: "customer_name",
@@ -101,6 +108,7 @@ describe("ColumnVisibilityDropdown", () => {
101
108
  renderAndOpen({ initiallyHidden: ["cust_age"] });
102
109
  expect(getOptionTexts()).toEqual([
103
110
  "Show all",
111
+ "Hide all",
104
112
  "cust_age",
105
113
  "customer_name",
106
114
  "order_total",
@@ -117,6 +125,7 @@ describe("ColumnVisibilityDropdown", () => {
117
125
 
118
126
  expect(getOptionTexts()).toEqual([
119
127
  "Show all",
128
+ "Hide all",
120
129
  "cust_age",
121
130
  "customer_name",
122
131
  "order_total",
@@ -132,6 +141,7 @@ describe("ColumnVisibilityDropdown", () => {
132
141
  fireEvent.click(getColumnOption("customer_name"));
133
142
  expect(getOptionTexts()).toEqual([
134
143
  "Show all",
144
+ "Hide all",
135
145
  "cust_age",
136
146
  "customer_name",
137
147
  "order_total",
@@ -144,6 +154,7 @@ describe("ColumnVisibilityDropdown", () => {
144
154
  // Reopen sorts both hidden columns first, preserving table order.
145
155
  expect(getOptionTexts()).toEqual([
146
156
  "Show all",
157
+ "Hide all",
147
158
  "customer_name",
148
159
  "cust_age",
149
160
  "order_total",
@@ -189,6 +200,52 @@ describe("ColumnVisibilityDropdown", () => {
189
200
  );
190
201
  });
191
202
 
203
+ it("'Hide all' hides every hideable column", () => {
204
+ renderAndOpen();
205
+ fireEvent.click(getColumnOption("Hide all"));
206
+
207
+ expect(
208
+ getColumnOption("customer_name").querySelector(".lucide-eye-off"),
209
+ ).not.toBeNull();
210
+ expect(
211
+ getColumnOption("cust_age").querySelector(".lucide-eye-off"),
212
+ ).not.toBeNull();
213
+ expect(
214
+ getColumnOption("order_total").querySelector(".lucide-eye-off"),
215
+ ).not.toBeNull();
216
+ expect(getColumnOption("Hide all")).toHaveAttribute(
217
+ "aria-disabled",
218
+ "true",
219
+ );
220
+ });
221
+
222
+ it("disables 'Hide all' when every column is already hidden", () => {
223
+ renderAndOpen({
224
+ initiallyHidden: ["customer_name", "cust_age", "order_total"],
225
+ });
226
+ expect(getColumnOption("Hide all")).toHaveAttribute(
227
+ "aria-disabled",
228
+ "true",
229
+ );
230
+ });
231
+
232
+ it("'Hide all' leaves non-hideable columns visible", () => {
233
+ renderAndOpen({ nonHideable: ["customer_name"] });
234
+ fireEvent.click(getColumnOption("Hide all"));
235
+
236
+ expect(
237
+ getColumnOption("cust_age").querySelector(".lucide-eye-off"),
238
+ ).not.toBeNull();
239
+ const nonHideable = getColumnOption("customer_name");
240
+ expect(nonHideable).toHaveAttribute("aria-disabled", "true");
241
+ expect(nonHideable.querySelector(".lucide-eye-off")).toBeNull();
242
+ // Every hideable column is now hidden, so the action gates off.
243
+ expect(getColumnOption("Hide all")).toHaveAttribute(
244
+ "aria-disabled",
245
+ "true",
246
+ );
247
+ });
248
+
192
249
  it("hides and shows matching columns via bulk actions while searching", () => {
193
250
  renderAndOpen();
194
251
  fireEvent.change(getSearchInput(), { target: { value: "cust" } });
@@ -50,7 +50,10 @@ import {
50
50
  import { smartMatch } from "@/utils/smartMatch";
51
51
  import type { Column, Table } from "@tanstack/react-table";
52
52
  import { cn } from "@/utils/cn";
53
- import { getColumnCountForDisplay } from "../hooks/use-column-visibility";
53
+ import {
54
+ getColumnCountForDisplay,
55
+ getUserColumnVisibilityCounts,
56
+ } from "../hooks/use-column-visibility";
54
57
 
55
58
  interface ColumnExplorerPanelProps<TData> {
56
59
  previewColumn: PreviewColumn;
@@ -90,6 +93,7 @@ export function ColumnExplorerPanel<TData>({
90
93
  totalColumns: effectiveTotalColumns,
91
94
  hiddenColumns: hiddenColumnCount,
92
95
  } = getColumnCountForDisplay(table, totalColumns);
96
+ const { visible: visibleColumnCount } = getUserColumnVisibilityCounts(table);
93
97
 
94
98
  const { rowsAndColumns, hiddenSuffix } = prettifyRowColumnCount({
95
99
  numRows: totalRows,
@@ -108,17 +112,34 @@ export function ColumnExplorerPanel<TData>({
108
112
  value={columns?.map(([columnName]) => columnName).join(",\n") || ""}
109
113
  className="h-3 w-3"
110
114
  />
111
- {hiddenColumnCount > 0 && (
112
- <Button
113
- type="button"
114
- variant="link"
115
- size="xs"
116
- className="h-auto p-0"
117
- onClick={() => table.resetColumnVisibility(true)}
118
- >
119
- Unhide all
120
- </Button>
121
- )}
115
+ <div className="ml-auto flex items-center gap-1">
116
+ <Tooltip content="Show all columns" delayDuration={400}>
117
+ <Button
118
+ type="button"
119
+ variant="ghost"
120
+ size="xs"
121
+ className="gap-1"
122
+ disabled={hiddenColumnCount === 0}
123
+ onClick={() => table.toggleAllColumnsVisible(true)}
124
+ >
125
+ <EyeIcon className="w-3 h-3" />
126
+ Show all
127
+ </Button>
128
+ </Tooltip>
129
+ <Tooltip content="Hide all columns" delayDuration={400}>
130
+ <Button
131
+ type="button"
132
+ variant="ghost"
133
+ size="xs"
134
+ className="gap-1"
135
+ disabled={visibleColumnCount === 0}
136
+ onClick={() => table.toggleAllColumnsVisible(false)}
137
+ >
138
+ <EyeOffIcon className="w-3 h-3" />
139
+ Hide all
140
+ </Button>
141
+ </Tooltip>
142
+ </div>
122
143
  </div>
123
144
  <Command className="h-5/6 bg-background" shouldFilter={false}>
124
145
  <CommandInput
@@ -59,6 +59,12 @@ export const ColumnVisibilityDropdown = <TData,>({
59
59
  const hiddenIds = userColumns
60
60
  .filter((column) => !column.getIsVisible())
61
61
  .map((column) => column.id);
62
+ const hideableIds = userColumns
63
+ .filter((column) => column.getCanHide())
64
+ .map((column) => column.id);
65
+ const visibleHideableCount = hideableIds.filter(
66
+ (id) => !hiddenIds.includes(id),
67
+ ).length;
62
68
 
63
69
  const applyHidden = (next: string[] | string | null) => {
64
70
  const hidden = new Set(Array.isArray(next) ? next : []);
@@ -127,6 +133,15 @@ export const ColumnVisibilityDropdown = <TData,>({
127
133
  <EyeIcon className="w-3 h-3 mr-1.5" />
128
134
  Show all
129
135
  </CommandItem>
136
+ <CommandItem
137
+ value="__hide_all__"
138
+ disabled={visibleHideableCount === 0}
139
+ onSelect={() => applyHidden(hideableIds)}
140
+ className="cursor-pointer"
141
+ >
142
+ <EyeOffIcon className="w-3 h-3 mr-1.5" />
143
+ Hide all
144
+ </CommandItem>
130
145
  <CommandSeparator />
131
146
  </>
132
147
  ) : (