@pushwoosh/dumb-components 1.1.232 → 1.1.233

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/NativeRichMediaPreview/NativeRichMediaPreview.d.ts +0 -30
  2. package/NativeRichMediaPreview/NativeRichMediaPreview.js +36 -9
  3. package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/NativeRichMediaThemeChip.d.ts +3 -0
  4. package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/NativeRichMediaThemeChip.js +25 -0
  5. package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/index.d.ts +1 -0
  6. package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/index.js +1 -0
  7. package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/styles.d.ts +8 -0
  8. package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/styles.js +7 -0
  9. package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/types.d.ts +8 -0
  10. package/NativeRichMediaPreview/components/NativeRichMediaThemeChip/types.js +1 -0
  11. package/NativeRichMediaPreview/icons/MoonIcon.svg +3 -0
  12. package/NativeRichMediaPreview/icons/SunIcon.svg +4 -0
  13. package/NativeRichMediaPreview/icons/index.d.ts +2 -0
  14. package/NativeRichMediaPreview/icons/index.js +3 -1
  15. package/NativeRichMediaPreview/index.d.ts +2 -1
  16. package/NativeRichMediaPreview/index.js +2 -1
  17. package/NativeRichMediaPreview/mergeNativeDarkOverlay.d.ts +3 -0
  18. package/NativeRichMediaPreview/mergeNativeDarkOverlay.js +89 -0
  19. package/NativeRichMediaPreview/polyglot/messages_ar.js +2 -1
  20. package/NativeRichMediaPreview/polyglot/messages_bn.js +2 -1
  21. package/NativeRichMediaPreview/polyglot/messages_de.js +2 -1
  22. package/NativeRichMediaPreview/polyglot/messages_en.js +2 -1
  23. package/NativeRichMediaPreview/polyglot/messages_es.js +2 -1
  24. package/NativeRichMediaPreview/polyglot/messages_fr.js +2 -1
  25. package/NativeRichMediaPreview/polyglot/messages_he.js +2 -1
  26. package/NativeRichMediaPreview/polyglot/messages_hi.js +2 -1
  27. package/NativeRichMediaPreview/polyglot/messages_ja.js +2 -1
  28. package/NativeRichMediaPreview/polyglot/messages_ko.js +2 -1
  29. package/NativeRichMediaPreview/polyglot/messages_pt.js +2 -1
  30. package/NativeRichMediaPreview/polyglot/messages_ru.js +2 -1
  31. package/NativeRichMediaPreview/polyglot/messages_th.js +2 -1
  32. package/NativeRichMediaPreview/polyglot/messages_zh.js +2 -1
  33. package/NativeRichMediaPreview/polyglot/types.d.ts +1 -0
  34. package/NativeRichMediaPreview/types.d.ts +26 -0
  35. package/index.d.ts +1 -1
  36. package/package.json +1 -1
@@ -1,33 +1,3 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { NativeRichMediaPreviewProps } from './types';
3
- /**
4
- * Preview of a native rich media (modal, banner, stories, spinwheel, …)
5
- * rendered from its JSON config; lays out with plain CSS in the real pixels
6
- * of the given width/height box, with no fidelity to any phone's pt-metrics
7
- * since this is a preview and devices vary. Content flows inside a scrollable
8
- * layer above a static backdrop (the dim overlay or, for
9
- * `fullscreen`/`video`/`stories`, the full-bleed background image or poster):
10
- * content taller than the box scrolls, shorter content aligns per display
11
- * type while the backdrop stays put. Pass `scale` to lay the content out on a
12
- * larger (or smaller) reference viewport and scale the whole preview to fill
13
- * the box — the way to cram a phone-sized layout into a small preview box
14
- * while keeping its proportions. Shows an invalid-config placeholder when the
15
- * config cannot be parsed or misses required contract fields.
16
- *
17
- * @example
18
- * <NativeRichMediaPreview
19
- * width={304}
20
- * height={659}
21
- * content={{
22
- * displayType: 'modal',
23
- * modal: {
24
- * showClose: true,
25
- * dimBackground: true,
26
- * background: '#FFFFFFFF',
27
- * title: { text: 'Hi', color: '#4B5057FF' },
28
- * buttons: [],
29
- * },
30
- * }}
31
- * />
32
- */
33
3
  export declare function NativeRichMediaPreview(props: NativeRichMediaPreviewProps): ReactElement;
@@ -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';
@@ -180,6 +182,17 @@ function renderConfig(config, activeIndex) {
180
182
  * }}
181
183
  * />
182
184
  */
185
+ function parseDarkVariant(content, withThemeToggle) {
186
+ if (!withThemeToggle) {
187
+ return null;
188
+ }
189
+ const merged = mergeNativeDarkOverlay(content);
190
+ // The merge hands back `content` itself, untouched, whenever there is nothing to apply.
191
+ if (merged === content) {
192
+ return null;
193
+ }
194
+ return parseNativeRichMediaConfig(merged);
195
+ }
183
196
  export function NativeRichMediaPreview(props) {
184
197
  const {
185
198
  content,
@@ -190,15 +203,25 @@ export function NativeRichMediaPreview(props) {
190
203
  scale = 1,
191
204
  activeIndex = 0,
192
205
  isLoading = false,
193
- withBackground = true
206
+ withBackground = true,
207
+ withThemeToggle = false
194
208
  } = props;
195
- const config = useMemo(() => {
196
- const parsed = parseNativeRichMediaConfig(content);
197
- if (!parsed) {
198
- return null;
199
- }
200
- return parseNativeRichMediaConfig(resolveLocalization(parsed, localization, language));
201
- }, [content, localization, language]);
209
+ const [theme, setTheme] = useState('light');
210
+ const {
211
+ config,
212
+ isDarkRendered,
213
+ canToggleDark
214
+ } = useMemo(() => {
215
+ const lightParsed = parseNativeRichMediaConfig(content);
216
+ const darkParsed = parseDarkVariant(content, withThemeToggle);
217
+ const themed = theme === 'dark' && darkParsed ? darkParsed : lightParsed;
218
+ const resolved = themed ? parseNativeRichMediaConfig(resolveLocalization(themed, localization, language)) : null;
219
+ return {
220
+ config: resolved,
221
+ isDarkRendered: Boolean(resolved) && theme === 'dark' && darkParsed !== null,
222
+ canToggleDark: darkParsed !== null
223
+ };
224
+ }, [content, localization, language, theme, withThemeToggle]);
202
225
  const shouldDim = !isLoading && dimsScreen(config);
203
226
  return _jsxs(PreviewHost, {
204
227
  ...LIGHT_ISLAND_PROPS,
@@ -215,6 +238,10 @@ export function NativeRichMediaPreview(props) {
215
238
  children: renderConfig(config, activeIndex)
216
239
  })
217
240
  }, config.displayType), !isLoading && config && renderChrome(config)]
241
+ }), !isLoading && config && withThemeToggle && _jsx(NativeRichMediaThemeChip, {
242
+ theme: isDarkRendered ? 'dark' : 'light',
243
+ disabled: !canToggleDark,
244
+ onToggle: () => setTheme(theme === 'dark' ? 'light' : 'dark')
218
245
  }), isLoading && _jsx(SpinnerLayer, {
219
246
  children: _jsx(Spinner, {
220
247
  size: "medium",
@@ -0,0 +1,3 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { NativeRichMediaThemeChipProps } from './types';
3
+ export declare function NativeRichMediaThemeChip(props: NativeRichMediaThemeChipProps): ReactElement;
@@ -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,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none">
2
+ <path d="M20.5 14.9A8.6 8.6 0 019.1 3.5a8.6 8.6 0 1011.4 11.4z" fill="#fff"/>
3
+ </svg>
@@ -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, } 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
  };
@@ -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
  };
@@ -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 = {
@@ -315,4 +339,6 @@ export type NativeRichMediaPreviewProps = {
315
339
  isLoading?: boolean;
316
340
  /** Render the container chrome — white backdrop and border (default `true`). Set `false` for a transparent preview over the consumer's own background. */
317
341
  withBackground?: boolean;
342
+ /** Show a chip that switches the preview between the light and dark variants (default `false`). The preview always opens light. */
343
+ withThemeToggle?: boolean;
318
344
  };
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, } 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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushwoosh/dumb-components",
3
- "version": "1.1.232",
3
+ "version": "1.1.233",
4
4
  "description": "React components to build Pushwoosh products",
5
5
  "main": "index.js",
6
6
  "module": "index.js",