@substrate-system/tonic 17.1.0 → 17.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -6
- package/dist/hydrate.cjs +39 -0
- package/dist/hydrate.cjs.map +7 -0
- package/dist/hydrate.d.ts +30 -0
- package/dist/hydrate.d.ts.map +1 -0
- package/dist/hydrate.js +18 -0
- package/dist/hydrate.js.map +7 -0
- package/dist/hydrate.min.cjs +2 -0
- package/dist/hydrate.min.cjs.map +7 -0
- package/dist/hydrate.min.mjs +3 -0
- package/dist/hydrate.min.mjs.map +7 -0
- package/dist/hydrate.mjs +20 -0
- package/dist/hydrate.mjs.map +7 -0
- package/dist/index.cjs +128 -24
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +129 -25
- package/dist/index.js.map +2 -2
- package/dist/index.min.cjs +2 -2
- package/dist/index.min.cjs.map +3 -3
- package/dist/index.min.mjs +2 -2
- package/dist/index.min.mjs.map +3 -3
- package/dist/index.mjs +127 -24
- package/dist/index.mjs.map +2 -2
- package/dist/meta.json +41 -9
- package/dist/render-to-string.cjs +69 -1
- package/dist/render-to-string.cjs.map +3 -3
- package/dist/render-to-string.d.ts +60 -0
- package/dist/render-to-string.d.ts.map +1 -0
- package/dist/render-to-string.js +66 -0
- package/dist/render-to-string.js.map +3 -3
- package/dist/render-to-string.min.cjs +2 -1
- package/dist/render-to-string.min.cjs.map +3 -3
- package/dist/render-to-string.min.mjs +2 -1
- package/dist/render-to-string.min.mjs.map +3 -3
- package/dist/render-to-string.mjs +68 -1
- package/dist/render-to-string.mjs.map +3 -3
- package/package.json +7 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import morphdom from '@substrate-system/morphdom'\n\nexport class TonicTemplate {\n rawText:string\n unsafe:boolean\n templateStrings?:string[]|TemplateStringsArray|null\n isTonicTemplate:true\n\n constructor (\n rawText,\n templateStrings?:string[]|TemplateStringsArray|null,\n unsafe?:boolean\n ) {\n this.isTonicTemplate = true\n this.unsafe = !!unsafe\n this.rawText = rawText\n this.templateStrings = templateStrings\n }\n\n valueOf () { return this.rawText }\n toString () { return this.rawText }\n}\n\n/**\n * Class Tonic\n *\n * @template {T extends object = Record<string, any>} T Type of the props\n */\nexport abstract class Tonic<\n T extends { [key:string]:any}=Record<string, any>\n> extends window.HTMLElement {\n private static _tags = ''\n private static _refIds:string[] = []\n private static _data = {}\n private static _states = {}\n private static _children = {}\n private static _reg = {}\n private static _stylesheetRegistry:(()=>string)[] = []\n private static _index = 0\n // @ts-expect-error VERSION is injected during build\n static get version () { return VERSION ?? null }\n static get SPREAD () { return /\\.\\.\\.\\s?(__\\w+__\\w+__)/g }\n static get ESC () { return /[\"&'<>`/]/g }\n static get AsyncFunctionGenerator ():AsyncGeneratorFunctionConstructor {\n return (async function * () {\n }.constructor) as AsyncGeneratorFunctionConstructor\n }\n // eslint-disable-next-line\n static get AsyncFunction ():Function {\n return (async function () {}.constructor)\n }\n\n static get MAP () {\n /* eslint-disable object-property-newline, object-property-newline,\n object-curly-newline */\n return { '\"': '"', '&': '&', '\\'': ''', '<': '<',\n '>': '>', '`': '`', '/': '/' }\n }\n\n static ssr\n static nonce\n\n private _state:any\n stylesheet?:()=>string\n styles:()=>string\n props:T\n preventRenderOnReconnect:boolean\n private _id:string\n pendingReRender?:Promise<this>|null\n updated?:((props:Record<string, any>)=>any)\n willRender?:(()=>any)\n root?:ShadowRoot|this\n willConnect?:()=>any\n private _source?:string\n connected?:()=>void\n disconnected?:()=>void\n\n private elements:Element[] & { __children__? }\n private nodes:ChildNode[] & { __children__? }\n private _props = Tonic.getPropertyNames(this)\n\n constructor () {\n super()\n const state = Tonic._states[super.id]\n delete Tonic._states[super.id]\n this._state = state || {}\n this.preventRenderOnReconnect = false\n this.props = {} as T\n this.elements = [...this.children]\n this.elements.__children__ = true\n this.nodes = [...this.childNodes]\n this.nodes.__children__ = true\n this._events()\n }\n\n abstract render ():TonicTemplate|Promise<TonicTemplate>\n\n defaults ():Record<string, any> {\n return {}\n }\n\n get isTonicComponent ():true {\n return true\n }\n\n /**\n * Get a namespaced event name, given a non-namespaced string.\n *\n * @example\n * MyElement.event('example') // => my-element:example\n *\n * @param {string} type The name of the event\n * @returns {string} The namespaced event name\n */\n static event (type:string):string {\n return `${this.tag}:${type}`\n }\n\n /**\n * Get the tag name of this component.\n */\n static get tag ():string {\n return Tonic.getTagName(this.name)\n }\n\n private static _createId () {\n return `tonic${Tonic._index++}`\n }\n\n private static _normalizeAttrs (o, x = {}) {\n [...o].forEach(o => (x[o.name] = o.value))\n return x\n }\n\n private _checkId () {\n const _id = super.id\n if (!_id) {\n const html = this.outerHTML.replace(this.innerHTML, '...')\n throw new Error(`Component: ${html} has no id`)\n }\n return _id\n }\n\n /**\n * Get the component state property.\n */\n get state () {\n return (this._checkId(), this._state)\n }\n\n set state (newState) {\n this._state = (this._checkId(), newState)\n }\n\n private _events () {\n const hp = Object.getOwnPropertyNames(window.HTMLElement.prototype)\n // this is where we map methods like `handle_click` to event handlers.\n // look at the HTMLElement prototype, and if it is has a method like\n // `onclick`, then add an event listener for 'click'\n for (const p of this._props) {\n if (!p.includes('handle_')) continue\n const evName = p.split('_')[1]\n\n if (hp.indexOf('on' + evName) === -1) continue\n this.addEventListener(evName, this)\n }\n }\n\n private _prop (o) {\n const id = this._id\n const p = `__${id}__${Tonic._createId()}__`\n Tonic._data[id] = Tonic._data[id] || {}\n Tonic._data[id][p] = o\n return p\n }\n\n private _placehold (r) {\n const id = this._id\n const ref = `placehold:${id}:${Tonic._createId()}__`\n Tonic._children[id] = Tonic._children[id] || {}\n Tonic._children[id][ref] = r\n return ref\n }\n\n static match (el:HTMLElement, s:string) {\n if (!el.matches) el = el.parentElement!\n return el.matches(s) ? el : el.closest(s)\n }\n\n static getTagName (camelName:string) {\n return camelName.match(/[A-Z][a-z0-9]*/g)!.join('-').toLowerCase()\n }\n\n /**\n * Add all methods to this._props\n */\n static getPropertyNames (proto) {\n const props:string[] = []\n while (proto && proto !== Tonic.prototype) {\n props.push(...Object.getOwnPropertyNames(proto))\n proto = Object.getPrototypeOf(proto)\n }\n return props\n }\n\n /**\n * Add a component. Calls `window.customElements.define` with the\n * component's name.\n *\n * @param {Tonic} c Component to add\n * @param {string} [htmlName] Name of the element, default to the class name\n * @returns {Tonic}\n */\n static add (c, htmlName?:string) {\n const hasValidName = htmlName || (c.name && c.name.length > 1)\n if (!hasValidName) {\n throw Error('Mangling. https://bit.ly/2TkJ6zP')\n }\n\n if (!htmlName) htmlName = Tonic.getTagName(c.name)\n if (!Tonic.ssr && window.customElements.get(htmlName)) {\n throw new Error(`Cannot Tonic.add(${c.name}, '${htmlName}') twice`)\n }\n\n if (!c.prototype || !c.prototype.isTonicComponent) {\n const tmp = { [c.name]: class extends Tonic { render } }[c.name]\n tmp.prototype.render = c\n c = tmp\n }\n\n c.prototype._props = Tonic.getPropertyNames(c.prototype)\n\n Tonic._reg[htmlName] = c\n Tonic._tags = Object.keys(Tonic._reg).join()\n window.customElements.define(htmlName, c as unknown as CustomElementConstructor)\n\n if (typeof c.stylesheet === 'function') {\n Tonic.registerStyles(c.stylesheet)\n }\n\n return c\n }\n\n static registerStyles (stylesheetFn:()=>string) {\n if (Tonic._stylesheetRegistry.includes(stylesheetFn)) return\n Tonic._stylesheetRegistry.push(stylesheetFn)\n\n const styleNode = document.createElement('style')\n if (Tonic.nonce) styleNode.setAttribute('nonce', Tonic.nonce)\n styleNode.appendChild(document.createTextNode(stylesheetFn()))\n if (document.head) document.head.appendChild(styleNode)\n }\n\n static escape (s:string):string {\n return s.replace(Tonic.ESC, c => Tonic.MAP[c])\n }\n\n static unsafeRawString (\n s:string,\n templateStrings:string[]\n ):InstanceType<typeof TonicTemplate> {\n return new TonicTemplate(s, templateStrings, true)\n }\n\n /**\n * Emit a regular, non-namespaced event.\n *\n * @param {string} eventName Event name as a string.\n * @param {any} detail Any data to go with the event.\n */\n dispatch (eventName:string, detail:any = null):void {\n const opts = { bubbles: true, detail }\n this.dispatchEvent(new window.CustomEvent(eventName, opts))\n }\n\n /**\n * Emit a namespaced event, using a convention for event names.\n *\n * @example\n * myComponent.emit('test') // => `my-compnent:test`\n *\n * @param {string} type The event type, comes after `:` in event name.\n * @param {string|object|any[]} detail detail for Event constructor\n * @param {{ bubbles?:boolean, cancelable?:boolean }} opts `Cancelable` and\n * `bubbles`\n * @returns {boolean}\n */\n emit (type:string, detail:string|object|any[] = {}, opts:Partial<{\n bubbles:boolean;\n cancelable:boolean\n }> = {}):boolean {\n const namespace = Tonic.getTagName(this.constructor.name)\n const event = new CustomEvent(`${namespace}:${type}`, {\n bubbles: (opts.bubbles === undefined) ? true : opts.bubbles,\n cancelable: (opts.cancelable === undefined) ? true : opts.cancelable,\n detail\n })\n\n return this.dispatchEvent(event)\n }\n\n html (\n strings:string[]|TemplateStringsArray,\n ...values\n ):InstanceType<typeof TonicTemplate> {\n const refs = o => {\n if (o && o.__children__) return this._placehold(o)\n if (o && o.isTonicTemplate) return o.rawText\n switch (Object.prototype.toString.call(o)) {\n case '[object HTMLCollection]':\n case '[object NodeList]': return this._placehold([...o])\n case '[object Array]': {\n if (o.every(x => x.isTonicTemplate && !x.unsafe)) {\n return new TonicTemplate(o.join('\\n'), null, false)\n }\n return this._prop(o)\n }\n case '[object Object]':\n case '[object Function]':\n case '[object AsyncFunction]':\n case '[object Set]':\n case '[object Map]':\n case '[object WeakMap]':\n case '[object File]':\n return this._prop(o)\n case '[object NamedNodeMap]':\n return this._prop(Tonic._normalizeAttrs(o))\n case '[object Number]': return `${o}__float`\n case '[object String]': return Tonic.escape(o)\n case '[object Boolean]': return `${o}__boolean`\n case '[object Null]': return `${o}__null`\n case '[object HTMLElement]':\n return this._placehold([o])\n }\n if (\n typeof o === 'object' && o && o.nodeType === 1 &&\n typeof o.cloneNode === 'function'\n ) {\n return this._placehold([o])\n }\n return o\n }\n\n const out:string[] = []\n for (let i = 0; i < strings.length - 1; i++) {\n out.push(strings[i], refs(values[i]))\n }\n out.push(strings[strings.length - 1])\n\n const htmlStr = out.join('').replace(Tonic.SPREAD, (_, p) => {\n const o = Tonic._data[p.split('__')[1]][p]\n return Object.entries(o).map(([key, value]) => {\n const k = key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n if (value === true) return k\n else if (value) return `${k}=\"${Tonic.escape(String(value))}\"`\n else return ''\n }).filter(Boolean).join(' ')\n })\n // Process type markers in template content\n .replace(/(\\d+(?:\\.\\d+)?)__float/g, '$1')\n .replace(/(true|false)__boolean/g, '$1')\n .replace(/null__null/g, 'null')\n\n return new TonicTemplate(htmlStr, strings, false)\n }\n\n scheduleReRender (oldProps:any):Promise<this> {\n if (this.pendingReRender) return this.pendingReRender\n\n this.pendingReRender = new Promise(resolve => setTimeout(() => {\n if (!this.isInDocument(this.shadowRoot || this)) return\n const p = this._set(this.shadowRoot || this, this.render)\n this.pendingReRender = null\n\n if (p && p.then) {\n return p.then(() => {\n this.updated && this.updated(oldProps)\n resolve(this)\n })\n }\n\n this.updated && this.updated(oldProps)\n resolve(this)\n }, 0))\n\n return this.pendingReRender\n }\n\n /**\n * Update the view\n */\n reRender (o:T|((props:T)=>T) = this.props):Promise<this> {\n const oldProps = { ...this.props }\n this.props = typeof o === 'function' ? (o as (props:T)=>T)(oldProps) : o\n return this.scheduleReRender(oldProps)\n }\n\n /**\n * If there is a method with the same name as the event type,\n * then call the method.\n * @see {@link https://gomakethings.com/the-handleevent-method-is-the-absolute-best-way-to-handle-events-in-web-components/#what-is-the-handleevent-method What is the handleEvent() method?}\n */\n handleEvent (ev:Event):void {\n this['handle_' + ev.type] && this['handle_' + ev.type](ev)\n }\n\n private _drainIterator (target, iterator) {\n return iterator.next().then((result) => {\n this._set(target, null, result.value)\n if (result.done) return\n return this._drainIterator(target, iterator)\n })\n }\n\n /**\n * _set\n * @param {Element|InstanceType<typeof Tonic>|ShadowRoot} target\n * @param {()=>any} render\n * @param {string} content\n * @returns {Promise<void>|void}\n * @private\n */\n private _set (target, render, content = ''):Promise<void>|void {\n this.willRender && this.willRender()\n for (const node of target.querySelectorAll(Tonic._tags)) {\n if (!node.isTonicComponent) continue\n\n const id = node.getAttribute('id')\n if (!id || !Tonic._refIds.includes(id)) continue\n Tonic._states[id] = node.state\n }\n\n if (render instanceof Tonic.AsyncFunction) {\n return ((render as ()=>any)\n .call(this, this.html, this.props)\n .then(content => this._apply(target, content))\n )\n } else if (render instanceof Tonic.AsyncFunctionGenerator) {\n return this._drainIterator(target, (render as AsyncGeneratorFunction).call(this))\n } else if (render === null) {\n this._apply(target, content)\n } else if (render instanceof Function) {\n this._apply(target, render.call(this, this.html, this.props) || '')\n }\n }\n\n private _apply (target, content) {\n if (content && content.isTonicTemplate) {\n content = content.rawText\n } else if (typeof content === 'string') {\n content = Tonic.escape(content)\n }\n\n if (typeof content === 'string') {\n if (this.stylesheet) {\n content = `<style nonce=${Tonic.nonce || ''}>${this.stylesheet()}</style>${content}`\n }\n\n // Check if we should use morphdom for DOM state preservation\n const hasFormElements = target.querySelector && (\n target.querySelector('input') ||\n target.querySelector('textarea') ||\n target.querySelector('select')\n )\n\n const shouldUseMorphdom = (\n hasFormElements &&\n document.activeElement &&\n (\n target.contains(document.activeElement) ||\n target === document.activeElement\n )\n )\n\n if (shouldUseMorphdom) {\n // Use morphdom to preserve DOM state during updates\n const tempContainer = document.createElement('div')\n tempContainer.innerHTML = content\n\n morphdom(target, tempContainer, {\n childrenOnly: true,\n onBeforeElUpdated: (fromEl, toEl) => {\n // Skip updating if the elements are the same and preserve form state\n if (fromEl.isEqualNode && fromEl.isEqualNode(toEl)) {\n return false\n }\n\n // For inputs, preserve value and selection\n if (fromEl.tagName === 'INPUT' && toEl.tagName === 'INPUT') {\n const fromInput = fromEl as HTMLInputElement\n const toInput = toEl as HTMLInputElement\n\n // Preserve form values\n if (fromInput.value !== '') {\n toInput.value = fromInput.value\n }\n\n // Preserve selection/cursor position\n if (document.activeElement === fromInput) {\n toInput.setAttribute('data-preserve-focus', 'true')\n toInput.setAttribute('data-selection-start', String(fromInput.selectionStart || 0))\n toInput.setAttribute('data-selection-end', String(fromInput.selectionEnd || 0))\n }\n }\n\n // For textareas, preserve value and selection\n if (fromEl.tagName === 'TEXTAREA' && toEl.tagName === 'TEXTAREA') {\n const fromTextarea = fromEl as HTMLTextAreaElement\n const toTextarea = toEl as HTMLTextAreaElement\n\n // Preserve form values\n if (fromTextarea.value !== '') {\n toTextarea.value = fromTextarea.value\n }\n\n // Preserve selection/cursor position\n if (document.activeElement === fromTextarea) {\n toTextarea.setAttribute('data-preserve-focus', 'true')\n toTextarea.setAttribute('data-selection-start', String(fromTextarea.selectionStart || 0))\n toTextarea.setAttribute('data-selection-end', String(fromTextarea.selectionEnd || 0))\n }\n }\n\n return true\n },\n\n onElUpdated: (el) => {\n // Restore focus and selection after update\n if (el.hasAttribute('data-preserve-focus')) {\n const startPos = parseInt(el.getAttribute('data-selection-start') || '0', 10)\n const endPos = parseInt(el.getAttribute('data-selection-end') || '0', 10)\n\n // Clean up attributes\n el.removeAttribute('data-preserve-focus')\n el.removeAttribute('data-selection-start')\n el.removeAttribute('data-selection-end')\n\n // Focus and restore selection\n el.focus()\n if ('setSelectionRange' in el) {\n (el as HTMLInputElement|HTMLTextAreaElement).setSelectionRange(startPos, endPos)\n }\n }\n }\n })\n } else {\n // Use original innerHTML approach\n target.innerHTML = content\n }\n\n if (this.styles) {\n const styles = this.styles()\n for (const node of target.querySelectorAll('[styles]')) {\n for (const s of node.getAttribute('styles').split(/\\s+/)) {\n Object.assign(node.style, styles[s.trim()])\n }\n }\n }\n\n const children = Tonic._children[this._id] || {}\n\n const walk = (node, fn) => {\n if (node.nodeType === 3) {\n const id = node.textContent.trim()\n if (children[id]) fn(node, children[id], id)\n }\n\n const childNodes = node.childNodes\n if (!childNodes) return\n\n for (let i = 0; i < childNodes.length; i++) {\n walk(childNodes[i], fn)\n }\n }\n\n walk(target, (node, children, id) => {\n for (const child of children) {\n node.parentNode.insertBefore(child, node)\n }\n delete Tonic._children[this._id][id]\n node.parentNode.removeChild(node)\n })\n } else {\n target.innerHTML = ''\n target.appendChild(content.cloneNode(true))\n }\n }\n\n connectedCallback () {\n this.root = this.shadowRoot || this // here for back compat\n\n if (super.id && !Tonic._refIds.includes(super.id)) {\n Tonic._refIds.push(super.id)\n }\n const cc = s => s.replace(/-(.)/g, (_, m) => m.toUpperCase())\n\n for (const { name: _name, value } of this.attributes) {\n const name = cc(_name)\n const p = (this.props as { [key:string]:any })[name] = value\n\n if (/__\\w+__\\w+__/.test(p)) {\n const { 1: root } = p.split('__');\n (this.props as { [key:string]:any })[name] = Tonic._data[root][p]\n } else if (/\\d+__float/.test(p)) {\n (this.props as { [key:string]:any })[name] = parseFloat(p)\n } else if (p === 'null__null') {\n (this.props as { [key:string]:any })[name] = null\n } else if (/\\w+__boolean/.test(p)) {\n (this.props as { [key:string]:any })[name] = p.includes('true')\n } else if (/placehold:\\w+:\\w+__/.test(p)) {\n const { 1: root } = p.split(':');\n (this.props as { [key:string]:any })[name] =\n Tonic._children[root][p][0]\n }\n }\n\n this.props = Object.assign(\n this.defaults(),\n this.props\n )\n\n this._id = this._id || Tonic._createId()\n\n this.willConnect && this.willConnect()\n\n if (!this.isInDocument(this.root)) return\n if (!this.preventRenderOnReconnect) {\n if (!this._source) {\n this._source = this.innerHTML\n } else {\n this.innerHTML = this._source\n }\n const p = this._set(this.root, this.render)\n if (p && p.then) {\n return p.then(() => this.connected && this.connected())\n }\n }\n\n this.connected && this.connected()\n }\n\n isInDocument (target:HTMLElement|ShadowRoot):boolean {\n const root = target.getRootNode()\n return root === document || root.toString() === '[object ShadowRoot]'\n }\n\n disconnectedCallback ():void {\n this.disconnected && this.disconnected()\n delete Tonic._data[this._id]\n delete Tonic._children[this._id]\n }\n}\n\nexport default Tonic\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import morphdom from '@substrate-system/morphdom'\n\nexport class TonicTemplate {\n rawText:string\n unsafe:boolean\n templateStrings?:string[]|TemplateStringsArray|null\n isTonicTemplate:true\n\n constructor (\n rawText,\n templateStrings?:string[]|TemplateStringsArray|null,\n unsafe?:boolean\n ) {\n this.isTonicTemplate = true\n this.unsafe = !!unsafe\n this.rawText = rawText\n this.templateStrings = templateStrings\n }\n\n valueOf () { return this.rawText }\n toString () { return this.rawText }\n}\n\n/**\n * Class Tonic\n *\n * @template {T extends object = Record<string, any>} T Type of the props\n */\nexport abstract class Tonic<\n T extends { [key:string]:any}=Record<string, any>\n> extends window.HTMLElement {\n private static _tags = ''\n private static _refIds:string[] = []\n private static _data = {}\n private static _states = {}\n private static _children = {}\n private static _reg = {}\n private static _stylesheetRegistry:(()=>string)[] = []\n private static _index = 0\n // @ts-expect-error VERSION is injected during build\n static get version () { return VERSION ?? null }\n static get SPREAD () { return /\\.\\.\\.\\s?(__\\w+__\\w+__)/g }\n static get ESC () { return /[\"&'<>`/]/g }\n static get AsyncFunctionGenerator ():AsyncGeneratorFunctionConstructor {\n return (async function * () {\n }.constructor) as AsyncGeneratorFunctionConstructor\n }\n // eslint-disable-next-line\n static get AsyncFunction ():Function {\n return (async function () {}.constructor)\n }\n\n static get MAP () {\n /* eslint-disable object-property-newline, object-property-newline,\n object-curly-newline */\n return { '\"': '"', '&': '&', '\\'': ''', '<': '<',\n '>': '>', '`': '`', '/': '/' }\n }\n\n static ssr\n static nonce\n static _hydrating:boolean = false\n static _ssrState:Record<string, any>|null = null\n\n private _state:any\n declare stylesheet?:()=>string\n declare styles?:()=>string\n props:T\n preventRenderOnReconnect:boolean\n private _id?:string\n pendingReRender?:Promise<this>|null\n declare updated?:((props:Record<string, any>)=>any)\n declare willRender?:(()=>any)\n root?:ShadowRoot|this\n declare willConnect?:()=>any\n private _source?:string\n declare connected?:()=>void\n declare disconnected?:()=>void\n\n private elements:Element[] & { __children__? }\n private nodes:ChildNode[] & { __children__? }\n private _props = Tonic.getPropertyNames(this)\n\n constructor () {\n super()\n const state = Tonic._states[super.id]\n delete Tonic._states[super.id]\n this._state = state || {}\n this.preventRenderOnReconnect = false\n this.props = {} as T\n this.elements = [...this.children]\n this.elements.__children__ = true\n this.nodes = [...this.childNodes]\n this.nodes.__children__ = true\n this._events()\n }\n\n abstract render ():TonicTemplate|Promise<TonicTemplate>\n\n defaults ():Record<string, any> {\n return {}\n }\n\n get isTonicComponent ():true {\n return true\n }\n\n /**\n * Get a namespaced event name, given a non-namespaced string.\n *\n * @example\n * MyElement.event('example') // => my-element:example\n *\n * @param {string} type The name of the event\n * @returns {string} The namespaced event name\n */\n static event (type:string):string {\n return `${this.TAG}:${type}`\n }\n\n /**\n * Get the tag name of this component.\n */\n static get TAG ():string {\n return Tonic.getTagName(this.name)\n }\n\n private static _createId () {\n return `tonic${Tonic._index++}`\n }\n\n private static _normalizeAttrs (o, x = {}) {\n [...o].forEach(o => (x[o.name] = o.value))\n return x\n }\n\n private _checkId () {\n const _id = super.id\n if (!_id) {\n const html = this.outerHTML.replace(this.innerHTML, '...')\n throw new Error(`Component: ${html} has no id`)\n }\n return _id\n }\n\n /**\n * Get the component state property.\n */\n get state () {\n return (this._checkId(), this._state)\n }\n\n set state (newState) {\n this._state = (this._checkId(), newState)\n }\n\n private _events () {\n const hp = Object.getOwnPropertyNames(window.HTMLElement.prototype)\n // this is where we map methods like `handle_click` to event handlers.\n // look at the HTMLElement prototype, and if it is has a method like\n // `onclick`, then add an event listener for 'click'\n for (const p of this._props) {\n if (!p.includes('handle_')) continue\n const evName = p.split('_')[1]\n\n if (hp.indexOf('on' + evName) === -1) continue\n this.addEventListener(evName, this)\n }\n }\n\n private _prop (o) {\n const id = this._id!\n const p = `__${id}__${Tonic._createId()}__`\n Tonic._data[id] = Tonic._data[id] || {}\n Tonic._data[id][p] = o\n return p\n }\n\n private _placehold (r) {\n const id = this._id!\n const ref = `placehold:${id}:${Tonic._createId()}__`\n Tonic._children[id] = Tonic._children[id] || {}\n Tonic._children[id][ref] = r\n return ref\n }\n\n static match (el:HTMLElement, s:string) {\n if (!el.matches) el = el.parentElement!\n return el.matches(s) ? el : el.closest(s)\n }\n\n static getTagName (camelName:string) {\n return camelName.match(/[A-Z][a-z0-9]*/g)!.join('-').toLowerCase()\n }\n\n /**\n * Add all methods to this._props\n */\n static getPropertyNames (proto) {\n const props:string[] = []\n while (proto && proto !== Tonic.prototype) {\n props.push(...Object.getOwnPropertyNames(proto))\n proto = Object.getPrototypeOf(proto)\n }\n return props\n }\n\n /**\n * Add a component. Calls `window.customElements.define` with the\n * component's name.\n *\n * @param {Tonic} c Component to add\n * @param {string} [htmlName] Name of the element, default to the class name\n * @returns {Tonic}\n */\n static add (c, htmlName?:string) {\n const hasValidName = htmlName || (c.name && c.name.length > 1)\n if (!hasValidName) {\n throw Error('Mangling. https://bit.ly/2TkJ6zP')\n }\n\n if (!htmlName) htmlName = Tonic.getTagName(c.name)\n if (!Tonic.ssr && window.customElements.get(htmlName)) {\n throw new Error(`Cannot Tonic.add(${c.name}, '${htmlName}') twice`)\n }\n\n if (!c.prototype || !c.prototype.isTonicComponent) {\n const tmp = { [c.name]: class extends Tonic {\n render () {\n return new TonicTemplate('', null)\n }\n } }[c.name]\n tmp.prototype.render = c\n c = tmp\n }\n\n c.prototype._props = Tonic.getPropertyNames(c.prototype)\n\n Tonic._reg[htmlName] = c\n Tonic._tags = Object.keys(Tonic._reg).join()\n window.customElements.define(htmlName, c as unknown as\n CustomElementConstructor)\n\n if (typeof c.stylesheet === 'function') {\n Tonic.registerStyles(c.stylesheet)\n }\n\n return c\n }\n\n static registerStyles (stylesheetFn:()=>string) {\n if (Tonic._stylesheetRegistry.includes(stylesheetFn)) return\n Tonic._stylesheetRegistry.push(stylesheetFn)\n\n const styleNode = document.createElement('style')\n if (Tonic.nonce) styleNode.setAttribute('nonce', Tonic.nonce)\n styleNode.appendChild(document.createTextNode(stylesheetFn()))\n if (document.head) document.head.appendChild(styleNode)\n }\n\n static escape (s:string):string {\n return s.replace(Tonic.ESC, c => Tonic.MAP[c])\n }\n\n static unsafeRawString (\n s:string,\n templateStrings:string[]\n ):InstanceType<typeof TonicTemplate> {\n return new TonicTemplate(s, templateStrings, true)\n }\n\n /**\n * Emit a regular, non-namespaced event.\n *\n * @param {string} eventName Event name as a string.\n * @param {any} detail Any data to go with the event.\n */\n dispatch (eventName:string, detail:any = null):void {\n const opts = { bubbles: true, detail }\n this.dispatchEvent(new window.CustomEvent(eventName, opts))\n }\n\n /**\n * Emit a namespaced event, using a convention for event names.\n *\n * @example\n * myComponent.emit('test') // => `my-compnent:test`\n *\n * @param {string} type The event type, comes after `:` in event name.\n * @param {string|object|any[]} detail detail for Event constructor\n * @param {{ bubbles?:boolean, cancelable?:boolean }} opts `Cancelable` and\n * `bubbles`\n * @returns {boolean}\n */\n emit (type:string, detail:string|object|any[] = {}, opts:Partial<{\n bubbles:boolean;\n cancelable:boolean\n }> = {}):boolean {\n const namespace = Tonic.getTagName(this.constructor.name)\n const event = new CustomEvent(`${namespace}:${type}`, {\n bubbles: (opts.bubbles === undefined) ? true : opts.bubbles,\n cancelable: (opts.cancelable === undefined) ? true : opts.cancelable,\n detail\n })\n\n return this.dispatchEvent(event)\n }\n\n html (\n strings:string[]|TemplateStringsArray,\n ...values\n ):InstanceType<typeof TonicTemplate> {\n const refs = o => {\n if (o && o.__children__) return this._placehold(o)\n if (o && o.isTonicTemplate) return o.rawText\n switch (Object.prototype.toString.call(o)) {\n case '[object HTMLCollection]':\n case '[object NodeList]': return this._placehold([...o])\n case '[object Array]': {\n if (o.every(x => x.isTonicTemplate && !x.unsafe)) {\n return new TonicTemplate(o.join('\\n'), null, false)\n }\n return this._prop(o)\n }\n case '[object Object]':\n case '[object Function]':\n case '[object AsyncFunction]':\n case '[object Set]':\n case '[object Map]':\n case '[object WeakMap]':\n case '[object File]':\n return this._prop(o)\n case '[object NamedNodeMap]':\n return this._prop(Tonic._normalizeAttrs(o))\n case '[object Number]': return `${o}__float`\n case '[object String]': return Tonic.escape(o)\n case '[object Boolean]': return `${o}__boolean`\n case '[object Null]': return `${o}__null`\n case '[object HTMLElement]':\n return this._placehold([o])\n }\n if (\n typeof o === 'object' && o && o.nodeType === 1 &&\n typeof o.cloneNode === 'function'\n ) {\n return this._placehold([o])\n }\n return o\n }\n\n const out:string[] = []\n for (let i = 0; i < strings.length - 1; i++) {\n out.push(strings[i], refs(values[i]))\n }\n out.push(strings[strings.length - 1])\n\n const htmlStr = out.join('').replace(Tonic.SPREAD, (_, p) => {\n const o = Tonic._data[p.split('__')[1]][p]\n return Object.entries(o).map(([key, value]) => {\n const k = key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n if (value === true) return k\n else if (value) return `${k}=\"${Tonic.escape(String(value))}\"`\n else return ''\n }).filter(Boolean).join(' ')\n })\n // Process type markers in template content\n .replace(/(\\d+(?:\\.\\d+)?)__float/g, '$1')\n .replace(/(true|false)__boolean/g, '$1')\n .replace(/null__null/g, 'null')\n\n return new TonicTemplate(htmlStr, strings, false)\n }\n\n scheduleReRender (oldProps:any):Promise<this> {\n if (this.pendingReRender) return this.pendingReRender\n\n this.pendingReRender = new Promise(resolve => setTimeout(() => {\n if (!this.isInDocument(this.shadowRoot || this)) return\n const p = this._set(this.shadowRoot || this, this.render)\n this.pendingReRender = null\n\n if (p && p.then) {\n return p.then(() => {\n this.updated && this.updated(oldProps)\n resolve(this)\n })\n }\n\n this.updated && this.updated(oldProps)\n resolve(this)\n }, 0))\n\n return this.pendingReRender\n }\n\n /**\n * Update the view\n */\n reRender (o:T|((props:T)=>T) = this.props):Promise<this> {\n const oldProps = { ...this.props }\n this.props = typeof o === 'function' ? (o as (props:T)=>T)(oldProps) : o\n return this.scheduleReRender(oldProps)\n }\n\n /**\n * If there is a method with the same name as the event type,\n * then call the method.\n * @see {@link https://gomakethings.com/the-handleevent-method-is-the-absolute-best-way-to-handle-events-in-web-components/#what-is-the-handleevent-method What is the handleEvent() method?}\n */\n handleEvent (ev:Event):void {\n this['handle_' + ev.type] && this['handle_' + ev.type](ev)\n }\n\n private _drainIterator (target, iterator) {\n return iterator.next().then((result) => {\n this._set(target, null, result.value)\n if (result.done) return\n return this._drainIterator(target, iterator)\n })\n }\n\n /**\n * _set\n * @param {Element|InstanceType<typeof Tonic>|ShadowRoot} target\n * @param {()=>any} render\n * @param {string} content\n * @returns {Promise<void>|void}\n * @private\n */\n private _set (target, render, content = ''):Promise<void>|void {\n this.willRender && this.willRender()\n for (const node of target.querySelectorAll(Tonic._tags)) {\n if (!node.isTonicComponent) continue\n\n const id = node.getAttribute('id')\n if (!id || !Tonic._refIds.includes(id)) continue\n Tonic._states[id] = node.state\n }\n\n if (render instanceof Tonic.AsyncFunction) {\n return ((render as (...args:any)=>any)\n .call(this, this.html, this.props)\n .then(content => this._apply(target, content))\n )\n } else if (render instanceof Tonic.AsyncFunctionGenerator) {\n return this._drainIterator(\n target,\n (render as AsyncGeneratorFunction).call(this))\n } else if (render === null) {\n this._apply(target, content)\n } else if (render instanceof Function) {\n this._apply(target, render.call(this, this.html, this.props) || '')\n }\n }\n\n private _apply (target, content) {\n if (content && content.isTonicTemplate) {\n content = content.rawText\n } else if (typeof content === 'string') {\n content = Tonic.escape(content)\n }\n\n if (typeof content === 'string') {\n if (this.stylesheet) {\n content = `<style nonce=${Tonic.nonce || ''}>${this.stylesheet()}</style>${content}`\n }\n\n // Check if we should use morphdom for DOM state\n // preservation (cursor position, selection, focus)\n const hasFormElements = target.querySelector && (\n target.querySelector('input') ||\n target.querySelector('textarea') ||\n target.querySelector('select')\n )\n\n const shouldUseMorphdom = (\n hasFormElements &&\n document.activeElement &&\n (\n target.contains(document.activeElement) ||\n target === document.activeElement\n )\n )\n\n if (shouldUseMorphdom) {\n // Use morphdom to preserve DOM state\n const tempContainer =\n document.createElement('div')\n tempContainer.innerHTML = content\n\n morphdom(target, tempContainer, {\n childrenOnly: true,\n onBeforeElUpdated: (fromEl, toEl) => {\n if (\n fromEl.isEqualNode &&\n fromEl.isEqualNode(toEl)\n ) {\n return false\n }\n\n // For inputs, preserve value\n // and selection\n if (\n fromEl.tagName === 'INPUT' &&\n toEl.tagName === 'INPUT'\n ) {\n const fromInput =\n fromEl as HTMLInputElement\n const toInput =\n toEl as HTMLInputElement\n\n if (fromInput.value !== '') {\n toInput.value =\n fromInput.value\n }\n\n if (\n document.activeElement ===\n fromInput\n ) {\n toInput.setAttribute(\n 'data-preserve-focus',\n 'true')\n toInput.setAttribute(\n 'data-selection-start',\n String(\n fromInput\n .selectionStart\n || 0\n ))\n toInput.setAttribute(\n 'data-selection-end',\n String(\n fromInput\n .selectionEnd\n || 0\n ))\n }\n }\n\n // For textareas, preserve value\n // and selection\n if (\n fromEl.tagName === 'TEXTAREA' &&\n toEl.tagName === 'TEXTAREA'\n ) {\n const fromTa =\n fromEl as HTMLTextAreaElement\n const toTa =\n toEl as HTMLTextAreaElement\n\n if (fromTa.value !== '') {\n toTa.value = fromTa.value\n }\n\n if (\n document.activeElement ===\n fromTa\n ) {\n toTa.setAttribute(\n 'data-preserve-focus',\n 'true')\n toTa.setAttribute(\n 'data-selection-start',\n String(\n fromTa\n .selectionStart\n || 0\n ))\n toTa.setAttribute(\n 'data-selection-end',\n String(\n fromTa\n .selectionEnd\n || 0\n ))\n }\n }\n\n return true\n },\n\n onElUpdated: (el) => {\n if (\n !el.hasAttribute(\n 'data-preserve-focus'\n )\n ) return\n\n const startPos = parseInt(\n el.getAttribute(\n 'data-selection-start'\n ) || '0',\n 10\n )\n const endPos = parseInt(\n el.getAttribute(\n 'data-selection-end'\n ) || '0',\n 10\n )\n\n el.removeAttribute(\n 'data-preserve-focus')\n el.removeAttribute(\n 'data-selection-start')\n el.removeAttribute(\n 'data-selection-end')\n\n el.focus()\n if ('setSelectionRange' in el) {\n (el as\n HTMLInputElement |\n HTMLTextAreaElement\n ).setSelectionRange(\n startPos,\n endPos\n )\n }\n }\n })\n } else {\n // Save user-modified form values by\n // position so they survive innerHTML\n // replacement. Only save when the user\n // changed the value (value !== default).\n type FormEl = HTMLInputElement |\n HTMLTextAreaElement |\n HTMLSelectElement\n const selector =\n 'input, textarea, select'\n const saved:\n { v:string; c:boolean; dirty:boolean }[]\n = []\n if (hasFormElements) {\n const els = target.querySelectorAll(\n selector\n ) as NodeListOf<FormEl>\n for (const el of els) {\n const inp = el as HTMLInputElement\n const isCheck = (\n inp.type === 'checkbox' ||\n inp.type === 'radio'\n )\n saved.push({\n v: el.value,\n c: inp.checked,\n dirty: isCheck ?\n inp.checked !==\n inp.defaultChecked :\n el.value !==\n (el as HTMLInputElement)\n .defaultValue\n })\n }\n }\n\n target.innerHTML = content\n\n if (saved.length) {\n const els = target.querySelectorAll(\n selector\n ) as NodeListOf<FormEl>\n for (\n let i = 0;\n i < Math.min(\n saved.length,\n els.length\n );\n i++\n ) {\n if (!saved[i].dirty) continue\n const el = els[i]\n const type =\n (el as HTMLInputElement).type\n if (\n type === 'checkbox' ||\n type === 'radio'\n ) {\n (el as HTMLInputElement)\n .checked = saved[i].c\n } else {\n el.value = saved[i].v\n }\n }\n }\n }\n\n if (this.styles) {\n const styles = this.styles()\n for (const node of target.querySelectorAll('[styles]')) {\n for (const s of node.getAttribute('styles').split(/\\s+/)) {\n Object.assign(node.style, styles[s.trim()])\n }\n }\n }\n\n const children = Tonic._children[this._id!] || {}\n\n const walk = (node, fn) => {\n if (node.nodeType === 3) {\n const id = node.textContent.trim()\n if (children[id]) fn(node, children[id], id)\n }\n\n const childNodes = node.childNodes\n if (!childNodes) return\n\n for (let i = 0; i < childNodes.length; i++) {\n walk(childNodes[i], fn)\n }\n }\n\n walk(target, (node, children, id) => {\n for (const child of children) {\n node.parentNode.insertBefore(child, node)\n }\n delete Tonic._children[this._id!][id]\n node.parentNode.removeChild(node)\n })\n } else {\n target.innerHTML = ''\n target.appendChild(content.cloneNode(true))\n }\n }\n\n connectedCallback () {\n this.root = this.shadowRoot || this // here for back compat\n\n if (super.id && !Tonic._refIds.includes(super.id)) {\n Tonic._refIds.push(super.id)\n }\n const cc = s => s.replace(/-(.)/g, (_, m) => m.toUpperCase())\n\n for (const { name: _name, value } of this.attributes) {\n const name = cc(_name)\n const p = (this.props as { [key:string]:any })[name] = value\n\n if (/__\\w+__\\w+__/.test(p)) {\n const { 1: root } = p.split('__');\n (this.props as { [key:string]:any })[name] = Tonic._data[root][p]\n } else if (/\\d+__float/.test(p)) {\n (this.props as { [key:string]:any })[name] = parseFloat(p)\n } else if (p === 'null__null') {\n (this.props as { [key:string]:any })[name] = null\n } else if (/\\w+__boolean/.test(p)) {\n (this.props as { [key:string]:any })[name] = p.includes('true')\n } else if (/placehold:\\w+:\\w+__/.test(p)) {\n const { 1: root } = p.split(':');\n (this.props as { [key:string]:any })[name] =\n Tonic._children[root][p][0]\n }\n }\n\n this.props = Object.assign(\n this.defaults(),\n this.props\n )\n\n this._id = this._id || Tonic._createId()\n\n this.willConnect && this.willConnect()\n\n if (!this.isInDocument(this.root)) return\n\n if (Tonic._hydrating) {\n if (super.id && Tonic._ssrState?.[super.id]) {\n this.props = Object.assign(\n this.props,\n Tonic._ssrState[super.id]\n )\n }\n this._source = this.innerHTML\n this.connected && this.connected()\n return\n }\n\n if (!this.preventRenderOnReconnect) {\n if (!this._source) {\n this._source = this.innerHTML\n } else {\n this.innerHTML = this._source\n }\n const p = this._set(this.root, this.render)\n if (p && p.then) {\n return p.then(() => this.connected && this.connected())\n }\n }\n\n this.connected && this.connected()\n }\n\n isInDocument (target:HTMLElement|ShadowRoot):boolean {\n const root = target.getRootNode()\n return root === document || root.toString() === '[object ShadowRoot]'\n }\n\n disconnectedCallback ():void {\n this.disconnected && this.disconnected()\n delete Tonic._data[this._id!]\n delete Tonic._children[this._id!]\n }\n}\n\nexport default Tonic\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["o", "content", "children"]
|
|
7
7
|
}
|
package/dist/meta.json
CHANGED
|
@@ -1,22 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"inputs": {
|
|
3
|
+
"src/hydrate.ts": {
|
|
4
|
+
"bytes": 1390,
|
|
5
|
+
"imports": [],
|
|
6
|
+
"format": "esm"
|
|
7
|
+
},
|
|
3
8
|
"src/index.ts": {
|
|
4
|
-
"bytes":
|
|
9
|
+
"bytes": 28182,
|
|
5
10
|
"imports": [],
|
|
6
11
|
"format": "esm"
|
|
7
12
|
},
|
|
8
13
|
"src/render-to-string.ts": {
|
|
9
|
-
"bytes":
|
|
14
|
+
"bytes": 9126,
|
|
10
15
|
"imports": [],
|
|
11
16
|
"format": "esm"
|
|
12
17
|
}
|
|
13
18
|
},
|
|
14
19
|
"outputs": {
|
|
20
|
+
"dist/hydrate.mjs.map": {
|
|
21
|
+
"imports": [],
|
|
22
|
+
"exports": [],
|
|
23
|
+
"inputs": {},
|
|
24
|
+
"bytes": 1787
|
|
25
|
+
},
|
|
26
|
+
"dist/hydrate.mjs": {
|
|
27
|
+
"imports": [
|
|
28
|
+
{
|
|
29
|
+
"path": "./index.js",
|
|
30
|
+
"kind": "import-statement",
|
|
31
|
+
"external": true
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"exports": [
|
|
35
|
+
"hydrate"
|
|
36
|
+
],
|
|
37
|
+
"entryPoint": "src/hydrate.ts",
|
|
38
|
+
"inputs": {
|
|
39
|
+
"src/hydrate.ts": {
|
|
40
|
+
"bytesInOutput": 380
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"bytes": 568
|
|
44
|
+
},
|
|
15
45
|
"dist/index.mjs.map": {
|
|
16
46
|
"imports": [],
|
|
17
47
|
"exports": [],
|
|
18
48
|
"inputs": {},
|
|
19
|
-
"bytes":
|
|
49
|
+
"bytes": 42588
|
|
20
50
|
},
|
|
21
51
|
"dist/index.mjs": {
|
|
22
52
|
"imports": [
|
|
@@ -34,16 +64,16 @@
|
|
|
34
64
|
"entryPoint": "src/index.ts",
|
|
35
65
|
"inputs": {
|
|
36
66
|
"src/index.ts": {
|
|
37
|
-
"bytesInOutput":
|
|
67
|
+
"bytesInOutput": 19837
|
|
38
68
|
}
|
|
39
69
|
},
|
|
40
|
-
"bytes":
|
|
70
|
+
"bytes": 20066
|
|
41
71
|
},
|
|
42
72
|
"dist/render-to-string.mjs.map": {
|
|
43
73
|
"imports": [],
|
|
44
74
|
"exports": [],
|
|
45
75
|
"inputs": {},
|
|
46
|
-
"bytes":
|
|
76
|
+
"bytes": 12780
|
|
47
77
|
},
|
|
48
78
|
"dist/render-to-string.mjs": {
|
|
49
79
|
"imports": [
|
|
@@ -54,15 +84,17 @@
|
|
|
54
84
|
}
|
|
55
85
|
],
|
|
56
86
|
"exports": [
|
|
57
|
-
"
|
|
87
|
+
"getHydrationScript",
|
|
88
|
+
"render",
|
|
89
|
+
"toHtml"
|
|
58
90
|
],
|
|
59
91
|
"entryPoint": "src/render-to-string.ts",
|
|
60
92
|
"inputs": {
|
|
61
93
|
"src/render-to-string.ts": {
|
|
62
|
-
"bytesInOutput":
|
|
94
|
+
"bytesInOutput": 4574
|
|
63
95
|
}
|
|
64
96
|
},
|
|
65
|
-
"bytes":
|
|
97
|
+
"bytes": 4802
|
|
66
98
|
}
|
|
67
99
|
}
|
|
68
100
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -28,7 +29,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
30
|
var render_to_string_exports = {};
|
|
30
31
|
__export(render_to_string_exports, {
|
|
31
|
-
|
|
32
|
+
getHydrationScript: () => getHydrationScript,
|
|
33
|
+
render: () => render,
|
|
34
|
+
toHtml: () => toHtml
|
|
32
35
|
});
|
|
33
36
|
module.exports = __toCommonJS(render_to_string_exports);
|
|
34
37
|
var parse5 = __toESM(require("parse5"), 1);
|
|
@@ -78,6 +81,47 @@ async function render(component) {
|
|
|
78
81
|
return parse5.serialize(fragment);
|
|
79
82
|
}
|
|
80
83
|
__name(render, "render");
|
|
84
|
+
function escapeAttr(s) {
|
|
85
|
+
return s.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
86
|
+
}
|
|
87
|
+
__name(escapeAttr, "escapeAttr");
|
|
88
|
+
function getTagName(name) {
|
|
89
|
+
return name.match(/[A-Z][a-z0-9]*/g).join("-").toLowerCase();
|
|
90
|
+
}
|
|
91
|
+
__name(getTagName, "getTagName");
|
|
92
|
+
function propsToAttrs(props, id) {
|
|
93
|
+
const parts = [];
|
|
94
|
+
if (id) parts.push(`id="${escapeAttr(id)}"`);
|
|
95
|
+
for (const [key, value] of Object.entries(props)) {
|
|
96
|
+
const attr = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
97
|
+
if (value === null) {
|
|
98
|
+
parts.push(`${attr}="null__null"`);
|
|
99
|
+
} else if (typeof value === "boolean") {
|
|
100
|
+
parts.push(`${attr}="${value}__boolean"`);
|
|
101
|
+
} else if (typeof value === "number") {
|
|
102
|
+
parts.push(`${attr}="${value}__float"`);
|
|
103
|
+
} else if (typeof value === "string") {
|
|
104
|
+
parts.push(`${attr}="${escapeAttr(value)}"`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return parts.length ? " " + parts.join(" ") : "";
|
|
108
|
+
}
|
|
109
|
+
__name(propsToAttrs, "propsToAttrs");
|
|
110
|
+
function getHydrationScript(state) {
|
|
111
|
+
const json = JSON.stringify(state);
|
|
112
|
+
return '<script type="application/json" data-tonic-ssr>' + json + "<\/script>";
|
|
113
|
+
}
|
|
114
|
+
__name(getHydrationScript, "getHydrationScript");
|
|
115
|
+
function toHtml(component, content, opts) {
|
|
116
|
+
const tag = opts?.tagName || getTagName(component.constructor.name);
|
|
117
|
+
const attrs = propsToAttrs(component.props, opts?.id);
|
|
118
|
+
let html = `<${tag}${attrs}>${content}</${tag}>`;
|
|
119
|
+
if (opts?.state) {
|
|
120
|
+
html += "\n" + getHydrationScript(opts.state);
|
|
121
|
+
}
|
|
122
|
+
return html;
|
|
123
|
+
}
|
|
124
|
+
__name(toHtml, "toHtml");
|
|
81
125
|
async function visitNode(node, registry) {
|
|
82
126
|
if (node.tagName && registry[node.tagName]) {
|
|
83
127
|
const ComponentClass = registry[node.tagName];
|
|
@@ -92,6 +136,30 @@ async function visitNode(node, registry) {
|
|
|
92
136
|
} else {
|
|
93
137
|
instance.props = instance.defaults?.() || {};
|
|
94
138
|
}
|
|
139
|
+
if (node.childNodes && node.childNodes.length > 0) {
|
|
140
|
+
const childHtml2 = parse5.serialize(
|
|
141
|
+
{ childNodes: node.childNodes }
|
|
142
|
+
);
|
|
143
|
+
if (childHtml2.trim()) {
|
|
144
|
+
const arr = [{
|
|
145
|
+
isTonicTemplate: true,
|
|
146
|
+
unsafe: false,
|
|
147
|
+
rawText: childHtml2,
|
|
148
|
+
toString() {
|
|
149
|
+
return childHtml2;
|
|
150
|
+
},
|
|
151
|
+
valueOf() {
|
|
152
|
+
return childHtml2;
|
|
153
|
+
}
|
|
154
|
+
}];
|
|
155
|
+
Object.defineProperty(instance, "children", {
|
|
156
|
+
get() {
|
|
157
|
+
return arr;
|
|
158
|
+
},
|
|
159
|
+
configurable: true
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
95
163
|
const template = await Promise.resolve(instance.render());
|
|
96
164
|
const childHtml = template.rawText;
|
|
97
165
|
const childFragment = parse5.parseFragment(childHtml);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/render-to-string.ts"],
|
|
4
|
-
"sourcesContent": ["import * as parse5 from 'parse5'\nimport type { Tonic, TonicTemplate } from './index.js'\n\n// Set up minimal globals needed for Tonic SSR in Node.js\n// Only set these up if we're in a Node.js environment (no window)\nif (typeof window === 'undefined') {\n (global as any).window = {\n HTMLElement: class HTMLElement {\n children:any[] = []\n childNodes:any[] = []\n attributes:any[] = []\n\n getRootNode () {\n return this\n }\n\n addEventListener () {}\n dispatchEvent () {}\n },\n customElements: {\n define: () => {},\n get: () => null\n },\n CustomEvent: class CustomEvent {}\n }\n}\n\n/**\n * Render a Tonic component instance to an HTML string.\n *\n * This function takes a Tonic component instance, calls its render method,\n * and recursively processes any nested Tonic components to produce a complete\n * HTML string suitable for server-side rendering.\n *\n * @param component - A Tonic component instance to render\n * @returns A promise that resolves to an HTML string\n *\n * @example\n * ```ts\n * import { render } from '@substrate-system/tonic/render-to-string'\n * import { MyComponent } from './components'\n *\n * const component = new MyComponent()\n * const html = await render(component)\n * console.log(html) // <div>...</div>\n * ```\n */\nexport async function render (\n component:InstanceType<typeof Tonic>\n):Promise<string> {\n // Get the registry of all registered Tonic components\n // @ts-expect-error _reg is private but we need it for SSR\n const registry = component.constructor._reg || {}\n\n // Initialize props with defaults if not already set\n if (!component.props || Object.keys(component.props).length === 0) {\n component.props = component.defaults?.() || {}\n } else {\n // Merge defaults with existing props\n component.props = Object.assign(component.defaults?.() || {}, component.props)\n }\n\n // Call the component's render method to get the template\n const template:TonicTemplate|Promise<TonicTemplate> = component.render()\n const resolvedTemplate = await Promise.resolve(template)\n\n // Extract the raw HTML string from the TonicTemplate\n const htmlString = resolvedTemplate.rawText\n\n // Parse the HTML string into a parse5 document fragment\n const fragment = parse5.parseFragment(htmlString)\n\n // Recursively visit and render nested Tonic components\n await visitNode(fragment, registry)\n\n // Serialize the document fragment back to an HTML string\n return parse5.serialize(fragment)\n}\n\n/**\n * Recursively visit nodes in the parse5 AST and render any Tonic components
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import * as parse5 from 'parse5'\nimport type { Tonic, TonicTemplate } from './index.js'\n\n// Set up minimal globals needed for Tonic SSR in Node.js\n// Only set these up if we're in a Node.js environment (no window)\nif (typeof window === 'undefined') {\n // @ts-expect-error its ok\n (global as any).window = {\n HTMLElement: class HTMLElement {\n children:any[] = []\n childNodes:any[] = []\n attributes:any[] = []\n\n getRootNode () {\n return this\n }\n\n addEventListener () {}\n dispatchEvent () {}\n },\n customElements: {\n define: () => {},\n get: () => null\n },\n CustomEvent: class CustomEvent {}\n }\n}\n\n/**\n * Render a Tonic component instance to an HTML string.\n *\n * This function takes a Tonic component instance, calls its render method,\n * and recursively processes any nested Tonic components to produce a complete\n * HTML string suitable for server-side rendering.\n *\n * @param component - A Tonic component instance to render\n * @returns A promise that resolves to an HTML string\n *\n * @example\n * ```ts\n * import { render } from '@substrate-system/tonic/render-to-string'\n * import { MyComponent } from './components'\n *\n * const component = new MyComponent()\n * const html = await render(component)\n * console.log(html) // <div>...</div>\n * ```\n */\nexport async function render (\n component:InstanceType<typeof Tonic>\n):Promise<string> {\n // Get the registry of all registered Tonic components\n // @ts-expect-error _reg is private but we need it for SSR\n const registry = component.constructor._reg || {}\n\n // Initialize props with defaults if not already set\n if (!component.props || Object.keys(component.props).length === 0) {\n component.props = component.defaults?.() || {}\n } else {\n // Merge defaults with existing props\n component.props = Object.assign(component.defaults?.() || {}, component.props)\n }\n\n // Call the component's render method to get the template\n const template:TonicTemplate|Promise<TonicTemplate> = component.render()\n const resolvedTemplate = await Promise.resolve(template)\n\n // Extract the raw HTML string from the TonicTemplate\n const htmlString = resolvedTemplate.rawText\n\n // Parse the HTML string into a parse5 document fragment\n const fragment = parse5.parseFragment(htmlString)\n\n // Recursively visit and render nested Tonic components\n await visitNode(fragment, registry)\n\n // Serialize the document fragment back to an HTML string\n return parse5.serialize(fragment)\n}\n\nfunction escapeAttr (s:string):string {\n return s\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n}\n\nfunction getTagName (name:string):string {\n return name.match(/[A-Z][a-z0-9]*/g)!\n .join('-').toLowerCase()\n}\n\n/**\n * Encode component props as HTML attribute string.\n *\n * Simple types (string, number, boolean, null) are encoded\n * using Tonic's type marker conventions. Complex types\n * (objects, arrays, functions) are skipped -- put those in\n * the `state` JSON instead.\n */\nfunction propsToAttrs (\n props:Record<string, any>,\n id?:string\n):string {\n const parts:string[] = []\n\n if (id) parts.push(`id=\"${escapeAttr(id)}\"`)\n\n for (const [key, value] of Object.entries(props)) {\n const attr = key\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .toLowerCase()\n\n if (value === null) {\n parts.push(`${attr}=\"null__null\"`)\n } else if (typeof value === 'boolean') {\n parts.push(`${attr}=\"${value}__boolean\"`)\n } else if (typeof value === 'number') {\n parts.push(`${attr}=\"${value}__float\"`)\n } else if (typeof value === 'string') {\n parts.push(`${attr}=\"${escapeAttr(value)}\"`)\n }\n // Complex types (objects, arrays, functions) are\n // skipped -- they belong in the state JSON.\n }\n\n return parts.length ? ' ' + parts.join(' ') : ''\n}\n\n/**\n * Generate a `<script>` tag containing serialized hydration\n * state.\n *\n * Embed this in your HTML page so the client-side `hydrate`\n * function can read it. The state object keys should be\n * component `id` attributes, mapping to the props for that\n * component.\n *\n * @example\n * ```ts\n * const script = getHydrationScript({\n * app: { title: 'Hello', items: [1, 2, 3] }\n * })\n * // <script type=\"application/json\" data-tonic-ssr>\n * // {\"app\":{\"title\":\"Hello\",\"items\":[1,2,3]}}\n * // </script>\n * ```\n */\nexport function getHydrationScript (\n state:Record<string, any>\n):string {\n const json = JSON.stringify(state)\n return '<script type=\"application/json\" ' +\n 'data-tonic-ssr>' + json + '</script>'\n}\n\n/**\n * Wrap rendered component content in its custom element tag,\n * with props encoded as attributes.\n *\n * Use this to build a hydratable HTML page from\n * server-rendered content.\n *\n * @param component The component instance that was rendered\n * @param content The HTML string from `render(component)`\n * @param opts.id Element `id` attribute (required for\n * state transfer via hydration)\n * @param opts.tagName Override the tag name (defaults to\n * the class name converted to kebab-case)\n * @param opts.state Hydration state -- if provided, a\n * `<script data-tonic-ssr>` tag is\n * appended with the serialized JSON\n *\n * @example\n * ```ts\n * import { render, toHtml } from\n * '@substrate-system/tonic/render-to-string'\n *\n * const app = new MyApp()\n * app.props = { title: 'Hello', items: [1, 2, 3] }\n * const content = await render(app)\n *\n * const html = toHtml(app, content, {\n * id: 'app',\n * state: {\n * app: { title: 'Hello', items: [1, 2, 3] }\n * }\n * })\n * ```\n */\nexport function toHtml (\n component:InstanceType<typeof Tonic>,\n content:string,\n opts?:{\n id?:string;\n tagName?:string;\n state?:Record<string, any>;\n }\n):string {\n const tag = opts?.tagName ||\n getTagName(component.constructor.name)\n\n const attrs = propsToAttrs(component.props, opts?.id)\n\n let html = `<${tag}${attrs}>${content}</${tag}>`\n\n if (opts?.state) {\n html += '\\n' + getHydrationScript(opts.state)\n }\n\n return html\n}\n\n/**\n * Recursively visit nodes in the parse5 AST\n * and render any Tonic components.\n */\nasync function visitNode (node:any, registry:Record<string, any>):Promise<void> {\n // Check if this node is a registered Tonic component\n if (node.tagName && registry[node.tagName]) {\n const ComponentClass = registry[node.tagName]\n\n // Create an instance of the component\n const instance = new ComponentClass()\n\n // Set up the component's attributes/props from the node\n if (node.attrs && node.attrs.length > 0) {\n const props = {}\n for (const attr of node.attrs) {\n // Convert kebab-case attribute names to camelCase prop names\n const propName = attr.name.replace(/-(.)/g, (_, char) => char.toUpperCase())\n props[propName] = attr.value\n }\n instance.props = Object.assign(instance.defaults?.() || {}, props)\n } else {\n instance.props = instance.defaults?.() || {}\n }\n\n // Pass existing child content so this.children works.\n // Must use defineProperty because in browsers\n // Element.children is a read-only getter.\n if (node.childNodes && node.childNodes.length > 0) {\n const childHtml = parse5.serialize(\n { childNodes: node.childNodes } as any\n )\n if (childHtml.trim()) {\n const arr = [{\n isTonicTemplate: true,\n unsafe: false,\n rawText: childHtml,\n toString () { return childHtml },\n valueOf () { return childHtml },\n }]\n Object.defineProperty(instance, 'children', {\n get () { return arr },\n configurable: true,\n })\n }\n }\n\n // Render the component\n const template = await Promise.resolve(instance.render())\n const childHtml = template.rawText\n\n // Parse the rendered HTML\n const childFragment = parse5.parseFragment(childHtml)\n\n // Recursively visit children of the rendered component\n for (const child of childFragment.childNodes) {\n if ('childNodes' in child && child.childNodes) {\n await visitNode(child, registry)\n }\n }\n\n // Replace the component tag with its rendered content\n node.childNodes = childFragment.childNodes\n }\n\n // Visit all child nodes\n if ('childNodes' in node && node.childNodes) {\n for (const child of node.childNodes) {\n await visitNode(child, registry)\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["childHtml"]
|
|
7
7
|
}
|
|
@@ -20,3 +20,63 @@ import type { Tonic } from './index.js';
|
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
export declare function render(component: InstanceType<typeof Tonic>): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Generate a `<script>` tag containing serialized hydration
|
|
25
|
+
* state.
|
|
26
|
+
*
|
|
27
|
+
* Embed this in your HTML page so the client-side `hydrate`
|
|
28
|
+
* function can read it. The state object keys should be
|
|
29
|
+
* component `id` attributes, mapping to the props for that
|
|
30
|
+
* component.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const script = getHydrationScript({
|
|
35
|
+
* app: { title: 'Hello', items: [1, 2, 3] }
|
|
36
|
+
* })
|
|
37
|
+
* // <script type="application/json" data-tonic-ssr>
|
|
38
|
+
* // {"app":{"title":"Hello","items":[1,2,3]}}
|
|
39
|
+
* // </script>
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function getHydrationScript(state: Record<string, any>): string;
|
|
43
|
+
/**
|
|
44
|
+
* Wrap rendered component content in its custom element tag,
|
|
45
|
+
* with props encoded as attributes.
|
|
46
|
+
*
|
|
47
|
+
* Use this to build a hydratable HTML page from
|
|
48
|
+
* server-rendered content.
|
|
49
|
+
*
|
|
50
|
+
* @param component The component instance that was rendered
|
|
51
|
+
* @param content The HTML string from `render(component)`
|
|
52
|
+
* @param opts.id Element `id` attribute (required for
|
|
53
|
+
* state transfer via hydration)
|
|
54
|
+
* @param opts.tagName Override the tag name (defaults to
|
|
55
|
+
* the class name converted to kebab-case)
|
|
56
|
+
* @param opts.state Hydration state -- if provided, a
|
|
57
|
+
* `<script data-tonic-ssr>` tag is
|
|
58
|
+
* appended with the serialized JSON
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { render, toHtml } from
|
|
63
|
+
* '@substrate-system/tonic/render-to-string'
|
|
64
|
+
*
|
|
65
|
+
* const app = new MyApp()
|
|
66
|
+
* app.props = { title: 'Hello', items: [1, 2, 3] }
|
|
67
|
+
* const content = await render(app)
|
|
68
|
+
*
|
|
69
|
+
* const html = toHtml(app, content, {
|
|
70
|
+
* id: 'app',
|
|
71
|
+
* state: {
|
|
72
|
+
* app: { title: 'Hello', items: [1, 2, 3] }
|
|
73
|
+
* }
|
|
74
|
+
* })
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function toHtml(component: InstanceType<typeof Tonic>, content: string, opts?: {
|
|
78
|
+
id?: string;
|
|
79
|
+
tagName?: string;
|
|
80
|
+
state?: Record<string, any>;
|
|
81
|
+
}): string;
|
|
82
|
+
//# sourceMappingURL=render-to-string.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-to-string.d.ts","sourceRoot":"","sources":["../src/render-to-string.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,YAAY,CAAA;AA2BtD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,MAAM,CACxB,SAAS,EAAC,YAAY,CAAC,OAAO,KAAK,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CA4BhB;AAqDD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC3B,MAAM,CAIP;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,MAAM,CAClB,SAAS,EAAC,YAAY,CAAC,OAAO,KAAK,CAAC,EACpC,OAAO,EAAC,MAAM,EACd,IAAI,CAAC,EAAC;IACF,EAAE,CAAC,EAAC,MAAM,CAAC;IACX,OAAO,CAAC,EAAC,MAAM,CAAC;IAChB,KAAK,CAAC,EAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B,GACH,MAAM,CAaP"}
|
package/dist/render-to-string.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
4
|
import * as parse5 from "parse5";
|
|
@@ -47,6 +48,47 @@ export async function render(component) {
|
|
|
47
48
|
return parse5.serialize(fragment);
|
|
48
49
|
}
|
|
49
50
|
__name(render, "render");
|
|
51
|
+
function escapeAttr(s) {
|
|
52
|
+
return s.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
53
|
+
}
|
|
54
|
+
__name(escapeAttr, "escapeAttr");
|
|
55
|
+
function getTagName(name) {
|
|
56
|
+
return name.match(/[A-Z][a-z0-9]*/g).join("-").toLowerCase();
|
|
57
|
+
}
|
|
58
|
+
__name(getTagName, "getTagName");
|
|
59
|
+
function propsToAttrs(props, id) {
|
|
60
|
+
const parts = [];
|
|
61
|
+
if (id) parts.push(`id="${escapeAttr(id)}"`);
|
|
62
|
+
for (const [key, value] of Object.entries(props)) {
|
|
63
|
+
const attr = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
64
|
+
if (value === null) {
|
|
65
|
+
parts.push(`${attr}="null__null"`);
|
|
66
|
+
} else if (typeof value === "boolean") {
|
|
67
|
+
parts.push(`${attr}="${value}__boolean"`);
|
|
68
|
+
} else if (typeof value === "number") {
|
|
69
|
+
parts.push(`${attr}="${value}__float"`);
|
|
70
|
+
} else if (typeof value === "string") {
|
|
71
|
+
parts.push(`${attr}="${escapeAttr(value)}"`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return parts.length ? " " + parts.join(" ") : "";
|
|
75
|
+
}
|
|
76
|
+
__name(propsToAttrs, "propsToAttrs");
|
|
77
|
+
export function getHydrationScript(state) {
|
|
78
|
+
const json = JSON.stringify(state);
|
|
79
|
+
return '<script type="application/json" data-tonic-ssr>' + json + "<\/script>";
|
|
80
|
+
}
|
|
81
|
+
__name(getHydrationScript, "getHydrationScript");
|
|
82
|
+
export function toHtml(component, content, opts) {
|
|
83
|
+
const tag = opts?.tagName || getTagName(component.constructor.name);
|
|
84
|
+
const attrs = propsToAttrs(component.props, opts?.id);
|
|
85
|
+
let html = `<${tag}${attrs}>${content}</${tag}>`;
|
|
86
|
+
if (opts?.state) {
|
|
87
|
+
html += "\n" + getHydrationScript(opts.state);
|
|
88
|
+
}
|
|
89
|
+
return html;
|
|
90
|
+
}
|
|
91
|
+
__name(toHtml, "toHtml");
|
|
50
92
|
async function visitNode(node, registry) {
|
|
51
93
|
if (node.tagName && registry[node.tagName]) {
|
|
52
94
|
const ComponentClass = registry[node.tagName];
|
|
@@ -61,6 +103,30 @@ async function visitNode(node, registry) {
|
|
|
61
103
|
} else {
|
|
62
104
|
instance.props = instance.defaults?.() || {};
|
|
63
105
|
}
|
|
106
|
+
if (node.childNodes && node.childNodes.length > 0) {
|
|
107
|
+
const childHtml2 = parse5.serialize(
|
|
108
|
+
{ childNodes: node.childNodes }
|
|
109
|
+
);
|
|
110
|
+
if (childHtml2.trim()) {
|
|
111
|
+
const arr = [{
|
|
112
|
+
isTonicTemplate: true,
|
|
113
|
+
unsafe: false,
|
|
114
|
+
rawText: childHtml2,
|
|
115
|
+
toString() {
|
|
116
|
+
return childHtml2;
|
|
117
|
+
},
|
|
118
|
+
valueOf() {
|
|
119
|
+
return childHtml2;
|
|
120
|
+
}
|
|
121
|
+
}];
|
|
122
|
+
Object.defineProperty(instance, "children", {
|
|
123
|
+
get() {
|
|
124
|
+
return arr;
|
|
125
|
+
},
|
|
126
|
+
configurable: true
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
64
130
|
const template = await Promise.resolve(instance.render());
|
|
65
131
|
const childHtml = template.rawText;
|
|
66
132
|
const childFragment = parse5.parseFragment(childHtml);
|