quidproquo-web-react 0.0.248 → 0.0.249
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/lib/commonjs/hooks/index.d.ts +3 -0
- package/lib/commonjs/hooks/index.js +3 -0
- package/lib/commonjs/hooks/useBubbleReducer.d.ts +7 -0
- package/lib/commonjs/hooks/useBubbleReducer.js +32 -0
- package/lib/commonjs/hooks/useQpq.d.ts +2 -0
- package/lib/commonjs/hooks/useQpq.js +42 -0
- package/lib/commonjs/hooks/useQpqReducer/actionProcessor/getStateDispatchActionProcessor.d.ts +3 -0
- package/lib/commonjs/hooks/useQpqReducer/actionProcessor/getStateDispatchActionProcessor.js +23 -0
- package/lib/commonjs/hooks/useQpqReducer/actionProcessor/index.d.ts +1 -0
- package/lib/commonjs/hooks/useQpqReducer/actionProcessor/index.js +17 -0
- package/lib/commonjs/hooks/useQpqReducer/index.d.ts +1 -0
- package/lib/commonjs/hooks/useQpqReducer/index.js +17 -0
- package/lib/commonjs/hooks/useQpqReducer/useQpqReducer.d.ts +1 -0
- package/lib/commonjs/hooks/useQpqReducer/useQpqReducer.js +63 -0
- package/lib/esm/hooks/index.d.ts +3 -0
- package/lib/esm/hooks/index.js +3 -0
- package/lib/esm/hooks/useBubbleReducer.d.ts +7 -0
- package/lib/esm/hooks/useBubbleReducer.js +27 -0
- package/lib/esm/hooks/useQpq.d.ts +2 -0
- package/lib/esm/hooks/useQpq.js +30 -0
- package/lib/esm/hooks/useQpqReducer/actionProcessor/getStateDispatchActionProcessor.d.ts +3 -0
- package/lib/esm/hooks/useQpqReducer/actionProcessor/getStateDispatchActionProcessor.js +8 -0
- package/lib/esm/hooks/useQpqReducer/actionProcessor/index.d.ts +1 -0
- package/lib/esm/hooks/useQpqReducer/actionProcessor/index.js +1 -0
- package/lib/esm/hooks/useQpqReducer/index.d.ts +1 -0
- package/lib/esm/hooks/useQpqReducer/index.js +1 -0
- package/lib/esm/hooks/useQpqReducer/useQpqReducer.d.ts +1 -0
- package/lib/esm/hooks/useQpqReducer/useQpqReducer.js +59 -0
- package/package.json +5 -5
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from './useAsyncEffect';
|
|
2
|
+
export * from './useBubbleReducer';
|
|
2
3
|
export * from './useFastCallback';
|
|
3
4
|
export * from './useOnKeyDownEffect';
|
|
5
|
+
export * from './useQpq';
|
|
6
|
+
export * from './useQpqReducer';
|
|
4
7
|
export * from './useRunEvery';
|
|
5
8
|
export * from './useThrottledMemo';
|
|
@@ -15,7 +15,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./useAsyncEffect"), exports);
|
|
18
|
+
__exportStar(require("./useBubbleReducer"), exports);
|
|
18
19
|
__exportStar(require("./useFastCallback"), exports);
|
|
19
20
|
__exportStar(require("./useOnKeyDownEffect"), exports);
|
|
21
|
+
__exportStar(require("./useQpq"), exports);
|
|
22
|
+
__exportStar(require("./useQpqReducer"), exports);
|
|
20
23
|
__exportStar(require("./useRunEvery"), exports);
|
|
21
24
|
__exportStar(require("./useThrottledMemo"), exports);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type QpqBubbleReducer<S, A> = (prevState: S, action: A) => [S, boolean];
|
|
3
|
+
export declare const useBubblingReducer: <TState, TAction>(reducer: QpqBubbleReducer<TState, TAction>, initialState: TState) => [TState, (action: TAction) => void];
|
|
4
|
+
export declare const BubbleReducerDispatchProvider: ({ children, dispatch }: {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
dispatch: (action: any) => void;
|
|
7
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BubbleReducerDispatchProvider = exports.useBubblingReducer = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
// Create a context with a default NOOP dispatcher
|
|
7
|
+
const BubbleReducerDispatchContext = (0, react_1.createContext)((_action) => {
|
|
8
|
+
// NOOP
|
|
9
|
+
});
|
|
10
|
+
const useBubblingReducer = (reducer, initialState) => {
|
|
11
|
+
const ref = (0, react_1.useRef)(initialState);
|
|
12
|
+
// Use useState so we can leverage functional updates
|
|
13
|
+
const [state, setState] = (0, react_1.useState)(ref.current);
|
|
14
|
+
// Get the parent dispatch from the context
|
|
15
|
+
const parentDispatch = (0, react_1.useContext)(BubbleReducerDispatchContext);
|
|
16
|
+
// Custom Dispatch using functional updates
|
|
17
|
+
const dispatch = (action) => {
|
|
18
|
+
const [newState, preventBubble] = reducer(ref.current, action);
|
|
19
|
+
if (preventBubble) {
|
|
20
|
+
// If the action was handled, update state
|
|
21
|
+
ref.current = newState;
|
|
22
|
+
setState(newState);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
parentDispatch(action);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
return [state, dispatch];
|
|
29
|
+
};
|
|
30
|
+
exports.useBubblingReducer = useBubblingReducer;
|
|
31
|
+
const BubbleReducerDispatchProvider = ({ children, dispatch }) => ((0, jsx_runtime_1.jsx)(BubbleReducerDispatchContext.Provider, Object.assign({ value: dispatch }, { children: children })));
|
|
32
|
+
exports.BubbleReducerDispatchProvider = BubbleReducerDispatchProvider;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.useQpq = void 0;
|
|
13
|
+
const quidproquo_actionprocessor_node_1 = require("quidproquo-actionprocessor-node");
|
|
14
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
15
|
+
// WIP ~ useFastCallback, wack things like loggers in a context, try to only make once instance of the runtime.
|
|
16
|
+
// Also don't create every refresh.. useMemo / useCallback etc
|
|
17
|
+
function useQpq(getActionProcessors = () => __awaiter(this, void 0, void 0, function* () { return ({}); })) {
|
|
18
|
+
const logger = {
|
|
19
|
+
enableLogs: () => __awaiter(this, void 0, void 0, function* () { }),
|
|
20
|
+
log: () => __awaiter(this, void 0, void 0, function* () { }),
|
|
21
|
+
waitToFinishWriting: () => __awaiter(this, void 0, void 0, function* () { }),
|
|
22
|
+
moveToPermanentStorage: () => __awaiter(this, void 0, void 0, function* () { }),
|
|
23
|
+
};
|
|
24
|
+
const resolveStory = (0, quidproquo_core_1.createRuntime)([(0, quidproquo_core_1.defineModule)('UI')], {
|
|
25
|
+
depth: 0,
|
|
26
|
+
context: {},
|
|
27
|
+
}, (qpqConfig, dynamicModuleLoader) => __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
return (Object.assign(Object.assign({}, (yield (0, quidproquo_actionprocessor_node_1.getCoreActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield getActionProcessors(qpqConfig, dynamicModuleLoader))));
|
|
29
|
+
}), () => new Date().toISOString(), logger, `frontend::${'uuid'}`, quidproquo_core_1.QpqRuntimeType.UI, (_runtime) => __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
// noop
|
|
31
|
+
}));
|
|
32
|
+
return function getStoryExecutor(story) {
|
|
33
|
+
return (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
34
|
+
const result = yield resolveStory(story, args);
|
|
35
|
+
if (result.error) {
|
|
36
|
+
throw new Error(result.error.errorText);
|
|
37
|
+
}
|
|
38
|
+
return result.result;
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
exports.useQpq = useQpq;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getStateDispatchActionListResolver = void 0;
|
|
13
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
14
|
+
const getProcessStateDispatch = (dispatch) => ({ action }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
+
dispatch(action);
|
|
16
|
+
return (0, quidproquo_core_1.actionResult)(undefined);
|
|
17
|
+
});
|
|
18
|
+
const getStateDispatchActionListResolver = (dispatch) => (_qpqConfig, _dynamicModuleLoader) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
+
return ({
|
|
20
|
+
[quidproquo_core_1.StateActionType.Dispatch]: getProcessStateDispatch(dispatch),
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
exports.getStateDispatchActionListResolver = getStateDispatchActionListResolver;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getStateDispatchActionProcessor';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./getStateDispatchActionProcessor"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useQpqReducer';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./useQpqReducer"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useQpqReducer: () => void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
import { AskResponseReturnType, Story } from 'quidproquo-core';
|
|
4
|
+
|
|
5
|
+
import { useMemo, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { QpqBubbleReducer, useBubblingReducer } from '../useBubbleReducer';
|
|
8
|
+
import { useQpq } from '../useQpq';
|
|
9
|
+
import { getStateDispatchActionListResolver } from './actionProcessor';
|
|
10
|
+
|
|
11
|
+
// Helper type to remap keys from "askXyz" to "xyz" (with lowercase first letter)
|
|
12
|
+
type RemoveAskPrefix<K extends string> = K extends `ask${infer R}` ? Uncapitalize<R> : never;
|
|
13
|
+
|
|
14
|
+
// Define the mapped API type.
|
|
15
|
+
// We extract only string keys and then use a conditional type to infer parameters and return type.
|
|
16
|
+
type MappedApi<TApi extends Record<`ask${string}`, Story<any, any>>> = {
|
|
17
|
+
[K in Extract<keyof TApi, string> as RemoveAskPrefix<K>]: TApi[K] extends (...args: infer P) => infer R
|
|
18
|
+
? (...args: P) => Promise<AskResponseReturnType<R>>
|
|
19
|
+
: never;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function useQpqReducer<
|
|
23
|
+
TState,
|
|
24
|
+
TAction,
|
|
25
|
+
// Constrain TApi so that all keys must start with "ask"
|
|
26
|
+
TApi extends Record<`ask${string}`, Story<any, any>>,
|
|
27
|
+
>(
|
|
28
|
+
apiGenerators: TApi,
|
|
29
|
+
reducer: QpqBubbleReducer<TState, TAction> = (s) => [s, false],
|
|
30
|
+
initialState: TState = {} as TState,
|
|
31
|
+
): [MappedApi<TApi>, TState, (action: any) => void] {
|
|
32
|
+
const [state, dispatch] = useBubblingReducer(reducer, initialState);
|
|
33
|
+
|
|
34
|
+
// Api generators are memoized to prevent unnecessary re-renders.
|
|
35
|
+
const [memoedApiGenerators] = useState(() => apiGenerators);
|
|
36
|
+
const resolver = useQpq(getStateDispatchActionListResolver(dispatch));
|
|
37
|
+
|
|
38
|
+
// Wrap and remap each API generator using the resolver.
|
|
39
|
+
const api = useMemo(() => {
|
|
40
|
+
const wrapped = {} as MappedApi<TApi>;
|
|
41
|
+
for (const key in memoedApiGenerators) {
|
|
42
|
+
if (Object.prototype.hasOwnProperty.call(memoedApiGenerators, key)) {
|
|
43
|
+
// Remove the 'ask' prefix and lower-case the first character.
|
|
44
|
+
const withoutAsk = key.slice(3); // e.g., "FetchTodos"
|
|
45
|
+
const newKey = withoutAsk.charAt(0).toLowerCase() + withoutAsk.slice(1); // "fetchTodos"
|
|
46
|
+
// We know newKey matches our mapped type so we can assign.
|
|
47
|
+
// (A type assertion is used here to quiet the compiler.)
|
|
48
|
+
wrapped[newKey as RemoveAskPrefix<typeof key>] = resolver(memoedApiGenerators[key as any]) as any;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return wrapped;
|
|
52
|
+
}, [resolver, memoedApiGenerators]);
|
|
53
|
+
|
|
54
|
+
return [api, state, dispatch];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
*/
|
|
58
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
59
|
+
exports.useQpqReducer = void 0;
|
|
60
|
+
const useQpqReducer = () => {
|
|
61
|
+
// NOOP
|
|
62
|
+
};
|
|
63
|
+
exports.useQpqReducer = useQpqReducer;
|
package/lib/esm/hooks/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from './useAsyncEffect';
|
|
2
|
+
export * from './useBubbleReducer';
|
|
2
3
|
export * from './useFastCallback';
|
|
3
4
|
export * from './useOnKeyDownEffect';
|
|
5
|
+
export * from './useQpq';
|
|
6
|
+
export * from './useQpqReducer';
|
|
4
7
|
export * from './useRunEvery';
|
|
5
8
|
export * from './useThrottledMemo';
|
package/lib/esm/hooks/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from './useAsyncEffect';
|
|
2
|
+
export * from './useBubbleReducer';
|
|
2
3
|
export * from './useFastCallback';
|
|
3
4
|
export * from './useOnKeyDownEffect';
|
|
5
|
+
export * from './useQpq';
|
|
6
|
+
export * from './useQpqReducer';
|
|
4
7
|
export * from './useRunEvery';
|
|
5
8
|
export * from './useThrottledMemo';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type QpqBubbleReducer<S, A> = (prevState: S, action: A) => [S, boolean];
|
|
3
|
+
export declare const useBubblingReducer: <TState, TAction>(reducer: QpqBubbleReducer<TState, TAction>, initialState: TState) => [TState, (action: TAction) => void];
|
|
4
|
+
export declare const BubbleReducerDispatchProvider: ({ children, dispatch }: {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
dispatch: (action: any) => void;
|
|
7
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useRef, useState } from 'react';
|
|
3
|
+
// Create a context with a default NOOP dispatcher
|
|
4
|
+
const BubbleReducerDispatchContext = createContext((_action) => {
|
|
5
|
+
// NOOP
|
|
6
|
+
});
|
|
7
|
+
export const useBubblingReducer = (reducer, initialState) => {
|
|
8
|
+
const ref = useRef(initialState);
|
|
9
|
+
// Use useState so we can leverage functional updates
|
|
10
|
+
const [state, setState] = useState(ref.current);
|
|
11
|
+
// Get the parent dispatch from the context
|
|
12
|
+
const parentDispatch = useContext(BubbleReducerDispatchContext);
|
|
13
|
+
// Custom Dispatch using functional updates
|
|
14
|
+
const dispatch = (action) => {
|
|
15
|
+
const [newState, preventBubble] = reducer(ref.current, action);
|
|
16
|
+
if (preventBubble) {
|
|
17
|
+
// If the action was handled, update state
|
|
18
|
+
ref.current = newState;
|
|
19
|
+
setState(newState);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
parentDispatch(action);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
return [state, dispatch];
|
|
26
|
+
};
|
|
27
|
+
export const BubbleReducerDispatchProvider = ({ children, dispatch }) => (_jsx(BubbleReducerDispatchContext.Provider, { value: dispatch, children: children }));
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getCoreActionProcessor } from 'quidproquo-actionprocessor-node';
|
|
2
|
+
import { createRuntime, defineModule, QpqRuntimeType, } from 'quidproquo-core';
|
|
3
|
+
// WIP ~ useFastCallback, wack things like loggers in a context, try to only make once instance of the runtime.
|
|
4
|
+
// Also don't create every refresh.. useMemo / useCallback etc
|
|
5
|
+
export function useQpq(getActionProcessors = async () => ({})) {
|
|
6
|
+
const logger = {
|
|
7
|
+
enableLogs: async () => { },
|
|
8
|
+
log: async () => { },
|
|
9
|
+
waitToFinishWriting: async () => { },
|
|
10
|
+
moveToPermanentStorage: async () => { },
|
|
11
|
+
};
|
|
12
|
+
const resolveStory = createRuntime([defineModule('UI')], {
|
|
13
|
+
depth: 0,
|
|
14
|
+
context: {},
|
|
15
|
+
}, async (qpqConfig, dynamicModuleLoader) => ({
|
|
16
|
+
...(await getCoreActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
17
|
+
...(await getActionProcessors(qpqConfig, dynamicModuleLoader)),
|
|
18
|
+
}), () => new Date().toISOString(), logger, `frontend::${'uuid'}`, QpqRuntimeType.UI, async (_runtime) => {
|
|
19
|
+
// noop
|
|
20
|
+
});
|
|
21
|
+
return function getStoryExecutor(story) {
|
|
22
|
+
return async (...args) => {
|
|
23
|
+
const result = await resolveStory(story, args);
|
|
24
|
+
if (result.error) {
|
|
25
|
+
throw new Error(result.error.errorText);
|
|
26
|
+
}
|
|
27
|
+
return result.result;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { actionResult, StateActionType } from 'quidproquo-core';
|
|
2
|
+
const getProcessStateDispatch = (dispatch) => async ({ action }) => {
|
|
3
|
+
dispatch(action);
|
|
4
|
+
return actionResult(undefined);
|
|
5
|
+
};
|
|
6
|
+
export const getStateDispatchActionListResolver = (dispatch) => async (_qpqConfig, _dynamicModuleLoader) => ({
|
|
7
|
+
[StateActionType.Dispatch]: getProcessStateDispatch(dispatch),
|
|
8
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getStateDispatchActionProcessor';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getStateDispatchActionProcessor';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useQpqReducer';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useQpqReducer';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useQpqReducer: () => void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
import { AskResponseReturnType, Story } from 'quidproquo-core';
|
|
3
|
+
|
|
4
|
+
import { useMemo, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import { QpqBubbleReducer, useBubblingReducer } from '../useBubbleReducer';
|
|
7
|
+
import { useQpq } from '../useQpq';
|
|
8
|
+
import { getStateDispatchActionListResolver } from './actionProcessor';
|
|
9
|
+
|
|
10
|
+
// Helper type to remap keys from "askXyz" to "xyz" (with lowercase first letter)
|
|
11
|
+
type RemoveAskPrefix<K extends string> = K extends `ask${infer R}` ? Uncapitalize<R> : never;
|
|
12
|
+
|
|
13
|
+
// Define the mapped API type.
|
|
14
|
+
// We extract only string keys and then use a conditional type to infer parameters and return type.
|
|
15
|
+
type MappedApi<TApi extends Record<`ask${string}`, Story<any, any>>> = {
|
|
16
|
+
[K in Extract<keyof TApi, string> as RemoveAskPrefix<K>]: TApi[K] extends (...args: infer P) => infer R
|
|
17
|
+
? (...args: P) => Promise<AskResponseReturnType<R>>
|
|
18
|
+
: never;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function useQpqReducer<
|
|
22
|
+
TState,
|
|
23
|
+
TAction,
|
|
24
|
+
// Constrain TApi so that all keys must start with "ask"
|
|
25
|
+
TApi extends Record<`ask${string}`, Story<any, any>>,
|
|
26
|
+
>(
|
|
27
|
+
apiGenerators: TApi,
|
|
28
|
+
reducer: QpqBubbleReducer<TState, TAction> = (s) => [s, false],
|
|
29
|
+
initialState: TState = {} as TState,
|
|
30
|
+
): [MappedApi<TApi>, TState, (action: any) => void] {
|
|
31
|
+
const [state, dispatch] = useBubblingReducer(reducer, initialState);
|
|
32
|
+
|
|
33
|
+
// Api generators are memoized to prevent unnecessary re-renders.
|
|
34
|
+
const [memoedApiGenerators] = useState(() => apiGenerators);
|
|
35
|
+
const resolver = useQpq(getStateDispatchActionListResolver(dispatch));
|
|
36
|
+
|
|
37
|
+
// Wrap and remap each API generator using the resolver.
|
|
38
|
+
const api = useMemo(() => {
|
|
39
|
+
const wrapped = {} as MappedApi<TApi>;
|
|
40
|
+
for (const key in memoedApiGenerators) {
|
|
41
|
+
if (Object.prototype.hasOwnProperty.call(memoedApiGenerators, key)) {
|
|
42
|
+
// Remove the 'ask' prefix and lower-case the first character.
|
|
43
|
+
const withoutAsk = key.slice(3); // e.g., "FetchTodos"
|
|
44
|
+
const newKey = withoutAsk.charAt(0).toLowerCase() + withoutAsk.slice(1); // "fetchTodos"
|
|
45
|
+
// We know newKey matches our mapped type so we can assign.
|
|
46
|
+
// (A type assertion is used here to quiet the compiler.)
|
|
47
|
+
wrapped[newKey as RemoveAskPrefix<typeof key>] = resolver(memoedApiGenerators[key as any]) as any;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return wrapped;
|
|
51
|
+
}, [resolver, memoedApiGenerators]);
|
|
52
|
+
|
|
53
|
+
return [api, state, dispatch];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
*/
|
|
57
|
+
export const useQpqReducer = () => {
|
|
58
|
+
// NOOP
|
|
59
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quidproquo-web-react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.249",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/commonjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://github.com/joe-coady/quidproquo#readme",
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"quidproquo-core": "0.0.
|
|
36
|
-
"quidproquo-tsconfig": "0.0.
|
|
37
|
-
"quidproquo-webserver": "0.0.
|
|
38
|
-
"quidproquo-web": "0.0.
|
|
35
|
+
"quidproquo-core": "0.0.249",
|
|
36
|
+
"quidproquo-tsconfig": "0.0.249",
|
|
37
|
+
"quidproquo-webserver": "0.0.249",
|
|
38
|
+
"quidproquo-web": "0.0.249",
|
|
39
39
|
"typescript": "^4.9.3"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|