uikit-react-public 0.26.3 → 0.27.1

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 (24) hide show
  1. package/dist/components/BaseCheckbox/BaseCheckbox.d.ts +26 -0
  2. package/dist/components/BaseCheckbox/BaseCheckbox.stories.d.ts +29 -0
  3. package/dist/components/BaseCheckbox/__tests__/BaseCheckbox.test.d.ts +1 -0
  4. package/dist/components/BaseCheckbox/index.d.ts +2 -0
  5. package/dist/components/MenuNew/MenuAccordion/MenuAccordionItem.d.ts +2 -3
  6. package/dist/components/MenuNew/MenuBaseItem.d.ts +2 -1
  7. package/dist/components/MenuNew/index.d.ts +1 -1
  8. package/dist/components/index.d.ts +2 -0
  9. package/dist/index.js +2865 -2776
  10. package/lib/components/BaseCheckbox/BaseCheckbox.stories.tsx +82 -0
  11. package/lib/components/BaseCheckbox/BaseCheckbox.tsx +168 -0
  12. package/lib/components/BaseCheckbox/__tests__/BaseCheckbox.test.tsx +98 -0
  13. package/lib/components/BaseCheckbox/index.ts +2 -0
  14. package/lib/components/Checkbox/Checkbox.tsx +49 -53
  15. package/lib/components/Checkbox/__tests__/__snapshots__/Checkbox.test.tsx.snap +66 -43
  16. package/lib/components/MenuNew/MenuAccordion/MenuAccordion.tsx +2 -1
  17. package/lib/components/MenuNew/MenuAccordion/MenuAccordionItem.tsx +7 -6
  18. package/lib/components/MenuNew/MenuBaseItem.tsx +17 -0
  19. package/lib/components/MenuNew/__tests__/Menu.test.tsx +64 -0
  20. package/lib/components/MenuNew/index.ts +1 -0
  21. package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +7 -2
  22. package/lib/components/Table/subcomponents/HeadCell/__tests__/__snapshots__/HeadCell.test.tsx.snap +7 -2
  23. package/lib/components/index.ts +3 -0
  24. package/package.json +1 -1
@@ -0,0 +1,82 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { useArgs } from '@storybook/preview-api';
3
+
4
+ import BaseCheckbox from './BaseCheckbox';
5
+ import Icon from '../Icon';
6
+
7
+ const meta = {
8
+ title: 'Components/BaseCheckbox',
9
+ component: BaseCheckbox,
10
+ parameters: {
11
+ layout: 'centered',
12
+ },
13
+ argTypes: {
14
+ checked: { control: { type: 'boolean' } },
15
+ indeterminate: { control: { type: 'boolean' } },
16
+ disabled: { control: { type: 'boolean' } },
17
+ },
18
+ } satisfies Meta<typeof BaseCheckbox>;
19
+
20
+ export default meta;
21
+ type Story = StoryObj<typeof meta>;
22
+
23
+ export const Default: Story = {
24
+ args: {
25
+ checked: false,
26
+ indeterminate: false,
27
+ uncheckedComponent: <Icon.Square size={32} />,
28
+ checkedComponent: <Icon.CheckSquare size={32} />,
29
+ indeterminateComponent: <Icon.MinusSquare size={32} />,
30
+ },
31
+ render: (args) => {
32
+ const [, updateArgs] = useArgs();
33
+
34
+ return (
35
+ <BaseCheckbox
36
+ {...args}
37
+ onChange={(ev) => updateArgs({ checked: ev.target.checked })}
38
+ />
39
+ );
40
+ },
41
+ };
42
+
43
+ export const RenderVisual: Story = {
44
+ args: {
45
+ checked: false,
46
+ indeterminate: false,
47
+ renderVisual: ({ checked, indeterminate }) => (
48
+ <Icon.Empty
49
+ size={32}
50
+ strokeLinecap='square'
51
+ strokeLinejoin='miter'
52
+ >
53
+ <rect
54
+ x='5'
55
+ y='5'
56
+ width='14'
57
+ height='14'
58
+ rx='2'
59
+ />
60
+ {indeterminate && (
61
+ <line
62
+ x1='9'
63
+ y1='16'
64
+ x2='23'
65
+ y2='16'
66
+ />
67
+ )}
68
+ {checked && <polyline points='23 11 14 20 10 16' />}
69
+ </Icon.Empty>
70
+ ),
71
+ },
72
+ render: (args) => {
73
+ const [, updateArgs] = useArgs();
74
+
75
+ return (
76
+ <BaseCheckbox
77
+ {...args}
78
+ onChange={(ev) => updateArgs({ checked: ev.target.checked })}
79
+ />
80
+ );
81
+ },
82
+ };
@@ -0,0 +1,168 @@
1
+ import {
2
+ ChangeEvent,
3
+ InputHTMLAttributes,
4
+ memo,
5
+ ReactNode,
6
+ Ref,
7
+ useCallback,
8
+ useEffect,
9
+ useRef,
10
+ useState,
11
+ } from 'react';
12
+ import { css, cx } from '@emotion/css';
13
+
14
+ export const NAME = 'ucl-uikit-base-checkbox';
15
+
16
+ export interface BaseCheckboxState {
17
+ checked: boolean;
18
+ indeterminate: boolean;
19
+ disabled: boolean;
20
+ }
21
+
22
+ interface BaseCheckboxBaseProps extends Omit<
23
+ InputHTMLAttributes<HTMLInputElement>,
24
+ 'type'
25
+ > {
26
+ indeterminate?: boolean;
27
+ testId?: string;
28
+ ref?: Ref<HTMLInputElement>;
29
+ }
30
+
31
+ type BaseCheckboxVisualProps =
32
+ | {
33
+ renderVisual: (state: BaseCheckboxState) => ReactNode;
34
+ checkedComponent?: never;
35
+ uncheckedComponent?: never;
36
+ indeterminateComponent?: never;
37
+ }
38
+ | {
39
+ renderVisual?: never;
40
+ checkedComponent: ReactNode;
41
+ uncheckedComponent: ReactNode;
42
+ indeterminateComponent?: ReactNode;
43
+ };
44
+
45
+ export type BaseCheckboxProps = BaseCheckboxBaseProps & BaseCheckboxVisualProps;
46
+
47
+ const BaseCheckbox = ({
48
+ renderVisual,
49
+ checkedComponent,
50
+ uncheckedComponent,
51
+ indeterminateComponent,
52
+ checked,
53
+ defaultChecked,
54
+ indeterminate = false,
55
+ disabled,
56
+ testId = NAME,
57
+ className,
58
+ onChange,
59
+ ref,
60
+ ...props
61
+ }: BaseCheckboxProps) => {
62
+ const inputRef = useRef<HTMLInputElement | null>(null);
63
+
64
+ const isControlled = checked !== undefined;
65
+ const [internalChecked, setInternalChecked] = useState(
66
+ defaultChecked ?? false
67
+ );
68
+ const displayedChecked = isControlled ? checked : internalChecked;
69
+
70
+ useEffect(() => {
71
+ if (inputRef.current) {
72
+ inputRef.current.indeterminate = indeterminate;
73
+ }
74
+ }, [indeterminate]);
75
+
76
+ const setRef = useCallback(
77
+ (node: HTMLInputElement | null) => {
78
+ inputRef.current = node;
79
+
80
+ if (typeof ref === 'function') {
81
+ ref(node);
82
+ } else if (ref) {
83
+ ref.current = node;
84
+ }
85
+ },
86
+ [ref]
87
+ );
88
+
89
+ const handleChange = (ev: ChangeEvent<HTMLInputElement>) => {
90
+ if (!isControlled) {
91
+ setInternalChecked(ev.target.checked);
92
+ }
93
+
94
+ onChange?.(ev);
95
+ };
96
+
97
+ const rootStyle = css`
98
+ position: relative;
99
+ display: inline-grid;
100
+ cursor: ${disabled ? 'not-allowed' : 'pointer'};
101
+ `;
102
+
103
+ const inputStyle = css`
104
+ position: absolute;
105
+ inset: 0;
106
+ width: 100%;
107
+ height: 100%;
108
+ margin: 0;
109
+ padding: 0;
110
+ border: 0;
111
+ opacity: 0;
112
+ cursor: inherit;
113
+ `;
114
+
115
+ const visualStyle = css`
116
+ grid-area: 1 / 1;
117
+ line-height: 0;
118
+ pointer-events: none;
119
+
120
+ input:focus-visible + & {
121
+ outline: 2px solid currentColor;
122
+ outline-offset: 2px;
123
+ }
124
+ `;
125
+
126
+ const style = cx(NAME, rootStyle, className);
127
+
128
+ const visualState = {
129
+ checked: displayedChecked,
130
+ indeterminate,
131
+ disabled: !!disabled,
132
+ };
133
+
134
+ const visual = renderVisual
135
+ ? renderVisual(visualState)
136
+ : indeterminate && indeterminateComponent
137
+ ? indeterminateComponent
138
+ : displayedChecked
139
+ ? checkedComponent
140
+ : uncheckedComponent;
141
+
142
+ return (
143
+ <span
144
+ className={style}
145
+ data-testid={testId}
146
+ >
147
+ <input
148
+ ref={setRef}
149
+ type='checkbox'
150
+ className={inputStyle}
151
+ {...props}
152
+ checked={isControlled ? checked : undefined}
153
+ defaultChecked={isControlled ? undefined : defaultChecked}
154
+ disabled={disabled}
155
+ aria-checked={indeterminate ? 'mixed' : props['aria-checked']}
156
+ onChange={handleChange}
157
+ />
158
+ <span
159
+ className={visualStyle}
160
+ aria-hidden='true'
161
+ >
162
+ {visual}
163
+ </span>
164
+ </span>
165
+ );
166
+ };
167
+
168
+ export default memo(BaseCheckbox);
@@ -0,0 +1,98 @@
1
+ import { describe, expect, test, vi } from 'vitest';
2
+ import { render } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+
5
+ import BaseCheckbox from '../BaseCheckbox';
6
+
7
+ describe('BaseCheckbox', () => {
8
+ test('renders the unchecked visual by default', () => {
9
+ const { getByText, queryByText } = render(
10
+ <BaseCheckbox
11
+ uncheckedComponent={<span>Unchecked</span>}
12
+ checkedComponent={<span>Checked</span>}
13
+ />
14
+ );
15
+
16
+ expect(getByText('Unchecked')).toBeTruthy();
17
+ expect(queryByText('Checked')).toBeNull();
18
+ });
19
+
20
+ test('renders the checked visual when checked', () => {
21
+ const { getByText, queryByText } = render(
22
+ <BaseCheckbox
23
+ checked
24
+ uncheckedComponent={<span>Unchecked</span>}
25
+ checkedComponent={<span>Checked</span>}
26
+ />
27
+ );
28
+
29
+ expect(getByText('Checked')).toBeTruthy();
30
+ expect(queryByText('Unchecked')).toBeNull();
31
+ });
32
+
33
+ test('renders the indeterminate visual when indeterminate', () => {
34
+ const { getByRole, getByText } = render(
35
+ <BaseCheckbox
36
+ checked
37
+ indeterminate
38
+ uncheckedComponent={<span>Unchecked</span>}
39
+ checkedComponent={<span>Checked</span>}
40
+ indeterminateComponent={<span>Indeterminate</span>}
41
+ />
42
+ );
43
+
44
+ expect(getByText('Indeterminate')).toBeTruthy();
45
+ expect(getByRole('checkbox')).toHaveAttribute('aria-checked', 'mixed');
46
+ });
47
+
48
+ test('updates uncontrolled state when clicked', async () => {
49
+ const user = userEvent.setup();
50
+ const { getByRole, getByText } = render(
51
+ <BaseCheckbox
52
+ uncheckedComponent={<span>Unchecked</span>}
53
+ checkedComponent={<span>Checked</span>}
54
+ />
55
+ );
56
+
57
+ await user.click(getByRole('checkbox'));
58
+
59
+ expect(getByText('Checked')).toBeTruthy();
60
+ });
61
+
62
+ test('calls onChange when clicked', async () => {
63
+ const user = userEvent.setup();
64
+ const onChange = vi.fn();
65
+ const { getByRole } = render(
66
+ <BaseCheckbox
67
+ uncheckedComponent={<span>Unchecked</span>}
68
+ checkedComponent={<span>Checked</span>}
69
+ onChange={onChange}
70
+ />
71
+ );
72
+
73
+ await user.click(getByRole('checkbox'));
74
+
75
+ expect(onChange).toHaveBeenCalledTimes(1);
76
+ });
77
+
78
+ test('passes state to renderVisual', async () => {
79
+ const user = userEvent.setup();
80
+ const { getByRole, getByText } = render(
81
+ <BaseCheckbox
82
+ renderVisual={({ checked, indeterminate, disabled }) => (
83
+ <span>
84
+ {checked ? 'Checked' : 'Unchecked'}
85
+ {indeterminate ? ' mixed' : ''}
86
+ {disabled ? ' disabled' : ''}
87
+ </span>
88
+ )}
89
+ />
90
+ );
91
+
92
+ expect(getByText('Unchecked')).toBeTruthy();
93
+
94
+ await user.click(getByRole('checkbox'));
95
+
96
+ expect(getByText('Checked')).toBeTruthy();
97
+ });
98
+ });
@@ -0,0 +1,2 @@
1
+ export { default } from './BaseCheckbox';
2
+ export type { BaseCheckboxProps, BaseCheckboxState } from './BaseCheckbox';
@@ -7,6 +7,7 @@ import {
7
7
  } from 'react';
8
8
  import { css, cx } from '@emotion/css';
9
9
  import useTheme from '../../theme/useTheme';
10
+ import BaseCheckbox from '../BaseCheckbox';
10
11
  import Icon from '../Icon';
11
12
  import marginsStyle, { MarginProps } from '../common/marginsStyle';
12
13
 
@@ -32,6 +33,7 @@ const Checkbox = forwardRef<Ref, CheckboxProps>(
32
33
  testId = NAME,
33
34
  ariaLabel,
34
35
  className,
36
+ onChange,
35
37
  ...props
36
38
  },
37
39
  ref
@@ -48,12 +50,11 @@ const Checkbox = forwardRef<Ref, CheckboxProps>(
48
50
  if (!isControlled) {
49
51
  setInternalChecked(ev.target.checked);
50
52
  }
51
- props.onChange?.(ev);
53
+ onChange?.(ev);
52
54
  };
53
55
 
54
56
  const baseStyle = css`
55
57
  position: relative;
56
- display: inline-block;
57
58
  width: 24px;
58
59
  height: 24px;
59
60
  flex-shrink: 0;
@@ -104,20 +105,6 @@ const Checkbox = forwardRef<Ref, CheckboxProps>(
104
105
  className
105
106
  );
106
107
 
107
- const hiddenInputStyle = css`
108
- cursor: inherit;
109
- position: absolute;
110
- opacity: 0;
111
- left: -1px;
112
- top: -1px;
113
- width: calc(100% + 2px);
114
- height: calc(100% + 2px);
115
- border-radius: 2px;
116
- border: none;
117
- margin: 0;
118
- padding: 0;
119
- `;
120
-
121
108
  const checkStyle = css`
122
109
  position: absolute;
123
110
  left: -1px;
@@ -135,43 +122,52 @@ const Checkbox = forwardRef<Ref, CheckboxProps>(
135
122
  `;
136
123
 
137
124
  return (
138
- <span className={style}>
139
- <input
140
- type='checkbox'
141
- ref={ref}
142
- className={hiddenInputStyle}
143
- data-testid={testId}
144
- aria-label={ariaLabel}
145
- {...(isControlled ? { checked } : { defaultChecked })}
146
- disabled={disabled}
147
- onChange={handleChange}
148
- {...props}
149
- />
150
- {!indeterminate && isChecked && (
151
- <Icon.Empty
152
- className={checkStyle}
153
- size={24}
154
- strokeLinecap='square'
155
- strokeLinejoin='miter'
156
- >
157
- <polyline points='17 9 10 16 7 13' />
158
- </Icon.Empty>
159
- )}
160
- {indeterminate && (
161
- <Icon.Empty
162
- className={indeterminateLineStyle}
163
- size={24}
164
- strokeLinecap='square'
165
- >
166
- <line
167
- x1='7'
168
- y1='12'
169
- x2='17'
170
- y2='12'
171
- />
172
- </Icon.Empty>
173
- )}
174
- </span>
125
+ <BaseCheckbox
126
+ ref={ref}
127
+ className={style}
128
+ testId={`${testId}__root`}
129
+ data-testid={testId}
130
+ aria-label={ariaLabel}
131
+ checked={isControlled ? checked : undefined}
132
+ defaultChecked={isControlled ? undefined : defaultChecked}
133
+ disabled={disabled}
134
+ indeterminate={indeterminate}
135
+ renderVisual={(state) => {
136
+ if (state.indeterminate) {
137
+ return (
138
+ <Icon.Empty
139
+ className={indeterminateLineStyle}
140
+ size={24}
141
+ strokeLinecap='square'
142
+ >
143
+ <line
144
+ x1='7'
145
+ y1='12'
146
+ x2='17'
147
+ y2='12'
148
+ />
149
+ </Icon.Empty>
150
+ );
151
+ }
152
+
153
+ if (state.checked) {
154
+ return (
155
+ <Icon.Empty
156
+ className={checkStyle}
157
+ size={24}
158
+ strokeLinecap='square'
159
+ strokeLinejoin='miter'
160
+ >
161
+ <polyline points='17 9 10 16 7 13' />
162
+ </Icon.Empty>
163
+ );
164
+ }
165
+
166
+ return null;
167
+ }}
168
+ onChange={handleChange}
169
+ {...props}
170
+ />
175
171
  );
176
172
  }
177
173
  );
@@ -2,86 +2,109 @@
2
2
 
3
3
  exports[`Checkbox > snapshot: checked prop 1`] = `
4
4
  <span
5
- class="ucl-uikit-checkbox css-xzd91z"
5
+ class="ucl-uikit-base-checkbox ucl-uikit-checkbox css-ohh0va"
6
+ data-testid="ucl-uikit-checkbox__root"
6
7
  >
7
8
  <input
8
9
  checked=""
9
- class="css-nzy7im"
10
+ class="css-1bjd9qx"
10
11
  data-testid="ucl-uikit-checkbox"
11
12
  type="checkbox"
12
13
  />
13
- <svg
14
- class="ucl-uikit-icon css-1nacdsu"
15
- data-testid="ucl-uikit-icon"
16
- fill="none"
17
- height="24"
18
- stroke="currentColor"
19
- stroke-linecap="square"
20
- stroke-linejoin="miter"
21
- stroke-width="2"
22
- viewBox="0 0 24 24"
23
- width="24"
24
- xmlns="http://www.w3.org/2000/svg"
14
+ <span
15
+ aria-hidden="true"
16
+ class="css-1quq9cp"
25
17
  >
26
- <polyline
27
- points="17 9 10 16 7 13"
28
- />
29
- </svg>
18
+ <svg
19
+ class="ucl-uikit-icon css-1nacdsu"
20
+ data-testid="ucl-uikit-icon"
21
+ fill="none"
22
+ height="24"
23
+ stroke="currentColor"
24
+ stroke-linecap="square"
25
+ stroke-linejoin="miter"
26
+ stroke-width="2"
27
+ viewBox="0 0 24 24"
28
+ width="24"
29
+ xmlns="http://www.w3.org/2000/svg"
30
+ >
31
+ <polyline
32
+ points="17 9 10 16 7 13"
33
+ />
34
+ </svg>
35
+ </span>
30
36
  </span>
31
37
  `;
32
38
 
33
39
  exports[`Checkbox > snapshot: indeterminate prop 1`] = `
34
40
  <span
35
- class="ucl-uikit-checkbox css-xzd91z"
41
+ class="ucl-uikit-base-checkbox ucl-uikit-checkbox css-ohh0va"
42
+ data-testid="ucl-uikit-checkbox__root"
36
43
  >
37
44
  <input
38
- class="css-nzy7im"
45
+ aria-checked="mixed"
46
+ class="css-1bjd9qx"
39
47
  data-testid="ucl-uikit-checkbox"
40
48
  type="checkbox"
41
49
  />
42
- <svg
43
- class="ucl-uikit-icon css-2i3jn5"
44
- data-testid="ucl-uikit-icon"
45
- fill="none"
46
- height="24"
47
- stroke="currentColor"
48
- stroke-linecap="square"
49
- stroke-linejoin="round"
50
- stroke-width="2"
51
- viewBox="0 0 24 24"
52
- width="24"
53
- xmlns="http://www.w3.org/2000/svg"
50
+ <span
51
+ aria-hidden="true"
52
+ class="css-1quq9cp"
54
53
  >
55
- <line
56
- x1="7"
57
- x2="17"
58
- y1="12"
59
- y2="12"
60
- />
61
- </svg>
54
+ <svg
55
+ class="ucl-uikit-icon css-2i3jn5"
56
+ data-testid="ucl-uikit-icon"
57
+ fill="none"
58
+ height="24"
59
+ stroke="currentColor"
60
+ stroke-linecap="square"
61
+ stroke-linejoin="round"
62
+ stroke-width="2"
63
+ viewBox="0 0 24 24"
64
+ width="24"
65
+ xmlns="http://www.w3.org/2000/svg"
66
+ >
67
+ <line
68
+ x1="7"
69
+ x2="17"
70
+ y1="12"
71
+ y2="12"
72
+ />
73
+ </svg>
74
+ </span>
62
75
  </span>
63
76
  `;
64
77
 
65
78
  exports[`Checkbox > snapshot: no props 1`] = `
66
79
  <span
67
- class="ucl-uikit-checkbox css-tumlz"
80
+ class="ucl-uikit-base-checkbox ucl-uikit-checkbox css-tfrbiv"
81
+ data-testid="ucl-uikit-checkbox__root"
68
82
  >
69
83
  <input
70
- class="css-nzy7im"
84
+ class="css-1bjd9qx"
71
85
  data-testid="ucl-uikit-checkbox"
72
86
  type="checkbox"
73
87
  />
88
+ <span
89
+ aria-hidden="true"
90
+ class="css-1quq9cp"
91
+ />
74
92
  </span>
75
93
  `;
76
94
 
77
95
  exports[`Checkbox > snapshot: testId prop 1`] = `
78
96
  <span
79
- class="ucl-uikit-checkbox css-tumlz"
97
+ class="ucl-uikit-base-checkbox ucl-uikit-checkbox css-tfrbiv"
98
+ data-testid="test123__root"
80
99
  >
81
100
  <input
82
- class="css-nzy7im"
101
+ class="css-1bjd9qx"
83
102
  data-testid="test123"
84
103
  type="checkbox"
85
104
  />
105
+ <span
106
+ aria-hidden="true"
107
+ class="css-1quq9cp"
108
+ />
86
109
  </span>
87
110
  `;
@@ -63,7 +63,8 @@ const MenuAccordion = ({
63
63
  const bodyStyle = css`
64
64
  display: grid;
65
65
  grid-template-rows: 0fr;
66
- width: 100%;
66
+ width: calc(100% + ${FOCUS_RING_GUTTER_PX * 2}px);
67
+ margin-left: -${FOCUS_RING_GUTTER_PX}px;
67
68
  margin-top: 0;
68
69
  overflow: hidden;
69
70
  opacity: 0;
@@ -1,14 +1,15 @@
1
- import { HTMLAttributes } from 'react';
2
1
  import { css, cx } from '@emotion/css';
3
- import MenuBaseItem from '../MenuBaseItem';
2
+ import MenuBaseItem, { MenuBaseItemProps } from '../MenuBaseItem';
4
3
  import MenuItemText from '../MenuItemText';
5
4
  import { useTheme } from '../../../theme';
6
5
 
7
6
  export const NAME = 'ucl-uikit-menu__accordion-item';
8
7
  const FOCUS_RING_GUTTER_PX = 6;
9
8
 
10
- export interface MenuAccordionItemProps extends HTMLAttributes<HTMLDivElement> {
11
- asChild?: boolean;
9
+ export interface MenuAccordionItemProps extends Omit<
10
+ MenuBaseItemProps,
11
+ 'iconPosition'
12
+ > {
12
13
  testId?: string;
13
14
  }
14
15
 
@@ -24,10 +25,10 @@ const MenuAccordionItem = ({
24
25
  const baseStyle = css`
25
26
  width: calc(100% - ${FOCUS_RING_GUTTER_PX * 2}px);
26
27
  margin: 0 ${FOCUS_RING_GUTTER_PX}px;
27
- padding-left: calc(${theme.padding.p40} - ${FOCUS_RING_GUTTER_PX}px);
28
+ padding-left: ${theme.padding.p40};
28
29
 
29
30
  @media screen and (min-width: ${theme.breakpoints.tablet}px) {
30
- padding: 0 calc(${theme.padding.p56} - ${FOCUS_RING_GUTTER_PX}px);
31
+ padding: 0 ${theme.padding.p56};
31
32
  }
32
33
  `;
33
34