@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.
Files changed (179) hide show
  1. package/dist/assets/{CellStatus-Ba6Af_Tb.js → CellStatus-b7Yo2X9j.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-KlUs_Sz3.js → ConnectedDataExplorerComponent-Cr6-n9Em.js} +1 -1
  3. package/dist/assets/{ErrorBoundary-Drf1manw.js → ErrorBoundary-C7JBxSzd.js} +1 -1
  4. package/dist/assets/{ImperativeModal-q6QlC2aZ.js → ImperativeModal-DVhvP4lH.js} +1 -1
  5. package/dist/assets/{JsonOutput-4ruRfyOj.js → JsonOutput-C8Eo1zBR.js} +5 -5
  6. package/dist/assets/{LazyAnyLanguageCodeMirror-jpEDlD0M.js → LazyAnyLanguageCodeMirror-Cp2punaU.js} +2 -2
  7. package/dist/assets/{MarimoErrorOutput-DnjH3pD8.js → MarimoErrorOutput-CXBGzjO2.js} +2 -2
  8. package/dist/assets/{RenderHTML-DaJXe2U2.js → RenderHTML-SoetmcW2.js} +1 -1
  9. package/dist/assets/VisuallyHidden-B9t3FhTP.js +1 -0
  10. package/dist/assets/{add-cell-with-ai-Bsds_6SU.js → add-cell-with-ai-D2qS3Nos.js} +21 -21
  11. package/dist/assets/{add-database-form-CqIp3_WN.js → add-database-form-BBkiGMZ_.js} +2 -2
  12. package/dist/assets/agent-panel-BzV4XUTo.js +287 -0
  13. package/dist/assets/{ai-model-dropdown-LK8Wr5iu.js → ai-model-dropdown-CrMTCgo7.js} +1 -1
  14. package/dist/assets/{alert-dialog-k5KxevGr.js → alert-dialog-jcHA5geR.js} +1 -1
  15. package/dist/assets/{any-language-editor-DQu1Tt2N.js → any-language-editor-Cm83E7D_.js} +1 -1
  16. package/dist/assets/{app-config-button-BaVc4Y5z.js → app-config-button-9izWmQ0X.js} +1 -1
  17. package/dist/assets/button-B8cGZzP5.js +1 -0
  18. package/dist/assets/{cache-panel-C1So4Zu3.js → cache-panel-1FqnpB9y.js} +1 -1
  19. package/dist/assets/cell-editor-Do6lWWk9.js +23 -0
  20. package/dist/assets/cell-link-BP7_Ns0N.js +1 -0
  21. package/dist/assets/{cells-KYKWFk6C.js → cells-Cv9PtwL9.js} +49 -49
  22. package/dist/assets/{chat-components-O6DUIpBx.js → chat-components-Be6BPrbT.js} +1 -1
  23. package/dist/assets/{chat-display-DD3KokYi.js → chat-display-BRKfnhbm.js} +1 -1
  24. package/dist/assets/{chat-panel-D4DIcOM1.js → chat-panel-71zcilvi.js} +2 -2
  25. package/dist/assets/client-CGOlSEYr.js +4 -0
  26. package/dist/assets/{column-preview-EpCGr4Xp.js → column-preview-MC6VOHbd.js} +1 -1
  27. package/dist/assets/{command-Dqe0kvHp.js → command-n_oMaKjl.js} +1 -1
  28. package/dist/assets/{command-palette-DWacsFDk.js → command-palette-DfZNcw7W.js} +1 -1
  29. package/dist/assets/common-MUZIZluQ.js +1 -0
  30. package/dist/assets/config-DFDEcYvy.js +1 -0
  31. package/dist/assets/context-DHfVoQfl.js +1 -0
  32. package/dist/assets/{copy-icon-B69c-352.js → copy-icon-jWsqdLn1.js} +1 -1
  33. package/dist/assets/{datasource-JeWYnuIr.js → datasource-CEsMStKs.js} +2 -2
  34. package/dist/assets/{dependency-graph-panel-BJibnwCO.js → dependency-graph-panel-CNTGbfLZ.js} +4 -4
  35. package/dist/assets/{dialog-DUEuLcT2.js → dialog-CF5DtF1E.js} +1 -1
  36. package/dist/assets/{dist-DOFFh6Ii.js → dist-Dg7UO_Vw.js} +1 -1
  37. package/dist/assets/{documentation-panel-B2W3q2YB.js → documentation-panel-Cb9AHO2C.js} +1 -1
  38. package/dist/assets/{download-NfnO_JCs.js → download-24bI2vH0.js} +1 -1
  39. package/dist/assets/edit-page-DSuXLdcn.js +12 -0
  40. package/dist/assets/{error-banner-DU5Qb8a8.js → error-banner-DvT0IGDZ.js} +1 -1
  41. package/dist/assets/{error-panel-Bv-7GYgJ.js → error-panel-CpYH0GfR.js} +1 -1
  42. package/dist/assets/{es-KtEicG7U.js → es-BITbuY9w.js} +1 -1
  43. package/dist/assets/{field-DDKGFzpC.js → field-Clr_fqUr.js} +1 -1
  44. package/dist/assets/{file-explorer-panel-CToUezud.js → file-explorer-panel-CdA81LHh.js} +1 -1
  45. package/dist/assets/{floating-outline-Db40vhG8.js → floating-outline-BbJ4ldyu.js} +1 -1
  46. package/dist/assets/{focus-BCdX47jS.js → focus-D1y1tXyC.js} +1 -1
  47. package/dist/assets/{form-DwtJQd_Z.js → form-BAtvsPJL.js} +2 -2
  48. package/dist/assets/{glide-data-editor-D_bRnWfy.js → glide-data-editor-Dv8ZW9dk.js} +1 -1
  49. package/dist/assets/{globals-MS86g8oR.js → globals-C6OH39EA.js} +1 -1
  50. package/dist/assets/{home-page-BfVf41OG.js → home-page-B_YprqxM.js} +2 -2
  51. package/dist/assets/house-CncUa_LL.js +1 -0
  52. package/dist/assets/index-C30GhE0W.css +2 -0
  53. package/dist/assets/index-DoE3JZXY.js +43 -0
  54. package/dist/assets/input-B80Yt1uu.js +1 -0
  55. package/dist/assets/{kiosk-mode-CEhvsEr0.js → kiosk-mode-DfyjlR7p.js} +1 -1
  56. package/dist/assets/{label-qwandMoh.js → label-CNZLffHW.js} +1 -1
  57. package/dist/assets/{layout-Cvaok8Kj.js → layout-9uQoV-6h.js} +4 -4
  58. package/dist/assets/links-DbDrjRnm.js +1 -0
  59. package/dist/assets/{logs-panel-J2FKnKaj.js → logs-panel-svcirwjp.js} +1 -1
  60. package/dist/assets/{markdown-renderer-BlG9DgUG.js → markdown-renderer-DlVqlHOL.js} +2 -2
  61. package/dist/assets/mode-PeuS_Lp-.js +1 -0
  62. package/dist/assets/{multi-map-fjX9ImVF.js → multi-map-CQd4MZr5.js} +1 -1
  63. package/dist/assets/name-cell-input-YMoA0SQj.js +1 -0
  64. package/dist/assets/{outline-panel-Doj3GJrQ.js → outline-panel-RKJ5Mqrt.js} +1 -1
  65. package/dist/assets/{packages-panel-nqWXQzKf.js → packages-panel-BuiAGEBw.js} +1 -1
  66. package/dist/assets/panels-BKsZUDjc.js +1 -0
  67. package/dist/assets/{process-output-DiSW8Nbo.js → process-output-KJWsSvCT.js} +1 -1
  68. package/dist/assets/{readonly-python-code-CKY5LsMp.js → readonly-python-code-HPlG_YPX.js} +1 -1
  69. package/dist/assets/run-page-CBDzVDX3.js +1 -0
  70. package/dist/assets/scratchpad-panel-CarbQVYs.js +1 -0
  71. package/dist/assets/{secrets-panel-CDWmmmBS.js → secrets-panel-BMY6PPth.js} +1 -1
  72. package/dist/assets/{select-D0g5GnIs.js → select-D9lTzMzP.js} +1 -1
  73. package/dist/assets/{session-panel-CGFRSBw9.js → session-panel-Cv14Ehfm.js} +1 -1
  74. package/dist/assets/{slides-component-MkPkpql1.js → slides-component-Dp0Yv5b0.js} +1 -1
  75. package/dist/assets/{snippets-panel-ClHeSpc5.js → snippets-panel-OAdQXQ93.js} +1 -1
  76. package/dist/assets/state-DYG6kYly.js +1 -0
  77. package/dist/assets/state-xh6GqNrp.js +1 -0
  78. package/dist/assets/{switch-BmbGJWHc.js → switch-DPeh0R76.js} +1 -1
  79. package/dist/assets/{terminal-BvgBa6Ri.js → terminal-BbAhzgnR.js} +1 -1
  80. package/dist/assets/{textarea-WklymBeK.js → textarea-wbzgrXvB.js} +1 -1
  81. package/dist/assets/{tracing-D0WYhZdr.js → tracing-Bh3EJxAS.js} +1 -1
  82. package/dist/assets/{tracing-panel-CNxN58z7.js → tracing-panel-BzSQ7qvB.js} +2 -2
  83. package/dist/assets/{types-BrgXpvGt.js → types-B8Qb1FfB.js} +1 -1
  84. package/dist/assets/{useAddCell-a9qZ0_KE.js → useAddCell-DBGvrN8K.js} +1 -1
  85. package/dist/assets/{useBoolean-5kuXz69O.js → useBoolean-CyOFPk5r.js} +1 -1
  86. package/dist/assets/{useCellActionButton-9W_R41MM.js → useCellActionButton-BlS_HKk-.js} +1 -1
  87. package/dist/assets/{useDateFormatter-CV0QXb5P.js → useDateFormatter-DsANziQR.js} +1 -1
  88. package/dist/assets/useDeleteCell-BvQIJfpI.js +1 -0
  89. package/dist/assets/{useDependencyPanelTab-0reaqvvh.js → useDependencyPanelTab-BqEhbPr2.js} +1 -1
  90. package/dist/assets/useInterval-BGPIviJp.js +1 -0
  91. package/dist/assets/useNotebookActions-D1Woz3AV.js +1 -0
  92. package/dist/assets/{useNumberFormatter-D8ks3oPN.js → useNumberFormatter-FoXhpyAb.js} +1 -1
  93. package/dist/assets/usePress-DTwIUo40.js +7 -0
  94. package/dist/assets/useRunCells-B9Xr4tcH.js +1 -0
  95. package/dist/assets/useSplitCell-7xBW3b8-.js +1 -0
  96. package/dist/assets/utilities.esm-xahhGpny.js +3 -0
  97. package/dist/assets/{vega-component-DpAAiTdH.js → vega-component-dUiiVmIx.js} +1 -1
  98. package/dist/assets/{write-secret-modal-CLm48gMe.js → write-secret-modal-hOetwavI.js} +1 -1
  99. package/dist/index.html +54 -54
  100. package/package.json +5 -5
  101. package/src/__mocks__/requests.ts +1 -0
  102. package/src/__tests__/mount.test.ts +128 -0
  103. package/src/components/app-config/__tests__/get-dirty-values.test.ts +1 -1
  104. package/src/components/app-config/user-config-form.tsx +1 -1
  105. package/src/components/chat/acp/agent-panel.tsx +56 -43
  106. package/src/components/chat/chat-utils.ts +0 -19
  107. package/src/components/data-table/column-header.tsx +1 -1
  108. package/src/components/editor/KernelStartupErrorModal.tsx +101 -0
  109. package/src/components/editor/actions/name-cell-input.tsx +10 -4
  110. package/src/components/editor/ai/completion-handlers.tsx +1 -1
  111. package/src/components/editor/alerts/connecting-alert.tsx +33 -6
  112. package/src/components/editor/chrome/types.ts +2 -4
  113. package/src/components/editor/chrome/wrapper/app-chrome.tsx +55 -58
  114. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +150 -96
  115. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +27 -0
  116. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +6 -0
  117. package/src/components/utils/lazy-mount.tsx +29 -8
  118. package/src/core/MarimoApp.tsx +2 -0
  119. package/src/core/cells/cells.ts +2 -0
  120. package/src/core/cells/scrollCellIntoView.ts +3 -2
  121. package/src/core/codemirror/cm.ts +2 -0
  122. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +123 -0
  123. package/src/core/codemirror/lsp/notebook-lsp.ts +44 -4
  124. package/src/core/codemirror/misc/__tests__/string-braces.test.ts +200 -0
  125. package/src/core/codemirror/misc/string-braces.ts +37 -0
  126. package/src/core/errors/state.ts +7 -1
  127. package/src/core/export/__tests__/hooks.test.ts +504 -0
  128. package/src/core/export/hooks.ts +93 -4
  129. package/src/core/islands/bridge.ts +1 -0
  130. package/src/core/islands/main.ts +2 -0
  131. package/src/core/kernel/__tests__/handlers.test.ts +2 -2
  132. package/src/core/kernel/state.ts +1 -0
  133. package/src/core/network/__tests__/requests-lazy.test.ts +1 -1
  134. package/src/core/network/__tests__/requests-network.test.ts +0 -18
  135. package/src/core/network/requests-lazy.ts +3 -2
  136. package/src/core/network/requests-network.ts +10 -7
  137. package/src/core/network/requests-static.ts +1 -0
  138. package/src/core/network/requests-toasting.tsx +1 -0
  139. package/src/core/network/types.ts +2 -0
  140. package/src/core/wasm/bridge.ts +1 -0
  141. package/src/core/websocket/types.ts +1 -0
  142. package/src/core/websocket/useMarimoKernelConnection.tsx +18 -1
  143. package/src/css/globals.css +2 -0
  144. package/src/hooks/__tests__/useInterval.test.tsx +104 -0
  145. package/src/hooks/useInterval.ts +32 -6
  146. package/src/mount.tsx +6 -0
  147. package/src/plugins/impl/chat/chat-ui.tsx +16 -4
  148. package/src/plugins/impl/chat/types.ts +5 -12
  149. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +3 -1
  150. package/src/utils/events.ts +1 -0
  151. package/dist/assets/VisuallyHidden-BodIky8L.js +0 -1
  152. package/dist/assets/agent-panel-CaAPVPdJ.js +0 -287
  153. package/dist/assets/button-DuYGqRtX.js +0 -1
  154. package/dist/assets/cell-editor-OFm-OSAP.js +0 -23
  155. package/dist/assets/cell-link-CfLJRl3p.js +0 -1
  156. package/dist/assets/client-Cha_JfGC.js +0 -4
  157. package/dist/assets/common-A6YWtmpq.js +0 -1
  158. package/dist/assets/config-babG4OBR.js +0 -1
  159. package/dist/assets/context-BAYdLMF_.js +0 -1
  160. package/dist/assets/edit-page-nuU4FVXi.js +0 -12
  161. package/dist/assets/globe-CY9im410.js +0 -1
  162. package/dist/assets/index-BI88xbv4.js +0 -43
  163. package/dist/assets/index-Chgc_07S.css +0 -2
  164. package/dist/assets/input-CaEtLL8p.js +0 -1
  165. package/dist/assets/links-ENMiP32L.js +0 -1
  166. package/dist/assets/mode-CK5Oq-Jz.js +0 -1
  167. package/dist/assets/name-cell-input-D7axzd6k.js +0 -1
  168. package/dist/assets/panels-CdYbZBqo.js +0 -1
  169. package/dist/assets/run-page-GP8eGE39.js +0 -1
  170. package/dist/assets/scratchpad-panel-B1p8zqAE.js +0 -1
  171. package/dist/assets/state-BBgXjqJI.js +0 -1
  172. package/dist/assets/state-CP7_TGWl.js +0 -1
  173. package/dist/assets/useDeleteCell-5kJUaejE.js +0 -1
  174. package/dist/assets/useInterval-DpipYmgs.js +0 -1
  175. package/dist/assets/useNotebookActions-o341ZCMJ.js +0 -1
  176. package/dist/assets/usePress-C2LPFxyv.js +0 -7
  177. package/dist/assets/useRunCells-wXhl9zOP.js +0 -1
  178. package/dist/assets/useSplitCell-mmm5jxn2.js +0 -1
  179. package/dist/assets/utilities.esm-Ckt5kMF-.js +0 -3
@@ -1,4 +1,4 @@
1
- /* Copyright 2024 Marimo. All rights reserved. */
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 Promise.resolve();
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 { isConnectedAtom, waitForConnectionOpen } from "./connection";
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
- // Rather than waiting, we just drop all sendRun requests if the connection is not open.
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>;
@@ -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
@@ -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
  });
@@ -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 { delayMs, whenVisible, disabled = false } = opts;
17
- const savedCallback = useRef<() => void>(undefined);
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
- savedCallback.current?.();
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
- savedCallback.current?.();
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 = { ...localConfig, [key]: finalValue };
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(localConfig).map(([key, value]) => (
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={Object.keys(columns).length}
322
+ totalColumns={totalColumns ?? 0}
321
323
  maxColumns="all"
322
324
  pageSize={pageSize}
323
325
  pagination={true}
@@ -42,6 +42,7 @@ export const Events = {
42
42
  target.tagName === "INPUT" ||
43
43
  target.tagName === "TEXTAREA" ||
44
44
  target.tagName.startsWith("MARIMO") ||
45
+ target.isContentEditable ||
45
46
  Events.fromCodeMirror(e)
46
47
  );
47
48
  },
@@ -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};