diff --git a/public/admin/assets/js/ops/core.js b/public/admin/assets/js/ops/core.js index 9ef9321..3f4611a 100644 --- a/public/admin/assets/js/ops/core.js +++ b/public/admin/assets/js/ops/core.js @@ -1,6 +1,31 @@ // Shared plumbing: htm binding, hash router, polling fetch, formatters. const { createElement, useState, useEffect, useRef, useCallback } = React; -export const html = htm.bind(createElement); + +// htm hands props straight through, and React refuses a style string (error #62). +// Writing style objects everywhere in tagged templates is miserable, so convert +// once here instead and let the views keep using plain css. +function cssToObject(css) { + const style = {}; + for (const declaration of String(css).split(';')) { + const split = declaration.indexOf(':'); + if (split === -1) continue; + const property = declaration.slice(0, split).trim(); + const value = declaration.slice(split + 1).trim(); + if (!property || !value) continue; + // custom properties have to stay verbatim, the rest camelCase + style[property.startsWith('--') ? property : property.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = value; + } + return style; +} + +function h(type, props, ...children) { + if (props && typeof props.style === 'string') { + return createElement(type, { ...props, style: cssToObject(props.style) }, ...children); + } + return createElement(type, props, ...children); +} + +export const html = htm.bind(h); export { useState, useEffect, useRef, useCallback }; export async function api(path, options = {}) {