@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.
- package/dist/attributes-editor/Field.d.ts +3 -1
- package/dist/attributes-editor/attributesEditorModelTypes.d.ts +3 -0
- package/dist/attributes-editor/useAttributesEditorModel.d.ts +1 -1
- package/dist/build-components/FormSubmitButton/FormSubmitButtonProps.generated.d.ts +8 -3
- package/dist/build-components/GlobalProvider/GlobalContext.d.ts +28 -0
- package/dist/build-components/GlobalProvider/GlobalProvider.d.ts +5 -0
- package/dist/build-components/GlobalProvider/GlobalProviderProps.generated.d.ts +60 -0
- package/dist/build-components/GlobalProvider/globalProviderUtils.d.ts +28 -0
- package/dist/build-components/GlobalProvider/useGlobalNavigation.d.ts +19 -0
- package/dist/build-components/GlobalProvider/useGlobalProviderLogic.d.ts +15 -0
- package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +8 -3
- package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +2 -0
- package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +2 -0
- package/dist/build-components/SystemButton/SystemButtonProps.generated.d.ts +8 -3
- package/dist/build-components/SystemButton/usePlacementButtonEvents.d.ts +15 -2
- package/dist/build-components/TermsProvider/TermsProvider.d.ts +5 -0
- package/dist/build-components/TermsProvider/TermsProviderProps.generated.d.ts +55 -0
- package/dist/build-components/index.d.ts +3 -1
- package/dist/build-components/patterns.generated.d.ts +2128 -1333
- package/dist/components/DeviceButton.d.ts +2 -1
- package/dist/index.cjs.js +3 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +3 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.web.cjs.js +3 -3
- package/dist/index.web.cjs.js.map +1 -1
- package/dist/index.web.d.ts +5 -1
- package/dist/index.web.esm.js +3 -3
- package/dist/index.web.esm.js.map +1 -1
- package/dist/modals/PromptManagerModal.d.ts +5 -1
- package/dist/store.d.ts +65 -0
- package/dist/styles.css +1 -1
- package/dist/utils/nodeTree.d.ts +18 -0
- package/package.json +1 -1
- package/scripts/.DS_Store +0 -0
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +68 -4
- package/src/.DS_Store +0 -0
- package/src/assets/meta.json +1 -1
- package/src/assets/prompt-scheme-onboard.generated.ts +1 -1
- package/src/assets/prompt-scheme-paywall.generated.ts +1 -1
- package/src/assets/samples/getSamples.ts +2 -0
- package/src/assets/samples/global-onboard-flow.json +735 -0
- package/src/assets/samples/terms-and-privacy-no-form.json +1 -1
- package/src/assets/samples/terms-and-privacy.json +1 -1
- package/src/attributes-editor/AttributesEditorView.tsx +3 -0
- package/src/attributes-editor/Field.tsx +144 -2
- package/src/attributes-editor/attributesEditorModelTypes.ts +3 -0
- package/src/attributes-editor/useAttributesEditorModel.ts +8 -0
- package/src/build-components/FormCheckbox/FormCheckbox.tsx +3 -3
- package/src/build-components/FormSubmitButton/FormSubmitButton.tsx +6 -0
- package/src/build-components/FormSubmitButton/FormSubmitButtonProps.generated.ts +26 -3
- package/src/build-components/GlobalProvider/GlobalContext.ts +48 -0
- package/src/build-components/GlobalProvider/GlobalProvider.tsx +51 -0
- package/src/build-components/GlobalProvider/GlobalProviderProps.generated.ts +78 -0
- package/src/build-components/GlobalProvider/globalProviderUtils.ts +204 -0
- package/src/build-components/GlobalProvider/pattern.json +55 -0
- package/src/build-components/GlobalProvider/useGlobalNavigation.ts +65 -0
- package/src/build-components/GlobalProvider/useGlobalProviderLogic.ts +172 -0
- package/src/build-components/OnboardButton/OnboardButton.tsx +8 -1
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +26 -3
- package/src/build-components/OnboardButton/pattern.json +5 -3
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +12 -0
- package/src/build-components/OnboardProvider/pattern.json +9 -1
- package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +12 -0
- package/src/build-components/PaywallProvider/pattern.json +9 -1
- package/src/build-components/RenderNode.generated.tsx +10 -0
- package/src/build-components/SystemButton/SystemButton.tsx +6 -0
- package/src/build-components/SystemButton/SystemButtonProps.generated.ts +26 -3
- package/src/build-components/SystemButton/pattern.json +5 -3
- package/src/build-components/SystemButton/usePlacementButtonEvents.ts +51 -27
- package/src/build-components/TermsProvider/TermsProvider.tsx +45 -0
- package/src/build-components/TermsProvider/TermsProviderProps.generated.ts +82 -0
- package/src/build-components/TermsProvider/pattern.json +35 -0
- package/src/build-components/index.ts +10 -0
- package/src/build-components/patterns.generated.ts +2290 -1399
- package/src/components/AttributesEditorPanel.tsx +1 -0
- package/src/components/BottomBar.tsx +134 -14
- package/src/components/DeviceButton.tsx +81 -22
- package/src/components/EditorHeader.tsx +3 -2
- package/src/index.web.ts +32 -1
- package/src/modals/CreateDeviceModal.tsx +12 -2
- package/src/modals/DeviceSelectorModal.tsx +3 -1
- package/src/modals/PromptManagerModal.tsx +228 -38
- package/src/patterns/event-constants.json +19 -0
- package/src/store.ts +85 -0
- package/src/styles/components/_bottom-bar.scss +79 -0
- package/src/styles/components/_editor-shell.scss +235 -9
- package/src/styles/components/_global-provider.scss +131 -0
- package/src/styles/index.scss +1 -0
- package/src/styles/modals/_device-selector.scss +2 -2
- package/src/styles/modals/_prompt-manager-modal.scss +75 -5
- package/src/utils/analyseNodeByPatterns.ts +5 -2
- package/src/utils/nodeTree.ts +115 -0
- package/src/assets/.DS_Store +0 -0
|
@@ -81,6 +81,7 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
|
|
|
81
81
|
loadedFonts,
|
|
82
82
|
markFontLoaded,
|
|
83
83
|
addError,
|
|
84
|
+
projectOptions,
|
|
84
85
|
} = props;
|
|
85
86
|
|
|
86
87
|
const headerSection = (
|
|
@@ -277,6 +278,7 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
|
|
|
277
278
|
viewAttributes={viewAttributes}
|
|
278
279
|
label={isBoolean ? label : undefined}
|
|
279
280
|
preferredScale={preferredScale}
|
|
281
|
+
projectOptions={projectOptions}
|
|
280
282
|
/>
|
|
281
283
|
)}
|
|
282
284
|
</div>
|
|
@@ -355,6 +357,7 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
|
|
|
355
357
|
viewAttributes={viewAttributes}
|
|
356
358
|
label={isBoolean ? label : undefined}
|
|
357
359
|
preferredScale={preferredScale}
|
|
360
|
+
projectOptions={projectOptions}
|
|
358
361
|
/>
|
|
359
362
|
)}
|
|
360
363
|
</div>
|
|
@@ -12,6 +12,8 @@ import { Checkbox } from '../components/Checkbox';
|
|
|
12
12
|
import { LayoutPreviewPicker } from './LayoutPreviewPicker';
|
|
13
13
|
import { SizeField, type PreferredScale } from './SizeField';
|
|
14
14
|
import { LayoutContext, LayoutFieldName, isBooleanFieldType } from './types';
|
|
15
|
+
import type { ProjectOptions } from '../utils/nodeTree';
|
|
16
|
+
import { useRenderStore } from '../store';
|
|
15
17
|
|
|
16
18
|
type FieldProps = {
|
|
17
19
|
name: string;
|
|
@@ -24,6 +26,7 @@ type FieldProps = {
|
|
|
24
26
|
viewAttributes?: Partial<ViewPropsGenerated['attributes']>;
|
|
25
27
|
label?: React.ReactNode;
|
|
26
28
|
preferredScale?: PreferredScale;
|
|
29
|
+
projectOptions?: ProjectOptions;
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
const layoutFieldNames: LayoutFieldName[] = [
|
|
@@ -36,6 +39,40 @@ function isLayoutField(name: string): name is LayoutFieldName {
|
|
|
36
39
|
return layoutFieldNames.includes(name as LayoutFieldName);
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
type MediaFieldKind = 'image' | 'lottie' | 'video';
|
|
43
|
+
|
|
44
|
+
function resolveMediaFieldKind(
|
|
45
|
+
name: string,
|
|
46
|
+
componentType?: string,
|
|
47
|
+
type?: string | string[],
|
|
48
|
+
): MediaFieldKind | null {
|
|
49
|
+
if (type !== 'string') return null;
|
|
50
|
+
|
|
51
|
+
const field = name.trim().toLowerCase();
|
|
52
|
+
const component = (componentType ?? '').trim().toLowerCase();
|
|
53
|
+
|
|
54
|
+
if (field === 'lottie' || field === 'lottie_url') {
|
|
55
|
+
return 'lottie';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (field === 'video' || field === 'video_url') {
|
|
59
|
+
return 'video';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const isImageLikeField =
|
|
63
|
+
field === 'src' || field === 'image' || field === 'image_url';
|
|
64
|
+
const isImageLikeComponent =
|
|
65
|
+
component.includes('image') ||
|
|
66
|
+
component.includes('background') ||
|
|
67
|
+
component.includes('onboard');
|
|
68
|
+
|
|
69
|
+
if (isImageLikeField && (!component || isImageLikeComponent)) {
|
|
70
|
+
return 'image';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
39
76
|
export function Field({
|
|
40
77
|
name,
|
|
41
78
|
type,
|
|
@@ -47,7 +84,11 @@ export function Field({
|
|
|
47
84
|
viewAttributes,
|
|
48
85
|
label,
|
|
49
86
|
preferredScale,
|
|
87
|
+
projectOptions,
|
|
50
88
|
}: FieldProps) {
|
|
89
|
+
const CustomMediaField = useRenderStore((s) => s.renderMediaField);
|
|
90
|
+
const mediaFieldKind = resolveMediaFieldKind(name, componentType, type);
|
|
91
|
+
|
|
51
92
|
if (Array.isArray(type)) {
|
|
52
93
|
if (isLayoutField(name)) {
|
|
53
94
|
const enumOptions = type.filter(
|
|
@@ -64,6 +105,11 @@ export function Field({
|
|
|
64
105
|
/>
|
|
65
106
|
);
|
|
66
107
|
}
|
|
108
|
+
const options =
|
|
109
|
+
name === 'type'
|
|
110
|
+
? Array.from(new Set([...type, ...(projectOptions?.eventTypes ?? [])]))
|
|
111
|
+
: type;
|
|
112
|
+
|
|
67
113
|
return (
|
|
68
114
|
<select
|
|
69
115
|
value={value ?? ''}
|
|
@@ -71,7 +117,7 @@ export function Field({
|
|
|
71
117
|
className="input"
|
|
72
118
|
>
|
|
73
119
|
<option value="">(none)</option>
|
|
74
|
-
{
|
|
120
|
+
{options.map((opt) => (
|
|
75
121
|
<option key={opt} value={opt}>
|
|
76
122
|
{opt}
|
|
77
123
|
</option>
|
|
@@ -117,6 +163,54 @@ export function Field({
|
|
|
117
163
|
);
|
|
118
164
|
case 'string':
|
|
119
165
|
case 'description':
|
|
166
|
+
if (name === 'validation') {
|
|
167
|
+
const options = projectOptions?.validationTypes ?? [];
|
|
168
|
+
return (
|
|
169
|
+
<select
|
|
170
|
+
value={itemValue ?? ''}
|
|
171
|
+
onChange={(e) => {
|
|
172
|
+
const next = [...arr];
|
|
173
|
+
next[idx] =
|
|
174
|
+
e.target.value === '' ? undefined : e.target.value;
|
|
175
|
+
onChange(next);
|
|
176
|
+
}}
|
|
177
|
+
className="input"
|
|
178
|
+
style={{ flex: 1 }}
|
|
179
|
+
>
|
|
180
|
+
<option value="">(none)</option>
|
|
181
|
+
{options.map((opt) => (
|
|
182
|
+
<option key={opt} value={opt}>
|
|
183
|
+
{opt}
|
|
184
|
+
</option>
|
|
185
|
+
))}
|
|
186
|
+
</select>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
if (name === 'type') {
|
|
190
|
+
const options = projectOptions?.eventTypes ?? [];
|
|
191
|
+
if (options.length > 0) {
|
|
192
|
+
return (
|
|
193
|
+
<select
|
|
194
|
+
value={itemValue ?? ''}
|
|
195
|
+
onChange={(e) => {
|
|
196
|
+
const next = [...arr];
|
|
197
|
+
next[idx] =
|
|
198
|
+
e.target.value === '' ? undefined : e.target.value;
|
|
199
|
+
onChange(next);
|
|
200
|
+
}}
|
|
201
|
+
className="input"
|
|
202
|
+
style={{ flex: 1 }}
|
|
203
|
+
>
|
|
204
|
+
<option value="">(none)</option>
|
|
205
|
+
{options.map((opt) => (
|
|
206
|
+
<option key={opt} value={opt}>
|
|
207
|
+
{opt}
|
|
208
|
+
</option>
|
|
209
|
+
))}
|
|
210
|
+
</select>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
120
214
|
return (
|
|
121
215
|
<input
|
|
122
216
|
type="text"
|
|
@@ -244,6 +338,7 @@ export function Field({
|
|
|
244
338
|
layoutContext={layoutContext}
|
|
245
339
|
viewAttributes={viewAttributes}
|
|
246
340
|
label={fieldName}
|
|
341
|
+
projectOptions={projectOptions}
|
|
247
342
|
/>
|
|
248
343
|
</div>
|
|
249
344
|
);
|
|
@@ -265,6 +360,7 @@ export function Field({
|
|
|
265
360
|
projectColors={projectColors}
|
|
266
361
|
layoutContext={layoutContext}
|
|
267
362
|
viewAttributes={viewAttributes}
|
|
363
|
+
projectOptions={projectOptions}
|
|
268
364
|
/>
|
|
269
365
|
</React.Fragment>
|
|
270
366
|
);
|
|
@@ -369,6 +465,7 @@ export function Field({
|
|
|
369
465
|
layoutContext={layoutContext}
|
|
370
466
|
viewAttributes={viewAttributes}
|
|
371
467
|
label={fieldName}
|
|
468
|
+
projectOptions={projectOptions}
|
|
372
469
|
/>
|
|
373
470
|
</div>
|
|
374
471
|
);
|
|
@@ -388,6 +485,7 @@ export function Field({
|
|
|
388
485
|
projectColors={projectColors}
|
|
389
486
|
layoutContext={layoutContext}
|
|
390
487
|
viewAttributes={viewAttributes}
|
|
488
|
+
projectOptions={projectOptions}
|
|
391
489
|
/>
|
|
392
490
|
</React.Fragment>
|
|
393
491
|
);
|
|
@@ -496,7 +594,50 @@ export function Field({
|
|
|
496
594
|
/>
|
|
497
595
|
);
|
|
498
596
|
case 'string':
|
|
499
|
-
case 'description':
|
|
597
|
+
case 'description': {
|
|
598
|
+
// 1. Custom media field override (from host app)
|
|
599
|
+
if (type === 'string' && CustomMediaField && mediaFieldKind) {
|
|
600
|
+
return (
|
|
601
|
+
<CustomMediaField
|
|
602
|
+
value={typeof value === 'string' ? value : undefined}
|
|
603
|
+
onChange={(next) => onChange(next === '' ? undefined : next)}
|
|
604
|
+
fieldName={name}
|
|
605
|
+
componentType={componentType}
|
|
606
|
+
fieldKind={mediaFieldKind}
|
|
607
|
+
/>
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// 2. ProjectOptions-based dropdown
|
|
612
|
+
let options: string[] = [];
|
|
613
|
+
if (name === 'navigate_to' || name === 'pageKey') {
|
|
614
|
+
options = projectOptions?.pageKeys ?? [];
|
|
615
|
+
} else if (name === 'conditionKey') {
|
|
616
|
+
options = projectOptions?.conditionKeys ?? [];
|
|
617
|
+
} else if (name === 'placementKey') {
|
|
618
|
+
options = projectOptions?.placementKeys ?? [];
|
|
619
|
+
} else if (name === 'name' && componentType?.startsWith('Form')) {
|
|
620
|
+
options = projectOptions?.formFieldNames ?? [];
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (options.length > 0) {
|
|
624
|
+
return (
|
|
625
|
+
<select
|
|
626
|
+
value={value ?? ''}
|
|
627
|
+
onChange={(e) => onChange(e.target.value || undefined)}
|
|
628
|
+
className="input"
|
|
629
|
+
>
|
|
630
|
+
<option value="">(none)</option>
|
|
631
|
+
{options.map((opt) => (
|
|
632
|
+
<option key={opt} value={opt}>
|
|
633
|
+
{opt}
|
|
634
|
+
</option>
|
|
635
|
+
))}
|
|
636
|
+
</select>
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// 3. Default text input
|
|
500
641
|
return (
|
|
501
642
|
<input
|
|
502
643
|
type="text"
|
|
@@ -507,6 +648,7 @@ export function Field({
|
|
|
507
648
|
className="input"
|
|
508
649
|
/>
|
|
509
650
|
);
|
|
651
|
+
}
|
|
510
652
|
case 'title':
|
|
511
653
|
return (
|
|
512
654
|
<input
|
|
@@ -3,6 +3,7 @@ import type { ProjectColors } from '../types/Project';
|
|
|
3
3
|
import type { ViewPropsGenerated } from '../build-components/View/ViewProps.generated';
|
|
4
4
|
import type { Fonts } from '../types/Fonts';
|
|
5
5
|
import type { LayoutContext, SchemaEntry } from './types';
|
|
6
|
+
import type { ProjectOptions } from '../utils/nodeTree';
|
|
6
7
|
|
|
7
8
|
export type TabId = 'style' | 'container' | 'other';
|
|
8
9
|
|
|
@@ -10,6 +11,7 @@ export type AttributesEditorProps = {
|
|
|
10
11
|
node: Node;
|
|
11
12
|
onChange: (next: Node) => void;
|
|
12
13
|
projectColors?: ProjectColors;
|
|
14
|
+
projectRoot?: Node;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
export type AttributesEditorTabConfig = {
|
|
@@ -60,6 +62,7 @@ export type AttributesEditorModel = {
|
|
|
60
62
|
projectColorsForPicker?: ProjectColors;
|
|
61
63
|
viewAttributes?: Partial<ViewPropsGenerated['attributes']>;
|
|
62
64
|
layoutContext: LayoutContext;
|
|
65
|
+
projectOptions: ProjectOptions;
|
|
63
66
|
getAttributeValue: (name: string) => unknown;
|
|
64
67
|
handleAttributeChange: (name: string, val: unknown) => void;
|
|
65
68
|
handleChildrenChange: (val: string) => void;
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from '../utils/patterns';
|
|
14
14
|
import { useRenderStore } from '../store';
|
|
15
15
|
import type { LayoutContext, SchemaEntry } from './types';
|
|
16
|
+
import { collectProjectMetadata } from '../utils/nodeTree';
|
|
16
17
|
import {
|
|
17
18
|
buildAttributesEditorEntries,
|
|
18
19
|
findLegacyFlatStyleKeys,
|
|
@@ -36,6 +37,7 @@ export function useAttributesEditorModel({
|
|
|
36
37
|
node,
|
|
37
38
|
onChange,
|
|
38
39
|
projectColors,
|
|
40
|
+
projectRoot,
|
|
39
41
|
}: AttributesEditorProps): AttributesEditorModel {
|
|
40
42
|
const isInvalidNode = !node || isNodeString(node);
|
|
41
43
|
// Memoize baseData to prevent it from changing on every render
|
|
@@ -141,6 +143,11 @@ export function useAttributesEditorModel({
|
|
|
141
143
|
[projectColors],
|
|
142
144
|
);
|
|
143
145
|
|
|
146
|
+
const projectOptions = useMemo(
|
|
147
|
+
() => collectProjectMetadata(projectRoot || baseData),
|
|
148
|
+
[projectRoot, baseData],
|
|
149
|
+
);
|
|
150
|
+
|
|
144
151
|
const viewAttributes = useMemo<
|
|
145
152
|
Partial<ViewPropsGenerated['attributes']> | undefined
|
|
146
153
|
>(
|
|
@@ -428,6 +435,7 @@ export function useAttributesEditorModel({
|
|
|
428
435
|
projectColorsForPicker,
|
|
429
436
|
viewAttributes,
|
|
430
437
|
layoutContext,
|
|
438
|
+
projectOptions,
|
|
431
439
|
getAttributeValue,
|
|
432
440
|
handleAttributeChange,
|
|
433
441
|
handleChildrenChange,
|
|
@@ -70,12 +70,13 @@ function validationArrayToRules(validation: string[] | undefined): {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/** FormCheckbox wraps Checkbox with RHF; UI and styling come from Checkbox. */
|
|
73
|
-
|
|
73
|
+
// eslint-disable-next-line react/prop-types
|
|
74
74
|
export function FormCheckbox({ node }: FormCheckboxComponentProps) {
|
|
75
75
|
useLogRender('FormCheckbox');
|
|
76
76
|
node = useNode(node);
|
|
77
77
|
const ctx = useContext(formContext);
|
|
78
|
-
|
|
78
|
+
// eslint-disable-next-line react/prop-types
|
|
79
|
+
const attrs = node?.attributes;
|
|
79
80
|
const name = attrs?.name as string | undefined;
|
|
80
81
|
const validation = attrs?.validation as string[] | undefined;
|
|
81
82
|
|
|
@@ -105,4 +106,3 @@ export function FormCheckbox({ node }: FormCheckboxComponentProps) {
|
|
|
105
106
|
/>
|
|
106
107
|
);
|
|
107
108
|
}
|
|
108
|
-
/* eslint-enable react/prop-types */
|
|
@@ -6,6 +6,8 @@ import useNode from '../useNode';
|
|
|
6
6
|
import { useLogRender } from '../../utils/useLogRender';
|
|
7
7
|
import { useMockOSContext, useMockPermission } from '../../mockOS';
|
|
8
8
|
import { usePlacementButtonEvents } from '../SystemButton/usePlacementButtonEvents';
|
|
9
|
+
import { useGlobalNavigation } from '../GlobalProvider/useGlobalNavigation';
|
|
10
|
+
import { useGlobalContext } from '../GlobalProvider/GlobalContext';
|
|
9
11
|
|
|
10
12
|
export function FormSubmitButton({ node }: FormSubmitButtonComponentProps) {
|
|
11
13
|
useLogRender('FormSubmitButton');
|
|
@@ -13,12 +15,16 @@ export function FormSubmitButton({ node }: FormSubmitButtonComponentProps) {
|
|
|
13
15
|
const ctx = useContext(formContext);
|
|
14
16
|
const context = useMockOSContext();
|
|
15
17
|
const mockPermissionManager = useMockPermission(context);
|
|
18
|
+
const globalNavigate = useGlobalNavigation();
|
|
19
|
+
const globalCtx = useGlobalContext();
|
|
16
20
|
const attrs = node.attributes;
|
|
17
21
|
|
|
18
22
|
const runPlacementEvents = usePlacementButtonEvents(attrs?.events, {
|
|
19
23
|
context,
|
|
20
24
|
requestPermission: (permission) =>
|
|
21
25
|
mockPermissionManager.requestPermission(permission),
|
|
26
|
+
globalNavigate,
|
|
27
|
+
setCondition: globalCtx?.setCondition,
|
|
22
28
|
});
|
|
23
29
|
|
|
24
30
|
const validationRequired =
|
|
@@ -2,7 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
import type { NodeData } from '../../types/Node';
|
|
4
4
|
|
|
5
|
-
export type TypeOptionType =
|
|
5
|
+
export type TypeOptionType =
|
|
6
|
+
| 'Permission'
|
|
7
|
+
| 'Navigate'
|
|
8
|
+
| 'Placement'
|
|
9
|
+
| 'SetCondition';
|
|
10
|
+
export type PermissionOptionType =
|
|
11
|
+
| 'notification'
|
|
12
|
+
| 'camera'
|
|
13
|
+
| 'microphone'
|
|
14
|
+
| 'location'
|
|
15
|
+
| 'photos'
|
|
16
|
+
| 'contacts'
|
|
17
|
+
| 'att'
|
|
18
|
+
| 'rating'
|
|
19
|
+
| 'GDPR';
|
|
20
|
+
export type PlacementKeyOptionType =
|
|
21
|
+
| 'terms'
|
|
22
|
+
| 'onboard'
|
|
23
|
+
| 'paywall'
|
|
24
|
+
| 'subscription'
|
|
25
|
+
| 'home';
|
|
26
|
+
export type ConditionKeyOptionType = 'termsAccepted';
|
|
6
27
|
export type FlexDirectionOptionType = 'row' | 'column';
|
|
7
28
|
export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
|
|
8
29
|
export type AlignItemsOptionType =
|
|
@@ -22,10 +43,12 @@ export type PositionOptionType = 'relative' | 'absolute';
|
|
|
22
43
|
|
|
23
44
|
export interface EventObjectGenerated {
|
|
24
45
|
type?: TypeOptionType;
|
|
25
|
-
permission?:
|
|
46
|
+
permission?: PermissionOptionType;
|
|
26
47
|
navigate_to?: string;
|
|
27
48
|
targetIndex?: number;
|
|
28
|
-
placementKey?:
|
|
49
|
+
placementKey?: PlacementKeyOptionType;
|
|
50
|
+
conditionKey?: ConditionKeyOptionType;
|
|
51
|
+
value?: boolean;
|
|
29
52
|
}
|
|
30
53
|
|
|
31
54
|
export interface FormSubmitButtonStyleGenerated {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import type { NodeData } from '../../types/Node';
|
|
3
|
+
|
|
4
|
+
/** Supported transition animations when navigating to this page (platform-style names).
|
|
5
|
+
* rn stack transition animations
|
|
6
|
+
*/
|
|
7
|
+
export const GLOBAL_PAGE_ANIMATIONS = [
|
|
8
|
+
'default',
|
|
9
|
+
'fade',
|
|
10
|
+
'fade_from_bottom',
|
|
11
|
+
'fade_from_right',
|
|
12
|
+
'reveal_from_bottom',
|
|
13
|
+
'scale_from_center',
|
|
14
|
+
'slide_from_right',
|
|
15
|
+
'slide_from_left',
|
|
16
|
+
'slide_from_bottom',
|
|
17
|
+
'none',
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
export type GlobalPageAnimationType = (typeof GLOBAL_PAGE_ANIMATIONS)[number];
|
|
21
|
+
|
|
22
|
+
export interface GlobalPage {
|
|
23
|
+
key: string;
|
|
24
|
+
node: NodeData;
|
|
25
|
+
/** Condition key: this page is skipped when conditions[skipIf] === true */
|
|
26
|
+
skipIf?: string;
|
|
27
|
+
/** Optional transition animation when this page is shown (push/enter). */
|
|
28
|
+
animation?: string;
|
|
29
|
+
index: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface GlobalContextValue {
|
|
33
|
+
currentPageKey: string;
|
|
34
|
+
pages: GlobalPage[];
|
|
35
|
+
pageStack: string[];
|
|
36
|
+
navigate: (key: string) => void;
|
|
37
|
+
goNext: () => void;
|
|
38
|
+
goBack: () => boolean;
|
|
39
|
+
/** Runtime boolean conditions (e.g. termsAccepted) */
|
|
40
|
+
conditions: Record<string, boolean>;
|
|
41
|
+
setCondition: (key: string, value: boolean) => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const GlobalContext = createContext<GlobalContextValue | null>(null);
|
|
45
|
+
|
|
46
|
+
export function useGlobalContext(): GlobalContextValue | null {
|
|
47
|
+
return useContext(GlobalContext);
|
|
48
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { GlobalProviderComponentProps } from './GlobalProviderProps.generated';
|
|
3
|
+
import { GlobalContext } from './GlobalContext';
|
|
4
|
+
import { useGlobalProviderLogic } from './useGlobalProviderLogic';
|
|
5
|
+
import RenderNode from '../RenderNode.generated';
|
|
6
|
+
import { useLogRender } from '../../utils/useLogRender';
|
|
7
|
+
|
|
8
|
+
function GlobalProvider({ node }: GlobalProviderComponentProps) {
|
|
9
|
+
useLogRender('GlobalProvider');
|
|
10
|
+
|
|
11
|
+
const { attributeName, attributeKey, attrs, activePage, contextValue } =
|
|
12
|
+
useGlobalProviderLogic({ node });
|
|
13
|
+
|
|
14
|
+
const animationClass = (() => {
|
|
15
|
+
const a = activePage?.animation;
|
|
16
|
+
if (a === 'default') return 'global-provider-page--default';
|
|
17
|
+
if (!a || a === 'none') return ''; // No modifier: no animation at all
|
|
18
|
+
return `global-provider-page--${a}`;
|
|
19
|
+
})();
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<GlobalContext.Provider value={contextValue}>
|
|
23
|
+
<div
|
|
24
|
+
attribute-name={attributeName}
|
|
25
|
+
attribute-key={attributeKey}
|
|
26
|
+
{...(attrs?.testID ? { 'data-testid': attrs.testID } : {})}
|
|
27
|
+
style={{
|
|
28
|
+
flex: 1,
|
|
29
|
+
display: 'flex',
|
|
30
|
+
flexDirection: 'column',
|
|
31
|
+
height: '100%',
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
{activePage ? (
|
|
35
|
+
<div
|
|
36
|
+
key={activePage.key}
|
|
37
|
+
className={
|
|
38
|
+
animationClass
|
|
39
|
+
? `global-provider-page ${animationClass}`
|
|
40
|
+
: 'global-provider-page'
|
|
41
|
+
}
|
|
42
|
+
>
|
|
43
|
+
<RenderNode node={activePage.node} />
|
|
44
|
+
</div>
|
|
45
|
+
) : null}
|
|
46
|
+
</div>
|
|
47
|
+
</GlobalContext.Provider>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default React.memo(GlobalProvider);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* AUTO-GENERATED FILE - DO NOT EDIT */
|
|
2
|
+
|
|
3
|
+
import type { NodeData } from '../../types/Node';
|
|
4
|
+
|
|
5
|
+
export type FlexDirectionOptionType = 'row' | 'column';
|
|
6
|
+
export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
|
|
7
|
+
export type AlignItemsOptionType =
|
|
8
|
+
| 'flex-start'
|
|
9
|
+
| 'center'
|
|
10
|
+
| 'flex-end'
|
|
11
|
+
| 'stretch'
|
|
12
|
+
| 'baseline';
|
|
13
|
+
export type JustifyContentOptionType =
|
|
14
|
+
| 'flex-start'
|
|
15
|
+
| 'center'
|
|
16
|
+
| 'flex-end'
|
|
17
|
+
| 'space-between'
|
|
18
|
+
| 'space-around'
|
|
19
|
+
| 'space-evenly';
|
|
20
|
+
export type PositionOptionType = 'relative' | 'absolute';
|
|
21
|
+
|
|
22
|
+
export interface SkipConditionEntryGenerated {
|
|
23
|
+
pageKey?: string;
|
|
24
|
+
conditionKey?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface GlobalProviderStyleGenerated {
|
|
28
|
+
flexDirection?: FlexDirectionOptionType;
|
|
29
|
+
flexWrap?: FlexWrapOptionType;
|
|
30
|
+
alignItems?: AlignItemsOptionType;
|
|
31
|
+
justifyContent?: JustifyContentOptionType;
|
|
32
|
+
gap?: string;
|
|
33
|
+
padding?: string;
|
|
34
|
+
paddingHorizontal?: string;
|
|
35
|
+
paddingVertical?: string;
|
|
36
|
+
paddingTop?: string;
|
|
37
|
+
paddingBottom?: string;
|
|
38
|
+
paddingLeft?: string;
|
|
39
|
+
paddingRight?: string;
|
|
40
|
+
margin?: string;
|
|
41
|
+
marginHorizontal?: string;
|
|
42
|
+
marginVertical?: string;
|
|
43
|
+
marginTop?: string;
|
|
44
|
+
marginBottom?: string;
|
|
45
|
+
marginLeft?: string;
|
|
46
|
+
marginRight?: string;
|
|
47
|
+
backgroundColor?: string;
|
|
48
|
+
borderRadius?: string;
|
|
49
|
+
width?: string;
|
|
50
|
+
minWidth?: string;
|
|
51
|
+
maxWidth?: string;
|
|
52
|
+
height?: string;
|
|
53
|
+
minHeight?: string;
|
|
54
|
+
maxHeight?: string;
|
|
55
|
+
flex?: number;
|
|
56
|
+
position?: PositionOptionType;
|
|
57
|
+
top?: string;
|
|
58
|
+
bottom?: string;
|
|
59
|
+
left?: string;
|
|
60
|
+
right?: string;
|
|
61
|
+
zIndex?: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface GlobalProviderPropsGenerated {
|
|
65
|
+
child: string;
|
|
66
|
+
attributes: {
|
|
67
|
+
styles?: GlobalProviderStyleGenerated;
|
|
68
|
+
scrollable?: boolean;
|
|
69
|
+
testID?: string;
|
|
70
|
+
initialPage?: string;
|
|
71
|
+
persistProgress?: boolean;
|
|
72
|
+
skipConditions?: SkipConditionEntryGenerated[];
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface GlobalProviderComponentProps {
|
|
77
|
+
node: NodeData<GlobalProviderPropsGenerated['attributes']>;
|
|
78
|
+
}
|