@developer_tribe/react-builder 1.2.46 → 1.2.48

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 (94) hide show
  1. package/dist/attributes-editor/Field.d.ts +3 -1
  2. package/dist/attributes-editor/attributesEditorModelTypes.d.ts +3 -0
  3. package/dist/attributes-editor/useAttributesEditorModel.d.ts +1 -1
  4. package/dist/build-components/FormSubmitButton/FormSubmitButtonProps.generated.d.ts +8 -3
  5. package/dist/build-components/GlobalProvider/GlobalContext.d.ts +28 -0
  6. package/dist/build-components/GlobalProvider/GlobalProvider.d.ts +5 -0
  7. package/dist/build-components/GlobalProvider/GlobalProviderProps.generated.d.ts +60 -0
  8. package/dist/build-components/GlobalProvider/globalProviderUtils.d.ts +28 -0
  9. package/dist/build-components/GlobalProvider/useGlobalNavigation.d.ts +19 -0
  10. package/dist/build-components/GlobalProvider/useGlobalProviderLogic.d.ts +15 -0
  11. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +8 -3
  12. package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +2 -0
  13. package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +2 -0
  14. package/dist/build-components/SystemButton/SystemButtonProps.generated.d.ts +8 -3
  15. package/dist/build-components/SystemButton/usePlacementButtonEvents.d.ts +15 -2
  16. package/dist/build-components/TermsProvider/TermsProvider.d.ts +5 -0
  17. package/dist/build-components/TermsProvider/TermsProviderProps.generated.d.ts +55 -0
  18. package/dist/build-components/index.d.ts +3 -1
  19. package/dist/build-components/patterns.generated.d.ts +2128 -1333
  20. package/dist/components/DeviceButton.d.ts +2 -1
  21. package/dist/index.cjs.js +3 -3
  22. package/dist/index.cjs.js.map +1 -1
  23. package/dist/index.esm.js +3 -3
  24. package/dist/index.esm.js.map +1 -1
  25. package/dist/index.web.cjs.js +3 -3
  26. package/dist/index.web.cjs.js.map +1 -1
  27. package/dist/index.web.d.ts +5 -1
  28. package/dist/index.web.esm.js +3 -3
  29. package/dist/index.web.esm.js.map +1 -1
  30. package/dist/modals/PromptManagerModal.d.ts +5 -1
  31. package/dist/store.d.ts +65 -0
  32. package/dist/styles.css +1 -1
  33. package/dist/utils/nodeTree.d.ts +18 -0
  34. package/package.json +1 -1
  35. package/scripts/.DS_Store +0 -0
  36. package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +68 -4
  37. package/src/.DS_Store +0 -0
  38. package/src/assets/meta.json +1 -1
  39. package/src/assets/prompt-scheme-onboard.generated.ts +1 -1
  40. package/src/assets/prompt-scheme-paywall.generated.ts +1 -1
  41. package/src/assets/samples/getSamples.ts +2 -0
  42. package/src/assets/samples/global-onboard-flow.json +735 -0
  43. package/src/assets/samples/terms-and-privacy-no-form.json +1 -1
  44. package/src/assets/samples/terms-and-privacy.json +1 -1
  45. package/src/attributes-editor/AttributesEditorView.tsx +3 -0
  46. package/src/attributes-editor/Field.tsx +144 -2
  47. package/src/attributes-editor/attributesEditorModelTypes.ts +3 -0
  48. package/src/attributes-editor/useAttributesEditorModel.ts +8 -0
  49. package/src/build-components/FormCheckbox/FormCheckbox.tsx +3 -3
  50. package/src/build-components/FormSubmitButton/FormSubmitButton.tsx +6 -0
  51. package/src/build-components/FormSubmitButton/FormSubmitButtonProps.generated.ts +26 -3
  52. package/src/build-components/GlobalProvider/GlobalContext.ts +48 -0
  53. package/src/build-components/GlobalProvider/GlobalProvider.tsx +51 -0
  54. package/src/build-components/GlobalProvider/GlobalProviderProps.generated.ts +78 -0
  55. package/src/build-components/GlobalProvider/globalProviderUtils.ts +204 -0
  56. package/src/build-components/GlobalProvider/pattern.json +55 -0
  57. package/src/build-components/GlobalProvider/useGlobalNavigation.ts +65 -0
  58. package/src/build-components/GlobalProvider/useGlobalProviderLogic.ts +172 -0
  59. package/src/build-components/OnboardButton/OnboardButton.tsx +8 -1
  60. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +26 -3
  61. package/src/build-components/OnboardButton/pattern.json +5 -3
  62. package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +12 -0
  63. package/src/build-components/OnboardProvider/pattern.json +9 -1
  64. package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +12 -0
  65. package/src/build-components/PaywallProvider/pattern.json +9 -1
  66. package/src/build-components/RenderNode.generated.tsx +10 -0
  67. package/src/build-components/SystemButton/SystemButton.tsx +6 -0
  68. package/src/build-components/SystemButton/SystemButtonProps.generated.ts +26 -3
  69. package/src/build-components/SystemButton/pattern.json +5 -3
  70. package/src/build-components/SystemButton/usePlacementButtonEvents.ts +51 -27
  71. package/src/build-components/TermsProvider/TermsProvider.tsx +45 -0
  72. package/src/build-components/TermsProvider/TermsProviderProps.generated.ts +82 -0
  73. package/src/build-components/TermsProvider/pattern.json +35 -0
  74. package/src/build-components/index.ts +10 -0
  75. package/src/build-components/patterns.generated.ts +2290 -1399
  76. package/src/components/AttributesEditorPanel.tsx +1 -0
  77. package/src/components/BottomBar.tsx +134 -14
  78. package/src/components/DeviceButton.tsx +81 -22
  79. package/src/components/EditorHeader.tsx +3 -2
  80. package/src/index.web.ts +32 -1
  81. package/src/modals/CreateDeviceModal.tsx +12 -2
  82. package/src/modals/DeviceSelectorModal.tsx +3 -1
  83. package/src/modals/PromptManagerModal.tsx +228 -38
  84. package/src/patterns/event-constants.json +19 -0
  85. package/src/store.ts +85 -0
  86. package/src/styles/components/_bottom-bar.scss +79 -0
  87. package/src/styles/components/_editor-shell.scss +235 -9
  88. package/src/styles/components/_global-provider.scss +131 -0
  89. package/src/styles/index.scss +1 -0
  90. package/src/styles/modals/_device-selector.scss +2 -2
  91. package/src/styles/modals/_prompt-manager-modal.scss +75 -5
  92. package/src/utils/analyseNodeByPatterns.ts +5 -2
  93. package/src/utils/nodeTree.ts +115 -0
  94. package/src/assets/.DS_Store +0 -0
@@ -73,27 +73,205 @@
73
73
  display: flex;
74
74
  flex-direction: row;
75
75
  align-items: stretch;
76
- gap: 8px;
76
+ gap: 6px;
77
77
  overflow: auto;
78
78
  height: 60px;
79
79
  padding: sizes.$spaceTight;
80
+ min-width: 0;
80
81
  }
81
82
 
82
83
  .editor-device-button {
84
+ --device-preview-height: 30px;
83
85
  position: relative;
84
- min-width: 160px;
86
+ min-width: 92px;
85
87
  height: 100%;
88
+ padding: 4px 8px 5px;
86
89
  border: 1px solid colors.$borderColor;
87
- border-radius: 6px;
90
+ border-radius: sizes.$radiusRounded;
88
91
  background: colors.$surfaceColor;
89
92
  color: colors.$textColor;
90
93
  cursor: pointer;
91
- font-size: 12px;
94
+ font-size: sizes.$fontSizeXs;
95
+ display: flex;
96
+ flex-direction: column;
97
+ align-items: center;
98
+ justify-content: flex-end;
99
+ gap: 4px;
100
+ overflow: hidden;
101
+ transition:
102
+ border-color 0.18s ease,
103
+ box-shadow 0.18s ease,
104
+ transform 0.12s ease;
105
+
106
+ &:hover {
107
+ border-color: hsl(
108
+ var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.35
109
+ );
110
+ }
111
+
112
+ &:focus-visible {
113
+ outline: none;
114
+ border-color: colors.$accentColor;
115
+ box-shadow: 0 0 0 2px
116
+ hsl(var(--primary, var(--rb-primary, 221.2 83.2% 53.3%)) / 0.2);
117
+ }
118
+
92
119
  &.editor-device-button--selected {
93
- border-color: colors.$textColor;
120
+ border-color: colors.$accentColor;
121
+ box-shadow: 0 0 0 1px
122
+ hsl(var(--primary, var(--rb-primary, 221.2 83.2% 53.3%)) / 0.4) inset;
94
123
  }
95
124
  }
96
125
 
126
+ .editor-device-button--header {
127
+ min-width: 94px;
128
+ max-width: 112px;
129
+ }
130
+
131
+ .editor-device-button--modal {
132
+ --device-preview-height: 58px;
133
+ min-width: 152px;
134
+ min-height: 136px;
135
+ height: 136px;
136
+ padding: 10px 10px 8px;
137
+ gap: 8px;
138
+ }
139
+
140
+ .editor-device-button__preview {
141
+ flex: 1 1 auto;
142
+ min-height: 0;
143
+ width: 100%;
144
+ display: flex;
145
+ align-items: flex-end;
146
+ justify-content: center;
147
+ }
148
+
149
+ .editor-device-button__frame {
150
+ position: relative;
151
+ height: var(--device-preview-height);
152
+ aspect-ratio: 9 / 19.5;
153
+ min-width: 10px;
154
+ max-width: calc(var(--device-preview-height) * 1.85);
155
+ border-radius: clamp(6px, calc(var(--device-preview-height) * 0.3), 16px);
156
+ border: 1px solid
157
+ hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.28);
158
+ background: linear-gradient(
159
+ 160deg,
160
+ hsl(var(--muted, var(--rb-muted, 220 14.3% 95.9%))),
161
+ hsl(var(--background, var(--rb-background, 220 14.3% 95.9%)))
162
+ );
163
+ box-shadow:
164
+ 0 2px 6px hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.18),
165
+ inset 0 1px 0 hsl(var(--background, var(--rb-background, 220 14.3% 95.9%)));
166
+ overflow: hidden;
167
+ }
168
+
169
+ .editor-device-button__frame[data-type='tablet'] {
170
+ border-radius: clamp(4px, calc(var(--device-preview-height) * 0.16), 10px);
171
+ }
172
+
173
+ .editor-device-button__frame[data-platform='ios'] {
174
+ background: linear-gradient(
175
+ 160deg,
176
+ hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.18),
177
+ hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.06)
178
+ );
179
+ }
180
+
181
+ .editor-device-button__frame[data-platform='android'] {
182
+ background: linear-gradient(
183
+ 160deg,
184
+ hsl(var(--primary, var(--rb-primary, 221.2 83.2% 53.3%)) / 0.2),
185
+ hsl(var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.07)
186
+ );
187
+ }
188
+
189
+ .editor-device-button__screen {
190
+ position: absolute;
191
+ inset: 2px;
192
+ border-radius: inherit;
193
+ background: linear-gradient(
194
+ 180deg,
195
+ hsl(var(--background, var(--rb-background, 220 14.3% 95.9%)) / 0.95),
196
+ hsl(var(--muted, var(--rb-muted, 220 14.3% 95.9%)) / 0.85)
197
+ );
198
+ }
199
+
200
+ .editor-device-button__notch {
201
+ position: absolute;
202
+ top: 2px;
203
+ left: 50%;
204
+ transform: translateX(-50%);
205
+ width: 34%;
206
+ max-width: 14px;
207
+ height: 3px;
208
+ border-radius: 0 0 4px 4px;
209
+ background: hsl(
210
+ var(--foreground, var(--rb-foreground, 220.9 39.3% 11%)) / 0.35
211
+ );
212
+ }
213
+
214
+ .editor-device-button--modal .editor-device-button__notch {
215
+ height: 4px;
216
+ }
217
+
218
+ .editor-device-button__frame[data-type='tablet'] .editor-device-button__notch {
219
+ display: none;
220
+ }
221
+
222
+ .editor-device-button__name {
223
+ width: 100%;
224
+ padding: 0 16px 0 12px;
225
+ text-align: center;
226
+ font-size: sizes.$fontSizeXs;
227
+ font-weight: 600;
228
+ line-height: 1.05;
229
+ white-space: nowrap;
230
+ overflow: hidden;
231
+ text-overflow: ellipsis;
232
+ }
233
+
234
+ .editor-device-button__popover {
235
+ position: absolute;
236
+ top: 6px;
237
+ left: 50%;
238
+ transform: translate(-50%, -6px) scale(0.98);
239
+ width: calc(100% - 12px);
240
+ padding: 4px 6px;
241
+ border-radius: sizes.$radiusMid;
242
+ border: 1px solid colors.$borderColor;
243
+ background: hsl(var(--card, var(--rb-card, 0 0% 100%)) / 0.98);
244
+ box-shadow: sizes.$shadowTooltip;
245
+ opacity: 0;
246
+ pointer-events: none;
247
+ z-index: 2;
248
+ transition:
249
+ opacity 0.16s ease,
250
+ transform 0.16s ease;
251
+ }
252
+
253
+ .editor-device-button:hover .editor-device-button__popover,
254
+ .editor-device-button:focus-visible .editor-device-button__popover {
255
+ opacity: 1;
256
+ transform: translate(-50%, 0) scale(1);
257
+ }
258
+
259
+ .editor-device-button__popover-title {
260
+ display: block;
261
+ font-size: 10px;
262
+ font-weight: 700;
263
+ white-space: nowrap;
264
+ overflow: hidden;
265
+ text-overflow: ellipsis;
266
+ }
267
+
268
+ .editor-device-button__popover-meta {
269
+ display: block;
270
+ margin-top: 1px;
271
+ font-size: 10px;
272
+ color: colors.$mutedTextColor;
273
+ }
274
+
97
275
  .editor-device-button__platform {
98
276
  position: absolute;
99
277
  bottom: 4px;
@@ -101,9 +279,10 @@
101
279
  background-color: colors.$muted;
102
280
  border-radius: 50%;
103
281
  display: block;
104
- width: 22px;
105
- height: 22px;
282
+ width: 16px;
283
+ height: 16px;
106
284
  overflow: hidden;
285
+ z-index: 3;
107
286
  }
108
287
 
109
288
  .editor-device-button__platform img {
@@ -111,13 +290,40 @@
111
290
  top: 50%;
112
291
  left: 50%;
113
292
  transform: translate(-50%, -50%);
114
- max-width: 11px;
115
- max-height: 11px;
293
+ max-width: 9px;
294
+ max-height: 9px;
116
295
  width: auto;
117
296
  height: auto;
118
297
  }
119
298
 
299
+ .editor-device-button--modal .editor-device-button__platform {
300
+ width: 18px;
301
+ height: 18px;
302
+ }
303
+
304
+ .editor-device-button--modal .editor-device-button__platform img {
305
+ max-width: 10px;
306
+ max-height: 10px;
307
+ }
308
+
309
+ .editor-device-button__favorite {
310
+ position: absolute;
311
+ top: 4px;
312
+ right: 4px;
313
+ cursor: pointer;
314
+ z-index: 3;
315
+ display: inline-flex;
316
+ line-height: 0;
317
+ }
318
+
120
319
  .editor-device-button__edit {
320
+ position: absolute;
321
+ top: 4px;
322
+ left: 4px;
323
+ cursor: pointer;
324
+ z-index: 3;
325
+ display: inline-flex;
326
+ line-height: 0;
121
327
  transition:
122
328
  opacity 0.2s ease,
123
329
  transform 0.2s ease;
@@ -127,6 +333,26 @@
127
333
  }
128
334
  }
129
335
 
336
+ .editor-device-button--more {
337
+ min-width: 88px;
338
+ max-width: 102px;
339
+ justify-content: center;
340
+ gap: 0;
341
+ border-style: dashed;
342
+ background: hsl(var(--muted, var(--rb-muted, 220 14.3% 95.9%)) / 0.35);
343
+ }
344
+
345
+ .editor-device-button__more-label {
346
+ font-size: sizes.$fontSizeXs;
347
+ font-weight: 600;
348
+ line-height: 1.2;
349
+ color: colors.$mutedTextColor;
350
+ }
351
+
352
+ .editor-device-button--more:hover .editor-device-button__more-label {
353
+ color: colors.$textColor;
354
+ }
355
+
130
356
  .editor-header__actions {
131
357
  margin-left: auto; /* push actions to the far right */
132
358
  display: flex;
@@ -0,0 +1,131 @@
1
+ /* Page transition animations for GlobalProvider (platform-style names). */
2
+ $page-transition-duration: 0.3s;
3
+ $page-transition-easing: cubic-bezier(0.32, 0.72, 0, 1);
4
+
5
+ .global-provider-page {
6
+ flex: 1;
7
+ display: flex;
8
+ flex-direction: column;
9
+ height: 100%;
10
+ overflow: hidden;
11
+ }
12
+
13
+ .global-provider-page--none {
14
+ animation: none;
15
+ }
16
+
17
+ .global-provider-page--default {
18
+ animation: global-provider-fade $page-transition-duration $page-transition-easing;
19
+ }
20
+
21
+ .global-provider-page--fade {
22
+ animation: global-provider-fade $page-transition-duration $page-transition-easing;
23
+ }
24
+
25
+ @keyframes global-provider-fade {
26
+ from {
27
+ opacity: 0;
28
+ }
29
+ to {
30
+ opacity: 1;
31
+ }
32
+ }
33
+
34
+ .global-provider-page--fade_from_bottom {
35
+ animation: global-provider-fade-from-bottom $page-transition-duration $page-transition-easing;
36
+ }
37
+
38
+ @keyframes global-provider-fade-from-bottom {
39
+ from {
40
+ opacity: 0;
41
+ transform: translateY(24px);
42
+ }
43
+ to {
44
+ opacity: 1;
45
+ transform: translateY(0);
46
+ }
47
+ }
48
+
49
+ .global-provider-page--fade_from_right {
50
+ animation: global-provider-fade-from-right $page-transition-duration $page-transition-easing;
51
+ }
52
+
53
+ @keyframes global-provider-fade-from-right {
54
+ from {
55
+ opacity: 0;
56
+ transform: translateX(24px);
57
+ }
58
+ to {
59
+ opacity: 1;
60
+ transform: translateX(0);
61
+ }
62
+ }
63
+
64
+ .global-provider-page--reveal_from_bottom {
65
+ animation: global-provider-reveal-from-bottom $page-transition-duration $page-transition-easing;
66
+ }
67
+
68
+ @keyframes global-provider-reveal-from-bottom {
69
+ from {
70
+ opacity: 0;
71
+ transform: translateY(100%);
72
+ }
73
+ to {
74
+ opacity: 1;
75
+ transform: translateY(0);
76
+ }
77
+ }
78
+
79
+ .global-provider-page--scale_from_center {
80
+ animation: global-provider-scale-from-center $page-transition-duration $page-transition-easing;
81
+ }
82
+
83
+ @keyframes global-provider-scale-from-center {
84
+ from {
85
+ opacity: 0;
86
+ transform: scale(0.95);
87
+ }
88
+ to {
89
+ opacity: 1;
90
+ transform: scale(1);
91
+ }
92
+ }
93
+
94
+ .global-provider-page--slide_from_right {
95
+ animation: global-provider-slide-from-right $page-transition-duration $page-transition-easing;
96
+ }
97
+
98
+ @keyframes global-provider-slide-from-right {
99
+ from {
100
+ transform: translateX(100%);
101
+ }
102
+ to {
103
+ transform: translateX(0);
104
+ }
105
+ }
106
+
107
+ .global-provider-page--slide_from_left {
108
+ animation: global-provider-slide-from-left $page-transition-duration $page-transition-easing;
109
+ }
110
+
111
+ @keyframes global-provider-slide-from-left {
112
+ from {
113
+ transform: translateX(-100%);
114
+ }
115
+ to {
116
+ transform: translateX(0);
117
+ }
118
+ }
119
+
120
+ .global-provider-page--slide_from_bottom {
121
+ animation: global-provider-slide-from-bottom $page-transition-duration $page-transition-easing;
122
+ }
123
+
124
+ @keyframes global-provider-slide-from-bottom {
125
+ from {
126
+ transform: translateY(100%);
127
+ }
128
+ to {
129
+ transform: translateY(0);
130
+ }
131
+ }
@@ -16,6 +16,7 @@
16
16
  @use './components/mockos-router';
17
17
  @use './components/bottom-bar';
18
18
  @use './components/onboard';
19
+ @use './components/global-provider';
19
20
 
20
21
  @use './components/webview';
21
22
  @use './components/checkbox';
@@ -7,12 +7,12 @@
7
7
  .device-selector-modal__grid {
8
8
  padding: sizes.$spaceRoomy;
9
9
  display: grid;
10
- grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
10
+ grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
11
11
  gap: sizes.$spaceCozy;
12
12
  overflow: auto;
13
13
  }
14
14
 
15
15
  .device-selector-modal__grid .editor-device-button {
16
- height: 80px;
16
+ height: 136px;
17
17
  min-width: unset;
18
18
  }
@@ -3,15 +3,22 @@
3
3
  @use '../foundation/typography' as typography;
4
4
 
5
5
  .prompt-manager-modal__content {
6
- width: calc(100vw - 32px);
7
- height: calc(100vh - 32px);
8
- max-width: 1400px;
9
- max-height: calc(100vh - 32px);
6
+ width: calc(100vw - 48px);
7
+ height: calc(100vh - 48px);
8
+ max-width: 1240px;
9
+ max-height: calc(100vh - 48px);
10
10
  padding: 0;
11
11
  display: flex;
12
12
  flex-direction: column;
13
13
  }
14
14
 
15
+ .prompt-manager-modal__content--ai-layout {
16
+ width: min(1320px, calc(100vw - 36px));
17
+ height: min(860px, calc(100vh - 28px));
18
+ max-height: calc(100vh - 28px);
19
+ border-radius: 14px;
20
+ }
21
+
15
22
  .prompt-manager-modal__header {
16
23
  padding: sizes.$spaceComfy sizes.$spaceRoomy;
17
24
  border-bottom: 1px solid colors.$borderColor;
@@ -54,7 +61,11 @@
54
61
  padding: sizes.$spaceRoomy;
55
62
  display: flex;
56
63
  flex-direction: column;
57
- overflow: hidden;
64
+ overflow: auto;
65
+ }
66
+
67
+ .prompt-manager-modal__body--ai-layout {
68
+ padding: sizes.$spaceComfy;
58
69
  }
59
70
 
60
71
  .prompt-manager-modal__editor-wrap {
@@ -71,6 +82,65 @@
71
82
  justify-content: space-between;
72
83
  }
73
84
 
85
+ .prompt-manager-modal__toolbar--stack {
86
+ flex-direction: column;
87
+ align-items: stretch;
88
+ gap: sizes.$spaceComfy;
89
+ }
90
+
91
+ .prompt-manager-modal__inline-row {
92
+ display: flex;
93
+ align-items: flex-end;
94
+ gap: sizes.$spaceComfy;
95
+ flex-wrap: wrap;
96
+ }
97
+
98
+ .prompt-manager-modal__inline-row--end {
99
+ justify-content: flex-end;
100
+ }
101
+
102
+ .prompt-manager-modal__label {
103
+ display: flex;
104
+ flex-direction: column;
105
+ gap: 6px;
106
+ font-size: 12px;
107
+ color: colors.$mutedTextColor;
108
+ }
109
+
110
+ .prompt-manager-modal__select {
111
+ min-width: 170px;
112
+ border: 1px solid colors.$borderColor;
113
+ border-radius: sizes.$radiusRounded;
114
+ background: colors.$surfaceColor;
115
+ color: colors.$textColor;
116
+ padding: 8px 10px;
117
+ font-size: 13px;
118
+ outline: none;
119
+
120
+ &:focus {
121
+ border-color: colors.$primary;
122
+ box-shadow: 0 0 0 2px color-mix(in srgb, colors.$primary, transparent 90%);
123
+ }
124
+ }
125
+
126
+ .prompt-manager-modal__prompt-input {
127
+ min-height: 90px;
128
+ resize: vertical;
129
+ border: 1px solid colors.$borderColor;
130
+ border-radius: sizes.$radiusRounded;
131
+ background: colors.$surfaceColor;
132
+ color: colors.$textColor;
133
+ padding: sizes.$spaceComfy;
134
+ font-size: 13px;
135
+ line-height: 1.45;
136
+ outline: none;
137
+
138
+ &:focus {
139
+ border-color: colors.$primary;
140
+ box-shadow: 0 0 0 2px color-mix(in srgb, colors.$primary, transparent 90%);
141
+ }
142
+ }
143
+
74
144
  .prompt-manager-modal__editor {
75
145
  flex: 1;
76
146
  width: 100%;
@@ -439,12 +439,15 @@ function validateAttributesByPattern(
439
439
  if (
440
440
  attrName === 'title' ||
441
441
  attrName === 'description' ||
442
- attrName === 'testID'
442
+ attrName === 'testID' ||
443
+ attrName === 'animation'
443
444
  ) {
444
445
  const res = validateAttributeValue(
445
446
  pattern.pattern.type,
446
447
  attrValue,
447
- attrName === 'testID' ? 'string' : attrName,
448
+ attrName === 'testID' || attrName === 'animation'
449
+ ? 'string'
450
+ : attrName,
448
451
  joinPath(path, attrName),
449
452
  );
450
453
  if (!res.valid) return res;
@@ -1,4 +1,5 @@
1
1
  import type { Node, NodeData } from '../types/Node';
2
+ import eventConstants from '../patterns/event-constants.json';
2
3
 
3
4
  export function deleteNodeFromTree(root: Node, target: Node): Node {
4
5
  if (root === null || root === undefined) return root;
@@ -97,3 +98,117 @@ export function findNodeByKey(root: Node, key?: string): Node | null {
97
98
 
98
99
  return null;
99
100
  }
101
+
102
+ export type ProjectOptions = {
103
+ pageKeys: string[];
104
+ conditionKeys: string[];
105
+ placementKeys: string[];
106
+ formFieldNames: string[];
107
+ eventTypes: string[];
108
+ validationTypes: string[];
109
+ };
110
+
111
+ /**
112
+ * Traverses the entire node tree to dynamically discover project-level metadata
113
+ * (page keys, condition keys, form field names, etc.) and merges them with
114
+ * central constants from event-constants.json.
115
+ *
116
+ * This enables the Attributes Editor to provide a complete list of valid options
117
+ * for dropdown fields, combining predefined standards with actually used keys
118
+ * in the current design.
119
+ */
120
+ export function collectProjectMetadata(root: Node): ProjectOptions {
121
+ const pageKeys = new Set<string>();
122
+ const conditionKeys = new Set<string>();
123
+ const placementKeys = new Set<string>();
124
+ const formFieldNames = new Set<string>();
125
+ const eventTypes = new Set<string>();
126
+
127
+ function traverse(node: Node) {
128
+ if (!node || typeof node === 'string') return;
129
+
130
+ if (Array.isArray(node)) {
131
+ node.forEach(traverse);
132
+ return;
133
+ }
134
+
135
+ const data = node as NodeData;
136
+ const type = data.type;
137
+ const attrs = (data.attributes ?? {}) as Record<string, any>;
138
+
139
+ // Collect Page Keys
140
+ if (type === 'GlobalProvider' && Array.isArray(data.children)) {
141
+ data.children.forEach((child) => {
142
+ if (typeof child === 'object' && child !== null && 'key' in child) {
143
+ if (typeof child.key === 'string') pageKeys.add(child.key);
144
+ }
145
+ });
146
+ }
147
+ if (attrs.pageKey && typeof attrs.pageKey === 'string') {
148
+ pageKeys.add(attrs.pageKey);
149
+ }
150
+
151
+ // Collect Condition Keys
152
+ if (attrs.conditionKey && typeof attrs.conditionKey === 'string') {
153
+ conditionKeys.add(attrs.conditionKey);
154
+ }
155
+ if (Array.isArray(attrs.skipConditions)) {
156
+ attrs.skipConditions.forEach((entry: any) => {
157
+ if (entry?.conditionKey) conditionKeys.add(entry.conditionKey);
158
+ });
159
+ }
160
+
161
+ // Collect Placement Keys
162
+ if (attrs.placementKey && typeof attrs.placementKey === 'string') {
163
+ placementKeys.add(attrs.placementKey);
164
+ }
165
+
166
+ // Collect Form Field Names
167
+ if (type.startsWith('Form') && type !== 'FormProvider' && attrs.name) {
168
+ if (typeof attrs.name === 'string') formFieldNames.add(attrs.name);
169
+ }
170
+
171
+ // Collect from events
172
+ if (Array.isArray(attrs.events)) {
173
+ attrs.events.forEach((evt: any) => {
174
+ if (evt.type && typeof evt.type === 'string') eventTypes.add(evt.type);
175
+ if (evt.navigate_to) pageKeys.add(evt.navigate_to);
176
+ if (evt.placementKey) placementKeys.add(evt.placementKey);
177
+ if (evt.conditionKey) conditionKeys.add(evt.conditionKey);
178
+ });
179
+ }
180
+
181
+ if (data.children) {
182
+ traverse(data.children as Node);
183
+ }
184
+ }
185
+
186
+ traverse(root);
187
+
188
+ // Merge with central constants for a complete set of options
189
+ const result: ProjectOptions = {
190
+ pageKeys: Array.from(
191
+ new Set([...pageKeys, ...eventConstants.placementKeys]),
192
+ ).sort(),
193
+ conditionKeys: Array.from(
194
+ new Set([...conditionKeys, ...eventConstants.conditionKeys]),
195
+ ).sort(),
196
+ placementKeys: Array.from(
197
+ new Set([...placementKeys, ...eventConstants.placementKeys]),
198
+ ).sort(),
199
+ formFieldNames: Array.from(
200
+ new Set([
201
+ ...formFieldNames,
202
+ ...((eventConstants as any).formFieldNames as string[]),
203
+ ]),
204
+ ).sort(),
205
+ eventTypes: Array.from(
206
+ new Set([...eventTypes, ...eventConstants.eventTypes]),
207
+ ).sort(),
208
+ validationTypes: Array.from(
209
+ new Set((eventConstants as any).validationTypes as string[]),
210
+ ).sort(),
211
+ };
212
+
213
+ return result;
214
+ }
Binary file