@marimo-team/islands 0.21.1-dev94 → 0.21.2-dev0
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/{Combination-Dk6JxauT.js → Combination-BBPQRrDo.js} +1 -1
- package/dist/{ConnectedDataExplorerComponent-Bh11efrC.js → ConnectedDataExplorerComponent-D0GoOd_c.js} +14 -13
- package/dist/{any-language-editor-BIj11a2e.js → any-language-editor-DlsjUw_l.js} +4 -4
- package/dist/{button-DQpBib29.js → button-BKkuUpZh.js} +8 -0
- package/dist/{check-DpqPQmzz.js → check-Diwc5emq.js} +1 -1
- package/dist/{copy-BkBF0Xgk.js → copy-DIK6DiIA.js} +2 -2
- package/dist/{dist-WIWVvdBh.js → dist-C0Rnbr-_.js} +2 -2
- package/dist/{error-banner-BctofTCP.js → error-banner-Dmi5ujan.js} +2 -2
- package/dist/{esm-BBkPJL8N.js → esm-BLobyqMs.js} +8 -7
- package/dist/{glide-data-editor-DqxJOnJk.js → glide-data-editor-pZyd9UJ_.js} +6 -6
- package/dist/{label-BLDcDYdI.js → label-BbpGrh4j.js} +4 -4
- package/dist/{loader-DsE3MiYo.js → loader-CABJs6GU.js} +12 -3
- package/dist/main.js +186 -127
- package/dist/{mermaid-DkdSmFY8.js → mermaid-CrKqsE2j.js} +5 -5
- package/dist/{slides-component-DwvL_HJi.js → slides-component-GkilRW21.js} +2 -2
- package/dist/{spec-CbYkiXG3.js → spec-Bfvf9Hre.js} +4 -4
- package/dist/style.css +1 -1
- package/dist/{tooltip-SPkubVH3.js → tooltip-CKG75XQa.js} +3 -3
- package/dist/{types-0FB-N7AA.js → types-CGc7peZV.js} +6 -6
- package/dist/{useAsyncData-D7-oahg5.js → useAsyncData-CEjJxwFB.js} +1 -1
- package/dist/{useDeepCompareMemoize-DLS-bHHT.js → useDeepCompareMemoize-BWUwfh37.js} +4 -4
- package/dist/{useIframeCapabilities-DFGZKWkO.js → useIframeCapabilities-OQaMKgZl.js} +1 -1
- package/dist/{useTheme-D0rdoMBF.js → useTheme-CPybHVFN.js} +2 -2
- package/dist/{vega-component-CnO3mkFC.js → vega-component-CuPTCRp5.js} +13 -10
- package/package.json +1 -1
- package/src/components/data-table/charts/lazy-chart.tsx +2 -0
- package/src/components/data-table/column-summary/column-summary.tsx +1 -0
- package/src/components/datasources/column-preview.tsx +1 -0
- package/src/components/editor/Output.tsx +2 -0
- package/src/components/editor/actions/useCellActionButton.tsx +38 -29
- package/src/components/editor/cell/code/cell-editor.tsx +9 -0
- package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +6 -0
- package/src/components/editor/chrome/wrapper/__tests__/utils.test.ts +35 -0
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +12 -14
- package/src/components/editor/chrome/wrapper/utils.ts +5 -1
- package/src/components/editor/header/status.tsx +19 -11
- package/src/components/editor/renderers/grid-layout/grid-layout.tsx +10 -3
- package/src/core/cells/cells.ts +6 -0
- package/src/core/cells/utils.ts +1 -0
- package/src/core/codemirror/__tests__/setup.test.ts +1 -0
- package/src/core/codemirror/cells/state.ts +1 -0
- package/src/core/codemirror/extensions.ts +20 -0
- package/src/core/codemirror/language/utils.ts +16 -1
- package/src/core/codemirror/reactive-references/__tests__/analyzer.test.ts +54 -0
- package/src/core/codemirror/reactive-references/analyzer.ts +14 -0
- package/src/core/dom/outline.ts +1 -1
- package/src/core/hotkeys/hotkeys.ts +8 -0
- package/src/css/md.css +4 -0
- package/src/plugins/core/sanitize-html.ts +50 -0
- package/src/plugins/core/sanitize.ts +3 -49
- package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +6 -3
- package/src/plugins/impl/vega/__tests__/utils.test.ts +36 -0
- package/src/plugins/impl/vega/utils.ts +14 -0
- package/src/plugins/impl/vega/vega-component.tsx +6 -7
- package/src/plugins/impl/vega/vega.css +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-Bs6Z0kvn.js";
|
|
3
3
|
import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
|
|
4
|
-
import { a as Content, i as Arrow, o as Root2, r as Anchor, s as createPopperScope, t as Root } from "./dist-
|
|
5
|
-
import { m as useComposedRefs, y as cn } from "./button-
|
|
6
|
-
import { _t as createContextScope, at as useControllableState, ct as useId, ft as Primitive, ht as createSlottable, it as StyleNamespace, nt as withSmartCollisionBoundary, ot as Presence, st as Portal, tt as withFullScreenAsRoot, ut as DismissableLayer, vt as composeEventHandlers } from "./Combination-
|
|
4
|
+
import { a as Content, i as Arrow, o as Root2, r as Anchor, s as createPopperScope, t as Root } from "./dist-C0Rnbr-_.js";
|
|
5
|
+
import { m as useComposedRefs, y as cn } from "./button-BKkuUpZh.js";
|
|
6
|
+
import { _t as createContextScope, at as useControllableState, ct as useId, ft as Primitive, ht as createSlottable, it as StyleNamespace, nt as withSmartCollisionBoundary, ot as Presence, st as Portal, tt as withFullScreenAsRoot, ut as DismissableLayer, vt as composeEventHandlers } from "./Combination-BBPQRrDo.js";
|
|
7
7
|
import { t as require_jsx_runtime } from "./jsx-runtime-CTBg5pdT.js";
|
|
8
8
|
var import_react = /* @__PURE__ */ __toESM(require_react(), 1), import_jsx_runtime = /* @__PURE__ */ __toESM(require_jsx_runtime(), 1), [createTooltipContext, createTooltipScope] = createContextScope("Tooltip", [createPopperScope]), usePopperScope = createPopperScope(), PROVIDER_NAME = "TooltipProvider", DEFAULT_DELAY_DURATION = 700, TOOLTIP_OPEN = "tooltip.open", [TooltipProviderContextProvider, useTooltipProviderContext] = createTooltipContext(PROVIDER_NAME), TooltipProvider$1 = (t) => {
|
|
9
9
|
let { __scopeTooltip: k, delayDuration: A = DEFAULT_DELAY_DURATION, skipDelayDuration: j = 300, disableHoverableContent: M = false, children: N } = t, P = import_react.useRef(true), F = import_react.useRef(false), I = import_react.useRef(0);
|
|
@@ -5,17 +5,17 @@ var _a;
|
|
|
5
5
|
import { s as __toESM, t as __commonJSMin } from "./chunk-BNovOVIE.js";
|
|
6
6
|
import { t as require_react } from "./react-Bs6Z0kvn.js";
|
|
7
7
|
import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
|
|
8
|
-
import { a as Content, i as Arrow, l as createLucideIcon, o as Root2$1, r as Anchor, s as createPopperScope } from "./dist-
|
|
9
|
-
import { t as Check } from "./check-
|
|
10
|
-
import { A as $a916eb452884faea$export$b7a616150fdb9f44, C as useDirection, F as $b5e257d569688ac6$export$619500959fc48b26, I as X, L as ChevronUp, M as $18f2051aff69b9bf$export$43bb16f9c6d9e3f7, R as ChevronDown, _ as menuItemVariants, b as menuSubTriggerVariants, g as menuControlVariants, h as menuControlCheckVariants, j as $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5, k as upperFirst_default, m as menuContentCommon, v as menuLabelVariants, w as createCollection, y as menuSeparatorVariants } from "./label-
|
|
8
|
+
import { a as Content, i as Arrow, l as createLucideIcon, o as Root2$1, r as Anchor, s as createPopperScope } from "./dist-C0Rnbr-_.js";
|
|
9
|
+
import { t as Check } from "./check-Diwc5emq.js";
|
|
10
|
+
import { A as $a916eb452884faea$export$b7a616150fdb9f44, C as useDirection, F as $b5e257d569688ac6$export$619500959fc48b26, I as X, L as ChevronUp, M as $18f2051aff69b9bf$export$43bb16f9c6d9e3f7, R as ChevronDown, _ as menuItemVariants, b as menuSubTriggerVariants, g as menuControlVariants, h as menuControlCheckVariants, j as $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5, k as upperFirst_default, m as menuContentCommon, v as menuLabelVariants, w as createCollection, y as menuSeparatorVariants } from "./label-BbpGrh4j.js";
|
|
11
11
|
import { n as clsx_default } from "./clsx-D2KVTYnW.js";
|
|
12
|
-
import { g as Logger, h as Events, m as useComposedRefs, p as composeRefs, t as Button, y as cn } from "./button-
|
|
13
|
-
import { _t as createContextScope, at as useControllableState, ct as useId, dt as useCallbackRef, et as MAX_HEIGHT_OFFSET, ft as Primitive, i as useFocusGuards, it as StyleNamespace, mt as createSlot, n as hideOthers, nt as withSmartCollisionBoundary, ot as Presence, pt as dispatchDiscreteCustomEvent, r as FocusScope, st as Portal, t as Combination_default, tt as withFullScreenAsRoot, ut as DismissableLayer, vt as composeEventHandlers } from "./Combination-
|
|
12
|
+
import { g as Logger, h as Events, m as useComposedRefs, p as composeRefs, t as Button, y as cn } from "./button-BKkuUpZh.js";
|
|
13
|
+
import { _t as createContextScope, at as useControllableState, ct as useId, dt as useCallbackRef, et as MAX_HEIGHT_OFFSET, ft as Primitive, i as useFocusGuards, it as StyleNamespace, mt as createSlot, n as hideOthers, nt as withSmartCollisionBoundary, ot as Presence, pt as dispatchDiscreteCustomEvent, r as FocusScope, st as Portal, t as Combination_default, tt as withFullScreenAsRoot, ut as DismissableLayer, vt as composeEventHandlers } from "./Combination-BBPQRrDo.js";
|
|
14
14
|
import { t as require_jsx_runtime } from "./jsx-runtime-CTBg5pdT.js";
|
|
15
15
|
import { t as require_react_dom } from "./react-dom-CqtLRVZP.js";
|
|
16
16
|
import { t as toString_default } from "./toString-DbIAWQpF.js";
|
|
17
17
|
import { i as debounce_default, n as Constants } from "./constants-CytQ_3LM.js";
|
|
18
|
-
import { C as useEvent_default } from "./useTheme-
|
|
18
|
+
import { C as useEvent_default } from "./useTheme-CPybHVFN.js";
|
|
19
19
|
import { t as memoizeLastValue } from "./once-BqS42WgZ.js";
|
|
20
20
|
var ChevronRight = createLucideIcon("chevron-right", [["path", {
|
|
21
21
|
d: "m9 18 6-6-6-6",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-Bs6Z0kvn.js";
|
|
3
3
|
import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
|
|
4
|
-
import { C as useEvent_default } from "./useTheme-
|
|
4
|
+
import { C as useEvent_default } from "./useTheme-CPybHVFN.js";
|
|
5
5
|
import { t as invariant } from "./invariant-D9QLJ4SZ.js";
|
|
6
6
|
var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1), Result = {
|
|
7
7
|
error(e, s) {
|
|
@@ -4,12 +4,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
4
4
|
import { s as __toESM, t as __commonJSMin } from "./chunk-BNovOVIE.js";
|
|
5
5
|
import { t as require_react } from "./react-Bs6Z0kvn.js";
|
|
6
6
|
import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
|
|
7
|
-
import { l as createLucideIcon } from "./dist-
|
|
8
|
-
import { a as cva, g as Logger, y as cn } from "./button-
|
|
7
|
+
import { l as createLucideIcon } from "./dist-C0Rnbr-_.js";
|
|
8
|
+
import { a as cva, g as Logger, y as cn } from "./button-BKkuUpZh.js";
|
|
9
9
|
import { t as require_jsx_runtime } from "./jsx-runtime-CTBg5pdT.js";
|
|
10
10
|
import { r as KnownQueryParams } from "./constants-CytQ_3LM.js";
|
|
11
|
-
import { f as waitFor, p as isIslands, u as store, y as atom } from "./useTheme-
|
|
12
|
-
import { i as tableFromIPC } from "./loader-
|
|
11
|
+
import { f as waitFor, p as isIslands, u as store, y as atom } from "./useTheme-CPybHVFN.js";
|
|
12
|
+
import { i as tableFromIPC } from "./loader-CABJs6GU.js";
|
|
13
13
|
var CircleQuestionMark = createLucideIcon("circle-question-mark", [
|
|
14
14
|
["circle", {
|
|
15
15
|
cx: "12",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-Bs6Z0kvn.js";
|
|
3
3
|
import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
|
|
4
|
-
import { g as Logger } from "./button-
|
|
4
|
+
import { g as Logger } from "./button-BKkuUpZh.js";
|
|
5
5
|
import { n as once } from "./once-BqS42WgZ.js";
|
|
6
6
|
function testStorage(e) {
|
|
7
7
|
try {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-Bs6Z0kvn.js";
|
|
3
3
|
import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
|
|
4
|
-
import { g as Logger, s as OverridingHotkeyProvider, u as resolvePlatform } from "./button-
|
|
5
|
-
import { B as record, H as string, L as number, O as array, P as looseObject, R as object, W as union, k as boolean, w as _enum } from "./Combination-
|
|
4
|
+
import { g as Logger, s as OverridingHotkeyProvider, u as resolvePlatform } from "./button-BKkuUpZh.js";
|
|
5
|
+
import { B as record, H as string, L as number, O as array, P as looseObject, R as object, W as union, k as boolean, w as _enum } from "./Combination-BBPQRrDo.js";
|
|
6
6
|
import { t as _baseIsEqual_default } from "./_baseIsEqual-CvgsjYoW.js";
|
|
7
7
|
import { t as merge_default } from "./merge-NuyC7LN7.js";
|
|
8
8
|
function isEqual(e, A) {
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_react } from "./react-Bs6Z0kvn.js";
|
|
3
3
|
import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
|
|
4
|
-
import { S as CircleQuestionMark, a as AlertTitle, m as asRemoteURL, n as arrow, o as isValid, r as Alert, t as useDeepCompareMemoize } from "./useDeepCompareMemoize-
|
|
5
|
-
import { d as Objects, g as Logger, h as Events, y as cn } from "./button-
|
|
6
|
-
import "./Combination-
|
|
4
|
+
import { S as CircleQuestionMark, a as AlertTitle, m as asRemoteURL, n as arrow, o as isValid, r as Alert, t as useDeepCompareMemoize } from "./useDeepCompareMemoize-BWUwfh37.js";
|
|
5
|
+
import { d as Objects, g as Logger, h as Events, y as cn } from "./button-BKkuUpZh.js";
|
|
6
|
+
import "./Combination-BBPQRrDo.js";
|
|
7
7
|
import { t as require_jsx_runtime } from "./jsx-runtime-CTBg5pdT.js";
|
|
8
8
|
import "./react-dom-CqtLRVZP.js";
|
|
9
|
-
import { t as Tooltip } from "./tooltip-
|
|
9
|
+
import { t as Tooltip } from "./tooltip-CKG75XQa.js";
|
|
10
10
|
import { i as debounce_default } from "./constants-CytQ_3LM.js";
|
|
11
|
-
import { C as useEvent_default, n as useTheme } from "./useTheme-
|
|
12
|
-
import { a as
|
|
11
|
+
import { C as useEvent_default, n as useTheme } from "./useTheme-CPybHVFN.js";
|
|
12
|
+
import { a as getContainerWidth, n as vegaLoadData, s as tooltipHandler } from "./loader-CABJs6GU.js";
|
|
13
13
|
import { t as uniq_default } from "./uniq-H2E5nMLq.js";
|
|
14
|
-
import { n as ErrorBanner } from "./error-banner-
|
|
14
|
+
import { n as ErrorBanner } from "./error-banner-Dmi5ujan.js";
|
|
15
15
|
import { n as formats } from "./vega-loader.browser-CQ-lnUkI.js";
|
|
16
|
-
import { t as useAsyncData } from "./useAsyncData-
|
|
16
|
+
import { t as useAsyncData } from "./useAsyncData-CEjJxwFB.js";
|
|
17
17
|
import { t as j } from "./react-vega-C6kwcd86.js";
|
|
18
18
|
import "./defaultLocale-Bklbu-Tp.js";
|
|
19
19
|
import "./defaultLocale-CfQ4kBaV.js";
|
|
@@ -598,9 +598,12 @@ var VegaComponent = (e) => {
|
|
|
598
598
|
children: B.stack
|
|
599
599
|
})]
|
|
600
600
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
601
|
-
className: cn("relative"
|
|
601
|
+
className: cn("relative"),
|
|
602
602
|
onPointerDown: Events.stopPropagation(),
|
|
603
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
603
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
604
|
+
ref: R,
|
|
605
|
+
"data-container-width": getContainerWidth(W)
|
|
606
|
+
}), Q()]
|
|
604
607
|
})] });
|
|
605
608
|
};
|
|
606
609
|
function convertSetToList(e) {
|
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import React from "react";
|
|
|
4
4
|
import type { TopLevelSpec } from "vega-lite";
|
|
5
5
|
import { LazyVegaEmbed } from "@/components/charts/lazy";
|
|
6
6
|
import { tooltipHandler } from "@/components/charts/tooltip";
|
|
7
|
+
import { getContainerWidth } from "@/plugins/impl/vega/utils";
|
|
7
8
|
import { useTheme } from "@/theme/useTheme";
|
|
8
9
|
import type { ErrorMessage } from "./chart-spec/spec";
|
|
9
10
|
import { augmentSpecWithData } from "./chart-spec/spec";
|
|
@@ -30,6 +31,7 @@ export const LazyChart: React.FC<{
|
|
|
30
31
|
<React.Suspense fallback={<LoadingChart />}>
|
|
31
32
|
<LazyVegaEmbed
|
|
32
33
|
spec={spec}
|
|
34
|
+
data-container-width={getContainerWidth(spec)}
|
|
33
35
|
options={{
|
|
34
36
|
theme: theme === "dark" ? "dark" : undefined,
|
|
35
37
|
height: height,
|
|
@@ -224,6 +224,7 @@ export function renderChart(chartSpec: string, theme: Theme) {
|
|
|
224
224
|
return (
|
|
225
225
|
<Suspense fallback={LoadingChart}>
|
|
226
226
|
<LazyVegaEmbed
|
|
227
|
+
data-container-width="container"
|
|
227
228
|
spec={updateSpec(JSON.parse(chartSpec) as TopLevelFacetedUnitSpec)}
|
|
228
229
|
options={{
|
|
229
230
|
theme: theme === "dark" ? "dark" : "vox",
|
|
@@ -27,6 +27,7 @@ import { useOverflowDetection } from "@/hooks/useOverflowDetection";
|
|
|
27
27
|
import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
28
28
|
import { Banner } from "@/plugins/impl/common/error-banner";
|
|
29
29
|
import type { TopLevelFacetedUnitSpec } from "@/plugins/impl/data-explorer/queries/types";
|
|
30
|
+
import { getContainerWidth } from "@/plugins/impl/vega/utils";
|
|
30
31
|
import { useTheme } from "@/theme/useTheme";
|
|
31
32
|
import { Events } from "@/utils/events";
|
|
32
33
|
import { invariant } from "@/utils/invariant";
|
|
@@ -205,6 +206,7 @@ export const OutputRenderer: React.FC<{
|
|
|
205
206
|
<Suspense fallback={<ChartLoadingState />}>
|
|
206
207
|
<LazyVegaEmbed
|
|
207
208
|
spec={parsedJsonData as TopLevelFacetedUnitSpec}
|
|
209
|
+
data-container-width={getContainerWidth(parsedJsonData)}
|
|
208
210
|
options={{
|
|
209
211
|
theme: theme === "dark" ? "dark" : undefined,
|
|
210
212
|
mode: "vega-lite",
|
|
@@ -41,7 +41,10 @@ import { hasOnlyOneCellAtom, useCellActions } from "@/core/cells/cells";
|
|
|
41
41
|
import { type CellId, SETUP_CELL_ID } from "@/core/cells/ids";
|
|
42
42
|
import type { CellData } from "@/core/cells/types";
|
|
43
43
|
import { formatEditorViews } from "@/core/codemirror/format";
|
|
44
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
getCurrentLanguageAdapter,
|
|
46
|
+
toggleToLanguage,
|
|
47
|
+
} from "@/core/codemirror/language/commands";
|
|
45
48
|
import { switchLanguage } from "@/core/codemirror/language/extension";
|
|
46
49
|
import { MARKDOWN_INITIAL_HIDE_CODE } from "@/core/codemirror/language/languages/markdown";
|
|
47
50
|
import {
|
|
@@ -235,35 +238,41 @@ export function useCellActionButtons({ cell, closePopover }: Props) {
|
|
|
235
238
|
},
|
|
236
239
|
hidden: isSetupCell,
|
|
237
240
|
},
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
241
|
+
// We need to check this here because the user may have toggled the language
|
|
242
|
+
getCurrentLanguageAdapter(getEditorView()) === "sql"
|
|
243
|
+
? {
|
|
244
|
+
icon: <PythonIcon />,
|
|
245
|
+
label: "View as Python",
|
|
246
|
+
hotkey: "cell.viewAsSQL",
|
|
247
|
+
handle: () => {
|
|
248
|
+
const editorView = getEditorView();
|
|
249
|
+
if (!editorView) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
toggleToLanguage(editorView, "python", { force: true });
|
|
253
|
+
},
|
|
254
|
+
hidden: isSetupCell,
|
|
245
255
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
},
|
|
256
|
+
: {
|
|
257
|
+
icon: <DatabaseIcon size={13} strokeWidth={1.5} />,
|
|
258
|
+
label: "Convert to SQL",
|
|
259
|
+
hotkey: "cell.viewAsSQL",
|
|
260
|
+
handle: () => {
|
|
261
|
+
const editorView = getEditorView();
|
|
262
|
+
if (!editorView) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
maybeAddMarimoImport({
|
|
266
|
+
autoInstantiate,
|
|
267
|
+
createNewCell: createCell,
|
|
268
|
+
});
|
|
269
|
+
switchLanguage(editorView, {
|
|
270
|
+
language: "sql",
|
|
271
|
+
keepCodeAsIs: false,
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
hidden: isSetupCell,
|
|
275
|
+
},
|
|
267
276
|
],
|
|
268
277
|
|
|
269
278
|
// Movement
|
|
@@ -163,6 +163,13 @@ const CellEditorInternal = ({
|
|
|
163
163
|
}
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
+
const afterToggleSQL = useEvent(() => {
|
|
167
|
+
maybeAddMarimoImport({
|
|
168
|
+
autoInstantiate,
|
|
169
|
+
createNewCell: cellActions.createNewCell,
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
166
173
|
const aiEnabled = isAiEnabled(userConfig);
|
|
167
174
|
|
|
168
175
|
const extensions = useMemo(() => {
|
|
@@ -173,6 +180,7 @@ const CellEditorInternal = ({
|
|
|
173
180
|
cellActions: {
|
|
174
181
|
...cellActions,
|
|
175
182
|
afterToggleMarkdown,
|
|
183
|
+
afterToggleSQL,
|
|
176
184
|
onRun: handleRunCell,
|
|
177
185
|
deleteCell: handleDelete,
|
|
178
186
|
saveNotebook: saveOrNameNotebook,
|
|
@@ -267,6 +275,7 @@ const CellEditorInternal = ({
|
|
|
267
275
|
handleRunCell,
|
|
268
276
|
setAiCompletionCell,
|
|
269
277
|
afterToggleMarkdown,
|
|
278
|
+
afterToggleSQL,
|
|
270
279
|
setLanguageAdapter,
|
|
271
280
|
showHiddenCode,
|
|
272
281
|
saveOrNameNotebook,
|
|
@@ -5,6 +5,7 @@ import { useAtom } from "jotai";
|
|
|
5
5
|
import { CrosshairIcon, PinIcon, PinOffIcon, XIcon } from "lucide-react";
|
|
6
6
|
import type { PropsWithChildren } from "react";
|
|
7
7
|
import { Panel, PanelResizeHandle } from "react-resizable-panels";
|
|
8
|
+
import { raf2 } from "@/components/editor/navigation/focus-utils";
|
|
8
9
|
import { Button } from "@/components/ui/button";
|
|
9
10
|
import { Toggle } from "@/components/ui/toggle";
|
|
10
11
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
@@ -151,6 +152,11 @@ const ResizableComponent = ({ children }: ResizableComponentProps) => {
|
|
|
151
152
|
startingWidth: 400,
|
|
152
153
|
minWidth: 300,
|
|
153
154
|
maxWidth: 1500,
|
|
155
|
+
onResize: () => {
|
|
156
|
+
raf2(() => {
|
|
157
|
+
window.dispatchEvent(new Event("resize"));
|
|
158
|
+
});
|
|
159
|
+
},
|
|
154
160
|
});
|
|
155
161
|
|
|
156
162
|
return (
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { handleDragging } from "../utils";
|
|
5
|
+
|
|
6
|
+
describe("handleDragging", () => {
|
|
7
|
+
it("should dispatch a resize event after dragging ends", async () => {
|
|
8
|
+
const listener = vi.fn();
|
|
9
|
+
window.addEventListener("resize", listener);
|
|
10
|
+
|
|
11
|
+
handleDragging(false);
|
|
12
|
+
|
|
13
|
+
// raf2: wait two animation frames
|
|
14
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
15
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
16
|
+
|
|
17
|
+
expect(listener).toHaveBeenCalledTimes(1);
|
|
18
|
+
|
|
19
|
+
window.removeEventListener("resize", listener);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should not dispatch a resize event while dragging", async () => {
|
|
23
|
+
const listener = vi.fn();
|
|
24
|
+
window.addEventListener("resize", listener);
|
|
25
|
+
|
|
26
|
+
handleDragging(true);
|
|
27
|
+
|
|
28
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
29
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
30
|
+
|
|
31
|
+
expect(listener).not.toHaveBeenCalled();
|
|
32
|
+
|
|
33
|
+
window.removeEventListener("resize", listener);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -17,6 +17,7 @@ import "./app-chrome.css";
|
|
|
17
17
|
import { TooltipProvider } from "@radix-ui/react-tooltip";
|
|
18
18
|
import { useAtom, useAtomValue } from "jotai";
|
|
19
19
|
import { XIcon } from "lucide-react";
|
|
20
|
+
import useEvent from "react-use-event-hook";
|
|
20
21
|
import { Button } from "@/components/ui/button";
|
|
21
22
|
import { ReorderableList } from "@/components/ui/reorderable-list";
|
|
22
23
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
@@ -26,6 +27,7 @@ import { capabilitiesAtom } from "@/core/config/capabilities";
|
|
|
26
27
|
import { getFeatureFlag } from "@/core/config/feature-flag";
|
|
27
28
|
import { cn } from "@/utils/cn";
|
|
28
29
|
import { ErrorBoundary } from "../../boundary/ErrorBoundary";
|
|
30
|
+
import { raf2 } from "../../navigation/focus-utils";
|
|
29
31
|
import { ContextAwarePanel } from "../panels/context-aware-panel/context-aware-panel";
|
|
30
32
|
import { PanelSectionProvider } from "../panels/panel-context";
|
|
31
33
|
import { panelLayoutAtom, useChromeActions, useChromeState } from "../state";
|
|
@@ -147,6 +149,14 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
147
149
|
});
|
|
148
150
|
}, [panelLayout.sidebar, capabilities]);
|
|
149
151
|
|
|
152
|
+
const emitResizeEvent = useEvent(() => {
|
|
153
|
+
// HACK: Unfortunately, we have to do this twice to make sure the
|
|
154
|
+
// panel is fully expanded before we dispatch the resize event
|
|
155
|
+
raf2(() => {
|
|
156
|
+
window.dispatchEvent(new Event("resize"));
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
150
160
|
// sync sidebar
|
|
151
161
|
useEffect(() => {
|
|
152
162
|
if (!sidebarRef.current) {
|
|
@@ -162,13 +172,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
162
172
|
}
|
|
163
173
|
|
|
164
174
|
// Dispatch a resize event so widgets know to resize
|
|
165
|
-
|
|
166
|
-
// HACK: Unfortunately, we have to do this twice to make sure it the
|
|
167
|
-
// panel is fully expanded before we dispatch the resize event
|
|
168
|
-
requestAnimationFrame(() => {
|
|
169
|
-
window.dispatchEvent(new Event("resize"));
|
|
170
|
-
});
|
|
171
|
-
});
|
|
175
|
+
emitResizeEvent();
|
|
172
176
|
}, [isSidebarOpen]);
|
|
173
177
|
|
|
174
178
|
// sync panel
|
|
@@ -186,13 +190,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
186
190
|
}
|
|
187
191
|
|
|
188
192
|
// Dispatch a resize event so widgets know to resize
|
|
189
|
-
|
|
190
|
-
// HACK: Unfortunately, we have to do this twice to make sure it the
|
|
191
|
-
// panel is fully expanded before we dispatch the resize event
|
|
192
|
-
requestAnimationFrame(() => {
|
|
193
|
-
window.dispatchEvent(new Event("resize"));
|
|
194
|
-
});
|
|
195
|
-
});
|
|
193
|
+
emitResizeEvent();
|
|
196
194
|
}, [isDeveloperPanelOpen]);
|
|
197
195
|
|
|
198
196
|
// Auto-correct developer panel selection when the selected tab is no longer available
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
+
import { raf2 } from "../../navigation/focus-utils";
|
|
4
|
+
|
|
3
5
|
export function handleDragging(isDragging: boolean) {
|
|
4
6
|
if (!isDragging) {
|
|
5
7
|
// Once the user is done dragging, dispatch a resize event
|
|
6
|
-
|
|
8
|
+
raf2(() => {
|
|
9
|
+
window.dispatchEvent(new Event("resize"));
|
|
10
|
+
});
|
|
7
11
|
}
|
|
8
12
|
}
|
|
@@ -5,6 +5,7 @@ import { HourglassIcon, LockIcon, UnlinkIcon } from "lucide-react";
|
|
|
5
5
|
import React from "react";
|
|
6
6
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
7
7
|
import { notebookScrollToRunning } from "@/core/cells/actions";
|
|
8
|
+
import { onlyScratchpadIsRunningAtom } from "@/core/cells/cells";
|
|
8
9
|
import { viewStateAtom } from "@/core/mode";
|
|
9
10
|
import { type ConnectionStatus, WebSocketState } from "@/core/websocket/types";
|
|
10
11
|
import { cn } from "@/utils/cn";
|
|
@@ -52,17 +53,24 @@ const LockedIcon = () => (
|
|
|
52
53
|
</Tooltip>
|
|
53
54
|
);
|
|
54
55
|
|
|
55
|
-
const RunningIcon = () =>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
const RunningIcon = () => {
|
|
57
|
+
const scratchpadOnly = useAtomValue(onlyScratchpadIsRunningAtom);
|
|
58
|
+
const tooltip = scratchpadOnly
|
|
59
|
+
? "Scratchpad is running"
|
|
60
|
+
: "Jump to running cell";
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Tooltip content={tooltip} side="right">
|
|
64
|
+
<div
|
|
65
|
+
className={topLeftStatus}
|
|
66
|
+
data-testid="loading-indicator"
|
|
67
|
+
onClick={scratchpadOnly ? undefined : notebookScrollToRunning}
|
|
68
|
+
>
|
|
69
|
+
<HourglassIcon className="running-app-icon" size={30} strokeWidth={1} />
|
|
70
|
+
</div>
|
|
71
|
+
</Tooltip>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
66
74
|
|
|
67
75
|
const NoiseBackground = () => (
|
|
68
76
|
<>
|
|
@@ -158,12 +158,19 @@ export const GridLayoutRenderer: React.FC<Props> = ({
|
|
|
158
158
|
compactType={null}
|
|
159
159
|
preventCollision={true}
|
|
160
160
|
rowHeight={layout.rowHeight}
|
|
161
|
-
onLayoutChange={(cellLayouts) =>
|
|
161
|
+
onLayoutChange={(cellLayouts) => {
|
|
162
|
+
// Don't update state in read mode — the layout is static and
|
|
163
|
+
// updating triggers a re-render cycle that causes an infinite loop
|
|
164
|
+
// (React error https://react.dev/errors/185 Maximum update depth exceeded).
|
|
165
|
+
// https://github.com/marimo-team/marimo/issues/8644
|
|
166
|
+
if (isReading) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
162
169
|
setLayout({
|
|
163
170
|
...layout,
|
|
164
171
|
cells: cellLayouts,
|
|
165
|
-
})
|
|
166
|
-
}
|
|
172
|
+
});
|
|
173
|
+
}}
|
|
167
174
|
droppingItem={
|
|
168
175
|
droppingItem
|
|
169
176
|
? {
|
package/src/core/cells/cells.ts
CHANGED
|
@@ -1640,6 +1640,12 @@ export const cellsRuntimeAtom = atom((get) => get(notebookAtom).cellRuntime);
|
|
|
1640
1640
|
export const notebookIsRunningAtom = atom((get) =>
|
|
1641
1641
|
notebookIsRunning(get(notebookAtom)),
|
|
1642
1642
|
);
|
|
1643
|
+
export const onlyScratchpadIsRunningAtom = atom((get) => {
|
|
1644
|
+
const { cellRuntime } = get(notebookAtom);
|
|
1645
|
+
return Object.entries(cellRuntime).every(
|
|
1646
|
+
([id, rt]) => rt.status !== "running" || id === SCRATCH_CELL_ID,
|
|
1647
|
+
);
|
|
1648
|
+
});
|
|
1643
1649
|
export const notebookQueuedOrRunningCountAtom = atom((get) =>
|
|
1644
1650
|
notebookQueueOrRunningCount(get(notebookAtom)),
|
|
1645
1651
|
);
|
package/src/core/cells/utils.ts
CHANGED
|
@@ -11,6 +11,7 @@ export function notebookIsRunning(state: NotebookState) {
|
|
|
11
11
|
(cell) => cell.status === "running",
|
|
12
12
|
);
|
|
13
13
|
}
|
|
14
|
+
|
|
14
15
|
export function notebookQueueOrRunningCount(state: NotebookState) {
|
|
15
16
|
return Object.values(state.cellRuntime).filter(
|
|
16
17
|
(cell) => cell.status === "running" || cell.status === "queued",
|
|
@@ -45,6 +45,7 @@ function getOpts() {
|
|
|
45
45
|
onRun: namedFunction("onRun"),
|
|
46
46
|
deleteCell: namedFunction("deleteCell"),
|
|
47
47
|
afterToggleMarkdown: namedFunction("afterToggleMarkdown"),
|
|
48
|
+
afterToggleSQL: namedFunction("afterToggleSQL"),
|
|
48
49
|
} as unknown as CodemirrorCellActions,
|
|
49
50
|
completionConfig: {
|
|
50
51
|
activate_on_typing: false,
|
|
@@ -42,6 +42,26 @@ export function formatKeymapExtension(hotkeys: HotkeyProvider) {
|
|
|
42
42
|
actions.afterToggleMarkdown();
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
return response !== false;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: hotkeys.getHotkey("cell.viewAsSQL").key,
|
|
50
|
+
preventDefault: true,
|
|
51
|
+
run: (ev) => {
|
|
52
|
+
const currentLanguage = getCurrentLanguageAdapter(ev);
|
|
53
|
+
const destinationLanguage =
|
|
54
|
+
currentLanguage === "sql" ? "python" : "sql";
|
|
55
|
+
|
|
56
|
+
const response = toggleToLanguage(ev, destinationLanguage, {
|
|
57
|
+
force: true,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (response === "sql") {
|
|
61
|
+
const actions = ev.state.facet(cellActionsState);
|
|
62
|
+
actions.afterToggleSQL();
|
|
63
|
+
}
|
|
64
|
+
|
|
45
65
|
return response !== false;
|
|
46
66
|
},
|
|
47
67
|
},
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
import type { EditorState } from "@codemirror/state";
|
|
4
4
|
import type { EditorView } from "@codemirror/view";
|
|
5
5
|
import { replaceEditorContent } from "../replace-editor-content";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
languageAdapterFromCode,
|
|
8
|
+
languageAdapterState,
|
|
9
|
+
switchLanguage,
|
|
10
|
+
} from "./extension";
|
|
7
11
|
import { languageMetadataField } from "./metadata";
|
|
8
12
|
|
|
9
13
|
/**
|
|
@@ -35,6 +39,17 @@ export function updateEditorCodeFromPython(
|
|
|
35
39
|
editor: EditorView,
|
|
36
40
|
pythonCode: string,
|
|
37
41
|
): string {
|
|
42
|
+
const currentAdapter = editor.state.field(languageAdapterState);
|
|
43
|
+
const correctAdapter = languageAdapterFromCode(pythonCode);
|
|
44
|
+
|
|
45
|
+
// If the language type changed (e.g., markdown → python), switch adapters
|
|
46
|
+
if (correctAdapter.type !== currentAdapter.type) {
|
|
47
|
+
switchLanguage(editor, {
|
|
48
|
+
language: correctAdapter.type,
|
|
49
|
+
keepCodeAsIs: true,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
38
53
|
const languageAdapter = editor.state.field(languageAdapterState);
|
|
39
54
|
const [code] = languageAdapter.transformIn(pythonCode);
|
|
40
55
|
// Use replaceEditorContent which preserves cursor position when focused
|