fractostate 1.0.2 → 2.0.0
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/cjs/src/index.js +90 -21
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/esm/src/index.js +90 -22
- package/dist/esm/src/index.js.map +1 -1
- package/dist/index.d.ts +71 -25
- package/package.json +6 -15
package/dist/cjs/src/index.js
CHANGED
|
@@ -4,33 +4,93 @@ var react = require('react');
|
|
|
4
4
|
var store = require('./store.js');
|
|
5
5
|
var proxy = require('./proxy.js');
|
|
6
6
|
|
|
7
|
+
/***************************************************************************
|
|
8
|
+
* FractoState - Fast And Secure
|
|
9
|
+
*
|
|
10
|
+
* @author Nehonix
|
|
11
|
+
* @license NOSL
|
|
12
|
+
*
|
|
13
|
+
* Copyright (c) 2025 Nehonix. All rights reserved.
|
|
14
|
+
*
|
|
15
|
+
* This License governs the use, modification, and distribution of software
|
|
16
|
+
* provided by NEHONIX under its open source projects.
|
|
17
|
+
* NEHONIX is committed to fostering collaborative innovation while strictly
|
|
18
|
+
* protecting its intellectual property rights.
|
|
19
|
+
* Violation of any term of this License will result in immediate termination of all granted rights
|
|
20
|
+
* and may subject the violator to legal action.
|
|
21
|
+
*
|
|
22
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
23
|
+
* INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
24
|
+
* AND NON-INFRINGEMENT.
|
|
25
|
+
* IN NO EVENT SHALL NEHONIX BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
26
|
+
* OR CONSEQUENTIAL DAMAGES ARISING FROM THE USE OR INABILITY TO USE THE SOFTWARE,
|
|
27
|
+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
28
|
+
*
|
|
29
|
+
***************************************************************************** */
|
|
30
|
+
/**
|
|
31
|
+
* Defines a derived flow that automatically updates based on a source flow.
|
|
32
|
+
* No store registration happens here; it's purely a definition for the hook.
|
|
33
|
+
*/
|
|
34
|
+
function defineDerived(source, selector, derivedKey) {
|
|
35
|
+
return {
|
|
36
|
+
key: derivedKey || `${source.key}_derived_${Date.now()}`,
|
|
37
|
+
source,
|
|
38
|
+
selector,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
7
41
|
/**
|
|
8
42
|
* Defines a flow in a centralized manner.
|
|
9
43
|
* Allows defining the key, initial state, and options in a single reusable object.
|
|
10
44
|
*/
|
|
11
45
|
function defineFlow(key, initial, options) {
|
|
46
|
+
// If generic T is provided manually but A is not, we want A to be inferred from options
|
|
47
|
+
// However, explicit generics override inference.
|
|
48
|
+
// The user should ideally use `defineFlow('key', { ...initial }, { actions: ... })`
|
|
49
|
+
// without explicit generics to get full inference.
|
|
50
|
+
// Or provide both. This signature supports both but relies on inference for best DX.
|
|
12
51
|
return { key, initial, options };
|
|
13
52
|
}
|
|
14
|
-
|
|
15
|
-
* Unique "All-in-One" hook to create or consume a FractoState flow.
|
|
16
|
-
* - If called with a FlowDefinition or an initial value: initializes the flow if it doesn't exist.
|
|
17
|
-
* - If called with just a key: connects to the existing flow.
|
|
18
|
-
*
|
|
19
|
-
* Returns a 2-element array: [state, toolbox]
|
|
20
|
-
* where toolbox contains { ops, set, undo, redo, history, ... }
|
|
21
|
-
*/
|
|
53
|
+
// --- Implementation ---
|
|
22
54
|
function useFlow(keyOrDef, maybeInitialValue, options = {}) {
|
|
23
|
-
//
|
|
55
|
+
// 1. Identify if we are dealing with a Derived Flow
|
|
56
|
+
const isDerived = typeof keyOrDef === "object" &&
|
|
57
|
+
"selector" in keyOrDef &&
|
|
58
|
+
"source" in keyOrDef;
|
|
59
|
+
// --- Logic for DERIVED Flows (Read-Only Reactive) ---
|
|
60
|
+
if (isDerived) {
|
|
61
|
+
const derivedDef = keyOrDef;
|
|
62
|
+
const sourceKey = derivedDef.source.key;
|
|
63
|
+
const selector = derivedDef.selector;
|
|
64
|
+
const getSourceState = () => store.store.get(sourceKey, derivedDef.source.initial);
|
|
65
|
+
// Initial derived state
|
|
66
|
+
const [derivedState, setDerivedState] = react.useState(() => selector(getSourceState()));
|
|
67
|
+
react.useEffect(() => {
|
|
68
|
+
const unsub = store.store.subscribe(sourceKey, () => {
|
|
69
|
+
const nextSource = getSourceState();
|
|
70
|
+
const nextDerived = selector(nextSource);
|
|
71
|
+
setDerivedState((prev) => {
|
|
72
|
+
if (prev === nextDerived)
|
|
73
|
+
return prev;
|
|
74
|
+
return nextDerived;
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
return unsub;
|
|
78
|
+
}, [sourceKey, selector]);
|
|
79
|
+
return [derivedState, {}];
|
|
80
|
+
}
|
|
81
|
+
// --- Logic for STANDARD Flows (Read-Write) ---
|
|
24
82
|
const isDef = typeof keyOrDef !== "string";
|
|
25
|
-
const key = isDef
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
83
|
+
const key = isDef
|
|
84
|
+
? keyOrDef.key
|
|
85
|
+
: keyOrDef;
|
|
86
|
+
const initialValue = isDef
|
|
87
|
+
? keyOrDef.initial
|
|
88
|
+
: maybeInitialValue;
|
|
89
|
+
const opt = isDef
|
|
90
|
+
? { ...keyOrDef.options, ...options }
|
|
91
|
+
: options;
|
|
31
92
|
const [state, setState] = react.useState(() => store.store.get(key, initialValue));
|
|
32
93
|
react.useEffect(() => {
|
|
33
|
-
// Subscribe to store changes
|
|
34
94
|
const unsub = store.store.subscribe(key, () => {
|
|
35
95
|
setState(store.store.get(key, initialValue));
|
|
36
96
|
});
|
|
@@ -42,12 +102,20 @@ function useFlow(keyOrDef, maybeInitialValue, options = {}) {
|
|
|
42
102
|
store.store.set(key, next, opt);
|
|
43
103
|
}, [key, initialValue, opt]);
|
|
44
104
|
const toolbox = react.useMemo(() => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
get
|
|
48
|
-
return proxy.createDeepProxy(key, [], store.store.get(key, initialValue), opt);
|
|
49
|
-
},
|
|
105
|
+
const defaultOps = {
|
|
106
|
+
get self() {
|
|
107
|
+
return proxy.createDeepProxy(key, [], store.store.get(key, initialValue), opt);
|
|
50
108
|
},
|
|
109
|
+
};
|
|
110
|
+
const boundActions = {};
|
|
111
|
+
if (opt.actions) {
|
|
112
|
+
for (const [actionName, actionFn] of Object.entries(opt.actions)) {
|
|
113
|
+
boundActions[actionName] = (...args) => actionFn(defaultOps, ...args);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
ops: defaultOps,
|
|
118
|
+
actions: boundActions,
|
|
51
119
|
set: setManual,
|
|
52
120
|
undo: () => store.store.undo(key),
|
|
53
121
|
redo: () => store.store.redo(key),
|
|
@@ -61,6 +129,7 @@ function useFlow(keyOrDef, maybeInitialValue, options = {}) {
|
|
|
61
129
|
return [state, toolbox];
|
|
62
130
|
}
|
|
63
131
|
|
|
132
|
+
exports.defineDerived = defineDerived;
|
|
64
133
|
exports.defineFlow = defineFlow;
|
|
65
134
|
exports.useFlow = useFlow;
|
|
66
135
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useMemo } from \"react\";\nimport type { FlowOptions, FlowOperations, FlowDefinition } from \"./types\";\nimport { store } from \"./store\";\nimport { createDeepProxy } from \"./proxy\";\n\nexport * from \"./types\";\n\n/**\n * Defines a flow in a centralized manner.\n * Allows defining the key, initial state, and options in a single reusable object.\n */\nexport function defineFlow<T>(\n key: string,\n initial: T,\n options?: FlowOptions<T>,\n): FlowDefinition<T> {\n return { key, initial, options };\n}\n\n/**\n * Unique \"All-in-One\" hook to create or consume a FractoState flow.\n * - If called with a FlowDefinition or an initial value: initializes the flow if it doesn't exist.\n * - If called with just a key: connects to the existing flow.\n *\n * Returns a 2-element array: [state, toolbox]\n * where toolbox contains { ops, set, undo, redo, history, ... }\n */\nexport function useFlow<T>(\n keyOrDef: string | FlowDefinition<T>,\n maybeInitialValue?: T,\n options: FlowOptions<T> = {},\n): [T, FlowOperations<T>] {\n // Argument analysis to unify initialization and consumption\n const isDef = typeof keyOrDef !== \"string\";\n const key = isDef ? keyOrDef.key : keyOrDef;\n\n // Initial data comes either from the definition or the direct argument\n const initialValue = isDef ? keyOrDef.initial : maybeInitialValue;\n\n // Merge options\n const opt = isDef ? { ...keyOrDef.options, ...options } : options;\n\n // Store access: store.get handles initialization if initialValue is present\n const [state, setState] = useState(() => store.get(key, initialValue));\n\n useEffect(() => {\n // Subscribe to store changes\n const unsub = store.subscribe(key, () => {\n setState(store.get(key, initialValue));\n });\n return unsub;\n }, [key, initialValue]);\n\n const setManual = useCallback(\n (val: T | ((prev: T) => T)) => {\n const current = store.get(key, initialValue);\n const next = typeof val === \"function\" ? (val as any)(current) : val;\n store.set(key, next, opt);\n },\n [key, initialValue, opt],\n );\n\n const toolbox = useMemo((): FlowOperations<T> => {\n return {\n ops: {\n get self() {\n return createDeepProxy<T>(key, [], store.get(key, initialValue), opt);\n },\n },\n set: setManual,\n undo: () => store.undo(key),\n redo: () => store.redo(key),\n history: store.getHistory(key),\n canUndo: store.getHistory(key).length > 1,\n canRedo: store.getRedoStack(key).length > 0,\n reset: () => store.reset(key),\n cf: opt,\n };\n }, [key, opt, state, initialValue, setManual]);\n\n return [state, toolbox];\n}\n"],"names":["useState","store","useEffect","useCallback","useMemo","createDeepProxy"],"mappings":";;;;;;AAOA;;;AAGG;SACa,UAAU,CACxB,GAAW,EACX,OAAU,EACV,OAAwB,EAAA;AAExB,IAAA,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;AAClC;AAEA;;;;;;;AAOG;AACG,SAAU,OAAO,CACrB,QAAoC,EACpC,iBAAqB,EACrB,UAA0B,EAAE,EAAA;;AAG5B,IAAA,MAAM,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ;AAC1C,IAAA,MAAM,GAAG,GAAG,KAAK,GAAG,QAAQ,CAAC,GAAG,GAAG,QAAQ;;AAG3C,IAAA,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,CAAC,OAAO,GAAG,iBAAiB;;AAGjE,IAAA,MAAM,GAAG,GAAG,KAAK,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO;;IAGjE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAGA,cAAQ,CAAC,MAAMC,WAAK,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAEtEC,eAAS,CAAC,MAAK;;QAEb,MAAM,KAAK,GAAGD,WAAK,CAAC,SAAS,CAAC,GAAG,EAAE,MAAK;YACtC,QAAQ,CAACA,WAAK,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;AACxC,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,KAAK;AACd,IAAA,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;AAEvB,IAAA,MAAM,SAAS,GAAGE,iBAAW,CAC3B,CAAC,GAAyB,KAAI;QAC5B,MAAM,OAAO,GAAGF,WAAK,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC;AAC5C,QAAA,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,UAAU,GAAI,GAAW,CAAC,OAAO,CAAC,GAAG,GAAG;QACpEA,WAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC;IAC3B,CAAC,EACD,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,CAAC,CACzB;AAED,IAAA,MAAM,OAAO,GAAGG,aAAO,CAAC,MAAwB;QAC9C,OAAO;AACL,YAAA,GAAG,EAAE;AACH,gBAAA,IAAI,IAAI,GAAA;AACN,oBAAA,OAAOC,qBAAe,CAAI,GAAG,EAAE,EAAE,EAAEJ,WAAK,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,GAAG,CAAC;gBACvE,CAAC;AACF,aAAA;AACD,YAAA,GAAG,EAAE,SAAS;YACd,IAAI,EAAE,MAAMA,WAAK,CAAC,IAAI,CAAC,GAAG,CAAC;YAC3B,IAAI,EAAE,MAAMA,WAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AAC3B,YAAA,OAAO,EAAEA,WAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAC9B,OAAO,EAAEA,WAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;YACzC,OAAO,EAAEA,WAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;YAC3C,KAAK,EAAE,MAAMA,WAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,YAAA,EAAE,EAAE,GAAG;SACR;AACH,IAAA,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;AAE9C,IAAA,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;AACzB;;;;;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":["/***************************************************************************\n * FractoState - Fast And Secure\n *\n * @author Nehonix\n * @license NOSL\n *\n * Copyright (c) 2025 Nehonix. All rights reserved.\n *\n * This License governs the use, modification, and distribution of software\n * provided by NEHONIX under its open source projects.\n * NEHONIX is committed to fostering collaborative innovation while strictly\n * protecting its intellectual property rights.\n * Violation of any term of this License will result in immediate termination of all granted rights\n * and may subject the violator to legal action.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,\n * AND NON-INFRINGEMENT.\n * IN NO EVENT SHALL NEHONIX BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n * OR CONSEQUENTIAL DAMAGES ARISING FROM THE USE OR INABILITY TO USE THE SOFTWARE,\n * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n *\n ***************************************************************************** */\n\nimport { useState, useEffect, useCallback, useMemo } from \"react\";\nimport type {\n FlowOptions,\n FlowOperations,\n FlowDefinition,\n FlowAction,\n} from \"./types\";\nimport { store } from \"./store\";\nimport { createDeepProxy } from \"./proxy\";\n\nexport * from \"./types\";\n\n// --- New feature: Derived Flows ---\n\nexport interface DerivedFlowDefinition<T, R> {\n key: string;\n source: FlowDefinition<T, any>; // The source flow\n selector: (state: T) => R; // The computation logic\n options?: any;\n}\n\n/**\n * Defines a derived flow that automatically updates based on a source flow.\n * No store registration happens here; it's purely a definition for the hook.\n */\nexport function defineDerived<T, R>(\n source: FlowDefinition<T, any>,\n selector: (state: T) => R,\n derivedKey?: string,\n): DerivedFlowDefinition<T, R> {\n return {\n key: derivedKey || `${source.key}_derived_${Date.now()}`,\n source,\n selector,\n };\n}\n\n/**\n * Defines a flow in a centralized manner.\n * Allows defining the key, initial state, and options in a single reusable object.\n */\nexport function defineFlow<T, A extends Record<string, FlowAction<T>> = {}>(\n key: string,\n initial: T,\n options?: FlowOptions<T, A>,\n): FlowDefinition<T, A> {\n // If generic T is provided manually but A is not, we want A to be inferred from options\n // However, explicit generics override inference.\n // The user should ideally use `defineFlow('key', { ...initial }, { actions: ... })`\n // without explicit generics to get full inference.\n // Or provide both. This signature supports both but relies on inference for best DX.\n return { key, initial, options };\n}\n\n// --- 1. Overload for DERIVED Flows (Read-Only) ---\nexport function useFlow<T, R>(derivedDef: DerivedFlowDefinition<T, R>): [R, {}];\n\n// --- 2. Overload for STANDARD Flows (Read-Write) ---\nexport function useFlow<\n T,\n A extends Record<string, FlowAction<T>> = Record<string, FlowAction<T>>,\n>(\n keyOrDef: string | FlowDefinition<T, A>,\n maybeInitialValue?: T,\n options?: FlowOptions<T, A>,\n): [T, FlowOperations<T, A>];\n\n// --- Implementation ---\nexport function useFlow<\n T,\n A extends Record<string, FlowAction<T>> = Record<string, FlowAction<T>>,\n R = T,\n>(\n keyOrDef: string | FlowDefinition<T, A> | DerivedFlowDefinition<any, R>,\n maybeInitialValue?: T,\n options: FlowOptions<T, A> = {},\n): [R extends T ? T : R, Partial<FlowOperations<T, A>>] {\n // 1. Identify if we are dealing with a Derived Flow\n const isDerived =\n typeof keyOrDef === \"object\" &&\n \"selector\" in keyOrDef &&\n \"source\" in keyOrDef;\n\n // --- Logic for DERIVED Flows (Read-Only Reactive) ---\n if (isDerived) {\n const derivedDef = keyOrDef as DerivedFlowDefinition<any, R>;\n const sourceKey = derivedDef.source.key;\n const selector = derivedDef.selector;\n\n const getSourceState = () =>\n store.get(sourceKey, derivedDef.source.initial);\n\n // Initial derived state\n const [derivedState, setDerivedState] = useState(() =>\n selector(getSourceState()),\n );\n\n useEffect(() => {\n const unsub = store.subscribe(sourceKey, () => {\n const nextSource = getSourceState();\n const nextDerived = selector(nextSource);\n setDerivedState((prev) => {\n if (prev === nextDerived) return prev;\n return nextDerived;\n });\n });\n return unsub;\n }, [sourceKey, selector]);\n\n return [derivedState as any, {}];\n }\n\n // --- Logic for STANDARD Flows (Read-Write) ---\n const isDef = typeof keyOrDef !== \"string\";\n const key = isDef\n ? (keyOrDef as FlowDefinition<T, A>).key\n : (keyOrDef as string);\n\n const initialValue = isDef\n ? (keyOrDef as FlowDefinition<T, A>).initial\n : maybeInitialValue;\n\n const opt: FlowOptions<T, A> = isDef\n ? { ...(keyOrDef as FlowDefinition<T, A>).options, ...options }\n : options;\n\n const [state, setState] = useState(() => store.get(key, initialValue));\n\n useEffect(() => {\n const unsub = store.subscribe(key, () => {\n setState(store.get(key, initialValue));\n });\n return unsub;\n }, [key, initialValue]);\n\n const setManual = useCallback(\n (val: T | ((prev: T) => T)) => {\n const current = store.get(key, initialValue);\n const next = typeof val === \"function\" ? (val as any)(current) : val;\n store.set(key, next, opt);\n },\n [key, initialValue, opt],\n );\n\n const toolbox = useMemo((): FlowOperations<T, A> => {\n const defaultOps = {\n get self() {\n return createDeepProxy<T>(key, [], store.get(key, initialValue), opt);\n },\n };\n\n const boundActions = {} as any;\n if (opt.actions) {\n for (const [actionName, actionFn] of Object.entries(opt.actions)) {\n boundActions[actionName] = (...args: any[]) =>\n (actionFn as Function)(defaultOps as any, ...args);\n }\n }\n\n return {\n ops: defaultOps,\n actions: boundActions,\n set: setManual,\n undo: () => store.undo(key),\n redo: () => store.redo(key),\n history: store.getHistory(key),\n canUndo: store.getHistory(key).length > 1,\n canRedo: store.getRedoStack(key).length > 0,\n reset: () => store.reset(key),\n cf: opt,\n };\n }, [key, opt, state, initialValue, setManual]);\n\n return [state as any, toolbox];\n}\n"],"names":["store","useState","useEffect","useCallback","useMemo","createDeepProxy"],"mappings":"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"}
|
package/dist/esm/src/index.js
CHANGED
|
@@ -2,33 +2,93 @@ import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
|
2
2
|
import { store } from './store.js';
|
|
3
3
|
import { createDeepProxy } from './proxy.js';
|
|
4
4
|
|
|
5
|
+
/***************************************************************************
|
|
6
|
+
* FractoState - Fast And Secure
|
|
7
|
+
*
|
|
8
|
+
* @author Nehonix
|
|
9
|
+
* @license NOSL
|
|
10
|
+
*
|
|
11
|
+
* Copyright (c) 2025 Nehonix. All rights reserved.
|
|
12
|
+
*
|
|
13
|
+
* This License governs the use, modification, and distribution of software
|
|
14
|
+
* provided by NEHONIX under its open source projects.
|
|
15
|
+
* NEHONIX is committed to fostering collaborative innovation while strictly
|
|
16
|
+
* protecting its intellectual property rights.
|
|
17
|
+
* Violation of any term of this License will result in immediate termination of all granted rights
|
|
18
|
+
* and may subject the violator to legal action.
|
|
19
|
+
*
|
|
20
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
21
|
+
* INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
22
|
+
* AND NON-INFRINGEMENT.
|
|
23
|
+
* IN NO EVENT SHALL NEHONIX BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
24
|
+
* OR CONSEQUENTIAL DAMAGES ARISING FROM THE USE OR INABILITY TO USE THE SOFTWARE,
|
|
25
|
+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
26
|
+
*
|
|
27
|
+
***************************************************************************** */
|
|
28
|
+
/**
|
|
29
|
+
* Defines a derived flow that automatically updates based on a source flow.
|
|
30
|
+
* No store registration happens here; it's purely a definition for the hook.
|
|
31
|
+
*/
|
|
32
|
+
function defineDerived(source, selector, derivedKey) {
|
|
33
|
+
return {
|
|
34
|
+
key: derivedKey || `${source.key}_derived_${Date.now()}`,
|
|
35
|
+
source,
|
|
36
|
+
selector,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
5
39
|
/**
|
|
6
40
|
* Defines a flow in a centralized manner.
|
|
7
41
|
* Allows defining the key, initial state, and options in a single reusable object.
|
|
8
42
|
*/
|
|
9
43
|
function defineFlow(key, initial, options) {
|
|
44
|
+
// If generic T is provided manually but A is not, we want A to be inferred from options
|
|
45
|
+
// However, explicit generics override inference.
|
|
46
|
+
// The user should ideally use `defineFlow('key', { ...initial }, { actions: ... })`
|
|
47
|
+
// without explicit generics to get full inference.
|
|
48
|
+
// Or provide both. This signature supports both but relies on inference for best DX.
|
|
10
49
|
return { key, initial, options };
|
|
11
50
|
}
|
|
12
|
-
|
|
13
|
-
* Unique "All-in-One" hook to create or consume a FractoState flow.
|
|
14
|
-
* - If called with a FlowDefinition or an initial value: initializes the flow if it doesn't exist.
|
|
15
|
-
* - If called with just a key: connects to the existing flow.
|
|
16
|
-
*
|
|
17
|
-
* Returns a 2-element array: [state, toolbox]
|
|
18
|
-
* where toolbox contains { ops, set, undo, redo, history, ... }
|
|
19
|
-
*/
|
|
51
|
+
// --- Implementation ---
|
|
20
52
|
function useFlow(keyOrDef, maybeInitialValue, options = {}) {
|
|
21
|
-
//
|
|
53
|
+
// 1. Identify if we are dealing with a Derived Flow
|
|
54
|
+
const isDerived = typeof keyOrDef === "object" &&
|
|
55
|
+
"selector" in keyOrDef &&
|
|
56
|
+
"source" in keyOrDef;
|
|
57
|
+
// --- Logic for DERIVED Flows (Read-Only Reactive) ---
|
|
58
|
+
if (isDerived) {
|
|
59
|
+
const derivedDef = keyOrDef;
|
|
60
|
+
const sourceKey = derivedDef.source.key;
|
|
61
|
+
const selector = derivedDef.selector;
|
|
62
|
+
const getSourceState = () => store.get(sourceKey, derivedDef.source.initial);
|
|
63
|
+
// Initial derived state
|
|
64
|
+
const [derivedState, setDerivedState] = useState(() => selector(getSourceState()));
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const unsub = store.subscribe(sourceKey, () => {
|
|
67
|
+
const nextSource = getSourceState();
|
|
68
|
+
const nextDerived = selector(nextSource);
|
|
69
|
+
setDerivedState((prev) => {
|
|
70
|
+
if (prev === nextDerived)
|
|
71
|
+
return prev;
|
|
72
|
+
return nextDerived;
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
return unsub;
|
|
76
|
+
}, [sourceKey, selector]);
|
|
77
|
+
return [derivedState, {}];
|
|
78
|
+
}
|
|
79
|
+
// --- Logic for STANDARD Flows (Read-Write) ---
|
|
22
80
|
const isDef = typeof keyOrDef !== "string";
|
|
23
|
-
const key = isDef
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
81
|
+
const key = isDef
|
|
82
|
+
? keyOrDef.key
|
|
83
|
+
: keyOrDef;
|
|
84
|
+
const initialValue = isDef
|
|
85
|
+
? keyOrDef.initial
|
|
86
|
+
: maybeInitialValue;
|
|
87
|
+
const opt = isDef
|
|
88
|
+
? { ...keyOrDef.options, ...options }
|
|
89
|
+
: options;
|
|
29
90
|
const [state, setState] = useState(() => store.get(key, initialValue));
|
|
30
91
|
useEffect(() => {
|
|
31
|
-
// Subscribe to store changes
|
|
32
92
|
const unsub = store.subscribe(key, () => {
|
|
33
93
|
setState(store.get(key, initialValue));
|
|
34
94
|
});
|
|
@@ -40,12 +100,20 @@ function useFlow(keyOrDef, maybeInitialValue, options = {}) {
|
|
|
40
100
|
store.set(key, next, opt);
|
|
41
101
|
}, [key, initialValue, opt]);
|
|
42
102
|
const toolbox = useMemo(() => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
get
|
|
46
|
-
return createDeepProxy(key, [], store.get(key, initialValue), opt);
|
|
47
|
-
},
|
|
103
|
+
const defaultOps = {
|
|
104
|
+
get self() {
|
|
105
|
+
return createDeepProxy(key, [], store.get(key, initialValue), opt);
|
|
48
106
|
},
|
|
107
|
+
};
|
|
108
|
+
const boundActions = {};
|
|
109
|
+
if (opt.actions) {
|
|
110
|
+
for (const [actionName, actionFn] of Object.entries(opt.actions)) {
|
|
111
|
+
boundActions[actionName] = (...args) => actionFn(defaultOps, ...args);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
ops: defaultOps,
|
|
116
|
+
actions: boundActions,
|
|
49
117
|
set: setManual,
|
|
50
118
|
undo: () => store.undo(key),
|
|
51
119
|
redo: () => store.redo(key),
|
|
@@ -59,5 +127,5 @@ function useFlow(keyOrDef, maybeInitialValue, options = {}) {
|
|
|
59
127
|
return [state, toolbox];
|
|
60
128
|
}
|
|
61
129
|
|
|
62
|
-
export { defineFlow, useFlow };
|
|
130
|
+
export { defineDerived, defineFlow, useFlow };
|
|
63
131
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":["/***************************************************************************\n * FractoState - Fast And Secure\n *\n * @author Nehonix\n * @license NOSL\n *\n * Copyright (c) 2025 Nehonix. All rights reserved.\n *\n * This License governs the use, modification, and distribution of software\n * provided by NEHONIX under its open source projects.\n * NEHONIX is committed to fostering collaborative innovation while strictly\n * protecting its intellectual property rights.\n * Violation of any term of this License will result in immediate termination of all granted rights\n * and may subject the violator to legal action.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,\n * AND NON-INFRINGEMENT.\n * IN NO EVENT SHALL NEHONIX BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n * OR CONSEQUENTIAL DAMAGES ARISING FROM THE USE OR INABILITY TO USE THE SOFTWARE,\n * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n *\n ***************************************************************************** */\n\nimport { useState, useEffect, useCallback, useMemo } from \"react\";\nimport type {\n FlowOptions,\n FlowOperations,\n FlowDefinition,\n FlowAction,\n} from \"./types\";\nimport { store } from \"./store\";\nimport { createDeepProxy } from \"./proxy\";\n\nexport * from \"./types\";\n\n// --- New feature: Derived Flows ---\n\nexport interface DerivedFlowDefinition<T, R> {\n key: string;\n source: FlowDefinition<T, any>; // The source flow\n selector: (state: T) => R; // The computation logic\n options?: any;\n}\n\n/**\n * Defines a derived flow that automatically updates based on a source flow.\n * No store registration happens here; it's purely a definition for the hook.\n */\nexport function defineDerived<T, R>(\n source: FlowDefinition<T, any>,\n selector: (state: T) => R,\n derivedKey?: string,\n): DerivedFlowDefinition<T, R> {\n return {\n key: derivedKey || `${source.key}_derived_${Date.now()}`,\n source,\n selector,\n };\n}\n\n/**\n * Defines a flow in a centralized manner.\n * Allows defining the key, initial state, and options in a single reusable object.\n */\nexport function defineFlow<T, A extends Record<string, FlowAction<T>> = {}>(\n key: string,\n initial: T,\n options?: FlowOptions<T, A>,\n): FlowDefinition<T, A> {\n // If generic T is provided manually but A is not, we want A to be inferred from options\n // However, explicit generics override inference.\n // The user should ideally use `defineFlow('key', { ...initial }, { actions: ... })`\n // without explicit generics to get full inference.\n // Or provide both. This signature supports both but relies on inference for best DX.\n return { key, initial, options };\n}\n\n// --- 1. Overload for DERIVED Flows (Read-Only) ---\nexport function useFlow<T, R>(derivedDef: DerivedFlowDefinition<T, R>): [R, {}];\n\n// --- 2. Overload for STANDARD Flows (Read-Write) ---\nexport function useFlow<\n T,\n A extends Record<string, FlowAction<T>> = Record<string, FlowAction<T>>,\n>(\n keyOrDef: string | FlowDefinition<T, A>,\n maybeInitialValue?: T,\n options?: FlowOptions<T, A>,\n): [T, FlowOperations<T, A>];\n\n// --- Implementation ---\nexport function useFlow<\n T,\n A extends Record<string, FlowAction<T>> = Record<string, FlowAction<T>>,\n R = T,\n>(\n keyOrDef: string | FlowDefinition<T, A> | DerivedFlowDefinition<any, R>,\n maybeInitialValue?: T,\n options: FlowOptions<T, A> = {},\n): [R extends T ? T : R, Partial<FlowOperations<T, A>>] {\n // 1. Identify if we are dealing with a Derived Flow\n const isDerived =\n typeof keyOrDef === \"object\" &&\n \"selector\" in keyOrDef &&\n \"source\" in keyOrDef;\n\n // --- Logic for DERIVED Flows (Read-Only Reactive) ---\n if (isDerived) {\n const derivedDef = keyOrDef as DerivedFlowDefinition<any, R>;\n const sourceKey = derivedDef.source.key;\n const selector = derivedDef.selector;\n\n const getSourceState = () =>\n store.get(sourceKey, derivedDef.source.initial);\n\n // Initial derived state\n const [derivedState, setDerivedState] = useState(() =>\n selector(getSourceState()),\n );\n\n useEffect(() => {\n const unsub = store.subscribe(sourceKey, () => {\n const nextSource = getSourceState();\n const nextDerived = selector(nextSource);\n setDerivedState((prev) => {\n if (prev === nextDerived) return prev;\n return nextDerived;\n });\n });\n return unsub;\n }, [sourceKey, selector]);\n\n return [derivedState as any, {}];\n }\n\n // --- Logic for STANDARD Flows (Read-Write) ---\n const isDef = typeof keyOrDef !== \"string\";\n const key = isDef\n ? (keyOrDef as FlowDefinition<T, A>).key\n : (keyOrDef as string);\n\n const initialValue = isDef\n ? (keyOrDef as FlowDefinition<T, A>).initial\n : maybeInitialValue;\n\n const opt: FlowOptions<T, A> = isDef\n ? { ...(keyOrDef as FlowDefinition<T, A>).options, ...options }\n : options;\n\n const [state, setState] = useState(() => store.get(key, initialValue));\n\n useEffect(() => {\n const unsub = store.subscribe(key, () => {\n setState(store.get(key, initialValue));\n });\n return unsub;\n }, [key, initialValue]);\n\n const setManual = useCallback(\n (val: T | ((prev: T) => T)) => {\n const current = store.get(key, initialValue);\n const next = typeof val === \"function\" ? (val as any)(current) : val;\n store.set(key, next, opt);\n },\n [key, initialValue, opt],\n );\n\n const toolbox = useMemo((): FlowOperations<T, A> => {\n const defaultOps = {\n get self() {\n return createDeepProxy<T>(key, [], store.get(key, initialValue), opt);\n },\n };\n\n const boundActions = {} as any;\n if (opt.actions) {\n for (const [actionName, actionFn] of Object.entries(opt.actions)) {\n boundActions[actionName] = (...args: any[]) =>\n (actionFn as Function)(defaultOps as any, ...args);\n }\n }\n\n return {\n ops: defaultOps,\n actions: boundActions,\n set: setManual,\n undo: () => store.undo(key),\n redo: () => store.redo(key),\n history: store.getHistory(key),\n canUndo: store.getHistory(key).length > 1,\n canRedo: store.getRedoStack(key).length > 0,\n reset: () => store.reset(key),\n cf: opt,\n };\n }, [key, opt, state, initialValue, setManual]);\n\n return [state as any, toolbox];\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
type FlowAction<T> = (ops: {
|
|
2
|
+
self: TypeAwareOps<T>;
|
|
3
|
+
}, ...args: any[]) => any;
|
|
4
|
+
/**
|
|
5
|
+
* Utility type to extract the public signature of actions.
|
|
6
|
+
* It removes the first argument (ops) from each action function.
|
|
7
|
+
*/
|
|
8
|
+
type BoundActions<A> = {
|
|
9
|
+
[K in keyof A]: A[K] extends (ops: any, ...args: infer P) => infer R ? (...args: P) => R : never;
|
|
10
|
+
};
|
|
11
|
+
interface FlowOptions<T = any, A extends Record<string, FlowAction<T>> = {}> {
|
|
2
12
|
/** Enable history tracking for undo/redo functionality */
|
|
3
13
|
timeTravel?: boolean;
|
|
4
14
|
/** Maximum number of states to keep in history (default: 100) */
|
|
@@ -7,6 +17,8 @@ interface FlowOptions<T = any> {
|
|
|
7
17
|
debounce?: number;
|
|
8
18
|
/** Array of functions to transform state before it is saved */
|
|
9
19
|
middleware?: Array<(state: T) => T>;
|
|
20
|
+
/** Custom async actions attached to the flow */
|
|
21
|
+
actions?: A;
|
|
10
22
|
}
|
|
11
23
|
type BaseOps<T> = {
|
|
12
24
|
/** Replaces the entire value at this path */
|
|
@@ -73,20 +85,26 @@ type BooleanOps = BaseOps<boolean> & {
|
|
|
73
85
|
toggle: () => void;
|
|
74
86
|
};
|
|
75
87
|
type TypeAwareOps<T> = T extends number ? NumberOps : T extends string ? StringOps : T extends boolean ? BooleanOps : T extends Array<infer U> ? ArrayOps<U> : T extends object ? ObjectOps<T> : BaseOps<T>;
|
|
76
|
-
|
|
88
|
+
type FlowOpsObject<T> = {
|
|
89
|
+
/**
|
|
90
|
+
* Recursive, type-aware proxy that provides surgical atomic operations
|
|
91
|
+
* tailored to the shape of your state. It allows direct-like manipulation
|
|
92
|
+
* that is internally processed as immutable updates.
|
|
93
|
+
*/
|
|
94
|
+
self: TypeAwareOps<T>;
|
|
95
|
+
};
|
|
96
|
+
interface FlowDefinition<T, A extends Record<string, FlowAction<T>> = {}> {
|
|
77
97
|
key: string;
|
|
78
98
|
initial: T;
|
|
79
|
-
options?: FlowOptions<T>;
|
|
99
|
+
options?: FlowOptions<T, A>;
|
|
80
100
|
}
|
|
81
|
-
interface FlowOperations<T> {
|
|
82
|
-
ops:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
self: TypeAwareOps<T>;
|
|
89
|
-
};
|
|
101
|
+
interface FlowOperations<T, A extends Record<string, FlowAction<T>> = {}> {
|
|
102
|
+
ops: FlowOpsObject<T>;
|
|
103
|
+
/**
|
|
104
|
+
* Custom actions bound to the flow.
|
|
105
|
+
* The 'ops' argument is automatically injected.
|
|
106
|
+
*/
|
|
107
|
+
actions: BoundActions<A>;
|
|
90
108
|
/** Reverts to the previous state in history */
|
|
91
109
|
undo: () => void;
|
|
92
110
|
/** Restores the previously undone state */
|
|
@@ -102,23 +120,51 @@ interface FlowOperations<T> {
|
|
|
102
120
|
/** Restores the state to its initial value */
|
|
103
121
|
reset: () => void;
|
|
104
122
|
/** Current flow configuration options */
|
|
105
|
-
cf: FlowOptions<T>;
|
|
123
|
+
cf: FlowOptions<T, A>;
|
|
106
124
|
}
|
|
107
125
|
|
|
126
|
+
/***************************************************************************
|
|
127
|
+
* FractoState - Fast And Secure
|
|
128
|
+
*
|
|
129
|
+
* @author Nehonix
|
|
130
|
+
* @license NOSL
|
|
131
|
+
*
|
|
132
|
+
* Copyright (c) 2025 Nehonix. All rights reserved.
|
|
133
|
+
*
|
|
134
|
+
* This License governs the use, modification, and distribution of software
|
|
135
|
+
* provided by NEHONIX under its open source projects.
|
|
136
|
+
* NEHONIX is committed to fostering collaborative innovation while strictly
|
|
137
|
+
* protecting its intellectual property rights.
|
|
138
|
+
* Violation of any term of this License will result in immediate termination of all granted rights
|
|
139
|
+
* and may subject the violator to legal action.
|
|
140
|
+
*
|
|
141
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
142
|
+
* INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
143
|
+
* AND NON-INFRINGEMENT.
|
|
144
|
+
* IN NO EVENT SHALL NEHONIX BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
145
|
+
* OR CONSEQUENTIAL DAMAGES ARISING FROM THE USE OR INABILITY TO USE THE SOFTWARE,
|
|
146
|
+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
147
|
+
*
|
|
148
|
+
***************************************************************************** */
|
|
149
|
+
|
|
150
|
+
interface DerivedFlowDefinition<T, R> {
|
|
151
|
+
key: string;
|
|
152
|
+
source: FlowDefinition<T, any>;
|
|
153
|
+
selector: (state: T) => R;
|
|
154
|
+
options?: any;
|
|
155
|
+
}
|
|
108
156
|
/**
|
|
109
|
-
* Defines a flow
|
|
110
|
-
*
|
|
157
|
+
* Defines a derived flow that automatically updates based on a source flow.
|
|
158
|
+
* No store registration happens here; it's purely a definition for the hook.
|
|
111
159
|
*/
|
|
112
|
-
declare function
|
|
160
|
+
declare function defineDerived<T, R>(source: FlowDefinition<T, any>, selector: (state: T) => R, derivedKey?: string): DerivedFlowDefinition<T, R>;
|
|
113
161
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* - If called with just a key: connects to the existing flow.
|
|
117
|
-
*
|
|
118
|
-
* Returns a 2-element array: [state, toolbox]
|
|
119
|
-
* where toolbox contains { ops, set, undo, redo, history, ... }
|
|
162
|
+
* Defines a flow in a centralized manner.
|
|
163
|
+
* Allows defining the key, initial state, and options in a single reusable object.
|
|
120
164
|
*/
|
|
121
|
-
declare function
|
|
165
|
+
declare function defineFlow<T, A extends Record<string, FlowAction<T>> = {}>(key: string, initial: T, options?: FlowOptions<T, A>): FlowDefinition<T, A>;
|
|
166
|
+
declare function useFlow<T, R>(derivedDef: DerivedFlowDefinition<T, R>): [R, {}];
|
|
167
|
+
declare function useFlow<T, A extends Record<string, FlowAction<T>> = Record<string, FlowAction<T>>>(keyOrDef: string | FlowDefinition<T, A>, maybeInitialValue?: T, options?: FlowOptions<T, A>): [T, FlowOperations<T, A>];
|
|
122
168
|
|
|
123
|
-
export { defineFlow, useFlow };
|
|
124
|
-
export type { ArrayOps, BaseOps, BooleanOps, FlowDefinition, FlowOperations, FlowOptions, NumberOps, ObjectOps, StringOps, TypeAwareOps };
|
|
169
|
+
export { defineDerived, defineFlow, useFlow };
|
|
170
|
+
export type { ArrayOps, BaseOps, BooleanOps, BoundActions, DerivedFlowDefinition, FlowAction, FlowDefinition, FlowOperations, FlowOpsObject, FlowOptions, NumberOps, ObjectOps, StringOps, TypeAwareOps };
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
+
"version": "2.0.0",
|
|
2
3
|
"author": {
|
|
3
4
|
"name": "Nehonix",
|
|
4
5
|
"url": "https://nehonix.com",
|
|
@@ -43,18 +44,8 @@
|
|
|
43
44
|
"exports": {
|
|
44
45
|
".": {
|
|
45
46
|
"types": "./dist/index.d.ts",
|
|
46
|
-
"import":
|
|
47
|
-
|
|
48
|
-
"default": "./dist/esm/index.js"
|
|
49
|
-
},
|
|
50
|
-
"require": {
|
|
51
|
-
"types": "./dist/index.d.ts",
|
|
52
|
-
"default": "./dist/cjs/index.js"
|
|
53
|
-
},
|
|
54
|
-
"node": {
|
|
55
|
-
"import": "./dist/esm/index.js",
|
|
56
|
-
"require": "./dist/cjs/index.js"
|
|
57
|
-
},
|
|
47
|
+
"import": "./dist/esm/index.js",
|
|
48
|
+
"require": "./dist/cjs/index.js",
|
|
58
49
|
"default": "./dist/cjs/index.js"
|
|
59
50
|
},
|
|
60
51
|
"./package.json": "./package.json"
|
|
@@ -71,7 +62,7 @@
|
|
|
71
62
|
"build": "rollup -c",
|
|
72
63
|
"dev": "tsup src/index.ts --watch --dts --format esm,cjs",
|
|
73
64
|
"lint": "eslint src",
|
|
74
|
-
"test": "vitest"
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
"test": "vitest",
|
|
66
|
+
"prepublishOnly": "npm run build"
|
|
67
|
+
}
|
|
77
68
|
}
|