@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,101 @@
|
|
|
1
|
+
import { useRef, useCallback } from 'react';
|
|
2
|
+
import type { MockOSContextValue } from '../../mockOS/context/MockOSContextBase';
|
|
3
|
+
import type { PermissionStatus } from '../../mockOS/managers/mockPermissionManager';
|
|
4
|
+
|
|
5
|
+
/** Event shape shared by SystemButton and OnboardButton. Placement = go to placementKey (onboard/terms/paywall); Navigate = navigate_to or carousel. */
|
|
6
|
+
export interface PlacementEventObject {
|
|
7
|
+
type?: 'Permission' | 'Navigate' | 'Placement';
|
|
8
|
+
permission?: string | null;
|
|
9
|
+
placementKey?: string;
|
|
10
|
+
navigate_to?: string;
|
|
11
|
+
targetIndex?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface UsePlacementButtonEventsOptions {
|
|
15
|
+
context: MockOSContextValue | null;
|
|
16
|
+
requestPermission: (permission: string) => Promise<PermissionStatus>;
|
|
17
|
+
/** Called for Navigate events when placementKey is not set (e.g. carousel or navigate_to). Return true if handled. */
|
|
18
|
+
onNavigateWithoutPlacement?: (
|
|
19
|
+
e: PlacementEventObject,
|
|
20
|
+
) => Promise<boolean> | boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Optional global navigate function (from useGlobalNavigation).
|
|
23
|
+
* When provided, Navigate/Placement events try this first before falling back
|
|
24
|
+
* to MockOSContext. Return true if the navigation was handled.
|
|
25
|
+
*/
|
|
26
|
+
globalNavigate?: (target: string) => boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Shared hook for Permission + Navigate(placementKey / navigate_to) used by SystemButton and OnboardButton.
|
|
31
|
+
* OnboardButton can pass onNavigateWithoutPlacement to handle carousel (targetIndex) and navigate_to.
|
|
32
|
+
* Onboard events are pushed to handledEventsRef too: double-click is ignored; "back to terms then click again" still works because the terms screen remounts and the ref is fresh.
|
|
33
|
+
*/
|
|
34
|
+
export function usePlacementButtonEvents(
|
|
35
|
+
events: PlacementEventObject[] | undefined,
|
|
36
|
+
options: UsePlacementButtonEventsOptions,
|
|
37
|
+
): () => Promise<void> {
|
|
38
|
+
const {
|
|
39
|
+
context,
|
|
40
|
+
requestPermission,
|
|
41
|
+
onNavigateWithoutPlacement,
|
|
42
|
+
globalNavigate,
|
|
43
|
+
} = options;
|
|
44
|
+
const handledEventsRef = useRef<PlacementEventObject[]>([]);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Attempts to navigate to a target. Tries globalNavigate first (GlobalProvider),
|
|
48
|
+
* then falls back to MockOSContext.
|
|
49
|
+
*/
|
|
50
|
+
function navigateTo(target: string): void {
|
|
51
|
+
if (globalNavigate?.(target)) return;
|
|
52
|
+
context?.navigation(target as Parameters<typeof context.navigation>[0]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const handleClick = useCallback(async () => {
|
|
56
|
+
const list = events ?? [];
|
|
57
|
+
|
|
58
|
+
for (const e of list) {
|
|
59
|
+
if (handledEventsRef.current.includes(e)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (e.type === 'Permission') {
|
|
64
|
+
const permission = e.permission ?? 'camera';
|
|
65
|
+
await requestPermission(permission);
|
|
66
|
+
handledEventsRef.current.push(e);
|
|
67
|
+
} else if (e.type === 'Placement' && e.placementKey) {
|
|
68
|
+
const target =
|
|
69
|
+
e.placementKey === 'paywall' ? 'paywall' : e.placementKey;
|
|
70
|
+
navigateTo(target);
|
|
71
|
+
handledEventsRef.current.push(e);
|
|
72
|
+
} else if (e.type === 'Navigate') {
|
|
73
|
+
if (e.placementKey) {
|
|
74
|
+
const target =
|
|
75
|
+
e.placementKey === 'paywall' ? 'paywall' : e.placementKey;
|
|
76
|
+
navigateTo(target);
|
|
77
|
+
handledEventsRef.current.push(e);
|
|
78
|
+
} else {
|
|
79
|
+
const handled =
|
|
80
|
+
onNavigateWithoutPlacement != null &&
|
|
81
|
+
(await Promise.resolve(onNavigateWithoutPlacement(e)));
|
|
82
|
+
if (handled) {
|
|
83
|
+
handledEventsRef.current.push(e);
|
|
84
|
+
} else if (e.navigate_to && typeof e.navigate_to === 'string') {
|
|
85
|
+
navigateTo(e.navigate_to);
|
|
86
|
+
handledEventsRef.current.push(e);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
92
|
+
}, [
|
|
93
|
+
events,
|
|
94
|
+
context,
|
|
95
|
+
requestPermission,
|
|
96
|
+
onNavigateWithoutPlacement,
|
|
97
|
+
globalNavigate,
|
|
98
|
+
]);
|
|
99
|
+
|
|
100
|
+
return handleClick;
|
|
101
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, { useId } from 'react';
|
|
2
|
+
import type { TermsProviderComponentProps } from './TermsProviderProps.generated';
|
|
3
|
+
import RenderNode from '../RenderNode.generated';
|
|
4
|
+
import type { Node } from '../../types/Node';
|
|
5
|
+
import useNode from '../useNode';
|
|
6
|
+
import { useBuilderParams } from '../../components/BuilderProvider';
|
|
7
|
+
import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
|
|
8
|
+
import { useLogRender } from '../../utils/useLogRender';
|
|
9
|
+
import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
|
|
10
|
+
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
11
|
+
|
|
12
|
+
function TermsProvider({ node }: TermsProviderComponentProps) {
|
|
13
|
+
useLogRender('TermsProvider');
|
|
14
|
+
node = useNode(node);
|
|
15
|
+
|
|
16
|
+
const generatedId = useId();
|
|
17
|
+
const attributeName = node.sourceType ?? node.type ?? 'TermsProvider';
|
|
18
|
+
const attributeKey = node.key ?? generatedId;
|
|
19
|
+
|
|
20
|
+
const { previewMode, selectedKey } = useBuilderParams();
|
|
21
|
+
|
|
22
|
+
const baseStyle = useExtractViewStyle(node);
|
|
23
|
+
|
|
24
|
+
const isSelected = isNodeSelected({
|
|
25
|
+
previewMode: !!previewMode,
|
|
26
|
+
current: selectedKey ? { key: selectedKey } : undefined,
|
|
27
|
+
node,
|
|
28
|
+
});
|
|
29
|
+
const style = useMergedStyle(
|
|
30
|
+
baseStyle,
|
|
31
|
+
isSelected ? SELECTED_OUTLINE_STYLE : undefined,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
attribute-name={attributeName}
|
|
37
|
+
attribute-key={attributeKey}
|
|
38
|
+
style={style}
|
|
39
|
+
>
|
|
40
|
+
{node.children && <RenderNode node={node.children as Node} />}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default React.memo(TermsProvider);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* AUTO-GENERATED FILE - DO NOT EDIT */
|
|
2
|
+
|
|
3
|
+
import type { NodeData } from '../../types/Node';
|
|
4
|
+
|
|
5
|
+
export type AnimationOptionType =
|
|
6
|
+
| 'default'
|
|
7
|
+
| 'fade'
|
|
8
|
+
| 'fade_from_bottom'
|
|
9
|
+
| 'fade_from_right'
|
|
10
|
+
| 'reveal_from_bottom'
|
|
11
|
+
| 'scale_from_center'
|
|
12
|
+
| 'slide_from_right'
|
|
13
|
+
| 'slide_from_left'
|
|
14
|
+
| 'slide_from_bottom'
|
|
15
|
+
| 'none';
|
|
16
|
+
export type FlexDirectionOptionType = 'row' | 'column';
|
|
17
|
+
export type FlexWrapOptionType = 'nowrap' | 'wrap' | 'wrap-reverse';
|
|
18
|
+
export type AlignItemsOptionType =
|
|
19
|
+
| 'flex-start'
|
|
20
|
+
| 'center'
|
|
21
|
+
| 'flex-end'
|
|
22
|
+
| 'stretch'
|
|
23
|
+
| 'baseline';
|
|
24
|
+
export type JustifyContentOptionType =
|
|
25
|
+
| 'flex-start'
|
|
26
|
+
| 'center'
|
|
27
|
+
| 'flex-end'
|
|
28
|
+
| 'space-between'
|
|
29
|
+
| 'space-around'
|
|
30
|
+
| 'space-evenly';
|
|
31
|
+
export type PositionOptionType = 'relative' | 'absolute';
|
|
32
|
+
|
|
33
|
+
export interface TermsProviderStyleGenerated {
|
|
34
|
+
flexDirection?: FlexDirectionOptionType;
|
|
35
|
+
flexWrap?: FlexWrapOptionType;
|
|
36
|
+
alignItems?: AlignItemsOptionType;
|
|
37
|
+
justifyContent?: JustifyContentOptionType;
|
|
38
|
+
gap?: string;
|
|
39
|
+
padding?: string;
|
|
40
|
+
paddingHorizontal?: string;
|
|
41
|
+
paddingVertical?: string;
|
|
42
|
+
paddingTop?: string;
|
|
43
|
+
paddingBottom?: string;
|
|
44
|
+
paddingLeft?: string;
|
|
45
|
+
paddingRight?: string;
|
|
46
|
+
margin?: string;
|
|
47
|
+
marginHorizontal?: string;
|
|
48
|
+
marginVertical?: string;
|
|
49
|
+
marginTop?: string;
|
|
50
|
+
marginBottom?: string;
|
|
51
|
+
marginLeft?: string;
|
|
52
|
+
marginRight?: string;
|
|
53
|
+
backgroundColor?: string;
|
|
54
|
+
borderRadius?: string;
|
|
55
|
+
width?: string;
|
|
56
|
+
minWidth?: string;
|
|
57
|
+
maxWidth?: string;
|
|
58
|
+
height?: string;
|
|
59
|
+
minHeight?: string;
|
|
60
|
+
maxHeight?: string;
|
|
61
|
+
flex?: number;
|
|
62
|
+
position?: PositionOptionType;
|
|
63
|
+
top?: string;
|
|
64
|
+
bottom?: string;
|
|
65
|
+
left?: string;
|
|
66
|
+
right?: string;
|
|
67
|
+
zIndex?: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface TermsProviderPropsGenerated {
|
|
71
|
+
child: string;
|
|
72
|
+
attributes: {
|
|
73
|
+
styles?: TermsProviderStyleGenerated;
|
|
74
|
+
scrollable?: boolean;
|
|
75
|
+
testID?: string;
|
|
76
|
+
animation?: AnimationOptionType;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface TermsProviderComponentProps {
|
|
81
|
+
node: NodeData<TermsProviderPropsGenerated['attributes']>;
|
|
82
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"pattern": {
|
|
4
|
+
"type": "TermsProvider",
|
|
5
|
+
"title": "title",
|
|
6
|
+
"description": "description",
|
|
7
|
+
"children": "node",
|
|
8
|
+
"extends": "View",
|
|
9
|
+
"attributes": {
|
|
10
|
+
"animation": ["default", "fade", "fade_from_bottom", "fade_from_right", "reveal_from_bottom", "scale_from_center", "slide_from_right", "slide_from_left", "slide_from_bottom", "none"]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"defaults": {
|
|
14
|
+
"styles": {
|
|
15
|
+
"width": "100%",
|
|
16
|
+
"height": "100%",
|
|
17
|
+
"flex": 1
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"meta": {
|
|
21
|
+
"desiredParent": ["root", "GlobalProvider"],
|
|
22
|
+
"label": "Terms Provider",
|
|
23
|
+
"description": "Provider for terms & privacy page (e.g. WebView + form). Use as a GlobalProvider page.",
|
|
24
|
+
"attributes": {
|
|
25
|
+
"animation": {
|
|
26
|
+
"label": "Page transition animation",
|
|
27
|
+
"description": "When this component is a GlobalProvider page: animation used when navigating to this screen.",
|
|
28
|
+
"category": "other",
|
|
29
|
+
"specialCategory": null,
|
|
30
|
+
"sort": 1
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"styles": {}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
|
+
import { WebViewComponentProps } from './WebViewProps.generated';
|
|
3
|
+
import useNode from '../useNode';
|
|
4
|
+
import { useLogRender } from '../../utils/useLogRender';
|
|
5
|
+
import { useExtractViewStyle } from '../../attribute-analyser/style/web/useExtractViewStyle';
|
|
6
|
+
import { useBuilderParams } from '../../components/BuilderProvider';
|
|
7
|
+
import { parseColor } from '../../utils/parseColor';
|
|
8
|
+
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
9
|
+
|
|
10
|
+
export function WebView({ node }: WebViewComponentProps) {
|
|
11
|
+
useLogRender('WebView');
|
|
12
|
+
node = useNode(node);
|
|
13
|
+
const attrs = node.attributes;
|
|
14
|
+
const viewStyle = useExtractViewStyle(node as any);
|
|
15
|
+
const { selectedTheme: theme, projectColors, device } = useBuilderParams();
|
|
16
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
17
|
+
|
|
18
|
+
const [loading, setLoading] = useState(true);
|
|
19
|
+
|
|
20
|
+
const platform = device?.platform || 'ios';
|
|
21
|
+
const url = platform === 'ios' ? attrs?.iosUrl : attrs?.androidUrl;
|
|
22
|
+
|
|
23
|
+
const effectiveTheme = theme ?? 'dark';
|
|
24
|
+
const colorOpts = { projectColors, theme };
|
|
25
|
+
|
|
26
|
+
const backgroundColor =
|
|
27
|
+
parseColor('THEME_COLORS.BACKGROUND', colorOpts) ??
|
|
28
|
+
parseColor('STATIC_COLORS.WHITE', colorOpts) ??
|
|
29
|
+
undefined;
|
|
30
|
+
const textColor =
|
|
31
|
+
parseColor('THEME_COLORS.TEXT', colorOpts) ??
|
|
32
|
+
parseColor('STATIC_COLORS.BLACK', colorOpts) ??
|
|
33
|
+
undefined;
|
|
34
|
+
|
|
35
|
+
const loaderColor =
|
|
36
|
+
parseColor(attrs?.styles?.loaderColor as string, colorOpts) ?? textColor;
|
|
37
|
+
|
|
38
|
+
const loaderSize = attrs?.styles?.loaderSize ?? 30;
|
|
39
|
+
const loaderBorderWidth = attrs?.styles?.loaderBorderWidth ?? 3;
|
|
40
|
+
const loaderAnimationDuration = attrs?.styles?.loaderAnimationDuration ?? 1;
|
|
41
|
+
|
|
42
|
+
const themeStyle = useMergedStyle(
|
|
43
|
+
backgroundColor != null ? { backgroundColor } : undefined,
|
|
44
|
+
textColor != null ? { color: textColor } : undefined,
|
|
45
|
+
);
|
|
46
|
+
const containerStyle = useMergedStyle(viewStyle, themeStyle, {
|
|
47
|
+
['--rb-webview-loader-size' as string]: `${loaderSize}px`,
|
|
48
|
+
['--rb-webview-loader-border-width' as string]: `${loaderBorderWidth}px`,
|
|
49
|
+
['--rb-webview-loader-duration' as string]: `${loaderAnimationDuration}s`,
|
|
50
|
+
});
|
|
51
|
+
const overlayStyle = useMergedStyle(themeStyle);
|
|
52
|
+
const frameWrapperStyle = useMergedStyle(themeStyle, {
|
|
53
|
+
flex: 1,
|
|
54
|
+
minHeight: 0,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Same-origin iframe: inject/update theme styles. Idempotent: updates existing
|
|
58
|
+
// style[data-rb-webview-theme] so theme change does not require iframe reload.
|
|
59
|
+
const injectThemeStyles = useCallback(() => {
|
|
60
|
+
if (backgroundColor == null || textColor == null) return;
|
|
61
|
+
const doc = iframeRef.current?.contentDocument;
|
|
62
|
+
if (!doc?.head) {
|
|
63
|
+
if (url) {
|
|
64
|
+
console.debug(
|
|
65
|
+
'[WebView] Theme styles not injected: contentDocument not accessible (cross-origin).',
|
|
66
|
+
'URL:',
|
|
67
|
+
url,
|
|
68
|
+
'— Use same-origin URL or rely on the wrapper filter for dark mode.',
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const existing = doc.querySelector('style[data-rb-webview-theme]');
|
|
74
|
+
const css = [
|
|
75
|
+
`body{background-color:${backgroundColor};color:${textColor}}`,
|
|
76
|
+
`*{color:${textColor}}`,
|
|
77
|
+
`span{background-color:${backgroundColor}}`,
|
|
78
|
+
].join(' ');
|
|
79
|
+
if (existing) {
|
|
80
|
+
existing.textContent = css;
|
|
81
|
+
} else {
|
|
82
|
+
const style = doc.createElement('style');
|
|
83
|
+
style.setAttribute('data-rb-webview-theme', '');
|
|
84
|
+
style.textContent = css;
|
|
85
|
+
doc.head.appendChild(style);
|
|
86
|
+
}
|
|
87
|
+
}, [backgroundColor, textColor, url]);
|
|
88
|
+
|
|
89
|
+
const handleIframeLoad = useCallback(() => {
|
|
90
|
+
setLoading(false);
|
|
91
|
+
injectThemeStyles();
|
|
92
|
+
}, [injectThemeStyles]);
|
|
93
|
+
|
|
94
|
+
// Tema değişince iframe yeniden yüklemeden stil güncelle (same-origin). Cross-origin
|
|
95
|
+
// için sadece wrapper filter kullanılıyor, re-render yeterli.
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (loading) return;
|
|
98
|
+
injectThemeStyles();
|
|
99
|
+
}, [theme, backgroundColor, textColor, loading, injectThemeStyles]);
|
|
100
|
+
|
|
101
|
+
// Cross-origin iframe'lere stil enjekte edilemez. Dark modda içeriği görsel olarak
|
|
102
|
+
// koyu göstermek için sadece iframe saran div'e CSS filter uyguluyoruz.
|
|
103
|
+
// Tema değişiminde iframe yeniden render edilmez (kullanıcı konumu/inputlar korunur).
|
|
104
|
+
const useForceDarkFilter = effectiveTheme === 'dark';
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div
|
|
108
|
+
className="rb-webview"
|
|
109
|
+
style={containerStyle}
|
|
110
|
+
data-testid={attrs?.testID}
|
|
111
|
+
>
|
|
112
|
+
{loading && (
|
|
113
|
+
<div className="rb-webview__overlay" style={overlayStyle}>
|
|
114
|
+
<div
|
|
115
|
+
className="rb-webview__loader"
|
|
116
|
+
style={{
|
|
117
|
+
borderColor: loaderColor != null ? `${loaderColor}40` : undefined,
|
|
118
|
+
borderTopColor: loaderColor ?? undefined,
|
|
119
|
+
}}
|
|
120
|
+
/>
|
|
121
|
+
</div>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
<div className="rb-webview__frame-wrapper" style={frameWrapperStyle}>
|
|
125
|
+
<div
|
|
126
|
+
className="rb-webview__frame-inner"
|
|
127
|
+
style={
|
|
128
|
+
useForceDarkFilter
|
|
129
|
+
? {
|
|
130
|
+
width: '100%',
|
|
131
|
+
height: '100%',
|
|
132
|
+
filter: 'invert(1) hue-rotate(180deg)',
|
|
133
|
+
}
|
|
134
|
+
: { width: '100%', height: '100%' }
|
|
135
|
+
}
|
|
136
|
+
>
|
|
137
|
+
<iframe
|
|
138
|
+
ref={iframeRef}
|
|
139
|
+
src={url}
|
|
140
|
+
className="rb-webview__frame"
|
|
141
|
+
style={{ opacity: loading ? 0 : 1, backgroundColor: 'transparent' }}
|
|
142
|
+
onLoad={handleIframeLoad}
|
|
143
|
+
title="WebView Content"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
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 WebViewStyleGenerated {
|
|
23
|
+
flexDirection?: FlexDirectionOptionType;
|
|
24
|
+
flexWrap?: FlexWrapOptionType;
|
|
25
|
+
alignItems?: AlignItemsOptionType;
|
|
26
|
+
justifyContent?: JustifyContentOptionType;
|
|
27
|
+
gap?: string;
|
|
28
|
+
padding?: string;
|
|
29
|
+
paddingHorizontal?: string;
|
|
30
|
+
paddingVertical?: string;
|
|
31
|
+
paddingTop?: string;
|
|
32
|
+
paddingBottom?: string;
|
|
33
|
+
paddingLeft?: string;
|
|
34
|
+
paddingRight?: string;
|
|
35
|
+
margin?: string;
|
|
36
|
+
marginHorizontal?: string;
|
|
37
|
+
marginVertical?: string;
|
|
38
|
+
marginTop?: string;
|
|
39
|
+
marginBottom?: string;
|
|
40
|
+
marginLeft?: string;
|
|
41
|
+
marginRight?: string;
|
|
42
|
+
backgroundColor?: string;
|
|
43
|
+
borderRadius?: string;
|
|
44
|
+
width?: string;
|
|
45
|
+
minWidth?: string;
|
|
46
|
+
maxWidth?: string;
|
|
47
|
+
height?: string;
|
|
48
|
+
minHeight?: string;
|
|
49
|
+
maxHeight?: string;
|
|
50
|
+
flex?: number;
|
|
51
|
+
position?: PositionOptionType;
|
|
52
|
+
top?: string;
|
|
53
|
+
bottom?: string;
|
|
54
|
+
left?: string;
|
|
55
|
+
right?: string;
|
|
56
|
+
zIndex?: number;
|
|
57
|
+
loaderColor?: string;
|
|
58
|
+
loaderSize?: number;
|
|
59
|
+
loaderBorderWidth?: number;
|
|
60
|
+
loaderAnimationDuration?: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface WebViewPropsGenerated {
|
|
64
|
+
child: string;
|
|
65
|
+
attributes: {
|
|
66
|
+
styles?: WebViewStyleGenerated;
|
|
67
|
+
scrollable?: boolean;
|
|
68
|
+
testID?: string;
|
|
69
|
+
iosUrl?: string;
|
|
70
|
+
androidUrl?: string;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface WebViewComponentProps {
|
|
75
|
+
node: NodeData<WebViewPropsGenerated['attributes']>;
|
|
76
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"pattern": {
|
|
4
|
+
"type": "WebView",
|
|
5
|
+
"title": "WebView",
|
|
6
|
+
"description": "A component to display web content.",
|
|
7
|
+
"children": "never",
|
|
8
|
+
"extends": "View",
|
|
9
|
+
"attributes": {
|
|
10
|
+
"iosUrl": "string",
|
|
11
|
+
"androidUrl": "string",
|
|
12
|
+
"styles": {
|
|
13
|
+
"loaderColor": "color",
|
|
14
|
+
"loaderSize": "number",
|
|
15
|
+
"loaderBorderWidth": "number",
|
|
16
|
+
"loaderAnimationDuration": "number"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"defaults": {
|
|
21
|
+
"styles": {
|
|
22
|
+
"loaderSize": 30,
|
|
23
|
+
"loaderBorderWidth": 3,
|
|
24
|
+
"loaderAnimationDuration": 1
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"meta": {
|
|
28
|
+
"label": "Web View",
|
|
29
|
+
"description": "Embeds web content using an iframe on web and WebView on mobile.",
|
|
30
|
+
"attributes": {
|
|
31
|
+
"iosUrl": {
|
|
32
|
+
"label": "iOS URL",
|
|
33
|
+
"description": "The iOS URL to load in the web view.",
|
|
34
|
+
"category": "other",
|
|
35
|
+
"sort": 1
|
|
36
|
+
},
|
|
37
|
+
"androidUrl": {
|
|
38
|
+
"label": "Android URL",
|
|
39
|
+
"description": "The Android URL to load in the web view.",
|
|
40
|
+
"category": "other",
|
|
41
|
+
"sort": 2
|
|
42
|
+
},
|
|
43
|
+
"styles": {
|
|
44
|
+
"loaderColor": {
|
|
45
|
+
"label": "Loader color",
|
|
46
|
+
"description": "Loading spinner color. Defaults to THEME_COLORS.TEXT.",
|
|
47
|
+
"category": "style",
|
|
48
|
+
"sort": 1
|
|
49
|
+
},
|
|
50
|
+
"loaderSize": {
|
|
51
|
+
"label": "Loader size",
|
|
52
|
+
"description": "Size of the loading spinner (px). Shared by web and native.",
|
|
53
|
+
"category": "style",
|
|
54
|
+
"sort": 2
|
|
55
|
+
},
|
|
56
|
+
"loaderBorderWidth": {
|
|
57
|
+
"label": "Loader border width",
|
|
58
|
+
"description": "Border width of the loading spinner (px). Shared by web and native.",
|
|
59
|
+
"category": "style",
|
|
60
|
+
"sort": 3
|
|
61
|
+
},
|
|
62
|
+
"loaderAnimationDuration": {
|
|
63
|
+
"label": "Loader animation duration",
|
|
64
|
+
"description": "Duration of one full spin (seconds). Shared by web and native.",
|
|
65
|
+
"category": "style",
|
|
66
|
+
"sort": 4
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -13,7 +13,13 @@ export const allcomponentNames = [
|
|
|
13
13
|
'CarouselDots',
|
|
14
14
|
'CarouselItem',
|
|
15
15
|
'CarouselProvider',
|
|
16
|
+
'Checkbox',
|
|
16
17
|
'CountDown',
|
|
18
|
+
'FormCheckbox',
|
|
19
|
+
'FormErrorText',
|
|
20
|
+
'FormProvider',
|
|
21
|
+
'FormSubmitButton',
|
|
22
|
+
'GlobalProvider',
|
|
17
23
|
'Image',
|
|
18
24
|
'Main',
|
|
19
25
|
'NavigationBarColor',
|
|
@@ -39,8 +45,11 @@ export const allcomponentNames = [
|
|
|
39
45
|
'RadioButton',
|
|
40
46
|
'Separator',
|
|
41
47
|
'StatusBarColor',
|
|
48
|
+
'SystemButton',
|
|
49
|
+
'TermsProvider',
|
|
42
50
|
'Text',
|
|
43
51
|
'View',
|
|
52
|
+
'WebView',
|
|
44
53
|
] as const;
|
|
45
54
|
|
|
46
55
|
export type {
|
|
@@ -75,10 +84,34 @@ export type {
|
|
|
75
84
|
CarouselProviderPropsGenerated,
|
|
76
85
|
CarouselProviderComponentProps,
|
|
77
86
|
} from './CarouselProvider/CarouselProviderProps.generated';
|
|
87
|
+
export type {
|
|
88
|
+
CheckboxPropsGenerated,
|
|
89
|
+
CheckboxComponentProps,
|
|
90
|
+
} from './Checkbox/CheckboxProps.generated';
|
|
78
91
|
export type {
|
|
79
92
|
CountDownPropsGenerated,
|
|
80
93
|
CountDownComponentProps,
|
|
81
94
|
} from './CountDown/CountDownProps.generated';
|
|
95
|
+
export type {
|
|
96
|
+
FormCheckboxPropsGenerated,
|
|
97
|
+
FormCheckboxComponentProps,
|
|
98
|
+
} from './FormCheckbox/FormCheckboxProps.generated';
|
|
99
|
+
export type {
|
|
100
|
+
FormErrorTextPropsGenerated,
|
|
101
|
+
FormErrorTextComponentProps,
|
|
102
|
+
} from './FormErrorText/FormErrorTextProps.generated';
|
|
103
|
+
export type {
|
|
104
|
+
FormProviderPropsGenerated,
|
|
105
|
+
FormProviderComponentProps,
|
|
106
|
+
} from './FormProvider/FormProviderProps.generated';
|
|
107
|
+
export type {
|
|
108
|
+
FormSubmitButtonPropsGenerated,
|
|
109
|
+
FormSubmitButtonComponentProps,
|
|
110
|
+
} from './FormSubmitButton/FormSubmitButtonProps.generated';
|
|
111
|
+
export type {
|
|
112
|
+
GlobalProviderPropsGenerated,
|
|
113
|
+
GlobalProviderComponentProps,
|
|
114
|
+
} from './GlobalProvider/GlobalProviderProps.generated';
|
|
82
115
|
export type {
|
|
83
116
|
ImagePropsGenerated,
|
|
84
117
|
ImageComponentProps,
|
|
@@ -179,6 +212,14 @@ export type {
|
|
|
179
212
|
StatusBarColorPropsGenerated,
|
|
180
213
|
StatusBarColorComponentProps,
|
|
181
214
|
} from './StatusBarColor/StatusBarColorProps.generated';
|
|
215
|
+
export type {
|
|
216
|
+
SystemButtonPropsGenerated,
|
|
217
|
+
SystemButtonComponentProps,
|
|
218
|
+
} from './SystemButton/SystemButtonProps.generated';
|
|
219
|
+
export type {
|
|
220
|
+
TermsProviderPropsGenerated,
|
|
221
|
+
TermsProviderComponentProps,
|
|
222
|
+
} from './TermsProvider/TermsProviderProps.generated';
|
|
182
223
|
export type {
|
|
183
224
|
TextPropsGenerated,
|
|
184
225
|
TextComponentProps,
|
|
@@ -187,3 +228,7 @@ export type {
|
|
|
187
228
|
ViewPropsGenerated,
|
|
188
229
|
ViewComponentProps,
|
|
189
230
|
} from './View/ViewProps.generated';
|
|
231
|
+
export type {
|
|
232
|
+
WebViewPropsGenerated,
|
|
233
|
+
WebViewComponentProps,
|
|
234
|
+
} from './WebView/WebViewProps.generated';
|