@vnejs/plugins.views.screens.history 0.1.8

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.
@@ -0,0 +1,14 @@
1
+ export const SUBSCRIBE_EVENTS = {
2
+ GET: "vne:history:get",
3
+ ADD: "vne:history:add",
4
+ LOAD: "vne:history:load",
5
+ BACK: "vne:history:back",
6
+ KEYS: "vne:history:keys",
7
+ CLEAR: "vne:history:clear",
8
+
9
+ HIDE: "vne:history:hide",
10
+ SHOW: "vne:history:show",
11
+ CLICK: "vne:history:click",
12
+ UPDATE: "vne:history:update",
13
+ ACCEPT: "vne:history:accept",
14
+ };
@@ -0,0 +1,11 @@
1
+ export const MAX_LENGTH = 50;
2
+
3
+ export const ZINDEX = 2000;
4
+ export const TRANSITION = 300;
5
+ export const LOC_LABEL = "history";
6
+
7
+ export const VIEW_PROPS = {
8
+ screen: { isDisableAutoread: true, withBlur: true, withDark: true, zIndex: ZINDEX, transition: TRANSITION },
9
+ lines: { position: { top: 120, left: 120, right: 120 }, controls: { wrapHeight: 1800, withScrollbar: true, flexGap: 36, textSize: 60, textMarginTop: 36 } },
10
+ close: { position: { bottom: 120, left: 120 }, text: { size: 60 } },
11
+ };
package/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import { regPlugin } from "@vnejs/shared";
2
+
3
+ import { SUBSCRIBE_EVENTS } from "./const/events";
4
+ import * as params from "./const/params";
5
+
6
+ import { HistoryController } from "./modules/controller";
7
+ import { History } from "./modules/history";
8
+ import { HistoryView } from "./modules/view";
9
+
10
+ regPlugin("HISTORY", { events: SUBSCRIBE_EVENTS, params }, [HistoryController, History, HistoryView]);
@@ -0,0 +1,49 @@
1
+ import { ModuleController } from "@vnejs/module.components";
2
+
3
+ export class HistoryController extends ModuleController {
4
+ name = "history.controller";
5
+
6
+ emitHide = () => this.emit(this.EVENTS.HISTORY.HIDE);
7
+
8
+ updateEvent = this.EVENTS.HISTORY.UPDATE;
9
+ controls = {
10
+ [this.CONST.CONTROLS.BUTTONS.BACK]: this.emitHide,
11
+ [this.CONST.CONTROLS.BUTTONS.MENU]: this.emitHide,
12
+ [this.CONST.CONTROLS.BUTTONS.GAMEMENU]: this.emitHide,
13
+ [this.CONST.CONTROLS.BUTTONS.ARROW_UP]: this.decCurrentItem,
14
+ [this.CONST.CONTROLS.BUTTONS.ARROW_BOTTOM]: this.incCurrentItem,
15
+ [this.CONST.CONTROLS.BUTTONS.ACCEPT]: () => this.emit(this.EVENTS.HISTORY.ACCEPT),
16
+ };
17
+ controlsIndex = this.PARAMS.HISTORY.ZINDEX;
18
+
19
+ subscribe = () => {
20
+ this.on(this.EVENTS.HISTORY.SHOW, this.onShow);
21
+ this.on(this.EVENTS.HISTORY.HIDE, this.onHide);
22
+ this.on(this.EVENTS.HISTORY.ACCEPT, this.onAccept);
23
+ this.on(this.EVENTS.HISTORY.CLICK, this.onClick);
24
+
25
+ this.on(this.EVENTS.STATE.SET, this.onStateSet);
26
+ };
27
+
28
+ beforeShow = async () => {
29
+ this.maxCurrentItem = this.globalState.history.history.length - 1;
30
+
31
+ this.updateState({
32
+ historyLocs: await Promise.all(this.globalState.history.history.map(this.getHistoryText)),
33
+ historyKeys: await this.emitOne(this.EVENTS.HISTORY.KEYS),
34
+ history: this.globalState.history.history,
35
+ });
36
+ };
37
+ afterHide = () => this.setDefaultState();
38
+
39
+ onAccept = () => this.currentItem !== null && this.emit(this.EVENTS.HISTORY.CLICK, { uid: this.globalState.history.history[this.currentItem].uid });
40
+ onClick = ({ uid } = {}) => this.state.historyKeys.includes(uid) && this.emit(this.EVENTS.HISTORY.LOAD, { uid });
41
+
42
+ onStateSet = () => this.emit(this.EVENTS.HISTORY.HIDE, { isForce: true });
43
+
44
+ getHistoryText = async ({ label, text, args, uid } = {}) => {
45
+ const state = await this.emitOne(this.EVENTS.HISTORY.GET, { uid });
46
+
47
+ return this.emitOne(this.EVENTS.TEXT.REPLACE, { label, text, args, state });
48
+ };
49
+ }
@@ -0,0 +1,66 @@
1
+ import { Module } from "@vnejs/module";
2
+
3
+ export class History extends Module {
4
+ name = "history";
5
+
6
+ isLoadInProcess = false;
7
+
8
+ subscribe = () => {
9
+ this.on(this.EVENTS.HISTORY.ADD, this.onHistoryAdd);
10
+ this.on(this.EVENTS.HISTORY.GET, this.onHistoryGet);
11
+ this.on(this.EVENTS.HISTORY.LOAD, this.onHistoryLoad);
12
+ this.on(this.EVENTS.HISTORY.BACK, this.onHistoryBack);
13
+ this.on(this.EVENTS.HISTORY.KEYS, this.onHistoryKeys);
14
+
15
+ this.on(this.EVENTS.STATE.CLEAR, this.setDefaultState);
16
+ this.on(this.EVENTS.STATE.SET, this.onStateSet);
17
+ };
18
+
19
+ init = () => this.emit(this.EVENTS.MEMORY.REG, { module: this.name });
20
+
21
+ onHistoryAdd = async (historyObj = {}) => {
22
+ if (this.isLoadInProcess) return;
23
+
24
+ const [state, uid] = await Promise.all([this.emitOne(this.EVENTS.STATE.GET), this.emitOne(this.EVENTS.VENDORS.UID)]);
25
+
26
+ this.emit(this.EVENTS.LOGS.EMIT, { module: this.name, value: { action: "add", uid } });
27
+
28
+ await this.emit(this.EVENTS.MEMORY.SET, { module: this.name, key: uid, value: state });
29
+
30
+ this.state.history.push({ uid, ...historyObj });
31
+
32
+ if (this.state.history.length > this.PARAMS.HISTORY.MAX_LENGTH)
33
+ this.state.history = this.state.history.slice(this.state.history.length - this.PARAMS.HISTORY.MAX_LENGTH, this.state.history.length);
34
+
35
+ this.updateHistoryKeys();
36
+ };
37
+ onHistoryLoad = async ({ uid } = {}) => {
38
+ this.isLoadInProcess = true;
39
+
40
+ this.emit(this.EVENTS.LOGS.EMIT, { module: this.name, value: { action: "load start", uid } });
41
+
42
+ const state = await this.emitOne(this.EVENTS.HISTORY.GET, { uid });
43
+
44
+ if (!state) return void this.emit(this.EVENTS.LOGS.EMIT, { module: this.name, value: { action: "load deleted", uid } });
45
+
46
+ await this.emit(this.EVENTS.STATE.LOAD, await this.emitOne(this.EVENTS.VENDORS.CLONE, state));
47
+
48
+ this.emit(this.EVENTS.SCENARIO.LABEL_GET, { label: state.scenario.label });
49
+
50
+ this.isLoadInProcess = false;
51
+
52
+ this.emit(this.EVENTS.LOGS.EMIT, { module: this.name, value: { action: "load end", uid } });
53
+
54
+ this.updateHistoryKeys();
55
+ };
56
+ onHistoryBack = () =>
57
+ !this.isLoadInProcess && this.state.history.length && this.emit(this.EVENTS.HISTORY.LOAD, { uid: this.state.history[this.state.history.length - 1].uid });
58
+ onHistoryKeys = () => this.emitOne(this.EVENTS.MEMORY.KEYS, { module: this.name });
59
+ onHistoryGet = ({ uid = "" } = {}) => this.emitOne(this.EVENTS.MEMORY.GET, { module: this.name, key: uid });
60
+
61
+ onStateSet = async ({ [this.name]: state } = {}) => this.setState(await this.emitOne(this.EVENTS.VENDORS.CLONE, state));
62
+
63
+ updateHistoryKeys = () => Promise.all(this.state.history.map(({ uid = "" } = {}) => this.emitOne(this.EVENTS.HISTORY.GET, { uid })));
64
+
65
+ getDefaultState = () => ({ history: [] });
66
+ }
@@ -0,0 +1,14 @@
1
+ import { ModuleView } from "@vnejs/module.components";
2
+
3
+ import { render } from "../view";
4
+
5
+ export class HistoryView extends ModuleView {
6
+ name = "history.view";
7
+
8
+ locLabel = this.PARAMS.HISTORY.LOC_LABEL;
9
+ animationTime = this.PARAMS.HISTORY.TRANSITION;
10
+ updateEvent = this.EVENTS.HISTORY.UPDATE;
11
+
12
+ renderFunc = render;
13
+ updateHandler = this.onUpdateStoreComponent;
14
+ }
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@vnejs/plugins.views.screens.history",
3
+ "version": "0.1.8",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1",
7
+ "publish:major:plugin": "npm run publish:major",
8
+ "publish:minor:plugin": "npm run publish:minor",
9
+ "publish:patch:plugin": "npm run publish:patch",
10
+ "publish:major": "npm version major && npm publish --access public",
11
+ "publish:minor": "npm version minor && npm publish --access public",
12
+ "publish:patch": "npm version patch && npm publish --access public"
13
+ },
14
+ "author": "",
15
+ "license": "ISC",
16
+ "description": ""
17
+ }
@@ -0,0 +1,15 @@
1
+ import { useCallback, useMemo } from "react";
2
+
3
+ import { PositionBox, Text } from "@vnejs/uis.react";
4
+
5
+ export const HistoryClose = ({ locs = {}, ...props } = {}) => {
6
+ const onClick = useCallback(() => props.emit(props.EVENTS.HISTORY.HIDE), []);
7
+
8
+ const propsText = useMemo(() => ({ ...props.PARAMS.HISTORY.VIEW_PROPS.close.text, text: locs.back, onClick }), [locs]);
9
+
10
+ return (
11
+ <PositionBox {...props.PARAMS.HISTORY.VIEW_PROPS.close.position}>
12
+ <Text {...propsText} />
13
+ </PositionBox>
14
+ );
15
+ };
@@ -0,0 +1,53 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+
3
+ import { PositionBox, Text, TextControls } from "@vnejs/uis.react";
4
+
5
+ const scrollToBottom = (scrollbarWrapRef) => {
6
+ if (!scrollbarWrapRef.current) return requestAnimationFrame(() => scrollToBottom(scrollbarWrapRef));
7
+ if (scrollbarWrapRef.current.clientHeight === scrollbarWrapRef.current.scrollHeight || scrollbarWrapRef.current.scrollTop !== 0) return;
8
+
9
+ scrollbarWrapRef.current.scrollTop = 9999999;
10
+ requestAnimationFrame(() => scrollToBottom(scrollbarWrapRef));
11
+ };
12
+
13
+ export const HistoryLines = ({ isShow = false, history = [], currentItem = null, historyLocs = [], historyKeys = [], locs = {}, ...props } = {}) => {
14
+ const scrollbarWrapRef = useRef(null);
15
+
16
+ const onClick = useCallback((uid) => historyKeys.includes(uid) && props.emit(props.EVENTS.HISTORY.CLICK, { uid }), [historyKeys]);
17
+
18
+ const mapTexts = useCallback(
19
+ ({ text, uid, speaker, meet }, i) => {
20
+ const speakers = props.PARAMS.TEXT.SPEAKERS_INFO;
21
+
22
+ const { speakerColor = "white" } = speakers[speaker] || speakers.default;
23
+ const speakerName = locs[`speaker.${speaker}.${meet}`];
24
+
25
+ return {
26
+ text: (historyLocs && historyLocs[i]) || text,
27
+ value: uid,
28
+ textPrefix: speakerName ? `${speakerName}: ` : undefined,
29
+ colorPrefix: speakerColor,
30
+ weightPrefix: Text.WEIGHT.BOLD,
31
+ isHoverable: Boolean(historyKeys.find((key) => key === uid)),
32
+ };
33
+ },
34
+ [historyLocs, historyKeys],
35
+ );
36
+
37
+ useEffect(() => {
38
+ if (isShow) requestAnimationFrame(() => scrollToBottom(scrollbarWrapRef));
39
+ }, [isShow]);
40
+
41
+ const texts = useMemo(() => history.map(mapTexts), [history, mapTexts]);
42
+
43
+ const propsView = props.PARAMS.HISTORY.VIEW_PROPS.lines;
44
+
45
+ const propsControlsCommon = useMemo(() => ({ ...propsView.controls, onClick, scrollbarWrapRef }), [scrollbarWrapRef]);
46
+ const propsControls = useMemo(() => ({ ...propsControlsCommon, texts, selectedIndex: currentItem }), [texts, currentItem]);
47
+
48
+ return (
49
+ <PositionBox {...propsView.position}>
50
+ <TextControls {...propsControls} />
51
+ </PositionBox>
52
+ );
53
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./HistoryClose";
2
+ export * from "./HistoryLines";
package/view/index.jsx ADDED
@@ -0,0 +1,27 @@
1
+ import { useEffect, useMemo, useState } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+
4
+ import { Screen } from "@vnejs/uis.react";
5
+
6
+ import { HistoryClose, HistoryLines } from "./components";
7
+
8
+ const History = ({ store, onMount, ...props } = {}) => {
9
+ const [{ isShow = false, isForce = false, locs = {}, history = [], historyLocs = [], historyKeys = [], currentItem = null }, setState] = useState({});
10
+
11
+ useEffect(() => store.subscribe(setState), []);
12
+ useEffect(() => void onMount(), []);
13
+
14
+ const propsScreen = useMemo(() => ({ ...props.PARAMS.HISTORY.VIEW_PROPS.screen, isShow, isForce }), [isShow, isForce]);
15
+ const propsHistory = useMemo(() => ({ history, historyLocs, historyKeys }), [history, historyLocs, historyKeys]);
16
+ const propsLines = useMemo(() => ({ ...props, ...propsHistory, isShow, currentItem, locs }), [propsHistory, isShow, currentItem, locs]);
17
+ const propsClose = useMemo(() => ({ ...props, locs }), [locs]);
18
+
19
+ return (
20
+ <Screen {...propsScreen}>
21
+ <HistoryLines {...propsLines} />
22
+ <HistoryClose {...propsClose} />
23
+ </Screen>
24
+ );
25
+ };
26
+
27
+ export const render = (props, root) => createRoot(root).render(<History {...props} />);