@myst-theme/jupyter 0.18.0 → 1.0.0

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.
@@ -0,0 +1,13 @@
1
+ import type { IOutput } from '@jupyterlab/nbformat';
2
+ import type { ThebeCore } from 'thebe-core';
3
+ import { type MinifiedOutput } from 'nbtx';
4
+ export declare function ActiveOutputRenderer({ outputsId, initialData, core, }: {
5
+ outputsId: string;
6
+ initialData: IOutput[];
7
+ core: ThebeCore;
8
+ }): import("react/jsx-runtime").JSX.Element;
9
+ export declare function ActiveJupyterCellOutputs({ outputsId, outputs, }: {
10
+ outputsId: string;
11
+ outputs: MinifiedOutput[];
12
+ }): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=active.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active.d.ts","sourceRoot":"","sources":["../src/active.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK5C,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,MAAM,CAAC;AAM9D,wBAAgB,oBAAoB,CAAC,EACnC,SAAS,EACT,WAAW,EACX,IAAI,GACL,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,IAAI,EAAE,SAAS,CAAC;CACjB,2CA0CA;AAED,wBAAgB,wBAAwB,CAAC,EACvC,SAAS,EACT,OAAO,GACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B,2CA6CA"}
package/dist/active.js ADDED
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { useCellExecution } from './execute/index.js';
4
+ import { usePlaceholder } from './decoration.js';
5
+ import { MyST } from 'myst-to-react';
6
+ import classNames from 'classnames';
7
+ import { convertToIOutputs } from 'nbtx';
8
+ import { useThebeLoader } from 'thebe-react';
9
+ import { useFetchAnyTruncatedContent } from './hooks.js';
10
+ import { useXRefState } from '@myst-theme/providers';
11
+ import { fetchAndEncodeOutputImages } from './convertImages.js';
12
+ export function ActiveOutputRenderer({ outputsId, initialData, core, }) {
13
+ var _a;
14
+ const exec = useCellExecution(outputsId);
15
+ const placeholder = usePlaceholder();
16
+ const ref = useRef(null);
17
+ useEffect(() => {
18
+ var _a, _b, _c;
19
+ if (!ref.current || !(exec === null || exec === void 0 ? void 0 : exec.cell)) {
20
+ console.debug(`Jupyter: No cell ref available for cell ${outputsId}:${(_a = exec === null || exec === void 0 ? void 0 : exec.cell) === null || _a === void 0 ? void 0 : _a.id}`);
21
+ return;
22
+ }
23
+ const verb = exec.cell.isAttachedToDOM ? 'reattaching' : 'attaching';
24
+ console.debug(`${verb} cell ${exec.cell.id} to DOM at:`, {
25
+ el: ref.current,
26
+ connected: ref.current.isConnected,
27
+ data: (_b = core === null || core === void 0 ? void 0 : core.stripWidgets(initialData)) !== null && _b !== void 0 ? _b : initialData,
28
+ });
29
+ exec.cell.attachToDOM(ref.current);
30
+ if (exec.cell.executionCount == null) {
31
+ exec.cell.initOutputs((_c = core === null || core === void 0 ? void 0 : core.stripWidgets(initialData, true, placeholder ? () => '' : undefined)) !== null && _c !== void 0 ? _c : initialData);
32
+ }
33
+ }, [ref === null || ref === void 0 ? void 0 : ref.current, exec === null || exec === void 0 ? void 0 : exec.cell]);
34
+ const executed = ((_a = exec === null || exec === void 0 ? void 0 : exec.cell) === null || _a === void 0 ? void 0 : _a.executionCount) != null;
35
+ console.debug(`Jupyter: Cell ${outputsId} executed: ${executed}; Show output: ${executed || !placeholder}`);
36
+ return (_jsxs("div", { children: [_jsx("div", { ref: ref, "data-thebe-active-ref": "true", className: classNames('relative', { 'invisible h-0': !executed && placeholder }) }), exec.ready && placeholder && !executed && _jsx(MyST, { ast: placeholder })] }));
37
+ }
38
+ export function ActiveJupyterCellOutputs({ outputsId, outputs, }) {
39
+ const { core, load } = useThebeLoader();
40
+ const { inCrossRef } = useXRefState();
41
+ const exec = useCellExecution(outputsId);
42
+ // NOTE: could maybe lift this into the outputs renderer, from here and the passive renderer
43
+ // but the images will be cached anywways, so there is limited benefit
44
+ const { data, error } = useFetchAnyTruncatedContent(outputs);
45
+ const [fullOutputs, setFullOutputs] = useState(null);
46
+ useEffect(() => {
47
+ if (core)
48
+ return;
49
+ load();
50
+ }, [core, load]);
51
+ useEffect(() => {
52
+ if (!data || fullOutputs != null)
53
+ return;
54
+ fetchAndEncodeOutputImages(data).then((out) => {
55
+ const compactOutputs = convertToIOutputs(out, {});
56
+ setFullOutputs(compactOutputs);
57
+ });
58
+ }, [outputsId, data, fullOutputs]);
59
+ if (error) {
60
+ console.error(error);
61
+ return _jsxs("div", { className: "text-red-500", children: ["Error rendering output: ", error.message] });
62
+ }
63
+ if (!inCrossRef && (exec === null || exec === void 0 ? void 0 : exec.ready)) {
64
+ return (_jsxs("div", { children: [!fullOutputs && _jsx("div", { className: "p-2.5", children: "Fetching full output data..." }), core && fullOutputs && (_jsx(ActiveOutputRenderer, { outputsId: outputsId, initialData: fullOutputs, core: core }, outputsId))] }));
65
+ }
66
+ return _jsx("div", { children: "ActiveJupyterCellOutputs in cross reference" });
67
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/components.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,+BAI1B;IACD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC;CAC1C,4CAWA,CAAC;AAEF,eAAO,MAAM,aAAa,yBAA0B;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,4CAWtE,CAAC"}
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/components.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,GAAI,4BAI9B;IACD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC;CAC1C,4CAWA,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,sBAAsB;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,4CAWtE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"decoration.d.ts","sourceRoot":"","sources":["../src/decoration.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAsB/C,wBAAgB,cAAc,4BAG7B;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,KAA0B,EAC1B,GAAG,EACH,aAAa,GACd,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,2CAkEA"}
1
+ {"version":3,"file":"decoration.d.ts","sourceRoot":"","sources":["../src/decoration.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA4B/C,wBAAgB,cAAc,4BAG7B;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,KAA0B,EAC1B,GAAG,EACH,aAAa,GACd,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,2CAuEA"}
@@ -1,10 +1,10 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { SourceFileKind } from 'myst-spec-ext';
4
4
  import { useCellExecution } from './execute/index.js';
5
5
  import { ArticleResetNotebook, ArticleRunNotebook, ArticleStatusBadge, } from './controls/ArticleCellControls.js';
6
6
  import { JupyterIcon } from '@scienceicons/react/24/solid';
7
- import { useLinkProvider, useBaseurl, withBaseurl, useThemeTop } from '@myst-theme/providers';
7
+ import { useLinkProvider, useBaseurl, withBaseurl, useThemeTop, useXRefState, } from '@myst-theme/providers';
8
8
  import { useComputeOptions } from './providers.js';
9
9
  const PlaceholderContext = React.createContext({});
10
10
  function PlaceholderProvider({ placeholder, children, }) {
@@ -21,17 +21,19 @@ export function OutputDecoration({ outputId, placeholder, children, title = 'Jup
21
21
  const Link = useLinkProvider();
22
22
  const top = useThemeTop();
23
23
  const baseurl = useBaseurl();
24
+ const { inCrossRef } = useXRefState();
24
25
  const showComputeControls = (compute === null || compute === void 0 ? void 0 : compute.enabled) &&
25
26
  (compute === null || compute === void 0 ? void 0 : compute.features.figureCompute) &&
26
27
  kind === SourceFileKind.Article &&
27
- !remoteBaseUrl;
28
+ !remoteBaseUrl &&
29
+ !inCrossRef;
28
30
  if (showComputeControls) {
29
- return (_jsxs("div", { className: "myst-jp-output-deco mb-4 shadow", children: [_jsx("div", { className: "myst-jp-output-deco-header sticky z-[2] w-full bg-gray-100/80 backdrop-blur dark:bg-neutral-800/80 py-1 px-2", style: { top }, children: _jsxs("div", { className: "myst-jp-output-deco-inner flex items-center", children: [_jsxs("div", { className: "myst-jp-output-deco-source flex items-center", children: [_jsx(JupyterIcon, { width: "1.25rem", height: "1.25rem", className: "inline-block" }), _jsx("span", { className: "myst-jp-output-deco-label ml-2", children: "Source:" }), url && (_jsx(Link, { to: withBaseurl(url, remoteBaseUrl !== null && remoteBaseUrl !== void 0 ? remoteBaseUrl : baseurl), className: "myst-jp-output-deco-link ml-2 no-underline text-normal hover:underline", children: title }))] }), _jsx("div", { className: "flex-grow" }), _jsx(ArticleStatusBadge, { id: outputId }), _jsx(ArticleRunNotebook, { id: outputId }), _jsx(ArticleResetNotebook, { id: outputId })] }) }), _jsx(PlaceholderProvider, { placeholder: placeholder, children: children })] }));
31
+ return (_jsxs("div", { "data-name": "output-decoration-with-compute-ctrls", className: "mb-4 shadow myst-jp-output-deco", children: [_jsx("div", { className: "myst-jp-output-deco-header sticky z-[2] w-full bg-gray-100/80 backdrop-blur dark:bg-neutral-800/80 py-1 px-2", style: { top }, children: _jsxs("div", { className: "flex items-center myst-jp-output-deco-inner", children: [_jsxs("div", { className: "flex items-center myst-jp-output-deco-source", children: [_jsx(JupyterIcon, { width: "1.25rem", height: "1.25rem", className: "inline-block" }), _jsx("span", { className: "ml-2 myst-jp-output-deco-label", children: "Source:" }), url && (_jsx(Link, { to: withBaseurl(url, remoteBaseUrl !== null && remoteBaseUrl !== void 0 ? remoteBaseUrl : baseurl), className: "ml-2 no-underline myst-jp-output-deco-link text-normal hover:underline", children: title }))] }), _jsx("div", { className: "flex-grow" }), _jsx(ArticleStatusBadge, { id: outputId }), _jsx(ArticleRunNotebook, { id: outputId }), _jsx(ArticleResetNotebook, { id: outputId })] }) }), _jsx(PlaceholderProvider, { placeholder: placeholder, children: children })] }));
30
32
  }
31
33
  // light
32
34
  if (kind === SourceFileKind.Article) {
33
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "myst-jp-output-deco-light flex items-center justify-end text-xs", children: [_jsx(JupyterIcon, { width: "0.75rem", height: "0.75rem", className: "inline-block" }), _jsx("div", { className: "myst-jp-output-deco-label ml-1", children: "Source:" }), url && (_jsx(Link, { to: withBaseurl(url, remoteBaseUrl !== null && remoteBaseUrl !== void 0 ? remoteBaseUrl : baseurl), className: "myst-jp-output-deco-link ml-1 no-underline text-normal hover:underline", children: title }))] }), _jsx(PlaceholderProvider, { placeholder: placeholder, children: children })] }));
35
+ return (_jsxs("div", { "data-name": "output-decoration-article", children: [_jsxs("div", { className: "flex justify-end items-center text-xsmyst-jp-output-deco-light", children: [_jsx(JupyterIcon, { width: "0.75rem", height: "0.75rem", className: "inline-block" }), _jsx("div", { className: "ml-1 myst-jp-output-deco-label", children: "Source:" }), url && (_jsx(Link, { to: withBaseurl(url, remoteBaseUrl !== null && remoteBaseUrl !== void 0 ? remoteBaseUrl : baseurl), className: "ml-1 no-underline myst-jp-output-deco-link text-normal hover:underline", children: title }))] }), _jsx(PlaceholderProvider, { placeholder: placeholder, children: children })] }));
34
36
  }
35
37
  // Notebook outputs do not need any decoration
36
- return _jsx(_Fragment, { children: children });
38
+ return _jsx("div", { "data-name": "output-decoration-notebook-output", children: children });
37
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,wBAAgB,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,2CAcpD"}
1
+ {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,wBAAgB,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,2CA6BpD"}
package/dist/embed.js CHANGED
@@ -1,10 +1,16 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { OutputDecoration } from './decoration.js';
3
3
  import { MyST } from 'myst-to-react';
4
+ import { OutputsContextProvider } from './providers.js';
4
5
  export function Embed({ node }) {
5
- var _a, _b, _c, _d;
6
+ var _a, _b, _c, _d, _e, _f, _g;
6
7
  const output = (_a = node.children) === null || _a === void 0 ? void 0 : _a.find((child) => child.type === 'output');
7
- if (!output)
8
- return _jsx(MyST, { ast: node.children });
9
- return (_jsx(OutputDecoration, { outputId: output.id, title: (_b = node.source) === null || _b === void 0 ? void 0 : _b.title, url: (_c = node.source) === null || _c === void 0 ? void 0 : _c.url, remoteBaseUrl: (_d = node.source) === null || _d === void 0 ? void 0 : _d.remoteBaseUrl, children: _jsx(MyST, { ast: node.children }) }, node.key));
8
+ const outputs = (_b = node.children) === null || _b === void 0 ? void 0 : _b.find((child) => child.type === 'outputs');
9
+ if (outputs) {
10
+ return (_jsx(OutputDecoration, { outputId: (_c = outputs.id) !== null && _c !== void 0 ? _c : outputs.key, title: (_d = node.source) === null || _d === void 0 ? void 0 : _d.title, url: (_e = node.source) === null || _e === void 0 ? void 0 : _e.url, remoteBaseUrl: (_f = node.source) === null || _f === void 0 ? void 0 : _f.remoteBaseUrl, children: _jsx(OutputsContextProvider, { outputsId: (_g = outputs.id) !== null && _g !== void 0 ? _g : outputs.key, children: _jsx(MyST, { ast: node.children }) }) }, node.key));
11
+ }
12
+ else if (output) {
13
+ return (_jsx(OutputsContextProvider, { outputsId: output.key, children: _jsx(MyST, { ast: node.children }) }));
14
+ }
15
+ return _jsx(MyST, { ast: node.children });
10
16
  }
@@ -38,7 +38,7 @@ export function notebookFromMdast(core, config, pageSlug, notebookSlug, mdast, i
38
38
  // no metadata included in mdast yet
39
39
  //Object.assign(notebook.metadata, ipynb.metadata);
40
40
  notebook.cells = mdast.children.map((block) => {
41
- var _a, _b, _c;
41
+ var _a, _b, _c, _d;
42
42
  if (block.type !== 'block')
43
43
  console.warn(`Unexpected block type ${block.type}`);
44
44
  const executableNodes = executableNodesFromBlock(block);
@@ -53,7 +53,7 @@ export function notebookFromMdast(core, config, pageSlug, notebookSlug, mdast, i
53
53
  cellId: block.key,
54
54
  };
55
55
  idkmap[block.key] = target; // can reference from block in notebook views
56
- idkmap[output.id] = target; // can reference from output in article views
56
+ idkmap[(_a = output.id) !== null && _a !== void 0 ? _a : output.key] = target; // can reference from output in article views
57
57
  // include identifiers to enable lookup by (normalized) labels
58
58
  if (block.identifier)
59
59
  idkmap[block.identifier] = target;
@@ -61,12 +61,12 @@ export function notebookFromMdast(core, config, pageSlug, notebookSlug, mdast, i
61
61
  idkmap[codeCell.identifier] = target;
62
62
  if (output.identifier)
63
63
  idkmap[output.identifier] = target;
64
- return new core.ThebeCodeCell(target.cellId, notebook.id, (_a = codeCell.value) !== null && _a !== void 0 ? _a : '', config, (_b = block.data) !== null && _b !== void 0 ? _b : {}, notebook.rendermime);
64
+ return new core.ThebeCodeCell(target.cellId, notebook.id, (_b = codeCell.value) !== null && _b !== void 0 ? _b : '', config, (_c = block.data) !== null && _c !== void 0 ? _c : {}, notebook.rendermime);
65
65
  }
66
66
  else {
67
67
  // assume content - concatenate it
68
68
  // TODO inject cell metadata
69
- const cell = new core.ThebeMarkdownCell(block.key, notebook.id, block.children.reduce((acc, child) => { var _a; return acc + '\n' + ((_a = child.value) !== null && _a !== void 0 ? _a : ''); }, ''), (_c = block.data) !== null && _c !== void 0 ? _c : {}, notebook.rendermime);
69
+ const cell = new core.ThebeMarkdownCell(block.key, notebook.id, block.children.reduce((acc, child) => { var _a; return acc + '\n' + ((_a = child.value) !== null && _a !== void 0 ? _a : ''); }, ''), (_d = block.data) !== null && _d !== void 0 ? _d : {}, notebook.rendermime);
70
70
  return cell;
71
71
  }
72
72
  });
@@ -1 +1 @@
1
- {"version":3,"file":"figure.d.ts","sourceRoot":"","sources":["../src/figure.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,2CA0BrD"}
1
+ {"version":3,"file":"figure.d.ts","sourceRoot":"","sources":["../src/figure.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/C,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,2CAgDrD"}
package/dist/figure.js CHANGED
@@ -1,17 +1,24 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { SourceFileKind } from 'myst-spec-ext';
3
3
  import { DEFAULT_RENDERERS, MyST } from 'myst-to-react';
4
4
  import classNames from 'classnames';
5
5
  import { OutputDecoration } from './decoration.js';
6
+ import { OutputsContextProvider } from './providers.js';
6
7
  export function Figure({ node }) {
7
- var _a, _b, _c, _d, _e, _f, _g;
8
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
8
9
  const { base: Container } = DEFAULT_RENDERERS['container'];
9
10
  const isFromJupyer = ((_a = node.source) === null || _a === void 0 ? void 0 : _a.kind) === SourceFileKind.Notebook;
10
11
  const output = (_b = node.children) === null || _b === void 0 ? void 0 : _b.find((child) => child.type === 'output');
11
- if (isFromJupyer && !!output) {
12
- const placeholder = (_c = node.children) === null || _c === void 0 ? void 0 : _c.find((child) => child.type === 'image' && child.placeholder);
13
- const others = (_d = node.children) === null || _d === void 0 ? void 0 : _d.filter((child) => !(child.type === 'image' && child.placeholder));
14
- return (_jsx("figure", { id: node.html_id || node.identifier || node.key, className: classNames('myst-jp-figure', { subcontainer: node.subcontainer }, node.class), children: _jsx(OutputDecoration, { outputId: output.id, placeholder: placeholder, title: (_e = node.source) === null || _e === void 0 ? void 0 : _e.title, url: (_f = node.source) === null || _f === void 0 ? void 0 : _f.url, remoteBaseUrl: (_g = node.source) === null || _g === void 0 ? void 0 : _g.remoteBaseUrl, children: _jsx(MyST, { ast: others }) }, node.key) }));
12
+ const outputs = (_c = node.children) === null || _c === void 0 ? void 0 : _c.find((child) => child.type === 'outputs');
13
+ if (isFromJupyer) {
14
+ if (outputs) {
15
+ const placeholder = (_d = node.children) === null || _d === void 0 ? void 0 : _d.find((child) => child.type === 'image' && child.placeholder);
16
+ const others = (_e = node.children) === null || _e === void 0 ? void 0 : _e.filter((child) => !(child.type === 'image' && child.placeholder));
17
+ return (_jsx("figure", { id: node.html_id || node.identifier || node.key, className: classNames('myst-jp-figure', { subcontainer: node.subcontainer }, node.class), children: _jsx(OutputDecoration, { outputId: (_f = outputs.id) !== null && _f !== void 0 ? _f : outputs.key, placeholder: placeholder, title: (_g = node.source) === null || _g === void 0 ? void 0 : _g.title, url: (_h = node.source) === null || _h === void 0 ? void 0 : _h.url, remoteBaseUrl: (_j = node.source) === null || _j === void 0 ? void 0 : _j.remoteBaseUrl, children: _jsx(OutputsContextProvider, { outputsId: (_k = outputs.id) !== null && _k !== void 0 ? _k : outputs.key, children: _jsx(MyST, { ast: others }) }) }, node.key) }));
18
+ }
19
+ else if (output) {
20
+ return (_jsx("div", { className: "border border-gred-500", children: _jsxs("details", { children: [_jsx("summary", { children: "Legacy Output Embedded" }), _jsx("pre", { children: JSON.stringify(output, null, 2) })] }) }));
21
+ }
15
22
  }
16
23
  return _jsx(Container, { node: node });
17
24
  }
package/dist/jupyter.d.ts CHANGED
@@ -1,7 +1,13 @@
1
1
  import React from 'react';
2
2
  import type { MinifiedOutput } from 'nbtx';
3
- export declare const JupyterOutputs: React.MemoExoticComponent<({ id, outputs }: {
4
- id: string;
5
- outputs: MinifiedOutput[];
3
+ /**
4
+ * Render a single output as a Jupyter output.
5
+ *
6
+ * @param id - The id of the cell.
7
+ * @param output - The output data.
8
+ */
9
+ export declare const JupyterOutput: React.MemoExoticComponent<({ outputsId, output }: {
10
+ outputsId: string;
11
+ output: MinifiedOutput;
6
12
  }) => import("react/jsx-runtime").JSX.Element>;
7
13
  //# sourceMappingURL=jupyter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jupyter.d.ts","sourceRoot":"","sources":["../src/jupyter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAG3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AA4F3C,eAAO,MAAM,cAAc,8CACP;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,6CAwD5D,CAAC"}
1
+ {"version":3,"file":"jupyter.d.ts","sourceRoot":"","sources":["../src/jupyter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAO3C;;;;;GAKG;AACH,eAAO,MAAM,aAAa,oDACA;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,6CAiDtE,CAAC"}
package/dist/jupyter.js CHANGED
@@ -1,86 +1,47 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useEffect, useRef, useState } from 'react';
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useEffect, useState } from 'react';
3
3
  import { useFetchAnyTruncatedContent } from './hooks.js';
4
4
  import { convertToIOutputs } from 'nbtx';
5
5
  import { fetchAndEncodeOutputImages } from './convertImages.js';
6
6
  import { SourceFileKind } from 'myst-spec-ext';
7
- import { useXRefState } from '@myst-theme/providers';
8
7
  import { useThebeLoader } from 'thebe-react';
9
- import { useCellExecution } from './execute/index.js';
10
- import { usePlaceholder } from './decoration.js';
11
- import { MyST } from 'myst-to-react';
12
- import classNames from 'classnames';
13
- import { usePlotlyPassively } from './plotly.js';
14
- function ActiveOutputRenderer({ id, initialData, core, }) {
15
- var _a;
16
- const exec = useCellExecution(id);
17
- const placeholder = usePlaceholder();
18
- const ref = useRef(null);
19
- useEffect(() => {
20
- var _a, _b, _c;
21
- if (!ref.current || !(exec === null || exec === void 0 ? void 0 : exec.cell)) {
22
- console.debug(`Jupyter: No cell ref available for cell ${id}:${(_a = exec === null || exec === void 0 ? void 0 : exec.cell) === null || _a === void 0 ? void 0 : _a.id}`);
23
- return;
24
- }
25
- const verb = exec.cell.isAttachedToDOM ? 'reattaching' : 'attaching';
26
- console.debug(`${verb} cell ${exec.cell.id} to DOM at:`, {
27
- el: ref.current,
28
- connected: ref.current.isConnected,
29
- data: (_b = core === null || core === void 0 ? void 0 : core.stripWidgets(initialData)) !== null && _b !== void 0 ? _b : initialData,
30
- });
31
- exec.cell.attachToDOM(ref.current);
32
- if (exec.cell.executionCount == null) {
33
- exec.cell.initOutputs((_c = core === null || core === void 0 ? void 0 : core.stripWidgets(initialData, true, placeholder ? () => '' : undefined)) !== null && _c !== void 0 ? _c : initialData);
34
- }
35
- }, [ref === null || ref === void 0 ? void 0 : ref.current, exec === null || exec === void 0 ? void 0 : exec.cell]);
36
- const executed = ((_a = exec === null || exec === void 0 ? void 0 : exec.cell) === null || _a === void 0 ? void 0 : _a.executionCount) != null;
37
- console.debug(`Jupyter: Cell ${id} executed: ${executed}; Show output: ${executed || !placeholder}`);
38
- return (_jsxs("div", { children: [_jsx("div", { ref: ref, "data-thebe-active-ref": "true", className: classNames('relative', { 'invisible h-0': !executed && placeholder }) }), placeholder && !executed && _jsx(MyST, { ast: placeholder })] }));
39
- }
40
- function PassiveOutputRenderer({ id, data, core, }) {
41
- const rendermime = core.makeRenderMimeRegistry();
42
- const cell = useRef(new core.PassiveCellRenderer(id, rendermime, undefined));
43
- const ref = useRef(null);
44
- const { loaded } = usePlotlyPassively(rendermime, data);
45
- useEffect(() => {
46
- var _a, _b;
47
- if (!ref.current || !loaded)
48
- return;
49
- // eslint-disable-next-line import/no-extraneous-dependencies
50
- cell.current.attachToDOM((_a = ref.current) !== null && _a !== void 0 ? _a : undefined, true);
51
- cell.current.render((_b = core === null || core === void 0 ? void 0 : core.stripWidgets(data)) !== null && _b !== void 0 ? _b : data);
52
- }, [ref, loaded]);
53
- return _jsx("div", { ref: ref, "data-thebe-passive-ref": "true" });
54
- }
55
- export const JupyterOutputs = React.memo(({ id, outputs }) => {
8
+ import { PassiveOutputRenderer } from './passive.js';
9
+ /**
10
+ * Render a single output as a Jupyter output.
11
+ *
12
+ * @param id - The id of the cell.
13
+ * @param output - The output data.
14
+ */
15
+ export const JupyterOutput = React.memo(({ outputsId, output }) => {
56
16
  const { core, load } = useThebeLoader();
57
- const { inCrossRef } = useXRefState();
58
- const { data, error } = useFetchAnyTruncatedContent(outputs);
59
- const [fullOutputs, setFullOutputs] = useState(null);
60
- const exec = useCellExecution(id);
61
- const placeholder = usePlaceholder();
17
+ const { data, error } = useFetchAnyTruncatedContent([output]);
18
+ const [fullOutput, setFullOutput] = useState(null);
62
19
  useEffect(() => {
63
20
  if (core)
64
21
  return;
65
22
  load();
66
23
  }, [core, load]);
67
24
  useEffect(() => {
68
- if (!data || fullOutputs != null)
25
+ if (!data || fullOutput != null)
69
26
  return;
70
27
  fetchAndEncodeOutputImages(data).then((out) => {
71
28
  const compactOutputs = convertToIOutputs(out, {});
72
- setFullOutputs(compactOutputs);
29
+ setFullOutput(compactOutputs[0]);
73
30
  });
74
- }, [id, data, fullOutputs]);
31
+ }, [outputsId, data, fullOutput]);
75
32
  if (error) {
76
33
  console.error(error);
77
34
  return _jsxs("div", { className: "text-red-500", children: ["Error rendering output: ", error.message] });
78
35
  }
79
- if (!inCrossRef && (exec === null || exec === void 0 ? void 0 : exec.ready)) {
80
- return (_jsxs("div", { children: [!fullOutputs && _jsx("div", { className: "p-2.5", children: "Fetching full output data..." }), core && fullOutputs && (_jsx(ActiveOutputRenderer, { id: id, initialData: fullOutputs, core: core }, id))] }));
81
- }
82
- if (placeholder) {
83
- return _jsx(MyST, { ast: placeholder });
84
- }
85
- return (_jsxs("div", { children: [!fullOutputs && _jsx("div", { className: "p-2.5", children: "Loading..." }), fullOutputs && core && (_jsx(PassiveOutputRenderer, { id: id, data: fullOutputs, core: core, kind: SourceFileKind.Notebook }))] }));
36
+ // if (!inCrossRef && exec?.ready) {
37
+ // return (
38
+ // <div>
39
+ // {!fullOutputs && <div className="p-2.5">Fetching full output data...</div>}
40
+ // {core && fullOutputs && (
41
+ // <ActiveOutputRenderer key={id} id={id} initialData={fullOutputs} core={core} />
42
+ // )}
43
+ // </div>
44
+ // );
45
+ // }
46
+ return (_jsxs("div", { children: [!fullOutput && _jsx("div", { className: "p-2.5", children: "Loading..." }), fullOutput && core && (_jsx(PassiveOutputRenderer, { id: outputsId, data: fullOutput, core: core, kind: SourceFileKind.Notebook }))] }));
86
47
  });
package/dist/output.d.ts CHANGED
@@ -2,14 +2,7 @@ import type { GenericNode } from 'myst-common';
2
2
  import type { MinifiedOutput } from 'nbtx';
3
3
  export declare const DIRECT_OUTPUT_TYPES: Set<string>;
4
4
  export declare const DIRECT_MIME_TYPES: Set<string>;
5
- export declare function allOutputsAreSafe(outputs: MinifiedOutput[], directOutputTypes: Set<string>, directMimeTypes: Set<string>): boolean;
6
- export declare function JupyterOutput({ outputId, identifier, data, align, className, }: {
7
- outputId: string;
8
- identifier?: string;
9
- data: MinifiedOutput[];
10
- align?: 'left' | 'center' | 'right';
11
- className?: string;
12
- }): import("react/jsx-runtime").JSX.Element;
5
+ export declare function isOutputSafe(output: MinifiedOutput, directOutputTypes: Set<string>, directMimeTypes: Set<string>): boolean;
13
6
  export declare function Output({ node }: {
14
7
  node: GenericNode;
15
8
  }): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,MAAM,CAAC;AAS/D,eAAO,MAAM,mBAAmB,aAA+B,CAAC;AAEhE,eAAO,MAAM,iBAAiB,EAMxB,GAAG,CAAC,MAAM,CAAC,CAAC;AAElB,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,cAAc,EAAE,EACzB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,WAa7B;AAED,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,UAAU,EACV,IAAI,EACJ,KAAK,EACL,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAuCA;AAED,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,2CAcrD"}
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,MAAM,CAAC;AAO/D,eAAO,MAAM,mBAAmB,aAA+B,CAAC;AAEhE,eAAO,MAAM,iBAAiB,EAMxB,GAAG,CAAC,MAAM,CAAC,CAAC;AAElB,wBAAgB,YAAY,CAC1B,MAAM,EAAE,cAAc,EACtB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,WAU7B;AAED,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,2CAYrD"}
package/dist/output.js CHANGED
@@ -1,12 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { KnownCellOutputMimeTypes } from 'nbtx';
3
- import classNames from 'classnames';
4
- import { SafeOutputs } from './safe.js';
5
- import { JupyterOutputs } from './jupyter.js';
3
+ import { SafeOutput } from './safe.js';
4
+ import { JupyterOutput } from './jupyter.js';
6
5
  import { useMemo } from 'react';
7
6
  import { useCellExecution } from './execute/index.js';
8
- import { usePlaceholder } from './decoration.js';
9
- import { Details, MyST } from 'myst-to-react';
7
+ import { useOutputsContext } from './providers.js';
10
8
  export const DIRECT_OUTPUT_TYPES = new Set(['stream', 'error']);
11
9
  export const DIRECT_MIME_TYPES = new Set([
12
10
  KnownCellOutputMimeTypes.TextPlain,
@@ -15,48 +13,24 @@ export const DIRECT_MIME_TYPES = new Set([
15
13
  KnownCellOutputMimeTypes.ImageJpeg,
16
14
  KnownCellOutputMimeTypes.ImageBmp,
17
15
  ]);
18
- export function allOutputsAreSafe(outputs, directOutputTypes, directMimeTypes) {
19
- if (!outputs || outputs.length === 0)
16
+ export function isOutputSafe(output, directOutputTypes, directMimeTypes) {
17
+ if (directOutputTypes.has(output.output_type))
20
18
  return true;
21
- return outputs.reduce((flag, output) => {
22
- if (directOutputTypes.has(output.output_type))
23
- return flag && true;
24
- const data = output.data;
25
- const mimetypes = data ? Object.keys(data) : [];
26
- const safe = 'data' in output &&
27
- Boolean(output.data) &&
28
- mimetypes.every((mimetype) => directMimeTypes.has(mimetype));
29
- return flag && safe;
30
- }, true);
31
- }
32
- export function JupyterOutput({ outputId, identifier, data, align, className, }) {
33
- const { ready } = useCellExecution(outputId);
34
- const outputs = data;
35
- const allSafe = useMemo(() => allOutputsAreSafe(outputs, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES), [outputs]);
36
- const placeholder = usePlaceholder();
37
- let component;
38
- if (allSafe && !ready) {
39
- if (placeholder && (!outputs || outputs.length === 0)) {
40
- if (placeholder) {
41
- return _jsx(MyST, { ast: placeholder });
42
- }
43
- }
44
- component = _jsx(SafeOutputs, { keyStub: outputId, outputs: outputs });
45
- }
46
- else {
47
- component = _jsx(JupyterOutputs, { id: outputId, outputs: outputs });
48
- }
49
- return (_jsx("div", { id: identifier || undefined, "data-mdast-node-id": outputId, className: classNames('myst-jp-output max-w-full overflow-y-visible overflow-x-auto m-0 group not-prose relative', {
50
- 'text-left': !align || align === 'left',
51
- 'text-center': align === 'center',
52
- 'text-right': align === 'right',
53
- 'mb-5': outputs && outputs.length > 0,
54
- }, className), children: component }));
19
+ const data = output.data;
20
+ const mimetypes = data ? Object.keys(data) : [];
21
+ return ('data' in output &&
22
+ Boolean(output.data) &&
23
+ mimetypes.every((mimetype) => directMimeTypes.has(mimetype)));
55
24
  }
56
25
  export function Output({ node }) {
57
- const output = (_jsx(JupyterOutput, { className: classNames({ hidden: node.visibility === 'remove' }), outputId: node.id, identifier: node.identifier, align: node.align, data: node.data }));
58
- if (node.visibility === 'hide') {
59
- return _jsx(Details, { title: "Output", children: output });
26
+ const { outputsId } = useOutputsContext();
27
+ const { ready } = useCellExecution(outputsId);
28
+ // FUTURE: we'll be rendering AST outputs directly in future
29
+ const maybeSafeOutput = useMemo(() => node.jupyter_data, [node]);
30
+ const isSafe = isOutputSafe(maybeSafeOutput, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES);
31
+ if (isSafe && !ready) {
32
+ return _jsx(SafeOutput, { output: maybeSafeOutput });
60
33
  }
61
- return output;
34
+ // TODO: myst-jp-output should be added to the first child div
35
+ return _jsx(JupyterOutput, { outputsId: outputsId, output: maybeSafeOutput });
62
36
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=output.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.spec.d.ts","sourceRoot":"","sources":["../src/output.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,133 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import { describe, it, expect } from 'vitest';
3
+ import { isOutputSafe, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES } from './output.js';
4
+ import { KnownCellOutputMimeTypes } from 'nbtx';
5
+ describe('Output Safety Functions', () => {
6
+ describe('isOutputSafe', () => {
7
+ it('should return true for direct output types', () => {
8
+ const output = {
9
+ output_type: 'stream',
10
+ name: 'stdout',
11
+ text: 'some output',
12
+ };
13
+ expect(isOutputSafe(output, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES)).toBe(true);
14
+ });
15
+ it('should return true for safe mime types', () => {
16
+ const output = {
17
+ output_type: 'display_data',
18
+ data: {
19
+ [KnownCellOutputMimeTypes.TextPlain]: {
20
+ content_type: 'text/plain',
21
+ content: 'some text',
22
+ },
23
+ [KnownCellOutputMimeTypes.ImagePng]: {
24
+ content_type: 'image/png',
25
+ content: 'base64data',
26
+ },
27
+ },
28
+ metadata: {},
29
+ };
30
+ expect(isOutputSafe(output, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES)).toBe(true);
31
+ });
32
+ it('should return false for unsafe mime types', () => {
33
+ const output = {
34
+ output_type: 'display_data',
35
+ data: {
36
+ 'application/javascript': {
37
+ content_type: 'application/javascript',
38
+ content: 'alert("unsafe")',
39
+ },
40
+ },
41
+ metadata: {},
42
+ };
43
+ expect(isOutputSafe(output, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES)).toBe(false);
44
+ });
45
+ it('should return false for output without data', () => {
46
+ // technically malformed input, but we'll handle it gracefully
47
+ const output = {
48
+ output_type: 'display_data',
49
+ metadata: {},
50
+ };
51
+ expect(isOutputSafe(output, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES)).toBe(false);
52
+ });
53
+ });
54
+ // describe('allOutputsAreSafe', () => {
55
+ // it('should return true for empty outputs', () => {
56
+ // expect(allOutputsAreSafe([], DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES)).toBe(true);
57
+ // });
58
+ // it('should return true when all outputs are safe', () => {
59
+ // const outputs: MinifiedOutput[] = [
60
+ // {
61
+ // output_type: 'stream',
62
+ // name: 'stdout',
63
+ // text: 'some output',
64
+ // },
65
+ // {
66
+ // output_type: 'display_data',
67
+ // data: {
68
+ // [KnownCellOutputMimeTypes.TextPlain]: {
69
+ // content_type: 'text/plain',
70
+ // content: 'text',
71
+ // },
72
+ // [KnownCellOutputMimeTypes.ImagePng]: {
73
+ // content_type: 'image/png',
74
+ // content: 'data',
75
+ // },
76
+ // },
77
+ // metadata: {},
78
+ // },
79
+ // ];
80
+ // expect(allOutputsAreSafe(outputs, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES)).toBe(true);
81
+ // });
82
+ // it('should return false when any output is unsafe', () => {
83
+ // const outputs: MinifiedOutput[] = [
84
+ // {
85
+ // output_type: 'stream',
86
+ // name: 'stdout',
87
+ // text: 'some output',
88
+ // },
89
+ // {
90
+ // output_type: 'display_data',
91
+ // data: {
92
+ // 'application/javascript': {
93
+ // content_type: 'application/javascript',
94
+ // content: 'alert("unsafe")',
95
+ // },
96
+ // },
97
+ // metadata: {},
98
+ // },
99
+ // ];
100
+ // expect(allOutputsAreSafe(outputs, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES)).toBe(false);
101
+ // });
102
+ // it('should handle mixed safe and unsafe outputs', () => {
103
+ // const outputs: MinifiedOutput[] = [
104
+ // {
105
+ // output_type: 'stream',
106
+ // name: 'stdout',
107
+ // text: 'some output',
108
+ // },
109
+ // {
110
+ // output_type: 'display_data',
111
+ // data: {
112
+ // [KnownCellOutputMimeTypes.TextPlain]: {
113
+ // content_type: 'text/plain',
114
+ // content: 'text',
115
+ // },
116
+ // },
117
+ // metadata: {},
118
+ // },
119
+ // {
120
+ // output_type: 'display_data',
121
+ // data: {
122
+ // 'application/javascript': {
123
+ // content_type: 'application/javascript',
124
+ // content: 'alert("unsafe")',
125
+ // },
126
+ // },
127
+ // metadata: {},
128
+ // },
129
+ // ];
130
+ // expect(allOutputsAreSafe(outputs, DIRECT_OUTPUT_TYPES, DIRECT_MIME_TYPES)).toBe(false);
131
+ // });
132
+ // });
133
+ });
@@ -0,0 +1,5 @@
1
+ import type { GenericNode } from 'myst-common';
2
+ export declare function Outputs({ node }: {
3
+ node: GenericNode;
4
+ }): import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=outputs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outputs.d.ts","sourceRoot":"","sources":["../src/outputs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAU/C,wBAAgB,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,2CAoDtD"}
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import classNames from 'classnames';
3
+ import { useMemo } from 'react';
4
+ import { useCellExecution } from './execute/index.js';
5
+ import { usePlaceholder } from './decoration.js';
6
+ import { Details, MyST } from 'myst-to-react';
7
+ import { selectAll } from 'unist-util-select';
8
+ import { OutputsContextProvider } from './providers.js';
9
+ import { ActiveJupyterCellOutputs } from './active.js';
10
+ export function Outputs({ node }) {
11
+ var _a;
12
+ const className = classNames({ hidden: node.visibility === 'remove' });
13
+ const { children, identifier, align } = node;
14
+ const outputsId = (_a = node.id) !== null && _a !== void 0 ? _a : node.key;
15
+ const cellExecutionContext = useCellExecution(outputsId);
16
+ const { ready } = cellExecutionContext;
17
+ const legacyOutputsArray = useMemo(() => {
18
+ return selectAll('output', node).map((child) => child.jupyter_data);
19
+ }, [children]);
20
+ const atLeastOneChildHasJupyterData = legacyOutputsArray.length > 0;
21
+ // NOTE: a placeholder is actually an option on the figure node, not the outputs node
22
+ // perhaps we should move the placeholder to the figure renderer?
23
+ const placeholder = usePlaceholder();
24
+ if (!ready && placeholder) {
25
+ return _jsx(MyST, { ast: placeholder });
26
+ }
27
+ // if not ready, we leave each output to independently render
28
+ // NOTE: we need to see that bokeh & plotly can render ok in this way
29
+ if (!ready) {
30
+ const passiveOutputs = (_jsx("div", { "data-name": "outputs-container", id: identifier || undefined, "data-mdast-node-id": outputsId, className: classNames('max-w-full overflow-y-visible overflow-x-auto m-0 group not-prose relative', {
31
+ 'text-left': !align || align === 'left',
32
+ 'text-center': align === 'center',
33
+ 'text-right': align === 'right',
34
+ 'mb-5': atLeastOneChildHasJupyterData,
35
+ }, className), children: _jsx(OutputsContextProvider, { outputsId: outputsId, children: _jsx(MyST, { ast: children }) }) }));
36
+ if (node.visibility === 'hide') {
37
+ return _jsx(Details, { title: "Output", children: passiveOutputs });
38
+ }
39
+ return passiveOutputs;
40
+ }
41
+ // else compute is ready, and we need to treat the whole cell output as one unit
42
+ return _jsx(ActiveJupyterCellOutputs, { outputsId: outputsId, outputs: legacyOutputsArray });
43
+ }
@@ -0,0 +1,20 @@
1
+ import type { IOutput } from '@jupyterlab/nbformat';
2
+ import type { ThebeCore } from 'thebe-core';
3
+ import type { SourceFileKind } from 'myst-spec-ext';
4
+ /**
5
+ * Render a single output as a passive cell output.
6
+ *
7
+ * This is used for outputs that require jupyters rendermime support, such as Plotly.
8
+ *
9
+ * @param id - The id of the cell.
10
+ * @param data - The output data.
11
+ * @param core - The Thebe core.
12
+ * @param kind - The kind of source file.
13
+ */
14
+ export declare function PassiveOutputRenderer({ id, data, core, }: {
15
+ id: string;
16
+ data: IOutput;
17
+ core: ThebeCore;
18
+ kind: SourceFileKind;
19
+ }): import("react/jsx-runtime").JSX.Element;
20
+ //# sourceMappingURL=passive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passive.d.ts","sourceRoot":"","sources":["../src/passive.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,EAAE,EACF,IAAI,EACJ,IAAI,GACL,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,cAAc,CAAC;CACtB,2CAgBA"}
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from 'react';
3
+ import { usePlotlyPassively } from './plotly.js';
4
+ /**
5
+ * Render a single output as a passive cell output.
6
+ *
7
+ * This is used for outputs that require jupyters rendermime support, such as Plotly.
8
+ *
9
+ * @param id - The id of the cell.
10
+ * @param data - The output data.
11
+ * @param core - The Thebe core.
12
+ * @param kind - The kind of source file.
13
+ */
14
+ export function PassiveOutputRenderer({ id, data, core, }) {
15
+ const rendermime = core.makeRenderMimeRegistry();
16
+ const cell = useRef(new core.PassiveCellRenderer(id, rendermime, undefined));
17
+ const ref = useRef(null);
18
+ const { loaded } = usePlotlyPassively(rendermime, [data]);
19
+ useEffect(() => {
20
+ var _a, _b;
21
+ if (!ref.current || !loaded)
22
+ return;
23
+ // eslint-disable-next-line import/no-extraneous-dependencies
24
+ cell.current.attachToDOM((_a = ref.current) !== null && _a !== void 0 ? _a : undefined, true);
25
+ cell.current.render((_b = core === null || core === void 0 ? void 0 : core.stripWidgets([data])) !== null && _b !== void 0 ? _b : data);
26
+ }, [ref, loaded]);
27
+ return _jsx("div", { ref: ref, "data-thebe-passive-ref": "true", "data-output-id": id });
28
+ }
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import { type ExtendedCoreOptions } from './utils.js';
4
4
  import type { GenericParent } from 'myst-common';
5
5
  import type { RepoProviderSpec } from 'thebe-core';
6
+ import type { IdOrKey } from './execute/types.js';
6
7
  type ComputeOptionsContextType = {
7
8
  enabled: boolean;
8
9
  features: {
@@ -41,5 +42,13 @@ export declare function ThebeLoaderAndServer({ baseurl, connect, children, }: Re
41
42
  connect?: boolean;
42
43
  baseurl?: string;
43
44
  }>): import("react/jsx-runtime").JSX.Element;
45
+ type OutputsContextType = {
46
+ outputsId: IdOrKey;
47
+ };
48
+ export declare function useOutputsContext(): OutputsContextType;
49
+ export declare function OutputsContextProvider({ outputsId, children, }: {
50
+ children: React.ReactNode;
51
+ outputsId: IdOrKey;
52
+ }): import("react/jsx-runtime").JSX.Element;
44
53
  export {};
45
54
  //# sourceMappingURL=providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../src/providers.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAqB,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,KAAK,mBAAmB,EAA6B,MAAM,YAAY,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnD,KAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE;QACR,eAAe,EAAE,OAAO,CAAC;QACzB,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC1C,CAAC;AAIF,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,gBAAgB,EAChB,mBAAmB,EACnB,QAAQ,GACT,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACzB,QAAQ,EAAE;QACR,eAAe,EAAE,OAAO,CAAC;QACzB,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,mBAAmB,KAAK,mBAAmB,GAAG,SAAS,CAAC;IACnF,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC1C,CAAC,2CA2BD;AAED,wBAAgB,aAAa,wBAG5B;AAED,wBAAgB,iBAAiB,0CAEhC;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,QAAQ,GACT,EAAE,KAAK,CAAC,iBAAiB,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,2CAkBlE"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../src/providers.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAqB,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,KAAK,mBAAmB,EAA6B,MAAM,YAAY,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,KAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE;QACR,eAAe,EAAE,OAAO,CAAC;QACzB,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC1C,CAAC;AAIF,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,gBAAgB,EAChB,mBAAmB,EACnB,QAAQ,GACT,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACzB,QAAQ,EAAE;QACR,eAAe,EAAE,OAAO,CAAC;QACzB,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,mBAAmB,KAAK,mBAAmB,GAAG,SAAS,CAAC;IACnF,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC1C,CAAC,2CA2BD;AAED,wBAAgB,aAAa,wBAG5B;AAED,wBAAgB,iBAAiB,0CAEhC;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,QAAQ,GACT,EAAE,KAAK,CAAC,iBAAiB,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,2CAkBlE;AAED,KAAK,kBAAkB,GAAG;IACxB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAGF,wBAAgB,iBAAiB,uBAMhC;AACD,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB,2CAEA"}
package/dist/providers.js CHANGED
@@ -44,3 +44,14 @@ export function ThebeLoaderAndServer({ baseurl, connect, children, }) {
44
44
  const compute = useComputeOptions();
45
45
  return (_jsx(ThebeBundleLoaderProvider, { loadThebeLite: (_b = (_a = compute === null || compute === void 0 ? void 0 : compute.thebe) === null || _a === void 0 ? void 0 : _a.useJupyterLite) !== null && _b !== void 0 ? _b : false, publicPath: baseurl, children: _jsx(ThebeServerProvider, { connect: connect !== null && connect !== void 0 ? connect : false, options: compute === null || compute === void 0 ? void 0 : compute.thebe, useBinder: (_d = (_c = compute === null || compute === void 0 ? void 0 : compute.thebe) === null || _c === void 0 ? void 0 : _c.useBinder) !== null && _d !== void 0 ? _d : false, useJupyterLite: (_f = (_e = compute === null || compute === void 0 ? void 0 : compute.thebe) === null || _e === void 0 ? void 0 : _e.useJupyterLite) !== null && _f !== void 0 ? _f : false, customRepoProviders: (_g = compute === null || compute === void 0 ? void 0 : compute.customRepoProviders) !== null && _g !== void 0 ? _g : [], children: children }) }));
46
46
  }
47
+ const OutputsContext = React.createContext(null);
48
+ export function useOutputsContext() {
49
+ const context = useContext(OutputsContext);
50
+ if (context === null) {
51
+ throw new Error('useOutputsContext must be used within a OutputsContextProvider');
52
+ }
53
+ return context;
54
+ }
55
+ export function OutputsContextProvider({ outputsId, children, }) {
56
+ return _jsx(OutputsContext.Provider, { value: { outputsId }, children: children });
57
+ }
@@ -1,8 +1,10 @@
1
1
  import { Embed } from './embed.js';
2
+ import { Outputs } from './outputs.js';
2
3
  import { Output } from './output.js';
3
4
  import { Figure } from './figure.js';
4
5
  export { NOTEBOOK_BLOCK_RENDERERS } from './block.js';
5
6
  export declare const OUTPUT_RENDERERS: {
7
+ outputs: typeof Outputs;
6
8
  output: typeof Output;
7
9
  embed: typeof Embed;
8
10
  container: typeof Figure;
@@ -1 +1 @@
1
- {"version":3,"file":"renderers.d.ts","sourceRoot":"","sources":["../src/renderers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,eAAO,MAAM,gBAAgB;;;;CAI5B,CAAC;AACF,eAAO,MAAM,iBAAiB,+CAA+D,CAAC"}
1
+ {"version":3,"file":"renderers.d.ts","sourceRoot":"","sources":["../src/renderers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,eAAO,MAAM,gBAAgB;;;;;CAK5B,CAAC;AACF,eAAO,MAAM,iBAAiB,+CAA+D,CAAC"}
package/dist/renderers.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import { Embed } from './embed.js';
2
+ import { Outputs } from './outputs.js';
2
3
  import { Output } from './output.js';
3
4
  import { Figure } from './figure.js';
4
5
  import { mergeRenderers } from '@myst-theme/providers';
5
6
  import { NOTEBOOK_BLOCK_RENDERERS } from './block.js';
6
7
  export { NOTEBOOK_BLOCK_RENDERERS } from './block.js';
7
8
  export const OUTPUT_RENDERERS = {
9
+ outputs: Outputs,
8
10
  output: Output,
9
11
  embed: Embed,
10
12
  container: Figure,
package/dist/safe.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import type { MinifiedOutput } from 'nbtx';
2
- export declare function SafeOutputs({ keyStub, outputs }: {
3
- keyStub: string;
4
- outputs: MinifiedOutput[];
2
+ export declare function SafeOutput({ output }: {
3
+ output: MinifiedOutput;
5
4
  }): import("react/jsx-runtime").JSX.Element | null;
6
5
  //# sourceMappingURL=safe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe.d.ts","sourceRoot":"","sources":["../src/safe.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA2C,cAAc,EAAE,MAAM,MAAM,CAAC;AAwEpF,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,kDAO/F"}
1
+ {"version":3,"file":"safe.d.ts","sourceRoot":"","sources":["../src/safe.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA2C,cAAc,EAAE,MAAM,MAAM,CAAC;AA8CpF,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,kDAwChE"}
package/dist/safe.js CHANGED
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { KnownCellOutputMimeTypes } from 'nbtx';
3
3
  import Stream from './stream.js';
4
4
  import Error from './error.js';
@@ -40,12 +40,12 @@ function OutputImage({ image, text }) {
40
40
  var _a;
41
41
  return _jsx("img", { src: image === null || image === void 0 ? void 0 : image.path, alt: (_a = text === null || text === void 0 ? void 0 : text.content) !== null && _a !== void 0 ? _a : 'Image produced in Jupyter' });
42
42
  }
43
- function SafeOutput({ output }) {
43
+ export function SafeOutput({ output }) {
44
44
  switch (output.output_type) {
45
45
  case 'stream':
46
- return _jsx(Stream, { output: output });
46
+ return (_jsx("div", { "data-name": "safe-output-stream", children: _jsx(Stream, { output: output }) }));
47
47
  case 'error':
48
- return _jsx(Error, { output: output });
48
+ return (_jsx("div", { "data-name": "safe-output-error", children: _jsx(Error, { output: output }) }));
49
49
  case 'display_data':
50
50
  case 'execute_result':
51
51
  case 'update_display_data': {
@@ -53,9 +53,9 @@ function SafeOutput({ output }) {
53
53
  if (!image && !text)
54
54
  return null;
55
55
  if (image)
56
- return _jsx(OutputImage, { image: image, text: text });
56
+ return (_jsx("div", { "data-name": "safe-output-image", children: _jsx(OutputImage, { image: image, text: text }) }));
57
57
  if (text)
58
- return (_jsx("div", { className: "myst-jp-safe-output-text font-mono text-sm whitespace-pre-wrap", children: _jsx(Ansi, { children: text.content }) }));
58
+ return (_jsx("div", { "data-name": "safe-output-text", className: "font-mono text-sm whitespace-pre-wrap myst-jp-safe-output-text", children: _jsx(Ansi, { children: text.content }) }));
59
59
  return null;
60
60
  }
61
61
  default:
@@ -63,10 +63,3 @@ function SafeOutput({ output }) {
63
63
  return null;
64
64
  }
65
65
  }
66
- export function SafeOutputs({ keyStub, outputs }) {
67
- if (!outputs)
68
- return null;
69
- // TODO better key - add keys during content creation?
70
- const components = outputs.map((output, idx) => (_jsx(SafeOutput, { output: output }, `${keyStub}-${idx}`)));
71
- return _jsx(_Fragment, { children: components });
72
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myst-theme/jupyter",
3
- "version": "0.18.0",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "exports": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -25,7 +25,7 @@
25
25
  "@curvenote/ansi-to-react": "^7.0.0",
26
26
  "@headlessui/react": "^1.7.15",
27
27
  "@heroicons/react": "^2.0.18",
28
- "@myst-theme/providers": "^0.18.0",
28
+ "@myst-theme/providers": "^1.0.0",
29
29
  "@scienceicons/react": "^0.0.13",
30
30
  "buffer": "^6.0.3",
31
31
  "classnames": "^2.5.1",
@@ -35,7 +35,7 @@
35
35
  "myst-frontmatter": "^1.7.9",
36
36
  "myst-spec": "^0.0.5",
37
37
  "myst-spec-ext": "^1.8.1",
38
- "myst-to-react": "^0.18.0",
38
+ "myst-to-react": "^1.0.0",
39
39
  "nanoid": "^4.0.2",
40
40
  "nbtx": "^0.2.3",
41
41
  "react-syntax-highlighter": "^15.5.0",
@@ -45,6 +45,11 @@
45
45
  "thebe-react": "0.5.0",
46
46
  "unist-util-select": "^4.0.3"
47
47
  },
48
+ "devDependencies": {
49
+ "@types/react": "^18.0.0",
50
+ "@types/react-dom": "^18.0.0",
51
+ "vitest": "^1.0.0"
52
+ },
48
53
  "peerDependencies": {
49
54
  "@types/react": "^16.8 || ^17.0 || ^18.0",
50
55
  "@types/react-dom": "^16.8 || ^17.0 || ^18.0",