agroptima-design-system 1.2.38-beta.4 → 1.2.38
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.
- package/package.json +1 -1
- package/src/atoms/CheckboxWithDivider/CheckboxWithDivider.scss +18 -0
- package/src/atoms/CheckboxWithDivider/CheckboxWithDivider.tsx +31 -0
- package/src/atoms/CheckboxWithDivider/index.ts +4 -0
- package/src/atoms/Divider.scss +2 -7
- package/src/atoms/Divider.tsx +1 -1
- package/src/atoms/Modal/ModalDialog.tsx +3 -4
- package/src/generic/_helpers.scss +4 -0
- package/src/settings/_borders.scss +1 -0
- package/src/stories/Changelog.mdx +1 -2
- package/src/stories/CheckboxWithDivider.stories.tsx +48 -0
- package/src/stories/Modal.stories.tsx +1 -1
- package/tests/CheckboxWithDivider.spec.tsx +67 -0
- package/tests/Divider.spec.tsx +4 -4
- package/tests/Modal.spec.tsx +0 -84
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
@use '../../settings/typography/content' as typography;
|
|
2
|
+
@use '../../settings/borders';
|
|
3
|
+
@use '../../settings/config';
|
|
4
|
+
|
|
5
|
+
.checkbox-with-divider {
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
gap: config.$space-3x;
|
|
9
|
+
margin-bottom: config.$space-4x;
|
|
10
|
+
|
|
11
|
+
.form-label {
|
|
12
|
+
@include typography.body-bold;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.line {
|
|
16
|
+
border: borders.$divider-border-line;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import './CheckboxWithDivider.scss'
|
|
2
|
+
import type { CheckboxProps } from '../Checkbox'
|
|
3
|
+
import { Checkbox } from '../Checkbox'
|
|
4
|
+
|
|
5
|
+
export interface CheckboxWithDividerProps extends Omit<
|
|
6
|
+
CheckboxProps,
|
|
7
|
+
'checked'
|
|
8
|
+
> {
|
|
9
|
+
title: string
|
|
10
|
+
checked: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function CheckboxWithDivider({
|
|
14
|
+
title,
|
|
15
|
+
accessibilityLabel,
|
|
16
|
+
className,
|
|
17
|
+
...props
|
|
18
|
+
}: CheckboxWithDividerProps) {
|
|
19
|
+
return (
|
|
20
|
+
<div className="checkbox-with-divider">
|
|
21
|
+
<Checkbox
|
|
22
|
+
accessibilityLabel={accessibilityLabel || title}
|
|
23
|
+
className={className}
|
|
24
|
+
{...props}
|
|
25
|
+
>
|
|
26
|
+
{title}
|
|
27
|
+
</Checkbox>
|
|
28
|
+
<div className="flex-grow line" />
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
package/src/atoms/Divider.scss
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
@use '../settings/typography/content' as typography;
|
|
2
|
+
@use '../settings/borders';
|
|
2
3
|
@use '../settings/config';
|
|
3
4
|
@use '../settings/mixins';
|
|
4
5
|
|
|
5
|
-
$border-line: 1px solid var(--neutral-color-200);
|
|
6
|
-
|
|
7
6
|
.divider-container {
|
|
8
7
|
@include mixins.icon-color(var(--primary-color-600));
|
|
9
8
|
@include typography.body_bold;
|
|
@@ -27,11 +26,7 @@ $border-line: 1px solid var(--neutral-color-200);
|
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
.line {
|
|
30
|
-
border:
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.long {
|
|
34
|
-
flex: 1;
|
|
29
|
+
border: borders.$divider-border-line;
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
.icon {
|
package/src/atoms/Divider.tsx
CHANGED
|
@@ -4,8 +4,7 @@ import React, { useEffect, useRef } from 'react'
|
|
|
4
4
|
import { classNames } from '../../utils/classNames'
|
|
5
5
|
import type { Variant } from './Modal'
|
|
6
6
|
|
|
7
|
-
export interface ModalDialogProps
|
|
8
|
-
extends React.HTMLAttributes<HTMLDialogElement> {
|
|
7
|
+
export interface ModalDialogProps extends React.HTMLAttributes<HTMLDialogElement> {
|
|
9
8
|
isOpen?: boolean
|
|
10
9
|
onClose?: () => void
|
|
11
10
|
details?: boolean
|
|
@@ -30,12 +29,12 @@ export function ModalDialog({
|
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
useEffect(() => {
|
|
33
|
-
// if (!isOpen) return
|
|
34
|
-
|
|
35
32
|
keepScrollbarSpace()
|
|
33
|
+
window.addEventListener('resize', keepScrollbarSpace)
|
|
36
34
|
|
|
37
35
|
return () => {
|
|
38
36
|
removeScrollbarSpace()
|
|
37
|
+
window.removeEventListener('resize', keepScrollbarSpace)
|
|
39
38
|
}
|
|
40
39
|
}, [])
|
|
41
40
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$divider-border-line: 1px solid var(--neutral-color-200);
|
|
@@ -6,8 +6,7 @@ import { Meta } from "@storybook/addon-docs/blocks";
|
|
|
6
6
|
|
|
7
7
|
## 1.2.38
|
|
8
8
|
|
|
9
|
-
*
|
|
10
|
-
* Fix Modal scroll lock width flickering on window resize while open, caused by recalculating the scrollbar width after `overflow: hidden` had already removed it
|
|
9
|
+
* Add CheckboxWithDivider component
|
|
11
10
|
|
|
12
11
|
## 1.2.37
|
|
13
12
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { StoryObj } from '@storybook/nextjs'
|
|
2
|
+
import { CheckboxWithDivider } from '../atoms/CheckboxWithDivider'
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Design System/Atoms/CheckboxWithDivider',
|
|
6
|
+
component: CheckboxWithDivider,
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component:
|
|
11
|
+
'<h2>Usage guidelines</h2>' +
|
|
12
|
+
'<p>A CheckboxWithDivider combines a Checkbox with a divider line, used as a selectable group header (e.g. "select all" on a list of items).</p>',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
tags: ['autodocs', 'Layout components'],
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default meta
|
|
20
|
+
type Story = StoryObj<typeof meta>
|
|
21
|
+
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
title: '19/01/2025 - My gaming diary',
|
|
25
|
+
name: 'select-all',
|
|
26
|
+
checked: false,
|
|
27
|
+
onChange: () => console.log('change'),
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const Checked: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
title: '19/01/2025 - My gaming diary',
|
|
34
|
+
name: 'select-all',
|
|
35
|
+
checked: true,
|
|
36
|
+
onChange: () => console.log('change'),
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const Indeterminate: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
title: '19/01/2025 - My gaming diary',
|
|
43
|
+
name: 'select-all',
|
|
44
|
+
checked: true,
|
|
45
|
+
indeterminate: true,
|
|
46
|
+
onChange: () => console.log('change'),
|
|
47
|
+
},
|
|
48
|
+
}
|
|
@@ -37,7 +37,7 @@ const meta = {
|
|
|
37
37
|
' <li>Require a response from the user</li>' +
|
|
38
38
|
' <li>Notify the user of any related information</li>' +
|
|
39
39
|
' <li>Confirm a user decision</li>' +
|
|
40
|
-
" <li>It's opened/closed through `isOpen` prop
|
|
40
|
+
" <li>It's opened/closed through `isOpen` prop. If we don't want it to be part of the DOM, we can also add a conditional render on the frontend project.</li>" +
|
|
41
41
|
' <li>Natively, focus is set on the first nested focusable element and explicitly indicated by default by the browser</li>' +
|
|
42
42
|
" <li>When nesting a Form inside Modal component, remember to add `type='button'` to all Cancel buttons to not to be considered as submitable</li>" +
|
|
43
43
|
'</ul>',
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { render } from '@testing-library/react'
|
|
2
|
+
import userEvent from '@testing-library/user-event'
|
|
3
|
+
import { CheckboxWithDivider } from '../src/atoms/CheckboxWithDivider'
|
|
4
|
+
|
|
5
|
+
describe('CheckboxWithDivider', () => {
|
|
6
|
+
it('renders the title and a divider line', () => {
|
|
7
|
+
const { getByRole, getByText, container } = render(
|
|
8
|
+
<CheckboxWithDivider
|
|
9
|
+
title="19/01/2025 - My gaming diary"
|
|
10
|
+
name="select-all"
|
|
11
|
+
checked={false}
|
|
12
|
+
onChange={() => {}}
|
|
13
|
+
/>,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
expect(getByRole('checkbox')).toBeInTheDocument()
|
|
17
|
+
expect(getByText('19/01/2025 - My gaming diary')).toBeInTheDocument()
|
|
18
|
+
expect(container.querySelector('.flex-grow.line')).toBeInTheDocument()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('toggles when clicking the title, thanks to the native label', async () => {
|
|
22
|
+
const user = userEvent.setup()
|
|
23
|
+
const handleChange = jest.fn()
|
|
24
|
+
|
|
25
|
+
const { getByText } = render(
|
|
26
|
+
<CheckboxWithDivider
|
|
27
|
+
title="19/01/2025 - My gaming diary"
|
|
28
|
+
name="select-all"
|
|
29
|
+
checked={false}
|
|
30
|
+
onChange={handleChange}
|
|
31
|
+
/>,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
await user.click(getByText('19/01/2025 - My gaming diary'))
|
|
35
|
+
|
|
36
|
+
expect(handleChange).toHaveBeenCalledTimes(1)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('renders as indeterminate', () => {
|
|
40
|
+
const { getByRole } = render(
|
|
41
|
+
<CheckboxWithDivider
|
|
42
|
+
title="19/01/2025 - My gaming diary"
|
|
43
|
+
name="select-all"
|
|
44
|
+
checked
|
|
45
|
+
indeterminate
|
|
46
|
+
onChange={() => {}}
|
|
47
|
+
/>,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
expect(getByRole('checkbox')).toBeChecked()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('falls back to the title as the accessible name', () => {
|
|
54
|
+
const { getByRole } = render(
|
|
55
|
+
<CheckboxWithDivider
|
|
56
|
+
title="19/01/2025 - My gaming diary"
|
|
57
|
+
name="select-all"
|
|
58
|
+
checked={false}
|
|
59
|
+
onChange={() => {}}
|
|
60
|
+
/>,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
expect(
|
|
64
|
+
getByRole('checkbox', { name: '19/01/2025 - My gaming diary' }),
|
|
65
|
+
).toBeInTheDocument()
|
|
66
|
+
})
|
|
67
|
+
})
|
package/tests/Divider.spec.tsx
CHANGED
|
@@ -10,7 +10,7 @@ describe('Divider', () => {
|
|
|
10
10
|
)
|
|
11
11
|
expect(getByRole('separator')).toHaveClass('divider primary')
|
|
12
12
|
expect(container.querySelector('.short.line')).toBeInTheDocument()
|
|
13
|
-
expect(container.querySelector('.
|
|
13
|
+
expect(container.querySelector('.flex-grow.line')).toBeInTheDocument()
|
|
14
14
|
expect(getByText('A title divider')).toBeInTheDocument()
|
|
15
15
|
})
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ describe('Divider', () => {
|
|
|
19
19
|
<Divider title="A title divider with icon" icon="DeliveryNote" />,
|
|
20
20
|
)
|
|
21
21
|
expect(getByRole('img')).toHaveClass(/icon/i)
|
|
22
|
-
expect(container.querySelector('.
|
|
22
|
+
expect(container.querySelector('.flex-grow.line')).toBeInTheDocument()
|
|
23
23
|
expect(getByText('A title divider with icon')).toBeInTheDocument()
|
|
24
24
|
})
|
|
25
25
|
|
|
@@ -40,7 +40,7 @@ describe('Divider', () => {
|
|
|
40
40
|
await user.click(getByRole('button', { name: 'Delete' }))
|
|
41
41
|
|
|
42
42
|
expect(getByRole('img', { name: 'DeliveryNote' })).toBeInTheDocument()
|
|
43
|
-
expect(container.querySelector('.
|
|
43
|
+
expect(container.querySelector('.flex-grow.line')).toBeInTheDocument()
|
|
44
44
|
expect(getByText('A title divider with button')).toBeInTheDocument()
|
|
45
45
|
expect(handleClick).toHaveBeenCalledTimes(1)
|
|
46
46
|
})
|
|
@@ -48,6 +48,6 @@ describe('Divider', () => {
|
|
|
48
48
|
it('renders without title nor icon', () => {
|
|
49
49
|
const { getByRole, container } = render(<Divider />)
|
|
50
50
|
expect(getByRole('separator')).toHaveClass('divider primary')
|
|
51
|
-
expect(container.querySelector('.
|
|
51
|
+
expect(container.querySelector('.flex-grow.line')).toBeInTheDocument()
|
|
52
52
|
})
|
|
53
53
|
})
|
package/tests/Modal.spec.tsx
CHANGED
|
@@ -145,88 +145,4 @@ describe('Modal', () => {
|
|
|
145
145
|
expect(screen.queryAllByRole('option')).toHaveLength(3)
|
|
146
146
|
expect(screen.getByRole('option', { name: 'Item 3' })).toBeInTheDocument()
|
|
147
147
|
})
|
|
148
|
-
|
|
149
|
-
it('clears the scroll lock when isOpen toggles to false while the modal stays mounted', async () => {
|
|
150
|
-
const originalInnerWidth = window.innerWidth
|
|
151
|
-
Object.defineProperty(window, 'innerWidth', {
|
|
152
|
-
configurable: true,
|
|
153
|
-
value: 1024,
|
|
154
|
-
})
|
|
155
|
-
Object.defineProperty(document.documentElement, 'clientWidth', {
|
|
156
|
-
configurable: true,
|
|
157
|
-
value: 1000,
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
const user = userEvent.setup()
|
|
161
|
-
const ToggleableModal = () => {
|
|
162
|
-
const [isOpen, setIsOpen] = React.useState(true)
|
|
163
|
-
|
|
164
|
-
return (
|
|
165
|
-
<Modal
|
|
166
|
-
id="scroll-lock-modal"
|
|
167
|
-
isOpen={isOpen}
|
|
168
|
-
title="Scroll lock modal"
|
|
169
|
-
buttons={[
|
|
170
|
-
{
|
|
171
|
-
label: 'Close',
|
|
172
|
-
onClick: () => setIsOpen(false),
|
|
173
|
-
},
|
|
174
|
-
]}
|
|
175
|
-
>
|
|
176
|
-
content
|
|
177
|
-
</Modal>
|
|
178
|
-
)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
render(<ToggleableModal />)
|
|
182
|
-
|
|
183
|
-
expect(document.documentElement).toHaveClass('modal-scroll')
|
|
184
|
-
|
|
185
|
-
await user.click(screen.getByRole('button', { name: 'Close' }))
|
|
186
|
-
|
|
187
|
-
expect(document.documentElement).not.toHaveClass('modal-scroll')
|
|
188
|
-
|
|
189
|
-
Object.defineProperty(window, 'innerWidth', {
|
|
190
|
-
configurable: true,
|
|
191
|
-
value: originalInnerWidth,
|
|
192
|
-
})
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
it('does not recalculate the scroll lock width on window resize while open', () => {
|
|
196
|
-
const originalInnerWidth = window.innerWidth
|
|
197
|
-
Object.defineProperty(window, 'innerWidth', {
|
|
198
|
-
configurable: true,
|
|
199
|
-
value: 1024,
|
|
200
|
-
})
|
|
201
|
-
Object.defineProperty(document.documentElement, 'clientWidth', {
|
|
202
|
-
configurable: true,
|
|
203
|
-
value: 1000,
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
render(
|
|
207
|
-
<Modal id="resize-modal" isOpen={true} title="Resize modal" buttons={[]}>
|
|
208
|
-
content
|
|
209
|
-
</Modal>,
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
expect(document.documentElement).toHaveClass('modal-scroll')
|
|
213
|
-
expect(document.documentElement.style.getPropertyValue('--modal-scroll-width')).toBe('24px')
|
|
214
|
-
|
|
215
|
-
// Simulates the browser removing the native scrollbar once `overflow: hidden`
|
|
216
|
-
// is applied, which previously made the resize listener think the scrollbar
|
|
217
|
-
// was gone and drop the lock.
|
|
218
|
-
Object.defineProperty(document.documentElement, 'clientWidth', {
|
|
219
|
-
configurable: true,
|
|
220
|
-
value: 1024,
|
|
221
|
-
})
|
|
222
|
-
window.dispatchEvent(new Event('resize'))
|
|
223
|
-
|
|
224
|
-
expect(document.documentElement).toHaveClass('modal-scroll')
|
|
225
|
-
expect(document.documentElement.style.getPropertyValue('--modal-scroll-width')).toBe('24px')
|
|
226
|
-
|
|
227
|
-
Object.defineProperty(window, 'innerWidth', {
|
|
228
|
-
configurable: true,
|
|
229
|
-
value: originalInnerWidth,
|
|
230
|
-
})
|
|
231
|
-
})
|
|
232
148
|
})
|