@marimo-team/islands 0.21.2-dev77 → 0.21.2-dev79
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-CSvBdMtG.js → any-language-editor-BBegsg-m.js} +17 -17
- package/dist/{chat-ui-CedqKBe3.js → chat-ui-D4ay_SFE.js} +9 -9
- package/dist/{dist-CEmSeYaL.js → dist-1-E4bC9V.js} +2 -2
- package/dist/{dist-DoO66t8e.js → dist-APyhcmvq.js} +1 -1
- package/dist/{dist-B6ZvKwIz.js → dist-B5thW2rT.js} +1 -1
- package/dist/{dist-mpvRA2Bc.js → dist-BFe8Nc_2.js} +3 -3
- package/dist/dist-BHGf2Zey.js +5 -0
- package/dist/dist-BImOGJZM.js +5 -0
- package/dist/{dist-DKr1M-ru.js → dist-BJvk9DSp.js} +1 -1
- package/dist/{dist-fRW2mZtS.js → dist-BLrc9iNb.js} +2 -2
- package/dist/{dist-DqweMfpO.js → dist-BYr4a-wE.js} +1 -1
- package/dist/dist-BbJfmCHJ.js +5 -0
- package/dist/{dist-Bc-mOFlk.js → dist-BrJQDkv_.js} +2 -2
- package/dist/dist-C0v-nFs_.js +8 -0
- package/dist/{dist-D2nC1On3.js → dist-C16JG-Ok.js} +2 -2
- package/dist/{dist-N1lm7LVK.js → dist-C4EV3aDt.js} +37 -71
- package/dist/dist-C8N7114Z.js +5 -0
- package/dist/dist-C9TDg2aq.js +8 -0
- package/dist/{dist-DvjVNme1.js → dist-CGH6Jw-c.js} +1 -1
- package/dist/{dist-CXsGjNbR.js → dist-CKVkWFcB.js} +2 -2
- package/dist/dist-CN4RKgNR.js +5 -0
- package/dist/{dist--MUqhsBh.js → dist-CQ3XmGIH.js} +1 -1
- package/dist/{dist-B771Ewvn.js → dist-CSiTW5NO.js} +3 -3
- package/dist/dist-CVOkf_3P.js +6 -0
- package/dist/{dist-8-jPFKws.js → dist-CYuoqvce.js} +2 -2
- package/dist/dist-Cbkga3s5.js +5 -0
- package/dist/{dist-TuFHGVp2.js → dist-Cm4SOB1A.js} +1 -1
- package/dist/{dist-BsyHyGqX.js → dist-CxczluAk.js} +2 -2
- package/dist/dist-D6YTv0Kj.js +5 -0
- package/dist/{dist-DlacJSaE.js → dist-D75XqRaT.js} +2 -2
- package/dist/dist-D9vawryf.js +8 -0
- package/dist/{dist-CpNdP46s.js → dist-DFBjYgbq.js} +2 -2
- package/dist/{dist-DqT0O-4m.js → dist-DUg5n_x5.js} +5 -5
- package/dist/dist-DasJgTvL.js +6 -0
- package/dist/{dist-DNSJBJI7.js → dist-DbyoYfBn.js} +2 -2
- package/dist/{dist-CsToCMcA.js → dist-Dd9vDQtp.js} +2 -2
- package/dist/{dist-QxBlbqgj.js → dist-Dk13KZ54.js} +3 -3
- package/dist/dist-Ui51qXMz.js +8 -0
- package/dist/{dist-DEmPLkH9.js → dist-XYBhoeSX.js} +4 -4
- package/dist/{dist-CwP9oyR8.js → dist-Y9GfSR6_.js} +2 -2
- package/dist/{dist-BjYGwQ65.js → dist-aW74oyUt.js} +1 -1
- package/dist/dist-d2msfN-B.js +5 -0
- package/dist/{dist-Bg1YGq2b.js → dist-iM9VwH8Z.js} +1 -1
- package/dist/{dist-DSSPn3fP.js → dist-uR-o9IVx.js} +2 -2
- package/dist/{dist-CJEfzjG5.js → dist-zGOEySUQ.js} +4 -4
- package/dist/{esm-B_4hpmV_.js → esm-CCD9xN05.js} +22 -22
- package/dist/{esm-Bcbo0Yvz.js → esm-CxoKu9RN.js} +3 -3
- package/dist/main.js +948 -334
- package/dist/{process-output-Xg5O7mVz.js → process-output-Cv8vQ4At.js} +33 -33
- package/package.json +2 -1
- package/src/__tests__/setup.ts +15 -0
- package/src/components/data-table/TableActions.tsx +8 -2
- package/src/components/data-table/__tests__/data-table.test.tsx +63 -0
- package/src/components/data-table/data-table.tsx +10 -31
- package/src/components/data-table/hooks/use-scroll-container-height.ts +97 -0
- package/src/components/data-table/renderers.tsx +103 -46
- package/src/components/data-table/types.ts +14 -0
- package/src/core/islands/main.ts +0 -1
- package/src/core/websocket/useMarimoKernelConnection.tsx +1 -10
- package/dist/dist-BK8Ch8me.js +0 -5
- package/dist/dist-BPlAe3w3.js +0 -6
- package/dist/dist-BQnLGf1A.js +0 -8
- package/dist/dist-BZRBnAnM.js +0 -5
- package/dist/dist-BmTKj-5m.js +0 -5
- package/dist/dist-C1UyhB0b.js +0 -5
- package/dist/dist-C1uqqTuH.js +0 -5
- package/dist/dist-CCeSY9xv.js +0 -5
- package/dist/dist-CMWhb0s1.js +0 -5
- package/dist/dist-DYoFz28E.js +0 -8
- package/dist/dist-DeSnQwvL.js +0 -6
- package/dist/dist-e8VqCQ_P.js +0 -5
- package/dist/dist-kGaha3sX.js +0 -8
- package/dist/dist-wQD8nhf9.js +0 -8
|
@@ -17,19 +17,19 @@ import { H as string, L as number, N as literal, O as array, R as object, W as u
|
|
|
17
17
|
import { t as require_jsx_runtime } from "./jsx-runtime-9hcJiI23.js";
|
|
18
18
|
import { t as require_react_dom } from "./react-dom-BKwCWYPW.js";
|
|
19
19
|
import { i as TooltipProvider, t as Tooltip } from "./tooltip-DnI4CwIS.js";
|
|
20
|
-
import { a as linter, c as historyField, i as forEachDiagnostic, l as insertTab, o as setDiagnostics, s as history, u as CopyClipboardIcon } from "./esm-
|
|
20
|
+
import { a as linter, c as historyField, i as forEachDiagnostic, l as insertTab, o as setDiagnostics, s as history, u as CopyClipboardIcon } from "./esm-CxoKu9RN.js";
|
|
21
21
|
import { t as toInteger_default } from "./toInteger-BUeg_O0F.js";
|
|
22
22
|
import { i as debounce_default } from "./constants-LmeAawHa.js";
|
|
23
23
|
import { a as getResolvedMarimoConfig, g as useAtomValue, h as useAtom, i as autoInstantiateAtom, l as createDeepEqualAtom, m as Provider, n as useTheme, p as isIslands, t as resolvedThemeAtom, u as store, w as isEqual_default, y as atom } from "./useTheme-5GTtjXjy.js";
|
|
24
|
-
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-
|
|
24
|
+
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-C4EV3aDt.js";
|
|
25
25
|
import { t as invariant } from "./invariant-Ctm_8TNZ.js";
|
|
26
26
|
import { a as arrayInsert, i as arrayDelete, n as once, o as arrayInsertMany, s as arrayMove, u as clamp } from "./once-DjP4Kbhy.js";
|
|
27
27
|
import { t as getIframeCapabilities } from "./capabilities-DAGZLwa6.js";
|
|
28
|
-
import { d as snippet, n as acceptCompletion, r as autocompletion, u as insertCompletionText } from "./dist-
|
|
28
|
+
import { d as snippet, n as acceptCompletion, r as autocompletion, u as insertCompletionText } from "./dist-BYr4a-wE.js";
|
|
29
29
|
import { t as require_main } from "./main-sxFlUO_N.js";
|
|
30
|
-
import { a as PLSQL, c as SQLite, d as schemaCompletionSource, f as sql, i as MySQL, l as StandardSQL, n as MSSQL, o as PostgreSQL, r as MariaSQL, s as SQLDialect, t as Cassandra, u as keywordCompletionSource } from "./dist-
|
|
31
|
-
import { a as markdown, s as markdownLanguage } from "./dist-
|
|
32
|
-
import { a as parser, i as pythonLanguage, n as localCompletionSource, r as python, t as globalCompletion } from "./dist-
|
|
30
|
+
import { a as PLSQL, c as SQLite, d as schemaCompletionSource, f as sql, i as MySQL, l as StandardSQL, n as MSSQL, o as PostgreSQL, r as MariaSQL, s as SQLDialect, t as Cassandra, u as keywordCompletionSource } from "./dist-D75XqRaT.js";
|
|
31
|
+
import { a as markdown, s as markdownLanguage } from "./dist-CSiTW5NO.js";
|
|
32
|
+
import { a as parser, i as pythonLanguage, n as localCompletionSource, r as python, t as globalCompletion } from "./dist-C16JG-Ok.js";
|
|
33
33
|
import { n as stexMath } from "./stex-7yEw16Ww.js";
|
|
34
34
|
import { t as purify } from "./purify.es-Co_dANLh.js";
|
|
35
35
|
import { t as useAsyncData } from "./useAsyncData-BtHYXgXF.js";
|
|
@@ -16172,7 +16172,7 @@ ${r.join("\n")}`;
|
|
|
16172
16172
|
return new LanguageSupport(StreamLanguage.define(e));
|
|
16173
16173
|
}
|
|
16174
16174
|
function sql$1(e) {
|
|
16175
|
-
return import("./dist-
|
|
16175
|
+
return import("./dist-Dd9vDQtp.js").then((t) => t.sql({
|
|
16176
16176
|
dialect: t[e]
|
|
16177
16177
|
}));
|
|
16178
16178
|
}
|
|
@@ -16185,7 +16185,7 @@ ${r.join("\n")}`;
|
|
|
16185
16185
|
"ino"
|
|
16186
16186
|
],
|
|
16187
16187
|
load() {
|
|
16188
|
-
return import("./dist-
|
|
16188
|
+
return import("./dist-D6YTv0Kj.js").then((e) => e.cpp());
|
|
16189
16189
|
}
|
|
16190
16190
|
}),
|
|
16191
16191
|
LanguageDescription.of({
|
|
@@ -16204,7 +16204,7 @@ ${r.join("\n")}`;
|
|
|
16204
16204
|
"hxx"
|
|
16205
16205
|
],
|
|
16206
16206
|
load() {
|
|
16207
|
-
return import("./dist-
|
|
16207
|
+
return import("./dist-D6YTv0Kj.js").then((e) => e.cpp());
|
|
16208
16208
|
}
|
|
16209
16209
|
}),
|
|
16210
16210
|
LanguageDescription.of({
|
|
@@ -16225,7 +16225,7 @@ ${r.join("\n")}`;
|
|
|
16225
16225
|
"css"
|
|
16226
16226
|
],
|
|
16227
16227
|
load() {
|
|
16228
|
-
return import("./dist-
|
|
16228
|
+
return import("./dist-Cbkga3s5.js").then((e) => e.css());
|
|
16229
16229
|
}
|
|
16230
16230
|
}),
|
|
16231
16231
|
LanguageDescription.of({
|
|
@@ -16234,7 +16234,7 @@ ${r.join("\n")}`;
|
|
|
16234
16234
|
"go"
|
|
16235
16235
|
],
|
|
16236
16236
|
load() {
|
|
16237
|
-
return import("./dist-
|
|
16237
|
+
return import("./dist-CKVkWFcB.js").then((e) => e.go());
|
|
16238
16238
|
}
|
|
16239
16239
|
}),
|
|
16240
16240
|
LanguageDescription.of({
|
|
@@ -16249,7 +16249,7 @@ ${r.join("\n")}`;
|
|
|
16249
16249
|
"hbs"
|
|
16250
16250
|
],
|
|
16251
16251
|
load() {
|
|
16252
|
-
return import("./dist-
|
|
16252
|
+
return import("./dist-XYBhoeSX.js").then((e) => e.html());
|
|
16253
16253
|
}
|
|
16254
16254
|
}),
|
|
16255
16255
|
LanguageDescription.of({
|
|
@@ -16258,7 +16258,7 @@ ${r.join("\n")}`;
|
|
|
16258
16258
|
"java"
|
|
16259
16259
|
],
|
|
16260
16260
|
load() {
|
|
16261
|
-
return import("./dist-
|
|
16261
|
+
return import("./dist-BHGf2Zey.js").then((e) => e.java());
|
|
16262
16262
|
}
|
|
16263
16263
|
}),
|
|
16264
16264
|
LanguageDescription.of({
|
|
@@ -16274,7 +16274,7 @@ ${r.join("\n")}`;
|
|
|
16274
16274
|
"cjs"
|
|
16275
16275
|
],
|
|
16276
16276
|
load() {
|
|
16277
|
-
return import("./dist-
|
|
16277
|
+
return import("./dist-Y9GfSR6_.js").then((e) => e.javascript());
|
|
16278
16278
|
}
|
|
16279
16279
|
}),
|
|
16280
16280
|
LanguageDescription.of({
|
|
@@ -16285,7 +16285,7 @@ ${r.join("\n")}`;
|
|
|
16285
16285
|
"jinja2"
|
|
16286
16286
|
],
|
|
16287
16287
|
load() {
|
|
16288
|
-
return import("./dist-
|
|
16288
|
+
return import("./dist-Ui51qXMz.js").then((e) => e.jinja());
|
|
16289
16289
|
}
|
|
16290
16290
|
}),
|
|
16291
16291
|
LanguageDescription.of({
|
|
@@ -16298,7 +16298,7 @@ ${r.join("\n")}`;
|
|
|
16298
16298
|
"map"
|
|
16299
16299
|
],
|
|
16300
16300
|
load() {
|
|
16301
|
-
return import("./dist-
|
|
16301
|
+
return import("./dist-CN4RKgNR.js").then((e) => e.json());
|
|
16302
16302
|
}
|
|
16303
16303
|
}),
|
|
16304
16304
|
LanguageDescription.of({
|
|
@@ -16307,7 +16307,7 @@ ${r.join("\n")}`;
|
|
|
16307
16307
|
"jsx"
|
|
16308
16308
|
],
|
|
16309
16309
|
load() {
|
|
16310
|
-
return import("./dist-
|
|
16310
|
+
return import("./dist-Y9GfSR6_.js").then((e) => e.javascript({
|
|
16311
16311
|
jsx: true
|
|
16312
16312
|
}));
|
|
16313
16313
|
}
|
|
@@ -16318,7 +16318,7 @@ ${r.join("\n")}`;
|
|
|
16318
16318
|
"less"
|
|
16319
16319
|
],
|
|
16320
16320
|
load() {
|
|
16321
|
-
return import("./dist-
|
|
16321
|
+
return import("./dist-CVOkf_3P.js").then((e) => e.less());
|
|
16322
16322
|
}
|
|
16323
16323
|
}),
|
|
16324
16324
|
LanguageDescription.of({
|
|
@@ -16327,7 +16327,7 @@ ${r.join("\n")}`;
|
|
|
16327
16327
|
"liquid"
|
|
16328
16328
|
],
|
|
16329
16329
|
load() {
|
|
16330
|
-
return import("./dist-
|
|
16330
|
+
return import("./dist-C9TDg2aq.js").then((e) => e.liquid());
|
|
16331
16331
|
}
|
|
16332
16332
|
}),
|
|
16333
16333
|
LanguageDescription.of({
|
|
@@ -16344,7 +16344,7 @@ ${r.join("\n")}`;
|
|
|
16344
16344
|
"mkd"
|
|
16345
16345
|
],
|
|
16346
16346
|
load() {
|
|
16347
|
-
return import("./dist-
|
|
16347
|
+
return import("./dist-DUg5n_x5.js").then((e) => e.markdown());
|
|
16348
16348
|
}
|
|
16349
16349
|
}),
|
|
16350
16350
|
LanguageDescription.of({
|
|
@@ -16370,7 +16370,7 @@ ${r.join("\n")}`;
|
|
|
16370
16370
|
"phtml"
|
|
16371
16371
|
],
|
|
16372
16372
|
load() {
|
|
16373
|
-
return import("./dist-
|
|
16373
|
+
return import("./dist-D9vawryf.js").then((e) => e.php());
|
|
16374
16374
|
}
|
|
16375
16375
|
}),
|
|
16376
16376
|
LanguageDescription.of({
|
|
@@ -16398,7 +16398,7 @@ ${r.join("\n")}`;
|
|
|
16398
16398
|
],
|
|
16399
16399
|
filename: /^(BUCK|BUILD)$/,
|
|
16400
16400
|
load() {
|
|
16401
|
-
return import("./dist-
|
|
16401
|
+
return import("./dist-C8N7114Z.js").then((e) => e.python());
|
|
16402
16402
|
}
|
|
16403
16403
|
}),
|
|
16404
16404
|
LanguageDescription.of({
|
|
@@ -16407,7 +16407,7 @@ ${r.join("\n")}`;
|
|
|
16407
16407
|
"rs"
|
|
16408
16408
|
],
|
|
16409
16409
|
load() {
|
|
16410
|
-
return import("./dist-
|
|
16410
|
+
return import("./dist-BImOGJZM.js").then((e) => e.rust());
|
|
16411
16411
|
}
|
|
16412
16412
|
}),
|
|
16413
16413
|
LanguageDescription.of({
|
|
@@ -16416,7 +16416,7 @@ ${r.join("\n")}`;
|
|
|
16416
16416
|
"sass"
|
|
16417
16417
|
],
|
|
16418
16418
|
load() {
|
|
16419
|
-
return import("./dist-
|
|
16419
|
+
return import("./dist-DasJgTvL.js").then((e) => e.sass({
|
|
16420
16420
|
indented: true
|
|
16421
16421
|
}));
|
|
16422
16422
|
}
|
|
@@ -16427,7 +16427,7 @@ ${r.join("\n")}`;
|
|
|
16427
16427
|
"scss"
|
|
16428
16428
|
],
|
|
16429
16429
|
load() {
|
|
16430
|
-
return import("./dist-
|
|
16430
|
+
return import("./dist-DasJgTvL.js").then((e) => e.sass());
|
|
16431
16431
|
}
|
|
16432
16432
|
}),
|
|
16433
16433
|
LanguageDescription.of({
|
|
@@ -16451,7 +16451,7 @@ ${r.join("\n")}`;
|
|
|
16451
16451
|
"tsx"
|
|
16452
16452
|
],
|
|
16453
16453
|
load() {
|
|
16454
|
-
return import("./dist-
|
|
16454
|
+
return import("./dist-Y9GfSR6_.js").then((e) => e.javascript({
|
|
16455
16455
|
jsx: true,
|
|
16456
16456
|
typescript: true
|
|
16457
16457
|
}));
|
|
@@ -16468,7 +16468,7 @@ ${r.join("\n")}`;
|
|
|
16468
16468
|
"cts"
|
|
16469
16469
|
],
|
|
16470
16470
|
load() {
|
|
16471
|
-
return import("./dist-
|
|
16471
|
+
return import("./dist-Y9GfSR6_.js").then((e) => e.javascript({
|
|
16472
16472
|
typescript: true
|
|
16473
16473
|
}));
|
|
16474
16474
|
}
|
|
@@ -16480,7 +16480,7 @@ ${r.join("\n")}`;
|
|
|
16480
16480
|
"wast"
|
|
16481
16481
|
],
|
|
16482
16482
|
load() {
|
|
16483
|
-
return import("./dist-
|
|
16483
|
+
return import("./dist-d2msfN-B.js").then((e) => e.wast());
|
|
16484
16484
|
}
|
|
16485
16485
|
}),
|
|
16486
16486
|
LanguageDescription.of({
|
|
@@ -16497,7 +16497,7 @@ ${r.join("\n")}`;
|
|
|
16497
16497
|
"svg"
|
|
16498
16498
|
],
|
|
16499
16499
|
load() {
|
|
16500
|
-
return import("./dist-
|
|
16500
|
+
return import("./dist-uR-o9IVx.js").then((e) => e.xml());
|
|
16501
16501
|
}
|
|
16502
16502
|
}),
|
|
16503
16503
|
LanguageDescription.of({
|
|
@@ -16510,7 +16510,7 @@ ${r.join("\n")}`;
|
|
|
16510
16510
|
"yml"
|
|
16511
16511
|
],
|
|
16512
16512
|
load() {
|
|
16513
|
-
return import("./dist-
|
|
16513
|
+
return import("./dist-BbJfmCHJ.js").then((e) => e.yaml());
|
|
16514
16514
|
}
|
|
16515
16515
|
}),
|
|
16516
16516
|
LanguageDescription.of({
|
|
@@ -17610,13 +17610,13 @@ ${r.join("\n")}`;
|
|
|
17610
17610
|
"vue"
|
|
17611
17611
|
],
|
|
17612
17612
|
load() {
|
|
17613
|
-
return import("./dist-
|
|
17613
|
+
return import("./dist-C0v-nFs_.js").then((e) => e.vue());
|
|
17614
17614
|
}
|
|
17615
17615
|
}),
|
|
17616
17616
|
LanguageDescription.of({
|
|
17617
17617
|
name: "Angular Template",
|
|
17618
17618
|
load() {
|
|
17619
|
-
return import("./dist-
|
|
17619
|
+
return import("./dist-zGOEySUQ.js").then((e) => e.angular());
|
|
17620
17620
|
}
|
|
17621
17621
|
})
|
|
17622
17622
|
], cache$1 = /* @__PURE__ */ new WeakMap(), newline = /(\n|\r\n?|\u2028|\u2029)/g, leadingWhitespace = /^\s*/, nonWhitespace = /\S/, slice = Array.prototype.slice, zero = 48, nine = 57, lowerA = 97, lowerF = 102, upperA = 65, upperF = 70;
|
|
@@ -27193,7 +27193,7 @@ ${n.sqlString}
|
|
|
27193
27193
|
hasConsoleOutput: (o == null ? void 0 : o.consoleOutputs) != null
|
|
27194
27194
|
};
|
|
27195
27195
|
}
|
|
27196
|
-
LazyAnyLanguageCodeMirror = (0, import_react.lazy)(() => import("./any-language-editor-
|
|
27196
|
+
LazyAnyLanguageCodeMirror = (0, import_react.lazy)(() => import("./any-language-editor-BBegsg-m.js"));
|
|
27197
27197
|
var import_compiler_runtime$1 = require_compiler_runtime(), extensions = [
|
|
27198
27198
|
EditorView.lineWrapping
|
|
27199
27199
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marimo-team/islands",
|
|
3
|
-
"version": "0.21.2-
|
|
3
|
+
"version": "0.21.2-dev79",
|
|
4
4
|
"main": "dist/main.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"@tailwindcss/postcss": "^4.1.18",
|
|
97
97
|
"@tailwindcss/typography": "^0.5.19",
|
|
98
98
|
"@tanstack/react-table": "^8.21.3",
|
|
99
|
+
"@tanstack/react-virtual": "^3.13.23",
|
|
99
100
|
"@textea/json-viewer": "^4.0.1",
|
|
100
101
|
"@types/humanize-duration": "^3.27.4",
|
|
101
102
|
"@types/js-cookie": "^3.0.6",
|
package/src/__tests__/setup.ts
CHANGED
|
@@ -5,6 +5,21 @@ import { afterEach, beforeEach, vi } from "vitest";
|
|
|
5
5
|
import "@testing-library/jest-dom/vitest";
|
|
6
6
|
import "blob-polyfill";
|
|
7
7
|
|
|
8
|
+
// mock implementation because jsdom doesn't support ResizeObserver
|
|
9
|
+
// if we need to test ResizeObserver functionality
|
|
10
|
+
// we can use a library like "resize-observer-polyfill"
|
|
11
|
+
globalThis.ResizeObserver ??= class {
|
|
12
|
+
observe(_target: Element) {
|
|
13
|
+
/* noop */
|
|
14
|
+
}
|
|
15
|
+
unobserve(_target: Element) {
|
|
16
|
+
/* noop */
|
|
17
|
+
}
|
|
18
|
+
disconnect() {
|
|
19
|
+
/* noop */
|
|
20
|
+
}
|
|
21
|
+
} as never;
|
|
22
|
+
|
|
8
23
|
// Global setup for all tests
|
|
9
24
|
beforeEach(() => {
|
|
10
25
|
// Reset all mocks before each test
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
SearchIcon,
|
|
10
10
|
} from "lucide-react";
|
|
11
11
|
import React from "react";
|
|
12
|
+
import { useLocale } from "react-aria";
|
|
12
13
|
import type { GetRowIds } from "@/plugins/impl/DataTablePlugin";
|
|
13
14
|
import { cn } from "@/utils/cn";
|
|
14
15
|
import type { PanelType } from "../editor/chrome/panels/context-aware-panel/context-aware-panel";
|
|
@@ -16,7 +17,7 @@ import { Button } from "../ui/button";
|
|
|
16
17
|
import { Tooltip } from "../ui/tooltip";
|
|
17
18
|
import { toast } from "../ui/use-toast";
|
|
18
19
|
import { type DownloadActionProps, DownloadAs } from "./download-actions";
|
|
19
|
-
import { DataTablePagination } from "./pagination";
|
|
20
|
+
import { DataTablePagination, prettifyRowColumnCount } from "./pagination";
|
|
20
21
|
import type { DataTableSelection } from "./types";
|
|
21
22
|
|
|
22
23
|
interface TableActionsProps<TData> {
|
|
@@ -64,6 +65,7 @@ export const TableActions = <TData,>({
|
|
|
64
65
|
isPanelOpen,
|
|
65
66
|
tableLoading,
|
|
66
67
|
}: TableActionsProps<TData>) => {
|
|
68
|
+
const { locale } = useLocale();
|
|
67
69
|
const handleSelectAllRows = (value: boolean) => {
|
|
68
70
|
if (!onRowSelectionChange) {
|
|
69
71
|
return;
|
|
@@ -173,7 +175,7 @@ export const TableActions = <TData,>({
|
|
|
173
175
|
</>
|
|
174
176
|
)}
|
|
175
177
|
|
|
176
|
-
{pagination
|
|
178
|
+
{pagination ? (
|
|
177
179
|
<DataTablePagination
|
|
178
180
|
totalColumns={totalColumns}
|
|
179
181
|
selection={selection}
|
|
@@ -182,6 +184,10 @@ export const TableActions = <TData,>({
|
|
|
182
184
|
tableLoading={tableLoading}
|
|
183
185
|
showPageSizeSelector={showPageSizeSelector}
|
|
184
186
|
/>
|
|
187
|
+
) : (
|
|
188
|
+
<span className="text-xs text-muted-foreground px-2">
|
|
189
|
+
{prettifyRowColumnCount(table.getRowCount(), totalColumns, locale)}
|
|
190
|
+
</span>
|
|
185
191
|
)}
|
|
186
192
|
<div className="ml-auto">
|
|
187
193
|
{downloadAs && (
|
|
@@ -101,6 +101,69 @@ describe("DataTable", () => {
|
|
|
101
101
|
expect(rows[2]).toHaveAttribute("title", "Jim Halpert");
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
+
it("does not virtualize small datasets without pagination", () => {
|
|
105
|
+
const testData = Array.from({ length: 50 }, (_, i) => ({
|
|
106
|
+
id: i,
|
|
107
|
+
name: `Item ${i}`,
|
|
108
|
+
}));
|
|
109
|
+
|
|
110
|
+
const columns: ColumnDef<TestData>[] = [
|
|
111
|
+
{ accessorKey: "id", header: "ID" },
|
|
112
|
+
{ accessorKey: "name", header: "Name" },
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
render(
|
|
116
|
+
<TooltipProvider>
|
|
117
|
+
<DataTable
|
|
118
|
+
data={testData}
|
|
119
|
+
columns={columns}
|
|
120
|
+
selection={null}
|
|
121
|
+
totalRows={50}
|
|
122
|
+
totalColumns={2}
|
|
123
|
+
pagination={false}
|
|
124
|
+
/>
|
|
125
|
+
</TooltipProvider>,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// All 50 data rows + 1 header row should be in the DOM (no virtualization)
|
|
129
|
+
const rows = screen.getAllByRole("row");
|
|
130
|
+
expect(rows).toHaveLength(51);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("virtualizes large datasets — renders fewer rows than the full dataset", () => {
|
|
134
|
+
const testData = Array.from({ length: 200 }, (_, i) => ({
|
|
135
|
+
id: i,
|
|
136
|
+
name: `Item ${i}`,
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
const columns: ColumnDef<TestData>[] = [
|
|
140
|
+
{ accessorKey: "id", header: "ID" },
|
|
141
|
+
{ accessorKey: "name", header: "Name" },
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
render(
|
|
145
|
+
<TooltipProvider>
|
|
146
|
+
<DataTable
|
|
147
|
+
data={testData}
|
|
148
|
+
columns={columns}
|
|
149
|
+
selection={null}
|
|
150
|
+
totalRows={200}
|
|
151
|
+
totalColumns={2}
|
|
152
|
+
pagination={false}
|
|
153
|
+
/>
|
|
154
|
+
</TooltipProvider>,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// In jsdom the virtualizer sees a 0-height container and renders 0 data
|
|
158
|
+
// rows (no layout engine). The key assertion is that significantly fewer
|
|
159
|
+
// than 200 rows are in the DOM, which catches regressions where
|
|
160
|
+
// virtualization is accidentally disabled and all rows are rendered.
|
|
161
|
+
const rows = screen.getAllByRole("row");
|
|
162
|
+
// Subtract 1 for the header row
|
|
163
|
+
const dataRows = rows.length - 1;
|
|
164
|
+
expect(dataRows).toBeLessThan(200);
|
|
165
|
+
});
|
|
166
|
+
|
|
104
167
|
it("should display updated data after rerender with manual sorting and pagination", () => {
|
|
105
168
|
// Simulates the bug from issue #8023:
|
|
106
169
|
// When a user sorts a table, rows that moved from page 2 to page 1
|
|
@@ -38,12 +38,17 @@ import type { DownloadActionProps } from "./download-actions";
|
|
|
38
38
|
import { FilterPills } from "./filter-pills";
|
|
39
39
|
import { FocusRowFeature } from "./focus-row/feature";
|
|
40
40
|
import { useColumnPinning } from "./hooks/use-column-pinning";
|
|
41
|
+
import { useScrollContainerHeight } from "./hooks/use-scroll-container-height";
|
|
41
42
|
import { CellSelectionStats } from "./range-focus/cell-selection-stats";
|
|
42
43
|
import { CellSelectionProvider } from "./range-focus/provider";
|
|
43
44
|
import { DataTableBody, renderTableHeader } from "./renderers";
|
|
44
45
|
import { SearchBar } from "./SearchBar";
|
|
45
46
|
import { TableActions } from "./TableActions";
|
|
46
|
-
import
|
|
47
|
+
import {
|
|
48
|
+
type DataTableSelection,
|
|
49
|
+
MIN_ROWS_TO_VIRTUALIZE,
|
|
50
|
+
type TooManyRows,
|
|
51
|
+
} from "./types";
|
|
47
52
|
import { getStableRowId } from "./utils";
|
|
48
53
|
|
|
49
54
|
interface DataTableProps<TData> extends Partial<DownloadActionProps> {
|
|
@@ -268,36 +273,9 @@ const DataTableInternal = <TData,>({
|
|
|
268
273
|
});
|
|
269
274
|
|
|
270
275
|
const rowViewerPanelOpen = isPanelOpen?.("row-viewer") ?? false;
|
|
276
|
+
const virtualize = !pagination && data.length > MIN_ROWS_TO_VIRTUALIZE;
|
|
271
277
|
|
|
272
|
-
const tableRef =
|
|
273
|
-
|
|
274
|
-
// Why use a ref to set max-height on the wrapper?
|
|
275
|
-
// - position: sticky only works when the sticky element's nearest scrollable
|
|
276
|
-
// ancestor is its immediate container. If max-height/overflow are applied
|
|
277
|
-
// on a grandparent, sticky table headers (th) will not stick.
|
|
278
|
-
// - We keep the scroll wrapper colocated with the base Table component, but
|
|
279
|
-
// derive the scroll boundary from maxHeight here to avoid coupling UI base
|
|
280
|
-
// components to data-table specifics or expanding their API surface.
|
|
281
|
-
// - Setting styles on the table's direct wrapper ensures the header sticks
|
|
282
|
-
// reliably across browsers without changing upstream components.
|
|
283
|
-
React.useEffect(() => {
|
|
284
|
-
if (!tableRef.current) {
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
const wrapper = tableRef.current.parentElement as HTMLDivElement | null;
|
|
288
|
-
if (!wrapper) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
if (maxHeight) {
|
|
292
|
-
wrapper.style.maxHeight = `${maxHeight}px`;
|
|
293
|
-
// Ensure wrapper scrolls
|
|
294
|
-
if (!wrapper.style.overflow) {
|
|
295
|
-
wrapper.style.overflow = "auto";
|
|
296
|
-
}
|
|
297
|
-
} else {
|
|
298
|
-
wrapper.style.removeProperty("max-height");
|
|
299
|
-
}
|
|
300
|
-
}, [maxHeight]);
|
|
278
|
+
const tableRef = useScrollContainerHeight({ maxHeight, virtualize });
|
|
301
279
|
|
|
302
280
|
return (
|
|
303
281
|
<div className={cn(wrapperClassName, "flex flex-col space-y-1")}>
|
|
@@ -317,13 +295,14 @@ const DataTableInternal = <TData,>({
|
|
|
317
295
|
{showLoadingBar && (
|
|
318
296
|
<thead className="absolute top-0 left-0 h-[3px] w-1/2 bg-primary animate-slide" />
|
|
319
297
|
)}
|
|
320
|
-
{renderTableHeader(table, Boolean(maxHeight))}
|
|
298
|
+
{renderTableHeader(table, virtualize || Boolean(maxHeight))}
|
|
321
299
|
<DataTableBody
|
|
322
300
|
table={table}
|
|
323
301
|
columns={columns}
|
|
324
302
|
rowViewerPanelOpen={rowViewerPanelOpen}
|
|
325
303
|
getRowIndex={getPaginatedRowIndex}
|
|
326
304
|
viewedRowIdx={viewedRowIdx}
|
|
305
|
+
virtualize={virtualize}
|
|
327
306
|
/>
|
|
328
307
|
</Table>
|
|
329
308
|
</div>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { useEffect, useLayoutEffect, useRef } from "react";
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_VIRTUAL_ROWS,
|
|
6
|
+
TABLE_HEADER_HEIGHT_PX,
|
|
7
|
+
TABLE_ROW_HEIGHT_PX,
|
|
8
|
+
} from "../types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages the scroll container's max-height for the data table.
|
|
12
|
+
*
|
|
13
|
+
* Why set max-height on the table's direct wrapper via a ref?
|
|
14
|
+
* - `position: sticky` only works when the sticky element's nearest scrollable
|
|
15
|
+
* ancestor is its immediate container. If max-height/overflow are applied on
|
|
16
|
+
* a grandparent, sticky `<th>` elements will not stick.
|
|
17
|
+
* - The <Table> UI component wraps <table> in a div with overflow-auto. We
|
|
18
|
+
* derive the scroll boundary from this wrapper (tableRef.parentElement) to
|
|
19
|
+
* keep sticky headers working without coupling base UI components to
|
|
20
|
+
* data-table specifics or expanding their API surface.
|
|
21
|
+
*
|
|
22
|
+
* 3 scenarios:
|
|
23
|
+
* - maxHeight applied directly. This always takes preference
|
|
24
|
+
* - Virtualize without maxHeight: observed via ResizeObserver on <thead>
|
|
25
|
+
* so the container reacts to header size changes (charts loading, toggles).
|
|
26
|
+
* - No maxHeight and no virtualization: render everything
|
|
27
|
+
* in practice virtualization kicks in after 100 rows with pagination disabled
|
|
28
|
+
*/
|
|
29
|
+
export function useScrollContainerHeight({
|
|
30
|
+
maxHeight,
|
|
31
|
+
virtualize,
|
|
32
|
+
}: {
|
|
33
|
+
maxHeight?: number;
|
|
34
|
+
virtualize: boolean;
|
|
35
|
+
}) {
|
|
36
|
+
const tableRef = useRef<HTMLTableElement | null>(null);
|
|
37
|
+
|
|
38
|
+
// Handle explicit maxHeight and non-virtualize cases synchronously
|
|
39
|
+
// before paint to avoid flickering.
|
|
40
|
+
useLayoutEffect(() => {
|
|
41
|
+
if (!tableRef.current) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const wrapper = tableRef.current.parentElement as HTMLDivElement | null;
|
|
45
|
+
if (!wrapper) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (maxHeight) {
|
|
49
|
+
wrapper.style.maxHeight = `${maxHeight}px`;
|
|
50
|
+
if (!wrapper.style.overflow) {
|
|
51
|
+
wrapper.style.overflow = "auto";
|
|
52
|
+
}
|
|
53
|
+
} else if (!virtualize) {
|
|
54
|
+
wrapper.style.removeProperty("max-height");
|
|
55
|
+
}
|
|
56
|
+
// When virtualizing without an explicit maxHeight, the ResizeObserver
|
|
57
|
+
// below handles setting maxHeight reactively based on actual header size.
|
|
58
|
+
}, [maxHeight, virtualize]);
|
|
59
|
+
|
|
60
|
+
// When virtualizing without an explicit maxHeight, observe the <thead> for
|
|
61
|
+
// size changes (column summaries, charts loading async, header toggle) and
|
|
62
|
+
// recompute the scroll container height accordingly.
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (!virtualize || maxHeight) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const table = tableRef.current;
|
|
68
|
+
if (!table) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const wrapper = table.parentElement as HTMLDivElement | null;
|
|
72
|
+
const thead = table.querySelector("thead");
|
|
73
|
+
if (!wrapper || !thead) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const updateMaxHeight = () => {
|
|
77
|
+
const headerHeight =
|
|
78
|
+
thead.getBoundingClientRect().height || TABLE_HEADER_HEIGHT_PX;
|
|
79
|
+
// Skip virtual spacer rows — they have arbitrary heights for scroll offset.
|
|
80
|
+
const firstDataRow = table.querySelector(
|
|
81
|
+
"tbody tr:not([data-virtual-spacer])",
|
|
82
|
+
);
|
|
83
|
+
const rowHeight =
|
|
84
|
+
firstDataRow?.getBoundingClientRect().height || TABLE_ROW_HEIGHT_PX;
|
|
85
|
+
wrapper.style.maxHeight = `${DEFAULT_VIRTUAL_ROWS * rowHeight + headerHeight}px`;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Set initial height
|
|
89
|
+
updateMaxHeight();
|
|
90
|
+
|
|
91
|
+
const observer = new ResizeObserver(updateMaxHeight);
|
|
92
|
+
observer.observe(thead);
|
|
93
|
+
return () => observer.disconnect();
|
|
94
|
+
}, [virtualize, maxHeight]);
|
|
95
|
+
|
|
96
|
+
return tableRef;
|
|
97
|
+
}
|