@nordcraft/runtime 1.0.95 → 1.0.97
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/api/createAPI.js +29 -11
- package/dist/api/createAPI.js.map +1 -1
- package/dist/api/createAPIv2.js +49 -11
- package/dist/api/createAPIv2.js.map +1 -1
- package/dist/components/createComponent.js +19 -10
- package/dist/components/createComponent.js.map +1 -1
- package/dist/components/createElement.js +48 -16
- package/dist/components/createElement.js.map +1 -1
- package/dist/components/createNode.js +22 -11
- package/dist/components/createNode.js.map +1 -1
- package/dist/components/createNode.test.js +3 -3
- package/dist/components/createNode.test.js.map +1 -1
- package/dist/components/createSlot.js +2 -1
- package/dist/components/createSlot.js.map +1 -1
- package/dist/components/createText.js +7 -2
- package/dist/components/createText.js.map +1 -1
- package/dist/components/renderComponent.d.ts +4 -1
- package/dist/components/renderComponent.js +4 -2
- package/dist/components/renderComponent.js.map +1 -1
- package/dist/context/subscribeToContext.js +12 -2
- package/dist/context/subscribeToContext.js.map +1 -1
- package/dist/custom-element/ToddleComponent.js +12 -4
- package/dist/custom-element/ToddleComponent.js.map +1 -1
- package/dist/custom-element.main.esm.js +29 -29
- package/dist/custom-element.main.esm.js.map +4 -4
- package/dist/editor/editorUtils.d.ts +2 -0
- package/dist/editor/editorUtils.js +26 -0
- package/dist/editor/editorUtils.js.map +1 -0
- package/dist/editor/types.d.ts +4 -0
- package/dist/editor/types.js.map +1 -1
- package/dist/editor-preview.main.js +82 -18
- package/dist/editor-preview.main.js.map +1 -1
- package/dist/events/handleAction.js +74 -42
- package/dist/events/handleAction.js.map +1 -1
- package/dist/page.main.esm.js +3 -3
- package/dist/page.main.esm.js.map +4 -4
- package/dist/page.main.js +39 -8
- package/dist/page.main.js.map +1 -1
- package/dist/utils/createFormulaCache.js.map +1 -1
- package/dist/utils/nodes.d.ts +1 -0
- package/dist/utils/nodes.js +9 -0
- package/dist/utils/nodes.js.map +1 -1
- package/dist/utils/nodes.test.d.ts +1 -0
- package/dist/utils/nodes.test.js +192 -0
- package/dist/utils/nodes.test.js.map +1 -0
- package/dist/utils/subscribeCustomProperty.d.ts +1 -1
- package/dist/utils/subscribeCustomProperty.js +8 -4
- package/dist/utils/subscribeCustomProperty.js.map +1 -1
- package/dist/utils/subscribeCustomProperty.test.d.ts +1 -0
- package/dist/utils/subscribeCustomProperty.test.js +63 -0
- package/dist/utils/subscribeCustomProperty.test.js.map +1 -0
- package/package.json +3 -3
- package/src/api/createAPI.ts +90 -46
- package/src/api/createAPIv2.ts +79 -13
- package/src/components/createComponent.ts +123 -85
- package/src/components/createElement.ts +63 -27
- package/src/components/createNode.test.ts +3 -3
- package/src/components/createNode.ts +55 -31
- package/src/components/createSlot.ts +2 -1
- package/src/components/createText.ts +35 -18
- package/src/components/renderComponent.ts +8 -1
- package/src/context/subscribeToContext.ts +12 -2
- package/src/custom-element/ToddleComponent.ts +37 -22
- package/src/editor/editorUtils.ts +28 -0
- package/src/editor/types.ts +5 -0
- package/src/editor-preview.main.ts +137 -46
- package/src/events/handleAction.ts +190 -113
- package/src/page.main.ts +64 -26
- package/src/types.d.ts +3 -0
- package/src/utils/createFormulaCache.ts +2 -2
- package/src/utils/nodes.test.ts +246 -0
- package/src/utils/nodes.ts +11 -0
- package/src/utils/subscribeCustomProperty.test.ts +78 -0
- package/src/utils/subscribeCustomProperty.ts +21 -22
package/src/api/createAPI.ts
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
import type { LegacyComponentAPI } from '@nordcraft/core/dist/api/apiTypes'
|
|
3
3
|
import { mapHeadersToObject } from '@nordcraft/core/dist/api/headers'
|
|
4
4
|
import type { ComponentData } from '@nordcraft/core/dist/component/component.types'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
applyFormula,
|
|
7
|
+
isFormula,
|
|
8
|
+
type FormulaContext,
|
|
9
|
+
} from '@nordcraft/core/dist/formula/formula'
|
|
6
10
|
import type { Nullable } from '@nordcraft/core/dist/types'
|
|
7
|
-
import {
|
|
11
|
+
import { mapObject } from '@nordcraft/core/dist/utils/collections'
|
|
8
12
|
import { parseJSONWithDate } from '@nordcraft/core/dist/utils/json'
|
|
9
13
|
import { handleAction } from '../events/handleAction'
|
|
10
14
|
import type { Signal } from '../signal/signal'
|
|
@@ -35,7 +39,7 @@ export function createLegacyAPI(
|
|
|
35
39
|
api: LegacyComponentAPI,
|
|
36
40
|
data: ComponentData,
|
|
37
41
|
): ApiRequest {
|
|
38
|
-
const formulaContext = {
|
|
42
|
+
const formulaContext: FormulaContext = {
|
|
39
43
|
data,
|
|
40
44
|
component: ctx.component,
|
|
41
45
|
formulaCache: ctx.formulaCache,
|
|
@@ -43,14 +47,20 @@ export function createLegacyAPI(
|
|
|
43
47
|
package: ctx.package,
|
|
44
48
|
toddle: ctx.toddle,
|
|
45
49
|
env: ctx.env,
|
|
50
|
+
jsonPath: ctx.jsonPath,
|
|
51
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
// construct the url
|
|
49
|
-
const baseUrl = applyFormula(api.url, formulaContext) ?? ''
|
|
55
|
+
const baseUrl = applyFormula(api.url, formulaContext, ['url']) ?? ''
|
|
50
56
|
const urlPath =
|
|
51
57
|
api.path && api.path.length > 0
|
|
52
58
|
? '/' +
|
|
53
|
-
api.path
|
|
59
|
+
api.path
|
|
60
|
+
.map((p, i) =>
|
|
61
|
+
applyFormula(p.formula, formulaContext, ['path', i, 'formula']),
|
|
62
|
+
)
|
|
63
|
+
.join('/')
|
|
54
64
|
: ''
|
|
55
65
|
|
|
56
66
|
// build querystring
|
|
@@ -60,25 +70,21 @@ export function createLegacyAPI(
|
|
|
60
70
|
? '?' +
|
|
61
71
|
queryParams
|
|
62
72
|
.map(
|
|
63
|
-
(param) =>
|
|
73
|
+
(param, i) =>
|
|
64
74
|
`${param.name}=${encodeURIComponent(
|
|
65
|
-
applyFormula(param.formula, formulaContext
|
|
75
|
+
applyFormula(param.formula, formulaContext, [
|
|
76
|
+
'queryParams',
|
|
77
|
+
i,
|
|
78
|
+
'formula',
|
|
79
|
+
]),
|
|
66
80
|
)}`,
|
|
67
81
|
)
|
|
68
82
|
.join('&')
|
|
69
83
|
: ''
|
|
70
84
|
const headers = isFormula(api.headers) // this is supporting a few legacy cases where the whole header object was set as a formula. This is no longer possible
|
|
71
|
-
? applyFormula(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
formulaCache: ctx.formulaCache,
|
|
75
|
-
root: ctx.root,
|
|
76
|
-
package: ctx.package,
|
|
77
|
-
toddle: ctx.toddle,
|
|
78
|
-
env: ctx.env,
|
|
79
|
-
})
|
|
80
|
-
: mapValues(api.headers ?? {}, (value) =>
|
|
81
|
-
applyFormula(value, {
|
|
85
|
+
? applyFormula(
|
|
86
|
+
api.headers,
|
|
87
|
+
{
|
|
82
88
|
data,
|
|
83
89
|
component: ctx.component,
|
|
84
90
|
formulaCache: ctx.formulaCache,
|
|
@@ -86,7 +92,27 @@ export function createLegacyAPI(
|
|
|
86
92
|
package: ctx.package,
|
|
87
93
|
toddle: ctx.toddle,
|
|
88
94
|
env: ctx.env,
|
|
89
|
-
|
|
95
|
+
jsonPath: ctx.jsonPath,
|
|
96
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
97
|
+
},
|
|
98
|
+
['headers'],
|
|
99
|
+
)
|
|
100
|
+
: mapObject(api.headers ?? {}, ([key, value]) =>
|
|
101
|
+
applyFormula(
|
|
102
|
+
value,
|
|
103
|
+
{
|
|
104
|
+
data,
|
|
105
|
+
component: ctx.component,
|
|
106
|
+
formulaCache: ctx.formulaCache,
|
|
107
|
+
root: ctx.root,
|
|
108
|
+
package: ctx.package,
|
|
109
|
+
toddle: ctx.toddle,
|
|
110
|
+
env: ctx.env,
|
|
111
|
+
jsonPath: ctx.jsonPath,
|
|
112
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
113
|
+
},
|
|
114
|
+
['headers', key],
|
|
115
|
+
),
|
|
90
116
|
)
|
|
91
117
|
const contentType = String(
|
|
92
118
|
Object.entries(headers).find(
|
|
@@ -97,15 +123,21 @@ export function createLegacyAPI(
|
|
|
97
123
|
const body =
|
|
98
124
|
api.body && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)
|
|
99
125
|
? encodeBody(
|
|
100
|
-
applyFormula(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
126
|
+
applyFormula(
|
|
127
|
+
api.body,
|
|
128
|
+
{
|
|
129
|
+
data,
|
|
130
|
+
component: ctx.component,
|
|
131
|
+
formulaCache: ctx.formulaCache,
|
|
132
|
+
root: ctx.root,
|
|
133
|
+
package: ctx.package,
|
|
134
|
+
toddle: ctx.toddle,
|
|
135
|
+
env: ctx.env,
|
|
136
|
+
jsonPath: ctx.jsonPath,
|
|
137
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
138
|
+
},
|
|
139
|
+
['body'],
|
|
140
|
+
),
|
|
109
141
|
contentType,
|
|
110
142
|
)
|
|
111
143
|
: undefined
|
|
@@ -286,15 +318,21 @@ export function createLegacyAPI(
|
|
|
286
318
|
data: null,
|
|
287
319
|
isLoading:
|
|
288
320
|
api.autoFetch &&
|
|
289
|
-
applyFormula(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
321
|
+
applyFormula(
|
|
322
|
+
api.autoFetch,
|
|
323
|
+
{
|
|
324
|
+
data: ctx.dataSignal.get(),
|
|
325
|
+
component: ctx.component,
|
|
326
|
+
formulaCache: ctx.formulaCache,
|
|
327
|
+
root: ctx.root,
|
|
328
|
+
package: ctx.package,
|
|
329
|
+
toddle: ctx.toddle,
|
|
330
|
+
env: ctx.env,
|
|
331
|
+
jsonPath: ctx.jsonPath,
|
|
332
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
333
|
+
},
|
|
334
|
+
['autoFetch'],
|
|
335
|
+
)
|
|
298
336
|
? true
|
|
299
337
|
: false,
|
|
300
338
|
error: null,
|
|
@@ -308,15 +346,21 @@ export function createLegacyAPI(
|
|
|
308
346
|
payloadSignal.subscribe((body) => {
|
|
309
347
|
if (
|
|
310
348
|
api.autoFetch &&
|
|
311
|
-
applyFormula(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
349
|
+
applyFormula(
|
|
350
|
+
api.autoFetch,
|
|
351
|
+
{
|
|
352
|
+
data: ctx.dataSignal.get(),
|
|
353
|
+
component: ctx.component,
|
|
354
|
+
formulaCache: ctx.formulaCache,
|
|
355
|
+
root: ctx.root,
|
|
356
|
+
package: ctx.package,
|
|
357
|
+
toddle: ctx.toddle,
|
|
358
|
+
env: ctx.env,
|
|
359
|
+
jsonPath: ctx.jsonPath,
|
|
360
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
361
|
+
},
|
|
362
|
+
['autoFetch'],
|
|
363
|
+
)
|
|
320
364
|
) {
|
|
321
365
|
// We should only lookup cached data for pages since
|
|
322
366
|
// we don't fetch data for component APIs during SSR
|
package/src/api/createAPIv2.ts
CHANGED
|
@@ -97,7 +97,7 @@ export function createAPI({
|
|
|
97
97
|
componentData: ComponentData | undefined,
|
|
98
98
|
): FormulaContext {
|
|
99
99
|
// Use the general formula context to evaluate the arguments of the api
|
|
100
|
-
const formulaContext = {
|
|
100
|
+
const formulaContext: FormulaContext = {
|
|
101
101
|
data: ctx.dataSignal.get(),
|
|
102
102
|
component: ctx.component,
|
|
103
103
|
formulaCache: ctx.formulaCache,
|
|
@@ -105,13 +105,15 @@ export function createAPI({
|
|
|
105
105
|
package: ctx.package,
|
|
106
106
|
toddle: ctx.toddle,
|
|
107
107
|
env: ctx.env,
|
|
108
|
+
jsonPath: ctx.jsonPath,
|
|
109
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
// Make sure inputs are also available in the formula context
|
|
111
113
|
const evaluatedInputs = Object.entries(api.inputs).reduce<
|
|
112
114
|
Record<string, unknown>
|
|
113
115
|
>((acc, [key, value]) => {
|
|
114
|
-
acc[key] = applyFormula(value.formula, formulaContext)
|
|
116
|
+
acc[key] = applyFormula(value.formula, formulaContext, ['inputs', key])
|
|
115
117
|
return acc
|
|
116
118
|
}, {})
|
|
117
119
|
|
|
@@ -131,6 +133,8 @@ export function createAPI({
|
|
|
131
133
|
data,
|
|
132
134
|
toddle: ctx.toddle,
|
|
133
135
|
env: ctx.env,
|
|
136
|
+
jsonPath: ctx.jsonPath,
|
|
137
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
134
138
|
}
|
|
135
139
|
}
|
|
136
140
|
|
|
@@ -140,15 +144,19 @@ export function createAPI({
|
|
|
140
144
|
([_, rule]) => rule.index,
|
|
141
145
|
)) {
|
|
142
146
|
const formulaContext = getFormulaContext(api, componentData)
|
|
143
|
-
const location = applyFormula(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
...formulaContext
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
const location = applyFormula(
|
|
148
|
+
rule.formula,
|
|
149
|
+
{
|
|
150
|
+
...formulaContext,
|
|
151
|
+
data: {
|
|
152
|
+
...formulaContext.data,
|
|
153
|
+
Apis: {
|
|
154
|
+
[api.name]: ctx.dataSignal.get().Apis?.[api.name] as ApiStatus,
|
|
155
|
+
},
|
|
149
156
|
},
|
|
150
157
|
},
|
|
151
|
-
|
|
158
|
+
['redirectRules', ruleName],
|
|
159
|
+
)
|
|
152
160
|
if (typeof location === 'string') {
|
|
153
161
|
const url = validateUrl({
|
|
154
162
|
path: location,
|
|
@@ -282,6 +290,22 @@ export function createAPI({
|
|
|
282
290
|
},
|
|
283
291
|
},
|
|
284
292
|
})
|
|
293
|
+
|
|
294
|
+
ctx.reportFormulaEvaluation?.(
|
|
295
|
+
['apis', api.name],
|
|
296
|
+
{
|
|
297
|
+
isLoading: false,
|
|
298
|
+
data: data.body,
|
|
299
|
+
error: null,
|
|
300
|
+
response: {
|
|
301
|
+
status: data.status,
|
|
302
|
+
headers: data.headers,
|
|
303
|
+
performance,
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
ctx,
|
|
307
|
+
)
|
|
308
|
+
|
|
285
309
|
const appliedRedirectRule = handleRedirectRules(api, componentData)
|
|
286
310
|
if (appliedRedirectRule) {
|
|
287
311
|
ctx.dataSignal.set({
|
|
@@ -345,6 +369,22 @@ export function createAPI({
|
|
|
345
369
|
},
|
|
346
370
|
},
|
|
347
371
|
})
|
|
372
|
+
|
|
373
|
+
ctx.reportFormulaEvaluation?.(
|
|
374
|
+
['apis', api.name],
|
|
375
|
+
{
|
|
376
|
+
isLoading: false,
|
|
377
|
+
data: null,
|
|
378
|
+
error: data.body,
|
|
379
|
+
response: {
|
|
380
|
+
status: data.status,
|
|
381
|
+
headers: data.headers,
|
|
382
|
+
performance,
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
ctx,
|
|
386
|
+
)
|
|
387
|
+
|
|
348
388
|
const appliedRedirectRule = handleRedirectRules(api, componentData)
|
|
349
389
|
if (appliedRedirectRule) {
|
|
350
390
|
ctx.dataSignal.set({
|
|
@@ -400,6 +440,17 @@ export function createAPI({
|
|
|
400
440
|
},
|
|
401
441
|
},
|
|
402
442
|
})
|
|
443
|
+
|
|
444
|
+
ctx.reportFormulaEvaluation?.(
|
|
445
|
+
['apis', api.name],
|
|
446
|
+
{
|
|
447
|
+
isLoading: true,
|
|
448
|
+
data: ctx.dataSignal.get().Apis?.[api.name]?.data ?? null,
|
|
449
|
+
error: null,
|
|
450
|
+
},
|
|
451
|
+
ctx,
|
|
452
|
+
)
|
|
453
|
+
|
|
403
454
|
let response
|
|
404
455
|
|
|
405
456
|
try {
|
|
@@ -407,6 +458,7 @@ export function createAPI({
|
|
|
407
458
|
? (applyFormula(
|
|
408
459
|
api.server.proxy.enabled.formula,
|
|
409
460
|
getFormulaContext(api, componentData),
|
|
461
|
+
['server', 'proxy', 'enabled'],
|
|
410
462
|
) ?? false)
|
|
411
463
|
: false
|
|
412
464
|
|
|
@@ -429,6 +481,7 @@ export function createAPI({
|
|
|
429
481
|
applyFormula(
|
|
430
482
|
api.server?.proxy?.useTemplatesInBody?.formula,
|
|
431
483
|
getFormulaContext(api, componentData),
|
|
484
|
+
['server', 'proxy', 'useTemplatesInBody'],
|
|
432
485
|
),
|
|
433
486
|
)
|
|
434
487
|
if (allowBodyTemplateValues) {
|
|
@@ -490,6 +543,7 @@ export function createAPI({
|
|
|
490
543
|
applyFormula(
|
|
491
544
|
api.client?.debounce?.formula,
|
|
492
545
|
getFormulaContext(api, componentData),
|
|
546
|
+
['client', 'debounce'],
|
|
493
547
|
),
|
|
494
548
|
)
|
|
495
549
|
})
|
|
@@ -984,15 +1038,24 @@ export function createAPI({
|
|
|
984
1038
|
payloadSignal = ctx.dataSignal.map((data) => {
|
|
985
1039
|
const payloadContext = getFormulaContext(api, data)
|
|
986
1040
|
const request = constructRequest(api, data)
|
|
1041
|
+
|
|
1042
|
+
if (ctx.reportFormulaEvaluation) {
|
|
1043
|
+
const apiStatus = data.Apis?.[api.name]
|
|
1044
|
+
if (apiStatus) {
|
|
1045
|
+
ctx.reportFormulaEvaluation(['apis', api.name], apiStatus, ctx)
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
987
1048
|
return {
|
|
988
1049
|
request,
|
|
989
1050
|
api: getApiForComparison(api),
|
|
990
1051
|
// Serialize the Headers object to be able to compare changes
|
|
991
1052
|
headers: Array.from(request.requestSettings.headers.entries()),
|
|
992
1053
|
autoFetch: api.autoFetch
|
|
993
|
-
? applyFormula(api.autoFetch, payloadContext)
|
|
1054
|
+
? applyFormula(api.autoFetch, payloadContext, ['autoFetch'])
|
|
994
1055
|
: false,
|
|
995
|
-
proxy: applyFormula(api.server?.proxy?.enabled.formula, payloadContext
|
|
1056
|
+
proxy: applyFormula(api.server?.proxy?.enabled.formula, payloadContext, [
|
|
1057
|
+
'proxy',
|
|
1058
|
+
]),
|
|
996
1059
|
}
|
|
997
1060
|
})
|
|
998
1061
|
payloadSignal.subscribe(async (apiData) => {
|
|
@@ -1050,6 +1113,7 @@ export function createAPI({
|
|
|
1050
1113
|
applyFormula(
|
|
1051
1114
|
api.autoFetch,
|
|
1052
1115
|
getFormulaContext(api, initialComponentData),
|
|
1116
|
+
['autoFetch'],
|
|
1053
1117
|
)
|
|
1054
1118
|
) {
|
|
1055
1119
|
// Execute will set the initial status of the api in the dataSignal
|
|
@@ -1155,7 +1219,8 @@ export function createAPI({
|
|
|
1155
1219
|
api = newApi
|
|
1156
1220
|
const updateContext = getFormulaContext(api, componentData)
|
|
1157
1221
|
const autoFetch =
|
|
1158
|
-
api.autoFetch &&
|
|
1222
|
+
api.autoFetch &&
|
|
1223
|
+
applyFormula(api.autoFetch, updateContext, ['autoFetch'])
|
|
1159
1224
|
if (autoFetch) {
|
|
1160
1225
|
const request = constructRequest(newApi, componentData)
|
|
1161
1226
|
payloadSignal?.set({
|
|
@@ -1165,6 +1230,7 @@ export function createAPI({
|
|
|
1165
1230
|
proxy: applyFormula(
|
|
1166
1231
|
newApi.server?.proxy?.enabled.formula,
|
|
1167
1232
|
updateContext,
|
|
1233
|
+
['proxy'],
|
|
1168
1234
|
),
|
|
1169
1235
|
// Serialize the Headers object to be able to compare changes
|
|
1170
1236
|
headers: Array.from(request.requestSettings.headers.entries()),
|
|
@@ -1174,7 +1240,7 @@ export function createAPI({
|
|
|
1174
1240
|
triggerActions: (componentData) => {
|
|
1175
1241
|
const apiData = ctx.dataSignal.get().Apis?.[api.name]
|
|
1176
1242
|
if (
|
|
1177
|
-
apiData
|
|
1243
|
+
!isDefined(apiData) ||
|
|
1178
1244
|
(apiData.data === null && apiData.error === null)
|
|
1179
1245
|
) {
|
|
1180
1246
|
return
|
|
@@ -6,9 +6,10 @@ import type {
|
|
|
6
6
|
} from '@nordcraft/core/dist/component/component.types'
|
|
7
7
|
import { applyFormula } from '@nordcraft/core/dist/formula/formula'
|
|
8
8
|
import { appendUnit } from '@nordcraft/core/dist/styling/customProperty'
|
|
9
|
-
import { mapObject } from '@nordcraft/core/dist/utils/collections'
|
|
9
|
+
import { filterObject, mapObject } from '@nordcraft/core/dist/utils/collections'
|
|
10
10
|
import { getNodeSelector } from '@nordcraft/core/dist/utils/getNodeSelector'
|
|
11
11
|
import { isDefined } from '@nordcraft/core/dist/utils/util'
|
|
12
|
+
import type { ComponentAPI } from '@nordcraft/core/src/api/apiTypes'
|
|
12
13
|
import { isContextApiV2 } from '../api/apiUtils'
|
|
13
14
|
import { createLegacyAPI } from '../api/createAPI'
|
|
14
15
|
import { createAPI } from '../api/createAPIv2'
|
|
@@ -68,15 +69,20 @@ export function createComponent({
|
|
|
68
69
|
package: ctx.package,
|
|
69
70
|
toddle: ctx.toddle,
|
|
70
71
|
env: ctx.env,
|
|
72
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
71
73
|
}
|
|
72
74
|
const attributesSignal = dataSignal.map((data) => {
|
|
73
75
|
return mapObject(node.attrs, ([attr, value]) => [
|
|
74
76
|
attr,
|
|
75
77
|
value?.type !== 'value'
|
|
76
|
-
? applyFormula(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
? applyFormula(
|
|
79
|
+
value,
|
|
80
|
+
{
|
|
81
|
+
...formulaCtx,
|
|
82
|
+
data,
|
|
83
|
+
},
|
|
84
|
+
['attrs', attr],
|
|
85
|
+
)
|
|
80
86
|
: value?.value,
|
|
81
87
|
])
|
|
82
88
|
})
|
|
@@ -84,22 +90,29 @@ export function createComponent({
|
|
|
84
90
|
const componentDataSignal = signal<ComponentData>({
|
|
85
91
|
Location: dataSignal.get().Location,
|
|
86
92
|
Attributes: attributesSignal.get(),
|
|
87
|
-
Apis: mapObject(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
Apis: mapObject(
|
|
94
|
+
filterObject(component.apis ?? {}, ([_, api]) => isDefined(api)),
|
|
95
|
+
([name, api]) => [
|
|
96
|
+
name,
|
|
97
|
+
{
|
|
98
|
+
data: null,
|
|
99
|
+
isLoading:
|
|
100
|
+
api!.autoFetch &&
|
|
101
|
+
applyFormula(
|
|
102
|
+
api!.autoFetch,
|
|
103
|
+
{
|
|
104
|
+
...formulaCtx,
|
|
105
|
+
component,
|
|
106
|
+
data: dataSignal.get(),
|
|
107
|
+
},
|
|
108
|
+
['apis', name, 'autoFetch'],
|
|
109
|
+
)
|
|
110
|
+
? true
|
|
111
|
+
: false,
|
|
112
|
+
error: null,
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
),
|
|
103
116
|
})
|
|
104
117
|
|
|
105
118
|
// Subscribe to global stores (currently only theme)
|
|
@@ -120,30 +133,67 @@ export function createComponent({
|
|
|
120
133
|
...data,
|
|
121
134
|
Variables: mapObject(component.variables ?? {}, ([name, variable]) => [
|
|
122
135
|
name,
|
|
123
|
-
applyFormula(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
136
|
+
applyFormula(
|
|
137
|
+
variable.initialValue,
|
|
138
|
+
{
|
|
139
|
+
// Initial value
|
|
140
|
+
...formulaCtx,
|
|
141
|
+
component,
|
|
142
|
+
data: componentDataSignal.get(),
|
|
143
|
+
},
|
|
144
|
+
['variables', name],
|
|
145
|
+
),
|
|
129
146
|
]),
|
|
130
147
|
}))
|
|
131
148
|
registerComponentToLogState(component, componentDataSignal)
|
|
132
149
|
|
|
133
150
|
// Call the abort signal if the component's datasignal is destroyed (component unmounted) to cancel any pending requests
|
|
134
151
|
const abortController = new AbortController()
|
|
135
|
-
componentDataSignal.subscribe(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
152
|
+
componentDataSignal.subscribe(
|
|
153
|
+
(data) => {
|
|
154
|
+
Object.entries(data.Variables ?? {}).forEach(([name, value]) => {
|
|
155
|
+
ctx.reportFormulaEvaluation?.(['variables', name], value, ctx)
|
|
156
|
+
})
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
destroy: () =>
|
|
160
|
+
abortController.abort(`Component ${component.name} unmounted`),
|
|
161
|
+
},
|
|
162
|
+
)
|
|
139
163
|
const formulaCache = createFormulaCache(component)
|
|
140
164
|
|
|
141
165
|
// Note: this function must run procedurally to ensure apis (which are in correct order) can reference each other
|
|
142
166
|
const apis: Record<string, ContextApi> = {}
|
|
143
|
-
sortApiObjects(
|
|
144
|
-
(
|
|
145
|
-
|
|
146
|
-
|
|
167
|
+
sortApiObjects(
|
|
168
|
+
Object.entries(component.apis ?? {}).filter(
|
|
169
|
+
(entry): entry is [string, ComponentAPI] => isDefined(entry[1]),
|
|
170
|
+
),
|
|
171
|
+
).forEach(([name, api]) => {
|
|
172
|
+
if (isLegacyApi(api)) {
|
|
173
|
+
apis[name] = createLegacyAPI(api, {
|
|
174
|
+
...ctx,
|
|
175
|
+
apis,
|
|
176
|
+
component,
|
|
177
|
+
dataSignal: componentDataSignal,
|
|
178
|
+
abortSignal: abortController.signal,
|
|
179
|
+
isRootComponent: false,
|
|
180
|
+
formulaCache,
|
|
181
|
+
package: node.package ?? ctx.package,
|
|
182
|
+
triggerEvent: (eventTrigger, data) => {
|
|
183
|
+
const eventHandler = Object.values(node.events).find(
|
|
184
|
+
(e) => e.trigger === eventTrigger,
|
|
185
|
+
)
|
|
186
|
+
if (eventHandler) {
|
|
187
|
+
eventHandler.actions?.forEach((action) =>
|
|
188
|
+
handleAction(action, { ...dataSignal.get(), Event: data }, ctx),
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
})
|
|
193
|
+
} else {
|
|
194
|
+
apis[name] = createAPI({
|
|
195
|
+
apiRequest: api,
|
|
196
|
+
ctx: {
|
|
147
197
|
...ctx,
|
|
148
198
|
apis,
|
|
149
199
|
component,
|
|
@@ -162,39 +212,11 @@ export function createComponent({
|
|
|
162
212
|
)
|
|
163
213
|
}
|
|
164
214
|
},
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
...ctx,
|
|
171
|
-
apis,
|
|
172
|
-
component,
|
|
173
|
-
dataSignal: componentDataSignal,
|
|
174
|
-
abortSignal: abortController.signal,
|
|
175
|
-
isRootComponent: false,
|
|
176
|
-
formulaCache,
|
|
177
|
-
package: node.package ?? ctx.package,
|
|
178
|
-
triggerEvent: (eventTrigger, data) => {
|
|
179
|
-
const eventHandler = Object.values(node.events).find(
|
|
180
|
-
(e) => e.trigger === eventTrigger,
|
|
181
|
-
)
|
|
182
|
-
if (eventHandler) {
|
|
183
|
-
eventHandler.actions?.forEach((action) =>
|
|
184
|
-
handleAction(
|
|
185
|
-
action,
|
|
186
|
-
{ ...dataSignal.get(), Event: data },
|
|
187
|
-
ctx,
|
|
188
|
-
),
|
|
189
|
-
)
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
componentData: componentDataSignal.get(),
|
|
194
|
-
})
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
)
|
|
215
|
+
},
|
|
216
|
+
componentData: componentDataSignal.get(),
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
})
|
|
198
220
|
Object.values(apis)
|
|
199
221
|
.filter(isContextApiV2)
|
|
200
222
|
.forEach((api) => {
|
|
@@ -221,15 +243,21 @@ export function createComponent({
|
|
|
221
243
|
.map(([name, formula]) => [
|
|
222
244
|
name,
|
|
223
245
|
componentDataSignal.map((data) =>
|
|
224
|
-
applyFormula(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
246
|
+
applyFormula(
|
|
247
|
+
formula.formula,
|
|
248
|
+
{
|
|
249
|
+
data,
|
|
250
|
+
component,
|
|
251
|
+
formulaCache: ctx.formulaCache,
|
|
252
|
+
root: ctx.root,
|
|
253
|
+
package: ctx.package,
|
|
254
|
+
toddle: ctx.toddle,
|
|
255
|
+
env: ctx.env,
|
|
256
|
+
jsonPath: ctx.jsonPath,
|
|
257
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
258
|
+
},
|
|
259
|
+
['formulas', name],
|
|
260
|
+
),
|
|
233
261
|
),
|
|
234
262
|
]),
|
|
235
263
|
)
|
|
@@ -301,6 +329,8 @@ export function createComponent({
|
|
|
301
329
|
node.id === 'root'
|
|
302
330
|
? { ...instance, [ctx.component.name]: 'root' }
|
|
303
331
|
: { [ctx.component.name]: node.id ?? '' },
|
|
332
|
+
jsonPath: ctx.jsonPath,
|
|
333
|
+
reportFormulaEvaluation: ctx.reportFormulaEvaluation,
|
|
304
334
|
})
|
|
305
335
|
|
|
306
336
|
// Custom properties instance overrides are added after the child tree is rendered to ensure correct order
|
|
@@ -314,10 +344,14 @@ export function createComponent({
|
|
|
314
344
|
}),
|
|
315
345
|
signal: dataSignal.map((data) =>
|
|
316
346
|
appendUnit(
|
|
317
|
-
applyFormula(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
347
|
+
applyFormula(
|
|
348
|
+
customProperty.formula,
|
|
349
|
+
{
|
|
350
|
+
...formulaCtx,
|
|
351
|
+
data,
|
|
352
|
+
},
|
|
353
|
+
['customProperties', customPropertyName, 'formula'],
|
|
354
|
+
),
|
|
321
355
|
customProperty.unit,
|
|
322
356
|
),
|
|
323
357
|
),
|
|
@@ -337,10 +371,14 @@ export function createComponent({
|
|
|
337
371
|
}),
|
|
338
372
|
signal: dataSignal.map((data) =>
|
|
339
373
|
appendUnit(
|
|
340
|
-
applyFormula(
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
374
|
+
applyFormula(
|
|
375
|
+
customProperty.formula,
|
|
376
|
+
{
|
|
377
|
+
...formulaCtx,
|
|
378
|
+
data,
|
|
379
|
+
},
|
|
380
|
+
['customProperties', customPropertyName, 'formula'],
|
|
381
|
+
),
|
|
344
382
|
customProperty.unit,
|
|
345
383
|
),
|
|
346
384
|
),
|