@agimon-ai/po-web-components 0.0.0-alpha.79 → 0.0.0-alpha.80
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/packages/core/po-web-components/src/components/Markdown.d.mts.map +1 -1
- package/dist/packages/core/po-web-components/src/components/Markdown.mjs +2 -2
- package/dist/packages/core/po-web-components/src/components/Markdown.mjs.map +1 -1
- package/dist/src/components/Markdown.cjs +2 -2
- package/dist/src/components/Markdown.cjs.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Markdown.d.mts","names":[],"sources":["../../../../../../src/components/Markdown.tsx"],"mappings":";;;;;;;;;;YAoCY,mBAAmB,cAAc;;KAWxC,eAAe,iBAAiB;EAAU;EAAa;EAAiB;;;
|
|
1
|
+
{"version":3,"file":"Markdown.d.mts","names":[],"sources":["../../../../../../src/components/Markdown.tsx"],"mappings":";;;;;;;;;;YAoCY,mBAAmB,cAAc;;KAWxC,eAAe,iBAAiB;EAAU;EAAa;EAAiB;;;wBA2M7D,WACd,MACA,YACA,WACA,cACA;EAEA;EACA,aAAa;EACb,YAAY;;EAEZ;;EAEA,oBAAoB;oBACrB,IAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{MarkdownMediaContext as e}from"../lib/markdownMedia.mjs";import{CodeBlock as t}from"./CodeBlock.mjs";import{MediaViewerDialog as n}from"./MediaViewerDialog.mjs";import{jsx as r,jsxs as i}from"react/jsx-runtime";import{createContext as a,isValidElement as o,useContext as s,useEffect as c,useMemo as l,useState as u}from"react";import d from"react-markdown";import
|
|
2
|
-
`)?t:void 0,o=a===void 0||e!==void 0?void 0:i?.(a);return o!==void 0&&a!==void 0?/* @__PURE__ */ r(`button`,{type:`button`,"data-testid":`markdown-file-link`,title:`open ${a}`,onClick:o,className:`${
|
|
1
|
+
import{MarkdownMediaContext as e}from"../lib/markdownMedia.mjs";import{CodeBlock as t}from"./CodeBlock.mjs";import{MediaViewerDialog as n}from"./MediaViewerDialog.mjs";import{jsx as r,jsxs as i}from"react/jsx-runtime";import{createContext as a,isValidElement as o,useContext as s,useEffect as c,useMemo as l,useState as u}from"react";import d,{defaultUrlTransform as f}from"react-markdown";import p from"remark-gfm";const m=[p],h=`rounded bg-po-deep px-1 py-px font-mono text-po-green`,g=a(void 0),_=a(void 0);function v({src:t,alt:n}){let a=s(_),o=s(e),l=typeof t==`string`&&/^@?artifact:/u.test(t),d;if(typeof t==`string`&&t!==``&&(l||!/^(?:[a-z][a-z\d+.-]*:|\/\/|#|\?)/i.test(t)))try{d=decodeURIComponent((l&&t.startsWith(`@`)?t.slice(1):t).split(/[?#]/,1)[0])}catch{d=``}let[f,p]=u();c(()=>{if(a===void 0||d===void 0)return;let e=!0,t;return Promise.resolve().then(()=>{if(e&&p(void 0),d===``)throw Error(`Invalid image path.`);return a(d)}).then(n=>{e?(t=n,p({path:d,loader:a,url:n.url,sourcePath:n.path??d})):n.dispose()}).catch(()=>{e&&p({path:d,loader:a,failed:!0})}),()=>{e=!1,t?.dispose()}},[d,a]);let m=f?.path===d&&f?.loader===a?f:void 0,h=m?.failed===!0||l&&a===void 0;if(h||a!==void 0&&d!==void 0&&m?.url===void 0)return/* @__PURE__ */ i(`span`,{role:h?`alert`:`status`,title:d,children:[n||d||`Image`,` (`,h?`unavailable`:`loading...`,`)`]});let g=a!==void 0&&d!==void 0?m?.url:t,v=/* @__PURE__ */ r(`img`,{src:g,alt:n??``,onError:a!==void 0&&d!==void 0?()=>p({path:d,loader:a,failed:!0}):void 0,className:`max-h-[480px] max-w-full rounded border border-po-border`});if(o===void 0||typeof g!=`string`||g===``)return v;let y=n||d||`Image`;return/* @__PURE__ */ r(`button`,{type:`button`,"data-testid":`markdown-media-open`,"aria-label":`Open ${y} full screen`,onClick:()=>o.open({kind:`image`,title:y,url:g,sourcePath:m?.sourcePath??d}),className:`max-w-full cursor-zoom-in rounded focus-visible:ring-2 focus-visible:ring-po-blue focus-visible:outline-none`,children:v})}function y({className:e,children:t,...n}){let i=s(g),a=typeof t==`string`&&!t.includes(`
|
|
2
|
+
`)?t:void 0,o=a===void 0||e!==void 0?void 0:i?.(a);return o!==void 0&&a!==void 0?/* @__PURE__ */ r(`button`,{type:`button`,"data-testid":`markdown-file-link`,title:`open ${a}`,onClick:o,className:`${h} cursor-pointer underline decoration-po-green/40 underline-offset-2 hover:text-po-hi hover:decoration-po-hi`,children:a}):/* @__PURE__ */ r(`code`,{...n,className:`${e??``} ${h} [pre_&]:bg-transparent [pre_&]:p-0 [pre_&]:text-po-hi`,children:t})}function b({href:e,children:t}){let n=s(g),i=e;try{i=e===void 0?void 0:decodeURIComponent(e)}catch{i=void 0}let a=i!==void 0&&i!==``&&!/^(?:[a-z][a-z\d+.-]*:|\/\/|#|\?)/i.test(i)?n?.(i,!0):void 0;return a===void 0?/* @__PURE__ */ r(`a`,{href:e,target:`_blank`,rel:`noreferrer`,className:`text-po-blue underline decoration-po-blue/50`,children:t}):/* @__PURE__ */ r(`button`,{type:`button`,"data-testid":`markdown-file-link`,title:`open ${i}`,onClick:a,className:`text-po-blue underline decoration-po-blue/50`,children:t})}function x(e){return typeof e==`string`?e:Array.isArray(e)?e.map(e=>x(e)).join(``):``}function S({children:e}){let n=o(e)?e:void 0;return n===void 0?/* @__PURE__ */ r(`pre`,{className:`overflow-x-auto rounded border border-po-border bg-po-deep p-2.5 text-sm leading-relaxed`,children:e}):/* @__PURE__ */ r(t,{text:x(n.props.children).replace(/\n$/,``),className:n.props.className})}const C={p:({children:e})=>/* @__PURE__ */ r(`p`,{className:`whitespace-pre-wrap break-words`,children:e}),strong:({children:e})=>/* @__PURE__ */ r(`strong`,{className:`font-semibold text-po-hi`,children:e}),em:({children:e})=>/* @__PURE__ */ r(`em`,{className:`italic`,children:e}),del:({children:e})=>/* @__PURE__ */ r(`del`,{className:`text-po-dim line-through`,children:e}),a:b,code:y,pre:S,ul:({children:e})=>/* @__PURE__ */ r(`ul`,{className:`list-disc pl-5`,children:e}),ol:({children:e})=>/* @__PURE__ */ r(`ol`,{className:`list-decimal pl-5`,children:e}),li:({children:e})=>/* @__PURE__ */ r(`li`,{className:`whitespace-pre-wrap break-words`,children:e}),h1:({children:e})=>/* @__PURE__ */ r(`h1`,{className:`mt-2 text-2xl font-semibold text-po-hi first:mt-0`,children:e}),h2:({children:e})=>/* @__PURE__ */ r(`h2`,{className:`mt-2 text-xl font-semibold text-po-hi first:mt-0`,children:e}),h3:({children:e})=>/* @__PURE__ */ r(`h3`,{className:`mt-1 text-lg font-semibold text-po-hi first:mt-0`,children:e}),h4:({children:e})=>/* @__PURE__ */ r(`h4`,{className:`font-semibold text-po-hi`,children:e}),h5:({children:e})=>/* @__PURE__ */ r(`h5`,{className:`font-semibold text-po-text`,children:e}),h6:({children:e})=>/* @__PURE__ */ r(`h6`,{className:`font-semibold text-po-dim`,children:e}),blockquote:({children:e})=>/* @__PURE__ */ r(`blockquote`,{className:`border-l-2 border-po-border pl-3 text-po-dim`,children:e}),hr:()=>/* @__PURE__ */ r(`hr`,{className:`border-po-border-soft`}),table:({children:e})=>/* @__PURE__ */ r(`div`,{className:`overflow-x-auto`,children:/* @__PURE__ */ r(`table`,{className:`border-collapse`,children:e})}),th:({children:e})=>/* @__PURE__ */ r(`th`,{className:`border border-po-border bg-po-deep px-2 py-1 text-left font-semibold text-po-hi`,children:e}),td:({children:e})=>/* @__PURE__ */ r(`td`,{className:`border border-po-border px-2 py-1 align-top`,children:e}),img:v};function w({text:t,onFileLink:a,loadImage:o,documentPath:s,renderMediaReview:c}){let[p,h]=u(),v=l(()=>({open:e=>h({...e,...s===void 0?{}:{documentPath:s}})}),[s]),y=()=>h(void 0);return/* @__PURE__ */ r(g.Provider,{value:a,children:/* @__PURE__ */ r(_.Provider,{value:o,children:/* @__PURE__ */ i(e.Provider,{value:v,children:[/* @__PURE__ */ r(`div`,{className:`flex min-w-0 flex-col gap-2`,children:/* @__PURE__ */ r(d,{remarkPlugins:m,components:C,urlTransform:(e,t,n)=>t===`src`&&n.tagName===`img`&&/^@?artifact:/u.test(e)?e:f(e),children:t})}),/* @__PURE__ */ r(n,{media:p,onClose:y,review:p===void 0?void 0:c?.(p,y)})]})})})}export{w as Markdown};
|
|
3
3
|
//# sourceMappingURL=Markdown.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Markdown.mjs","names":["ReactMarkdown","remarkGfm","REMARK_PLUGINS","CODE_CLASS","FileLinkContext","createContext","ImageContext","Image","loader","useContext","media","MarkdownMediaContext","path","src","loaded","setLoaded","useState","useEffect","active","asset","result","current","alt","url","image","title","Code","rest","onFileLink","label","children","open","className","Link","href","textOf","child","Pre","code","isValidElement","CodeBlock","COMPONENTS","Markdown","opened","setOpened","useMemo","next","documentPath","close","loadImage","text","MediaViewerDialog","renderMediaReview"],"sources":["../../../../../../src/components/Markdown.tsx"],"sourcesContent":["import {\n createContext,\n type ComponentProps,\n isValidElement,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nimport {\n type MarkdownMedia,\n MarkdownMediaContext,\n type MarkdownMediaContextValue,\n type MarkdownMediaReview,\n} from '../lib/markdownMedia';\nimport { CodeBlock } from './CodeBlock';\nimport { MediaViewerDialog } from './MediaViewerDialog';\n\nconst REMARK_PLUGINS = [remarkGfm];\n\n// No size: inline code follows the prose it sits in, 15px in the conversation\n// and 13px in a compact transcript, so a path never reads smaller than its sentence.\nconst CODE_CLASS = 'rounded bg-po-deep px-1 py-px font-mono text-po-green';\n\n/**\n * What a piece of inline code opens, when the host knows.\n *\n * Returning undefined leaves the span as plain code, which is the answer for\n * everything a message quotes that is not a file: a class name, a flag, a\n * command. The caller decides what counts, because only it knows which files\n * the session has.\n */\nexport type FileLinkHandler = (text: string, explicit?: boolean) => (() => void) | undefined;\n\n/**\n * Passed by context rather than as a component prop so the component map stays\n * a module constant. Rebuilding that map per render gives react-markdown new\n * component identities, which remounts the whole rendered tree on every frame\n * of a streaming reply.\n */\nconst FileLinkContext = createContext<FileLinkHandler | undefined>(undefined);\n\n/** `path` is the file the host resolved the image to, kept as review provenance. */\ntype ImageLoader = (path: string) => Promise<{ url: string; dispose(): void; path?: string }>;\nconst ImageContext = createContext<ImageLoader | undefined>(undefined);\n\nfunction Image({ src, alt }: ComponentProps<'img'>) {\n const loader = useContext(ImageContext);\n const media = useContext(MarkdownMediaContext);\n let path: string | undefined;\n if (typeof src === 'string' && src !== '' && !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|#|\\?)/i.test(src)) {\n try {\n path = decodeURIComponent(src.split(/[?#]/, 1)[0]!);\n } catch {\n // An invalid encoded filename is shown as unavailable, never fetched.\n path = '';\n }\n }\n const [loaded, setLoaded] = useState<{\n path: string;\n loader: ImageLoader;\n url?: string;\n sourcePath?: string;\n failed?: boolean;\n }>();\n useEffect(() => {\n if (loader === undefined || path === undefined) return;\n let active = true;\n let asset: Awaited<ReturnType<ImageLoader>> | undefined;\n void Promise.resolve()\n .then(() => {\n if (active) setLoaded(undefined);\n if (path === '') throw new Error('Invalid image path.');\n return loader(path);\n })\n .then((result) => {\n if (!active) {\n result.dispose();\n return;\n }\n asset = result;\n setLoaded({ path, loader, url: result.url, sourcePath: result.path ?? path });\n })\n .catch(() => {\n if (active) setLoaded({ path, loader, failed: true });\n });\n return () => {\n active = false;\n asset?.dispose();\n };\n }, [path, loader]);\n const current = loaded?.path === path && loaded?.loader === loader ? loaded : undefined;\n if (loader !== undefined && path !== undefined && (current?.url === undefined || current.failed))\n return (\n <span role={current?.failed ? 'alert' : 'status'} title={path}>\n {alt || path || 'Image'} ({current?.failed ? 'unavailable' : 'loading...'})\n </span>\n );\n const url = loader !== undefined && path !== undefined ? current?.url : src;\n const image = (\n <img\n src={url}\n alt={alt ?? ''}\n onError={loader !== undefined && path !== undefined ? () => setLoaded({ path, loader, failed: true }) : undefined}\n className=\"max-h-[480px] max-w-full rounded border border-po-border\"\n />\n );\n if (media === undefined || typeof url !== 'string' || url === '') return image;\n const title = alt || path || 'Image';\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-media-open\"\n aria-label={`Open ${title} full screen`}\n onClick={() => media.open({ kind: 'image', title, url, sourcePath: current?.sourcePath ?? path })}\n className=\"max-w-full cursor-zoom-in rounded focus-visible:ring-2 focus-visible:ring-po-blue focus-visible:outline-none\"\n >\n {image}\n </button>\n );\n}\n\nfunction Code({ className, children, ...rest }: ComponentProps<'code'>) {\n const onFileLink = useContext(FileLinkContext);\n // Only a single-line span with no language class is a candidate: a fenced\n // block is content, not a reference, and its own renderer owns it.\n const label = typeof children === 'string' && !children.includes('\\n') ? children : undefined;\n const open = label === undefined || className !== undefined ? undefined : onFileLink?.(label);\n if (open !== undefined && label !== undefined) {\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-file-link\"\n title={`open ${label}`}\n onClick={open}\n className={`${CODE_CLASS} cursor-pointer underline decoration-po-green/40 underline-offset-2 hover:text-po-hi hover:decoration-po-hi`}\n >\n {label}\n </button>\n );\n }\n return (\n <code\n {...rest}\n className={`${className ?? ''} ${CODE_CLASS} [pre_&]:bg-transparent [pre_&]:p-0 [pre_&]:text-po-hi`}\n >\n {children}\n </code>\n );\n}\n\nfunction Link({ href, children }: ComponentProps<'a'>) {\n const onFileLink = useContext(FileLinkContext);\n let path = href;\n try {\n path = href === undefined ? undefined : decodeURIComponent(href);\n } catch {\n path = undefined;\n }\n const isFile = path !== undefined && path !== '' && !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|#|\\?)/i.test(path);\n const open = isFile ? onFileLink?.(path!, true) : undefined;\n if (open !== undefined)\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-file-link\"\n title={`open ${path}`}\n onClick={open}\n className=\"text-po-blue underline decoration-po-blue/50\"\n >\n {children}\n </button>\n );\n return (\n <a href={href} target=\"_blank\" rel=\"noreferrer\" className=\"text-po-blue underline decoration-po-blue/50\">\n {children}\n </a>\n );\n}\n\n/** The text inside a fence, which react-markdown hands over as nested strings. */\nfunction textOf(children: ReactNode): string {\n if (typeof children === 'string') return children;\n if (Array.isArray(children)) return children.map((child) => textOf(child as ReactNode)).join('');\n return '';\n}\n\n/**\n * A fenced block, read off the <code> child that carries its language.\n *\n * The block is handed to `CodeBlock` whole rather than rendered as a styled\n * <pre> around inline code, because a fence is content with its own\n * presentation: it is coloured, it can be copied, and a mermaid fence is a\n * picture. A <pre> that came from raw HTML has no such child and keeps the\n * plain box.\n */\nfunction Pre({ children }: ComponentProps<'pre'>) {\n const code = isValidElement<{ className?: string; children?: ReactNode }>(children) ? children : undefined;\n if (code === undefined)\n return (\n <pre className=\"overflow-x-auto rounded border border-po-border bg-po-deep p-2.5 text-sm leading-relaxed\">\n {children}\n </pre>\n );\n // Markdown ends every fence with a newline the author did not type.\n return <CodeBlock text={textOf(code.props.children).replace(/\\n$/, '')} className={code.props.className} />;\n}\nconst COMPONENTS: Components = {\n p: ({ children }) => <p className=\"whitespace-pre-wrap break-words\">{children}</p>,\n strong: ({ children }) => <strong className=\"font-semibold text-po-hi\">{children}</strong>,\n em: ({ children }) => <em className=\"italic\">{children}</em>,\n del: ({ children }) => <del className=\"text-po-dim line-through\">{children}</del>,\n a: Link,\n code: Code,\n pre: Pre,\n ul: ({ children }) => <ul className=\"list-disc pl-5\">{children}</ul>,\n ol: ({ children }) => <ol className=\"list-decimal pl-5\">{children}</ol>,\n li: ({ children }) => <li className=\"whitespace-pre-wrap break-words\">{children}</li>,\n // Headings step up from the prose they sit in and never shrink below it, so a\n // reply's `##` reads as a heading in both the 15px conversation and a 13px\n // compact transcript. h4 to h6 keep the prose size and lean on weight alone.\n h1: ({ children }) => <h1 className=\"mt-2 text-2xl font-semibold text-po-hi first:mt-0\">{children}</h1>,\n h2: ({ children }) => <h2 className=\"mt-2 text-xl font-semibold text-po-hi first:mt-0\">{children}</h2>,\n h3: ({ children }) => <h3 className=\"mt-1 text-lg font-semibold text-po-hi first:mt-0\">{children}</h3>,\n h4: ({ children }) => <h4 className=\"font-semibold text-po-hi\">{children}</h4>,\n h5: ({ children }) => <h5 className=\"font-semibold text-po-text\">{children}</h5>,\n h6: ({ children }) => <h6 className=\"font-semibold text-po-dim\">{children}</h6>,\n blockquote: ({ children }) => (\n <blockquote className=\"border-l-2 border-po-border pl-3 text-po-dim\">{children}</blockquote>\n ),\n hr: () => <hr className=\"border-po-border-soft\" />,\n table: ({ children }) => (\n <div className=\"overflow-x-auto\">\n <table className=\"border-collapse\">{children}</table>\n </div>\n ),\n th: ({ children }) => (\n <th className=\"border border-po-border bg-po-deep px-2 py-1 text-left font-semibold text-po-hi\">{children}</th>\n ),\n td: ({ children }) => <td className=\"border border-po-border px-2 py-1 align-top\">{children}</td>,\n img: Image,\n};\n\n/** GitHub-flavored Markdown using the cockpit's safe, shared presentation. */\nexport function Markdown({\n text,\n onFileLink,\n loadImage,\n documentPath,\n renderMediaReview,\n}: {\n text: string;\n onFileLink?: FileLinkHandler;\n loadImage?: ImageLoader;\n /** The file this Markdown came from, passed to a reviewer of its pictures. */\n documentPath?: string;\n /** Annotate and review surface for an opened picture; without it the viewer only pans and zooms. */\n renderMediaReview?: MarkdownMediaReview;\n}) {\n const [opened, setOpened] = useState<MarkdownMedia>();\n const media = useMemo<MarkdownMediaContextValue>(\n () => ({ open: (next) => setOpened({ ...next, ...(documentPath === undefined ? {} : { documentPath }) }) }),\n [documentPath],\n );\n const close = () => setOpened(undefined);\n return (\n <FileLinkContext.Provider value={onFileLink}>\n <ImageContext.Provider value={loadImage}>\n <MarkdownMediaContext.Provider value={media}>\n <div className=\"flex min-w-0 flex-col gap-2\">\n <ReactMarkdown remarkPlugins={REMARK_PLUGINS} components={COMPONENTS}>\n {text}\n </ReactMarkdown>\n </div>\n <MediaViewerDialog\n media={opened}\n onClose={close}\n review={opened === undefined ? undefined : renderMediaReview?.(opened, close)}\n />\n </MarkdownMediaContext.Provider>\n </ImageContext.Provider>\n </FileLinkContext.Provider>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Markdown.mjs","names":["ReactMarkdown","remarkGfm","REMARK_PLUGINS","CODE_CLASS","FileLinkContext","createContext","ImageContext","Image","loader","useContext","media","MarkdownMediaContext","artifact","src","path","loaded","setLoaded","useState","useEffect","active","asset","result","current","unavailable","alt","url","image","title","Code","rest","onFileLink","label","children","open","className","Link","href","textOf","child","Pre","code","isValidElement","CodeBlock","COMPONENTS","Markdown","opened","setOpened","useMemo","next","documentPath","close","loadImage","key","node","defaultUrlTransform","text","MediaViewerDialog","renderMediaReview"],"sources":["../../../../../../src/components/Markdown.tsx"],"sourcesContent":["import {\n createContext,\n type ComponentProps,\n isValidElement,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport ReactMarkdown, { defaultUrlTransform, type Components } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nimport {\n type MarkdownMedia,\n MarkdownMediaContext,\n type MarkdownMediaContextValue,\n type MarkdownMediaReview,\n} from '../lib/markdownMedia';\nimport { CodeBlock } from './CodeBlock';\nimport { MediaViewerDialog } from './MediaViewerDialog';\n\nconst REMARK_PLUGINS = [remarkGfm];\n\n// No size: inline code follows the prose it sits in, 15px in the conversation\n// and 13px in a compact transcript, so a path never reads smaller than its sentence.\nconst CODE_CLASS = 'rounded bg-po-deep px-1 py-px font-mono text-po-green';\n\n/**\n * What a piece of inline code opens, when the host knows.\n *\n * Returning undefined leaves the span as plain code, which is the answer for\n * everything a message quotes that is not a file: a class name, a flag, a\n * command. The caller decides what counts, because only it knows which files\n * the session has.\n */\nexport type FileLinkHandler = (text: string, explicit?: boolean) => (() => void) | undefined;\n\n/**\n * Passed by context rather than as a component prop so the component map stays\n * a module constant. Rebuilding that map per render gives react-markdown new\n * component identities, which remounts the whole rendered tree on every frame\n * of a streaming reply.\n */\nconst FileLinkContext = createContext<FileLinkHandler | undefined>(undefined);\n\n/** `path` is the file the host resolved the image to, kept as review provenance. */\ntype ImageLoader = (path: string) => Promise<{ url: string; dispose(): void; path?: string }>;\nconst ImageContext = createContext<ImageLoader | undefined>(undefined);\n\nfunction Image({ src, alt }: ComponentProps<'img'>) {\n const loader = useContext(ImageContext);\n const media = useContext(MarkdownMediaContext);\n const artifact = typeof src === 'string' && /^@?artifact:/u.test(src);\n let path: string | undefined;\n if (typeof src === 'string' && src !== '' && (artifact || !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|#|\\?)/i.test(src))) {\n try {\n path = decodeURIComponent((artifact && src.startsWith('@') ? src.slice(1) : src).split(/[?#]/, 1)[0]!);\n } catch {\n // An invalid encoded filename is shown as unavailable, never fetched.\n path = '';\n }\n }\n const [loaded, setLoaded] = useState<{\n path: string;\n loader: ImageLoader;\n url?: string;\n sourcePath?: string;\n failed?: boolean;\n }>();\n useEffect(() => {\n if (loader === undefined || path === undefined) return;\n let active = true;\n let asset: Awaited<ReturnType<ImageLoader>> | undefined;\n void Promise.resolve()\n .then(() => {\n if (active) setLoaded(undefined);\n if (path === '') throw new Error('Invalid image path.');\n return loader(path);\n })\n .then((result) => {\n if (!active) {\n result.dispose();\n return;\n }\n asset = result;\n setLoaded({ path, loader, url: result.url, sourcePath: result.path ?? path });\n })\n .catch(() => {\n if (active) setLoaded({ path, loader, failed: true });\n });\n return () => {\n active = false;\n asset?.dispose();\n };\n }, [path, loader]);\n const current = loaded?.path === path && loaded?.loader === loader ? loaded : undefined;\n const unavailable = current?.failed === true || (artifact && loader === undefined);\n if (unavailable || (loader !== undefined && path !== undefined && current?.url === undefined))\n return (\n <span role={unavailable ? 'alert' : 'status'} title={path}>\n {alt || path || 'Image'} ({unavailable ? 'unavailable' : 'loading...'})\n </span>\n );\n const url = loader !== undefined && path !== undefined ? current?.url : src;\n const image = (\n <img\n src={url}\n alt={alt ?? ''}\n onError={loader !== undefined && path !== undefined ? () => setLoaded({ path, loader, failed: true }) : undefined}\n className=\"max-h-[480px] max-w-full rounded border border-po-border\"\n />\n );\n if (media === undefined || typeof url !== 'string' || url === '') return image;\n const title = alt || path || 'Image';\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-media-open\"\n aria-label={`Open ${title} full screen`}\n onClick={() => media.open({ kind: 'image', title, url, sourcePath: current?.sourcePath ?? path })}\n className=\"max-w-full cursor-zoom-in rounded focus-visible:ring-2 focus-visible:ring-po-blue focus-visible:outline-none\"\n >\n {image}\n </button>\n );\n}\n\nfunction Code({ className, children, ...rest }: ComponentProps<'code'>) {\n const onFileLink = useContext(FileLinkContext);\n // Only a single-line span with no language class is a candidate: a fenced\n // block is content, not a reference, and its own renderer owns it.\n const label = typeof children === 'string' && !children.includes('\\n') ? children : undefined;\n const open = label === undefined || className !== undefined ? undefined : onFileLink?.(label);\n if (open !== undefined && label !== undefined) {\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-file-link\"\n title={`open ${label}`}\n onClick={open}\n className={`${CODE_CLASS} cursor-pointer underline decoration-po-green/40 underline-offset-2 hover:text-po-hi hover:decoration-po-hi`}\n >\n {label}\n </button>\n );\n }\n return (\n <code\n {...rest}\n className={`${className ?? ''} ${CODE_CLASS} [pre_&]:bg-transparent [pre_&]:p-0 [pre_&]:text-po-hi`}\n >\n {children}\n </code>\n );\n}\n\nfunction Link({ href, children }: ComponentProps<'a'>) {\n const onFileLink = useContext(FileLinkContext);\n let path = href;\n try {\n path = href === undefined ? undefined : decodeURIComponent(href);\n } catch {\n path = undefined;\n }\n const isFile = path !== undefined && path !== '' && !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|#|\\?)/i.test(path);\n const open = isFile ? onFileLink?.(path!, true) : undefined;\n if (open !== undefined)\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-file-link\"\n title={`open ${path}`}\n onClick={open}\n className=\"text-po-blue underline decoration-po-blue/50\"\n >\n {children}\n </button>\n );\n return (\n <a href={href} target=\"_blank\" rel=\"noreferrer\" className=\"text-po-blue underline decoration-po-blue/50\">\n {children}\n </a>\n );\n}\n\n/** The text inside a fence, which react-markdown hands over as nested strings. */\nfunction textOf(children: ReactNode): string {\n if (typeof children === 'string') return children;\n if (Array.isArray(children)) return children.map((child) => textOf(child as ReactNode)).join('');\n return '';\n}\n\n/**\n * A fenced block, read off the <code> child that carries its language.\n *\n * The block is handed to `CodeBlock` whole rather than rendered as a styled\n * <pre> around inline code, because a fence is content with its own\n * presentation: it is coloured, it can be copied, and a mermaid fence is a\n * picture. A <pre> that came from raw HTML has no such child and keeps the\n * plain box.\n */\nfunction Pre({ children }: ComponentProps<'pre'>) {\n const code = isValidElement<{ className?: string; children?: ReactNode }>(children) ? children : undefined;\n if (code === undefined)\n return (\n <pre className=\"overflow-x-auto rounded border border-po-border bg-po-deep p-2.5 text-sm leading-relaxed\">\n {children}\n </pre>\n );\n // Markdown ends every fence with a newline the author did not type.\n return <CodeBlock text={textOf(code.props.children).replace(/\\n$/, '')} className={code.props.className} />;\n}\nconst COMPONENTS: Components = {\n p: ({ children }) => <p className=\"whitespace-pre-wrap break-words\">{children}</p>,\n strong: ({ children }) => <strong className=\"font-semibold text-po-hi\">{children}</strong>,\n em: ({ children }) => <em className=\"italic\">{children}</em>,\n del: ({ children }) => <del className=\"text-po-dim line-through\">{children}</del>,\n a: Link,\n code: Code,\n pre: Pre,\n ul: ({ children }) => <ul className=\"list-disc pl-5\">{children}</ul>,\n ol: ({ children }) => <ol className=\"list-decimal pl-5\">{children}</ol>,\n li: ({ children }) => <li className=\"whitespace-pre-wrap break-words\">{children}</li>,\n // Headings step up from the prose they sit in and never shrink below it, so a\n // reply's `##` reads as a heading in both the 15px conversation and a 13px\n // compact transcript. h4 to h6 keep the prose size and lean on weight alone.\n h1: ({ children }) => <h1 className=\"mt-2 text-2xl font-semibold text-po-hi first:mt-0\">{children}</h1>,\n h2: ({ children }) => <h2 className=\"mt-2 text-xl font-semibold text-po-hi first:mt-0\">{children}</h2>,\n h3: ({ children }) => <h3 className=\"mt-1 text-lg font-semibold text-po-hi first:mt-0\">{children}</h3>,\n h4: ({ children }) => <h4 className=\"font-semibold text-po-hi\">{children}</h4>,\n h5: ({ children }) => <h5 className=\"font-semibold text-po-text\">{children}</h5>,\n h6: ({ children }) => <h6 className=\"font-semibold text-po-dim\">{children}</h6>,\n blockquote: ({ children }) => (\n <blockquote className=\"border-l-2 border-po-border pl-3 text-po-dim\">{children}</blockquote>\n ),\n hr: () => <hr className=\"border-po-border-soft\" />,\n table: ({ children }) => (\n <div className=\"overflow-x-auto\">\n <table className=\"border-collapse\">{children}</table>\n </div>\n ),\n th: ({ children }) => (\n <th className=\"border border-po-border bg-po-deep px-2 py-1 text-left font-semibold text-po-hi\">{children}</th>\n ),\n td: ({ children }) => <td className=\"border border-po-border px-2 py-1 align-top\">{children}</td>,\n img: Image,\n};\n\n/** GitHub-flavored Markdown using the cockpit's safe, shared presentation. */\nexport function Markdown({\n text,\n onFileLink,\n loadImage,\n documentPath,\n renderMediaReview,\n}: {\n text: string;\n onFileLink?: FileLinkHandler;\n loadImage?: ImageLoader;\n /** The file this Markdown came from, passed to a reviewer of its pictures. */\n documentPath?: string;\n /** Annotate and review surface for an opened picture; without it the viewer only pans and zooms. */\n renderMediaReview?: MarkdownMediaReview;\n}) {\n const [opened, setOpened] = useState<MarkdownMedia>();\n const media = useMemo<MarkdownMediaContextValue>(\n () => ({ open: (next) => setOpened({ ...next, ...(documentPath === undefined ? {} : { documentPath }) }) }),\n [documentPath],\n );\n const close = () => setOpened(undefined);\n return (\n <FileLinkContext.Provider value={onFileLink}>\n <ImageContext.Provider value={loadImage}>\n <MarkdownMediaContext.Provider value={media}>\n <div className=\"flex min-w-0 flex-col gap-2\">\n <ReactMarkdown\n remarkPlugins={REMARK_PLUGINS}\n components={COMPONENTS}\n urlTransform={(url, key, node) =>\n key === 'src' && node.tagName === 'img' && /^@?artifact:/u.test(url) ? url : defaultUrlTransform(url)\n }\n >\n {text}\n </ReactMarkdown>\n </div>\n <MediaViewerDialog\n media={opened}\n onClose={close}\n review={opened === undefined ? undefined : renderMediaReview?.(opened, close)}\n />\n </MarkdownMediaContext.Provider>\n </ImageContext.Provider>\n </FileLinkContext.Provider>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../lib/markdownMedia.cjs"),n=require("./CodeBlock.cjs"),r=require("./MediaViewerDialog.cjs");let i=require("react/jsx-runtime"),a=require("react"),o=require("react-markdown");o=e.__toESM(o,1);let s=require("remark-gfm");s=e.__toESM(s,1);const c=[s.default],l=`rounded bg-po-deep px-1 py-px font-mono text-po-green`,u=(0,a.createContext)(void 0),d=(0,a.createContext)(void 0);function f({src:e,alt:n}){let r=(0,a.useContext)(d),o=(0,a.useContext)(t.MarkdownMediaContext),s;if(typeof e==`string`&&e
|
|
2
|
-
`)?t:void 0,s=o===void 0||e!==void 0?void 0:r?.(o);return s!==void 0&&o!==void 0?/* @__PURE__ */ (0,i.jsx)(`button`,{type:`button`,"data-testid":`markdown-file-link`,title:`open ${o}`,onClick:s,className:`${l} cursor-pointer underline decoration-po-green/40 underline-offset-2 hover:text-po-hi hover:decoration-po-hi`,children:o}):/* @__PURE__ */ (0,i.jsx)(`code`,{...n,className:`${e??``} ${l} [pre_&]:bg-transparent [pre_&]:p-0 [pre_&]:text-po-hi`,children:t})}function m({href:e,children:t}){let n=(0,a.useContext)(u),r=e;try{r=e===void 0?void 0:decodeURIComponent(e)}catch{r=void 0}let o=r!==void 0&&r!==``&&!/^(?:[a-z][a-z\d+.-]*:|\/\/|#|\?)/i.test(r)?n?.(r,!0):void 0;return o===void 0?/* @__PURE__ */ (0,i.jsx)(`a`,{href:e,target:`_blank`,rel:`noreferrer`,className:`text-po-blue underline decoration-po-blue/50`,children:t}):/* @__PURE__ */ (0,i.jsx)(`button`,{type:`button`,"data-testid":`markdown-file-link`,title:`open ${r}`,onClick:o,className:`text-po-blue underline decoration-po-blue/50`,children:t})}function h(e){return typeof e==`string`?e:Array.isArray(e)?e.map(e=>h(e)).join(``):``}function g({children:e}){let t=(0,a.isValidElement)(e)?e:void 0;return t===void 0?/* @__PURE__ */ (0,i.jsx)(`pre`,{className:`overflow-x-auto rounded border border-po-border bg-po-deep p-2.5 text-sm leading-relaxed`,children:e}):/* @__PURE__ */ (0,i.jsx)(n.CodeBlock,{text:h(t.props.children).replace(/\n$/,``),className:t.props.className})}const _={p:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`p`,{className:`whitespace-pre-wrap break-words`,children:e}),strong:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`strong`,{className:`font-semibold text-po-hi`,children:e}),em:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`em`,{className:`italic`,children:e}),del:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`del`,{className:`text-po-dim line-through`,children:e}),a:m,code:p,pre:g,ul:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`ul`,{className:`list-disc pl-5`,children:e}),ol:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`ol`,{className:`list-decimal pl-5`,children:e}),li:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`li`,{className:`whitespace-pre-wrap break-words`,children:e}),h1:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h1`,{className:`mt-2 text-2xl font-semibold text-po-hi first:mt-0`,children:e}),h2:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h2`,{className:`mt-2 text-xl font-semibold text-po-hi first:mt-0`,children:e}),h3:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h3`,{className:`mt-1 text-lg font-semibold text-po-hi first:mt-0`,children:e}),h4:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h4`,{className:`font-semibold text-po-hi`,children:e}),h5:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h5`,{className:`font-semibold text-po-text`,children:e}),h6:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h6`,{className:`font-semibold text-po-dim`,children:e}),blockquote:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`blockquote`,{className:`border-l-2 border-po-border pl-3 text-po-dim`,children:e}),hr:()=>/* @__PURE__ */ (0,i.jsx)(`hr`,{className:`border-po-border-soft`}),table:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`div`,{className:`overflow-x-auto`,children:/* @__PURE__ */ (0,i.jsx)(`table`,{className:`border-collapse`,children:e})}),th:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`th`,{className:`border border-po-border bg-po-deep px-2 py-1 text-left font-semibold text-po-hi`,children:e}),td:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`td`,{className:`border border-po-border px-2 py-1 align-top`,children:e}),img:f};function v({text:e,onFileLink:n,loadImage:s,documentPath:l,renderMediaReview:f}){let[p,m]=(0,a.useState)(),h=(0,a.useMemo)(()=>({open:e=>m({...e,...l===void 0?{}:{documentPath:l}})}),[l]),g=()=>m(void 0);return/* @__PURE__ */ (0,i.jsx)(u.Provider,{value:n,children:/* @__PURE__ */ (0,i.jsx)(d.Provider,{value:s,children:/* @__PURE__ */ (0,i.jsxs)(t.MarkdownMediaContext.Provider,{value:h,children:[/* @__PURE__ */ (0,i.jsx)(`div`,{className:`flex min-w-0 flex-col gap-2`,children:/* @__PURE__ */ (0,i.jsx)(o.default,{remarkPlugins:c,components:_,children:e})}),/* @__PURE__ */ (0,i.jsx)(r.MediaViewerDialog,{media:p,onClose:g,review:p===void 0?void 0:f?.(p,g)})]})})})}exports.Markdown=v;
|
|
1
|
+
const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../lib/markdownMedia.cjs"),n=require("./CodeBlock.cjs"),r=require("./MediaViewerDialog.cjs");let i=require("react/jsx-runtime"),a=require("react"),o=require("react-markdown");o=e.__toESM(o,1);let s=require("remark-gfm");s=e.__toESM(s,1);const c=[s.default],l=`rounded bg-po-deep px-1 py-px font-mono text-po-green`,u=(0,a.createContext)(void 0),d=(0,a.createContext)(void 0);function f({src:e,alt:n}){let r=(0,a.useContext)(d),o=(0,a.useContext)(t.MarkdownMediaContext),s=typeof e==`string`&&/^@?artifact:/u.test(e),c;if(typeof e==`string`&&e!==``&&(s||!/^(?:[a-z][a-z\d+.-]*:|\/\/|#|\?)/i.test(e)))try{c=decodeURIComponent((s&&e.startsWith(`@`)?e.slice(1):e).split(/[?#]/,1)[0])}catch{c=``}let[l,u]=(0,a.useState)();(0,a.useEffect)(()=>{if(r===void 0||c===void 0)return;let e=!0,t;return Promise.resolve().then(()=>{if(e&&u(void 0),c===``)throw Error(`Invalid image path.`);return r(c)}).then(n=>{e?(t=n,u({path:c,loader:r,url:n.url,sourcePath:n.path??c})):n.dispose()}).catch(()=>{e&&u({path:c,loader:r,failed:!0})}),()=>{e=!1,t?.dispose()}},[c,r]);let f=l?.path===c&&l?.loader===r?l:void 0,p=f?.failed===!0||s&&r===void 0;if(p||r!==void 0&&c!==void 0&&f?.url===void 0)return/* @__PURE__ */ (0,i.jsxs)(`span`,{role:p?`alert`:`status`,title:c,children:[n||c||`Image`,` (`,p?`unavailable`:`loading...`,`)`]});let m=r!==void 0&&c!==void 0?f?.url:e,h=/* @__PURE__ */ (0,i.jsx)(`img`,{src:m,alt:n??``,onError:r!==void 0&&c!==void 0?()=>u({path:c,loader:r,failed:!0}):void 0,className:`max-h-[480px] max-w-full rounded border border-po-border`});if(o===void 0||typeof m!=`string`||m===``)return h;let g=n||c||`Image`;return/* @__PURE__ */ (0,i.jsx)(`button`,{type:`button`,"data-testid":`markdown-media-open`,"aria-label":`Open ${g} full screen`,onClick:()=>o.open({kind:`image`,title:g,url:m,sourcePath:f?.sourcePath??c}),className:`max-w-full cursor-zoom-in rounded focus-visible:ring-2 focus-visible:ring-po-blue focus-visible:outline-none`,children:h})}function p({className:e,children:t,...n}){let r=(0,a.useContext)(u),o=typeof t==`string`&&!t.includes(`
|
|
2
|
+
`)?t:void 0,s=o===void 0||e!==void 0?void 0:r?.(o);return s!==void 0&&o!==void 0?/* @__PURE__ */ (0,i.jsx)(`button`,{type:`button`,"data-testid":`markdown-file-link`,title:`open ${o}`,onClick:s,className:`${l} cursor-pointer underline decoration-po-green/40 underline-offset-2 hover:text-po-hi hover:decoration-po-hi`,children:o}):/* @__PURE__ */ (0,i.jsx)(`code`,{...n,className:`${e??``} ${l} [pre_&]:bg-transparent [pre_&]:p-0 [pre_&]:text-po-hi`,children:t})}function m({href:e,children:t}){let n=(0,a.useContext)(u),r=e;try{r=e===void 0?void 0:decodeURIComponent(e)}catch{r=void 0}let o=r!==void 0&&r!==``&&!/^(?:[a-z][a-z\d+.-]*:|\/\/|#|\?)/i.test(r)?n?.(r,!0):void 0;return o===void 0?/* @__PURE__ */ (0,i.jsx)(`a`,{href:e,target:`_blank`,rel:`noreferrer`,className:`text-po-blue underline decoration-po-blue/50`,children:t}):/* @__PURE__ */ (0,i.jsx)(`button`,{type:`button`,"data-testid":`markdown-file-link`,title:`open ${r}`,onClick:o,className:`text-po-blue underline decoration-po-blue/50`,children:t})}function h(e){return typeof e==`string`?e:Array.isArray(e)?e.map(e=>h(e)).join(``):``}function g({children:e}){let t=(0,a.isValidElement)(e)?e:void 0;return t===void 0?/* @__PURE__ */ (0,i.jsx)(`pre`,{className:`overflow-x-auto rounded border border-po-border bg-po-deep p-2.5 text-sm leading-relaxed`,children:e}):/* @__PURE__ */ (0,i.jsx)(n.CodeBlock,{text:h(t.props.children).replace(/\n$/,``),className:t.props.className})}const _={p:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`p`,{className:`whitespace-pre-wrap break-words`,children:e}),strong:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`strong`,{className:`font-semibold text-po-hi`,children:e}),em:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`em`,{className:`italic`,children:e}),del:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`del`,{className:`text-po-dim line-through`,children:e}),a:m,code:p,pre:g,ul:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`ul`,{className:`list-disc pl-5`,children:e}),ol:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`ol`,{className:`list-decimal pl-5`,children:e}),li:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`li`,{className:`whitespace-pre-wrap break-words`,children:e}),h1:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h1`,{className:`mt-2 text-2xl font-semibold text-po-hi first:mt-0`,children:e}),h2:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h2`,{className:`mt-2 text-xl font-semibold text-po-hi first:mt-0`,children:e}),h3:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h3`,{className:`mt-1 text-lg font-semibold text-po-hi first:mt-0`,children:e}),h4:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h4`,{className:`font-semibold text-po-hi`,children:e}),h5:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h5`,{className:`font-semibold text-po-text`,children:e}),h6:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`h6`,{className:`font-semibold text-po-dim`,children:e}),blockquote:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`blockquote`,{className:`border-l-2 border-po-border pl-3 text-po-dim`,children:e}),hr:()=>/* @__PURE__ */ (0,i.jsx)(`hr`,{className:`border-po-border-soft`}),table:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`div`,{className:`overflow-x-auto`,children:/* @__PURE__ */ (0,i.jsx)(`table`,{className:`border-collapse`,children:e})}),th:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`th`,{className:`border border-po-border bg-po-deep px-2 py-1 text-left font-semibold text-po-hi`,children:e}),td:({children:e})=>/* @__PURE__ */ (0,i.jsx)(`td`,{className:`border border-po-border px-2 py-1 align-top`,children:e}),img:f};function v({text:e,onFileLink:n,loadImage:s,documentPath:l,renderMediaReview:f}){let[p,m]=(0,a.useState)(),h=(0,a.useMemo)(()=>({open:e=>m({...e,...l===void 0?{}:{documentPath:l}})}),[l]),g=()=>m(void 0);return/* @__PURE__ */ (0,i.jsx)(u.Provider,{value:n,children:/* @__PURE__ */ (0,i.jsx)(d.Provider,{value:s,children:/* @__PURE__ */ (0,i.jsxs)(t.MarkdownMediaContext.Provider,{value:h,children:[/* @__PURE__ */ (0,i.jsx)(`div`,{className:`flex min-w-0 flex-col gap-2`,children:/* @__PURE__ */ (0,i.jsx)(o.default,{remarkPlugins:c,components:_,urlTransform:(e,t,n)=>t===`src`&&n.tagName===`img`&&/^@?artifact:/u.test(e)?e:(0,o.defaultUrlTransform)(e),children:e})}),/* @__PURE__ */ (0,i.jsx)(r.MediaViewerDialog,{media:p,onClose:g,review:p===void 0?void 0:f?.(p,g)})]})})})}exports.Markdown=v;
|
|
3
3
|
//# sourceMappingURL=Markdown.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Markdown.cjs","names":["remarkGfm","createContext","useContext","MarkdownMediaContext","useState","isValidElement","CodeBlock","useMemo","ReactMarkdown","MediaViewerDialog","require_runtime","require_markdownMedia","require_CodeBlock","require_MediaViewerDialog","react_jsx_runtime","react","react_markdown","remark_gfm","REMARK_PLUGINS","CODE_CLASS","FileLinkContext","ImageContext","Image","loader","media","path","src","loaded","setLoaded","active","asset","result","current","alt","url","image","title","Code","rest","onFileLink","label","children","open","className","Link","href","textOf","child","Pre","code","COMPONENTS","Markdown","opened","setOpened","next","documentPath","close","loadImage","text","renderMediaReview"],"sources":["../../../src/components/Markdown.tsx"],"sourcesContent":["import {\n createContext,\n type ComponentProps,\n isValidElement,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nimport {\n type MarkdownMedia,\n MarkdownMediaContext,\n type MarkdownMediaContextValue,\n type MarkdownMediaReview,\n} from '../lib/markdownMedia';\nimport { CodeBlock } from './CodeBlock';\nimport { MediaViewerDialog } from './MediaViewerDialog';\n\nconst REMARK_PLUGINS = [remarkGfm];\n\n// No size: inline code follows the prose it sits in, 15px in the conversation\n// and 13px in a compact transcript, so a path never reads smaller than its sentence.\nconst CODE_CLASS = 'rounded bg-po-deep px-1 py-px font-mono text-po-green';\n\n/**\n * What a piece of inline code opens, when the host knows.\n *\n * Returning undefined leaves the span as plain code, which is the answer for\n * everything a message quotes that is not a file: a class name, a flag, a\n * command. The caller decides what counts, because only it knows which files\n * the session has.\n */\nexport type FileLinkHandler = (text: string, explicit?: boolean) => (() => void) | undefined;\n\n/**\n * Passed by context rather than as a component prop so the component map stays\n * a module constant. Rebuilding that map per render gives react-markdown new\n * component identities, which remounts the whole rendered tree on every frame\n * of a streaming reply.\n */\nconst FileLinkContext = createContext<FileLinkHandler | undefined>(undefined);\n\n/** `path` is the file the host resolved the image to, kept as review provenance. */\ntype ImageLoader = (path: string) => Promise<{ url: string; dispose(): void; path?: string }>;\nconst ImageContext = createContext<ImageLoader | undefined>(undefined);\n\nfunction Image({ src, alt }: ComponentProps<'img'>) {\n const loader = useContext(ImageContext);\n const media = useContext(MarkdownMediaContext);\n let path: string | undefined;\n if (typeof src === 'string' && src !== '' && !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|#|\\?)/i.test(src)) {\n try {\n path = decodeURIComponent(src.split(/[?#]/, 1)[0]!);\n } catch {\n // An invalid encoded filename is shown as unavailable, never fetched.\n path = '';\n }\n }\n const [loaded, setLoaded] = useState<{\n path: string;\n loader: ImageLoader;\n url?: string;\n sourcePath?: string;\n failed?: boolean;\n }>();\n useEffect(() => {\n if (loader === undefined || path === undefined) return;\n let active = true;\n let asset: Awaited<ReturnType<ImageLoader>> | undefined;\n void Promise.resolve()\n .then(() => {\n if (active) setLoaded(undefined);\n if (path === '') throw new Error('Invalid image path.');\n return loader(path);\n })\n .then((result) => {\n if (!active) {\n result.dispose();\n return;\n }\n asset = result;\n setLoaded({ path, loader, url: result.url, sourcePath: result.path ?? path });\n })\n .catch(() => {\n if (active) setLoaded({ path, loader, failed: true });\n });\n return () => {\n active = false;\n asset?.dispose();\n };\n }, [path, loader]);\n const current = loaded?.path === path && loaded?.loader === loader ? loaded : undefined;\n if (loader !== undefined && path !== undefined && (current?.url === undefined || current.failed))\n return (\n <span role={current?.failed ? 'alert' : 'status'} title={path}>\n {alt || path || 'Image'} ({current?.failed ? 'unavailable' : 'loading...'})\n </span>\n );\n const url = loader !== undefined && path !== undefined ? current?.url : src;\n const image = (\n <img\n src={url}\n alt={alt ?? ''}\n onError={loader !== undefined && path !== undefined ? () => setLoaded({ path, loader, failed: true }) : undefined}\n className=\"max-h-[480px] max-w-full rounded border border-po-border\"\n />\n );\n if (media === undefined || typeof url !== 'string' || url === '') return image;\n const title = alt || path || 'Image';\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-media-open\"\n aria-label={`Open ${title} full screen`}\n onClick={() => media.open({ kind: 'image', title, url, sourcePath: current?.sourcePath ?? path })}\n className=\"max-w-full cursor-zoom-in rounded focus-visible:ring-2 focus-visible:ring-po-blue focus-visible:outline-none\"\n >\n {image}\n </button>\n );\n}\n\nfunction Code({ className, children, ...rest }: ComponentProps<'code'>) {\n const onFileLink = useContext(FileLinkContext);\n // Only a single-line span with no language class is a candidate: a fenced\n // block is content, not a reference, and its own renderer owns it.\n const label = typeof children === 'string' && !children.includes('\\n') ? children : undefined;\n const open = label === undefined || className !== undefined ? undefined : onFileLink?.(label);\n if (open !== undefined && label !== undefined) {\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-file-link\"\n title={`open ${label}`}\n onClick={open}\n className={`${CODE_CLASS} cursor-pointer underline decoration-po-green/40 underline-offset-2 hover:text-po-hi hover:decoration-po-hi`}\n >\n {label}\n </button>\n );\n }\n return (\n <code\n {...rest}\n className={`${className ?? ''} ${CODE_CLASS} [pre_&]:bg-transparent [pre_&]:p-0 [pre_&]:text-po-hi`}\n >\n {children}\n </code>\n );\n}\n\nfunction Link({ href, children }: ComponentProps<'a'>) {\n const onFileLink = useContext(FileLinkContext);\n let path = href;\n try {\n path = href === undefined ? undefined : decodeURIComponent(href);\n } catch {\n path = undefined;\n }\n const isFile = path !== undefined && path !== '' && !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|#|\\?)/i.test(path);\n const open = isFile ? onFileLink?.(path!, true) : undefined;\n if (open !== undefined)\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-file-link\"\n title={`open ${path}`}\n onClick={open}\n className=\"text-po-blue underline decoration-po-blue/50\"\n >\n {children}\n </button>\n );\n return (\n <a href={href} target=\"_blank\" rel=\"noreferrer\" className=\"text-po-blue underline decoration-po-blue/50\">\n {children}\n </a>\n );\n}\n\n/** The text inside a fence, which react-markdown hands over as nested strings. */\nfunction textOf(children: ReactNode): string {\n if (typeof children === 'string') return children;\n if (Array.isArray(children)) return children.map((child) => textOf(child as ReactNode)).join('');\n return '';\n}\n\n/**\n * A fenced block, read off the <code> child that carries its language.\n *\n * The block is handed to `CodeBlock` whole rather than rendered as a styled\n * <pre> around inline code, because a fence is content with its own\n * presentation: it is coloured, it can be copied, and a mermaid fence is a\n * picture. A <pre> that came from raw HTML has no such child and keeps the\n * plain box.\n */\nfunction Pre({ children }: ComponentProps<'pre'>) {\n const code = isValidElement<{ className?: string; children?: ReactNode }>(children) ? children : undefined;\n if (code === undefined)\n return (\n <pre className=\"overflow-x-auto rounded border border-po-border bg-po-deep p-2.5 text-sm leading-relaxed\">\n {children}\n </pre>\n );\n // Markdown ends every fence with a newline the author did not type.\n return <CodeBlock text={textOf(code.props.children).replace(/\\n$/, '')} className={code.props.className} />;\n}\nconst COMPONENTS: Components = {\n p: ({ children }) => <p className=\"whitespace-pre-wrap break-words\">{children}</p>,\n strong: ({ children }) => <strong className=\"font-semibold text-po-hi\">{children}</strong>,\n em: ({ children }) => <em className=\"italic\">{children}</em>,\n del: ({ children }) => <del className=\"text-po-dim line-through\">{children}</del>,\n a: Link,\n code: Code,\n pre: Pre,\n ul: ({ children }) => <ul className=\"list-disc pl-5\">{children}</ul>,\n ol: ({ children }) => <ol className=\"list-decimal pl-5\">{children}</ol>,\n li: ({ children }) => <li className=\"whitespace-pre-wrap break-words\">{children}</li>,\n // Headings step up from the prose they sit in and never shrink below it, so a\n // reply's `##` reads as a heading in both the 15px conversation and a 13px\n // compact transcript. h4 to h6 keep the prose size and lean on weight alone.\n h1: ({ children }) => <h1 className=\"mt-2 text-2xl font-semibold text-po-hi first:mt-0\">{children}</h1>,\n h2: ({ children }) => <h2 className=\"mt-2 text-xl font-semibold text-po-hi first:mt-0\">{children}</h2>,\n h3: ({ children }) => <h3 className=\"mt-1 text-lg font-semibold text-po-hi first:mt-0\">{children}</h3>,\n h4: ({ children }) => <h4 className=\"font-semibold text-po-hi\">{children}</h4>,\n h5: ({ children }) => <h5 className=\"font-semibold text-po-text\">{children}</h5>,\n h6: ({ children }) => <h6 className=\"font-semibold text-po-dim\">{children}</h6>,\n blockquote: ({ children }) => (\n <blockquote className=\"border-l-2 border-po-border pl-3 text-po-dim\">{children}</blockquote>\n ),\n hr: () => <hr className=\"border-po-border-soft\" />,\n table: ({ children }) => (\n <div className=\"overflow-x-auto\">\n <table className=\"border-collapse\">{children}</table>\n </div>\n ),\n th: ({ children }) => (\n <th className=\"border border-po-border bg-po-deep px-2 py-1 text-left font-semibold text-po-hi\">{children}</th>\n ),\n td: ({ children }) => <td className=\"border border-po-border px-2 py-1 align-top\">{children}</td>,\n img: Image,\n};\n\n/** GitHub-flavored Markdown using the cockpit's safe, shared presentation. */\nexport function Markdown({\n text,\n onFileLink,\n loadImage,\n documentPath,\n renderMediaReview,\n}: {\n text: string;\n onFileLink?: FileLinkHandler;\n loadImage?: ImageLoader;\n /** The file this Markdown came from, passed to a reviewer of its pictures. */\n documentPath?: string;\n /** Annotate and review surface for an opened picture; without it the viewer only pans and zooms. */\n renderMediaReview?: MarkdownMediaReview;\n}) {\n const [opened, setOpened] = useState<MarkdownMedia>();\n const media = useMemo<MarkdownMediaContextValue>(\n () => ({ open: (next) => setOpened({ ...next, ...(documentPath === undefined ? {} : { documentPath }) }) }),\n [documentPath],\n );\n const close = () => setOpened(undefined);\n return (\n <FileLinkContext.Provider value={onFileLink}>\n <ImageContext.Provider value={loadImage}>\n <MarkdownMediaContext.Provider value={media}>\n <div className=\"flex min-w-0 flex-col gap-2\">\n <ReactMarkdown remarkPlugins={REMARK_PLUGINS} components={COMPONENTS}>\n {text}\n </ReactMarkdown>\n </div>\n <MediaViewerDialog\n media={opened}\n onClose={close}\n review={opened === undefined ? undefined : renderMediaReview?.(opened, close)}\n />\n </MarkdownMediaContext.Provider>\n </ImageContext.Provider>\n </FileLinkContext.Provider>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Markdown.cjs","names":["remarkGfm","createContext","useContext","MarkdownMediaContext","useState","isValidElement","CodeBlock","useMemo","ReactMarkdown","defaultUrlTransform","MediaViewerDialog","require_runtime","require_markdownMedia","require_CodeBlock","require_MediaViewerDialog","react_jsx_runtime","react","react_markdown","remark_gfm","REMARK_PLUGINS","CODE_CLASS","FileLinkContext","ImageContext","Image","loader","media","artifact","src","path","loaded","setLoaded","active","asset","result","current","unavailable","alt","url","image","title","Code","rest","onFileLink","label","children","open","className","Link","href","textOf","child","Pre","code","COMPONENTS","Markdown","opened","setOpened","next","documentPath","close","loadImage","key","node","text","renderMediaReview"],"sources":["../../../src/components/Markdown.tsx"],"sourcesContent":["import {\n createContext,\n type ComponentProps,\n isValidElement,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport ReactMarkdown, { defaultUrlTransform, type Components } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nimport {\n type MarkdownMedia,\n MarkdownMediaContext,\n type MarkdownMediaContextValue,\n type MarkdownMediaReview,\n} from '../lib/markdownMedia';\nimport { CodeBlock } from './CodeBlock';\nimport { MediaViewerDialog } from './MediaViewerDialog';\n\nconst REMARK_PLUGINS = [remarkGfm];\n\n// No size: inline code follows the prose it sits in, 15px in the conversation\n// and 13px in a compact transcript, so a path never reads smaller than its sentence.\nconst CODE_CLASS = 'rounded bg-po-deep px-1 py-px font-mono text-po-green';\n\n/**\n * What a piece of inline code opens, when the host knows.\n *\n * Returning undefined leaves the span as plain code, which is the answer for\n * everything a message quotes that is not a file: a class name, a flag, a\n * command. The caller decides what counts, because only it knows which files\n * the session has.\n */\nexport type FileLinkHandler = (text: string, explicit?: boolean) => (() => void) | undefined;\n\n/**\n * Passed by context rather than as a component prop so the component map stays\n * a module constant. Rebuilding that map per render gives react-markdown new\n * component identities, which remounts the whole rendered tree on every frame\n * of a streaming reply.\n */\nconst FileLinkContext = createContext<FileLinkHandler | undefined>(undefined);\n\n/** `path` is the file the host resolved the image to, kept as review provenance. */\ntype ImageLoader = (path: string) => Promise<{ url: string; dispose(): void; path?: string }>;\nconst ImageContext = createContext<ImageLoader | undefined>(undefined);\n\nfunction Image({ src, alt }: ComponentProps<'img'>) {\n const loader = useContext(ImageContext);\n const media = useContext(MarkdownMediaContext);\n const artifact = typeof src === 'string' && /^@?artifact:/u.test(src);\n let path: string | undefined;\n if (typeof src === 'string' && src !== '' && (artifact || !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|#|\\?)/i.test(src))) {\n try {\n path = decodeURIComponent((artifact && src.startsWith('@') ? src.slice(1) : src).split(/[?#]/, 1)[0]!);\n } catch {\n // An invalid encoded filename is shown as unavailable, never fetched.\n path = '';\n }\n }\n const [loaded, setLoaded] = useState<{\n path: string;\n loader: ImageLoader;\n url?: string;\n sourcePath?: string;\n failed?: boolean;\n }>();\n useEffect(() => {\n if (loader === undefined || path === undefined) return;\n let active = true;\n let asset: Awaited<ReturnType<ImageLoader>> | undefined;\n void Promise.resolve()\n .then(() => {\n if (active) setLoaded(undefined);\n if (path === '') throw new Error('Invalid image path.');\n return loader(path);\n })\n .then((result) => {\n if (!active) {\n result.dispose();\n return;\n }\n asset = result;\n setLoaded({ path, loader, url: result.url, sourcePath: result.path ?? path });\n })\n .catch(() => {\n if (active) setLoaded({ path, loader, failed: true });\n });\n return () => {\n active = false;\n asset?.dispose();\n };\n }, [path, loader]);\n const current = loaded?.path === path && loaded?.loader === loader ? loaded : undefined;\n const unavailable = current?.failed === true || (artifact && loader === undefined);\n if (unavailable || (loader !== undefined && path !== undefined && current?.url === undefined))\n return (\n <span role={unavailable ? 'alert' : 'status'} title={path}>\n {alt || path || 'Image'} ({unavailable ? 'unavailable' : 'loading...'})\n </span>\n );\n const url = loader !== undefined && path !== undefined ? current?.url : src;\n const image = (\n <img\n src={url}\n alt={alt ?? ''}\n onError={loader !== undefined && path !== undefined ? () => setLoaded({ path, loader, failed: true }) : undefined}\n className=\"max-h-[480px] max-w-full rounded border border-po-border\"\n />\n );\n if (media === undefined || typeof url !== 'string' || url === '') return image;\n const title = alt || path || 'Image';\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-media-open\"\n aria-label={`Open ${title} full screen`}\n onClick={() => media.open({ kind: 'image', title, url, sourcePath: current?.sourcePath ?? path })}\n className=\"max-w-full cursor-zoom-in rounded focus-visible:ring-2 focus-visible:ring-po-blue focus-visible:outline-none\"\n >\n {image}\n </button>\n );\n}\n\nfunction Code({ className, children, ...rest }: ComponentProps<'code'>) {\n const onFileLink = useContext(FileLinkContext);\n // Only a single-line span with no language class is a candidate: a fenced\n // block is content, not a reference, and its own renderer owns it.\n const label = typeof children === 'string' && !children.includes('\\n') ? children : undefined;\n const open = label === undefined || className !== undefined ? undefined : onFileLink?.(label);\n if (open !== undefined && label !== undefined) {\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-file-link\"\n title={`open ${label}`}\n onClick={open}\n className={`${CODE_CLASS} cursor-pointer underline decoration-po-green/40 underline-offset-2 hover:text-po-hi hover:decoration-po-hi`}\n >\n {label}\n </button>\n );\n }\n return (\n <code\n {...rest}\n className={`${className ?? ''} ${CODE_CLASS} [pre_&]:bg-transparent [pre_&]:p-0 [pre_&]:text-po-hi`}\n >\n {children}\n </code>\n );\n}\n\nfunction Link({ href, children }: ComponentProps<'a'>) {\n const onFileLink = useContext(FileLinkContext);\n let path = href;\n try {\n path = href === undefined ? undefined : decodeURIComponent(href);\n } catch {\n path = undefined;\n }\n const isFile = path !== undefined && path !== '' && !/^(?:[a-z][a-z\\d+.-]*:|\\/\\/|#|\\?)/i.test(path);\n const open = isFile ? onFileLink?.(path!, true) : undefined;\n if (open !== undefined)\n return (\n <button\n type=\"button\"\n data-testid=\"markdown-file-link\"\n title={`open ${path}`}\n onClick={open}\n className=\"text-po-blue underline decoration-po-blue/50\"\n >\n {children}\n </button>\n );\n return (\n <a href={href} target=\"_blank\" rel=\"noreferrer\" className=\"text-po-blue underline decoration-po-blue/50\">\n {children}\n </a>\n );\n}\n\n/** The text inside a fence, which react-markdown hands over as nested strings. */\nfunction textOf(children: ReactNode): string {\n if (typeof children === 'string') return children;\n if (Array.isArray(children)) return children.map((child) => textOf(child as ReactNode)).join('');\n return '';\n}\n\n/**\n * A fenced block, read off the <code> child that carries its language.\n *\n * The block is handed to `CodeBlock` whole rather than rendered as a styled\n * <pre> around inline code, because a fence is content with its own\n * presentation: it is coloured, it can be copied, and a mermaid fence is a\n * picture. A <pre> that came from raw HTML has no such child and keeps the\n * plain box.\n */\nfunction Pre({ children }: ComponentProps<'pre'>) {\n const code = isValidElement<{ className?: string; children?: ReactNode }>(children) ? children : undefined;\n if (code === undefined)\n return (\n <pre className=\"overflow-x-auto rounded border border-po-border bg-po-deep p-2.5 text-sm leading-relaxed\">\n {children}\n </pre>\n );\n // Markdown ends every fence with a newline the author did not type.\n return <CodeBlock text={textOf(code.props.children).replace(/\\n$/, '')} className={code.props.className} />;\n}\nconst COMPONENTS: Components = {\n p: ({ children }) => <p className=\"whitespace-pre-wrap break-words\">{children}</p>,\n strong: ({ children }) => <strong className=\"font-semibold text-po-hi\">{children}</strong>,\n em: ({ children }) => <em className=\"italic\">{children}</em>,\n del: ({ children }) => <del className=\"text-po-dim line-through\">{children}</del>,\n a: Link,\n code: Code,\n pre: Pre,\n ul: ({ children }) => <ul className=\"list-disc pl-5\">{children}</ul>,\n ol: ({ children }) => <ol className=\"list-decimal pl-5\">{children}</ol>,\n li: ({ children }) => <li className=\"whitespace-pre-wrap break-words\">{children}</li>,\n // Headings step up from the prose they sit in and never shrink below it, so a\n // reply's `##` reads as a heading in both the 15px conversation and a 13px\n // compact transcript. h4 to h6 keep the prose size and lean on weight alone.\n h1: ({ children }) => <h1 className=\"mt-2 text-2xl font-semibold text-po-hi first:mt-0\">{children}</h1>,\n h2: ({ children }) => <h2 className=\"mt-2 text-xl font-semibold text-po-hi first:mt-0\">{children}</h2>,\n h3: ({ children }) => <h3 className=\"mt-1 text-lg font-semibold text-po-hi first:mt-0\">{children}</h3>,\n h4: ({ children }) => <h4 className=\"font-semibold text-po-hi\">{children}</h4>,\n h5: ({ children }) => <h5 className=\"font-semibold text-po-text\">{children}</h5>,\n h6: ({ children }) => <h6 className=\"font-semibold text-po-dim\">{children}</h6>,\n blockquote: ({ children }) => (\n <blockquote className=\"border-l-2 border-po-border pl-3 text-po-dim\">{children}</blockquote>\n ),\n hr: () => <hr className=\"border-po-border-soft\" />,\n table: ({ children }) => (\n <div className=\"overflow-x-auto\">\n <table className=\"border-collapse\">{children}</table>\n </div>\n ),\n th: ({ children }) => (\n <th className=\"border border-po-border bg-po-deep px-2 py-1 text-left font-semibold text-po-hi\">{children}</th>\n ),\n td: ({ children }) => <td className=\"border border-po-border px-2 py-1 align-top\">{children}</td>,\n img: Image,\n};\n\n/** GitHub-flavored Markdown using the cockpit's safe, shared presentation. */\nexport function Markdown({\n text,\n onFileLink,\n loadImage,\n documentPath,\n renderMediaReview,\n}: {\n text: string;\n onFileLink?: FileLinkHandler;\n loadImage?: ImageLoader;\n /** The file this Markdown came from, passed to a reviewer of its pictures. */\n documentPath?: string;\n /** Annotate and review surface for an opened picture; without it the viewer only pans and zooms. */\n renderMediaReview?: MarkdownMediaReview;\n}) {\n const [opened, setOpened] = useState<MarkdownMedia>();\n const media = useMemo<MarkdownMediaContextValue>(\n () => ({ open: (next) => setOpened({ ...next, ...(documentPath === undefined ? {} : { documentPath }) }) }),\n [documentPath],\n );\n const close = () => setOpened(undefined);\n return (\n <FileLinkContext.Provider value={onFileLink}>\n <ImageContext.Provider value={loadImage}>\n <MarkdownMediaContext.Provider value={media}>\n <div className=\"flex min-w-0 flex-col gap-2\">\n <ReactMarkdown\n remarkPlugins={REMARK_PLUGINS}\n components={COMPONENTS}\n urlTransform={(url, key, node) =>\n key === 'src' && node.tagName === 'img' && /^@?artifact:/u.test(url) ? url : defaultUrlTransform(url)\n }\n >\n {text}\n </ReactMarkdown>\n </div>\n <MediaViewerDialog\n media={opened}\n onClose={close}\n review={opened === undefined ? undefined : renderMediaReview?.(opened, close)}\n />\n </MarkdownMediaContext.Provider>\n </ImageContext.Provider>\n </FileLinkContext.Provider>\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/po-web-components",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.80",
|
|
4
4
|
"description": "Shared web components and theme tokens for the Po cockpit and its web plugins: shadcn-style primitives on Radix, tuned to the Po palette, with runtime theme configs.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"tailwind-merge": "3.7.0"
|
|
108
108
|
},
|
|
109
109
|
"devDependencies": {
|
|
110
|
-
"@agimon-ai/po-core": "0.0.0-alpha.
|
|
111
|
-
"@agimon-ai/vibe-lint-plugin-po-web": "0.0.0-alpha.
|
|
110
|
+
"@agimon-ai/po-core": "0.0.0-alpha.80",
|
|
111
|
+
"@agimon-ai/vibe-lint-plugin-po-web": "0.0.0-alpha.80",
|
|
112
112
|
"@types/node": "26.6.5",
|
|
113
113
|
"@types/react": "19.3.0",
|
|
114
114
|
"@types/react-dom": "19.3.0",
|