@pushwoosh/dumb-components 1.1.232 → 1.1.234
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/NativeRichMediaPreview/NativeRichMediaPreview.d.ts +3 -0
- package/NativeRichMediaPreview/NativeRichMediaPreview.js +50 -8
- package/NativeRichMediaPreview/__tests__/NativeRichMediaPreview.test.d.ts +1 -0
- package/NativeRichMediaPreview/__tests__/NativeRichMediaPreview.test.js +81 -0
- package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/NativeRichMediaThemeChip.d.ts +3 -0
- package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/NativeRichMediaThemeChip.js +25 -0
- package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/index.d.ts +1 -0
- package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/index.js +1 -0
- package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/styles.d.ts +8 -0
- package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/styles.js +7 -0
- package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/types.d.ts +8 -0
- package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/types.js +1 -0
- package/NativeRichMediaPreview/icons/MoonIcon.svg +3 -0
- package/NativeRichMediaPreview/icons/SunIcon.svg +4 -0
- package/NativeRichMediaPreview/icons/index.d.ts +2 -0
- package/NativeRichMediaPreview/icons/index.js +3 -1
- package/NativeRichMediaPreview/index.d.ts +2 -1
- package/NativeRichMediaPreview/index.js +2 -1
- package/NativeRichMediaPreview/mergeNativeDarkOverlay.d.ts +3 -0
- package/NativeRichMediaPreview/mergeNativeDarkOverlay.js +89 -0
- package/NativeRichMediaPreview/polyglot/messages_ar.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_bn.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_de.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_en.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_es.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_fr.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_he.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_hi.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_ja.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_ko.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_pt.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_ru.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_th.js +2 -1
- package/NativeRichMediaPreview/polyglot/messages_zh.js +2 -1
- package/NativeRichMediaPreview/polyglot/types.d.ts +1 -0
- package/NativeRichMediaPreview/types.d.ts +32 -0
- package/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -13,6 +13,9 @@ import type { NativeRichMediaPreviewProps } from './types';
|
|
|
13
13
|
* the box — the way to cram a phone-sized layout into a small preview box
|
|
14
14
|
* while keeping its proportions. Shows an invalid-config placeholder when the
|
|
15
15
|
* config cannot be parsed or misses required contract fields.
|
|
16
|
+
* With `withThemeToggle` the preview carries a chip that flips it between the light
|
|
17
|
+
* values and the dark overlay merged over them; pass `theme` with `onThemeChange`
|
|
18
|
+
* to drive that from outside, when a surrounding editor has its own theme switch.
|
|
16
19
|
*
|
|
17
20
|
* @example
|
|
18
21
|
* <NativeRichMediaPreview
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo } from 'react';
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
3
|
import { Color } from '@pushwoosh/kit-constants';
|
|
4
4
|
import { Spinner } from '../Spinner';
|
|
5
5
|
import { NativeRichMediaCloseChip } from './components/NativeRichMediaCloseChip';
|
|
6
6
|
import { NativeRichMediaCoverImg } from './components/NativeRichMediaCoverImg';
|
|
7
7
|
import { NativeRichMediaDim } from './components/NativeRichMediaDim';
|
|
8
8
|
import { NativeRichMediaMuteChip } from './components/NativeRichMediaMuteChip';
|
|
9
|
+
import { NativeRichMediaThemeChip } from './components/NativeRichMediaThemeChip';
|
|
9
10
|
import { EDGE_INSET, clampIndex } from './helpers';
|
|
11
|
+
import { mergeNativeDarkOverlay } from './mergeNativeDarkOverlay';
|
|
10
12
|
import { parseNativeRichMediaConfig } from './parseNativeRichMediaConfig';
|
|
11
13
|
import { resolveLocalization } from './resolveLocalization';
|
|
12
14
|
import { BackdropLayer, ContentFlow, PreviewHost, ScaleViewport, ScrollLayer, SpinnerLayer } from './styles';
|
|
@@ -150,6 +152,17 @@ function renderConfig(config, activeIndex) {
|
|
|
150
152
|
return _jsx(NativeRichMediaInvalidView, {});
|
|
151
153
|
}
|
|
152
154
|
}
|
|
155
|
+
function parseDarkVariant(content, withThemeToggle) {
|
|
156
|
+
if (!withThemeToggle) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const merged = mergeNativeDarkOverlay(content);
|
|
160
|
+
// The merge hands back `content` itself, untouched, whenever there is nothing to apply.
|
|
161
|
+
if (merged === content) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return parseNativeRichMediaConfig(merged);
|
|
165
|
+
}
|
|
153
166
|
/**
|
|
154
167
|
* Preview of a native rich media (modal, banner, stories, spinwheel, …)
|
|
155
168
|
* rendered from its JSON config; lays out with plain CSS in the real pixels
|
|
@@ -163,6 +176,9 @@ function renderConfig(config, activeIndex) {
|
|
|
163
176
|
* the box — the way to cram a phone-sized layout into a small preview box
|
|
164
177
|
* while keeping its proportions. Shows an invalid-config placeholder when the
|
|
165
178
|
* config cannot be parsed or misses required contract fields.
|
|
179
|
+
* With `withThemeToggle` the preview carries a chip that flips it between the light
|
|
180
|
+
* values and the dark overlay merged over them; pass `theme` with `onThemeChange`
|
|
181
|
+
* to drive that from outside, when a surrounding editor has its own theme switch.
|
|
166
182
|
*
|
|
167
183
|
* @example
|
|
168
184
|
* <NativeRichMediaPreview
|
|
@@ -190,15 +206,37 @@ export function NativeRichMediaPreview(props) {
|
|
|
190
206
|
scale = 1,
|
|
191
207
|
activeIndex = 0,
|
|
192
208
|
isLoading = false,
|
|
193
|
-
withBackground = true
|
|
209
|
+
withBackground = true,
|
|
210
|
+
withThemeToggle = false,
|
|
211
|
+
theme: controlledTheme,
|
|
212
|
+
onThemeChange
|
|
194
213
|
} = props;
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
214
|
+
const [ownTheme, setOwnTheme] = useState('light');
|
|
215
|
+
const isControlled = controlledTheme !== undefined;
|
|
216
|
+
const theme = controlledTheme ?? ownTheme;
|
|
217
|
+
const toggleTheme = () => {
|
|
218
|
+
const next = theme === 'dark' ? 'light' : 'dark';
|
|
219
|
+
if (!isControlled) {
|
|
220
|
+
setOwnTheme(next);
|
|
199
221
|
}
|
|
200
|
-
|
|
201
|
-
}
|
|
222
|
+
onThemeChange?.(next);
|
|
223
|
+
};
|
|
224
|
+
const {
|
|
225
|
+
config,
|
|
226
|
+
isDarkRendered,
|
|
227
|
+
canToggleDark
|
|
228
|
+
} = useMemo(() => {
|
|
229
|
+
const lightParsed = parseNativeRichMediaConfig(content);
|
|
230
|
+
const darkParsed = parseDarkVariant(content, withThemeToggle);
|
|
231
|
+
const themed = theme === 'dark' && darkParsed ? darkParsed : lightParsed;
|
|
232
|
+
const resolved = themed ? parseNativeRichMediaConfig(resolveLocalization(themed, localization, language)) : null;
|
|
233
|
+
return {
|
|
234
|
+
config: resolved,
|
|
235
|
+
isDarkRendered: Boolean(resolved) && theme === 'dark' && darkParsed !== null,
|
|
236
|
+
canToggleDark: darkParsed !== null
|
|
237
|
+
};
|
|
238
|
+
}, [content, localization, language, theme, withThemeToggle]);
|
|
239
|
+
const renderedTheme = isDarkRendered ? 'dark' : 'light';
|
|
202
240
|
const shouldDim = !isLoading && dimsScreen(config);
|
|
203
241
|
return _jsxs(PreviewHost, {
|
|
204
242
|
...LIGHT_ISLAND_PROPS,
|
|
@@ -215,6 +253,10 @@ export function NativeRichMediaPreview(props) {
|
|
|
215
253
|
children: renderConfig(config, activeIndex)
|
|
216
254
|
})
|
|
217
255
|
}, config.displayType), !isLoading && config && renderChrome(config)]
|
|
256
|
+
}), !isLoading && config && withThemeToggle && _jsx(NativeRichMediaThemeChip, {
|
|
257
|
+
theme: isControlled ? theme : renderedTheme,
|
|
258
|
+
disabled: !isControlled && !canToggleDark,
|
|
259
|
+
onToggle: toggleTheme
|
|
218
260
|
}), isLoading && _jsx(SpinnerLayer, {
|
|
219
261
|
children: _jsx(Spinner, {
|
|
220
262
|
size: "medium",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
+
import { NativeRichMediaPreview } from '../NativeRichMediaPreview';
|
|
4
|
+
const lightContent = {
|
|
5
|
+
displayType: 'modal',
|
|
6
|
+
modal: {
|
|
7
|
+
showClose: true,
|
|
8
|
+
dimBackground: true,
|
|
9
|
+
background: '#FFFFFFFF',
|
|
10
|
+
title: {
|
|
11
|
+
text: 'Hi',
|
|
12
|
+
color: '#4B5057FF'
|
|
13
|
+
},
|
|
14
|
+
buttons: []
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const darkableContent = {
|
|
18
|
+
...lightContent,
|
|
19
|
+
modal: {
|
|
20
|
+
...lightContent.modal,
|
|
21
|
+
dark: {
|
|
22
|
+
background: '#14161AFF',
|
|
23
|
+
title: {
|
|
24
|
+
color: '#F2F4F7FF'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const themeChip = () => screen.getByLabelText('Switch light and dark');
|
|
30
|
+
const renderPreview = (props = {}) => render(_jsx(NativeRichMediaPreview, {
|
|
31
|
+
content: darkableContent,
|
|
32
|
+
width: 304,
|
|
33
|
+
height: 659,
|
|
34
|
+
withThemeToggle: true,
|
|
35
|
+
...props
|
|
36
|
+
}));
|
|
37
|
+
describe('NativeRichMediaPreview theme toggle', () => {
|
|
38
|
+
it('keeps its own theme when uncontrolled', () => {
|
|
39
|
+
renderPreview();
|
|
40
|
+
expect(themeChip()).toHaveAttribute('aria-pressed', 'false');
|
|
41
|
+
fireEvent.click(themeChip());
|
|
42
|
+
expect(themeChip()).toHaveAttribute('aria-pressed', 'true');
|
|
43
|
+
});
|
|
44
|
+
it('follows the theme prop instead of a click when controlled', () => {
|
|
45
|
+
const onThemeChange = jest.fn();
|
|
46
|
+
const {
|
|
47
|
+
rerender
|
|
48
|
+
} = renderPreview({
|
|
49
|
+
theme: 'dark',
|
|
50
|
+
onThemeChange
|
|
51
|
+
});
|
|
52
|
+
expect(themeChip()).toHaveAttribute('aria-pressed', 'true');
|
|
53
|
+
fireEvent.click(themeChip());
|
|
54
|
+
expect(onThemeChange).toHaveBeenCalledWith('light');
|
|
55
|
+
expect(themeChip()).toHaveAttribute('aria-pressed', 'true');
|
|
56
|
+
rerender(_jsx(NativeRichMediaPreview, {
|
|
57
|
+
content: darkableContent,
|
|
58
|
+
width: 304,
|
|
59
|
+
height: 659,
|
|
60
|
+
withThemeToggle: true,
|
|
61
|
+
theme: "light",
|
|
62
|
+
onThemeChange: onThemeChange
|
|
63
|
+
}));
|
|
64
|
+
expect(themeChip()).toHaveAttribute('aria-pressed', 'false');
|
|
65
|
+
});
|
|
66
|
+
it('reports the controlled theme even when the content has no dark overlay', () => {
|
|
67
|
+
renderPreview({
|
|
68
|
+
content: lightContent,
|
|
69
|
+
theme: 'dark',
|
|
70
|
+
onThemeChange: jest.fn()
|
|
71
|
+
});
|
|
72
|
+
expect(themeChip()).toHaveAttribute('aria-pressed', 'true');
|
|
73
|
+
expect(themeChip()).not.toBeDisabled();
|
|
74
|
+
});
|
|
75
|
+
it('disables the chip on content without a dark overlay when uncontrolled', () => {
|
|
76
|
+
renderPreview({
|
|
77
|
+
content: lightContent
|
|
78
|
+
});
|
|
79
|
+
expect(themeChip()).toBeDisabled();
|
|
80
|
+
});
|
|
81
|
+
});
|
package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/NativeRichMediaThemeChip.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ThemeToggleChip } from './styles';
|
|
3
|
+
import { MoonIcon, SunIcon } from '../../icons';
|
|
4
|
+
import { useLang } from '../../polyglot';
|
|
5
|
+
export function NativeRichMediaThemeChip(props) {
|
|
6
|
+
const {
|
|
7
|
+
theme,
|
|
8
|
+
disabled,
|
|
9
|
+
onToggle
|
|
10
|
+
} = props;
|
|
11
|
+
const lang = useLang();
|
|
12
|
+
return _jsx(ThemeToggleChip, {
|
|
13
|
+
as: "button",
|
|
14
|
+
type: "button",
|
|
15
|
+
"$bottom": 8,
|
|
16
|
+
"$right": 8,
|
|
17
|
+
disabled: disabled,
|
|
18
|
+
"aria-label": lang({
|
|
19
|
+
message: 'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME'
|
|
20
|
+
}),
|
|
21
|
+
"aria-pressed": theme === 'dark',
|
|
22
|
+
onClick: onToggle,
|
|
23
|
+
children: theme === 'dark' ? _jsx(MoonIcon, {}) : _jsx(SunIcon, {})
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NativeRichMediaThemeChip } from './NativeRichMediaThemeChip';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NativeRichMediaThemeChip } from './NativeRichMediaThemeChip';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** `Chip` is a `div`; rendered `as="button"` it needs the UA button chrome stripped or it fights `border-radius: 50%`. */
|
|
2
|
+
export declare const ThemeToggleChip: import("styled-components").StyledComponent<"div", any, {
|
|
3
|
+
$small?: boolean;
|
|
4
|
+
$top?: number;
|
|
5
|
+
$right?: number;
|
|
6
|
+
$bottom?: number;
|
|
7
|
+
$left?: number;
|
|
8
|
+
}, never>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import { Chip } from '../NativeRichMediaCloseChip';
|
|
3
|
+
/** `Chip` is a `div`; rendered `as="button"` it needs the UA button chrome stripped or it fights `border-radius: 50%`. */
|
|
4
|
+
export const ThemeToggleChip = styled(Chip).withConfig({
|
|
5
|
+
displayName: "ThemeToggleChip",
|
|
6
|
+
componentId: "sc-e7nbqw-0"
|
|
7
|
+
})(["border:none;padding:0;appearance:none;font:inherit;&:disabled{cursor:default;opacity:0.4;}"]);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type NativeRichMediaThemeChipProps = {
|
|
2
|
+
/** Theme actually rendered right now — may lag a click while an overlay applies, or fall back to light. */
|
|
3
|
+
theme: 'light' | 'dark';
|
|
4
|
+
/** Disable when the current content has no dark overlay to switch to. */
|
|
5
|
+
disabled: boolean;
|
|
6
|
+
/** Flip to the other theme. */
|
|
7
|
+
onToggle: () => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none">
|
|
2
|
+
<circle cx="12" cy="12" r="4.5" fill="#fff"/>
|
|
3
|
+
<path d="M12 2v2.5M12 19.5V22M4.22 4.22l1.77 1.77M18.01 18.01l1.77 1.77M2 12h2.5M19.5 12H22M4.22 19.78l1.77-1.77M18.01 5.99l1.77-1.77" stroke="#fff" stroke-width="2" stroke-linecap="round"/>
|
|
4
|
+
</svg>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { default as CopyIcon } from './CopyIcon.svg';
|
|
2
2
|
export { default as ExpandIcon } from './ExpandIcon.svg';
|
|
3
|
+
export { default as MoonIcon } from './MoonIcon.svg';
|
|
3
4
|
export { default as MutedIcon } from './MutedIcon.svg';
|
|
4
5
|
export { default as ScribbleIcon } from './ScribbleIcon.svg';
|
|
5
6
|
export { default as SoundIcon } from './SoundIcon.svg';
|
|
7
|
+
export { default as SunIcon } from './SunIcon.svg';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { default as CopyIcon } from './CopyIcon.svg';
|
|
2
2
|
export { default as ExpandIcon } from './ExpandIcon.svg';
|
|
3
|
+
export { default as MoonIcon } from './MoonIcon.svg';
|
|
3
4
|
export { default as MutedIcon } from './MutedIcon.svg';
|
|
4
5
|
export { default as ScribbleIcon } from './ScribbleIcon.svg';
|
|
5
|
-
export { default as SoundIcon } from './SoundIcon.svg';
|
|
6
|
+
export { default as SoundIcon } from './SoundIcon.svg';
|
|
7
|
+
export { default as SunIcon } from './SunIcon.svg';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export type { NativeRichMediaConfig, NativeRichMediaDisplayType, NativeRichMediaText, NativeRichMediaBorder, NativeRichMediaCover, NativeRichMediaAction, NativeRichMediaButton, NativeRichMediaReward, NativeRichMediaModalBlock, NativeRichMediaSheetBlock, NativeRichMediaCarouselBlock, NativeRichMediaStoriesBlock, NativeRichMediaBannerBlock, NativeRichMediaFullscreenBlock, NativeRichMediaVideoBlock, NativeRichMediaPipBlock, NativeRichMediaScratchcardBlock, NativeRichMediaSpinwheelBlock, NativeRichMediaPreviewProps, NativeRichMediaLocalization, } from './types';
|
|
1
|
+
export type { NativeRichMediaConfig, NativeRichMediaDisplayType, NativeRichMediaDarkOverlay, NativeRichMediaText, NativeRichMediaBorder, NativeRichMediaCover, NativeRichMediaAction, NativeRichMediaButton, NativeRichMediaReward, NativeRichMediaModalBlock, NativeRichMediaSheetBlock, NativeRichMediaCarouselBlock, NativeRichMediaStoriesBlock, NativeRichMediaBannerBlock, NativeRichMediaFullscreenBlock, NativeRichMediaVideoBlock, NativeRichMediaPipBlock, NativeRichMediaScratchcardBlock, NativeRichMediaSpinwheelBlock, NativeRichMediaPreviewProps, NativeRichMediaLocalization, NativeRichMediaTheme, } from './types';
|
|
2
2
|
export { NATIVE_RICH_MEDIA_DISPLAY_TYPES, EDITABLE_NATIVE_RICH_MEDIA_DISPLAY_TYPES } from './types';
|
|
3
3
|
export { parseNativeRichMediaConfig } from './parseNativeRichMediaConfig';
|
|
4
4
|
export { parseLocalizationParams } from './parseLocalizationParams';
|
|
5
5
|
export { NativeRichMediaPreview } from './NativeRichMediaPreview';
|
|
6
|
+
export { mergeNativeDarkOverlay } from './mergeNativeDarkOverlay';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { NATIVE_RICH_MEDIA_DISPLAY_TYPES, EDITABLE_NATIVE_RICH_MEDIA_DISPLAY_TYPES } from './types';
|
|
2
2
|
export { parseNativeRichMediaConfig } from './parseNativeRichMediaConfig';
|
|
3
3
|
export { parseLocalizationParams } from './parseLocalizationParams';
|
|
4
|
-
export { NativeRichMediaPreview } from './NativeRichMediaPreview';
|
|
4
|
+
export { NativeRichMediaPreview } from './NativeRichMediaPreview';
|
|
5
|
+
export { mergeNativeDarkOverlay } from './mergeNativeDarkOverlay';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { NativeRichMediaConfig } from './types';
|
|
2
|
+
/** Applies a config's `dark` overlay onto its display block ahead of strict parsing, since the light block may only become valid once the overlay lands; any break returns the input untouched. */
|
|
3
|
+
export declare function mergeNativeDarkOverlay(content: string | NativeRichMediaConfig): string | NativeRichMediaConfig;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { isObject } from './helpers';
|
|
2
|
+
/** Leaves a theme may replace: everything else is content, not appearance. */
|
|
3
|
+
const VISUAL_LEAF_KEYS = new Set(['background', 'color', 'image', 'poster', 'fallback']);
|
|
4
|
+
/** The only arrays that merge; both sides must line up element for element. */
|
|
5
|
+
const POSITIONAL_ARRAY_KEYS = new Set(['buttons', 'items']);
|
|
6
|
+
function overlayOnto(light, dark) {
|
|
7
|
+
const merged = {
|
|
8
|
+
...light
|
|
9
|
+
};
|
|
10
|
+
for (const key of Object.keys(dark)) {
|
|
11
|
+
const darkValue = dark[key];
|
|
12
|
+
const lightValue = light[key];
|
|
13
|
+
if (darkValue === null || darkValue === undefined) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (POSITIONAL_ARRAY_KEYS.has(key)) {
|
|
17
|
+
if (!Array.isArray(darkValue) || !Array.isArray(lightValue)) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (darkValue.length !== lightValue.length) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const items = [];
|
|
24
|
+
for (let i = 0; i < darkValue.length; i += 1) {
|
|
25
|
+
const darkItem = darkValue[i];
|
|
26
|
+
const lightItem = lightValue[i];
|
|
27
|
+
if (!isObject(darkItem) || !isObject(lightItem)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const mergedItem = overlayOnto(lightItem, darkItem);
|
|
31
|
+
if (!mergedItem) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
items.push(mergedItem);
|
|
35
|
+
}
|
|
36
|
+
merged[key] = items;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (isObject(lightValue)) {
|
|
40
|
+
if (isObject(darkValue)) {
|
|
41
|
+
const mergedChild = overlayOnto(lightValue, darkValue);
|
|
42
|
+
if (!mergedChild) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
merged[key] = mergedChild;
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (VISUAL_LEAF_KEYS.has(key)) {
|
|
50
|
+
merged[key] = Array.isArray(darkValue) ? [...darkValue] : darkValue;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
55
|
+
/** Applies a config's `dark` overlay onto its display block ahead of strict parsing, since the light block may only become valid once the overlay lands; any break returns the input untouched. */
|
|
56
|
+
export function mergeNativeDarkOverlay(content) {
|
|
57
|
+
let raw = content;
|
|
58
|
+
if (typeof content === 'string') {
|
|
59
|
+
try {
|
|
60
|
+
raw = JSON.parse(content);
|
|
61
|
+
} catch {
|
|
62
|
+
return content;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!isObject(raw)) {
|
|
66
|
+
return content;
|
|
67
|
+
}
|
|
68
|
+
const displayType = raw.displayType;
|
|
69
|
+
if (typeof displayType !== 'string') {
|
|
70
|
+
return content;
|
|
71
|
+
}
|
|
72
|
+
const block = raw[displayType];
|
|
73
|
+
if (!isObject(block)) {
|
|
74
|
+
return content;
|
|
75
|
+
}
|
|
76
|
+
const overlay = block.dark;
|
|
77
|
+
if (!isObject(overlay)) {
|
|
78
|
+
return content;
|
|
79
|
+
}
|
|
80
|
+
const merged = overlayOnto(block, overlay);
|
|
81
|
+
if (!merged) {
|
|
82
|
+
return content;
|
|
83
|
+
}
|
|
84
|
+
delete merged.dark;
|
|
85
|
+
return {
|
|
86
|
+
...raw,
|
|
87
|
+
[displayType]: merged
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'تكوين rich media غير صالح',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'اكشط هنا'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'اكشط هنا',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'تبديل الوضع الفاتح والداكن'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'অবৈধ rich media কনফিগারেশন',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'এখানে ঘষুন'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'এখানে ঘষুন',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'হালকা এবং গাঢ় থিমের মধ্যে পরিবর্তন করুন'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'Ungültige Rich-Media-Konfiguration',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Hier freirubbeln'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Hier freirubbeln',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'Zwischen hellem und dunklem Design wechseln'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'Invalid rich media config',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Scratch here'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Scratch here',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'Switch light and dark'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'Configuración de rich media no válida',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Rasca aquí'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Rasca aquí',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'Cambiar entre claro y oscuro'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'Configuration rich media non valide',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Grattez ici'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Grattez ici',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'Basculer entre clair et sombre'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'תצורת rich media לא חוקית',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'גרדו כאן'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'גרדו כאן',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'החלף בין ערכת נושא בהירה לכהה'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'अमान्य rich media कॉन्फ़िगरेशन',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'यहाँ खरोंचें'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'यहाँ खरोंचें',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'लाइट और डार्क थीम के बीच स्विच करें'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'リッチメディア設定が無効です',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'ここを削ってください'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'ここを削ってください',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'ライトとダークを切り替える'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': '리치 미디어 구성이 잘못되었습니다',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': '여기를 긁어보세요'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': '여기를 긁어보세요',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': '라이트와 다크 테마 전환'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'Configuração de rich media inválida',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Raspe aqui'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Raspe aqui',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'Alternar entre claro e escuro'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'Некорректная конфигурация rich media',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Сотрите здесь'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'Сотрите здесь',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'Переключить светлую и тёмную тему'
|
|
4
5
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const messages = {
|
|
2
2
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': 'การกำหนดค่า rich media ไม่ถูกต้อง',
|
|
3
|
-
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'ขูดที่นี่'
|
|
3
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': 'ขูดที่นี่',
|
|
4
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': 'สลับธีมสว่างและมืด'
|
|
4
5
|
};
|
|
@@ -2,4 +2,5 @@ import type { NoParams } from '../../polyglot';
|
|
|
2
2
|
export type NativeRichMediaPreviewMessages = {
|
|
3
3
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.INVALID_CONFIG': NoParams;
|
|
4
4
|
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.SCRATCH_HERE': NoParams;
|
|
5
|
+
'DUMB.NATIVE_RICH_MEDIA_PREVIEW.TOGGLE_THEME': NoParams;
|
|
5
6
|
};
|
|
@@ -50,6 +50,10 @@ export type NativeRichMediaReward = {
|
|
|
50
50
|
/** Confirmation button, including its own tap action. */
|
|
51
51
|
button?: NativeRichMediaButton;
|
|
52
52
|
};
|
|
53
|
+
/** Sparse dark overlay over a display block: visual leaves replace, objects merge recursively, `buttons`/`items` positionally; typed loosely because the shape is checked at merge time. */
|
|
54
|
+
export type NativeRichMediaDarkOverlay = {
|
|
55
|
+
[key: string]: string | string[] | NativeRichMediaDarkOverlay | NativeRichMediaDarkOverlay[] | undefined;
|
|
56
|
+
};
|
|
53
57
|
/** Content of a `banner` rich media. */
|
|
54
58
|
export type NativeRichMediaBannerBlock = {
|
|
55
59
|
/** Show a close (✕) chip. */
|
|
@@ -68,6 +72,8 @@ export type NativeRichMediaBannerBlock = {
|
|
|
68
72
|
action: NativeRichMediaAction;
|
|
69
73
|
/** Auto-dismiss timeout in seconds; omit to keep the banner until closed. */
|
|
70
74
|
autoDismiss?: number;
|
|
75
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
76
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
71
77
|
};
|
|
72
78
|
/** Content of a `carousel` rich media. */
|
|
73
79
|
export type NativeRichMediaCarouselBlock = {
|
|
@@ -84,6 +90,8 @@ export type NativeRichMediaCarouselBlock = {
|
|
|
84
90
|
/** Tap action of the card. */
|
|
85
91
|
action?: NativeRichMediaAction;
|
|
86
92
|
}>;
|
|
93
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
94
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
87
95
|
};
|
|
88
96
|
/** Content of a `modal` rich media. */
|
|
89
97
|
export type NativeRichMediaModalBlock = {
|
|
@@ -101,6 +109,8 @@ export type NativeRichMediaModalBlock = {
|
|
|
101
109
|
message?: NativeRichMediaText;
|
|
102
110
|
/** Action buttons under the message. */
|
|
103
111
|
buttons: Array<NativeRichMediaButton>;
|
|
112
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
113
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
104
114
|
};
|
|
105
115
|
/** Content of a `sheet` rich media. */
|
|
106
116
|
export type NativeRichMediaSheetBlock = {
|
|
@@ -118,6 +128,8 @@ export type NativeRichMediaSheetBlock = {
|
|
|
118
128
|
message?: NativeRichMediaText;
|
|
119
129
|
/** Action buttons under the message. */
|
|
120
130
|
buttons: Array<NativeRichMediaButton>;
|
|
131
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
132
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
121
133
|
};
|
|
122
134
|
/** Content of a `stories` rich media. */
|
|
123
135
|
export type NativeRichMediaStoriesBlock = {
|
|
@@ -138,6 +150,8 @@ export type NativeRichMediaStoriesBlock = {
|
|
|
138
150
|
/** Slide duration in seconds (SDK: default 5, max 30). */
|
|
139
151
|
duration: number;
|
|
140
152
|
}>;
|
|
153
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
154
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
141
155
|
};
|
|
142
156
|
/** Content of a `fullscreen` rich media. */
|
|
143
157
|
export type NativeRichMediaFullscreenBlock = {
|
|
@@ -151,6 +165,8 @@ export type NativeRichMediaFullscreenBlock = {
|
|
|
151
165
|
message?: NativeRichMediaText;
|
|
152
166
|
/** Action buttons at the bottom. */
|
|
153
167
|
buttons: Array<NativeRichMediaButton>;
|
|
168
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
169
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
154
170
|
};
|
|
155
171
|
/** Content of a `video` rich media. */
|
|
156
172
|
export type NativeRichMediaVideoBlock = {
|
|
@@ -172,6 +188,8 @@ export type NativeRichMediaVideoBlock = {
|
|
|
172
188
|
fallback?: string;
|
|
173
189
|
/** Action buttons at the bottom. */
|
|
174
190
|
buttons: Array<NativeRichMediaButton>;
|
|
191
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
192
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
175
193
|
};
|
|
176
194
|
/** Content of a `pip` (picture-in-picture) rich media. */
|
|
177
195
|
export type NativeRichMediaPipBlock = {
|
|
@@ -197,6 +215,8 @@ export type NativeRichMediaPipBlock = {
|
|
|
197
215
|
borderRadius?: number;
|
|
198
216
|
/** Tap action of the pip window itself. */
|
|
199
217
|
action?: NativeRichMediaAction;
|
|
218
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
219
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
200
220
|
};
|
|
201
221
|
/** Content of a `scratchcard` rich media. */
|
|
202
222
|
export type NativeRichMediaScratchcardBlock = {
|
|
@@ -216,6 +236,8 @@ export type NativeRichMediaScratchcardBlock = {
|
|
|
216
236
|
message?: NativeRichMediaText;
|
|
217
237
|
/** Reward revealed under the cover; required by the SDK, may be absent in a draft. */
|
|
218
238
|
reward?: NativeRichMediaReward;
|
|
239
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
240
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
219
241
|
};
|
|
220
242
|
/** Content of a `spinwheel` rich media. */
|
|
221
243
|
export type NativeRichMediaSpinwheelBlock = {
|
|
@@ -246,6 +268,8 @@ export type NativeRichMediaSpinwheelBlock = {
|
|
|
246
268
|
/** Reward granted when the wheel stops on this sector. */
|
|
247
269
|
reward?: NativeRichMediaReward;
|
|
248
270
|
}>;
|
|
271
|
+
/** Dark-theme overlay merged over this block when the dark variant is shown. */
|
|
272
|
+
dark?: NativeRichMediaDarkOverlay;
|
|
249
273
|
};
|
|
250
274
|
/** Native rich media config: a display type and the matching content block. */
|
|
251
275
|
export type NativeRichMediaConfig = {
|
|
@@ -295,6 +319,8 @@ export declare const EDITABLE_NATIVE_RICH_MEDIA_DISPLAY_TYPES: NativeRichMediaDi
|
|
|
295
319
|
* fallback. Text lives here rather than inline in `content`.
|
|
296
320
|
*/
|
|
297
321
|
export type NativeRichMediaLocalization = Record<string, Record<string, string>>;
|
|
322
|
+
/** Colour scheme the preview renders: the light values, or them merged with the dark overlay. */
|
|
323
|
+
export type NativeRichMediaTheme = 'light' | 'dark';
|
|
298
324
|
/** Props of {@link NativeRichMediaPreview}. */
|
|
299
325
|
export type NativeRichMediaPreviewProps = {
|
|
300
326
|
/** Rich media config, as an object or a JSON string. */
|
|
@@ -315,4 +341,10 @@ export type NativeRichMediaPreviewProps = {
|
|
|
315
341
|
isLoading?: boolean;
|
|
316
342
|
/** Render the container chrome — white backdrop and border (default `true`). Set `false` for a transparent preview over the consumer's own background. */
|
|
317
343
|
withBackground?: boolean;
|
|
344
|
+
/** Show a chip that switches the preview between the light and dark variants (default `false`). Uncontrolled, the preview opens light. */
|
|
345
|
+
withThemeToggle?: boolean;
|
|
346
|
+
/** Theme to render, making the chip controlled: the preview follows this value, the chip mirrors it (rather than the rendered result, since content without a dark overlay renders identically in both themes) and only reports clicks through `onThemeChange`. Omit to let the preview keep its own state. */
|
|
347
|
+
theme?: NativeRichMediaTheme;
|
|
348
|
+
/** Called with the other theme when the chip is clicked; the only way to react to the chip on a controlled preview. */
|
|
349
|
+
onThemeChange?: (theme: NativeRichMediaTheme) => void;
|
|
318
350
|
};
|
package/index.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export { Chip, type ChipProps, type ChipVariant } from './Chip';
|
|
|
50
50
|
export { RichmediaPreview, useRichmediaHtml } from './RichmediaPreview';
|
|
51
51
|
export { SandboxedHtmlFrame, type SandboxedHtmlFrameProps, type IsolatedSandboxedHtmlFrameProps, type InspectableSandboxedHtmlFrameProps, } from './SandboxedHtmlFrame';
|
|
52
52
|
export { NativeRichMediaPreview, parseNativeRichMediaConfig, parseLocalizationParams, NATIVE_RICH_MEDIA_DISPLAY_TYPES, EDITABLE_NATIVE_RICH_MEDIA_DISPLAY_TYPES, } from './NativeRichMediaPreview';
|
|
53
|
-
export type { NativeRichMediaConfig, NativeRichMediaDisplayType, NativeRichMediaText, NativeRichMediaBorder, NativeRichMediaCover, NativeRichMediaAction, NativeRichMediaButton, NativeRichMediaReward, NativeRichMediaModalBlock, NativeRichMediaSheetBlock, NativeRichMediaCarouselBlock, NativeRichMediaStoriesBlock, NativeRichMediaBannerBlock, NativeRichMediaFullscreenBlock, NativeRichMediaVideoBlock, NativeRichMediaPipBlock, NativeRichMediaScratchcardBlock, NativeRichMediaSpinwheelBlock, NativeRichMediaPreviewProps, NativeRichMediaLocalization, } from './NativeRichMediaPreview';
|
|
53
|
+
export type { NativeRichMediaConfig, NativeRichMediaDisplayType, NativeRichMediaText, NativeRichMediaBorder, NativeRichMediaCover, NativeRichMediaAction, NativeRichMediaButton, NativeRichMediaReward, NativeRichMediaDarkOverlay, NativeRichMediaModalBlock, NativeRichMediaSheetBlock, NativeRichMediaCarouselBlock, NativeRichMediaStoriesBlock, NativeRichMediaBannerBlock, NativeRichMediaFullscreenBlock, NativeRichMediaVideoBlock, NativeRichMediaPipBlock, NativeRichMediaScratchcardBlock, NativeRichMediaSpinwheelBlock, NativeRichMediaPreviewProps, NativeRichMediaLocalization, NativeRichMediaTheme, } from './NativeRichMediaPreview';
|
|
54
54
|
export { RichMessageEditor, RichMessageViewer, type DynamicContent, } from './RichMessageEditor';
|
|
55
55
|
export { FrequencyCappingEdit, FrequencyCappingReadonly, FrequencyCappingInApps, CappingCountingMode, CountingMode, type CountingModeProps, type LocalCapping, type CappingInAppBase, } from './FrequencyCapping';
|
|
56
56
|
export { SendRateEdit, SendRateReadonly, type SendRateBase, type SendRateEditProps, type SendRateReadonlyProps, } from './SendRate';
|