@shopgate/engage 7.32.0-beta.7 → 7.32.0-beta.9

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 (188) hide show
  1. package/account/components/Profile/Profile.provider.d.ts +1 -1
  2. package/account/components/Profile/ProfileAddressBook.d.ts.map +1 -1
  3. package/account/components/Profile/ProfileAddressBook.js +13 -22
  4. package/account/components/Profile/ProfileAddressCard.d.ts.map +1 -1
  5. package/account/components/Profile/ProfileAddressCard.js +8 -18
  6. package/account/components/Profile/ProfileForm.d.ts.map +1 -1
  7. package/account/components/Profile/ProfileForm.js +15 -42
  8. package/account/components/ProfileContact/ProfileContact.js +13 -21
  9. package/admin-preview/components/FrontendSettingsPreviewBridge/FrontendSettingsPreviewBridge.d.ts.map +1 -1
  10. package/admin-preview/components/FrontendSettingsPreviewBridge/FrontendSettingsPreviewBridge.js +41 -7
  11. package/admin-preview/components/FrontendSettingsPreviewBridge/types.d.ts +7 -0
  12. package/admin-preview/components/FrontendSettingsPreviewBridge/types.d.ts.map +1 -1
  13. package/admin-preview/initialization/_internal/initialFrontendSettings.d.ts +32 -0
  14. package/admin-preview/initialization/_internal/initialFrontendSettings.d.ts.map +1 -0
  15. package/admin-preview/initialization/_internal/initialFrontendSettings.js +43 -0
  16. package/admin-preview/initialization/awaitInitialFrontendSettings.d.ts +22 -0
  17. package/admin-preview/initialization/awaitInitialFrontendSettings.d.ts.map +1 -0
  18. package/admin-preview/initialization/awaitInitialFrontendSettings.js +84 -0
  19. package/back-in-stock/components/BackInStockButton/index.js +5 -5
  20. package/cart/components/CartItem/CartItemProductLayout.js +1 -0
  21. package/cart/components/CartItem/CartItemProductLayoutWideRemoveItem.js +7 -14
  22. package/cart/components/CartItem/CartItemQuantityPicker.js +1 -0
  23. package/cart/components/CartItems/CartItemCardReservationLabelChangeStore.js +6 -24
  24. package/cart/components/CartSummaryWide/CartSummaryWide.js +2 -2
  25. package/cart/components/CartSummaryWide/CartSummaryWideCheckoutButton.js +9 -23
  26. package/cart/components/PaymentBar/PaymentBarCheckoutButton.js +8 -30
  27. package/cart/components/PaymentBar/testUtils/mockFactories.js +4 -11
  28. package/category/components/CategoryImage/index.js +13 -2
  29. package/checkout/components/AddressBook/AddressList.js +14 -23
  30. package/checkout/components/Checkout/CheckoutActions.js +4 -3
  31. package/checkout/components/Checkout/CheckoutAddress.js +8 -0
  32. package/checkout/components/Checkout/CheckoutSection.js +6 -2
  33. package/checkout/components/CheckoutConfirmation/CheckoutConfirmation.js +6 -7
  34. package/checkout/components/ResponsiveBackButton/ResponsiveBackButton.js +7 -17
  35. package/components/Badge/spec.js +6 -29
  36. package/components/Card/Card.js +1 -1
  37. package/components/ChipLayout/index.js +2 -4
  38. package/components/NavigationHandler/connector.js +1 -1
  39. package/components/NavigationHandler/index.d.ts +2 -2
  40. package/components/NavigationHandler/spec.js +10 -1
  41. package/components/Paper/Paper.d.ts +1 -2
  42. package/components/Paper/Paper.d.ts.map +1 -1
  43. package/components/Paper/spec.js +5 -22
  44. package/components/Tabs/components/Tab.d.ts.map +1 -1
  45. package/components/Tabs/components/Tab.js +14 -16
  46. package/components/Typography/Typography.d.ts +1 -1
  47. package/components/v2/Button/Button.d.ts +24 -13
  48. package/components/v2/Button/Button.d.ts.map +1 -1
  49. package/components/v2/Button/Button.js +139 -41
  50. package/components/v2/ButtonBase/ButtonBase.d.ts +50 -10
  51. package/components/v2/ButtonBase/ButtonBase.d.ts.map +1 -1
  52. package/components/v2/ButtonBase/ButtonBase.js +192 -17
  53. package/components/v2/ButtonBase/hooks.d.ts +0 -1
  54. package/components/v2/ButtonBase/hooks.d.ts.map +1 -1
  55. package/components/v2/ButtonBase/hooks.js +36 -12
  56. package/components/v2/ButtonGroup/ButtonGroup.d.ts +11 -5
  57. package/components/v2/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  58. package/components/v2/ButtonGroup/ButtonGroup.js +49 -26
  59. package/components/v2/CircularProgress/CircularProgress.d.ts.map +1 -1
  60. package/components/v2/CircularProgress/CircularProgress.js +10 -5
  61. package/core/hooks/useNavigation.d.ts +10 -2
  62. package/core/hooks/useNavigation.d.ts.map +1 -1
  63. package/core/hooks/useNavigation.js +1 -2
  64. package/core/initialization/index.d.ts.map +1 -1
  65. package/core/initialization/index.js +24 -5
  66. package/core/router/conductor.d.ts +9 -0
  67. package/core/router/helpers.d.ts +28 -15
  68. package/core/router/helpers.d.ts.map +1 -1
  69. package/core/router/helpers.js +8 -8
  70. package/development/components/DevelopmentSettings/DevelopmentSettings.js +3 -3
  71. package/favorites/components/FavoriteButtonWide/FavoriteButtonWide.js +7 -17
  72. package/favorites/components/List/List.d.ts.map +1 -1
  73. package/favorites/components/List/List.js +0 -1
  74. package/favorites/components/List/ListContent.js +4 -5
  75. package/favorites/components/Lists/Lists.js +4 -5
  76. package/filter/components/FilterPageContent/components/ApplyButton/index.js +8 -10
  77. package/filter/components/FilterPageContent/components/ResetButton/index.js +8 -6
  78. package/locations/components/ChangeLocationButton/ChangeLocationButton.js +10 -14
  79. package/locations/components/FulfillmentSlotSwitcher/FulfillmentSlotDialog.js +4 -8
  80. package/locations/components/FulfillmentSlotSwitcher/FulfillmentSlotSwitcher.js +1 -1
  81. package/locations/components/FulfillmentSlotSwitcher/FulfillmentSlotSwitcherBar.js +8 -13
  82. package/locations/components/FulfillmentSlotSwitcher/FulfillmentSlotSwitcherDefault.js +10 -10
  83. package/locations/components/GlobalLocationSwitcher/GlobalLocationSwitcherBar.js +8 -14
  84. package/locations/components/GlobalLocationSwitcher/GlobalLocationSwitcherDefault.js +9 -10
  85. package/locations/components/ReserveForm/ReserveForm.js +6 -7
  86. package/locations/components/StoreDetails/components/GetDirectionsButton.js +2 -4
  87. package/locations/components/StoreDetails/components/StoreDetails.js +5 -10
  88. package/locations/components/StoreDetails/components/StoresNearbyListItem.js +13 -21
  89. package/locations/components/StoreFinder/StoreFinderSelectLocationButton.js +5 -11
  90. package/locations/components/StoreFinder/StoreFinderStoreInfoButton.js +5 -11
  91. package/locations/components/StoreList/StoreListSearch.js +1 -0
  92. package/locations/components/StoreList/StoreSelectLocationButton.js +5 -11
  93. package/login/components/ForgotPassword/ForgotPassword.js +11 -23
  94. package/orders/components/OrderDetails/OrderDetailsAuthenticate.js +5 -7
  95. package/package.json +7 -7
  96. package/page/components/NotFound.d.ts.map +1 -1
  97. package/page/components/NotFound.js +7 -6
  98. package/page/components/ResponsiveWidgetImage/ResponsiveWidgetImage.d.ts +1 -1
  99. package/page/components/ResponsiveWidgetImage/ResponsiveWidgetImage.js +2 -2
  100. package/page/components/WidgetVideo/WidgetVideo.d.ts +1 -1
  101. package/page/components/WidgetVideo/WidgetVideo.d.ts.map +1 -1
  102. package/page/helpers/index.d.ts +5 -2
  103. package/page/helpers/index.d.ts.map +1 -1
  104. package/page/helpers/index.js +8 -5
  105. package/page/widgets/Button/Button.js +2 -3
  106. package/page/widgets/NestedCategoryFilter/NestedCategoryFilter.js +8 -8
  107. package/page/widgets/ProductList/ProductList.js +18 -14
  108. package/page/widgets/Video/hooks.d.ts +2 -2
  109. package/product/components/ProductCard/index.js +7 -1
  110. package/product/components/ProductGrid/components/Item/components/ItemDetails/index.js +6 -1
  111. package/product/components/ProductGrid/components/Item/components/ItemImage/index.js +1 -11
  112. package/product/components/ProductGrid/components/Item/index.js +3 -2
  113. package/product/components/ProductGrid/components/Layout/index.js +2 -1
  114. package/product/components/ProductGridPrice/index.js +0 -1
  115. package/product/components/ProductImage/ProductImage.d.ts.map +1 -1
  116. package/product/components/ProductImage/ProductImage.js +7 -2
  117. package/product/components/ProductImage/ProductImagePlaceholder.js +3 -3
  118. package/product/components/ProductSlider/index.js +1 -1
  119. package/product/components/UnitQuantityPicker/UnitQuantityPicker.d.ts.map +1 -1
  120. package/product/components/UnitQuantityPicker/UnitQuantityPicker.js +15 -33
  121. package/push-opt-in/components/PushOptInModal/index.js +4 -4
  122. package/registration/components/Registration/RegistrationFormActions.js +4 -4
  123. package/reviews/components/Reviews/components/AllReviewsLink/index.js +6 -6
  124. package/reviews/components/Reviews/components/Header/components/WriteReviewLink/index.js +4 -3
  125. package/reviews/components/Reviews/components/Header/components/WriteReviewLink/spec.js +28 -22
  126. package/reviews/components/Reviews/spec.js +5 -6
  127. package/settings/reducers/appSettings.d.ts.map +1 -1
  128. package/settings/reducers/appSettings.js +18 -2
  129. package/settings/selectors/appSettings.d.ts +37 -2
  130. package/settings/selectors/appSettings.d.ts.map +1 -1
  131. package/settings/selectors/appSettings.js +30 -1
  132. package/settings/types/appSettings.d.ts +42 -2
  133. package/settings/types/appSettings.d.ts.map +1 -1
  134. package/settings/types/appSettings.js +124 -1
  135. package/styles/helpers/index.d.ts +1 -0
  136. package/styles/helpers/index.js +1 -0
  137. package/styles/helpers/loadFontCss.d.ts +22 -0
  138. package/styles/helpers/loadFontCss.d.ts.map +1 -0
  139. package/styles/helpers/loadFontCss.js +138 -0
  140. package/styles/helpers/loadThemeCss.d.ts.map +1 -1
  141. package/styles/helpers/loadThemeCss.js +11 -0
  142. package/styles/index.d.ts +1 -1
  143. package/styles/index.d.ts.map +1 -1
  144. package/styles/theme/createDefaultThemeOptions/index.d.ts.map +1 -1
  145. package/styles/theme/createDefaultThemeOptions/index.js +94 -3
  146. package/styles/theme/createTheme/createComponents.types.d.ts +25 -0
  147. package/styles/theme/createTheme/createComponents.types.d.ts.map +1 -1
  148. package/styles/theme/createTheme/createComponents.types.js +28 -3
  149. package/styles/theme/createTheme/createShape.d.ts +2 -3
  150. package/styles/theme/createTheme/createShape.d.ts.map +1 -1
  151. package/styles/theme/createTheme/createShape.js +1 -2
  152. package/styles/theme/createTheme/createThemeFromColorScheme.d.ts +3 -1
  153. package/styles/theme/createTheme/createThemeFromColorScheme.d.ts.map +1 -1
  154. package/styles/theme/createTheme/createThemeFromColorScheme.js +4 -2
  155. package/styles/theme/createTheme/createTypography.d.ts +2 -1
  156. package/styles/theme/createTheme/createTypography.js +58 -18
  157. package/styles/theme/createTheme/index.d.ts +2 -2
  158. package/styles/theme/createTheme/index.d.ts.map +1 -1
  159. package/styles/theme/createTheme/index.js +2 -2
  160. package/styles/theme/createTheme/types.d.ts +9 -2
  161. package/styles/theme/createTheme/types.d.ts.map +1 -1
  162. package/styles/theme/createTheme/types.js +6 -0
  163. package/styles/theme/hooks/useColorScheme.d.ts +2 -2
  164. package/styles/theme/hooks/useColorScheme.d.ts.map +1 -1
  165. package/styles/theme/hooks/useColorScheme.js +1 -1
  166. package/styles/theme/hooks/useMediaQuery.d.ts +7 -0
  167. package/styles/theme/hooks/useMediaQuery.d.ts.map +1 -1
  168. package/styles/theme/hooks/useMediaQuery.js +5 -5
  169. package/styles/theme/hooks/useTheme.js +1 -1
  170. package/styles/theme/index.d.ts +3 -1
  171. package/styles/theme/index.d.ts.map +1 -1
  172. package/styles/theme/providers/ColorSchemeContext.d.ts +30 -9
  173. package/styles/theme/providers/ColorSchemeContext.d.ts.map +1 -1
  174. package/styles/theme/providers/ColorSchemeContext.js +8 -0
  175. package/styles/theme/providers/ThemeContext.d.ts +3 -0
  176. package/styles/theme/providers/ThemeContext.d.ts.map +1 -0
  177. package/styles/theme/providers/ThemeContext.js +2 -0
  178. package/styles/theme/providers/ThemeProvider.d.ts +2 -2
  179. package/styles/theme/providers/ThemeProvider.d.ts.map +1 -1
  180. package/styles/theme/providers/ThemeProvider.js +58 -16
  181. package/styles/theme/utils/color.d.ts +12 -12
  182. package/styles/theme/utils/color.d.ts.map +1 -1
  183. package/tracking/components/CookieConsentModal/index.js +3 -4
  184. package/tracking/components/PrivacySettings/index.js +3 -3
  185. package/cart/components/PaymentBar/PaymentBarReserveButton.connector.js +0 -6
  186. package/cart/components/PaymentBar/PaymentBarReserveButton.js +0 -71
  187. package/locations/components/StoreFinder/StoreFinderGetDirectionsButton.connector.js +0 -16
  188. package/locations/components/StoreFinder/StoreFinderGetDirectionsButton.js +0 -52
@@ -1,10 +1,5 @@
1
1
  import React from 'react';
2
- /**
3
- * The ButtonBase component serves as a foundational button element that can be extended with
4
- * additional styles and functionality. It handles basic button behavior, including disabled
5
- * state and type validation.
6
- */
7
- declare const ButtonBase: React.ForwardRefExoticComponent<ButtonBaseOwnProps & React.ButtonHTMLAttributes<HTMLButtonElement> & React.RefAttributes<HTMLButtonElement>>;
2
+ import type { NavigationState } from '@shopgate/engage/core/router/helpers';
8
3
  declare const useStyles: (params: void, muiStyleOverridesParams?: {
9
4
  props: Record<string, unknown>;
10
5
  ownerState?: Record<string, unknown> | undefined;
@@ -14,9 +9,41 @@ declare const useStyles: (params: void, muiStyleOverridesParams?: {
14
9
  css: import("tss-react").Css;
15
10
  cx: import("tss-react").Cx;
16
11
  };
17
- export interface ButtonBaseOwnProps {
12
+ export interface LinkOptions {
18
13
  /**
19
- * If true, the button will be disabled and not respond to user interactions.
14
+ * Meta state to attach to the target route.
15
+ */
16
+ state?: NavigationState;
17
+ /**
18
+ * Where to open the target, e.g. `_blank`. Read by the router when the target is an external
19
+ * or a native link.
20
+ */
21
+ target?: string;
22
+ /**
23
+ * If true, the current route is replaced instead of a new one being pushed.
24
+ * @default false
25
+ */
26
+ replace?: boolean;
27
+ }
28
+ export interface ButtonBaseOwnProps<C extends React.ElementType = 'button'> {
29
+ /**
30
+ * The element or component rendered as the root node. Defaults to `button`, or to `a` on web
31
+ * builds when `href` is set. Note that a non focusable element (e.g. `div`) needs its own
32
+ * `tabIndex` to stay keyboard operable.
33
+ */
34
+ component?: C;
35
+ /**
36
+ * Renders the button as a link to this path. Navigation goes through the app router rather than
37
+ * the browser, so external and native URLs are handled as well.
38
+ */
39
+ href?: string;
40
+ /**
41
+ * Navigation options. Only meaningful together with `href`.
42
+ */
43
+ linkOptions?: LinkOptions;
44
+ /**
45
+ * If true, the button will be disabled and not respond to user interactions. Rendered as the
46
+ * native attribute on a button, and as `aria-disabled` on any other element.
20
47
  * @default false
21
48
  */
22
49
  disabled?: boolean;
@@ -25,16 +52,29 @@ export interface ButtonBaseOwnProps {
25
52
  * @default false
26
53
  */
27
54
  disableRipple?: boolean;
55
+ /**
56
+ * If true, the `engage__button-base` css hook is not rendered. Set by wrappers that provide a
57
+ * hook of their own, such as `Button`.
58
+ * @default false
59
+ */
60
+ disableBaseClassName?: boolean;
28
61
  /**
29
62
  * Custom class name for the button.
30
63
  */
31
64
  className?: string;
65
+ /**
66
+ * Value for the `data-test-id` attribute of the button.
67
+ */
68
+ testId?: string;
32
69
  /**
33
70
  * Override or extend the styles applied to the component.
34
71
  */
35
72
  classes?: Partial<ReturnType<typeof useStyles>['classes']>;
36
73
  children: React.ReactNode;
37
74
  }
38
- export type ButtonBaseProps = ButtonBaseOwnProps & React.ButtonHTMLAttributes<HTMLButtonElement>;
39
- export default ButtonBase;
75
+ export type ButtonBaseProps<C extends React.ElementType = 'button'> = ButtonBaseOwnProps<C> & Omit<React.ComponentPropsWithRef<C>, keyof ButtonBaseOwnProps<C>>;
76
+ declare const _default: <C extends React.ElementType = "button">(props: ButtonBaseProps<C> & {
77
+ ref?: React.ComponentPropsWithRef<C>["ref"];
78
+ }) => React.ReactElement | null;
79
+ export default _default;
40
80
  //# sourceMappingURL=ButtonBase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonBase.d.ts","sourceRoot":"","sources":["../../../../components/v2/ButtonBase/ButtonBase.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAQ1C;;;;GAIG;AACH,QAAA,MAAM,UAAU,8IAsEd,CAAC;AAEH,QAAA,MAAM,SAAS;;cAyCP,CAAC;;;;;;CAVP,CAAC;AAEH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,eAAe,GAAG,kBAAkB,GAAG,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;AAEjG,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ButtonBase.d.ts","sourceRoot":"","sources":["../../../../components/v2/ButtonBase/ButtonBase.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAOrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AA0Q5E,QAAA,MAAM,SAAS;;cArLJ,CAAC;;;;;;CAuNV,CAAC;AAEH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,KAAK,CAAC,WAAW,GAAG,QAAQ;IACxE;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,KAAK,CAAC,WAAW,GAAG,QAAQ,IAChE,kBAAkB,CAAC,CAAC,CAAC,GACrB,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,MAAM,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;wBAQhC,CAAC,CAAC,SAAS,KAAK,CAAC,WAAW,GAAG,QAAQ,EACzE,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;CAAE,KACxE,KAAK,CAAC,YAAY,GAAG,IAAI;AAF9B,wBAE+B"}
@@ -1,87 +1,254 @@
1
1
  import "core-js/modules/es.array.includes.js";
2
- import React, { forwardRef } from 'react';
2
+ import "core-js/modules/es.string.replace.js";
3
+ import React, { forwardRef, useEffect } from 'react';
3
4
  import { makeStyles } from '@shopgate/engage/styles';
4
5
  import { useReduceMotion } from '@shopgate/engage/a11y/hooks';
6
+ // Imported from the defining modules instead of the `core` barrels on purpose: `core/hooks` imports
7
+ // from `engage/components`, so going through a barrel would create a circular import.
8
+ import { useNavigation } from '@shopgate/engage/core/hooks/useNavigation';
9
+ import { hasWebBridge } from '@shopgate/engage/core/helpers/bridge';
5
10
  import Ripple from "./Ripple";
6
11
  import { usePressRipple } from "./hooks";
7
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
13
  const supportedButtonTypes = ['button', 'submit', 'reset'];
9
14
 
15
+ /**
16
+ * Whether a pointer position sits within the bounds of an element.
17
+ * @param element The element to measure.
18
+ * @param clientX Horizontal position of the pointer.
19
+ * @param clientY Vertical position of the pointer.
20
+ * @returns Whether the position is inside the element.
21
+ */
22
+ const containsPoint = (element, clientX, clientY) => {
23
+ const {
24
+ top,
25
+ right,
26
+ bottom,
27
+ left
28
+ } = element.getBoundingClientRect();
29
+ return clientX >= left && clientX <= right && clientY >= top && clientY <= bottom;
30
+ };
31
+
32
+ /**
33
+ * Props read off the resolved element rather than declared on `ButtonBaseOwnProps`. Typed loosely
34
+ * because the element type is generic - `React.ComponentPropsWithRef<C>` keeps consumers exact.
35
+ */
36
+
10
37
  /**
11
38
  * The ButtonBase component serves as a foundational button element that can be extended with
12
39
  * additional styles and functionality. It handles basic button behavior, including disabled
13
40
  * state and type validation.
14
41
  */
15
- const ButtonBase = /*#__PURE__*/forwardRef((props, ref) => {
42
+ function ButtonBase(props, ref) {
16
43
  const {
44
+ component,
45
+ href,
46
+ linkOptions,
17
47
  disabled = false,
18
48
  disableRipple: disableRippleProp = false,
49
+ disableBaseClassName = false,
50
+ className,
51
+ classes: classesProp,
52
+ testId,
53
+ children,
54
+ ...rest
55
+ } = props;
56
+ const {
19
57
  type = 'button',
58
+ onClick,
59
+ onKeyDown,
20
60
  onPointerDown,
21
61
  onPointerUp,
22
62
  onPointerLeave,
23
63
  onPointerCancel,
24
- className,
25
- children,
26
64
  ...other
27
- } = props;
65
+ } = rest;
28
66
  const {
29
67
  classes,
30
68
  cx
31
69
  } = useStyles(undefined, {
32
70
  props: {
33
- classes: props.classes
71
+ classes: classesProp
34
72
  }
35
73
  });
36
74
  const {
37
75
  ripples,
38
76
  start,
39
- end
77
+ end,
78
+ clearAll
40
79
  } = usePressRipple();
41
80
  const reduceMotion = useReduceMotion();
81
+ const {
82
+ push,
83
+ replace
84
+ } = useNavigation();
42
85
  const disableRipple = disableRippleProp || reduceMotion;
86
+
87
+ // A button that disables itself on click gets `pointer-events: none`, which makes the browser
88
+ // drop the pointer capture. The pointer up then lands somewhere else and the ripple would never
89
+ // be told to finish, so it's cleared here instead.
90
+ useEffect(() => {
91
+ if (disabled) {
92
+ clearAll();
93
+ }
94
+ }, [disabled, clearAll]);
95
+
96
+ // A real anchor is only safe on web builds. Inside the app webview `preventDefault()` sometimes
97
+ // fails and the page navigates for real, so link buttons stay `<button>` there.
98
+ const Component = component || (href && hasWebBridge() ? 'a' : 'button');
99
+ const isButtonElement = Component === 'button';
100
+
101
+ /**
102
+ * Hands the target over to the app router. Deferred like the `Link` component does, so the
103
+ * current event finishes dispatching before the route changes.
104
+ */
105
+ const navigate = () => {
106
+ if (!href) {
107
+ return;
108
+ }
109
+ const state = {
110
+ ...linkOptions?.state,
111
+ ...(linkOptions?.target ? {
112
+ target: linkOptions.target
113
+ } : {})
114
+ };
115
+ const params = {
116
+ pathname: href,
117
+ ...(Object.keys(state).length ? {
118
+ state
119
+ } : {})
120
+ };
121
+ setTimeout(() => {
122
+ if (linkOptions?.replace) {
123
+ replace(params);
124
+ } else {
125
+ push(params);
126
+ }
127
+ }, 0);
128
+ };
129
+ const handleClick = event => {
130
+ if (disabled) {
131
+ event.preventDefault();
132
+ return;
133
+ }
134
+
135
+ // The pointer capture taken on pointer down redirects the release to this element, so a pointer
136
+ // that went up somewhere else still arrives here as a click. Without the capture the browser
137
+ // would have dropped it. Keyboard activation reports no button presses and carries no position,
138
+ // so it never takes this path.
139
+ if (event.detail > 0 && !containsPoint(event.currentTarget, event.clientX, event.clientY)) {
140
+ event.preventDefault();
141
+ return;
142
+ }
143
+ onClick?.(event);
144
+ if (!href || event.defaultPrevented) {
145
+ return;
146
+ }
147
+ event.preventDefault();
148
+ navigate();
149
+ };
150
+ const handleKeyDown = event => {
151
+ onKeyDown?.(event);
152
+ if (isButtonElement || disabled || event.defaultPrevented) {
153
+ return;
154
+ }
155
+ if (event.key !== 'Enter' && event.key !== ' ') {
156
+ return;
157
+ }
158
+
159
+ // Only buttons activate on Enter and Space. Preventing the default also stops an anchor from
160
+ // firing its own click on Enter, so the element is activated exactly once.
161
+ event.preventDefault();
162
+ event.currentTarget.click();
163
+ };
43
164
  const handlePointerDown = event => {
44
- if (!disabled && !disableRipple) {
165
+ if (disabled) {
166
+ return;
167
+ }
168
+ if (!disableRipple) {
45
169
  event.currentTarget.setPointerCapture?.(event.pointerId);
46
170
  start(event);
47
171
  }
48
172
  onPointerDown?.(event);
49
173
  };
174
+
175
+ /**
176
+ * Gives up pointer capture that was taken on pointer down. While an element captures the pointer,
177
+ * hit testing is redirected to it, so it keeps matching `:hover` and never receives a leave event.
178
+ * @param event The pointer event.
179
+ */
180
+ const releaseCapture = event => {
181
+ const target = event.currentTarget;
182
+ if (target.hasPointerCapture?.(event.pointerId)) {
183
+ target.releasePointerCapture(event.pointerId);
184
+ }
185
+ };
50
186
  const handlePointerUp = event => {
187
+ releaseCapture(event);
51
188
  if (!disableRipple) {
52
189
  end(event.pointerId);
53
190
  }
191
+ if (disabled) {
192
+ return;
193
+ }
54
194
  onPointerUp?.(event);
55
195
  };
56
196
  const handlePointerCancel = event => {
197
+ releaseCapture(event);
57
198
  if (!disableRipple) {
58
199
  end(event.pointerId);
59
200
  }
201
+ if (disabled) {
202
+ return;
203
+ }
60
204
  onPointerCancel?.(event);
61
205
  };
206
+
207
+ /**
208
+ * Fires whenever the capture taken on pointer down ends - including when the browser drops it
209
+ * because the element stopped being hit testable. Without this the ripple would stay behind.
210
+ * @param event The pointer event.
211
+ */
212
+ const handleLostPointerCapture = event => {
213
+ if (!disableRipple) {
214
+ end(event.pointerId);
215
+ }
216
+ };
62
217
  const handlePointerLeave = event => {
63
218
  if (!disableRipple && event.buttons === 1) {
64
219
  end(event.pointerId);
65
220
  }
221
+ if (disabled) {
222
+ return;
223
+ }
66
224
  onPointerLeave?.(event);
67
225
  };
68
- return /*#__PURE__*/_jsxs("button", {
226
+ return /*#__PURE__*/_jsxs(Component, {
69
227
  ref: ref,
70
- className: cx(classes.root, className),
71
- disabled: disabled,
228
+ "data-test-id": testId,
229
+ className: cx(classes.root, !disableBaseClassName && 'engage__button-base', className),
230
+ onClick: handleClick,
231
+ onKeyDown: handleKeyDown,
72
232
  onPointerDown: handlePointerDown,
73
233
  onPointerUp: handlePointerUp,
74
234
  onPointerCancel: handlePointerCancel,
75
- onPointerLeave: handlePointerLeave
76
- // eslint-disable-next-line react/button-has-type
77
- ,
78
- type: supportedButtonTypes.includes(type) ? type : 'button',
235
+ onPointerLeave: handlePointerLeave,
236
+ onLostPointerCapture: handleLostPointerCapture,
237
+ ...(isButtonElement ? {
238
+ disabled,
239
+ type: supportedButtonTypes.includes(type) ? type : 'button'
240
+ } : {
241
+ 'aria-disabled': disabled || undefined,
242
+ ...(href ? {
243
+ href
244
+ } : {})
245
+ }),
79
246
  ...other,
80
247
  children: [children, !disableRipple && /*#__PURE__*/_jsx(Ripple, {
81
248
  ripples: ripples
82
249
  })]
83
250
  });
84
- });
251
+ }
85
252
  const useStyles = makeStyles({
86
253
  name: 'ButtonBase'
87
254
  })({
@@ -109,9 +276,17 @@ const useStyles = makeStyles({
109
276
  borderStyle: 'none'
110
277
  },
111
278
  '&:disabled': {
279
+ cursor: 'not-allowed'
280
+ },
281
+ '&[aria-disabled="true"]': {
112
282
  pointerEvents: 'none',
113
283
  cursor: 'default'
114
284
  }
115
285
  }
116
286
  });
117
- export default ButtonBase;
287
+ const ButtonBaseWithRef = /*#__PURE__*/forwardRef(ButtonBase);
288
+ ButtonBaseWithRef.displayName = 'ButtonBase';
289
+
290
+ // `forwardRef` erases the generic, so the call signature is restored with a cast. Same approach as
291
+ // the Typography component.
292
+ export default ButtonBaseWithRef;
@@ -1,6 +1,5 @@
1
1
  export interface RippleItem {
2
2
  key: number;
3
- pointerId: number;
4
3
  x: number;
5
4
  y: number;
6
5
  size: number;
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../../components/v2/ButtonBase/hooks.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc;;mBAKM,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC;qBA2B7B,MAAM;;EA0B3C"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../../components/v2/ButtonBase/hooks.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc;;mBAYM,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC;qBAqC7B,MAAM;;EA2C3C"}
@@ -1,4 +1,4 @@
1
- import { useCallback, useRef, useState } from 'react';
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { RIPPLE_MIN_VISIBLE_MS } from "./constants";
3
3
  /**
4
4
  * Manages the active ripple queue.
@@ -12,39 +12,63 @@ import { RIPPLE_MIN_VISIBLE_MS } from "./constants";
12
12
  export function usePressRipple() {
13
13
  const [ripples, setRipples] = useState([]);
14
14
  const nextKey = useRef(0);
15
- const startedAtByPointer = useRef(new Map());
15
+ const startedAtByKey = useRef(new Map());
16
+ const activeKeyByPointer = useRef(new Map());
17
+ const pendingTimeouts = useRef(new Set());
18
+ useEffect(() => () => {
19
+ pendingTimeouts.current.forEach(timeoutId => window.clearTimeout(timeoutId));
20
+ pendingTimeouts.current.clear();
21
+ }, []);
16
22
  const start = useCallback(event => {
17
23
  const element = event.currentTarget;
18
24
  const rect = element.getBoundingClientRect();
19
- const rippleX = Math.round(event.clientX - rect.left);
20
- const rippleY = Math.round(event.clientY - rect.top);
25
+ const hasPointerPosition = Number.isFinite(event.clientX) && Number.isFinite(event.clientY);
26
+ const rippleX = hasPointerPosition ? Math.round(event.clientX - rect.left) : Math.round(element.clientWidth / 2);
27
+ const rippleY = hasPointerPosition ? Math.round(event.clientY - rect.top) : Math.round(element.clientHeight / 2);
21
28
  const sizeX = Math.max(element.clientWidth - rippleX, rippleX) * 2 + 2;
22
29
  const sizeY = Math.max(element.clientHeight - rippleY, rippleY) * 2 + 2;
23
30
  const rippleSize = Math.sqrt(sizeX ** 2 + sizeY ** 2);
24
- startedAtByPointer.current.set(event.pointerId, performance.now());
25
31
  nextKey.current += 1;
32
+ const key = nextKey.current;
33
+ startedAtByKey.current.set(key, performance.now());
34
+
35
+ // A mouse reuses one pointerId for every press, so the pointer only ever points at the newest
36
+ // one. Keying the rest by ripple instead means an earlier press can no longer end this one.
37
+ activeKeyByPointer.current.set(event.pointerId, key);
26
38
  setRipples(prev => [].concat(prev, [{
27
- key: nextKey.current,
28
- pointerId: event.pointerId,
39
+ key,
29
40
  x: rippleX,
30
41
  y: rippleY,
31
42
  size: rippleSize
32
43
  }]));
33
44
  }, []);
34
45
  const end = useCallback(pointerId => {
35
- const startedAt = startedAtByPointer.current.get(pointerId);
46
+ const key = activeKeyByPointer.current.get(pointerId);
47
+ if (key == null) {
48
+ return;
49
+ }
50
+
51
+ // Pointer up, cancel, leave and lost capture can all fire for a single press, and the press is
52
+ // over after whichever comes first.
53
+ activeKeyByPointer.current.delete(pointerId);
54
+ const startedAt = startedAtByKey.current.get(key);
36
55
  if (startedAt == null) {
37
56
  return;
38
57
  }
39
58
  const elapsed = performance.now() - startedAt;
40
59
  const delay = Math.max(0, RIPPLE_MIN_VISIBLE_MS - elapsed);
41
- window.setTimeout(() => {
42
- setRipples(prev => prev.filter(ripple => ripple.pointerId !== pointerId));
43
- startedAtByPointer.current.delete(pointerId);
60
+ const timeoutId = window.setTimeout(() => {
61
+ pendingTimeouts.current.delete(timeoutId);
62
+ setRipples(prev => prev.filter(ripple => ripple.key !== key));
63
+ startedAtByKey.current.delete(key);
44
64
  }, delay);
65
+ pendingTimeouts.current.add(timeoutId);
45
66
  }, []);
46
67
  const clearAll = useCallback(() => {
47
- startedAtByPointer.current.clear();
68
+ pendingTimeouts.current.forEach(timeoutId => window.clearTimeout(timeoutId));
69
+ pendingTimeouts.current.clear();
70
+ startedAtByKey.current.clear();
71
+ activeKeyByPointer.current.clear();
48
72
  setRipples([]);
49
73
  }, []);
50
74
  return {
@@ -8,7 +8,7 @@ declare const useStyles: (params: Omit<ButtonGroupOwnProps, "children">, muiStyl
8
8
  props: Record<string, unknown>;
9
9
  ownerState?: Record<string, unknown> | undefined;
10
10
  } | undefined) => {
11
- classes: Record<"root" | "disabled" | "contained" | "disableElevation" | "fullWidth" | "vertical" | "grouped" | "groupedHorizontal" | "groupedVertical" | "groupedContained" | "groupedContainedHorizontal" | "groupedContainedVertical" | "groupedOutlined" | "groupedOutlinedHorizontal" | "groupedOutlinedVertical" | "groupedText" | "groupedTextHorizontal" | "groupedTextVertical", string>;
11
+ classes: Record<"root" | "disabled" | "vertical" | "enableElevation" | "fullWidth" | "grouped" | "groupedHorizontal" | "groupedVertical" | "groupedContained" | "groupedContainedHorizontal" | "groupedContainedVertical" | "groupedOutlined" | "groupedOutlinedHorizontal" | "groupedOutlinedVertical" | "groupedText" | "groupedTextHorizontal" | "groupedTextVertical", string>;
12
12
  theme: import("@shopgate/engage/styles").Theme;
13
13
  css: import("tss-react").Css;
14
14
  cx: import("tss-react").Cx;
@@ -24,21 +24,27 @@ export interface ButtonGroupOwnProps {
24
24
  * @default 'medium'
25
25
  */
26
26
  size?: 'small' | 'medium' | 'large';
27
+ /**
28
+ * If true, the buttons use reduced padding.
29
+ * @default false
30
+ */
31
+ dense?: boolean;
27
32
  /**
28
33
  * The orientation of the buttons in the group.
29
34
  * @default 'horizontal'
30
35
  */
31
36
  orientation?: 'horizontal' | 'vertical';
32
37
  /**
33
- * If true, no elevation is used for contained buttons.
38
+ * If true, a drop shadow is added to the group. Button groups are flat by default.
34
39
  * @default false
35
40
  */
36
- disableElevation?: boolean;
41
+ enableElevation?: boolean;
37
42
  /**
38
- * The color of the component.
43
+ * The color of the component. Besides the palette colors, `cta` is supported. It resolves to the
44
+ * merchant configurable call to action color from `components.ctaButton`.
39
45
  * @default 'inherit'
40
46
  */
41
- color?: PaletteColorsWithMain | 'inherit';
47
+ color?: PaletteColorsWithMain | 'inherit' | 'cta';
42
48
  /**
43
49
  * If true, the buttons will take up the full width of their container.
44
50
  * @default false
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonGroup.d.ts","sourceRoot":"","sources":["../../../../components/v2/ButtonGroup/ButtonGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE;;GAEG;AACH,QAAA,MAAM,WAAW,mIA4Df,CAAC;AAEH,QAAA,MAAM,SAAS;;cAoDM,CAAA;;;;;;CAmFnB,CAAC;AAEH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;IAC5C;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC;;;OAGG;IACH,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC1C;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAA;AAEzF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"ButtonGroup.d.ts","sourceRoot":"","sources":["../../../../components/v2/ButtonGroup/ButtonGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE;;GAEG;AACH,QAAA,MAAM,WAAW,mIAsEf,CAAC;AAQH,QAAA,MAAM,SAAS;;cAyB8B,CAAC;;;;;;CAqH5C,CAAC;AAEH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;IAC5C;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,qBAAqB,GAAG,SAAS,GAAG,KAAK,CAAC;IAClD;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAA;AAIzF,eAAe,WAAW,CAAC"}