hyperscript-rxjs 1.3.14 → 1.3.15

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 (279) hide show
  1. package/package.json +13 -22
  2. package/src/array/advance.d.ts +9 -0
  3. package/src/array/advance.js +13 -0
  4. package/src/array/advance.test.js +12 -0
  5. package/src/array/arrayInsert.d.ts +8 -0
  6. package/src/array/arrayInsert.js +13 -0
  7. package/src/array/arrayInsert.test.js +13 -0
  8. package/src/array/arrayRemove.d.ts +7 -0
  9. package/src/array/arrayRemove.js +15 -0
  10. package/src/array/arrayRemove.test.js +13 -0
  11. package/src/array/findLastIndex.d.ts +14 -0
  12. package/src/array/findLastIndex.js +20 -0
  13. package/src/array/findLastIndex.test.js +41 -0
  14. package/src/array/index.d.ts +9 -0
  15. package/src/array/index.js +9 -0
  16. package/src/array/isRange.d.ts +7 -0
  17. package/src/array/isRange.js +15 -0
  18. package/src/array/isRange.test.js +6 -0
  19. package/src/array/rangeArray.d.ts +7 -0
  20. package/src/array/rangeArray.js +10 -0
  21. package/src/array/rangeArray.test.js +11 -0
  22. package/src/array/unwrapArgs.d.ts +10 -0
  23. package/src/array/unwrapArgs.js +15 -0
  24. package/src/array/unwrapArgs.test.js +33 -0
  25. package/src/array/zipArray.d.ts +11 -0
  26. package/src/array/zipArray.js +24 -0
  27. package/src/array/zipArray.test.js +16 -0
  28. package/src/comparers/Comparer.d.ts +101 -0
  29. package/src/comparers/Comparer.js +149 -0
  30. package/src/comparers/comparers.d.ts +21 -0
  31. package/src/comparers/comparers.js +10 -0
  32. package/src/comparers/differenceSet.d.ts +20 -0
  33. package/src/comparers/differenceSet.js +35 -0
  34. package/src/comparers/differenceSet.test.js +11 -0
  35. package/src/comparers/distinctArray.d.ts +13 -0
  36. package/src/comparers/distinctArray.js +30 -0
  37. package/src/comparers/distinctArray.test.js +10 -0
  38. package/src/comparers/findIndexInSet.d.ts +20 -0
  39. package/src/comparers/findIndexInSet.js +27 -0
  40. package/src/comparers/findIndexInSet.test.js +8 -0
  41. package/src/comparers/groupArrayBy.d.ts +19 -0
  42. package/src/comparers/groupArrayBy.js +29 -0
  43. package/src/comparers/groupArrayBy.test.js +38 -0
  44. package/src/comparers/groupSortedEntries.d.ts +17 -0
  45. package/src/comparers/groupSortedEntries.js +38 -0
  46. package/src/comparers/groupSortedEntries.test.js +46 -0
  47. package/src/comparers/index.d.ts +14 -0
  48. package/src/comparers/index.js +14 -0
  49. package/src/comparers/intersectSet.d.ts +19 -0
  50. package/src/comparers/intersectSet.js +35 -0
  51. package/src/comparers/intersectSet.test.js +14 -0
  52. package/src/comparers/isEqualset.d.ts +22 -0
  53. package/src/comparers/isEqualset.js +33 -0
  54. package/src/comparers/isEqualset.test.js +22 -0
  55. package/src/comparers/isSubset.d.ts +21 -0
  56. package/src/comparers/isSubset.js +33 -0
  57. package/src/comparers/isSubset.test.js +21 -0
  58. package/src/comparers/isSuperset.d.ts +21 -0
  59. package/src/comparers/isSuperset.js +13 -0
  60. package/src/comparers/isSuperset.test.js +21 -0
  61. package/src/comparers/sortedArrayToSet.d.ts +20 -0
  62. package/src/comparers/sortedArrayToSet.js +35 -0
  63. package/src/comparers/sortedArrayToSet.test.js +11 -0
  64. package/src/comparers/unionSet.d.ts +21 -0
  65. package/src/comparers/unionSet.js +34 -0
  66. package/src/comparers/unionSet.test.js +11 -0
  67. package/src/comparison/compareDate.d.ts +8 -0
  68. package/src/comparison/compareDate.js +11 -0
  69. package/src/comparison/compareEntries.d.ts +13 -0
  70. package/src/comparison/compareEntries.js +13 -0
  71. package/src/comparison/compareKey.d.ts +11 -0
  72. package/src/comparison/compareKey.js +25 -0
  73. package/src/comparison/compareKey.test.js +21 -0
  74. package/src/comparison/compareKeyPath.d.ts +15 -0
  75. package/src/comparison/compareKeyPath.js +33 -0
  76. package/src/comparison/compareKeyPath.test.js +28 -0
  77. package/src/comparison/compareNumber.d.ts +11 -0
  78. package/src/comparison/compareNumber.js +27 -0
  79. package/src/comparison/compareNumber.test.js +21 -0
  80. package/src/comparison/defaultCompare.d.ts +8 -0
  81. package/src/comparison/defaultCompare.js +12 -0
  82. package/src/comparison/defaultCompare.test.js +24 -0
  83. package/src/comparison/index.d.ts +7 -0
  84. package/src/comparison/index.js +7 -0
  85. package/src/comparison/infinity.test.js +122 -0
  86. package/src/comparison/typeof.test.js +64 -0
  87. package/src/comparison/types.d.ts +5 -0
  88. package/src/comparison/types.js +11 -0
  89. package/src/deep/Deep.d.ts +58 -0
  90. package/src/deep/Deep.js +267 -0
  91. package/src/deep/Deep.test.js +130 -0
  92. package/src/deep/deepCombineLatest.test.js +36 -0
  93. package/src/deep/deepMerge.test.js +34 -0
  94. package/src/deep/differenceDeep.test.js +31 -0
  95. package/src/deep/freshValueDeep.test.js +17 -0
  96. package/src/deep/index.d.ts +1 -0
  97. package/src/deep/index.js +2 -0
  98. package/src/deep/intersectDeep.test.js +25 -0
  99. package/src/deep/intersectEntries.d.ts +13 -0
  100. package/src/deep/intersectEntries.js +37 -0
  101. package/src/deep/intersectEntries.test.js +20 -0
  102. package/src/deep/objectToDeep.test.js +31 -0
  103. package/src/deep/replaceValueDeep.test.js +21 -0
  104. package/src/deep/unionDeep.test.js +30 -0
  105. package/src/deep/zipValueDeep.test.js +21 -0
  106. package/src/deep-rxjs/ObservableArray.d.ts +55 -0
  107. package/src/deep-rxjs/ObservableArray.js +94 -0
  108. package/src/deep-rxjs/ObservableArray.test.js +117 -0
  109. package/src/deep-rxjs/index.d.ts +2 -0
  110. package/src/deep-rxjs/index.js +2 -0
  111. package/src/deep-rxjs/isRxType.d.ts +9 -0
  112. package/src/deep-rxjs/isRxType.js +15 -0
  113. package/src/deep-rxjs/isRxType.test.js +43 -0
  114. package/src/hyperscript-rxjs/HyperscriptExtensions.d.ts +20 -0
  115. package/src/hyperscript-rxjs/checkbox.d.ts +13 -0
  116. package/src/hyperscript-rxjs/checkbox.js +47 -0
  117. package/src/hyperscript-rxjs/checkbox.test.js +68 -0
  118. package/src/hyperscript-rxjs/choice.d.ts +13 -0
  119. package/src/hyperscript-rxjs/choice.js +24 -0
  120. package/src/hyperscript-rxjs/choice.test.js +108 -0
  121. package/src/hyperscript-rxjs/collapse.d.ts +14 -0
  122. package/src/hyperscript-rxjs/collapse.js +32 -0
  123. package/src/hyperscript-rxjs/collapse.test.js +67 -0
  124. package/src/hyperscript-rxjs/displays/blockLevelFamily.d.ts +5 -0
  125. package/src/hyperscript-rxjs/displays/blockLevelFamily.js +51 -0
  126. package/src/hyperscript-rxjs/displays/getDisplay.d.ts +7 -0
  127. package/src/hyperscript-rxjs/displays/getDisplay.js +51 -0
  128. package/src/hyperscript-rxjs/displays/getDisplay.test.js +56 -0
  129. package/src/hyperscript-rxjs/displays/index.d.ts +3 -0
  130. package/src/hyperscript-rxjs/displays/index.js +3 -0
  131. package/src/hyperscript-rxjs/displays/inlineFamily.d.ts +5 -0
  132. package/src/hyperscript-rxjs/displays/inlineFamily.js +73 -0
  133. package/src/hyperscript-rxjs/flip.d.ts +15 -0
  134. package/src/hyperscript-rxjs/flip.js +29 -0
  135. package/src/hyperscript-rxjs/flip.test.js +85 -0
  136. package/src/hyperscript-rxjs/fragment.d.ts +10 -0
  137. package/src/hyperscript-rxjs/fragment.js +22 -0
  138. package/src/hyperscript-rxjs/fragment.test.js +70 -0
  139. package/src/hyperscript-rxjs/hyperscript.d.ts +15 -0
  140. package/src/hyperscript-rxjs/hyperscript.js +170 -0
  141. package/src/hyperscript-rxjs/hyperscript.test.js +75 -0
  142. package/src/hyperscript-rxjs/index.d.ts +19 -0
  143. package/src/hyperscript-rxjs/index.js +19 -0
  144. package/src/hyperscript-rxjs/multiselect.d.ts +18 -0
  145. package/src/hyperscript-rxjs/multiselect.js +41 -0
  146. package/src/hyperscript-rxjs/multiselect.test.js +121 -0
  147. package/src/hyperscript-rxjs/numberbox.d.ts +14 -0
  148. package/src/hyperscript-rxjs/numberbox.js +73 -0
  149. package/src/hyperscript-rxjs/numberbox.test.js +84 -0
  150. package/src/hyperscript-rxjs/radio.d.ts +15 -0
  151. package/src/hyperscript-rxjs/radio.js +53 -0
  152. package/src/hyperscript-rxjs/radio.test.js +59 -0
  153. package/src/hyperscript-rxjs/select.d.ts +28 -0
  154. package/src/hyperscript-rxjs/select.js +88 -0
  155. package/src/hyperscript-rxjs/select.test.js +101 -0
  156. package/src/hyperscript-rxjs/tabControls/bindTabIndex.d.ts +12 -0
  157. package/src/hyperscript-rxjs/tabControls/bindTabIndex.js +59 -0
  158. package/src/hyperscript-rxjs/tabControls/index.d.ts +8 -0
  159. package/src/hyperscript-rxjs/tabControls/index.js +10 -0
  160. package/src/hyperscript-rxjs/tabControls/tabControl.d.ts +19 -0
  161. package/src/hyperscript-rxjs/tabControls/tabControl.js +40 -0
  162. package/src/hyperscript-rxjs/tabControls/tabControl.test.js +98 -0
  163. package/src/hyperscript-rxjs/tabControls/tabNavItem.d.ts +9 -0
  164. package/src/hyperscript-rxjs/tabControls/tabNavItem.js +30 -0
  165. package/src/hyperscript-rxjs/tabControls/tabPanel.d.ts +9 -0
  166. package/src/hyperscript-rxjs/tabControls/tabPanel.js +21 -0
  167. package/src/hyperscript-rxjs/tabControls/tabRoot.d.ts +7 -0
  168. package/src/hyperscript-rxjs/tabControls/tabRoot.js +26 -0
  169. package/src/hyperscript-rxjs/tags.d.ts +193 -0
  170. package/src/hyperscript-rxjs/tags.js +751 -0
  171. package/src/hyperscript-rxjs/tags.test.js +75 -0
  172. package/src/hyperscript-rxjs/textNode.d.ts +11 -0
  173. package/src/hyperscript-rxjs/textNode.js +51 -0
  174. package/src/hyperscript-rxjs/textNode.test.js +56 -0
  175. package/src/hyperscript-rxjs/textarea.d.ts +17 -0
  176. package/src/hyperscript-rxjs/textarea.js +45 -0
  177. package/src/hyperscript-rxjs/textarea.test.js +52 -0
  178. package/src/hyperscript-rxjs/textbox.d.ts +15 -0
  179. package/src/hyperscript-rxjs/textbox.js +42 -0
  180. package/src/hyperscript-rxjs/textbox.test.js +52 -0
  181. package/src/index.d.ts +19 -0
  182. package/src/index.js +19 -0
  183. package/src/nodes/attachSubscriptionToNode.d.ts +13 -0
  184. package/src/nodes/attachSubscriptionToNode.js +25 -0
  185. package/src/nodes/attachSubscriptionToNode.test.js +73 -0
  186. package/src/nodes/index.d.ts +6 -0
  187. package/src/nodes/index.js +6 -0
  188. package/src/nodes/normalizeChildNodes.d.ts +9 -0
  189. package/src/nodes/normalizeChildNodes.js +15 -0
  190. package/src/nodes/normalizeChildNodes.test.js +55 -0
  191. package/src/nodes/parseHyperscriptArgs.d.ts +10 -0
  192. package/src/nodes/parseHyperscriptArgs.js +57 -0
  193. package/src/nodes/parseHyperscriptArgs.test.js +85 -0
  194. package/src/nodes/pipeEvent.d.ts +15 -0
  195. package/src/nodes/pipeEvent.js +49 -0
  196. package/src/nodes/pipeEvent.test.js +97 -0
  197. package/src/nodes/subscribeEvent.d.ts +15 -0
  198. package/src/nodes/subscribeEvent.js +56 -0
  199. package/src/nodes/subscribeEvent.test.js +88 -0
  200. package/src/object/index.d.ts +10 -0
  201. package/src/object/index.js +11 -0
  202. package/src/object/intersectObject.d.ts +12 -0
  203. package/src/object/intersectObject.js +23 -0
  204. package/src/object/intersectObject.test.js +69 -0
  205. package/src/object/isEmptyObject.d.ts +7 -0
  206. package/src/object/isEmptyObject.js +13 -0
  207. package/src/object/isEmptyObject.test.js +33 -0
  208. package/src/object/isPlainObject.d.ts +11 -0
  209. package/src/object/isPlainObject.js +18 -0
  210. package/src/object/nestedCombineLatest.d.ts +11 -0
  211. package/src/object/nestedCombineLatest.js +18 -0
  212. package/src/object/nestedCombineLatest.test.js +25 -0
  213. package/src/object/nestedMerge.d.ts +11 -0
  214. package/src/object/nestedMerge.js +11 -0
  215. package/src/object/nestedMerge.test.js +61 -0
  216. package/src/object/pickBehaviorSubject.d.ts +13 -0
  217. package/src/object/pickBehaviorSubject.js +81 -0
  218. package/src/object/pickBehaviorSubject.test.js +88 -0
  219. package/src/object/pluckProperty.d.ts +13 -0
  220. package/src/object/pluckProperty.js +24 -0
  221. package/src/object/pluckProperty.test.js +37 -0
  222. package/src/object/restore.d.ts +12 -0
  223. package/src/object/restore.js +69 -0
  224. package/src/object/restore.test.js +124 -0
  225. package/src/object/splitObjectByObservable.d.ts +12 -0
  226. package/src/object/splitObjectByObservable.js +41 -0
  227. package/src/object/splitObjectByObservable.test.js +78 -0
  228. package/src/props/getNestedProperty.d.ts +12 -0
  229. package/src/props/getNestedProperty.js +31 -0
  230. package/src/props/getNestedProperty.test.js +72 -0
  231. package/src/props/index.d.ts +7 -0
  232. package/src/props/index.js +7 -0
  233. package/src/props/parsePropName.d.ts +13 -0
  234. package/src/props/parsePropName.js +45 -0
  235. package/src/props/parsePropName.test.js +67 -0
  236. package/src/props/setProp.d.ts +16 -0
  237. package/src/props/setProp.js +42 -0
  238. package/src/props/setProp.test.js +59 -0
  239. package/src/props/setProps.d.ts +14 -0
  240. package/src/props/setProps.js +47 -0
  241. package/src/props/setProps.test.js +97 -0
  242. package/src/props/subscribeProp.d.ts +16 -0
  243. package/src/props/subscribeProp.js +47 -0
  244. package/src/props/subscribeProp.test.js +81 -0
  245. package/src/ramda/compose.d.ts +10 -0
  246. package/src/ramda/compose.js +36 -0
  247. package/src/ramda/compose.test.js +73 -0
  248. package/src/ramda/cond.d.ts +12 -0
  249. package/src/ramda/cond.js +29 -0
  250. package/src/ramda/cond.test.js +88 -0
  251. package/src/ramda/fold.d.ts +13 -0
  252. package/src/ramda/fold.js +20 -0
  253. package/src/ramda/fold.test.js +51 -0
  254. package/src/ramda/index.d.ts +6 -0
  255. package/src/ramda/index.js +6 -0
  256. package/src/ramda/pipe.d.ts +13 -0
  257. package/src/ramda/pipe.js +27 -0
  258. package/src/ramda/pipe.test.js +77 -0
  259. package/src/ramda/unfold.d.ts +11 -0
  260. package/src/ramda/unfold.js +20 -0
  261. package/src/ramda/unfold.test.js +29 -0
  262. package/src/unquoted-json/ajax.test.js +1074 -0
  263. package/src/unquoted-json/index.d.ts +13 -0
  264. package/src/unquoted-json/index.js +12 -0
  265. package/src/unquoted-json/queryStringify.d.ts +8 -0
  266. package/src/unquoted-json/queryStringify.js +70 -0
  267. package/src/unquoted-json/queryStringify.test.js +110 -0
  268. package/src/unquoted-json/stringifyKey.d.ts +7 -0
  269. package/src/unquoted-json/stringifyKey.js +16 -0
  270. package/src/unquoted-json/stringifyKey.test.js +51 -0
  271. package/src/unquoted-json/stringifyStringValue.d.ts +7 -0
  272. package/src/unquoted-json/stringifyStringValue.js +17 -0
  273. package/src/unquoted-json/stringifyStringValue.test.js +52 -0
  274. package/src/unquoted-json/unquotedJsonStringify.d.ts +7 -0
  275. package/src/unquoted-json/unquotedJsonStringify.js +39 -0
  276. package/src/unquoted-json/unquotedJsonStringify.test.js +52 -0
  277. package/dist/hyperscript-rxjs.d.ts +0 -1412
  278. package/dist/hyperscript-rxjs.js +0 -1
  279. package/dist/tsdoc-metadata.json +0 -11
@@ -0,0 +1,75 @@
1
+ import { div, br, img, span, p, option } from './tags';
2
+
3
+ describe('tags', () => {
4
+ test('should create a div element with props and children', () => {
5
+ const props = { id: 'test', className: 'example' };
6
+ const child1 = 'Hello';
7
+ const child2 = 'World';
8
+
9
+ const element = div(props, child1, child2);
10
+
11
+ expect(element.tagName).toBe('DIV');
12
+ expect(element.id).toBe('test');
13
+ expect(element.className).toBe('example');
14
+ expect(element.childNodes.length).toBe(2);
15
+ expect(element.childNodes[0].textContent).toBe('Hello');
16
+ expect(element.childNodes[1].textContent).toBe('World');
17
+ });
18
+
19
+ test('should create a br element with no props or children', () => {
20
+ const element = br();
21
+
22
+ expect(element.tagName).toBe('BR');
23
+ expect(element.childNodes.length).toBe(0);
24
+ });
25
+
26
+ test('should create an img element with only props', () => {
27
+ const props = { id: 'test', src: 'image.png', alt: 'Example Image' };
28
+
29
+ const element = img(props);
30
+
31
+ expect(element.tagName).toBe('IMG');
32
+ expect(element.id).toBe('test');
33
+ expect(element.src).toContain('image.png');
34
+ expect(element.alt).toBe('Example Image');
35
+ });
36
+
37
+ test('should create a span element with only children', () => {
38
+ const child1 = 'Hello';
39
+ const child2 = 'World';
40
+
41
+ const element = span(null, child1, child2);
42
+
43
+ expect(element.tagName).toBe('SPAN');
44
+ expect(element.childNodes.length).toBe(2);
45
+ expect(element.childNodes[0].textContent).toBe('Hello');
46
+ expect(element.childNodes[1].textContent).toBe('World');
47
+ });
48
+
49
+ test('should create a p element with both props and children', () => {
50
+ const props = { id: 'test', className: 'example' };
51
+ const child1 = 'Hello';
52
+ const child2 = 'World';
53
+
54
+ const element = p(props, child1, child2);
55
+
56
+ expect(element.tagName).toBe('P');
57
+ expect(element.id).toBe('test');
58
+ expect(element.className).toBe('example');
59
+ expect(element.childNodes.length).toBe(2);
60
+ expect(element.childNodes[0].textContent).toBe('Hello');
61
+ expect(element.childNodes[1].textContent).toBe('World');
62
+ });
63
+
64
+ test('should create an option element with props and children', () => {
65
+ const props = { value: '1', selected: true };
66
+ const child = 'Option 1';
67
+
68
+ const element = option(props, child);
69
+
70
+ expect(element.tagName).toBe('OPTION');
71
+ expect(element.value).toBe('1');
72
+ expect(element.selected).toBe(true);
73
+ expect(element.textContent).toBe('Option 1');
74
+ });
75
+ });
@@ -0,0 +1,11 @@
1
+ import { Observable, Subscription } from 'rxjs';
2
+
3
+ /**
4
+ * 创建一个文本节点,支持静态文本和基于 Observable 的动态文本。
5
+ *
6
+ * @param text - Observable<any> | any。
7
+ * @returns 文本节点,若为动态文本节点则带有 unsubscribe 方法。
8
+ */
9
+ export function textNode(
10
+ text: any
11
+ ): Text & { subscription?: Subscription, unsubscribe?: () => void };
@@ -0,0 +1,51 @@
1
+ import { Observable, isObservable, Subscription } from 'rxjs';
2
+ import { map } from 'rxjs/operators';
3
+
4
+ /**
5
+ * @typedef {Text & {subscription?: Subscription, unsubscribe?: ()=>void}} ObservableTextNode
6
+ */
7
+
8
+ /**
9
+ * 创建一个文本节点。
10
+ * 支持静态文本和动态更新的文本(通过 RxJS Observable)。
11
+ *
12
+ * - 如果传入的是字符串,则创建一个静态文本节点。
13
+ * - 如果传入的是 RxJS Observable,则创建一个动态文本节点,并根据 Observable 的值实时更新文本内容。
14
+ * - 动态文本节点支持通过 `unsubscribe` 方法取消订阅。
15
+ *
16
+ * @param {any} text Observable<any> | any。
17
+ * @returns {ObservableTextNode}
18
+ *
19
+ */
20
+ export function textNode(text) {
21
+ // 如果传入的是 Observable
22
+ if (isObservable(text)) {
23
+ const node = document.createTextNode("");
24
+
25
+ // 创建订阅并更新文本节点
26
+ const subscription = text.pipe(
27
+ map(d => String(d))
28
+ ).subscribe({
29
+ next(t) { node.nodeValue = t; },
30
+ error(err) { node.nodeValue = `Error: ${err.message}`; }
31
+ })
32
+
33
+ return Object.assign(node, {
34
+ subscription,
35
+ /**
36
+ * @this {ObservableTextNode}
37
+ */
38
+ unsubscribe() {
39
+ if (this.subscription) {
40
+ this.subscription.unsubscribe();
41
+ delete this.subscription; // 删除 subscription 成员
42
+ delete this.unsubscribe;
43
+ }
44
+ }
45
+ });
46
+
47
+ } else {
48
+ return document.createTextNode(String(text)); // 转换为字符串
49
+ }
50
+ }
51
+
@@ -0,0 +1,56 @@
1
+ import { BehaviorSubject, throwError, Subscription } from 'rxjs';
2
+ import { textNode } from './textNode';
3
+
4
+ describe('textNode', () => {
5
+ test('should create a static text node', () => {
6
+ const node = textNode('Hello, World!');
7
+ expect(node).toBeInstanceOf(Text);
8
+ expect(node.nodeValue).toBe('Hello, World!');
9
+ });
10
+
11
+ test('should create a dynamic text node from an Observable', () => {
12
+ const text$ = new BehaviorSubject('Initial Text');
13
+ const node = textNode(text$);
14
+
15
+ expect(node).toBeInstanceOf(Text);
16
+ expect(node.nodeValue).toBe('Initial Text');
17
+
18
+ // Update the Observable value
19
+ text$.next('Updated Text');
20
+ expect(node.nodeValue).toBe('Updated Text');
21
+ });
22
+
23
+ test('should handle errors from an Observable', () => {
24
+ const error$ = throwError(() => new Error('Something went wrong'));
25
+ const node = textNode(error$);
26
+
27
+ expect(node).toBeInstanceOf(Text);
28
+ expect(node.nodeValue).toBe('Error: Something went wrong');
29
+ });
30
+
31
+ test('should unsubscribe from the Observable when unsubscribeTextNode is called', () => {
32
+ const text$ = new BehaviorSubject('Initial Text');
33
+ const node = textNode(text$);
34
+
35
+ expect(node.subscription).toBeInstanceOf(Subscription);
36
+
37
+ node.unsubscribe();
38
+
39
+ expect(node.subscription).toBeUndefined();
40
+ expect(node.unsubscribe).toBeUndefined();
41
+
42
+ });
43
+
44
+
45
+ test('should convert non-string static values to text', () => {
46
+ const node = textNode(12345);
47
+ expect(node).toBeInstanceOf(Text);
48
+ expect(node.nodeValue).toBe('12345');
49
+ });
50
+
51
+ test('should handle boolean values as static text', () => {
52
+ const node = textNode(true);
53
+ expect(node).toBeInstanceOf(Text);
54
+ expect(node.nodeValue).toBe('true');
55
+ });
56
+ });
@@ -0,0 +1,17 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+ import { HyperscriptExtensions } from './HyperscriptExtensions';
3
+
4
+ /**
5
+ * 创建一个支持 RxJS 数据绑定的 <textarea> 元素。
6
+ *
7
+ * @param props - 配置对象,包含 <textarea> 元素的属性,必须包含 value(BehaviorSubject<string>)。
8
+ * @returns 创建的 <textarea> 元素。
9
+ * @throws 如果 props 不是对象,或者 value 不是 BehaviorSubject 会抛出错误。
10
+ */
11
+ export function textarea(
12
+ props: {
13
+ value: BehaviorSubject<string>,
14
+ [key: string]: any
15
+ }
16
+ ): HyperscriptExtensions<HTMLTextAreaElement>;
17
+
@@ -0,0 +1,45 @@
1
+ import { map } from 'rxjs/operators';
2
+ import { hyperscript } from './hyperscript';
3
+ import { BehaviorSubject, Observable } from 'rxjs';
4
+
5
+ /**
6
+ * @typedef {import("./HyperscriptExtensions").HyperscriptExtensions<HTMLTextAreaElement>} HyperscriptTextAreaElement
7
+ */
8
+
9
+ /**
10
+ * 创建一个支持 RxJS 数据绑定的 <textarea> 元素。
11
+ *
12
+ * @param {{value:BehaviorSubject<string>, [key:string]:any}} props - 配置对象,包含 <textarea> 元素的属性。
13
+ * @returns {HyperscriptTextAreaElement} - 创建的 <textarea> 元素。
14
+ * @throws {Error} 如果 `props` 不是对象,或者 `value` 不是 BehaviorSubject。
15
+ */
16
+ export function textarea(props) {
17
+ if (typeof props !== 'object' || props === null) {
18
+ throw new Error('`textarea` requires a `props` object.');
19
+ }
20
+
21
+ const { value } = props;
22
+
23
+ if (!(value instanceof BehaviorSubject)) {
24
+ throw new Error('`value` must be an instance of BehaviorSubject.');
25
+ }
26
+
27
+ // 创建 <textarea> 元素
28
+ const elem = /** @type {HyperscriptTextAreaElement} */ (hyperscript('textarea', props));
29
+
30
+ // 订阅输入事件并更新 BehaviorSubject
31
+ const subscriber =
32
+ /**
33
+ *
34
+ * @param {Observable<Event>} input$
35
+ * @returns
36
+ */
37
+ input$ =>
38
+ input$.pipe(
39
+ map(e => /** @type {HTMLTextAreaElement} */ (e.target).value),
40
+ ).subscribe(value);
41
+
42
+ elem.pipeEvent('input', subscriber);
43
+
44
+ return elem;
45
+ }
@@ -0,0 +1,52 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+ import { textarea } from './textarea';
3
+
4
+ describe('textarea', () => {
5
+ beforeEach(() => {
6
+ document.body.innerHTML = ''; // 清空 DOM
7
+ });
8
+
9
+ test('should create a <textarea> element bound to value', () => {
10
+ const value = new BehaviorSubject('');
11
+
12
+ const elem = textarea({ value });
13
+
14
+ // 验证返回的元素
15
+ expect(elem).toBeInstanceOf(HTMLTextAreaElement);
16
+
17
+ // 初始状态
18
+ expect(elem.value).toBe('');
19
+ expect(value.getValue()).toBe('');
20
+
21
+ // 更新 BehaviorSubject
22
+ value.next('Hello, world!');
23
+ expect(elem.value).toBe('Hello, world!');
24
+
25
+ // 模拟用户输入
26
+ elem.value = 'New input';
27
+ elem.dispatchEvent(new Event('input'));
28
+ expect(value.getValue()).toBe('New input');
29
+ });
30
+
31
+ test('should throw an error if props is not an object', () => {
32
+ expect(() => textarea(null)).toThrow('`textarea` requires a `props` object.');
33
+ expect(() => textarea(undefined)).toThrow('`textarea` requires a `props` object.');
34
+ expect(() => textarea(42)).toThrow('`textarea` requires a `props` object.');
35
+ });
36
+
37
+ test('should throw an error if value is not a BehaviorSubject', () => {
38
+ expect(() => textarea({ value: null })).toThrow('`value` must be an instance of BehaviorSubject.');
39
+ expect(() => textarea({ value: 42 })).toThrow('`value` must be an instance of BehaviorSubject.');
40
+ expect(() => textarea({ value: {} })).toThrow('`value` must be an instance of BehaviorSubject.');
41
+ });
42
+
43
+ test('should pass additional attributes to the <textarea> element', () => {
44
+ const value = new BehaviorSubject('');
45
+ const elem = textarea({ value, placeholder: 'Enter text', rows: 5, cols: 30 });
46
+
47
+ // 验证额外属性
48
+ expect(elem.placeholder).toBe('Enter text');
49
+ expect(elem.rows).toBe(5);
50
+ expect(elem.cols).toBe(30);
51
+ });
52
+ });
@@ -0,0 +1,15 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+ import { HyperscriptExtensions } from './HyperscriptExtensions';
3
+
4
+ /**
5
+ * 创建一个支持 RxJS 数据绑定的 <input type="text"> 元素。
6
+ *
7
+ * @param props - 配置对象,包含 <input> 元素的属性,必须包含 value(BehaviorSubject<string>)。
8
+ * @returns 创建的 <input type="text"> 元素。
9
+ * @throws 如果 props 不是对象,或者 value 不是 BehaviorSubject 会抛出错误。
10
+ */
11
+ export function textbox(props: {
12
+ value: BehaviorSubject<string>,
13
+ [key: string]: any
14
+ }): HyperscriptExtensions<HTMLInputElement>;
15
+
@@ -0,0 +1,42 @@
1
+ import { BehaviorSubject, Observable } from 'rxjs';
2
+ import { map } from 'rxjs/operators';
3
+ import { input } from './tags';
4
+
5
+ /**
6
+ * @typedef {import("./HyperscriptExtensions").HyperscriptExtensions<HTMLInputElement>} HyperscriptInputElement
7
+ */
8
+
9
+ /**
10
+ * 创建一个支持 RxJS 数据绑定的 <input type="text"> 元素。
11
+ *
12
+ * @param {{value: BehaviorSubject<string>, [key: string]: any}} props - 配置对象,包含 <input> 元素的属性。
13
+ * @returns {HyperscriptInputElement} - 创建的 <input type="text"> 元素。
14
+ * @throws {Error} 如果 `props` 不是对象,或者 `value` 不是 BehaviorSubject。
15
+ */
16
+ export function textbox(props) {
17
+ if (typeof props !== 'object' || props === null) {
18
+ throw new Error('`textbox` requires a `props` object.');
19
+ }
20
+
21
+ const { value } = props;
22
+
23
+ if (!(value instanceof BehaviorSubject)) {
24
+ throw new Error('`value` must be an instance of BehaviorSubject.');
25
+ }
26
+
27
+ // 创建 <input type="text"> 元素
28
+ const elem = /** @type {HyperscriptInputElement} */ (input({ ...props, type: 'text' }));
29
+
30
+ // 订阅输入事件并更新 BehaviorSubject
31
+ const subscriber =
32
+ /**
33
+ * @param {Observable<Event>} input$
34
+ * @returns
35
+ */
36
+ input$ =>
37
+ input$.pipe(
38
+ map(e => /** @type {HTMLInputElement} */(e.target).value),
39
+ ).subscribe(value);
40
+ elem.pipeEvent('input', subscriber);
41
+ return elem;
42
+ }
@@ -0,0 +1,52 @@
1
+ import { BehaviorSubject } from 'rxjs';
2
+ import { textbox } from './textbox';
3
+
4
+ describe('textbox', () => {
5
+ beforeEach(() => {
6
+ document.body.innerHTML = ''; // 清空 DOM
7
+ });
8
+
9
+ test('should create a <input type="text"> element bound to value', () => {
10
+ const value = new BehaviorSubject('');
11
+
12
+ const elem = textbox({ value });
13
+
14
+ // 验证返回的元素
15
+ expect(elem).toBeInstanceOf(HTMLInputElement);
16
+ expect(elem.type).toBe('text');
17
+
18
+ // 初始状态
19
+ expect(elem.value).toBe('');
20
+ expect(value.getValue()).toBe('');
21
+
22
+ // 更新 BehaviorSubject
23
+ value.next('Hello, world!');
24
+ expect(elem.value).toBe('Hello, world!');
25
+
26
+ // 模拟用户输入
27
+ elem.value = 'New input';
28
+ elem.dispatchEvent(new Event('input'));
29
+ expect(value.getValue()).toBe('New input');
30
+ });
31
+
32
+ test('should throw an error if props is not an object', () => {
33
+ expect(() => textbox(null)).toThrow('`textbox` requires a `props` object.');
34
+ expect(() => textbox(undefined)).toThrow('`textbox` requires a `props` object.');
35
+ expect(() => textbox(42)).toThrow('`textbox` requires a `props` object.');
36
+ });
37
+
38
+ test('should throw an error if value is not a BehaviorSubject', () => {
39
+ expect(() => textbox({ value: null })).toThrow('`value` must be an instance of BehaviorSubject.');
40
+ expect(() => textbox({ value: 42 })).toThrow('`value` must be an instance of BehaviorSubject.');
41
+ expect(() => textbox({ value: {} })).toThrow('`value` must be an instance of BehaviorSubject.');
42
+ });
43
+
44
+ test('should pass additional attributes to the <input> element', () => {
45
+ const value = new BehaviorSubject('');
46
+ const elem = textbox({ value, placeholder: 'Enter text', maxLength: 50 });
47
+
48
+ // 验证额外属性
49
+ expect(elem.placeholder).toBe('Enter text');
50
+ expect(elem.maxLength).toBe(50);
51
+ });
52
+ });
package/src/index.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ // 将所有命名导出作为当前模块的命名导出
2
+ export * from "./array"
3
+
4
+ export * from "./comparers"
5
+ export * from "./comparison"
6
+
7
+ export * from "./deep"
8
+ export * from "./deep-rxjs"
9
+ export * from "./hyperscript-rxjs"
10
+
11
+ export * from "./nodes"
12
+ export * from "./object"
13
+ export * from "./props"
14
+
15
+ export * from "./ramda"
16
+
17
+ export * from "./structures"
18
+
19
+ export * from "./unquoted-json"
package/src/index.js ADDED
@@ -0,0 +1,19 @@
1
+ // 将所有命名导出作为当前模块的命名导出
2
+ export * from "./array"
3
+
4
+ export * from "./comparers"
5
+ export * from "./comparison"
6
+
7
+ export * from "./deep"
8
+ export * from "./deep-rxjs"
9
+ export * from "./hyperscript-rxjs"
10
+
11
+ export * from "./nodes"
12
+ export * from "./object"
13
+ export * from "./props"
14
+
15
+ export * from "./ramda"
16
+
17
+ export * from "./structures"
18
+
19
+ export * from "./unquoted-json"
@@ -0,0 +1,13 @@
1
+ import { Subscription } from 'rxjs';
2
+
3
+ /**
4
+ * 将 RxJS 订阅对象附加到 DOM 节点上,便于管理。
5
+ * @private
6
+ * @param elem - 要附加订阅的 DOM 节点。
7
+ * @param subscription - 要附加的 RxJS Subscription 对象。
8
+ * @throws 如果参数无效会抛出错误。
9
+ */
10
+ export function attachSubscriptionToNode(
11
+ elem: Node & { subscription?: Subscription },
12
+ subscription: Subscription
13
+ ): void;
@@ -0,0 +1,25 @@
1
+ import { Subscription } from 'rxjs';
2
+
3
+ /**
4
+ * Attaches an RxJS subscription to a DOM node.
5
+ * @param {Node & { subscription?: Subscription }} elem - DOM node to attach the subscription to.
6
+ * @param {Subscription} subscription - RxJS subscription to attach.
7
+ * @throws {Error} If parameters are invalid.
8
+ */
9
+ export const attachSubscriptionToNode = (elem, subscription) => {
10
+ if (!(elem instanceof Node)) {
11
+ throw new Error('Valid DOM node required');
12
+ }
13
+
14
+ if (!(subscription instanceof Subscription)) {
15
+ throw new Error('Valid RxJS subscription required');
16
+ }
17
+
18
+ //新建或附加订阅
19
+ if (!elem.subscription) {
20
+ elem.subscription = subscription;
21
+ } else {
22
+ elem.subscription.add(subscription);
23
+ }
24
+
25
+ };
@@ -0,0 +1,73 @@
1
+ import { Subscription } from 'rxjs';
2
+ import { attachSubscriptionToNode } from './attachSubscriptionToNode';
3
+
4
+ describe('attachSubscriptionToNode', () => {
5
+ test('should attach a subscription to a valid DOM node', () => {
6
+ const elem = document.createElement('div');
7
+ const subscription = new Subscription();
8
+
9
+ attachSubscriptionToNode(elem, subscription);
10
+
11
+ expect(elem.subscription).toBe(subscription);
12
+ });
13
+
14
+ test('should add a new subscription to an existing subscription on the node', () => {
15
+ const elem = document.createElement('div');
16
+ const existingSubscription = new Subscription();
17
+ const newSubscription = new Subscription();
18
+
19
+ // Attach the first subscription
20
+ attachSubscriptionToNode(elem, existingSubscription);
21
+
22
+ // Attach the second subscription
23
+ attachSubscriptionToNode(elem, newSubscription);
24
+
25
+ // Verify that the existing subscription contains the new subscription
26
+ expect(elem.subscription).toBe(existingSubscription);
27
+ expect(existingSubscription.closed).toBe(false); // Ensure it's still active
28
+ });
29
+
30
+ test('should throw an error if the element is not a valid DOM node', () => {
31
+ const invalidElem = null;
32
+ const subscription = new Subscription();
33
+
34
+ expect(() => attachSubscriptionToNode(invalidElem, subscription)).toThrow(
35
+ 'Valid DOM node required'
36
+ );
37
+ });
38
+
39
+ test('should throw an error if the subscription is not a valid RxJS subscription', () => {
40
+ const elem = document.createElement('div');
41
+ const invalidSubscription = {};
42
+
43
+ expect(() => attachSubscriptionToNode(elem, invalidSubscription)).toThrow(
44
+ 'Valid RxJS subscription required'
45
+ );
46
+ });
47
+
48
+ test('should handle multiple subscriptions correctly', () => {
49
+ const elem = document.createElement('div');
50
+ const subscription1 = new Subscription();
51
+ const subscription2 = new Subscription();
52
+
53
+ attachSubscriptionToNode(elem, subscription1);
54
+ attachSubscriptionToNode(elem, subscription2);
55
+
56
+ // Ensure both subscriptions are managed
57
+ expect(elem.subscription).toBe(subscription1);
58
+ expect(subscription1.closed).toBe(false);
59
+ expect(subscription2.closed).toBe(false);
60
+ });
61
+
62
+ test('should not overwrite existing subscriptions', () => {
63
+ const elem = document.createElement('div');
64
+ const subscription1 = new Subscription();
65
+ const subscription2 = new Subscription();
66
+
67
+ attachSubscriptionToNode(elem, subscription1);
68
+ attachSubscriptionToNode(elem, subscription2);
69
+
70
+ // Ensure the original subscription is still the main subscription
71
+ expect(elem.subscription).toBe(subscription1);
72
+ });
73
+ });
@@ -0,0 +1,6 @@
1
+ export * from './attachSubscriptionToNode';
2
+ export * from './normalizeChildNodes';
3
+ export * from './parseHyperscriptArgs';
4
+ export * from './pipeEvent';
5
+ export * from './subscribeEvent';
6
+
@@ -0,0 +1,6 @@
1
+ export * from './attachSubscriptionToNode';
2
+ export * from './normalizeChildNodes';
3
+ export * from './parseHyperscriptArgs';
4
+ export * from './pipeEvent';
5
+ export * from './subscribeEvent';
6
+
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 规范化子节点,将非节点转换为文本节点。
3
+ *
4
+ * @param childNodes - 子节点数组。
5
+ * @returns 返回规范化后的节点数组。
6
+ */
7
+ export function normalizeChildNodes(
8
+ childNodes: any[]
9
+ ): Node[];
@@ -0,0 +1,15 @@
1
+ import { unwrapArgs } from '../array/unwrapArgs';
2
+
3
+ /**
4
+ * 规范化子节点,将非节点转换为文本节点。
5
+ *
6
+ * @param {any[]} childNodes - 子节点数组。
7
+ * @returns {Node[]} - 返回规范化后的节点数组。
8
+ */
9
+ export function normalizeChildNodes(childNodes) {
10
+ const normalizedNodes = unwrapArgs(childNodes); // 解构子节点数组
11
+
12
+ return normalizedNodes.map(child =>
13
+ child instanceof Node ? child : document.createTextNode(String(child)) // 将非节点转换为文本节点
14
+ );
15
+ }