@marimo-team/frontend 0.19.3-dev4 → 0.19.3-dev42
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/assets/{CellStatus-Ba6Af_Tb.js → CellStatus-b7Yo2X9j.js} +1 -1
- package/dist/assets/{ConnectedDataExplorerComponent-KlUs_Sz3.js → ConnectedDataExplorerComponent-Cr6-n9Em.js} +1 -1
- package/dist/assets/{ErrorBoundary-Drf1manw.js → ErrorBoundary-C7JBxSzd.js} +1 -1
- package/dist/assets/{ImperativeModal-q6QlC2aZ.js → ImperativeModal-DVhvP4lH.js} +1 -1
- package/dist/assets/{JsonOutput-4ruRfyOj.js → JsonOutput-C8Eo1zBR.js} +5 -5
- package/dist/assets/{LazyAnyLanguageCodeMirror-jpEDlD0M.js → LazyAnyLanguageCodeMirror-Cp2punaU.js} +2 -2
- package/dist/assets/{MarimoErrorOutput-DnjH3pD8.js → MarimoErrorOutput-CXBGzjO2.js} +2 -2
- package/dist/assets/{RenderHTML-DaJXe2U2.js → RenderHTML-SoetmcW2.js} +1 -1
- package/dist/assets/VisuallyHidden-B9t3FhTP.js +1 -0
- package/dist/assets/{add-cell-with-ai-Bsds_6SU.js → add-cell-with-ai-D2qS3Nos.js} +21 -21
- package/dist/assets/{add-database-form-CqIp3_WN.js → add-database-form-BBkiGMZ_.js} +2 -2
- package/dist/assets/agent-panel-BzV4XUTo.js +287 -0
- package/dist/assets/{ai-model-dropdown-LK8Wr5iu.js → ai-model-dropdown-CrMTCgo7.js} +1 -1
- package/dist/assets/{alert-dialog-k5KxevGr.js → alert-dialog-jcHA5geR.js} +1 -1
- package/dist/assets/{any-language-editor-DQu1Tt2N.js → any-language-editor-Cm83E7D_.js} +1 -1
- package/dist/assets/{app-config-button-BaVc4Y5z.js → app-config-button-9izWmQ0X.js} +1 -1
- package/dist/assets/button-B8cGZzP5.js +1 -0
- package/dist/assets/{cache-panel-C1So4Zu3.js → cache-panel-1FqnpB9y.js} +1 -1
- package/dist/assets/cell-editor-Do6lWWk9.js +23 -0
- package/dist/assets/cell-link-BP7_Ns0N.js +1 -0
- package/dist/assets/{cells-KYKWFk6C.js → cells-Cv9PtwL9.js} +49 -49
- package/dist/assets/{chat-components-O6DUIpBx.js → chat-components-Be6BPrbT.js} +1 -1
- package/dist/assets/{chat-display-DD3KokYi.js → chat-display-BRKfnhbm.js} +1 -1
- package/dist/assets/{chat-panel-D4DIcOM1.js → chat-panel-71zcilvi.js} +2 -2
- package/dist/assets/client-CGOlSEYr.js +4 -0
- package/dist/assets/{column-preview-EpCGr4Xp.js → column-preview-MC6VOHbd.js} +1 -1
- package/dist/assets/{command-Dqe0kvHp.js → command-n_oMaKjl.js} +1 -1
- package/dist/assets/{command-palette-DWacsFDk.js → command-palette-DfZNcw7W.js} +1 -1
- package/dist/assets/common-MUZIZluQ.js +1 -0
- package/dist/assets/config-DFDEcYvy.js +1 -0
- package/dist/assets/context-DHfVoQfl.js +1 -0
- package/dist/assets/{copy-icon-B69c-352.js → copy-icon-jWsqdLn1.js} +1 -1
- package/dist/assets/{datasource-JeWYnuIr.js → datasource-CEsMStKs.js} +2 -2
- package/dist/assets/{dependency-graph-panel-BJibnwCO.js → dependency-graph-panel-CNTGbfLZ.js} +4 -4
- package/dist/assets/{dialog-DUEuLcT2.js → dialog-CF5DtF1E.js} +1 -1
- package/dist/assets/{dist-DOFFh6Ii.js → dist-Dg7UO_Vw.js} +1 -1
- package/dist/assets/{documentation-panel-B2W3q2YB.js → documentation-panel-Cb9AHO2C.js} +1 -1
- package/dist/assets/{download-NfnO_JCs.js → download-24bI2vH0.js} +1 -1
- package/dist/assets/edit-page-DSuXLdcn.js +12 -0
- package/dist/assets/{error-banner-DU5Qb8a8.js → error-banner-DvT0IGDZ.js} +1 -1
- package/dist/assets/{error-panel-Bv-7GYgJ.js → error-panel-CpYH0GfR.js} +1 -1
- package/dist/assets/{es-KtEicG7U.js → es-BITbuY9w.js} +1 -1
- package/dist/assets/{field-DDKGFzpC.js → field-Clr_fqUr.js} +1 -1
- package/dist/assets/{file-explorer-panel-CToUezud.js → file-explorer-panel-CdA81LHh.js} +1 -1
- package/dist/assets/{floating-outline-Db40vhG8.js → floating-outline-BbJ4ldyu.js} +1 -1
- package/dist/assets/{focus-BCdX47jS.js → focus-D1y1tXyC.js} +1 -1
- package/dist/assets/{form-DwtJQd_Z.js → form-BAtvsPJL.js} +2 -2
- package/dist/assets/{glide-data-editor-D_bRnWfy.js → glide-data-editor-Dv8ZW9dk.js} +1 -1
- package/dist/assets/{globals-MS86g8oR.js → globals-C6OH39EA.js} +1 -1
- package/dist/assets/{home-page-BfVf41OG.js → home-page-B_YprqxM.js} +2 -2
- package/dist/assets/house-CncUa_LL.js +1 -0
- package/dist/assets/index-C30GhE0W.css +2 -0
- package/dist/assets/index-DoE3JZXY.js +43 -0
- package/dist/assets/input-B80Yt1uu.js +1 -0
- package/dist/assets/{kiosk-mode-CEhvsEr0.js → kiosk-mode-DfyjlR7p.js} +1 -1
- package/dist/assets/{label-qwandMoh.js → label-CNZLffHW.js} +1 -1
- package/dist/assets/{layout-Cvaok8Kj.js → layout-9uQoV-6h.js} +4 -4
- package/dist/assets/links-DbDrjRnm.js +1 -0
- package/dist/assets/{logs-panel-J2FKnKaj.js → logs-panel-svcirwjp.js} +1 -1
- package/dist/assets/{markdown-renderer-BlG9DgUG.js → markdown-renderer-DlVqlHOL.js} +2 -2
- package/dist/assets/mode-PeuS_Lp-.js +1 -0
- package/dist/assets/{multi-map-fjX9ImVF.js → multi-map-CQd4MZr5.js} +1 -1
- package/dist/assets/name-cell-input-YMoA0SQj.js +1 -0
- package/dist/assets/{outline-panel-Doj3GJrQ.js → outline-panel-RKJ5Mqrt.js} +1 -1
- package/dist/assets/{packages-panel-nqWXQzKf.js → packages-panel-BuiAGEBw.js} +1 -1
- package/dist/assets/panels-BKsZUDjc.js +1 -0
- package/dist/assets/{process-output-DiSW8Nbo.js → process-output-KJWsSvCT.js} +1 -1
- package/dist/assets/{readonly-python-code-CKY5LsMp.js → readonly-python-code-HPlG_YPX.js} +1 -1
- package/dist/assets/run-page-CBDzVDX3.js +1 -0
- package/dist/assets/scratchpad-panel-CarbQVYs.js +1 -0
- package/dist/assets/{secrets-panel-CDWmmmBS.js → secrets-panel-BMY6PPth.js} +1 -1
- package/dist/assets/{select-D0g5GnIs.js → select-D9lTzMzP.js} +1 -1
- package/dist/assets/{session-panel-CGFRSBw9.js → session-panel-Cv14Ehfm.js} +1 -1
- package/dist/assets/{slides-component-MkPkpql1.js → slides-component-Dp0Yv5b0.js} +1 -1
- package/dist/assets/{snippets-panel-ClHeSpc5.js → snippets-panel-OAdQXQ93.js} +1 -1
- package/dist/assets/state-DYG6kYly.js +1 -0
- package/dist/assets/state-xh6GqNrp.js +1 -0
- package/dist/assets/{switch-BmbGJWHc.js → switch-DPeh0R76.js} +1 -1
- package/dist/assets/{terminal-BvgBa6Ri.js → terminal-BbAhzgnR.js} +1 -1
- package/dist/assets/{textarea-WklymBeK.js → textarea-wbzgrXvB.js} +1 -1
- package/dist/assets/{tracing-D0WYhZdr.js → tracing-Bh3EJxAS.js} +1 -1
- package/dist/assets/{tracing-panel-CNxN58z7.js → tracing-panel-BzSQ7qvB.js} +2 -2
- package/dist/assets/{types-BrgXpvGt.js → types-B8Qb1FfB.js} +1 -1
- package/dist/assets/{useAddCell-a9qZ0_KE.js → useAddCell-DBGvrN8K.js} +1 -1
- package/dist/assets/{useBoolean-5kuXz69O.js → useBoolean-CyOFPk5r.js} +1 -1
- package/dist/assets/{useCellActionButton-9W_R41MM.js → useCellActionButton-BlS_HKk-.js} +1 -1
- package/dist/assets/{useDateFormatter-CV0QXb5P.js → useDateFormatter-DsANziQR.js} +1 -1
- package/dist/assets/useDeleteCell-BvQIJfpI.js +1 -0
- package/dist/assets/{useDependencyPanelTab-0reaqvvh.js → useDependencyPanelTab-BqEhbPr2.js} +1 -1
- package/dist/assets/useInterval-BGPIviJp.js +1 -0
- package/dist/assets/useNotebookActions-D1Woz3AV.js +1 -0
- package/dist/assets/{useNumberFormatter-D8ks3oPN.js → useNumberFormatter-FoXhpyAb.js} +1 -1
- package/dist/assets/usePress-DTwIUo40.js +7 -0
- package/dist/assets/useRunCells-B9Xr4tcH.js +1 -0
- package/dist/assets/useSplitCell-7xBW3b8-.js +1 -0
- package/dist/assets/utilities.esm-xahhGpny.js +3 -0
- package/dist/assets/{vega-component-DpAAiTdH.js → vega-component-dUiiVmIx.js} +1 -1
- package/dist/assets/{write-secret-modal-CLm48gMe.js → write-secret-modal-hOetwavI.js} +1 -1
- package/dist/index.html +54 -54
- package/package.json +5 -5
- package/src/__mocks__/requests.ts +1 -0
- package/src/__tests__/mount.test.ts +128 -0
- package/src/components/app-config/__tests__/get-dirty-values.test.ts +1 -1
- package/src/components/app-config/user-config-form.tsx +1 -1
- package/src/components/chat/acp/agent-panel.tsx +56 -43
- package/src/components/chat/chat-utils.ts +0 -19
- package/src/components/data-table/column-header.tsx +1 -1
- package/src/components/editor/KernelStartupErrorModal.tsx +101 -0
- package/src/components/editor/actions/name-cell-input.tsx +10 -4
- package/src/components/editor/ai/completion-handlers.tsx +1 -1
- package/src/components/editor/alerts/connecting-alert.tsx +33 -6
- package/src/components/editor/chrome/types.ts +2 -4
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +55 -58
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +150 -96
- package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +27 -0
- package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +6 -0
- package/src/components/utils/lazy-mount.tsx +29 -8
- package/src/core/MarimoApp.tsx +2 -0
- package/src/core/cells/cells.ts +2 -0
- package/src/core/cells/scrollCellIntoView.ts +3 -2
- package/src/core/codemirror/cm.ts +2 -0
- package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +123 -0
- package/src/core/codemirror/lsp/notebook-lsp.ts +44 -4
- package/src/core/codemirror/misc/__tests__/string-braces.test.ts +200 -0
- package/src/core/codemirror/misc/string-braces.ts +37 -0
- package/src/core/errors/state.ts +7 -1
- package/src/core/export/__tests__/hooks.test.ts +504 -0
- package/src/core/export/hooks.ts +93 -4
- package/src/core/islands/bridge.ts +1 -0
- package/src/core/islands/main.ts +2 -0
- package/src/core/kernel/__tests__/handlers.test.ts +2 -2
- package/src/core/kernel/state.ts +1 -0
- package/src/core/network/__tests__/requests-lazy.test.ts +1 -1
- package/src/core/network/__tests__/requests-network.test.ts +0 -18
- package/src/core/network/requests-lazy.ts +3 -2
- package/src/core/network/requests-network.ts +10 -7
- package/src/core/network/requests-static.ts +1 -0
- package/src/core/network/requests-toasting.tsx +1 -0
- package/src/core/network/types.ts +2 -0
- package/src/core/wasm/bridge.ts +1 -0
- package/src/core/websocket/types.ts +1 -0
- package/src/core/websocket/useMarimoKernelConnection.tsx +18 -1
- package/src/css/globals.css +2 -0
- package/src/hooks/__tests__/useInterval.test.tsx +104 -0
- package/src/hooks/useInterval.ts +32 -6
- package/src/mount.tsx +6 -0
- package/src/plugins/impl/chat/chat-ui.tsx +16 -4
- package/src/plugins/impl/chat/types.ts +5 -12
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +3 -1
- package/src/utils/events.ts +1 -0
- package/dist/assets/VisuallyHidden-BodIky8L.js +0 -1
- package/dist/assets/agent-panel-CaAPVPdJ.js +0 -287
- package/dist/assets/button-DuYGqRtX.js +0 -1
- package/dist/assets/cell-editor-OFm-OSAP.js +0 -23
- package/dist/assets/cell-link-CfLJRl3p.js +0 -1
- package/dist/assets/client-Cha_JfGC.js +0 -4
- package/dist/assets/common-A6YWtmpq.js +0 -1
- package/dist/assets/config-babG4OBR.js +0 -1
- package/dist/assets/context-BAYdLMF_.js +0 -1
- package/dist/assets/edit-page-nuU4FVXi.js +0 -12
- package/dist/assets/globe-CY9im410.js +0 -1
- package/dist/assets/index-BI88xbv4.js +0 -43
- package/dist/assets/index-Chgc_07S.css +0 -2
- package/dist/assets/input-CaEtLL8p.js +0 -1
- package/dist/assets/links-ENMiP32L.js +0 -1
- package/dist/assets/mode-CK5Oq-Jz.js +0 -1
- package/dist/assets/name-cell-input-D7axzd6k.js +0 -1
- package/dist/assets/panels-CdYbZBqo.js +0 -1
- package/dist/assets/run-page-GP8eGE39.js +0 -1
- package/dist/assets/scratchpad-panel-B1p8zqAE.js +0 -1
- package/dist/assets/state-BBgXjqJI.js +0 -1
- package/dist/assets/state-CP7_TGWl.js +0 -1
- package/dist/assets/useDeleteCell-5kJUaejE.js +0 -1
- package/dist/assets/useInterval-DpipYmgs.js +0 -1
- package/dist/assets/useNotebookActions-o341ZCMJ.js +0 -1
- package/dist/assets/usePress-C2LPFxyv.js +0 -7
- package/dist/assets/useRunCells-wXhl9zOP.js +0 -1
- package/dist/assets/useSplitCell-mmm5jxn2.js +0 -1
- package/dist/assets/utilities.esm-Ckt5kMF-.js +0 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Copyright
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { NoKernelConnectedError } from "@/utils/errors";
|
|
4
4
|
import { Logger } from "@/utils/Logger";
|
|
@@ -67,6 +67,7 @@ const ACTIONS: Record<keyof AllRequests, Action> = {
|
|
|
67
67
|
autoExportAsHTML: "waitForConnectionOpen",
|
|
68
68
|
autoExportAsMarkdown: "waitForConnectionOpen",
|
|
69
69
|
autoExportAsIPYNB: "waitForConnectionOpen",
|
|
70
|
+
updateCellOutputs: "waitForConnectionOpen",
|
|
70
71
|
|
|
71
72
|
// Sidebar operations that wait for connection
|
|
72
73
|
listSecretKeys: "throwError",
|
|
@@ -152,7 +153,7 @@ export function createLazyRequests(
|
|
|
152
153
|
`Dropping request: ${key}, since not connected to a kernel.`,
|
|
153
154
|
);
|
|
154
155
|
// Silently drop the request
|
|
155
|
-
return
|
|
156
|
+
return;
|
|
156
157
|
|
|
157
158
|
case "throwError":
|
|
158
159
|
throw new NoKernelConnectedError();
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { once } from "lodash-es";
|
|
4
4
|
import { getRuntimeManager } from "../runtime/config";
|
|
5
|
-
import { store } from "../state/jotai";
|
|
6
5
|
import { API, createClientWithRuntimeManager } from "./api";
|
|
7
|
-
import {
|
|
6
|
+
import { waitForConnectionOpen } from "./connection";
|
|
8
7
|
import type { EditRequests, RunRequests } from "./types";
|
|
9
8
|
|
|
10
9
|
const { handleResponse, handleResponseReturnNull } = API;
|
|
@@ -105,11 +104,7 @@ export function createNetworkRequests(): EditRequests & RunRequests {
|
|
|
105
104
|
.then(handleResponseReturnNull);
|
|
106
105
|
},
|
|
107
106
|
sendRun: async (request) => {
|
|
108
|
-
|
|
109
|
-
// Otherwise we can get into a weird state of sending requests for cells that no longer exist.
|
|
110
|
-
if (!store.get(isConnectedAtom)) {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
107
|
+
await waitForConnectionOpen();
|
|
113
108
|
return getClient()
|
|
114
109
|
.POST("/api/kernel/run", {
|
|
115
110
|
body: request,
|
|
@@ -410,6 +405,14 @@ export function createNetworkRequests(): EditRequests & RunRequests {
|
|
|
410
405
|
})
|
|
411
406
|
.then(handleResponseReturnNull);
|
|
412
407
|
},
|
|
408
|
+
updateCellOutputs: async (request) => {
|
|
409
|
+
return getClient()
|
|
410
|
+
.POST("/api/export/update_cell_outputs", {
|
|
411
|
+
body: request,
|
|
412
|
+
params: getParams(),
|
|
413
|
+
})
|
|
414
|
+
.then(handleResponseReturnNull);
|
|
415
|
+
},
|
|
413
416
|
addPackage: (request) => {
|
|
414
417
|
return getClient()
|
|
415
418
|
.POST("/api/packages/add", {
|
|
@@ -79,6 +79,7 @@ export function createStaticRequests(): EditRequests & RunRequests {
|
|
|
79
79
|
autoExportAsHTML: throwNotInEditMode,
|
|
80
80
|
autoExportAsMarkdown: throwNotInEditMode,
|
|
81
81
|
autoExportAsIPYNB: throwNotInEditMode,
|
|
82
|
+
updateCellOutputs: throwNotInEditMode,
|
|
82
83
|
addPackage: throwNotInEditMode,
|
|
83
84
|
removePackage: throwNotInEditMode,
|
|
84
85
|
getPackageList: throwNotInEditMode,
|
|
@@ -64,6 +64,7 @@ export function createErrorToastingRequests(
|
|
|
64
64
|
autoExportAsHTML: "", // No toast
|
|
65
65
|
autoExportAsMarkdown: "", // No toast
|
|
66
66
|
autoExportAsIPYNB: "", // No toast
|
|
67
|
+
updateCellOutputs: "", // No toast
|
|
67
68
|
addPackage: "Failed to add package",
|
|
68
69
|
removePackage: "Failed to remove package",
|
|
69
70
|
getPackageList: "Failed to get package list",
|
|
@@ -21,6 +21,7 @@ export type ExportAsHTMLRequest = schemas["ExportAsHTMLRequest"];
|
|
|
21
21
|
export type ExportAsMarkdownRequest = schemas["ExportAsMarkdownRequest"];
|
|
22
22
|
export type ExportAsIPYNBRequest = schemas["ExportAsIPYNBRequest"];
|
|
23
23
|
export type ExportAsScriptRequest = schemas["ExportAsScriptRequest"];
|
|
24
|
+
export type UpdateCellOutputsRequest = schemas["UpdateCellOutputsRequest"];
|
|
24
25
|
export type FileCreateRequest = schemas["FileCreateRequest"];
|
|
25
26
|
export type FileCreateResponse = schemas["FileCreateResponse"];
|
|
26
27
|
export type FileDeleteRequest = schemas["FileDeleteRequest"];
|
|
@@ -175,6 +176,7 @@ export interface EditRequests {
|
|
|
175
176
|
autoExportAsHTML: (request: ExportAsHTMLRequest) => Promise<null>;
|
|
176
177
|
autoExportAsMarkdown: (request: ExportAsMarkdownRequest) => Promise<null>;
|
|
177
178
|
autoExportAsIPYNB: (request: ExportAsIPYNBRequest) => Promise<null>;
|
|
179
|
+
updateCellOutputs: (request: UpdateCellOutputsRequest) => Promise<null>;
|
|
178
180
|
// Package requests
|
|
179
181
|
getPackageList: () => Promise<ListPackagesResponse>;
|
|
180
182
|
getDependencyTree: () => Promise<DependencyTreeResponse>;
|
package/src/core/wasm/bridge.ts
CHANGED
|
@@ -589,6 +589,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
|
|
|
589
589
|
autoExportAsHTML = throwNotImplemented;
|
|
590
590
|
autoExportAsMarkdown = throwNotImplemented;
|
|
591
591
|
autoExportAsIPYNB = throwNotImplemented;
|
|
592
|
+
updateCellOutputs = throwNotImplemented;
|
|
592
593
|
writeSecret = throwNotImplemented;
|
|
593
594
|
invokeAiTool = throwNotImplemented;
|
|
594
595
|
clearCache = throwNotImplemented;
|
|
@@ -16,6 +16,7 @@ export const WebSocketClosedReason = {
|
|
|
16
16
|
KERNEL_DISCONNECTED: "KERNEL_DISCONNECTED",
|
|
17
17
|
ALREADY_RUNNING: "ALREADY_RUNNING",
|
|
18
18
|
MALFORMED_QUERY: "MALFORMED_QUERY",
|
|
19
|
+
KERNEL_STARTUP_ERROR: "KERNEL_STARTUP_ERROR",
|
|
19
20
|
} as const;
|
|
20
21
|
|
|
21
22
|
export type WebSocketClosedReason =
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
} from "../datasets/request-registry";
|
|
41
41
|
import { useDatasetsActions } from "../datasets/state";
|
|
42
42
|
import { UI_ELEMENT_REGISTRY } from "../dom/uiregistry";
|
|
43
|
-
import { useBannersActions } from "../errors/state";
|
|
43
|
+
import { kernelStartupErrorAtom, useBannersActions } from "../errors/state";
|
|
44
44
|
import { FUNCTIONS_REGISTRY } from "../functions/FunctionRegistry";
|
|
45
45
|
import {
|
|
46
46
|
handleCellNotificationeration,
|
|
@@ -105,6 +105,7 @@ export function useMarimoKernelConnection(opts: {
|
|
|
105
105
|
const setCapabilities = useSetAtom(capabilitiesAtom);
|
|
106
106
|
const runtimeManager = useRuntimeManager();
|
|
107
107
|
const setCacheInfo = useSetAtom(cacheInfoAtom);
|
|
108
|
+
const setKernelStartupError = useSetAtom(kernelStartupErrorAtom);
|
|
108
109
|
|
|
109
110
|
const handleMessage = (e: MessageEvent<JsonString<NotificationPayload>>) => {
|
|
110
111
|
const msg = jsonParseWithSpecialChar(e.data);
|
|
@@ -134,6 +135,11 @@ export function useMarimoKernelConnection(opts: {
|
|
|
134
135
|
case "interrupted":
|
|
135
136
|
return;
|
|
136
137
|
|
|
138
|
+
case "kernel-startup-error":
|
|
139
|
+
// Full error received via message before websocket close
|
|
140
|
+
setKernelStartupError(msg.data.error);
|
|
141
|
+
return;
|
|
142
|
+
|
|
137
143
|
case "send-ui-element-message": {
|
|
138
144
|
const modelId = msg.data.model_id;
|
|
139
145
|
const uiElement = msg.data.ui_element;
|
|
@@ -413,6 +419,17 @@ export function useMarimoKernelConnection(opts: {
|
|
|
413
419
|
return;
|
|
414
420
|
|
|
415
421
|
default:
|
|
422
|
+
// Check for kernel startup error (full error already received via message)
|
|
423
|
+
if (e.reason === "MARIMO_KERNEL_STARTUP_ERROR") {
|
|
424
|
+
setConnection({
|
|
425
|
+
state: WebSocketState.CLOSED,
|
|
426
|
+
code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
|
|
427
|
+
reason: "Failed to start kernel sandbox",
|
|
428
|
+
});
|
|
429
|
+
ws.close(); // prevent reconnecting
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
416
433
|
// Session should be valid
|
|
417
434
|
// - browser tab might have been closed or re-opened
|
|
418
435
|
// - computer might have just woken from sleep
|
package/src/css/globals.css
CHANGED
|
@@ -184,8 +184,10 @@
|
|
|
184
184
|
--shadow-2xl-solid: 10px 12px 0px 0px var(--base-shadow-darker), 0 0px 8px 0px hsl(0deg 0% 90% / 50%);
|
|
185
185
|
|
|
186
186
|
/* Solid shadows with lighter shade color */
|
|
187
|
+
|
|
187
188
|
/* biome-ignore format: definition needs to be oneline or breaks variants */
|
|
188
189
|
--shadow-sm-solid-shade: 2px 2px 0px 0px var(--base-shadow), 0px 0px 2px 0px hsl(0deg 0% 50% / 20%);
|
|
190
|
+
|
|
189
191
|
/* biome-ignore format: definition needs to be oneline or breaks variants */
|
|
190
192
|
--shadow-md-solid-shade: 4px 4px 0px 0px var(--base-shadow), 0 0px 2px 0px hsl(0deg 0% 60% / 50%);
|
|
191
193
|
}
|
|
@@ -67,4 +67,108 @@ describe("useInterval", () => {
|
|
|
67
67
|
vi.advanceTimersByTime(1000);
|
|
68
68
|
expect(callback).not.toHaveBeenCalled();
|
|
69
69
|
});
|
|
70
|
+
|
|
71
|
+
describe("skipIfRunning", () => {
|
|
72
|
+
it("should allow overlapping async calls by default", async () => {
|
|
73
|
+
let concurrentCalls = 0;
|
|
74
|
+
let maxConcurrentCalls = 0;
|
|
75
|
+
|
|
76
|
+
const callback = vi.fn(async () => {
|
|
77
|
+
concurrentCalls++;
|
|
78
|
+
maxConcurrentCalls = Math.max(maxConcurrentCalls, concurrentCalls);
|
|
79
|
+
// Simulate slow async work
|
|
80
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
81
|
+
concurrentCalls--;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
renderHook(() =>
|
|
85
|
+
useInterval(callback, { delayMs: 500, whenVisible: false }),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// First call at 500ms
|
|
89
|
+
vi.advanceTimersByTime(500);
|
|
90
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
91
|
+
|
|
92
|
+
// Second call at 1000ms (while first is still running)
|
|
93
|
+
vi.advanceTimersByTime(500);
|
|
94
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
95
|
+
|
|
96
|
+
// Third call at 1500ms
|
|
97
|
+
vi.advanceTimersByTime(500);
|
|
98
|
+
expect(callback).toHaveBeenCalledTimes(3);
|
|
99
|
+
|
|
100
|
+
// Multiple concurrent calls should have occurred
|
|
101
|
+
expect(maxConcurrentCalls).toBeGreaterThan(1);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should skip calls when skipIfRunning is true", async () => {
|
|
105
|
+
let concurrentCalls = 0;
|
|
106
|
+
let maxConcurrentCalls = 0;
|
|
107
|
+
|
|
108
|
+
const callback = vi.fn(async () => {
|
|
109
|
+
concurrentCalls++;
|
|
110
|
+
maxConcurrentCalls = Math.max(maxConcurrentCalls, concurrentCalls);
|
|
111
|
+
// Simulate slow async work (3 seconds)
|
|
112
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 3000));
|
|
113
|
+
concurrentCalls--;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
renderHook(() =>
|
|
117
|
+
useInterval(callback, {
|
|
118
|
+
delayMs: 500,
|
|
119
|
+
whenVisible: false,
|
|
120
|
+
skipIfRunning: true,
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// First call at 500ms
|
|
125
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
126
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
127
|
+
|
|
128
|
+
// Second interval tick at 1000ms - should be skipped since first is still running
|
|
129
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
130
|
+
expect(callback).toHaveBeenCalledTimes(1); // Still 1, not 2
|
|
131
|
+
|
|
132
|
+
// Third interval tick at 1500ms - should still be skipped
|
|
133
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
134
|
+
expect(callback).toHaveBeenCalledTimes(1); // Still 1
|
|
135
|
+
|
|
136
|
+
// Only one concurrent call should have occurred
|
|
137
|
+
expect(maxConcurrentCalls).toBe(1);
|
|
138
|
+
|
|
139
|
+
// Advance past the 3 second timeout to complete first callback
|
|
140
|
+
await vi.advanceTimersByTimeAsync(2000);
|
|
141
|
+
|
|
142
|
+
// Next interval tick should now be able to run
|
|
143
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
144
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should allow next call after previous async call completes with skipIfRunning true", async () => {
|
|
148
|
+
const callback = vi.fn(async () => {
|
|
149
|
+
// Quick async operation
|
|
150
|
+
await Promise.resolve();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
renderHook(() =>
|
|
154
|
+
useInterval(callback, {
|
|
155
|
+
delayMs: 1000,
|
|
156
|
+
whenVisible: false,
|
|
157
|
+
skipIfRunning: true,
|
|
158
|
+
}),
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// First call
|
|
162
|
+
await vi.advanceTimersByTimeAsync(1000);
|
|
163
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
164
|
+
|
|
165
|
+
// Second call - should proceed since first completed
|
|
166
|
+
await vi.advanceTimersByTimeAsync(1000);
|
|
167
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
168
|
+
|
|
169
|
+
// Third call
|
|
170
|
+
await vi.advanceTimersByTimeAsync(1000);
|
|
171
|
+
expect(callback).toHaveBeenCalledTimes(3);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
70
174
|
});
|
package/src/hooks/useInterval.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
3
3
|
import { useEventListener } from "./useEventListener";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates an interval that runs a callback every `delayMs` milliseconds.
|
|
7
|
+
*
|
|
8
|
+
* @param callback - The callback to run.
|
|
9
|
+
* @param opts - The options for the interval.
|
|
10
|
+
* @param opts.delayMs - The delay in milliseconds between runs.
|
|
11
|
+
* @param opts.whenVisible - Whether to run the callback when the document is visible.
|
|
12
|
+
* @param opts.disabled - Whether to disable the interval.
|
|
13
|
+
* @param opts.skipIfRunning - Whether to skip the callback if it is already running.
|
|
7
14
|
*/
|
|
8
15
|
export function useInterval(
|
|
9
16
|
callback: () => void,
|
|
@@ -11,16 +18,35 @@ export function useInterval(
|
|
|
11
18
|
delayMs: number | null;
|
|
12
19
|
whenVisible: boolean;
|
|
13
20
|
disabled?: boolean;
|
|
21
|
+
skipIfRunning?: boolean;
|
|
14
22
|
},
|
|
15
23
|
) {
|
|
16
|
-
const {
|
|
17
|
-
|
|
24
|
+
const {
|
|
25
|
+
delayMs,
|
|
26
|
+
whenVisible,
|
|
27
|
+
disabled = false,
|
|
28
|
+
skipIfRunning = false,
|
|
29
|
+
} = opts;
|
|
30
|
+
const savedCallback = useRef<() => void | Promise<void>>(undefined);
|
|
31
|
+
const isRunning = useRef(false);
|
|
18
32
|
|
|
19
33
|
// Store the callback
|
|
20
34
|
useEffect(() => {
|
|
21
35
|
savedCallback.current = callback;
|
|
22
36
|
}, [callback]);
|
|
23
37
|
|
|
38
|
+
const runCallback = useCallback(async () => {
|
|
39
|
+
if (isRunning.current && skipIfRunning) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
isRunning.current = true;
|
|
43
|
+
try {
|
|
44
|
+
await savedCallback.current?.();
|
|
45
|
+
} finally {
|
|
46
|
+
isRunning.current = false;
|
|
47
|
+
}
|
|
48
|
+
}, [skipIfRunning]);
|
|
49
|
+
|
|
24
50
|
// Run the interval
|
|
25
51
|
useEffect(() => {
|
|
26
52
|
if (delayMs === null || disabled) {
|
|
@@ -32,16 +58,16 @@ export function useInterval(
|
|
|
32
58
|
return;
|
|
33
59
|
}
|
|
34
60
|
|
|
35
|
-
|
|
61
|
+
runCallback();
|
|
36
62
|
}, delayMs);
|
|
37
63
|
|
|
38
64
|
return () => clearInterval(id);
|
|
39
|
-
}, [delayMs, whenVisible, disabled]);
|
|
65
|
+
}, [delayMs, whenVisible, disabled, runCallback]);
|
|
40
66
|
|
|
41
67
|
// When the document becomes visible, run the callback
|
|
42
68
|
useEventListener(document, "visibilitychange", () => {
|
|
43
69
|
if (document.visibilityState === "visible" && whenVisible && !disabled) {
|
|
44
|
-
|
|
70
|
+
runCallback();
|
|
45
71
|
}
|
|
46
72
|
});
|
|
47
73
|
|
package/src/mount.tsx
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
import { MarimoApp, preloadPage } from "./core/MarimoApp";
|
|
30
30
|
import { type AppMode, initialModeAtom, viewStateAtom } from "./core/mode";
|
|
31
31
|
import { cleanupAuthQueryParams } from "./core/network/auth";
|
|
32
|
+
import { connectionAtom } from "./core/network/connection";
|
|
32
33
|
import { requestClientAtom } from "./core/network/requests";
|
|
33
34
|
import { resolveRequestClient } from "./core/network/resolve";
|
|
34
35
|
import {
|
|
@@ -42,6 +43,7 @@ import { isStaticNotebook } from "./core/static/static-state";
|
|
|
42
43
|
import { maybeRegisterVSCodeBindings } from "./core/vscode/vscode-bindings";
|
|
43
44
|
import type { FileStore } from "./core/wasm/store";
|
|
44
45
|
import { notebookFileStore } from "./core/wasm/store";
|
|
46
|
+
import { WebSocketState } from "./core/websocket/types";
|
|
45
47
|
import { vegaLoader } from "./plugins/impl/vega/loader";
|
|
46
48
|
import { initializePlugins } from "./plugins/plugins";
|
|
47
49
|
import { ThemeProvider } from "./theme/ThemeProvider";
|
|
@@ -304,6 +306,10 @@ function initStore(options: unknown) {
|
|
|
304
306
|
...firstRuntimeConfig,
|
|
305
307
|
serverToken: parsedOptions.data.serverToken,
|
|
306
308
|
});
|
|
309
|
+
// If the remote runtime is not lazy, start it in CONNECTING
|
|
310
|
+
if (!firstRuntimeConfig.lazy && !isStaticNotebook()) {
|
|
311
|
+
store.set(connectionAtom, { state: WebSocketState.CONNECTING });
|
|
312
|
+
}
|
|
307
313
|
} else {
|
|
308
314
|
store.set(runtimeConfigAtom, {
|
|
309
315
|
...DEFAULT_RUNTIME_CONFIG,
|
|
@@ -75,12 +75,26 @@ interface Props extends PluginFunctions {
|
|
|
75
75
|
export const Chatbot: React.FC<Props> = (props) => {
|
|
76
76
|
const [input, setInput] = useState("");
|
|
77
77
|
const [config, setConfig] = useState<ChatConfig>(props.config);
|
|
78
|
+
const [prevPropsConfig, setPrevPropsConfig] = useState<ChatConfig>(
|
|
79
|
+
props.config,
|
|
80
|
+
);
|
|
78
81
|
const [files, setFiles] = useState<File[] | undefined>(undefined);
|
|
79
82
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
80
83
|
const formRef = useRef<HTMLFormElement>(null);
|
|
81
84
|
const codeMirrorInputRef = useRef<ReactCodeMirrorRef>(null);
|
|
82
85
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
83
86
|
|
|
87
|
+
const configChanged = Object.keys(props.config).some(
|
|
88
|
+
(key) =>
|
|
89
|
+
props.config[key as keyof ChatConfig] !==
|
|
90
|
+
prevPropsConfig[key as keyof ChatConfig],
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (configChanged) {
|
|
94
|
+
setConfig(props.config);
|
|
95
|
+
setPrevPropsConfig(props.config);
|
|
96
|
+
}
|
|
97
|
+
|
|
84
98
|
// Use a ref to avoid stale closure in the fetch callback
|
|
85
99
|
const configRef = useRef<ChatConfig>(config);
|
|
86
100
|
configRef.current = config;
|
|
@@ -739,7 +753,6 @@ const ConfigPopup: React.FC<{
|
|
|
739
753
|
config: ChatConfig;
|
|
740
754
|
onChange: (newConfig: ChatConfig) => void;
|
|
741
755
|
}> = ({ config, onChange }) => {
|
|
742
|
-
const [localConfig, setLocalConfig] = useState<ChatConfig>(config);
|
|
743
756
|
const [open, setOpen] = useState(false);
|
|
744
757
|
|
|
745
758
|
const handleChange = (key: keyof ChatConfig, value: number | null) => {
|
|
@@ -754,8 +767,7 @@ const ConfigPopup: React.FC<{
|
|
|
754
767
|
finalValue = clampedValue;
|
|
755
768
|
}
|
|
756
769
|
|
|
757
|
-
const newConfig = { ...
|
|
758
|
-
setLocalConfig(newConfig);
|
|
770
|
+
const newConfig = { ...config, [key]: finalValue };
|
|
759
771
|
onChange(newConfig);
|
|
760
772
|
};
|
|
761
773
|
|
|
@@ -782,7 +794,7 @@ const ConfigPopup: React.FC<{
|
|
|
782
794
|
<PopoverContent className="w-70 border">
|
|
783
795
|
<div className="grid gap-3">
|
|
784
796
|
<h4 className="font-bold leading-none">Configuration</h4>
|
|
785
|
-
{Objects.entries(
|
|
797
|
+
{Objects.entries(config).map(([key, value]) => (
|
|
786
798
|
<div key={key} className="grid grid-cols-3 items-center gap-1">
|
|
787
799
|
<Label
|
|
788
800
|
htmlFor={key}
|
|
@@ -8,18 +8,6 @@ export interface ChatMessage extends UIMessage {
|
|
|
8
8
|
content: string | null; // Content is only added for backwards compatibility
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export interface SendMessageRequest {
|
|
12
|
-
messages: ChatMessage[];
|
|
13
|
-
config: {
|
|
14
|
-
max_tokens: number | null;
|
|
15
|
-
temperature: number | null;
|
|
16
|
-
top_p: number | null;
|
|
17
|
-
top_k: number | null;
|
|
18
|
-
frequency_penalty: number | null;
|
|
19
|
-
presence_penalty: number | null;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
11
|
/**
|
|
24
12
|
* These are snake_case because they come from the backend,
|
|
25
13
|
* and are not modified when sent to the frontend.
|
|
@@ -32,3 +20,8 @@ export interface ChatConfig {
|
|
|
32
20
|
frequency_penalty: number | null;
|
|
33
21
|
presence_penalty: number | null;
|
|
34
22
|
}
|
|
23
|
+
|
|
24
|
+
export interface SendMessageRequest {
|
|
25
|
+
messages: ChatMessage[];
|
|
26
|
+
config: ChatConfig;
|
|
27
|
+
}
|
|
@@ -202,6 +202,8 @@ export const DataFrameComponent = memo(
|
|
|
202
202
|
sql_code,
|
|
203
203
|
} = data || {};
|
|
204
204
|
|
|
205
|
+
const totalColumns = field_types?.length;
|
|
206
|
+
|
|
205
207
|
const [internalValue, setInternalValue] = useState<Transformations>(
|
|
206
208
|
value || EMPTY,
|
|
207
209
|
);
|
|
@@ -317,7 +319,7 @@ export const DataFrameComponent = memo(
|
|
|
317
319
|
data={url || ""}
|
|
318
320
|
hasStableRowId={false}
|
|
319
321
|
totalRows={total_rows ?? 0}
|
|
320
|
-
totalColumns={
|
|
322
|
+
totalColumns={totalColumns ?? 0}
|
|
321
323
|
maxColumns="all"
|
|
322
324
|
pageSize={pageSize}
|
|
323
325
|
pagination={true}
|
package/src/utils/events.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as be}from"./chunk-LvLJmgfZ.js";import{t as me}from"./react-BGmjiNul.js";import{L as ve,P as Ee,R as Te}from"./input-CaEtLL8p.js";import{A as w,C as ge,M as we,N as v,O as Re,b as J,c as Ce,j as S,k as X,l as ye,w as Se,z as R}from"./usePress-C2LPFxyv.js";import{t as ke}from"./context-BAYdLMF_.js";var f=be(me(),1),_e=(0,f.createContext)(null);(0,f.createContext)(null),(0,f.createContext)(null),(0,f.createContext)(null),(0,f.createContext)(null);var Le=(0,f.createContext)({}),xe=(0,f.createContext)(null);(0,f.createContext)(null);var Fe=class{get currentNode(){return this._currentNode}set currentNode(e){if(!X(this.root,e))throw Error("Cannot set currentNode to a node that is not contained by the root node.");let t=[],r=e,n=e;for(this._currentNode=e;r&&r!==this.root;)if(r.nodeType===Node.DOCUMENT_FRAGMENT_NODE){let i=r,l=this._doc.createTreeWalker(i,this.whatToShow,{acceptNode:this._acceptNode});t.push(l),l.currentNode=n,this._currentSetFor.add(l),r=n=i.host}else r=r.parentNode;let o=this._doc.createTreeWalker(this.root,this.whatToShow,{acceptNode:this._acceptNode});t.push(o),o.currentNode=n,this._currentSetFor.add(o),this._walkerStack=t}get doc(){return this._doc}firstChild(){let e=this.currentNode,t=this.nextNode();return X(e,t)?(t&&(this.currentNode=t),t):(this.currentNode=e,null)}lastChild(){let e=this._walkerStack[0].lastChild();return e&&(this.currentNode=e),e}nextNode(){var t;let e=this._walkerStack[0].nextNode();if(e){if(e.shadowRoot){let r;if(typeof this.filter=="function"?r=this.filter(e):(t=this.filter)!=null&&t.acceptNode&&(r=this.filter.acceptNode(e)),r===NodeFilter.FILTER_ACCEPT)return this.currentNode=e,e;let n=this.nextNode();return n&&(this.currentNode=n),n}return e&&(this.currentNode=e),e}else if(this._walkerStack.length>1){this._walkerStack.shift();let r=this.nextNode();return r&&(this.currentNode=r),r}else return null}previousNode(){var r;let e=this._walkerStack[0];if(e.currentNode===e.root){if(this._currentSetFor.has(e))if(this._currentSetFor.delete(e),this._walkerStack.length>1){this._walkerStack.shift();let n=this.previousNode();return n&&(this.currentNode=n),n}else return null;return null}let t=e.previousNode();if(t){if(t.shadowRoot){let n;if(typeof this.filter=="function"?n=this.filter(t):(r=this.filter)!=null&&r.acceptNode&&(n=this.filter.acceptNode(t)),n===NodeFilter.FILTER_ACCEPT)return t&&(this.currentNode=t),t;let o=this.lastChild();return o&&(this.currentNode=o),o}return t&&(this.currentNode=t),t}else if(this._walkerStack.length>1){this._walkerStack.shift();let n=this.previousNode();return n&&(this.currentNode=n),n}else return null}nextSibling(){return null}previousSibling(){return null}parentNode(){return null}constructor(e,t,r,n){this._walkerStack=[],this._currentSetFor=new Set,this._acceptNode=i=>{var l;if(i.nodeType===Node.ELEMENT_NODE){let s=i.shadowRoot;if(s){let u=this._doc.createTreeWalker(s,this.whatToShow,{acceptNode:this._acceptNode});return this._walkerStack.unshift(u),NodeFilter.FILTER_ACCEPT}else{if(typeof this.filter=="function")return this.filter(i);if((l=this.filter)!=null&&l.acceptNode)return this.filter.acceptNode(i);if(this.filter===null)return NodeFilter.FILTER_ACCEPT}}return NodeFilter.FILTER_SKIP},this._doc=e,this.root=t,this.filter=n??null,this.whatToShow=r??NodeFilter.SHOW_ALL,this._currentNode=t,this._walkerStack.unshift(e.createTreeWalker(t,r,this._acceptNode));let o=t.shadowRoot;if(o){let i=this._doc.createTreeWalker(o,this.whatToShow,{acceptNode:this._acceptNode});this._walkerStack.unshift(i)}}};function Me(e,t,r,n){return we()?new Fe(e,t,r,n):e.createTreeWalker(t,r,n)}function Ie(e,t){let r=(0,f.useRef)(!0),n=(0,f.useRef)(null);(0,f.useEffect)(()=>(r.current=!0,()=>{r.current=!1}),[]),(0,f.useEffect)(()=>{let o=n.current;r.current?r.current=!1:(!o||t.some((i,l)=>!Object.is(i,o[l])))&&e(),n.current=t},t)}function x(e,t){if(!e)return!1;let r=window.getComputedStyle(e),n=/(auto|scroll)/.test(r.overflow+r.overflowX+r.overflowY);return n&&t&&(n=e.scrollHeight!==e.clientHeight||e.scrollWidth!==e.clientWidth),n}function Pe(e,t){let r=e;for(x(r,t)&&(r=r.parentElement);r&&!x(r,t);)r=r.parentElement;return r||document.scrollingElement||document.documentElement}function Ae(e,t){let r=[];for(;e&&e!==document.documentElement;)x(e,t)&&r.push(e),e=e.parentElement;return r}function We(e){return ge()?e.metaKey:e.ctrlKey}var Ke=new Set(["checkbox","radio","range","color","file","image","button","submit","reset"]);function He(e){return e instanceof HTMLInputElement&&!Ke.has(e.type)||e instanceof HTMLTextAreaElement||e instanceof HTMLElement&&e.isContentEditable}var Oe=0,z=new Map;function De(e){let[t,r]=(0,f.useState)();return R(()=>{if(!e)return;let n=z.get(e);if(n)r(n.element.id);else{let o=`react-aria-description-${Oe++}`;r(o);let i=document.createElement("div");i.id=o,i.style.display="none",i.textContent=e,document.body.appendChild(i),n={refCount:0,element:i},z.set(e,n)}return n.refCount++,()=>{n&&--n.refCount===0&&(n.element.remove(),z.delete(e))}},[e]),{"aria-describedby":e?t:void 0}}function Y(e,t){let r=Q(e,t,"left"),n=Q(e,t,"top"),o=t.offsetWidth,i=t.offsetHeight,l=e.scrollLeft,s=e.scrollTop,{borderTopWidth:u,borderLeftWidth:c,scrollPaddingTop:a,scrollPaddingRight:p,scrollPaddingBottom:d,scrollPaddingLeft:N}=getComputedStyle(e),{scrollMarginTop:m,scrollMarginRight:L,scrollMarginBottom:k,scrollMarginLeft:ce}=getComputedStyle(t),se=l+parseInt(c,10),G=s+parseInt(u,10),M=se+e.clientWidth,I=G+e.clientHeight,P=parseInt(a,10)||0,A=parseInt(d,10)||0,W=parseInt(p,10)||0,K=parseInt(N,10)||0,ae=parseInt(m,10)||0,ue=parseInt(k,10)||0,de=parseInt(L,10)||0,H=r-(parseInt(ce,10)||0),O=r+o+de,D=n-ae,j=n+i+ue,fe=l+parseInt(c,10)+K,pe=M-W,he=s+parseInt(u,10)+P,Ne=I-A;(H>fe||O<pe)&&(H<=l+K?l=H-parseInt(c,10)-K:O>M-W&&(l+=O-M+W)),(D>he||j<Ne)&&(D<=G+P?s=D-parseInt(u,10)-P:j>I-A&&(s+=j-I+A)),e.scrollTo({left:l,top:s})}function Q(e,t,r){let n=r==="left"?"offsetLeft":"offsetTop",o=0;for(;t.offsetParent&&(o+=t[n],t.offsetParent!==e);){if(t.offsetParent.contains(e)){o-=e[n];break}t=t.offsetParent}return o}function je(e,t){if(e&&document.contains(e)){let l=document.scrollingElement||document.documentElement;if(window.getComputedStyle(l).overflow!=="hidden"&&!J()){var r;let{left:s,top:u}=e.getBoundingClientRect();e==null||(r=e.scrollIntoView)==null||r.call(e,{block:"nearest"});let{left:c,top:a}=e.getBoundingClientRect();if(Math.abs(s-c)>1||Math.abs(u-a)>1){var n,o,i;t==null||(o=t.containingElement)==null||(n=o.scrollIntoView)==null||n.call(o,{block:"center",inline:"center"}),(i=e.scrollIntoView)==null||i.call(e,{block:"nearest"})}}else{let s=Ae(e);for(let u of s)Y(u,e)}}}var B=new Map;function ze(e){let{locale:t}=ke(),r=t+(e?Object.entries(e).sort((o,i)=>o[0]<i[0]?-1:1).join():"");if(B.has(r))return B.get(r);let n=new Intl.Collator(t,e);return B.set(r,n),n}var Z=f.createContext(null),q="react-aria-focus-scope-restore",h=null;function Be(e){let{children:t,contain:r,restoreFocus:n,autoFocus:o}=e,i=(0,f.useRef)(null),l=(0,f.useRef)(null),s=(0,f.useRef)([]),{parentNode:u}=(0,f.useContext)(Z)||{},c=(0,f.useMemo)(()=>new $({scopeRef:s}),[s]);R(()=>{let d=u||b.root;if(b.getTreeNode(d.scopeRef)&&h&&!F(h,d.scopeRef)){let N=b.getTreeNode(h);N&&(d=N)}d.addChild(c),b.addNode(c)},[c,u]),R(()=>{let d=b.getTreeNode(s);d&&(d.contain=!!r)},[r]),R(()=>{var L;let d=(L=i.current)==null?void 0:L.nextSibling,N=[],m=k=>k.stopPropagation();for(;d&&d!==l.current;)N.push(d),d.addEventListener(q,m),d=d.nextSibling;return s.current=N,()=>{for(let k of N)k.removeEventListener(q,m)}},[t]),Je(s,n,r),Ve(s,r),Xe(s,n,r),Ge(s,o),(0,f.useEffect)(()=>{let d=w(v(s.current?s.current[0]:void 0)),N=null;if(g(d,s.current)){for(let m of b.traverse())m.scopeRef&&g(d,m.scopeRef.current)&&(N=m);N===b.getTreeNode(s)&&(h=N.scopeRef)}},[s]),R(()=>()=>{var N,m;let d=((m=(N=b.getTreeNode(s))==null?void 0:N.parent)==null?void 0:m.scopeRef)??null;(s===h||F(s,h))&&(!d||b.getTreeNode(d))&&(h=d),b.removeTreeNode(s)},[s]);let a=(0,f.useMemo)(()=>qe(s),[]),p=(0,f.useMemo)(()=>({focusManager:a,parentNode:c}),[c,a]);return f.createElement(Z.Provider,{value:p},f.createElement("span",{"data-focus-scope-start":!0,hidden:!0,ref:i}),t,f.createElement("span",{"data-focus-scope-end":!0,hidden:!0,ref:l}))}function qe(e){return{focusNext(t={}){let r=e.current,{from:n,tabbable:o,wrap:i,accept:l}=t,s=n||w(v(r[0]??void 0)),u=r[0].previousElementSibling,c=T(y(r),{tabbable:o,accept:l},r);c.currentNode=g(s,r)?s:u;let a=c.nextNode();return!a&&i&&(c.currentNode=u,a=c.nextNode()),a&&E(a,!0),a},focusPrevious(t={}){let r=e.current,{from:n,tabbable:o,wrap:i,accept:l}=t,s=n||w(v(r[0]??void 0)),u=r[r.length-1].nextElementSibling,c=T(y(r),{tabbable:o,accept:l},r);c.currentNode=g(s,r)?s:u;let a=c.previousNode();return!a&&i&&(c.currentNode=u,a=c.previousNode()),a&&E(a,!0),a},focusFirst(t={}){let r=e.current,{tabbable:n,accept:o}=t,i=T(y(r),{tabbable:n,accept:o},r);i.currentNode=r[0].previousElementSibling;let l=i.nextNode();return l&&E(l,!0),l},focusLast(t={}){let r=e.current,{tabbable:n,accept:o}=t,i=T(y(r),{tabbable:n,accept:o},r);i.currentNode=r[r.length-1].nextElementSibling;let l=i.previousNode();return l&&E(l,!0),l}}}function y(e){return e[0].parentElement}function _(e){let t=b.getTreeNode(h);for(;t&&t.scopeRef!==e;){if(t.contain)return!1;t=t.parent}return!0}function Ue(e){var r,n;if(e.checked)return!0;let t=[];return t=e.form?[...((n=(r=e.form)==null?void 0:r.elements)==null?void 0:n.namedItem(e.name))??[]]:[...v(e).querySelectorAll(`input[type="radio"][name="${CSS.escape(e.name)}"]`)].filter(o=>!o.form),t?!t.some(o=>o.checked):!1}function Ve(e,t){let r=(0,f.useRef)(void 0),n=(0,f.useRef)(void 0);R(()=>{let o=e.current;if(!t){n.current&&(n.current=(cancelAnimationFrame(n.current),void 0));return}let i=v(o?o[0]:void 0),l=c=>{if(c.key!=="Tab"||c.altKey||c.ctrlKey||c.metaKey||!_(e)||c.isComposing)return;let a=w(i),p=e.current;if(!p||!g(a,p))return;let d=T(y(p),{tabbable:!0},p);if(!a)return;d.currentNode=a;let N=c.shiftKey?d.previousNode():d.nextNode();N||(N=(d.currentNode=c.shiftKey?p[p.length-1].nextElementSibling:p[0].previousElementSibling,c.shiftKey?d.previousNode():d.nextNode())),c.preventDefault(),N&&E(N,!0)},s=c=>{(!h||F(h,e))&&g(S(c),e.current)?(h=e,r.current=S(c)):_(e)&&!C(S(c),e)?r.current?r.current.focus():h&&h.current&&U(h.current):_(e)&&(r.current=S(c))},u=c=>{n.current&&cancelAnimationFrame(n.current),n.current=requestAnimationFrame(()=>{let a=Te(),p=(a==="virtual"||a===null)&&Se()&&J(),d=w(i);if(!p&&d&&_(e)&&!C(d,e)){h=e;let m=S(c);if(m&&m.isConnected){var N;r.current=m,(N=r.current)==null||N.focus()}else h.current&&U(h.current)}})};return i.addEventListener("keydown",l,!1),i.addEventListener("focusin",s,!1),o==null||o.forEach(c=>c.addEventListener("focusin",s,!1)),o==null||o.forEach(c=>c.addEventListener("focusout",u,!1)),()=>{i.removeEventListener("keydown",l,!1),i.removeEventListener("focusin",s,!1),o==null||o.forEach(c=>c.removeEventListener("focusin",s,!1)),o==null||o.forEach(c=>c.removeEventListener("focusout",u,!1))}},[e,t]),R(()=>()=>{n.current&&cancelAnimationFrame(n.current)},[n])}function ee(e){return C(e)}function g(e,t){return!e||!t?!1:t.some(r=>r.contains(e))}function C(e,t=null){if(e instanceof Element&&e.closest("[data-react-aria-top-layer]"))return!0;for(let{scopeRef:r}of b.traverse(b.getTreeNode(t)))if(r&&g(e,r.current))return!0;return!1}function $e(e){return C(e,h)}function F(e,t){var n;let r=(n=b.getTreeNode(t))==null?void 0:n.parent;for(;r;){if(r.scopeRef===e)return!0;r=r.parent}return!1}function E(e,t=!1){if(e!=null&&!t)try{ve(e)}catch{}else if(e!=null)try{e.focus()}catch{}}function te(e,t=!0){let r=e[0].previousElementSibling,n=y(e),o=T(n,{tabbable:t},e);o.currentNode=r;let i=o.nextNode();return t&&!i&&(n=y(e),o=T(n,{tabbable:!1},e),o.currentNode=r,i=o.nextNode()),i}function U(e,t=!0){E(te(e,t))}function Ge(e,t){let r=f.useRef(t);(0,f.useEffect)(()=>{r.current&&(h=e,!g(w(v(e.current?e.current[0]:void 0)),h.current)&&e.current&&U(e.current)),r.current=!1},[e])}function Je(e,t,r){R(()=>{if(t||r)return;let n=e.current,o=v(n?n[0]:void 0),i=l=>{let s=S(l);g(s,e.current)?h=e:ee(s)||(h=null)};return o.addEventListener("focusin",i,!1),n==null||n.forEach(l=>l.addEventListener("focusin",i,!1)),()=>{o.removeEventListener("focusin",i,!1),n==null||n.forEach(l=>l.removeEventListener("focusin",i,!1))}},[e,t,r])}function re(e){let t=b.getTreeNode(h);for(;t&&t.scopeRef!==e;){if(t.nodeToRestore)return!1;t=t.parent}return(t==null?void 0:t.scopeRef)===e}function Xe(e,t,r){let n=(0,f.useRef)(typeof document<"u"?w(v(e.current?e.current[0]:void 0)):null);R(()=>{let o=e.current,i=v(o?o[0]:void 0);if(!t||r)return;let l=()=>{(!h||F(h,e))&&g(w(i),e.current)&&(h=e)};return i.addEventListener("focusin",l,!1),o==null||o.forEach(s=>s.addEventListener("focusin",l,!1)),()=>{i.removeEventListener("focusin",l,!1),o==null||o.forEach(s=>s.removeEventListener("focusin",l,!1))}},[e,r]),R(()=>{let o=v(e.current?e.current[0]:void 0);if(!t)return;let i=l=>{if(l.key!=="Tab"||l.altKey||l.ctrlKey||l.metaKey||!_(e)||l.isComposing)return;let s=o.activeElement;if(!C(s,e)||!re(e))return;let u=b.getTreeNode(e);if(!u)return;let c=u.nodeToRestore,a=T(o.body,{tabbable:!0});a.currentNode=s;let p=l.shiftKey?a.previousNode():a.nextNode();if((!c||!c.isConnected||c===o.body)&&(c=void 0,u.nodeToRestore=void 0),(!p||!C(p,e))&&c){a.currentNode=c;do p=l.shiftKey?a.previousNode():a.nextNode();while(C(p,e));l.preventDefault(),l.stopPropagation(),p?E(p,!0):ee(c)?E(c,!0):s.blur()}};return r||o.addEventListener("keydown",i,!0),()=>{r||o.removeEventListener("keydown",i,!0)}},[e,t,r]),R(()=>{let o=v(e.current?e.current[0]:void 0);if(!t)return;let i=b.getTreeNode(e);if(i)return i.nodeToRestore=n.current??void 0,()=>{let l=b.getTreeNode(e);if(!l)return;let s=l.nodeToRestore,u=w(o);if(t&&s&&(u&&C(u,e)||u===o.body&&re(e))){let c=b.clone();requestAnimationFrame(()=>{if(o.activeElement===o.body){let a=c.getTreeNode(e);for(;a;){if(a.nodeToRestore&&a.nodeToRestore.isConnected){ne(a.nodeToRestore);return}a=a.parent}for(a=c.getTreeNode(e);a;){if(a.scopeRef&&a.scopeRef.current&&b.getTreeNode(a.scopeRef)){ne(te(a.scopeRef.current,!0));return}a=a.parent}}})}}},[e,t])}function ne(e){e.dispatchEvent(new CustomEvent(q,{bubbles:!0,cancelable:!0}))&&E(e)}function T(e,t,r){let n=t!=null&&t.tabbable?ye:Ce,o=v((e==null?void 0:e.nodeType)===Node.ELEMENT_NODE?e:null),i=Me(o,e||o,NodeFilter.SHOW_ELEMENT,{acceptNode(l){var s;return t!=null&&((s=t.from)!=null&&s.contains(l))||t!=null&&t.tabbable&&l.tagName==="INPUT"&&l.getAttribute("type")==="radio"&&(!Ue(l)||i.currentNode.tagName==="INPUT"&&i.currentNode.type==="radio"&&i.currentNode.name===l.name)?NodeFilter.FILTER_REJECT:n(l)&&(!r||g(l,r))&&(!(t!=null&&t.accept)||t.accept(l))?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});return t!=null&&t.from&&(i.currentNode=t.from),i}function Ye(e,t={}){return{focusNext(r={}){let n=e.current;if(!n)return null;let{from:o,tabbable:i=t.tabbable,wrap:l=t.wrap,accept:s=t.accept}=r,u=o||w(v(n)),c=T(n,{tabbable:i,accept:s});n.contains(u)&&(c.currentNode=u);let a=c.nextNode();return!a&&l&&(c.currentNode=n,a=c.nextNode()),a&&E(a,!0),a},focusPrevious(r=t){let n=e.current;if(!n)return null;let{from:o,tabbable:i=t.tabbable,wrap:l=t.wrap,accept:s=t.accept}=r,u=o||w(v(n)),c=T(n,{tabbable:i,accept:s});if(n.contains(u))c.currentNode=u;else{let p=V(c);return p&&E(p,!0),p??null}let a=c.previousNode();if(!a&&l){c.currentNode=n;let p=V(c);if(!p)return null;a=p}return a&&E(a,!0),a??null},focusFirst(r=t){let n=e.current;if(!n)return null;let{tabbable:o=t.tabbable,accept:i=t.accept}=r,l=T(n,{tabbable:o,accept:i}).nextNode();return l&&E(l,!0),l},focusLast(r=t){let n=e.current;if(!n)return null;let{tabbable:o=t.tabbable,accept:i=t.accept}=r,l=V(T(n,{tabbable:o,accept:i}));return l&&E(l,!0),l??null}}}function V(e){let t,r;do r=e.lastChild(),r&&(t=r);while(r);return t}var Qe=class le{get size(){return this.fastMap.size}getTreeNode(t){return this.fastMap.get(t)}addTreeNode(t,r,n){let o=this.fastMap.get(r??null);if(!o)return;let i=new $({scopeRef:t});o.addChild(i),i.parent=o,this.fastMap.set(t,i),n&&(i.nodeToRestore=n)}addNode(t){this.fastMap.set(t.scopeRef,t)}removeTreeNode(t){if(t===null)return;let r=this.fastMap.get(t);if(!r)return;let n=r.parent;for(let i of this.traverse())i!==r&&r.nodeToRestore&&i.nodeToRestore&&r.scopeRef&&r.scopeRef.current&&g(i.nodeToRestore,r.scopeRef.current)&&(i.nodeToRestore=r.nodeToRestore);let o=r.children;n&&(n.removeChild(r),o.size>0&&o.forEach(i=>n&&n.addChild(i))),this.fastMap.delete(r.scopeRef)}*traverse(t=this.root){if(t.scopeRef!=null&&(yield t),t.children.size>0)for(let r of t.children)yield*this.traverse(r)}clone(){var r;let t=new le;for(let n of this.traverse())t.addTreeNode(n.scopeRef,((r=n.parent)==null?void 0:r.scopeRef)??null,n.nodeToRestore);return t}constructor(){this.fastMap=new Map,this.root=new $({scopeRef:null}),this.fastMap.set(null,this.root)}},$=class{addChild(e){this.children.add(e),e.parent=this}removeChild(e){this.children.delete(e),e.parent=void 0}constructor(e){this.children=new Set,this.contain=!1,this.scopeRef=e.scopeRef}},b=new Qe,oe={border:0,clip:"rect(0 0 0 0)",clipPath:"inset(50%)",height:"1px",margin:"-1px",overflow:"hidden",padding:0,position:"absolute",width:"1px",whiteSpace:"nowrap"};function ie(e={}){let{style:t,isFocusable:r}=e,[n,o]=(0,f.useState)(!1),{focusWithinProps:i}=Ee({isDisabled:!r,onFocusWithinChange:s=>o(s)}),l=(0,f.useMemo)(()=>n?t:t?{...oe,...t}:oe,[n]);return{visuallyHiddenProps:{...i,style:l}}}function Ze(e){let{children:t,elementType:r="div",isFocusable:n,style:o,...i}=e,{visuallyHiddenProps:l}=ie(e);return f.createElement(r,Re(i,l),t)}export{xe as _,T as a,Y as c,We as d,He as f,_e as g,Ie as h,Be as i,je as l,x as m,ie as n,Ye as o,Pe as p,$e as r,ze as s,Ze as t,De as u,Le as v};
|