@immediately-run/sdk 0.42.0 → 0.43.1
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/components/Link.cjs +11 -6
- package/dist/components/Link.cjs.map +1 -1
- package/dist/components/Link.d.cts +13 -2
- package/dist/components/Link.d.ts +13 -2
- package/dist/components/Link.js +11 -6
- package/dist/components/Link.js.map +1 -1
- package/dist/editorContext.cjs +5 -2
- package/dist/editorContext.cjs.map +1 -1
- package/dist/editorContext.d.cts +9 -0
- package/dist/editorContext.d.ts +9 -0
- package/dist/editorContext.js +5 -2
- package/dist/editorContext.js.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/routing.cjs +19 -2
- package/dist/routing.cjs.map +1 -1
- package/dist/routing.d.cts +6 -6
- package/dist/routing.d.ts +6 -6
- package/dist/routing.js +18 -2
- package/dist/routing.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +7 -7
package/dist/components/Link.cjs
CHANGED
|
@@ -51,18 +51,23 @@ const FragmentLink = ({
|
|
|
51
51
|
const InternalLink = ({
|
|
52
52
|
href,
|
|
53
53
|
children,
|
|
54
|
+
onClick,
|
|
55
|
+
target,
|
|
54
56
|
...props
|
|
55
57
|
}) => {
|
|
56
58
|
const clickHandler = (0, import_react.useCallback)(
|
|
57
59
|
(e) => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
onClick?.(e);
|
|
61
|
+
if (e.defaultPrevented) return;
|
|
62
|
+
if (!href) return;
|
|
63
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
|
|
64
|
+
if (target && target !== "_self") return;
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
(0, import_routing.navigate)(href);
|
|
62
67
|
},
|
|
63
|
-
[href]
|
|
68
|
+
[href, onClick, target]
|
|
64
69
|
);
|
|
65
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href, onClick: clickHandler,
|
|
70
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { ...props, href, target, onClick: clickHandler, children });
|
|
66
71
|
};
|
|
67
72
|
const Link = ({
|
|
68
73
|
href,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/Link.tsx"],"sourcesContent":["import { ReactNode, use, useCallback } from 'react';\nimport { navigate } from '../routing';\nimport { scrollToId } from '../scrollToId';\nimport { TinkerableContext } from '../TinkerableContext';\nimport { constructOuterUrl, isInternalHref } from '../urlUtils';\n\n/** A same-page anchor (`#frag`): scrolls the addressed section into view on click\n * **without a route change** (MARKDOWN_SYNTAX_SPEC §13.5). The default behavior of a\n * bare `#`-href is intercepted so the sandbox URL the host owns is never mutated\n * out from under it; a fragment that names nothing leaves the scroll position\n * untouched (a soft failure). */\nexport const FragmentLink = ({\n href,\n children,\n onClick,\n ...props\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const clickHandler = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.(e);\n if (e.defaultPrevented) return;\n if (href && href.startsWith('#')) {\n e.preventDefault();\n scrollToId(href.slice(1));\n }\n },\n [href, onClick]\n );\n return (\n <a href={href} onClick={clickHandler} {...props}>\n {children}\n </a>\n );\n};\n\n/** An `<a>` that performs in-sandbox navigation on click (prevents the default\n * full-page load and routes via {@link navigate}). */\nexport const InternalLink = ({\n href,\n children,\n ...props\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const clickHandler = useCallback(\n (e:
|
|
1
|
+
{"version":3,"sources":["../../src/components/Link.tsx"],"sourcesContent":["import { ReactNode, use, useCallback } from 'react';\nimport { navigate } from '../routing';\nimport { scrollToId } from '../scrollToId';\nimport { TinkerableContext } from '../TinkerableContext';\nimport { constructOuterUrl, isInternalHref } from '../urlUtils';\n\n/** A same-page anchor (`#frag`): scrolls the addressed section into view on click\n * **without a route change** (MARKDOWN_SYNTAX_SPEC §13.5). The default behavior of a\n * bare `#`-href is intercepted so the sandbox URL the host owns is never mutated\n * out from under it; a fragment that names nothing leaves the scroll position\n * untouched (a soft failure). */\nexport const FragmentLink = ({\n href,\n children,\n onClick,\n ...props\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const clickHandler = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.(e);\n if (e.defaultPrevented) return;\n if (href && href.startsWith('#')) {\n e.preventDefault();\n scrollToId(href.slice(1));\n }\n },\n [href, onClick]\n );\n return (\n <a href={href} onClick={clickHandler} {...props}>\n {children}\n </a>\n );\n};\n\n/** An `<a>` that performs in-sandbox navigation on click (prevents the default\n * full-page load and routes via {@link navigate}).\n *\n * A consumer-supplied `onClick` is COMPOSED with the router interception, never\n * substituted for it (the {@link FragmentLink} contract): it runs first, and\n * calling `preventDefault()` opts out of routing. Regression guard: `...props`\n * used to spread AFTER `onClick={clickHandler}`, so a consumer `onClick` (e.g. a\n * drawer's close-on-navigate) silently REPLACED the interception — the default\n * anchor action then navigated the sandboxed iframe itself to the host URL,\n * reloading the whole app (and framing the host inside its own sandbox).\n *\n * Modifier/middle clicks and explicit non-self `target`s keep the browser\n * default: the rendered href is a real host URL, so open-in-new-tab works. */\nexport const InternalLink = ({\n href,\n children,\n onClick,\n target,\n ...props\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const clickHandler = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.(e);\n if (e.defaultPrevented) return;\n if (!href) return;\n // Open-in-new-tab gestures (and an explicit target) are the browser's.\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;\n if (target && target !== '_self') return;\n e.preventDefault();\n navigate(href);\n },\n [href, onClick, target]\n );\n // Spread FIRST so no forwarded prop can clobber the interception or the href.\n return (\n <a {...props} href={href} target={target} onClick={clickHandler}>\n {children}\n </a>\n );\n};\n\n/** A link that routes same-app hrefs through the sandbox router (as an\n * {@link InternalLink}) and renders external hrefs as a plain `<a>`. */\nexport const Link = ({\n href,\n children,\n ...properties\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const { outerHref, navigationState } = use(TinkerableContext);\n // A pure same-page fragment (`#sec-8-9`) scrolls in place — no route change (§13.5).\n if (href && href.startsWith('#')) {\n return (\n <FragmentLink href={href} {...properties}>\n {children}\n </FragmentLink>\n );\n }\n if (href && isInternalHref(outerHref, href, navigationState)) {\n const targetHref = constructOuterUrl(outerHref, href, navigationState);\n return (\n <InternalLink href={targetHref} {...properties}>\n {children}\n </InternalLink>\n );\n } else {\n // create a regular link to external resource\n return <a {...{ href, ...properties }}>{children}</a>;\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BI;AA7BJ,mBAA4C;AAC5C,qBAAyB;AACzB,wBAA2B;AAC3B,+BAAkC;AAClC,sBAAkD;AAO3C,MAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAA4G;AAC1G,QAAM,mBAAe;AAAA,IACnB,CAAC,MAA2C;AAC1C,gBAAU,CAAC;AACX,UAAI,EAAE,iBAAkB;AACxB,UAAI,QAAQ,KAAK,WAAW,GAAG,GAAG;AAChC,UAAE,eAAe;AACjB,0CAAW,KAAK,MAAM,CAAC,CAAC;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,CAAC,MAAM,OAAO;AAAA,EAChB;AACA,SACE,4CAAC,OAAE,MAAY,SAAS,cAAe,GAAG,OACvC,UACH;AAEJ;AAeO,MAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAA4G;AAC1G,QAAM,mBAAe;AAAA,IACnB,CAAC,MAA2C;AAC1C,gBAAU,CAAC;AACX,UAAI,EAAE,iBAAkB;AACxB,UAAI,CAAC,KAAM;AAEX,UAAI,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAG;AACxE,UAAI,UAAU,WAAW,QAAS;AAClC,QAAE,eAAe;AACjB,mCAAS,IAAI;AAAA,IACf;AAAA,IACA,CAAC,MAAM,SAAS,MAAM;AAAA,EACxB;AAEA,SACE,4CAAC,OAAG,GAAG,OAAO,MAAY,QAAgB,SAAS,cAChD,UACH;AAEJ;AAIO,MAAM,OAAO,CAAC;AAAA,EACnB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAA4G;AAC1G,QAAM,EAAE,WAAW,gBAAgB,QAAI,kBAAI,0CAAiB;AAE5D,MAAI,QAAQ,KAAK,WAAW,GAAG,GAAG;AAChC,WACE,4CAAC,gBAAa,MAAa,GAAG,YAC3B,UACH;AAAA,EAEJ;AACA,MAAI,YAAQ,gCAAe,WAAW,MAAM,eAAe,GAAG;AAC5D,UAAM,iBAAa,mCAAkB,WAAW,MAAM,eAAe;AACrE,WACE,4CAAC,gBAAa,MAAM,YAAa,GAAG,YACjC,UACH;AAAA,EAEJ,OAAO;AAEL,WAAO,4CAAC,OAAG,GAAG,EAAE,MAAM,GAAG,WAAW,GAAI,UAAS;AAAA,EACnD;AACF;","names":[]}
|
|
@@ -7,8 +7,19 @@ import { ReactNode } from 'react';
|
|
|
7
7
|
* untouched (a soft failure). */
|
|
8
8
|
declare const FragmentLink: ({ href, children, onClick, ...props }: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => ReactNode;
|
|
9
9
|
/** An `<a>` that performs in-sandbox navigation on click (prevents the default
|
|
10
|
-
* full-page load and routes via {@link navigate}).
|
|
11
|
-
|
|
10
|
+
* full-page load and routes via {@link navigate}).
|
|
11
|
+
*
|
|
12
|
+
* A consumer-supplied `onClick` is COMPOSED with the router interception, never
|
|
13
|
+
* substituted for it (the {@link FragmentLink} contract): it runs first, and
|
|
14
|
+
* calling `preventDefault()` opts out of routing. Regression guard: `...props`
|
|
15
|
+
* used to spread AFTER `onClick={clickHandler}`, so a consumer `onClick` (e.g. a
|
|
16
|
+
* drawer's close-on-navigate) silently REPLACED the interception — the default
|
|
17
|
+
* anchor action then navigated the sandboxed iframe itself to the host URL,
|
|
18
|
+
* reloading the whole app (and framing the host inside its own sandbox).
|
|
19
|
+
*
|
|
20
|
+
* Modifier/middle clicks and explicit non-self `target`s keep the browser
|
|
21
|
+
* default: the rendered href is a real host URL, so open-in-new-tab works. */
|
|
22
|
+
declare const InternalLink: ({ href, children, onClick, target, ...props }: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => ReactNode;
|
|
12
23
|
/** A link that routes same-app hrefs through the sandbox router (as an
|
|
13
24
|
* {@link InternalLink}) and renders external hrefs as a plain `<a>`. */
|
|
14
25
|
declare const Link: ({ href, children, ...properties }: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => ReactNode;
|
|
@@ -7,8 +7,19 @@ import { ReactNode } from 'react';
|
|
|
7
7
|
* untouched (a soft failure). */
|
|
8
8
|
declare const FragmentLink: ({ href, children, onClick, ...props }: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => ReactNode;
|
|
9
9
|
/** An `<a>` that performs in-sandbox navigation on click (prevents the default
|
|
10
|
-
* full-page load and routes via {@link navigate}).
|
|
11
|
-
|
|
10
|
+
* full-page load and routes via {@link navigate}).
|
|
11
|
+
*
|
|
12
|
+
* A consumer-supplied `onClick` is COMPOSED with the router interception, never
|
|
13
|
+
* substituted for it (the {@link FragmentLink} contract): it runs first, and
|
|
14
|
+
* calling `preventDefault()` opts out of routing. Regression guard: `...props`
|
|
15
|
+
* used to spread AFTER `onClick={clickHandler}`, so a consumer `onClick` (e.g. a
|
|
16
|
+
* drawer's close-on-navigate) silently REPLACED the interception — the default
|
|
17
|
+
* anchor action then navigated the sandboxed iframe itself to the host URL,
|
|
18
|
+
* reloading the whole app (and framing the host inside its own sandbox).
|
|
19
|
+
*
|
|
20
|
+
* Modifier/middle clicks and explicit non-self `target`s keep the browser
|
|
21
|
+
* default: the rendered href is a real host URL, so open-in-new-tab works. */
|
|
22
|
+
declare const InternalLink: ({ href, children, onClick, target, ...props }: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => ReactNode;
|
|
12
23
|
/** A link that routes same-app hrefs through the sandbox router (as an
|
|
13
24
|
* {@link InternalLink}) and renders external hrefs as a plain `<a>`. */
|
|
14
25
|
declare const Link: ({ href, children, ...properties }: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => ReactNode;
|
package/dist/components/Link.js
CHANGED
|
@@ -27,18 +27,23 @@ const FragmentLink = ({
|
|
|
27
27
|
const InternalLink = ({
|
|
28
28
|
href,
|
|
29
29
|
children,
|
|
30
|
+
onClick,
|
|
31
|
+
target,
|
|
30
32
|
...props
|
|
31
33
|
}) => {
|
|
32
34
|
const clickHandler = useCallback(
|
|
33
35
|
(e) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
onClick?.(e);
|
|
37
|
+
if (e.defaultPrevented) return;
|
|
38
|
+
if (!href) return;
|
|
39
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
|
|
40
|
+
if (target && target !== "_self") return;
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
navigate(href);
|
|
38
43
|
},
|
|
39
|
-
[href]
|
|
44
|
+
[href, onClick, target]
|
|
40
45
|
);
|
|
41
|
-
return /* @__PURE__ */ jsx("a", { href, onClick: clickHandler,
|
|
46
|
+
return /* @__PURE__ */ jsx("a", { ...props, href, target, onClick: clickHandler, children });
|
|
42
47
|
};
|
|
43
48
|
const Link = ({
|
|
44
49
|
href,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/Link.tsx"],"sourcesContent":["import { ReactNode, use, useCallback } from 'react';\nimport { navigate } from '../routing';\nimport { scrollToId } from '../scrollToId';\nimport { TinkerableContext } from '../TinkerableContext';\nimport { constructOuterUrl, isInternalHref } from '../urlUtils';\n\n/** A same-page anchor (`#frag`): scrolls the addressed section into view on click\n * **without a route change** (MARKDOWN_SYNTAX_SPEC §13.5). The default behavior of a\n * bare `#`-href is intercepted so the sandbox URL the host owns is never mutated\n * out from under it; a fragment that names nothing leaves the scroll position\n * untouched (a soft failure). */\nexport const FragmentLink = ({\n href,\n children,\n onClick,\n ...props\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const clickHandler = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.(e);\n if (e.defaultPrevented) return;\n if (href && href.startsWith('#')) {\n e.preventDefault();\n scrollToId(href.slice(1));\n }\n },\n [href, onClick]\n );\n return (\n <a href={href} onClick={clickHandler} {...props}>\n {children}\n </a>\n );\n};\n\n/** An `<a>` that performs in-sandbox navigation on click (prevents the default\n * full-page load and routes via {@link navigate}). */\nexport const InternalLink = ({\n href,\n children,\n ...props\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const clickHandler = useCallback(\n (e:
|
|
1
|
+
{"version":3,"sources":["../../src/components/Link.tsx"],"sourcesContent":["import { ReactNode, use, useCallback } from 'react';\nimport { navigate } from '../routing';\nimport { scrollToId } from '../scrollToId';\nimport { TinkerableContext } from '../TinkerableContext';\nimport { constructOuterUrl, isInternalHref } from '../urlUtils';\n\n/** A same-page anchor (`#frag`): scrolls the addressed section into view on click\n * **without a route change** (MARKDOWN_SYNTAX_SPEC §13.5). The default behavior of a\n * bare `#`-href is intercepted so the sandbox URL the host owns is never mutated\n * out from under it; a fragment that names nothing leaves the scroll position\n * untouched (a soft failure). */\nexport const FragmentLink = ({\n href,\n children,\n onClick,\n ...props\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const clickHandler = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.(e);\n if (e.defaultPrevented) return;\n if (href && href.startsWith('#')) {\n e.preventDefault();\n scrollToId(href.slice(1));\n }\n },\n [href, onClick]\n );\n return (\n <a href={href} onClick={clickHandler} {...props}>\n {children}\n </a>\n );\n};\n\n/** An `<a>` that performs in-sandbox navigation on click (prevents the default\n * full-page load and routes via {@link navigate}).\n *\n * A consumer-supplied `onClick` is COMPOSED with the router interception, never\n * substituted for it (the {@link FragmentLink} contract): it runs first, and\n * calling `preventDefault()` opts out of routing. Regression guard: `...props`\n * used to spread AFTER `onClick={clickHandler}`, so a consumer `onClick` (e.g. a\n * drawer's close-on-navigate) silently REPLACED the interception — the default\n * anchor action then navigated the sandboxed iframe itself to the host URL,\n * reloading the whole app (and framing the host inside its own sandbox).\n *\n * Modifier/middle clicks and explicit non-self `target`s keep the browser\n * default: the rendered href is a real host URL, so open-in-new-tab works. */\nexport const InternalLink = ({\n href,\n children,\n onClick,\n target,\n ...props\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const clickHandler = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n onClick?.(e);\n if (e.defaultPrevented) return;\n if (!href) return;\n // Open-in-new-tab gestures (and an explicit target) are the browser's.\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;\n if (target && target !== '_self') return;\n e.preventDefault();\n navigate(href);\n },\n [href, onClick, target]\n );\n // Spread FIRST so no forwarded prop can clobber the interception or the href.\n return (\n <a {...props} href={href} target={target} onClick={clickHandler}>\n {children}\n </a>\n );\n};\n\n/** A link that routes same-app hrefs through the sandbox router (as an\n * {@link InternalLink}) and renders external hrefs as a plain `<a>`. */\nexport const Link = ({\n href,\n children,\n ...properties\n}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>): ReactNode => {\n const { outerHref, navigationState } = use(TinkerableContext);\n // A pure same-page fragment (`#sec-8-9`) scrolls in place — no route change (§13.5).\n if (href && href.startsWith('#')) {\n return (\n <FragmentLink href={href} {...properties}>\n {children}\n </FragmentLink>\n );\n }\n if (href && isInternalHref(outerHref, href, navigationState)) {\n const targetHref = constructOuterUrl(outerHref, href, navigationState);\n return (\n <InternalLink href={targetHref} {...properties}>\n {children}\n </InternalLink>\n );\n } else {\n // create a regular link to external resource\n return <a {...{ href, ...properties }}>{children}</a>;\n }\n};\n"],"mappings":";AA6BI;AA7BJ,SAAoB,KAAK,mBAAmB;AAC5C,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,yBAAyB;AAClC,SAAS,mBAAmB,sBAAsB;AAO3C,MAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAA4G;AAC1G,QAAM,eAAe;AAAA,IACnB,CAAC,MAA2C;AAC1C,gBAAU,CAAC;AACX,UAAI,EAAE,iBAAkB;AACxB,UAAI,QAAQ,KAAK,WAAW,GAAG,GAAG;AAChC,UAAE,eAAe;AACjB,mBAAW,KAAK,MAAM,CAAC,CAAC;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,CAAC,MAAM,OAAO;AAAA,EAChB;AACA,SACE,oBAAC,OAAE,MAAY,SAAS,cAAe,GAAG,OACvC,UACH;AAEJ;AAeO,MAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAA4G;AAC1G,QAAM,eAAe;AAAA,IACnB,CAAC,MAA2C;AAC1C,gBAAU,CAAC;AACX,UAAI,EAAE,iBAAkB;AACxB,UAAI,CAAC,KAAM;AAEX,UAAI,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAG;AACxE,UAAI,UAAU,WAAW,QAAS;AAClC,QAAE,eAAe;AACjB,eAAS,IAAI;AAAA,IACf;AAAA,IACA,CAAC,MAAM,SAAS,MAAM;AAAA,EACxB;AAEA,SACE,oBAAC,OAAG,GAAG,OAAO,MAAY,QAAgB,SAAS,cAChD,UACH;AAEJ;AAIO,MAAM,OAAO,CAAC;AAAA,EACnB;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAA4G;AAC1G,QAAM,EAAE,WAAW,gBAAgB,IAAI,IAAI,iBAAiB;AAE5D,MAAI,QAAQ,KAAK,WAAW,GAAG,GAAG;AAChC,WACE,oBAAC,gBAAa,MAAa,GAAG,YAC3B,UACH;AAAA,EAEJ;AACA,MAAI,QAAQ,eAAe,WAAW,MAAM,eAAe,GAAG;AAC5D,UAAM,aAAa,kBAAkB,WAAW,MAAM,eAAe;AACrE,WACE,oBAAC,gBAAa,MAAM,YAAa,GAAG,YACjC,UACH;AAAA,EAEJ,OAAO;AAEL,WAAO,oBAAC,OAAG,GAAG,EAAE,MAAM,GAAG,WAAW,GAAI,UAAS;AAAA,EACnD;AACF;","names":[]}
|
package/dist/editorContext.cjs
CHANGED
|
@@ -28,7 +28,7 @@ const isStringArray = (v) => Array.isArray(v) && v.every((p) => typeof p === "st
|
|
|
28
28
|
const channel = (0, import_pushChannel.createPushChannel)({
|
|
29
29
|
pushType: "editor-context",
|
|
30
30
|
requestType: "request-editor-context",
|
|
31
|
-
initial: { dirtyPaths: [], openFiles: [], activeFile: null },
|
|
31
|
+
initial: { dirtyPaths: [], openFiles: [], activeFile: null, viewedFile: null },
|
|
32
32
|
parse: (msg) => isStringArray(msg.dirtyPaths) ? {
|
|
33
33
|
dirtyPaths: msg.dirtyPaths,
|
|
34
34
|
// `openFiles` is newer than `dirtyPaths`; tolerate an older host that
|
|
@@ -36,7 +36,10 @@ const channel = (0, import_pushChannel.createPushChannel)({
|
|
|
36
36
|
openFiles: isStringArray(msg.openFiles) ? msg.openFiles : [],
|
|
37
37
|
// `activeFile` is newer still; an older host that omits it (or sends a
|
|
38
38
|
// non-string) reads as `null` — no file highlighted, never a throw.
|
|
39
|
-
activeFile: typeof msg.activeFile === "string" ? msg.activeFile : null
|
|
39
|
+
activeFile: typeof msg.activeFile === "string" ? msg.activeFile : null,
|
|
40
|
+
// `viewedFile` is the newest (R3-268); same tolerance — an older host
|
|
41
|
+
// that omits it reads as `null` (no stage highlight), never a throw.
|
|
42
|
+
viewedFile: typeof msg.viewedFile === "string" ? msg.viewedFile : null
|
|
40
43
|
} : void 0
|
|
41
44
|
});
|
|
42
45
|
const getEditorContext = () => channel.get();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/editorContext.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\n\n/**\n * The editor \"dirty set\" mirrored from the immediately.run host into the sandbox\n * (UI_AS_APPS_SPEC §5.3): which files the user has changed but not yet saved.\n *\n * This is the ELEVATED `editor:read` capability — only a system app whose binding\n * grants it (e.g. the contribute dialog) receives it. The active file and ref are\n * already available to every app via routing (`useNavigationState`), so this\n * channel carries only the genuine delta: the unsaved paths. An app without\n * `editor:read` simply sees an empty dirty set.\n */\nexport interface EditorContext {\n /** Repo-relative paths the user has modified but not yet saved. */\n dirtyPaths: string[];\n /** Repo-relative paths currently open as tabs in the host editor (§4.2). */\n openFiles: string[];\n /**\n * The one file currently focused in the host editor (repo-relative, leading\n * slash — e.g. `/src/index.ts`), or `null` when no file is open. Distinct from\n * {@link dirtyPaths} (the unsaved SET) and {@link openFiles} (the open-tab set):\n * this is the single ACTIVE file. A baseline app reads its own active file from\n * the route, but a self-routed system panel (`drivesHostRoute=false`, e.g. the\n * file explorer) does not see the host editor's route, so it receives the active\n * file here instead (UI_AS_APPS_SPEC §5.3 self-routed-panel refinement).\n */\n activeFile: string | null;\n}\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `editor-context`\n// and answers `request-editor-context` — but only for a frame holding `editor:read`\n// (gated by the channel router). An app without it gets no reply, so the empty\n// default below stands. Wire format: site-main channelBridge.ts.\nconst isStringArray = (v: unknown): v is string[] =>\n Array.isArray(v) && v.every((p) => typeof p === 'string');\n\nconst channel = createPushChannel<EditorContext>({\n pushType: 'editor-context',\n requestType: 'request-editor-context',\n initial: { dirtyPaths: [], openFiles: [], activeFile: null },\n parse: (msg) =>\n isStringArray(msg.dirtyPaths)\n ? {\n dirtyPaths: msg.dirtyPaths,\n // `openFiles` is newer than `dirtyPaths`; tolerate an older host that\n // omits it (defensive SDK — defaults to empty rather than rejecting).\n openFiles: isStringArray(msg.openFiles) ? msg.openFiles : [],\n // `activeFile` is newer still; an older host that omits it (or sends a\n // non-string) reads as `null` — no file highlighted, never a throw.\n activeFile: typeof msg.activeFile === 'string' ? msg.activeFile : null,\n }\n : undefined,\n});\n\n/**\n * Returns the current editor context (dirty set). Poll this for a one-off read;\n * use {@link onEditorContextChange} or {@link useEditorContext} to react.\n */\nexport const getEditorContext = (): EditorContext => channel.get();\n\n/**\n * Subscribe to editor-context changes. The listener is invoked immediately with\n * the current context, then again on every change. Returns an unsubscribe fn.\n */\nexport const onEditorContextChange = (listener: (context: EditorContext) => void): (() => void) =>\n channel.onChange(listener);\n\n/**\n * React hook returning the current editor context (dirty set), re-rendering when\n * it changes. Handy for a contribute dialog: `const { dirtyPaths } =\n * useEditorContext()` to show \"you'll save N files\" before calling `contribute()`.\n */\nexport const useEditorContext = (): EditorContext => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAkC;
|
|
1
|
+
{"version":3,"sources":["../src/editorContext.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\n\n/**\n * The editor \"dirty set\" mirrored from the immediately.run host into the sandbox\n * (UI_AS_APPS_SPEC §5.3): which files the user has changed but not yet saved.\n *\n * This is the ELEVATED `editor:read` capability — only a system app whose binding\n * grants it (e.g. the contribute dialog) receives it. The active file and ref are\n * already available to every app via routing (`useNavigationState`), so this\n * channel carries only the genuine delta: the unsaved paths. An app without\n * `editor:read` simply sees an empty dirty set.\n */\nexport interface EditorContext {\n /** Repo-relative paths the user has modified but not yet saved. */\n dirtyPaths: string[];\n /** Repo-relative paths currently open as tabs in the host editor (§4.2). */\n openFiles: string[];\n /**\n * The one file currently focused in the host editor (repo-relative, leading\n * slash — e.g. `/src/index.ts`), or `null` when no file is open. Distinct from\n * {@link dirtyPaths} (the unsaved SET) and {@link openFiles} (the open-tab set):\n * this is the single ACTIVE file. A baseline app reads its own active file from\n * the route, but a self-routed system panel (`drivesHostRoute=false`, e.g. the\n * file explorer) does not see the host editor's route, so it receives the active\n * file here instead (UI_AS_APPS_SPEC §5.3 self-routed-panel refinement).\n */\n activeFile: string | null;\n /**\n * The viewed-document HINT (R3-268): the working-tree file the STAGE app is\n * currently rendering (leading slash), or `null`. Distinct from\n * {@link activeFile} (the editor's focus): this is what is ON STAGE. It is an\n * app-supplied claim the host validated for existence only — consume it as a\n * highlight and nothing more (never scroll, move focus, or switch files on\n * it; that contract is what keeps the signal activation-free).\n */\n viewedFile: string | null;\n}\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `editor-context`\n// and answers `request-editor-context` — but only for a frame holding `editor:read`\n// (gated by the channel router). An app without it gets no reply, so the empty\n// default below stands. Wire format: site-main channelBridge.ts.\nconst isStringArray = (v: unknown): v is string[] =>\n Array.isArray(v) && v.every((p) => typeof p === 'string');\n\nconst channel = createPushChannel<EditorContext>({\n pushType: 'editor-context',\n requestType: 'request-editor-context',\n initial: { dirtyPaths: [], openFiles: [], activeFile: null, viewedFile: null },\n parse: (msg) =>\n isStringArray(msg.dirtyPaths)\n ? {\n dirtyPaths: msg.dirtyPaths,\n // `openFiles` is newer than `dirtyPaths`; tolerate an older host that\n // omits it (defensive SDK — defaults to empty rather than rejecting).\n openFiles: isStringArray(msg.openFiles) ? msg.openFiles : [],\n // `activeFile` is newer still; an older host that omits it (or sends a\n // non-string) reads as `null` — no file highlighted, never a throw.\n activeFile: typeof msg.activeFile === 'string' ? msg.activeFile : null,\n // `viewedFile` is the newest (R3-268); same tolerance — an older host\n // that omits it reads as `null` (no stage highlight), never a throw.\n viewedFile: typeof msg.viewedFile === 'string' ? msg.viewedFile : null,\n }\n : undefined,\n});\n\n/**\n * Returns the current editor context (dirty set). Poll this for a one-off read;\n * use {@link onEditorContextChange} or {@link useEditorContext} to react.\n */\nexport const getEditorContext = (): EditorContext => channel.get();\n\n/**\n * Subscribe to editor-context changes. The listener is invoked immediately with\n * the current context, then again on every change. Returns an unsubscribe fn.\n */\nexport const onEditorContextChange = (listener: (context: EditorContext) => void): (() => void) =>\n channel.onChange(listener);\n\n/**\n * React hook returning the current editor context (dirty set), re-rendering when\n * it changes. Handy for a contribute dialog: `const { dirtyPaths } =\n * useEditorContext()` to show \"you'll save N files\" before calling `contribute()`.\n */\nexport const useEditorContext = (): EditorContext => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAkC;AA0ClC,MAAM,gBAAgB,CAAC,MACrB,MAAM,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,OAAO,MAAM,QAAQ;AAE1D,MAAM,cAAU,sCAAiC;AAAA,EAC/C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS,EAAE,YAAY,CAAC,GAAG,WAAW,CAAC,GAAG,YAAY,MAAM,YAAY,KAAK;AAAA,EAC7E,OAAO,CAAC,QACN,cAAc,IAAI,UAAU,IACxB;AAAA,IACE,YAAY,IAAI;AAAA;AAAA;AAAA,IAGhB,WAAW,cAAc,IAAI,SAAS,IAAI,IAAI,YAAY,CAAC;AAAA;AAAA;AAAA,IAG3D,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA;AAAA;AAAA,IAGlE,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,EACpE,IACA;AACR,CAAC;AAMM,MAAM,mBAAmB,MAAqB,QAAQ,IAAI;AAM1D,MAAM,wBAAwB,CAAC,aACpC,QAAQ,SAAS,QAAQ;AAOpB,MAAM,mBAAmB,MAAqB,QAAQ,IAAI;","names":[]}
|
package/dist/editorContext.d.cts
CHANGED
|
@@ -23,6 +23,15 @@ interface EditorContext {
|
|
|
23
23
|
* file here instead (UI_AS_APPS_SPEC §5.3 self-routed-panel refinement).
|
|
24
24
|
*/
|
|
25
25
|
activeFile: string | null;
|
|
26
|
+
/**
|
|
27
|
+
* The viewed-document HINT (R3-268): the working-tree file the STAGE app is
|
|
28
|
+
* currently rendering (leading slash), or `null`. Distinct from
|
|
29
|
+
* {@link activeFile} (the editor's focus): this is what is ON STAGE. It is an
|
|
30
|
+
* app-supplied claim the host validated for existence only — consume it as a
|
|
31
|
+
* highlight and nothing more (never scroll, move focus, or switch files on
|
|
32
|
+
* it; that contract is what keeps the signal activation-free).
|
|
33
|
+
*/
|
|
34
|
+
viewedFile: string | null;
|
|
26
35
|
}
|
|
27
36
|
/**
|
|
28
37
|
* Returns the current editor context (dirty set). Poll this for a one-off read;
|
package/dist/editorContext.d.ts
CHANGED
|
@@ -23,6 +23,15 @@ interface EditorContext {
|
|
|
23
23
|
* file here instead (UI_AS_APPS_SPEC §5.3 self-routed-panel refinement).
|
|
24
24
|
*/
|
|
25
25
|
activeFile: string | null;
|
|
26
|
+
/**
|
|
27
|
+
* The viewed-document HINT (R3-268): the working-tree file the STAGE app is
|
|
28
|
+
* currently rendering (leading slash), or `null`. Distinct from
|
|
29
|
+
* {@link activeFile} (the editor's focus): this is what is ON STAGE. It is an
|
|
30
|
+
* app-supplied claim the host validated for existence only — consume it as a
|
|
31
|
+
* highlight and nothing more (never scroll, move focus, or switch files on
|
|
32
|
+
* it; that contract is what keeps the signal activation-free).
|
|
33
|
+
*/
|
|
34
|
+
viewedFile: string | null;
|
|
26
35
|
}
|
|
27
36
|
/**
|
|
28
37
|
* Returns the current editor context (dirty set). Poll this for a one-off read;
|
package/dist/editorContext.js
CHANGED
|
@@ -4,7 +4,7 @@ const isStringArray = (v) => Array.isArray(v) && v.every((p) => typeof p === "st
|
|
|
4
4
|
const channel = createPushChannel({
|
|
5
5
|
pushType: "editor-context",
|
|
6
6
|
requestType: "request-editor-context",
|
|
7
|
-
initial: { dirtyPaths: [], openFiles: [], activeFile: null },
|
|
7
|
+
initial: { dirtyPaths: [], openFiles: [], activeFile: null, viewedFile: null },
|
|
8
8
|
parse: (msg) => isStringArray(msg.dirtyPaths) ? {
|
|
9
9
|
dirtyPaths: msg.dirtyPaths,
|
|
10
10
|
// `openFiles` is newer than `dirtyPaths`; tolerate an older host that
|
|
@@ -12,7 +12,10 @@ const channel = createPushChannel({
|
|
|
12
12
|
openFiles: isStringArray(msg.openFiles) ? msg.openFiles : [],
|
|
13
13
|
// `activeFile` is newer still; an older host that omits it (or sends a
|
|
14
14
|
// non-string) reads as `null` — no file highlighted, never a throw.
|
|
15
|
-
activeFile: typeof msg.activeFile === "string" ? msg.activeFile : null
|
|
15
|
+
activeFile: typeof msg.activeFile === "string" ? msg.activeFile : null,
|
|
16
|
+
// `viewedFile` is the newest (R3-268); same tolerance — an older host
|
|
17
|
+
// that omits it reads as `null` (no stage highlight), never a throw.
|
|
18
|
+
viewedFile: typeof msg.viewedFile === "string" ? msg.viewedFile : null
|
|
16
19
|
} : void 0
|
|
17
20
|
});
|
|
18
21
|
const getEditorContext = () => channel.get();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/editorContext.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\n\n/**\n * The editor \"dirty set\" mirrored from the immediately.run host into the sandbox\n * (UI_AS_APPS_SPEC §5.3): which files the user has changed but not yet saved.\n *\n * This is the ELEVATED `editor:read` capability — only a system app whose binding\n * grants it (e.g. the contribute dialog) receives it. The active file and ref are\n * already available to every app via routing (`useNavigationState`), so this\n * channel carries only the genuine delta: the unsaved paths. An app without\n * `editor:read` simply sees an empty dirty set.\n */\nexport interface EditorContext {\n /** Repo-relative paths the user has modified but not yet saved. */\n dirtyPaths: string[];\n /** Repo-relative paths currently open as tabs in the host editor (§4.2). */\n openFiles: string[];\n /**\n * The one file currently focused in the host editor (repo-relative, leading\n * slash — e.g. `/src/index.ts`), or `null` when no file is open. Distinct from\n * {@link dirtyPaths} (the unsaved SET) and {@link openFiles} (the open-tab set):\n * this is the single ACTIVE file. A baseline app reads its own active file from\n * the route, but a self-routed system panel (`drivesHostRoute=false`, e.g. the\n * file explorer) does not see the host editor's route, so it receives the active\n * file here instead (UI_AS_APPS_SPEC §5.3 self-routed-panel refinement).\n */\n activeFile: string | null;\n}\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `editor-context`\n// and answers `request-editor-context` — but only for a frame holding `editor:read`\n// (gated by the channel router). An app without it gets no reply, so the empty\n// default below stands. Wire format: site-main channelBridge.ts.\nconst isStringArray = (v: unknown): v is string[] =>\n Array.isArray(v) && v.every((p) => typeof p === 'string');\n\nconst channel = createPushChannel<EditorContext>({\n pushType: 'editor-context',\n requestType: 'request-editor-context',\n initial: { dirtyPaths: [], openFiles: [], activeFile: null },\n parse: (msg) =>\n isStringArray(msg.dirtyPaths)\n ? {\n dirtyPaths: msg.dirtyPaths,\n // `openFiles` is newer than `dirtyPaths`; tolerate an older host that\n // omits it (defensive SDK — defaults to empty rather than rejecting).\n openFiles: isStringArray(msg.openFiles) ? msg.openFiles : [],\n // `activeFile` is newer still; an older host that omits it (or sends a\n // non-string) reads as `null` — no file highlighted, never a throw.\n activeFile: typeof msg.activeFile === 'string' ? msg.activeFile : null,\n }\n : undefined,\n});\n\n/**\n * Returns the current editor context (dirty set). Poll this for a one-off read;\n * use {@link onEditorContextChange} or {@link useEditorContext} to react.\n */\nexport const getEditorContext = (): EditorContext => channel.get();\n\n/**\n * Subscribe to editor-context changes. The listener is invoked immediately with\n * the current context, then again on every change. Returns an unsubscribe fn.\n */\nexport const onEditorContextChange = (listener: (context: EditorContext) => void): (() => void) =>\n channel.onChange(listener);\n\n/**\n * React hook returning the current editor context (dirty set), re-rendering when\n * it changes. Handy for a contribute dialog: `const { dirtyPaths } =\n * useEditorContext()` to show \"you'll save N files\" before calling `contribute()`.\n */\nexport const useEditorContext = (): EditorContext => channel.use();\n"],"mappings":";AAAA,SAAS,yBAAyB;
|
|
1
|
+
{"version":3,"sources":["../src/editorContext.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\n\n/**\n * The editor \"dirty set\" mirrored from the immediately.run host into the sandbox\n * (UI_AS_APPS_SPEC §5.3): which files the user has changed but not yet saved.\n *\n * This is the ELEVATED `editor:read` capability — only a system app whose binding\n * grants it (e.g. the contribute dialog) receives it. The active file and ref are\n * already available to every app via routing (`useNavigationState`), so this\n * channel carries only the genuine delta: the unsaved paths. An app without\n * `editor:read` simply sees an empty dirty set.\n */\nexport interface EditorContext {\n /** Repo-relative paths the user has modified but not yet saved. */\n dirtyPaths: string[];\n /** Repo-relative paths currently open as tabs in the host editor (§4.2). */\n openFiles: string[];\n /**\n * The one file currently focused in the host editor (repo-relative, leading\n * slash — e.g. `/src/index.ts`), or `null` when no file is open. Distinct from\n * {@link dirtyPaths} (the unsaved SET) and {@link openFiles} (the open-tab set):\n * this is the single ACTIVE file. A baseline app reads its own active file from\n * the route, but a self-routed system panel (`drivesHostRoute=false`, e.g. the\n * file explorer) does not see the host editor's route, so it receives the active\n * file here instead (UI_AS_APPS_SPEC §5.3 self-routed-panel refinement).\n */\n activeFile: string | null;\n /**\n * The viewed-document HINT (R3-268): the working-tree file the STAGE app is\n * currently rendering (leading slash), or `null`. Distinct from\n * {@link activeFile} (the editor's focus): this is what is ON STAGE. It is an\n * app-supplied claim the host validated for existence only — consume it as a\n * highlight and nothing more (never scroll, move focus, or switch files on\n * it; that contract is what keeps the signal activation-free).\n */\n viewedFile: string | null;\n}\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `editor-context`\n// and answers `request-editor-context` — but only for a frame holding `editor:read`\n// (gated by the channel router). An app without it gets no reply, so the empty\n// default below stands. Wire format: site-main channelBridge.ts.\nconst isStringArray = (v: unknown): v is string[] =>\n Array.isArray(v) && v.every((p) => typeof p === 'string');\n\nconst channel = createPushChannel<EditorContext>({\n pushType: 'editor-context',\n requestType: 'request-editor-context',\n initial: { dirtyPaths: [], openFiles: [], activeFile: null, viewedFile: null },\n parse: (msg) =>\n isStringArray(msg.dirtyPaths)\n ? {\n dirtyPaths: msg.dirtyPaths,\n // `openFiles` is newer than `dirtyPaths`; tolerate an older host that\n // omits it (defensive SDK — defaults to empty rather than rejecting).\n openFiles: isStringArray(msg.openFiles) ? msg.openFiles : [],\n // `activeFile` is newer still; an older host that omits it (or sends a\n // non-string) reads as `null` — no file highlighted, never a throw.\n activeFile: typeof msg.activeFile === 'string' ? msg.activeFile : null,\n // `viewedFile` is the newest (R3-268); same tolerance — an older host\n // that omits it reads as `null` (no stage highlight), never a throw.\n viewedFile: typeof msg.viewedFile === 'string' ? msg.viewedFile : null,\n }\n : undefined,\n});\n\n/**\n * Returns the current editor context (dirty set). Poll this for a one-off read;\n * use {@link onEditorContextChange} or {@link useEditorContext} to react.\n */\nexport const getEditorContext = (): EditorContext => channel.get();\n\n/**\n * Subscribe to editor-context changes. The listener is invoked immediately with\n * the current context, then again on every change. Returns an unsubscribe fn.\n */\nexport const onEditorContextChange = (listener: (context: EditorContext) => void): (() => void) =>\n channel.onChange(listener);\n\n/**\n * React hook returning the current editor context (dirty set), re-rendering when\n * it changes. Handy for a contribute dialog: `const { dirtyPaths } =\n * useEditorContext()` to show \"you'll save N files\" before calling `contribute()`.\n */\nexport const useEditorContext = (): EditorContext => channel.use();\n"],"mappings":";AAAA,SAAS,yBAAyB;AA0ClC,MAAM,gBAAgB,CAAC,MACrB,MAAM,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,OAAO,MAAM,QAAQ;AAE1D,MAAM,UAAU,kBAAiC;AAAA,EAC/C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS,EAAE,YAAY,CAAC,GAAG,WAAW,CAAC,GAAG,YAAY,MAAM,YAAY,KAAK;AAAA,EAC7E,OAAO,CAAC,QACN,cAAc,IAAI,UAAU,IACxB;AAAA,IACE,YAAY,IAAI;AAAA;AAAA;AAAA,IAGhB,WAAW,cAAc,IAAI,SAAS,IAAI,IAAI,YAAY,CAAC;AAAA;AAAA;AAAA,IAG3D,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA;AAAA;AAAA,IAGlE,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,EACpE,IACA;AACR,CAAC;AAMM,MAAM,mBAAmB,MAAqB,QAAQ,IAAI;AAM1D,MAAM,wBAAwB,CAAC,aACpC,QAAQ,SAAS,QAAQ;AAOpB,MAAM,mBAAmB,MAAqB,QAAQ,IAAI;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { MDXProvider, useMDXComponents } from './MDXProvider.cjs';
|
|
2
|
-
export { AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, useRoute, useRouteParams, useTinkerableLink } from './routing.cjs';
|
|
2
|
+
export { AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, setViewedDocumentResolver, useRoute, useRouteParams, useTinkerableLink } from './routing.cjs';
|
|
3
3
|
export { BootProps, CATCH_ALL_ROUTING_SPEC, DEFAULT_ROUTING_SPEC, MdxComponents, TinkerableApp, boot, resolveMdxComponents } from './boot.cjs';
|
|
4
4
|
export { Include, RenderExportedComponent } from './components/Include.cjs';
|
|
5
5
|
export { SafeInclude } from './components/SafeInclude.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { MDXProvider, useMDXComponents } from './MDXProvider.js';
|
|
2
|
-
export { AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, useRoute, useRouteParams, useTinkerableLink } from './routing.js';
|
|
2
|
+
export { AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, setViewedDocumentResolver, useRoute, useRouteParams, useTinkerableLink } from './routing.js';
|
|
3
3
|
export { BootProps, CATCH_ALL_ROUTING_SPEC, DEFAULT_ROUTING_SPEC, MdxComponents, TinkerableApp, boot, resolveMdxComponents } from './boot.js';
|
|
4
4
|
export { Include, RenderExportedComponent } from './components/Include.js';
|
|
5
5
|
export { SafeInclude } from './components/SafeInclude.js';
|
package/dist/routing.cjs
CHANGED
|
@@ -22,6 +22,7 @@ __export(routing_exports, {
|
|
|
22
22
|
applyRoutingRule: () => applyRoutingRule,
|
|
23
23
|
navigate: () => navigate,
|
|
24
24
|
renderRoute: () => renderRoute,
|
|
25
|
+
setViewedDocumentResolver: () => setViewedDocumentResolver,
|
|
25
26
|
useRoute: () => useRoute,
|
|
26
27
|
useRouteParams: () => useRouteParams,
|
|
27
28
|
useTinkerableLink: () => useTinkerableLink
|
|
@@ -84,12 +85,27 @@ const useRoute = () => {
|
|
|
84
85
|
ref
|
|
85
86
|
};
|
|
86
87
|
};
|
|
87
|
-
|
|
88
|
+
let viewedDocumentResolver = null;
|
|
89
|
+
const setViewedDocumentResolver = (resolver) => {
|
|
90
|
+
viewedDocumentResolver = resolver;
|
|
91
|
+
};
|
|
92
|
+
const navigate = (target, opts) => {
|
|
88
93
|
console.log(`[Sandbox] Navigating to ${target}`);
|
|
94
|
+
let declared = {};
|
|
95
|
+
if (opts && "viewedDocument" in opts) {
|
|
96
|
+
declared = { viewedDocument: opts.viewedDocument ?? null };
|
|
97
|
+
} else if (viewedDocumentResolver) {
|
|
98
|
+
try {
|
|
99
|
+
const v = viewedDocumentResolver(target);
|
|
100
|
+
if (v !== void 0) declared = { viewedDocument: v };
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
}
|
|
89
104
|
(0, import_sandboxUtils.sendMessage)("urlchange", {
|
|
90
105
|
url: target,
|
|
91
106
|
back: false,
|
|
92
|
-
forward: false
|
|
107
|
+
forward: false,
|
|
108
|
+
...declared
|
|
93
109
|
});
|
|
94
110
|
};
|
|
95
111
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -98,6 +114,7 @@ const navigate = (target) => {
|
|
|
98
114
|
applyRoutingRule,
|
|
99
115
|
navigate,
|
|
100
116
|
renderRoute,
|
|
117
|
+
setViewedDocumentResolver,
|
|
101
118
|
useRoute,
|
|
102
119
|
useRouteParams,
|
|
103
120
|
useTinkerableLink
|
package/dist/routing.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/routing.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { use, useContext } from 'react';\n\nimport { sendMessage } from './sandboxUtils';\nimport { NavigationState, TinkerableContext } from './TinkerableContext';\nimport { RouteParams, RoutingRule, RoutingSpec } from './RoutingSpec';\nimport { matchRoute } from './routeMatch';\nimport { constructUrl, isAbsolutePath, parseTarget } from './urlUtils';\nimport { joinPaths } from './pathUtils';\n\n/** The result of matching a path: the winning {@link RoutingRule} plus its captured params. */\nexport type AppliedRoutingRule = {\n routingRule: RoutingRule,\n pathParameters?: Record<string, string>;\n}\n\n/** Build the full outer href for an in-app target (absolute `sandboxPath` or a\n * path relative to the current route), e.g. for an `href` attribute. */\nexport const useTinkerableLink = (newSandboxLocation: string) => {\n const { outerHref, navigationState: navigation } = use(TinkerableContext);\n let newNavigationState = parseTarget(newSandboxLocation, navigation);\n if (!isAbsolutePath(newSandboxLocation)) {\n newNavigationState.sandboxPath = joinPaths(navigation.sandboxPath, newSandboxLocation)\n } else {\n newNavigationState.sandboxPath = newSandboxLocation\n }\n return constructUrl(outerHref, newNavigationState);\n}\n\n/** Find the first rule in `routingSpec` whose pattern matches the current\n * `sandboxPath`, returning it with the captured params (or `undefined`). */\nexport const applyRoutingRule = (routingSpec:RoutingSpec, navigationState: NavigationState): AppliedRoutingRule | undefined => {\n const { sandboxPath } = navigationState;\n for (const routingRule of routingSpec.routes) {\n const pathParameters = matchRoute(routingRule.pattern, sandboxPath);\n if (pathParameters) {\n return { routingRule, pathParameters };\n }\n }\n return undefined;\n}\n\n/** Render a matched rule, passing params to a `component` and falling back to `element`/`reactNode`. */\nexport const renderRoute = (routingRule: RoutingRule, params: RouteParams): ReactNode => {\n if (routingRule.component) {\n const Component = routingRule.component;\n return <Component params={params} />;\n }\n return routingRule.element ?? routingRule.reactNode ?? null;\n};\n\n/** Render the route matched for the current location (set up by `boot`'s route table). */\nexport const Router = () => {\n const context = useContext(TinkerableContext);\n const {navigationState: {routingRule, pathParameters}} = context;\n if (!routingRule) {\n // TODO: better error\n throw new Error(`No route registered for path ${context.navigationState.sandboxPath}!`);\n }\n\n return renderRoute(routingRule, pathParameters ?? {});\n};\n\n/** Read the current route's matched params (`:name` segments and the `*` wildcard). */\nexport const useRouteParams = <T extends RouteParams = RouteParams>(): T =>\n (use(TinkerableContext).navigationState.pathParameters ?? {}) as T;\n\n/**\n * Read the current route: the matched rule's `name`, its `params`, the app-owned\n * `sandboxPath`, and the read-only platform prefix fields (`mode`, `provider`,\n * `namespace`, `repository`, `ref`) — e.g. to tell `/edit` from `/present`.\n */\nexport const useRoute = () => {\n const { navigationState } = use(TinkerableContext);\n const { routingRule, pathParameters, sandboxPath, mode, provider, namespace, repository, ref } = navigationState;\n return {\n name: routingRule?.name,\n params: (pathParameters ?? {}) as RouteParams,\n sandboxPath,\n mode,\n provider,\n namespace,\n repository,\n ref,\n };\n};\n\n\n/**\n * Navigate within the app. Messages the host to update the URL; the host then\n * pushes the new href back, which drives the actual route change.\n */\nexport const navigate = (target: string) => {\n console.log(`[Sandbox] Navigating to ${target}`)\n sendMessage('urlchange', {\n url: target,\n back: false,\n forward: false,\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8CW;AA7CX,mBAAgC;AAEhC,0BAA4B;AAC5B,+BAAmD;AAEnD,wBAA2B;AAC3B,sBAA0D;AAC1D,uBAA0B;AAUnB,MAAM,oBAAoB,CAAC,uBAA+B;AAC/D,QAAM,EAAE,WAAW,iBAAiB,WAAW,QAAI,kBAAI,0CAAiB;AACxE,MAAI,yBAAqB,6BAAY,oBAAoB,UAAU;AACnE,MAAI,KAAC,gCAAe,kBAAkB,GAAG;AACvC,uBAAmB,kBAAc,4BAAU,WAAW,aAAa,kBAAkB;AAAA,EACvF,OAAO;AACL,uBAAmB,cAAc;AAAA,EACnC;AACA,aAAO,8BAAa,WAAW,kBAAkB;AACnD;AAIO,MAAM,mBAAmB,CAAC,aAAyB,oBAAqE;AAC7H,QAAM,EAAE,YAAY,IAAI;AACxB,aAAW,eAAe,YAAY,QAAQ;AAC5C,UAAM,qBAAiB,8BAAW,YAAY,SAAS,WAAW;AAClE,QAAI,gBAAgB;AAClB,aAAO,EAAE,aAAa,eAAe;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAGO,MAAM,cAAc,CAAC,aAA0B,WAAmC;AACvF,MAAI,YAAY,WAAW;AACzB,UAAM,YAAY,YAAY;AAC9B,WAAO,4CAAC,aAAU,QAAgB;AAAA,EACpC;AACA,SAAO,YAAY,WAAW,YAAY,aAAa;AACzD;AAGO,MAAM,SAAS,MAAM;AAC1B,QAAM,cAAU,yBAAW,0CAAiB;AAC5C,QAAM,EAAC,iBAAiB,EAAC,aAAa,eAAc,EAAC,IAAI;AACzD,MAAI,CAAC,aAAa;AAEhB,UAAM,IAAI,MAAM,gCAAgC,QAAQ,gBAAgB,WAAW,GAAG;AAAA,EACxF;AAEA,SAAO,YAAY,aAAa,kBAAkB,CAAC,CAAC;AACtD;AAGO,MAAM,iBAAiB,UAC3B,kBAAI,0CAAiB,EAAE,gBAAgB,kBAAkB,CAAC;AAOtD,MAAM,WAAW,MAAM;AAC5B,QAAM,EAAE,gBAAgB,QAAI,kBAAI,0CAAiB;AACjD,QAAM,EAAE,aAAa,gBAAgB,aAAa,MAAM,UAAU,WAAW,YAAY,IAAI,IAAI;AACjG,SAAO;AAAA,IACL,MAAM,aAAa;AAAA,IACnB,QAAS,kBAAkB,CAAC;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;
|
|
1
|
+
{"version":3,"sources":["../src/routing.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { use, useContext } from 'react';\n\nimport { sendMessage } from './sandboxUtils';\nimport { NavigationState, TinkerableContext } from './TinkerableContext';\nimport { RouteParams, RoutingRule, RoutingSpec } from './RoutingSpec';\nimport { matchRoute } from './routeMatch';\nimport { constructUrl, isAbsolutePath, parseTarget } from './urlUtils';\nimport { joinPaths } from './pathUtils';\n\n/** The result of matching a path: the winning {@link RoutingRule} plus its captured params. */\nexport type AppliedRoutingRule = {\n routingRule: RoutingRule,\n pathParameters?: Record<string, string>;\n}\n\n/** Build the full outer href for an in-app target (absolute `sandboxPath` or a\n * path relative to the current route), e.g. for an `href` attribute. */\nexport const useTinkerableLink = (newSandboxLocation: string) => {\n const { outerHref, navigationState: navigation } = use(TinkerableContext);\n let newNavigationState = parseTarget(newSandboxLocation, navigation);\n if (!isAbsolutePath(newSandboxLocation)) {\n newNavigationState.sandboxPath = joinPaths(navigation.sandboxPath, newSandboxLocation)\n } else {\n newNavigationState.sandboxPath = newSandboxLocation\n }\n return constructUrl(outerHref, newNavigationState);\n}\n\n/** Find the first rule in `routingSpec` whose pattern matches the current\n * `sandboxPath`, returning it with the captured params (or `undefined`). */\nexport const applyRoutingRule = (routingSpec:RoutingSpec, navigationState: NavigationState): AppliedRoutingRule | undefined => {\n const { sandboxPath } = navigationState;\n for (const routingRule of routingSpec.routes) {\n const pathParameters = matchRoute(routingRule.pattern, sandboxPath);\n if (pathParameters) {\n return { routingRule, pathParameters };\n }\n }\n return undefined;\n}\n\n/** Render a matched rule, passing params to a `component` and falling back to `element`/`reactNode`. */\nexport const renderRoute = (routingRule: RoutingRule, params: RouteParams): ReactNode => {\n if (routingRule.component) {\n const Component = routingRule.component;\n return <Component params={params} />;\n }\n return routingRule.element ?? routingRule.reactNode ?? null;\n};\n\n/** Render the route matched for the current location (set up by `boot`'s route table). */\nexport const Router = () => {\n const context = useContext(TinkerableContext);\n const {navigationState: {routingRule, pathParameters}} = context;\n if (!routingRule) {\n // TODO: better error\n throw new Error(`No route registered for path ${context.navigationState.sandboxPath}!`);\n }\n\n return renderRoute(routingRule, pathParameters ?? {});\n};\n\n/** Read the current route's matched params (`:name` segments and the `*` wildcard). */\nexport const useRouteParams = <T extends RouteParams = RouteParams>(): T =>\n (use(TinkerableContext).navigationState.pathParameters ?? {}) as T;\n\n/**\n * Read the current route: the matched rule's `name`, its `params`, the app-owned\n * `sandboxPath`, and the read-only platform prefix fields (`mode`, `provider`,\n * `namespace`, `repository`, `ref`) — e.g. to tell `/edit` from `/present`.\n */\nexport const useRoute = () => {\n const { navigationState } = use(TinkerableContext);\n const { routingRule, pathParameters, sandboxPath, mode, provider, namespace, repository, ref } = navigationState;\n return {\n name: routingRule?.name,\n params: (pathParameters ?? {}) as RouteParams,\n sandboxPath,\n mode,\n provider,\n namespace,\n repository,\n ref,\n };\n};\n\n\n/**\n * Navigate within the app. Messages the host to update the URL; the host then\n * pushes the new href back, which drives the actual route change.\n *\n * `opts.viewedDocument` (R3-268) optionally declares which WORKING-TREE file\n * this destination renders — a tri-state rider on the navigation event:\n * - omit the option entirely → the host derives the hint from the URL's\n * `files/` suffix convention (the zero-SDK default);\n * - `null` → this view shows no file (clears the highlight — tag pages,\n * search, home views);\n * - a repo-relative path (the CORPUS path under dispatch — only the viewer\n * can map its own key space) → the file explorer highlights it.\n * The hint is highlight-only by contract (it never scrolls, never moves focus\n * or panes, never switches the editor) and is validated host-side for\n * existence — a wrong path degrades to \"no highlight\", never an error. The\n * host remembers declarations per URL, so back/forward reproduces them\n * without re-announcement.\n */\n// R3-268: an app-registered rule mapping a navigation TARGET to its viewed\n// document, consulted by `navigate()` whenever the caller did not declare one\n// explicitly. Registered ONCE (e.g. at boot) so an app whose links all flow\n// through `<Link>`/`navigate` gets correct declarations everywhere without\n// threading an option through every call site. Return `undefined` for \"no\n// declaration\" (the host falls back to the URL convention), `null` for \"this\n// view shows no file\", or a working-tree repo-relative path.\nlet viewedDocumentResolver: ((targetHref: string) => string | null | undefined) | null = null;\n\n/** Register the app's route→viewed-document rule (R3-268); pass `null` to clear. */\nexport const setViewedDocumentResolver = (\n resolver: ((targetHref: string) => string | null | undefined) | null,\n): void => {\n viewedDocumentResolver = resolver;\n};\n\nexport const navigate = (\n target: string,\n opts?: { viewedDocument?: string | null },\n) => {\n console.log(`[Sandbox] Navigating to ${target}`)\n // Explicit option first; else the registered resolver; else nothing on the\n // wire (the host derives from the URL convention). A resolver throw is\n // swallowed to \"no declaration\" — a mapping bug must never break navigation.\n let declared: { viewedDocument: string | null } | Record<string, never> = {};\n if (opts && 'viewedDocument' in opts) {\n declared = { viewedDocument: opts.viewedDocument ?? null };\n } else if (viewedDocumentResolver) {\n try {\n const v = viewedDocumentResolver(target);\n if (v !== undefined) declared = { viewedDocument: v };\n } catch {\n /* no declaration */\n }\n }\n sendMessage('urlchange', {\n url: target,\n back: false,\n forward: false,\n ...declared,\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8CW;AA7CX,mBAAgC;AAEhC,0BAA4B;AAC5B,+BAAmD;AAEnD,wBAA2B;AAC3B,sBAA0D;AAC1D,uBAA0B;AAUnB,MAAM,oBAAoB,CAAC,uBAA+B;AAC/D,QAAM,EAAE,WAAW,iBAAiB,WAAW,QAAI,kBAAI,0CAAiB;AACxE,MAAI,yBAAqB,6BAAY,oBAAoB,UAAU;AACnE,MAAI,KAAC,gCAAe,kBAAkB,GAAG;AACvC,uBAAmB,kBAAc,4BAAU,WAAW,aAAa,kBAAkB;AAAA,EACvF,OAAO;AACL,uBAAmB,cAAc;AAAA,EACnC;AACA,aAAO,8BAAa,WAAW,kBAAkB;AACnD;AAIO,MAAM,mBAAmB,CAAC,aAAyB,oBAAqE;AAC7H,QAAM,EAAE,YAAY,IAAI;AACxB,aAAW,eAAe,YAAY,QAAQ;AAC5C,UAAM,qBAAiB,8BAAW,YAAY,SAAS,WAAW;AAClE,QAAI,gBAAgB;AAClB,aAAO,EAAE,aAAa,eAAe;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAGO,MAAM,cAAc,CAAC,aAA0B,WAAmC;AACvF,MAAI,YAAY,WAAW;AACzB,UAAM,YAAY,YAAY;AAC9B,WAAO,4CAAC,aAAU,QAAgB;AAAA,EACpC;AACA,SAAO,YAAY,WAAW,YAAY,aAAa;AACzD;AAGO,MAAM,SAAS,MAAM;AAC1B,QAAM,cAAU,yBAAW,0CAAiB;AAC5C,QAAM,EAAC,iBAAiB,EAAC,aAAa,eAAc,EAAC,IAAI;AACzD,MAAI,CAAC,aAAa;AAEhB,UAAM,IAAI,MAAM,gCAAgC,QAAQ,gBAAgB,WAAW,GAAG;AAAA,EACxF;AAEA,SAAO,YAAY,aAAa,kBAAkB,CAAC,CAAC;AACtD;AAGO,MAAM,iBAAiB,UAC3B,kBAAI,0CAAiB,EAAE,gBAAgB,kBAAkB,CAAC;AAOtD,MAAM,WAAW,MAAM;AAC5B,QAAM,EAAE,gBAAgB,QAAI,kBAAI,0CAAiB;AACjD,QAAM,EAAE,aAAa,gBAAgB,aAAa,MAAM,UAAU,WAAW,YAAY,IAAI,IAAI;AACjG,SAAO;AAAA,IACL,MAAM,aAAa;AAAA,IACnB,QAAS,kBAAkB,CAAC;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA4BA,IAAI,yBAAqF;AAGlF,MAAM,4BAA4B,CACvC,aACS;AACT,2BAAyB;AAC3B;AAEO,MAAM,WAAW,CACtB,QACA,SACG;AACH,UAAQ,IAAI,2BAA2B,MAAM,EAAE;AAI/C,MAAI,WAAsE,CAAC;AAC3E,MAAI,QAAQ,oBAAoB,MAAM;AACpC,eAAW,EAAE,gBAAgB,KAAK,kBAAkB,KAAK;AAAA,EAC3D,WAAW,wBAAwB;AACjC,QAAI;AACF,YAAM,IAAI,uBAAuB,MAAM;AACvC,UAAI,MAAM,OAAW,YAAW,EAAE,gBAAgB,EAAE;AAAA,IACtD,QAAQ;AAAA,IAER;AAAA,EACF;AACA,uCAAY,aAAa;AAAA,IACvB,KAAK;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,GAAG;AAAA,EACL,CAAC;AACH;","names":[]}
|
package/dist/routing.d.cts
CHANGED
|
@@ -35,10 +35,10 @@ declare const useRoute: () => {
|
|
|
35
35
|
repository: string;
|
|
36
36
|
ref: string;
|
|
37
37
|
};
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
/** Register the app's route→viewed-document rule (R3-268); pass `null` to clear. */
|
|
39
|
+
declare const setViewedDocumentResolver: (resolver: ((targetHref: string) => string | null | undefined) | null) => void;
|
|
40
|
+
declare const navigate: (target: string, opts?: {
|
|
41
|
+
viewedDocument?: string | null;
|
|
42
|
+
}) => void;
|
|
43
43
|
|
|
44
|
-
export { type AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, useRoute, useRouteParams, useTinkerableLink };
|
|
44
|
+
export { type AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, setViewedDocumentResolver, useRoute, useRouteParams, useTinkerableLink };
|
package/dist/routing.d.ts
CHANGED
|
@@ -35,10 +35,10 @@ declare const useRoute: () => {
|
|
|
35
35
|
repository: string;
|
|
36
36
|
ref: string;
|
|
37
37
|
};
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
/** Register the app's route→viewed-document rule (R3-268); pass `null` to clear. */
|
|
39
|
+
declare const setViewedDocumentResolver: (resolver: ((targetHref: string) => string | null | undefined) | null) => void;
|
|
40
|
+
declare const navigate: (target: string, opts?: {
|
|
41
|
+
viewedDocument?: string | null;
|
|
42
|
+
}) => void;
|
|
43
43
|
|
|
44
|
-
export { type AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, useRoute, useRouteParams, useTinkerableLink };
|
|
44
|
+
export { type AppliedRoutingRule, Router, applyRoutingRule, navigate, renderRoute, setViewedDocumentResolver, useRoute, useRouteParams, useTinkerableLink };
|
package/dist/routing.js
CHANGED
|
@@ -56,12 +56,27 @@ const useRoute = () => {
|
|
|
56
56
|
ref
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
|
-
|
|
59
|
+
let viewedDocumentResolver = null;
|
|
60
|
+
const setViewedDocumentResolver = (resolver) => {
|
|
61
|
+
viewedDocumentResolver = resolver;
|
|
62
|
+
};
|
|
63
|
+
const navigate = (target, opts) => {
|
|
60
64
|
console.log(`[Sandbox] Navigating to ${target}`);
|
|
65
|
+
let declared = {};
|
|
66
|
+
if (opts && "viewedDocument" in opts) {
|
|
67
|
+
declared = { viewedDocument: opts.viewedDocument ?? null };
|
|
68
|
+
} else if (viewedDocumentResolver) {
|
|
69
|
+
try {
|
|
70
|
+
const v = viewedDocumentResolver(target);
|
|
71
|
+
if (v !== void 0) declared = { viewedDocument: v };
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
61
75
|
sendMessage("urlchange", {
|
|
62
76
|
url: target,
|
|
63
77
|
back: false,
|
|
64
|
-
forward: false
|
|
78
|
+
forward: false,
|
|
79
|
+
...declared
|
|
65
80
|
});
|
|
66
81
|
};
|
|
67
82
|
export {
|
|
@@ -69,6 +84,7 @@ export {
|
|
|
69
84
|
applyRoutingRule,
|
|
70
85
|
navigate,
|
|
71
86
|
renderRoute,
|
|
87
|
+
setViewedDocumentResolver,
|
|
72
88
|
useRoute,
|
|
73
89
|
useRouteParams,
|
|
74
90
|
useTinkerableLink
|
package/dist/routing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/routing.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { use, useContext } from 'react';\n\nimport { sendMessage } from './sandboxUtils';\nimport { NavigationState, TinkerableContext } from './TinkerableContext';\nimport { RouteParams, RoutingRule, RoutingSpec } from './RoutingSpec';\nimport { matchRoute } from './routeMatch';\nimport { constructUrl, isAbsolutePath, parseTarget } from './urlUtils';\nimport { joinPaths } from './pathUtils';\n\n/** The result of matching a path: the winning {@link RoutingRule} plus its captured params. */\nexport type AppliedRoutingRule = {\n routingRule: RoutingRule,\n pathParameters?: Record<string, string>;\n}\n\n/** Build the full outer href for an in-app target (absolute `sandboxPath` or a\n * path relative to the current route), e.g. for an `href` attribute. */\nexport const useTinkerableLink = (newSandboxLocation: string) => {\n const { outerHref, navigationState: navigation } = use(TinkerableContext);\n let newNavigationState = parseTarget(newSandboxLocation, navigation);\n if (!isAbsolutePath(newSandboxLocation)) {\n newNavigationState.sandboxPath = joinPaths(navigation.sandboxPath, newSandboxLocation)\n } else {\n newNavigationState.sandboxPath = newSandboxLocation\n }\n return constructUrl(outerHref, newNavigationState);\n}\n\n/** Find the first rule in `routingSpec` whose pattern matches the current\n * `sandboxPath`, returning it with the captured params (or `undefined`). */\nexport const applyRoutingRule = (routingSpec:RoutingSpec, navigationState: NavigationState): AppliedRoutingRule | undefined => {\n const { sandboxPath } = navigationState;\n for (const routingRule of routingSpec.routes) {\n const pathParameters = matchRoute(routingRule.pattern, sandboxPath);\n if (pathParameters) {\n return { routingRule, pathParameters };\n }\n }\n return undefined;\n}\n\n/** Render a matched rule, passing params to a `component` and falling back to `element`/`reactNode`. */\nexport const renderRoute = (routingRule: RoutingRule, params: RouteParams): ReactNode => {\n if (routingRule.component) {\n const Component = routingRule.component;\n return <Component params={params} />;\n }\n return routingRule.element ?? routingRule.reactNode ?? null;\n};\n\n/** Render the route matched for the current location (set up by `boot`'s route table). */\nexport const Router = () => {\n const context = useContext(TinkerableContext);\n const {navigationState: {routingRule, pathParameters}} = context;\n if (!routingRule) {\n // TODO: better error\n throw new Error(`No route registered for path ${context.navigationState.sandboxPath}!`);\n }\n\n return renderRoute(routingRule, pathParameters ?? {});\n};\n\n/** Read the current route's matched params (`:name` segments and the `*` wildcard). */\nexport const useRouteParams = <T extends RouteParams = RouteParams>(): T =>\n (use(TinkerableContext).navigationState.pathParameters ?? {}) as T;\n\n/**\n * Read the current route: the matched rule's `name`, its `params`, the app-owned\n * `sandboxPath`, and the read-only platform prefix fields (`mode`, `provider`,\n * `namespace`, `repository`, `ref`) — e.g. to tell `/edit` from `/present`.\n */\nexport const useRoute = () => {\n const { navigationState } = use(TinkerableContext);\n const { routingRule, pathParameters, sandboxPath, mode, provider, namespace, repository, ref } = navigationState;\n return {\n name: routingRule?.name,\n params: (pathParameters ?? {}) as RouteParams,\n sandboxPath,\n mode,\n provider,\n namespace,\n repository,\n ref,\n };\n};\n\n\n/**\n * Navigate within the app. Messages the host to update the URL; the host then\n * pushes the new href back, which drives the actual route change.\n */\nexport const navigate = (target: string) => {\n console.log(`[Sandbox] Navigating to ${target}`)\n sendMessage('urlchange', {\n url: target,\n back: false,\n forward: false,\n });\n};\n"],"mappings":";AA8CW;AA7CX,SAAS,KAAK,kBAAkB;AAEhC,SAAS,mBAAmB;AAC5B,SAA0B,yBAAyB;AAEnD,SAAS,kBAAkB;AAC3B,SAAS,cAAc,gBAAgB,mBAAmB;AAC1D,SAAS,iBAAiB;AAUnB,MAAM,oBAAoB,CAAC,uBAA+B;AAC/D,QAAM,EAAE,WAAW,iBAAiB,WAAW,IAAI,IAAI,iBAAiB;AACxE,MAAI,qBAAqB,YAAY,oBAAoB,UAAU;AACnE,MAAI,CAAC,eAAe,kBAAkB,GAAG;AACvC,uBAAmB,cAAc,UAAU,WAAW,aAAa,kBAAkB;AAAA,EACvF,OAAO;AACL,uBAAmB,cAAc;AAAA,EACnC;AACA,SAAO,aAAa,WAAW,kBAAkB;AACnD;AAIO,MAAM,mBAAmB,CAAC,aAAyB,oBAAqE;AAC7H,QAAM,EAAE,YAAY,IAAI;AACxB,aAAW,eAAe,YAAY,QAAQ;AAC5C,UAAM,iBAAiB,WAAW,YAAY,SAAS,WAAW;AAClE,QAAI,gBAAgB;AAClB,aAAO,EAAE,aAAa,eAAe;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAGO,MAAM,cAAc,CAAC,aAA0B,WAAmC;AACvF,MAAI,YAAY,WAAW;AACzB,UAAM,YAAY,YAAY;AAC9B,WAAO,oBAAC,aAAU,QAAgB;AAAA,EACpC;AACA,SAAO,YAAY,WAAW,YAAY,aAAa;AACzD;AAGO,MAAM,SAAS,MAAM;AAC1B,QAAM,UAAU,WAAW,iBAAiB;AAC5C,QAAM,EAAC,iBAAiB,EAAC,aAAa,eAAc,EAAC,IAAI;AACzD,MAAI,CAAC,aAAa;AAEhB,UAAM,IAAI,MAAM,gCAAgC,QAAQ,gBAAgB,WAAW,GAAG;AAAA,EACxF;AAEA,SAAO,YAAY,aAAa,kBAAkB,CAAC,CAAC;AACtD;AAGO,MAAM,iBAAiB,MAC3B,IAAI,iBAAiB,EAAE,gBAAgB,kBAAkB,CAAC;AAOtD,MAAM,WAAW,MAAM;AAC5B,QAAM,EAAE,gBAAgB,IAAI,IAAI,iBAAiB;AACjD,QAAM,EAAE,aAAa,gBAAgB,aAAa,MAAM,UAAU,WAAW,YAAY,IAAI,IAAI;AACjG,SAAO;AAAA,IACL,MAAM,aAAa;AAAA,IACnB,QAAS,kBAAkB,CAAC;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;
|
|
1
|
+
{"version":3,"sources":["../src/routing.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { use, useContext } from 'react';\n\nimport { sendMessage } from './sandboxUtils';\nimport { NavigationState, TinkerableContext } from './TinkerableContext';\nimport { RouteParams, RoutingRule, RoutingSpec } from './RoutingSpec';\nimport { matchRoute } from './routeMatch';\nimport { constructUrl, isAbsolutePath, parseTarget } from './urlUtils';\nimport { joinPaths } from './pathUtils';\n\n/** The result of matching a path: the winning {@link RoutingRule} plus its captured params. */\nexport type AppliedRoutingRule = {\n routingRule: RoutingRule,\n pathParameters?: Record<string, string>;\n}\n\n/** Build the full outer href for an in-app target (absolute `sandboxPath` or a\n * path relative to the current route), e.g. for an `href` attribute. */\nexport const useTinkerableLink = (newSandboxLocation: string) => {\n const { outerHref, navigationState: navigation } = use(TinkerableContext);\n let newNavigationState = parseTarget(newSandboxLocation, navigation);\n if (!isAbsolutePath(newSandboxLocation)) {\n newNavigationState.sandboxPath = joinPaths(navigation.sandboxPath, newSandboxLocation)\n } else {\n newNavigationState.sandboxPath = newSandboxLocation\n }\n return constructUrl(outerHref, newNavigationState);\n}\n\n/** Find the first rule in `routingSpec` whose pattern matches the current\n * `sandboxPath`, returning it with the captured params (or `undefined`). */\nexport const applyRoutingRule = (routingSpec:RoutingSpec, navigationState: NavigationState): AppliedRoutingRule | undefined => {\n const { sandboxPath } = navigationState;\n for (const routingRule of routingSpec.routes) {\n const pathParameters = matchRoute(routingRule.pattern, sandboxPath);\n if (pathParameters) {\n return { routingRule, pathParameters };\n }\n }\n return undefined;\n}\n\n/** Render a matched rule, passing params to a `component` and falling back to `element`/`reactNode`. */\nexport const renderRoute = (routingRule: RoutingRule, params: RouteParams): ReactNode => {\n if (routingRule.component) {\n const Component = routingRule.component;\n return <Component params={params} />;\n }\n return routingRule.element ?? routingRule.reactNode ?? null;\n};\n\n/** Render the route matched for the current location (set up by `boot`'s route table). */\nexport const Router = () => {\n const context = useContext(TinkerableContext);\n const {navigationState: {routingRule, pathParameters}} = context;\n if (!routingRule) {\n // TODO: better error\n throw new Error(`No route registered for path ${context.navigationState.sandboxPath}!`);\n }\n\n return renderRoute(routingRule, pathParameters ?? {});\n};\n\n/** Read the current route's matched params (`:name` segments and the `*` wildcard). */\nexport const useRouteParams = <T extends RouteParams = RouteParams>(): T =>\n (use(TinkerableContext).navigationState.pathParameters ?? {}) as T;\n\n/**\n * Read the current route: the matched rule's `name`, its `params`, the app-owned\n * `sandboxPath`, and the read-only platform prefix fields (`mode`, `provider`,\n * `namespace`, `repository`, `ref`) — e.g. to tell `/edit` from `/present`.\n */\nexport const useRoute = () => {\n const { navigationState } = use(TinkerableContext);\n const { routingRule, pathParameters, sandboxPath, mode, provider, namespace, repository, ref } = navigationState;\n return {\n name: routingRule?.name,\n params: (pathParameters ?? {}) as RouteParams,\n sandboxPath,\n mode,\n provider,\n namespace,\n repository,\n ref,\n };\n};\n\n\n/**\n * Navigate within the app. Messages the host to update the URL; the host then\n * pushes the new href back, which drives the actual route change.\n *\n * `opts.viewedDocument` (R3-268) optionally declares which WORKING-TREE file\n * this destination renders — a tri-state rider on the navigation event:\n * - omit the option entirely → the host derives the hint from the URL's\n * `files/` suffix convention (the zero-SDK default);\n * - `null` → this view shows no file (clears the highlight — tag pages,\n * search, home views);\n * - a repo-relative path (the CORPUS path under dispatch — only the viewer\n * can map its own key space) → the file explorer highlights it.\n * The hint is highlight-only by contract (it never scrolls, never moves focus\n * or panes, never switches the editor) and is validated host-side for\n * existence — a wrong path degrades to \"no highlight\", never an error. The\n * host remembers declarations per URL, so back/forward reproduces them\n * without re-announcement.\n */\n// R3-268: an app-registered rule mapping a navigation TARGET to its viewed\n// document, consulted by `navigate()` whenever the caller did not declare one\n// explicitly. Registered ONCE (e.g. at boot) so an app whose links all flow\n// through `<Link>`/`navigate` gets correct declarations everywhere without\n// threading an option through every call site. Return `undefined` for \"no\n// declaration\" (the host falls back to the URL convention), `null` for \"this\n// view shows no file\", or a working-tree repo-relative path.\nlet viewedDocumentResolver: ((targetHref: string) => string | null | undefined) | null = null;\n\n/** Register the app's route→viewed-document rule (R3-268); pass `null` to clear. */\nexport const setViewedDocumentResolver = (\n resolver: ((targetHref: string) => string | null | undefined) | null,\n): void => {\n viewedDocumentResolver = resolver;\n};\n\nexport const navigate = (\n target: string,\n opts?: { viewedDocument?: string | null },\n) => {\n console.log(`[Sandbox] Navigating to ${target}`)\n // Explicit option first; else the registered resolver; else nothing on the\n // wire (the host derives from the URL convention). A resolver throw is\n // swallowed to \"no declaration\" — a mapping bug must never break navigation.\n let declared: { viewedDocument: string | null } | Record<string, never> = {};\n if (opts && 'viewedDocument' in opts) {\n declared = { viewedDocument: opts.viewedDocument ?? null };\n } else if (viewedDocumentResolver) {\n try {\n const v = viewedDocumentResolver(target);\n if (v !== undefined) declared = { viewedDocument: v };\n } catch {\n /* no declaration */\n }\n }\n sendMessage('urlchange', {\n url: target,\n back: false,\n forward: false,\n ...declared,\n });\n};\n"],"mappings":";AA8CW;AA7CX,SAAS,KAAK,kBAAkB;AAEhC,SAAS,mBAAmB;AAC5B,SAA0B,yBAAyB;AAEnD,SAAS,kBAAkB;AAC3B,SAAS,cAAc,gBAAgB,mBAAmB;AAC1D,SAAS,iBAAiB;AAUnB,MAAM,oBAAoB,CAAC,uBAA+B;AAC/D,QAAM,EAAE,WAAW,iBAAiB,WAAW,IAAI,IAAI,iBAAiB;AACxE,MAAI,qBAAqB,YAAY,oBAAoB,UAAU;AACnE,MAAI,CAAC,eAAe,kBAAkB,GAAG;AACvC,uBAAmB,cAAc,UAAU,WAAW,aAAa,kBAAkB;AAAA,EACvF,OAAO;AACL,uBAAmB,cAAc;AAAA,EACnC;AACA,SAAO,aAAa,WAAW,kBAAkB;AACnD;AAIO,MAAM,mBAAmB,CAAC,aAAyB,oBAAqE;AAC7H,QAAM,EAAE,YAAY,IAAI;AACxB,aAAW,eAAe,YAAY,QAAQ;AAC5C,UAAM,iBAAiB,WAAW,YAAY,SAAS,WAAW;AAClE,QAAI,gBAAgB;AAClB,aAAO,EAAE,aAAa,eAAe;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAGO,MAAM,cAAc,CAAC,aAA0B,WAAmC;AACvF,MAAI,YAAY,WAAW;AACzB,UAAM,YAAY,YAAY;AAC9B,WAAO,oBAAC,aAAU,QAAgB;AAAA,EACpC;AACA,SAAO,YAAY,WAAW,YAAY,aAAa;AACzD;AAGO,MAAM,SAAS,MAAM;AAC1B,QAAM,UAAU,WAAW,iBAAiB;AAC5C,QAAM,EAAC,iBAAiB,EAAC,aAAa,eAAc,EAAC,IAAI;AACzD,MAAI,CAAC,aAAa;AAEhB,UAAM,IAAI,MAAM,gCAAgC,QAAQ,gBAAgB,WAAW,GAAG;AAAA,EACxF;AAEA,SAAO,YAAY,aAAa,kBAAkB,CAAC,CAAC;AACtD;AAGO,MAAM,iBAAiB,MAC3B,IAAI,iBAAiB,EAAE,gBAAgB,kBAAkB,CAAC;AAOtD,MAAM,WAAW,MAAM;AAC5B,QAAM,EAAE,gBAAgB,IAAI,IAAI,iBAAiB;AACjD,QAAM,EAAE,aAAa,gBAAgB,aAAa,MAAM,UAAU,WAAW,YAAY,IAAI,IAAI;AACjG,SAAO;AAAA,IACL,MAAM,aAAa;AAAA,IACnB,QAAS,kBAAkB,CAAC;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA4BA,IAAI,yBAAqF;AAGlF,MAAM,4BAA4B,CACvC,aACS;AACT,2BAAyB;AAC3B;AAEO,MAAM,WAAW,CACtB,QACA,SACG;AACH,UAAQ,IAAI,2BAA2B,MAAM,EAAE;AAI/C,MAAI,WAAsE,CAAC;AAC3E,MAAI,QAAQ,oBAAoB,MAAM;AACpC,eAAW,EAAE,gBAAgB,KAAK,kBAAkB,KAAK;AAAA,EAC3D,WAAW,wBAAwB;AACjC,QAAI;AACF,YAAM,IAAI,uBAAuB,MAAM;AACvC,UAAI,MAAM,OAAW,YAAW,EAAE,gBAAgB,EAAE;AAAA,IACtD,QAAQ;AAAA,IAER;AAAA,EACF;AACA,cAAY,aAAa;AAAA,IACvB,KAAK;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,GAAG;AAAA,EACL,CAAC;AACH;","names":[]}
|
package/dist/version.cjs
CHANGED
|
@@ -21,7 +21,7 @@ __export(version_exports, {
|
|
|
21
21
|
SDK_VERSION: () => SDK_VERSION
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(version_exports);
|
|
24
|
-
const SDK_VERSION = "0.
|
|
24
|
+
const SDK_VERSION = "0.43.1";
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
27
|
SDK_VERSION
|
package/dist/version.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.43.1';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,MAAM,cAAc;","names":[]}
|
package/dist/version.d.cts
CHANGED
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.43.1';\n"],"mappings":";AAIO,MAAM,cAAc;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@immediately-run/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.1",
|
|
4
4
|
"description": "Runtime SDK for code executing inside an immediately.run sandbox.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "github:immediately-run/immediately-run-sdk",
|
|
@@ -48,19 +48,19 @@
|
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@immediately-run/mdx-plugins": "^0.1.0",
|
|
50
50
|
"@testing-library/dom": "^10.4.1",
|
|
51
|
-
"esbuild": "^0.27.0",
|
|
52
|
-
"mdast-util-from-markdown": "^2.0.3",
|
|
53
|
-
"mdast-util-gfm": "^3.1.0",
|
|
54
|
-
"mdast-util-mdx-jsx": "^3.2.0",
|
|
55
|
-
"micromark-extension-gfm": "^3.0.0",
|
|
56
|
-
"micromark-extension-mdx-jsx": "^3.0.2",
|
|
57
51
|
"@testing-library/react": "^16.3.2",
|
|
58
52
|
"@types/jest": "^29.5.0",
|
|
59
53
|
"@types/react": "^19.0.0",
|
|
60
54
|
"@types/react-dom": "^19.0.0",
|
|
55
|
+
"esbuild": "^0.27.0",
|
|
61
56
|
"jest": "^29.5.0",
|
|
62
57
|
"jest-environment-jsdom": "^29.7.0",
|
|
63
58
|
"jsdom": "^25.0.1",
|
|
59
|
+
"mdast-util-from-markdown": "^2.0.3",
|
|
60
|
+
"mdast-util-gfm": "^3.1.0",
|
|
61
|
+
"mdast-util-mdx-jsx": "^3.2.0",
|
|
62
|
+
"micromark-extension-gfm": "^3.0.0",
|
|
63
|
+
"micromark-extension-mdx-jsx": "^3.0.2",
|
|
64
64
|
"react": "^19.1.0",
|
|
65
65
|
"react-dom": "^19.1.0",
|
|
66
66
|
"ts-jest": "^29.1.0",
|