UNPKG

thorish

Version:

This is a library of useful JS concepts and data structures for Node and the browser. It it, unashamedly, a dumping ground for code needed by [@samthor](https://twitter.com/samthor)'s projects.

190 lines (183 loc) 5.49 kB
import { abortedSignal, escapeStringFor, preprocessHtmlTemplateTag, tickRunner } from "../../chunk-FJEQHTCW.js"; // src/dom/index.ts function css(arr, ...rest) { const parts = [arr[0]]; for (let i = 1; i < arr.length; ++i) { parts.push(String(rest[i - 1]), arr[i]); } const styleSheet = new CSSStyleSheet(); styleSheet.replaceSync(parts.join("")); return styleSheet; } function html(arr, ...rest) { const idToReplace = /* @__PURE__ */ new Map(); const states = preprocessHtmlTemplateTag(arr); if (states.length + 1 !== arr.length || states.length !== rest.length) { throw new Error(`unexpected html tag length`); } const parts = []; for (let i = 0; i < states.length; ++i) { parts.push(arr[i]); const state = states[i]; const inner = rest[i]; if (inner instanceof Node) { if (state !== 0 /* Normal */) { throw new Error(`can only place Node within regular HTML`); } const id = `__html_${Math.random()}`; parts.push(`<link id="${id}" />`); idToReplace.set(id, inner); continue; } parts.push(escapeStringFor(state, inner)); } parts.push(arr[arr.length - 1]); const node = document.createElement("div"); node.innerHTML = parts.join(""); const frag = document.createDocumentFragment(); frag.append(...node.children); for (const [id, node2] of idToReplace) { const target = frag.getElementById(id); if (node2 instanceof DocumentFragment) { target.replaceWith(node2.cloneNode(true)); } else { target.replaceWith(node2); } } return frag; } function buildShadow(src, ...styles) { return buildShadowOptions({}, src, ...styles); } function buildShadowOptions(options, src, ...styles) { return (target) => { const root = target.attachShadow({ mode: "open", delegatesFocus: options.delegatesFocus }); root.append(src.cloneNode(true)); root.adoptedStyleSheets = styles; return root; }; } var SignalHTMLElement = class extends HTMLElement { abort = (reason) => { }; signal = abortedSignal; connectedCallback() { this.maybeRefresh(); } disconnectedCallback() { if (this.isConnected && !this.reparentShouldInvalidate()) { } else { this.abort("disconnected"); } } /** * Call to cause a refresh, e.g., some value has changed. */ invalidate() { this.abort("invalidate"); this.maybeRefresh(); } /** * Return `true` if this should cause a refresh/signal to be aborted. */ reparentShouldInvalidate() { return false; } maybeRefresh() { if (!this.isConnected || !this.signal.aborted) { return; } const c = new AbortController(); this.signal = c.signal; this.abort = (reason) => c.abort(reason); this.refresh(this.signal); } }; var SizingElement = class extends HTMLElement { constructor() { super(); const s = buildShadow( html`<div id="inner"><slot></slot></div>`, css` :host { all: inherit; display: inline-flex; } :host([block]) { display: flex; } #inner { margin: var(--sizing-negative-margin); flex-grow: 1; position: relative; width: 0; } #inner { display: flex; flex-flow: row; } ::slotted(*) { flex-grow: 1 !important; } :host([grid]) #inner { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); } :host([grid]) ::slotted(*) { grid-column: 1 / -1 !important; grid-row: 1 / -1 !important; max-width: 100% !important; max-height: 100% !important; box-sizing: border-box !important; } ` ); const root = s(this); const inner = root.firstElementChild; const prop = (prop2, value) => inner.style.setProperty(prop2, value); const refreshState = () => { const cs = window.getComputedStyle(this); const { paddingTop, paddingRight, paddingBottom, paddingLeft, padding } = cs; const negativePadding = `-${paddingTop} -${paddingRight} -${paddingBottom} -${paddingLeft}`; const width = cs.getPropertyValue("width"); const height = cs.getPropertyValue("height"); prop("--sizing-extra-width", `calc(${paddingLeft} + ${paddingRight})`); prop("--sizing-extra-height", `calc(${paddingTop} + ${paddingBottom})`); prop("--sizing-padding", padding); if (cs.boxSizing === "border-box") { const { borderLeftWidth, borderRightWidth, borderTopWidth, borderBottomWidth } = cs; prop( "--sizing-inner-width", `calc(${width} - (${paddingLeft} + ${paddingRight} + ${borderLeftWidth} + ${borderRightWidth}))` ); prop( "--sizing-inner-height", `calc(${height} - (${paddingTop} + ${paddingBottom} + ${borderTopWidth} + ${borderBottomWidth}))` ); } else { prop("--sizing-inner-width", width); prop("--sizing-inner-height", height); } prop("--sizing-negative-margin", negativePadding); }; const ro = new ResizeObserver(tickRunner(refreshState)); ro.observe(this, { box: "content-box" }); ro.observe(this, { box: "border-box" }); ro.observe(inner); } }; export { SignalHTMLElement, SizingElement, buildShadow, buildShadowOptions, css, html }; //# sourceMappingURL=index.js.map