@nordcraft/runtime 1.0.95 → 1.0.96

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.
Files changed (74) hide show
  1. package/dist/api/createAPI.js +29 -11
  2. package/dist/api/createAPI.js.map +1 -1
  3. package/dist/api/createAPIv2.js +49 -11
  4. package/dist/api/createAPIv2.js.map +1 -1
  5. package/dist/components/createComponent.js +14 -5
  6. package/dist/components/createComponent.js.map +1 -1
  7. package/dist/components/createElement.js +48 -16
  8. package/dist/components/createElement.js.map +1 -1
  9. package/dist/components/createNode.js +23 -10
  10. package/dist/components/createNode.js.map +1 -1
  11. package/dist/components/createNode.test.js +3 -3
  12. package/dist/components/createNode.test.js.map +1 -1
  13. package/dist/components/createSlot.js +2 -1
  14. package/dist/components/createSlot.js.map +1 -1
  15. package/dist/components/createText.js +7 -2
  16. package/dist/components/createText.js.map +1 -1
  17. package/dist/components/renderComponent.d.ts +4 -1
  18. package/dist/components/renderComponent.js +4 -2
  19. package/dist/components/renderComponent.js.map +1 -1
  20. package/dist/context/subscribeToContext.js +12 -2
  21. package/dist/context/subscribeToContext.js.map +1 -1
  22. package/dist/custom-element/ToddleComponent.js +12 -4
  23. package/dist/custom-element/ToddleComponent.js.map +1 -1
  24. package/dist/custom-element.main.esm.js +29 -29
  25. package/dist/custom-element.main.esm.js.map +4 -4
  26. package/dist/editor/editorUtils.d.ts +1 -0
  27. package/dist/editor/editorUtils.js +14 -0
  28. package/dist/editor/editorUtils.js.map +1 -0
  29. package/dist/editor/types.d.ts +4 -0
  30. package/dist/editor/types.js.map +1 -1
  31. package/dist/editor-preview.main.js +71 -18
  32. package/dist/editor-preview.main.js.map +1 -1
  33. package/dist/events/handleAction.js +62 -31
  34. package/dist/events/handleAction.js.map +1 -1
  35. package/dist/page.main.esm.js +3 -3
  36. package/dist/page.main.esm.js.map +4 -4
  37. package/dist/page.main.js +39 -8
  38. package/dist/page.main.js.map +1 -1
  39. package/dist/utils/createFormulaCache.js.map +1 -1
  40. package/dist/utils/nodes.d.ts +1 -0
  41. package/dist/utils/nodes.js +9 -0
  42. package/dist/utils/nodes.js.map +1 -1
  43. package/dist/utils/nodes.test.d.ts +1 -0
  44. package/dist/utils/nodes.test.js +192 -0
  45. package/dist/utils/nodes.test.js.map +1 -0
  46. package/dist/utils/subscribeCustomProperty.d.ts +1 -1
  47. package/dist/utils/subscribeCustomProperty.js +8 -4
  48. package/dist/utils/subscribeCustomProperty.js.map +1 -1
  49. package/dist/utils/subscribeCustomProperty.test.d.ts +1 -0
  50. package/dist/utils/subscribeCustomProperty.test.js +63 -0
  51. package/dist/utils/subscribeCustomProperty.test.js.map +1 -0
  52. package/package.json +3 -3
  53. package/src/api/createAPI.ts +90 -46
  54. package/src/api/createAPIv2.ts +67 -13
  55. package/src/components/createComponent.ts +85 -67
  56. package/src/components/createElement.ts +63 -27
  57. package/src/components/createNode.test.ts +3 -3
  58. package/src/components/createNode.ts +47 -22
  59. package/src/components/createSlot.ts +2 -1
  60. package/src/components/createText.ts +34 -18
  61. package/src/components/renderComponent.ts +8 -1
  62. package/src/context/subscribeToContext.ts +12 -2
  63. package/src/custom-element/ToddleComponent.ts +37 -22
  64. package/src/editor/editorUtils.ts +13 -0
  65. package/src/editor/types.ts +5 -0
  66. package/src/editor-preview.main.ts +125 -46
  67. package/src/events/handleAction.ts +173 -96
  68. package/src/page.main.ts +64 -26
  69. package/src/types.d.ts +3 -0
  70. package/src/utils/createFormulaCache.ts +2 -2
  71. package/src/utils/nodes.test.ts +246 -0
  72. package/src/utils/nodes.ts +11 -0
  73. package/src/utils/subscribeCustomProperty.test.ts +78 -0
  74. package/src/utils/subscribeCustomProperty.ts +21 -22
@@ -60,6 +60,7 @@ export function createElement({
60
60
  package: ctx.package,
61
61
  toddle: ctx.toddle,
62
62
  env: ctx.env,
63
+ reportFormulaEvaluation: ctx.reportFormulaEvaluation,
63
64
  }
64
65
 
65
66
  elem.setAttribute('data-node-id', id)
@@ -107,12 +108,19 @@ export function createElement({
107
108
  if (value.type === 'value') {
108
109
  setAttribute(elem, attr, value?.value)
109
110
  } else {
110
- o = dataSignal.map((data) =>
111
- applyFormula(value, {
112
- ...formulaCtx,
113
- data,
114
- }),
115
- )
111
+ const attrPath = ['nodes', id, 'attrs', attr]
112
+ o = dataSignal.map((data) => {
113
+ const val = applyFormula(
114
+ value,
115
+ {
116
+ ...formulaCtx,
117
+ data,
118
+ },
119
+ attrPath,
120
+ )
121
+ ctx.reportFormulaEvaluation?.(attrPath, val)
122
+ return val
123
+ })
116
124
  o.subscribe((val) => {
117
125
  setAttribute(elem, attr, val)
118
126
  })
@@ -135,13 +143,19 @@ export function createElement({
135
143
  setupAttribute()
136
144
  }
137
145
  })
138
- node['style-variables']?.forEach((styleVariable) => {
146
+ node['style-variables']?.forEach((styleVariable, i) => {
139
147
  const { name, formula, unit } = styleVariable
148
+ const styleVarPath = ['nodes', id, 'style-variables', i, 'formula']
140
149
  const signal = dataSignal.map((data) => {
141
- const value = applyFormula(formula, {
142
- ...formulaCtx,
143
- data,
144
- })
150
+ const value = applyFormula(
151
+ formula,
152
+ {
153
+ ...formulaCtx,
154
+ data,
155
+ },
156
+ styleVarPath,
157
+ )
158
+ ctx.reportFormulaEvaluation?.(styleVarPath, value)
145
159
  return unit ? value + unit : value
146
160
  })
147
161
 
@@ -151,6 +165,13 @@ export function createElement({
151
165
  Object.entries(node.customProperties ?? {})
152
166
  .filter(([_, { formula }]) => formulaHasValue(formula))
153
167
  .forEach(([customPropertyName, { formula, unit }]) => {
168
+ const cpPath = [
169
+ 'nodes',
170
+ id,
171
+ 'customProperties',
172
+ customPropertyName,
173
+ 'formula',
174
+ ]
154
175
  subscribeCustomProperty({
155
176
  customPropertyName,
156
177
  selector:
@@ -159,38 +180,53 @@ export function createElement({
159
180
  path === '0'
160
181
  ? `${getNodeSelector(path)}, :host`
161
182
  : getNodeSelector(path),
162
- signal: dataSignal.map((data) =>
163
- appendUnit(
164
- applyFormula(formula, {
183
+ signal: dataSignal.map((data) => {
184
+ const val = applyFormula(
185
+ formula,
186
+ {
165
187
  ...formulaCtx,
166
188
  data,
167
- }),
168
- unit,
169
- ),
170
- ),
189
+ },
190
+ cpPath,
191
+ )
192
+ ctx.reportFormulaEvaluation?.(cpPath, val)
193
+ return appendUnit(val, unit)
194
+ }),
171
195
  root: ctx.root,
172
196
  })
173
197
  })
174
198
 
175
- node.variants?.forEach((variant) => {
199
+ node.variants?.forEach((variant, variantIndex) => {
176
200
  Object.entries(variant.customProperties ?? {})
177
201
  .filter(([_, { formula }]) => formulaHasValue(formula))
178
202
  .forEach(([customPropertyName, { formula, unit }]) => {
203
+ const variantCpPath = [
204
+ 'nodes',
205
+ id,
206
+ 'variants',
207
+ variantIndex,
208
+ 'customProperties',
209
+ customPropertyName,
210
+ 'formula',
211
+ ]
179
212
  subscribeCustomProperty({
180
213
  customPropertyName,
181
214
  selector: getNodeSelector(path, {
182
215
  variant,
183
216
  }),
184
217
  variant,
185
- signal: dataSignal.map((data) =>
186
- appendUnit(
187
- applyFormula(formula, {
218
+ signal: dataSignal.map((data) => {
219
+ const val = applyFormula(
220
+ formula,
221
+ {
188
222
  ...formulaCtx,
189
223
  data,
190
- }),
191
- unit,
192
- ),
193
- ),
224
+ },
225
+ variantCpPath,
226
+ )
227
+ ctx.reportFormulaEvaluation?.(variantCpPath, val)
228
+ return appendUnit(val, unit)
229
+ }),
194
230
  root: ctx.root,
195
231
  })
196
232
  })
@@ -260,7 +296,7 @@ export function createElement({
260
296
  id: child,
261
297
  path: path + '.' + i,
262
298
  dataSignal,
263
- ctx,
299
+ ctx: { ...ctx, jsonPath: ['nodes', child] },
264
300
  namespace,
265
301
  instance,
266
302
  }),
@@ -4,7 +4,7 @@ import { describe, expect, test } from 'bun:test'
4
4
  import '../happydom'
5
5
  import { signal } from '../signal/signal'
6
6
  import type { ComponentContext } from '../types'
7
- import { customPropertiesStylesheet } from '../utils/subscribeCustomProperty'
7
+ import { customPropertiesStylesheets } from '../utils/subscribeCustomProperty'
8
8
  import { createNode } from './createNode'
9
9
 
10
10
  describe('createNode()', () => {
@@ -114,7 +114,7 @@ describe('createNode()', () => {
114
114
  })
115
115
 
116
116
  // Custom properties stylesheet should be created and have the custom property from the node
117
- const sheet = customPropertiesStylesheet?.getStyleSheet()
117
+ const sheet = customPropertiesStylesheets.get(document)?.getStyleSheet()
118
118
  expect(sheet).toBeTruthy()
119
119
  expect(sheet?.cssRules.length).toBe(3)
120
120
  expect(sheet?.cssRules[0].cssText).toBe(
@@ -675,7 +675,7 @@ describe('createNode()', () => {
675
675
  instance: {},
676
676
  })
677
677
 
678
- const sheet = customPropertiesStylesheet?.getStyleSheet()
678
+ const sheet = customPropertiesStylesheets.get(ctx.root)?.getStyleSheet()
679
679
  // Test that the order makes sense
680
680
  expect(Array.from(sheet?.cssRules ?? []).map((r) => r.cssText)).toEqual([
681
681
  `[data-id="0"] { --color: ${innermostColor}; }`,
@@ -86,19 +86,30 @@ export function createNode({
86
86
  }: NodeRenderer<NodeModel>): ReadonlyArray<Element | Text> {
87
87
  let firstRun = true
88
88
  let childDataSignal: Signal<ComponentData> | null = null
89
- const showSignal = dataSignal.map((data) =>
90
- toBoolean(
91
- applyFormula(node.condition, {
92
- data,
93
- component: ctx.component,
94
- formulaCache: ctx.formulaCache,
95
- root: ctx.root,
96
- package: ctx.package,
97
- toddle: ctx.toddle,
98
- env: ctx.env,
99
- }),
100
- ),
101
- )
89
+ const showSignal = dataSignal.map((data) => {
90
+ const conditionPath = ['nodes', id, 'condition']
91
+ const show = toBoolean(
92
+ applyFormula(
93
+ node.condition,
94
+ {
95
+ data,
96
+ component: ctx.component,
97
+ formulaCache: ctx.formulaCache,
98
+ root: ctx.root,
99
+ package: ctx.package,
100
+ toddle: ctx.toddle,
101
+ env: ctx.env,
102
+ jsonPath: ctx.jsonPath,
103
+ reportFormulaEvaluation: ctx.reportFormulaEvaluation,
104
+ },
105
+ conditionPath,
106
+ ),
107
+ )
108
+
109
+ ctx.reportFormulaEvaluation?.(conditionPath, show)
110
+
111
+ return show
112
+ })
102
113
 
103
114
  const elements: Array<Element | Text> = []
104
115
  const toggle = (show: boolean) => {
@@ -182,15 +193,23 @@ export function createNode({
182
193
  }
183
194
  >()
184
195
  const repeatSignal = dataSignal.map((data) => {
185
- const list = applyFormula(node?.repeat, {
186
- data,
187
- component: ctx.component,
188
- formulaCache: ctx.formulaCache,
189
- root: ctx.root,
190
- package: ctx.package,
191
- toddle: ctx.toddle,
192
- env: ctx.env,
193
- })
196
+ const listPath = ['nodes', id, 'repeat']
197
+ const list = applyFormula(
198
+ node?.repeat,
199
+ {
200
+ data,
201
+ component: ctx.component,
202
+ formulaCache: ctx.formulaCache,
203
+ root: ctx.root,
204
+ package: ctx.package,
205
+ toddle: ctx.toddle,
206
+ env: ctx.env,
207
+ },
208
+ listPath,
209
+ )
210
+
211
+ ctx.reportFormulaEvaluation?.(listPath, list)
212
+
194
213
  if (typeof list !== 'object') {
195
214
  return []
196
215
  }
@@ -216,6 +235,7 @@ export function createNode({
216
235
  Key,
217
236
  },
218
237
  }
238
+ const repeatKeyPath = ['nodes', id, 'repeatKey']
219
239
  let childKey = node?.repeatKey
220
240
  ? applyFormula(node.repeatKey, {
221
241
  data: childData,
@@ -228,6 +248,10 @@ export function createNode({
228
248
  })
229
249
  : Key
230
250
 
251
+ if (node?.repeatKey) {
252
+ ctx.reportFormulaEvaluation?.(repeatKeyPath, childKey)
253
+ }
254
+
231
255
  if (seenKeys.has(childKey)) {
232
256
  console.warn(
233
257
  `Duplicate key "${childKey}" found in repeat. Fallback to index as key. This will cause a re-render of the duplicated children on every change.`,
@@ -380,6 +404,7 @@ export function createNode({
380
404
  instance,
381
405
  })
382
406
  }
407
+
383
408
  export type NodeRenderer<NodeType> = {
384
409
  node: NodeType
385
410
  dataSignal: Signal<ComponentData>
@@ -37,6 +37,7 @@ export function createSlot({
37
37
  ctx: {
38
38
  ...child.ctx,
39
39
  providers: ctx.providers,
40
+ jsonPath: ['nodes', child.id],
40
41
  },
41
42
  instance,
42
43
  namespace,
@@ -53,7 +54,7 @@ export function createSlot({
53
54
  id: child,
54
55
  path: path + '.' + i,
55
56
  dataSignal,
56
- ctx,
57
+ ctx: { ...ctx, jsonPath: ['nodes', child] },
57
58
  parentElement,
58
59
  instance,
59
60
  namespace,
@@ -48,21 +48,31 @@ export function createText({
48
48
  if (value.type !== 'value') {
49
49
  const sig = dataSignal.map((data) =>
50
50
  String(
51
- applyFormula(value, {
52
- data,
53
- component: ctx.component,
54
- formulaCache: ctx.formulaCache,
55
- root: ctx.root,
56
- package: ctx.package,
57
- toddle: ctx.toddle,
58
- env: ctx.env,
59
- }),
51
+ applyFormula(
52
+ value,
53
+ {
54
+ data,
55
+ component: ctx.component,
56
+ formulaCache: ctx.formulaCache,
57
+ root: ctx.root,
58
+ package: ctx.package,
59
+ toddle: ctx.toddle,
60
+ env: ctx.env,
61
+ jsonPath: ctx.jsonPath,
62
+ reportFormulaEvaluation: ctx.reportFormulaEvaluation,
63
+ },
64
+ ['value'],
65
+ ),
60
66
  ),
61
67
  )
62
68
  sig.subscribe((value) => {
63
69
  elem.innerText = value
64
70
  })
65
71
  } else {
72
+ ctx.reportFormulaEvaluation?.(
73
+ [...(ctx.jsonPath ?? []), 'value'],
74
+ value.value,
75
+ )
66
76
  elem.innerText = String(value.value)
67
77
  }
68
78
  return elem
@@ -82,15 +92,21 @@ export function createTextNS({
82
92
  if (value.type !== 'value') {
83
93
  const sig = dataSignal.map((data) =>
84
94
  String(
85
- applyFormula(value, {
86
- data,
87
- component: ctx.component,
88
- formulaCache: ctx.formulaCache,
89
- root: ctx.root,
90
- package: ctx.package,
91
- toddle: ctx.toddle,
92
- env: ctx.env,
93
- }),
95
+ applyFormula(
96
+ value,
97
+ {
98
+ data,
99
+ component: ctx.component,
100
+ formulaCache: ctx.formulaCache,
101
+ root: ctx.root,
102
+ package: ctx.package,
103
+ toddle: ctx.toddle,
104
+ env: ctx.env,
105
+ jsonPath: ctx.jsonPath,
106
+ reportFormulaEvaluation: ctx.reportFormulaEvaluation,
107
+ },
108
+ ['value'],
109
+ ),
94
110
  ),
95
111
  )
96
112
  sig.subscribe((value) => {
@@ -4,6 +4,7 @@ import type {
4
4
  SupportedNamespaces,
5
5
  } from '@nordcraft/core/dist/component/component.types'
6
6
  import type { ToddleEnv } from '@nordcraft/core/dist/formula/formula'
7
+ import type { FormulaEvaluationReporter } from '@nordcraft/core/dist/formula/formulaTypes'
7
8
  import type { Toddle } from '@nordcraft/core/dist/types'
8
9
  import { measure } from '@nordcraft/core/dist/utils/measure'
9
10
  import fastDeepEqual from 'fast-deep-equal'
@@ -49,6 +50,8 @@ interface RenderComponentProps {
49
50
  toddle: Toddle<LocationSignal, PreviewShowSignal>
50
51
  namespace?: SupportedNamespaces
51
52
  env: ToddleEnv
53
+ jsonPath: Array<string | number> | undefined
54
+ reportFormulaEvaluation?: FormulaEvaluationReporter
52
55
  }
53
56
 
54
57
  const BATCH_QUEUE = new BatchQueue()
@@ -73,6 +76,8 @@ export function renderComponent({
73
76
  toddle,
74
77
  namespace,
75
78
  env,
79
+ jsonPath,
80
+ reportFormulaEvaluation,
76
81
  }: RenderComponentProps): ReadonlyArray<Element | Text> {
77
82
  const stopMeasure = measure(`Render component: ${component.name}`, {
78
83
  component: component.name,
@@ -94,13 +99,15 @@ export function renderComponent({
94
99
  package: packageName,
95
100
  toddle,
96
101
  env,
102
+ jsonPath,
103
+ reportFormulaEvaluation,
97
104
  }
98
105
 
99
106
  const rootElem = createNode({
100
107
  id: 'root',
101
108
  path,
102
109
  dataSignal,
103
- ctx,
110
+ ctx: { ...ctx, jsonPath: ['nodes', 'root'] },
104
111
  parentElement,
105
112
  namespace,
106
113
  instance,
@@ -83,6 +83,8 @@ export function subscribeToContext(
83
83
  package: testProviderPackage ?? ctx?.package,
84
84
  toddle: ctx.toddle,
85
85
  env: ctx.env,
86
+ jsonPath: ctx.jsonPath,
87
+ reportFormulaEvaluation: ctx.reportFormulaEvaluation,
86
88
  }
87
89
 
88
90
  if (testProvider.route) {
@@ -102,7 +104,11 @@ export function subscribeToContext(
102
104
  testProvider.variables ?? {},
103
105
  ([name, variable]) => [
104
106
  name,
105
- applyFormula(variable.initialValue, formulaContext),
107
+ applyFormula(variable.initialValue, {
108
+ ...formulaContext,
109
+ // We should not report formula evaluations for test data on context providers
110
+ reportFormulaEvaluation: undefined,
111
+ }),
106
112
  ],
107
113
  )
108
114
 
@@ -123,7 +129,11 @@ export function subscribeToContext(
123
129
 
124
130
  return [
125
131
  formulaName,
126
- applyFormula(formula.formula, formulaContext),
132
+ applyFormula(formula.formula, {
133
+ ...formulaContext,
134
+ // We should not report formula evaluations for test data on context providers
135
+ reportFormulaEvaluation: undefined,
136
+ }),
127
137
  ]
128
138
  }),
129
139
  ),
@@ -14,6 +14,7 @@ import {
14
14
  import type { Toddle } from '@nordcraft/core/dist/types'
15
15
  import { mapObject } from '@nordcraft/core/dist/utils/collections'
16
16
  import { isDefined } from '@nordcraft/core/dist/utils/util'
17
+ import type { ComponentAPI } from '@nordcraft/core/src/api/apiTypes'
17
18
  import { isContextApiV2 } from '../api/apiUtils'
18
19
  import { createLegacyAPI } from '../api/createAPI'
19
20
  import { createAPI } from '../api/createAPIv2'
@@ -97,23 +98,32 @@ export class ToddleComponent extends HTMLElement {
97
98
  package: undefined,
98
99
  toddle,
99
100
  env,
101
+ jsonPath: [],
100
102
  }
101
103
  }
102
104
 
103
105
  connectedCallback() {
104
- sortApiObjects(Object.entries(this.#component.apis ?? {})).forEach(
105
- ([name, api]) => {
106
- if (isLegacyApi(api)) {
107
- this.#ctx.apis[name] = createLegacyAPI(api, this.#ctx)
108
- } else {
109
- this.#ctx.apis[name] = createAPI({
110
- apiRequest: api,
111
- ctx: this.#ctx,
112
- componentData: this.#signal.get(),
113
- })
114
- }
115
- },
116
- )
106
+ sortApiObjects(
107
+ Object.entries(this.#component.apis ?? {}).filter(
108
+ (entry): entry is [string, ComponentAPI] => isDefined(entry[1]),
109
+ ),
110
+ ).forEach(([name, api]) => {
111
+ if (isLegacyApi(api)) {
112
+ this.#ctx.apis[name] = createLegacyAPI(api, {
113
+ ...this.#ctx,
114
+ jsonPath: ['apis', name],
115
+ })
116
+ } else {
117
+ this.#ctx.apis[name] = createAPI({
118
+ apiRequest: api,
119
+ ctx: {
120
+ ...this.#ctx,
121
+ jsonPath: ['apis', name],
122
+ },
123
+ componentData: this.#signal.get(),
124
+ })
125
+ }
126
+ })
117
127
  Object.values(this.#ctx.apis)
118
128
  .filter(isContextApiV2)
119
129
  .forEach((api) => {
@@ -129,15 +139,20 @@ export class ToddleComponent extends HTMLElement {
129
139
  .map(([name, formula]) => [
130
140
  name,
131
141
  this.#signal.map((data) =>
132
- applyFormula(formula.formula, {
133
- data,
134
- component: this.#component,
135
- formulaCache: this.#ctx.formulaCache,
136
- root: this.#ctx.root,
137
- package: this.#ctx.package,
138
- toddle: this.#ctx.toddle,
139
- env: this.#ctx.env,
140
- }),
142
+ applyFormula(
143
+ formula.formula,
144
+ {
145
+ data,
146
+ component: this.#component,
147
+ formulaCache: this.#ctx.formulaCache,
148
+ root: this.#ctx.root,
149
+ package: this.#ctx.package,
150
+ toddle: this.#ctx.toddle,
151
+ env: this.#ctx.env,
152
+ jsonPath: [],
153
+ },
154
+ ['formulas', name],
155
+ ),
141
156
  ),
142
157
  ]),
143
158
  )
@@ -0,0 +1,13 @@
1
+ export const debounce = (func: () => void, wait: number, immediate = false) => {
2
+ let timeout: ReturnType<typeof setTimeout> | undefined = undefined
3
+ return () => {
4
+ const callNow = immediate && !timeout
5
+ clearTimeout(timeout)
6
+ timeout = setTimeout(() => {
7
+ func()
8
+ }, wait)
9
+ if (callNow) {
10
+ func()
11
+ }
12
+ }
13
+ }
@@ -189,6 +189,11 @@ export type EditorPostMessageType =
189
189
  }
190
190
  }
191
191
  | { type: 'data'; data: ComponentData }
192
+ | {
193
+ type: 'componentFormulaData'
194
+ data: Record<string, any>
195
+ component?: string
196
+ }
192
197
  | {
193
198
  type: 'selectionRect'
194
199
  rect: ReturnType<typeof getRectData>