@vnejs/plugins.views.settings 0.2.2 → 0.2.4

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 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.currentItem = null;
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 { currentItem, fields = [] } = this.state;
50
- if (currentItem == null || !fields.length)
52
+ const { currentArrowVerticalItem, fields = [] } = this.state;
53
+ if (currentArrowVerticalItem == null || !fields.length)
51
54
  return;
52
- return fields[currentItem];
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
  };
@@ -13,7 +13,7 @@ export type SettingsViewPluginState = {
13
13
  fields?: SettingsField[];
14
14
  locs?: Record<string, string>;
15
15
  showTextExample?: boolean;
16
- currentItem?: number | null;
16
+ currentArrowVerticalItem?: number | null;
17
17
  currentItemInner?: number | null;
18
18
  };
19
19
  export type SettingsViewTabPayload = {
@@ -18,8 +18,6 @@ export const SettingsExampleText = ({ isShow = false, locs = {}, PARAMS, shared,
18
18
  const tm = setTimeout(() => setTokens([]), PARAMS.SETTINGS_VIEW.TRANSITION);
19
19
  return () => clearTimeout(tm);
20
20
  }, [isShow, isForce, PARAMS.SETTINGS_VIEW.TRANSITION]);
21
- const charDelay = isForce
22
- ? 0
23
- : PARAMS.TEXT_SMOOTH.TOKEN_RENDER_DELAY / Number(shared.settings[SETTINGS.TEXT_SMOOTH.TOKEN_RENDER_SPEED]);
21
+ const charDelay = isForce ? 0 : PARAMS.TEXT_SMOOTH.TOKEN_RENDER_DELAY / Number(shared.settings[SETTINGS.TEXT_SMOOTH.TOKEN_RENDER_SPEED]);
24
22
  return (_jsx(SmoothText, { tokens: tokens, isForce: isForce, charDelay: charDelay, tokensVisibleForce: isForce ? tokens.length : null, transition: PARAMS.SETTINGS_VIEW.VIEW_PROPS.exampleText.transition, size: PARAMS.SETTINGS_VIEW.VIEW_PROPS.exampleText.size, color: PARAMS.SETTINGS_VIEW.VIEW_PROPS.exampleText.color, height: PARAMS.SETTINGS_VIEW.VIEW_PROPS.exampleText.height, scrollBarTextSize: Number(shared.settings[SETTINGS.TEXTSIZE.VALUE]) }));
25
23
  };
@@ -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 = "", currentItem = null, currentItemInner = null, } = useStoreState(store, onMount);
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,20 @@ 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, currentItem, currentItemInner, locs]);
15
+ const propsTab = useMemo(() => ({
16
+ store,
17
+ onMount,
18
+ PARAMS,
19
+ emit,
20
+ EVENTS,
21
+ shared,
22
+ CONST,
23
+ SETTINGS,
24
+ isForce: isRealForce,
25
+ currentItem: currentArrowVerticalItem,
26
+ currentItemInner,
27
+ locs,
28
+ }), [store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isRealForce, currentArrowVerticalItem, currentItemInner, locs]);
16
29
  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
30
  };
18
31
  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.2",
3
+ "version": "0.2.4",
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,12 +29,8 @@ 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
- ? Object.fromEntries(
36
- Object.entries(payload.tabs).map(([tabKey, settingsTab]) => [tabKey, this.tabContentOf(settingsTab, locs)]),
37
- )
33
+ ? Object.fromEntries(Object.entries(payload.tabs).map(([tabKey, settingsTab]) => [tabKey, this.tabContentOf(settingsTab, locs)]))
38
34
  : { ...(this.state.tabsContent ?? {}), [key]: this.tabContentOf(tab, locs) };
39
35
 
40
36
  return {
@@ -55,9 +51,7 @@ export class SettingsViewController extends ModuleController<
55
51
 
56
52
  const isForce = Boolean(payload.isForce || this.shared.viewForceAnimationSources?.isNotEmpty());
57
53
 
58
- this.currentItem = null;
59
-
60
- const next = { ...this.applyTab(payload), currentItem: null as null };
54
+ const next = { ...this.applyTab(payload), currentArrowVerticalItem: null as null };
61
55
 
62
56
  if (isForce) return this.updateStateAndViewForce(next);
63
57
 
@@ -73,12 +67,19 @@ export class SettingsViewController extends ModuleController<
73
67
  return this.updateStateAndView(next);
74
68
  };
75
69
 
70
+ onStateUpdate = (payload: Partial<SettingsViewPluginState> = {}) => {
71
+ const currentArrowVerticalItem = payload.currentArrowVerticalItem;
72
+ const field = currentArrowVerticalItem == null ? undefined : this.state.fields?.[currentArrowVerticalItem];
73
+
74
+ this.updateState({ ...payload, currentItemInner: this.innerIndexOfField(field) });
75
+ };
76
+
76
77
  getFocusedField = () => {
77
- const { currentItem, fields = [] } = this.state;
78
+ const { currentArrowVerticalItem, fields = [] } = this.state;
78
79
 
79
- if (currentItem == null || !fields.length) return;
80
+ if (currentArrowVerticalItem == null || !fields.length) return;
80
81
 
81
- return fields[currentItem];
82
+ return fields[currentArrowVerticalItem];
82
83
  };
83
84
 
84
85
  innerIndexOfField = (field?: SettingsField) => {
@@ -116,20 +117,6 @@ export class SettingsViewController extends ModuleController<
116
117
  }
117
118
  };
118
119
 
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
120
  onArrowLeft = () => {
134
121
  const field = this.getFocusedField();
135
122
 
@@ -200,8 +187,6 @@ export class SettingsViewController extends ModuleController<
200
187
  [this.CONST.CONTROLS.BUTTONS.INTERACT]: () => void this.onInteract(),
201
188
  [this.CONST.CONTROLS.BUTTONS.ARROW_LEFT]: () => void this.onArrowLeft(),
202
189
  [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
190
  };
206
191
  controlsCheckNext = true;
207
192
 
@@ -209,6 +194,8 @@ export class SettingsViewController extends ModuleController<
209
194
  this.on(this.EVENTS.SETTINGS_VIEW.SHOW, this.onShowFields);
210
195
  this.on(this.EVENTS.SETTINGS_VIEW.HIDE, this.onHide);
211
196
  this.on(this.EVENTS.SETTINGS_VIEW.TAB_SET, this.onTabSet);
197
+ this.on(this.EVENTS.SETTINGS_VIEW.STATE_UPDATE, this.onStateUpdate);
198
+ this.on(this.EVENTS.SETTINGS_VIEW.UPDATE_FAST, this.updateViewFast);
212
199
 
213
200
  this.on(this.EVENTS.SETTINGS.CHANGED, this.onSettingChange);
214
201
  this.on(this.EVENTS.COMPONENTS.EXTERNAL_UPDATE, this.onSettingChange);
@@ -0,0 +1,104 @@
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: [
11
+ { settingKey: "a", type: "toggle" },
12
+ { settingKey: "b", type: "toggle" },
13
+ ],
14
+ };
15
+
16
+ describe("SettingsViewArrows", () => {
17
+ beforeEach(() => {
18
+ registerSettingsViewPluginVne();
19
+ });
20
+
21
+ it("SHOW pushes arrow controls above the controller layer", async () => {
22
+ const { module, observer } = createSettingsViewTestModule(SettingsViewArrows);
23
+ const arrows = module as SettingsViewArrows;
24
+ const push = spyEvent(observer, CONTROLS_EVENTS.PUSH);
25
+
26
+ await observer.emit(SUBSCRIBE_EVENTS.SHOW, { tab: generalTab });
27
+
28
+ expect(arrows.currentItem).toBeNull();
29
+ expect(arrows.fields).toHaveLength(2);
30
+ expect(push).toHaveBeenCalledExactlyOnceWith(
31
+ expect.objectContaining({
32
+ key: "settings.fields.controller.arrows",
33
+ checkNext: true,
34
+ index: arrows.PARAMS.SETTINGS_VIEW.ZINDEX + 1,
35
+ }),
36
+ );
37
+ });
38
+
39
+ it("HIDE pops arrow controls", async () => {
40
+ const { observer } = createSettingsViewTestModule(SettingsViewArrows);
41
+ const pop = spyEvent(observer, CONTROLS_EVENTS.POP);
42
+
43
+ await observer.emit(SUBSCRIBE_EVENTS.HIDE);
44
+
45
+ expect(pop).toHaveBeenCalledExactlyOnceWith({ key: "settings.fields.controller.arrows" });
46
+ });
47
+
48
+ it("first ARROW_BOTTOM selects 0 and emits STATE_UPDATE plus UPDATE_FAST", async () => {
49
+ const { module, observer } = createSettingsViewTestModule(SettingsViewArrows);
50
+ const arrows = module as SettingsViewArrows;
51
+ const stateUpdate = spyEvent(observer, SUBSCRIBE_EVENTS.STATE_UPDATE);
52
+ const updateFast = spyEvent(observer, SUBSCRIBE_EVENTS.UPDATE_FAST);
53
+
54
+ await observer.emit(SUBSCRIBE_EVENTS.SHOW, { tab: generalTab });
55
+ await arrows.incCurrentItem();
56
+
57
+ expect(arrows.currentItem).toBe(0);
58
+ expect(stateUpdate).toHaveBeenCalledExactlyOnceWith({ currentArrowVerticalItem: 0 });
59
+ expect(updateFast).toHaveBeenCalledOnce();
60
+ });
61
+
62
+ it("arrow wrap cycles fields", async () => {
63
+ const { module, observer } = createSettingsViewTestModule(SettingsViewArrows);
64
+ const arrows = module as SettingsViewArrows;
65
+ const stateUpdate = spyEvent(observer, SUBSCRIBE_EVENTS.STATE_UPDATE);
66
+
67
+ await observer.emit(SUBSCRIBE_EVENTS.SHOW, { tab: generalTab });
68
+ await arrows.incCurrentItem();
69
+ await arrows.incCurrentItem();
70
+ expect(arrows.currentItem).toBe(1);
71
+
72
+ await arrows.incCurrentItem();
73
+ expect(arrows.currentItem).toBe(0);
74
+ expect(stateUpdate).toHaveBeenLastCalledWith({ currentArrowVerticalItem: 0 });
75
+
76
+ await arrows.decCurrentItem();
77
+ expect(arrows.currentItem).toBe(1);
78
+ });
79
+
80
+ it("TAB_SET resets currentItem and syncs fields", async () => {
81
+ const { module, observer } = createSettingsViewTestModule(SettingsViewArrows);
82
+ const arrows = module as SettingsViewArrows;
83
+ const stateUpdate = spyEvent(observer, SUBSCRIBE_EVENTS.STATE_UPDATE);
84
+
85
+ await observer.emit(SUBSCRIBE_EVENTS.SHOW, { tab: generalTab });
86
+ await arrows.incCurrentItem();
87
+ expect(arrows.currentItem).toBe(0);
88
+
89
+ await observer.emit(SUBSCRIBE_EVENTS.TAB_SET, {
90
+ tab: {
91
+ titleLocKey: "audio",
92
+ fields: [
93
+ { settingKey: "c", type: "toggle" },
94
+ { settingKey: "d", type: "toggle" },
95
+ { settingKey: "e", type: "toggle" },
96
+ ],
97
+ },
98
+ });
99
+
100
+ expect(arrows.currentItem).toBeNull();
101
+ expect(arrows.fields).toHaveLength(3);
102
+ expect(stateUpdate).toHaveBeenLastCalledWith({ currentArrowVerticalItem: null });
103
+ });
104
+ });
@@ -11,7 +11,7 @@ describe("SettingsViewController", () => {
11
11
  registerSettingsViewPluginVne();
12
12
  });
13
13
 
14
- it("SHOW stores fields from tab and maxCurrentItem", async () => {
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).currentItem = 0;
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.currentItem = 0;
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.currentItem = 0;
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.currentItem = 0;
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("setCurrentItem syncs currentItemInner to the current option", async () => {
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.currentItem = 0;
232
- controller.updateState({ currentItem: 0, currentItemInner: 99 });
226
+ controller.updateState({ currentArrowVerticalItem: 0, currentItemInner: 99 });
233
227
 
234
- await controller.setCurrentItem(1, 0);
228
+ await observer.emit(SUBSCRIBE_EVENTS.STATE_UPDATE, { currentArrowVerticalItem: 1 });
235
229
 
236
- expect(controller.currentItem).toBe(1);
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
  });
@@ -1,12 +1,7 @@
1
1
  import { CONSTANTS as CONTROLS_CONST, PLUGIN_NAME as CONTROLS, SUBSCRIBE_EVENTS as CONTROLS_EVENTS } from "@vnejs/contracts.controls";
2
2
  import { PARAMS, PLUGIN_NAME, SUBSCRIBE_EVENTS } from "@vnejs/contracts.views.settings";
3
3
  import { SourcesSet } from "@vnejs/sources-set";
4
- import {
5
- createTestModule as baseCreateTestModule,
6
- registerCoreVne,
7
- registerVnePlugin,
8
- stubSilentEvent,
9
- } from "@vnejs/test-utils";
4
+ import { createTestModule as baseCreateTestModule, registerCoreVne, registerVnePlugin, stubSilentEvent } from "@vnejs/test-utils";
10
5
 
11
6
  export const registerSettingsViewPluginVne = () => {
12
7
  registerCoreVne();
@@ -23,7 +18,7 @@ export const createSettingsViewTestModule = <T extends Parameters<typeof baseCre
23
18
  const result = baseCreateTestModule(ModuleClass, {
24
19
  ...rest,
25
20
  state: {
26
- "settings.fields.controller": { isShow: false, fields: [], currentItem: null, currentItemInner: 0 },
21
+ "settings.fields.controller": { isShow: false, fields: [], currentArrowVerticalItem: null, currentItemInner: 0 },
27
22
  ...(stateOption ?? {}),
28
23
  },
29
24
  shared: {
@@ -36,9 +31,11 @@ export const createSettingsViewTestModule = <T extends Parameters<typeof baseCre
36
31
  stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.SHOW);
37
32
  stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.HIDE);
38
33
  stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.UPDATE);
34
+ stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.UPDATE_FAST);
35
+ stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.STATE_UPDATE);
39
36
  stubSilentEvent(result.observer, SUBSCRIBE_EVENTS.TAB_SET);
40
37
 
41
38
  return result;
42
39
  };
43
40
 
44
- export { SUBSCRIBE_EVENTS, PARAMS, PLUGIN_NAME };
41
+ export { SUBSCRIBE_EVENTS, PARAMS, PLUGIN_NAME, CONTROLS_EVENTS };
package/src/types.ts CHANGED
@@ -5,9 +5,7 @@ import type { SettingsKeys as TextsizeSettingsKeys, PluginName as TextsizePlugin
5
5
  import type { Params as TextSmoothParams, PluginName as TextSmoothPluginName, SettingsKeys as TextSmoothSettingsKeys } from "@vnejs/contracts.text.smooth";
6
6
  import type { Params, PluginName, SubscribeEvents } from "@vnejs/contracts.views.settings";
7
7
 
8
- export type SettingsViewPluginEvents = ModuleComponentsEvents &
9
- Record<PluginName, SubscribeEvents> &
10
- Record<SettingsPluginName, SettingsSubscribeEvents>;
8
+ export type SettingsViewPluginEvents = ModuleComponentsEvents & Record<PluginName, SubscribeEvents> & Record<SettingsPluginName, SettingsSubscribeEvents>;
11
9
 
12
10
  export type SettingsViewPluginConstants = ModuleComponentsConstants & Record<ControlsPluginName, ControlsConstants>;
13
11
 
@@ -15,6 +13,4 @@ export type SettingsViewPluginSettings = ModuleComponentsSettings &
15
13
  Record<TextSmoothPluginName, TextSmoothSettingsKeys> &
16
14
  Record<TextsizePluginName, TextsizeSettingsKeys>;
17
15
 
18
- export type SettingsViewPluginParams = ModuleComponentsParams &
19
- Record<PluginName, Params> &
20
- Record<TextSmoothPluginName, TextSmoothParams>;
16
+ export type SettingsViewPluginParams = ModuleComponentsParams & Record<PluginName, Params> & Record<TextSmoothPluginName, TextSmoothParams>;
@@ -15,7 +15,7 @@ export type SettingsViewPluginState = {
15
15
  fields?: SettingsField[];
16
16
  locs?: Record<string, string>;
17
17
  showTextExample?: boolean;
18
- currentItem?: number | null;
18
+ currentArrowVerticalItem?: number | null;
19
19
  currentItemInner?: number | null;
20
20
  };
21
21
 
@@ -41,9 +41,7 @@ export const SettingsExampleText = ({ isShow = false, locs = {}, PARAMS, shared,
41
41
  return () => clearTimeout(tm);
42
42
  }, [isShow, isForce, PARAMS.SETTINGS_VIEW.TRANSITION]);
43
43
 
44
- const charDelay = isForce
45
- ? 0
46
- : PARAMS.TEXT_SMOOTH.TOKEN_RENDER_DELAY / Number(shared.settings[SETTINGS.TEXT_SMOOTH.TOKEN_RENDER_SPEED]);
44
+ const charDelay = isForce ? 0 : PARAMS.TEXT_SMOOTH.TOKEN_RENDER_DELAY / Number(shared.settings[SETTINGS.TEXT_SMOOTH.TOKEN_RENDER_SPEED]);
47
45
 
48
46
  return (
49
47
  <SmoothText
@@ -21,7 +21,7 @@ const SettingsViewComponent = ({ store, onMount, PARAMS, emit, EVENTS, shared, C
21
21
  locs = {},
22
22
  tabsContent = {},
23
23
  tabKey = "",
24
- currentItem = null,
24
+ currentArrowVerticalItem = null,
25
25
  currentItemInner = null,
26
26
  } = useStoreState<SettingsViewPluginState>(store, onMount);
27
27
 
@@ -40,8 +40,21 @@ 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, currentItem, currentItemInner, locs],
43
+ () => ({
44
+ store,
45
+ onMount,
46
+ PARAMS,
47
+ emit,
48
+ EVENTS,
49
+ shared,
50
+ CONST,
51
+ SETTINGS,
52
+ isForce: isRealForce,
53
+ currentItem: currentArrowVerticalItem,
54
+ currentItemInner,
55
+ locs,
56
+ }),
57
+ [store, onMount, PARAMS, emit, EVENTS, shared, CONST, SETTINGS, isRealForce, currentArrowVerticalItem, currentItemInner, locs],
45
58
  );
46
59
 
47
60
  return (