@pihanga2/core 0.2.0 → 0.3.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/card.d.ts +1 -8
- package/dist/card.d.ts.map +1 -1
- package/dist/card.js +5 -185
- package/dist/card.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/dist/reducer.d.ts.map +1 -1
- package/dist/reducer.js +41 -32
- package/dist/reducer.js.map +1 -1
- package/dist/register_cards.d.ts +56 -0
- package/dist/register_cards.d.ts.map +1 -0
- package/dist/register_cards.js +235 -0
- package/dist/register_cards.js.map +1 -0
- package/dist/rest/types.d.ts +1 -1
- package/dist/rest/types.d.ts.map +1 -1
- package/dist/root.d.ts +3 -0
- package/dist/root.d.ts.map +1 -0
- package/dist/root.js +9 -0
- package/dist/root.js.map +1 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/types.d.ts +8 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -6
- package/src/card.tsx +4 -255
- package/src/{index.tsx → index.ts} +21 -14
- package/src/reducer.ts +48 -28
- package/src/register_cards.ts +308 -0
- package/src/rest/types.ts +1 -1
- package/src/root.tsx +14 -0
- package/src/types.ts +11 -4
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import equal from "deep-equal"
|
|
2
|
+
import { getLogger } from "./logger"
|
|
3
|
+
import {
|
|
4
|
+
CSSModuleClasses,
|
|
5
|
+
CardAction,
|
|
6
|
+
CardProp,
|
|
7
|
+
DispatchF,
|
|
8
|
+
GenericCardParameterT,
|
|
9
|
+
MetaCardMapperF,
|
|
10
|
+
PiCardDef,
|
|
11
|
+
PiCardRef,
|
|
12
|
+
PiMapProps,
|
|
13
|
+
PiRegisterComponent,
|
|
14
|
+
PiRegisterMetaCard,
|
|
15
|
+
PiRegisterReducerF,
|
|
16
|
+
ReduxState,
|
|
17
|
+
RegisterCardF,
|
|
18
|
+
StateMapper,
|
|
19
|
+
StateMapperContext,
|
|
20
|
+
} from "./types"
|
|
21
|
+
import { Action, AnyAction, Dispatch } from "@reduxjs/toolkit"
|
|
22
|
+
|
|
23
|
+
const logger = getLogger("card-register")
|
|
24
|
+
|
|
25
|
+
export function isCardRef(p: any): boolean {
|
|
26
|
+
return (typeof p === "object" && p.cardType !== undefined)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type Mapping = {
|
|
30
|
+
cardType: string
|
|
31
|
+
props: { [k: string]: unknown }
|
|
32
|
+
eventMappers: { [k: string]: (ev: Action) => Action | null }
|
|
33
|
+
cardEvents: { [key: string]: string }
|
|
34
|
+
parameters: PiCardDef // original
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type MetaCard = {
|
|
38
|
+
type: string
|
|
39
|
+
registerCard: RegisterCardF
|
|
40
|
+
mapper: MetaCardMapperF
|
|
41
|
+
events?: { [key: string]: string }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const cardTypes: { [k: string]: PiRegisterComponent } = {}
|
|
45
|
+
export const metacardTypes: { [k: string]: MetaCard } = {}
|
|
46
|
+
|
|
47
|
+
export let framework: string // name of active UI framework
|
|
48
|
+
export const cardMappings: { [k: string]: Mapping } = {}
|
|
49
|
+
export const dispatch2registerReducer: [React.Dispatch<any>, PiRegisterReducerF][] = []
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
export function registerCardComponent(card: PiRegisterComponent): void {
|
|
53
|
+
if (cardTypes[card.name]) {
|
|
54
|
+
logger.warn(`Overwriting definition for card type "${card.name}"`)
|
|
55
|
+
}
|
|
56
|
+
logger.info(`Register card type "${card.name}"`)
|
|
57
|
+
if (!framework) {
|
|
58
|
+
// set default framework
|
|
59
|
+
const na = card.name.split("/")
|
|
60
|
+
if (na.length >= 2) {
|
|
61
|
+
framework = na[0]
|
|
62
|
+
logger.info(`Setting UI framework to "${framework}"`)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
cardTypes[card.name] = card
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function registerMetacard(registerCard: RegisterCardF) {
|
|
69
|
+
function f<C>(declaration: PiRegisterMetaCard) {
|
|
70
|
+
const { type, mapper, events } = declaration
|
|
71
|
+
if (metacardTypes[type]) {
|
|
72
|
+
logger.warn(`Overwriting definition for meta card type "${type}"`)
|
|
73
|
+
}
|
|
74
|
+
logger.info(`Register meta card type "${type}"`)
|
|
75
|
+
metacardTypes[type] = { type, registerCard, mapper, events }
|
|
76
|
+
}
|
|
77
|
+
return f
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
export function registerCard(
|
|
82
|
+
registerReducer: PiRegisterReducerF,
|
|
83
|
+
dispatchF: React.Dispatch<any>,
|
|
84
|
+
) {
|
|
85
|
+
// to be used by dynamically registered cards
|
|
86
|
+
dispatch2registerReducer.push([dispatchF, registerReducer])
|
|
87
|
+
return (name: string, parameters: PiCardDef): PiCardRef => {
|
|
88
|
+
return _registerCard(name, parameters, registerReducer)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function updateOrRegisterCard(
|
|
93
|
+
registerReducer: PiRegisterReducerF,
|
|
94
|
+
dispatchF: React.Dispatch<any>,
|
|
95
|
+
) {
|
|
96
|
+
// to be used by dynamically registered cards
|
|
97
|
+
dispatch2registerReducer.push([dispatchF, registerReducer])
|
|
98
|
+
return (name: string, parameters: { [key: string]: GenericCardParameterT }): PiCardRef => {
|
|
99
|
+
return _updateCard(name, parameters, registerReducer)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function _registerCard(
|
|
104
|
+
name: string,
|
|
105
|
+
parameters: PiCardDef,
|
|
106
|
+
registerReducer: PiRegisterReducerF,
|
|
107
|
+
overrideEvents?: { [key: string]: string },
|
|
108
|
+
): PiCardRef {
|
|
109
|
+
if (cardMappings[name]) {
|
|
110
|
+
logger.warn(`Overwriting definition for card "${name}"`)
|
|
111
|
+
}
|
|
112
|
+
let cardType = cardTypes[parameters.cardType]
|
|
113
|
+
if (!cardType) {
|
|
114
|
+
if (framework) {
|
|
115
|
+
cardType = cardTypes[`${framework}/${parameters.cardType}`]
|
|
116
|
+
}
|
|
117
|
+
if (!cardType) {
|
|
118
|
+
// maybe it's a metadata card
|
|
119
|
+
if (_registerMetadataCard(name, parameters, registerReducer)) {
|
|
120
|
+
return name
|
|
121
|
+
}
|
|
122
|
+
logger.warn("unknown card type", parameters.cardType)
|
|
123
|
+
return name
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const events = overrideEvents || cardType.events || {}
|
|
128
|
+
_createCardMapping(name, parameters, registerReducer, events)
|
|
129
|
+
return name
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function _updateCard(
|
|
133
|
+
name: string,
|
|
134
|
+
parameters: { [key: string]: GenericCardParameterT },
|
|
135
|
+
registerReducer: PiRegisterReducerF,
|
|
136
|
+
overrideEvents?: { [key: string]: string },
|
|
137
|
+
): PiCardRef {
|
|
138
|
+
const mappings = cardMappings[name]
|
|
139
|
+
if (!mappings) {
|
|
140
|
+
// first time
|
|
141
|
+
if (!parameters.cardType) {
|
|
142
|
+
logger.warn("missing 'cardType'", name)
|
|
143
|
+
return name
|
|
144
|
+
}
|
|
145
|
+
const p: any = parameters
|
|
146
|
+
return _registerCard(name, p, registerReducer, overrideEvents)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const p = { ...mappings.parameters, ...parameters }
|
|
150
|
+
_createCardMapping(name, p, registerReducer, mappings.cardEvents)
|
|
151
|
+
return name
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function _createCardMapping(
|
|
156
|
+
name: string,
|
|
157
|
+
parameters: PiCardDef,
|
|
158
|
+
registerReducer: PiRegisterReducerF,
|
|
159
|
+
cardEvents: { [key: string]: string },
|
|
160
|
+
) {
|
|
161
|
+
const props = {} as { [k: string]: unknown }
|
|
162
|
+
const eventMappers = {} as { [k: string]: (ev: Action) => Action }
|
|
163
|
+
|
|
164
|
+
Object.entries(parameters).forEach(([k, v]) => {
|
|
165
|
+
if (k === "cardType") return
|
|
166
|
+
if (typeof v === "object") {
|
|
167
|
+
const cd = v as PiCardDef // speculative
|
|
168
|
+
if (cd.cardType) {
|
|
169
|
+
const cardName = `${name}/${k}`
|
|
170
|
+
v = _registerCard(cardName, cd, registerReducer)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (
|
|
174
|
+
k.startsWith("on") &&
|
|
175
|
+
processEventParameter(k, v, cardEvents, eventMappers, registerReducer, name)
|
|
176
|
+
) {
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
props[k] = v
|
|
180
|
+
})
|
|
181
|
+
cardMappings[name] = { cardType: parameters.cardType, props, eventMappers, cardEvents, parameters }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function _updateCardMapping(
|
|
185
|
+
name: string,
|
|
186
|
+
parameters: PiCardDef,
|
|
187
|
+
registerReducer: PiRegisterReducerF,
|
|
188
|
+
mappings: Mapping,
|
|
189
|
+
) {
|
|
190
|
+
return _createCardMapping(name, parameters, registerReducer, mappings.cardEvents)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function _registerMetadataCard(
|
|
194
|
+
metaName: string,
|
|
195
|
+
parameters: PiCardDef,
|
|
196
|
+
registerReducer: PiRegisterReducerF,
|
|
197
|
+
): boolean {
|
|
198
|
+
let mc = metacardTypes[parameters.cardType]
|
|
199
|
+
if (!mc) {
|
|
200
|
+
if (framework) {
|
|
201
|
+
mc = metacardTypes[`${framework}/${parameters.cardType}`]
|
|
202
|
+
}
|
|
203
|
+
if (!mc) {
|
|
204
|
+
return false
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function registerCard(name: string, parameters: PiCardDef): PiCardRef {
|
|
208
|
+
const n = `${metaName}/${name}`
|
|
209
|
+
return mc.registerCard(n, parameters)
|
|
210
|
+
}
|
|
211
|
+
const top = mc.mapper(metaName, parameters, registerCard)
|
|
212
|
+
_registerCard(metaName, top, registerReducer, mc.events)
|
|
213
|
+
return true
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// NOT IMPLEMENTED YET
|
|
217
|
+
// function _updateMetadataCard(
|
|
218
|
+
// metaName: string,
|
|
219
|
+
// parameters: PiCardDef,
|
|
220
|
+
// registerReducer: PiRegisterReducerF,
|
|
221
|
+
// ): boolean {
|
|
222
|
+
// let mc = metacardTypes[parameters.cardType]
|
|
223
|
+
// if (!mc) {
|
|
224
|
+
// if (framework) {
|
|
225
|
+
// mc = metacardTypes[`${framework}/${parameters.cardType}`]
|
|
226
|
+
// }
|
|
227
|
+
// if (!mc) {
|
|
228
|
+
// return false
|
|
229
|
+
// }
|
|
230
|
+
// }
|
|
231
|
+
// function updateCard(name: string, parameters: PiCardDef): PiCardRef {
|
|
232
|
+
// const n = `${metaName}/${name}`
|
|
233
|
+
// return mc.updateCard(n, parameters)
|
|
234
|
+
// }
|
|
235
|
+
// const top = mc.mapper(metaName, parameters, updateCard)
|
|
236
|
+
// _updateCard(metaName, top, registerReducer, mc.events)
|
|
237
|
+
// return true
|
|
238
|
+
// }
|
|
239
|
+
|
|
240
|
+
export function createCardDeclaration<Props = {}, Events = {}>(
|
|
241
|
+
cardType: string,
|
|
242
|
+
): <S extends ReduxState>(p: PiMapProps<Props, S, Events>) => PiCardDef {
|
|
243
|
+
return (p) => ({
|
|
244
|
+
...p,
|
|
245
|
+
cardType,
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function processEventParameter(
|
|
250
|
+
propName: string,
|
|
251
|
+
value: unknown,
|
|
252
|
+
events: { [key: string]: string },
|
|
253
|
+
eventMappers: { [k: string]: (ev: Action) => Action },
|
|
254
|
+
registerReducer: PiRegisterReducerF,
|
|
255
|
+
cardName: string,
|
|
256
|
+
): boolean {
|
|
257
|
+
const eva = Object.entries(events).find(([n, _]) => {
|
|
258
|
+
return propName === n || propName === `${n}Mapper`
|
|
259
|
+
})
|
|
260
|
+
if (!eva) {
|
|
261
|
+
logger.warn(
|
|
262
|
+
`encountered property '${propName}' for card '${cardName}' which looks like an even but is not defined`,
|
|
263
|
+
)
|
|
264
|
+
return false
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const [evName, actionType] = eva
|
|
268
|
+
if (propName === evName) {
|
|
269
|
+
const r = value as (state: ReduxState, action: CardAction, dispatch: DispatchF) => ReduxState
|
|
270
|
+
registerReducer(actionType, (s, a, d) => {
|
|
271
|
+
const ca = a as CardAction
|
|
272
|
+
if (ca.cardID === cardName) {
|
|
273
|
+
s = r(s, ca, d)
|
|
274
|
+
}
|
|
275
|
+
return s
|
|
276
|
+
}, 0, `${cardName}|${propName}`)
|
|
277
|
+
}
|
|
278
|
+
if (propName === `${evName}Mapper`) {
|
|
279
|
+
logger.debug("processEventParameter", cardName)
|
|
280
|
+
|
|
281
|
+
const m = value as (ev: Action) => Action
|
|
282
|
+
eventMappers[evName] = m
|
|
283
|
+
}
|
|
284
|
+
return true
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function memo<P, T, S extends ReduxState, C>(
|
|
288
|
+
filterF: (state: S, context: StateMapperContext<C>) => P,
|
|
289
|
+
mapperF: (partial: P, context: StateMapperContext<C>, state: S) => T,
|
|
290
|
+
): (state: S, context: StateMapperContext<C>) => T {
|
|
291
|
+
const lastFilter: { [k: string]: P } = {}
|
|
292
|
+
const lastValue: { [k: string]: T } = {}
|
|
293
|
+
const isNotFirst: { [k: string]: boolean } = {}
|
|
294
|
+
|
|
295
|
+
return (state: S, context: StateMapperContext<C>): T => {
|
|
296
|
+
const k = context.cardKey || "-"
|
|
297
|
+
const fv = filterF(state, context)
|
|
298
|
+
if (isNotFirst[k] && equal(fv, lastFilter[k])) {
|
|
299
|
+
// nothing changed
|
|
300
|
+
return lastValue[k]
|
|
301
|
+
}
|
|
302
|
+
lastFilter[k] = fv
|
|
303
|
+
const v = mapperF(fv, context, state)
|
|
304
|
+
lastValue[k] = v
|
|
305
|
+
isNotFirst[k] = true
|
|
306
|
+
return v
|
|
307
|
+
}
|
|
308
|
+
}
|
package/src/rest/types.ts
CHANGED
package/src/root.tsx
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { Provider } from "react-redux"
|
|
3
|
+
|
|
4
|
+
import { Card } from "./card"
|
|
5
|
+
|
|
6
|
+
export function RootComponent(store: any) {
|
|
7
|
+
return (
|
|
8
|
+
<React.StrictMode>
|
|
9
|
+
<Provider store={store}>
|
|
10
|
+
<Card cardName="_window" parentCard="" />
|
|
11
|
+
</Provider>
|
|
12
|
+
</React.StrictMode>
|
|
13
|
+
)
|
|
14
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -31,13 +31,13 @@ export type ReduceF<S extends ReduxState, A extends ReduxAction> = (
|
|
|
31
31
|
state: S,
|
|
32
32
|
action: A,
|
|
33
33
|
dispatch: DispatchF,
|
|
34
|
-
) => S
|
|
34
|
+
) => void // S
|
|
35
35
|
|
|
36
36
|
export type ReduceOnceF<S extends ReduxState, A extends ReduxAction> = (
|
|
37
37
|
state: S,
|
|
38
38
|
action: A,
|
|
39
39
|
dispatch: DispatchF,
|
|
40
|
-
) => [S, boolean]
|
|
40
|
+
) => boolean // [S, boolean]
|
|
41
41
|
|
|
42
42
|
export type DispatchF = <T extends ReduxAction>(a: T) => void
|
|
43
43
|
|
|
@@ -52,6 +52,7 @@ export type PiRegisterReducerF = <S extends ReduxState, A extends ReduxAction>(
|
|
|
52
52
|
eventType: string,
|
|
53
53
|
mapper: ReduceF<S, A>, // (state: S, action: A, dispatch: DispatchF) => S,
|
|
54
54
|
priority?: number,
|
|
55
|
+
key?: string,
|
|
55
56
|
) => void
|
|
56
57
|
|
|
57
58
|
export type PiRegisterOneShotReducerF = <
|
|
@@ -76,6 +77,12 @@ export type CardProp = {
|
|
|
76
77
|
parentCard: string
|
|
77
78
|
} & PiDefCtxtProps
|
|
78
79
|
|
|
80
|
+
// props for the 'root' of all cards
|
|
81
|
+
export type WindowProps = {
|
|
82
|
+
page: PiCardRef
|
|
83
|
+
framework?: string // select framework to render window
|
|
84
|
+
theme?: any // depends on framework
|
|
85
|
+
}
|
|
79
86
|
|
|
80
87
|
// type which needs to be implemented by card components
|
|
81
88
|
export type PiCardProps<P, E = {}> = P & {
|
|
@@ -84,8 +91,8 @@ export type PiCardProps<P, E = {}> = P & {
|
|
|
84
91
|
_cls: (elName: string | string[], styles?: CSSModuleClasses) => string
|
|
85
92
|
_dispatch: DispatchF
|
|
86
93
|
} & {
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
[Key in keyof E]: (ev: E[Key]) => void
|
|
95
|
+
}
|
|
89
96
|
|
|
90
97
|
export type CSSModuleClasses = { readonly [key: string]: string }
|
|
91
98
|
|