@marimo-team/islands 0.21.2-dev93 → 0.21.2-dev94

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 (40) hide show
  1. package/dist/{Combination-BVnmMSzE.js → Combination-B--d1_LV.js} +8 -8
  2. package/dist/{ConnectedDataExplorerComponent-BzRetIpL.js → ConnectedDataExplorerComponent-CTfvzyMi.js} +19 -19
  3. package/dist/{any-language-editor-BgjMQ0JO.js → any-language-editor-Bj-3432h.js} +4 -4
  4. package/dist/{button-CxEhg2E1.js → button-qsiIHncQ.js} +10 -11
  5. package/dist/{capabilities-x7AvQTfX.js → capabilities-BC3mzKnw.js} +1 -1
  6. package/dist/{chat-ui-Blhe8Kd8.js → chat-ui-BvK3aDSR.js} +13 -13
  7. package/dist/{check-Cfbm1K98.js → check-D_YwHEgY.js} +1 -1
  8. package/dist/{copy-Bb-tO2YP.js → copy-CBo9JcJW.js} +2 -2
  9. package/dist/{dist-eWNxvDQG.js → dist-D2Rk1j4R.js} +2 -2
  10. package/dist/{error-banner-CW87Aylu.js → error-banner-DkDzvax3.js} +25 -25
  11. package/dist/{esm-BjPSZ7Qf.js → esm-C9_jY_wu.js} +4 -4
  12. package/dist/{glide-data-editor-CSemfq4D.js → glide-data-editor-D0IYL4_F.js} +7 -7
  13. package/dist/{input-EtKyRcb-.js → input-C5uUN4xL.js} +9 -9
  14. package/dist/{label-mQKeDCJ8.js → label-DwSVaniz.js} +4 -4
  15. package/dist/{loader-hvRcVSq5.js → loader-DrMJeyDu.js} +15 -15
  16. package/dist/main.js +17389 -17351
  17. package/dist/{mermaid-CjhFZReU.js → mermaid-Bwy7OYzI.js} +5 -5
  18. package/dist/{process-output-Cy0KEXJh.js → process-output-CT8hHGp6.js} +15 -15
  19. package/dist/{slides-component-DKg-ohoF.js → slides-component-BsaaAy66.js} +2 -2
  20. package/dist/{spec-DLNqef4y.js → spec-BLAZSydG.js} +3 -3
  21. package/dist/style.css +1 -1
  22. package/dist/{toDate-BEXAEQ0o.js → toDate-BWaG12Pv.js} +3 -3
  23. package/dist/{tooltip-CYv8qy5F.js → tooltip-DGHTbHl5.js} +3 -3
  24. package/dist/{types-B7Om6oxp.js → types-Dqw69fPc.js} +2 -2
  25. package/dist/{useAsyncData-b2IfqSIa.js → useAsyncData-Dqt2tV1E.js} +1 -1
  26. package/dist/{useDeepCompareMemoize-C7Ut95sA.js → useDeepCompareMemoize-D2PKDkrk.js} +4 -4
  27. package/dist/{useIframeCapabilities-DHGxPMu5.js → useIframeCapabilities-DlwLttZw.js} +1 -1
  28. package/dist/{useLifecycle-Q7CzdfPd.js → useLifecycle-CJ_5Z4Mk.js} +3 -3
  29. package/dist/{useTheme-5rRsavIK.js → useTheme-BIAKDAh6.js} +2 -2
  30. package/dist/{vega-component-B0Ik4707.js → vega-component-CTOT0vRO.js} +9 -9
  31. package/package.json +1 -1
  32. package/src/components/data-table/TableActions.tsx +25 -50
  33. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +24 -13
  34. package/src/components/data-table/data-table.tsx +11 -9
  35. package/src/components/data-table/hooks/use-panel-ownership.ts +15 -5
  36. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +53 -44
  37. package/src/components/data-table/table-explorer-panel/table-explorer-panel.tsx +161 -0
  38. package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +16 -9
  39. package/src/core/slots/slots.ts +1 -0
  40. package/src/plugins/impl/DataTablePlugin.tsx +19 -22
@@ -3,10 +3,10 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { t as __commonJSMin } from "./chunk-BNovOVIE.js";
5
5
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
6
- import { l as createLucideIcon } from "./dist-eWNxvDQG.js";
7
- import { g as Logger } from "./button-CxEhg2E1.js";
6
+ import { l as createLucideIcon } from "./dist-D2Rk1j4R.js";
7
+ import { h as Logger } from "./button-qsiIHncQ.js";
8
8
  import { r as KnownQueryParams } from "./constants-CXiS0vdr.js";
9
- import { f as waitFor, p as isIslands, u as store, y as atom } from "./useTheme-5rRsavIK.js";
9
+ import { f as waitFor, p as isIslands, u as store, y as atom } from "./useTheme-BIAKDAh6.js";
10
10
  var CircleQuestionMark = createLucideIcon("circle-question-mark", [
11
11
  ["circle", {
12
12
  cx: "12",
@@ -1,9 +1,9 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-Bs6Z0kvn.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
- import { a as Content, i as Arrow, o as Root2, r as Anchor, s as createPopperScope, t as Root } from "./dist-eWNxvDQG.js";
5
- import { m as useComposedRefs, y as cn } from "./button-CxEhg2E1.js";
6
- import { _t as createContextScope, at as useControllableState, ct as useId, ft as Primitive, ht as createSlottable, it as StyleNamespace, nt as withSmartCollisionBoundary, ot as Presence, st as Portal, tt as withFullScreenAsRoot, ut as DismissableLayer, vt as composeEventHandlers } from "./Combination-BVnmMSzE.js";
4
+ import { a as Content, i as Arrow, o as Root2, r as Anchor, s as createPopperScope, t as Root } from "./dist-D2Rk1j4R.js";
5
+ import { p as useComposedRefs, v as cn } from "./button-qsiIHncQ.js";
6
+ import { _t as createContextScope, at as useControllableState, ct as useId, ft as Primitive, ht as createSlottable, it as StyleNamespace, nt as withSmartCollisionBoundary, ot as Presence, st as Portal, tt as withFullScreenAsRoot, ut as DismissableLayer, vt as composeEventHandlers } from "./Combination-B--d1_LV.js";
7
7
  import { t as require_jsx_runtime } from "./jsx-runtime-9hcJiI23.js";
8
8
  var import_react = /* @__PURE__ */ __toESM(require_react(), 1), import_jsx_runtime = /* @__PURE__ */ __toESM(require_jsx_runtime(), 1), [createTooltipContext, createTooltipScope] = createContextScope("Tooltip", [createPopperScope]), usePopperScope = createPopperScope(), PROVIDER_NAME = "TooltipProvider", DEFAULT_DELAY_DURATION = 700, TOOLTIP_OPEN = "tooltip.open", [TooltipProviderContextProvider, useTooltipProviderContext] = createTooltipContext(PROVIDER_NAME), TooltipProvider$1 = (t) => {
9
9
  let { __scopeTooltip: k, delayDuration: A = DEFAULT_DELAY_DURATION, skipDelayDuration: j = 300, disableHoverableContent: M = false, children: N } = t, P = import_react.useRef(true), F = import_react.useRef(false), I = import_react.useRef(0);
@@ -1,8 +1,8 @@
1
1
  import { s as __toESM, t as __commonJSMin } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-Bs6Z0kvn.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
- import { l as createLucideIcon } from "./dist-eWNxvDQG.js";
5
- import { t as Button } from "./button-CxEhg2E1.js";
4
+ import { l as createLucideIcon } from "./dist-D2Rk1j4R.js";
5
+ import { t as Button } from "./button-qsiIHncQ.js";
6
6
  import { t as require_jsx_runtime } from "./jsx-runtime-9hcJiI23.js";
7
7
  import { n as Constants } from "./constants-CXiS0vdr.js";
8
8
  var Pencil = createLucideIcon("pencil", [["path", {
@@ -1,7 +1,7 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-Bs6Z0kvn.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
- import { w as useEvent_default } from "./useTheme-5rRsavIK.js";
4
+ import { w as useEvent_default } from "./useTheme-BIAKDAh6.js";
5
5
  import { t as invariant } from "./invariant-CzjtdzpE.js";
6
6
  var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1), Result = {
7
7
  error(e, s) {
@@ -1,11 +1,11 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-Bs6Z0kvn.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
- import { t as toDate } from "./toDate-BEXAEQ0o.js";
5
- import { a as cva, y as cn } from "./button-CxEhg2E1.js";
4
+ import { t as toDate } from "./toDate-BWaG12Pv.js";
5
+ import { a as cva, v as cn } from "./button-qsiIHncQ.js";
6
6
  import { t as require_jsx_runtime } from "./jsx-runtime-9hcJiI23.js";
7
- import { C as dequal } from "./useTheme-5rRsavIK.js";
8
- import { i as tableFromIPC } from "./loader-hvRcVSq5.js";
7
+ import { C as dequal } from "./useTheme-BIAKDAh6.js";
8
+ import { i as tableFromIPC } from "./loader-DrMJeyDu.js";
9
9
  function isDate(t) {
10
10
  return t instanceof Date || typeof t == "object" && Object.prototype.toString.call(t) === "[object Date]";
11
11
  }
@@ -1,7 +1,7 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-Bs6Z0kvn.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
- import { t as getIframeCapabilities } from "./capabilities-x7AvQTfX.js";
4
+ import { t as getIframeCapabilities } from "./capabilities-BC3mzKnw.js";
5
5
  var import_compiler_runtime = require_compiler_runtime();
6
6
  require_react();
7
7
  function useIframeCapabilities() {
@@ -1,10 +1,10 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-Bs6Z0kvn.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
- import { l as createLucideIcon } from "./dist-eWNxvDQG.js";
5
- import { a as cva, g as Logger, y as cn } from "./button-CxEhg2E1.js";
4
+ import { l as createLucideIcon } from "./dist-D2Rk1j4R.js";
5
+ import { a as cva, h as Logger, v as cn } from "./button-qsiIHncQ.js";
6
6
  import { t as require_jsx_runtime } from "./jsx-runtime-9hcJiI23.js";
7
- import { _ as useSetAtom, y as atom } from "./useTheme-5rRsavIK.js";
7
+ import { _ as useSetAtom, y as atom } from "./useTheme-BIAKDAh6.js";
8
8
  var Calendar = createLucideIcon("calendar", [
9
9
  ["path", {
10
10
  d: "M8 2v4",
@@ -1,8 +1,8 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-Bs6Z0kvn.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
- import { g as Logger, s as OverridingHotkeyProvider, u as resolvePlatform } from "./button-CxEhg2E1.js";
5
- import { B as record, H as string, L as number, O as array, P as looseObject, R as object, W as union, k as boolean, w as _enum } from "./Combination-BVnmMSzE.js";
4
+ import { h as Logger, l as resolvePlatform, s as OverridingHotkeyProvider } from "./button-qsiIHncQ.js";
5
+ import { B as record, H as string, L as number, O as array, P as looseObject, R as object, W as union, k as boolean, w as _enum } from "./Combination-B--d1_LV.js";
6
6
  import { t as merge_default } from "./merge-Byt9w-nO.js";
7
7
  var import_react = /* @__PURE__ */ __toESM(require_react()), useInsertionEffect = typeof window < "u" ? import_react.useInsertionEffect || import_react.useLayoutEffect : () => {
8
8
  };
@@ -1,20 +1,20 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-Bs6Z0kvn.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
- import { c as asRemoteURL, g as CircleQuestionMark } from "./toDate-BEXAEQ0o.js";
5
- import { d as Objects, g as Logger, h as Events, y as cn } from "./button-CxEhg2E1.js";
6
- import "./Combination-BVnmMSzE.js";
4
+ import { c as asRemoteURL, g as CircleQuestionMark } from "./toDate-BWaG12Pv.js";
5
+ import { h as Logger, m as Events, u as Objects, v as cn } from "./button-qsiIHncQ.js";
6
+ import "./Combination-B--d1_LV.js";
7
7
  import { t as require_jsx_runtime } from "./jsx-runtime-9hcJiI23.js";
8
8
  import "./react-dom-BKwCWYPW.js";
9
- import { t as Tooltip } from "./tooltip-CYv8qy5F.js";
9
+ import { t as Tooltip } from "./tooltip-DGHTbHl5.js";
10
10
  import { i as debounce_default } from "./constants-CXiS0vdr.js";
11
- import { n as useTheme, w as useEvent_default } from "./useTheme-5rRsavIK.js";
11
+ import { n as useTheme, w as useEvent_default } from "./useTheme-BIAKDAh6.js";
12
12
  import { c as uniq } from "./arrays--2cd0hte.js";
13
- import { a as AlertTitle, n as arrow, o as isValid, r as Alert, t as useDeepCompareMemoize } from "./useDeepCompareMemoize-C7Ut95sA.js";
14
- import { n as ErrorBanner } from "./error-banner-CW87Aylu.js";
13
+ import { a as AlertTitle, n as arrow, o as isValid, r as Alert, t as useDeepCompareMemoize } from "./useDeepCompareMemoize-D2PKDkrk.js";
14
+ import { n as ErrorBanner } from "./error-banner-DkDzvax3.js";
15
15
  import { n as formats } from "./vega-loader.browser-hMqVC9bf.js";
16
- import { a as getContainerWidth, n as vegaLoadData, s as tooltipHandler } from "./loader-hvRcVSq5.js";
17
- import { t as useAsyncData } from "./useAsyncData-b2IfqSIa.js";
16
+ import { a as getContainerWidth, n as vegaLoadData, s as tooltipHandler } from "./loader-DrMJeyDu.js";
17
+ import { t as useAsyncData } from "./useAsyncData-Dqt2tV1E.js";
18
18
  import { t as j } from "./react-vega-JMnqwKtN.js";
19
19
  import "./defaultLocale-DjFHq3Xk.js";
20
20
  import "./defaultLocale-B_A76Zpk.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.21.2-dev93",
3
+ "version": "0.21.2-dev94",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -2,17 +2,15 @@
2
2
  "use no memo";
3
3
 
4
4
  import type { RowSelectionState, Table } from "@tanstack/react-table";
5
- import {
6
- ChartColumnStacked,
7
- ChartSplineIcon,
8
- PanelRightIcon,
9
- SearchIcon,
10
- } from "lucide-react";
5
+ import { ChartSplineIcon, PanelRightIcon, SearchIcon } from "lucide-react";
11
6
  import React from "react";
12
7
  import { useLocale } from "react-aria";
13
8
  import type { GetRowIds } from "@/plugins/impl/DataTablePlugin";
14
9
  import { cn } from "@/utils/cn";
15
- import type { PanelType } from "../editor/chrome/panels/context-aware-panel/context-aware-panel";
10
+ import {
11
+ PANEL_TYPES,
12
+ type PanelType,
13
+ } from "../editor/chrome/panels/context-aware-panel/context-aware-panel";
16
14
  import { Button } from "../ui/button";
17
15
  import { Tooltip } from "../ui/tooltip";
18
16
  import { toast } from "../ui/use-toast";
@@ -35,11 +33,10 @@ interface TableActionsProps<TData> {
35
33
  getRowIds?: GetRowIds;
36
34
  toggleDisplayHeader?: () => void;
37
35
  showChartBuilder?: boolean;
38
- showColumnExplorer?: boolean;
39
- showRowExplorer?: boolean;
36
+ showTableExplorer?: boolean;
40
37
  showPageSizeSelector?: boolean;
41
38
  togglePanel?: (panelType: PanelType) => void;
42
- isPanelOpen?: (panelType: PanelType) => boolean;
39
+ isAnyPanelOpen?: boolean;
43
40
  tableLoading?: boolean;
44
41
  }
45
42
 
@@ -58,11 +55,10 @@ export const TableActions = <TData,>({
58
55
  getRowIds,
59
56
  toggleDisplayHeader,
60
57
  showChartBuilder,
61
- showColumnExplorer,
62
- showRowExplorer,
58
+ showTableExplorer,
63
59
  showPageSizeSelector,
64
60
  togglePanel,
65
- isPanelOpen,
61
+ isAnyPanelOpen,
66
62
  tableLoading,
67
63
  }: TableActionsProps<TData>) => {
68
64
  const { locale } = useLocale();
@@ -136,43 +132,22 @@ export const TableActions = <TData,>({
136
132
  </Button>
137
133
  </Tooltip>
138
134
  )}
139
- {togglePanel && isPanelOpen !== undefined && (
140
- <>
141
- {showRowExplorer && (
142
- <Tooltip content="Toggle row viewer">
143
- <Button
144
- variant="text"
145
- size="xs"
146
- onClick={() => togglePanel("row-viewer")}
147
- className="print:hidden"
148
- >
149
- <PanelRightIcon
150
- className={cn(
151
- "w-4 h-4 text-muted-foreground",
152
- isPanelOpen("row-viewer") && "text-primary",
153
- )}
154
- />
155
- </Button>
156
- </Tooltip>
157
- )}
158
- {showColumnExplorer && (
159
- <Tooltip content="Toggle column explorer">
160
- <Button
161
- variant="text"
162
- size="xs"
163
- onClick={() => togglePanel("column-explorer")}
164
- className="print:hidden"
165
- >
166
- <ChartColumnStacked
167
- className={cn(
168
- "w-4 h-4 text-muted-foreground",
169
- isPanelOpen("column-explorer") && "text-primary",
170
- )}
171
- />
172
- </Button>
173
- </Tooltip>
174
- )}
175
- </>
135
+ {showTableExplorer && togglePanel && (
136
+ <Tooltip content="Toggle table explorer">
137
+ <Button
138
+ variant="text"
139
+ size="xs"
140
+ onClick={() => togglePanel(PANEL_TYPES.ROW_VIEWER)}
141
+ className="print:hidden"
142
+ >
143
+ <PanelRightIcon
144
+ className={cn(
145
+ "w-4 h-4 text-muted-foreground",
146
+ isAnyPanelOpen && "text-primary",
147
+ )}
148
+ />
149
+ </Button>
150
+ </Tooltip>
176
151
  )}
177
152
 
178
153
  {pagination ? (
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import { ChevronDownIcon, ChevronRightIcon } from "lucide-react";
3
4
  import { useState } from "react";
4
5
  import { useLocale } from "react-aria";
5
6
  import {
@@ -88,18 +89,21 @@ export const ColumnExplorerPanel = ({
88
89
  />
89
90
  <CommandList className="max-h-full">
90
91
  <CommandEmpty>No results.</CommandEmpty>
91
- {filteredColumns?.map(([columnName, [dataType, externalType]]) => {
92
- return (
93
- <ColumnItem
94
- // Tables may have the same column names, hence we use tableId to make it unique
95
- key={`${tableId}-${columnName}`}
96
- columnName={columnName}
97
- dataType={dataType}
98
- externalType={externalType}
99
- previewColumn={previewColumn}
100
- />
101
- );
102
- })}
92
+ {filteredColumns?.map(
93
+ ([columnName, [dataType, externalType]], index) => {
94
+ return (
95
+ <ColumnItem
96
+ // Tables may have the same column names, hence we use tableId to make it unique
97
+ key={`${tableId}-${columnName}`}
98
+ columnName={columnName}
99
+ dataType={dataType}
100
+ externalType={externalType}
101
+ previewColumn={previewColumn}
102
+ defaultExpanded={index === 0}
103
+ />
104
+ );
105
+ },
106
+ )}
103
107
  </CommandList>
104
108
  </Command>
105
109
  </div>
@@ -111,13 +115,15 @@ const ColumnItem = ({
111
115
  dataType,
112
116
  externalType,
113
117
  previewColumn,
118
+ defaultExpanded = false,
114
119
  }: {
115
120
  columnName: string;
116
121
  dataType: DataType;
117
122
  externalType: string;
118
123
  previewColumn: PreviewColumn;
124
+ defaultExpanded?: boolean;
119
125
  }) => {
120
- const [isExpanded, setIsExpanded] = useState(false);
126
+ const [isExpanded, setIsExpanded] = useState(defaultExpanded);
121
127
 
122
128
  const columnText = (
123
129
  <span className={isExpanded ? "font-semibold" : ""}>{columnName}</span>
@@ -130,6 +136,11 @@ const ColumnItem = ({
130
136
  onSelect={() => setIsExpanded(!isExpanded)}
131
137
  className="flex flex-row items-center gap-1.5 group w-full cursor-pointer"
132
138
  >
139
+ {isExpanded ? (
140
+ <ChevronDownIcon className="w-3 h-3 shrink-0 text-muted-foreground" />
141
+ ) : (
142
+ <ChevronRightIcon className="w-3 h-3 shrink-0 text-muted-foreground" />
143
+ )}
133
144
  <ColumnName columnName={columnText} dataType={dataType} />
134
145
  <div className="ml-auto">
135
146
  <Tooltip content="Copy column name" delayDuration={400}>
@@ -24,7 +24,10 @@ import { useLocale } from "react-aria";
24
24
  import { Table } from "@/components/ui/table";
25
25
  import type { GetRowIds } from "@/plugins/impl/DataTablePlugin";
26
26
  import { cn } from "@/utils/cn";
27
- import type { PanelType } from "../editor/chrome/panels/context-aware-panel/context-aware-panel";
27
+ import {
28
+ PANEL_TYPES,
29
+ type PanelType,
30
+ } from "../editor/chrome/panels/context-aware-panel/context-aware-panel";
28
31
  import { CellHoverTemplateFeature } from "./cell-hover-template/feature";
29
32
  import { CellHoverTextFeature } from "./cell-hover-text/feature";
30
33
  import { CellSelectionFeature } from "./cell-selection/feature";
@@ -97,10 +100,10 @@ interface DataTableProps<TData> extends Partial<DownloadActionProps> {
97
100
  // Others
98
101
  showChartBuilder?: boolean;
99
102
  showPageSizeSelector?: boolean;
100
- showColumnExplorer?: boolean;
101
- showRowExplorer?: boolean;
103
+ showTableExplorer?: boolean;
102
104
  togglePanel?: (panelType: PanelType) => void;
103
105
  isPanelOpen?: (panelType: PanelType) => boolean;
106
+ isAnyPanelOpen?: boolean;
104
107
  }
105
108
 
106
109
  const DataTableInternal = <TData,>({
@@ -142,10 +145,10 @@ const DataTableInternal = <TData,>({
142
145
  toggleDisplayHeader,
143
146
  showChartBuilder,
144
147
  showPageSizeSelector,
145
- showColumnExplorer,
146
- showRowExplorer,
148
+ showTableExplorer,
147
149
  togglePanel,
148
150
  isPanelOpen,
151
+ isAnyPanelOpen,
149
152
  viewedRowIdx,
150
153
  onViewedRowChange,
151
154
  }: DataTableProps<TData>) => {
@@ -272,7 +275,7 @@ const DataTableInternal = <TData,>({
272
275
  },
273
276
  });
274
277
 
275
- const rowViewerPanelOpen = isPanelOpen?.("row-viewer") ?? false;
278
+ const rowViewerPanelOpen = isPanelOpen?.(PANEL_TYPES.ROW_VIEWER) ?? false;
276
279
  const virtualize = !pagination && data.length > MIN_ROWS_TO_VIRTUALIZE;
277
280
 
278
281
  const tableRef = useScrollContainerHeight({ maxHeight, virtualize });
@@ -324,10 +327,9 @@ const DataTableInternal = <TData,>({
324
327
  toggleDisplayHeader={toggleDisplayHeader}
325
328
  showChartBuilder={showChartBuilder}
326
329
  showPageSizeSelector={showPageSizeSelector}
327
- showColumnExplorer={showColumnExplorer}
328
- showRowExplorer={showRowExplorer}
330
+ showTableExplorer={showTableExplorer}
329
331
  togglePanel={togglePanel}
330
- isPanelOpen={isPanelOpen}
332
+ isAnyPanelOpen={isAnyPanelOpen}
331
333
  tableLoading={reloading}
332
334
  />
333
335
  </div>
@@ -13,7 +13,10 @@ import { Logger } from "@/utils/Logger";
13
13
 
14
14
  interface PanelOwnershipResult {
15
15
  isPanelOpen: (panelType: PanelType) => boolean;
16
- togglePanel: (panelType: PanelType) => void;
16
+ isAnyPanelOpen: boolean;
17
+ togglePanel: (panelType?: PanelType) => void;
18
+ panelType: PanelType | null;
19
+ setPanelType: (panelType: PanelType) => void;
17
20
  }
18
21
 
19
22
  export function usePanelOwnership(
@@ -55,24 +58,31 @@ export function usePanelOwnership(
55
58
  setPanelOwner(panelId);
56
59
  }
57
60
 
58
- function togglePanel(panelType: PanelType) {
59
- if (isPanelOpen(panelType)) {
61
+ const isAnyPanelOpen = panelOwner === panelId && isContextAwarePanelOpen;
62
+
63
+ function togglePanel(requestedType?: PanelType) {
64
+ if (isAnyPanelOpen) {
60
65
  setPanelOwner(null);
61
66
  setContextAwarePanelOpen(false);
62
67
  } else {
63
68
  setPanelOwner(panelId);
64
- // if cell-aware, we want to focus on this cell when toggled open
65
69
  if (isPanelCellAware && cellId) {
66
70
  focusCell({ cellId });
67
71
  }
68
72
  setContextAwarePanelOpen(true);
69
- setPanelType(panelType);
73
+ // Only set type if explicitly requested and no previous type exists
74
+ if (requestedType && !panelType) {
75
+ setPanelType(requestedType);
76
+ }
70
77
  }
71
78
  }
72
79
 
73
80
  return {
74
81
  isPanelOpen,
82
+ isAnyPanelOpen,
75
83
  togglePanel,
84
+ panelType,
85
+ setPanelType,
76
86
  };
77
87
  }
78
88
 
@@ -12,16 +12,16 @@ import {
12
12
  ChevronsLeft,
13
13
  ChevronsRight,
14
14
  Info,
15
- SearchIcon,
16
15
  } from "lucide-react";
17
- import { useRef, useState } from "react";
16
+ import { type KeyboardEvent, useId, useRef, useState } from "react";
18
17
  import { useLocale } from "react-aria";
19
18
  import { ColumnName } from "@/components/datasources/components";
20
19
  import { CopyClipboardIcon } from "@/components/icons/copy-icon";
21
20
  import { Spinner } from "@/components/icons/spinner";
22
21
  import { KeyboardHotkeys } from "@/components/shortcuts/renderShortcut";
23
22
  import { Button } from "@/components/ui/button";
24
- import { Input } from "@/components/ui/input";
23
+ import { Checkbox } from "@/components/ui/checkbox";
24
+ import { Command, CommandInput } from "@/components/ui/command";
25
25
  import {
26
26
  Table,
27
27
  TableBody,
@@ -32,7 +32,6 @@ import {
32
32
  } from "@/components/ui/table";
33
33
  import { DelayMount } from "@/components/utils/delay-mount";
34
34
  import { useAsyncData } from "@/hooks/useAsyncData";
35
- import { useKeydownOnElement } from "@/hooks/useHotkey";
36
35
  import { Banner, ErrorBanner } from "@/plugins/impl/common/error-banner";
37
36
  import type { GetRowResult } from "@/plugins/impl/DataTablePlugin";
38
37
  import { NAMELESS_COLUMN_PREFIX, renderCellValue } from "../columns";
@@ -68,7 +67,7 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
68
67
  }: RowViewerPanelProps) => {
69
68
  const [searchQuery, setSearchQuery] = useState("");
70
69
  const panelRef = useRef<HTMLDivElement>(null);
71
- const searchInputRef = useRef<HTMLInputElement>(null);
70
+ const checkboxId = useId();
72
71
  const { locale } = useLocale();
73
72
 
74
73
  const tooManyRows = totalRows === TOO_MANY_ROWS;
@@ -102,26 +101,29 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
102
101
  setRow(totalRows - 1);
103
102
  }
104
103
 
105
- useKeydownOnElement(panelRef, {
106
- ArrowLeft: (e) => {
107
- if (e?.target === searchInputRef.current) {
108
- return false;
109
- }
110
- setRow(rowIdx - 1);
111
- },
112
- ArrowRight: (e) => {
113
- if (e?.target === searchInputRef.current) {
114
- return false;
115
- }
116
- setRow(rowIdx + 1);
117
- },
118
- Space: (e) => {
119
- if (e?.target === searchInputRef.current) {
120
- return false;
121
- }
122
- toggleRowSelection();
123
- },
124
- });
104
+ const handleKeyDown = (e: KeyboardEvent) => {
105
+ // Don't intercept keys when typing in an input
106
+ if (e.target instanceof HTMLInputElement) {
107
+ return;
108
+ }
109
+ switch (e.key) {
110
+ case "ArrowLeft":
111
+ setRow(rowIdx - 1);
112
+
113
+ break;
114
+
115
+ case "ArrowRight":
116
+ setRow(rowIdx + 1);
117
+
118
+ break;
119
+
120
+ case " ":
121
+ e.preventDefault();
122
+ toggleRowSelection();
123
+
124
+ break;
125
+ }
126
+ };
125
127
 
126
128
  const buttonStyles = "h-6 w-6 p-0.5";
127
129
 
@@ -248,19 +250,29 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
248
250
  className="flex flex-col gap-3 mt-4 focus:outline-hidden"
249
251
  ref={panelRef}
250
252
  tabIndex={-1}
253
+ onKeyDown={handleKeyDown}
251
254
  >
252
- <div className="flex flex-row gap-2 items-center mr-2">
255
+ <div className="flex flex-row gap-2 items-center mr-2 px-2">
253
256
  {isSelectable && (
254
- <div className="flex flex-row gap-1 items-center">
255
- <Button
256
- variant="link"
257
- size="xs"
258
- className="pr-0"
259
- onClick={toggleRowSelection}
260
- >
261
- {isRowSelected ? "Deselect row" : "Select row"}
262
- </Button>
263
- <KeyboardHotkeys shortcut="Space" />
257
+ <div
258
+ className="flex items-center"
259
+ title="Select/unselect the current row"
260
+ >
261
+ <div className="flex items-center gap-1.5">
262
+ <Checkbox
263
+ id={checkboxId}
264
+ checked={isRowSelected}
265
+ onCheckedChange={toggleRowSelection}
266
+ className="h-3.5 w-3.5"
267
+ />
268
+ <label
269
+ htmlFor={checkboxId}
270
+ className="text-xs text-muted-foreground cursor-pointer"
271
+ >
272
+ Select
273
+ </label>
274
+ </div>
275
+ <KeyboardHotkeys shortcut="Space" className="scale-75" />
264
276
  </div>
265
277
  )}
266
278
 
@@ -315,17 +327,14 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
315
327
  </Button>
316
328
  </div>
317
329
 
318
- <div className="mx-2 -mb-1">
319
- <Input
320
- ref={searchInputRef}
321
- type="text"
330
+ <Command className="bg-background" shouldFilter={false}>
331
+ <CommandInput
322
332
  placeholder="Search"
323
- onChange={(e) => setSearchQuery(e.target.value)}
324
- icon={<SearchIcon className="w-4 h-4" />}
325
- className="mb-0 border-border"
333
+ value={searchQuery}
334
+ onValueChange={setSearchQuery}
326
335
  data-testid="selection-panel-search-input"
327
336
  />
328
- </div>
337
+ </Command>
329
338
  {renderTable()}
330
339
  </div>
331
340
  );