@pushwoosh/dumb-components 1.1.167 → 1.1.169

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.
@@ -36,13 +36,14 @@ export function EmailTemplatePreview(props) {
36
36
  } = props;
37
37
  const [liquidInstance] = useState(createLiquidInstance);
38
38
  const src = useMemo(() => {
39
+ let withDynamicContent = template;
39
40
  try {
40
41
  const withLocalization = replaceLocalization(template, localization);
41
- const withDynamicContent = replacePlaceholders(withLocalization, values);
42
+ withDynamicContent = replacePlaceholders(withLocalization, values);
42
43
  return liquidInstance.parseAndRenderSync(withDynamicContent, values);
43
44
  } catch (e) {
44
45
  console.error('Error in PreviewIframe', e);
45
- return `<body style="font-size: 24px; color: darkred">${e.message}</body>`;
46
+ return withDynamicContent;
46
47
  }
47
48
  }, [template, localization, values, liquidInstance]);
48
49
  return _jsx(IframeStyled, {
@@ -8,6 +8,7 @@ import { NativeRichMediaDim } from './components/NativeRichMediaDim';
8
8
  import { NativeRichMediaMuteChip } from './components/NativeRichMediaMuteChip';
9
9
  import { EDGE_INSET, clampIndex } from './helpers';
10
10
  import { parseNativeRichMediaConfig } from './parseNativeRichMediaConfig';
11
+ import { resolveLocalization } from './resolveLocalization';
11
12
  import { BackdropLayer, ContentFlow, PreviewHost, ScrollLayer, SpinnerLayer } from './styles';
12
13
  import { NativeRichMediaBannerView, NativeRichMediaCarouselView, NativeRichMediaFullscreenView, NativeRichMediaInvalidView, NativeRichMediaModalView, NativeRichMediaPipView, NativeRichMediaScratchcardView, NativeRichMediaSheetView, NativeRichMediaSpinwheelView, NativeRichMediaStoriesView, NativeRichMediaVideoView } from './views';
13
14
  import { GradientOverlay } from './views/shared/styles';
@@ -184,13 +185,21 @@ function renderConfig(config, activeIndex) {
184
185
  export function NativeRichMediaPreview(props) {
185
186
  const {
186
187
  content,
188
+ localization,
189
+ language,
187
190
  width,
188
191
  height,
189
192
  activeIndex = 0,
190
193
  isLoading = false,
191
194
  withBackground = true
192
195
  } = props;
193
- const config = useMemo(() => parseNativeRichMediaConfig(content), [content]);
196
+ const config = useMemo(() => {
197
+ const parsed = parseNativeRichMediaConfig(content);
198
+ if (!parsed) {
199
+ return null;
200
+ }
201
+ return parseNativeRichMediaConfig(resolveLocalization(parsed, localization, language));
202
+ }, [content, localization, language]);
194
203
  const shouldDim = !isLoading && dimsScreen(config);
195
204
  return _jsxs(PreviewHost, {
196
205
  width: width,
@@ -1,4 +1,4 @@
1
- export type { NativeRichMediaConfig, NativeRichMediaDisplayType, NativeRichMediaText, NativeRichMediaBorder, NativeRichMediaCover, NativeRichMediaAction, NativeRichMediaButton, NativeRichMediaReward, NativeRichMediaModalBlock, NativeRichMediaSheetBlock, NativeRichMediaCarouselBlock, NativeRichMediaStoriesBlock, NativeRichMediaBannerBlock, NativeRichMediaFullscreenBlock, NativeRichMediaVideoBlock, NativeRichMediaPipBlock, NativeRichMediaScratchcardBlock, NativeRichMediaSpinwheelBlock, NativeRichMediaPreviewProps, } from './types';
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';
2
2
  export { NATIVE_RICH_MEDIA_DISPLAY_TYPES } from './types';
3
3
  export { parseNativeRichMediaConfig } from './parseNativeRichMediaConfig';
4
4
  export { NativeRichMediaPreview } from './NativeRichMediaPreview';
@@ -0,0 +1,9 @@
1
+ import type { NativeRichMediaConfig, NativeRichMediaLocalization } from './types';
2
+ /**
3
+ * Replaces every `{{key|type}}` (or `{{key|type|default}}`) placeholder in a
4
+ * parsed config with the text from `localization[language][key]`, falling back
5
+ * to the `default` bucket and then to the placeholder's default segment (or the
6
+ * key itself when it has none). Returns a new config; non-placeholder (already
7
+ * literal) values are copied through unchanged.
8
+ */
9
+ export declare function resolveLocalization(config: NativeRichMediaConfig, localization: NativeRichMediaLocalization | undefined, language: string | undefined): NativeRichMediaConfig;
@@ -0,0 +1,45 @@
1
+ const PLACEHOLDER_RE = /^\{\{([^|}]+)\|[^|}]*(?:\|([^}]*))?\}\}$/;
2
+ function resolveValue(value, localization, language) {
3
+ var _localization$languag, _localization$default;
4
+ const match = PLACEHOLDER_RE.exec(value);
5
+ if (!match) {
6
+ return value;
7
+ }
8
+ const key = match[1];
9
+ const fallback = match[2] ?? key;
10
+ const languageValue = language ? localization === null || localization === void 0 || (_localization$languag = localization[language]) === null || _localization$languag === void 0 ? void 0 : _localization$languag[key] : undefined;
11
+ if (typeof languageValue === 'string') {
12
+ return languageValue;
13
+ }
14
+ const defaultValue = localization === null || localization === void 0 || (_localization$default = localization.default) === null || _localization$default === void 0 ? void 0 : _localization$default[key];
15
+ if (typeof defaultValue === 'string') {
16
+ return defaultValue;
17
+ }
18
+ return fallback;
19
+ }
20
+ function resolveNode(node, localization, language) {
21
+ if (typeof node === 'string') {
22
+ return resolveValue(node, localization, language);
23
+ }
24
+ if (Array.isArray(node)) {
25
+ return node.map(item => resolveNode(item, localization, language));
26
+ }
27
+ if (node !== null && typeof node === 'object') {
28
+ const result = {};
29
+ Object.entries(node).forEach(([key, value]) => {
30
+ result[key] = resolveNode(value, localization, language);
31
+ });
32
+ return result;
33
+ }
34
+ return node;
35
+ }
36
+ /**
37
+ * Replaces every `{{key|type}}` (or `{{key|type|default}}`) placeholder in a
38
+ * parsed config with the text from `localization[language][key]`, falling back
39
+ * to the `default` bucket and then to the placeholder's default segment (or the
40
+ * key itself when it has none). Returns a new config; non-placeholder (already
41
+ * literal) values are copied through unchanged.
42
+ */
43
+ export function resolveLocalization(config, localization, language) {
44
+ return resolveNode(config, localization, language);
45
+ }
@@ -283,10 +283,20 @@ export type NativeRichMediaConfig = {
283
283
  export type NativeRichMediaDisplayType = NativeRichMediaConfig['displayType'];
284
284
  /** All supported {@link NativeRichMediaDisplayType} values. */
285
285
  export declare const NATIVE_RICH_MEDIA_DISPLAY_TYPES: NativeRichMediaDisplayType[];
286
+ /**
287
+ * Per-language text for `{{key|type|default}}` placeholders in the config:
288
+ * `{ [language]: { [key]: text } }`, plus a `default` bucket used as the
289
+ * fallback. Text lives here rather than inline in `content`.
290
+ */
291
+ export type NativeRichMediaLocalization = Record<string, Record<string, string>>;
286
292
  /** Props of {@link NativeRichMediaPreview}. */
287
293
  export type NativeRichMediaPreviewProps = {
288
294
  /** Rich media config, as an object or a JSON string. */
289
295
  content: string | NativeRichMediaConfig;
296
+ /** Per-language text for placeholders in `content`; when given, placeholders are resolved for `language` (falling back to `default`). */
297
+ localization?: NativeRichMediaLocalization;
298
+ /** Language code to resolve placeholders for; falls back to the `default` bucket. */
299
+ language?: string;
290
300
  /** Preview box width; number is treated as px. */
291
301
  width: string | number;
292
302
  /** Preview box height; number is treated as px. */
package/index.d.ts CHANGED
@@ -44,7 +44,7 @@ export { EnhancedInput, SearchInput } from './EnhancedInput';
44
44
  export { Chip, type ChipProps, type ChipVariant } from './Chip';
45
45
  export { RichmediaPreview, useRichmediaHtml } from './RichmediaPreview';
46
46
  export { NativeRichMediaPreview, parseNativeRichMediaConfig, NATIVE_RICH_MEDIA_DISPLAY_TYPES } from './NativeRichMediaPreview';
47
- export type { NativeRichMediaConfig, NativeRichMediaDisplayType, NativeRichMediaText, NativeRichMediaBorder, NativeRichMediaCover, NativeRichMediaAction, NativeRichMediaButton, NativeRichMediaReward, NativeRichMediaModalBlock, NativeRichMediaSheetBlock, NativeRichMediaCarouselBlock, NativeRichMediaStoriesBlock, NativeRichMediaBannerBlock, NativeRichMediaFullscreenBlock, NativeRichMediaVideoBlock, NativeRichMediaPipBlock, NativeRichMediaScratchcardBlock, NativeRichMediaSpinwheelBlock, NativeRichMediaPreviewProps, } from './NativeRichMediaPreview';
47
+ export type { NativeRichMediaConfig, NativeRichMediaDisplayType, NativeRichMediaText, NativeRichMediaBorder, NativeRichMediaCover, NativeRichMediaAction, NativeRichMediaButton, NativeRichMediaReward, NativeRichMediaModalBlock, NativeRichMediaSheetBlock, NativeRichMediaCarouselBlock, NativeRichMediaStoriesBlock, NativeRichMediaBannerBlock, NativeRichMediaFullscreenBlock, NativeRichMediaVideoBlock, NativeRichMediaPipBlock, NativeRichMediaScratchcardBlock, NativeRichMediaSpinwheelBlock, NativeRichMediaPreviewProps, NativeRichMediaLocalization, } from './NativeRichMediaPreview';
48
48
  export { RichMessageEditor, RichMessageViewer, type DynamicContent, } from './RichMessageEditor';
49
49
  export { FrequencyCappingEdit, FrequencyCappingReadonly, FrequencyCappingInApps, type LocalCapping, type CappingInAppBase, } from './FrequencyCapping';
50
50
  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.167",
3
+ "version": "1.1.169",
4
4
  "description": "React components to build Pushwoosh products",
5
5
  "main": "index.js",
6
6
  "module": "index.js",