@developer_tribe/react-builder 1.2.43 → 1.2.44-test.1
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/build-components/Checkbox/Checkbox.d.ts +6 -0
- package/dist/build-components/Checkbox/CheckboxProps.generated.d.ts +67 -0
- package/dist/build-components/FormCheckbox/FormCheckbox.d.ts +3 -0
- package/dist/build-components/FormCheckbox/FormCheckboxProps.generated.d.ts +69 -0
- package/dist/build-components/FormErrorText/FormErrorText.d.ts +3 -0
- package/dist/build-components/FormErrorText/FormErrorTextProps.generated.d.ts +61 -0
- package/dist/build-components/FormProvider/FormProvider.d.ts +11 -0
- package/dist/build-components/FormProvider/FormProviderProps.generated.d.ts +55 -0
- package/dist/build-components/FormSubmitButton/FormSubmitButton.d.ts +2 -0
- package/dist/build-components/FormSubmitButton/FormSubmitButtonProps.generated.d.ts +73 -0
- 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 +37 -0
- package/dist/build-components/GlobalProvider/useGlobalNavigation.d.ts +19 -0
- package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +17 -10
- 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/SystemButton.d.ts +7 -0
- package/dist/build-components/SystemButton/SystemButtonProps.generated.d.ts +71 -0
- package/dist/build-components/SystemButton/usePlacementButtonEvents.d.ts +28 -0
- 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/WebView/WebView.d.ts +2 -0
- package/dist/build-components/WebView/WebViewProps.generated.d.ts +59 -0
- package/dist/build-components/index.d.ts +10 -1
- package/dist/build-components/patterns.generated.d.ts +5639 -1686
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.web.cjs.js +5 -5
- package/dist/index.web.cjs.js.map +1 -1
- package/dist/index.web.d.ts +1 -0
- package/dist/index.web.esm.js +4 -4
- package/dist/index.web.esm.js.map +1 -1
- package/dist/mockOS/context/MockOSContextBase.d.ts +3 -1
- package/dist/styles.css +1 -1
- package/dist/types/PreviewConfig.d.ts +1 -1
- package/package.json +2 -1
- 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 +7 -0
- package/src/assets/samples/global-onboard-flow.json +729 -0
- package/src/assets/samples/terms-and-privacy-no-form.json +108 -0
- package/src/assets/samples/terms-and-privacy.json +130 -0
- package/src/build-components/Checkbox/Checkbox.tsx +165 -0
- package/src/build-components/Checkbox/CheckboxProps.generated.ts +84 -0
- package/src/build-components/Checkbox/pattern.json +83 -0
- package/src/build-components/FormCheckbox/FormCheckbox.tsx +106 -0
- package/src/build-components/FormCheckbox/FormCheckboxProps.generated.ts +86 -0
- package/src/build-components/FormCheckbox/pattern.json +39 -0
- package/src/build-components/FormErrorText/FormErrorText.tsx +34 -0
- package/src/build-components/FormErrorText/FormErrorTextProps.generated.ts +78 -0
- package/src/build-components/FormErrorText/pattern.json +21 -0
- package/src/build-components/FormProvider/FormProvider.tsx +131 -0
- package/src/build-components/FormProvider/FormProviderProps.generated.ts +72 -0
- package/src/build-components/FormProvider/pattern.json +33 -0
- package/src/build-components/FormSubmitButton/FormSubmitButton.tsx +49 -0
- package/src/build-components/FormSubmitButton/FormSubmitButtonProps.generated.ts +91 -0
- package/src/build-components/FormSubmitButton/pattern.json +33 -0
- package/src/build-components/GlobalProvider/GlobalContext.ts +48 -0
- package/src/build-components/GlobalProvider/GlobalProvider.tsx +191 -0
- package/src/build-components/GlobalProvider/GlobalProviderProps.generated.ts +78 -0
- package/src/build-components/GlobalProvider/globalProviderUtils.ts +163 -0
- package/src/build-components/GlobalProvider/pattern.json +55 -0
- package/src/build-components/GlobalProvider/useGlobalNavigation.ts +70 -0
- package/src/build-components/OnboardButton/OnboardButton.tsx +41 -36
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +17 -10
- package/src/build-components/OnboardButton/pattern.json +5 -4
- 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 +46 -1
- package/src/build-components/SystemButton/SystemButton.tsx +71 -0
- package/src/build-components/SystemButton/SystemButtonProps.generated.ts +89 -0
- package/src/build-components/SystemButton/pattern.json +61 -0
- package/src/build-components/SystemButton/usePlacementButtonEvents.ts +101 -0
- 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/WebView/WebView.tsx +149 -0
- package/src/build-components/WebView/WebViewProps.generated.ts +76 -0
- package/src/build-components/WebView/pattern.json +71 -0
- package/src/build-components/index.ts +45 -0
- package/src/build-components/patterns.generated.ts +5701 -1559
- package/src/index.web.ts +3 -0
- package/src/mockOS/components/MockOSRouter.tsx +21 -0
- package/src/mockOS/context/MockOSContext.tsx +7 -0
- package/src/mockOS/context/MockOSContextBase.ts +4 -0
- package/src/styles/components/_checkbox.scss +19 -0
- package/src/styles/components/_global-provider.scss +131 -0
- package/src/styles/components/_webview.scss +52 -0
- package/src/styles/index.scss +4 -0
- package/src/types/PreviewConfig.ts +19 -0
- package/src/utils/analyseNodeByPatterns.ts +5 -2
- package/src/utils/projectColors.ts +4 -0
- package/src/.DS_Store +0 -0
- package/src/assets/.DS_Store +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Terms and Privacy (no form)",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"type": "terms",
|
|
5
|
+
"data": {
|
|
6
|
+
"type": "Main",
|
|
7
|
+
"isMain": true,
|
|
8
|
+
"attributes": {
|
|
9
|
+
"useSafeAreaView": true,
|
|
10
|
+
"description": "Terms and Privacy screen without FormProvider; plain Checkbox and SystemButton.",
|
|
11
|
+
"title": "Terms & Privacy",
|
|
12
|
+
"styles": {
|
|
13
|
+
"backgroundColor": "THEME_COLORS.BACKGROUND",
|
|
14
|
+
"flex": 1
|
|
15
|
+
},
|
|
16
|
+
"testID": "TermsPrivacyNoForm-Main"
|
|
17
|
+
},
|
|
18
|
+
"children": [
|
|
19
|
+
{
|
|
20
|
+
"type": "View",
|
|
21
|
+
"attributes": {
|
|
22
|
+
"description": "Header section",
|
|
23
|
+
"styles": {
|
|
24
|
+
"padding": 16,
|
|
25
|
+
"alignItems": "center",
|
|
26
|
+
"borderBottomWidth": 1,
|
|
27
|
+
"borderBottomColor": "THEME_COLORS.LINE",
|
|
28
|
+
"backgroundColor": "THEME_COLORS.BACKGROUND"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"children": [
|
|
32
|
+
{
|
|
33
|
+
"type": "Text",
|
|
34
|
+
"children": "view.terms.header.title",
|
|
35
|
+
"attributes": {
|
|
36
|
+
"styles": {
|
|
37
|
+
"fontSize": 20,
|
|
38
|
+
"fontWeight": "700",
|
|
39
|
+
"color": "THEME_COLORS.TEXT"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"type": "WebView",
|
|
47
|
+
"attributes": {
|
|
48
|
+
"iosUrl": "https://stage.vpn111.net/page/ios/privacy",
|
|
49
|
+
"androidUrl": "https://stage.vpn111.net/page/android/privacy",
|
|
50
|
+
"styles": {
|
|
51
|
+
"flex": 1,
|
|
52
|
+
"backgroundColor": "THEME_COLORS.BACKGROUND"
|
|
53
|
+
},
|
|
54
|
+
"testID": "TermsPrivacyNoForm-WebView"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "View",
|
|
59
|
+
"attributes": {
|
|
60
|
+
"description": "Footer section",
|
|
61
|
+
"styles": {
|
|
62
|
+
"padding": 20,
|
|
63
|
+
"backgroundColor": "THEME_COLORS.BACKGROUND",
|
|
64
|
+
"borderTopWidth": 1,
|
|
65
|
+
"borderTopColor": "THEME_COLORS.LINE",
|
|
66
|
+
"gap": 16
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"children": [
|
|
70
|
+
{
|
|
71
|
+
"type": "Checkbox",
|
|
72
|
+
"attributes": {
|
|
73
|
+
"checked": false,
|
|
74
|
+
"label": "view.terms.checkbox.label",
|
|
75
|
+
"checkedColor": "THEME_COLORS.CHECKBOX_ACTIVE_COLOR",
|
|
76
|
+
"styles": {
|
|
77
|
+
"marginBottom": 8
|
|
78
|
+
},
|
|
79
|
+
"testID": "TermsPrivacyNoForm-Checkbox"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"type": "SystemButton",
|
|
84
|
+
"attributes": {
|
|
85
|
+
"labelKey": "view.terms.accept.button",
|
|
86
|
+
"events": [
|
|
87
|
+
{
|
|
88
|
+
"type": "Navigate",
|
|
89
|
+
"placementKey": "onboard"
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"styles": {
|
|
93
|
+
"backgroundColor": "STATIC_COLORS.ONBOARD_BUTTON_PRIMARY_BACKGROUND",
|
|
94
|
+
"color": "#FFFFFF",
|
|
95
|
+
"height": 48,
|
|
96
|
+
"borderRadius": 8,
|
|
97
|
+
"alignItems": "center",
|
|
98
|
+
"justifyContent": "center",
|
|
99
|
+
"fontWeight": "600"
|
|
100
|
+
},
|
|
101
|
+
"testID": "TermsPrivacyNoForm-AcceptButton"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Terms and Privacy",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"type": "terms",
|
|
5
|
+
"data": {
|
|
6
|
+
"type": "Main",
|
|
7
|
+
"isMain": true,
|
|
8
|
+
"attributes": {
|
|
9
|
+
"useSafeAreaView": true,
|
|
10
|
+
"description": "Terms and Privacy screen container",
|
|
11
|
+
"title": "Terms & Privacy",
|
|
12
|
+
"styles": {
|
|
13
|
+
"backgroundColor": "THEME_COLORS.BACKGROUND",
|
|
14
|
+
"flex": 1
|
|
15
|
+
},
|
|
16
|
+
"testID": "TermsPrivacy-Main"
|
|
17
|
+
},
|
|
18
|
+
"children": [
|
|
19
|
+
{
|
|
20
|
+
"type": "View",
|
|
21
|
+
"attributes": {
|
|
22
|
+
"description": "Header section",
|
|
23
|
+
"styles": {
|
|
24
|
+
"padding": 16,
|
|
25
|
+
"alignItems": "center",
|
|
26
|
+
"borderBottomWidth": 1,
|
|
27
|
+
"borderBottomColor": "THEME_COLORS.LINE",
|
|
28
|
+
"backgroundColor": "THEME_COLORS.BACKGROUND"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"children": [
|
|
32
|
+
{
|
|
33
|
+
"type": "Text",
|
|
34
|
+
"children": "view.terms.header.title",
|
|
35
|
+
"attributes": {
|
|
36
|
+
"styles": {
|
|
37
|
+
"fontSize": 20,
|
|
38
|
+
"fontWeight": "700",
|
|
39
|
+
"color": "THEME_COLORS.TEXT"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"type": "WebView",
|
|
47
|
+
"attributes": {
|
|
48
|
+
"iosUrl": "https://stage.vpn111.net/page/ios/privacy",
|
|
49
|
+
"androidUrl": "https://stage.vpn111.net/page/android/privacy",
|
|
50
|
+
"styles": {
|
|
51
|
+
"flex": 1,
|
|
52
|
+
"backgroundColor": "THEME_COLORS.BACKGROUND"
|
|
53
|
+
},
|
|
54
|
+
"testID": "TermsPrivacy-WebView"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "View",
|
|
59
|
+
"attributes": {
|
|
60
|
+
"description": "Footer section",
|
|
61
|
+
"styles": {
|
|
62
|
+
"padding": 20,
|
|
63
|
+
"backgroundColor": "THEME_COLORS.BACKGROUND",
|
|
64
|
+
"borderTopWidth": 1,
|
|
65
|
+
"borderTopColor": "THEME_COLORS.LINE",
|
|
66
|
+
"gap": 16
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"children": [
|
|
70
|
+
{
|
|
71
|
+
"type": "FormProvider",
|
|
72
|
+
"attributes": {
|
|
73
|
+
"defaultValues": "{\"termsAccepted\": false}",
|
|
74
|
+
"validationErrorMessageKey": "view.terms.error.must_accept"
|
|
75
|
+
},
|
|
76
|
+
"children": [
|
|
77
|
+
{
|
|
78
|
+
"type": "FormCheckbox",
|
|
79
|
+
"attributes": {
|
|
80
|
+
"name": "termsAccepted",
|
|
81
|
+
"validation": ["required"],
|
|
82
|
+
"checked": false,
|
|
83
|
+
"label": "view.terms.checkbox.label",
|
|
84
|
+
"checkedColor": "THEME_COLORS.CHECKBOX_ACTIVE_COLOR",
|
|
85
|
+
"styles": {
|
|
86
|
+
"marginBottom": 8
|
|
87
|
+
},
|
|
88
|
+
"testID": "TermsPrivacy-Checkbox"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"type": "FormErrorText",
|
|
93
|
+
"attributes": {
|
|
94
|
+
"styles": {
|
|
95
|
+
"marginBottom": 8
|
|
96
|
+
},
|
|
97
|
+
"testID": "TermsPrivacy-FormErrorText"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"type": "FormSubmitButton",
|
|
102
|
+
"attributes": {
|
|
103
|
+
"labelKey": "view.terms.accept.button",
|
|
104
|
+
"validationRequired": true,
|
|
105
|
+
"disableIfUnvalidated": true,
|
|
106
|
+
"events": [
|
|
107
|
+
{
|
|
108
|
+
"type": "Navigate",
|
|
109
|
+
"placementKey": "onboard"
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
"styles": {
|
|
113
|
+
"backgroundColor": "STATIC_COLORS.ONBOARD_BUTTON_PRIMARY_BACKGROUND",
|
|
114
|
+
"color": "#FFFFFF",
|
|
115
|
+
"height": 48,
|
|
116
|
+
"borderRadius": 8,
|
|
117
|
+
"alignItems": "center",
|
|
118
|
+
"justifyContent": "center",
|
|
119
|
+
"fontWeight": "600"
|
|
120
|
+
},
|
|
121
|
+
"testID": "TermsPrivacy-AcceptButton"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React, { useState, useId } from 'react';
|
|
2
|
+
import type { NodeData } from '../../types/Node';
|
|
3
|
+
import type { ViewPropsGenerated } from '../View/ViewProps.generated';
|
|
4
|
+
import { CheckboxComponentProps } from './CheckboxProps.generated';
|
|
5
|
+
import useNode from '../useNode';
|
|
6
|
+
import { useLogRender } from '../../utils/useLogRender';
|
|
7
|
+
import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
|
|
8
|
+
import { parseColor, type ParseColorOptions } from '../../utils/parseColor';
|
|
9
|
+
import { useBuilderParams } from '../../components/BuilderProvider';
|
|
10
|
+
import { useLocalize } from '../../hooks/useLocalize';
|
|
11
|
+
import { Icon } from '../../components/Icon.generated';
|
|
12
|
+
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
13
|
+
import { getStyleBag, toAttributeRecord } from '../../utils/attributeStyle';
|
|
14
|
+
|
|
15
|
+
export interface CheckboxProps extends CheckboxComponentProps {
|
|
16
|
+
checked?: boolean;
|
|
17
|
+
onCheckedChange?: (value: boolean) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function resolveCheckedColor(
|
|
21
|
+
attrRecord: Record<string, unknown>,
|
|
22
|
+
stylesBag: Record<string, unknown> | undefined,
|
|
23
|
+
colorOpts: ParseColorOptions,
|
|
24
|
+
): string {
|
|
25
|
+
const raw =
|
|
26
|
+
(attrRecord.checkedColor as string | undefined) ??
|
|
27
|
+
(attrRecord.color as string | undefined) ??
|
|
28
|
+
(stylesBag?.color as string | undefined);
|
|
29
|
+
const token =
|
|
30
|
+
(typeof raw === 'string' && raw.trim()) ||
|
|
31
|
+
'THEME_COLORS.CHECKBOX_ACTIVE_COLOR';
|
|
32
|
+
return parseColor(token, colorOpts) ?? '#000000';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function Checkbox({
|
|
36
|
+
node,
|
|
37
|
+
checked: controlledChecked,
|
|
38
|
+
onCheckedChange,
|
|
39
|
+
}: CheckboxProps) {
|
|
40
|
+
useLogRender('Checkbox');
|
|
41
|
+
node = useNode(node);
|
|
42
|
+
const attrs = node.attributes;
|
|
43
|
+
const attrRecord = toAttributeRecord(attrs);
|
|
44
|
+
const stylesBag = getStyleBag(attrs);
|
|
45
|
+
const labelId = useId();
|
|
46
|
+
const viewStyle = useExtractViewStyle(
|
|
47
|
+
node as NodeData<ViewPropsGenerated['attributes']>,
|
|
48
|
+
);
|
|
49
|
+
const { selectedTheme: theme, projectColors } = useBuilderParams();
|
|
50
|
+
const localize = useLocalize();
|
|
51
|
+
const colorOpts: ParseColorOptions = {
|
|
52
|
+
projectColors,
|
|
53
|
+
theme: theme ?? 'light',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const isControlled =
|
|
57
|
+
controlledChecked !== undefined && onCheckedChange !== undefined;
|
|
58
|
+
const [internalChecked, setInternalChecked] = useState(
|
|
59
|
+
attrs?.checked ?? false,
|
|
60
|
+
);
|
|
61
|
+
const checked = isControlled ? controlledChecked : internalChecked;
|
|
62
|
+
|
|
63
|
+
const activeColor = resolveCheckedColor(attrRecord, stylesBag, colorOpts);
|
|
64
|
+
|
|
65
|
+
const inactiveBorderColor =
|
|
66
|
+
parseColor('THEME_COLORS.LINE', colorOpts) ??
|
|
67
|
+
parseColor('STATIC_COLORS.ONBOARD_SEPARATOR_COLOR', colorOpts);
|
|
68
|
+
|
|
69
|
+
const labelRaw = attrs?.label ?? '';
|
|
70
|
+
const label = localize(labelRaw);
|
|
71
|
+
|
|
72
|
+
const labelFontSize = attrs?.styles?.fontSize ?? 14;
|
|
73
|
+
const labelFontFamily = attrs?.styles?.fontFamily as string | undefined;
|
|
74
|
+
const labelFontWeight = attrs?.styles?.fontWeight as
|
|
75
|
+
| string
|
|
76
|
+
| number
|
|
77
|
+
| undefined;
|
|
78
|
+
const labelTextAlign = attrs?.styles?.textAlign as
|
|
79
|
+
| React.CSSProperties['textAlign']
|
|
80
|
+
| undefined;
|
|
81
|
+
const labelColor =
|
|
82
|
+
parseColor(attrs?.styles?.color as string, colorOpts) ??
|
|
83
|
+
parseColor('THEME_COLORS.TEXT', colorOpts) ??
|
|
84
|
+
parseColor('STATIC_COLORS.BLACK', colorOpts);
|
|
85
|
+
|
|
86
|
+
const checkIconColor =
|
|
87
|
+
parseColor('STATIC_COLORS.WHITE', colorOpts) ?? undefined;
|
|
88
|
+
|
|
89
|
+
const styles = attrs?.styles;
|
|
90
|
+
const boxWidth = styles?.width ?? 20;
|
|
91
|
+
const boxHeight = styles?.height ?? 20;
|
|
92
|
+
const boxBorderRadius = styles?.borderRadius ?? 4;
|
|
93
|
+
const checkIconSize = styles?.checkIconSize ?? 12;
|
|
94
|
+
const checkIconStrokeWidth = styles?.checkIconStrokeWidth ?? 1.7;
|
|
95
|
+
const boxMarginRight = styles?.marginRight ?? 10;
|
|
96
|
+
|
|
97
|
+
const handleToggle = () => {
|
|
98
|
+
const next = !checked;
|
|
99
|
+
if (isControlled) {
|
|
100
|
+
onCheckedChange?.(next);
|
|
101
|
+
} else {
|
|
102
|
+
setInternalChecked(next);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
107
|
+
if (e.key === ' ' || e.key === 'Enter') {
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
handleToggle();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const containerStyle = useMergedStyle(viewStyle);
|
|
114
|
+
const boxStyle = {
|
|
115
|
+
width: boxWidth,
|
|
116
|
+
height: boxHeight,
|
|
117
|
+
minWidth: boxWidth,
|
|
118
|
+
minHeight: boxHeight,
|
|
119
|
+
borderRadius: boxBorderRadius,
|
|
120
|
+
border: `2px solid ${checked ? (activeColor ?? 'transparent') : (inactiveBorderColor ?? 'transparent')}`,
|
|
121
|
+
backgroundColor: checked ? (activeColor ?? 'transparent') : 'transparent',
|
|
122
|
+
marginRight: boxMarginRight,
|
|
123
|
+
};
|
|
124
|
+
const labelStyle: React.CSSProperties = {
|
|
125
|
+
fontSize: labelFontSize,
|
|
126
|
+
color: labelColor ?? undefined,
|
|
127
|
+
fontFamily: labelFontFamily,
|
|
128
|
+
fontWeight: labelFontWeight,
|
|
129
|
+
textAlign: labelTextAlign,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<div
|
|
134
|
+
role="checkbox"
|
|
135
|
+
aria-checked={checked}
|
|
136
|
+
aria-labelledby={label ? labelId : undefined}
|
|
137
|
+
aria-label={!label ? 'Checkbox' : undefined}
|
|
138
|
+
tabIndex={0}
|
|
139
|
+
className="rb-checkbox"
|
|
140
|
+
style={containerStyle}
|
|
141
|
+
onClick={handleToggle}
|
|
142
|
+
onKeyDown={handleKeyDown}
|
|
143
|
+
data-testid={attrs?.testID}
|
|
144
|
+
>
|
|
145
|
+
<div className="rb-checkbox__box" style={boxStyle}>
|
|
146
|
+
{checked && (
|
|
147
|
+
<Icon
|
|
148
|
+
iconType="check"
|
|
149
|
+
size={checkIconSize}
|
|
150
|
+
strokeWidth={checkIconStrokeWidth}
|
|
151
|
+
color={
|
|
152
|
+
typeof checkIconColor === 'string' ? checkIconColor : undefined
|
|
153
|
+
}
|
|
154
|
+
alt=""
|
|
155
|
+
/>
|
|
156
|
+
)}
|
|
157
|
+
</div>
|
|
158
|
+
{label ? (
|
|
159
|
+
<span id={labelId} className="rb-checkbox__label" style={labelStyle}>
|
|
160
|
+
{label}
|
|
161
|
+
</span>
|
|
162
|
+
) : null}
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
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 CheckboxStyleGenerated {
|
|
23
|
+
color?: string;
|
|
24
|
+
fontSize?: string;
|
|
25
|
+
fontFamily?: string;
|
|
26
|
+
fontWeight?: string;
|
|
27
|
+
textAlign?: string;
|
|
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?: number;
|
|
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
|
+
checkIconSize?: number;
|
|
63
|
+
checkIconStrokeWidth?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface CheckboxPropsGenerated {
|
|
67
|
+
child: string;
|
|
68
|
+
attributes: {
|
|
69
|
+
styles?: CheckboxStyleGenerated;
|
|
70
|
+
adjustsFontSizeToFit?: boolean;
|
|
71
|
+
numberOfLines?: number;
|
|
72
|
+
translateCounter?: number;
|
|
73
|
+
scrollable?: boolean;
|
|
74
|
+
testID?: string;
|
|
75
|
+
checked?: boolean;
|
|
76
|
+
label?: string;
|
|
77
|
+
checkedColor?: string;
|
|
78
|
+
syncTermsAccepted?: boolean;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface CheckboxComponentProps {
|
|
83
|
+
node: NodeData<CheckboxPropsGenerated['attributes']>;
|
|
84
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"pattern": {
|
|
4
|
+
"type": "Checkbox",
|
|
5
|
+
"title": "Checkbox",
|
|
6
|
+
"description": "A standard checkbox component.",
|
|
7
|
+
"children": "never",
|
|
8
|
+
"extends": "Text",
|
|
9
|
+
"attributes": {
|
|
10
|
+
"checked": "boolean",
|
|
11
|
+
"label": "string",
|
|
12
|
+
"checkedColor": "color",
|
|
13
|
+
"syncTermsAccepted": "boolean",
|
|
14
|
+
"styles": {
|
|
15
|
+
"borderRadius": "number",
|
|
16
|
+
"checkIconSize": "number",
|
|
17
|
+
"checkIconStrokeWidth": "number"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"defaults": {
|
|
21
|
+
"checked": false,
|
|
22
|
+
"label": "view.terms.checkbox.label",
|
|
23
|
+
"styles": {
|
|
24
|
+
"borderRadius": 4,
|
|
25
|
+
"checkIconSize": 12,
|
|
26
|
+
"checkIconStrokeWidth": 1.7,
|
|
27
|
+
"flexDirection": "row"
|
|
28
|
+
},
|
|
29
|
+
"checkedColor": "THEME_COLORS.CHECKBOX_ACTIVE_COLOR"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"meta": {
|
|
33
|
+
"label": "Checkbox",
|
|
34
|
+
"description": "A checkbox with an optional label.",
|
|
35
|
+
"attributes": {
|
|
36
|
+
"checked": {
|
|
37
|
+
"label": "Checked",
|
|
38
|
+
"description": "Whether the checkbox is checked by default.",
|
|
39
|
+
"category": "other",
|
|
40
|
+
"sort": 1
|
|
41
|
+
},
|
|
42
|
+
"label": {
|
|
43
|
+
"label": "Label",
|
|
44
|
+
"description": "The text label next to the checkbox.",
|
|
45
|
+
"category": "other",
|
|
46
|
+
"sort": 2
|
|
47
|
+
},
|
|
48
|
+
"checkedColor": {
|
|
49
|
+
"label": "Checked color",
|
|
50
|
+
"description": "The color of the checkbox when checked.",
|
|
51
|
+
"category": "style",
|
|
52
|
+
"sort": 3
|
|
53
|
+
},
|
|
54
|
+
"styles": {
|
|
55
|
+
"width": {
|
|
56
|
+
"label": "Box Width",
|
|
57
|
+
"description": "Width of the checkbox box (px).",
|
|
58
|
+
"category": "style"
|
|
59
|
+
},
|
|
60
|
+
"height": {
|
|
61
|
+
"label": "Box Height",
|
|
62
|
+
"description": "Height of the checkbox box (px).",
|
|
63
|
+
"category": "style"
|
|
64
|
+
},
|
|
65
|
+
"borderRadius": {
|
|
66
|
+
"label": "Box Border Radius",
|
|
67
|
+
"description": "Border radius of the checkbox box (px).",
|
|
68
|
+
"category": "style"
|
|
69
|
+
},
|
|
70
|
+
"checkIconSize": {
|
|
71
|
+
"label": "Check Icon Size",
|
|
72
|
+
"description": "Size of the check icon inside the box (px).",
|
|
73
|
+
"category": "style"
|
|
74
|
+
},
|
|
75
|
+
"checkIconStrokeWidth": {
|
|
76
|
+
"label": "Check Icon Stroke Width",
|
|
77
|
+
"description": "Stroke width of the check icon inside the box.",
|
|
78
|
+
"category": "style"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
import { Controller } from 'react-hook-form';
|
|
3
|
+
import type {
|
|
4
|
+
FieldValues,
|
|
5
|
+
Control,
|
|
6
|
+
ControllerRenderProps,
|
|
7
|
+
} from 'react-hook-form';
|
|
8
|
+
import type { FormCheckboxComponentProps } from './FormCheckboxProps.generated';
|
|
9
|
+
import { formContext } from '../FormProvider/FormProvider';
|
|
10
|
+
import { Checkbox } from '../Checkbox/Checkbox';
|
|
11
|
+
import useNode from '../useNode';
|
|
12
|
+
import { useLogRender } from '../../utils/useLogRender';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Converts builder validation array to react-hook-form rules.
|
|
16
|
+
* Builder must send validation as key-value pairs; e.g. ['required'] or ['min', 2], ['max', 5].
|
|
17
|
+
* If 'min' or 'max' is the last element (no value following), that rule is skipped (no crash).
|
|
18
|
+
*/
|
|
19
|
+
function validationArrayToRules(validation: string[] | undefined): {
|
|
20
|
+
required?: boolean;
|
|
21
|
+
min?: number;
|
|
22
|
+
max?: number;
|
|
23
|
+
} {
|
|
24
|
+
const rules: { required?: boolean; min?: number; max?: number } = {};
|
|
25
|
+
if (!Array.isArray(validation)) return rules;
|
|
26
|
+
if (validation.includes('required')) rules.required = true;
|
|
27
|
+
const minIdx = validation.indexOf('min');
|
|
28
|
+
if (minIdx >= 0) {
|
|
29
|
+
if (validation[minIdx + 1] != null) {
|
|
30
|
+
const minVal = Number(validation[minIdx + 1]);
|
|
31
|
+
if (Number.isFinite(minVal)) rules.min = minVal;
|
|
32
|
+
else {
|
|
33
|
+
console.warn(
|
|
34
|
+
'[FormCheckbox] validation "min" rule skipped: value must be a number.',
|
|
35
|
+
'Received:',
|
|
36
|
+
validation[minIdx + 1],
|
|
37
|
+
'— Expected e.g. ["min", 2].',
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
console.warn(
|
|
42
|
+
'[FormCheckbox] validation "min" rule skipped: no value after "min".',
|
|
43
|
+
'Expected e.g. ["min", 2], got:',
|
|
44
|
+
validation,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const maxIdx = validation.indexOf('max');
|
|
49
|
+
if (maxIdx >= 0) {
|
|
50
|
+
if (validation[maxIdx + 1] != null) {
|
|
51
|
+
const maxVal = Number(validation[maxIdx + 1]);
|
|
52
|
+
if (Number.isFinite(maxVal)) rules.max = maxVal;
|
|
53
|
+
else {
|
|
54
|
+
console.warn(
|
|
55
|
+
'[FormCheckbox] validation "max" rule skipped: value must be a number.',
|
|
56
|
+
'Received:',
|
|
57
|
+
validation[maxIdx + 1],
|
|
58
|
+
'— Expected e.g. ["max", 5].',
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
console.warn(
|
|
63
|
+
'[FormCheckbox] validation "max" rule skipped: no value after "max".',
|
|
64
|
+
'Expected e.g. ["max", 5], got:',
|
|
65
|
+
validation,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return rules;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** FormCheckbox wraps Checkbox with RHF; UI and styling come from Checkbox. */
|
|
73
|
+
export function FormCheckbox({ node }: FormCheckboxComponentProps) {
|
|
74
|
+
useLogRender('FormCheckbox');
|
|
75
|
+
node = useNode(node);
|
|
76
|
+
const ctx = useContext(formContext);
|
|
77
|
+
const attrs = node.attributes;
|
|
78
|
+
const name = attrs?.name as string | undefined;
|
|
79
|
+
const validation = attrs?.validation as string[] | undefined;
|
|
80
|
+
|
|
81
|
+
if (!ctx || !name) {
|
|
82
|
+
return <Checkbox node={node as Parameters<typeof Checkbox>[0]['node']} />;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const control = ctx.control as Control<FieldValues>;
|
|
86
|
+
const rules = validationArrayToRules(validation);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<Controller
|
|
90
|
+
name={name}
|
|
91
|
+
control={control}
|
|
92
|
+
rules={rules}
|
|
93
|
+
render={({
|
|
94
|
+
field,
|
|
95
|
+
}: {
|
|
96
|
+
field: ControllerRenderProps<FieldValues, string>;
|
|
97
|
+
}) => (
|
|
98
|
+
<Checkbox
|
|
99
|
+
node={node as Parameters<typeof Checkbox>[0]['node']}
|
|
100
|
+
checked={Boolean(field.value)}
|
|
101
|
+
onCheckedChange={(value) => field.onChange(value)}
|
|
102
|
+
/>
|
|
103
|
+
)}
|
|
104
|
+
/>
|
|
105
|
+
);
|
|
106
|
+
}
|