lilact 0.30.1 → 0.31.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 +82 -60
  2. package/dist/lilact.development.js.map +2 -2
  3. package/dist/lilact.development.min.js +29 -29
  4. package/dist/lilact.development.min.js.map +3 -3
  5. package/dist/lilact.production.min.js +29 -29
  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.memo.html +1 -1
  19. package/docs/functions/components.render.html +1 -1
  20. package/docs/functions/components.replaceAllComponentInstances.html +1 -1
  21. package/docs/functions/components.replaceComponentEntity.html +1 -1
  22. package/docs/functions/run.lazy.html +1 -1
  23. package/docs/functions/run.runScripts.html +1 -1
  24. package/docs/hierarchy.html +1 -1
  25. package/docs/modules/components.html +1 -1
  26. package/docs/static/lilact.development.js +82 -60
  27. package/docs/static/lilact.development.js.map +2 -2
  28. package/docs/static/lilact.development.min.js +29 -29
  29. package/docs/static/lilact.development.min.js.map +3 -3
  30. package/docs/static/lilact.production.min.js +29 -29
  31. package/docs/variables/components.cloneElement.html +1 -1
  32. package/examples/lilact.development.js +82 -60
  33. package/examples/lilact.development.js.map +2 -2
  34. package/examples/lilact.development.min.js +29 -29
  35. package/examples/lilact.development.min.js.map +3 -3
  36. package/examples/lilact.production.min.js +29 -29
  37. package/package.json +1 -1
  38. package/src/components.jsx +121 -98
  39. package/src/jsx.js +6 -2
  40. package/src/lilact.jsx +1 -1
  41. package/src/run.jsx +1 -0
  42. package/src/symbols.jsx +5 -1
  43. package/docs/functions/components.hotReloadRoot.html +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lilact",
3
- "version": "0.30.1",
3
+ "version": "0.31.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/",
@@ -30,7 +30,7 @@
30
30
 
31
31
  import Lilact from './lilact.jsx';
32
32
 
33
- import { CORE, COMPONENT, TEXT, IS_ZOMBIE, IDX, CHILD_CLASS_ADDENDUM, MEMOIZED } from "./symbols.jsx"
33
+ import { CORE, COMPONENT, TEXT, IS_ZOMBIE, IDX, CHILD_CLASS_ADDENDUM, MEMOIZED, LOCATION } from "./symbols.jsx"
34
34
  import { shallowEqual, toBool, isClass, isThenable } from "./misc.jsx";
35
35
 
36
36
  import { PropTypes } from './proptypes.jsx';
@@ -38,10 +38,30 @@ import { PropTypes } from './proptypes.jsx';
38
38
  const SVG_NS = "http://www.w3.org/2000/svg";
39
39
 
40
40
 
41
+
41
42
  function getComponentEntity(entity) {
42
43
  return entity?.[MEMOIZED] ? entity.component : entity;
43
44
  }
44
45
 
46
+ const hotEntityAliases = new Map();
47
+
48
+ function resolveHotEntity(entity) {
49
+ entity = getComponentEntity(entity);
50
+
51
+ const visited = new Set();
52
+
53
+ while (
54
+ typeof entity === "function" &&
55
+ hotEntityAliases.has(entity) &&
56
+ !visited.has(entity)
57
+ ) {
58
+ visited.add(entity);
59
+ entity = hotEntityAliases.get(entity);
60
+ }
61
+
62
+ return entity;
63
+ }
64
+
45
65
  const componentInstances = new Map();
46
66
 
47
67
  function registerComponentCore(core) {
@@ -105,7 +125,7 @@ export function replaceComponentEntity(componentCore, nextEntity) {
105
125
  }
106
126
 
107
127
  const oldEntity = getComponentEntity(componentCore.entity);
108
- const newEntity = getComponentEntity(nextEntity);
128
+ const newEntity = resolveHotEntity(nextEntity);
109
129
 
110
130
  if (oldEntity === newEntity) {
111
131
  return true;
@@ -148,6 +168,16 @@ export function replaceAllComponentInstances(oldEntity, newEntity) {
148
168
  return 0;
149
169
  }
150
170
 
171
+ newEntity = resolveHotEntity(newEntity);
172
+
173
+ if (oldEntity === newEntity) {
174
+ return 0;
175
+ }
176
+
177
+ // Keep this alias even when there are currently no instances.
178
+ // A future instance may still be created with oldEntity.
179
+ hotEntityAliases.set(oldEntity, newEntity);
180
+
151
181
  const instances = componentInstances.get(oldEntity);
152
182
 
153
183
  if (!instances) {
@@ -168,6 +198,7 @@ export function replaceAllComponentInstances(oldEntity, newEntity) {
168
198
  return count;
169
199
  }
170
200
 
201
+
171
202
  /*
172
203
  ComponentCache is for internal use. It is the heart of the JSX runtime,
173
204
  it holds child components and detects which one is being rendered or updated.
@@ -194,19 +225,18 @@ class ComponentCache
194
225
  bucket[IDX]++;
195
226
 
196
227
  const oldEntity = getComponentEntity(componentCore.entity);
197
- const newEntity = getComponentEntity(nextEntity);
228
+ const newEntity = resolveHotEntity(nextEntity);
198
229
 
199
230
  const incompatible =
200
- typeof oldEntity !== typeof newEntity ||
201
- (
202
- typeof oldEntity === "function" &&
203
- isClass(oldEntity) !== isClass(newEntity)
204
- );
205
-
231
+ typeof oldEntity !== typeof newEntity ||
232
+ (
233
+ typeof oldEntity === "function" &&
234
+ isClass(oldEntity) !== isClass(newEntity)
235
+ );
236
+
206
237
  if (incompatible) {
207
238
  componentCore = construct_func();
208
- }
209
- else if (newEntity) {
239
+ } else if (newEntity) {
210
240
  replaceComponentEntity(componentCore, newEntity);
211
241
  }
212
242
  } else {
@@ -810,92 +840,105 @@ const renderErrorHandler = (c, e) =>
810
840
 
811
841
 
812
842
 
813
- function constructFunc(core, parent) // returns {text} or component, and not component core.
814
- {
843
+ function constructFunc(core, parent) {
815
844
  let comp = core;
816
845
 
817
- if( core[TEXT]!==undefined ) {
818
- // do nothing...
819
- }
820
- else {
846
+ if (core[TEXT] === undefined) {
821
847
  let entity = core.entity;
822
848
  let memoized = false;
823
849
 
824
- if(typeof(entity)==='object') {
825
- if( entity[MEMOIZED] ) {
850
+ const loc = core.props[LOCATION];
851
+ if(loc) delete core.props[LOCATION];
852
+
853
+ if (typeof entity === "object") {
854
+ if (entity[MEMOIZED]) {
826
855
  memoized = entity[MEMOIZED];
827
856
  entity = entity.component;
828
- }
829
- else {
857
+ } else {
830
858
  throw new Error("Invalid component.");
831
859
  }
832
860
  }
833
861
 
834
- if(typeof(entity)==='string') {
835
- comp = new HTMLComponent(entity, core.props);
836
- }
837
- else {
838
-
839
- if( isClass(entity) ) {
840
- if(entity?.defaultProps) {
841
- core.props = { ...entity.defaultProps, ...core.props };
842
- }
843
-
844
- comp = new entity(core.props);
862
+ entity = resolveHotEntity(entity);
845
863
 
846
- const desc = Object.getOwnPropertyDescriptor(comp, "state");
847
- if(desc) {
848
- if (typeof desc.get !== "function" && typeof desc.set !== "function") {
849
- comp[CORE].state = comp.state;
864
+ if (typeof entity === "string") {
865
+ comp = new HTMLComponent(entity, core.props);
866
+ }
867
+ else if (isClass(entity)) {
868
+ if (entity?.defaultProps) {
869
+ core.props = {
870
+ ...entity.defaultProps,
871
+ ...core.props,
872
+ };
873
+ }
850
874
 
851
- Object.defineProperty(comp, "state", {
852
- get() { return this[CORE].state },
853
- set(v) {
854
- // todo: this should be changed, it should be only directly settable in constructor.
855
- if(this[CORE].state===undefined) {
856
- this[CORE].state = v;
857
- }
858
- else {
859
- throw new Error('Assigning component state this way is not allowed.');
860
- }
875
+ comp = new entity(core.props);
876
+
877
+ const desc = Object.getOwnPropertyDescriptor(comp, "state");
878
+
879
+ if (desc) {
880
+ if (
881
+ typeof desc.get !== "function" &&
882
+ typeof desc.set !== "function"
883
+ ) {
884
+ comp[CORE].state = comp.state;
885
+
886
+ Object.defineProperty(comp, "state", {
887
+ get() {
888
+ return this[CORE].state;
889
+ },
890
+ set(value) {
891
+ if (this[CORE].state === undefined) {
892
+ this[CORE].state = value;
893
+ } else {
894
+ throw new Error(
895
+ "Assigning component state this way is not allowed."
896
+ );
861
897
  }
862
- });
863
- }
898
+ },
899
+ });
864
900
  }
865
901
  }
866
- else if(typeof(entity)==='function') {
902
+ }
903
+ else if (typeof entity === "function") {
904
+ if (entity?.defaultProps) {
905
+ core.props = {
906
+ ...entity.defaultProps,
907
+ ...core.props,
908
+ };
909
+ }
867
910
 
868
- if(entity?.defaultProps) {
869
- core.props = { ...entity.defaultProps, ...core.props };
870
- }
911
+ comp = new Component(core.props);
912
+ comp.render = entity.bind(comp);
913
+ comp[CORE].hooks = [];
914
+ comp[CORE].hook_index = 0;
915
+ }
916
+ else {
917
+ throw new Error("Error in constructing component.");
918
+ }
871
919
 
872
- comp = new Component(core.props);
920
+ if(loc) comp[CORE].location = loc;
873
921
 
874
- // the binding is not necessary and is not according to the specs,
875
- // probably not even recommended! but helpful.
876
- comp.render = entity.bind(comp);
877
- comp[CORE].hooks = [];
878
- comp[CORE].hook_index = 0;
879
- }
880
- else {
881
- throw new Error("Error in constructing component.");
882
- }
922
+ comp[CORE].entity = entity;
923
+ registerComponentCore(comp[CORE]);
883
924
 
884
- comp[CORE].entity = entity;
885
- registerComponentCore(comp[CORE]);
925
+ if (core.container) {
926
+ comp[CORE].container = core.container;
927
+ }
886
928
 
887
- if (core.container) {
888
- comp[CORE].container = core.container;
889
- }
929
+ if (memoized) {
930
+ comp[CORE][MEMOIZED] = true;
890
931
  }
932
+ }
891
933
 
892
- if(memoized) comp[CORE][MEMOIZED] = true;
934
+ if (parent instanceof ComponentCore) {
935
+ comp[CORE].parent = parent;
893
936
  }
894
937
 
895
- if(parent instanceof ComponentCore) comp[CORE].parent = parent;
896
938
  return comp;
897
939
  }
898
940
 
941
+
899
942
  function prepareCore(parent, core) {
900
943
  try {
901
944
  parent.cache ??= new ComponentCache(parent);
@@ -903,13 +946,12 @@ function prepareCore(parent, core) {
903
946
  const isText = core[TEXT] !== undefined;
904
947
 
905
948
  const key = isText
906
- ? ':text:'
907
- : core.props?.key;
949
+ ? ':text:'
950
+ : core.props?.key;
908
951
 
909
- const entity =
910
- isText || core instanceof ComponentCore
911
- ? undefined
912
- : core.entity;
952
+ const entity = isText || core instanceof ComponentCore
953
+ ? undefined
954
+ : core.entity;
913
955
 
914
956
  return parent.cache.pick(
915
957
  key,
@@ -920,10 +962,12 @@ function prepareCore(parent, core) {
920
962
  ),
921
963
  entity
922
964
  );
923
- } catch (e) {
965
+ }
966
+ catch (e) {
924
967
  if (core?.component?.componentDidCatch) {
925
968
  core.component.componentDidCatch(e);
926
- } else {
969
+ }
970
+ else {
927
971
  throw e;
928
972
  }
929
973
  }
@@ -1383,7 +1427,6 @@ export function createRoot(element)
1383
1427
  },
1384
1428
 
1385
1429
  getCore() {
1386
- console.log(root, root[CORE]);
1387
1430
  return root[CORE];
1388
1431
  }
1389
1432
  }
@@ -1391,26 +1434,6 @@ export function createRoot(element)
1391
1434
 
1392
1435
 
1393
1436
 
1394
- export function hotReloadRoot(rootCore, nextEntity, props) {
1395
- if (!rootCore || !rootCore.component) {
1396
- throw new Error("Invalid root component.");
1397
- }
1398
-
1399
- const replaced = replaceComponentEntity(rootCore, nextEntity);
1400
-
1401
- if (!replaced) {
1402
- throw new Error(
1403
- "Cannot hot-reload the root from a class component to a function component, or vice versa."
1404
- );
1405
- }
1406
-
1407
- rootCore.apply(props === undefined ? rootCore.props : {...rootCore.props, ...props});
1408
-
1409
- return rootCore;
1410
- }
1411
-
1412
-
1413
-
1414
1437
  /**
1415
1438
  * Creates a portal — a way to render children into a DOM node
1416
1439
  * that exists outside the current component hierarchy.
package/src/jsx.js CHANGED
@@ -50,7 +50,7 @@
50
50
  import * as vlq from './vlq.js'
51
51
  import {processImportExports} from './expscan.js'
52
52
 
53
-
53
+ const LOCATION = Symbol.for('LILACT:LOCATION'); // it is also defined in symbols.jsx.
54
54
 
55
55
  /** @ignore */
56
56
  export const transpilerConfig = {
@@ -982,6 +982,7 @@ export function transpileJSX( jsx, {
982
982
  discardComments = false,
983
983
  produceCJS = false,
984
984
  logErrors = false,
985
+ addLocationProp = false,
985
986
 
986
987
  // lilact internal
987
988
  mappings = [],
@@ -1175,7 +1176,10 @@ export function transpileJSX( jsx, {
1175
1176
  }
1176
1177
 
1177
1178
  const loc = getRowCol(eols,node.begin);
1178
- out = ` ${factory}( ${node.tag}, { ${out} )`; //lilact_jsx_loc:["${path}", ${loc}]
1179
+ if(addLocationProp)
1180
+ out = ` ${factory}( ${node.tag}, { [Lilact.LOCATION]:["${path}", ${loc}], ${out} )`;
1181
+ else
1182
+ out = ` ${factory}( ${node.tag}, { ${out} )`;
1179
1183
 
1180
1184
  return out;
1181
1185
  }
package/src/lilact.jsx CHANGED
@@ -94,7 +94,7 @@ export {transpileJSX, transpilerConfig} from "./jsx";
94
94
  export const Lilact =
95
95
  {
96
96
 
97
- VERSION: "RC.6",
97
+ VERSION: "RC.7",
98
98
 
99
99
  // Configuration
100
100
 
package/src/run.jsx CHANGED
@@ -355,6 +355,7 @@ export function run(
355
355
  appendSourcemap: true,
356
356
  injectTraceLabels: true,
357
357
  produceCJS: true,
358
+ addLocationProp: true,
358
359
  blocksInfo: Lilact.blocksInfo,
359
360
  });
360
361
  } catch (value) {
package/src/symbols.jsx CHANGED
@@ -30,6 +30,8 @@
30
30
 
31
31
 
32
32
  export const [
33
+ LOCATION,
34
+
33
35
  CORE,
34
36
  COMPONENT,
35
37
  TEXT,
@@ -44,9 +46,11 @@ export const [
44
46
  CLEARED,
45
47
  INTERVAL,
46
48
  CALLBACK,
47
- ARGS
49
+ ARGS
48
50
  ] =
49
51
  [
52
+ Symbol.for('LILACT:LOCATION'),
53
+
50
54
  Symbol.for('LILACT:CORE'),
51
55
  Symbol.for('LILACT:COMPONENT'),
52
56
  Symbol.for('LILACT:TEXT'),
@@ -1 +0,0 @@
1
- <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>hotReloadRoot | Lilact</title><meta name="description" content="Documentation for Lilact"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">Lilact</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="../modules/components.html">components</a></li><li><a href="" aria-current="page">hotReloadRoot</a></li></ul><h1>Function hotReloadRoot</h1></div><section class="tsd-panel"><ul class="tsd-signatures"><li class=""><div class="tsd-signature tsd-anchor-link" id="hotreloadroot"><span class="tsd-kind-call-signature">hotReloadRoot</span><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">rootCore</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">,</span> <span class="tsd-kind-parameter">nextEntity</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">,</span> <span class="tsd-kind-parameter">props</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">any</span><a href="#hotreloadroot" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></div><div class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">rootCore</span>: <span class="tsd-signature-type">any</span></span></li><li><span><span class="tsd-kind-parameter">nextEntity</span>: <span class="tsd-signature-type">any</span></span></li><li><span><span class="tsd-kind-parameter">props</span>: <span class="tsd-signature-type">any</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">any</span></h4><aside class="tsd-sources"><ul><li>Defined in components.jsx:1394</li></ul></aside></div></li></ul></section></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">Lilact</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>