ilha 0.4.2 → 0.4.4

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.d.ts CHANGED
@@ -34,6 +34,10 @@ declare const RAW: unique symbol;
34
34
  declare const SIGNAL_ACCESSOR: unique symbol;
35
35
  declare const ISLAND: unique symbol;
36
36
  declare const ISLAND_CALL: unique symbol;
37
+ /** @internal Internal hook used by a parent's mountSlots to mount a child island and
38
+ * retain a handle to push updated props into it on subsequent parent
39
+ * re-renders. Not part of the public surface. */
40
+ declare const ISLAND_MOUNT_INTERNAL: unique symbol;
37
41
  interface RawHtml {
38
42
  [RAW]: true;
39
43
  value: string;
@@ -288,4 +292,4 @@ declare const mount: typeof mountAll;
288
292
  declare const from: typeof ilhaFrom;
289
293
  declare const context: typeof ilhaContext;
290
294
  //#endregion
291
- export { DerivedValue, ErrorContext, ErrorSource, ExternalSignal, HandlerContext, HandlerContextFor, HydratableOptions, Island, IslandDerived, IslandState, KeyedIsland, MountOptions, MountResult, OnMountContext, RawHtml, SignalAccessor, batch, context, css, ilha as default, from, html, ilhaSignal, ilhaSignal as signal, mount, raw, untrack };
295
+ export { DerivedValue, ErrorContext, ErrorSource, ExternalSignal, HandlerContext, HandlerContextFor, HydratableOptions, ISLAND_MOUNT_INTERNAL, Island, IslandDerived, IslandState, KeyedIsland, MountOptions, MountResult, OnMountContext, RawHtml, SignalAccessor, batch, context, css, ilha as default, from, html, ilhaSignal, ilhaSignal as signal, mount, raw, untrack };
package/dist/index.js CHANGED
@@ -92,6 +92,9 @@ const RAW = Symbol("ilha.raw");
92
92
  const SIGNAL_ACCESSOR = Symbol("ilha.signalAccessor");
93
93
  const ISLAND = Symbol("ilha.island");
94
94
  const ISLAND_CALL = Symbol("ilha.islandCall");
95
+ /** @internal Internal hook used by a parent's mountSlots to mount a child island and
96
+ * retain a handle to push updated props into it on subsequent parent
97
+ * re-renders. Not part of the public surface. */
95
98
  const ISLAND_MOUNT_INTERNAL = Symbol("ilha.islandMountInternal");
96
99
  const SLOT_ATTR = "data-ilha-slot";
97
100
  const PROPS_ATTR = "data-ilha-props";
@@ -275,81 +278,137 @@ function batch(fn) {
275
278
  endBatch();
276
279
  }
277
280
  }
278
- function buildDerivedSignals(entries, state, input, derivedSnapshot) {
281
+ function createDerivedProxy(entries, state, input, derivedSnapshot) {
279
282
  const envelopes = /* @__PURE__ */ new Map();
280
- const stops = [];
281
283
  for (const entry of entries) {
282
- const env = signal(derivedSnapshot?.[entry.key] ?? {
284
+ let initialEnvelope;
285
+ if (derivedSnapshot != null && entry.key in derivedSnapshot) initialEnvelope = { ...derivedSnapshot[entry.key] };
286
+ else if (!(entry.fn.constructor.name === "AsyncFunction" || entry.fn.constructor.name === "AsyncGeneratorFunction")) {
287
+ const ac = new AbortController();
288
+ try {
289
+ const result = entry.fn({
290
+ state,
291
+ input,
292
+ signal: ac.signal
293
+ });
294
+ if (!(result instanceof Promise)) initialEnvelope = {
295
+ loading: false,
296
+ value: result,
297
+ error: void 0
298
+ };
299
+ else {
300
+ initialEnvelope = {
301
+ loading: true,
302
+ value: void 0,
303
+ error: void 0
304
+ };
305
+ result.catch(() => {});
306
+ }
307
+ } catch (err) {
308
+ initialEnvelope = {
309
+ loading: false,
310
+ value: void 0,
311
+ error: err instanceof Error ? err : new Error(String(err))
312
+ };
313
+ } finally {
314
+ ac.abort();
315
+ }
316
+ } else initialEnvelope = {
283
317
  loading: true,
284
318
  value: void 0,
285
319
  error: void 0
286
- });
320
+ };
321
+ const env = signal(initialEnvelope);
287
322
  envelopes.set(entry.key, env);
288
- let ac = new AbortController();
289
- let skipFirst = derivedSnapshot != null && entry.key in derivedSnapshot;
290
- const stopEffect = effect(() => {
291
- ac.abort();
292
- ac = new AbortController();
293
- const currentAc = ac;
294
- const result = entry.fn({
295
- state,
296
- input,
297
- signal: currentAc.signal
298
- });
299
- if (skipFirst) {
300
- skipFirst = false;
301
- if (result instanceof Promise) result.catch(() => {});
302
- return;
303
- }
304
- if (!(result instanceof Promise)) {
323
+ }
324
+ const proxy = new Proxy({}, { get(_, key) {
325
+ const env = envelopes.get(key);
326
+ if (!env) return {
327
+ loading: false,
328
+ value: void 0,
329
+ error: void 0
330
+ };
331
+ return env();
332
+ } });
333
+ const setup = () => {
334
+ const stops = [];
335
+ for (const entry of entries) {
336
+ const env = envelopes.get(entry.key);
337
+ let ac = new AbortController();
338
+ let skipFirst = derivedSnapshot != null && entry.key in derivedSnapshot;
339
+ const stopEffect = effect(() => {
340
+ ac.abort();
341
+ ac = new AbortController();
342
+ const currentAc = ac;
343
+ let result;
344
+ try {
345
+ result = entry.fn({
346
+ state,
347
+ input,
348
+ signal: currentAc.signal
349
+ });
350
+ } catch (err) {
351
+ if (skipFirst) {
352
+ skipFirst = false;
353
+ return;
354
+ }
355
+ const prevSub = setActiveSub(void 0);
356
+ env({
357
+ loading: false,
358
+ value: void 0,
359
+ error: err instanceof Error ? err : new Error(String(err))
360
+ });
361
+ setActiveSub(prevSub);
362
+ return;
363
+ }
364
+ if (skipFirst) {
365
+ skipFirst = false;
366
+ if (result instanceof Promise) result.catch(() => {});
367
+ return;
368
+ }
369
+ if (!(result instanceof Promise)) {
370
+ const prevSub = setActiveSub(void 0);
371
+ env({
372
+ loading: false,
373
+ value: result,
374
+ error: void 0
375
+ });
376
+ setActiveSub(prevSub);
377
+ return;
378
+ }
305
379
  const prevSub = setActiveSub(void 0);
306
380
  env({
307
- loading: false,
308
- value: result,
381
+ loading: true,
382
+ value: env().value,
309
383
  error: void 0
310
384
  });
311
385
  setActiveSub(prevSub);
312
- return;
313
- }
314
- const prevSub = setActiveSub(void 0);
315
- env({
316
- loading: true,
317
- value: env().value,
318
- error: void 0
319
- });
320
- setActiveSub(prevSub);
321
- result.then((value) => {
322
- if (currentAc.signal.aborted) return;
323
- env({
324
- loading: false,
325
- value,
326
- error: void 0
327
- });
328
- }).catch((err) => {
329
- if (currentAc.signal.aborted) return;
330
- env({
331
- loading: false,
332
- value: void 0,
333
- error: err instanceof Error ? err : new Error(String(err))
386
+ result.then((value) => {
387
+ if (currentAc.signal.aborted) return;
388
+ env({
389
+ loading: false,
390
+ value,
391
+ error: void 0
392
+ });
393
+ }).catch((err) => {
394
+ if (currentAc.signal.aborted) return;
395
+ env({
396
+ loading: false,
397
+ value: void 0,
398
+ error: err instanceof Error ? err : new Error(String(err))
399
+ });
334
400
  });
335
401
  });
336
- });
337
- stops.push(() => {
338
- stopEffect();
339
- ac.abort();
340
- });
341
- }
402
+ stops.push(() => {
403
+ stopEffect();
404
+ ac.abort();
405
+ });
406
+ }
407
+ return () => stops.forEach((s) => s());
408
+ };
342
409
  return {
343
- proxy: new Proxy({}, { get(_, key) {
344
- const env = envelopes.get(key);
345
- if (!env) return {
346
- loading: false,
347
- value: void 0,
348
- error: void 0
349
- };
350
- return env();
351
- } }),
352
- stop: () => stops.forEach((s) => s())
410
+ proxy,
411
+ setup
353
412
  };
354
413
  }
355
414
  function resolveBindConfig(el) {
@@ -774,8 +833,8 @@ Element: ${host.outerHTML.slice(0, 120)}`);
774
833
  const result = transition.enter(host);
775
834
  if (result instanceof Promise) result.catch(console.error);
776
835
  }
777
- const { proxy: derived, stop: stopDerived } = buildDerivedSignals(deriveds, state, input, derivedSnapshot);
778
- cleanups.push(stopDerived);
836
+ const { proxy: derived, setup: setupDerived } = createDerivedProxy(deriveds, state, input, derivedSnapshot);
837
+ let stopDerived = () => {};
779
838
  function reportError(err, source) {
780
839
  const error = err instanceof Error ? err : new Error(String(err));
781
840
  if (onErrors.length === 0) {
@@ -947,6 +1006,47 @@ Element: ${host.outerHTML.slice(0, 120)}`);
947
1006
  }
948
1007
  if (userCleanup) cleanups.push(userCleanup);
949
1008
  }
1009
+ for (const entry of effects) {
1010
+ let userCleanup;
1011
+ let runController = null;
1012
+ const stopEffect = effect(() => {
1013
+ if (userCleanup) {
1014
+ try {
1015
+ userCleanup();
1016
+ } catch (err) {
1017
+ reportError(err, "effect");
1018
+ }
1019
+ userCleanup = void 0;
1020
+ }
1021
+ if (runController) runController.abort();
1022
+ runController = new AbortController();
1023
+ const runSignal = anySignal([unmountController.signal, runController.signal]);
1024
+ startBatch();
1025
+ try {
1026
+ userCleanup = entry.fn({
1027
+ state,
1028
+ input,
1029
+ host,
1030
+ signal: runSignal
1031
+ });
1032
+ } catch (err) {
1033
+ reportError(err, "effect");
1034
+ } finally {
1035
+ endBatch();
1036
+ }
1037
+ });
1038
+ cleanups.push(() => {
1039
+ stopEffect();
1040
+ if (userCleanup) try {
1041
+ userCleanup();
1042
+ } catch (err) {
1043
+ reportError(err, "effect");
1044
+ }
1045
+ if (runController) runController.abort();
1046
+ });
1047
+ }
1048
+ stopDerived = setupDerived();
1049
+ cleanups.push(stopDerived);
950
1050
  let initialized = false;
951
1051
  const initialRenderedHtml = initial.html;
952
1052
  const stopRender = effect(() => {
@@ -989,45 +1089,6 @@ Element: ${host.outerHTML.slice(0, 120)}`);
989
1089
  });
990
1090
  cleanups.push(stopRender);
991
1091
  cleanups.push(detachListeners);
992
- for (const entry of effects) {
993
- let userCleanup;
994
- let runController = null;
995
- const stopEffect = effect(() => {
996
- if (userCleanup) {
997
- try {
998
- userCleanup();
999
- } catch (err) {
1000
- reportError(err, "effect");
1001
- }
1002
- userCleanup = void 0;
1003
- }
1004
- if (runController) runController.abort();
1005
- runController = new AbortController();
1006
- const runSignal = anySignal([unmountController.signal, runController.signal]);
1007
- startBatch();
1008
- try {
1009
- userCleanup = entry.fn({
1010
- state,
1011
- input,
1012
- host,
1013
- signal: runSignal
1014
- });
1015
- } catch (err) {
1016
- reportError(err, "effect");
1017
- } finally {
1018
- endBatch();
1019
- }
1020
- });
1021
- cleanups.push(() => {
1022
- stopEffect();
1023
- if (userCleanup) try {
1024
- userCleanup();
1025
- } catch (err) {
1026
- reportError(err, "effect");
1027
- }
1028
- if (runController) runController.abort();
1029
- });
1030
- }
1031
1092
  let tornDown = false;
1032
1093
  const unmount = () => {
1033
1094
  if (tornDown) return;
@@ -1231,4 +1292,4 @@ const mount = mountAll;
1231
1292
  const from = ilhaFrom;
1232
1293
  const context = ilhaContext;
1233
1294
  //#endregion
1234
- export { batch, context, css, ilha as default, from, html, ilhaSignal, ilhaSignal as signal, mount, raw, untrack };
1295
+ export { ISLAND_MOUNT_INTERNAL, batch, context, css, ilha as default, from, html, ilhaSignal, ilhaSignal as signal, mount, raw, untrack };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilha",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "A tiny, framework-free island architecture library",
5
5
  "license": "MIT",
6
6
  "author": "Ryuz <ryuzer@proton.me>",
@@ -23,7 +23,7 @@
23
23
  "test": "bun test"
24
24
  },
25
25
  "dependencies": {
26
- "alien-signals": "3.1.2"
26
+ "alien-signals": "3.2.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "zod": "^4.4.3"