agroptima-design-system 0.34.8 → 0.34.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agroptima-design-system",
3
- "version": "0.34.8",
3
+ "version": "0.34.10",
4
4
  "scripts": {
5
5
  "dev": "npm run storybook",
6
6
  "storybook": "storybook dev -p 6006 --ci",
@@ -10,21 +10,27 @@ $border-line: 1px solid color_alias.$neutral-color-200;
10
10
  @include typography.body_bold;
11
11
  display: flex;
12
12
  align-items: center;
13
+ gap: config.$space-3x;
13
14
 
14
- .line {
15
- border: $border-line;
15
+ &-title {
16
+ display: flex;
17
+ align-items: center;
16
18
  }
17
19
 
18
- .long {
19
- flex: 1;
20
- margin-left: config.$space-3x;
21
- }
22
20
 
23
21
  .short {
24
22
  width: config.$space-6x;
25
23
  margin-right: config.$space-3x;
26
24
  }
27
25
 
26
+ .line {
27
+ border: $border-line;
28
+ }
29
+
30
+ .long {
31
+ flex: 1;
32
+ }
33
+
28
34
  .icon {
29
35
  margin-right: config.$space-2x;
30
36
  }
@@ -34,4 +40,8 @@ $border-line: 1px solid color_alias.$neutral-color-200;
34
40
  text-decoration-line: underline;
35
41
  cursor: default;
36
42
  }
43
+
44
+ .iconButton {
45
+ margin-left: config.$space-3x;
46
+ }
37
47
  }
@@ -1,13 +1,16 @@
1
1
  import './Divider.scss'
2
- import Link from 'next/link'
2
+ import type { ComponentPropsWithoutRef } from 'react'
3
3
  import { classNames } from '../utils/classNames'
4
4
  import type { IconType } from './Icon'
5
5
  import { Icon } from './Icon'
6
6
 
7
- export interface DividerProps extends React.ComponentPropsWithoutRef<'div'> {
7
+ type DividerIconTypes = IconType | 'Line'
8
+
9
+ export interface DividerProps extends ComponentPropsWithoutRef<'div'> {
8
10
  title: string
9
11
  variant?: string
10
- icon?: IconType
12
+ icon?: DividerIconTypes
13
+ iconButton?: IconType
11
14
  hasAction?: boolean
12
15
  onClick?: () => void
13
16
  }
@@ -18,21 +21,27 @@ export function Divider({
18
21
  icon,
19
22
  hasAction,
20
23
  className,
24
+ children,
21
25
  onClick = () => {},
22
26
  }: DividerProps) {
23
27
  const cssClasses = classNames('divider', variant, className)
24
28
 
25
29
  return (
26
30
  <div role="separator" className={cssClasses}>
27
- {icon ? (
28
- <Icon className="icon" name={icon} size="3" />
29
- ) : (
30
- <div className="short line"></div>
31
- )}
32
- <span onClick={onClick} className={classNames({ link: hasAction })}>
33
- {title}
34
- </span>
31
+ <div className="divider-title">
32
+ <DividerIcon icon={icon} />
33
+ <span onClick={onClick} className={classNames({ link: hasAction })}>
34
+ {title}
35
+ </span>
36
+ </div>
35
37
  <div className="long line"></div>
38
+ {children}
36
39
  </div>
37
40
  )
38
41
  }
42
+
43
+ function DividerIcon({ icon }: { icon?: DividerIconTypes }) {
44
+ if (!icon) return null
45
+ if (icon === 'Line') return <div className="short line" />
46
+ return <Icon className="icon" name={icon} size="3" />
47
+ }
@@ -29,6 +29,7 @@ export interface SelectProps extends InputPropsWithoutOnChange {
29
29
  onChange?: (value: string) => void
30
30
  isSearchable?: boolean
31
31
  searchLabel?: string
32
+ isClereable?: boolean
32
33
  }
33
34
 
34
35
  const EMPTY_OPTION = { id: '', label: '' }
@@ -50,11 +51,12 @@ export function Select({
50
51
  defaultValue,
51
52
  isSearchable = false,
52
53
  searchLabel = 'Search',
54
+ isClereable = true,
53
55
  ...props
54
56
  }: SelectProps): React.JSX.Element {
55
57
  const { isOpen, close, toggle } = useOpen()
56
58
  const defaultOption =
57
- options.find((option) => option.id === defaultValue) || EMPTY_OPTION
59
+ options.find((option) => option.id === defaultValue) || (isClereable ? EMPTY_OPTION : options[0])
58
60
  const [selectedOption, setSelectedOption] = useState<Option>(defaultOption)
59
61
  const isEmpty = selectedOption.id === EMPTY_OPTION.id
60
62
  const isInvalid = Boolean(errors?.length)
@@ -98,6 +100,7 @@ export function Select({
98
100
  onClick={toggle}
99
101
  onClear={handleClear}
100
102
  isEmpty={isEmpty}
103
+ isClereable={isClereable}
101
104
  >
102
105
  {selectedOption.label || placeholder}
103
106
  </SelectTrigger>
@@ -12,6 +12,7 @@ export interface SelectTriggerProps {
12
12
  isEmpty: boolean
13
13
  onClick: () => void
14
14
  onClear: (event: React.MouseEvent) => void
15
+ isClereable?: boolean
15
16
  children: React.ReactNode
16
17
  }
17
18
 
@@ -24,6 +25,7 @@ export function SelectTrigger({
24
25
  isOpen,
25
26
  onClick,
26
27
  onClear,
28
+ isClereable=true,
27
29
  isEmpty,
28
30
  children,
29
31
  }: SelectTriggerProps) {
@@ -54,7 +56,7 @@ export function SelectTrigger({
54
56
  visible={isEmpty}
55
57
  />
56
58
  </button>
57
- <IconButton
59
+ {isClereable && (<IconButton
58
60
  type="button"
59
61
  size="3"
60
62
  icon="Close"
@@ -62,7 +64,7 @@ export function SelectTrigger({
62
64
  accessibilityLabel="clear"
63
65
  onClick={handleClear}
64
66
  visible={!isEmpty}
65
- />
67
+ />)}
66
68
  </div>
67
69
  )
68
70
  }
@@ -4,6 +4,10 @@ import { Meta } from "@storybook/blocks";
4
4
 
5
5
  # Changelog
6
6
 
7
+ ## 0.34.9
8
+
9
+ * Add icon logic to Divider component
10
+
7
11
  ## 0.34.8
8
12
 
9
13
  * Add fixed position to Drawer component container due to bug related with sticky CardsTable
@@ -1,4 +1,5 @@
1
1
  import type { StoryObj } from '@storybook/react'
2
+ import { IconButton } from '../atoms/Button'
2
3
  import { Divider } from '../atoms/Divider'
3
4
 
4
5
  const meta = {
@@ -38,6 +39,15 @@ export const Primary: Story = {
38
39
  args: {
39
40
  title: '19/01/2025 - My gaming diary',
40
41
  variant: 'primary',
42
+ icon: 'DeliveryNote',
43
+ },
44
+ parameters: figmaPrimaryDesign,
45
+ }
46
+
47
+ export const WithLine: Story = {
48
+ args: {
49
+ title: '19/01/2025 - My gaming diary',
50
+ icon: 'Line',
41
51
  },
42
52
  parameters: figmaPrimaryDesign,
43
53
  }
@@ -46,7 +56,6 @@ export const WithIcon: Story = {
46
56
  args: {
47
57
  title: '19/01/2025 - My gaming diary',
48
58
  icon: 'DeliveryNote',
49
- variant: 'primary',
50
59
  },
51
60
  parameters: figmaPrimaryDesign,
52
61
  }
@@ -60,3 +69,19 @@ export const WithLink: Story = {
60
69
  },
61
70
  parameters: figmaPrimaryDesign,
62
71
  }
72
+
73
+ export const WithButton: Story = {
74
+ args: {
75
+ title: '19/01/2025 - My gaming diary',
76
+ icon: 'Delete',
77
+ children: <IconButton icon="Delete" accessibilityLabel="Delete" />,
78
+ },
79
+ parameters: figmaPrimaryDesign,
80
+ }
81
+
82
+ export const NoIcon: Story = {
83
+ args: {
84
+ title: '19/01/2025 - My gaming diary',
85
+ },
86
+ parameters: figmaPrimaryDesign,
87
+ }
@@ -82,6 +82,7 @@ export const Primary: Story = {
82
82
  accessibilityLabel: 'Select your favourite gaming system options',
83
83
  hideLabel: false,
84
84
  isSearchable: false,
85
+ isClereable: true,
85
86
  placeholder: 'Select your favourite gaming system...',
86
87
  options: [
87
88
  { id: '1', label: 'Nintendo Switch' },
@@ -120,6 +121,7 @@ export const PrimaryWithSelectedOptions: Story = {
120
121
  hideLabel: false,
121
122
  placeholder: 'Select your favourite gaming system...',
122
123
  isSearchable: false,
124
+ isClereable: true,
123
125
  options: [
124
126
  { id: '1', label: 'Nintendo Switch' },
125
127
  { id: '2', label: 'PlayStation 5' },
@@ -142,6 +144,7 @@ export const PrimaryWithErrors: Story = {
142
144
  hideLabel: false,
143
145
  placeholder: 'Select your favourite gaming system...',
144
146
  isSearchable: false,
147
+ isClereable: true,
145
148
  options: [
146
149
  { id: '1', label: 'Nintendo Switch' },
147
150
  { id: '2', label: 'PlayStation 5' },
@@ -187,6 +190,7 @@ export const PrimaryWithSearch: Story = {
187
190
  id: 'select-videogames',
188
191
  onChange: (optionId) => console.log('onChange optionId:', optionId),
189
192
  isSearchable: true,
193
+ isClereable: true,
190
194
  searchLabel: 'Search',
191
195
  },
192
196
  parameters: figmaPrimaryDesign,
@@ -1,23 +1,47 @@
1
1
  import { render } from '@testing-library/react'
2
+ import userEvent from '@testing-library/user-event'
3
+ import { IconButton } from '../src/atoms/Button'
2
4
  import { Divider } from '../src/atoms/Divider'
3
5
 
4
6
  describe('Divider', () => {
5
7
  it('renders', () => {
6
- const { getByRole, getAllByRole, getByText } = render(
7
- <Divider title="A title divider" />,
8
+ const { getByRole, getByText, container } = render(
9
+ <Divider title="A title divider" icon="Line" />,
8
10
  )
9
11
  expect(getByRole('separator')).toHaveClass('divider primary')
10
- expect(getAllByRole('generic')[1]).toHaveClass('short line')
11
- expect(getAllByRole('generic')[3]).toHaveClass('long line')
12
+ expect(container.querySelector('.short.line')).toBeInTheDocument()
13
+ expect(container.querySelector('.long.line')).toBeInTheDocument()
12
14
  expect(getByText('A title divider')).toBeInTheDocument()
13
15
  })
14
16
 
15
17
  it('renders with icon', () => {
16
- const { getByRole, getAllByRole, getByText } = render(
18
+ const { getByRole, container, getByText } = render(
17
19
  <Divider title="A title divider with icon" icon="DeliveryNote" />,
18
20
  )
19
21
  expect(getByRole('img')).toHaveClass(/icon/i)
20
- expect(getAllByRole('generic')[2]).toHaveClass('long line')
22
+ expect(container.querySelector('.long.line')).toBeInTheDocument()
21
23
  expect(getByText('A title divider with icon')).toBeInTheDocument()
22
24
  })
25
+
26
+ it('renders with button', async () => {
27
+ const user = userEvent.setup()
28
+ const handleClick = jest.fn()
29
+
30
+ const { getByRole, container, getByText } = render(
31
+ <Divider title="A title divider with button" icon="DeliveryNote">
32
+ <IconButton
33
+ icon="Delete"
34
+ accessibilityLabel="Delete"
35
+ type="button"
36
+ onClick={handleClick}
37
+ />
38
+ </Divider>,
39
+ )
40
+ await user.click(getByRole('button', { name: 'Delete' }))
41
+
42
+ expect(getByRole('img', { name: 'DeliveryNote' })).toBeInTheDocument()
43
+ expect(container.querySelector('.long.line')).toBeInTheDocument()
44
+ expect(getByText('A title divider with button')).toBeInTheDocument()
45
+ expect(handleClick).toHaveBeenCalledTimes(1)
46
+ })
23
47
  })
@@ -166,4 +166,43 @@ describe('Select', () => {
166
166
  playstation5.label,
167
167
  )
168
168
  })
169
+
170
+ describe('when isClereable is false', () => {
171
+ it('hides deselect button', async () => {
172
+ const user = userEvent.setup()
173
+
174
+ render(
175
+ <Select
176
+ label="Videogames"
177
+ name="select-videogames"
178
+ isSearchable
179
+ disabled
180
+ defaultValue={playstation5.id}
181
+ options={OPTIONS}
182
+ isClereable={false}
183
+ />,
184
+ )
185
+
186
+ expect(screen.queryByLabelText(/clear/i)).not.toBeInTheDocument()
187
+ })
188
+
189
+ it('renders first option by default if no other is passed', async () => {
190
+ const user = userEvent.setup()
191
+
192
+ render(
193
+ <Select
194
+ isClereable={false}
195
+ helpText="This text can help you"
196
+ label="Videogames"
197
+ name="videogames"
198
+ options={OPTIONS}
199
+ placeholder="Select your favourite gaming system..."
200
+ />,
201
+ )
202
+
203
+ expect(screen.getByLabelText('Videogames')).toHaveTextContent(
204
+ 'Nintendo Switch',
205
+ )
206
+ })
207
+ })
169
208
  })