@shopgate/pwa-common 7.32.0-beta.1 → 7.32.0-beta.11

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 (69) hide show
  1. package/components/Button/index.js +6 -0
  2. package/components/Icon/index.d.ts +1 -1
  3. package/components/Icon/index.d.ts.map +1 -1
  4. package/components/Image/Image.d.ts +78 -0
  5. package/components/Image/Image.d.ts.map +1 -0
  6. package/components/Image/Image.js +123 -91
  7. package/components/Image/ImageInner.d.ts +45 -0
  8. package/components/Image/ImageInner.d.ts.map +1 -0
  9. package/components/Image/ImageInner.js +23 -29
  10. package/components/Image/index.d.ts +3 -0
  11. package/components/Image/index.d.ts.map +1 -0
  12. package/components/Modal/index.js +4 -4
  13. package/components/SurroundPortals/index.d.ts +1 -1
  14. package/components/SurroundPortals/index.d.ts.map +1 -1
  15. package/components/Swiper/index.js +1 -0
  16. package/constants/Configuration.js +7 -0
  17. package/helpers/mocks/mockRenderOptions.js +21 -0
  18. package/package.json +5 -5
  19. package/providers/toast/index.js +63 -49
  20. package/subscriptions/error.js +50 -27
  21. package/subscriptions/helpers/pipeline.js +68 -0
  22. package/subscriptions/router.js +2 -2
  23. package/action-creators/app/spec.js +0 -96
  24. package/action-creators/client/spec.js +0 -44
  25. package/action-creators/menu/spec.js +0 -37
  26. package/action-creators/modal/spec.js +0 -26
  27. package/action-creators/page/spec.js +0 -38
  28. package/action-creators/url/spec.js +0 -45
  29. package/action-creators/user/spec.js +0 -186
  30. package/components/Backdrop/spec.js +0 -24
  31. package/components/Button/spec.js +0 -42
  32. package/components/Checkbox/spec.js +0 -111
  33. package/components/CountdownTimer/spec.js +0 -141
  34. package/components/Drawer/spec.js +0 -79
  35. package/components/Ellipsis/spec.js +0 -15
  36. package/components/EmbeddedMedia/spec.js +0 -61
  37. package/components/Grid/components/Item/spec.js +0 -24
  38. package/components/Grid/spec.js +0 -24
  39. package/components/HtmlSanitizer/spec.js +0 -229
  40. package/components/I18n/components/FormatDate/spec.js +0 -54
  41. package/components/I18n/components/FormatNumber/spec.js +0 -51
  42. package/components/I18n/components/FormatPrice/spec.js +0 -54
  43. package/components/I18n/components/FormatTime/spec.js +0 -51
  44. package/components/I18n/components/I18nProvider/spec.js +0 -40
  45. package/components/I18n/components/Placeholder/spec.js +0 -37
  46. package/components/I18n/components/Translate/spec.js +0 -33
  47. package/components/InfiniteContainer/spec.js +0 -204
  48. package/components/Input/spec.js +0 -123
  49. package/components/Link/spec.js +0 -60
  50. package/components/List/spec.js +0 -26
  51. package/components/ModalContainer/spec.js +0 -115
  52. package/components/Select/spec.js +0 -122
  53. package/components/SelectBox/spec.js +0 -68
  54. package/components/Swiper/components/SwiperItem/spec.js +0 -26
  55. package/components/Widgets/components/Widget/spec.js +0 -75
  56. package/components/Widgets/components/WidgetGrid/spec.js +0 -53
  57. package/components/Widgets/spec.js +0 -234
  58. package/helpers/data/spec.js +0 -194
  59. package/helpers/date/spec.js +0 -92
  60. package/helpers/style/spec.js +0 -108
  61. package/helpers/validation/spec.js +0 -10
  62. package/styles/reset/form.js +0 -58
  63. package/styles/reset/index.js +0 -8
  64. package/styles/reset/media.js +0 -26
  65. package/styles/reset/root.js +0 -37
  66. package/styles/reset/table.js +0 -14
  67. package/styles/reset/typography.js +0 -30
  68. package/tsconfig.build.json +0 -16
  69. package/tsconfig.json +0 -3
@@ -49,4 +49,10 @@ Button.defaultProps = {
49
49
  onClick: null,
50
50
  testId: 'Button'
51
51
  };
52
+
53
+ /**
54
+ * @deprecated Use `ButtonBase` from `@shopgate/engage/components/v2` instead — it renders the same
55
+ * unstyled click target, adds a ripple, and accepts `component` / `href` to change the element.
56
+ * For a styled button use `Button` from the same module.
57
+ */
52
58
  export default /*#__PURE__*/memo(Button);
@@ -31,6 +31,6 @@ export interface IconProps {
31
31
  * Provides basic styling via `currentColor` and supports size and color
32
32
  * overrides through props while allowing external class-based overrides.
33
33
  */
34
- declare const Icon: ({ content, className, color, viewBox, size, }: IconProps) => import("react/jsx-runtime").JSX.Element;
34
+ declare const Icon: ({ content, className, color, viewBox, size, }: IconProps) => import("react").JSX.Element;
35
35
  export default Icon;
36
36
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/Icon/index.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,IAAI,GAAI,+CAMX,SAAS,4CAgBX,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/Icon/index.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,IAAI,GAAI,+CAMX,SAAS,gCAgBX,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,78 @@
1
+ import type { ReactElement, SyntheticEvent } from 'react';
2
+ import type { ImageResolution } from '@shopgate/engage/settings/types/appSettings';
3
+ export interface ImageProps {
4
+ /**
5
+ * Optional alt text for the image. Without one the image is marked decorative.
6
+ */
7
+ alt?: string | null;
8
+ /**
9
+ * The background color of the image container.
10
+ */
11
+ backgroundColor?: string;
12
+ /**
13
+ * External class name for the image container.
14
+ */
15
+ className?: string | null;
16
+ /**
17
+ * External class name for the image itself.
18
+ */
19
+ classNameImg?: string | null;
20
+ /**
21
+ * Shows the `placeholder` even when the image could be loaded. For a parent that decides on
22
+ * grounds this component cannot see, e.g. a product that is not orderable.
23
+ */
24
+ forcePlaceholder?: boolean;
25
+ /**
26
+ * Callback that is invoked when the image with the highest resolution has been loaded.
27
+ */
28
+ highestResolutionLoaded?: () => void;
29
+ /**
30
+ * Microdata property name, e.g. "image" for a schema.org Product. Emitted as the itemprop
31
+ * attribute so crawlers can pick the image out of the surrounding item.
32
+ */
33
+ itemProp?: string;
34
+ /**
35
+ * Whether the image is loaded only once it comes near the viewport. Turn it off for images that
36
+ * are visible immediately, e.g. the first tile of a list.
37
+ */
38
+ lazy?: boolean;
39
+ /**
40
+ * Callback that is invoked when image loading failed. Handling the failure is not required - a
41
+ * `placeholder` covers that - so this is for callers that need to react beyond the image itself.
42
+ */
43
+ onError?: (event: SyntheticEvent<HTMLImageElement>) => void;
44
+ /**
45
+ * Callback that is invoked when the image has been loaded.
46
+ */
47
+ onLoad?: (event: SyntheticEvent<HTMLImageElement>) => void;
48
+ /**
49
+ * Rendered in place of the image when there is no `src`, when `forcePlaceholder` is set, or when
50
+ * the image failed to load. It renders inside the container, so it inherits the reserved aspect
51
+ * ratio box and needs no sizing of its own.
52
+ */
53
+ placeholder?: ReactElement | null;
54
+ /**
55
+ * Width and height parts of the rendered aspect ratio, e.g. [16, 9]. Without one the ratio is
56
+ * calculated from the highest resolution.
57
+ */
58
+ ratio?: number[] | null;
59
+ /**
60
+ * The resolutions to request, ordered ascending. The last is displayed; the second to last is
61
+ * loaded first as a preview, so something appears as soon as possible.
62
+ */
63
+ resolutions?: ImageResolution[];
64
+ /**
65
+ * Image source. A url the image service serves is rewritten to carry the requested dimensions and
66
+ * the app wide quality and fill settings. Any other url is used as it is, so `resolutions` and
67
+ * `ratio` then only affect the layout, not what is downloaded.
68
+ */
69
+ src?: string | null;
70
+ /**
71
+ * Renders a plain img tag without the container, for callers that position the image themselves.
72
+ * Nothing reserves its space while it loads, and `backgroundColor` has nothing to apply to.
73
+ */
74
+ unwrapped?: boolean;
75
+ }
76
+ declare const _default: import("react").MemoExoticComponent<(props: ImageProps) => import("react").JSX.Element | null>;
77
+ export default _default;
78
+ //# sourceMappingURL=Image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../components/Image/Image.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAiB,YAAY,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAKzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAGnF,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;OAEG;IACH,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC5D;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC3D;;;;OAIG;IACH,WAAW,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;oEA8EqB,UAAU;AAoMhC,wBAA2B"}
@@ -1,8 +1,8 @@
1
- import React, { useMemo, useState, useEffect, useRef, useCallback, memo } from 'react';
2
- import PropTypes from 'prop-types';
1
+ import { useMemo, useState, useEffect, useRef, useCallback, memo } from 'react';
3
2
  import noop from 'lodash/noop';
4
3
  import { makeStyles } from '@shopgate/engage/styles';
5
4
  import { getFullImageSource } from '@shopgate/engage/core/helpers';
5
+ import { useImageServiceSettings } from '@shopgate/engage/settings/hooks';
6
6
  import ImageInner from "./ImageInner";
7
7
  import { jsx as _jsx } from "react/jsx-runtime";
8
8
  const useStyles = makeStyles()((_theme, {
@@ -23,57 +23,112 @@ const useStyles = makeStyles()((_theme, {
23
23
  }));
24
24
 
25
25
  /**
26
- * Calculates the Greatest Common Divisor (GCD) of two numbers using the Euclidean algorithm.
27
- *
28
- * @param {number} a - The first number (must be a positive integer).
29
- * @param {number} b - The second number (must be a positive integer).
30
- * @returns {number} The greatest common divisor of `a` and `b`.
31
- *
32
- * @example
33
- * gcd(1920, 1080); // Returns 120
34
- * gcd(10, 15); // Returns 5
35
- * gcd(100, 25); // Returns 25
26
+ * Calculates the Greatest Common Divisor of two numbers using the Euclidean algorithm.
27
+ * @param a The first number.
28
+ * @param b The second number.
29
+ * @returns The greatest common divisor, or 1 when the pair cannot be reduced.
36
30
  */
37
- const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
31
+ const gcd = (a, b) => {
32
+ // Anything but a pair of positive whole numbers is left unreduced. The values can originate from
33
+ // an admin field a merchant is still typing into, and NaN or Infinity would otherwise recurse
34
+ // until the stack overflows, while a fraction would reduce to a near-zero divisor.
35
+ if (!Number.isInteger(a) || !Number.isInteger(b) || a <= 0 || b <= 0) {
36
+ return 1;
37
+ }
38
+ let dividend = a;
39
+ let remainder = b;
40
+ while (remainder !== 0) {
41
+ const next = dividend % remainder;
42
+ dividend = remainder;
43
+ remainder = next;
44
+ }
45
+ return dividend;
46
+ };
38
47
 
39
48
  /**
40
- * The image component.
41
- * @param {Object} props The components props.
42
- * @returns {JSX.Element}
49
+ * Whether a value can be used as one side of an aspect ratio.
50
+ * @param value The value to check.
51
+ * @returns Whether it is a usable length.
52
+ */
53
+ const isUsableLength = value => Number.isFinite(value) && value > 0;
54
+ const defaultResolutions = [{
55
+ width: 440,
56
+ height: 440
57
+ }];
58
+
59
+ /**
60
+ * Renders an image at the configured resolutions, inside a container that reserves its aspect ratio
61
+ * so the layout does not shift while it loads.
62
+ *
63
+ * What a caller should know:
64
+ *
65
+ * - **Nothing is rendered until there is something to render.** Without a `src`, the container is
66
+ * still there and keeps its space, but it stays empty unless a `placeholder` is given.
67
+ * - **A failed image is remembered per source, not per component.** Once a `placeholder` is given,
68
+ * it takes over on failure, and the image returns by itself as soon as the requested url changes -
69
+ * a new `src`, different `resolutions`, or an app wide image setting edited in the admin. Callers
70
+ * that pass no `placeholder` keep the failed image, and `onError` keeps reporting every attempt.
71
+ * - **`onLoad` and `onError` are always forwarded**, whether or not a placeholder is involved.
72
+ * - **`unwrapped` gives up the container**, and with it the reserved aspect ratio box and the
73
+ * background color. The caller has to provide the space itself.
74
+ * @param props The components props.
75
+ * @returns The rendered component.
43
76
  */
44
- const Image = ({
45
- alt,
46
- backgroundColor,
47
- className,
48
- classNameImg,
49
- forcePlaceholder: parentRendersPlaceholder,
50
- highestResolutionLoaded,
51
- onError,
52
- onLoad,
53
- ratio,
54
- resolutions,
55
- src,
56
- lazy,
57
- unwrapped
58
- }) => {
77
+ const Image = props => {
78
+ const {
79
+ alt = null,
80
+ backgroundColor = 'var(--sg-palette-background-emphasized)',
81
+ className = '',
82
+ classNameImg = '',
83
+ forcePlaceholder: parentRendersPlaceholder = false,
84
+ highestResolutionLoaded = noop,
85
+ itemProp,
86
+ onError = noop,
87
+ onLoad = noop,
88
+ placeholder = null,
89
+ ratio = null,
90
+ resolutions = defaultResolutions,
91
+ src = null,
92
+ lazy = true,
93
+ unwrapped = false
94
+ } = props;
95
+
96
+ // Quality and fill color are configured app wide, so they are resolved here rather than passed
97
+ // in by every caller. The returned object is reference stable, so it does not defeat the memo.
98
+ const imageServiceSettings = useImageServiceSettings();
99
+
59
100
  // Prepare two image sources - a small preview image and a large main image. The idea is to
60
101
  // display an image as soon as possible. Small images might be also available in the cache from
61
102
  // the previous page.
62
103
  const sources = useMemo(() => {
63
104
  // Create a preview source when resolutions array has more than one element
64
- const preview = resolutions.length > 1 ? getFullImageSource(src, resolutions[resolutions.length - 2]) : null;
105
+ const preview = resolutions.length > 1 ? getFullImageSource(src, resolutions[resolutions.length - 2], imageServiceSettings) : null;
65
106
 
66
107
  // Create a main source when resolutions array has at least one element (highest resolution)
67
- const main = resolutions.length > 0 ? getFullImageSource(src, resolutions[resolutions.length - 1]) : null;
108
+ const main = resolutions.length > 0 ? getFullImageSource(src, resolutions[resolutions.length - 1], imageServiceSettings) : null;
68
109
  return {
69
110
  // Only assign preview source if it is different from the main source. Image swap logic
70
111
  // will not run when no preview source is available.
71
112
  preview: preview !== main ? preview : null,
72
113
  main
73
114
  };
74
- }, [resolutions, src]);
115
+ }, [resolutions, src, imageServiceSettings]);
75
116
  const imgRef = useRef(null);
76
117
  const [isInView, setIsInView] = useState(!lazy);
118
+ const [failedSource, setFailedSource] = useState(null);
119
+
120
+ // A failure counts against the source that produced it, not against the component. Anything that
121
+ // rebuilds the url - a new src, a reconfigured ratio, a different fill color - is by itself the
122
+ // decision to try again, so the placeholder gives way without anyone having to reset a flag.
123
+ //
124
+ // Only callers that provide a placeholder have the image taken away from them. Without one there
125
+ // is nothing to swap to, so a failed image stays mounted and keeps reporting through onError,
126
+ // exactly as it behaved before this prop existed.
127
+ //
128
+ // The null check matters: an empty resolutions array leaves no source to request, and would
129
+ // otherwise match the initial state and report a failure that never happened.
130
+ const hasFailed = sources.main !== null && failedSource === sources.main;
131
+ const showPlaceholder = !src || parentRendersPlaceholder || !!placeholder && hasFailed;
77
132
 
78
133
  // Effect to create an Intersection Observer to enable lazy loading of preview images
79
134
  useEffect(() => {
@@ -103,40 +158,41 @@ const Image = ({
103
158
 
104
159
  /**
105
160
  * Handles the onLoad event of the image.
161
+ * @param event The load event.
106
162
  */
107
- const handleOnLoad = useCallback(e => {
163
+ const handleOnLoad = useCallback(event => {
108
164
  highestResolutionLoaded();
109
- onLoad(e);
165
+ onLoad(event);
110
166
  }, [highestResolutionLoaded, onLoad]);
111
167
 
112
168
  /**
113
169
  * Handles the onError event of the image.
170
+ * @param event The error event.
114
171
  */
115
- const handleOnError = useCallback(e => {
116
- onError(e);
117
- }, [onError]);
172
+ const handleOnError = useCallback(event => {
173
+ setFailedSource(sources.main);
174
+ onError(event);
175
+ }, [onError, sources.main]);
118
176
 
119
177
  /**
120
178
  * Memoized calculation of aspect ratio and CSS padding-hack ratio for responsive elements.
121
179
  *
122
- * Returns n object containing:
123
- * - `aspectRatio` {string} - The aspect ratio in the format `width / height` (e.g., `16 / 9`).
124
- * - `paddingHackRatio` {string} - The CSS padding-hack ratio as a percentage for older browsers
125
- * (e.g., `56.250%` for a 16:9 ratio).
180
+ * aspectRatio is the ratio in the format `width / height` (e.g. `16 / 9`), paddingHackRatio the
181
+ * same as a percentage for older browsers (e.g. `56.250%` for a 16:9 ratio).
126
182
  */
127
183
  const {
128
184
  aspectRatio,
129
185
  paddingHackRatio
130
186
  } = useMemo(() => {
131
- let width;
132
- let height;
133
- if (ratio) {
134
- [width, height] = ratio;
135
- } else {
136
- ({
137
- width,
138
- height
139
- } = resolutions[resolutions.length - 1]);
187
+ const [width, height] = ratio ?? [resolutions[resolutions.length - 1]?.width, resolutions[resolutions.length - 1]?.height];
188
+
189
+ // Fall back to a square rather than emitting "NaN / NaN" or dividing by zero. Reached when the
190
+ // resolutions are empty, or when a ratio arrives half typed from the admin.
191
+ if (!isUsableLength(width) || !isUsableLength(height)) {
192
+ return {
193
+ aspectRatio: '1 / 1',
194
+ paddingHackRatio: '100.000%'
195
+ };
140
196
  }
141
197
  const divisor = gcd(width, height);
142
198
  return {
@@ -151,22 +207,24 @@ const Image = ({
151
207
  background: backgroundColor,
152
208
  paddingTop: paddingHackRatio
153
209
  });
210
+ const innerStyle = {
211
+ aspectRatio,
212
+ ...(isInView && sources.preview && {
213
+ backgroundImage: `url(${sources.preview})`,
214
+ backgroundSize: 'contain',
215
+ backgroundRepeat: 'no-repeat',
216
+ backgroundPosition: 'center'
217
+ })
218
+ };
154
219
  if (unwrapped) {
155
- if (!(src && !parentRendersPlaceholder)) return null;
220
+ if (showPlaceholder) return placeholder;
156
221
  return /*#__PURE__*/_jsx(ImageInner, {
157
222
  ref: imgRef,
158
223
  src: sources.main,
159
224
  className: cx(classNameImg),
160
- style: {
161
- aspectRatio,
162
- ...(isInView && sources.preview && {
163
- backgroundImage: `url(${sources.preview})`,
164
- backgroundSize: 'contain',
165
- backgroundRepeat: 'no-repeat',
166
- backgroundPosition: 'center'
167
- })
168
- },
225
+ style: innerStyle,
169
226
  alt: alt,
227
+ itemProp: itemProp,
170
228
  lazy: lazy,
171
229
  onLoad: handleOnLoad,
172
230
  onError: handleOnError
@@ -174,43 +232,17 @@ const Image = ({
174
232
  }
175
233
  return /*#__PURE__*/_jsx("div", {
176
234
  className: cx(classes.container, className, 'common__image__container'),
177
- children: src && !parentRendersPlaceholder && /*#__PURE__*/_jsx(ImageInner, {
235
+ children: showPlaceholder ? placeholder : /*#__PURE__*/_jsx(ImageInner, {
178
236
  ref: imgRef,
179
237
  src: sources.main,
180
238
  className: cx(classNameImg),
181
- style: {
182
- aspectRatio,
183
- ...(isInView && sources.preview && {
184
- backgroundImage: `url(${sources.preview})`,
185
- backgroundSize: 'contain',
186
- backgroundRepeat: 'no-repeat',
187
- backgroundPosition: 'center'
188
- })
189
- },
239
+ style: innerStyle,
190
240
  alt: alt,
241
+ itemProp: itemProp,
191
242
  lazy: lazy,
192
243
  onLoad: handleOnLoad,
193
244
  onError: handleOnError
194
245
  })
195
246
  });
196
247
  };
197
- const defaultResolutions = [{
198
- width: 440,
199
- height: 440
200
- }];
201
- Image.defaultProps = {
202
- alt: null,
203
- backgroundColor: 'var(--sg-palette-background-emphasized)',
204
- className: '',
205
- classNameImg: '',
206
- forcePlaceholder: false,
207
- highestResolutionLoaded: noop,
208
- onError: noop,
209
- onLoad: noop,
210
- ratio: null,
211
- resolutions: defaultResolutions,
212
- src: null,
213
- unwrapped: false,
214
- lazy: true
215
- };
216
248
  export default /*#__PURE__*/memo(Image);
@@ -0,0 +1,45 @@
1
+ import type { CSSProperties, SyntheticEvent } from 'react';
2
+ export interface ImageInnerProps {
3
+ /**
4
+ * Alt text. Without one the image is marked decorative.
5
+ */
6
+ alt?: string | null;
7
+ /**
8
+ * External class name for the img element.
9
+ */
10
+ className?: string | null;
11
+ /**
12
+ * Microdata property name, e.g. "image" for a schema.org Product. Emitted as the itemprop
13
+ * attribute so crawlers can pick the image out of the surrounding item.
14
+ */
15
+ itemProp?: string;
16
+ /**
17
+ * Whether the browser defers loading until the image is near the viewport.
18
+ */
19
+ lazy?: boolean;
20
+ /**
21
+ * Callback that is invoked when image loading failed.
22
+ */
23
+ onError?: (event: SyntheticEvent<HTMLImageElement>) => void;
24
+ /**
25
+ * Callback that is invoked when the image has been loaded.
26
+ */
27
+ onLoad?: (event: SyntheticEvent<HTMLImageElement>) => void;
28
+ /**
29
+ * The resolved image url.
30
+ */
31
+ src?: string | null;
32
+ /**
33
+ * Inline styles, used to pin the aspect ratio and paint the preview behind the image.
34
+ */
35
+ style?: CSSProperties | null;
36
+ }
37
+ /**
38
+ * The ImageInner component renders the actual image of the Image component.
39
+ * @param props The component props.
40
+ * @param ref The component reference.
41
+ * @returns The rendered component.
42
+ */
43
+ declare const ImageInner: import("react").ForwardRefExoticComponent<ImageInnerProps & import("react").RefAttributes<HTMLImageElement>>;
44
+ export default ImageInner;
45
+ //# sourceMappingURL=ImageInner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageInner.d.ts","sourceRoot":"","sources":["../../../components/Image/ImageInner.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAI3D,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC5D;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC3D;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CAC9B;AAeD;;;;;GAKG;AACH,QAAA,MAAM,UAAU,8GAkCd,CAAC;AAEH,eAAe,UAAU,CAAC"}
@@ -1,5 +1,4 @@
1
- import React, { forwardRef } from 'react';
2
- import PropTypes from 'prop-types';
1
+ import { forwardRef } from 'react';
3
2
  import noop from 'lodash/noop';
4
3
  import { makeStyles } from '@shopgate/engage/styles';
5
4
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -11,25 +10,28 @@ const useStyles = makeStyles()({
11
10
  width: '100%',
12
11
  maxHeight: '100%',
13
12
  WebkitTouchCallout: 'none',
14
- fontSize: 0
13
+ fontSize: 0,
14
+ objectFit: 'contain'
15
15
  }
16
16
  });
17
17
 
18
18
  /**
19
- * The ImageInner component renders tha actual image of the Image component.
20
- * @param {Object} props The component props
21
- * @param {Function} ref The component reference
22
- * @returns {JSX.Element}
19
+ * The ImageInner component renders the actual image of the Image component.
20
+ * @param props The component props.
21
+ * @param ref The component reference.
22
+ * @returns The rendered component.
23
23
  */
24
- const ImageInner = /*#__PURE__*/forwardRef(({
25
- src,
26
- className,
27
- alt,
28
- lazy,
29
- onLoad,
30
- onError,
31
- style
32
- }, ref) => {
24
+ const ImageInner = /*#__PURE__*/forwardRef((props, ref) => {
25
+ const {
26
+ src = null,
27
+ className = null,
28
+ alt = null,
29
+ itemProp,
30
+ lazy = false,
31
+ onLoad = noop,
32
+ onError = noop,
33
+ style = null
34
+ } = props;
33
35
  const {
34
36
  classes,
35
37
  cx
@@ -37,24 +39,16 @@ const ImageInner = /*#__PURE__*/forwardRef(({
37
39
  return /*#__PURE__*/_jsx("img", {
38
40
  ref: ref,
39
41
  loading: lazy ? 'lazy' : 'eager',
40
- src: src,
42
+ src: src ?? undefined,
41
43
  className: cx(classes.image, 'common__image', className),
42
- alt: alt,
43
- "aria-label": alt,
44
+ alt: alt ?? undefined,
45
+ "aria-label": alt ?? undefined,
44
46
  "aria-hidden": !alt,
45
47
  "data-test-id": "image",
48
+ itemProp: itemProp,
46
49
  onLoad: onLoad,
47
50
  onError: onError,
48
- style: style
51
+ style: style ?? undefined
49
52
  });
50
53
  });
51
- ImageInner.defaultProps = {
52
- src: null,
53
- alt: null,
54
- className: null,
55
- lazy: false,
56
- style: null,
57
- onError: noop,
58
- onLoad: noop
59
- };
60
54
  export default ImageInner;
@@ -0,0 +1,3 @@
1
+ export { default } from './Image';
2
+ export type { ImageProps } from './Image';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/Image/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}
@@ -4,7 +4,7 @@ import { createPortal } from 'react-dom';
4
4
  import { useTrackModalState } from '@shopgate/engage/a11y/hooks';
5
5
  import { makeStyles, responsiveMediaQuery } from '@shopgate/engage/styles';
6
6
  import { jsx as _jsx } from "react/jsx-runtime";
7
- const useStyles = makeStyles()({
7
+ const useStyles = makeStyles()(theme => ({
8
8
  container: {
9
9
  position: 'fixed',
10
10
  top: 0,
@@ -25,8 +25,8 @@ const useStyles = makeStyles()({
25
25
  position: 'relative',
26
26
  maxWidth: '100vw',
27
27
  maxHeight: '100vh',
28
- paddingTop: 'var(--safe-area-inset-top)',
29
- paddingBottom: 'var(--safe-area-inset-bottom)',
28
+ paddingTop: theme.layout.safeArea.top,
29
+ paddingBottom: theme.layout.safeArea.bottom,
30
30
  overflowY: 'scroll',
31
31
  [responsiveMediaQuery('>xs', {
32
32
  webOnly: true
@@ -34,7 +34,7 @@ const useStyles = makeStyles()({
34
34
  overflowY: 'initial'
35
35
  }
36
36
  }
37
- });
37
+ }));
38
38
 
39
39
  /**
40
40
  * The Modal component.
@@ -19,6 +19,6 @@ export interface SurroundPortalsProps {
19
19
  *
20
20
  * @returns The SurroundPortals component.
21
21
  */
22
- declare const SurroundPortals: ({ portalName, portalProps, children, }: SurroundPortalsProps) => import("react/jsx-runtime").JSX.Element;
22
+ declare const SurroundPortals: ({ portalName, portalProps, children, }: SurroundPortalsProps) => React.JSX.Element;
23
23
  export default SurroundPortals;
24
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/SurroundPortals/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,eAAe,GAAI,wCAItB,oBAAoB,4CAQtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/SurroundPortals/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,eAAe,GAAI,wCAItB,oBAAoB,sBAQtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -51,6 +51,7 @@ const useStyles = makeStyles()(theme => ({
51
51
  bottom: 'auto',
52
52
  fontSize: theme.typography.caption.fontSize,
53
53
  background: theme.components.swiper.paginationFractionBackground,
54
+ color: theme.contrastColor(theme.components.swiper.paginationFractionBackground),
54
55
  borderRadius: '50px',
55
56
  width: 'fit-content',
56
57
  padding: '4px 8px',
@@ -34,4 +34,11 @@ export const IS_CONNECT_EXTENSION_ATTACHED = 'IS_CONNECT_EXTENSION_ATTACHED';
34
34
  */
35
35
  export const CONFIGURATION_COLLECTION_CREATE_EXTERNAL_IMAGE_URL = 'CONFIGURATION_COLLECTION_CREATE_EXTERNAL_IMAGE_URL';
36
36
  export const CONFIGURATION_COLLECTION_KEY_THEME_TYPOGRAPHY = 'CONFIGURATION_COLLECTION_KEY_THEME_TYPOGRAPHY';
37
+
38
+ /**
39
+ * Capability flag the PWA sets to signal that base typography is applied on the root (`<html>`)
40
+ * element rather than the legacy `<body>` element. Consumers can read it to adjust behavior
41
+ * accordingly. Absent on older PWAs.
42
+ */
43
+ export const CONFIGURATION_COLLECTION_KEY_HAS_ROOT_TYPOGRAPHY = 'CONFIGURATION_COLLECTION_KEY_HAS_ROOT_TYPOGRAPHY';
37
44
  export const CONFIGURATION_COLLECTION_KEY_UNIVERSAL_LINK_HANDLER = 'universalLinkHandler';
@@ -0,0 +1,21 @@
1
+ import PropTypes from 'prop-types';
2
+ const options = {
3
+ context: {
4
+ i18n: () => ({
5
+ // eslint-disable-next-line no-underscore-dangle
6
+ __(input) {
7
+ if (input) {
8
+ return input;
9
+ }
10
+ return '';
11
+ },
12
+ _p: () => 'p',
13
+ _d: () => 'd',
14
+ _n: () => 'n'
15
+ })
16
+ },
17
+ childContextTypes: {
18
+ i18n: PropTypes.func
19
+ }
20
+ };
21
+ export default options;