wkit/src/html.js

710 lines
19 KiB
JavaScript
Raw Normal View History

2023-04-17 16:39:45 +08:00
/**
* {模板解析, 基于 lit-html 二次开发}
* @author yutent<yutent.io@gmail.com>
* @date 2023/03/7 16:36:59
*/
import { boolMap, WC_PART, NOTHING } from './constants.js'
import { animate, MODES } from './anim.js'
2023-03-08 11:50:38 +08:00
const boundAttributeSuffix = '$wc$'
const marker = `wc$${String(Math.random()).slice(9)}$`
const markerMatch = '?' + marker
const nodeMarker = `<${markerMatch}>`
const createMarker = (v = '') => document.createComment(v)
const isPrimitive = value =>
2023-03-07 19:15:23 +08:00
value === null || (typeof value != 'object' && typeof value != 'function')
const isArray = Array.isArray
const isIterable = value =>
2023-03-07 19:15:23 +08:00
isArray(value) ||
typeof (value === null || value === void 0
2023-03-08 11:50:38 +08:00
? false
2023-03-07 19:15:23 +08:00
: value[Symbol.iterator]) === 'function'
const SPACE_CHAR = `[ \n\f\r]`
const ATTR_VALUE_CHAR = `[^ \n\f\r"'\`<>=]`
const NAME_CHAR = `[^\\s"'>=/]`
const textEndRegex = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g
const COMMENT_START = 1
const TAG_NAME = 2
const DYNAMIC_TAG_NAME = 3
const commentEndRegex = /-->/g
const comment2EndRegex = />/g
const tagEndRegex = new RegExp(
2023-03-07 19:15:23 +08:00
`>|${SPACE_CHAR}(?:(${NAME_CHAR}+)(${SPACE_CHAR}*=${SPACE_CHAR}*(?:${ATTR_VALUE_CHAR}|("|')|))|$)`,
'g'
)
const ENTIRE_MATCH = 0
const ATTRIBUTE_NAME = 1
const SPACES_AND_EQUALS = 2
const QUOTE_CHAR = 3
const singleQuoteAttrEndRegex = /'/g
const doubleQuoteAttrEndRegex = /"/g
const rawTextElement = /^(?:script|style|textarea|title)$/i
const HTML_RESULT = 1
const SVG_RESULT = 2
const ATTRIBUTE_PART = 1
const CHILD_PART = 2
const EVENT_PART = 5
const ELEMENT_PART = 6
const COMMENT_PART = 7
2023-08-11 17:42:27 +08:00
const TEMPLATE_CACHE = new Map()
const walker = document.createTreeWalker(document, 129, null, false)
function noop() {}
function getTemplateHtml(strings, type) {
let len = strings.length - 1
let attrNames = []
2023-03-07 19:15:23 +08:00
let html2 = type === SVG_RESULT ? '<svg>' : ''
let rawTextEndRegex
let regex = textEndRegex
2023-03-08 15:13:15 +08:00
for (let i = 0; i < len; i++) {
let s = strings[i]
2023-03-07 19:15:23 +08:00
let attrNameEndIndex = -1
let attrName
let lastIndex = 0
let match
while (lastIndex < s.length) {
regex.lastIndex = lastIndex
match = regex.exec(s)
if (match === null) {
2023-03-06 19:20:23 +08:00
break
2023-03-07 19:15:23 +08:00
}
lastIndex = regex.lastIndex
if (regex === textEndRegex) {
if (match[COMMENT_START] === '!--') {
regex = commentEndRegex
} else if (match[COMMENT_START] !== void 0) {
regex = comment2EndRegex
} else if (match[TAG_NAME] !== void 0) {
if (rawTextElement.test(match[TAG_NAME])) {
rawTextEndRegex = new RegExp(`</${match[TAG_NAME]}`, 'g')
}
regex = tagEndRegex
} else if (match[DYNAMIC_TAG_NAME] !== void 0) {
regex = tagEndRegex
2023-03-06 19:20:23 +08:00
}
2023-03-07 19:15:23 +08:00
} else if (regex === tagEndRegex) {
if (match[ENTIRE_MATCH] === '>') {
regex =
rawTextEndRegex !== null && rawTextEndRegex !== void 0
? rawTextEndRegex
: textEndRegex
attrNameEndIndex = -1
} else if (match[ATTRIBUTE_NAME] === void 0) {
attrNameEndIndex = -2
} else {
attrNameEndIndex = regex.lastIndex - match[SPACES_AND_EQUALS].length
attrName = match[ATTRIBUTE_NAME]
regex =
match[QUOTE_CHAR] === void 0
? tagEndRegex
: match[QUOTE_CHAR] === '"'
? doubleQuoteAttrEndRegex
: singleQuoteAttrEndRegex
}
} else if (
regex === doubleQuoteAttrEndRegex ||
regex === singleQuoteAttrEndRegex
) {
regex = tagEndRegex
} else if (regex === commentEndRegex || regex === comment2EndRegex) {
regex = textEndRegex
} else {
regex = tagEndRegex
rawTextEndRegex = void 0
}
}
let end =
2023-03-07 19:15:23 +08:00
regex === tagEndRegex && strings[i + 1].startsWith('/>') ? ' ' : ''
html2 +=
regex === textEndRegex
? s + nodeMarker
: attrNameEndIndex >= 0
? (attrNames.push(attrName),
s.slice(0, attrNameEndIndex) +
boundAttributeSuffix +
s.slice(attrNameEndIndex)) +
marker +
end
: s +
marker +
(attrNameEndIndex === -2 ? (attrNames.push(void 0), i) : end)
}
let htmlResult =
2023-03-08 15:13:15 +08:00
html2 + (strings[len] || '<?>') + (type === SVG_RESULT ? '</svg>' : '')
2023-03-07 19:15:23 +08:00
if (!Array.isArray(strings) || !strings.hasOwnProperty('raw')) {
2023-05-08 18:43:04 +08:00
throw new Error('invalid html ast')
2023-03-07 19:15:23 +08:00
}
return [htmlResult, attrNames]
}
class Template {
2023-03-17 10:59:48 +08:00
constructor({ strings, ['__dom_type__']: type }, options) {
2023-03-07 19:15:23 +08:00
this.parts = []
let node
let nodeIndex = 0
let attrNameIndex = 0
let partCount = strings.length - 1
let parts = this.parts
let [html2, attrNames] = getTemplateHtml(strings, type)
2023-03-16 23:42:04 +08:00
this.el = Template.createElement(html2)
2023-03-07 19:15:23 +08:00
walker.currentNode = this.el.content
if (type === SVG_RESULT) {
let content = this.el.content
let svgElement = content.firstChild
2023-03-07 19:15:23 +08:00
svgElement.remove()
content.append(...svgElement.childNodes)
}
2023-03-17 10:18:40 +08:00
2023-03-07 19:15:23 +08:00
while ((node = walker.nextNode()) !== null && parts.length < partCount) {
if (node.nodeType === 1) {
if (node.hasAttributes()) {
let attrsToRemove = []
2023-03-17 10:18:40 +08:00
for (let name of node.getAttributeNames()) {
2023-03-07 19:15:23 +08:00
if (
name.endsWith(boundAttributeSuffix) ||
name.startsWith(marker)
) {
let realName = attrNames[attrNameIndex++]
2023-03-07 19:15:23 +08:00
attrsToRemove.push(name)
if (realName !== void 0) {
let value = node.getAttribute(
2023-03-07 19:15:23 +08:00
realName.toLowerCase() + boundAttributeSuffix
)
let statics = value.split(marker)
let m = /([#:@])?(.*)/.exec(realName)
let decorates = []
if (m[1] === '@' && m[2].includes('.')) {
decorates = m[2].split('.')
m[2] = decorates.shift()
}
2023-03-07 19:15:23 +08:00
parts.push({
type: ATTRIBUTE_PART,
index: nodeIndex,
name: m[2],
strings: statics,
decorates,
2023-03-07 19:15:23 +08:00
ctor:
m[1] === ':'
2023-03-07 19:15:23 +08:00
? PropertyPart
: m[1] === '#' && m[2] === 'animation'
? AnimPart
2023-03-07 19:15:23 +08:00
: m[1] === '@'
? EventPart
: AttributePart
})
} else {
parts.push({
type: ELEMENT_PART,
index: nodeIndex
})
}
}
}
for (let name of attrsToRemove) {
2023-03-07 19:15:23 +08:00
node.removeAttribute(name)
}
}
if (rawTextElement.test(node.tagName)) {
let strings2 = node.textContent.split(marker)
let lastIndex = strings2.length - 1
2023-03-07 19:15:23 +08:00
if (lastIndex > 0) {
node.textContent = ''
for (let i = 0; i < lastIndex; i++) {
node.append(strings2[i], createMarker())
walker.nextNode()
parts.push({ type: CHILD_PART, index: ++nodeIndex })
}
node.append(strings2[lastIndex], createMarker())
}
}
} else if (node.nodeType === 8) {
let data = node.data
2023-03-07 19:15:23 +08:00
if (data === markerMatch) {
parts.push({ type: CHILD_PART, index: nodeIndex })
} else {
let i = -1
while ((i = node.data.indexOf(marker, i + 1)) !== -1) {
parts.push({ type: COMMENT_PART, index: nodeIndex })
i += marker.length - 1
}
}
}
nodeIndex++
2023-03-06 19:20:23 +08:00
}
2023-03-07 19:15:23 +08:00
}
2023-03-16 23:42:04 +08:00
static createElement(html2) {
2023-03-13 18:37:12 +08:00
let el = document.createElement('template')
2023-03-07 19:15:23 +08:00
el.innerHTML = html2
return el
}
}
2023-03-07 19:15:23 +08:00
class TemplateInstance {
constructor(template, parent) {
2023-09-21 10:24:53 +08:00
this.$parts = []
this.$template = template
this.$parent = parent
2023-03-07 19:15:23 +08:00
}
get parentNode() {
2023-09-21 10:24:53 +08:00
return this.$parent.parentNode
2023-03-07 19:15:23 +08:00
}
2023-03-22 18:49:46 +08:00
#checkRef(node, walker, options) {
do {
2023-03-23 11:50:28 +08:00
if (node && node.nodeType === 1 && node.getAttribute('ref')) {
2023-03-22 18:49:46 +08:00
options.host.$refs[node.getAttribute('ref')] = node
node.removeAttribute('ref')
}
} while ((node = walker.nextNode()) !== null)
}
2023-03-07 19:15:23 +08:00
_clone(options) {
2023-03-13 18:37:12 +08:00
let {
2023-03-07 19:15:23 +08:00
el: { content },
parts
2023-09-21 10:24:53 +08:00
} = this.$template
2023-03-13 18:37:12 +08:00
2023-03-24 16:45:39 +08:00
let fragment = document.importNode(content, true)
2023-03-07 19:15:23 +08:00
let nodeIndex = 0
let partIndex = 0
let templatePart = parts[0]
2023-03-24 16:45:39 +08:00
let node = null
walker.currentNode = fragment
node = walker.nextNode()
// 没有动态绑定时, 查一遍是否有ref属性
if (templatePart === void 0) {
2023-03-22 18:49:46 +08:00
this.#checkRef(node, walker, options)
} else {
while (templatePart !== void 0) {
2023-03-23 11:50:28 +08:00
if (node.nodeType === 1 && node.getAttribute('ref')) {
if (options.host.$refs) {
options.host.$refs[node.getAttribute('ref')] = node
node.removeAttribute('ref')
}
}
if (nodeIndex === templatePart.index) {
let part
if (templatePart.type === CHILD_PART) {
part = new ChildPart(node, node.nextSibling, this, options)
} else if (templatePart.type === ATTRIBUTE_PART) {
part = new templatePart.ctor(
node,
templatePart.name,
templatePart.strings,
templatePart.decorates,
this,
options
)
} else if (templatePart.type === ELEMENT_PART) {
part = new ElementPart(node, this, options)
}
2023-09-21 10:24:53 +08:00
this.$parts.push(part)
templatePart = parts[++partIndex]
}
if (
nodeIndex !==
(templatePart === null || templatePart === void 0
? void 0
: templatePart.index)
) {
node = walker.nextNode()
nodeIndex++
2023-03-17 10:59:48 +08:00
}
2023-03-07 19:15:23 +08:00
}
2023-03-22 18:49:46 +08:00
// 再检查剩下没有动态绑定的节点
this.#checkRef(node, walker, options)
2023-03-07 19:15:23 +08:00
}
2023-03-07 19:15:23 +08:00
return fragment
}
_update(values) {
let i = 0
2023-09-21 10:24:53 +08:00
for (let part of this.$parts) {
2023-03-07 19:15:23 +08:00
if (part !== void 0) {
if (part.strings !== void 0) {
2023-09-20 19:11:22 +08:00
part.$setValue(values, i)
2023-03-07 19:15:23 +08:00
i += part.strings.length - 2
} else {
2023-09-20 19:11:22 +08:00
part.$setValue(values[i])
2023-03-07 19:15:23 +08:00
}
}
i++
}
}
}
2023-03-07 19:15:23 +08:00
class ChildPart {
constructor(startNode, endNode, parent, options) {
this.type = CHILD_PART
2023-03-08 15:13:15 +08:00
this._$committedValue = NOTHING
2023-09-21 10:24:53 +08:00
this.startNode = startNode
this.endNode = endNode
this.$parent = parent
2023-03-07 19:15:23 +08:00
this.options = options
}
2023-09-20 19:08:11 +08:00
2023-03-07 19:15:23 +08:00
get parentNode() {
2023-09-21 10:24:53 +08:00
let parentNode = this.startNode.parentNode
let parent = this.$parent
2023-03-07 19:15:23 +08:00
if (parent !== void 0 && parentNode.nodeType === 11) {
parentNode = parent.parentNode
}
return parentNode
}
2023-09-21 10:24:53 +08:00
2023-09-20 19:11:22 +08:00
$setValue(value) {
2023-03-07 19:15:23 +08:00
if (isPrimitive(value)) {
2023-03-08 15:13:15 +08:00
if (value === NOTHING || value == null || value === '') {
if (this._$committedValue !== NOTHING) {
this.#clear()
2023-03-07 19:15:23 +08:00
}
2023-03-08 15:13:15 +08:00
this._$committedValue = NOTHING
} else if (value !== this._$committedValue) {
2023-03-07 19:15:23 +08:00
this._commitText(value)
}
} else if (value['__dom_type__'] !== void 0) {
this._commitTemplateResult(value)
} else if (value.nodeType !== void 0) {
this._commitNode(value)
} else if (isIterable(value)) {
this._commitIterable(value)
} else {
this._commitText(value)
}
}
2023-09-21 10:24:53 +08:00
_insert(node, target = this.endNode) {
return this.startNode.parentNode.insertBefore(node, target)
2023-03-07 19:15:23 +08:00
}
_commitNode(value) {
if (this._$committedValue !== value) {
this.#clear()
2023-03-07 19:15:23 +08:00
this._$committedValue = this._insert(value)
}
}
_commitText(value) {
if (
2023-03-08 15:13:15 +08:00
this._$committedValue !== NOTHING &&
2023-03-07 19:15:23 +08:00
isPrimitive(this._$committedValue)
) {
2023-09-21 10:24:53 +08:00
let node = this.startNode.nextSibling
2023-03-08 11:11:05 +08:00
2023-03-07 19:15:23 +08:00
node.data = value
} else {
this._commitNode(document.createTextNode(value))
2023-03-07 19:15:23 +08:00
}
this._$committedValue = value
}
_commitTemplateResult(result) {
let { values, ['__dom_type__']: type } = result
let template =
2023-03-07 19:15:23 +08:00
typeof type === 'number'
2023-03-17 10:18:40 +08:00
? this.#getTemplate(result)
2023-03-16 23:42:04 +08:00
: (type.el === void 0 && (type.el = Template.createElement(type.h)),
2023-03-07 19:15:23 +08:00
type)
2023-03-08 11:50:38 +08:00
2023-09-21 10:24:53 +08:00
if (this._$committedValue?.$template === template) {
2023-03-07 19:15:23 +08:00
this._$committedValue._update(values)
} else {
let instance = new TemplateInstance(template, this)
let fragment = instance._clone(this.options)
2023-03-07 19:15:23 +08:00
instance._update(values)
2023-03-06 19:20:23 +08:00
2023-03-07 19:15:23 +08:00
this._commitNode(fragment)
this._$committedValue = instance
}
}
2023-03-17 10:18:40 +08:00
#getTemplate(result) {
2023-08-11 17:42:27 +08:00
let template = TEMPLATE_CACHE.get(result.strings.join())
2023-03-07 19:15:23 +08:00
if (template === void 0) {
2023-03-16 23:42:04 +08:00
template = new Template(result, this.options)
2023-08-11 17:42:27 +08:00
TEMPLATE_CACHE.set(result.strings.join(), template)
2023-03-07 19:15:23 +08:00
}
return template
}
_commitIterable(value) {
if (!isArray(this._$committedValue)) {
this._$committedValue = []
this.#clear()
2023-03-07 19:15:23 +08:00
}
let itemParts = this._$committedValue
2023-03-07 19:15:23 +08:00
let partIndex = 0
let itemPart
for (let item of value) {
2023-03-07 19:15:23 +08:00
if (partIndex === itemParts.length) {
itemParts.push(
(itemPart = new ChildPart(
this._insert(createMarker()),
this._insert(createMarker()),
this,
this.options
))
)
} else {
itemPart = itemParts[partIndex]
}
2023-09-20 19:11:22 +08:00
itemPart.$setValue(item)
2023-03-07 19:15:23 +08:00
partIndex++
}
if (partIndex < itemParts.length) {
2023-09-21 10:24:53 +08:00
this.#clear(itemPart && itemPart.endNode.nextSibling, partIndex)
2023-03-07 19:15:23 +08:00
itemParts.length = partIndex
}
}
2023-09-21 10:24:53 +08:00
#clear(start = this.startNode.nextSibling, from) {
while (start && start !== this.endNode) {
2023-03-08 11:50:38 +08:00
let node = start.nextSibling
2023-03-08 11:11:05 +08:00
start.remove()
2023-03-08 11:50:38 +08:00
start = node
2023-03-07 19:15:23 +08:00
}
}
2023-03-06 19:20:23 +08:00
}
// 常规属性
2023-03-07 19:15:23 +08:00
class AttributePart {
constructor(element, name, strings, decorates, parent, options = {}) {
2023-03-07 19:15:23 +08:00
this.type = ATTRIBUTE_PART
2023-03-08 15:13:15 +08:00
this._$committedValue = NOTHING
2023-03-07 19:15:23 +08:00
this.element = element
this.name = name
this.decorates = decorates
2023-09-21 10:24:53 +08:00
this.$parent = parent
2023-03-07 19:15:23 +08:00
this.options = options
if (strings.length > 2 || strings[0] !== '' || strings[1] !== '') {
this._$committedValue = new Array(strings.length - 1).fill(new String())
this.strings = strings
} else {
2023-03-08 15:13:15 +08:00
this._$committedValue = NOTHING
2023-03-07 19:15:23 +08:00
}
}
get tagName() {
return this.element.tagName
}
2023-09-20 19:11:22 +08:00
$setValue(value, valueIndex) {
let strings = this.strings
let changed = false
2023-03-07 19:15:23 +08:00
if (strings === void 0) {
changed = !isPrimitive(value) || value !== this._$committedValue
if (changed) {
2023-03-07 19:15:23 +08:00
this._$committedValue = value
}
} else {
let values = value
2023-03-07 19:15:23 +08:00
value = strings[0]
2023-03-08 15:13:15 +08:00
for (let i = 0; i < strings.length - 1; i++) {
let v = values[valueIndex + i]
changed || (changed = !isPrimitive(v) || v !== this._$committedValue[i])
2023-03-08 15:13:15 +08:00
if (v === NOTHING) {
value = NOTHING
} else if (value !== NOTHING) {
2023-03-07 19:15:23 +08:00
value += (v !== null && v !== void 0 ? v : '') + strings[i + 1]
}
this._$committedValue[i] = v
}
}
if (changed) {
2023-03-17 19:02:20 +08:00
this.commitValue(value)
2023-03-07 19:15:23 +08:00
}
}
2023-03-17 19:02:20 +08:00
commitValue(value) {
let isBoolAttr = boolMap[this.name]
2023-03-17 10:18:40 +08:00
// ref属性不渲染到节点上
if (this.name === 'ref') {
this.options.host.$refs[value] = this.element
return
}
if (isBoolAttr) {
this.element[isBoolAttr] = !(value === false || value === null)
if (this.element[isBoolAttr]) {
this.element.setAttribute(this.name, '')
} else {
this.element.removeAttribute(this.name)
}
2023-03-07 19:15:23 +08:00
} else {
if (value === null || value === void 0) {
this.element.removeAttribute(this.name)
} else {
this.element.setAttribute(this.name, value)
2023-03-07 19:15:23 +08:00
}
}
}
}
// 赋值属性
2023-03-07 19:15:23 +08:00
class PropertyPart extends AttributePart {
constructor(...args) {
super(...args)
2023-03-07 19:15:23 +08:00
}
2023-03-13 18:37:12 +08:00
2023-03-17 19:02:20 +08:00
commitValue(value) {
this.element[this.name] = value
2023-03-07 19:15:23 +08:00
}
}
// 动画属性
class AnimPart extends AttributePart {
constructor(...args) {
super(...args)
}
commitValue({ type = 'fade', duration, custom, immediate = false } = {}) {
2023-04-04 14:46:50 +08:00
let fromto = MODES[type] || MODES.fade
if (custom) {
fromto = custom
}
2023-04-04 12:04:17 +08:00
this.element.$animate = function (out = false) {
2023-04-04 13:55:01 +08:00
return animate.call(this, duration, fromto, out)
}
this.element.$animate.immediate = immediate
}
}
2023-03-13 18:37:12 +08:00
// 事件属性
2023-03-07 19:15:23 +08:00
class EventPart extends AttributePart {
#listener = null
#prevent = noop
#stop = noop
#checkSelf = noop
constructor(...args) {
super(...args)
2023-03-07 19:15:23 +08:00
this.type = EVENT_PART
}
2023-03-08 11:50:38 +08:00
2023-09-20 19:11:22 +08:00
$setValue(listener) {
2023-03-24 16:45:39 +08:00
let host = this.options.host
let options = {}
if (this.decorates.length) {
for (let it of this.decorates) {
switch (it) {
case 'stop':
this.#stop = ev => ev.stopPropagation()
break
case 'prevent':
this.#prevent = ev => ev.preventDefault()
break
case 'self':
this.#checkSelf = ev => ev.target === this.element
break
case 'capture':
case 'once':
case 'passive':
options[it] = true
break
}
}
2023-03-07 19:15:23 +08:00
}
let shouldRemove = listener !== this.#listener
if (this.#listener && host.$events[this.name]) {
for (let it of host.$events[this.name]) {
if (it.el === this.element) {
shouldRemove =
options.capture !== it.capture ||
options.once !== it.once ||
options.passive !== it.passive
if (shouldRemove) {
this.element.removeEventListener(this.name, it.listener, it.options)
}
break
}
}
2023-03-07 19:15:23 +08:00
}
if (listener && shouldRemove) {
this.element.addEventListener(this.name, this, options)
this.#listener = listener
2023-03-24 16:45:39 +08:00
if (host.$events[this.name]) {
host.$events[this.name].push({
el: this.element,
listener: this,
options
2023-03-24 16:45:39 +08:00
})
} else {
host.$events[this.name] = [
{
el: this.element,
listener: this,
options
2023-03-24 16:45:39 +08:00
}
]
}
}
2023-03-07 19:15:23 +08:00
}
handleEvent(ev) {
this.#stop(ev)
this.#prevent(ev)
if (this.#checkSelf(ev) === false) {
return
2023-03-07 19:15:23 +08:00
}
this.#listener.call(this.options.host, ev)
2023-03-07 19:15:23 +08:00
}
}
2023-03-07 19:15:23 +08:00
class ElementPart {
constructor(element, parent, options) {
this.element = element
this.type = ELEMENT_PART
2023-09-21 10:24:53 +08:00
this.$parent = parent
2023-03-07 19:15:23 +08:00
this.options = options
}
2023-09-20 19:08:11 +08:00
2023-09-20 19:11:22 +08:00
$setValue(value) {}
2023-03-07 19:15:23 +08:00
}
2023-03-16 23:42:04 +08:00
export function render(value, container, options = {}) {
2023-03-13 18:28:03 +08:00
let part = container[WC_PART]
2023-03-06 19:20:23 +08:00
2023-03-07 19:15:23 +08:00
if (part === void 0) {
2023-08-11 17:42:27 +08:00
part = new ChildPart(
2023-03-13 18:28:03 +08:00
container.insertBefore(createMarker(), null),
null,
2023-03-07 19:15:23 +08:00
void 0,
2023-03-16 23:42:04 +08:00
options
2023-03-07 19:15:23 +08:00
)
2023-08-11 17:42:27 +08:00
container[WC_PART] = part
2023-03-07 19:15:23 +08:00
}
2023-09-20 19:11:22 +08:00
part.$setValue(value)
2023-03-07 19:15:23 +08:00
return part
}
2023-03-08 15:13:15 +08:00
2023-04-21 15:26:27 +08:00
export function html(strings, ...values) {
2023-03-08 15:13:15 +08:00
return {
__dom_type__: HTML_RESULT,
strings,
values
}
}
2023-08-11 17:42:27 +08:00
export function raw(str, values = []) {
let strings = values.length ? str.split('%s') : [str]
strings.raw = true
return html(strings, ...values)
2023-04-21 15:26:27 +08:00
}
export function svg(strings, ...values) {
2023-03-08 15:13:15 +08:00
return {
__dom_type__: SVG_RESULT,
strings,
values
}
}