sinho 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 (117) hide show
  1. package/.github/workflows/ci.yml +24 -0
  2. package/.github/workflows/deploy-docs.yml +47 -0
  3. package/.prettierrc +3 -0
  4. package/LICENSE.md +21 -0
  5. package/README.md +33 -0
  6. package/ci/check-size.js +8 -0
  7. package/dist/array_mutation.d.ts +16 -0
  8. package/dist/array_mutation.js +75 -0
  9. package/dist/array_mutation.js.map +1 -0
  10. package/dist/bundle.d.ts +1126 -0
  11. package/dist/bundle.js +1074 -0
  12. package/dist/bundle.min.js +1 -0
  13. package/dist/component.d.ts +253 -0
  14. package/dist/component.js +256 -0
  15. package/dist/component.js.map +1 -0
  16. package/dist/context.d.ts +21 -0
  17. package/dist/context.js +34 -0
  18. package/dist/context.js.map +1 -0
  19. package/dist/create_element.d.ts +43 -0
  20. package/dist/create_element.js +43 -0
  21. package/dist/create_element.js.map +1 -0
  22. package/dist/dom.d.ts +602 -0
  23. package/dist/dom.js +97 -0
  24. package/dist/dom.js.map +1 -0
  25. package/dist/intrinsic/ClassComponent.d.ts +2 -0
  26. package/dist/intrinsic/ClassComponent.js +10 -0
  27. package/dist/intrinsic/ClassComponent.js.map +1 -0
  28. package/dist/intrinsic/Dynamic.d.ts +33 -0
  29. package/dist/intrinsic/Dynamic.js +53 -0
  30. package/dist/intrinsic/Dynamic.js.map +1 -0
  31. package/dist/intrinsic/ErrorBoundary.d.ts +14 -0
  32. package/dist/intrinsic/ErrorBoundary.js +36 -0
  33. package/dist/intrinsic/ErrorBoundary.js.map +1 -0
  34. package/dist/intrinsic/For.d.ts +10 -0
  35. package/dist/intrinsic/For.js +81 -0
  36. package/dist/intrinsic/For.js.map +1 -0
  37. package/dist/intrinsic/Fragment.d.ts +23 -0
  38. package/dist/intrinsic/Fragment.js +28 -0
  39. package/dist/intrinsic/Fragment.js.map +1 -0
  40. package/dist/intrinsic/If.d.ts +24 -0
  41. package/dist/intrinsic/If.js +47 -0
  42. package/dist/intrinsic/If.js.map +1 -0
  43. package/dist/intrinsic/Portal.d.ts +6 -0
  44. package/dist/intrinsic/Portal.js +15 -0
  45. package/dist/intrinsic/Portal.js.map +1 -0
  46. package/dist/intrinsic/Style.d.ts +7 -0
  47. package/dist/intrinsic/Style.js +70 -0
  48. package/dist/intrinsic/Style.js.map +1 -0
  49. package/dist/intrinsic/TagComponent.d.ts +4 -0
  50. package/dist/intrinsic/TagComponent.js +67 -0
  51. package/dist/intrinsic/TagComponent.js.map +1 -0
  52. package/dist/intrinsic/Text.d.ts +6 -0
  53. package/dist/intrinsic/Text.js +16 -0
  54. package/dist/intrinsic/Text.js.map +1 -0
  55. package/dist/intrinsic/mod.d.ts +5 -0
  56. package/dist/intrinsic/mod.js +6 -0
  57. package/dist/intrinsic/mod.js.map +1 -0
  58. package/dist/jsx-runtime/mod.d.ts +23 -0
  59. package/dist/jsx-runtime/mod.js +11 -0
  60. package/dist/jsx-runtime/mod.js.map +1 -0
  61. package/dist/mod.d.ts +8 -0
  62. package/dist/mod.js +7 -0
  63. package/dist/mod.js.map +1 -0
  64. package/dist/renderer.d.ts +13 -0
  65. package/dist/renderer.js +25 -0
  66. package/dist/renderer.js.map +1 -0
  67. package/dist/scope.d.ts +138 -0
  68. package/dist/scope.js +228 -0
  69. package/dist/scope.js.map +1 -0
  70. package/dist/template.d.ts +10 -0
  71. package/dist/template.js +7 -0
  72. package/dist/template.js.map +1 -0
  73. package/dist/utils.d.ts +6 -0
  74. package/dist/utils.js +13 -0
  75. package/dist/utils.js.map +1 -0
  76. package/package.json +71 -0
  77. package/src/array_mutation.ts +118 -0
  78. package/src/component.ts +624 -0
  79. package/src/context.ts +70 -0
  80. package/src/create_element.ts +89 -0
  81. package/src/dom.ts +819 -0
  82. package/src/intrinsic/ClassComponent.ts +17 -0
  83. package/src/intrinsic/For.ts +122 -0
  84. package/src/intrinsic/Fragment.ts +38 -0
  85. package/src/intrinsic/If.ts +73 -0
  86. package/src/intrinsic/Portal.ts +25 -0
  87. package/src/intrinsic/Style.ts +120 -0
  88. package/src/intrinsic/TagComponent.ts +102 -0
  89. package/src/intrinsic/Text.ts +24 -0
  90. package/src/intrinsic/mod.ts +5 -0
  91. package/src/jsx-runtime/mod.ts +41 -0
  92. package/src/mod.ts +37 -0
  93. package/src/renderer.ts +45 -0
  94. package/src/scope.ts +404 -0
  95. package/src/template.ts +16 -0
  96. package/src/utils.ts +29 -0
  97. package/terser.config.json +16 -0
  98. package/tsconfig.json +18 -0
  99. package/web/README.md +41 -0
  100. package/web/babel.config.js +3 -0
  101. package/web/dist/shingo.min.d.ts +1131 -0
  102. package/web/dist/shingo.min.js +1 -0
  103. package/web/docusaurus.config.ts +151 -0
  104. package/web/package-lock.json +14850 -0
  105. package/web/package.json +54 -0
  106. package/web/sidebars.ts +31 -0
  107. package/web/src/components/monacoEditor.tsx +72 -0
  108. package/web/src/components/playground.tsx +89 -0
  109. package/web/src/components/playgroundComponent.tsx +168 -0
  110. package/web/src/css/custom.css +37 -0
  111. package/web/src/pages/index.module.css +31 -0
  112. package/web/src/pages/index.tsx +73 -0
  113. package/web/src/pages/playground.tsx +64 -0
  114. package/web/static/.nojekyll +0 -0
  115. package/web/static/dist/bundle.d.ts +1126 -0
  116. package/web/static/dist/bundle.min.js +1 -0
  117. package/web/tsconfig.json +8 -0
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "sinho",
3
+ "version": "0.1.0",
4
+ "description": "A lightweight signal-based library for building web components with a React-like API.",
5
+ "keywords": [
6
+ "ui",
7
+ "framework",
8
+ "signal",
9
+ "webcomponent"
10
+ ],
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/yishn/sinho.git"
14
+ },
15
+ "author": "Yichuan Shen",
16
+ "license": "MIT",
17
+ "bugs": {
18
+ "url": "https://github.com/yishn/sinho/issues"
19
+ },
20
+ "type": "module",
21
+ "homepage": "https://github.com/yishn/sinho#readme",
22
+ "exports": {
23
+ ".": {
24
+ "import": {
25
+ "types": "./dist/mod.d.ts",
26
+ "default": "./dist/mod.js"
27
+ }
28
+ },
29
+ "./jsx-runtime": {
30
+ "import": {
31
+ "types": "./dist/jsx-runtime/mod.d.ts",
32
+ "default": "./dist/jsx-runtime/mod.js"
33
+ }
34
+ },
35
+ "./min": {
36
+ "import": {
37
+ "types": "./dist/mod.d.ts",
38
+ "default": "./dist/bundle.min.js"
39
+ }
40
+ },
41
+ "./min/jsx-runtime": {
42
+ "import": {
43
+ "types": "./dist/mod.d.ts",
44
+ "default": "./dist/bundle.min.js"
45
+ }
46
+ }
47
+ },
48
+ "scripts": {
49
+ "format": "prettier --write .",
50
+ "format-check": "prettier --check .",
51
+ "build": "tsc && npm run bundle && npm run minify",
52
+ "bundle": "rollup ./dist/mod.js --file ./dist/bundle.js --format es --plugin @rollup/plugin-node-resolve && rollup ./dist/mod.d.ts --file ./dist/bundle.d.ts --format es --plugin rollup-plugin-dts",
53
+ "minify": "terser ./dist/bundle.js --output ./dist/bundle.min.js --config-file ./terser.config.json",
54
+ "test": "node --test --experimental-test-coverage",
55
+ "build-test": "npm run build && npm test",
56
+ "check-size": "node ./ci/check-size.js",
57
+ "build-samples": "tsc --project ./samples/tsconfig.json && rollup ./samples/dist/counter/mod.js --file ./samples/dist/counter/bundle.js --format es --plugin @rollup/plugin-node-resolve && rollup ./samples/dist/theme/mod.js --file ./samples/dist/theme/bundle.js --format es --plugin @rollup/plugin-node-resolve && rollup ./samples/dist/todo/mod.js --file ./samples/dist/todo/bundle.js --format es --plugin @rollup/plugin-node-resolve"
58
+ },
59
+ "devDependencies": {
60
+ "@happy-dom/global-registrator": "^14.4.0",
61
+ "@rollup/plugin-node-resolve": "^15.2.3",
62
+ "@types/node": "^20.11.30",
63
+ "copyfiles": "^2.4.1",
64
+ "prettier": "^3.2.5",
65
+ "rollup": "^4.13.0",
66
+ "rollup-plugin-dts": "^6.1.0",
67
+ "serve": "^14.2.1",
68
+ "terser": "^5.29.2",
69
+ "typescript": "^5.4.3"
70
+ }
71
+ }
@@ -0,0 +1,118 @@
1
+ import { Signal, SignalLike, useEffect, useSignal } from "./scope.js";
2
+
3
+ const getIndexMap = <T>(
4
+ array: readonly T[],
5
+ keyFn: (entry: T, index: number) => unknown,
6
+ ): Map<unknown, number> => {
7
+ const keyMap = new Map<unknown, number>();
8
+
9
+ for (let i = 0; i < array.length; i++) {
10
+ const key = keyFn(array[i], i);
11
+
12
+ if (keyMap.has(key)) {
13
+ throw new Error(`Duplicate key '${key}'`);
14
+ }
15
+
16
+ keyMap.set(key, i);
17
+ }
18
+
19
+ return keyMap;
20
+ };
21
+
22
+ export type ArrayMutation =
23
+ | {
24
+ _type: "a" | "r"; // add | remove
25
+ _key: unknown;
26
+ _index: number;
27
+ }
28
+ | {
29
+ _type: "m"; // move
30
+ _key: unknown;
31
+ _from: number;
32
+ _to: number;
33
+ };
34
+
35
+ export interface ArrayMutationResult {
36
+ _mutations: ArrayMutation[];
37
+ _map: Map<unknown, number>;
38
+ }
39
+
40
+ export const useArrayMutation = <T extends unknown>(
41
+ array: SignalLike<readonly T[]>,
42
+ keyFn: (entry: T, index: number) => unknown,
43
+ ): Signal<ArrayMutationResult> => {
44
+ const [result, setResult] = useSignal<ArrayMutationResult>({
45
+ _mutations: [],
46
+ _map: new Map(),
47
+ });
48
+
49
+ let indexMap = new Map<unknown, number>();
50
+
51
+ useEffect(() => {
52
+ const mutations: ArrayMutation[] = [];
53
+ const oldIndexMap = indexMap;
54
+ const newIndexMap = getIndexMap(array(), keyFn);
55
+
56
+ const transformToOldIndex = (i: number = NaN) =>
57
+ mutations
58
+ .map((mutation): ((i: number) => number) =>
59
+ mutation._type == "r"
60
+ ? (j) =>
61
+ j < mutation._index ? j : j == mutation._index ? NaN : j - 1
62
+ : mutation._type == "a"
63
+ ? (j) => (j < mutation._index ? j : j + 1)
64
+ : mutation._type == "m"
65
+ ? (j) =>
66
+ mutation._to <= j && j < mutation._from
67
+ ? j + 1
68
+ : j == mutation._from
69
+ ? mutation._to
70
+ : j
71
+ : (j) => j,
72
+ )
73
+ .reduce((i, fn) => fn(i), i);
74
+
75
+ for (const key of oldIndexMap.keys()) {
76
+ const i = transformToOldIndex(oldIndexMap.get(key));
77
+
78
+ if (!newIndexMap.has(key)) {
79
+ mutations.push({
80
+ _type: "r",
81
+ _key: key,
82
+ _index: i,
83
+ });
84
+ }
85
+ }
86
+
87
+ for (let i = 0; i < array().length; i++) {
88
+ const key = keyFn(array()[i], i);
89
+ const oldIndex = transformToOldIndex(oldIndexMap.get(key));
90
+
91
+ if (isNaN(oldIndex)) {
92
+ mutations.push({
93
+ _type: "a",
94
+ _key: key,
95
+ _index: i,
96
+ });
97
+ } else if (oldIndex != i) {
98
+ mutations.push({
99
+ _type: "m",
100
+ _key: key,
101
+ _from: oldIndex,
102
+ _to: i,
103
+ });
104
+ }
105
+ }
106
+
107
+ if (mutations.length > 0) {
108
+ setResult({
109
+ _mutations: mutations,
110
+ _map: newIndexMap,
111
+ });
112
+ }
113
+
114
+ indexMap = newIndexMap;
115
+ });
116
+
117
+ return result;
118
+ };