diff --git a/.github/workflows/lit_samples_build.yml b/.github/workflows/lit_samples_build.yml index e3679e82d..4dc55bd23 100644 --- a/.github/workflows/lit_samples_build.yml +++ b/.github/workflows/lit_samples_build.yml @@ -35,21 +35,9 @@ jobs: with: node-version: '20' - - name: Install web_core deps - working-directory: ./renderers/web_core - run: npm ci - - - name: Build web_core - working-directory: ./renderers/web_core - run: npm run build - - - name: Install lib's deps - working-directory: ./renderers/lit - run: npm i - - - name: Build lib - working-directory: ./renderers/lit - run: npm run build + - name: Build lit renderer and its dependencies + working-directory: ./samples/client/lit + run: npm run build:renderer - name: Install all lit samples workspaces' dependencies working-directory: ./samples/client/lit diff --git a/renderers/lit/package-lock.json b/renderers/lit/package-lock.json index ced356e5f..437310760 100644 --- a/renderers/lit/package-lock.json +++ b/renderers/lit/package-lock.json @@ -1007,8 +1007,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/signal-polyfill/-/signal-polyfill-0.2.2.tgz", "integrity": "sha512-p63Y4Er5/eMQ9RHg0M0Y64NlsQKpiu6MDdhBXpyywRuWiPywhJTpKJ1iB5K2hJEbFZ0BnDS7ZkJ+0AfTuL37Rg==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/signal-utils": { "version": "0.21.1", diff --git a/renderers/lit/src/0.8/ui/context/context.ts b/renderers/lit/src/0.8/ui/context/context.ts new file mode 100644 index 000000000..0e5b7acf4 --- /dev/null +++ b/renderers/lit/src/0.8/ui/context/context.ts @@ -0,0 +1,24 @@ +/* + Copyright 2025 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import {markdownContext} from "./markdown.js"; +import {themeContext} from "./theme.js"; + +export { + markdownContext as markdown, + themeContext as theme, + themeContext, // Preserved for backwards compatibility. Prefer using `theme`. +}; diff --git a/renderers/lit/src/0.8/ui/context/markdown.ts b/renderers/lit/src/0.8/ui/context/markdown.ts new file mode 100644 index 000000000..0ad79d447 --- /dev/null +++ b/renderers/lit/src/0.8/ui/context/markdown.ts @@ -0,0 +1,26 @@ +/* + Copyright 2025 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +import { + DirectiveResult, +} from "lit/directive.js"; +import { createContext } from "@lit/context"; + +/** + * A Lit Context to override the default (noop) markdown renderer. + */ +export const markdownContext = createContext( + Symbol("a2ui-lit-markdown-renderer") +); diff --git a/renderers/lit/src/0.8/ui/directives/directives.ts b/renderers/lit/src/0.8/ui/directives/directives.ts index 3c838da9e..e81f614d6 100644 --- a/renderers/lit/src/0.8/ui/directives/directives.ts +++ b/renderers/lit/src/0.8/ui/directives/directives.ts @@ -14,4 +14,4 @@ limitations under the License. */ -export { markdown } from "./markdown.js"; +export { noopMarkdown } from "./noop_markdown.js"; diff --git a/renderers/lit/src/0.8/ui/directives/noop_markdown.ts b/renderers/lit/src/0.8/ui/directives/noop_markdown.ts new file mode 100644 index 000000000..4b343db4f --- /dev/null +++ b/renderers/lit/src/0.8/ui/directives/noop_markdown.ts @@ -0,0 +1,35 @@ +/* + Copyright 2025 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import { html, TemplateResult } from "lit"; +import { + directive, + Directive, +} from "lit/directive.js"; + +/** + * "Handles" Markdown rendering by doing nothing. + * + * Configure @a2ui/lit-markdown, or your custom Markdown renderer + * to actually parse and render Markdown in your app. + */ +class NoopMarkdownRendererDirective extends Directive { + render(markdown: string, _tagClassMap?: Record) : TemplateResult { + return html`
${markdown}
`; + } +} + +export const noopMarkdown = directive(NoopMarkdownRendererDirective); diff --git a/renderers/lit/src/0.8/ui/text.ts b/renderers/lit/src/0.8/ui/text.ts index 82ef4aea0..85e1aebcb 100644 --- a/renderers/lit/src/0.8/ui/text.ts +++ b/renderers/lit/src/0.8/ui/text.ts @@ -16,7 +16,9 @@ import { html, css, nothing } from "lit"; import { customElement, property } from "lit/decorators.js"; -import { markdown } from "./directives/directives.js"; +import { consume } from '@lit/context'; +import { noopMarkdown } from "./directives/noop_markdown.js"; +import * as Context from "./context/context.js"; import { Root } from "./root.js"; import { A2uiMessageProcessor } from "@a2ui/web_core/data/model-processor"; import * as Primitives from "@a2ui/web_core/types/primitives"; @@ -44,6 +46,9 @@ export class Text extends Root { @property({ reflect: true, attribute: "usage-hint" }) accessor usageHint: Types.ResolvedText["usageHint"] | null = null; + @consume({context: Context.markdown}) + accessor markdownRenderer = noopMarkdown; + static styles = [ structuralStyles, css` @@ -116,8 +121,8 @@ export class Text extends Root { break; // Body. } - return html`${markdown( - markdownText, + return html`${this.markdownRenderer( + markdownText, Styles.appendToAll(this.theme.markdown, ["ol", "ul", "li"], {}) )}`; } diff --git a/renderers/lit/src/0.8/ui/ui.ts b/renderers/lit/src/0.8/ui/ui.ts index 476d4d567..7038d90a5 100644 --- a/renderers/lit/src/0.8/ui/ui.ts +++ b/renderers/lit/src/0.8/ui/ui.ts @@ -43,7 +43,7 @@ import { TextField } from "./text-field.js"; import { Text } from "./text.js"; import { Video } from "./video.js"; -export * as Context from "./context/theme.js"; +export * as Context from "./context/context.js"; export * as Utils from "./utils/utils.js"; export { ComponentRegistry, componentRegistry } from "./component-registry.js"; export { registerCustomComponents } from "./custom-components/index.js"; diff --git a/renderers/markdown/README.md b/renderers/markdown/README.md new file mode 100644 index 000000000..5e26efd3d --- /dev/null +++ b/renderers/markdown/README.md @@ -0,0 +1,10 @@ +This directory contains the default markdown implementations for A2UI. + +* `markdown-it-shared` is a shared markdown renderer that uses markdown-it and + DOMPurify to render markdown content in general. +* `markdown-it-lit` is the Lit facade of the markdown renderer for Lit. +* `markdown-it-angular` is the Angular facade of the markdown renderer + for Angular. + +Users should use the facade packages in their apps. There's nothing of interest +in the shared renderer package. diff --git a/renderers/markdown/markdown-it-lit/.npmrc b/renderers/markdown/markdown-it-lit/.npmrc new file mode 100644 index 000000000..06b0eef7e --- /dev/null +++ b/renderers/markdown/markdown-it-lit/.npmrc @@ -0,0 +1,2 @@ +@a2ui:registry=https://us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/ +//us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/:always-auth=true diff --git a/renderers/markdown/markdown-it-lit/README.md b/renderers/markdown/markdown-it-lit/README.md new file mode 100644 index 000000000..53e88e951 --- /dev/null +++ b/renderers/markdown/markdown-it-lit/README.md @@ -0,0 +1 @@ +A2UI markdown renderer for Lit. diff --git a/renderers/markdown/markdown-it-lit/package-lock.json b/renderers/markdown/markdown-it-lit/package-lock.json new file mode 100644 index 000000000..2d1a22bb0 --- /dev/null +++ b/renderers/markdown/markdown-it-lit/package-lock.json @@ -0,0 +1,618 @@ +{ + "name": "@a2ui/markdown-it-lit", + "version": "0.8.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@a2ui/markdown-it-lit", + "version": "0.8.1", + "license": "Apache-2.0", + "dependencies": { + "@a2ui/lit": "file:../../lit", + "@a2ui/markdown-it-shared": "file:../markdown-it-shared", + "@a2ui/web_core": "file:../../web_core", + "@lit/context": "^1.1.4", + "lit": "^3.3.1" + }, + "devDependencies": { + "@types/node": "^24.10.1", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + } + }, + "../../lit": { + "name": "@a2ui/lit", + "version": "0.8.1", + "license": "Apache-2.0", + "dependencies": { + "@a2ui/web_core": "file:../web_core", + "@lit-labs/signals": "^0.1.3", + "@lit/context": "^1.1.4", + "lit": "^3.3.1", + "markdown-it": "^14.1.0", + "signal-utils": "^0.21.1" + }, + "devDependencies": { + "@types/markdown-it": "^14.1.2", + "@types/node": "^24.10.1", + "google-artifactregistry-auth": "^3.5.0", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + } + }, + "../../web_core": { + "name": "@a2ui/web_core", + "version": "0.8.0", + "license": "Apache-2.0", + "devDependencies": { + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + } + }, + "../markdown-it-shared": { + "name": "@a2ui/markdown-it-shared", + "version": "0.0.1", + "license": "Apache-2.0", + "dependencies": { + "markdown-it": "^14.1.0" + }, + "devDependencies": { + "@types/markdown-it": "^14.1.2", + "@types/node": "^24.10.1", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + } + }, + "../web_core": { + "name": "@a2ui/web_core", + "version": "0.8.0", + "extraneous": true, + "license": "Apache-2.0", + "devDependencies": { + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + } + }, + "node_modules/@a2ui/lit": { + "resolved": "../../lit", + "link": true + }, + "node_modules/@a2ui/markdown-it-shared": { + "resolved": "../markdown-it-shared", + "link": true + }, + "node_modules/@a2ui/web_core": { + "resolved": "../../web_core", + "link": true + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.5.1.tgz", + "integrity": "sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/context": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.6.tgz", + "integrity": "sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^1.6.2 || ^2.1.0" + } + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", + "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/node": { + "version": "24.10.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", + "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/balanced-match": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-3.0.1.tgz", + "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-4.0.1.tgz", + "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^3.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lit": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.2.tgz", + "integrity": "sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-element": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", + "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.2.tgz", + "integrity": "sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/wireit": { + "version": "0.15.0-pre.2", + "resolved": "https://registry.npmjs.org/wireit/-/wireit-0.15.0-pre.2.tgz", + "integrity": "sha512-pXOTR56btrL7STFOPQgtq8MjAFWagSqs188E2FflCgcxk5uc0Xbn8CuLIR9FbqK97U3Jw6AK8zDEu/M/9ENqgA==", + "dev": true, + "license": "Apache-2.0", + "workspaces": [ + "vscode-extension", + "website" + ], + "dependencies": { + "brace-expansion": "^4.0.0", + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "jsonc-parser": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "bin": { + "wireit": "bin/wireit.js" + }, + "engines": { + "node": ">=18.0.0" + } + } + } +} diff --git a/renderers/markdown/markdown-it-lit/package.json b/renderers/markdown/markdown-it-lit/package.json new file mode 100644 index 000000000..59cf91d54 --- /dev/null +++ b/renderers/markdown/markdown-it-lit/package.json @@ -0,0 +1,66 @@ +{ + "name": "@a2ui/markdown-it-lit", + "version": "0.8.1", + "description": "A2UI Lit markdown renderer.", + "main": "./dist/src/markdown.js", + "types": "./dist/src/markdown.d.ts", + "exports": { + ".": { + "types": "./dist/src/markdown.d.ts", + "default": "./dist/src/markdown.js" + } + }, + "type": "module", + "repository": { + "directory": "renderers/markdown-it-lit", + "type": "git", + "url": "git+https://github.com/google/A2UI.git" + }, + "files": [ + "dist/src" + ], + "scripts": { + "prepack": "npm run build", + "build": "wireit", + "build:tsc": "wireit" + }, + "wireit": { + "build": { + "dependencies": [ + "build:tsc" + ] + }, + "build:tsc": { + "command": "tsc -b --pretty", + "files": [ + "src/**/*.ts", + "src/**/*.json", + "tsconfig.json" + ], + "output": [ + "dist/", + "!dist/**/*.min.js{,.map}" + ], + "clean": "if-file-deleted" + } + }, + "keywords": [], + "author": "Google", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/google/A2UI/issues" + }, + "homepage": "https://github.com/google/A2UI/tree/main/web#readme", + "devDependencies": { + "@types/node": "^24.10.1", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + }, + "dependencies": { + "@lit/context": "^1.1.4", + "lit": "^3.3.1", + "@a2ui/lit": "file:../../lit", + "@a2ui/markdown-it-shared": "file:../markdown-it-shared", + "@a2ui/web_core": "file:../../web_core" + } +} diff --git a/renderers/markdown/markdown-it-lit/prepare-publish.mjs b/renderers/markdown/markdown-it-lit/prepare-publish.mjs new file mode 100644 index 000000000..73185139a --- /dev/null +++ b/renderers/markdown/markdown-it-lit/prepare-publish.mjs @@ -0,0 +1,73 @@ +import { readFileSync, writeFileSync, copyFileSync, mkdirSync, existsSync } from 'fs'; +import { join } from 'path'; + +// TODO: Review this script, it's copied wholesale from the lit package. + +// This script prepares the Lit package for publishing by: +// 1. Copying package.json to dist/ +// 2. Updating @a2ui/web_core dependency from 'file:...' to the actual version +// 3. Adjusting paths in package.json (main, types, exports) to be relative to dist/ + +const dirname = import.meta.dirname; +const corePkgPath = join(dirname, '../core/package.json'); +const litPkgPath = join(dirname, './package.json'); +const distDir = join(dirname, './dist'); + +if (!existsSync(distDir)) { + mkdirSync(distDir, { recursive: true }); +} + +// 1. Get Core Version +const corePkg = JSON.parse(readFileSync(corePkgPath, 'utf8')); +const coreVersion = corePkg.version; +if (!coreVersion) throw new Error('Cannot determine @a2ui/web_core version'); + +// 2. Read Lit Package +const litPkg = JSON.parse(readFileSync(litPkgPath, 'utf8')); + +// 3. Update Dependency +if (litPkg.dependencies && litPkg.dependencies['@a2ui/web_core']) { + litPkg.dependencies['@a2ui/web_core'] = '^' + coreVersion; +} else { + console.warn('Warning: @a2ui/web_core not found in dependencies.'); +} + +// 4. Adjust Paths for Dist +litPkg.main = adjustPath(litPkg.main); +litPkg.types = adjustPath(litPkg.types); + +if (litPkg.exports) { + for (const key in litPkg.exports) { + const exp = litPkg.exports[key]; + if (typeof exp === 'string') { + litPkg.exports[key] = adjustPath(exp); + } else { + if (exp.types) exp.types = adjustPath(exp.types); + if (exp.default) exp.default = adjustPath(exp.default); + if (exp.import) exp.import = adjustPath(exp.import); + if (exp.require) exp.require = adjustPath(exp.require); + } + } +} + +// 5. Write to dist/package.json +writeFileSync(join(distDir, 'package.json'), JSON.stringify(litPkg, null, 2)); + +// 6. Copy README and LICENSE +['README.md', 'LICENSE'].forEach(file => { + const src = join(dirname, file); + if (!existsSync(src)) { + throw new Error(`Missing required file for publishing: ${file}`); + } + copyFileSync(src, join(distDir, file)); +}); + +console.log(`Prepared dist/package.json with @a2ui/web_core@${coreVersion}`); + +// Utility function to adjustthe paths of the built files (dist/src/*) to (src/*) +function adjustPath(p) { + if (p && p.startsWith('./dist/')) { + return './' + p.substring(7); // Remove ./dist/ + } + return p; +} \ No newline at end of file diff --git a/renderers/markdown/markdown-it-lit/src/markdown.ts b/renderers/markdown/markdown-it-lit/src/markdown.ts new file mode 100644 index 000000000..0341bfef2 --- /dev/null +++ b/renderers/markdown/markdown-it-lit/src/markdown.ts @@ -0,0 +1,59 @@ +/* + Copyright 2025 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import { noChange } from "lit"; +import { + Directive, + DirectiveParameters, + Part, + directive, +} from "lit/directive.js"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; +import { markdownRenderer } from "@a2ui/markdown-it-shared"; + +/** + * A Lit directive that renders markdown to HTML. + * + * This directive is intended to be used by the A2UI Lit renderer to render + * markdown to HTML. + */ +class MarkdownDirective extends Directive { + private lastValue: string | null = null; + private lastTagClassMap: string | null = null; + + update(_part: Part, [value, tagClassMap]: DirectiveParameters) { + if ( + this.lastValue === value && + JSON.stringify(tagClassMap) === this.lastTagClassMap + ) { + return noChange; + } + + this.lastValue = value; + this.lastTagClassMap = JSON.stringify(tagClassMap); + return this.render(value, tagClassMap); + } + + /** + * Renders the markdown string to HTML. + */ + render(value: string, tagClassMap?: Record) { + const htmlString = markdownRenderer.render(value, tagClassMap); + return unsafeHTML(htmlString); + } +} + +export const markdown = directive(MarkdownDirective); diff --git a/renderers/markdown/markdown-it-lit/tsconfig.json b/renderers/markdown/markdown-it-lit/tsconfig.json new file mode 100644 index 000000000..f928e3840 --- /dev/null +++ b/renderers/markdown/markdown-it-lit/tsconfig.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + + "compilerOptions": { + "composite": true, + "declaration": true, + "declarationMap": true, + "incremental": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + // "allowJs": true, + "preserveWatchOutput": true, + "sourceMap": true, + "target": "es2022", + "module": "esnext", + "lib": ["es2023", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "useDefineForClassFields": false, + "rootDir": ".", + "outDir": "dist", + "tsBuildInfoFile": "dist/.tsbuildinfo", + + /* Bundler mode */ + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.json"] +} diff --git a/renderers/markdown/markdown-it-shared/.npmrc b/renderers/markdown/markdown-it-shared/.npmrc new file mode 100644 index 000000000..06b0eef7e --- /dev/null +++ b/renderers/markdown/markdown-it-shared/.npmrc @@ -0,0 +1,2 @@ +@a2ui:registry=https://us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/ +//us-npm.pkg.dev/oss-exit-gate-prod/a2ui--npm/:always-auth=true diff --git a/renderers/markdown/markdown-it-shared/README.md b/renderers/markdown/markdown-it-shared/README.md new file mode 100644 index 000000000..0c3252526 --- /dev/null +++ b/renderers/markdown/markdown-it-shared/README.md @@ -0,0 +1,6 @@ +Markdown renderer for A2UI using markdown-it and dompurify. + +This is used across all JS renderers, so the configuration is consistent. Each +renderer has a specific facade package that uses this renderer as a dependency. + +End users should use the facade package for their renderer of choice. diff --git a/renderers/markdown/markdown-it-shared/package-lock.json b/renderers/markdown/markdown-it-shared/package-lock.json new file mode 100644 index 000000000..5a52d0bf8 --- /dev/null +++ b/renderers/markdown/markdown-it-shared/package-lock.json @@ -0,0 +1,589 @@ +{ + "name": "@a2ui/markdown-it-shared", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@a2ui/markdown-it-shared", + "version": "0.0.1", + "license": "Apache-2.0", + "dependencies": { + "markdown-it": "^14.1.0" + }, + "devDependencies": { + "@types/markdown-it": "^14.1.2", + "@types/node": "^24.10.1", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + } + }, + "../web_core": { + "name": "@a2ui/web_core", + "version": "0.8.0", + "extraneous": true, + "license": "Apache-2.0", + "devDependencies": { + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", + "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-3.0.1.tgz", + "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-4.0.1.tgz", + "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^3.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/wireit": { + "version": "0.15.0-pre.2", + "resolved": "https://registry.npmjs.org/wireit/-/wireit-0.15.0-pre.2.tgz", + "integrity": "sha512-pXOTR56btrL7STFOPQgtq8MjAFWagSqs188E2FflCgcxk5uc0Xbn8CuLIR9FbqK97U3Jw6AK8zDEu/M/9ENqgA==", + "dev": true, + "license": "Apache-2.0", + "workspaces": [ + "vscode-extension", + "website" + ], + "dependencies": { + "brace-expansion": "^4.0.0", + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "jsonc-parser": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "bin": { + "wireit": "bin/wireit.js" + }, + "engines": { + "node": ">=18.0.0" + } + } + } +} diff --git a/renderers/markdown/markdown-it-shared/package.json b/renderers/markdown/markdown-it-shared/package.json new file mode 100644 index 000000000..3d58a0bd4 --- /dev/null +++ b/renderers/markdown/markdown-it-shared/package.json @@ -0,0 +1,63 @@ +{ + "name": "@a2ui/markdown-it-shared", + "version": "0.0.1", + "description": "A Markdown renderer using markdown-it and dompurify.", + "main": "./dist/src/markdown.js", + "types": "./dist/src/markdown.d.ts", + "exports": { + ".": { + "types": "./dist/src/markdown.d.ts", + "default": "./dist/src/markdown.js" + } + }, + "type": "module", + "repository": { + "directory": "renderers/markdown/markdown-it-shared", + "type": "git", + "url": "git+https://github.com/google/A2UI.git" + }, + "files": [ + "dist/src" + ], + "scripts": { + "prepack": "npm run build", + "build": "wireit", + "build:tsc": "wireit" + }, + "wireit": { + "build": { + "dependencies": [ + "build:tsc" + ] + }, + "build:tsc": { + "command": "tsc -b --pretty", + "files": [ + "src/**/*.ts", + "src/**/*.json", + "tsconfig.json" + ], + "output": [ + "dist/", + "!dist/**/*.min.js{,.map}" + ], + "clean": "if-file-deleted" + } + }, + "keywords": [], + "author": "Google", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/google/A2UI/issues" + }, + "homepage": "https://github.com/google/A2UI/tree/main/web#readme", + "devDependencies": { + "@types/markdown-it": "^14.1.2", + "@types/node": "^24.10.1", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + }, + "dependencies": { + "markdown-it": "^14.1.0" + } +} diff --git a/renderers/markdown/markdown-it-shared/prepare-publish.mjs b/renderers/markdown/markdown-it-shared/prepare-publish.mjs new file mode 100644 index 000000000..73185139a --- /dev/null +++ b/renderers/markdown/markdown-it-shared/prepare-publish.mjs @@ -0,0 +1,73 @@ +import { readFileSync, writeFileSync, copyFileSync, mkdirSync, existsSync } from 'fs'; +import { join } from 'path'; + +// TODO: Review this script, it's copied wholesale from the lit package. + +// This script prepares the Lit package for publishing by: +// 1. Copying package.json to dist/ +// 2. Updating @a2ui/web_core dependency from 'file:...' to the actual version +// 3. Adjusting paths in package.json (main, types, exports) to be relative to dist/ + +const dirname = import.meta.dirname; +const corePkgPath = join(dirname, '../core/package.json'); +const litPkgPath = join(dirname, './package.json'); +const distDir = join(dirname, './dist'); + +if (!existsSync(distDir)) { + mkdirSync(distDir, { recursive: true }); +} + +// 1. Get Core Version +const corePkg = JSON.parse(readFileSync(corePkgPath, 'utf8')); +const coreVersion = corePkg.version; +if (!coreVersion) throw new Error('Cannot determine @a2ui/web_core version'); + +// 2. Read Lit Package +const litPkg = JSON.parse(readFileSync(litPkgPath, 'utf8')); + +// 3. Update Dependency +if (litPkg.dependencies && litPkg.dependencies['@a2ui/web_core']) { + litPkg.dependencies['@a2ui/web_core'] = '^' + coreVersion; +} else { + console.warn('Warning: @a2ui/web_core not found in dependencies.'); +} + +// 4. Adjust Paths for Dist +litPkg.main = adjustPath(litPkg.main); +litPkg.types = adjustPath(litPkg.types); + +if (litPkg.exports) { + for (const key in litPkg.exports) { + const exp = litPkg.exports[key]; + if (typeof exp === 'string') { + litPkg.exports[key] = adjustPath(exp); + } else { + if (exp.types) exp.types = adjustPath(exp.types); + if (exp.default) exp.default = adjustPath(exp.default); + if (exp.import) exp.import = adjustPath(exp.import); + if (exp.require) exp.require = adjustPath(exp.require); + } + } +} + +// 5. Write to dist/package.json +writeFileSync(join(distDir, 'package.json'), JSON.stringify(litPkg, null, 2)); + +// 6. Copy README and LICENSE +['README.md', 'LICENSE'].forEach(file => { + const src = join(dirname, file); + if (!existsSync(src)) { + throw new Error(`Missing required file for publishing: ${file}`); + } + copyFileSync(src, join(distDir, file)); +}); + +console.log(`Prepared dist/package.json with @a2ui/web_core@${coreVersion}`); + +// Utility function to adjustthe paths of the built files (dist/src/*) to (src/*) +function adjustPath(p) { + if (p && p.startsWith('./dist/')) { + return './' + p.substring(7); // Remove ./dist/ + } + return p; +} \ No newline at end of file diff --git a/renderers/markdown/markdown-it-shared/src/markdown.ts b/renderers/markdown/markdown-it-shared/src/markdown.ts new file mode 100644 index 000000000..d1a5dac23 --- /dev/null +++ b/renderers/markdown/markdown-it-shared/src/markdown.ts @@ -0,0 +1,38 @@ +/* + Copyright 2025 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import { rawMarkdownRenderer, TagClassMap } from "./raw-markdown.js"; +import { sanitizer } from "./sanitizer.js"; + +// TODO: Do we need to export the TagClassMap type? + +/** + * A Markdown renderer using markdown-it and dompurify. + */ +export const markdownRenderer = { + /** + * Renders markdown to HTML. + * @param value The markdown code to render. + * @param tagClassMap A map of tag names to classes. + * @returns The rendered HTML as a string. + */ + render: (value: string, tagClassMap?: TagClassMap) => { + const htmlString = rawMarkdownRenderer.render(value, tagClassMap); + return sanitizer.sanitize(htmlString); + }, + + // TODO: Do we need an unsanitized renderer? +}; diff --git a/renderers/lit/src/0.8/ui/directives/markdown.ts b/renderers/markdown/markdown-it-shared/src/raw-markdown.ts similarity index 52% rename from renderers/lit/src/0.8/ui/directives/markdown.ts rename to renderers/markdown/markdown-it-shared/src/raw-markdown.ts index faf1b56a8..a17e5bf07 100644 --- a/renderers/lit/src/0.8/ui/directives/markdown.ts +++ b/renderers/markdown/markdown-it-shared/src/raw-markdown.ts @@ -14,20 +14,26 @@ limitations under the License. */ -import { noChange } from "lit"; -import { - Directive, - DirectiveParameters, - Part, - directive, -} from "lit/directive.js"; -import { unsafeHTML } from "lit/directives/unsafe-html.js"; -import MarkdownIt from "markdown-it"; -import { RenderRule } from "markdown-it/lib/renderer.mjs"; -import * as Sanitizer from "./sanitizer.js"; +import markdownit from 'markdown-it'; +import { sanitizer } from "./sanitizer"; + +/** + * A map of tag names to classes to apply when rendering a tag. + * + * For example, the following TagClassMap would apply the `a2ui-paragraph` class + * to all `

` tags: + * + * `{ "p": ["a2ui-paragraph"] }` + */ +export type TagClassMap = Record; -class MarkdownDirective extends Directive { - #markdownIt = MarkdownIt({ +/** + * A pre-configured instance of markdown-it to render markdown in A2UI web. + * + * This renderer does not perform any sanitization of the outgoing HTML. + */ +class MarkdownItCore { + private markdownIt = markdownit({ highlight: (str, lang) => { switch (lang) { case "html": { @@ -39,28 +45,17 @@ class MarkdownDirective extends Directive { } default: - return Sanitizer.escapeNodeText(str); + return sanitizer.sanitize(str); } }, }); - #lastValue: string | null = null; - #lastTagClassMap: string | null = null; - update(_part: Part, [value, tagClassMap]: DirectiveParameters) { - if ( - this.#lastValue === value && - JSON.stringify(tagClassMap) === this.#lastTagClassMap - ) { - return noChange; - } - - this.#lastValue = value; - this.#lastTagClassMap = JSON.stringify(tagClassMap); - return this.render(value, tagClassMap); - } - - #originalClassMap = new Map(); - #applyTagClassMap(tagClassMap: Record) { + /** + * Applies a tag class map to the markdown-it renderer. + * + * @param tagClassMap The tag class map to apply. + */ + private applyTagClassMap(tagClassMap: TagClassMap) { Object.entries(tagClassMap).forEach(([tag]) => { let tokenName; switch (tag) { @@ -100,7 +95,7 @@ class MarkdownDirective extends Directive { } const key = `${tokenName}_open`; - this.#markdownIt.renderer.rules[key] = ( + this.markdownIt.renderer.rules[key] = ( tokens, idx, options, @@ -118,35 +113,25 @@ class MarkdownDirective extends Directive { }); } - #unapplyTagClassMap() { - for (const [key] of this.#originalClassMap) { - delete this.#markdownIt.renderer.rules[key]; - } - - this.#originalClassMap.clear(); - } - /** - * Renders the markdown string to HTML using MarkdownIt. + * Renders the markdown string to HTML using the internal MarkdownIt instance. + * + * @param tagClassMap A map of tag names to classes to apply when rendering a tag. * - * Note: MarkdownIt doesn't enable HTML in its output, so we render the - * value directly without further sanitization. - * @see https://github.com/markdown-it/markdown-it/blob/master/docs/security.md + * This method does not perform any sanitization of the outgoing HTML. */ - render(value: string, tagClassMap?: Record) { + render(value: string, tagClassMap?: TagClassMap) { if (tagClassMap) { - this.#applyTagClassMap(tagClassMap); + this.applyTagClassMap(tagClassMap); } - const htmlString = this.#markdownIt.render(value); - this.#unapplyTagClassMap(); - - return unsafeHTML(htmlString); + const htmlString = this.markdownIt.render(value); + return htmlString; } } -export const markdown = directive(MarkdownDirective); - -const markdownItStandalone = MarkdownIt(); -export function renderMarkdownToHtmlString(value: string): string { - return markdownItStandalone.render(value); -} +/** + * A pre-configured instance of markdown-it to render markdown in A2UI web. + * + * This renderer does not perform any sanitization of the outgoing HTML. + */ +export const rawMarkdownRenderer = new MarkdownItCore(); diff --git a/renderers/markdown/markdown-it-shared/src/sanitizer.ts b/renderers/markdown/markdown-it-shared/src/sanitizer.ts new file mode 100644 index 000000000..fcd13bcfe --- /dev/null +++ b/renderers/markdown/markdown-it-shared/src/sanitizer.ts @@ -0,0 +1,24 @@ +/* + Copyright 2025 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +// TODO: Implement the DOMPurify sanitizer. + +/** + * A sanitizer that sanitizes HTML. + */ +export const sanitizer = { + sanitize: (html: string) => html, +} diff --git a/renderers/markdown/markdown-it-shared/tsconfig.json b/renderers/markdown/markdown-it-shared/tsconfig.json new file mode 100644 index 000000000..f928e3840 --- /dev/null +++ b/renderers/markdown/markdown-it-shared/tsconfig.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + + "compilerOptions": { + "composite": true, + "declaration": true, + "declarationMap": true, + "incremental": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + // "allowJs": true, + "preserveWatchOutput": true, + "sourceMap": true, + "target": "es2022", + "module": "esnext", + "lib": ["es2023", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "useDefineForClassFields": false, + "rootDir": ".", + "outDir": "dist", + "tsBuildInfoFile": "dist/.tsbuildinfo", + + /* Bundler mode */ + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.json"] +} diff --git a/samples/agent/adk/uv.lock b/samples/agent/adk/uv.lock index 48cf6be77..bbba9aba0 100644 --- a/samples/agent/adk/uv.lock +++ b/samples/agent/adk/uv.lock @@ -52,6 +52,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "pyink", specifier = ">=24.10.0" }, { name = "pytest", specifier = ">=9.0.2" }, { name = "pytest-asyncio", specifier = ">=1.3.0" }, ] @@ -1145,7 +1146,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/2f/28592176381b9ab2cafa12829ba7b472d177f3acc35d8fbcf3673d966fff/greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", size = 275140, upload-time = "2025-12-04T14:23:01.282Z" }, { url = "https://files.pythonhosted.org/packages/2c/80/fbe937bf81e9fca98c981fe499e59a3f45df2a04da0baa5c2be0dca0d329/greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", size = 599219, upload-time = "2025-12-04T14:50:08.309Z" }, { url = "https://files.pythonhosted.org/packages/c2/ff/7c985128f0514271b8268476af89aee6866df5eec04ac17dcfbc676213df/greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", size = 610211, upload-time = "2025-12-04T14:57:43.968Z" }, - { url = "https://files.pythonhosted.org/packages/79/07/c47a82d881319ec18a4510bb30463ed6891f2ad2c1901ed5ec23d3de351f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", size = 624311, upload-time = "2025-12-04T15:07:14.697Z" }, { url = "https://files.pythonhosted.org/packages/fd/8e/424b8c6e78bd9837d14ff7df01a9829fc883ba2ab4ea787d4f848435f23f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", size = 612833, upload-time = "2025-12-04T14:26:03.669Z" }, { url = "https://files.pythonhosted.org/packages/b5/ba/56699ff9b7c76ca12f1cdc27a886d0f81f2189c3455ff9f65246780f713d/greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", size = 1567256, upload-time = "2025-12-04T15:04:25.276Z" }, { url = "https://files.pythonhosted.org/packages/1e/37/f31136132967982d698c71a281a8901daf1a8fbab935dce7c0cf15f942cc/greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", size = 1636483, upload-time = "2025-12-04T14:27:30.804Z" }, @@ -1153,7 +1153,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/7c/f0a6d0ede2c7bf092d00bc83ad5bafb7e6ec9b4aab2fbdfa6f134dc73327/greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", size = 275671, upload-time = "2025-12-04T14:23:05.267Z" }, { url = "https://files.pythonhosted.org/packages/44/06/dac639ae1a50f5969d82d2e3dd9767d30d6dbdbab0e1a54010c8fe90263c/greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", size = 646360, upload-time = "2025-12-04T14:50:10.026Z" }, { url = "https://files.pythonhosted.org/packages/e0/94/0fb76fe6c5369fba9bf98529ada6f4c3a1adf19e406a47332245ef0eb357/greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", size = 658160, upload-time = "2025-12-04T14:57:45.41Z" }, - { url = "https://files.pythonhosted.org/packages/93/79/d2c70cae6e823fac36c3bbc9077962105052b7ef81db2f01ec3b9bf17e2b/greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", size = 671388, upload-time = "2025-12-04T15:07:15.789Z" }, { url = "https://files.pythonhosted.org/packages/b8/14/bab308fc2c1b5228c3224ec2bf928ce2e4d21d8046c161e44a2012b5203e/greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", size = 660166, upload-time = "2025-12-04T14:26:05.099Z" }, { url = "https://files.pythonhosted.org/packages/4b/d2/91465d39164eaa0085177f61983d80ffe746c5a1860f009811d498e7259c/greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", size = 1615193, upload-time = "2025-12-04T15:04:27.041Z" }, { url = "https://files.pythonhosted.org/packages/42/1b/83d110a37044b92423084d52d5d5a3b3a73cafb51b547e6d7366ff62eff1/greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", size = 1683653, upload-time = "2025-12-04T14:27:32.366Z" }, @@ -1161,7 +1160,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/66/bd6317bc5932accf351fc19f177ffba53712a202f9df10587da8df257c7e/greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", size = 282638, upload-time = "2025-12-04T14:25:20.941Z" }, { url = "https://files.pythonhosted.org/packages/30/cf/cc81cb030b40e738d6e69502ccbd0dd1bced0588e958f9e757945de24404/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", size = 651145, upload-time = "2025-12-04T14:50:11.039Z" }, { url = "https://files.pythonhosted.org/packages/9c/ea/1020037b5ecfe95ca7df8d8549959baceb8186031da83d5ecceff8b08cd2/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", size = 654236, upload-time = "2025-12-04T14:57:47.007Z" }, - { url = "https://files.pythonhosted.org/packages/69/cc/1e4bae2e45ca2fa55299f4e85854606a78ecc37fead20d69322f96000504/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", size = 662506, upload-time = "2025-12-04T15:07:16.906Z" }, { url = "https://files.pythonhosted.org/packages/57/b9/f8025d71a6085c441a7eaff0fd928bbb275a6633773667023d19179fe815/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", size = 653783, upload-time = "2025-12-04T14:26:06.225Z" }, { url = "https://files.pythonhosted.org/packages/f6/c7/876a8c7a7485d5d6b5c6821201d542ef28be645aa024cfe1145b35c120c1/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", size = 1614857, upload-time = "2025-12-04T15:04:28.484Z" }, { url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034, upload-time = "2025-12-04T14:27:33.531Z" }, diff --git a/samples/client/lit/contact/contact.ts b/samples/client/lit/contact/contact.ts index 8300abe16..796a2555b 100644 --- a/samples/client/lit/contact/contact.ts +++ b/samples/client/lit/contact/contact.ts @@ -37,6 +37,7 @@ import { type Snackbar } from "./ui/snackbar.js"; import { repeat } from "lit/directives/repeat.js"; import { v0_8 } from "@a2ui/lit"; import * as UI from "@a2ui/lit/ui"; +import { markdown } from "@a2ui/markdown-it-lit"; // Demo elements. import "./ui/ui.js"; @@ -54,6 +55,9 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { @provide({ context: UI.Context.themeContext }) accessor theme: v0_8.Types.Theme = uiTheme; + @provide({ context: UI.Context.markdown }) + accessor #markdown = markdown; + @state() accessor #requesting = false; diff --git a/samples/client/lit/contact/package.json b/samples/client/lit/contact/package.json index 58da6a441..fcfd6e017 100644 --- a/samples/client/lit/contact/package.json +++ b/samples/client/lit/contact/package.json @@ -77,6 +77,7 @@ "dependencies": { "@a2a-js/sdk": "^0.3.4", "@a2ui/lit": "file:../../../../renderers/lit", + "@a2ui/markdown-it-lit": "file:../../../../renderers/markdown-it-lit", "@lit-labs/signals": "^0.1.3", "@lit/context": "^1.1.4", "lit": "^3.3.1" diff --git a/samples/client/lit/contact/theme/theme.ts b/samples/client/lit/contact/theme/theme.ts index e9aef950b..67f8a41b0 100644 --- a/samples/client/lit/contact/theme/theme.ts +++ b/samples/client/lit/contact/theme/theme.ts @@ -83,6 +83,12 @@ const h3 = { "typography-sz-ts": true, }; +const h5 = { + ...heading, + "layout-mt-2": true, // To align with the icons + "typography-sz-bm": true, +}; + const iframe = { "behavior-sw-n": true, }; @@ -166,6 +172,7 @@ const buttonLight = v0_8.Styles.merge(button, { "color-c-n100": true }); const h1Light = v0_8.Styles.merge(h1, { "color-c-n5": true }); const h2Light = v0_8.Styles.merge(h2, { "color-c-n5": true }); const h3Light = v0_8.Styles.merge(h3, { "color-c-n5": true }); +const h5Light = v0_8.Styles.merge(h5, { "color-c-n5": true }); const bodyLight = v0_8.Styles.merge(body, { "color-c-n5": true }); const pLight = v0_8.Styles.merge(p, { "color-c-n60": true }); const preLight = v0_8.Styles.merge(pre, { "color-c-n35": true }); @@ -438,7 +445,7 @@ export const theme: v0_8.Types.Theme = { h2: h2Light, h3: h3Light, h4: {}, - h5: {}, + h5: h5Light, iframe, input: inputLight, p: pLight, @@ -452,7 +459,7 @@ export const theme: v0_8.Types.Theme = { h2: [...Object.keys(h2Light)], h3: [...Object.keys(h3Light)], h4: [], - h5: [], + h5: [...Object.keys(h5Light)], ul: [...Object.keys(unorderedListLight)], ol: [...Object.keys(orderedListLight)], li: [...Object.keys(listItemLight)], diff --git a/samples/client/lit/package-lock.json b/samples/client/lit/package-lock.json index 94aeccddf..2c60e5d90 100644 --- a/samples/client/lit/package-lock.json +++ b/samples/client/lit/package-lock.json @@ -36,6 +36,24 @@ "wireit": "^0.15.0-pre.2" } }, + "../../../renderers/markdown-it-lit": {}, + "../../../renderers/markdown/markdown-it-lit": { + "name": "@a2ui/markdown-it-lit", + "version": "0.8.1", + "license": "Apache-2.0", + "dependencies": { + "@a2ui/lit": "file:../../lit", + "@a2ui/markdown-it-shared": "file:../markdown-it-shared", + "@a2ui/web_core": "file:../../web_core", + "@lit/context": "^1.1.4", + "lit": "^3.3.1" + }, + "devDependencies": { + "@types/node": "^24.10.1", + "typescript": "^5.8.3", + "wireit": "^0.15.0-pre.2" + } + }, "contact": { "name": "@a2ui/contact", "version": "0.8.1", @@ -43,6 +61,7 @@ "dependencies": { "@a2a-js/sdk": "^0.3.4", "@a2ui/lit": "file:../../../../renderers/lit", + "@a2ui/markdown-it-lit": "file:../../../../renderers/markdown-it-lit", "@lit-labs/signals": "^0.1.3", "@lit/context": "^1.1.4", "lit": "^3.3.1" @@ -55,6 +74,10 @@ "wireit": "^0.15.0-pre.2" } }, + "contact/node_modules/@a2ui/markdown-it-lit": { + "resolved": "../../../renderers/markdown-it-lit", + "link": true + }, "node_modules/@a2a-js/sdk": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@a2a-js/sdk/-/sdk-0.3.8.tgz", @@ -96,6 +119,10 @@ "resolved": "../../../renderers/lit", "link": true }, + "node_modules/@a2ui/markdown-it-lit": { + "resolved": "../../../renderers/markdown/markdown-it-lit", + "link": true + }, "node_modules/@a2ui/shell": { "resolved": "shell", "link": true @@ -2159,7 +2186,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -2893,6 +2919,7 @@ "dependencies": { "@a2a-js/sdk": "^0.3.4", "@a2ui/lit": "file:../../../../renderers/lit", + "@a2ui/markdown-it-lit": "file:../../../../renderers/markdown/markdown-it-lit", "@google/genai": "^1.22.0", "@lit-labs/signals": "^0.1.3", "@lit/context": "^1.1.4", diff --git a/samples/client/lit/package.json b/samples/client/lit/package.json index fc5534f1b..31703cfd1 100644 --- a/samples/client/lit/package.json +++ b/samples/client/lit/package.json @@ -14,7 +14,8 @@ "serve:agent:rizzcharts": "cd ../../agent/adk/rizzcharts && uv run .", "serve:agent:orchestrator": "cd ../../agent/adk/orchestrator && uv run .", "serve:shell": "cd shell && npm run dev", - "build:renderer": "cd ../../../renderers/web_core && npm install && npm run build && cd ../lit && npm install && npm run build", + "serve:contact": "cd contact && npm run dev", + "build:renderer": "cd ../../../renderers && for dir in 'web_core' 'markdown/markdown-it-shared' 'markdown/markdown-it-lit' 'lit'; do (cd \"$dir\" && npm install && npm run build); done", "demo:all": "npm install && npm run build:renderer && concurrently -k -n \"SHELL,REST,CONT1\" -c \"magenta,blue,green\" \"npm run serve:shell\" \"npm run serve:agent:restaurant\" \"npm run serve:agent:contact_lookup\"", "demo:restaurant": "npm install && npm run build:renderer && concurrently -k -n \"SHELL,REST\" -c \"magenta,blue\" \"npm run serve:shell\" \"npm run serve:agent:restaurant\"", "demo:contact": "npm install && npm run build:renderer && concurrently -k -n \"SHELL,CONT1\" -c \"magenta,green\" \"npm run serve:shell\" \"npm run serve:agent:contact_lookup\"", diff --git a/samples/client/lit/shell/app.ts b/samples/client/lit/shell/app.ts index 33a16cf57..8960f12af 100644 --- a/samples/client/lit/shell/app.ts +++ b/samples/client/lit/shell/app.ts @@ -46,6 +46,7 @@ import { AppConfig } from "./configs/types.js"; import { config as restaurantConfig } from "./configs/restaurant.js"; import { config as contactsConfig } from "./configs/contacts.js"; import { styleMap } from "lit/directives/style-map.js"; +import { markdown } from "@a2ui/markdown-it-lit"; const configs: Record = { restaurant: restaurantConfig, @@ -54,8 +55,11 @@ const configs: Record = { @customElement("a2ui-shell") export class A2UILayoutEditor extends SignalWatcher(LitElement) { - @provide({ context: UI.Context.themeContext }) - accessor theme: v0_8.Types.Theme = uiTheme; + @provide({ context: UI.Context.theme }) + accessor #theme = uiTheme; + + @provide({ context: UI.Context.markdown }) + accessor #markdownRenderer = markdown; @state() accessor #requesting = false; @@ -290,7 +294,7 @@ export class A2UILayoutEditor extends SignalWatcher(LitElement) { // Apply the theme directly, which will use the Lit context. if (this.config.theme) { - this.theme = this.config.theme; + this.#theme = this.config.theme; } window.document.title = this.config.title; @@ -500,7 +504,7 @@ export class A2UILayoutEditor extends SignalWatcher(LitElement) { .surfaceId=${surfaceId} .surface=${surface} .processor=${this.#processor} - >`; + >`; } )} `; diff --git a/samples/client/lit/shell/package.json b/samples/client/lit/shell/package.json index 0264f5866..9ffefb92a 100644 --- a/samples/client/lit/shell/package.json +++ b/samples/client/lit/shell/package.json @@ -77,10 +77,11 @@ "dependencies": { "@a2a-js/sdk": "^0.3.4", "@a2ui/lit": "file:../../../../renderers/lit", + "@a2ui/markdown-it-lit": "file:../../../../renderers/markdown/markdown-it-lit", "@google/genai": "^1.22.0", "@lit-labs/signals": "^0.1.3", "@lit/context": "^1.1.4", "@types/node": "^24.7.1", "lit": "^3.3.1" } -} \ No newline at end of file +}