@hyperfixi/components 2.4.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/LICENSE +20 -0
- package/dist/attrs.d.ts +15 -0
- package/dist/index.cjs +481 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +451 -0
- package/dist/index.js.map +1 -0
- package/dist/register.d.ts +41 -0
- package/dist/scan.d.ts +24 -0
- package/dist/scope-css.d.ts +48 -0
- package/dist/slots.d.ts +15 -0
- package/dist/template-ast.d.ts +43 -0
- package/dist/types.d.ts +25 -0
- package/package.json +64 -0
- package/src/attrs.test.ts +62 -0
- package/src/attrs.ts +80 -0
- package/src/index.ts +110 -0
- package/src/integration.test.ts +609 -0
- package/src/register.ts +308 -0
- package/src/scan.ts +96 -0
- package/src/scope-css.test.ts +80 -0
- package/src/scope-css.ts +87 -0
- package/src/slots.test.ts +55 -0
- package/src/slots.ts +70 -0
- package/src/template-ast.test.ts +82 -0
- package/src/template-ast.ts +147 -0
- package/src/types.ts +29 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LokaScript Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/dist/attrs.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `attrs` proxy — read component attributes as values on the component scope.
|
|
3
|
+
*
|
|
4
|
+
* Simplified from upstream's hyperscript-expression-evaluating version: for v1
|
|
5
|
+
* we treat attributes as plain strings with a few type coercions (number, bool)
|
|
6
|
+
* and a kebab-case-to-camelCase accessor.
|
|
7
|
+
*
|
|
8
|
+
* `<my-counter initial-count="5">` exposes `attrs.initialCount` = 5 (number).
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Create a proxy over a component element's attributes. Getting a property
|
|
12
|
+
* reads and coerces the matching kebab-case attribute. Setting a property
|
|
13
|
+
* writes it back as a string (simple stringification for v1).
|
|
14
|
+
*/
|
|
15
|
+
export declare function createAttrsProxy(componentEl: Element): Record<string, unknown>;
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
componentsPlugin: () => componentsPlugin,
|
|
24
|
+
default: () => index_default,
|
|
25
|
+
registerTemplateComponent: () => registerTemplateComponent,
|
|
26
|
+
scanAndRegister: () => scanAndRegister,
|
|
27
|
+
watchForTemplates: () => watchForTemplates
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
|
|
31
|
+
// src/slots.ts
|
|
32
|
+
function partitionSlotContent(slotContent) {
|
|
33
|
+
const named = {};
|
|
34
|
+
const defaultParts = [];
|
|
35
|
+
if (typeof document === "undefined") {
|
|
36
|
+
return { named, defaultContent: slotContent };
|
|
37
|
+
}
|
|
38
|
+
const tmp = document.createElement("div");
|
|
39
|
+
tmp.innerHTML = slotContent;
|
|
40
|
+
for (const child of Array.from(tmp.childNodes)) {
|
|
41
|
+
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
42
|
+
const el = child;
|
|
43
|
+
const slotName = el.getAttribute("slot");
|
|
44
|
+
if (slotName) {
|
|
45
|
+
el.removeAttribute("slot");
|
|
46
|
+
if (!named[slotName]) named[slotName] = "";
|
|
47
|
+
named[slotName] += el.outerHTML;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
defaultParts.push(el.outerHTML);
|
|
51
|
+
} else if (child.nodeType === Node.TEXT_NODE) {
|
|
52
|
+
defaultParts.push(child.textContent ?? "");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { named, defaultContent: defaultParts.join("") };
|
|
56
|
+
}
|
|
57
|
+
function substituteSlots(templateSource, slotContent) {
|
|
58
|
+
if (!slotContent) return templateSource;
|
|
59
|
+
const { named, defaultContent } = partitionSlotContent(slotContent);
|
|
60
|
+
let source = templateSource.replace(
|
|
61
|
+
/<slot\s+name\s*=\s*["']([^"']+)["']\s*\/?\s*>(\s*<\/slot>)?/g,
|
|
62
|
+
(_match, name) => named[name] ?? ""
|
|
63
|
+
);
|
|
64
|
+
source = source.replace(/<slot\s*\/?\s*>(\s*<\/slot>)?/g, defaultContent);
|
|
65
|
+
return source;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/attrs.ts
|
|
69
|
+
function coerceAttrValue(raw) {
|
|
70
|
+
if (raw == null) return void 0;
|
|
71
|
+
if (raw === "true") return true;
|
|
72
|
+
if (raw === "false") return false;
|
|
73
|
+
if (raw !== "" && !Number.isNaN(Number(raw)) && /^-?(\d+\.?\d*|\.\d+)$/.test(raw)) {
|
|
74
|
+
return Number(raw);
|
|
75
|
+
}
|
|
76
|
+
return raw;
|
|
77
|
+
}
|
|
78
|
+
function camelToKebab(name) {
|
|
79
|
+
return name.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
80
|
+
}
|
|
81
|
+
function createAttrsProxy(componentEl) {
|
|
82
|
+
return new Proxy({}, {
|
|
83
|
+
get(_target, prop) {
|
|
84
|
+
if (typeof prop !== "string" || prop.startsWith("_")) return void 0;
|
|
85
|
+
const exact = componentEl.getAttribute(prop);
|
|
86
|
+
if (exact != null) return coerceAttrValue(exact);
|
|
87
|
+
const kebab = componentEl.getAttribute(camelToKebab(prop));
|
|
88
|
+
if (kebab != null) return coerceAttrValue(kebab);
|
|
89
|
+
return void 0;
|
|
90
|
+
},
|
|
91
|
+
set(_target, prop, value) {
|
|
92
|
+
if (typeof prop !== "string") return false;
|
|
93
|
+
const attrName = componentEl.hasAttribute(prop) ? prop : camelToKebab(prop);
|
|
94
|
+
componentEl.setAttribute(attrName, value == null ? "" : String(value));
|
|
95
|
+
return true;
|
|
96
|
+
},
|
|
97
|
+
has(_target, prop) {
|
|
98
|
+
if (typeof prop !== "string") return false;
|
|
99
|
+
return componentEl.hasAttribute(prop) || componentEl.hasAttribute(camelToKebab(prop));
|
|
100
|
+
},
|
|
101
|
+
ownKeys(_target) {
|
|
102
|
+
return Array.from(componentEl.attributes).map((a) => a.name);
|
|
103
|
+
},
|
|
104
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
105
|
+
if (typeof prop !== "string") return void 0;
|
|
106
|
+
const kebab = camelToKebab(prop);
|
|
107
|
+
if (componentEl.hasAttribute(prop) || componentEl.hasAttribute(kebab)) {
|
|
108
|
+
return {
|
|
109
|
+
enumerable: true,
|
|
110
|
+
configurable: true,
|
|
111
|
+
value: coerceAttrValue(componentEl.getAttribute(prop) ?? componentEl.getAttribute(kebab))
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/register.ts
|
|
120
|
+
var import_reactivity = require("@hyperfixi/reactivity");
|
|
121
|
+
var import_core = require("@hyperfixi/core");
|
|
122
|
+
|
|
123
|
+
// src/template-ast.ts
|
|
124
|
+
var IF_RE = /^#if\s+(.+)$/;
|
|
125
|
+
var ELSE_RE = /^#else\s*$/;
|
|
126
|
+
var END_RE = /^#end\s*$/;
|
|
127
|
+
var FOR_RE = /^#for\s+([A-Za-z_$][\w$]*)\s+in\s+(.+)$/;
|
|
128
|
+
function parseTemplate(source) {
|
|
129
|
+
const lines = source.split("\n");
|
|
130
|
+
const cursor = { i: 0 };
|
|
131
|
+
function parseBlock(stop) {
|
|
132
|
+
const nodes = [];
|
|
133
|
+
let textBuffer = [];
|
|
134
|
+
const flushText = () => {
|
|
135
|
+
if (textBuffer.length > 0) {
|
|
136
|
+
nodes.push({ kind: "text", content: textBuffer.join("\n") });
|
|
137
|
+
textBuffer = [];
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
while (cursor.i < lines.length) {
|
|
141
|
+
const line = lines[cursor.i];
|
|
142
|
+
const trimmed = line.trim();
|
|
143
|
+
if (stop(trimmed)) {
|
|
144
|
+
flushText();
|
|
145
|
+
return nodes;
|
|
146
|
+
}
|
|
147
|
+
const ifMatch = IF_RE.exec(trimmed);
|
|
148
|
+
const forMatch = FOR_RE.exec(trimmed);
|
|
149
|
+
if (ifMatch) {
|
|
150
|
+
flushText();
|
|
151
|
+
const cond = ifMatch[1].trim();
|
|
152
|
+
cursor.i++;
|
|
153
|
+
const thenBlock = parseBlock((l) => ELSE_RE.test(l) || END_RE.test(l));
|
|
154
|
+
let elseBlock = [];
|
|
155
|
+
if (cursor.i < lines.length && ELSE_RE.test(lines[cursor.i].trim())) {
|
|
156
|
+
cursor.i++;
|
|
157
|
+
elseBlock = parseBlock((l) => END_RE.test(l));
|
|
158
|
+
}
|
|
159
|
+
if (cursor.i < lines.length && END_RE.test(lines[cursor.i].trim())) cursor.i++;
|
|
160
|
+
nodes.push({ kind: "if", cond, then: thenBlock, else: elseBlock });
|
|
161
|
+
} else if (forMatch) {
|
|
162
|
+
flushText();
|
|
163
|
+
const varName = forMatch[1];
|
|
164
|
+
const iterableExpr = forMatch[2].trim();
|
|
165
|
+
cursor.i++;
|
|
166
|
+
const bodyBlock = parseBlock((l) => ELSE_RE.test(l) || END_RE.test(l));
|
|
167
|
+
let elseEmptyBlock = [];
|
|
168
|
+
if (cursor.i < lines.length && ELSE_RE.test(lines[cursor.i].trim())) {
|
|
169
|
+
cursor.i++;
|
|
170
|
+
elseEmptyBlock = parseBlock((l) => END_RE.test(l));
|
|
171
|
+
}
|
|
172
|
+
if (cursor.i < lines.length && END_RE.test(lines[cursor.i].trim())) cursor.i++;
|
|
173
|
+
nodes.push({
|
|
174
|
+
kind: "for",
|
|
175
|
+
varName,
|
|
176
|
+
iterableExpr,
|
|
177
|
+
body: bodyBlock,
|
|
178
|
+
elseEmpty: elseEmptyBlock
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
textBuffer.push(line);
|
|
182
|
+
cursor.i++;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
flushText();
|
|
186
|
+
return nodes;
|
|
187
|
+
}
|
|
188
|
+
return parseBlock(() => false);
|
|
189
|
+
}
|
|
190
|
+
function renderTemplate(nodes, scope, interpText, evalExpr) {
|
|
191
|
+
return nodes.map((node) => {
|
|
192
|
+
if (node.kind === "text") {
|
|
193
|
+
return interpText(node.content, scope);
|
|
194
|
+
}
|
|
195
|
+
if (node.kind === "if") {
|
|
196
|
+
const value = evalExpr(node.cond, scope);
|
|
197
|
+
const branch = value ? node.then : node.else;
|
|
198
|
+
return renderTemplate(branch, scope, interpText, evalExpr);
|
|
199
|
+
}
|
|
200
|
+
const iterable = evalExpr(node.iterableExpr, scope);
|
|
201
|
+
const items = iterable != null && typeof iterable[Symbol.iterator] === "function" ? Array.from(iterable) : [];
|
|
202
|
+
if (items.length === 0) {
|
|
203
|
+
return renderTemplate(node.elseEmpty, scope, interpText, evalExpr);
|
|
204
|
+
}
|
|
205
|
+
return items.map(
|
|
206
|
+
(item) => renderTemplate(node.body, { ...scope, [node.varName]: item }, interpText, evalExpr)
|
|
207
|
+
).join("\n");
|
|
208
|
+
}).join("\n");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/scope-css.ts
|
|
212
|
+
var STYLE_BLOCK_RE = /<style(?:\s[^>]*)?>([\s\S]*?)<\/style\s*>/gi;
|
|
213
|
+
function extractStyles(html) {
|
|
214
|
+
const styles = [];
|
|
215
|
+
const cleaned = html.replace(STYLE_BLOCK_RE, (_match, body) => {
|
|
216
|
+
styles.push(body);
|
|
217
|
+
return "";
|
|
218
|
+
});
|
|
219
|
+
return { html: cleaned, styles };
|
|
220
|
+
}
|
|
221
|
+
function injectScopedStyles(tagName, styles) {
|
|
222
|
+
if (styles.length === 0) return false;
|
|
223
|
+
if (typeof document === "undefined" || !document.head) return false;
|
|
224
|
+
const selector = `style[data-component="${cssAttrEscape(tagName)}"]`;
|
|
225
|
+
if (document.head.querySelector(selector)) return false;
|
|
226
|
+
const wrapped = styles.map((body) => `@scope (${tagName}) {
|
|
227
|
+
${body}
|
|
228
|
+
}`).join("\n\n");
|
|
229
|
+
const styleEl = document.createElement("style");
|
|
230
|
+
styleEl.setAttribute("data-component", tagName);
|
|
231
|
+
styleEl.textContent = wrapped;
|
|
232
|
+
document.head.appendChild(styleEl);
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
function cssAttrEscape(s) {
|
|
236
|
+
return s.replace(/["\\]/g, "\\$&");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// src/register.ts
|
|
240
|
+
var REGISTERED = /* @__PURE__ */ new Set();
|
|
241
|
+
function rewriteCaretRefs(expr) {
|
|
242
|
+
return expr.replace(/\^([a-zA-Z_][a-zA-Z0-9_]*)/g, "__c('$1')");
|
|
243
|
+
}
|
|
244
|
+
function evalInterpolation(expr, scope, hostElement) {
|
|
245
|
+
const rewritten = rewriteCaretRefs(expr);
|
|
246
|
+
const fn = new Function(
|
|
247
|
+
...Object.keys(scope),
|
|
248
|
+
"__c",
|
|
249
|
+
`"use strict"; try { return (${rewritten}); } catch (e) { return undefined; }`
|
|
250
|
+
);
|
|
251
|
+
return fn(...Object.values(scope), (name) => import_reactivity.reactive.readCaret(hostElement, name));
|
|
252
|
+
}
|
|
253
|
+
function interpolate(source, scope, hostElement) {
|
|
254
|
+
return source.replace(/\$\{([^}]+)\}/g, (_, expr) => {
|
|
255
|
+
try {
|
|
256
|
+
const result = evalInterpolation(expr.trim(), scope, hostElement);
|
|
257
|
+
return result == null ? "" : String(result);
|
|
258
|
+
} catch {
|
|
259
|
+
return "";
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function renderAst(nodes, scope, hostElement) {
|
|
264
|
+
return renderTemplate(
|
|
265
|
+
nodes,
|
|
266
|
+
scope,
|
|
267
|
+
(text, s) => interpolate(text, s, hostElement),
|
|
268
|
+
(expr, s) => evalInterpolation(expr.trim(), s, hostElement)
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
function registerTemplateComponent(templateEl, options = {}) {
|
|
272
|
+
const tagName = templateEl.getAttribute("component");
|
|
273
|
+
if (!tagName || !tagName.includes("-")) {
|
|
274
|
+
if (typeof console !== "undefined") {
|
|
275
|
+
console.error(
|
|
276
|
+
`[@hyperfixi/components] <template component="${tagName}"> must contain a dash`
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
if (REGISTERED.has(tagName) || customElements.get(tagName)) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
REGISTERED.add(tagName);
|
|
285
|
+
const { html: rawTemplateSource, init: initSource } = readTemplate(templateEl);
|
|
286
|
+
const runtime = options.runtime;
|
|
287
|
+
const { html: templateSource, styles } = extractStyles(rawTemplateSource);
|
|
288
|
+
injectScopedStyles(tagName, styles);
|
|
289
|
+
const templateAst = parseTemplate(templateSource);
|
|
290
|
+
class TemplateComponent extends HTMLElement {
|
|
291
|
+
_initialized = false;
|
|
292
|
+
_cleanupFns = [];
|
|
293
|
+
connectedCallback() {
|
|
294
|
+
if (this._initialized) return;
|
|
295
|
+
this._initialized = true;
|
|
296
|
+
if (!this.hasAttribute("dom-scope")) {
|
|
297
|
+
this.setAttribute("dom-scope", "isolated");
|
|
298
|
+
}
|
|
299
|
+
const slotContent = this.innerHTML;
|
|
300
|
+
this.innerHTML = "";
|
|
301
|
+
const attrs = createAttrsProxy(this);
|
|
302
|
+
const renderBody = () => {
|
|
303
|
+
const rendered = renderAst(templateAst, { attrs }, this);
|
|
304
|
+
return substituteSlots(rendered, slotContent);
|
|
305
|
+
};
|
|
306
|
+
if (initSource) {
|
|
307
|
+
try {
|
|
308
|
+
const initCtx = (0, import_core.createContext)(this);
|
|
309
|
+
initCtx.locals.set("attrs", attrs);
|
|
310
|
+
void import_core.hyperscript.eval(initSource, initCtx);
|
|
311
|
+
} catch (err) {
|
|
312
|
+
if (typeof console !== "undefined") {
|
|
313
|
+
console.error("[@hyperfixi/components] init script failed:", err);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const renderOnce = () => {
|
|
318
|
+
this.innerHTML = renderBody();
|
|
319
|
+
try {
|
|
320
|
+
import_core.hyperscript.process(this);
|
|
321
|
+
} catch (err) {
|
|
322
|
+
if (typeof console !== "undefined") {
|
|
323
|
+
console.error("[@hyperfixi/components] hyperscript.process failed:", err);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
renderOnce();
|
|
328
|
+
const stopEffect = import_reactivity.reactive.createEffect(() => renderBody(), renderOnce, this);
|
|
329
|
+
this._cleanupFns.push(stopEffect);
|
|
330
|
+
if (runtime) {
|
|
331
|
+
try {
|
|
332
|
+
runtime.getCleanupRegistry().registerCustom(
|
|
333
|
+
this,
|
|
334
|
+
() => {
|
|
335
|
+
for (const fn of this._cleanupFns) {
|
|
336
|
+
try {
|
|
337
|
+
fn();
|
|
338
|
+
} catch {
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
this._cleanupFns = [];
|
|
342
|
+
},
|
|
343
|
+
"template-component"
|
|
344
|
+
);
|
|
345
|
+
} catch {
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
disconnectedCallback() {
|
|
350
|
+
this._initialized = false;
|
|
351
|
+
for (const fn of this._cleanupFns) {
|
|
352
|
+
try {
|
|
353
|
+
fn();
|
|
354
|
+
} catch {
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
this._cleanupFns = [];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
customElements.define(tagName, TemplateComponent);
|
|
362
|
+
return true;
|
|
363
|
+
} catch (err) {
|
|
364
|
+
REGISTERED.delete(tagName);
|
|
365
|
+
if (typeof console !== "undefined") {
|
|
366
|
+
console.error(`[@hyperfixi/components] customElements.define("${tagName}") failed:`, err);
|
|
367
|
+
}
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function readTemplate(templateEl) {
|
|
372
|
+
const init = templateEl.getAttribute("_") ?? templateEl.getAttribute("data-init");
|
|
373
|
+
let html;
|
|
374
|
+
if (templateEl.content && typeof templateEl.content.childNodes !== "undefined") {
|
|
375
|
+
const container = document.createElement("div");
|
|
376
|
+
for (const child of Array.from(templateEl.content.childNodes)) {
|
|
377
|
+
container.appendChild(child.cloneNode(true));
|
|
378
|
+
}
|
|
379
|
+
html = container.innerHTML;
|
|
380
|
+
} else {
|
|
381
|
+
html = templateEl.innerHTML;
|
|
382
|
+
}
|
|
383
|
+
return { html, init };
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/scan.ts
|
|
387
|
+
function scanAndRegister(root = typeof document !== "undefined" ? document : null, options = {}) {
|
|
388
|
+
if (!root) return 0;
|
|
389
|
+
let count = 0;
|
|
390
|
+
const templates = root.querySelectorAll("template[component]");
|
|
391
|
+
templates.forEach((t) => {
|
|
392
|
+
if (registerTemplateComponent(t, options)) count++;
|
|
393
|
+
});
|
|
394
|
+
const scripts = root.querySelectorAll('script[type="text/hyperscript-template"][component]');
|
|
395
|
+
scripts.forEach((s) => {
|
|
396
|
+
const fake = document.createElement("template");
|
|
397
|
+
const componentAttr = s.getAttribute("component");
|
|
398
|
+
if (componentAttr) fake.setAttribute("component", componentAttr);
|
|
399
|
+
const initScript = s.getAttribute("_");
|
|
400
|
+
if (initScript) fake.setAttribute("data-init", initScript);
|
|
401
|
+
fake.innerHTML = s.textContent ?? "";
|
|
402
|
+
if (registerTemplateComponent(fake, options)) count++;
|
|
403
|
+
});
|
|
404
|
+
return count;
|
|
405
|
+
}
|
|
406
|
+
function watchForTemplates(options = {}) {
|
|
407
|
+
if (typeof document === "undefined" || typeof MutationObserver === "undefined") {
|
|
408
|
+
return () => {
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
const observer = new MutationObserver((mutations) => {
|
|
412
|
+
for (const mut of mutations) {
|
|
413
|
+
for (const node of Array.from(mut.addedNodes)) {
|
|
414
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
415
|
+
const el = node;
|
|
416
|
+
if (el.tagName === "TEMPLATE" && el.hasAttribute("component")) {
|
|
417
|
+
registerTemplateComponent(el, options);
|
|
418
|
+
}
|
|
419
|
+
if (el.tagName === "SCRIPT" && el.getAttribute("type") === "text/hyperscript-template" && el.hasAttribute("component")) {
|
|
420
|
+
const fake = document.createElement("template");
|
|
421
|
+
const componentAttr = el.getAttribute("component");
|
|
422
|
+
if (componentAttr) fake.setAttribute("component", componentAttr);
|
|
423
|
+
const initScript = el.getAttribute("_");
|
|
424
|
+
if (initScript) fake.setAttribute("data-init", initScript);
|
|
425
|
+
fake.innerHTML = el.textContent ?? "";
|
|
426
|
+
registerTemplateComponent(fake, options);
|
|
427
|
+
}
|
|
428
|
+
scanAndRegister(el, options);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
observer.observe(document.documentElement || document.body, {
|
|
433
|
+
childList: true,
|
|
434
|
+
subtree: true
|
|
435
|
+
});
|
|
436
|
+
return () => observer.disconnect();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/index.ts
|
|
440
|
+
var INSTALLED_RUNTIME = null;
|
|
441
|
+
var STOP_WATCH = null;
|
|
442
|
+
var componentsPlugin = {
|
|
443
|
+
name: "@hyperfixi/components",
|
|
444
|
+
install(ctx) {
|
|
445
|
+
INSTALLED_RUNTIME = ctx.runtime;
|
|
446
|
+
},
|
|
447
|
+
/**
|
|
448
|
+
* Scan `root` (defaults to `document`) for template components and register
|
|
449
|
+
* each. Safe to call before or after install (but install is needed for
|
|
450
|
+
* cleanup-registry hookup).
|
|
451
|
+
*/
|
|
452
|
+
scan(root) {
|
|
453
|
+
return scanAndRegister(root, { runtime: INSTALLED_RUNTIME ?? void 0 });
|
|
454
|
+
},
|
|
455
|
+
/**
|
|
456
|
+
* Start watching the document for dynamically-added template components.
|
|
457
|
+
* Idempotent — calling twice is a no-op on the second call.
|
|
458
|
+
* Returns a disposer that also clears the module-level handle.
|
|
459
|
+
*/
|
|
460
|
+
watch() {
|
|
461
|
+
if (STOP_WATCH) return STOP_WATCH;
|
|
462
|
+
const stop = watchForTemplates({ runtime: INSTALLED_RUNTIME ?? void 0 });
|
|
463
|
+
STOP_WATCH = () => {
|
|
464
|
+
stop();
|
|
465
|
+
STOP_WATCH = null;
|
|
466
|
+
};
|
|
467
|
+
return STOP_WATCH;
|
|
468
|
+
},
|
|
469
|
+
unwatch() {
|
|
470
|
+
if (STOP_WATCH) STOP_WATCH();
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
var index_default = componentsPlugin;
|
|
474
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
475
|
+
0 && (module.exports = {
|
|
476
|
+
componentsPlugin,
|
|
477
|
+
registerTemplateComponent,
|
|
478
|
+
scanAndRegister,
|
|
479
|
+
watchForTemplates
|
|
480
|
+
});
|
|
481
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/slots.ts","../src/attrs.ts","../src/register.ts","../src/template-ast.ts","../src/scope-css.ts","../src/scan.ts"],"sourcesContent":["/**\n * @hyperfixi/components — template-component plugin for hyperfixi.\n *\n * Registers custom elements from `<template component=\"tag-name\">` definitions\n * (mirrors upstream _hyperscript 0.9.91's component extension). Users write:\n *\n * ```html\n * <template component=\"my-counter\">\n * <button>Count: ${attrs.initialCount ?? 0}</button>\n * </template>\n *\n * <my-counter initial-count=\"5\"></my-counter>\n * ```\n *\n * Install at app startup:\n *\n * ```ts\n * import { createRuntime, installPlugin } from '@hyperfixi/core';\n * import { componentsPlugin } from '@hyperfixi/components';\n *\n * const runtime = createRuntime();\n * installPlugin(runtime, componentsPlugin);\n * // Then scan (typically after DOMContentLoaded):\n * componentsPlugin.scan(document);\n * ```\n *\n * v2.1 scope:\n * - `<template component=\"tag-name\">` scan + customElements.define\n * - `${attrs.name}` and `${^var}` interpolation (kebab-case attribute →\n * camelCase prop, with Number/Boolean coercion)\n * - `^var` reads tracked via @hyperfixi/reactivity; the template re-stamps\n * when any tracked `^var` changes\n * - Per-instance init script — `<template _=\"set ^count to 0\">` (or `_=`\n * on the upstream `<script type=\"text/hyperscript-template\">` form) runs\n * once on each instance via the runtime's standard init mechanism\n * - `attrs` available as a hyperscript local inside the init script — so\n * `_=\"set ^user to attrs.data as JSON\"` works (descendants don't see\n * attrs; copy via ^vars during init if needed)\n * - `<slot/>` + `<slot name=\"X\"/>` substitution from instantiation children\n * - `#if` / `#for` / `#else` / `#end` template directives\n * - `dom-scope=\"isolated\"` boundary auto-set on each instance — nested\n * components don't leak `^var` reads/writes through each other\n * - `<style>` blocks lifted into <head> wrapped in `@scope (tag-name)` so\n * styles only apply within instances of that tag\n * - disconnectedCallback fires CleanupRegistry teardown\n * - MutationObserver watches for dynamically-added templates\n *\n * v2.2+ deferred:\n * - `#continue` directive in `#for` loops\n * - Reactive array mutation auto-tracking (matches upstream's known limit)\n * - Full parent-scope hyperscript evaluation of attribute values (today\n * `attrs.X` returns the raw string; users `as JSON` to parse)\n */\n\nimport type { HyperfixiPlugin, HyperfixiPluginContext } from '@hyperfixi/core';\nimport type { RuntimeLike } from './types';\nimport { scanAndRegister, watchForTemplates } from './scan';\nimport { registerTemplateComponent } from './register';\n\nexport { registerTemplateComponent, scanAndRegister, watchForTemplates };\n\n/**\n * Module-level handle to the runtime captured at install time. Used by `scan`\n * and `watch` to thread the runtime into each registered component for\n * cleanup-registry access and child-processing.\n */\nlet INSTALLED_RUNTIME: RuntimeLike | null = null;\nlet STOP_WATCH: (() => void) | null = null;\n\n/**\n * Plugin object. `install()` captures the runtime; `scan()` / `watch()` can\n * be called any time after install.\n */\nexport const componentsPlugin: HyperfixiPlugin & {\n scan(root?: ParentNode): number;\n watch(): () => void;\n unwatch(): void;\n} = {\n name: '@hyperfixi/components',\n install(ctx: HyperfixiPluginContext) {\n INSTALLED_RUNTIME = ctx.runtime as unknown as RuntimeLike;\n },\n /**\n * Scan `root` (defaults to `document`) for template components and register\n * each. Safe to call before or after install (but install is needed for\n * cleanup-registry hookup).\n */\n scan(root?: ParentNode): number {\n return scanAndRegister(root, { runtime: INSTALLED_RUNTIME ?? undefined });\n },\n /**\n * Start watching the document for dynamically-added template components.\n * Idempotent — calling twice is a no-op on the second call.\n * Returns a disposer that also clears the module-level handle.\n */\n watch(): () => void {\n if (STOP_WATCH) return STOP_WATCH;\n const stop = watchForTemplates({ runtime: INSTALLED_RUNTIME ?? undefined });\n STOP_WATCH = () => {\n stop();\n STOP_WATCH = null;\n };\n return STOP_WATCH;\n },\n unwatch(): void {\n if (STOP_WATCH) STOP_WATCH();\n },\n};\n\nexport default componentsPlugin;\n","/**\n * Slot substitution — replace `<slot/>` and `<slot name=\"X\"/>` placeholders\n * in a template source string with content provided at instantiation.\n *\n * Port of upstream _hyperscript 0.9.91's `substituteSlots` (src/ext/component.js).\n * Regex-based rather than DOM-based so the template source stays a plain string\n * the render engine can consume.\n */\n\n/**\n * Partition raw slot content into named and default parts.\n * Named = elements with a `slot=\"name\"` attribute.\n * Default = all other children (elements or text).\n */\nfunction partitionSlotContent(slotContent: string): {\n named: Record<string, string>;\n defaultContent: string;\n} {\n const named: Record<string, string> = {};\n const defaultParts: string[] = [];\n\n if (typeof document === 'undefined') {\n // Non-browser fallback: treat everything as default content.\n return { named, defaultContent: slotContent };\n }\n\n const tmp = document.createElement('div');\n tmp.innerHTML = slotContent;\n\n for (const child of Array.from(tmp.childNodes)) {\n if (child.nodeType === Node.ELEMENT_NODE) {\n const el = child as Element;\n const slotName = el.getAttribute('slot');\n if (slotName) {\n el.removeAttribute('slot');\n if (!named[slotName]) named[slotName] = '';\n named[slotName] += (el as Element & { outerHTML: string }).outerHTML;\n continue;\n }\n defaultParts.push((el as Element & { outerHTML: string }).outerHTML);\n } else if (child.nodeType === Node.TEXT_NODE) {\n defaultParts.push(child.textContent ?? '');\n }\n }\n\n return { named, defaultContent: defaultParts.join('') };\n}\n\n/**\n * Replace `<slot name=\"X\"/>` / `<slot name=\"X\"></slot>` with named content,\n * and `<slot/>` / `<slot></slot>` with default content.\n *\n * Returns the template source with all `<slot>` placeholders substituted.\n */\nexport function substituteSlots(templateSource: string, slotContent: string): string {\n if (!slotContent) return templateSource;\n const { named, defaultContent } = partitionSlotContent(slotContent);\n\n // Named slots first: <slot name=\"X\"/> or <slot name=\"X\"></slot>.\n let source = templateSource.replace(\n /<slot\\s+name\\s*=\\s*[\"']([^\"']+)[\"']\\s*\\/?\\s*>(\\s*<\\/slot>)?/g,\n (_match, name) => named[name as string] ?? ''\n );\n\n // Default slots: <slot/> or <slot></slot> (after named, so named-with-no-name\n // attribute doesn't accidentally swallow default slot content).\n source = source.replace(/<slot\\s*\\/?\\s*>(\\s*<\\/slot>)?/g, defaultContent);\n\n return source;\n}\n","/**\n * `attrs` proxy — read component attributes as values on the component scope.\n *\n * Simplified from upstream's hyperscript-expression-evaluating version: for v1\n * we treat attributes as plain strings with a few type coercions (number, bool)\n * and a kebab-case-to-camelCase accessor.\n *\n * `<my-counter initial-count=\"5\">` exposes `attrs.initialCount` = 5 (number).\n */\n\n/**\n * Coerce attribute string to a typed value.\n * Rules:\n * - \"true\" → true\n * - \"false\" → false\n * - number-like strings (e.g. \"5\", \"-3.14\") → number\n * - everything else → original string\n */\nfunction coerceAttrValue(raw: string | null): unknown {\n if (raw == null) return undefined;\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n // Number check: not empty, fully numeric after Number()\n if (raw !== '' && !Number.isNaN(Number(raw)) && /^-?(\\d+\\.?\\d*|\\.\\d+)$/.test(raw)) {\n return Number(raw);\n }\n return raw;\n}\n\n/**\n * Convert camelCase prop name to kebab-case attribute name. Used so that\n * reading `attrs.initialCount` finds the `initial-count=\"...\"` attribute.\n */\nfunction camelToKebab(name: string): string {\n return name.replace(/[A-Z]/g, m => '-' + m.toLowerCase());\n}\n\n/**\n * Create a proxy over a component element's attributes. Getting a property\n * reads and coerces the matching kebab-case attribute. Setting a property\n * writes it back as a string (simple stringification for v1).\n */\nexport function createAttrsProxy(componentEl: Element): Record<string, unknown> {\n return new Proxy({} as Record<string, unknown>, {\n get(_target, prop) {\n if (typeof prop !== 'string' || prop.startsWith('_')) return undefined;\n // Try exact match first (e.g. \"role\", \"data-x\"), then kebab-cased form.\n const exact = componentEl.getAttribute(prop);\n if (exact != null) return coerceAttrValue(exact);\n const kebab = componentEl.getAttribute(camelToKebab(prop));\n if (kebab != null) return coerceAttrValue(kebab);\n return undefined;\n },\n set(_target, prop, value) {\n if (typeof prop !== 'string') return false;\n const attrName = componentEl.hasAttribute(prop) ? prop : camelToKebab(prop);\n componentEl.setAttribute(attrName, value == null ? '' : String(value));\n return true;\n },\n has(_target, prop) {\n if (typeof prop !== 'string') return false;\n return componentEl.hasAttribute(prop) || componentEl.hasAttribute(camelToKebab(prop));\n },\n ownKeys(_target) {\n return Array.from(componentEl.attributes).map(a => a.name);\n },\n getOwnPropertyDescriptor(_target, prop) {\n if (typeof prop !== 'string') return undefined;\n const kebab = camelToKebab(prop);\n if (componentEl.hasAttribute(prop) || componentEl.hasAttribute(kebab)) {\n return {\n enumerable: true,\n configurable: true,\n value: coerceAttrValue(componentEl.getAttribute(prop) ?? componentEl.getAttribute(kebab)),\n };\n }\n return undefined;\n },\n });\n}\n","/**\n * Template-component registry — builds a Custom Element class for each\n * `<template component=\"tag-name\">` element and registers it via\n * `customElements.define`.\n *\n * v2 render model:\n * - `${expr}` interpolation against `attrs`, with `^var` references rewritten\n * to call `reactive.readCaret(host, name)` so reads are tracked\n * - The render is wrapped in `reactive.createEffect(...)` so when any\n * tracked dep (e.g. `^count`) changes, the template re-stamps and the\n * runtime re-processes the new subtree\n * - Per-instance `_=` init script (from `<template _=\"...\">` or\n * `<script type=\"text/hyperscript-template\" _=\"...\">`) is transferred\n * to the host element so the runtime processes it once via its standard\n * init mechanism\n *\n * v2.1 additions:\n * - `attrs` injected as a hyperscript local inside the init script\n * - `dom-scope=\"isolated\"` set on each instance host\n * - `<style>` blocks lifted into <head> as `@scope (tag-name) { ... }`\n *\n * Deferred (v2.2+):\n * - Reactive re-render of attrs (today attrs values are read at first\n * render; mutating an attribute on the host doesn't re-render)\n */\n\nimport type { RuntimeLike } from './types';\nimport { substituteSlots } from './slots';\nimport { createAttrsProxy } from './attrs';\nimport { reactive } from '@hyperfixi/reactivity';\nimport { hyperscript, createContext } from '@hyperfixi/core';\nimport { parseTemplate, renderTemplate, type TemplateNode } from './template-ast';\nimport { extractStyles, injectScopedStyles } from './scope-css';\n\n/**\n * Module-level registry of tag names already defined. `customElements.define`\n * throws on duplicate registration, so we dedupe here.\n */\nconst REGISTERED = new Set<string>();\n\ninterface RegistryOptions {\n runtime?: RuntimeLike;\n}\n\n/**\n * Rewrite `^name` references in an expression so they become calls to a\n * tracked-read helper. Property access continues naturally:\n *\n * ^count → __c('count')\n * ^user.name → __c('user').name\n * ^items.length → __c('items').length\n *\n * Only matches `^` followed by an identifier — bitwise XOR (`a ^ b`) where\n * `b` starts with a digit/punctuation is unaffected. Bitwise XOR with a\n * named operand inside an interpolation is rare enough not to worry about.\n */\nfunction rewriteCaretRefs(expr: string): string {\n return expr.replace(/\\^([a-zA-Z_][a-zA-Z0-9_]*)/g, \"__c('$1')\");\n}\n\n/**\n * Evaluate a `${...}` expression. Supports:\n * - `attrs.X` — read from the component's attrs proxy\n * - `^name` and `^name.path` — read DOM-scoped vars via the reactivity graph\n *\n * Errors silently return empty string (matches upstream tolerance).\n */\nfunction evalInterpolation(\n expr: string,\n scope: Record<string, unknown>,\n hostElement: Element\n): unknown {\n const rewritten = rewriteCaretRefs(expr);\n const fn = new Function(\n ...Object.keys(scope),\n '__c',\n `\"use strict\"; try { return (${rewritten}); } catch (e) { return undefined; }`\n );\n return fn(...Object.values(scope), (name: string) => reactive.readCaret(hostElement, name));\n}\n\n/**\n * Stamp a static text block by replacing each `${...}` with the stringified\n * result of `evalInterpolation`.\n */\nfunction interpolate(source: string, scope: Record<string, unknown>, hostElement: Element): string {\n return source.replace(/\\$\\{([^}]+)\\}/g, (_, expr) => {\n try {\n const result = evalInterpolation(expr.trim(), scope, hostElement);\n return result == null ? '' : String(result);\n } catch {\n return '';\n }\n });\n}\n\n/**\n * Render a parsed template AST (with `#if`/`#for` directives) against a scope.\n * Routes both `${...}` interpolation and bare-expression evaluation through\n * the same caret-aware path so `^var` works uniformly.\n */\nfunction renderAst(\n nodes: TemplateNode[],\n scope: Record<string, unknown>,\n hostElement: Element\n): string {\n return renderTemplate(\n nodes,\n scope,\n (text, s) => interpolate(text, s, hostElement),\n (expr, s) => evalInterpolation(expr.trim(), s, hostElement)\n );\n}\n\n/**\n * Register a single `<template component=\"tag-name\">` element.\n * Idempotent: returns false (without error) if the tag is already registered.\n */\nexport function registerTemplateComponent(\n templateEl: HTMLTemplateElement,\n options: RegistryOptions = {}\n): boolean {\n const tagName = templateEl.getAttribute('component');\n if (!tagName || !tagName.includes('-')) {\n if (typeof console !== 'undefined') {\n console.error(\n `[@hyperfixi/components] <template component=\"${tagName}\"> must contain a dash`\n );\n }\n return false;\n }\n if (REGISTERED.has(tagName) || customElements.get(tagName)) {\n return false;\n }\n REGISTERED.add(tagName);\n\n const { html: rawTemplateSource, init: initSource } = readTemplate(templateEl);\n const runtime = options.runtime;\n\n // Lift `<style>` blocks out of the template, scope them to this tag, and\n // inject into <head>. The cleaned HTML (without the `<style>` blocks) is\n // what each instance stamps. Idempotent — calling registerTemplateComponent\n // a second time for the same tag is a no-op above; the style injection has\n // its own data-component dedup so re-extraction is harmless either way.\n const { html: templateSource, styles } = extractStyles(rawTemplateSource);\n injectScopedStyles(tagName, styles);\n\n // Parse the template AST once at registration time. Each instance reuses\n // this AST and re-renders against its own scope.\n const templateAst = parseTemplate(templateSource);\n\n class TemplateComponent extends HTMLElement {\n private _initialized = false;\n private _cleanupFns: Array<() => void> = [];\n\n connectedCallback() {\n if (this._initialized) return;\n this._initialized = true;\n\n // Mark this instance as a `^var` isolation boundary so descendant\n // caret-var reads/writes don't walk past it into the parent scope.\n // Set BEFORE init runs so the init's own `set ^X to Y` writes land\n // here (findCaretOwner stops at the boundary if no owner is found).\n if (!this.hasAttribute('dom-scope')) {\n this.setAttribute('dom-scope', 'isolated');\n }\n\n // Capture slot content (innerHTML) BEFORE we stamp the template, so\n // children written in the page get inserted into `<slot/>` placeholders.\n const slotContent = this.innerHTML;\n this.innerHTML = '';\n\n const attrs = createAttrsProxy(this);\n\n // Slot substitution happens on the source HTML before AST rendering, so\n // <slot/> placeholders are replaced once per instance against the AST's\n // serialized output. (Slots aren't reactive — content is stamped at\n // first render and stays stable across `^var` re-renders.)\n const renderBody = (): string => {\n const rendered = renderAst(templateAst, { attrs }, this);\n return substituteSlots(rendered, slotContent);\n };\n\n // Run init `_=` once via hyperscript.eval. We do NOT put it on the host\n // as an attribute — that would cause every subsequent reactive re-render\n // (which calls hyperscript.process(this)) to re-run init and reset state.\n //\n // We build the context manually so we can pre-populate `attrs` as a\n // local. That makes the upstream pattern `set ^user to attrs.data`\n // work — `attrs` is then resolvable as a hyperscript identifier inside\n // the init script. (Descendants' `_=` attributes go through the\n // standard process path and don't see `attrs` — by design; if you need\n // attrs values in descendants, copy them into `^vars` during init.)\n if (initSource) {\n try {\n const initCtx = createContext(this);\n initCtx.locals.set('attrs', attrs);\n void hyperscript.eval(initSource, initCtx);\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.error('[@hyperfixi/components] init script failed:', err);\n }\n }\n }\n\n // Synchronous first render so callers see content immediately on\n // appendChild — matches v1 semantics. Tracking-aware re-renders happen\n // through the reactive effect below.\n // Note: `hyperscript.process` is the singleton API entry point that\n // compiles + binds `_=` attributes (the per-runtime `Runtime` class\n // does not expose process directly).\n const renderOnce = (): void => {\n this.innerHTML = renderBody();\n try {\n hyperscript.process(this);\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.error('[@hyperfixi/components] hyperscript.process failed:', err);\n }\n }\n };\n renderOnce();\n\n // Reactive effect: any `^var` read during render is tracked, and\n // writes to those vars trigger a re-stamp + re-process. Effect\n // initializes via microtask; first run sees same content (Object.is\n // skips handler) but records dependencies for subsequent writes.\n const stopEffect = reactive.createEffect(() => renderBody(), renderOnce, this);\n this._cleanupFns.push(stopEffect);\n\n // Register cleanup so disconnect fires teardown of any hyperscript\n // observers bound to children. Uses core's CleanupRegistry via the\n // runtime passed at install time.\n if (runtime) {\n try {\n runtime.getCleanupRegistry().registerCustom(\n this,\n () => {\n for (const fn of this._cleanupFns) {\n try {\n fn();\n } catch {\n /* ignore */\n }\n }\n this._cleanupFns = [];\n },\n 'template-component'\n );\n } catch {\n /* getCleanupRegistry missing — skip */\n }\n }\n }\n\n disconnectedCallback() {\n this._initialized = false;\n for (const fn of this._cleanupFns) {\n try {\n fn();\n } catch {\n /* ignore */\n }\n }\n this._cleanupFns = [];\n }\n }\n\n try {\n customElements.define(tagName, TemplateComponent);\n return true;\n } catch (err) {\n REGISTERED.delete(tagName);\n if (typeof console !== 'undefined') {\n console.error(`[@hyperfixi/components] customElements.define(\"${tagName}\") failed:`, err);\n }\n return false;\n }\n}\n\n/**\n * Read a template definition: extract the body HTML and (if present) the\n * per-instance init script. Init source is read from `_=` (preferred) or\n * `data-init` (the `<script>`-form converter sets this in scan.ts).\n */\nfunction readTemplate(templateEl: HTMLTemplateElement): { html: string; init: string | null } {\n const init = templateEl.getAttribute('_') ?? templateEl.getAttribute('data-init');\n let html: string;\n if (templateEl.content && typeof templateEl.content.childNodes !== 'undefined') {\n const container = document.createElement('div');\n for (const child of Array.from(templateEl.content.childNodes)) {\n container.appendChild(child.cloneNode(true));\n }\n html = container.innerHTML;\n } else {\n html = templateEl.innerHTML;\n }\n return { html, init };\n}\n\n/**\n * Clear the registered-tags set. Intended for test isolation only — custom\n * element registrations cannot be un-defined, so this only affects our\n * idempotency check, not the real registry.\n */\nexport function _resetRegisteredForTest(): void {\n REGISTERED.clear();\n}\n","/**\n * Template AST — parse + render with `#if`/`#else`/`#end`/`#for` directives.\n *\n * Mirrors upstream _hyperscript 0.9.91's component template syntax. Directives\n * are line-oriented: each directive must occupy its own line (modulo\n * surrounding whitespace). `${...}` interpolation can appear anywhere in\n * static text; it's evaluated by the same path used outside directives.\n *\n * Supported:\n * #if <expr> ... [#else] ... #end\n * #for <name> in <expr> ... [#else] ... #end (#else fires on empty)\n *\n * Deferred (v2.1+):\n * #continue — skip the current iteration of the enclosing `#for`\n */\n\nexport type TemplateNode =\n | { kind: 'text'; content: string }\n | { kind: 'if'; cond: string; then: TemplateNode[]; else: TemplateNode[] }\n | {\n kind: 'for';\n varName: string;\n iterableExpr: string;\n body: TemplateNode[];\n elseEmpty: TemplateNode[];\n };\n\nconst IF_RE = /^#if\\s+(.+)$/;\nconst ELSE_RE = /^#else\\s*$/;\nconst END_RE = /^#end\\s*$/;\nconst FOR_RE = /^#for\\s+([A-Za-z_$][\\w$]*)\\s+in\\s+(.+)$/;\n\n/**\n * Parse a template body into a sequence of TemplateNodes.\n * Directives are recognized only when they occupy their own line.\n */\nexport function parseTemplate(source: string): TemplateNode[] {\n const lines = source.split('\\n');\n const cursor = { i: 0 };\n\n function parseBlock(stop: (line: string) => boolean): TemplateNode[] {\n const nodes: TemplateNode[] = [];\n let textBuffer: string[] = [];\n\n const flushText = (): void => {\n if (textBuffer.length > 0) {\n nodes.push({ kind: 'text', content: textBuffer.join('\\n') });\n textBuffer = [];\n }\n };\n\n while (cursor.i < lines.length) {\n const line = lines[cursor.i];\n const trimmed = line.trim();\n\n if (stop(trimmed)) {\n flushText();\n return nodes;\n }\n\n const ifMatch = IF_RE.exec(trimmed);\n const forMatch = FOR_RE.exec(trimmed);\n\n if (ifMatch) {\n flushText();\n const cond = ifMatch[1].trim();\n cursor.i++;\n const thenBlock = parseBlock(l => ELSE_RE.test(l) || END_RE.test(l));\n let elseBlock: TemplateNode[] = [];\n if (cursor.i < lines.length && ELSE_RE.test(lines[cursor.i].trim())) {\n cursor.i++;\n elseBlock = parseBlock(l => END_RE.test(l));\n }\n if (cursor.i < lines.length && END_RE.test(lines[cursor.i].trim())) cursor.i++;\n nodes.push({ kind: 'if', cond, then: thenBlock, else: elseBlock });\n } else if (forMatch) {\n flushText();\n const varName = forMatch[1];\n const iterableExpr = forMatch[2].trim();\n cursor.i++;\n const bodyBlock = parseBlock(l => ELSE_RE.test(l) || END_RE.test(l));\n let elseEmptyBlock: TemplateNode[] = [];\n if (cursor.i < lines.length && ELSE_RE.test(lines[cursor.i].trim())) {\n cursor.i++;\n elseEmptyBlock = parseBlock(l => END_RE.test(l));\n }\n if (cursor.i < lines.length && END_RE.test(lines[cursor.i].trim())) cursor.i++;\n nodes.push({\n kind: 'for',\n varName,\n iterableExpr,\n body: bodyBlock,\n elseEmpty: elseEmptyBlock,\n });\n } else {\n textBuffer.push(line);\n cursor.i++;\n }\n }\n flushText();\n return nodes;\n }\n\n return parseBlock(() => false);\n}\n\n/**\n * Render a parsed template AST against a scope. `interpText` handles `${...}`\n * interpolation in static blocks; `evalExpr` evaluates the bare expression in\n * `#if <expr>` and `#for <var> in <expr>`. Both are passed in so the renderer\n * stays decoupled from the components plugin's host-element / caret-var\n * specifics — each callsite supplies the appropriate evaluator closure.\n */\nexport function renderTemplate(\n nodes: TemplateNode[],\n scope: Record<string, unknown>,\n interpText: (text: string, scope: Record<string, unknown>) => string,\n evalExpr: (expr: string, scope: Record<string, unknown>) => unknown\n): string {\n return nodes\n .map(node => {\n if (node.kind === 'text') {\n return interpText(node.content, scope);\n }\n if (node.kind === 'if') {\n const value = evalExpr(node.cond, scope);\n const branch = value ? node.then : node.else;\n return renderTemplate(branch, scope, interpText, evalExpr);\n }\n // for\n const iterable = evalExpr(node.iterableExpr, scope) as Iterable<unknown> | null | undefined;\n const items =\n iterable != null &&\n typeof (iterable as { [Symbol.iterator]?: unknown })[Symbol.iterator] === 'function'\n ? Array.from(iterable as Iterable<unknown>)\n : [];\n if (items.length === 0) {\n return renderTemplate(node.elseEmpty, scope, interpText, evalExpr);\n }\n return items\n .map(item =>\n renderTemplate(node.body, { ...scope, [node.varName]: item }, interpText, evalExpr)\n )\n .join('\\n');\n })\n .join('\\n');\n}\n","/**\n * Scoped CSS — lift `<style>` blocks out of component templates and inject\n * them into `<head>` wrapped in `@scope (tag-name) { ... }`.\n *\n * Mirrors upstream _hyperscript 0.9.91's component style-scoping behavior.\n * Two reasons we do this:\n * 1. Without lifting, every instance's innerHTML would contain a copy of\n * the `<style>` block. The browser parses each one — wasteful and a\n * footgun if the user uses non-`@scope` selectors.\n * 2. Wrapping the contents in `@scope (tag-name) { ... }` confines them\n * to that custom-element tree, so styles authored against a generic\n * `.btn` class don't leak globally.\n *\n * Browser support: `@scope` is in Chrome 118+, Safari 17.4+, Firefox 128+.\n * In older browsers, the `@scope` rule is ignored and styles leak globally\n * — graceful degradation; nothing actively breaks.\n *\n * Idempotency: the same component may be (re)scanned multiple times via\n * `componentsPlugin.scan()` followed by `watchForTemplates()`. We dedupe by\n * a `data-component=\"${tagName}\"` attribute on the injected `<style>`.\n */\n\nconst STYLE_BLOCK_RE = /<style(?:\\s[^>]*)?>([\\s\\S]*?)<\\/style\\s*>/gi;\n\nexport interface ExtractResult {\n /** The HTML with all `<style>` blocks removed. */\n html: string;\n /** The raw text content of each removed `<style>` block, in document order. */\n styles: string[];\n}\n\n/**\n * Strip `<style>...</style>` blocks from `html` and return their text content.\n * Preserves the surrounding HTML otherwise. Tag-attributes on `<style>` are\n * dropped (we re-build the injected element's attributes ourselves).\n */\nexport function extractStyles(html: string): ExtractResult {\n const styles: string[] = [];\n const cleaned = html.replace(STYLE_BLOCK_RE, (_match, body: string) => {\n styles.push(body);\n return '';\n });\n return { html: cleaned, styles };\n}\n\n/**\n * Inject the given style blocks into `document.head` as a single\n * `<style data-component=\"${tagName}\">` element wrapped in `@scope`. No-op if\n * `styles` is empty or if the injection has already been done for this tag.\n *\n * Returns `true` if injection happened, `false` if it was skipped (already\n * present, no styles, or no document/head available).\n */\nexport function injectScopedStyles(tagName: string, styles: string[]): boolean {\n if (styles.length === 0) return false;\n if (typeof document === 'undefined' || !document.head) return false;\n\n const selector = `style[data-component=\"${cssAttrEscape(tagName)}\"]`;\n if (document.head.querySelector(selector)) return false;\n\n const wrapped = styles.map(body => `@scope (${tagName}) {\\n${body}\\n}`).join('\\n\\n');\n const styleEl = document.createElement('style');\n styleEl.setAttribute('data-component', tagName);\n styleEl.textContent = wrapped;\n document.head.appendChild(styleEl);\n return true;\n}\n\n/**\n * Test-only helper: remove any styles previously injected by\n * `injectScopedStyles`. Real usage doesn't need this — once a component is\n * registered, its scoped styles persist for the page's lifetime.\n */\nexport function _resetInjectedStylesForTest(): void {\n if (typeof document === 'undefined' || !document.head) return;\n const injected = document.head.querySelectorAll('style[data-component]');\n injected.forEach(el => el.parentNode?.removeChild(el));\n}\n\n/**\n * Escape `tagName` for safe use inside a CSS attribute-selector string.\n * Custom-element tag names are restricted by the spec (lowercase ASCII +\n * digit + hyphen + colon + dot + underscore), so this is mostly defensive.\n */\nfunction cssAttrEscape(s: string): string {\n return s.replace(/[\"\\\\]/g, '\\\\$&');\n}\n","/**\n * DOM scanner — finds `<template component=\"tag-name\">` elements and\n * registers them. Also supports `<script type=\"text/hyperscript-template\"\n * component=\"tag-name\">` for upstream compatibility.\n */\n\nimport type { RuntimeLike } from './types';\nimport { registerTemplateComponent } from './register';\n\ninterface ScanOptions {\n runtime?: RuntimeLike;\n}\n\n/**\n * Scan the given root (defaults to `document`) for template definitions and\n * register each as a custom element.\n *\n * Returns the number of new registrations performed.\n */\nexport function scanAndRegister(\n root: ParentNode = typeof document !== 'undefined' ? document : (null as never),\n options: ScanOptions = {}\n): number {\n if (!root) return 0;\n let count = 0;\n\n // <template component=\"tag-name\">\n const templates = root.querySelectorAll('template[component]');\n templates.forEach(t => {\n if (registerTemplateComponent(t as HTMLTemplateElement, options)) count++;\n });\n\n // <script type=\"text/hyperscript-template\" component=\"tag-name\" _=\"init script\">\n // Upstream uses this form; we support it for compat. Convert to a\n // synthetic HTMLTemplateElement so register code is shared. Init scripts\n // (`_=`) are preserved so they run once per instance.\n const scripts = root.querySelectorAll('script[type=\"text/hyperscript-template\"][component]');\n scripts.forEach(s => {\n const fake = document.createElement('template');\n const componentAttr = s.getAttribute('component');\n if (componentAttr) fake.setAttribute('component', componentAttr);\n const initScript = s.getAttribute('_');\n if (initScript) fake.setAttribute('data-init', initScript);\n fake.innerHTML = s.textContent ?? '';\n if (registerTemplateComponent(fake, options)) count++;\n });\n\n return count;\n}\n\n/**\n * Start watching the document for dynamically-added template definitions.\n * Returns a disposer that stops the observer.\n *\n * Safe to call in non-DOM environments (returns a no-op disposer).\n */\nexport function watchForTemplates(options: ScanOptions = {}): () => void {\n if (typeof document === 'undefined' || typeof MutationObserver === 'undefined') {\n return () => {};\n }\n\n const observer = new MutationObserver(mutations => {\n for (const mut of mutations) {\n for (const node of Array.from(mut.addedNodes)) {\n if (node.nodeType !== Node.ELEMENT_NODE) continue;\n const el = node as Element;\n // Added node itself\n if (el.tagName === 'TEMPLATE' && el.hasAttribute('component')) {\n registerTemplateComponent(el as HTMLTemplateElement, options);\n }\n if (\n el.tagName === 'SCRIPT' &&\n el.getAttribute('type') === 'text/hyperscript-template' &&\n el.hasAttribute('component')\n ) {\n const fake = document.createElement('template');\n const componentAttr = el.getAttribute('component');\n if (componentAttr) fake.setAttribute('component', componentAttr);\n const initScript = el.getAttribute('_');\n if (initScript) fake.setAttribute('data-init', initScript);\n fake.innerHTML = el.textContent ?? '';\n registerTemplateComponent(fake, options);\n }\n // Descendants\n scanAndRegister(el, options);\n }\n }\n });\n\n observer.observe(document.documentElement || document.body, {\n childList: true,\n subtree: true,\n });\n\n return () => observer.disconnect();\n}\n"],"mappings":"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","names":[]}
|