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.
- package/package.json +13 -22
- package/src/array/advance.d.ts +9 -0
- package/src/array/advance.js +13 -0
- package/src/array/advance.test.js +12 -0
- package/src/array/arrayInsert.d.ts +8 -0
- package/src/array/arrayInsert.js +13 -0
- package/src/array/arrayInsert.test.js +13 -0
- package/src/array/arrayRemove.d.ts +7 -0
- package/src/array/arrayRemove.js +15 -0
- package/src/array/arrayRemove.test.js +13 -0
- package/src/array/findLastIndex.d.ts +14 -0
- package/src/array/findLastIndex.js +20 -0
- package/src/array/findLastIndex.test.js +41 -0
- package/src/array/index.d.ts +9 -0
- package/src/array/index.js +9 -0
- package/src/array/isRange.d.ts +7 -0
- package/src/array/isRange.js +15 -0
- package/src/array/isRange.test.js +6 -0
- package/src/array/rangeArray.d.ts +7 -0
- package/src/array/rangeArray.js +10 -0
- package/src/array/rangeArray.test.js +11 -0
- package/src/array/unwrapArgs.d.ts +10 -0
- package/src/array/unwrapArgs.js +15 -0
- package/src/array/unwrapArgs.test.js +33 -0
- package/src/array/zipArray.d.ts +11 -0
- package/src/array/zipArray.js +24 -0
- package/src/array/zipArray.test.js +16 -0
- package/src/comparers/Comparer.d.ts +101 -0
- package/src/comparers/Comparer.js +149 -0
- package/src/comparers/comparers.d.ts +21 -0
- package/src/comparers/comparers.js +10 -0
- package/src/comparers/differenceSet.d.ts +20 -0
- package/src/comparers/differenceSet.js +35 -0
- package/src/comparers/differenceSet.test.js +11 -0
- package/src/comparers/distinctArray.d.ts +13 -0
- package/src/comparers/distinctArray.js +30 -0
- package/src/comparers/distinctArray.test.js +10 -0
- package/src/comparers/findIndexInSet.d.ts +20 -0
- package/src/comparers/findIndexInSet.js +27 -0
- package/src/comparers/findIndexInSet.test.js +8 -0
- package/src/comparers/groupArrayBy.d.ts +19 -0
- package/src/comparers/groupArrayBy.js +29 -0
- package/src/comparers/groupArrayBy.test.js +38 -0
- package/src/comparers/groupSortedEntries.d.ts +17 -0
- package/src/comparers/groupSortedEntries.js +38 -0
- package/src/comparers/groupSortedEntries.test.js +46 -0
- package/src/comparers/index.d.ts +14 -0
- package/src/comparers/index.js +14 -0
- package/src/comparers/intersectSet.d.ts +19 -0
- package/src/comparers/intersectSet.js +35 -0
- package/src/comparers/intersectSet.test.js +14 -0
- package/src/comparers/isEqualset.d.ts +22 -0
- package/src/comparers/isEqualset.js +33 -0
- package/src/comparers/isEqualset.test.js +22 -0
- package/src/comparers/isSubset.d.ts +21 -0
- package/src/comparers/isSubset.js +33 -0
- package/src/comparers/isSubset.test.js +21 -0
- package/src/comparers/isSuperset.d.ts +21 -0
- package/src/comparers/isSuperset.js +13 -0
- package/src/comparers/isSuperset.test.js +21 -0
- package/src/comparers/sortedArrayToSet.d.ts +20 -0
- package/src/comparers/sortedArrayToSet.js +35 -0
- package/src/comparers/sortedArrayToSet.test.js +11 -0
- package/src/comparers/unionSet.d.ts +21 -0
- package/src/comparers/unionSet.js +34 -0
- package/src/comparers/unionSet.test.js +11 -0
- package/src/comparison/compareDate.d.ts +8 -0
- package/src/comparison/compareDate.js +11 -0
- package/src/comparison/compareEntries.d.ts +13 -0
- package/src/comparison/compareEntries.js +13 -0
- package/src/comparison/compareKey.d.ts +11 -0
- package/src/comparison/compareKey.js +25 -0
- package/src/comparison/compareKey.test.js +21 -0
- package/src/comparison/compareKeyPath.d.ts +15 -0
- package/src/comparison/compareKeyPath.js +33 -0
- package/src/comparison/compareKeyPath.test.js +28 -0
- package/src/comparison/compareNumber.d.ts +11 -0
- package/src/comparison/compareNumber.js +27 -0
- package/src/comparison/compareNumber.test.js +21 -0
- package/src/comparison/defaultCompare.d.ts +8 -0
- package/src/comparison/defaultCompare.js +12 -0
- package/src/comparison/defaultCompare.test.js +24 -0
- package/src/comparison/index.d.ts +7 -0
- package/src/comparison/index.js +7 -0
- package/src/comparison/infinity.test.js +122 -0
- package/src/comparison/typeof.test.js +64 -0
- package/src/comparison/types.d.ts +5 -0
- package/src/comparison/types.js +11 -0
- package/src/deep/Deep.d.ts +58 -0
- package/src/deep/Deep.js +267 -0
- package/src/deep/Deep.test.js +130 -0
- package/src/deep/deepCombineLatest.test.js +36 -0
- package/src/deep/deepMerge.test.js +34 -0
- package/src/deep/differenceDeep.test.js +31 -0
- package/src/deep/freshValueDeep.test.js +17 -0
- package/src/deep/index.d.ts +1 -0
- package/src/deep/index.js +2 -0
- package/src/deep/intersectDeep.test.js +25 -0
- package/src/deep/intersectEntries.d.ts +13 -0
- package/src/deep/intersectEntries.js +37 -0
- package/src/deep/intersectEntries.test.js +20 -0
- package/src/deep/objectToDeep.test.js +31 -0
- package/src/deep/replaceValueDeep.test.js +21 -0
- package/src/deep/unionDeep.test.js +30 -0
- package/src/deep/zipValueDeep.test.js +21 -0
- package/src/deep-rxjs/ObservableArray.d.ts +55 -0
- package/src/deep-rxjs/ObservableArray.js +94 -0
- package/src/deep-rxjs/ObservableArray.test.js +117 -0
- package/src/deep-rxjs/index.d.ts +2 -0
- package/src/deep-rxjs/index.js +2 -0
- package/src/deep-rxjs/isRxType.d.ts +9 -0
- package/src/deep-rxjs/isRxType.js +15 -0
- package/src/deep-rxjs/isRxType.test.js +43 -0
- package/src/hyperscript-rxjs/HyperscriptExtensions.d.ts +20 -0
- package/src/hyperscript-rxjs/checkbox.d.ts +13 -0
- package/src/hyperscript-rxjs/checkbox.js +47 -0
- package/src/hyperscript-rxjs/checkbox.test.js +68 -0
- package/src/hyperscript-rxjs/choice.d.ts +13 -0
- package/src/hyperscript-rxjs/choice.js +24 -0
- package/src/hyperscript-rxjs/choice.test.js +108 -0
- package/src/hyperscript-rxjs/collapse.d.ts +14 -0
- package/src/hyperscript-rxjs/collapse.js +32 -0
- package/src/hyperscript-rxjs/collapse.test.js +67 -0
- package/src/hyperscript-rxjs/displays/blockLevelFamily.d.ts +5 -0
- package/src/hyperscript-rxjs/displays/blockLevelFamily.js +51 -0
- package/src/hyperscript-rxjs/displays/getDisplay.d.ts +7 -0
- package/src/hyperscript-rxjs/displays/getDisplay.js +51 -0
- package/src/hyperscript-rxjs/displays/getDisplay.test.js +56 -0
- package/src/hyperscript-rxjs/displays/index.d.ts +3 -0
- package/src/hyperscript-rxjs/displays/index.js +3 -0
- package/src/hyperscript-rxjs/displays/inlineFamily.d.ts +5 -0
- package/src/hyperscript-rxjs/displays/inlineFamily.js +73 -0
- package/src/hyperscript-rxjs/flip.d.ts +15 -0
- package/src/hyperscript-rxjs/flip.js +29 -0
- package/src/hyperscript-rxjs/flip.test.js +85 -0
- package/src/hyperscript-rxjs/fragment.d.ts +10 -0
- package/src/hyperscript-rxjs/fragment.js +22 -0
- package/src/hyperscript-rxjs/fragment.test.js +70 -0
- package/src/hyperscript-rxjs/hyperscript.d.ts +15 -0
- package/src/hyperscript-rxjs/hyperscript.js +170 -0
- package/src/hyperscript-rxjs/hyperscript.test.js +75 -0
- package/src/hyperscript-rxjs/index.d.ts +19 -0
- package/src/hyperscript-rxjs/index.js +19 -0
- package/src/hyperscript-rxjs/multiselect.d.ts +18 -0
- package/src/hyperscript-rxjs/multiselect.js +41 -0
- package/src/hyperscript-rxjs/multiselect.test.js +121 -0
- package/src/hyperscript-rxjs/numberbox.d.ts +14 -0
- package/src/hyperscript-rxjs/numberbox.js +73 -0
- package/src/hyperscript-rxjs/numberbox.test.js +84 -0
- package/src/hyperscript-rxjs/radio.d.ts +15 -0
- package/src/hyperscript-rxjs/radio.js +53 -0
- package/src/hyperscript-rxjs/radio.test.js +59 -0
- package/src/hyperscript-rxjs/select.d.ts +28 -0
- package/src/hyperscript-rxjs/select.js +88 -0
- package/src/hyperscript-rxjs/select.test.js +101 -0
- package/src/hyperscript-rxjs/tabControls/bindTabIndex.d.ts +12 -0
- package/src/hyperscript-rxjs/tabControls/bindTabIndex.js +59 -0
- package/src/hyperscript-rxjs/tabControls/index.d.ts +8 -0
- package/src/hyperscript-rxjs/tabControls/index.js +10 -0
- package/src/hyperscript-rxjs/tabControls/tabControl.d.ts +19 -0
- package/src/hyperscript-rxjs/tabControls/tabControl.js +40 -0
- package/src/hyperscript-rxjs/tabControls/tabControl.test.js +98 -0
- package/src/hyperscript-rxjs/tabControls/tabNavItem.d.ts +9 -0
- package/src/hyperscript-rxjs/tabControls/tabNavItem.js +30 -0
- package/src/hyperscript-rxjs/tabControls/tabPanel.d.ts +9 -0
- package/src/hyperscript-rxjs/tabControls/tabPanel.js +21 -0
- package/src/hyperscript-rxjs/tabControls/tabRoot.d.ts +7 -0
- package/src/hyperscript-rxjs/tabControls/tabRoot.js +26 -0
- package/src/hyperscript-rxjs/tags.d.ts +193 -0
- package/src/hyperscript-rxjs/tags.js +751 -0
- package/src/hyperscript-rxjs/tags.test.js +75 -0
- package/src/hyperscript-rxjs/textNode.d.ts +11 -0
- package/src/hyperscript-rxjs/textNode.js +51 -0
- package/src/hyperscript-rxjs/textNode.test.js +56 -0
- package/src/hyperscript-rxjs/textarea.d.ts +17 -0
- package/src/hyperscript-rxjs/textarea.js +45 -0
- package/src/hyperscript-rxjs/textarea.test.js +52 -0
- package/src/hyperscript-rxjs/textbox.d.ts +15 -0
- package/src/hyperscript-rxjs/textbox.js +42 -0
- package/src/hyperscript-rxjs/textbox.test.js +52 -0
- package/src/index.d.ts +19 -0
- package/src/index.js +19 -0
- package/src/nodes/attachSubscriptionToNode.d.ts +13 -0
- package/src/nodes/attachSubscriptionToNode.js +25 -0
- package/src/nodes/attachSubscriptionToNode.test.js +73 -0
- package/src/nodes/index.d.ts +6 -0
- package/src/nodes/index.js +6 -0
- package/src/nodes/normalizeChildNodes.d.ts +9 -0
- package/src/nodes/normalizeChildNodes.js +15 -0
- package/src/nodes/normalizeChildNodes.test.js +55 -0
- package/src/nodes/parseHyperscriptArgs.d.ts +10 -0
- package/src/nodes/parseHyperscriptArgs.js +57 -0
- package/src/nodes/parseHyperscriptArgs.test.js +85 -0
- package/src/nodes/pipeEvent.d.ts +15 -0
- package/src/nodes/pipeEvent.js +49 -0
- package/src/nodes/pipeEvent.test.js +97 -0
- package/src/nodes/subscribeEvent.d.ts +15 -0
- package/src/nodes/subscribeEvent.js +56 -0
- package/src/nodes/subscribeEvent.test.js +88 -0
- package/src/object/index.d.ts +10 -0
- package/src/object/index.js +11 -0
- package/src/object/intersectObject.d.ts +12 -0
- package/src/object/intersectObject.js +23 -0
- package/src/object/intersectObject.test.js +69 -0
- package/src/object/isEmptyObject.d.ts +7 -0
- package/src/object/isEmptyObject.js +13 -0
- package/src/object/isEmptyObject.test.js +33 -0
- package/src/object/isPlainObject.d.ts +11 -0
- package/src/object/isPlainObject.js +18 -0
- package/src/object/nestedCombineLatest.d.ts +11 -0
- package/src/object/nestedCombineLatest.js +18 -0
- package/src/object/nestedCombineLatest.test.js +25 -0
- package/src/object/nestedMerge.d.ts +11 -0
- package/src/object/nestedMerge.js +11 -0
- package/src/object/nestedMerge.test.js +61 -0
- package/src/object/pickBehaviorSubject.d.ts +13 -0
- package/src/object/pickBehaviorSubject.js +81 -0
- package/src/object/pickBehaviorSubject.test.js +88 -0
- package/src/object/pluckProperty.d.ts +13 -0
- package/src/object/pluckProperty.js +24 -0
- package/src/object/pluckProperty.test.js +37 -0
- package/src/object/restore.d.ts +12 -0
- package/src/object/restore.js +69 -0
- package/src/object/restore.test.js +124 -0
- package/src/object/splitObjectByObservable.d.ts +12 -0
- package/src/object/splitObjectByObservable.js +41 -0
- package/src/object/splitObjectByObservable.test.js +78 -0
- package/src/props/getNestedProperty.d.ts +12 -0
- package/src/props/getNestedProperty.js +31 -0
- package/src/props/getNestedProperty.test.js +72 -0
- package/src/props/index.d.ts +7 -0
- package/src/props/index.js +7 -0
- package/src/props/parsePropName.d.ts +13 -0
- package/src/props/parsePropName.js +45 -0
- package/src/props/parsePropName.test.js +67 -0
- package/src/props/setProp.d.ts +16 -0
- package/src/props/setProp.js +42 -0
- package/src/props/setProp.test.js +59 -0
- package/src/props/setProps.d.ts +14 -0
- package/src/props/setProps.js +47 -0
- package/src/props/setProps.test.js +97 -0
- package/src/props/subscribeProp.d.ts +16 -0
- package/src/props/subscribeProp.js +47 -0
- package/src/props/subscribeProp.test.js +81 -0
- package/src/ramda/compose.d.ts +10 -0
- package/src/ramda/compose.js +36 -0
- package/src/ramda/compose.test.js +73 -0
- package/src/ramda/cond.d.ts +12 -0
- package/src/ramda/cond.js +29 -0
- package/src/ramda/cond.test.js +88 -0
- package/src/ramda/fold.d.ts +13 -0
- package/src/ramda/fold.js +20 -0
- package/src/ramda/fold.test.js +51 -0
- package/src/ramda/index.d.ts +6 -0
- package/src/ramda/index.js +6 -0
- package/src/ramda/pipe.d.ts +13 -0
- package/src/ramda/pipe.js +27 -0
- package/src/ramda/pipe.test.js +77 -0
- package/src/ramda/unfold.d.ts +11 -0
- package/src/ramda/unfold.js +20 -0
- package/src/ramda/unfold.test.js +29 -0
- package/src/unquoted-json/ajax.test.js +1074 -0
- package/src/unquoted-json/index.d.ts +13 -0
- package/src/unquoted-json/index.js +12 -0
- package/src/unquoted-json/queryStringify.d.ts +8 -0
- package/src/unquoted-json/queryStringify.js +70 -0
- package/src/unquoted-json/queryStringify.test.js +110 -0
- package/src/unquoted-json/stringifyKey.d.ts +7 -0
- package/src/unquoted-json/stringifyKey.js +16 -0
- package/src/unquoted-json/stringifyKey.test.js +51 -0
- package/src/unquoted-json/stringifyStringValue.d.ts +7 -0
- package/src/unquoted-json/stringifyStringValue.js +17 -0
- package/src/unquoted-json/stringifyStringValue.test.js +52 -0
- package/src/unquoted-json/unquotedJsonStringify.d.ts +7 -0
- package/src/unquoted-json/unquotedJsonStringify.js +39 -0
- package/src/unquoted-json/unquotedJsonStringify.test.js +52 -0
- package/dist/hyperscript-rxjs.d.ts +0 -1412
- package/dist/hyperscript-rxjs.js +0 -1
- package/dist/tsdoc-metadata.json +0 -11
@@ -0,0 +1,20 @@
|
|
1
|
+
import { Observable, Observer, Subscription } from 'rxjs';
|
2
|
+
|
3
|
+
type HyperscriptExtensions<T extends HTMLElement> =
|
4
|
+
T & {
|
5
|
+
|
6
|
+
pipeEvent(
|
7
|
+
event: string,
|
8
|
+
subscriber: (input$: Observable<Event>) => Subscription
|
9
|
+
): HyperscriptExtensions<T>;
|
10
|
+
|
11
|
+
subscribeEvent(
|
12
|
+
event: string,
|
13
|
+
observer: ((value: Event) => void) | Partial<Observer<Event>>
|
14
|
+
): HyperscriptExtensions<T>;
|
15
|
+
|
16
|
+
unsubscribe(): void;
|
17
|
+
|
18
|
+
subscription?: Subscription;
|
19
|
+
|
20
|
+
};
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
2
|
+
import { HyperscriptExtensions } from './HyperscriptExtensions';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* 创建一个支持 RxJS 的复选框组件
|
6
|
+
* @param props - 复选框的属性对象
|
7
|
+
* @param props.checked - 可选的 RxJS BehaviorSubject,用于绑定复选框的选中状态
|
8
|
+
* @returns 返回一个增强的复选框元素
|
9
|
+
*/
|
10
|
+
export function checkbox(props: {
|
11
|
+
checked?: BehaviorSubject<boolean>,
|
12
|
+
[key: string]: any
|
13
|
+
}): HyperscriptExtensions<HTMLInputElement>;
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import { map } from 'rxjs/operators';
|
2
|
+
import { input } from './tags';
|
3
|
+
import { BehaviorSubject, Observable } from 'rxjs';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @typedef {import("./HyperscriptExtensions").HyperscriptExtensions<HTMLInputElement>} HyperscriptInputElement
|
7
|
+
*/
|
8
|
+
|
9
|
+
/**
|
10
|
+
* 创建一个支持 RxJS 的复选框组件。
|
11
|
+
*
|
12
|
+
* @param {{checked?:BehaviorSubject<boolean>, [key: string]: any}} props - 复选框的属性对象。
|
13
|
+
* @returns {HyperscriptInputElement} - 返回一个复选框元素。
|
14
|
+
*/
|
15
|
+
export function checkbox(props) {
|
16
|
+
if (typeof props !== 'object' || props === null) {
|
17
|
+
throw new Error('`checkbox` requires a `props` object.');
|
18
|
+
}
|
19
|
+
|
20
|
+
// 创建复选框元素,确保 type 为 'checkbox'
|
21
|
+
const elem = /** @type {HyperscriptInputElement}*/ (input({ ...props, type: 'checkbox' }));
|
22
|
+
|
23
|
+
// 如果传入了 checked 属性
|
24
|
+
if (props.checked && props.checked instanceof BehaviorSubject) {
|
25
|
+
// 监听复选框的 input 事件,并将选中状态推送到 Observable/Subject
|
26
|
+
let subscriber =
|
27
|
+
/**
|
28
|
+
*
|
29
|
+
* @param {Observable<Event>} input$
|
30
|
+
* @returns
|
31
|
+
*/
|
32
|
+
input$ =>
|
33
|
+
input$.pipe(
|
34
|
+
map(
|
35
|
+
e => /** @type {HTMLInputElement} */(e.target).checked
|
36
|
+
) // 提取复选框的选中状态
|
37
|
+
).subscribe(props.checked); // 推送选中状态到 Observable/Subject
|
38
|
+
|
39
|
+
elem.pipeEvent('input', subscriber); // 绑定事件处理器
|
40
|
+
} else {
|
41
|
+
throw new Error(
|
42
|
+
'`checkbox` requires a `checked` prop that is an instance of BehaviorSubject.'
|
43
|
+
);
|
44
|
+
}
|
45
|
+
|
46
|
+
return elem; // 返回复选框元素
|
47
|
+
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
2
|
+
import { checkbox } from './checkbox';
|
3
|
+
|
4
|
+
describe('checkbox', () => {
|
5
|
+
test('should create a checkbox element with default properties', () => {
|
6
|
+
const checked$ = new BehaviorSubject(false);
|
7
|
+
const elem = checkbox({ checked: checked$ });
|
8
|
+
|
9
|
+
// 验证元素类型
|
10
|
+
expect(elem.tagName).toBe('INPUT');
|
11
|
+
expect(elem.type).toBe('checkbox');
|
12
|
+
|
13
|
+
// 验证初始选中状态
|
14
|
+
expect(elem.checked).toBe(false);
|
15
|
+
});
|
16
|
+
|
17
|
+
test('should update BehaviorSubject when checkbox is toggled', () => {
|
18
|
+
const checked$ = new BehaviorSubject(false);
|
19
|
+
const elem = checkbox({ checked: checked$ });
|
20
|
+
|
21
|
+
// 初始状态
|
22
|
+
expect(checked$.value).toBe(false);
|
23
|
+
|
24
|
+
// 模拟用户点击复选框
|
25
|
+
elem.checked = true;
|
26
|
+
elem.dispatchEvent(new Event('input'));
|
27
|
+
|
28
|
+
// 验证 BehaviorSubject 的值是否更新
|
29
|
+
expect(checked$.value).toBe(true);
|
30
|
+
|
31
|
+
// 再次切换状态
|
32
|
+
elem.checked = false;
|
33
|
+
elem.dispatchEvent(new Event('input'));
|
34
|
+
|
35
|
+
// 验证 BehaviorSubject 的值是否更新
|
36
|
+
expect(checked$.value).toBe(false);
|
37
|
+
});
|
38
|
+
|
39
|
+
test('should throw an error if props is not an object', () => {
|
40
|
+
let errorMessage = '`checkbox` requires a `props` object.';
|
41
|
+
expect(() => checkbox(null)).toThrow(errorMessage);
|
42
|
+
expect(() => checkbox(undefined)).toThrow(errorMessage);
|
43
|
+
expect(() => checkbox()).toThrow(errorMessage);
|
44
|
+
expect(() => checkbox(42)).toThrow(errorMessage);
|
45
|
+
});
|
46
|
+
|
47
|
+
test('should throw an error if checked is not a BehaviorSubject', () => {
|
48
|
+
let errorMessage = '`checkbox` requires a `checked` prop that is an instance of BehaviorSubject.';
|
49
|
+
expect(() => checkbox({ checked: true })).toThrow(
|
50
|
+
errorMessage
|
51
|
+
);
|
52
|
+
expect(() => checkbox({ checked: null })).toThrow(
|
53
|
+
errorMessage
|
54
|
+
);
|
55
|
+
expect(() => checkbox({})).toThrow(
|
56
|
+
errorMessage
|
57
|
+
);
|
58
|
+
});
|
59
|
+
|
60
|
+
test('should support additional properties', () => {
|
61
|
+
const checked$ = new BehaviorSubject(false);
|
62
|
+
const elem = checkbox({ checked: checked$, id: 'test-checkbox', className: 'custom-class' });
|
63
|
+
|
64
|
+
// 验证额外属性
|
65
|
+
expect(elem.id).toBe('test-checkbox');
|
66
|
+
expect(elem.className).toBe('custom-class');
|
67
|
+
});
|
68
|
+
});
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Observable } from 'rxjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* 根据 chosen$ 的字符值动态显示或隐藏一组不同字符标签的可能性元素块。
|
5
|
+
*
|
6
|
+
* @param chosen$ - 一个可观察对象(如 BehaviorSubject),表示当前选中的可能性名称。
|
7
|
+
* @param possibilities - 一个对象,键为可能性名称,值为对应的 HTML 元素或 HTML 元素数组。
|
8
|
+
* @returns 包含所有可能性的 HTML 元素数组。
|
9
|
+
*/
|
10
|
+
export function choice(
|
11
|
+
chosen$: Observable<string>,
|
12
|
+
possibilities: Record<string, HTMLElement | HTMLElement[]>
|
13
|
+
): HTMLElement[];
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { Observable } from 'rxjs';
|
2
|
+
import { map } from 'rxjs/operators';
|
3
|
+
|
4
|
+
import { collapse } from './collapse';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @param {Observable<string>} chosen$
|
8
|
+
* @param {Record<string, HTMLElement | HTMLElement[]>} possibilities
|
9
|
+
* @returns {HTMLElement[]}
|
10
|
+
*/
|
11
|
+
export function choice(chosen$, possibilities) {
|
12
|
+
// 遍历 possibilities,将每个可能性绑定到 collapse
|
13
|
+
const elems = Object.entries(possibilities)
|
14
|
+
.map(([key, possibility]) => {
|
15
|
+
const hidden$ =
|
16
|
+
chosen$.pipe(
|
17
|
+
map(selectedKey => selectedKey !== key) // 如果当前选中的键不是当前可能性,则隐藏
|
18
|
+
);
|
19
|
+
return collapse(hidden$, possibility); // 绑定 hidden 属性
|
20
|
+
})
|
21
|
+
.reduce((acc, cur) => [...acc, ...cur], []); // 扁平化数组
|
22
|
+
|
23
|
+
return elems;
|
24
|
+
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
2
|
+
import { choice } from './choice';
|
3
|
+
import { div } from './tags';
|
4
|
+
|
5
|
+
describe('choice', () => {
|
6
|
+
test('should display the chosen possibility and hide others', () => {
|
7
|
+
const chosen = new BehaviorSubject('option1');
|
8
|
+
|
9
|
+
const div1 = div({ hidden: false }, 'Option 1');
|
10
|
+
const div2 = div('Option 2');
|
11
|
+
|
12
|
+
const possibilities = {
|
13
|
+
option1: div1,
|
14
|
+
option2: div2,
|
15
|
+
};
|
16
|
+
|
17
|
+
choice(chosen, possibilities);
|
18
|
+
|
19
|
+
// 初始状态:显示 div1,隐藏 div2
|
20
|
+
expect(div1.hidden).toBe(false);
|
21
|
+
expect(div2.hidden).toBe(true);
|
22
|
+
|
23
|
+
// 更新 chosen
|
24
|
+
chosen.next('option2');
|
25
|
+
expect(div1.hidden).toBe(true);
|
26
|
+
expect(div2.hidden).toBe(false);
|
27
|
+
});
|
28
|
+
|
29
|
+
test('should handle nested arrays of possibilities', () => {
|
30
|
+
const chosen = new BehaviorSubject('group1');
|
31
|
+
|
32
|
+
const group1 = [
|
33
|
+
div({ hidden: false }, 'Group 1 - Item 1'),
|
34
|
+
div({ hidden: false }, 'Group 1 - Item 2'),
|
35
|
+
];
|
36
|
+
|
37
|
+
const group2 = [
|
38
|
+
div('Group 2 - Item 1'),
|
39
|
+
div('Group 2 - Item 2'),
|
40
|
+
];
|
41
|
+
|
42
|
+
const possibilities = {
|
43
|
+
group1: group1,
|
44
|
+
group2: group2,
|
45
|
+
};
|
46
|
+
|
47
|
+
choice(chosen, possibilities);
|
48
|
+
|
49
|
+
// 初始状态:显示 group1,隐藏 group2
|
50
|
+
group1.forEach(item => expect(item.hidden).toBe(false));
|
51
|
+
group2.forEach(item => expect(item.hidden).toBe(true));
|
52
|
+
|
53
|
+
// 更新 chosen
|
54
|
+
chosen.next('group2');
|
55
|
+
group1.forEach(item => expect(item.hidden).toBe(true));
|
56
|
+
group2.forEach(item => expect(item.hidden).toBe(false));
|
57
|
+
});
|
58
|
+
|
59
|
+
test('should return all elements as a flat array', () => {
|
60
|
+
const chosen = new BehaviorSubject('option1');
|
61
|
+
|
62
|
+
const div1 = div();
|
63
|
+
const div2 = div();
|
64
|
+
const div3 = div();
|
65
|
+
|
66
|
+
const possibilities = {
|
67
|
+
option1: [div1, div2],
|
68
|
+
option2: div3,
|
69
|
+
};
|
70
|
+
|
71
|
+
const result = choice(chosen, possibilities);
|
72
|
+
|
73
|
+
expect(result).toEqual([div1, div2, div3]);
|
74
|
+
});
|
75
|
+
|
76
|
+
test('should handle empty possibilities', () => {
|
77
|
+
const chosen = new BehaviorSubject('option1');
|
78
|
+
|
79
|
+
const possibilities = {};
|
80
|
+
|
81
|
+
const result = choice(chosen, possibilities);
|
82
|
+
|
83
|
+
expect(result).toEqual([]);
|
84
|
+
});
|
85
|
+
|
86
|
+
test('should handle invalid chosen values gracefully', () => {
|
87
|
+
const chosen = new BehaviorSubject('invalidOption');
|
88
|
+
|
89
|
+
const div1 = div();
|
90
|
+
const div2 = div();
|
91
|
+
|
92
|
+
const possibilities = {
|
93
|
+
option1: div1,
|
94
|
+
option2: div2,
|
95
|
+
};
|
96
|
+
|
97
|
+
choice(chosen, possibilities);
|
98
|
+
|
99
|
+
// 初始状态:所有元素都隐藏
|
100
|
+
expect(div1.hidden).toBe(true);
|
101
|
+
expect(div2.hidden).toBe(true);
|
102
|
+
|
103
|
+
// 更新 chosen
|
104
|
+
chosen.next('option1');
|
105
|
+
expect(div1.hidden).toBe(false);
|
106
|
+
expect(div2.hidden).toBe(true);
|
107
|
+
});
|
108
|
+
});
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { Observable } from 'rxjs';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* 显示或隐藏包含的元素,通过绑定 hidden 属性实现动态显示或隐藏。
|
5
|
+
*
|
6
|
+
* @param hidden$ - 一个可观察对象(如 BehaviorSubject),用于控制元素的 hidden 属性。
|
7
|
+
* @param elements - 一个或多个 HTML 元素,或者包含 HTML 元素的数组。
|
8
|
+
* @returns 处理后的元素数组。
|
9
|
+
* @throws 如果 elements 中包含非 HTMLElement 节点会抛出错误。
|
10
|
+
*/
|
11
|
+
export function collapse(
|
12
|
+
hidden$: Observable<boolean>,
|
13
|
+
...elements: (HTMLElement | HTMLElement[])[]
|
14
|
+
): HTMLElement[];
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { Observable } from 'rxjs';
|
2
|
+
|
3
|
+
import { unwrapArgs } from '../array/unwrapArgs';
|
4
|
+
import { subscribeProp } from '../props/subscribeProp';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* 显示或隐藏包含的元素。
|
8
|
+
*
|
9
|
+
* `collapse` 函数通过绑定 `hidden` 属性,实现一组 HTML 元素的动态显示或隐藏。
|
10
|
+
*
|
11
|
+
* @param {Observable<boolean>} hidden$ - 一个可观察对象(如 BehaviorSubject),用于控制元素的 `hidden` 属性。
|
12
|
+
* @param {...HTMLElement|HTMLElement[]} elements - 一个或多个 HTML 元素,或者包含 HTML 元素的数组。
|
13
|
+
* @returns {HTMLElement[]} - 处理后的元素数组。
|
14
|
+
*
|
15
|
+
* @throws {Error} 如果 `elements` 中包含非元素节点(如 TextNode)。
|
16
|
+
*
|
17
|
+
*/
|
18
|
+
export function collapse(hidden$, ...elements) {
|
19
|
+
// 支持子元素包含在数组中:collapse([a, b, c]) 或 collapse(a, b, c)
|
20
|
+
let elems = unwrapArgs(elements);
|
21
|
+
|
22
|
+
elems.forEach(elem => {
|
23
|
+
if (!(elem instanceof HTMLElement)) {
|
24
|
+
throw new Error('`collapse` only supports HTMLElement nodes.');
|
25
|
+
}
|
26
|
+
|
27
|
+
// 绑定 hidden 属性到可观察对象
|
28
|
+
subscribeProp(elem, 'hidden', hidden$);
|
29
|
+
});
|
30
|
+
|
31
|
+
return elems;
|
32
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
2
|
+
import { collapse } from './collapse';
|
3
|
+
import { div } from './tags';
|
4
|
+
import { textNode } from './textNode';
|
5
|
+
|
6
|
+
describe('collapse', () => {
|
7
|
+
test('should bind hidden property to a single element', () => {
|
8
|
+
const hidden = new BehaviorSubject(false);
|
9
|
+
const div1 = div();
|
10
|
+
|
11
|
+
collapse(hidden, div1);
|
12
|
+
|
13
|
+
// 初始状态
|
14
|
+
expect(div1.hidden).toBe(false);
|
15
|
+
|
16
|
+
// 更新 BehaviorSubject
|
17
|
+
hidden.next(true);
|
18
|
+
expect(div1.hidden).toBe(true);
|
19
|
+
|
20
|
+
hidden.next(false);
|
21
|
+
expect(div1.hidden).toBe(false);
|
22
|
+
});
|
23
|
+
|
24
|
+
test('should bind hidden property to multiple elements', () => {
|
25
|
+
const hidden = new BehaviorSubject(false);
|
26
|
+
const div1 = div();
|
27
|
+
const div2 = div();
|
28
|
+
|
29
|
+
collapse(hidden, div1, div2);
|
30
|
+
|
31
|
+
// 初始状态
|
32
|
+
expect(div1.hidden).toBe(false);
|
33
|
+
expect(div2.hidden).toBe(false);
|
34
|
+
|
35
|
+
// 更新 BehaviorSubject
|
36
|
+
hidden.next(true);
|
37
|
+
expect(div1.hidden).toBe(true);
|
38
|
+
expect(div2.hidden).toBe(true);
|
39
|
+
|
40
|
+
hidden.next(false);
|
41
|
+
expect(div1.hidden).toBe(false);
|
42
|
+
expect(div2.hidden).toBe(false);
|
43
|
+
});
|
44
|
+
|
45
|
+
test('should throw an error if elements contain non-HTMLElement nodes', () => {
|
46
|
+
const hidden = new BehaviorSubject(false);
|
47
|
+
const textNode1 = textNode('This is a text node');
|
48
|
+
|
49
|
+
expect(() => collapse(hidden, textNode1)).toThrow('`collapse` only supports HTMLElement nodes.');
|
50
|
+
});
|
51
|
+
|
52
|
+
test('should return the processed elements', () => {
|
53
|
+
const hidden = new BehaviorSubject(false);
|
54
|
+
const div1 = div();
|
55
|
+
const div2 = div();
|
56
|
+
|
57
|
+
const result = collapse(hidden, div1, div2);
|
58
|
+
|
59
|
+
expect(result).toEqual([div1, div2]);
|
60
|
+
});
|
61
|
+
|
62
|
+
test('should handle empty elements array', () => {
|
63
|
+
const hidden = new BehaviorSubject(false);
|
64
|
+
const result = collapse(hidden);
|
65
|
+
expect(result).toEqual([]);
|
66
|
+
});
|
67
|
+
});
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/**
|
2
|
+
* 一个包含所有 HTML 块级元素标签名称的集合。
|
3
|
+
*
|
4
|
+
* 块级元素是 HTML 中的一类元素,它们通常会独占一行,并且可以包含内联元素或其他块级元素。
|
5
|
+
* 该集合中的标签名称均为大写,便于快速判断某个元素是否为块级元素。
|
6
|
+
*
|
7
|
+
* 常见的块级元素包括:
|
8
|
+
* - 文本结构元素:`P`、`H1`-`H6`、`ADDRESS` 等。
|
9
|
+
* - 列表元素:`UL`、`OL`、`LI`、`DL`、`DT`、`DD`。
|
10
|
+
* - 容器元素:`DIV`、`SECTION`、`ARTICLE`、`ASIDE`、`NAV` 等。
|
11
|
+
* - 表单元素:`FORM`、`FIELDSET`。
|
12
|
+
* - 表格元素:`TABLE`。
|
13
|
+
* - 其他:`BLOCKQUOTE`、`PRE`、`FIGURE` 等。
|
14
|
+
*
|
15
|
+
* @constant {Set<string>} blockLevelFamily
|
16
|
+
*/
|
17
|
+
export const blockLevelFamily = new Set([
|
18
|
+
'ADDRESS',
|
19
|
+
'ARTICLE',
|
20
|
+
'ASIDE',
|
21
|
+
'BLOCKQUOTE',
|
22
|
+
'DD',
|
23
|
+
'DETAILS',
|
24
|
+
'DIALOG',
|
25
|
+
'DIV',
|
26
|
+
'DL',
|
27
|
+
'DT',
|
28
|
+
'FIELDSET',
|
29
|
+
'FIGCAPTION',
|
30
|
+
'FIGURE',
|
31
|
+
'FOOTER',
|
32
|
+
'FORM',
|
33
|
+
'H1',
|
34
|
+
'H2',
|
35
|
+
'H3',
|
36
|
+
'H4',
|
37
|
+
'H5',
|
38
|
+
'H6',
|
39
|
+
'HEADER',
|
40
|
+
'HGROUP',
|
41
|
+
'HR',
|
42
|
+
'LI',
|
43
|
+
'MAIN',
|
44
|
+
'NAV',
|
45
|
+
'OL',
|
46
|
+
'P',
|
47
|
+
'PRE',
|
48
|
+
'SECTION',
|
49
|
+
'TABLE',
|
50
|
+
'UL',
|
51
|
+
])
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import { blockLevelFamily } from './blockLevelFamily'
|
2
|
+
import { inlineFamily } from './inlineFamily'
|
3
|
+
|
4
|
+
/**
|
5
|
+
* 获取 HTML 元素的默认 CSS `display` 值。
|
6
|
+
*
|
7
|
+
* 根据元素的标签名称 (`tagName`),返回其对应的默认 `display` 属性值。
|
8
|
+
* 支持表格相关标签、块级元素、内联元素等常见 HTML 标签。
|
9
|
+
*
|
10
|
+
* @param {HTMLElement} elem - 要获取 `display` 值的 HTML 元素。
|
11
|
+
* @returns {string} - 元素的默认 `display` 值:
|
12
|
+
* - 表格相关标签:
|
13
|
+
* - `TBODY` -> `'table-row-group'`
|
14
|
+
* - `THEAD` -> `'table-header-group'`
|
15
|
+
* - `TFOOT` -> `'table-footer-group'`
|
16
|
+
* - `TR` -> `'table-row'`
|
17
|
+
* - `TD`、`TH` -> `'table-cell'`
|
18
|
+
* - `COLGROUP` -> `'table-column-group'`
|
19
|
+
* - `COL` -> `'table-column'`
|
20
|
+
* - `CAPTION` -> `'table-caption'`
|
21
|
+
* - 块级元素 -> `'block'`
|
22
|
+
* - 内联元素 -> `'inline'`
|
23
|
+
* - 未知标签 -> `'unset'`
|
24
|
+
*
|
25
|
+
*/
|
26
|
+
export function getDisplay(elem) {
|
27
|
+
if (elem.tagName === 'TBODY') {
|
28
|
+
return 'table-row-group'
|
29
|
+
} else if (elem.tagName === 'THEAD') {
|
30
|
+
return 'table-header-group'
|
31
|
+
} else if (elem.tagName === 'TFOOT') {
|
32
|
+
return 'table-footer-group'
|
33
|
+
} else if (elem.tagName === 'TR') {
|
34
|
+
return 'table-row'
|
35
|
+
} else if (elem.tagName === 'TD' || elem.tagName === 'TH') {
|
36
|
+
return 'table-cell'
|
37
|
+
} else if (elem.tagName === 'COLGROUP') {
|
38
|
+
return 'table-column-group'
|
39
|
+
} else if (elem.tagName === 'COL') {
|
40
|
+
return 'table-column'
|
41
|
+
} else if (elem.tagName === 'CAPTION') {
|
42
|
+
return 'table-caption'
|
43
|
+
} else if (blockLevelFamily.has(elem.tagName)) {
|
44
|
+
return 'block'
|
45
|
+
} else if (inlineFamily.has(elem.tagName)) {
|
46
|
+
return 'inline'
|
47
|
+
} else {
|
48
|
+
return 'unset'
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import { getDisplay } from './getDisplay';
|
2
|
+
import { blockLevelFamily } from './blockLevelFamily';
|
3
|
+
import { inlineFamily } from './inlineFamily';
|
4
|
+
|
5
|
+
describe('getDisplay', () => {
|
6
|
+
test('should return correct display value for table-related tags', () => {
|
7
|
+
const tbody = document.createElement('tbody');
|
8
|
+
expect(getDisplay(tbody)).toBe('table-row-group');
|
9
|
+
|
10
|
+
const thead = document.createElement('thead');
|
11
|
+
expect(getDisplay(thead)).toBe('table-header-group');
|
12
|
+
|
13
|
+
const tfoot = document.createElement('tfoot');
|
14
|
+
expect(getDisplay(tfoot)).toBe('table-footer-group');
|
15
|
+
|
16
|
+
const tr = document.createElement('tr');
|
17
|
+
expect(getDisplay(tr)).toBe('table-row');
|
18
|
+
|
19
|
+
const td = document.createElement('td');
|
20
|
+
expect(getDisplay(td)).toBe('table-cell');
|
21
|
+
|
22
|
+
const th = document.createElement('th');
|
23
|
+
expect(getDisplay(th)).toBe('table-cell');
|
24
|
+
|
25
|
+
const colgroup = document.createElement('colgroup');
|
26
|
+
expect(getDisplay(colgroup)).toBe('table-column-group');
|
27
|
+
|
28
|
+
const col = document.createElement('col');
|
29
|
+
expect(getDisplay(col)).toBe('table-column');
|
30
|
+
|
31
|
+
const caption = document.createElement('caption');
|
32
|
+
expect(getDisplay(caption)).toBe('table-caption');
|
33
|
+
});
|
34
|
+
|
35
|
+
test('should return "block" for block-level elements', () => {
|
36
|
+
blockLevelFamily.forEach(tagName => {
|
37
|
+
const elem = document.createElement(tagName.toLowerCase());
|
38
|
+
expect(getDisplay(elem)).toBe('block');
|
39
|
+
});
|
40
|
+
});
|
41
|
+
|
42
|
+
test('should return "inline" for inline elements', () => {
|
43
|
+
inlineFamily.forEach(tagName => {
|
44
|
+
const elem = document.createElement(tagName.toLowerCase());
|
45
|
+
expect(getDisplay(elem)).toBe('inline');
|
46
|
+
});
|
47
|
+
});
|
48
|
+
|
49
|
+
test('should return "unset" for unknown tags', () => {
|
50
|
+
const customElement = document.createElement('custom-element');
|
51
|
+
expect(getDisplay(customElement)).toBe('unset');
|
52
|
+
|
53
|
+
const unknownElement = document.createElement('unknown');
|
54
|
+
expect(getDisplay(unknownElement)).toBe('unset');
|
55
|
+
});
|
56
|
+
});
|
@@ -0,0 +1,73 @@
|
|
1
|
+
/**
|
2
|
+
* 一个包含所有 HTML 内联元素标签名称的集合。
|
3
|
+
*
|
4
|
+
* 内联元素是 HTML 中的一类元素,它们不会独占一行,通常用于包裹文本或其他内联元素。
|
5
|
+
* 该集合中的标签名称均为大写,便于快速判断某个元素是否为内联元素。
|
6
|
+
*
|
7
|
+
* 常见的内联元素包括:
|
8
|
+
* - 文本样式:`B`、`I`、`U`、`STRONG`、`EM`、`MARK` 等。
|
9
|
+
* - 链接和交互:`A`、`BUTTON`、`LABEL`、`INPUT`、`SELECT`、`TEXTAREA` 等。
|
10
|
+
* - 媒体和嵌入:`IMG`、`SVG`、`VIDEO`、`AUDIO`、`CANVAS` 等。
|
11
|
+
* - 其他:`SPAN`、`BR`、`WBR`、`CODE`、`Q` 等。
|
12
|
+
*
|
13
|
+
* @constant {Set<string>} inlineFamily
|
14
|
+
*/
|
15
|
+
export const inlineFamily = new Set([
|
16
|
+
'A',
|
17
|
+
'ABBR',
|
18
|
+
'ACRONYM',
|
19
|
+
'AUDIO',
|
20
|
+
'B',
|
21
|
+
'BDI',
|
22
|
+
'BDO',
|
23
|
+
'BIG',
|
24
|
+
'BR',
|
25
|
+
'BUTTON',
|
26
|
+
'CANVAS',
|
27
|
+
'CITE',
|
28
|
+
'CODE',
|
29
|
+
'DATA',
|
30
|
+
'DATALIST',
|
31
|
+
'DEL',
|
32
|
+
'DFN',
|
33
|
+
'EM',
|
34
|
+
'EMBED',
|
35
|
+
'I',
|
36
|
+
'IFRAME',
|
37
|
+
'IMG',
|
38
|
+
'INPUT',
|
39
|
+
'INS',
|
40
|
+
'KBD',
|
41
|
+
'LABEL',
|
42
|
+
'MAP',
|
43
|
+
'MARK',
|
44
|
+
'METER',
|
45
|
+
'NOSCRIPT',
|
46
|
+
'OBJECT',
|
47
|
+
'OUTPUT',
|
48
|
+
'PICTURE',
|
49
|
+
'PROGRESS',
|
50
|
+
'Q',
|
51
|
+
'RUBY',
|
52
|
+
'S',
|
53
|
+
'SAMP',
|
54
|
+
'SCRIPT',
|
55
|
+
'SELECT',
|
56
|
+
'SLOT',
|
57
|
+
'SMALL',
|
58
|
+
'SPAN',
|
59
|
+
'STRONG',
|
60
|
+
'SUB',
|
61
|
+
'SUP',
|
62
|
+
'SVG',
|
63
|
+
'TEMPLATE',
|
64
|
+
'TEXTAREA',
|
65
|
+
'TIME',
|
66
|
+
'TT',
|
67
|
+
'U',
|
68
|
+
'VAR',
|
69
|
+
'VIDEO',
|
70
|
+
'WBR',
|
71
|
+
]);
|
72
|
+
|
73
|
+
// developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
|