@vnejs/plugins.views.settings 0.2.2 → 0.2.3
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/dist/index.js +2 -1
- package/dist/modules/arrows.d.ts +18 -0
- package/dist/modules/arrows.js +34 -0
- package/dist/modules/controller.d.ts +1 -3
- package/dist/modules/controller.js +11 -22
- package/dist/utils/settings.d.ts +1 -1
- package/dist/view/index.js +2 -2
- package/package.json +3 -1
- package/src/index.ts +2 -1
- package/src/modules/arrows.ts +54 -0
- package/src/modules/controller.ts +13 -24
- package/src/tests/arrows.test.ts +97 -0
- package/src/tests/controller.test.ts +10 -17
- package/src/tests/setup.ts +4 -2
- package/src/utils/settings.ts +1 -1
- package/src/view/index.tsx +3 -3
package/dist/index.js
CHANGED
|
@@ -2,5 +2,6 @@ import "@vnejs/contracts.views.settings";
|
|
|
2
2
|
import { regPlugin } from "@vnejs/shared";
|
|
3
3
|
import { PARAMS, PLUGIN_NAME, SUBSCRIBE_EVENTS } from "@vnejs/contracts.views.settings";
|
|
4
4
|
import { SettingsViewController } from "./modules/controller.js";
|
|
5
|
+
import { SettingsViewArrows } from "./modules/arrows.js";
|
|
5
6
|
import { SettingsView } from "./modules/view.js";
|
|
6
|
-
regPlugin(PLUGIN_NAME, { events: SUBSCRIBE_EVENTS, params: PARAMS }, [SettingsViewController, SettingsView]);
|
|
7
|
+
regPlugin(PLUGIN_NAME, { events: SUBSCRIBE_EVENTS, params: PARAMS }, [SettingsViewController, SettingsViewArrows, SettingsView]);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SettingsField } from "@vnejs/contracts.views.settings";
|
|
2
|
+
import { ModuleControllerArrowsVertical } from "@vnejs/module.controller.arrows.vertical";
|
|
3
|
+
import type { SettingsViewPluginConstants, SettingsViewPluginEvents, SettingsViewPluginParams, SettingsViewPluginSettings } from "../types.js";
|
|
4
|
+
import type { SettingsViewTabPayload } from "../utils/settings.js";
|
|
5
|
+
export declare class SettingsViewArrows extends ModuleControllerArrowsVertical<SettingsViewPluginEvents, SettingsViewPluginConstants, SettingsViewPluginSettings, SettingsViewPluginParams> {
|
|
6
|
+
name: string;
|
|
7
|
+
EVENT_SHOW: "vne:settings_view:show";
|
|
8
|
+
EVENT_HIDE: "vne:settings_view:hide";
|
|
9
|
+
EVENT_STATE_UPDATE: "vne:settings_view:state_update";
|
|
10
|
+
EVENT_UPDATE_FAST: "vne:settings_view:update_fast";
|
|
11
|
+
CONTROLS_ZINDEX: number;
|
|
12
|
+
fields: SettingsField[];
|
|
13
|
+
subscribe: () => void;
|
|
14
|
+
onShow: (payload?: SettingsViewTabPayload) => Promise<unknown[]> | undefined;
|
|
15
|
+
onTabSet: (payload?: SettingsViewTabPayload) => void;
|
|
16
|
+
getMaxCurrentItem: () => number;
|
|
17
|
+
syncFields: (payload?: SettingsViewTabPayload) => void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ModuleControllerArrowsVertical } from "@vnejs/module.controller.arrows.vertical";
|
|
2
|
+
export class SettingsViewArrows extends ModuleControllerArrowsVertical {
|
|
3
|
+
name = "settings.fields.controller.arrows";
|
|
4
|
+
EVENT_SHOW = this.EVENTS.SETTINGS_VIEW.SHOW;
|
|
5
|
+
EVENT_HIDE = this.EVENTS.SETTINGS_VIEW.HIDE;
|
|
6
|
+
EVENT_STATE_UPDATE = this.EVENTS.SETTINGS_VIEW.STATE_UPDATE;
|
|
7
|
+
EVENT_UPDATE_FAST = this.EVENTS.SETTINGS_VIEW.UPDATE_FAST;
|
|
8
|
+
CONTROLS_ZINDEX = this.PARAMS.SETTINGS_VIEW.ZINDEX;
|
|
9
|
+
fields = [];
|
|
10
|
+
subscribe = () => {
|
|
11
|
+
this.on(this.EVENT_SHOW, this.onShow);
|
|
12
|
+
this.on(this.EVENT_HIDE, this.onHide);
|
|
13
|
+
this.on(this.EVENTS.SETTINGS_VIEW.TAB_SET, this.onTabSet);
|
|
14
|
+
};
|
|
15
|
+
onShow = (payload = {}) => {
|
|
16
|
+
this.syncFields(payload);
|
|
17
|
+
this.currentItem = null;
|
|
18
|
+
return this.emit(this.EVENTS.CONTROLS.PUSH, {
|
|
19
|
+
key: this.name,
|
|
20
|
+
controls: this.controls,
|
|
21
|
+
index: this.CONTROLS_ZINDEX + 1,
|
|
22
|
+
checkNext: true,
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
onTabSet = (payload = {}) => {
|
|
26
|
+
this.syncFields(payload);
|
|
27
|
+
this.currentItem = null;
|
|
28
|
+
this.emitCurrentItem();
|
|
29
|
+
};
|
|
30
|
+
getMaxCurrentItem = () => Math.max((this.fields.length ?? 1) - 1, 0);
|
|
31
|
+
syncFields = (payload = {}) => {
|
|
32
|
+
this.fields = payload.tab?.fields ?? [];
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -21,11 +21,11 @@ export declare class SettingsViewController extends ModuleController<SettingsVie
|
|
|
21
21
|
};
|
|
22
22
|
onShowFields: (payload?: SettingsViewTabPayload) => Promise<void>;
|
|
23
23
|
onTabSet: (payload?: SettingsViewTabPayload) => Promise<void | unknown[]>;
|
|
24
|
+
onStateUpdate: (payload?: Partial<SettingsViewPluginState>) => void;
|
|
24
25
|
getFocusedField: () => SettingsField | undefined;
|
|
25
26
|
innerIndexOfField: (field?: SettingsField) => number;
|
|
26
27
|
optionIndexOf: (length: number, index?: number) => number;
|
|
27
28
|
shiftOptions: (direction: -1 | 1) => void;
|
|
28
|
-
setCurrentItem: (value: number, defaultValue: number) => Promise<void>;
|
|
29
29
|
onArrowLeft: () => void | false;
|
|
30
30
|
onArrowRight: () => void | false;
|
|
31
31
|
onInteract: () => void;
|
|
@@ -33,8 +33,6 @@ export declare class SettingsViewController extends ModuleController<SettingsVie
|
|
|
33
33
|
abstract_interact: () => undefined;
|
|
34
34
|
abstract_arrow_left: () => undefined;
|
|
35
35
|
abstract_arrow_right: () => undefined;
|
|
36
|
-
abstract_arrow_up: () => Promise<void>;
|
|
37
|
-
abstract_arrow_bottom: () => Promise<void>;
|
|
38
36
|
};
|
|
39
37
|
controlsCheckNext: boolean;
|
|
40
38
|
subscribe: () => void;
|
|
@@ -13,7 +13,6 @@ export class SettingsViewController extends ModuleController {
|
|
|
13
13
|
const { tab, locs } = payload;
|
|
14
14
|
const fields = tab?.fields ?? [];
|
|
15
15
|
const key = this.tabKeyOf(payload);
|
|
16
|
-
this.maxCurrentItem = Math.max((fields.length ?? 1) - 1, 0);
|
|
17
16
|
const tabsContent = payload.tabs
|
|
18
17
|
? Object.fromEntries(Object.entries(payload.tabs).map(([tabKey, settingsTab]) => [tabKey, this.tabContentOf(settingsTab, locs)]))
|
|
19
18
|
: { ...(this.state.tabsContent ?? {}), [key]: this.tabContentOf(tab, locs) };
|
|
@@ -32,8 +31,7 @@ export class SettingsViewController extends ModuleController {
|
|
|
32
31
|
if (!this.state.isShow)
|
|
33
32
|
return this.onShow(payload);
|
|
34
33
|
const isForce = Boolean(payload.isForce || this.shared.viewForceAnimationSources?.isNotEmpty());
|
|
35
|
-
this.
|
|
36
|
-
const next = { ...this.applyTab(payload), currentItem: null };
|
|
34
|
+
const next = { ...this.applyTab(payload), currentArrowVerticalItem: null };
|
|
37
35
|
if (isForce)
|
|
38
36
|
return this.updateStateAndViewForce(next);
|
|
39
37
|
const key = next.tabKey;
|
|
@@ -45,11 +43,16 @@ export class SettingsViewController extends ModuleController {
|
|
|
45
43
|
}
|
|
46
44
|
return this.updateStateAndView(next);
|
|
47
45
|
};
|
|
46
|
+
onStateUpdate = (payload = {}) => {
|
|
47
|
+
const currentArrowVerticalItem = payload.currentArrowVerticalItem;
|
|
48
|
+
const field = currentArrowVerticalItem == null ? undefined : this.state.fields?.[currentArrowVerticalItem];
|
|
49
|
+
this.updateState({ ...payload, currentItemInner: this.innerIndexOfField(field) });
|
|
50
|
+
};
|
|
48
51
|
getFocusedField = () => {
|
|
49
|
-
const {
|
|
50
|
-
if (
|
|
52
|
+
const { currentArrowVerticalItem, fields = [] } = this.state;
|
|
53
|
+
if (currentArrowVerticalItem == null || !fields.length)
|
|
51
54
|
return;
|
|
52
|
-
return fields[
|
|
55
|
+
return fields[currentArrowVerticalItem];
|
|
53
56
|
};
|
|
54
57
|
innerIndexOfField = (field) => {
|
|
55
58
|
const options = field?.options ?? [];
|
|
@@ -79,20 +82,6 @@ export class SettingsViewController extends ModuleController {
|
|
|
79
82
|
void this.emit(this.EVENTS.SETTINGS.SET, { name: settingKey, value: option.value });
|
|
80
83
|
}
|
|
81
84
|
};
|
|
82
|
-
setCurrentItem = async (value, defaultValue) => {
|
|
83
|
-
if (this.currentItem === null) {
|
|
84
|
-
this.currentItem = defaultValue;
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
this.currentItem = value;
|
|
88
|
-
if (this.currentItem > this.maxCurrentItem)
|
|
89
|
-
this.currentItem = 0;
|
|
90
|
-
if (this.currentItem < 0)
|
|
91
|
-
this.currentItem = this.maxCurrentItem;
|
|
92
|
-
}
|
|
93
|
-
const currentItemInner = this.innerIndexOfField(this.state.fields?.[this.currentItem]);
|
|
94
|
-
await this.updateStateAndViewFast({ currentItem: this.currentItem, currentItemInner });
|
|
95
|
-
};
|
|
96
85
|
onArrowLeft = () => {
|
|
97
86
|
const field = this.getFocusedField();
|
|
98
87
|
if (!field)
|
|
@@ -152,14 +141,14 @@ export class SettingsViewController extends ModuleController {
|
|
|
152
141
|
[this.CONST.CONTROLS.BUTTONS.INTERACT]: () => void this.onInteract(),
|
|
153
142
|
[this.CONST.CONTROLS.BUTTONS.ARROW_LEFT]: () => void this.onArrowLeft(),
|
|
154
143
|
[this.CONST.CONTROLS.BUTTONS.ARROW_RIGHT]: () => void this.onArrowRight(),
|
|
155
|
-
[this.CONST.CONTROLS.BUTTONS.ARROW_UP]: this.decCurrentItem,
|
|
156
|
-
[this.CONST.CONTROLS.BUTTONS.ARROW_BOTTOM]: this.incCurrentItem,
|
|
157
144
|
};
|
|
158
145
|
controlsCheckNext = true;
|
|
159
146
|
subscribe = () => {
|
|
160
147
|
this.on(this.EVENTS.SETTINGS_VIEW.SHOW, this.onShowFields);
|
|
161
148
|
this.on(this.EVENTS.SETTINGS_VIEW.HIDE, this.onHide);
|
|
162
149
|
this.on(this.EVENTS.SETTINGS_VIEW.TAB_SET, this.onTabSet);
|
|
150
|
+
this.on(this.EVENTS.SETTINGS_VIEW.STATE_UPDATE, this.onStateUpdate);
|
|
151
|
+
this.on(this.EVENTS.SETTINGS_VIEW.UPDATE_FAST, this.updateViewFast);
|
|
163
152
|
this.on(this.EVENTS.SETTINGS.CHANGED, this.onSettingChange);
|
|
164
153
|
this.on(this.EVENTS.COMPONENTS.EXTERNAL_UPDATE, this.onSettingChange);
|
|
165
154
|
};
|
package/dist/utils/settings.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type SettingsViewPluginState = {
|
|
|
13
13
|
fields?: SettingsField[];
|
|
14
14
|
locs?: Record<string, string>;
|
|
15
15
|
showTextExample?: boolean;
|
|
16
|
-
|
|
16
|
+
currentArrowVerticalItem?: number | null;
|
|
17
17
|
currentItemInner?: number | null;
|
|
18
18
|
};
|
|
19
19
|
export type SettingsViewTabPayload = {
|
package/dist/view/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createElement as _createElement } from "react";
|
|
|
3
3
|
import { View, createRenderFunc, useIsForceHook, useMemo, useStoreState } from "@vnejs/uis.react";
|
|
4
4
|
import { SettingsTabContent } from "./SettingsTabContent.js";
|
|
5
5
|
const SettingsViewComponent = ({ store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS }) => {
|
|
6
|
-
const { isShow = false, isForce = false, locs = {}, tabsContent = {}, tabKey = "",
|
|
6
|
+
const { isShow = false, isForce = false, locs = {}, tabsContent = {}, tabKey = "", currentArrowVerticalItem = null, currentItemInner = null, } = useStoreState(store, onMount);
|
|
7
7
|
const isRealForce = useIsForceHook(isForce);
|
|
8
8
|
const propsByView = PARAMS.SETTINGS_VIEW.VIEW_PROPS;
|
|
9
9
|
const propsView = useMemo(() => ({
|
|
@@ -12,7 +12,7 @@ const SettingsViewComponent = ({ store, onMount, PARAMS, emit, EVENTS, shared, C
|
|
|
12
12
|
isForce: isRealForce,
|
|
13
13
|
transition: isRealForce ? 0 : PARAMS.SETTINGS_VIEW.TRANSITION,
|
|
14
14
|
}), [isShow, isRealForce, propsByView.view, PARAMS.SETTINGS_VIEW.TRANSITION]);
|
|
15
|
-
const propsTab = useMemo(() => ({ store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isForce: isRealForce, currentItem, currentItemInner, locs }), [store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isRealForce,
|
|
15
|
+
const propsTab = useMemo(() => ({ store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isForce: isRealForce, currentItem: currentArrowVerticalItem, currentItemInner, locs }), [store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isRealForce, currentArrowVerticalItem, currentItemInner, locs]);
|
|
16
16
|
return (_jsx(View, { ...propsView, children: Object.entries(tabsContent).map(([key, content]) => (_createElement(SettingsTabContent, { ...propsTab, key: key, isShow: tabKey === key, fields: content.fields, showTextExample: content.showTextExample, locs: content.locs ?? locs }))) }));
|
|
17
17
|
};
|
|
18
18
|
export const render = createRenderFunc(SettingsViewComponent);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vnejs/plugins.views.settings",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"@vnejs/helpers": "~0.2.0",
|
|
37
37
|
"@vnejs/module.core": "~0.2.0",
|
|
38
38
|
"@vnejs/module.components": "~0.2.0",
|
|
39
|
+
"@vnejs/module.controller.arrows.vertical": "~0.2.0",
|
|
39
40
|
"@vnejs/contracts.controls": "~0.2.0",
|
|
40
41
|
"@vnejs/contracts.core.settings": "~0.2.0",
|
|
41
42
|
"@vnejs/contracts.settings.textsize": "~0.2.0",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"@vnejs/helpers": "~0.2.0",
|
|
56
57
|
"@vnejs/module.core": "~0.2.0",
|
|
57
58
|
"@vnejs/module.components": "~0.2.0",
|
|
59
|
+
"@vnejs/module.controller.arrows.vertical": "~0.2.0",
|
|
58
60
|
"@vnejs/shared": "~0.2.0",
|
|
59
61
|
"@vnejs/sources-set": "~0.2.0",
|
|
60
62
|
"@vnejs/uis.react": "~0.2.0"
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { regPlugin } from "@vnejs/shared";
|
|
|
4
4
|
import { PARAMS, PLUGIN_NAME, SUBSCRIBE_EVENTS } from "@vnejs/contracts.views.settings";
|
|
5
5
|
|
|
6
6
|
import { SettingsViewController } from "./modules/controller.js";
|
|
7
|
+
import { SettingsViewArrows } from "./modules/arrows.js";
|
|
7
8
|
import { SettingsView } from "./modules/view.js";
|
|
8
9
|
|
|
9
|
-
regPlugin(PLUGIN_NAME, { events: SUBSCRIBE_EVENTS, params: PARAMS }, [SettingsViewController, SettingsView]);
|
|
10
|
+
regPlugin(PLUGIN_NAME, { events: SUBSCRIBE_EVENTS, params: PARAMS }, [SettingsViewController, SettingsViewArrows, SettingsView]);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ControlsPushPayload } from "@vnejs/contracts.controls";
|
|
2
|
+
import type { SettingsField } from "@vnejs/contracts.views.settings";
|
|
3
|
+
import { ModuleControllerArrowsVertical } from "@vnejs/module.controller.arrows.vertical";
|
|
4
|
+
|
|
5
|
+
import type { SettingsViewPluginConstants, SettingsViewPluginEvents, SettingsViewPluginParams, SettingsViewPluginSettings } from "../types.js";
|
|
6
|
+
import type { SettingsViewTabPayload } from "../utils/settings.js";
|
|
7
|
+
|
|
8
|
+
export class SettingsViewArrows extends ModuleControllerArrowsVertical<
|
|
9
|
+
SettingsViewPluginEvents,
|
|
10
|
+
SettingsViewPluginConstants,
|
|
11
|
+
SettingsViewPluginSettings,
|
|
12
|
+
SettingsViewPluginParams
|
|
13
|
+
> {
|
|
14
|
+
name = "settings.fields.controller.arrows";
|
|
15
|
+
|
|
16
|
+
EVENT_SHOW = this.EVENTS.SETTINGS_VIEW.SHOW;
|
|
17
|
+
EVENT_HIDE = this.EVENTS.SETTINGS_VIEW.HIDE;
|
|
18
|
+
EVENT_STATE_UPDATE = this.EVENTS.SETTINGS_VIEW.STATE_UPDATE;
|
|
19
|
+
EVENT_UPDATE_FAST = this.EVENTS.SETTINGS_VIEW.UPDATE_FAST;
|
|
20
|
+
|
|
21
|
+
CONTROLS_ZINDEX = this.PARAMS.SETTINGS_VIEW.ZINDEX;
|
|
22
|
+
|
|
23
|
+
fields: SettingsField[] = [];
|
|
24
|
+
|
|
25
|
+
subscribe = () => {
|
|
26
|
+
this.on(this.EVENT_SHOW, this.onShow);
|
|
27
|
+
this.on(this.EVENT_HIDE, this.onHide);
|
|
28
|
+
this.on(this.EVENTS.SETTINGS_VIEW.TAB_SET, this.onTabSet);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
onShow = (payload: SettingsViewTabPayload = {}) => {
|
|
32
|
+
this.syncFields(payload);
|
|
33
|
+
this.currentItem = null;
|
|
34
|
+
|
|
35
|
+
return this.emit(this.EVENTS.CONTROLS.PUSH, {
|
|
36
|
+
key: this.name,
|
|
37
|
+
controls: this.controls,
|
|
38
|
+
index: this.CONTROLS_ZINDEX + 1,
|
|
39
|
+
checkNext: true,
|
|
40
|
+
} satisfies ControlsPushPayload);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
onTabSet = (payload: SettingsViewTabPayload = {}) => {
|
|
44
|
+
this.syncFields(payload);
|
|
45
|
+
this.currentItem = null;
|
|
46
|
+
this.emitCurrentItem();
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
getMaxCurrentItem = () => Math.max((this.fields.length ?? 1) - 1, 0);
|
|
50
|
+
|
|
51
|
+
syncFields = (payload: SettingsViewTabPayload = {}) => {
|
|
52
|
+
this.fields = payload.tab?.fields ?? [];
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -29,8 +29,6 @@ export class SettingsViewController extends ModuleController<
|
|
|
29
29
|
const fields = tab?.fields ?? [];
|
|
30
30
|
const key = this.tabKeyOf(payload);
|
|
31
31
|
|
|
32
|
-
this.maxCurrentItem = Math.max((fields.length ?? 1) - 1, 0);
|
|
33
|
-
|
|
34
32
|
const tabsContent = payload.tabs
|
|
35
33
|
? Object.fromEntries(
|
|
36
34
|
Object.entries(payload.tabs).map(([tabKey, settingsTab]) => [tabKey, this.tabContentOf(settingsTab, locs)]),
|
|
@@ -55,9 +53,7 @@ export class SettingsViewController extends ModuleController<
|
|
|
55
53
|
|
|
56
54
|
const isForce = Boolean(payload.isForce || this.shared.viewForceAnimationSources?.isNotEmpty());
|
|
57
55
|
|
|
58
|
-
this.
|
|
59
|
-
|
|
60
|
-
const next = { ...this.applyTab(payload), currentItem: null as null };
|
|
56
|
+
const next = { ...this.applyTab(payload), currentArrowVerticalItem: null as null };
|
|
61
57
|
|
|
62
58
|
if (isForce) return this.updateStateAndViewForce(next);
|
|
63
59
|
|
|
@@ -73,12 +69,19 @@ export class SettingsViewController extends ModuleController<
|
|
|
73
69
|
return this.updateStateAndView(next);
|
|
74
70
|
};
|
|
75
71
|
|
|
72
|
+
onStateUpdate = (payload: Partial<SettingsViewPluginState> = {}) => {
|
|
73
|
+
const currentArrowVerticalItem = payload.currentArrowVerticalItem;
|
|
74
|
+
const field = currentArrowVerticalItem == null ? undefined : this.state.fields?.[currentArrowVerticalItem];
|
|
75
|
+
|
|
76
|
+
this.updateState({ ...payload, currentItemInner: this.innerIndexOfField(field) });
|
|
77
|
+
};
|
|
78
|
+
|
|
76
79
|
getFocusedField = () => {
|
|
77
|
-
const {
|
|
80
|
+
const { currentArrowVerticalItem, fields = [] } = this.state;
|
|
78
81
|
|
|
79
|
-
if (
|
|
82
|
+
if (currentArrowVerticalItem == null || !fields.length) return;
|
|
80
83
|
|
|
81
|
-
return fields[
|
|
84
|
+
return fields[currentArrowVerticalItem];
|
|
82
85
|
};
|
|
83
86
|
|
|
84
87
|
innerIndexOfField = (field?: SettingsField) => {
|
|
@@ -116,20 +119,6 @@ export class SettingsViewController extends ModuleController<
|
|
|
116
119
|
}
|
|
117
120
|
};
|
|
118
121
|
|
|
119
|
-
setCurrentItem = async (value: number, defaultValue: number) => {
|
|
120
|
-
if (this.currentItem === null) {
|
|
121
|
-
this.currentItem = defaultValue;
|
|
122
|
-
} else {
|
|
123
|
-
this.currentItem = value;
|
|
124
|
-
if (this.currentItem > this.maxCurrentItem) this.currentItem = 0;
|
|
125
|
-
if (this.currentItem < 0) this.currentItem = this.maxCurrentItem;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const currentItemInner = this.innerIndexOfField(this.state.fields?.[this.currentItem]);
|
|
129
|
-
|
|
130
|
-
await this.updateStateAndViewFast({ currentItem: this.currentItem, currentItemInner });
|
|
131
|
-
};
|
|
132
|
-
|
|
133
122
|
onArrowLeft = () => {
|
|
134
123
|
const field = this.getFocusedField();
|
|
135
124
|
|
|
@@ -200,8 +189,6 @@ export class SettingsViewController extends ModuleController<
|
|
|
200
189
|
[this.CONST.CONTROLS.BUTTONS.INTERACT]: () => void this.onInteract(),
|
|
201
190
|
[this.CONST.CONTROLS.BUTTONS.ARROW_LEFT]: () => void this.onArrowLeft(),
|
|
202
191
|
[this.CONST.CONTROLS.BUTTONS.ARROW_RIGHT]: () => void this.onArrowRight(),
|
|
203
|
-
[this.CONST.CONTROLS.BUTTONS.ARROW_UP]: this.decCurrentItem,
|
|
204
|
-
[this.CONST.CONTROLS.BUTTONS.ARROW_BOTTOM]: this.incCurrentItem,
|
|
205
192
|
};
|
|
206
193
|
controlsCheckNext = true;
|
|
207
194
|
|
|
@@ -209,6 +196,8 @@ export class SettingsViewController extends ModuleController<
|
|
|
209
196
|
this.on(this.EVENTS.SETTINGS_VIEW.SHOW, this.onShowFields);
|
|
210
197
|
this.on(this.EVENTS.SETTINGS_VIEW.HIDE, this.onHide);
|
|
211
198
|
this.on(this.EVENTS.SETTINGS_VIEW.TAB_SET, this.onTabSet);
|
|
199
|
+
this.on(this.EVENTS.SETTINGS_VIEW.STATE_UPDATE, this.onStateUpdate);
|
|
200
|
+
this.on(this.EVENTS.SETTINGS_VIEW.UPDATE_FAST, this.updateViewFast);
|
|
212
201
|
|
|
213
202
|
this.on(this.EVENTS.SETTINGS.CHANGED, this.onSettingChange);
|
|
214
203
|
this.on(this.EVENTS.COMPONENTS.EXTERNAL_UPDATE, this.onSettingChange);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { spyEvent } from "@vnejs/test-utils";
|
|
4
|
+
|
|
5
|
+
import { SettingsViewArrows } from "../modules/arrows.js";
|
|
6
|
+
import { CONTROLS_EVENTS, createSettingsViewTestModule, registerSettingsViewPluginVne, SUBSCRIBE_EVENTS } from "./setup.js";
|
|
7
|
+
|
|
8
|
+
const generalTab = {
|
|
9
|
+
titleLocKey: "general",
|
|
10
|
+
fields: [{ settingKey: "a", type: "toggle" }, { settingKey: "b", type: "toggle" }],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
describe("SettingsViewArrows", () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
registerSettingsViewPluginVne();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("SHOW pushes arrow controls above the controller layer", async () => {
|
|
19
|
+
const { module, observer } = createSettingsViewTestModule(SettingsViewArrows);
|
|
20
|
+
const arrows = module as SettingsViewArrows;
|
|
21
|
+
const push = spyEvent(observer, CONTROLS_EVENTS.PUSH);
|
|
22
|
+
|
|
23
|
+
await observer.emit(SUBSCRIBE_EVENTS.SHOW, { tab: generalTab });
|
|
24
|
+
|
|
25
|
+
expect(arrows.currentItem).toBeNull();
|
|
26
|
+
expect(arrows.fields).toHaveLength(2);
|
|
27
|
+
expect(push).toHaveBeenCalledExactlyOnceWith(
|
|
28
|
+
expect.objectContaining({
|
|
29
|
+
key: "settings.fields.controller.arrows",
|
|
30
|
+
checkNext: true,
|
|
31
|
+
index: arrows.PARAMS.SETTINGS_VIEW.ZINDEX + 1,
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("HIDE pops arrow controls", async () => {
|
|
37
|
+
const { observer } = createSettingsViewTestModule(SettingsViewArrows);
|
|
38
|
+
const pop = spyEvent(observer, CONTROLS_EVENTS.POP);
|
|
39
|
+
|
|
40
|
+
await observer.emit(SUBSCRIBE_EVENTS.HIDE);
|
|
41
|
+
|
|
42
|
+
expect(pop).toHaveBeenCalledExactlyOnceWith({ key: "settings.fields.controller.arrows" });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("first ARROW_BOTTOM selects 0 and emits STATE_UPDATE plus UPDATE_FAST", async () => {
|
|
46
|
+
const { module, observer } = createSettingsViewTestModule(SettingsViewArrows);
|
|
47
|
+
const arrows = module as SettingsViewArrows;
|
|
48
|
+
const stateUpdate = spyEvent(observer, SUBSCRIBE_EVENTS.STATE_UPDATE);
|
|
49
|
+
const updateFast = spyEvent(observer, SUBSCRIBE_EVENTS.UPDATE_FAST);
|
|
50
|
+
|
|
51
|
+
await observer.emit(SUBSCRIBE_EVENTS.SHOW, { tab: generalTab });
|
|
52
|
+
await arrows.incCurrentItem();
|
|
53
|
+
|
|
54
|
+
expect(arrows.currentItem).toBe(0);
|
|
55
|
+
expect(stateUpdate).toHaveBeenCalledExactlyOnceWith({ currentArrowVerticalItem: 0 });
|
|
56
|
+
expect(updateFast).toHaveBeenCalledOnce();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("arrow wrap cycles fields", async () => {
|
|
60
|
+
const { module, observer } = createSettingsViewTestModule(SettingsViewArrows);
|
|
61
|
+
const arrows = module as SettingsViewArrows;
|
|
62
|
+
const stateUpdate = spyEvent(observer, SUBSCRIBE_EVENTS.STATE_UPDATE);
|
|
63
|
+
|
|
64
|
+
await observer.emit(SUBSCRIBE_EVENTS.SHOW, { tab: generalTab });
|
|
65
|
+
await arrows.incCurrentItem();
|
|
66
|
+
await arrows.incCurrentItem();
|
|
67
|
+
expect(arrows.currentItem).toBe(1);
|
|
68
|
+
|
|
69
|
+
await arrows.incCurrentItem();
|
|
70
|
+
expect(arrows.currentItem).toBe(0);
|
|
71
|
+
expect(stateUpdate).toHaveBeenLastCalledWith({ currentArrowVerticalItem: 0 });
|
|
72
|
+
|
|
73
|
+
await arrows.decCurrentItem();
|
|
74
|
+
expect(arrows.currentItem).toBe(1);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("TAB_SET resets currentItem and syncs fields", async () => {
|
|
78
|
+
const { module, observer } = createSettingsViewTestModule(SettingsViewArrows);
|
|
79
|
+
const arrows = module as SettingsViewArrows;
|
|
80
|
+
const stateUpdate = spyEvent(observer, SUBSCRIBE_EVENTS.STATE_UPDATE);
|
|
81
|
+
|
|
82
|
+
await observer.emit(SUBSCRIBE_EVENTS.SHOW, { tab: generalTab });
|
|
83
|
+
await arrows.incCurrentItem();
|
|
84
|
+
expect(arrows.currentItem).toBe(0);
|
|
85
|
+
|
|
86
|
+
await observer.emit(SUBSCRIBE_EVENTS.TAB_SET, {
|
|
87
|
+
tab: {
|
|
88
|
+
titleLocKey: "audio",
|
|
89
|
+
fields: [{ settingKey: "c", type: "toggle" }, { settingKey: "d", type: "toggle" }, { settingKey: "e", type: "toggle" }],
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
expect(arrows.currentItem).toBeNull();
|
|
94
|
+
expect(arrows.fields).toHaveLength(3);
|
|
95
|
+
expect(stateUpdate).toHaveBeenLastCalledWith({ currentArrowVerticalItem: null });
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -11,7 +11,7 @@ describe("SettingsViewController", () => {
|
|
|
11
11
|
registerSettingsViewPluginVne();
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it("SHOW stores fields from tab
|
|
14
|
+
it("SHOW stores fields from tab", async () => {
|
|
15
15
|
const { module, observer } = createSettingsViewTestModule(SettingsViewController);
|
|
16
16
|
|
|
17
17
|
await observer.emit(SUBSCRIBE_EVENTS.SHOW, {
|
|
@@ -26,7 +26,6 @@ describe("SettingsViewController", () => {
|
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
expect((module as SettingsViewController).state.fields).toHaveLength(2);
|
|
29
|
-
expect((module as SettingsViewController).maxCurrentItem).toBe(1);
|
|
30
29
|
expect((module as SettingsViewController).state.isShow).toBe(true);
|
|
31
30
|
expect((module as SettingsViewController).state.tabKey).toBe("general");
|
|
32
31
|
expect(Object.keys((module as SettingsViewController).state.tabsContent ?? {})).toEqual(["general"]);
|
|
@@ -41,8 +40,7 @@ describe("SettingsViewController", () => {
|
|
|
41
40
|
tab: { titleLocKey: "general", fields: [{ settingKey: "test.toggle", type: "toggle" }] },
|
|
42
41
|
});
|
|
43
42
|
|
|
44
|
-
(module as SettingsViewController).
|
|
45
|
-
(module as SettingsViewController).updateState({ currentItem: 0 });
|
|
43
|
+
(module as SettingsViewController).updateState({ currentArrowVerticalItem: 0 });
|
|
46
44
|
|
|
47
45
|
const settingsSet = spyEvent(observer, SETTINGS_EVENTS.SET);
|
|
48
46
|
|
|
@@ -85,8 +83,8 @@ describe("SettingsViewController", () => {
|
|
|
85
83
|
|
|
86
84
|
expect((module as SettingsViewController).state.fields).toHaveLength(2);
|
|
87
85
|
expect((module as SettingsViewController).state.showTextExample).toBe(true);
|
|
88
|
-
expect((module as SettingsViewController).maxCurrentItem).toBe(1);
|
|
89
86
|
expect((module as SettingsViewController).state.currentItemInner).toBe(0);
|
|
87
|
+
expect((module as SettingsViewController).state.currentArrowVerticalItem).toBeNull();
|
|
90
88
|
expect((module as SettingsViewController).state.tabKey).toBe("audio");
|
|
91
89
|
expect(Object.keys((module as SettingsViewController).state.tabsContent ?? {}).sort()).toEqual(["audio", "general"]);
|
|
92
90
|
});
|
|
@@ -115,8 +113,7 @@ describe("SettingsViewController", () => {
|
|
|
115
113
|
|
|
116
114
|
const controller = module as SettingsViewController;
|
|
117
115
|
|
|
118
|
-
controller.
|
|
119
|
-
controller.updateState({ currentItem: 0, currentItemInner: 0 });
|
|
116
|
+
controller.updateState({ currentArrowVerticalItem: 0, currentItemInner: 0 });
|
|
120
117
|
|
|
121
118
|
const settingsSet = spyEvent(observer, SETTINGS_EVENTS.SET);
|
|
122
119
|
|
|
@@ -150,8 +147,7 @@ describe("SettingsViewController", () => {
|
|
|
150
147
|
|
|
151
148
|
const controller = module as SettingsViewController;
|
|
152
149
|
|
|
153
|
-
controller.
|
|
154
|
-
controller.updateState({ currentItem: 0, currentItemInner: 0 });
|
|
150
|
+
controller.updateState({ currentArrowVerticalItem: 0, currentItemInner: 0 });
|
|
155
151
|
|
|
156
152
|
const settingsSet = spyEvent(observer, SETTINGS_EVENTS.SET);
|
|
157
153
|
|
|
@@ -185,8 +181,7 @@ describe("SettingsViewController", () => {
|
|
|
185
181
|
},
|
|
186
182
|
});
|
|
187
183
|
|
|
188
|
-
controller.
|
|
189
|
-
controller.updateState({ currentItem: 0, currentItemInner: 0 });
|
|
184
|
+
controller.updateState({ currentArrowVerticalItem: 0, currentItemInner: 0 });
|
|
190
185
|
|
|
191
186
|
const settingsSet = spyEvent(observer, SETTINGS_EVENTS.SET);
|
|
192
187
|
|
|
@@ -203,7 +198,7 @@ describe("SettingsViewController", () => {
|
|
|
203
198
|
expect(doA).not.toHaveBeenCalled();
|
|
204
199
|
});
|
|
205
200
|
|
|
206
|
-
it("
|
|
201
|
+
it("STATE_UPDATE syncs currentItemInner to the current option", async () => {
|
|
207
202
|
const { module, observer } = createSettingsViewTestModule(SettingsViewController, {
|
|
208
203
|
shared: { settings: { "test.lang": "en" } },
|
|
209
204
|
});
|
|
@@ -228,13 +223,11 @@ describe("SettingsViewController", () => {
|
|
|
228
223
|
|
|
229
224
|
const controller = module as SettingsViewController;
|
|
230
225
|
|
|
231
|
-
controller.
|
|
232
|
-
controller.updateState({ currentItem: 0, currentItemInner: 99 });
|
|
226
|
+
controller.updateState({ currentArrowVerticalItem: 0, currentItemInner: 99 });
|
|
233
227
|
|
|
234
|
-
await
|
|
228
|
+
await observer.emit(SUBSCRIBE_EVENTS.STATE_UPDATE, { currentArrowVerticalItem: 1 });
|
|
235
229
|
|
|
236
|
-
expect(controller.
|
|
237
|
-
expect(controller.state.currentItem).toBe(1);
|
|
230
|
+
expect(controller.state.currentArrowVerticalItem).toBe(1);
|
|
238
231
|
expect(controller.state.currentItemInner).toBe(1);
|
|
239
232
|
});
|
|
240
233
|
});
|
package/src/tests/setup.ts
CHANGED
|
@@ -23,7 +23,7 @@ export const createSettingsViewTestModule = <T extends Parameters<typeof baseCre
|
|
|
23
23
|
const result = baseCreateTestModule(ModuleClass, {
|
|
24
24
|
...rest,
|
|
25
25
|
state: {
|
|
26
|
-
"settings.fields.controller": { isShow: false, fields: [],
|
|
26
|
+
"settings.fields.controller": { isShow: false, fields: [], currentArrowVerticalItem: null, currentItemInner: 0 },
|
|
27
27
|
...(stateOption ?? {}),
|
|
28
28
|
},
|
|
29
29
|
shared: {
|
|
@@ -36,9 +36,11 @@ export const createSettingsViewTestModule = <T extends Parameters<typeof baseCre
|
|
|
36
36
|
stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.SHOW);
|
|
37
37
|
stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.HIDE);
|
|
38
38
|
stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.UPDATE);
|
|
39
|
+
stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.UPDATE_FAST);
|
|
40
|
+
stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.STATE_UPDATE);
|
|
39
41
|
stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.TAB_SET);
|
|
40
42
|
|
|
41
43
|
return result;
|
|
42
44
|
};
|
|
43
45
|
|
|
44
|
-
export { SUBSCRIBE_EVENTS, PARAMS, PLUGIN_NAME };
|
|
46
|
+
export { SUBSCRIBE_EVENTS, PARAMS, PLUGIN_NAME, CONTROLS_EVENTS };
|
package/src/utils/settings.ts
CHANGED
package/src/view/index.tsx
CHANGED
|
@@ -21,7 +21,7 @@ const SettingsViewComponent = ({ store, onMount, PARAMS, emit, EVENTS, shared, C
|
|
|
21
21
|
locs = {},
|
|
22
22
|
tabsContent = {},
|
|
23
23
|
tabKey = "",
|
|
24
|
-
|
|
24
|
+
currentArrowVerticalItem = null,
|
|
25
25
|
currentItemInner = null,
|
|
26
26
|
} = useStoreState<SettingsViewPluginState>(store, onMount);
|
|
27
27
|
|
|
@@ -40,8 +40,8 @@ const SettingsViewComponent = ({ store, onMount, PARAMS, emit, EVENTS, shared, C
|
|
|
40
40
|
);
|
|
41
41
|
|
|
42
42
|
const propsTab = useMemo(
|
|
43
|
-
() => ({ store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isForce: isRealForce, currentItem, currentItemInner, locs }),
|
|
44
|
-
[store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isRealForce,
|
|
43
|
+
() => ({ store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isForce: isRealForce, currentItem: currentArrowVerticalItem, currentItemInner, locs }),
|
|
44
|
+
[store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isRealForce, currentArrowVerticalItem, currentItemInner, locs],
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
return (
|