@shopgate/pwa-ui-shared 7.32.0-beta.4 → 7.32.0-beta.6

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.
@@ -33,7 +33,8 @@ const PipelineErrorDialog = ({
33
33
  params,
34
34
  message
35
35
  }) => {
36
- const [devMode, setDevMode] = useState(false);
36
+ // May be opened directly in developer detail mode (e.g. via long-pressing an error toast).
37
+ const [devMode, setDevMode] = useState(!!params.openWithDetails);
37
38
  const tapTimeoutRef = useRef(null);
38
39
  const tapCounterRef = useRef(0);
39
40
  const handleTapTimeout = useCallback(() => {
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
2
  import { mount } from 'enzyme';
3
+ import { render, screen } from '@testing-library/react';
4
+ import '@testing-library/jest-dom';
3
5
  import PipelineErrorDialog from "./index";
4
6
  import { jsx as _jsx } from "react/jsx-runtime";
5
7
  jest.mock('@shopgate/engage/a11y/components');
@@ -51,6 +53,20 @@ describe('<PipelineErrorDialog />', () => {
51
53
  clickElement.simulate('click');
52
54
  expect(wrapper.text()).not.toContain(devMarker);
53
55
  });
56
+ it('should open directly in developer detail mode when params.openWithDetails is set', () => {
57
+ render(/*#__PURE__*/_jsx(PipelineErrorDialog, {
58
+ actions: [],
59
+ params: {
60
+ ...defaultParams,
61
+ openWithDetails: true
62
+ }
63
+ }));
64
+
65
+ // Developer detail view is shown immediately, without any tapping.
66
+ expect(screen.getByText('Pipeline:')).toBeInTheDocument();
67
+ expect(screen.getByText('Code:')).toBeInTheDocument();
68
+ expect(screen.getByText(/fakePipeline/)).toBeInTheDocument();
69
+ });
54
70
  it('should not switch modes if tapped too slow', () => {
55
71
  jest.useFakeTimers();
56
72
  const wrapper = mount(/*#__PURE__*/_jsx(PipelineErrorDialog, {
@@ -15,7 +15,7 @@ const ICON_SIZES = {
15
15
  const useStyles = makeStyles()(theme => ({
16
16
  container: {
17
17
  position: 'relative',
18
- display: 'inline-block',
18
+ display: 'inline-flex',
19
19
  verticalAlign: 'middle',
20
20
  maxWidth: '100%'
21
21
  },
@@ -43,6 +43,11 @@ const useStyles = makeStyles()(theme => ({
43
43
  position: 'absolute',
44
44
  left: 0,
45
45
  top: 0,
46
+ // Purely decorative overlay: let every pointer event fall through to the
47
+ // empty-star buttons underneath, which span all slots and handle selection.
48
+ // Without this, the invisible spacers/half-stars cover the higher-index
49
+ // buttons and swallow clicks in selectable mode.
50
+ pointerEvents: 'none',
46
51
  color: theme.components.ratingStars.filled,
47
52
  display: 'inline-flex',
48
53
  alignItems: 'center',
@@ -107,10 +112,10 @@ const RatingStars = ({
107
112
  const starProps = {
108
113
  className: iconClassName,
109
114
  key: numStars + pos,
115
+ // Decorative duplicate of the underlying empty-star button; hidden from
116
+ // assistive tech and non-interactive (the empty layer handles clicks).
110
117
  ...(isSelectable && {
111
- 'aria-hidden': true,
112
- role: 'button',
113
- onClick: e => handleSelection(e, pos)
118
+ 'aria-hidden': true
114
119
  })
115
120
  };
116
121
  return /*#__PURE__*/_jsx("div", {
@@ -124,7 +129,13 @@ const RatingStars = ({
124
129
  children: /*#__PURE__*/_jsx(StarHalfIcon, {
125
130
  size: size
126
131
  })
127
- }, i + numFullStars))), [iconClassName, numFullStars, numHalfStars, size, handleSelection, isSelectable]);
132
+ }, i + numFullStars)), times(Math.max(numStars - numFullStars - numHalfStars, 0), i => /*#__PURE__*/_jsx("div", {
133
+ className: iconClassName,
134
+ style: {
135
+ width: size
136
+ },
137
+ "aria-hidden": true
138
+ }, `placeholder-${i}`))), [iconClassName, numFullStars, numHalfStars, size, isSelectable]);
128
139
  return /*#__PURE__*/_jsxs("div", {
129
140
  role: isSelectable ? undefined : 'img',
130
141
  className: rootClassName,
@@ -49,34 +49,37 @@ describe('<RatingStars />', () => {
49
49
  expect(wrapper.find(StarHalfIcon).length).toBe(1);
50
50
  expect(wrapper).toMatchSnapshot();
51
51
  });
52
- it('should call onSelection callback when component is selectable', () => {
53
- const spy = jest.fn();
52
+ it('should call onSelection with the clicked rating in selectable mode', () => {
53
+ const selections = [];
54
54
  const wrapper = shallow(/*#__PURE__*/_jsx(RatingStars, {
55
- value: 100,
55
+ value: 20,
56
56
  isSelectable: true,
57
57
  onSelection: e => {
58
+ selections.push(e.target.value);
58
59
  wrapper.setProps({
59
60
  value: e.target.value
60
61
  });
61
- spy();
62
62
  }
63
63
  }), mockRenderOptions);
64
- // Click on 1 filled star.
65
- wrapper.find('[role="button"]').at(5).simulate('click', {
66
- target: {
67
- value: 10
68
- }
64
+
65
+ // Only the empty-star layer is interactive: one button per position, always five.
66
+ // The decorative filled overlay is pointer-transparent and carries no buttons.
67
+ expect(wrapper.find('[role="button"]').length).toBe(numEmptyStars);
68
+
69
+ // Regression: at a low rating the higher positions used to be covered by the
70
+ // filled layer's invisible placeholders, which swallowed the click. Clicking the
71
+ // 5th star must still raise the rating to the full 5 stars.
72
+ wrapper.find('[role="button"]').at(4).simulate('click', {
73
+ target: {}
69
74
  });
70
- expect(spy.mock.calls.length).toBe(1);
71
- expect(wrapper.find('[role="button"]').length).toBe(6);
72
- // Click on 4th empty star
73
- wrapper.find('[role="button"]').at(3).simulate('click', {
74
- target: {
75
- value: 80
76
- }
75
+ expect(selections).toEqual([100]);
76
+
77
+ // The interactive layer is unaffected by the rating; clicking the 1st star lowers it.
78
+ expect(wrapper.find('[role="button"]').length).toBe(numEmptyStars);
79
+ wrapper.find('[role="button"]').at(0).simulate('click', {
80
+ target: {}
77
81
  });
78
- expect(wrapper.find('[role="button"]').length).toBe(9);
79
- expect(spy.mock.calls.length).toBe(2);
82
+ expect(selections).toEqual([100, 20]);
80
83
  });
81
84
  it('should NOT call onSelection callback when component is NOT selectable', () => {
82
85
  const spy = jest.fn();
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@shopgate/pwa-ui-shared",
3
- "version": "7.32.0-beta.4",
3
+ "version": "7.32.0-beta.6",
4
4
  "description": "Shopgate's shared UI components.",
5
5
  "main": "index.js",
6
6
  "license": "Apache-2.0",
7
7
  "dependencies": {
8
- "@shopgate/pwa-ui-ios": "7.32.0-beta.4",
9
- "@shopgate/pwa-ui-material": "7.32.0-beta.4"
8
+ "@shopgate/pwa-ui-ios": "7.32.0-beta.6",
9
+ "@shopgate/pwa-ui-material": "7.32.0-beta.6"
10
10
  },
11
11
  "devDependencies": {
12
- "@shopgate/pwa-common": "7.32.0-beta.4",
13
- "@shopgate/pwa-common-commerce": "7.32.0-beta.4",
12
+ "@shopgate/pwa-common": "7.32.0-beta.6",
13
+ "@shopgate/pwa-common-commerce": "7.32.0-beta.6",
14
14
  "classnames": "2.5.1",
15
15
  "react": "^17.0.2"
16
16
  },