@firsthandjs/dom 0.8.0 → 0.9.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.
@@ -1,3 +1,14 @@
1
+ import {
2
+ FLAT,
3
+ applyChild,
4
+ devComponent,
5
+ devPart,
6
+ devWarn,
7
+ devWarnOnce,
8
+ discard,
9
+ part
10
+ } from "./dev-chunk-HTXIHAW7.js";
11
+
1
12
  // packages/dom/src/adapter.ts
2
13
  var adapter = null;
3
14
  var adapted = /* @__PURE__ */ new WeakMap();
@@ -27,398 +38,16 @@ function adapt(target) {
27
38
  return component_;
28
39
  }
29
40
 
30
- // packages/dom/src/dev.ts
31
- function devWarn(message) {
32
- console.warn(`[firsthand] ${message}`);
33
- }
34
- var seen = /* @__PURE__ */ new Set();
35
- function devWarnOnce(key2, message) {
36
- if (!seen.has(key2)) {
37
- seen.add(key2);
38
- devWarn(message);
39
- }
40
- }
41
- function devWarnRenderedObject(value) {
42
- const cellish = "peek" in value && typeof value.peek === "function" && "value" in value;
43
- devWarnOnce(
44
- cellish ? "rendered-cell" : "rendered-object",
45
- cellish ? 'A signal or computed was rendered directly, so the page shows "[object Object]". Read it instead: {count.value} rather than {count}.' : `An object was rendered as text, so the page shows "${String(value)}". Render a string, a number or a node.`
46
- );
47
- }
48
- function hook() {
49
- const installed2 = globalThis.__FIRSTHAND_DEVTOOLS__;
50
- return installed2 !== void 0 && installed2.attached ? installed2 : void 0;
51
- }
52
- function devPart(node, property) {
53
- hook()?.part(node, property);
54
- }
55
- function devComponent(owner, name) {
56
- hook()?.component(owner, name);
57
- }
58
- function label(value, kind, name) {
59
- if (typeof value === "object" && value !== null) {
60
- hook()?.label(value, kind, name);
61
- }
62
- return value;
63
- }
64
- var QUIET = 20;
65
- function devRan(store2) {
66
- if (store2.busy === true) {
67
- store2.busy = false;
68
- store2.quiet = 0;
69
- return;
70
- }
71
- const quiet = (store2.quiet ?? 0) + 1;
72
- store2.quiet = quiet;
73
- if (quiet !== QUIET) {
74
- return;
75
- }
76
- devWarnOnce(
77
- `quiet-run:${store2.name}`,
78
- `<${store2.name}> ran ${String(QUIET)} times and wrote nothing.
79
- Something it reads in a statement changes more often than what it shows. Move that read into the markup, where it is a part of its own, or move the derivation into a computed in the setup.`
80
- );
81
- }
82
- function devHandedNewFunction(store2, value) {
83
- if (typeof value !== "function") {
84
- return;
85
- }
86
- devWarnOnce(
87
- `new-function:${store2.name}`,
88
- `<${store2.name}> hands a child a new function on every run, so that child runs again whenever this one does.
89
- If the handler does not depend on the run, define it in the setup.`
90
- );
91
- }
92
-
93
- // packages/dom/src/insert.ts
94
- import {
95
- bind,
96
- createOwner,
97
- signal,
98
- disposeOwner,
99
- getOwner,
100
- onCleanup,
101
- runWithOwner,
102
- setOwner
103
- } from "@firsthandjs/core";
104
- var TEXT_NODE = 3;
105
- function isNode(value) {
106
- return typeof value.nodeType === "number";
107
- }
108
- var PART = /* @__PURE__ */ Symbol("firsthand.part");
109
- function part(thunk) {
110
- return { [PART]: true, anchor: document.createTextNode(""), thunk, owner: getOwner() };
111
- }
112
- function isDynamicChild(value) {
113
- return PART in value;
114
- }
115
- function store(name = "") {
116
- return { slots: [], owner: getOwner(), generation: 0, name };
117
- }
118
- function wrote(store2) {
119
- store2.busy = true;
120
- }
121
- function site(store2, index) {
122
- const existing = store2.slots[index];
123
- if (existing !== void 0) {
124
- existing.seen = store2.generation;
125
- return existing;
126
- }
127
- const slot = { seen: store2.generation };
128
- store2.slots[index] = slot;
129
- return slot;
130
- }
131
- function open(store2, slot) {
132
- const owner = createOwner(store2.owner);
133
- slot.owner = owner;
134
- return setOwner(owner);
135
- }
136
- function close(previous) {
137
- setOwner(previous);
138
- }
139
- function ran(store2, value) {
140
- devRan(store2);
141
- const generation = store2.generation;
142
- const slots = store2.slots;
143
- for (let i = 0; i < slots.length; i++) {
144
- const slot = slots[i];
145
- if (slot === void 0 || slot.seen === generation) {
146
- continue;
147
- }
148
- if (slot.owner !== void 0) {
149
- disposeOwner(slot.owner);
150
- }
151
- slots[i] = void 0;
152
- }
153
- store2.generation = generation + 1;
154
- return value;
155
- }
156
- function cell(store2, index, value) {
157
- const slot = site(store2, index);
158
- const existing = slot.cell;
159
- if (existing === void 0) {
160
- const made = signal(value);
161
- slot.cell = made;
162
- return made;
163
- }
164
- if (existing.peek() !== value) {
165
- devHandedNewFunction(store2, value);
166
- wrote(store2);
167
- existing.value = value;
168
- }
169
- return existing;
170
- }
171
- function writeChild(store2, index, parent, marker, value) {
172
- const slot = site(store2, index);
173
- const type = typeof value;
174
- if (type === "string" || type === "number") {
175
- const text = String(value);
176
- if (text === slot.text) {
177
- return;
178
- }
179
- wrote(store2);
180
- slot.text = text;
181
- slot.node = applyChild(parent, marker, slot.node ?? null, text);
182
- return;
183
- }
184
- slot.text = void 0;
185
- if (value === slot.last) {
186
- return;
187
- }
188
- wrote(store2);
189
- slot.last = value;
190
- slot.node = applyChild(parent, marker, slot.node ?? null, value);
191
- }
192
- function insert(parent, value, marker = null) {
193
- if (typeof value !== "function") {
194
- applyChild(parent, marker, null, value);
195
- return;
196
- }
197
- let current = null;
198
- let written;
199
- bind(() => {
200
- const next = value();
201
- const type = typeof next;
202
- if (type === "string" || type === "number") {
203
- const text = String(next);
204
- if (text !== written) {
205
- written = text;
206
- current = applyChild(parent, marker, current, text);
207
- }
208
- return;
209
- }
210
- written = void 0;
211
- if (type === "function") {
212
- current = clear(current);
213
- insert(parent, next, marker);
214
- return;
215
- }
216
- current = applyChild(parent, marker, current, next);
217
- });
218
- onCleanup(() => {
219
- current = clear(current);
220
- });
221
- }
222
- function applyChild(parent, marker, current, value) {
223
- const type = typeof value;
224
- if (value == null || type === "boolean") {
225
- devPart(parent, "text");
226
- return clear(current);
227
- }
228
- if (type === "string" || type === "number") {
229
- devPart(parent, "text");
230
- const text = String(value);
231
- if (current !== null && !Array.isArray(current) && current.nodeType === TEXT_NODE) {
232
- current.data = text;
233
- return current;
234
- }
235
- return single(parent, marker, current, document.createTextNode(text));
236
- }
237
- if (type === "function") {
238
- return applyChild(parent, marker, current, value());
239
- }
240
- if (Array.isArray(value)) {
241
- const next = [];
242
- const dynamic = [];
243
- flatten(value, next, dynamic);
244
- if (next.length === 0) {
245
- return clear(current);
246
- }
247
- reconcile(
248
- parent,
249
- marker,
250
- current === null ? [] : Array.isArray(current) ? current : [current],
251
- next
252
- );
253
- for (let i = 0; i < dynamic.length; i++) {
254
- const child = dynamic[i];
255
- runWithOwner(child.owner ?? getOwner(), () => {
256
- insert(parent, child.thunk, child.anchor);
257
- });
258
- }
259
- return next;
260
- }
261
- if (isDynamicChild(value)) {
262
- return applyChild(parent, marker, current, [value]);
263
- }
264
- if (isNode(value)) {
265
- return single(parent, marker, current, value);
266
- }
267
- devWarnRenderedObject(value);
268
- return applyChild(parent, marker, current, String(value));
269
- }
270
- function flatten(value, out, dynamic) {
271
- for (let i = 0; i < value.length; i++) {
272
- let item = value[i];
273
- if (typeof item === "object" && item !== null && isDynamicChild(item)) {
274
- out.push(item.anchor);
275
- dynamic.push(item);
276
- continue;
277
- }
278
- while (typeof item === "function") {
279
- item = item();
280
- }
281
- if (item == null || typeof item === "boolean") {
282
- continue;
283
- }
284
- if (Array.isArray(item)) {
285
- flatten(item, out, dynamic);
286
- } else if (typeof item === "object" && isNode(item)) {
287
- out.push(item);
288
- } else {
289
- out.push(document.createTextNode(String(item)));
290
- }
291
- }
292
- }
293
- function detach(node) {
294
- const owner = node.parentNode;
295
- if (owner !== null) {
296
- owner.removeChild(node);
297
- }
298
- }
299
- function clear(current) {
300
- if (current !== null) {
301
- if (Array.isArray(current)) {
302
- for (let i = 0; i < current.length; i++) {
303
- detach(current[i]);
304
- }
305
- } else {
306
- detach(current);
307
- }
308
- }
309
- return null;
310
- }
311
- function single(parent, marker, current, node) {
312
- if (current === node) {
313
- return node;
314
- }
315
- if (current !== null && !Array.isArray(current)) {
316
- parent.replaceChild(node, current);
317
- return node;
318
- }
319
- clear(current);
320
- parent.insertBefore(node, marker);
321
- return node;
322
- }
323
- function reconcile(parent, marker, a, b) {
324
- let aStart = 0;
325
- let bStart = 0;
326
- let aEnd = a.length - 1;
327
- let bEnd = b.length - 1;
328
- while (aStart <= aEnd && bStart <= bEnd && a[aStart] === b[bStart]) {
329
- aStart++;
330
- bStart++;
331
- }
332
- while (aStart <= aEnd && bStart <= bEnd && a[aEnd] === b[bEnd]) {
333
- aEnd--;
334
- bEnd--;
335
- }
336
- const after = bEnd + 1 < b.length ? b[bEnd + 1] : marker;
337
- if (aStart > aEnd) {
338
- for (let i = bStart; i <= bEnd; i++) {
339
- parent.insertBefore(b[i], after);
340
- }
341
- return;
342
- }
343
- if (bStart > bEnd) {
344
- for (let i = aStart; i <= aEnd; i++) {
345
- parent.removeChild(a[i]);
346
- }
347
- return;
348
- }
349
- const oldIndex = /* @__PURE__ */ new Map();
350
- for (let i = aStart; i <= aEnd; i++) {
351
- oldIndex.set(a[i], i);
352
- }
353
- const middle = bEnd - bStart + 1;
354
- const sources = new Int32Array(middle).fill(-1);
355
- for (let j = 0; j < middle; j++) {
356
- const node = b[bStart + j];
357
- const found = oldIndex.get(node);
358
- if (found !== void 0) {
359
- sources[j] = found;
360
- oldIndex.delete(node);
361
- }
362
- }
363
- for (const node of oldIndex.keys()) {
364
- parent.removeChild(node);
365
- }
366
- const keep = longestIncreasing(sources);
367
- let k = keep.length - 1;
368
- let anchor = after;
369
- for (let j = middle - 1; j >= 0; j--) {
370
- const node = b[bStart + j];
371
- if (k >= 0 && keep[k] === j) {
372
- k--;
373
- } else {
374
- parent.insertBefore(node, anchor);
375
- }
376
- anchor = node;
377
- }
378
- }
379
- function longestIncreasing(sources) {
380
- const length = sources.length;
381
- const predecessor = new Int32Array(length).fill(-1);
382
- const tails = [];
383
- for (let i = 0; i < length; i++) {
384
- const value = sources[i];
385
- if (value === -1) {
386
- continue;
387
- }
388
- let low = 0;
389
- let high = tails.length;
390
- while (low < high) {
391
- const mid = low + high >> 1;
392
- if (sources[tails[mid]] < value) {
393
- low = mid + 1;
394
- } else {
395
- high = mid;
396
- }
397
- }
398
- if (low > 0) {
399
- predecessor[i] = tails[low - 1];
400
- }
401
- tails[low] = i;
402
- }
403
- const result = [];
404
- let cursor = tails.length > 0 ? tails[tails.length - 1] : -1;
405
- while (cursor !== -1) {
406
- result.push(cursor);
407
- cursor = predecessor[cursor];
408
- }
409
- return result.reverse();
410
- }
411
-
412
41
  // packages/dom/src/component.ts
413
42
  import {
414
- signal as signal2,
415
- createOwner as createOwner2,
43
+ signal,
44
+ createOwner,
416
45
  devEnterSetup,
417
46
  devExitSetup,
418
- disposeOwner as disposeOwner2,
419
- getOwner as getOwner2,
47
+ disposeOwner,
48
+ getOwner,
420
49
  handleError,
421
- setOwner as setOwner2,
50
+ setOwner,
422
51
  untrack
423
52
  } from "@firsthandjs/core";
424
53
  var COMPONENT = /* @__PURE__ */ Symbol.for("firsthand.component");
@@ -474,18 +103,18 @@ function createComponent(target, props) {
474
103
  if (target.tag !== void 0) {
475
104
  return createHost(target, props);
476
105
  }
477
- const owner = createOwner2(getOwner2());
106
+ const owner = createOwner(getOwner());
478
107
  devComponent(owner, target.name);
479
- const previous = setOwner2(owner);
108
+ const previous = setOwner(owner);
480
109
  try {
481
110
  devEnterSetup(target.id);
482
111
  const result = untrack(() => target.setup(props));
483
112
  devExitSetup();
484
- setOwner2(previous);
113
+ setOwner(previous);
485
114
  return result;
486
115
  } catch (error) {
487
116
  devExitSetup();
488
- setOwner2(previous);
117
+ setOwner(previous);
489
118
  handleError(error, owner);
490
119
  return null;
491
120
  }
@@ -533,13 +162,13 @@ function elementClass(target) {
533
162
  if (!this.$standalone || this.$owner === null) {
534
163
  return;
535
164
  }
536
- disposeOwner2(this.$owner);
165
+ disposeOwner(this.$owner);
537
166
  this.$owner = null;
538
167
  }
539
168
  attributeChangedCallback(name, _old, value) {
540
- const cell2 = this.$attrs?.[name];
541
- if (cell2 !== void 0) {
542
- cell2.value = codecs[name]?.(value);
169
+ const cell = this.$attrs?.[name];
170
+ if (cell !== void 0) {
171
+ cell.value = codecs[name]?.(value);
543
172
  }
544
173
  }
545
174
  };
@@ -549,21 +178,21 @@ function attributeProps(element, codecs, cells) {
549
178
  const props = {};
550
179
  if (codecs !== void 0) {
551
180
  for (const name in codecs) {
552
- const cell2 = signal2(codecs[name](element.getAttribute(name)));
553
- cells[name] = cell2;
181
+ const cell = signal(codecs[name](element.getAttribute(name)));
182
+ cells[name] = cell;
554
183
  Object.defineProperty(props, name, {
555
184
  enumerable: true,
556
- get: () => cell2.value
185
+ get: () => cell.value
557
186
  });
558
187
  }
559
188
  }
560
189
  return Object.freeze(props);
561
190
  }
562
191
  function mountHost(element, target, shadow) {
563
- const owner = createOwner2(getOwner2());
192
+ const owner = createOwner(getOwner());
564
193
  devComponent(owner, target.name);
565
194
  element.$owner = owner;
566
- const previous = setOwner2(owner);
195
+ const previous = setOwner(owner);
567
196
  try {
568
197
  devEnterSetup(target.id);
569
198
  const root = shadow ? element.attachShadow({ mode: "open" }) : element;
@@ -574,7 +203,7 @@ function mountHost(element, target, shadow) {
574
203
  devExitSetup();
575
204
  handleError(error, owner);
576
205
  } finally {
577
- setOwner2(previous);
206
+ setOwner(previous);
578
207
  }
579
208
  }
580
209
  function createHost(target, props) {
@@ -587,24 +216,32 @@ function createHost(target, props) {
587
216
  // packages/dom/src/list.ts
588
217
  import {
589
218
  batch,
590
- createOwner as createOwner3,
591
- disposeOwner as disposeOwner3,
592
- getOwner as getOwner3,
593
- setOwner as setOwner3,
594
- signal as signal3,
219
+ createOwner as createOwner2,
220
+ disposeOwner as disposeOwner2,
221
+ getOwner as getOwner2,
222
+ setOwner as setOwner2,
223
+ signal as signal2,
595
224
  untrack as untrack2
596
225
  } from "@firsthandjs/core";
597
226
  function list(each, keyOf, render) {
598
- const host = createOwner3(getOwner3());
227
+ const host = createOwner2(getOwner2());
599
228
  let rows = /* @__PURE__ */ new Map();
600
229
  return () => {
601
230
  const items = each();
602
231
  const next = /* @__PURE__ */ new Map();
603
232
  const nodes = [];
604
- batch(() => {
233
+ nodes[FLAT] = true;
234
+ untrack2(() => {
235
+ batch(() => {
236
+ buildRows();
237
+ });
238
+ });
239
+ rows = next;
240
+ return nodes;
241
+ function buildRows() {
605
242
  for (let i = 0; i < items.length; i++) {
606
243
  const item = items[i];
607
- const key2 = untrack2(() => keyOf(item, i));
244
+ const key2 = keyOf(item, i);
608
245
  if (next.has(key2)) {
609
246
  devWarn(
610
247
  `Duplicate list key ${String(key2)}. Keys must be unique, or rows will be dropped.`
@@ -624,25 +261,25 @@ function list(each, keyOf, render) {
624
261
  nodes.push(row.nodes[n]);
625
262
  }
626
263
  }
627
- for (const row of rows.values()) {
628
- disposeOwner3(row.owner);
629
- }
630
- });
631
- rows = next;
632
- return nodes;
264
+ discard(() => {
265
+ for (const row of rows.values()) {
266
+ disposeOwner2(row.owner);
267
+ }
268
+ });
269
+ }
633
270
  };
634
271
  }
635
272
  function createRow(host, item, index, render) {
636
- const owner = createOwner3(host);
637
- const itemCell = signal3(item);
638
- const indexCell = signal3(index);
639
- const previous = setOwner3(owner);
273
+ const owner = createOwner2(host);
274
+ const itemCell = signal2(item);
275
+ const indexCell = signal2(index);
276
+ const previous = setOwner2(owner);
640
277
  let result;
641
278
  try {
642
279
  result = untrack2(() => render(itemCell, indexCell));
643
- setOwner3(previous);
280
+ setOwner2(previous);
644
281
  } catch (error) {
645
- setOwner3(previous);
282
+ setOwner2(previous);
646
283
  throw error;
647
284
  }
648
285
  const nodes = [];
@@ -835,7 +472,9 @@ function hyphenate(name) {
835
472
  // packages/dom/src/props.ts
836
473
  function applyProp(node, name, value) {
837
474
  if (name === "class" || name === "className") {
838
- if (value !== null && typeof value === "object") {
475
+ if (Array.isArray(value)) {
476
+ setClass(node, value.filter(Boolean).join(" "));
477
+ } else if (value !== null && typeof value === "object") {
839
478
  setClassList(node, value, remember(node, "class", value));
840
479
  } else {
841
480
  setClass(node, value);
@@ -937,19 +576,6 @@ function remember(node, slot, value) {
937
576
  export {
938
577
  setComponentAdapter,
939
578
  FirsthandComponentError,
940
- label,
941
- part,
942
- store,
943
- wrote,
944
- site,
945
- open,
946
- close,
947
- ran,
948
- cell,
949
- writeChild,
950
- insert,
951
- applyChild,
952
- reconcile,
953
579
  COMPONENT,
954
580
  VIEW,
955
581
  setElementPrefix,