@myst-theme/jupyter 1.2.0 → 1.3.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.
package/dist/active.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import type { IOutput } from '@jupyterlab/nbformat';
2
2
  import type { ThebeCore } from 'thebe-core';
3
3
  import { type MinifiedOutput } from 'nbtx';
4
+ /**
5
+ * Attaches a live thebe kernel cell to the DOM so outputs update on re-execution.
6
+ * Used when thebe compute is "ready" (a kernel is connected). The passive
7
+ * counterpart, `PassiveOutputRenderer`, renders a fresh MIME bundle into a
8
+ * disposable cell instead.
9
+ */
4
10
  export declare function ActiveOutputRenderer({ outputsId, initialData, core, }: {
5
11
  outputsId: string;
6
12
  initialData: IOutput[];
@@ -1 +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"}
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;AAO9D;;;;;GAKG;AACH,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,2CA8CA;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 CHANGED
@@ -9,6 +9,13 @@ import { useThebeLoader } from 'thebe-react';
9
9
  import { useFetchAnyTruncatedContent } from './hooks.js';
10
10
  import { useXRefState } from '@myst-theme/providers';
11
11
  import { fetchAndEncodeOutputImages } from './convertImages.js';
12
+ import { observeScrollableA11y } from './passive.js';
13
+ /**
14
+ * Attaches a live thebe kernel cell to the DOM so outputs update on re-execution.
15
+ * Used when thebe compute is "ready" (a kernel is connected). The passive
16
+ * counterpart, `PassiveOutputRenderer`, renders a fresh MIME bundle into a
17
+ * disposable cell instead.
18
+ */
12
19
  export function ActiveOutputRenderer({ outputsId, initialData, core, }) {
13
20
  var _a;
14
21
  const exec = useCellExecution(outputsId);
@@ -30,10 +37,13 @@ export function ActiveOutputRenderer({ outputsId, initialData, core, }) {
30
37
  if (exec.cell.executionCount == null) {
31
38
  exec.cell.initOutputs((_c = core === null || core === void 0 ? void 0 : core.stripWidgets(initialData, true, placeholder ? () => '' : undefined)) !== null && _c !== void 0 ? _c : initialData);
32
39
  }
40
+ return observeScrollableA11y(ref.current);
33
41
  }, [ref === null || ref === void 0 ? void 0 : ref.current, exec === null || exec === void 0 ? void 0 : exec.cell]);
34
42
  const executed = ((_a = exec === null || exec === void 0 ? void 0 : exec.cell) === null || _a === void 0 ? void 0 : _a.executionCount) != null;
35
43
  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 })] }));
44
+ return (_jsxs("div", { children: [_jsx("div", { ref: ref, "data-thebe-active-ref": "true", className: classNames('relative not-prose', {
45
+ 'invisible h-0': !executed && placeholder,
46
+ }) }), exec.ready && placeholder && !executed && _jsx(MyST, { ast: placeholder })] }));
37
47
  }
38
48
  export function ActiveJupyterCellOutputs({ outputsId, outputs, }) {
39
49
  const { core, load } = useThebeLoader();
@@ -61,7 +71,7 @@ export function ActiveJupyterCellOutputs({ outputsId, outputs, }) {
61
71
  return _jsxs("div", { className: "text-red-500", children: ["Error rendering output: ", error.message] });
62
72
  }
63
73
  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))] }));
74
+ return (_jsxs("div", { "data-name": "active-outputs-container", className: "not-prose mb-5", 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
75
  }
66
76
  return _jsx("div", { children: "ActiveJupyterCellOutputs in cross reference" });
67
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAGhD,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,2CAcxE"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAIhD,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,2CAoBxE"}
package/dist/error.js CHANGED
@@ -2,8 +2,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import Ansi from '@curvenote/ansi-to-react';
3
3
  import { ensureString } from 'nbtx';
4
4
  import { MaybeLongContent } from './components.js';
5
+ import { useIsScrollable } from '@myst-theme/providers';
5
6
  export default function Error({ output }) {
6
- return (_jsx(MaybeLongContent, { content: ensureString(output.traceback), path: output.path, render: (content) => {
7
- return (_jsx("pre", { className: "myst-jp-error-output text-sm font-thin font-system jupyter-error", children: _jsx(Ansi, { children: content !== null && content !== void 0 ? content : '' }) }));
8
- } }));
7
+ const { ref, isScrollable } = useIsScrollable();
8
+ return (_jsx(MaybeLongContent, { content: ensureString(output.traceback), path: output.path, render: (content) => (_jsx("pre", { ref: ref, tabIndex: isScrollable ? 0 : undefined, role: isScrollable ? 'region' : undefined, "aria-label": "cell error output", className: "myst-jp-error-output text-sm font-thin font-system overflow-auto jupyter-error", children: _jsx(Ansi, { useClasses: true, children: content !== null && content !== void 0 ? content : '' }) })) }));
9
9
  }
package/dist/jupyter.d.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  import React from 'react';
2
2
  import type { MinifiedOutput } from 'nbtx';
3
3
  /**
4
- * Render a single output as a Jupyter output.
4
+ * Render one output whose MIME bundle can't be displayed with plain HTML
5
+ * (e.g. text/html from pandas, plotly JSON, Jupyter widgets).
6
+ * Outputs that CAN render directly go through `SafeOutput` instead (see `output.tsx`).
5
7
  *
6
- * @param id - The id of the cell.
8
+ * Uses thebe-core's rendermime registry via `PassiveOutputRenderer`.
9
+ * "thebe" here does NOT mean a live kernel, we're only using its MIME→DOM renderers.
10
+ *
11
+ * @param outputsId - The id of the cell.
7
12
  * @param output - The output data.
8
13
  */
9
14
  export declare const JupyterOutput: React.MemoExoticComponent<({ outputsId, output }: {
@@ -1 +1 @@
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"}
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;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,oDACA;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,6CAiDtE,CAAC"}
package/dist/jupyter.js CHANGED
@@ -7,9 +7,14 @@ import { SourceFileKind } from 'myst-spec-ext';
7
7
  import { useThebeLoader } from 'thebe-react';
8
8
  import { PassiveOutputRenderer } from './passive.js';
9
9
  /**
10
- * Render a single output as a Jupyter output.
10
+ * Render one output whose MIME bundle can't be displayed with plain HTML
11
+ * (e.g. text/html from pandas, plotly JSON, Jupyter widgets).
12
+ * Outputs that CAN render directly go through `SafeOutput` instead (see `output.tsx`).
11
13
  *
12
- * @param id - The id of the cell.
14
+ * Uses thebe-core's rendermime registry via `PassiveOutputRenderer`.
15
+ * "thebe" here does NOT mean a live kernel, we're only using its MIME→DOM renderers.
16
+ *
17
+ * @param outputsId - The id of the cell.
13
18
  * @param output - The output data.
14
19
  */
15
20
  export const JupyterOutput = React.memo(({ outputsId, output }) => {
@@ -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,YAAY,CAC1B,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EACzC,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,WAgB7B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAWA;AAED,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAoCpF"}
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;AAe/D,eAAO,MAAM,mBAAmB,aAA+B,CAAC;AAEhE,eAAO,MAAM,iBAAiB,EAMxB,GAAG,CAAC,MAAM,CAAC,CAAC;AAElB,wBAAgB,YAAY,CAC1B,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EACzC,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,WAgB7B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAWA;AAED,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAoCpF"}
package/dist/output.js CHANGED
@@ -7,6 +7,12 @@ import { useCellExecution } from './execute/index.js';
7
7
  import { useOutputsContext } from './providers.js';
8
8
  import { Callout } from 'myst-to-react';
9
9
  import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
10
+ // Output types and MIME types that can be rendered with plain HTML. For example:
11
+ // - stream/error or text/plain becomes <pre>
12
+ // - images become <img>, etc...
13
+ //
14
+ // Anything else (e.g., MIME outputs from pandas or plotly) use
15
+ // thebe-core's rendermime registry to turn the MIME bundle into DOM (see jupyter.tsx).
10
16
  export const DIRECT_OUTPUT_TYPES = new Set(['stream', 'error']);
11
17
  export const DIRECT_MIME_TYPES = new Set([
12
18
  KnownCellOutputMimeTypes.TextPlain,
package/dist/outputs.d.ts CHANGED
@@ -1,4 +1,15 @@
1
1
  import type { GenericNode } from 'myst-common';
2
+ /**
3
+ * Renders all outputs for a single cell.
4
+ *
5
+ * Two rendering paths:
6
+ * - Passive (no live compute, or live compute not ready): each child output renders
7
+ * itself via <Output />, which uses either `SafeOutput (output.tsx) or
8
+ * `JupyterOutput` (jupyter.tsx) to render the output depending on its type/MIME types.
9
+ * - Active (live thebe kernel ready): the whole cell is handed to
10
+ * `ActiveJupyterCellOutputs`, which attaches a live Jupyter cell so outputs
11
+ * can be re-rendered on execution.
12
+ */
2
13
  export declare function Outputs({ node }: {
3
14
  node: GenericNode;
4
15
  }): import("react/jsx-runtime").JSX.Element;
@@ -1 +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"}
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;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,2CAoDtD"}
package/dist/outputs.js CHANGED
@@ -7,6 +7,17 @@ import { Details, MyST } from 'myst-to-react';
7
7
  import { selectAll } from 'unist-util-select';
8
8
  import { OutputsContextProvider } from './providers.js';
9
9
  import { ActiveJupyterCellOutputs } from './active.js';
10
+ /**
11
+ * Renders all outputs for a single cell.
12
+ *
13
+ * Two rendering paths:
14
+ * - Passive (no live compute, or live compute not ready): each child output renders
15
+ * itself via <Output />, which uses either `SafeOutput (output.tsx) or
16
+ * `JupyterOutput` (jupyter.tsx) to render the output depending on its type/MIME types.
17
+ * - Active (live thebe kernel ready): the whole cell is handed to
18
+ * `ActiveJupyterCellOutputs`, which attaches a live Jupyter cell so outputs
19
+ * can be re-rendered on execution.
20
+ */
10
21
  export function Outputs({ node }) {
11
22
  var _a;
12
23
  const className = classNames({ hidden: node.visibility === 'remove' });
@@ -27,7 +38,7 @@ export function Outputs({ node }) {
27
38
  // if not ready, we leave each output to independently render
28
39
  // NOTE: we need to see that bokeh & plotly can render ok in this way
29
40
  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', {
41
+ const passiveOutputs = (_jsx("div", { "data-name": "outputs-container", id: identifier || undefined, "data-mdast-node-id": outputsId, className: classNames('max-w-full overflow-y-visible m-0 group not-prose relative', {
31
42
  'text-left': !align || align === 'left',
32
43
  'text-center': align === 'center',
33
44
  'text-right': align === 'right',
package/dist/passive.d.ts CHANGED
@@ -2,9 +2,25 @@ import type { IOutput } from '@jupyterlab/nbformat';
2
2
  import type { ThebeCore } from 'thebe-core';
3
3
  import type { SourceFileKind } from 'myst-spec-ext';
4
4
  /**
5
- * Render a single output as a passive cell output.
5
+ * Mark each `.jp-OutputArea-output` descendant of `root` as keyboard-focusable
6
+ * (tabIndex/role/aria-label) when its content overflows horizontally, so wide
7
+ * outputs (tables, plots) are reachable via keyboard.
8
+ */
9
+ export declare function stampScrollableA11y(root: HTMLElement | null): void;
10
+ /**
11
+ * Stamp `root` now and re-stamp on any DOM mutation. Needed because some
12
+ * renderers (e.g. Plotly) insert content asynchronously, and re-execution
13
+ * can swap the output DOM. Returns a disconnect function for effect cleanup.
14
+ */
15
+ export declare function observeScrollableA11y(root: HTMLElement | null): () => void;
16
+ /**
17
+ * Render one output without a live kernel, using thebe-core's rendermime registry
18
+ * to turn the MIME bundle into DOM.
19
+ *
20
+ * Used for outputs that browsers can't render directly
21
+ * (e.g., pandas or plotly MIME types).
6
22
  *
7
- * This is used for outputs that require jupyters rendermime support, such as Plotly.
23
+ * With live thebe kernels, the counterpart is `ActiveOutputRenderer` in `active.tsx`.
8
24
  *
9
25
  * @param id - The id of the cell.
10
26
  * @param data - The output data.
@@ -1 +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"}
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;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,QAQ3D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,cAM7D;AAED;;;;;;;;;;;;;GAaG;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,2CAiBA"}
package/dist/passive.js CHANGED
@@ -2,9 +2,40 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useRef } from 'react';
3
3
  import { usePlotlyPassively } from './plotly.js';
4
4
  /**
5
- * Render a single output as a passive cell output.
5
+ * Mark each `.jp-OutputArea-output` descendant of `root` as keyboard-focusable
6
+ * (tabIndex/role/aria-label) when its content overflows horizontally, so wide
7
+ * outputs (tables, plots) are reachable via keyboard.
8
+ */
9
+ export function stampScrollableA11y(root) {
10
+ root === null || root === void 0 ? void 0 : root.querySelectorAll('.jp-OutputArea-output').forEach((el) => {
11
+ if (el.scrollWidth > el.clientWidth) {
12
+ el.tabIndex = 0;
13
+ el.setAttribute('role', 'region');
14
+ el.setAttribute('aria-label', 'cell output');
15
+ }
16
+ });
17
+ }
18
+ /**
19
+ * Stamp `root` now and re-stamp on any DOM mutation. Needed because some
20
+ * renderers (e.g. Plotly) insert content asynchronously, and re-execution
21
+ * can swap the output DOM. Returns a disconnect function for effect cleanup.
22
+ */
23
+ export function observeScrollableA11y(root) {
24
+ if (!root)
25
+ return () => { };
26
+ stampScrollableA11y(root);
27
+ const observer = new MutationObserver(() => stampScrollableA11y(root));
28
+ observer.observe(root, { childList: true, subtree: true });
29
+ return () => observer.disconnect();
30
+ }
31
+ /**
32
+ * Render one output without a live kernel, using thebe-core's rendermime registry
33
+ * to turn the MIME bundle into DOM.
34
+ *
35
+ * Used for outputs that browsers can't render directly
36
+ * (e.g., pandas or plotly MIME types).
6
37
  *
7
- * This is used for outputs that require jupyters rendermime support, such as Plotly.
38
+ * With live thebe kernels, the counterpart is `ActiveOutputRenderer` in `active.tsx`.
8
39
  *
9
40
  * @param id - The id of the cell.
10
41
  * @param data - The output data.
@@ -23,6 +54,7 @@ export function PassiveOutputRenderer({ id, data, core, }) {
23
54
  // eslint-disable-next-line import/no-extraneous-dependencies
24
55
  cell.current.attachToDOM((_a = ref.current) !== null && _a !== void 0 ? _a : undefined, true);
25
56
  cell.current.render((_b = core === null || core === void 0 ? void 0 : core.stripWidgets([data])) !== null && _b !== void 0 ? _b : data);
57
+ return observeScrollableA11y(ref.current);
26
58
  }, [ref, loaded]);
27
59
  return _jsx("div", { ref: ref, "data-thebe-passive-ref": "true", "data-output-id": id });
28
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,MAAM,CAAC;AAGjD,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,oBAAoB,CAAA;CAAE,2CAY1E"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,MAAM,CAAC;AAMjD,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,oBAAoB,CAAA;CAAE,2CAwB1E"}
package/dist/stream.js CHANGED
@@ -2,6 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import Ansi from '@curvenote/ansi-to-react';
3
3
  import { ensureString } from 'nbtx';
4
4
  import { MaybeLongContent } from './components.js';
5
+ import { useIsScrollable } from '@myst-theme/providers';
6
+ import classNames from 'classnames';
5
7
  export default function Stream({ output }) {
6
- return (_jsx(MaybeLongContent, { content: ensureString(output.text), path: output.path, render: (content) => (_jsx("pre", { className: "myst-jp-stream-output text-sm font-thin font-system", children: _jsx(Ansi, { children: content !== null && content !== void 0 ? content : '' }) })) }));
8
+ const { ref, isScrollable } = useIsScrollable();
9
+ const isError = output.name === 'stderr';
10
+ return (_jsx(MaybeLongContent, { content: ensureString(output.text), path: output.path, render: (content) => (_jsx("pre", { ref: ref, tabIndex: isScrollable ? 0 : undefined, role: isScrollable ? 'region' : undefined, "aria-label": "cell output stream", className: classNames('myst-jp-stream-output text-sm font-thin font-system overflow-auto', isError ? 'jupyter-error' : 'jupyter-output'), children: _jsx(Ansi, { useClasses: true, children: content !== null && content !== void 0 ? content : '' }) })) }));
7
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myst-theme/jupyter",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "exports": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "@curvenote/ansi-to-react": "^7.0.0",
30
30
  "@headlessui/react": "^1.7.15",
31
31
  "@heroicons/react": "^2.0.18",
32
- "@myst-theme/providers": "^1.2.0",
32
+ "@myst-theme/providers": "^1.3.0",
33
33
  "@scienceicons/react": "^0.0.13",
34
34
  "buffer": "^6.0.3",
35
35
  "classnames": "^2.5.1",
@@ -39,7 +39,7 @@
39
39
  "myst-frontmatter": "^1.7.9",
40
40
  "myst-spec": "^0.0.5",
41
41
  "myst-spec-ext": "^1.8.1",
42
- "myst-to-react": "^1.2.0",
42
+ "myst-to-react": "^1.3.0",
43
43
  "nanoid": "^4.0.2",
44
44
  "nbtx": "^0.2.3",
45
45
  "react-syntax-highlighter": "^15.5.0",