lilact 0.30.0 → 0.30.1

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.
Files changed (43) hide show
  1. package/dist/lilact.development.js +100 -11
  2. package/dist/lilact.development.js.map +3 -3
  3. package/dist/lilact.development.min.js +25 -25
  4. package/dist/lilact.development.min.js.map +3 -3
  5. package/dist/lilact.production.min.js +25 -25
  6. package/docs/assets/hierarchy.js +1 -1
  7. package/docs/assets/navigation.js +1 -1
  8. package/docs/assets/search.js +1 -1
  9. package/docs/classes/accessories.ErrorBoundary.html +8 -8
  10. package/docs/classes/accessories.Suspense.html +7 -7
  11. package/docs/classes/components.Component.html +11 -11
  12. package/docs/classes/components.HTMLComponent.html +11 -11
  13. package/docs/classes/components.RootComponent.html +11 -11
  14. package/docs/functions/components.cloneComponent.html +1 -1
  15. package/docs/functions/components.createComponent.html +1 -1
  16. package/docs/functions/components.createPortal.html +1 -1
  17. package/docs/functions/components.createRoot.html +1 -1
  18. package/docs/functions/components.hotReloadRoot.html +1 -1
  19. package/docs/functions/components.memo.html +1 -1
  20. package/docs/functions/components.render.html +1 -1
  21. package/docs/functions/components.replaceAllComponentInstances.html +1 -0
  22. package/docs/functions/components.replaceComponentEntity.html +1 -1
  23. package/docs/functions/run.lazy.html +1 -1
  24. package/docs/functions/run.run.html +1 -1
  25. package/docs/functions/run.runScripts.html +1 -1
  26. package/docs/hierarchy.html +1 -1
  27. package/docs/modules/components.html +1 -1
  28. package/docs/static/index.html +1 -1
  29. package/docs/static/lilact.development.js +100 -11
  30. package/docs/static/lilact.development.js.map +3 -3
  31. package/docs/static/lilact.development.min.js +25 -25
  32. package/docs/static/lilact.development.min.js.map +3 -3
  33. package/docs/static/lilact.production.min.js +25 -25
  34. package/docs/variables/components.cloneElement.html +1 -1
  35. package/examples/index.html +1 -1
  36. package/examples/lilact.development.js +100 -11
  37. package/examples/lilact.development.js.map +3 -3
  38. package/examples/lilact.development.min.js +25 -25
  39. package/examples/lilact.development.min.js.map +3 -3
  40. package/examples/lilact.production.min.js +25 -25
  41. package/package.json +1 -1
  42. package/src/components.jsx +115 -21
  43. package/src/run.jsx +85 -53
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lilact",
3
- "version": "0.30.0",
3
+ "version": "0.30.1",
4
4
  "description": "A Little React/JSX Runtime Implementation for Browser",
5
5
  "repository": "github:arashkazemi/lilact",
6
6
  "homepage": "https://arashkazemi.github.io/lilact/",
@@ -39,9 +39,64 @@ const SVG_NS = "http://www.w3.org/2000/svg";
39
39
 
40
40
 
41
41
  function getComponentEntity(entity) {
42
- return entity?.[MEMOIZED]
43
- ? entity.component
44
- : entity;
42
+ return entity?.[MEMOIZED] ? entity.component : entity;
43
+ }
44
+
45
+ const componentInstances = new Map();
46
+
47
+ function registerComponentCore(core) {
48
+ const entity = getComponentEntity(core.entity);
49
+
50
+ if (typeof entity !== "function") return;
51
+
52
+ let instances = componentInstances.get(entity);
53
+
54
+ if (!instances) {
55
+ instances = new Set();
56
+ componentInstances.set(entity, instances);
57
+ }
58
+
59
+ instances.add(core);
60
+ core.registered_entity = entity;
61
+ }
62
+
63
+ function unregisterComponentCore(core) {
64
+ const entity = core.registered_entity;
65
+ if (!entity) return;
66
+
67
+ const instances = componentInstances.get(entity);
68
+
69
+ if (instances) {
70
+ instances.delete(core);
71
+
72
+ if (instances.size === 0) {
73
+ componentInstances.delete(entity);
74
+ }
75
+ }
76
+
77
+ delete core.registered_entity;
78
+ }
79
+
80
+ function moveComponentCore(core, oldEntity, newEntity) {
81
+ const oldInstances = componentInstances.get(oldEntity);
82
+
83
+ if (oldInstances) {
84
+ oldInstances.delete(core);
85
+
86
+ if (oldInstances.size === 0) {
87
+ componentInstances.delete(oldEntity);
88
+ }
89
+ }
90
+
91
+ let newInstances = componentInstances.get(newEntity);
92
+
93
+ if (!newInstances) {
94
+ newInstances = new Set();
95
+ componentInstances.set(newEntity, newInstances);
96
+ }
97
+
98
+ newInstances.add(core);
99
+ core.registered_entity = newEntity;
45
100
  }
46
101
 
47
102
  export function replaceComponentEntity(componentCore, nextEntity) {
@@ -62,27 +117,56 @@ export function replaceComponentEntity(componentCore, nextEntity) {
62
117
  return false;
63
118
  }
64
119
 
65
- const oldIsClass = isClass(oldEntity);
66
- const newIsClass = isClass(newEntity);
67
-
68
- // A function component cannot reuse a class instance, and vice versa.
69
- if (oldIsClass !== newIsClass) {
120
+ if (
121
+ typeof oldEntity !== "function" ||
122
+ typeof newEntity !== "function" ||
123
+ isClass(oldEntity) !== isClass(newEntity)
124
+ ) {
70
125
  return false;
71
126
  }
72
127
 
73
- if (newIsClass) {
74
- // componentCore.state and the component instance are preserved.
75
- // Only the class implementation changes.
128
+ if (isClass(newEntity)) {
76
129
  Object.setPrototypeOf(component, newEntity.prototype);
77
130
  } else {
78
- // The function is invoked with the ComponentCore as `this` by apply().
79
- component.render = newEntity;
131
+ component.render = newEntity.bind(component);
80
132
  }
81
133
 
82
134
  componentCore.entity = newEntity;
135
+ moveComponentCore(componentCore, oldEntity, newEntity);
136
+
83
137
  return true;
84
138
  }
85
139
 
140
+ export function replaceAllComponentInstances(oldEntity, newEntity) {
141
+ oldEntity = getComponentEntity(oldEntity);
142
+ newEntity = getComponentEntity(newEntity);
143
+
144
+ if (
145
+ typeof oldEntity !== "function" ||
146
+ typeof newEntity !== "function"
147
+ ) {
148
+ return 0;
149
+ }
150
+
151
+ const instances = componentInstances.get(oldEntity);
152
+
153
+ if (!instances) {
154
+ return 0;
155
+ }
156
+
157
+ let count = 0;
158
+
159
+ for (const core of [...instances]) {
160
+ if (!replaceComponentEntity(core, newEntity)) {
161
+ continue;
162
+ }
163
+
164
+ core.apply(core.props, core.state);
165
+ count++;
166
+ }
167
+
168
+ return count;
169
+ }
86
170
 
87
171
  /*
88
172
  ComponentCache is for internal use. It is the heart of the JSX runtime,
@@ -113,10 +197,12 @@ class ComponentCache
113
197
  const newEntity = getComponentEntity(nextEntity);
114
198
 
115
199
  const incompatible =
116
- typeof oldEntity === "function" &&
117
- typeof newEntity === "function" &&
118
- isClass(oldEntity) !== isClass(newEntity);
119
-
200
+ typeof oldEntity !== typeof newEntity ||
201
+ (
202
+ typeof oldEntity === "function" &&
203
+ isClass(oldEntity) !== isClass(newEntity)
204
+ );
205
+
120
206
  if (incompatible) {
121
207
  componentCore = construct_func();
122
208
  }
@@ -394,7 +480,8 @@ class ComponentCore
394
480
 
395
481
  async cleanup()
396
482
  {
397
- try {
483
+ unregisterComponentCore(this);
484
+ try {
398
485
  const promises = [];
399
486
 
400
487
  if(this.props?.ref) {
@@ -795,8 +882,9 @@ function constructFunc(core, parent) // returns {text} or component, and not com
795
882
  }
796
883
 
797
884
  comp[CORE].entity = entity;
885
+ registerComponentCore(comp[CORE]);
798
886
 
799
- if(core.container) {
887
+ if (core.container) {
800
888
  comp[CORE].container = core.container;
801
889
  }
802
890
  }
@@ -1274,6 +1362,7 @@ export function createRoot(element)
1274
1362
  let root;
1275
1363
 
1276
1364
  return {
1365
+
1277
1366
  render(component) {
1278
1367
  if(!root) {
1279
1368
  root = new RootComponent( element, {children:[component]} );
@@ -1291,6 +1380,11 @@ export function createRoot(element)
1291
1380
  root.cleanup();
1292
1381
  element.innerHTML="";
1293
1382
  }
1383
+ },
1384
+
1385
+ getCore() {
1386
+ console.log(root, root[CORE]);
1387
+ return root[CORE];
1294
1388
  }
1295
1389
  }
1296
1390
  }
@@ -1299,7 +1393,7 @@ export function createRoot(element)
1299
1393
 
1300
1394
  export function hotReloadRoot(rootCore, nextEntity, props) {
1301
1395
  if (!rootCore || !rootCore.component) {
1302
- throw new Error("Invalid Lilact root component.");
1396
+ throw new Error("Invalid root component.");
1303
1397
  }
1304
1398
 
1305
1399
  const replaced = replaceComponentEntity(rootCore, nextEntity);
@@ -1310,7 +1404,7 @@ export function hotReloadRoot(rootCore, nextEntity, props) {
1310
1404
  );
1311
1405
  }
1312
1406
 
1313
- rootCore.apply(props === undefined ? rootCore.props : props);
1407
+ rootCore.apply(props === undefined ? rootCore.props : {...rootCore.props, ...props});
1314
1408
 
1315
1409
  return rootCore;
1316
1410
  }
package/src/run.jsx CHANGED
@@ -245,69 +245,96 @@ export function require(path)
245
245
 
246
246
 
247
247
  function makeImportsObject(mod, options = {}) {
248
- mod.importsObject = {};
248
+ mod.importsObject ??= {};
249
249
 
250
- for (const path in mod.meta.imports) {
251
- const imps = mod.meta.imports[path];
250
+ for (const key of Object.keys(mod.importsObject)) {
251
+ delete mod.importsObject[key];
252
+ }
252
253
 
253
- const exps = loadModule(path, {
254
- requirer: mod,
255
- forceReload: options.forceReload,
256
- });
254
+ for (const path in mod.meta.imports) {
255
+ const imps = mod.meta.imports[path];
257
256
 
258
- for (const i in imps.named_imports) {
259
- if (i === '') continue;
257
+ const exps = loadModule(path, {
258
+ requirer: mod,
259
+ forceReload: options.forceReload,
260
+ });
260
261
 
261
- const exportedName = imps.named_imports[i];
262
+ for (const i in imps.named_imports) {
263
+ if (i === "") continue;
262
264
 
263
- if (!Object.prototype.hasOwnProperty.call(exps, exportedName)) {
264
- throw new Error(
265
- `Imported module does not export any "${i}".`
266
- );
267
- }
265
+ const exportedName = imps.named_imports[i];
268
266
 
269
- mod.importsObject[i] = exps[exportedName];
270
- }
267
+ if (!Object.prototype.hasOwnProperty.call(exps, exportedName)) {
268
+ throw new Error(
269
+ `Imported module does not export any "${i}".`
270
+ );
271
+ }
271
272
 
272
- for (const i of imps.import_defaults) {
273
- if (!Object.prototype.hasOwnProperty.call(exps, 'default')) {
274
- throw new Error(
275
- `Imported module does not export a default.`
276
- );
277
- }
273
+ mod.importsObject[i] = exps[exportedName];
274
+ }
278
275
 
279
- mod.importsObject[i] = exps.default;
280
- }
276
+ for (const i of imps.import_defaults) {
277
+ if (!Object.prototype.hasOwnProperty.call(exps, "default")) {
278
+ throw new Error(
279
+ "Imported module does not export a default."
280
+ );
281
+ }
281
282
 
282
- for (const i of imps.import_stars) {
283
- mod.importsObject[i] = { ...exps };
284
- }
285
- }
283
+ mod.importsObject[i] = exps.default;
284
+ }
285
+
286
+ for (const i of imps.import_stars) {
287
+ mod.importsObject[i] = { ...exps };
288
+ }
289
+ }
290
+
291
+ return mod.importsObject;
292
+ }
293
+
294
+
295
+ function exportEntries(value) {
296
+ return value && typeof value === "object"
297
+ ? value
298
+ : { default: value };
299
+ }
300
+
301
+ function replaceReloadedExports(previousExports, nextExports) {
302
+ if (!previousExports) return;
303
+
304
+ const oldExports = exportEntries(previousExports);
305
+ const newExports = exportEntries(nextExports);
306
+
307
+ for (const name of Object.keys(oldExports)) {
308
+ const oldExport = oldExports[name];
309
+ const newExport = newExports[name];
310
+
311
+ if (
312
+ typeof oldExport === "function" &&
313
+ typeof newExport === "function"
314
+ ) {
315
+ Lilact.replaceAllComponentInstances(oldExport, newExport);
316
+ }
317
+ }
286
318
  }
287
319
 
288
320
 
289
321
  export function run(
290
- jsx,
291
- path = `InlineJSX-${++Lilact.eval_num}`,
292
- options = {}
322
+ jsx,
323
+ path = `InlineJSX-${++Lilact.eval_num}`,
324
+ options = {}
293
325
  ) {
294
326
  let module = required_scripts[path];
295
327
 
296
- /*
297
- * A module may already have been created by require() while its source is
298
- * being fetched. Reuse that module so the request and its exports remain
299
- * associated with the same entry.
300
- */
328
+ const previousExports =
329
+ module?.loaded
330
+ ? module.exports
331
+ : undefined;
332
+
301
333
  if (!module) {
302
334
  module = createModule(path, {
303
335
  code: jsx,
304
336
  });
305
337
  } else {
306
- /*
307
- * Preserve module.request. It may represent the request that led to this
308
- * run() call, and clearing it here would make retry/deduplication logic
309
- * fragile.
310
- */
311
338
  module.path = path;
312
339
  module.code = String(jsx);
313
340
  module.mappings = [];
@@ -330,14 +357,16 @@ export function run(
330
357
  produceCJS: true,
331
358
  blocksInfo: Lilact.blocksInfo,
332
359
  });
333
- }
334
- catch (value) {
360
+ } catch (value) {
335
361
  const error = asError(value);
362
+
336
363
  error.fileName ??= path;
337
- error.lilact_source ??= {path};
364
+ error.lilact_source ??= { path };
338
365
  error.sourcePhase = "transpile";
366
+
339
367
  module.error = error;
340
368
  Lilact.error = error;
369
+
341
370
  throw error;
342
371
  }
343
372
 
@@ -345,25 +374,28 @@ export function run(
345
374
  Lilact.scanBlockLabels(processed, path);
346
375
  }
347
376
 
348
- /*
349
- * sourceURL helps when the browser includes eval locations in its stack.
350
- * It is not used as the authoritative source; the catch block below is.
351
- */
352
-
353
377
  try {
354
378
  globalThis.Lilact = Lilact;
355
379
  globalThis.createComponent = Lilact.createComponent;
356
380
  globalThis.Fragment = Lilact.Fragment;
357
381
 
358
382
  const result = eval(processed);
383
+
359
384
  module.loaded = true;
360
385
 
361
- return isEmpty(module.exports) ? result : module.exports;
362
- }
363
- catch (value) {
386
+ const nextExports = isEmpty(module.exports)
387
+ ? result
388
+ : module.exports;
389
+
390
+ replaceReloadedExports(previousExports, nextExports);
391
+
392
+ return nextExports;
393
+ } catch (value) {
364
394
  const error = report(value, path);
395
+
365
396
  error.sourcePhase ??= "runtime";
366
397
  module.error = error;
398
+
367
399
  throw error;
368
400
  }
369
401
  }