Add support for child generators as skooma args

Function arguments to skooma generators are now only treated as
initialisers if they take at least one named argument. Otherwise they
are called and their return value is evaluated as their replacement.

The process is recursive and can happen repeatedly for functions that
themselves return functions.
This commit is contained in:
Talia 2024-01-22 10:35:20 +01:00
parent 75fc1a7ce7
commit 3f838821e4
1 changed files with 22 additions and 16 deletions

View File

@ -52,7 +52,7 @@ const getCustom = args => args.reduce(
const isElement = object => HTMLElement.prototype.isPrototypeOf(object) const isElement = object => HTMLElement.prototype.isPrototypeOf(object)
const isReactive = object => !(object instanceof HTMLElement) export const isReactive = object => !(object instanceof HTMLElement)
&& (object instanceof EventTarget) && (object instanceof EventTarget)
&& ("value" in object) && ("value" in object)
@ -63,6 +63,8 @@ const toChild = arg => {
return arg return arg
} else if (isReactive(arg)) { } else if (isReactive(arg)) {
return reactiveChild(arg) return reactiveChild(arg)
} else {
return document.createComment("Placeholder for reactive content")
} }
} }
@ -98,7 +100,7 @@ const specialAttributes = {
}, },
shadowRoot: { shadowRoot: {
set: (element, value) => { set: (element, value) => {
parseArgs((element.shadowRoot || element.attachShadow({mode: "open"})), null, value) parseArgs((element.shadowRoot || element.attachShadow({mode: "open"})), value)
} }
} }
} }
@ -145,23 +147,27 @@ const setReactiveAttribute = (element, attribute, reactive, abortController) =>
} }
} }
const parseArgs = (element, before, ...args) => { const parseArgs = (element, ...args) => {
if (element.content) element = element.content if (element.content) element = element.content
for (const arg of args) if (arg !== empty) { for (const arg of args) if (arg !== empty) {
if (arg instanceof Array) {
parseArgs(element, ...arg)
} else {
const child = toChild(arg) const child = toChild(arg)
if (child) if (child)
element.insertBefore(child, before) element.append(child)
else if (arg === undefined || arg == null) else if (arg === undefined || arg == null)
console.warn(`An argument of type ${typeof arg} has been ignored`, element) console.warn(`An argument of type ${typeof arg} has been ignored`, element)
else if (typeof arg == "function" && arg.length == 0)
parseArgs(element, arg())
else if (typeof arg == "function") else if (typeof arg == "function")
arg(element) arg(element)
else if ("length" in arg)
parseArgs(element, before, ...arg)
else else
for (const key in arg) for (const key in arg)
setAttribute(element, key, arg[key]) setAttribute(element, key, arg[key])
} }
} }
}
const node = (name, args, options) => { const node = (name, args, options) => {
let element let element
@ -173,7 +179,7 @@ const node = (name, args, options) => {
element = document.createElementNS(options.xmlns, name, opts) element = document.createElementNS(options.xmlns, name, opts)
else else
element = document.createElement(name, opts) element = document.createElement(name, opts)
parseArgs(element, null, args) parseArgs(element, args)
return element return element
} }