lithent 0.1.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +202 -0
  3. package/dist/diff.d.ts +14 -0
  4. package/dist/hook/mountCallback.d.ts +3 -0
  5. package/dist/hook/ref.d.ts +3 -0
  6. package/dist/hook/unmount.d.ts +3 -0
  7. package/dist/hook/updateCallback.d.ts +2 -0
  8. package/dist/hook/useUpdate.d.ts +3 -0
  9. package/dist/index.d.ts +29 -0
  10. package/dist/lithent.mjs +867 -0
  11. package/dist/lithent.mjs.map +1 -0
  12. package/dist/lithent.umd.js +2 -0
  13. package/dist/lithent.umd.js.map +1 -0
  14. package/dist/render.d.ts +15 -0
  15. package/dist/types/index.d.ts +65 -0
  16. package/dist/utils/index.d.ts +3 -0
  17. package/dist/utils/predicator.d.ts +36 -0
  18. package/dist/utils/universalRef.d.ts +59 -0
  19. package/dist/wDom.d.ts +17 -0
  20. package/examples/dist/assets/index.e76a0ef8.js +2 -0
  21. package/examples/dist/assets/index.e76a0ef8.js.map +1 -0
  22. package/examples/dist/index.html +13 -0
  23. package/examples/package.json +33 -0
  24. package/examples/src/index.tsx +109 -0
  25. package/helper/dist/hook/computed.d.ts +4 -0
  26. package/helper/dist/hook/effect.d.ts +1 -0
  27. package/helper/dist/hook/state.d.ts +4 -0
  28. package/helper/dist/hook/store.d.ts +8 -0
  29. package/helper/dist/index.d.ts +4 -0
  30. package/helper/dist/lithentHelper.mjs +56 -0
  31. package/helper/dist/lithentHelper.mjs.map +1 -0
  32. package/helper/dist/lithentHelper.umd.js +2 -0
  33. package/helper/dist/lithentHelper.umd.js.map +1 -0
  34. package/helper/package.json +32 -0
  35. package/helper/src/hook/computed.ts +23 -0
  36. package/helper/src/hook/effect.ts +20 -0
  37. package/helper/src/hook/state.ts +26 -0
  38. package/helper/src/hook/store.ts +25 -0
  39. package/helper/src/index.ts +4 -0
  40. package/package.json +90 -0
  41. package/router/dist/Router.d.ts +4 -0
  42. package/router/dist/Router.mjs +56 -0
  43. package/router/dist/Router.mjs.map +1 -0
  44. package/router/dist/Router.umd.js +2 -0
  45. package/router/dist/Router.umd.js.map +1 -0
  46. package/router/dist/hook/params.d.ts +2 -0
  47. package/router/package.json +37 -0
  48. package/router/src/Router.tsx +63 -0
  49. package/router/src/components/Main.tsx +14 -0
  50. package/router/src/components/Sub.tsx +7 -0
  51. package/router/src/components/Sub2.tsx +17 -0
  52. package/router/src/example.tsx +19 -0
  53. package/router/src/hook/params.ts +9 -0
  54. package/src/diff.ts +235 -0
  55. package/src/examples/callback.tsx +81 -0
  56. package/src/examples/insert.tsx +36 -0
  57. package/src/examples/loop.tsx +33 -0
  58. package/src/examples/nested.tsx +44 -0
  59. package/src/examples/renew.tsx +29 -0
  60. package/src/examples/selectbox.tsx +42 -0
  61. package/src/examples/textarea.tsx +24 -0
  62. package/src/hook/mountCallback.ts +41 -0
  63. package/src/hook/ref.ts +1 -0
  64. package/src/hook/unmount.ts +26 -0
  65. package/src/hook/updateCallback.ts +29 -0
  66. package/src/hook/useUpdate.ts +51 -0
  67. package/src/index.ts +50 -0
  68. package/src/render.ts +409 -0
  69. package/src/types/index.ts +107 -0
  70. package/src/utils/index.ts +52 -0
  71. package/src/utils/predicator.ts +119 -0
  72. package/src/utils/universalRef.ts +137 -0
  73. package/src/wDom.ts +284 -0
@@ -0,0 +1,56 @@
1
+ import { mount as h, mountCallback as i, h as v, Fragment as m } from "lithent";
2
+ const w = (a, s) => {
3
+ let t = a;
4
+ return {
5
+ get value() {
6
+ return t;
7
+ },
8
+ get v() {
9
+ return t;
10
+ },
11
+ set value(r) {
12
+ t = r, s();
13
+ },
14
+ set v(r) {
15
+ t = r, s();
16
+ }
17
+ };
18
+ }, f = { value: {} };
19
+ function C() {
20
+ return f.value;
21
+ }
22
+ function S(a, s) {
23
+ f.value[a] = s;
24
+ }
25
+ const L = h((a, s, t) => {
26
+ const r = w("", a), g = (o) => t.find((n) => {
27
+ var e;
28
+ return ((e = n.componentProps) == null ? void 0 : e.path) === o;
29
+ }), P = () => t.find((o) => {
30
+ var n;
31
+ return /^:/.test(String(((n = o == null ? void 0 : o.componentProps) == null ? void 0 : n.path) || ""));
32
+ }), u = () => {
33
+ var e, c, p, l;
34
+ const o = window.location.hash.replace(/^[#\/]*/, "") || String(((c = (e = t[0]) == null ? void 0 : e.componentProps) == null ? void 0 : c.path) || "");
35
+ let n = g(o);
36
+ n || (n = P(), n && S(
37
+ String(((p = n == null ? void 0 : n.componentProps) == null ? void 0 : p.path) || "").replace(/^:/, ""),
38
+ o
39
+ )), n && (r.v = String(((l = n == null ? void 0 : n.componentProps) == null ? void 0 : l.path) || ""));
40
+ }, d = () => {
41
+ console.log("unmount"), window.removeEventListener("hashchange", u);
42
+ };
43
+ return window.addEventListener("hashchange", u), i(() => (u(), d)), () => /* @__PURE__ */ v(m, null, t.map((o) => {
44
+ var c, p;
45
+ const n = String(((c = o == null ? void 0 : o.componentProps) == null ? void 0 : c.path) || ""), e = (p = o == null ? void 0 : o.componentProps) == null ? void 0 : p.element;
46
+ return r.v === n ? e : null;
47
+ }));
48
+ }), R = h(function() {
49
+ return () => /* @__PURE__ */ v("div", null);
50
+ });
51
+ export {
52
+ L as Router,
53
+ R as RouterItem,
54
+ C as useParams
55
+ };
56
+ //# sourceMappingURL=Router.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Router.mjs","sources":["../../helper/dist/lithentHelper.mjs","../src/hook/params.ts","../src/Router.tsx"],"sourcesContent":["import { mountCallback as o, updateCallback as a } from \"lithent\";\nconst s = (r, e) => {\n let t = r;\n return {\n get value() {\n return t;\n },\n get v() {\n return t;\n },\n set value(u) {\n t = u, e();\n },\n set v(u) {\n t = u, e();\n }\n };\n}, v = (r) => {\n let e = r;\n return {\n get value() {\n return e();\n },\n get v() {\n return e();\n },\n set value(t) {\n throw new Error(\"You can't change 'computed'\");\n },\n set v(t) {\n throw new Error(\"You can't change 'computed'\");\n }\n };\n}, g = (r, e, t = () => []) => {\n o(() => (r(), e)), a(() => (e(), r), t);\n}, p = (r, e) => c({\n initValue: r,\n renew: e\n}), c = ({\n initValue: r,\n renew: e\n}) => new Proxy(r, {\n get(t, u) {\n return t[u];\n },\n set(t, u, n) {\n return t[u] = n, e(), !0;\n }\n});\nexport {\n v as computed,\n g as effect,\n s as state,\n p as store\n};\n//# sourceMappingURL=lithentHelper.mjs.map\n","const routerParams = { value: {} } as { value: Record<string, string> };\n\nexport function useParams() {\n return routerParams.value;\n}\n\nexport function addParams(key: string, value: string) {\n routerParams.value[key] = value;\n}\n","import { h, Fragment, TagFunction, mountCallback, mount } from 'lithent';\nimport { state } from 'lithent/helper';\nimport { addParams } from '@/hook/params';\nexport { useParams } from '@/hook/params';\n\nexport const Router: TagFunction = mount((renew, _props, children) => {\n const targetPathString = state<string>('', renew);\n const findPath = (injectPath: string) =>\n children.find(item => item.componentProps?.path === injectPath);\n\n const findDynamicPath = () =>\n children.find(item => /^:/.test(String(item?.componentProps?.path || '')));\n\n const handleHashChange = () => {\n const injectPath =\n window.location.hash.replace(/^[#\\/]*/, '') ||\n String(children[0]?.componentProps?.path || '');\n let targetPath = findPath(injectPath);\n\n if (!targetPath) {\n targetPath = findDynamicPath();\n\n if (targetPath) {\n addParams(\n String(targetPath?.componentProps?.path || '').replace(/^:/, ''),\n injectPath\n );\n }\n }\n\n if (targetPath) {\n targetPathString.v = String(targetPath?.componentProps?.path || '');\n }\n };\n\n const removeEvent = () => {\n console.log('unmount');\n window.removeEventListener('hashchange', handleHashChange);\n };\n\n window.addEventListener('hashchange', handleHashChange);\n\n mountCallback(() => {\n handleHashChange();\n\n return removeEvent;\n });\n\n return () => (\n <Fragment>\n {children.map(item => {\n const path = String(item?.componentProps?.path || '');\n const element = item?.componentProps?.element;\n\n return targetPathString.v === path ? element : null;\n })}\n </Fragment>\n );\n});\n\nexport const RouterItem: TagFunction = mount(function () {\n return () => <div />;\n});\n"],"names":["s","r","e","u","routerParams","useParams","addParams","key","value","Router","mount","renew","_props","children","targetPathString","state","findPath","injectPath","item","_a","findDynamicPath","handleHashChange","_b","targetPath","_c","_d","removeEvent","mountCallback","h","Fragment","path","element","RouterItem"],"mappings":";AACK,MAACA,IAAI,CAACC,GAAGC,MAAM;AAClB,MAAI,IAAID;AACR,SAAO;AAAA,IACL,IAAI,QAAQ;AACV,aAAO;AAAA,IACR;AAAA,IACD,IAAI,IAAI;AACN,aAAO;AAAA,IACR;AAAA,IACD,IAAI,MAAME,GAAG;AACX,UAAIA,GAAGD;IACR;AAAA,IACD,IAAI,EAAEC,GAAG;AACP,UAAIA,GAAGD;IACR;AAAA,EACL;AACA,GCjBME,IAAe,EAAE,OAAO,CAAA;AAEvB,SAASC,IAAY;AAC1B,SAAOD,EAAa;AACtB;AAEgB,SAAAE,EAAUC,GAAaC,GAAe;AACpD,EAAAJ,EAAa,MAAMG,KAAOC;AAC5B;ACHO,MAAMC,IAAsBC,EAAM,CAACC,GAAOC,GAAQC,MAAa;AAC9D,QAAAC,IAAmBC,EAAc,IAAIJ,CAAK,GAC1CK,IAAW,CAACC,MAChBJ,EAAS,KAAK,CAAQK,MAAA;;AAAA,aAAAC,IAAAD,EAAK,mBAAL,gBAAAC,EAAqB,UAASF;AAAA,GAAU,GAE1DG,IAAkB,MACtBP,EAAS,KAAK,CAAQK,MAAA;;AAAA,gBAAK,KAAK,SAAOC,IAAAD,KAAA,gBAAAA,EAAM,mBAAN,gBAAAC,EAAsB,SAAQ,EAAE,CAAC;AAAA,GAAC,GAErEE,IAAmB,MAAM;;AAC7B,UAAMJ,IACJ,OAAO,SAAS,KAAK,QAAQ,WAAW,EAAE,KAC1C,SAAOK,KAAAH,IAAAN,EAAS,OAAT,gBAAAM,EAAa,mBAAb,gBAAAG,EAA6B,SAAQ,EAAE;AAC5C,QAAAC,IAAaP,EAASC,CAAU;AAEpC,IAAKM,MACHA,IAAaH,EAAgB,GAEzBG,KACFjB;AAAA,MACE,SAAOkB,IAAAD,KAAA,gBAAAA,EAAY,mBAAZ,gBAAAC,EAA4B,SAAQ,EAAE,EAAE,QAAQ,MAAM,EAAE;AAAA,MAC/DP;AAAA,IAAA,IAKFM,MACFT,EAAiB,IAAI,SAAOW,IAAAF,KAAA,gBAAAA,EAAY,mBAAZ,gBAAAE,EAA4B,SAAQ,EAAE;AAAA,EACpE,GAGIC,IAAc,MAAM;AACxB,YAAQ,IAAI,SAAS,GACd,OAAA,oBAAoB,cAAcL,CAAgB;AAAA,EAAA;AAGpD,gBAAA,iBAAiB,cAAcA,CAAgB,GAEtDM,EAAc,OACKN,KAEVK,EACR,GAEM,MACL,gBAAAE,EAACC,GACE,MAAAhB,EAAS,IAAI,CAAQK,MAAA;;AACpB,UAAMY,IAAO,SAAOX,IAAAD,KAAA,gBAAAA,EAAM,mBAAN,gBAAAC,EAAsB,SAAQ,EAAE,GAC9CY,KAAUT,IAAAJ,KAAA,gBAAAA,EAAM,mBAAN,gBAAAI,EAAsB;AAE/B,WAAAR,EAAiB,MAAMgB,IAAOC,IAAU;AAAA,EAChD,CAAA,CACH;AAEJ,CAAC,GAEYC,IAA0BtB,EAAM,WAAY;AAChD,SAAA,wBAAO,OAAI,IAAA;AACpB,CAAC;"}
@@ -0,0 +1,2 @@
1
+ (function(t,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("lithent")):typeof define=="function"&&define.amd?define(["exports","lithent"],o):(t=typeof globalThis<"u"?globalThis:t||self,o(t.Router={},t.lithent))})(this,function(t,o){"use strict";const h=(a,c)=>{let r=a;return{get value(){return r},get v(){return r},set value(u){r=u,c()},set v(u){r=u,c()}}},d={value:{}};function v(){return d.value}function m(a,c){d.value[a]=c}const P=o.mount((a,c,r)=>{const u=h("",a),S=e=>r.find(n=>{var s;return((s=n.componentProps)==null?void 0:s.path)===e}),w=()=>r.find(e=>{var n;return/^:/.test(String(((n=e==null?void 0:e.componentProps)==null?void 0:n.path)||""))}),l=()=>{var s,p,i,f;const e=window.location.hash.replace(/^[#\/]*/,"")||String(((p=(s=r[0])==null?void 0:s.componentProps)==null?void 0:p.path)||"");let n=S(e);n||(n=w(),n&&m(String(((i=n==null?void 0:n.componentProps)==null?void 0:i.path)||"").replace(/^:/,""),e)),n&&(u.v=String(((f=n==null?void 0:n.componentProps)==null?void 0:f.path)||""))},R=()=>{console.log("unmount"),window.removeEventListener("hashchange",l)};return window.addEventListener("hashchange",l),o.mountCallback(()=>(l(),R)),()=>o.h(o.Fragment,null,r.map(e=>{var p,i;const n=String(((p=e==null?void 0:e.componentProps)==null?void 0:p.path)||""),s=(i=e==null?void 0:e.componentProps)==null?void 0:i.element;return u.v===n?s:null}))}),g=o.mount(function(){return()=>o.h("div",null)});t.Router=P,t.RouterItem=g,t.useParams=v,Object.defineProperties(t,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
2
+ //# sourceMappingURL=Router.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Router.umd.js","sources":["../../helper/dist/lithentHelper.mjs","../src/hook/params.ts","../src/Router.tsx"],"sourcesContent":["import { mountCallback as o, updateCallback as a } from \"lithent\";\nconst s = (r, e) => {\n let t = r;\n return {\n get value() {\n return t;\n },\n get v() {\n return t;\n },\n set value(u) {\n t = u, e();\n },\n set v(u) {\n t = u, e();\n }\n };\n}, v = (r) => {\n let e = r;\n return {\n get value() {\n return e();\n },\n get v() {\n return e();\n },\n set value(t) {\n throw new Error(\"You can't change 'computed'\");\n },\n set v(t) {\n throw new Error(\"You can't change 'computed'\");\n }\n };\n}, g = (r, e, t = () => []) => {\n o(() => (r(), e)), a(() => (e(), r), t);\n}, p = (r, e) => c({\n initValue: r,\n renew: e\n}), c = ({\n initValue: r,\n renew: e\n}) => new Proxy(r, {\n get(t, u) {\n return t[u];\n },\n set(t, u, n) {\n return t[u] = n, e(), !0;\n }\n});\nexport {\n v as computed,\n g as effect,\n s as state,\n p as store\n};\n//# sourceMappingURL=lithentHelper.mjs.map\n","const routerParams = { value: {} } as { value: Record<string, string> };\n\nexport function useParams() {\n return routerParams.value;\n}\n\nexport function addParams(key: string, value: string) {\n routerParams.value[key] = value;\n}\n","import { h, Fragment, TagFunction, mountCallback, mount } from 'lithent';\nimport { state } from 'lithent/helper';\nimport { addParams } from '@/hook/params';\nexport { useParams } from '@/hook/params';\n\nexport const Router: TagFunction = mount((renew, _props, children) => {\n const targetPathString = state<string>('', renew);\n const findPath = (injectPath: string) =>\n children.find(item => item.componentProps?.path === injectPath);\n\n const findDynamicPath = () =>\n children.find(item => /^:/.test(String(item?.componentProps?.path || '')));\n\n const handleHashChange = () => {\n const injectPath =\n window.location.hash.replace(/^[#\\/]*/, '') ||\n String(children[0]?.componentProps?.path || '');\n let targetPath = findPath(injectPath);\n\n if (!targetPath) {\n targetPath = findDynamicPath();\n\n if (targetPath) {\n addParams(\n String(targetPath?.componentProps?.path || '').replace(/^:/, ''),\n injectPath\n );\n }\n }\n\n if (targetPath) {\n targetPathString.v = String(targetPath?.componentProps?.path || '');\n }\n };\n\n const removeEvent = () => {\n console.log('unmount');\n window.removeEventListener('hashchange', handleHashChange);\n };\n\n window.addEventListener('hashchange', handleHashChange);\n\n mountCallback(() => {\n handleHashChange();\n\n return removeEvent;\n });\n\n return () => (\n <Fragment>\n {children.map(item => {\n const path = String(item?.componentProps?.path || '');\n const element = item?.componentProps?.element;\n\n return targetPathString.v === path ? element : null;\n })}\n </Fragment>\n );\n});\n\nexport const RouterItem: TagFunction = mount(function () {\n return () => <div />;\n});\n"],"names":["s","r","e","t","routerParams","useParams","addParams","key","value","Router","mount","renew","_props","children","targetPathString","state","findPath","injectPath","item","_a","findDynamicPath","handleHashChange","_b","targetPath","_c","_d","removeEvent","mountCallback","h","Fragment","path","element","RouterItem"],"mappings":"uQACK,MAACA,EAAI,CAACC,EAAGC,IAAM,CAClB,IAAIC,EAAIF,EACR,MAAO,CACL,IAAI,OAAQ,CACV,OAAOE,CACR,EACD,IAAI,GAAI,CACN,OAAOA,CACR,EACD,IAAI,MAAM,EAAG,CACXA,EAAI,EAAGD,GACR,EACD,IAAI,EAAE,EAAG,CACPC,EAAI,EAAGD,GACR,CACL,CACA,ECjBME,EAAe,CAAE,MAAO,CAAA,GAEvB,SAASC,GAAY,CAC1B,OAAOD,EAAa,KACtB,CAEgB,SAAAE,EAAUC,EAAaC,EAAe,CACpDJ,EAAa,MAAMG,GAAOC,CAC5B,CCHa,MAAAC,EAAsBC,EAAAA,MAAM,CAACC,EAAOC,EAAQC,IAAa,CAC9D,MAAAC,EAAmBC,EAAc,GAAIJ,CAAK,EAC1CK,EAAYC,GAChBJ,EAAS,KAAaK,GAAA,OAAA,QAAAC,EAAAD,EAAK,iBAAL,YAAAC,EAAqB,QAASF,EAAU,EAE1DG,EAAkB,IACtBP,EAAS,KAAaK,GAAA,OAAA,WAAK,KAAK,SAAOC,EAAAD,GAAA,YAAAA,EAAM,iBAAN,YAAAC,EAAsB,OAAQ,EAAE,CAAC,EAAC,EAErEE,EAAmB,IAAM,aAC7B,MAAMJ,EACJ,OAAO,SAAS,KAAK,QAAQ,UAAW,EAAE,GAC1C,SAAOK,GAAAH,EAAAN,EAAS,KAAT,YAAAM,EAAa,iBAAb,YAAAG,EAA6B,OAAQ,EAAE,EAC5C,IAAAC,EAAaP,EAASC,CAAU,EAE/BM,IACHA,EAAaH,EAAgB,EAEzBG,GACFjB,EACE,SAAOkB,EAAAD,GAAA,YAAAA,EAAY,iBAAZ,YAAAC,EAA4B,OAAQ,EAAE,EAAE,QAAQ,KAAM,EAAE,EAC/DP,CAAA,GAKFM,IACFT,EAAiB,EAAI,SAAOW,EAAAF,GAAA,YAAAA,EAAY,iBAAZ,YAAAE,EAA4B,OAAQ,EAAE,EACpE,EAGIC,EAAc,IAAM,CACxB,QAAQ,IAAI,SAAS,EACd,OAAA,oBAAoB,aAAcL,CAAgB,CAAA,EAGpD,cAAA,iBAAiB,aAAcA,CAAgB,EAEtDM,EAAAA,cAAc,KACKN,IAEVK,EACR,EAEM,IACLE,EAAA,EAACC,WACE,KAAAhB,EAAS,IAAYK,GAAA,SACpB,MAAMY,EAAO,SAAOX,EAAAD,GAAA,YAAAA,EAAM,iBAAN,YAAAC,EAAsB,OAAQ,EAAE,EAC9CY,GAAUT,EAAAJ,GAAA,YAAAA,EAAM,iBAAN,YAAAI,EAAsB,QAE/B,OAAAR,EAAiB,IAAMgB,EAAOC,EAAU,IAChD,CAAA,CACH,CAEJ,CAAC,EAEYC,EAA0BtB,QAAM,UAAY,CAChD,MAAA,QAAO,MAAI,IAAA,CACpB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function useParams(): Record<string, string>;
2
+ export declare function addParams(key: string, value: string): void;
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "lithent-router",
3
+ "private": true,
4
+ "version": "0.6.0",
5
+ "description": "lithent-router",
6
+ "main": "./dist/Router.umd.js",
7
+ "module": "./dist/Router.mjs",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/Router.mjs",
11
+ "require": "./dist/Router.umd.js"
12
+ }
13
+ },
14
+ "types": "./dist/Router.d.ts",
15
+ "scripts": {
16
+ "dev": "vite",
17
+ "build": "vite build"
18
+ },
19
+ "peerDependencies": {
20
+ "lithent": "workspace:*",
21
+ "lithent-helper": "workspace:*"
22
+ },
23
+ "author": "superlucky84",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https@github.com:superlucky84/lithent.git",
28
+ "directory": "router"
29
+ },
30
+ "homepage": "https://github.com/superlucky84/lithent/tree/master/router",
31
+ "keywords": [
32
+ "lithent"
33
+ ],
34
+ "volta": {
35
+ "node": "20.3.0"
36
+ }
37
+ }
@@ -0,0 +1,63 @@
1
+ import { h, Fragment, TagFunction, mountCallback, mount } from 'lithent';
2
+ import { state } from 'lithent/helper';
3
+ import { addParams } from '@/hook/params';
4
+ export { useParams } from '@/hook/params';
5
+
6
+ export const Router: TagFunction = mount((renew, _props, children) => {
7
+ const targetPathString = state<string>('', renew);
8
+ const findPath = (injectPath: string) =>
9
+ children.find(item => item.componentProps?.path === injectPath);
10
+
11
+ const findDynamicPath = () =>
12
+ children.find(item => /^:/.test(String(item?.componentProps?.path || '')));
13
+
14
+ const handleHashChange = () => {
15
+ const injectPath =
16
+ window.location.hash.replace(/^[#\/]*/, '') ||
17
+ String(children[0]?.componentProps?.path || '');
18
+ let targetPath = findPath(injectPath);
19
+
20
+ if (!targetPath) {
21
+ targetPath = findDynamicPath();
22
+
23
+ if (targetPath) {
24
+ addParams(
25
+ String(targetPath?.componentProps?.path || '').replace(/^:/, ''),
26
+ injectPath
27
+ );
28
+ }
29
+ }
30
+
31
+ if (targetPath) {
32
+ targetPathString.v = String(targetPath?.componentProps?.path || '');
33
+ }
34
+ };
35
+
36
+ const removeEvent = () => {
37
+ console.log('unmount');
38
+ window.removeEventListener('hashchange', handleHashChange);
39
+ };
40
+
41
+ window.addEventListener('hashchange', handleHashChange);
42
+
43
+ mountCallback(() => {
44
+ handleHashChange();
45
+
46
+ return removeEvent;
47
+ });
48
+
49
+ return () => (
50
+ <Fragment>
51
+ {children.map(item => {
52
+ const path = String(item?.componentProps?.path || '');
53
+ const element = item?.componentProps?.element;
54
+
55
+ return targetPathString.v === path ? element : null;
56
+ })}
57
+ </Fragment>
58
+ );
59
+ });
60
+
61
+ export const RouterItem: TagFunction = mount(function () {
62
+ return () => <div />;
63
+ });
@@ -0,0 +1,14 @@
1
+ import { h, Fragment, mount, TagFunction } from 'lithent';
2
+
3
+ const Main: TagFunction = mount(function () {
4
+ return () => (
5
+ <div>
6
+ <Fragment>
7
+ <div>3</div>
8
+ <div>3</div>
9
+ </Fragment>
10
+ </div>
11
+ );
12
+ });
13
+
14
+ export default Main;
@@ -0,0 +1,7 @@
1
+ import { h, mount, TagFunction } from 'lithent';
2
+
3
+ const Sub: TagFunction = mount(function Sub() {
4
+ return () => <div>Sub</div>;
5
+ });
6
+
7
+ export default Sub;
@@ -0,0 +1,17 @@
1
+ import { h, mount, TagFunction } from 'lithent';
2
+ import { useParams } from '@/hook/params';
3
+
4
+ const Sub2: TagFunction = mount(function () {
5
+ const params = useParams();
6
+ const handle = () => {
7
+ console.log('red', params);
8
+ };
9
+
10
+ return () => (
11
+ <div style={{ color: 'red' }} onClick={handle}>
12
+ Sub222
13
+ </div>
14
+ );
15
+ });
16
+
17
+ export default Sub2;
@@ -0,0 +1,19 @@
1
+ import { h, Fragment, render, mount } from 'lithent';
2
+ import { Router, RouterItem } from '@/Router';
3
+ import Main from '@/components/Main';
4
+ import Sub from '@/components/Sub';
5
+ import Sub2 from '@/components/Sub2';
6
+
7
+ const Root = mount(function () {
8
+ return () => (
9
+ <Fragment>
10
+ <Router>
11
+ <RouterItem path="main" element={<Main />} />
12
+ <RouterItem path="sub" element={<Sub />} />
13
+ <RouterItem path=":sub" element={<Sub2 />} />
14
+ </Router>
15
+ </Fragment>
16
+ );
17
+ });
18
+
19
+ render(<Root />, document.getElementById('root'));
@@ -0,0 +1,9 @@
1
+ const routerParams = { value: {} } as { value: Record<string, string> };
2
+
3
+ export function useParams() {
4
+ return routerParams.value;
5
+ }
6
+
7
+ export function addParams(key: string, value: string) {
8
+ routerParams.value[key] = value;
9
+ }
package/src/diff.ts ADDED
@@ -0,0 +1,235 @@
1
+ /**
2
+ * 변경점의 컴포넌트로 부터 기존트리와 상태를 비교하며 새로 가상돔 트리를 새로 만든다.
3
+ * (오리지널 가상돔으로 부터 유의미한 상태를 유지해야 하는 경우를 판별하여 새로운 트리를 만듬)
4
+ *
5
+ * 1. 동일한 트리의 위치해 있고 오리지널과 컴포넌트의 타입이 같은경우 기존 상태를 계승한다.
6
+ * 2. 동일한 컴포넌트가 아니라고 판단되는 경우에는 기존 상태를 무시하는 새로운 트리를 생성한다.
7
+ * 3. fragment타입의 경우에는 children의 갯수까지 같아야지 같은 타입이라고 판단한다.
8
+ * 4. loop타입의 자식들은 같은 키값을 가졌는지로 동일한지 판단하며 키값이 없을경우 fragment타입처럼 취급한다.
9
+ */
10
+ import { WDom, TagFunctionResolver, RenderType } from '@/types';
11
+ import { checkCustemComponentFunction } from '@/utils/predicator';
12
+ import { getParent, reRender } from '@/utils';
13
+ import { recursiveRemoveEvent } from '@/render';
14
+ import {
15
+ checkEmptyElement,
16
+ checkSameWDomWithOriginal,
17
+ getWDomType,
18
+ checkExisty,
19
+ } from '@/utils/predicator';
20
+
21
+ import { runUnmountQueueFromWDom } from '@/hook/unmount';
22
+ import { removeNodeChildKey } from '@/utils/universalRef';
23
+
24
+ type DiffPrimaryParam = {
25
+ originalWDom?: WDom;
26
+ newWDom: WDom | TagFunctionResolver;
27
+ isSameType: boolean;
28
+ };
29
+
30
+ type DiffSecondeParam = {
31
+ originalWDom?: WDom;
32
+ newWDom: WDom;
33
+ isSameType: boolean;
34
+ };
35
+
36
+ export const makeNewWDomTree = ({
37
+ originalWDom,
38
+ newWDom,
39
+ }: {
40
+ originalWDom?: WDom;
41
+ newWDom: WDom | TagFunctionResolver;
42
+ }) => {
43
+ const type = getWDomType(newWDom);
44
+
45
+ if (!type) {
46
+ throw new Error('Unknown type wdom');
47
+ }
48
+ const isSameType = checkSameWDomWithOriginal[type]({ originalWDom, newWDom });
49
+
50
+ const result = remakeNewWDom({ originalWDom, newWDom, isSameType });
51
+
52
+ if (result?.nodeChildKey) {
53
+ removeNodeChildKey(result.nodeChildKey);
54
+ }
55
+
56
+ return result;
57
+ };
58
+
59
+ const remakeNewWDom = ({
60
+ newWDom,
61
+ originalWDom,
62
+ isSameType,
63
+ }: DiffPrimaryParam) => {
64
+ const remakeWDom = generalize({ newWDom, originalWDom, isSameType });
65
+
66
+ remakeWDom.children = remakeChildrenForDiff({
67
+ isSameType,
68
+ newWDom: remakeWDom,
69
+ originalWDom,
70
+ });
71
+
72
+ const needRerender = addReRenderTypeProperty({
73
+ originalWDom,
74
+ newWDom: remakeWDom,
75
+ isSameType,
76
+ });
77
+
78
+ remakeWDom.needRerender = needRerender;
79
+
80
+ if (needRerender !== 'A' && originalWDom) {
81
+ remakeWDom.el = originalWDom.el;
82
+ }
83
+
84
+ if (
85
+ needRerender &&
86
+ ['D', 'R', 'SR'].includes(needRerender) &&
87
+ originalWDom?.componentKey
88
+ ) {
89
+ runUnmountQueueFromWDom(originalWDom);
90
+ recursiveRemoveEvent(originalWDom);
91
+ remakeWDom.children = originalWDom.children;
92
+ }
93
+
94
+ remakeWDom.oldProps = originalWDom?.props;
95
+
96
+ return remakeWDom;
97
+ };
98
+
99
+ const addReRenderTypeProperty = ({
100
+ originalWDom,
101
+ newWDom,
102
+ isSameType,
103
+ }: DiffSecondeParam): RenderType | undefined => {
104
+ const existOriginalWDom = originalWDom && originalWDom.type;
105
+ const isEmptyElement = checkEmptyElement(newWDom);
106
+ const isRoot = !newWDom.getParent;
107
+ const parentType = !isRoot && getParent(newWDom).type;
108
+ const key = getKey(newWDom);
109
+ const isKeyCheckedWDom = parentType === 'loop' && checkExisty(key);
110
+ const isSameText =
111
+ newWDom.type === 'text' &&
112
+ isSameType &&
113
+ newWDom.text === originalWDom?.text;
114
+
115
+ let result: RenderType | undefined;
116
+ if (isEmptyElement) {
117
+ result = 'D';
118
+ } else if (isSameText) {
119
+ result = 'N';
120
+ } else if (!existOriginalWDom) {
121
+ result = 'A';
122
+ } else if (isSameType) {
123
+ result = isKeyCheckedWDom ? 'SU' : 'U';
124
+ } else {
125
+ result = isKeyCheckedWDom ? 'SR' : 'R';
126
+ }
127
+
128
+ return result;
129
+ };
130
+
131
+ const generalize = ({
132
+ newWDom,
133
+ originalWDom,
134
+ isSameType,
135
+ }: DiffPrimaryParam): WDom => {
136
+ if (checkCustemComponentFunction(newWDom)) {
137
+ return isSameType && originalWDom
138
+ ? reRender(originalWDom, newWDom)
139
+ : newWDom.resolve();
140
+ }
141
+
142
+ return newWDom;
143
+ };
144
+
145
+ const remakeChildrenForDiff = ({
146
+ isSameType,
147
+ newWDom,
148
+ originalWDom,
149
+ }: DiffSecondeParam) =>
150
+ isSameType && originalWDom
151
+ ? remakeChildrenForUpdate(newWDom, originalWDom)
152
+ : remakeChildrenForAdd(newWDom);
153
+
154
+ const remakeChildrenForAdd = (newWDom: WDom) =>
155
+ (newWDom.children || []).map((item: WDom) => {
156
+ const childItem = makeNewWDomTree({ newWDom: item });
157
+
158
+ childItem.getParent = () => newWDom;
159
+
160
+ return childItem;
161
+ });
162
+
163
+ const remakeChildrenForUpdate = (newWDom: WDom, originalWDom: WDom) => {
164
+ if (
165
+ newWDom.type === 'loop' &&
166
+ checkExisty(getKey((newWDom.children || [])[0]))
167
+ ) {
168
+ return remakeChildrenForLoopUpdate(newWDom, originalWDom);
169
+ }
170
+
171
+ return (newWDom.children || []).map((item: WDom, index: number) => {
172
+ const childItem = makeNewWDomTree({
173
+ newWDom: item,
174
+ originalWDom: (originalWDom.children || [])[index],
175
+ });
176
+
177
+ childItem.getParent = () => newWDom;
178
+
179
+ return childItem;
180
+ });
181
+ };
182
+
183
+ const remakeChildrenForLoopUpdate = (newWDom: WDom, originalWDom: WDom) => {
184
+ const { remakedChildren, unUsedChildren } = diffLoopChildren(
185
+ newWDom,
186
+ originalWDom
187
+ );
188
+
189
+ unUsedChildren.map(unusedItem => {
190
+ const el = unusedItem.el;
191
+
192
+ if (el && el.parentNode) {
193
+ el.parentNode.removeChild(el);
194
+ }
195
+ });
196
+
197
+ return remakedChildren;
198
+ };
199
+
200
+ const diffLoopChildren = (newWDom: WDom, originalWDom: WDom) => {
201
+ const newChildren = [...(newWDom.children || [])];
202
+ const originalChildren = [...(originalWDom.children || [])];
203
+
204
+ const remakedChildren = newChildren.map(item => {
205
+ const originalItem = findSameKeyOriginalItem(item, originalChildren);
206
+ const childItem = makeNewWDomTree({
207
+ newWDom: item,
208
+ originalWDom: originalItem,
209
+ });
210
+
211
+ if (originalItem) {
212
+ originalChildren.splice(originalChildren.indexOf(originalItem), 1);
213
+ }
214
+
215
+ childItem.getParent = () => newWDom;
216
+
217
+ return childItem;
218
+ });
219
+
220
+ return {
221
+ remakedChildren,
222
+ unUsedChildren: originalChildren,
223
+ };
224
+ };
225
+
226
+ const findSameKeyOriginalItem = (item: WDom, originalChildren: WDom[]) => {
227
+ const key = getKey(item);
228
+
229
+ return originalChildren.find(
230
+ orignalChildItem => getKey(orignalChildItem) === key
231
+ );
232
+ };
233
+
234
+ const getKey = (target: WDom) =>
235
+ target?.componentProps?.key ?? target?.props?.key;
@@ -0,0 +1,81 @@
1
+ // example.jsx
2
+ import { h, Fragment, render, mount, mountCallback } from '@/index';
3
+
4
+ const Depth4 = mount(() => {
5
+ mountCallback(() => {
6
+ console.log('MOUNT - Depth4');
7
+ return () => console.log('UNMOUNT - Depth4');
8
+ });
9
+
10
+ return () => (
11
+ <Fragment>
12
+ <div>depth4</div>
13
+ </Fragment>
14
+ );
15
+ });
16
+
17
+ const Depth3 = mount(() => {
18
+ mountCallback(() => {
19
+ console.log('MOUNT - Depth3');
20
+ return () => console.log('UNMOUNT - Depth3');
21
+ });
22
+
23
+ return () => (
24
+ <Fragment>
25
+ <div>depth3</div>
26
+ <Depth4 />
27
+ </Fragment>
28
+ );
29
+ });
30
+
31
+ const Depth2 = mount(() => {
32
+ mountCallback(() => {
33
+ console.log('MOUNT - Depth2');
34
+ return () => console.log('UNMOUNT - Depth2');
35
+ });
36
+
37
+ return () => (
38
+ <Fragment>
39
+ <div>depth2</div>
40
+ <Depth3 />
41
+ </Fragment>
42
+ );
43
+ });
44
+
45
+ const Depth1 = mount(() => {
46
+ mountCallback(() => {
47
+ console.log('MOUNT - Depth1');
48
+ return () => console.log('UNMOUNT - Depth1');
49
+ });
50
+
51
+ return () => (
52
+ <Fragment>
53
+ <div>depth1</div>
54
+ <Depth2 />
55
+ </Fragment>
56
+ );
57
+ });
58
+
59
+ const CallbackRoot = mount(renew => {
60
+ let isShow = true;
61
+
62
+ const toggle = () => {
63
+ isShow = !isShow;
64
+ console.log(isShow);
65
+ renew();
66
+ };
67
+
68
+ return () => (
69
+ <Fragment>
70
+ <button onClick={toggle}>TOGGLE</button>
71
+ {isShow ? <Depth1 /> : null}
72
+ </Fragment>
73
+ );
74
+ });
75
+
76
+ const Root = <CallbackRoot />;
77
+
78
+ //@ts-ignore
79
+ window.root = Root;
80
+
81
+ render(Root, document.getElementById('root'));
@@ -0,0 +1,36 @@
1
+ // example.jsx
2
+ import { h, Fragment, render, mount } from '@/index';
3
+
4
+ const Root = mount(function (renew) {
5
+ let showFive = false;
6
+ let showSix = false;
7
+
8
+ const toggleFive = () => {
9
+ showFive = !showFive;
10
+ renew();
11
+ };
12
+
13
+ const toggleSix = () => {
14
+ showSix = !showSix;
15
+ renew();
16
+ };
17
+
18
+ return () => (
19
+ <Fragment>
20
+ <li>
21
+ 4 <button onClick={toggleFive}>ShowFive</button>
22
+ <button onClick={toggleSix}>ShowSix</button>
23
+ </li>
24
+ {showFive ? <li>5</li> : null}
25
+ {showSix ? <li>6</li> : null}
26
+ <li>7</li>
27
+ </Fragment>
28
+ );
29
+ });
30
+
31
+ const R = <Root />;
32
+
33
+ //@ts-ignore
34
+ window.root = R;
35
+
36
+ render(R, document.getElementById('list-root'), document.getElementById('8'));
@@ -0,0 +1,33 @@
1
+ import { mount, render, Fragment, h } from '@/index';
2
+
3
+ const Loop = mount(function (renew) {
4
+ let list: { key: number; value: string }[] = [
5
+ { key: 1, value: '일' },
6
+ { key: 2, value: '이' },
7
+ { key: 3, value: '삼' },
8
+ { key: 4, value: '사' },
9
+ ];
10
+ const handle = () => {
11
+ list = [
12
+ { key: 3, value: '삼삼' },
13
+ { key: 2, value: '이이' },
14
+ ];
15
+ renew();
16
+ };
17
+
18
+ return () => (
19
+ <Fragment>
20
+ <button onClick={handle}>handle</button>
21
+ {list.map(item => (
22
+ <div key={item.key}>{item.value}</div>
23
+ ))}
24
+ </Fragment>
25
+ );
26
+ });
27
+
28
+ const Root = <Loop />;
29
+
30
+ //@ts-ignore
31
+ window.root = Root;
32
+
33
+ render(Root, document.getElementById('root'));