@marimo-team/islands 0.23.10-dev5 → 0.23.10-dev8
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/{any-language-editor-DfdpyDv_.js → any-language-editor-CiES2a2h.js} +2 -2
- package/dist/{chat-ui-1rLrACXD.js → chat-ui-K84W5ecY.js} +5 -5
- package/dist/{code-visibility-Dek9JNl9.js → code-visibility-ChnpTxqU.js} +1036 -882
- package/dist/{copy-BuQpJEzp.js → copy-5jQ_kGE1.js} +32 -32
- package/dist/{esm-BfhQmZjp.js → esm-CCuYCd3R.js} +1 -1
- package/dist/{extends-BgdxCfYu.js → extends-CkydH1Q5.js} +1 -1
- package/dist/{glide-data-editor-BOmK9ETQ.js → glide-data-editor-CgIxTzAP.js} +1 -1
- package/dist/{html-to-image-CnBdHeLh.js → html-to-image-B93KtAVY.js} +3 -3
- package/dist/main.js +10 -10
- package/dist/{process-output-vFgqkyUT.js → process-output-BOXi9fnS.js} +1 -1
- package/dist/{reveal-component-C8AmnVfj.js → reveal-component-OrljHylW.js} +2 -2
- package/package.json +1 -1
- package/src/components/data-table/__tests__/data-table.test.tsx +154 -12
- package/src/components/data-table/hover-tooltip/__tests__/content.test.ts +60 -0
- package/src/components/data-table/hover-tooltip/content.ts +44 -0
- package/src/components/data-table/hover-tooltip/hover-tooltip.tsx +55 -0
- package/src/components/data-table/hover-tooltip/use-table-hover-tooltip.ts +159 -0
- package/src/components/data-table/renderers.tsx +27 -43
- package/src/components/ui/__tests__/use-toast.test.ts +75 -0
- package/src/components/ui/use-toast.ts +33 -13
- package/src/core/network/__tests__/requests-static.test.ts +30 -0
- package/src/core/network/requests-static.ts +14 -10
- package/src/plugins/layout/DownloadPlugin.tsx +1 -1
|
@@ -8,61 +8,61 @@ var TOAST_LIMIT = 1, TOAST_REMOVE_DELAY = 1e4, count = 0;
|
|
|
8
8
|
function genId() {
|
|
9
9
|
return count = (count + 1) % Number.MAX_VALUE, count.toString();
|
|
10
10
|
}
|
|
11
|
-
var toastTimeouts = /* @__PURE__ */ new Map(), addToRemoveQueue = (e) => {
|
|
11
|
+
var toastTimeouts = /* @__PURE__ */ new Map(), shownOnceKeys = /* @__PURE__ */ new Set(), addToRemoveQueue = (e) => {
|
|
12
12
|
if (toastTimeouts.has(e)) return;
|
|
13
|
-
let
|
|
13
|
+
let d = setTimeout(() => {
|
|
14
14
|
toastTimeouts.delete(e), dispatch({
|
|
15
15
|
type: "REMOVE_TOAST",
|
|
16
16
|
toastId: e
|
|
17
17
|
});
|
|
18
18
|
}, TOAST_REMOVE_DELAY);
|
|
19
|
-
toastTimeouts.set(e,
|
|
19
|
+
toastTimeouts.set(e, d);
|
|
20
20
|
};
|
|
21
|
-
const reducer = (e,
|
|
22
|
-
switch (
|
|
21
|
+
const reducer = (e, d) => {
|
|
22
|
+
switch (d.type) {
|
|
23
23
|
case "ADD_TOAST":
|
|
24
24
|
return {
|
|
25
25
|
...e,
|
|
26
|
-
toasts: [
|
|
26
|
+
toasts: [d.toast, ...e.toasts].slice(0, TOAST_LIMIT)
|
|
27
27
|
};
|
|
28
28
|
case "UPDATE_TOAST":
|
|
29
29
|
return {
|
|
30
30
|
...e,
|
|
31
|
-
toasts: e.toasts.map((e2) => e2.id ===
|
|
31
|
+
toasts: e.toasts.map((e2) => e2.id === d.toast.id ? {
|
|
32
32
|
...e2,
|
|
33
|
-
...
|
|
33
|
+
...d.toast
|
|
34
34
|
} : e2)
|
|
35
35
|
};
|
|
36
36
|
case "DISMISS_TOAST": {
|
|
37
|
-
let { toastId:
|
|
38
|
-
return
|
|
37
|
+
let { toastId: f } = d;
|
|
38
|
+
return f ? addToRemoveQueue(f) : e.toasts.forEach((e2) => {
|
|
39
39
|
addToRemoveQueue(e2.id);
|
|
40
40
|
}), {
|
|
41
41
|
...e,
|
|
42
|
-
toasts: e.toasts.map((e2) => e2.id ===
|
|
42
|
+
toasts: e.toasts.map((e2) => e2.id === f || f === void 0 ? {
|
|
43
43
|
...e2,
|
|
44
44
|
open: false
|
|
45
45
|
} : e2)
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
case "REMOVE_TOAST":
|
|
49
|
-
return
|
|
49
|
+
return d.toastId === void 0 ? {
|
|
50
50
|
...e,
|
|
51
51
|
toasts: []
|
|
52
52
|
} : {
|
|
53
53
|
...e,
|
|
54
|
-
toasts: e.toasts.filter((e2) => e2.id !==
|
|
54
|
+
toasts: e.toasts.filter((e2) => e2.id !== d.toastId)
|
|
55
55
|
};
|
|
56
56
|
case "UPSERT_TOAST":
|
|
57
|
-
return e.toasts.findIndex((e2) => e2.id ===
|
|
57
|
+
return e.toasts.findIndex((e2) => e2.id === d.toast.id) > -1 ? {
|
|
58
58
|
...e,
|
|
59
|
-
toasts: e.toasts.map((e2) => e2.id ===
|
|
59
|
+
toasts: e.toasts.map((e2) => e2.id === d.toast.id ? {
|
|
60
60
|
...e2,
|
|
61
|
-
...
|
|
61
|
+
...d.toast
|
|
62
62
|
} : e2)
|
|
63
63
|
} : {
|
|
64
64
|
...e,
|
|
65
|
-
toasts: [
|
|
65
|
+
toasts: [d.toast, ...e.toasts].slice(0, TOAST_LIMIT)
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
};
|
|
@@ -72,39 +72,39 @@ function dispatch(e) {
|
|
|
72
72
|
e2(memoryState);
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
|
-
function toast({ id: e, ...
|
|
76
|
-
let
|
|
75
|
+
function toast({ id: e, once: d, ...f }) {
|
|
76
|
+
let p = e || genId(), m = d === true && e !== void 0, h = (e2) => dispatch({
|
|
77
77
|
type: "UPDATE_TOAST",
|
|
78
78
|
toast: {
|
|
79
79
|
...e2,
|
|
80
|
-
id:
|
|
80
|
+
id: p
|
|
81
81
|
}
|
|
82
82
|
}), g = () => dispatch({
|
|
83
83
|
type: "DISMISS_TOAST",
|
|
84
|
-
toastId:
|
|
84
|
+
toastId: p
|
|
85
85
|
}), _ = (e2) => dispatch({
|
|
86
86
|
type: "UPSERT_TOAST",
|
|
87
87
|
toast: {
|
|
88
88
|
...e2,
|
|
89
|
-
id:
|
|
89
|
+
id: p,
|
|
90
90
|
open: true,
|
|
91
91
|
onOpenChange: (e3) => {
|
|
92
92
|
e3 || g();
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
-
});
|
|
96
|
-
return dispatch({
|
|
95
|
+
}), v = m && shownOnceKeys.has(p);
|
|
96
|
+
return m && shownOnceKeys.add(p), v || dispatch({
|
|
97
97
|
type: "ADD_TOAST",
|
|
98
98
|
toast: {
|
|
99
|
-
...
|
|
100
|
-
id:
|
|
99
|
+
...f,
|
|
100
|
+
id: p,
|
|
101
101
|
open: true,
|
|
102
102
|
onOpenChange: (e2) => {
|
|
103
103
|
e2 || g();
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
}), {
|
|
107
|
-
id:
|
|
107
|
+
id: p,
|
|
108
108
|
dismiss: g,
|
|
109
109
|
update: h,
|
|
110
110
|
upsert: _
|
|
@@ -122,17 +122,17 @@ var Copy = createLucideIcon("copy", [["rect", {
|
|
|
122
122
|
d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",
|
|
123
123
|
key: "zix9uf"
|
|
124
124
|
}]]);
|
|
125
|
-
async function copyToClipboard(e,
|
|
125
|
+
async function copyToClipboard(e, f) {
|
|
126
126
|
if (navigator.clipboard === void 0) {
|
|
127
127
|
Logger.warn("navigator.clipboard is not supported"), window.prompt("Copy to clipboard: Ctrl+C, Enter", e);
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
|
-
if (
|
|
131
|
-
let
|
|
132
|
-
"text/html": new Blob([
|
|
130
|
+
if (f && navigator.clipboard.write) try {
|
|
131
|
+
let d = new ClipboardItem({
|
|
132
|
+
"text/html": new Blob([f], { type: "text/html" }),
|
|
133
133
|
"text/plain": new Blob([e], { type: "text/plain" })
|
|
134
134
|
});
|
|
135
|
-
await navigator.clipboard.write([
|
|
135
|
+
await navigator.clipboard.write([d]);
|
|
136
136
|
return;
|
|
137
137
|
} catch {
|
|
138
138
|
Logger.warn("Failed to write rich text, falling back to plain text");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
3
3
|
import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
|
|
4
|
-
import { l as historyKeymap, o as defaultKeymap, r as lintKeymap, s as history, t as _extends, u as indentWithTab } from "./extends-
|
|
4
|
+
import { l as historyKeymap, o as defaultKeymap, r as lintKeymap, s as history, t as _extends, u as indentWithTab } from "./extends-CkydH1Q5.js";
|
|
5
5
|
import { $ as ViewPlugin, At as Prec, B as tags, Bt as combineConfig, C as foldKeymap, Dt as EditorState, Et as EditorSelection, F as syntaxHighlighting, Ft as StateField, Ht as findClusterBreak, Mt as RangeSetBuilder, Ot as Facet, Pt as StateEffect, Rt as codePointAt, Ut as fromCodePoint, Y as Decoration, Z as EditorView, _t as showDialog, a as HighlightStyle, bt as crelt, ct as highlightActiveLineGutter, dt as keymap, ft as lineNumbers, g as defaultHighlightStyle, gt as runScopeHandlers, ht as rectangularSelection, it as getPanel, j as indentUnit, k as indentOnInput, lt as highlightSpecialChars, mt as placeholder, nt as drawSelection, p as bracketMatching, rt as dropCursor, st as highlightActiveLine, tt as crosshairCursor, vt as showPanel, wt as CharCategory, x as foldGutter, xt as Annotation, zt as codePointSize } from "./dist-DNdhYsgW.js";
|
|
6
6
|
import { a as closeBracketsKeymap, c as completionKeymap, i as closeBrackets, r as autocompletion } from "./dist-DhHh0jLg.js";
|
|
7
7
|
var basicNormalize = typeof String.prototype.normalize == "function" ? (e2) => e2.normalize("NFKD") : (e2) => e2, SearchCursor = class {
|
|
@@ -2,7 +2,7 @@ import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
|
2
2
|
import { g as cn, h as Events } from "./button-C5K9fIPF.js";
|
|
3
3
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
4
4
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
5
|
-
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-
|
|
5
|
+
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-5jQ_kGE1.js";
|
|
6
6
|
import { t as Check } from "./check-DTbrK0zt.js";
|
|
7
7
|
import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
|
|
8
8
|
import { t as Tooltip } from "./tooltip-C5FYOpQc.js";
|
|
@@ -5,7 +5,7 @@ import { s as __toESM, t as __commonJSMin } from "./chunk-BNovOVIE.js";
|
|
|
5
5
|
import { _ as Logger, h as Events, t as Button } from "./button-C5K9fIPF.js";
|
|
6
6
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
7
7
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
8
|
-
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-
|
|
8
|
+
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-5jQ_kGE1.js";
|
|
9
9
|
import { S as logNever, i as SelectContent, l as SelectTrigger, n as capitalize, o as SelectItem, r as Select, u as SelectValue } from "./strings-Bu3vlb6W.js";
|
|
10
10
|
import { G as marked, W as useNonce, _ as DropdownMenuSub, d as DropdownMenuContent, g as DropdownMenuSeparator, h as DropdownMenuPortal, p as DropdownMenuItem, r as Input, u as DropdownMenu, v as DropdownMenuSubContent, y as DropdownMenuSubTrigger } from "./input-_2sjvfne.js";
|
|
11
11
|
import { n as Trash, r as Pencil, t as BulkEdit } from "./types-CVvp1fKr.js";
|
|
@@ -5,7 +5,7 @@ import { a as __toCommonJS, n as __esmMin, o as __toDynamicImportESM, r as __exp
|
|
|
5
5
|
import { _ as Logger, c as Objects, d as createSlot, g as cn, m as useComposedRefs, o as isPlatformMac, r as cva, t as Button } from "./button-C5K9fIPF.js";
|
|
6
6
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
7
7
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
8
|
-
import { r as toast, t as copyToClipboard } from "./copy-
|
|
8
|
+
import { r as toast, t as copyToClipboard } from "./copy-5jQ_kGE1.js";
|
|
9
9
|
import { o as xn, s as require_cjs, __tla as __tla_0 } from "./chunk-5FQGJX7Z-BNjes6Yx.js";
|
|
10
10
|
import { a as createPopperScope, i as Root2$3, l as VisuallyHidden, n as Arrow, o as useSize, r as Content$1, t as Anchor, u as createLucideIcon } from "./dist-C1BYNeCR.js";
|
|
11
11
|
import { a as Type, c as Calendar, i as createReducerAndAtoms, o as ToggleLeft, r as Badge, s as Hash, t as useOnMount } from "./useLifecycle-BBO9PIph.js";
|
|
@@ -17,7 +17,7 @@ import { t as require_react_dom } from "./react-dom-BTJzcVJ9.js";
|
|
|
17
17
|
import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
|
|
18
18
|
import { $ as StyleNamespace, B as union, N as number, P as object, R as string, T as boolean, X as withFullScreenAsRoot, Y as MAX_HEIGHT_OFFSET, Z as withSmartCollisionBoundary, _t as Primitive, at as FocusScope, ct as Root$1, dt as Presence, et as hideOthers, ft as useControllableState, gt as createContextScope, it as Portal, k as literal, lt as useCallbackRef, mt as composeEventHandlers, ot as Branch, pt as useLayoutEffect2, rt as useFocusGuards, st as DismissableLayer, tt as Combination_default, ut as useId, vt as dispatchDiscreteCustomEvent, w as array } from "./zod-CoBiJ5v4.js";
|
|
19
19
|
import { i as TooltipProvider, t as Tooltip } from "./tooltip-C5FYOpQc.js";
|
|
20
|
-
import { a as setDiagnostics, c as historyField, d as insertTab, f as CopyClipboardIcon, i as linter, n as forEachDiagnostic, s as history } from "./extends-
|
|
20
|
+
import { a as setDiagnostics, c as historyField, d as insertTab, f as CopyClipboardIcon, i as linter, n as forEachDiagnostic, s as history } from "./extends-CkydH1Q5.js";
|
|
21
21
|
import { i as debounce_default } from "./constants-T20xxyNf.js";
|
|
22
22
|
import { _ as useAtomValue, a as getResolvedMarimoConfig, b as atom, d as store, g as useAtom, h as Provider, i as autoInstantiateAtom, m as isIslands, n as useTheme, t as resolvedThemeAtom, u as createDeepEqualAtom, w as dequal } from "./useTheme-DHIrRQOe.js";
|
|
23
23
|
import { $ as ViewPlugin, At as Prec, B as tags, Dt as EditorState, E as getIndentUnit, Et as EditorSelection, Ft as StateField, I as syntaxTree, It as Text, J as parseMixed, L as unfoldAll, Lt as Transaction, Ot as Facet, Pt as StateEffect, Q as GutterMarker, S as foldInside, Tt as Compartment, Y as Decoration, Z as EditorView, b as foldAll, dt as keymap, f as StreamLanguage, jt as RangeSet, l as LanguageDescription, mt as placeholder, ot as gutter, u as LanguageSupport, ut as hoverTooltip, vt as showPanel, w as foldNodeProp, xt as Annotation, yt as showTooltip } from "./dist-DNdhYsgW.js";
|
|
@@ -27989,7 +27989,7 @@ ${n.sqlString}
|
|
|
27989
27989
|
hasConsoleOutput: (o == null ? void 0 : o.consoleOutputs) != null
|
|
27990
27990
|
};
|
|
27991
27991
|
}
|
|
27992
|
-
LazyAnyLanguageCodeMirror = (0, import_react.lazy)(() => import("./any-language-editor-
|
|
27992
|
+
LazyAnyLanguageCodeMirror = (0, import_react.lazy)(() => import("./any-language-editor-CiES2a2h.js"));
|
|
27993
27993
|
var import_compiler_runtime$1 = require_compiler_runtime(), extensions = [
|
|
27994
27994
|
EditorView.lineWrapping
|
|
27995
27995
|
];
|
package/dist/main.js
CHANGED
|
@@ -21,18 +21,18 @@ import { a as __toCommonJS, n as __esmMin, r as __export, s as __toESM, t as __c
|
|
|
21
21
|
import { _ as Logger, c as Objects, g as cn, h as Events, i as NOT_SET, l as useEventListener, m as useComposedRefs, n as buttonVariants, o as isPlatformMac, p as composeRefs, r as cva, t as Button, u as Slot, v as Functions, y as throwNotImplemented } from "./button-C5K9fIPF.js";
|
|
22
22
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
23
23
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
24
|
-
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-
|
|
25
|
-
import { $ as useCellActions, An as LoaderCircle, At as DeferredRequestRegistry, B as safeExtractSetUIElementMessageBuffers, Bn as Braces, Bt as getDataTypeColor, C as AccordionContent, Cn as Trigger2, Ct as customPythonLanguageSupport, Dn as PaintRoller, Dt as Paths, E as BorderAllIcon, En as Table2, Et as PathBuilder, F as base64ToDataView, Ft as jotaiJsonStorage, Gt as convertStatsName, H as getMarimoExportContext, In as Database, J as getCellNames, Jt as useRequestClient, K as createActions, Kt as getRequestClient, L as dataViewToBase64, Ln as Columns2, Mn as Info, Nn as FileText, Nt as repl, Pn as Eye, Q as reducer, Rt as PluralWords, S as Accordion, Sn as Root2$1, St as Checkbox, T as AccordionTrigger, Tn as Trash2, U as hasTrustedExportContext, V as renderHTML, Vt as require_client, W as hasRunAnyCellAtom, X as notebookOutline, Y as notebookAtom, Yt as isUninstantiated, Z as numColumnsAtom, _n as selectAtom, a as useCellFocusActions, an as parseInitialValue, bn as Content2, bt as isInternalCellName, ct as kioskModeAtom, dn as OBJECT_ID_ATTR, dt as outputIsLoading, en as NotebookScopedLocalStorage, et as useCellIds, f as isOutputEmpty, fn as RANDOM_ID_ATTR, ft as outputIsStale, gn as atomWithStorage, hn as atomWithReducer, i as LazyAnyLanguageCodeMirror, in as parseDataset, jn as Layers, jt as generateUUID, k as ChevronDownIcon, ln as UIElementId, mt as headingToIdentifier, n as Spinner, nt as createCell, o as useLastFocusedCellId, ot as getInitialAppMode, p as useExpandedConsoleOutput, pn as jsonParseWithSpecialChar, pt as isErrorMime, qt as requestClientAtom, rn as parseAttrValue, s as maybeAddAltairImport, sn as HTMLCellId, st as initialModeAtom, un as findCellId, w as AccordionItem, wt as MarkdownLanguageAdapter, xn as Item$1, xt as normalizeName, yt as getValidName, zn as CircleAlert, zt as DATA_TYPE_ICON, __tla as __tla_0 } from "./html-to-image-
|
|
24
|
+
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-5jQ_kGE1.js";
|
|
25
|
+
import { $ as useCellActions, An as LoaderCircle, At as DeferredRequestRegistry, B as safeExtractSetUIElementMessageBuffers, Bn as Braces, Bt as getDataTypeColor, C as AccordionContent, Cn as Trigger2, Ct as customPythonLanguageSupport, Dn as PaintRoller, Dt as Paths, E as BorderAllIcon, En as Table2, Et as PathBuilder, F as base64ToDataView, Ft as jotaiJsonStorage, Gt as convertStatsName, H as getMarimoExportContext, In as Database, J as getCellNames, Jt as useRequestClient, K as createActions, Kt as getRequestClient, L as dataViewToBase64, Ln as Columns2, Mn as Info, Nn as FileText, Nt as repl, Pn as Eye, Q as reducer, Rt as PluralWords, S as Accordion, Sn as Root2$1, St as Checkbox, T as AccordionTrigger, Tn as Trash2, U as hasTrustedExportContext, V as renderHTML, Vt as require_client, W as hasRunAnyCellAtom, X as notebookOutline, Y as notebookAtom, Yt as isUninstantiated, Z as numColumnsAtom, _n as selectAtom, a as useCellFocusActions, an as parseInitialValue, bn as Content2, bt as isInternalCellName, ct as kioskModeAtom, dn as OBJECT_ID_ATTR, dt as outputIsLoading, en as NotebookScopedLocalStorage, et as useCellIds, f as isOutputEmpty, fn as RANDOM_ID_ATTR, ft as outputIsStale, gn as atomWithStorage, hn as atomWithReducer, i as LazyAnyLanguageCodeMirror, in as parseDataset, jn as Layers, jt as generateUUID, k as ChevronDownIcon, ln as UIElementId, mt as headingToIdentifier, n as Spinner, nt as createCell, o as useLastFocusedCellId, ot as getInitialAppMode, p as useExpandedConsoleOutput, pn as jsonParseWithSpecialChar, pt as isErrorMime, qt as requestClientAtom, rn as parseAttrValue, s as maybeAddAltairImport, sn as HTMLCellId, st as initialModeAtom, un as findCellId, w as AccordionItem, wt as MarkdownLanguageAdapter, xn as Item$1, xt as normalizeName, yt as getValidName, zn as CircleAlert, zt as DATA_TYPE_ICON, __tla as __tla_0 } from "./html-to-image-B93KtAVY.js";
|
|
26
26
|
import { __tla as __tla_1 } from "./chunk-5FQGJX7Z-BNjes6Yx.js";
|
|
27
27
|
import { o as useSize, s as Root$2, u as createLucideIcon } from "./dist-C1BYNeCR.js";
|
|
28
28
|
import { A as SquareFunction, C as DEFAULT_COLOR_SCHEME, D as SCALE_TYPE_DESCRIPTIONS, E as EMPTY_VALUE$1, O as TIME_UNIT_DESCRIPTIONS, S as DEFAULT_AGGREGATION, T as DEFAULT_TIME_UNIT, _ as AGGREGATION_TYPE_DESCRIPTIONS, a as AGGREGATION_FNS$1, b as COLOR_SCHEMES, c as COLOR_BY_FIELDS, d as NONE_VALUE, f as SELECTABLE_DATA_TYPES, g as TIME_UNITS, h as STRING_AGGREGATION_FNS, i as convertDataTypeToSelectable, j as ChartColumn, k as escapeFieldName, l as COMBINED_TIME_UNITS, m as SORT_TYPES, n as createSpecWithoutData, o as BIN_AGGREGATION, p as SINGLE_TIME_UNITS, r as isFieldSet, s as CHART_TYPES, t as augmentSpecWithData, u as ChartType, v as AGGREGATION_TYPE_ICON, w as DEFAULT_MAX_BINS_FACET, x as COUNT_FIELD, y as CHART_TYPE_ICON } from "./spec-B96zNUEA.js";
|
|
29
|
-
import { $ as TableBody, $t as ChevronLeft, A as ComboboxItem, At as ChartErrorState, B as contextAwarePanelOpen, Bt as $fae977aafc393c5c$export$6b862160d295c8e, C as prettifyRowColumnCount, Ct as dateToLocalISODate, D as DatePicker, Dt as TabsContent, E as useInternalStateWithSync, Et as Tabs, F as CommandList, Ft as RenderTextWithLinks, G as slotsController, H as contextAwarePanelType, Ht as GripHorizontal, I as CommandSeparator, It as Kbd, Jt as Code, K as Toggle, Kt as Ellipsis, L as smartMatch, Lt as HtmlOutput, M as CommandEmpty, Mt as ChartLoadingState, N as CommandInput, Nt as LazyVegaEmbed, O as DateRangePicker, Ot as TabsList, P as CommandItem, Pt as useOverflowDetection, Q as Table, Qt as ChevronsDownUp, R as ContextAwarePanelItem, Rt as EmotionCacheProvider, S as downloadSizeLimitAtom, St as Maps, T as getColumnCountForDisplay, Tt as dateToLocalISOTime, U as isCellAwareAtom, Ut as Funnel, V as contextAwarePanelOwner, Vt as TextWrap, W as SlotNames, Wt as EyeOff, X as Fill, Xt as ChevronsRight, Yt as ChevronsUpDown, Z as Provider$1, Zt as ChevronsLeft, _ as downloadBlob, _t as SELECT_COLUMN_ID, at as generateColumns, b as Progress, bt as getMimeValues, c as Slide, ct as ColumnChartContext, d as JsonOutput, dt as useIntersectionObserver, en as ArrowDownWideNarrow, et as TableCell, f as OutputArea, ft as usePrevious$1, g as ADD_PRINTING_CLASS, gt as INDEX_COLUMN_NAME, h as InstallPackageButton, ht as loadTableData, it as NAMELESS_COLUMN_PREFIX, j as Command, jt as ChartInfoState, k as Combobox, kt as TabsTrigger, l as RadioGroup, lt as ColumnChartSpecModel, m as DataTable, mt as loadTableAndRawData, n as marimoVersionAtom, nt as TableHeader, o as SLIDE_TYPE_OPTIONS_BY_VALUE, ot as inferFieldTypes, p as OutputRenderer, pt as getPageIndexForRow, qt as Download, r as showCodeInRunModeAtom, rt as TableRow, st as renderCellValue, t as useNotebookCodeAvailable, tt as TableHead, u as RadioGroupItem, ut as DelayMount, v as downloadByURL, vt as TOO_MANY_ROWS, w as prettifyRowCount, wt as dateToLocalISODateTime, x as Filenames, xt as isNullishFilter, y as downloadHTMLAsImage, yt as toFieldTypes, z as PANEL_TYPES, zt as $fae977aafc393c5c$export$588937bcd60ade55, __tla as __tla_2 } from "./code-visibility-
|
|
29
|
+
import { $ as TableBody, $t as ChevronLeft, A as ComboboxItem, At as ChartErrorState, B as contextAwarePanelOpen, Bt as $fae977aafc393c5c$export$6b862160d295c8e, C as prettifyRowColumnCount, Ct as dateToLocalISODate, D as DatePicker, Dt as TabsContent, E as useInternalStateWithSync, Et as Tabs, F as CommandList, Ft as RenderTextWithLinks, G as slotsController, H as contextAwarePanelType, Ht as GripHorizontal, I as CommandSeparator, It as Kbd, Jt as Code, K as Toggle, Kt as Ellipsis, L as smartMatch, Lt as HtmlOutput, M as CommandEmpty, Mt as ChartLoadingState, N as CommandInput, Nt as LazyVegaEmbed, O as DateRangePicker, Ot as TabsList, P as CommandItem, Pt as useOverflowDetection, Q as Table, Qt as ChevronsDownUp, R as ContextAwarePanelItem, Rt as EmotionCacheProvider, S as downloadSizeLimitAtom, St as Maps, T as getColumnCountForDisplay, Tt as dateToLocalISOTime, U as isCellAwareAtom, Ut as Funnel, V as contextAwarePanelOwner, Vt as TextWrap, W as SlotNames, Wt as EyeOff, X as Fill, Xt as ChevronsRight, Yt as ChevronsUpDown, Z as Provider$1, Zt as ChevronsLeft, _ as downloadBlob, _t as SELECT_COLUMN_ID, at as generateColumns, b as Progress, bt as getMimeValues, c as Slide, ct as ColumnChartContext, d as JsonOutput, dt as useIntersectionObserver, en as ArrowDownWideNarrow, et as TableCell, f as OutputArea, ft as usePrevious$1, g as ADD_PRINTING_CLASS, gt as INDEX_COLUMN_NAME, h as InstallPackageButton, ht as loadTableData, it as NAMELESS_COLUMN_PREFIX, j as Command, jt as ChartInfoState, k as Combobox, kt as TabsTrigger, l as RadioGroup, lt as ColumnChartSpecModel, m as DataTable, mt as loadTableAndRawData, n as marimoVersionAtom, nt as TableHeader, o as SLIDE_TYPE_OPTIONS_BY_VALUE, ot as inferFieldTypes, p as OutputRenderer, pt as getPageIndexForRow, qt as Download, r as showCodeInRunModeAtom, rt as TableRow, st as renderCellValue, t as useNotebookCodeAvailable, tt as TableHead, u as RadioGroupItem, ut as DelayMount, v as downloadByURL, vt as TOO_MANY_ROWS, w as prettifyRowCount, wt as dateToLocalISODateTime, x as Filenames, xt as isNullishFilter, y as downloadHTMLAsImage, yt as toFieldTypes, z as PANEL_TYPES, zt as $fae977aafc393c5c$export$588937bcd60ade55, __tla as __tla_2 } from "./code-visibility-ChnpTxqU.js";
|
|
30
30
|
import { c as Calendar, i as createReducerAndAtoms, n as useOnUnmount, o as ToggleLeft, t as useOnMount } from "./useLifecycle-BBO9PIph.js";
|
|
31
31
|
import { t as Check } from "./check-DTbrK0zt.js";
|
|
32
32
|
import { A as Trigger$1, C as $a916eb452884faea$export$b7a616150fdb9f44, E as $18f2051aff69b9bf$export$a54013f0d02a8f82, F as X, L as ChevronDown, M as usePrevious$2, N as useDirection, P as createCollection, S as logNever, T as $18f2051aff69b9bf$export$43bb16f9c6d9e3f7, a as SelectGroup, c as SelectSeparator, d as NativeSelect, i as SelectContent, j as clamp$2, k as Icon, l as SelectTrigger, n as capitalize, o as SelectItem, r as Select, s as SelectLabel, t as Strings, u as SelectValue, x as assertNever } from "./strings-Bu3vlb6W.js";
|
|
33
33
|
import { I as $64fa3d84918910a7$export$29f1550f4b0d4415, K as useDebounceControlledState, L as $64fa3d84918910a7$export$4d86445c2cf5e3, Mt as $65484d02dcb7eb3e$export$457c3d6518dd4c6f, Nt as $3ef42575df84b30b$export$9d1611c77c2fe928, V as $64fa3d84918910a7$export$df3a06d6289f983e, Vt as $ff5963eb1fccf552$export$e08e3b67e392101e, a as NumberField, b as DropdownMenuTrigger, c as prettyNumber, d as DropdownMenuContent, f as DropdownMenuGroup, fn as Circle, g as DropdownMenuSeparator, i as OnBlurredInput, it as $701a24aa0da5b062$export$ea18c227d4417cc3, l as prettyScientificNumber, m as DropdownMenuLabel, n as DebouncedNumberInput, p as DropdownMenuItem, pn as ChevronRight, q as useDebouncedCallback, r as Input, rt as $f7dceffc5ad7768b$export$4e328f61c538687f, t as DebouncedInput, u as DropdownMenu, ut as $6179b936705e76d3$export$ae780daf29e6d456, vt as $458b0a5536c1a7cf$export$40bfa8c7b0832715 } from "./input-_2sjvfne.js";
|
|
34
34
|
import { _ as isWasm, c as asRemoteURL, d as isStaticNotebook, f as appendQueryParams, g as Deferred, m as require_cuid2, u as getStaticVirtualFiles, v as CircleQuestionMark } from "./toDate-x-WRDCH7.js";
|
|
35
|
-
import { a as MarimoIncomingMessageEvent, c as MarimoValueUpdateEvent, d as Square, f as File, i as PythonIcon, l as createInputEvent, n as blobToString, o as MarimoValueInputEvent, r as filesToBase64, s as MarimoValueReadyEvent, t as processOutput, u as deserializeBlob } from "./process-output-
|
|
35
|
+
import { a as MarimoIncomingMessageEvent, c as MarimoValueUpdateEvent, d as Square, f as File, i as PythonIcon, l as createInputEvent, n as blobToString, o as MarimoValueInputEvent, r as filesToBase64, s as MarimoValueReadyEvent, t as processOutput, u as deserializeBlob } from "./process-output-BOXi9fnS.js";
|
|
36
36
|
import { n as Trash, r as Pencil, t as BulkEdit } from "./types-CVvp1fKr.js";
|
|
37
37
|
import { n as require_prop_types, r as Plus, t as ErrorBoundary } from "./ErrorBoundary-rULOrC_p.js";
|
|
38
38
|
import { t as require_react_dom } from "./react-dom-BTJzcVJ9.js";
|
|
@@ -41,7 +41,7 @@ import { $ as StyleNamespace, A as looseObject, B as union, C as any, F as optio
|
|
|
41
41
|
import { i as prettyError, n as ErrorBanner, r as CellNotInitializedError, t as Banner } from "./error-banner-5bz0L9hS.js";
|
|
42
42
|
import { t as Label } from "./label-LWtdw5i8.js";
|
|
43
43
|
import { a as TooltipRoot, i as TooltipProvider, n as TooltipContent, o as TooltipTrigger, r as TooltipPortal, t as Tooltip } from "./tooltip-C5FYOpQc.js";
|
|
44
|
-
import { f as CopyClipboardIcon } from "./extends-
|
|
44
|
+
import { f as CopyClipboardIcon } from "./extends-CkydH1Q5.js";
|
|
45
45
|
import { a as get_default } from "./hasIn-Deg7jl_j.js";
|
|
46
46
|
import { n as _baseSet_default, t as pick_default } from "./pick-D1Qo8s2C.js";
|
|
47
47
|
import { i as debounce_default, r as KnownQueryParams, t as CSSClasses } from "./constants-T20xxyNf.js";
|
|
@@ -57,7 +57,7 @@ import "./dist-CcXxepx6.js";
|
|
|
57
57
|
import "./dist-DxvORzUR.js";
|
|
58
58
|
import "./dist-DqAWR3CS.js";
|
|
59
59
|
import { r as python } from "./dist-BotSqB48.js";
|
|
60
|
-
import { n as minimalSetup, t as esm_default } from "./esm-
|
|
60
|
+
import { n as minimalSetup, t as esm_default } from "./esm-CCuYCd3R.js";
|
|
61
61
|
import "./purify.es-H92eMd9-.js";
|
|
62
62
|
import { i as AlertTitle, n as Alert, r as AlertDescription } from "./formats-DHxc-FdY.js";
|
|
63
63
|
import "./vega-loader.browser-CZ-J8Py3.js";
|
|
@@ -5590,7 +5590,7 @@ let __tla = Promise.all([
|
|
|
5590
5590
|
};
|
|
5591
5591
|
}
|
|
5592
5592
|
};
|
|
5593
|
-
var LazyChatbot = import_react.lazy(() => import("./chat-ui-
|
|
5593
|
+
var LazyChatbot = import_react.lazy(() => import("./chat-ui-K84W5ecY.js").then((e) => ({
|
|
5594
5594
|
default: e.Chatbot
|
|
5595
5595
|
}))), messageSchema = array(object({
|
|
5596
5596
|
id: string(),
|
|
@@ -5739,7 +5739,7 @@ let __tla = Promise.all([
|
|
|
5739
5739
|
"time",
|
|
5740
5740
|
"unknown"
|
|
5741
5741
|
];
|
|
5742
|
-
var import_compiler_runtime$78 = require_compiler_runtime(), LazyDataEditor = import_react.lazy(() => import("./glide-data-editor-
|
|
5742
|
+
var import_compiler_runtime$78 = require_compiler_runtime(), LazyDataEditor = import_react.lazy(() => import("./glide-data-editor-CgIxTzAP.js").then(async (m) => {
|
|
5743
5743
|
await m.__tla;
|
|
5744
5744
|
return m;
|
|
5745
5745
|
}));
|
|
@@ -26689,7 +26689,7 @@ ${c}
|
|
|
26689
26689
|
l(true);
|
|
26690
26690
|
try {
|
|
26691
26691
|
let c3 = await r({});
|
|
26692
|
-
downloadByURL(c3.data, c3.filename ?? e.filename ?? void 0);
|
|
26692
|
+
downloadByURL(c3.data || e.data, c3.filename ?? e.filename ?? void 0);
|
|
26693
26693
|
} catch (e2) {
|
|
26694
26694
|
toast({
|
|
26695
26695
|
title: "Failed to download",
|
|
@@ -36116,7 +36116,7 @@ ${c}
|
|
|
36116
36116
|
if (l && l !== "slide") return l;
|
|
36117
36117
|
if (c == null ? void 0 : c.has(e)) return "skip";
|
|
36118
36118
|
}
|
|
36119
|
-
var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-
|
|
36119
|
+
var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-OrljHylW.js"));
|
|
36120
36120
|
const SlidesLayoutRenderer = ({ layout: e, setLayout: r, cells: c, mode: l }) => {
|
|
36121
36121
|
var _a3;
|
|
36122
36122
|
let u = useAtomValue(kioskModeAtom), d = l === "read" || u, f = useAtomValue(numColumnsAtom) > 1, [p, m] = (0, import_react.useState)(null), { slideCells: h, skippedIds: g, noOutputIds: _, slideTypes: v, startCellIndex: y } = (0, import_react.useMemo)(() => computeSlideCellsInfo(c, e), [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
3
|
-
import { it as parseHtmlContent, rt as ansiToPlainText } from "./html-to-image-
|
|
3
|
+
import { it as parseHtmlContent, rt as ansiToPlainText } from "./html-to-image-B93KtAVY.js";
|
|
4
4
|
import { u as createLucideIcon } from "./dist-C1BYNeCR.js";
|
|
5
5
|
import { t as Strings } from "./strings-Bu3vlb6W.js";
|
|
6
6
|
import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
|
|
@@ -6,10 +6,10 @@ import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
|
6
6
|
import { _ as Logger, g as cn, h as Events, l as useEventListener, t as Button } from "./button-C5K9fIPF.js";
|
|
7
7
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
8
8
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
9
|
-
import { ct as kioskModeAtom } from "./html-to-image-
|
|
9
|
+
import { ct as kioskModeAtom } from "./html-to-image-B93KtAVY.js";
|
|
10
10
|
import "./chunk-5FQGJX7Z-BNjes6Yx.js";
|
|
11
11
|
import { u as createLucideIcon } from "./dist-C1BYNeCR.js";
|
|
12
|
-
import { Gt as Expand, J as PanelGroup, Jt as Code, Wt as EyeOff, Y as PanelResizeHandle, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, q as Panel, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-
|
|
12
|
+
import { Gt as Expand, J as PanelGroup, Jt as Code, Wt as EyeOff, Y as PanelResizeHandle, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, q as Panel, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-ChnpTxqU.js";
|
|
13
13
|
import { q as useDebouncedCallback } from "./input-_2sjvfne.js";
|
|
14
14
|
import "./toDate-x-WRDCH7.js";
|
|
15
15
|
import "./react-dom-BTJzcVJ9.js";
|
package/package.json
CHANGED
|
@@ -5,8 +5,8 @@ import type {
|
|
|
5
5
|
RowSelectionState,
|
|
6
6
|
SortingState,
|
|
7
7
|
} from "@tanstack/react-table";
|
|
8
|
-
import { fireEvent, render, screen, within } from "@testing-library/react";
|
|
9
|
-
import { describe, expect, it, vi } from "vitest";
|
|
8
|
+
import { act, fireEvent, render, screen, within } from "@testing-library/react";
|
|
9
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
10
10
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
11
11
|
import { DataTable } from "../data-table";
|
|
12
12
|
|
|
@@ -16,6 +16,12 @@ interface TestData {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
describe("DataTable", () => {
|
|
19
|
+
// Restore real timers unconditionally so a failed assertion in a
|
|
20
|
+
// fake-timer test can't leak fake timers into later tests.
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
vi.useRealTimers();
|
|
23
|
+
});
|
|
24
|
+
|
|
19
25
|
it("should maintain selection state when remounted", () => {
|
|
20
26
|
const mockOnRowSelectionChange = vi.fn();
|
|
21
27
|
const testData: TestData[] = [
|
|
@@ -63,17 +69,15 @@ describe("DataTable", () => {
|
|
|
63
69
|
expect(commonProps.rowSelection).toEqual(initialRowSelection);
|
|
64
70
|
});
|
|
65
71
|
|
|
66
|
-
it("
|
|
72
|
+
it("shows the hoverTemplate text as a styled tooltip on hover", async () => {
|
|
73
|
+
vi.useFakeTimers();
|
|
67
74
|
interface RowData {
|
|
68
75
|
id: number;
|
|
69
76
|
first: string;
|
|
70
77
|
last: string;
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
const testData: RowData[] = [
|
|
74
|
-
{ id: 1, first: "Michael", last: "Scott" },
|
|
75
|
-
{ id: 2, first: "Jim", last: "Halpert" },
|
|
76
|
-
];
|
|
80
|
+
const testData: RowData[] = [{ id: 1, first: "Michael", last: "Scott" }];
|
|
77
81
|
|
|
78
82
|
const columns: ColumnDef<RowData>[] = [
|
|
79
83
|
{ accessorKey: "first", header: "First" },
|
|
@@ -86,7 +90,7 @@ describe("DataTable", () => {
|
|
|
86
90
|
data={testData}
|
|
87
91
|
columns={columns}
|
|
88
92
|
selection={null}
|
|
89
|
-
totalRows={
|
|
93
|
+
totalRows={1}
|
|
90
94
|
totalColumns={2}
|
|
91
95
|
pagination={false}
|
|
92
96
|
hoverTemplate={"{{first}} {{last}}"}
|
|
@@ -94,11 +98,149 @@ describe("DataTable", () => {
|
|
|
94
98
|
</TooltipProvider>,
|
|
95
99
|
);
|
|
96
100
|
|
|
97
|
-
// Grab all rows and assert title attribute computed from template
|
|
98
101
|
const rows = screen.getAllByRole("row");
|
|
99
|
-
//
|
|
100
|
-
expect(rows[1]).toHaveAttribute("title"
|
|
101
|
-
|
|
102
|
+
// Native title is gone; hover text now comes from the styled tooltip.
|
|
103
|
+
expect(rows[1]).not.toHaveAttribute("title");
|
|
104
|
+
|
|
105
|
+
const cell = within(rows[1]).getAllByRole("cell")[0];
|
|
106
|
+
fireEvent.mouseOver(cell, { buttons: 0 });
|
|
107
|
+
act(() => {
|
|
108
|
+
vi.advanceTimersByTime(400);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Radix renders the content twice (visible + a11y-hidden), so match all.
|
|
112
|
+
expect(screen.getAllByText("Michael Scott").length).toBeGreaterThan(0);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("shows per-cell hover text from cellHoverTexts on hover", () => {
|
|
116
|
+
vi.useFakeTimers();
|
|
117
|
+
const testData: TestData[] = [{ id: 1, name: "Test 1" }];
|
|
118
|
+
const columns: ColumnDef<TestData>[] = [
|
|
119
|
+
{ id: "name", accessorKey: "name", header: "Name" },
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
render(
|
|
123
|
+
<TooltipProvider>
|
|
124
|
+
<DataTable
|
|
125
|
+
data={testData}
|
|
126
|
+
columns={columns}
|
|
127
|
+
selection={null}
|
|
128
|
+
totalRows={1}
|
|
129
|
+
totalColumns={1}
|
|
130
|
+
pagination={false}
|
|
131
|
+
cellHoverTexts={{ "0": { name: "per-cell tip" } }}
|
|
132
|
+
/>
|
|
133
|
+
</TooltipProvider>,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const cell = within(screen.getAllByRole("row")[1]).getByRole("cell");
|
|
137
|
+
fireEvent.mouseOver(cell, { buttons: 0 });
|
|
138
|
+
act(() => {
|
|
139
|
+
vi.advanceTimersByTime(400);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
expect(screen.getAllByText("per-cell tip").length).toBeGreaterThan(0);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("links the focused cell to the tooltip content for assistive tech", () => {
|
|
146
|
+
const testData: TestData[] = [{ id: 1, name: "Test 1" }];
|
|
147
|
+
const columns: ColumnDef<TestData>[] = [
|
|
148
|
+
{ id: "name", accessorKey: "name", header: "Name" },
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
render(
|
|
152
|
+
<TooltipProvider>
|
|
153
|
+
<DataTable
|
|
154
|
+
data={testData}
|
|
155
|
+
columns={columns}
|
|
156
|
+
selection={null}
|
|
157
|
+
totalRows={1}
|
|
158
|
+
totalColumns={1}
|
|
159
|
+
pagination={false}
|
|
160
|
+
cellHoverTexts={{ "0": { name: "focus tip" } }}
|
|
161
|
+
/>
|
|
162
|
+
</TooltipProvider>,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const cell = within(screen.getAllByRole("row")[1]).getByRole("cell");
|
|
166
|
+
fireEvent.focus(cell);
|
|
167
|
+
|
|
168
|
+
const describedBy = cell.getAttribute("aria-describedby");
|
|
169
|
+
expect(describedBy).toBeTruthy();
|
|
170
|
+
expect(document.getElementById(describedBy as string)).toHaveTextContent(
|
|
171
|
+
"focus tip",
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
fireEvent.blur(cell);
|
|
175
|
+
expect(cell).not.toHaveAttribute("aria-describedby");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("does not show a tooltip on pointer-induced focus", () => {
|
|
179
|
+
const testData: TestData[] = [{ id: 1, name: "Test 1" }];
|
|
180
|
+
const columns: ColumnDef<TestData>[] = [
|
|
181
|
+
{ id: "name", accessorKey: "name", header: "Name" },
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
render(
|
|
185
|
+
<TooltipProvider>
|
|
186
|
+
<DataTable
|
|
187
|
+
data={testData}
|
|
188
|
+
columns={columns}
|
|
189
|
+
selection={null}
|
|
190
|
+
totalRows={1}
|
|
191
|
+
totalColumns={1}
|
|
192
|
+
pagination={false}
|
|
193
|
+
cellHoverTexts={{ "0": { name: "click tip" } }}
|
|
194
|
+
/>
|
|
195
|
+
</TooltipProvider>,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const cell = within(screen.getAllByRole("row")[1]).getByRole("cell");
|
|
199
|
+
// A click focuses the cell; the resulting focus must not show a tooltip.
|
|
200
|
+
fireEvent.mouseDown(cell);
|
|
201
|
+
fireEvent.focus(cell);
|
|
202
|
+
|
|
203
|
+
expect(cell).not.toHaveAttribute("aria-describedby");
|
|
204
|
+
expect(screen.queryByText("click tip")).toBeNull();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("does not let a pending hover timer overwrite a focus tooltip", () => {
|
|
208
|
+
vi.useFakeTimers();
|
|
209
|
+
interface RowData {
|
|
210
|
+
id: number;
|
|
211
|
+
a: string;
|
|
212
|
+
b: string;
|
|
213
|
+
}
|
|
214
|
+
const testData: RowData[] = [{ id: 1, a: "a", b: "b" }];
|
|
215
|
+
const columns: ColumnDef<RowData>[] = [
|
|
216
|
+
{ id: "a", accessorKey: "a", header: "A" },
|
|
217
|
+
{ id: "b", accessorKey: "b", header: "B" },
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
render(
|
|
221
|
+
<TooltipProvider>
|
|
222
|
+
<DataTable
|
|
223
|
+
data={testData}
|
|
224
|
+
columns={columns}
|
|
225
|
+
selection={null}
|
|
226
|
+
totalRows={1}
|
|
227
|
+
totalColumns={2}
|
|
228
|
+
pagination={false}
|
|
229
|
+
cellHoverTexts={{ "0": { a: "hover A", b: "focus B" } }}
|
|
230
|
+
/>
|
|
231
|
+
</TooltipProvider>,
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
const cells = within(screen.getAllByRole("row")[1]).getAllByRole("cell");
|
|
235
|
+
// Start a pending hover-show on cell A, then focus cell B before it fires.
|
|
236
|
+
fireEvent.mouseOver(cells[0], { buttons: 0 });
|
|
237
|
+
fireEvent.focus(cells[1]);
|
|
238
|
+
act(() => {
|
|
239
|
+
vi.advanceTimersByTime(400);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
expect(screen.getAllByText("focus B").length).toBeGreaterThan(0);
|
|
243
|
+
expect(screen.queryByText("hover A")).toBeNull();
|
|
102
244
|
});
|
|
103
245
|
|
|
104
246
|
it("does not virtualize small datasets without pagination", () => {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
import type { Cell } from "@tanstack/react-table";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { applyHoverTemplate, computeCellTooltipContent } from "../content";
|
|
5
|
+
|
|
6
|
+
function fakeCell(columnId: string, value: unknown, hoverTitle?: string) {
|
|
7
|
+
return {
|
|
8
|
+
column: { id: columnId },
|
|
9
|
+
getValue: () => value,
|
|
10
|
+
getHoverTitle: () => hoverTitle,
|
|
11
|
+
} as unknown as Cell<unknown, unknown>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("applyHoverTemplate", () => {
|
|
15
|
+
it("substitutes column placeholders", () => {
|
|
16
|
+
const cells = [fakeCell("first", "Michael"), fakeCell("last", "Scott")];
|
|
17
|
+
expect(applyHoverTemplate("{{first}} {{last}}", cells)).toBe(
|
|
18
|
+
"Michael Scott",
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("renders nulls as empty strings", () => {
|
|
23
|
+
const cells = [fakeCell("a", null)];
|
|
24
|
+
expect(applyHoverTemplate("[{{a}}]", cells)).toBe("[]");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("leaves unknown placeholders intact", () => {
|
|
28
|
+
expect(applyHoverTemplate("{{missing}}", [fakeCell("a", 1)])).toBe(
|
|
29
|
+
"{{missing}}",
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("computeCellTooltipContent", () => {
|
|
35
|
+
it("prefers cell-level hover title", () => {
|
|
36
|
+
const cell = fakeCell("a", 1, "cell text");
|
|
37
|
+
expect(computeCellTooltipContent(cell, "{{a}}")).toBe("cell text");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("falls back to row template when no cell title", () => {
|
|
41
|
+
const cell = {
|
|
42
|
+
column: { id: "first" },
|
|
43
|
+
getValue: () => "X",
|
|
44
|
+
getHoverTitle: () => undefined,
|
|
45
|
+
row: {
|
|
46
|
+
getVisibleCells: () => [
|
|
47
|
+
fakeCell("first", "Jim"),
|
|
48
|
+
fakeCell("last", "Halpert"),
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
} as unknown as Cell<unknown, unknown>;
|
|
52
|
+
expect(computeCellTooltipContent(cell, "{{first}} {{last}}")).toBe(
|
|
53
|
+
"Jim Halpert",
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("returns undefined with no title and no template", () => {
|
|
58
|
+
expect(computeCellTooltipContent(fakeCell("a", 1), null)).toBeUndefined();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
import type { Cell, RowData } from "@tanstack/react-table";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { stringifyUnknownValue } from "../utils";
|
|
5
|
+
|
|
6
|
+
export function applyHoverTemplate<TData extends RowData>(
|
|
7
|
+
template: string,
|
|
8
|
+
cells: Cell<TData, unknown>[],
|
|
9
|
+
): string {
|
|
10
|
+
const variableRegex = /{{(\w+)}}/g;
|
|
11
|
+
const idToValue = new Map<string, string>();
|
|
12
|
+
for (const c of cells) {
|
|
13
|
+
const s = stringifyUnknownValue({
|
|
14
|
+
value: c.getValue(),
|
|
15
|
+
nullAsEmptyString: true,
|
|
16
|
+
});
|
|
17
|
+
idToValue.set(c.column.id, s);
|
|
18
|
+
}
|
|
19
|
+
return template.replaceAll(variableRegex, (_substr, varName: string) => {
|
|
20
|
+
const val = idToValue.get(varName);
|
|
21
|
+
return val === undefined ? `{{${varName}}}` : val;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the tooltip content for a hovered cell.
|
|
27
|
+
*
|
|
28
|
+
* Cell-level (callable `hover_template`) takes precedence; otherwise the
|
|
29
|
+
* row-level string template is rendered against the row's visible cells.
|
|
30
|
+
* Returns `undefined` when there is nothing to show.
|
|
31
|
+
*/
|
|
32
|
+
export function computeCellTooltipContent<TData extends RowData>(
|
|
33
|
+
cell: Cell<TData, unknown>,
|
|
34
|
+
hoverTemplate: string | null,
|
|
35
|
+
): ReactNode {
|
|
36
|
+
const cellTitle = cell.getHoverTitle?.();
|
|
37
|
+
if (cellTitle != null && cellTitle !== "") {
|
|
38
|
+
return cellTitle;
|
|
39
|
+
}
|
|
40
|
+
if (hoverTemplate) {
|
|
41
|
+
return applyHoverTemplate(hoverTemplate, cell.row.getVisibleCells());
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|