diff --git a/CHANGELOG.md b/CHANGELOG.md index 55ca078..e892200 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [v0.2.23] - 2025-04-08 +## [v0.2.24] - 2025-04-17 + +### Added +- Add parser for web component/shadow DOM + +### Changed +- `createTrustedHTMLTemplate` now throws if not given a `TrustedTypePolicy` + ### Added - Add `createTrustedHTMLTemplate()` to create trusted HTML generating tagged templates diff --git a/core.js b/core.js index 7fe50ee..d39b37b 100644 --- a/core.js +++ b/core.js @@ -14,8 +14,9 @@ export { export { text, createStyleSheet, createCSSParser, css, lightCSS, darkCSS , - styleSheetToFile, styleSheetToLink, createHTMLParser, html, doc, + styleSheetToFile, styleSheetToLink, createHTMLParser, html, doc, trustedHTML, htmlUnsafe, docUnsafe, htmlToFile, createTrustedHTMLTemplate, xml, svg, json, math, url, + createShadowParser, shadow, el, } from './parsers.js'; export { diff --git a/package-lock.json b/package-lock.json index aa551f5..1b83470 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@aegisjsproject/core", - "version": "0.2.23", + "version": "0.2.24", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@aegisjsproject/core", - "version": "0.2.23", + "version": "0.2.24", "funding": [ { "type": "librepay", diff --git a/package.json b/package.json index 3edd0d3..d4058db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aegisjsproject/core", - "version": "0.2.23", + "version": "0.2.24", "description": "A fast, secure, modern, light-weight, and simple JS library for creating web components and more!", "keywords": [ "aegis", diff --git a/parsers.js b/parsers.js index 708d06d..fa37bc6 100644 --- a/parsers.js +++ b/parsers.js @@ -3,7 +3,10 @@ export { createStyleSheet, createCSSParser, css, lightCSS, darkCSS, styleSheetToFile, styleSheetToLink, } from './parsers/css.js'; -export { createHTMLParser, html, doc, htmlUnsafe, docUnsafe, htmlToFile, createTrustedHTMLTemplate } from './parsers/html.js'; +export { + createHTMLParser, html, doc, htmlUnsafe, docUnsafe, htmlToFile, + createTrustedHTMLTemplate, trustedHTML, createShadowParser, shadow, el, +} from './parsers/html.js'; export { xml } from './parsers/xml.js'; export { svg } from './parsers/svg.js'; export { json } from './parsers/json.js'; diff --git a/parsers/html.js b/parsers/html.js index d07e880..5a17981 100644 --- a/parsers/html.js +++ b/parsers/html.js @@ -16,11 +16,57 @@ const sanitizer = Object.freeze({ export const html = createHTMLParser(sanitizer, { mapper: stringify }); +export const el = (...args) => html.apply(null, args)?.firstElementChild; + +export function createShadowParser({ + tagName = 'div', + mode = 'open', + clonable = true, + serializable = true, + delegatesFocus = false, + slotAssignment = 'named', + sanitizer: sanitizerConfig = sanitizer, + exportParts, +} = {}) { + const parser = createHTMLParser(sanitizerConfig, { mapper: stringify }); + + if (Array.isArray(exportParts)) { + exportParts = exportParts.join(', '); + } else if (typeof exportParts === 'object') { + exportParts = Object.entries(exportParts).map(([k, v]) => `${k}: ${v}`).join(', '); + } + + return (...args) => { + const host = document.createElement(tagName); + const shadowRoot = host.attachShadow({ mode, clonable, serializable, delegatesFocus, slotAssignment }); + + shadowRoot.append(parser.apply(parser, args)); + + if (typeof exportParts === 'string') { + host.setAttribute('exportparts', exportParts); + } + + return host; + }; +} + +export const shadow = createShadowParser(); + export function createTrustedHTMLTemplate(policy) { if (isTrustPolicy(policy)) { - return (...args) => policy.createHTML(String.raw.apply(null, args)); + return (strings, ...values) => policy.createHTML(String.raw(strings, ...values.map(stringify))); + } else { + throw new TypeError('Not a Trusted Types Policy.'); + } +} + +export function trustedHTML(strings, ...values) { + if (isTrustPolicy(trustedTypes?.defaultPolicy)) { + return trustedTypes.defaultPolicy.createHTML(String.raw(strings, ...values.map(stringify))); + } else if (! ('trustedTypes' in globalThis)) { + throw new Error('Trusted Types is not supported.'); } else { - return String.raw; + throw new TypeError('No default Trusted Types Policy is available.'); } }