@pihanga2/core 0.3.0 → 0.3.2
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/card.d.ts +2 -1
- package/dist/card.d.ts.map +1 -1
- package/dist/card.js +24 -12
- package/dist/card.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/reducer.d.ts.map +1 -1
- package/dist/reducer.js +17 -6
- package/dist/reducer.js.map +1 -1
- package/dist/register_cards.d.ts +35 -2
- package/dist/register_cards.d.ts.map +1 -1
- package/dist/register_cards.js +38 -33
- package/dist/register_cards.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.d.ts +3 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/card.tsx +238 -187
- package/src/index.ts +5 -1
- package/src/reducer.ts +25 -10
- package/src/register_cards.ts +183 -123
- package/src/types.ts +83 -76
package/src/card.tsx
CHANGED
|
@@ -1,194 +1,234 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { useDispatch, useSelector } from "react-redux"
|
|
3
|
-
import equal from "deep-equal"
|
|
1
|
+
import React, { useEffect, useId } from "react";
|
|
2
|
+
import { useDispatch, useSelector, useStore } from "react-redux";
|
|
3
|
+
import equal from "deep-equal";
|
|
4
4
|
|
|
5
|
-
import { getLogger } from "./logger"
|
|
5
|
+
import { getLogger } from "./logger";
|
|
6
6
|
import {
|
|
7
7
|
CSSModuleClasses,
|
|
8
8
|
CardProp,
|
|
9
9
|
PiCardDef,
|
|
10
|
+
PiReducer,
|
|
10
11
|
PiRegisterComponent,
|
|
11
12
|
PiRegisterReducerF,
|
|
13
|
+
ReduceF,
|
|
14
|
+
ReduxAction,
|
|
12
15
|
ReduxState,
|
|
13
16
|
StateMapper,
|
|
14
17
|
StateMapperContext,
|
|
15
|
-
} from "./types"
|
|
16
|
-
import { Action, AnyAction, Dispatch } from "@reduxjs/toolkit"
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
} from "./types";
|
|
19
|
+
import { Action, AnyAction, Dispatch } from "@reduxjs/toolkit";
|
|
20
|
+
import {
|
|
21
|
+
_createCardMapping,
|
|
22
|
+
_updateCardMapping,
|
|
23
|
+
_registerCard,
|
|
24
|
+
cardMappings,
|
|
25
|
+
cardTypes,
|
|
26
|
+
dispatch2registerReducer,
|
|
27
|
+
framework,
|
|
28
|
+
Mapping,
|
|
29
|
+
} from "./register_cards";
|
|
30
|
+
|
|
31
|
+
const logger = getLogger("card");
|
|
20
32
|
|
|
21
33
|
// export type CardProp = {
|
|
22
34
|
// cardName: PiCardRef
|
|
23
35
|
// } & { [k: string]: any }
|
|
24
36
|
|
|
25
|
-
type CompProps = { [k: string]: any }
|
|
37
|
+
type CompProps = { [k: string]: any };
|
|
26
38
|
type CardInfo = {
|
|
27
|
-
mapping: Mapping
|
|
28
|
-
cardType: PiRegisterComponent
|
|
29
|
-
}
|
|
39
|
+
mapping: Mapping;
|
|
40
|
+
cardType: PiRegisterComponent;
|
|
41
|
+
};
|
|
30
42
|
|
|
31
43
|
export function Card(props: CardProp): JSX.Element {
|
|
32
|
-
let cardName: string
|
|
44
|
+
let cardName: string;
|
|
33
45
|
|
|
34
|
-
const [id, _] = React.useState<number>(Math.floor(Math.random() * 10000))
|
|
35
|
-
const dispatch = useDispatch() // never change the order of hooks called
|
|
46
|
+
const [id, _] = React.useState<number>(Math.floor(Math.random() * 10000));
|
|
47
|
+
const dispatch = useDispatch(); // never change the order of hooks called
|
|
36
48
|
|
|
37
49
|
if (typeof props.cardName === "string") {
|
|
38
|
-
cardName = props.cardName
|
|
50
|
+
cardName = props.cardName;
|
|
39
51
|
} else {
|
|
40
52
|
// lets fix it
|
|
41
|
-
cardName = checkForAnonymousCard(props, id, dispatch)
|
|
53
|
+
cardName = checkForAnonymousCard(props, id, dispatch);
|
|
42
54
|
}
|
|
43
55
|
if (cardName === "") {
|
|
44
|
-
logger.error("card name is not of type string", props.cardName)
|
|
45
|
-
return ErrorCard(
|
|
56
|
+
logger.error("card name is not of type string", props.cardName);
|
|
57
|
+
return ErrorCard(
|
|
58
|
+
<div>Unknown type of cardName '{`${props.cardName}`}'</div>
|
|
59
|
+
);
|
|
46
60
|
}
|
|
47
61
|
|
|
48
|
-
const [info, errCard] = getCardInfo(cardName)
|
|
62
|
+
const [info, errCard] = getCardInfo(cardName);
|
|
49
63
|
if (errCard) {
|
|
50
|
-
return ErrorCard(errCard)
|
|
64
|
+
return ErrorCard(errCard);
|
|
51
65
|
}
|
|
52
66
|
if (!info) {
|
|
53
|
-
throw new Error("info is empty, should never happen")
|
|
67
|
+
throw new Error("info is empty, should never happen");
|
|
54
68
|
}
|
|
55
|
-
return GenericCard(cardName, props, info, id)
|
|
69
|
+
return GenericCard(cardName, props, info, id);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function usePiReducer<S extends ReduxState, A extends ReduxAction>(
|
|
73
|
+
eventType: string,
|
|
74
|
+
mapper: ReduceF<S, A> // (state: S, action: A, dispatch: DispatchF) => S,
|
|
75
|
+
) {
|
|
76
|
+
const store = useStore();
|
|
77
|
+
const id = useId();
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
const r = (store as any).piReducer as PiReducer;
|
|
80
|
+
return r.register(eventType, mapper, 0, id);
|
|
81
|
+
});
|
|
56
82
|
}
|
|
57
83
|
|
|
58
|
-
function checkForAnonymousCard(
|
|
59
|
-
|
|
84
|
+
function checkForAnonymousCard(
|
|
85
|
+
props: any,
|
|
86
|
+
id: number,
|
|
87
|
+
dispatch: Dispatch<AnyAction>
|
|
88
|
+
): string {
|
|
89
|
+
const cardType = props.cardName?.cardType;
|
|
60
90
|
if (!cardType) {
|
|
61
|
-
return "" // not sure what that is
|
|
91
|
+
return ""; // not sure what that is
|
|
62
92
|
}
|
|
63
93
|
// looks like a potentially unregistered card
|
|
64
|
-
let cardName: string
|
|
94
|
+
let cardName: string;
|
|
65
95
|
if (props.parentCard) {
|
|
66
|
-
cardName = `${props.parentCard}/${cardType.split(
|
|
96
|
+
cardName = `${props.parentCard}/${cardType.split("/").pop()}`;
|
|
67
97
|
} else {
|
|
68
|
-
cardName = cardType
|
|
98
|
+
cardName = cardType;
|
|
69
99
|
}
|
|
70
100
|
if (props.cardKey) {
|
|
71
|
-
cardName = `${cardName}#${props.cardKey}-${id}
|
|
101
|
+
cardName = `${cardName}#${props.cardKey}-${id}`;
|
|
72
102
|
} else {
|
|
73
|
-
cardName = `${cardName}#${id}
|
|
103
|
+
cardName = `${cardName}#${id}`;
|
|
74
104
|
}
|
|
75
105
|
|
|
76
|
-
const mapping = cardMappings[cardName]
|
|
77
|
-
const parameters = props.cardName as PiCardDef
|
|
78
|
-
const el = dispatch2registerReducer.find(([d, _]) => d === dispatch)
|
|
106
|
+
const mapping = cardMappings[cardName];
|
|
107
|
+
const parameters = props.cardName as PiCardDef;
|
|
108
|
+
const el = dispatch2registerReducer.find(([d, _]) => d === dispatch);
|
|
79
109
|
if (!el) {
|
|
80
|
-
logger.warn("unexpected missing mapping between dispatcher and reducerF")
|
|
81
|
-
return ""
|
|
110
|
+
logger.warn("unexpected missing mapping between dispatcher and reducerF");
|
|
111
|
+
return "";
|
|
82
112
|
}
|
|
83
|
-
const regRed = el[1]
|
|
113
|
+
const regRed = el[1];
|
|
84
114
|
if (mapping) {
|
|
85
115
|
// looks like we already processed it
|
|
86
116
|
// do update props as they may have changed
|
|
87
|
-
_updateCardMapping(cardName, parameters, regRed, mapping)
|
|
117
|
+
_updateCardMapping(cardName, parameters, regRed, mapping);
|
|
88
118
|
} else {
|
|
89
|
-
_registerCard(cardName, parameters, regRed)
|
|
119
|
+
_registerCard(cardName, parameters, regRed);
|
|
90
120
|
}
|
|
91
|
-
return cardName
|
|
121
|
+
return cardName;
|
|
92
122
|
}
|
|
93
123
|
|
|
94
|
-
function GenericCard(
|
|
124
|
+
function GenericCard(
|
|
125
|
+
cardName: string,
|
|
126
|
+
props: CardProp,
|
|
127
|
+
info: CardInfo,
|
|
128
|
+
id: number
|
|
129
|
+
) {
|
|
95
130
|
const cardProps = useSelector<ReduxState, CompProps>(
|
|
96
131
|
(s) => getCardProps(cardName, s, props),
|
|
97
|
-
propEq
|
|
98
|
-
)
|
|
99
|
-
const dispatch = useDispatch()
|
|
100
|
-
|
|
101
|
-
const extCardProps = appendEventHandlers(info, cardProps, cardName, dispatch)
|
|
102
|
-
extCardProps._cls = cls_f(cardName, info.mapping.cardType)
|
|
103
|
-
return React.createElement(
|
|
132
|
+
propEq
|
|
133
|
+
);
|
|
134
|
+
const dispatch = useDispatch();
|
|
135
|
+
|
|
136
|
+
const extCardProps = appendEventHandlers(info, cardProps, cardName, dispatch);
|
|
137
|
+
extCardProps._cls = cls_f(cardName, info.mapping.cardType);
|
|
138
|
+
return React.createElement(
|
|
139
|
+
info.cardType.component,
|
|
140
|
+
extCardProps,
|
|
141
|
+
props.children
|
|
142
|
+
);
|
|
104
143
|
}
|
|
105
144
|
|
|
106
|
-
const EmptyCompProps = {} as CompProps
|
|
145
|
+
const EmptyCompProps = {} as CompProps;
|
|
107
146
|
|
|
108
147
|
function ErrorCard(el: JSX.Element) {
|
|
109
148
|
// Note: call the EXACT same hooks as 'GenericCard'
|
|
110
|
-
useSelector<ReduxState, CompProps>(
|
|
111
|
-
|
|
112
|
-
|
|
149
|
+
useSelector<ReduxState, CompProps>(
|
|
150
|
+
(s) => EmptyCompProps,
|
|
151
|
+
(a, b) => false
|
|
152
|
+
);
|
|
153
|
+
useDispatch();
|
|
154
|
+
return el;
|
|
113
155
|
}
|
|
114
156
|
|
|
115
|
-
|
|
116
157
|
function getCardInfo(cardName: string): [CardInfo?, JSX.Element?] {
|
|
117
|
-
const mapping = cardMappings[cardName]
|
|
158
|
+
const mapping = cardMappings[cardName];
|
|
118
159
|
if (!mapping) {
|
|
119
|
-
return [undefined, renderUnknownCard(cardName)]
|
|
160
|
+
return [undefined, renderUnknownCard(cardName)];
|
|
120
161
|
}
|
|
121
|
-
let cardType = cardTypes[mapping.cardType]
|
|
162
|
+
let cardType = cardTypes[mapping.cardType];
|
|
122
163
|
if (!cardType) {
|
|
123
164
|
if (framework) {
|
|
124
|
-
cardType = cardTypes[`${framework}/${mapping.cardType}`]
|
|
165
|
+
cardType = cardTypes[`${framework}/${mapping.cardType}`];
|
|
125
166
|
}
|
|
126
167
|
if (!cardType) {
|
|
127
|
-
return [undefined, renderUnknownCardType(mapping.cardType)]
|
|
168
|
+
return [undefined, renderUnknownCardType(mapping.cardType)];
|
|
128
169
|
}
|
|
129
170
|
}
|
|
130
|
-
const info = { mapping, cardType }
|
|
131
|
-
return [info, undefined]
|
|
171
|
+
const info = { mapping, cardType };
|
|
172
|
+
return [info, undefined];
|
|
132
173
|
}
|
|
133
174
|
|
|
134
|
-
|
|
135
175
|
function getCardProps(
|
|
136
176
|
cardName: string,
|
|
137
177
|
state: ReduxState,
|
|
138
|
-
props: CardProp
|
|
178
|
+
props: CardProp
|
|
139
179
|
): CompProps {
|
|
140
|
-
const mapping = cardMappings[cardName]
|
|
180
|
+
const mapping = cardMappings[cardName];
|
|
141
181
|
const ctxt: StateMapperContext<unknown> = {
|
|
142
182
|
cardName,
|
|
143
183
|
cardKey: props.cardKey,
|
|
144
184
|
ctxtProps: props,
|
|
145
|
-
}
|
|
185
|
+
};
|
|
146
186
|
const init: CompProps = {
|
|
147
187
|
cardName,
|
|
148
188
|
cardKey: props.cardKey,
|
|
149
|
-
}
|
|
189
|
+
};
|
|
150
190
|
const cprops = Object.entries(mapping.props).reduce((p, [key, vf]) => {
|
|
151
|
-
let v = vf
|
|
191
|
+
let v = vf;
|
|
152
192
|
if (typeof vf === "function") {
|
|
153
|
-
const f = vf as StateMapper<unknown, ReduxState, any
|
|
193
|
+
const f = vf as StateMapper<unknown, ReduxState, any>;
|
|
154
194
|
try {
|
|
155
|
-
v = f(state, ctxt)
|
|
195
|
+
v = f(state, ctxt);
|
|
156
196
|
} catch (ex) {
|
|
157
|
-
logger.error(`while resolving property '${key}'`, ex)
|
|
197
|
+
logger.error(`while resolving property '${key}'`, ex);
|
|
158
198
|
}
|
|
159
199
|
} else if (key in props) {
|
|
160
|
-
v = props[key]
|
|
200
|
+
v = props[key];
|
|
161
201
|
}
|
|
162
|
-
p[key] = v
|
|
163
|
-
return p
|
|
164
|
-
}, init)
|
|
165
|
-
return cprops
|
|
202
|
+
p[key] = v;
|
|
203
|
+
return p;
|
|
204
|
+
}, init);
|
|
205
|
+
return cprops;
|
|
166
206
|
}
|
|
167
207
|
|
|
168
208
|
function cls_f(
|
|
169
209
|
cardName: string,
|
|
170
210
|
cardComp: string,
|
|
171
|
-
prefix: string = "pi"
|
|
172
|
-
): (nodeName: string | string[],
|
|
173
|
-
const cn = cardName.replaceAll(/[/:]/g, "_")
|
|
174
|
-
const cp = cardComp.replaceAll(/[/:]/g, "_")
|
|
175
|
-
return (nodeName: string | string[],
|
|
176
|
-
const na: string[] = typeof nodeName === "string" ? [nodeName] : nodeName
|
|
177
|
-
const ca = [] as string[]
|
|
211
|
+
prefix: string = "pi"
|
|
212
|
+
): (nodeName: string | string[], className?: string) => string {
|
|
213
|
+
const cn = cardName.replaceAll(/[/:]/g, "_");
|
|
214
|
+
const cp = cardComp.replaceAll(/[/:]/g, "_");
|
|
215
|
+
return (nodeName: string | string[], className?: string): string => {
|
|
216
|
+
const na: string[] = typeof nodeName === "string" ? [nodeName] : nodeName;
|
|
217
|
+
const ca = [] as string[];
|
|
218
|
+
if (className) {
|
|
219
|
+
ca.push(className);
|
|
220
|
+
}
|
|
178
221
|
na.forEach((n) => {
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
})
|
|
186
|
-
return ca.join(" ")
|
|
187
|
-
}
|
|
222
|
+
const nn = n.replaceAll(/[/:]/g, "_");
|
|
223
|
+
ca.push(`${prefix}-${cn}-${nn}`);
|
|
224
|
+
ca.push(`${prefix}-${cp}-${nn}`);
|
|
225
|
+
});
|
|
226
|
+
return ca.join(" ");
|
|
227
|
+
};
|
|
188
228
|
}
|
|
189
229
|
|
|
190
230
|
function propEq(oldP: CompProps, newP: CompProps): boolean {
|
|
191
|
-
let isUnchanged = equal(oldP, newP)
|
|
231
|
+
let isUnchanged = equal(oldP, newP);
|
|
192
232
|
// for (const [k, v] of Object.entries(newP)) {
|
|
193
233
|
// const ov = oldP[k]
|
|
194
234
|
// if (ov !== v) {
|
|
@@ -199,179 +239,190 @@ function propEq(oldP: CompProps, newP: CompProps): boolean {
|
|
|
199
239
|
// }
|
|
200
240
|
// }
|
|
201
241
|
// }
|
|
202
|
-
RegisterCardState.changed(newP.cardName, isUnchanged, newP)
|
|
203
|
-
return isUnchanged
|
|
242
|
+
RegisterCardState.changed(newP.cardName, isUnchanged, newP);
|
|
243
|
+
return isUnchanged;
|
|
204
244
|
}
|
|
205
245
|
|
|
206
246
|
function appendEventHandlers(
|
|
207
247
|
info: CardInfo,
|
|
208
248
|
cardProps: CompProps,
|
|
209
249
|
cardName: string,
|
|
210
|
-
dispatch: Dispatch<Action
|
|
250
|
+
dispatch: Dispatch<Action>
|
|
211
251
|
): CompProps {
|
|
212
|
-
RegisterCardState.props(cardName, cardProps, dispatch)
|
|
252
|
+
RegisterCardState.props(cardName, cardProps, dispatch);
|
|
213
253
|
const cp: CompProps = {
|
|
214
254
|
...cardProps,
|
|
215
|
-
_dispatch: (a: AnyAction) => dispatch(a)
|
|
216
|
-
}
|
|
255
|
+
_dispatch: (a: AnyAction) => dispatch(a),
|
|
256
|
+
};
|
|
217
257
|
|
|
218
|
-
const events = info.cardType?.events
|
|
258
|
+
const events = info.cardType?.events;
|
|
219
259
|
if (!events) {
|
|
220
|
-
return cp
|
|
260
|
+
return cp;
|
|
221
261
|
}
|
|
222
|
-
const eventMappers = info.mapping.eventMappers
|
|
262
|
+
const eventMappers = info.mapping.eventMappers;
|
|
223
263
|
Object.entries(events).forEach(([name, actionType]) => {
|
|
224
|
-
const m = eventMappers[name]
|
|
264
|
+
const m = eventMappers[name];
|
|
225
265
|
if (m) {
|
|
226
|
-
logger.debug("setup mapper", cardName)
|
|
266
|
+
logger.debug("setup mapper", cardName);
|
|
227
267
|
cp[name] = (a: AnyAction) => {
|
|
228
|
-
a.cardID = cardName
|
|
229
|
-
const a2 = m(a)
|
|
230
|
-
if (a2) dispatch(a2)
|
|
231
|
-
}
|
|
268
|
+
a.cardID = cardName;
|
|
269
|
+
const a2 = m(a);
|
|
270
|
+
if (a2) dispatch(a2);
|
|
271
|
+
};
|
|
232
272
|
} else {
|
|
233
273
|
cp[name] = (a: AnyAction) => {
|
|
234
|
-
a.type = actionType
|
|
235
|
-
a.cardID = cardName
|
|
236
|
-
dispatch(a)
|
|
237
|
-
}
|
|
274
|
+
a.type = actionType;
|
|
275
|
+
a.cardID = cardName;
|
|
276
|
+
dispatch(a);
|
|
277
|
+
};
|
|
238
278
|
}
|
|
239
|
-
})
|
|
240
|
-
return cp
|
|
279
|
+
});
|
|
280
|
+
return cp;
|
|
241
281
|
}
|
|
242
282
|
|
|
243
283
|
function renderUnknownCard(cardName: string): JSX.Element {
|
|
244
|
-
return <div>Unknown card '{cardName}'</div
|
|
284
|
+
return <div>Unknown card '{cardName}'</div>;
|
|
245
285
|
}
|
|
246
286
|
|
|
247
287
|
function renderUnknownCardType(cardType: string): JSX.Element {
|
|
248
|
-
return <div>Unknown card type '{cardType}'</div
|
|
288
|
+
return <div>Unknown card type '{cardType}'</div>;
|
|
249
289
|
}
|
|
250
290
|
|
|
251
291
|
// Adding card state to redux state for debugging
|
|
252
292
|
|
|
253
|
-
export const UPDATE_STATE_ACTION = "pi/card/update_state"
|
|
293
|
+
export const UPDATE_STATE_ACTION = "pi/card/update_state";
|
|
254
294
|
|
|
255
295
|
type CardState = {
|
|
256
296
|
props: (
|
|
257
297
|
cardName: string,
|
|
258
298
|
cardProps: CompProps,
|
|
259
|
-
dispatch: Dispatch<Action
|
|
260
|
-
) => void
|
|
261
|
-
changed: (cardName: string, isUnchanged: boolean, props: CompProps) => void
|
|
262
|
-
reducer: (state: ReduxState, action: Action) => ReduxState
|
|
263
|
-
}
|
|
299
|
+
dispatch: Dispatch<Action>
|
|
300
|
+
) => void;
|
|
301
|
+
changed: (cardName: string, isUnchanged: boolean, props: CompProps) => void;
|
|
302
|
+
reducer: (state: ReduxState, action: Action) => ReduxState;
|
|
303
|
+
};
|
|
264
304
|
|
|
265
|
-
export const RegisterCardState = createCardState()
|
|
305
|
+
export const RegisterCardState = createCardState();
|
|
266
306
|
|
|
267
307
|
function createCardState(): CardState {
|
|
268
308
|
type S = {
|
|
269
|
-
cardProps?: CompProps
|
|
270
|
-
changedAt: number
|
|
271
|
-
reportedAt: number
|
|
272
|
-
}
|
|
273
|
-
const s: { [name: string]: S } = {}
|
|
274
|
-
let dispatch: Dispatch<Action
|
|
275
|
-
let timer: number
|
|
276
|
-
let lastReport = 0
|
|
309
|
+
cardProps?: CompProps;
|
|
310
|
+
changedAt: number;
|
|
311
|
+
reportedAt: number;
|
|
312
|
+
};
|
|
313
|
+
const s: { [name: string]: S } = {};
|
|
314
|
+
let dispatch: Dispatch<Action>;
|
|
315
|
+
let timer: number;
|
|
316
|
+
let lastReport = 0;
|
|
277
317
|
|
|
278
318
|
// const timer
|
|
279
319
|
const getS = (cardName: string, props: CompProps): S => {
|
|
280
|
-
const name = cardName
|
|
281
|
-
let e = s[name]
|
|
320
|
+
const name = cardName;
|
|
321
|
+
let e = s[name];
|
|
282
322
|
if (!e) {
|
|
283
|
-
const ts = Date.now()
|
|
323
|
+
const ts = Date.now();
|
|
284
324
|
e = {
|
|
285
325
|
changedAt: ts,
|
|
286
326
|
reportedAt: ts,
|
|
287
|
-
} as S
|
|
288
|
-
s[name] = e
|
|
289
|
-
resetTimer()
|
|
327
|
+
} as S;
|
|
328
|
+
s[name] = e;
|
|
329
|
+
resetTimer();
|
|
290
330
|
}
|
|
291
|
-
return e
|
|
292
|
-
}
|
|
331
|
+
return e;
|
|
332
|
+
};
|
|
293
333
|
const resetTimer = () => {
|
|
294
334
|
if (timer) {
|
|
295
|
-
clearTimeout(timer)
|
|
335
|
+
clearTimeout(timer);
|
|
296
336
|
}
|
|
297
337
|
timer = window.setTimeout(() => {
|
|
298
338
|
//logger.debug("... timer went off") // , s, dispatch)
|
|
299
339
|
if (dispatch) {
|
|
300
|
-
const changed = Object.values(s).filter(
|
|
340
|
+
const changed = Object.values(s).filter(
|
|
341
|
+
(s) => s.changedAt > lastReport
|
|
342
|
+
);
|
|
301
343
|
if (changed.length > 0) {
|
|
302
|
-
clearTimeout(timer) // just in case
|
|
303
|
-
dispatch({ type: UPDATE_STATE_ACTION })
|
|
344
|
+
clearTimeout(timer); // just in case
|
|
345
|
+
dispatch({ type: UPDATE_STATE_ACTION });
|
|
304
346
|
}
|
|
305
347
|
}
|
|
306
|
-
}, 1000)
|
|
307
|
-
}
|
|
348
|
+
}, 1000);
|
|
349
|
+
};
|
|
308
350
|
const props = (
|
|
309
351
|
cardName: string,
|
|
310
352
|
cardProps: CompProps,
|
|
311
|
-
_dispatch: Dispatch<Action
|
|
353
|
+
_dispatch: Dispatch<Action>
|
|
312
354
|
) => {
|
|
313
|
-
const e = getS(cardName, cardProps)
|
|
314
|
-
e.cardProps = cardProps
|
|
315
|
-
dispatch = _dispatch
|
|
316
|
-
}
|
|
317
|
-
const changed = (
|
|
318
|
-
|
|
319
|
-
|
|
355
|
+
const e = getS(cardName, cardProps);
|
|
356
|
+
e.cardProps = cardProps;
|
|
357
|
+
dispatch = _dispatch;
|
|
358
|
+
};
|
|
359
|
+
const changed = (
|
|
360
|
+
cardName: string,
|
|
361
|
+
isUnchanged: boolean,
|
|
362
|
+
props: CompProps
|
|
363
|
+
) => {
|
|
364
|
+
const e = getS(cardName, props);
|
|
365
|
+
e.reportedAt = Date.now();
|
|
320
366
|
if (!isUnchanged) {
|
|
321
|
-
logger.debug("card has changed:", cardName)
|
|
322
|
-
e.changedAt = Date.now()
|
|
323
|
-
resetTimer()
|
|
367
|
+
logger.debug("card has changed:", cardName);
|
|
368
|
+
e.changedAt = Date.now();
|
|
369
|
+
resetTimer();
|
|
324
370
|
}
|
|
325
|
-
}
|
|
371
|
+
};
|
|
326
372
|
const reducer = (state: ReduxState): ReduxState => {
|
|
327
373
|
const pi = Object.values(s)
|
|
328
374
|
.filter((s) => s.reportedAt > lastReport)
|
|
329
375
|
.reduce((p, s) => {
|
|
330
|
-
const cname = s.cardProps?.cardName
|
|
376
|
+
const cname = s.cardProps?.cardName;
|
|
331
377
|
if (!cname) {
|
|
332
|
-
logger.warn("Unexpected missing card name", s)
|
|
333
|
-
return p
|
|
378
|
+
logger.warn("Unexpected missing card name", s);
|
|
379
|
+
return p;
|
|
334
380
|
}
|
|
335
|
-
const name = cname
|
|
336
|
-
const props = copySafeProps(s.cardProps || {})
|
|
337
|
-
delete props.cardName
|
|
338
|
-
delete props._cls
|
|
339
|
-
p[name] = props
|
|
340
|
-
return p
|
|
341
|
-
}, {} as { [k: string]: any })
|
|
342
|
-
state.pihanga = pi
|
|
343
|
-
lastReport = Date.now()
|
|
344
|
-
return state
|
|
345
|
-
}
|
|
346
|
-
return { props, changed, reducer }
|
|
381
|
+
const name = cname;
|
|
382
|
+
const props = copySafeProps(s.cardProps || {});
|
|
383
|
+
delete props.cardName;
|
|
384
|
+
delete props._cls;
|
|
385
|
+
p[name] = props;
|
|
386
|
+
return p;
|
|
387
|
+
}, {} as { [k: string]: any });
|
|
388
|
+
state.pihanga = pi;
|
|
389
|
+
lastReport = Date.now();
|
|
390
|
+
return state;
|
|
391
|
+
};
|
|
392
|
+
return { props, changed, reducer };
|
|
347
393
|
}
|
|
348
394
|
|
|
349
395
|
function copySafeProps(props: CompProps): CompProps {
|
|
350
396
|
return Object.entries(props).reduce((p, [k, v]) => {
|
|
351
397
|
// const ok = (typeof v === 'undefined' || typeof v === 'string' || typeof v === 'boolean' || typeof v === 'number' || Array.isArray(v));
|
|
352
|
-
const sv = makeSafe(v)
|
|
353
|
-
p[k] = sv
|
|
354
|
-
return p
|
|
355
|
-
}, {} as CompProps)
|
|
398
|
+
const sv = makeSafe(v);
|
|
399
|
+
p[k] = sv;
|
|
400
|
+
return p;
|
|
401
|
+
}, {} as CompProps);
|
|
356
402
|
}
|
|
357
403
|
|
|
358
404
|
function makeSafe(v: any): any {
|
|
359
|
-
const t = typeof v
|
|
360
|
-
if (
|
|
361
|
-
|
|
405
|
+
const t = typeof v;
|
|
406
|
+
if (
|
|
407
|
+
t === "undefined" ||
|
|
408
|
+
t === "string" ||
|
|
409
|
+
t === "boolean" ||
|
|
410
|
+
t === "number"
|
|
411
|
+
) {
|
|
412
|
+
return v;
|
|
362
413
|
}
|
|
363
|
-
if (t ===
|
|
364
|
-
return "f(...)"
|
|
414
|
+
if (t === "function") {
|
|
415
|
+
return "f(...)";
|
|
365
416
|
}
|
|
366
417
|
if (Array.isArray(v)) {
|
|
367
|
-
return v.map(makeSafe)
|
|
418
|
+
return v.map(makeSafe);
|
|
368
419
|
}
|
|
369
|
-
if (t ===
|
|
420
|
+
if (t === "object") {
|
|
370
421
|
return Object.entries(v).reduce((p, [k, v]) => {
|
|
371
|
-
p[k] = makeSafe(v)
|
|
372
|
-
return p
|
|
373
|
-
}, {} as { [k: string]: any })
|
|
422
|
+
p[k] = makeSafe(v);
|
|
423
|
+
return p;
|
|
424
|
+
}, {} as { [k: string]: any });
|
|
374
425
|
}
|
|
375
|
-
logger.warn(">>> reject", v, typeof v)
|
|
376
|
-
return "..."
|
|
426
|
+
logger.warn(">>> reject", v, typeof v);
|
|
427
|
+
return "...";
|
|
377
428
|
}
|
package/src/index.ts
CHANGED
|
@@ -52,7 +52,7 @@ export type {
|
|
|
52
52
|
WindowProps,
|
|
53
53
|
} from "./types"
|
|
54
54
|
export { registerActions, actionTypesToEvents, createOnAction } from "./redux"
|
|
55
|
-
export { Card } from "./card"
|
|
55
|
+
export { Card, usePiReducer } from "./card"
|
|
56
56
|
export { memo, createCardDeclaration, isCardRef } from "./register_cards"
|
|
57
57
|
export { getLogger } from "./logger"
|
|
58
58
|
export type { PiCardProps, PiCardRef } from "./types"
|
|
@@ -166,6 +166,10 @@ export function start<S extends Partial<ReduxState>>(
|
|
|
166
166
|
}
|
|
167
167
|
})
|
|
168
168
|
})
|
|
169
|
+
// make pihanga's reducer interface available to cards
|
|
170
|
+
const anyStore: any = store
|
|
171
|
+
anyStore.piReducer = piReducer
|
|
172
|
+
|
|
169
173
|
dispatchF = store.dispatch
|
|
170
174
|
|
|
171
175
|
const card = registerCard(piReducer.register, dispatchF)
|