@expressive/dom 0.6.0 → 0.8.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as untrack, c as enter, d as release, f as schedule, i as track, l as afterFlush, m as transition, n as latest, o as call, p as settle$1, r as same, s as dispose, u as claim$1 } from "./chunk-hot-a8qgv3tf.js";
2
- import { a as createElement, i as childrenOf, n as PORTAL, o as isVNode, r as Portal, s as vnode, t as Fragment } from "./chunk-vnode-wpCWQ_Zg.js";
1
+ import { a as untrack, c as enter, d as claim$1, f as release, h as transition, i as track, l as owner, m as settle$1, n as latest, o as call, p as schedule, r as same, s as dispose, u as afterFlush } from "./chunk-hot-vusv_ouU.js";
2
+ import { a as authoring, c as isVNode, i as authorOf, l as vnode, n as PORTAL, o as childrenOf, r as Portal, s as createElement, t as Fragment } from "./chunk-vnode-BN2KOsCV.js";
3
3
  import "./jsx-runtime.js";
4
4
  import { Component, Context, Model, has, map, unbind } from "@expressive/mvc";
5
5
  import { watch } from "@expressive/mvc/observable";
@@ -12,7 +12,7 @@ let probe;
12
12
  * Does the CSSOM accept a bare number for this property? Probed once with a
13
13
  * canonical value; the answer is a property of CSS, not of the value.
14
14
  */
15
- function bare(property) {
15
+ function bare$1(property) {
16
16
  let known = unitless.get(property);
17
17
  if (known === void 0) {
18
18
  probe ||= document.createElement("div").style;
@@ -24,30 +24,14 @@ function bare(property) {
24
24
  }
25
25
  function sized(property, value) {
26
26
  if (Array.isArray(value)) return value.map((entry) => sized(property, entry));
27
- return typeof value == "number" && value !== 0 && !bare(property) ? `${value}px` : value;
27
+ return typeof value == "number" && value !== 0 && !bare$1(property) ? `${value}px` : value;
28
28
  }
29
29
  /**
30
30
  * Web macro pack. Register with `macro(css)` to opt into pixel units for
31
- * numbers and the axis shorthands CSS itself does not provide.
31
+ * numbers and the `size` shorthand.
32
32
  */
33
33
  const css = {
34
34
  "*": (value, key) => ({ [key]: sized(key, value) }),
35
- mx: (value) => ({
36
- marginLeft: value,
37
- marginRight: value
38
- }),
39
- my: (value) => ({
40
- marginTop: value,
41
- marginBottom: value
42
- }),
43
- px: (value) => ({
44
- paddingLeft: value,
45
- paddingRight: value
46
- }),
47
- py: (value) => ({
48
- paddingTop: value,
49
- paddingBottom: value
50
- }),
51
35
  size: (value) => Array.isArray(value) ? {
52
36
  width: value[0],
53
37
  height: value[1]
@@ -57,8 +41,26 @@ const css = {
57
41
  }
58
42
  };
59
43
 
44
+ //#endregion
45
+ //#region src/style/units.ts
46
+ function unit(suffix) {
47
+ return (...values) => values.map((value) => value + suffix).join(" ");
48
+ }
49
+ const rem = unit("rem");
50
+ const em = unit("em");
51
+ const px = unit("px");
52
+
53
+ //#endregion
54
+ //#region src/style/media.ts
55
+ function media(query) {
56
+ return `@media ${Object.entries(query).map(([key, value]) => {
57
+ return `(${key.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)}: ${typeof value == "number" ? `${value}px` : value})`;
58
+ }).join(" and ")}`;
59
+ }
60
+
60
61
  //#endregion
61
62
  //#region src/style/protocol.ts
63
+ const SUBCOMPONENT = /^_[A-Z]/;
62
64
  const registrations = /* @__PURE__ */ new WeakMap();
63
65
  const tokens = /* @__PURE__ */ new WeakMap();
64
66
  let root;
@@ -84,7 +86,7 @@ function appearanceRoot() {
84
86
  function appearanceSealed() {
85
87
  return rendered;
86
88
  }
87
- function enterAppearance(parent, type) {
89
+ function enterAppearance(parent, type, key) {
88
90
  const chain = [];
89
91
  let current = type;
90
92
  while (current && current !== Function.prototype) {
@@ -92,9 +94,12 @@ function enterAppearance(parent, type) {
92
94
  if (enter) chain.unshift(enter);
93
95
  current = Object.getPrototypeOf(current);
94
96
  }
95
- for (const enter of chain) parent = enter(parent);
97
+ for (const enter of chain) parent = enter(parent, key);
96
98
  return parent;
97
99
  }
100
+ function reserved(key) {
101
+ if (SUBCOMPONENT.test(key)) throw new Error(`"${key}" is reserved for subcomponents in style() maps.`);
102
+ }
98
103
  function createAppearanceToken(appearance) {
99
104
  const token = {};
100
105
  tokens.set(token, appearance);
@@ -107,6 +112,9 @@ function appearanceToken(value) {
107
112
  //#endregion
108
113
  //#region src/style/appearance.ts
109
114
  const bases = /* @__PURE__ */ new WeakMap();
115
+ const groups$1 = /* @__PURE__ */ new WeakMap();
116
+ const ownGroups = /* @__PURE__ */ new WeakMap();
117
+ const ancestors = /* @__PURE__ */ new Map();
110
118
  const chains = /* @__PURE__ */ new WeakMap();
111
119
  const contexts = /* @__PURE__ */ new WeakMap();
112
120
  const rootScopes = /* @__PURE__ */ new WeakMap();
@@ -122,42 +130,55 @@ function createStyleScope(parent, value, label, defines) {
122
130
  const own = [];
123
131
  const source = {};
124
132
  const base = {};
133
+ const scopeLabel = label || parent?.label || "style";
134
+ const root = { name: scopeLabel };
125
135
  for (const key of Object.keys(value)) {
126
136
  const entry = value[key];
127
137
  if (key[0] == "$") throw new Error(`Reserved key "${key}" in style map.`);
138
+ if (SUBCOMPONENT.test(key)) throw new Error(`Subcomponent "${key}" must be at the top of a style() map.`);
128
139
  if (key[0] == "_") {
129
140
  if (!isObject(entry)) throw new Error(`Rule "${key}" must be an object. Macros are defined by macro().`);
130
141
  const name = key.slice(1);
131
- own.push(name);
132
- source[name] = entry;
142
+ if (!own.includes(name)) own.push(name);
143
+ source[name] = merge(source[name], entry);
144
+ } else if (isCondition(key) && isObject(entry)) {
145
+ const rest = {};
146
+ for (const inner of Object.keys(entry)) if (inner[0] == "_") {
147
+ const name = inner.slice(1);
148
+ if (!own.includes(name)) own.push(name);
149
+ for (const when of split(key)) source[name] = merge(source[name], { [hoist(root, when)]: entry[inner] });
150
+ } else rest[inner] = entry[inner];
151
+ base[key] = merge(base[key], rest);
133
152
  } else if (defines && typeof entry == "function") {
134
153
  own.push(key);
135
154
  source[key] = entry;
136
155
  } else base[key] = entry;
137
156
  }
138
157
  const names = parent ? [...parent.names, ...own.filter((name) => !parent.names.includes(name))] : own;
158
+ const before = parent && parent !== parent.globals ? parent.local : [];
159
+ const local = defines ? [] : [...before, ...own.filter((name) => !before.includes(name))];
139
160
  const rules = Object.create(parent?.rules || null);
140
161
  const labels = Object.create(parent?.labels || null);
141
- const scopeLabel = label || parent?.label || "style";
142
162
  for (const name of own) {
143
163
  const rule = source[name];
144
164
  const inherited = parent?.rules[name];
145
- rules[name] = isObject(inherited) && isObject(rule) ? {
146
- ...inherited,
147
- ...rule
148
- } : rule;
165
+ rules[name] = isObject(inherited) && isObject(rule) && (defines || inherited !== parent.globals?.rules[name]) ? mergeRule(inherited, rule) : rule;
149
166
  labels[name] = scopeLabel;
150
167
  }
151
168
  const scope = {
152
169
  children: /* @__PURE__ */ new WeakMap(),
153
170
  expansions: /* @__PURE__ */ new Map(),
171
+ globals: parent?.globals,
154
172
  label: scopeLabel,
155
173
  labels,
174
+ local,
156
175
  names,
157
176
  own: base,
158
177
  routes: /* @__PURE__ */ new Map(),
159
178
  rules
160
179
  };
180
+ if (defines) scope.globals = scope;
181
+ if (root.group) ownGroups.set(scope, root.group);
161
182
  cache.set(value, scope);
162
183
  return scope;
163
184
  }
@@ -177,40 +198,54 @@ function createContext(scope) {
177
198
  function extendContext(parent, maps, label, defines) {
178
199
  let scope = parent?.scope;
179
200
  const base = { ...scope && bases.get(scope) };
201
+ const anchors = new Set(scope && groups$1.get(scope));
180
202
  for (const map of maps) {
181
203
  scope = createStyleScope(scope, map, label, defines);
182
- Object.assign(base, scope.own);
204
+ Object.assign(base, mergeRule(base, scope.own));
205
+ const own = ownGroups.get(scope);
206
+ if (own) anchors.add(own);
183
207
  }
184
208
  if (Object.keys(base).length) bases.set(scope, base);
209
+ if (anchors.size) groups$1.set(scope, [...anchors]);
185
210
  return createContext(scope);
186
211
  }
187
212
  function baseToken(scope) {
188
213
  const base = bases.get(scope);
189
- if (!base) return void 0;
190
- const expansion = expand(scope, base, /* @__PURE__ */ new Map());
214
+ const anchors = groups$1.get(scope);
215
+ if (!base && !anchors) return void 0;
216
+ const frame = { name: scope.label };
217
+ const expansion = expand(scope, base, /* @__PURE__ */ new Map(), frame);
218
+ const blocks = [...toBlocks(expansion, frame, shared(scope) - .5), ...anchors || []];
191
219
  const appearance = {};
192
- if (Object.keys(expansion.declarations).length) appearance.blocks = [{
193
- declarations: expansion.declarations,
194
- name: scope.label,
195
- ordinal: -1
196
- }];
220
+ if (blocks.length) appearance.blocks = blocks;
197
221
  if (expansion.classes.length) appearance.classes = expansion.classes;
198
222
  return createAppearanceToken(appearance);
199
223
  }
200
224
  function style$1(type, rules) {
201
225
  if (entered.has(type)) throw new Error("Cannot add styles after a component has rendered.");
202
- if (Object.hasOwn(type, STYLES)) type[STYLES].push(rules);
203
- else {
226
+ if (!Object.hasOwn(type, STYLES)) {
204
227
  const label = type.displayName || type.name;
205
228
  Object.defineProperty(type, STYLES, {
206
229
  configurable: true,
207
- value: [rules]
230
+ value: {
231
+ own: [],
232
+ subs: {}
233
+ }
208
234
  });
209
- registerAppearance(type, (parent) => {
235
+ registerAppearance(type, (parent, key) => {
236
+ const { own, subs } = type[STYLES];
210
237
  entered.add(type);
211
- return extendContext(parent, type[STYLES], label);
238
+ if (!key) return extendContext(parent, own, label);
239
+ return subs[key] ? extendContext(parent, subs[key], `${label}_${key}`) : parent;
212
240
  });
213
241
  }
242
+ const { own, subs } = type[STYLES];
243
+ const rest = {};
244
+ for (const key of Object.keys(rules)) if (SUBCOMPONENT.test(key)) {
245
+ if (!isObject(rules[key])) throw new Error(`Subcomponent "${key}" must be an object.`);
246
+ (subs[key.slice(1)] ||= []).push(rules[key]);
247
+ } else rest[key] = rules[key];
248
+ own.push(rest);
214
249
  return type;
215
250
  }
216
251
  function macro$1(rules) {
@@ -247,8 +282,8 @@ function resolveAppearance(scope, props, tag) {
247
282
  const parts = [];
248
283
  const names = route.tag ? [route.tag] : [];
249
284
  for (const name of route.flags) if (props[`_${name}`]) names.push(name);
250
- for (const name of names) parts.push(expandRule(route.scope, name));
251
- const blocks = parts.flatMap((part) => part.block ? [part.block] : []);
285
+ for (const name of names) expandShadowed(route.scope, name, parts);
286
+ const blocks = parts.flatMap((part) => part.blocks);
252
287
  const classes = parts.flatMap((part) => part.classes);
253
288
  let child = route.scope;
254
289
  for (const part of parts) for (const nested of part.nested) child = createStyleScope(child, nested, tag ? `${route.scope.label}_${tag}` : route.scope.label);
@@ -262,37 +297,83 @@ function resolveAppearance(scope, props, tag) {
262
297
  function expandRule(scope, name) {
263
298
  let expansion = scope.expansions.get(name);
264
299
  if (!expansion) {
265
- expansion = expand(scope, scope.rules[name], /* @__PURE__ */ new Map());
266
- if (Object.keys(expansion.declarations).length) expansion.block = {
267
- declarations: expansion.declarations,
268
- name: `${scope.labels[name]}_${name}`,
269
- ordinal: scope.names.indexOf(name)
270
- };
300
+ const frame = { name: `${scope.labels[name]}_${name}` };
301
+ expansion = expand(scope, scope.rules[name], /* @__PURE__ */ new Map(), frame);
302
+ expansion.blocks = toBlocks(expansion, frame, ordinal(scope, name));
271
303
  scope.expansions.set(name, expansion);
272
304
  }
273
305
  return expansion;
274
306
  }
307
+ function toBlocks({ declarations, variants }, { group, name }, ordinal) {
308
+ const blocks = [];
309
+ if (Object.keys(declarations).length) blocks.push({
310
+ declarations,
311
+ name,
312
+ ordinal
313
+ });
314
+ for (const { declarations, when } of variants) blocks.push({
315
+ declarations,
316
+ name,
317
+ ordinal: ordinal + .5 - .25 / when.length,
318
+ when: when.map((condition) => ancestors.get(condition) || condition)
319
+ });
320
+ if (group) blocks.push(group);
321
+ return blocks;
322
+ }
323
+ function hoist(frame, condition) {
324
+ if (condition[0] != ":") return condition;
325
+ if (condition.includes("::")) throw new Error(`Rules cannot nest inside pseudo-element "${condition}".`);
326
+ frame.group ||= {
327
+ declarations: {},
328
+ group: true,
329
+ name: frame.name,
330
+ ordinal: 0
331
+ };
332
+ const key = `\0${ancestors.size}`;
333
+ ancestors.set(key, {
334
+ on: frame.group,
335
+ state: condition
336
+ });
337
+ return key;
338
+ }
339
+ function shared(scope) {
340
+ return scope.globals ? scope.globals.names.length : 0;
341
+ }
342
+ function ordinal(scope, name) {
343
+ return scope.rules[name] === scope.globals?.rules[name] ? scope.names.indexOf(name) : shared(scope) + scope.local.indexOf(name);
344
+ }
345
+ function expandShadowed(scope, name, parts) {
346
+ const { globals } = scope;
347
+ if (globals && isObject(globals.rules[name]) && globals.rules[name] !== scope.rules[name]) parts.push(expandRule(globals, name));
348
+ parts.push(expandRule(scope, name));
349
+ }
275
350
  function handlers(scope, name) {
276
351
  let known = chains.get(scope);
277
352
  if (!known) chains.set(scope, known = /* @__PURE__ */ new Map());
278
353
  let chain = known.get(name);
279
354
  if (!chain) {
280
- chain = [];
281
- for (const key of [name, "*"]) for (let rules = scope.rules; rules; rules = Object.getPrototypeOf(rules)) {
282
- const own = Object.getOwnPropertyDescriptor(rules, key);
283
- if (own && typeof own.value == "function") chain.push(own.value);
355
+ chain = Object.assign([], { named: 0 });
356
+ for (const key of [name, "*"]) {
357
+ for (let rules = scope.rules; rules; rules = Object.getPrototypeOf(rules)) {
358
+ const own = Object.getOwnPropertyDescriptor(rules, key);
359
+ if (own && typeof own.value == "function") chain.push(own.value);
360
+ }
361
+ if (key == name) chain.named = chain.length;
284
362
  }
285
363
  known.set(name, chain);
286
364
  }
287
365
  return chain;
288
366
  }
289
- function expand(scope, value, depths) {
367
+ function expand(scope, value, depths, frame) {
290
368
  const output = {
369
+ blocks: [],
291
370
  classes: [],
292
371
  declarations: {},
293
- nested: []
372
+ nested: [],
373
+ variants: []
294
374
  };
295
375
  const nested = {};
376
+ const conditions = [];
296
377
  function walk(value, depths) {
297
378
  if (!value) return;
298
379
  if (typeof value == "string") {
@@ -305,25 +386,78 @@ function expand(scope, value, depths) {
305
386
  }
306
387
  for (const [name, entry] of Object.entries(value)) {
307
388
  if (name[0] == "_") {
308
- if (isObject(entry)) nested[name] = entry;
389
+ if (isObject(entry)) nested[name] = merge(nested[name], entry);
390
+ continue;
391
+ }
392
+ if (isCondition(name)) {
393
+ if (isObject(entry)) conditions.push([name, entry]);
394
+ else if (isPresent(entry)) throw new Error(`Condition "${name}" must be an object.`);
309
395
  continue;
310
396
  }
311
397
  const chain = handlers(scope, name);
312
398
  const depth = depths.get(name) || 0;
399
+ if (depth && depth >= chain.named && entry === true) throw new Error(`Macro "${name}" returned itself.`);
313
400
  if (depth < chain.length) {
314
401
  if (isPresent(entry)) walk(chain[depth](entry === true ? void 0 : entry, name), new Map(depths).set(name, depth + 1));
315
402
  } else output.declarations[name] = terminal(name, entry);
316
403
  }
317
404
  }
318
405
  walk(value, depths);
406
+ for (const [key, body] of conditions) for (const when of split(key)) {
407
+ const inner = expand(scope, body, depths, frame);
408
+ if (inner.classes.length) throw new Error(`Classes are not supported inside "${when}".`);
409
+ for (const map of inner.nested) {
410
+ const key = hoist(frame, when);
411
+ for (const rule of Object.keys(map)) nested[rule] = merge(nested[rule], { [key]: map[rule] });
412
+ }
413
+ if (Object.keys(inner.declarations).length) output.variants.push({
414
+ declarations: inner.declarations,
415
+ when: [when]
416
+ });
417
+ for (const variant of inner.variants) output.variants.push({
418
+ declarations: variant.declarations,
419
+ when: [when, ...variant.when]
420
+ });
421
+ }
319
422
  if (Object.keys(nested).length) output.nested.push(nested);
320
423
  return output;
321
424
  }
322
425
  function terminal(name, value) {
323
426
  if (Array.isArray(value)) return value.join(" ");
324
- if (typeof value == "function" || isObject(value)) throw new Error(`No macro handles "${name}".`);
427
+ if (value === true || typeof value == "function" || isObject(value)) throw new Error(`No macro handles "${name}".`);
325
428
  return typeof value == "number" ? String(value) : value;
326
429
  }
430
+ function isCondition(key) {
431
+ return key[0] == ":" || key[0] == "@" || key[0] == "\0";
432
+ }
433
+ function split(key) {
434
+ if (key[0] != ":") return [key];
435
+ const parts = [];
436
+ let depth = 0;
437
+ let start = 0;
438
+ for (let index = 0; index < key.length; index++) {
439
+ const char = key[index];
440
+ if (char == "(") depth++;
441
+ else if (char == ")") depth--;
442
+ else if (char == "," && !depth) {
443
+ parts.push(key.slice(start, index).trim());
444
+ start = index + 1;
445
+ }
446
+ }
447
+ parts.push(key.slice(start).trim());
448
+ return parts;
449
+ }
450
+ function merge(left, right) {
451
+ return isObject(left) ? mergeRule(left, right) : right;
452
+ }
453
+ function mergeRule(left, right) {
454
+ const output = {
455
+ ...left,
456
+ ...right
457
+ };
458
+ for (const key of Object.keys(right)) if (isCondition(key) && isObject(left[key]) && isObject(right[key])) output[key] = mergeRule(left[key], right[key]);
459
+ return output;
460
+ }
327
461
  function isPresent(value) {
328
462
  return value !== false && value !== null && value !== void 0;
329
463
  }
@@ -353,8 +487,9 @@ function applyDeclarations(style, declarations, previous = {}) {
353
487
  //#endregion
354
488
  //#region src/style/stylesheet.ts
355
489
  const sheets = /* @__PURE__ */ new WeakMap();
356
- function style(type, rules) {
357
- style$1(type, rules);
490
+ let groups = 0;
491
+ function style(type, ...maps) {
492
+ for (const rules of maps) if (rules) style$1(type, rules);
358
493
  registerEmitter(emit);
359
494
  return type;
360
495
  }
@@ -377,21 +512,40 @@ function emit(block, depth, document) {
377
512
  };
378
513
  sheets.set(document, sheet);
379
514
  }
515
+ if (block.group) depth = 0;
380
516
  let byDepth = sheet.emitted.get(block);
381
517
  if (!byDepth) sheet.emitted.set(block, byDepth = /* @__PURE__ */ new Map());
382
518
  const cached = byDepth.get(depth);
383
519
  if (cached) return cached;
384
- const css = serialize(document, block.declarations);
385
- const base = (depth ? `${block.name}-d${depth}` : block.name).replace(/[^\w-]/g, "_");
520
+ const when = block.when || [];
521
+ const at = when.filter((condition) => typeof condition == "string" && condition[0] == "@");
522
+ const pseudo = when.filter((condition) => typeof condition == "string" && condition[0] == ":").join("");
523
+ const split = pseudo.indexOf("::");
524
+ const states = split < 0 ? pseudo : pseudo.slice(0, split);
525
+ const element = split < 0 ? "" : pseudo.slice(split);
526
+ const selector = `${when.map((condition) => typeof condition == "string" ? "" : `:where(.${emit(condition.on, 0, document)}${condition.state}) `).join("")}.%${states ? `:where(${states})` : ""}${element}`;
527
+ const css = block.group ? `\0${groups++}` : serialize(document, block.declarations);
528
+ const key = [
529
+ ...at,
530
+ selector,
531
+ css
532
+ ].join("\0");
533
+ const base = [
534
+ depth ? `${block.name}-d${depth}` : block.name,
535
+ ...when.map((condition) => typeof condition == "string" ? condition : condition.on.name + condition.state),
536
+ ...block.group ? ["group"] : []
537
+ ].join("-").replace(/[^\w-]+/g, "_").replace(/_*(-)_*|_+$/g, "$1");
386
538
  let name = base;
387
- for (let index = 2; sheet.names.has(name) && sheet.names.get(name) !== css; index++) name = `${base}-${index}`;
539
+ for (let index = 2; sheet.names.has(name) && sheet.names.get(name) !== key; index++) name = `${base}-${index}`;
388
540
  if (!sheet.names.has(name)) {
389
- const { positions } = sheet;
390
- let at = positions.findIndex(([d, o]) => d > depth || d == depth && o > block.ordinal);
391
- if (at < 0) at = positions.length;
392
- sheet.names.set(name, css);
393
- positions.splice(at, 0, [depth, block.ordinal]);
394
- sheet.element.sheet.insertRule(`.${name}{${css}}`, at);
541
+ sheet.names.set(name, key);
542
+ if (!block.group) {
543
+ const { positions } = sheet;
544
+ let index = positions.findIndex(([d, o]) => d > depth || d == depth && o > block.ordinal);
545
+ if (index < 0) index = positions.length;
546
+ positions.splice(index, 0, [depth, block.ordinal]);
547
+ sheet.element.sheet.insertRule(at.reduceRight((rule, condition) => `${condition}{${rule}}`, `${selector.replace("%", name)}{${css}}`), index);
548
+ }
395
549
  }
396
550
  byDepth.set(depth, name);
397
551
  return name;
@@ -495,82 +649,32 @@ function removeRange(start, end) {
495
649
  }
496
650
  }
497
651
 
498
- //#endregion
499
- //#region src/render/collection.ts
500
- function mountCollection(value, parent, before, context, boundary, appearance) {
501
- const fiber = range("collection", parent, before, context);
502
- fiber.source = value;
503
- fiber.value = value;
504
- fiber.boundary = boundary;
505
- fiber.appearance = appearance;
506
- fiber.scope = makeScope(context, (passive) => runCollection(fiber, passive));
507
- let first = true;
508
- fiber.release = watch(value, (current) => {
509
- fiber.value = current;
510
- if (!first && fiber.scope?.active) schedule(fiber.scope);
511
- first = false;
512
- }, void 0, transition);
513
- return complete(fiber, () => {
514
- runCollection(fiber, passiveRender);
515
- });
516
- }
517
- function runCollection(fiber, passive) {
518
- attempt(fiber, passive, () => {
519
- return fiber.value.render();
520
- });
521
- }
522
- function patchCollection(fiber, appearance) {
523
- if (fiber.appearance === appearance) return;
524
- fiber.appearance = appearance;
525
- runCollection(fiber, passiveRender);
526
- }
527
- function isCollection(value) {
528
- return value instanceof has.List || value instanceof has.Pool || value instanceof map.Managed;
529
- }
530
-
531
- //#endregion
532
- //#region src/node/loader.ts
533
- const LOADS = /* @__PURE__ */ new WeakMap();
534
- function resolve(type, props, run) {
535
- const load = LOADS.get(type);
536
- if (load?.resolved) return vnode(load.resolved, props);
537
- if (load?.failed) {
538
- LOADS.delete(type);
539
- throw load.failed.error;
540
- }
541
- if (load) throw load.pending;
542
- const output = run();
543
- if (!output || typeof output.then != "function") return output;
544
- const next = {};
545
- LOADS.set(type, next);
546
- throw next.pending = output.then((module) => {
547
- const component = typeof module == "function" ? module : module?.default;
548
- if (typeof component == "function") next.resolved = component;
549
- else next.failed = { error: /* @__PURE__ */ new Error("Loader resolved no component.") };
550
- }, (error) => {
551
- next.failed = { error };
552
- });
553
- }
554
-
555
652
  //#endregion
556
653
  //#region src/style/claim.ts
557
654
  const tickets = /* @__PURE__ */ new WeakMap();
558
655
  function componentProps(type, props, appearance) {
559
656
  const context = appearance?.context;
657
+ for (const key of Object.keys(props)) reserved(key);
560
658
  if (!context || typeof type != "function") return {
561
659
  appearance,
562
660
  props
563
661
  };
564
662
  const value = context.resolve(props);
565
- const entries = appearance.entries;
663
+ const { author, entries } = appearance;
566
664
  if (!value) return {
567
- appearance: { entries },
665
+ appearance: {
666
+ author,
667
+ entries,
668
+ lexical: context
669
+ },
568
670
  props
569
671
  };
570
672
  return {
571
673
  appearance: {
674
+ author,
572
675
  context: value.context,
573
- entries
676
+ entries,
677
+ lexical: value.context || context
574
678
  },
575
679
  props: {
576
680
  ...props,
@@ -578,6 +682,9 @@ function componentProps(type, props, appearance) {
578
682
  }
579
683
  };
580
684
  }
685
+ function placed(appearance) {
686
+ return appearance && { entries: appearance.entries };
687
+ }
581
688
  function door(value) {
582
689
  const collected = {
583
690
  classes: [],
@@ -667,11 +774,69 @@ function appendClasses(classes, value) {
667
774
  if (typeof value == "string") classes.push(...value.split(/\s+/).filter(Boolean));
668
775
  }
669
776
 
777
+ //#endregion
778
+ //#region src/render/collection.ts
779
+ function mountCollection(value, parent, before, context, boundary, appearance) {
780
+ const fiber = range("collection", parent, before, context);
781
+ fiber.source = value;
782
+ fiber.value = value;
783
+ fiber.boundary = boundary;
784
+ fiber.appearance = appearance;
785
+ fiber.scope = makeScope(context, (passive) => runCollection(fiber, passive));
786
+ let first = true;
787
+ fiber.release = watch(value, (current) => {
788
+ fiber.value = current;
789
+ if (!first && fiber.scope?.active) schedule(fiber.scope);
790
+ first = false;
791
+ }, void 0, transition);
792
+ return complete(fiber, () => {
793
+ runCollection(fiber, passiveRender);
794
+ });
795
+ }
796
+ function runCollection(fiber, passive) {
797
+ attempt(fiber, passive, () => {
798
+ return fiber.value.render();
799
+ });
800
+ }
801
+ function patchCollection(fiber, appearance) {
802
+ if (fiber.appearance === appearance) return;
803
+ fiber.appearance = appearance;
804
+ runCollection(fiber, passiveRender);
805
+ }
806
+ function isCollection(value) {
807
+ return value instanceof has.List || value instanceof has.Pool || value instanceof map.Managed;
808
+ }
809
+
810
+ //#endregion
811
+ //#region src/node/loader.ts
812
+ const LOADS = /* @__PURE__ */ new WeakMap();
813
+ function resolve(type, props, run) {
814
+ const load = LOADS.get(type);
815
+ if (load?.resolved) return vnode(load.resolved, props);
816
+ if (load?.failed) {
817
+ LOADS.delete(type);
818
+ throw load.failed.error;
819
+ }
820
+ if (load) throw load.pending;
821
+ const output = run();
822
+ if (!output || typeof output.then != "function") return output;
823
+ const next = {};
824
+ LOADS.set(type, next);
825
+ throw next.pending = output.then((module) => {
826
+ const component = typeof module == "function" ? module : module?.default;
827
+ if (typeof component == "function") next.resolved = component;
828
+ else next.failed = { error: /* @__PURE__ */ new Error("Loader resolved no component.") };
829
+ }, (error) => {
830
+ next.failed = { error };
831
+ });
832
+ }
833
+
670
834
  //#endregion
671
835
  //#region src/render/style.ts
672
836
  let rendering;
673
837
  let touched = false;
674
838
  const observed = /* @__PURE__ */ new WeakMap();
839
+ const bare = /* @__PURE__ */ new WeakMap();
675
840
  function observe(props) {
676
841
  if (!("style" in props)) return props;
677
842
  let output = observed.get(props);
@@ -700,7 +865,7 @@ function consume(fiber, render) {
700
865
  rendering = fiber.props;
701
866
  touched = false;
702
867
  try {
703
- const output = render();
868
+ const output = authoring(fiber, render);
704
869
  fiber.consumed = touched;
705
870
  return output;
706
871
  } finally {
@@ -716,7 +881,8 @@ function renderedAppearance(fiber) {
716
881
  style
717
882
  }));
718
883
  const inherited = fiber.appearance?.context || appearanceRoot();
719
- const context = enterAppearance(inherited, latest(fiber.type));
884
+ const sub = owner(fiber.type);
885
+ const context = sub ? enterAppearance(inherited, latest(sub.owner.constructor), sub.key) : enterAppearance(inherited, latest(fiber.type));
720
886
  if (context?.base && context !== inherited) entries.push({
721
887
  hops: 0,
722
888
  style: context.base
@@ -725,10 +891,27 @@ function renderedAppearance(fiber) {
725
891
  hops: 0,
726
892
  style
727
893
  });
728
- return entries.length || context ? {
894
+ if (entries.length || context) return {
895
+ author: fiber,
729
896
  context,
730
897
  entries
731
- } : void 0;
898
+ };
899
+ let empty = bare.get(fiber);
900
+ if (!empty) bare.set(fiber, empty = {
901
+ author: fiber,
902
+ entries
903
+ });
904
+ return empty;
905
+ }
906
+ function authored(value, appearance) {
907
+ const author = authorOf(value);
908
+ if (!author || !appearance || author === appearance.author) return appearance;
909
+ for (let fiber = appearance.author; fiber; fiber = fiber.appearance?.author) if (fiber.appearance?.author === author) return {
910
+ author,
911
+ context: fiber.appearance.lexical,
912
+ entries: appearance.entries
913
+ };
914
+ return appearance;
732
915
  }
733
916
 
734
917
  //#endregion
@@ -784,7 +967,11 @@ function patchProps(fiber, next, appearance) {
784
967
  ...previous,
785
968
  ...next
786
969
  })) {
787
- if (key.startsWith("_") || key == "children" || key == "className" || key == "key" || key == "ref" || key == "style" || CONTROLS.includes(key)) continue;
970
+ if (key[0] == "_") {
971
+ reserved(key);
972
+ continue;
973
+ }
974
+ if (key == "children" || key == "className" || key == "key" || key == "ref" || key == "style" || CONTROLS.includes(key)) continue;
788
975
  if (previous[key] === next[key]) continue;
789
976
  patchProp(fiber, element, key, previous[key], next[key]);
790
977
  }
@@ -793,7 +980,8 @@ function patchProps(fiber, next, appearance) {
793
980
  fiber.claimed = claimed;
794
981
  fiber.props = next;
795
982
  fiber.appearance = appearance;
796
- if (!raw) reconcileChildren(fiber, element, null, next.children, fiber.context, fiber.boundary, claimed.context ? {
983
+ if (!raw) reconcileChildren(fiber, element, null, next.children, fiber.context, fiber.boundary, claimed.context || appearance?.author ? {
984
+ author: appearance?.author,
797
985
  context: claimed.context,
798
986
  entries: []
799
987
  } : void 0);
@@ -962,7 +1150,7 @@ function reconcileChildren(owner, parent, before, value, context, boundary, appe
962
1150
  let child = key !== null && key !== void 0 ? keyed.get(key) : old[index]?.key == null ? old[index] : void 0;
963
1151
  if (child && used.has(child)) child = void 0;
964
1152
  if (child) used.add(child);
965
- const fiber = patch(child, value, parent, before, context, boundary, appearance);
1153
+ const fiber = patch(child, value, parent, before, context, boundary, authored(value, appearance));
966
1154
  if (fiber !== child) used.delete(child);
967
1155
  next.push(fiber);
968
1156
  }
@@ -1175,13 +1363,20 @@ function mountFunction(value, parent, before, context, boundary, appearance) {
1175
1363
  run(fiber, passiveRender);
1176
1364
  });
1177
1365
  }
1366
+ const PLACED = /* @__PURE__ */ new WeakMap();
1367
+ Component.on({ setup(self) {
1368
+ return PLACED.get(self);
1369
+ } });
1178
1370
  function mountOwnedComponent(value, parent, before, context, boundary, appearance) {
1179
1371
  const resolved = componentProps(value.type, value.props, appearance);
1180
1372
  const Type = value.type;
1181
1373
  const props = observe(resolved.props);
1182
- return mountComponent(new Type(props), parent, before, context, boundary, resolved.appearance, true, value.key, props);
1374
+ const instance = new Type(props);
1375
+ let place;
1376
+ PLACED.set(instance, new Promise((resolve) => place = resolve));
1377
+ return mountComponent(instance, parent, before, context, boundary, resolved.appearance, true, value.key, props, place);
1183
1378
  }
1184
- function mountComponent(instance, parent, before, context, inherited, appearance, owned = false, key, props = instance.props) {
1379
+ function mountComponent(instance, parent, before, context, inherited, appearance, owned = false, key, props = instance.props, place) {
1185
1380
  const fiber = range("component", parent, before, context);
1186
1381
  const childContext = context.push(instance);
1187
1382
  const element = owned ? props : {};
@@ -1224,7 +1419,7 @@ function mountComponent(instance, parent, before, context, inherited, appearance
1224
1419
  run(fiber, passiveRender);
1225
1420
  });
1226
1421
  } finally {
1227
- if (owned && !fiber.dead) inserted(fiber, () => fiber.cleanup = instance.mount?.());
1422
+ if (owned && !fiber.dead) inserted(fiber, place);
1228
1423
  }
1229
1424
  return fiber;
1230
1425
  }
@@ -1256,7 +1451,7 @@ function patchFunction(fiber, value, appearance) {
1256
1451
  }
1257
1452
  function patchComponent(fiber, value, appearance) {
1258
1453
  const resolved = isVNode(value) ? componentProps(value.type, value.props, appearance) : {
1259
- appearance,
1454
+ appearance: placed(appearance),
1260
1455
  props: fiber.props
1261
1456
  };
1262
1457
  fiber.appearance = resolved.appearance;
@@ -1275,7 +1470,6 @@ function rerun(fiber, run) {
1275
1470
  settle$1(fiber.scope);
1276
1471
  }
1277
1472
  function unmountComponent(fiber) {
1278
- if (typeof fiber.cleanup == "function") fiber.cleanup();
1279
1473
  fiber.childContext?.pop();
1280
1474
  if (fiber.owned && !fiber.instance.get(null)) fiber.instance.set(null);
1281
1475
  }
@@ -1307,7 +1501,7 @@ function mount(value, parent, before, context, boundary, appearance) {
1307
1501
  children: []
1308
1502
  };
1309
1503
  }
1310
- if (renderable(value)) return mountComponent(value, parent, before, context, boundary, appearance);
1504
+ if (renderable(value)) return mountComponent(value, parent, before, context, boundary, placed(appearance));
1311
1505
  if (value instanceof Model) notRenderable(value.constructor);
1312
1506
  if (isCollection(value)) return mountCollection(value, parent, before, context, boundary, appearance);
1313
1507
  if (!isVNode(value)) throw new TypeError(`Cannot render ${String(value)}.`);
@@ -1436,5 +1630,5 @@ function attempt(fiber, passive, render) {
1436
1630
  }
1437
1631
 
1438
1632
  //#endregion
1439
- export { Fragment, Portal, createElement, css, macro, render, style };
1633
+ export { Fragment, Portal, createElement, css, em, macro, media, px, rem, render, style };
1440
1634
  //# sourceMappingURL=index.js.map