agroptima-design-system 0.26.9 → 0.27.0-beta.2

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.26.9",
3
+ "version": "0.27.0-beta.2",
4
4
  "scripts": {
5
5
  "dev": "npm run storybook",
6
6
  "storybook": "storybook dev -p 6006 --ci",
@@ -3,6 +3,28 @@
3
3
  @use '../../settings/config';
4
4
  @use '../../settings/breakpoints';
5
5
 
6
+ @mixin align-data-vertically() {
7
+ thead {
8
+ display: none;
9
+ }
10
+
11
+ tbody {
12
+ tr {
13
+ flex-direction: row;
14
+ flex-wrap: wrap;
15
+ position: relative;
16
+ gap: config.$space-1x;
17
+ padding: config.$space-2x config.$space-3x;
18
+ }
19
+ }
20
+
21
+ td {
22
+ width: 100%;
23
+ flex: inherit;
24
+ padding: 0px;
25
+ }
26
+ }
27
+
6
28
  .cards-table-list {
7
29
  display: flex;
8
30
  flex-direction: column;
@@ -184,28 +206,14 @@
184
206
  justify-content: flex-end !important;
185
207
  }
186
208
 
209
+ &.vertically {
210
+ @include align-data-vertically();
211
+ }
212
+
187
213
  // Media queries
188
214
  // Mobile & tablet cases
189
215
  @media only screen and (max-width: breakpoints.$large) {
190
- thead {
191
- display: none;
192
- }
193
-
194
- tbody {
195
- tr {
196
- flex-direction: row;
197
- flex-wrap: wrap;
198
- position: relative;
199
- gap: config.$space-1x;
200
- padding: config.$space-2x config.$space-3x;
201
- }
202
- }
203
-
204
- td {
205
- width: 100%;
206
- flex: inherit;
207
- padding: 0px;
208
- }
216
+ @include align-data-vertically();
209
217
 
210
218
  td:first-child {
211
219
  order: -2;
@@ -7,6 +7,7 @@ export interface CardsTableProps
7
7
  extends React.ComponentPropsWithoutRef<'table'> {
8
8
  variant?: Variant
9
9
  withTitle?: boolean
10
+ vertically?: boolean
10
11
  }
11
12
 
12
13
  export function CardsTable({
@@ -14,11 +15,13 @@ export function CardsTable({
14
15
  summary,
15
16
  variant = 'primary',
16
17
  withTitle = false,
18
+ vertically = false,
17
19
  children,
18
20
  ...props
19
21
  }: CardsTableProps): React.JSX.Element {
20
22
  const cssClasses = classNames('cards-table-list', variant, className, {
21
23
  'with-title': withTitle,
24
+ vertically: vertically,
22
25
  })
23
26
  return (
24
27
  <table summary={summary} role="table" className={cssClasses} {...props}>
@@ -34,7 +34,7 @@ export function CheckableTag({
34
34
  <span
35
35
  className={cssClasses}
36
36
  role="checkbox"
37
- aria-checked={isChecked}
37
+ aria-checked={false}
38
38
  tabIndex={0}
39
39
  aria-label={props['aria-label']}
40
40
  onClick={() => onSelect(label)}
@@ -3,43 +3,66 @@
3
3
  @use '../settings/config';
4
4
 
5
5
  .checkbox-group {
6
- @include typography.checkbox-label;
7
- display: flex;
8
- justify-content: flex-start;
9
- align-items: center;
10
- gap: config.$space-1x;
11
-
12
- .checkbox {
13
- -webkit-appearance: none;
14
- -moz-appearance: none;
15
- appearance: none;
16
- width: config.$icon-size-4x;
17
- height: config.$icon-size-4x;
18
- min-width: config.$icon-size-4x;
19
- }
6
+ .checkbox-label-container {
7
+ display: flex;
8
+ justify-content: flex-start;
9
+ align-items: center;
10
+ gap: config.$space-1x;
11
+
12
+ .background-icon {
13
+ width: config.$icon-size-4x;
14
+ height: config.$icon-size-4x;
15
+ }
20
16
 
21
- &.disabled {
22
- @include typography.checkbox-disabled-label;
17
+ .label {
18
+ @include typography.checkbox-label;
19
+ }
23
20
  }
24
21
 
25
22
  &.primary {
26
- .checkbox {
23
+ input[type='checkbox'] {
24
+ display: none;
25
+ }
26
+
27
+ input[type='checkbox'] + .checkbox-label-container .background-icon {
27
28
  background: url('../icons/checkbox-primary-inactive.svg') left top
28
29
  no-repeat;
29
30
  }
30
- .checkbox:checked {
31
+
32
+ input[type='checkbox']:checked
33
+ + .checkbox-label-container
34
+ .background-icon {
31
35
  background: url('../icons/checkbox-primary-active.svg') left top no-repeat;
32
36
  }
33
- .checkbox:disabled {
37
+
38
+ // Disabled
39
+ input[type='checkbox']
40
+ + .checkbox-label-container.disabled
41
+ .background-icon {
34
42
  background: url('../icons/checkbox-disabled-inactive.svg') left top
35
43
  no-repeat;
36
44
  }
37
- .checkbox:checked:disabled {
45
+
46
+ input[type='checkbox']:checked
47
+ + .checkbox-label-container.disabled
48
+ .background-icon {
38
49
  background: url('../icons/checkbox-disabled-active.svg') left top
39
50
  no-repeat;
40
51
  }
52
+
53
+ .checkbox-label-container {
54
+ &.disabled {
55
+ .label {
56
+ @include typography.checkbox-disabled-label;
57
+ }
58
+ }
59
+ }
60
+
61
+ // Hover
41
62
  &:hover {
42
- .checkbox:not(:checked):not(.disabled) {
63
+ input[type='checkbox']:not(:checked)
64
+ + .checkbox-label-container:not(.disabled)
65
+ .background-icon {
43
66
  background: url('../icons/checkbox-primary-hover-inactive.svg') left top
44
67
  no-repeat;
45
68
  }
@@ -4,42 +4,45 @@ import './Checkbox.scss'
4
4
  export type Variant = 'primary'
5
5
 
6
6
  export interface CheckboxProps extends React.ComponentPropsWithoutRef<'input'> {
7
- label: string
8
- accessibilityLabel?: string
7
+ label?: string
9
8
  hideLabel?: boolean
10
9
  variant?: Variant
11
10
  id?: string
11
+ accessibilityLabel: string
12
12
  }
13
13
 
14
14
  export function Checkbox({
15
- label,
16
15
  accessibilityLabel,
17
- hideLabel = false,
16
+ label,
17
+ hideLabel,
18
18
  disabled,
19
19
  variant = 'primary',
20
20
  id,
21
21
  name,
22
- className,
23
22
  ...props
24
23
  }: CheckboxProps) {
25
24
  const identifier = id || name
25
+ const inputCss = classNames('checkbox', variant)
26
+ const labelCss = classNames('checkbox-label-container', {
27
+ disabled: disabled,
28
+ })
26
29
 
27
30
  return (
28
- <div
29
- className={classNames('checkbox-group', variant, className, {
30
- disabled: disabled,
31
- })}
32
- >
31
+ <div className={`checkbox-group ${variant}`}>
33
32
  <input
34
33
  id={identifier}
35
34
  name={name}
36
35
  type="checkbox"
37
- className="checkbox"
36
+ className={inputCss}
38
37
  disabled={disabled}
39
- aria-label={accessibilityLabel || label}
38
+ aria-label={accessibilityLabel}
40
39
  {...props}
41
40
  />
42
- {!hideLabel && <label htmlFor={identifier}>{label}</label>}
41
+
42
+ <label className={labelCss} htmlFor={identifier}>
43
+ <span className="background-icon"></span>
44
+ {!hideLabel && <span className="label">{label}</span>}
45
+ </label>
43
46
  </div>
44
47
  )
45
48
  }
@@ -8,8 +8,14 @@
8
8
  flex-direction: column;
9
9
  margin-bottom: config.$space-3x;
10
10
 
11
+ &.single-line {
12
+ flex-direction: row;
13
+ gap: config.$space-1x;
14
+ }
15
+
11
16
  &.alignment-right {
12
17
  text-align: right;
18
+ justify-content: flex-end;
13
19
  }
14
20
 
15
21
  .title {
@@ -12,6 +12,7 @@ export interface DetailItemProps extends React.ComponentPropsWithoutRef<'div'> {
12
12
  variant?: Variant
13
13
  title?: string
14
14
  align?: Alignment
15
+ singleLine?: boolean
15
16
  }
16
17
 
17
18
  export function DetailItem({
@@ -20,6 +21,7 @@ export function DetailItem({
20
21
  variant = 'primary',
21
22
  title,
22
23
  align = Alignment.Left,
24
+ singleLine = false,
23
25
  children,
24
26
  ...props
25
27
  }: DetailItemProps): React.JSX.Element {
@@ -30,6 +32,7 @@ export function DetailItem({
30
32
  variant,
31
33
  `alignment-${align}`,
32
34
  className,
35
+ { 'single-line': singleLine },
33
36
  )}
34
37
  {...props}
35
38
  >
@@ -0,0 +1,92 @@
1
+ @use '../settings/color_alias';
2
+ @use '../settings/typography/form' as typography;
3
+ @use '../settings/config';
4
+
5
+ .radio-group {
6
+ display: flex;
7
+ align-items: center;
8
+ gap: config.$space-1x;
9
+
10
+ .radio-label-container {
11
+ .label {
12
+ @include typography.checkbox-label;
13
+ }
14
+
15
+ &.disabled {
16
+ .label {
17
+ @include typography.checkbox-disabled-label;
18
+ }
19
+ }
20
+ }
21
+
22
+ &.primary {
23
+ input[type='radio'] {
24
+ appearance: none;
25
+ position: relative;
26
+
27
+ margin: 0 1rem 0 0;
28
+
29
+ // Outside circle
30
+ &:after {
31
+ content: '';
32
+
33
+ position: absolute;
34
+ top: -6px;
35
+ left: -2px;
36
+
37
+ width: 16px;
38
+ height: 16px;
39
+
40
+ background: #fff;
41
+
42
+ border: 1px solid color_alias.$neutral-color-600;
43
+ border-radius: 50%;
44
+ }
45
+
46
+ &:checked {
47
+ // Inside circle
48
+ &:before {
49
+ content: '';
50
+ position: absolute;
51
+ top: -2px;
52
+ left: 2px;
53
+ z-index: 1;
54
+ width: 8px;
55
+ height: 8px;
56
+ background: color_alias.$primary-color-600;
57
+ border-radius: 50%;
58
+ }
59
+
60
+ &:after {
61
+ border: 1px solid color_alias.$primary-color-600;
62
+ }
63
+ }
64
+
65
+ &:hover {
66
+ &:after {
67
+ border: 1px solid color_alias.$primary-color-600;
68
+ }
69
+ }
70
+
71
+ &:disabled {
72
+ &:after {
73
+ border: 1px solid color_alias.$neutral-color-400;
74
+ }
75
+ &:checked {
76
+ &:before {
77
+ background: color_alias.$neutral-color-400;
78
+ }
79
+
80
+ &:after {
81
+ border: 1px solid color_alias.$neutral-color-400;
82
+ }
83
+ }
84
+ &:hover {
85
+ &:after {
86
+ border: 1px solid color_alias.$neutral-color-400;
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,47 @@
1
+ import { classNames } from '../utils/classNames'
2
+ import './RadioButton.scss'
3
+
4
+ export type Variant = 'primary'
5
+
6
+ export interface RadioButtonProps
7
+ extends React.ComponentPropsWithoutRef<'input'> {
8
+ label?: string
9
+ hideLabel?: boolean
10
+ variant?: Variant
11
+ id?: string
12
+ accessibilityLabel: string
13
+ }
14
+
15
+ export function RadioButton({
16
+ accessibilityLabel,
17
+ label,
18
+ hideLabel,
19
+ disabled,
20
+ variant = 'primary',
21
+ id,
22
+ name,
23
+ ...props
24
+ }: RadioButtonProps) {
25
+ const inputCss = classNames('radio', variant)
26
+ const labelCss = classNames('radio-label-container', {
27
+ disabled: disabled,
28
+ })
29
+
30
+ return (
31
+ <div className={`radio-group ${variant}`}>
32
+ <input
33
+ id={id}
34
+ name={name}
35
+ type="radio"
36
+ className={inputCss}
37
+ disabled={disabled}
38
+ aria-label={accessibilityLabel}
39
+ {...props}
40
+ />
41
+
42
+ <label className={labelCss} htmlFor={id}>
43
+ {!hideLabel && <span className="label">{label}</span>}
44
+ </label>
45
+ </div>
46
+ )
47
+ }
@@ -218,3 +218,19 @@ export const OnlyTitle = {
218
218
  </CardsTable>
219
219
  ),
220
220
  }
221
+
222
+ export const DataAlignedVertically = {
223
+ render: (args) => (
224
+ <CardsTable vertically {...args}>
225
+ <CardsTableBody>
226
+ <CardsTableRow>
227
+ <CardsTableCell>Silent Hill</CardsTableCell>
228
+ <CardsTableCell>Metal Gear Solid 5</CardsTableCell>
229
+ <CardsTableCell>Tekken 8</CardsTableCell>
230
+ <CardsTableCell>The Witcher 3</CardsTableCell>
231
+ <CardsTableCell>Zone of the Enders: The 2nd Runner</CardsTableCell>
232
+ </CardsTableRow>
233
+ </CardsTableBody>
234
+ </CardsTable>
235
+ ),
236
+ }
@@ -4,17 +4,11 @@ import { Meta } from "@storybook/blocks";
4
4
 
5
5
  # Changelog
6
6
 
7
- # 0.26.9
7
+ # 0.27.0
8
8
 
9
- * Update Checkbox component to use input and not span
10
-
11
- BREAKING CHANGES
12
-
13
- * Checkbox component make label mandatory and accessibilityLabel optional
14
-
15
- # 0.26.8
16
-
17
- * Set check value in CheckableTag
9
+ * Add RadioButton component.
10
+ * Add `vertically` prop to CardsTable component in order to display the data vertically both on desktop and mobile.
11
+ * Add `singleLine` prop to DetailItem component in order to display the data on a single line.
18
12
 
19
13
  # 0.26.7
20
14
 
@@ -162,7 +162,12 @@ export const Details = {
162
162
  <p>Final Fantasy X</p>
163
163
  </Card>
164
164
  </Collapsible>
165
- <DetailItem style={{ marginTop: '10px' }} align="right" title="Price">
165
+ <DetailItem
166
+ singleLine
167
+ style={{ marginTop: '10px' }}
168
+ align="right"
169
+ title="Price"
170
+ >
166
171
  59,95 €
167
172
  </DetailItem>
168
173
  </Modal>
@@ -0,0 +1,94 @@
1
+ import { RadioButton } from '../atoms/RadioButton'
2
+
3
+ const figmaPrimaryDesign = {
4
+ design: {
5
+ type: 'figma',
6
+ url: 'https://www.figma.com/design/DN2ova21vWqCRvPspBXgI1/Design-System?node-id=527-73&m=dev',
7
+ },
8
+ }
9
+
10
+ const meta = {
11
+ title: 'Design System/Atoms/RadioButton',
12
+ component: RadioButton,
13
+ tags: ['autodocs'],
14
+ argTypes: {
15
+ accessibilityLabel: {
16
+ description: 'Accessible name & description of the element',
17
+ },
18
+ variant: {
19
+ description: 'Variant used from a list of values',
20
+ },
21
+ disabled: {
22
+ description: 'Is the component in disabled state?',
23
+ },
24
+ label: {
25
+ description: 'Label for the component',
26
+ },
27
+ hideLabel: {
28
+ description: 'Hide or show label?',
29
+ },
30
+ id: {
31
+ description: 'Value needed for the label relation',
32
+ },
33
+ },
34
+ parameters: figmaPrimaryDesign,
35
+ }
36
+
37
+ export default meta
38
+
39
+ export const Enabled = {
40
+ render: () => (
41
+ <>
42
+ <RadioButton
43
+ accessibilityLabel="Marks if the user likes action videogames"
44
+ id="preference-1"
45
+ name="videogames-preference"
46
+ value="action"
47
+ label="Action games"
48
+ variant="primary"
49
+ />
50
+ <RadioButton
51
+ accessibilityLabel="Marks if the user likes party videogames"
52
+ id="preference-2"
53
+ name="videogames-preference"
54
+ value="party"
55
+ label="Party games"
56
+ variant="primary"
57
+ />
58
+ <RadioButton
59
+ accessibilityLabel="Marks if the user likes platform videogames"
60
+ id="preference-3"
61
+ name="videogames-preference"
62
+ value="platform"
63
+ label="Platform games"
64
+ variant="primary"
65
+ />
66
+ </>
67
+ ),
68
+ }
69
+
70
+ export const Disabled = {
71
+ render: () => (
72
+ <>
73
+ <RadioButton
74
+ disabled
75
+ accessibilityLabel="Marks if the user likes platform videogames"
76
+ id="preference-3"
77
+ name="videogames-preference"
78
+ value="action"
79
+ label="Action games"
80
+ variant="primary"
81
+ />
82
+ <RadioButton
83
+ disabled
84
+ checked
85
+ accessibilityLabel="Marks if the user likes platform videogames"
86
+ id="preference-4"
87
+ name="videogames-preference"
88
+ value="platform"
89
+ label="Platform games"
90
+ variant="primary"
91
+ />
92
+ </>
93
+ ),
94
+ }
@@ -15,7 +15,7 @@ describe('Checkbox', () => {
15
15
  />,
16
16
  )
17
17
  expect(getAllByRole('generic')[1]).toHaveClass(`checkbox-group ${variant}`)
18
- expect(getByRole('checkbox')).toHaveClass('checkbox')
18
+ expect(getByRole('checkbox')).toHaveClass(`checkbox ${variant}`)
19
19
  expect(getByText(/Do you like videogames/i)).toBeInTheDocument()
20
20
  })
21
21
  })
@@ -0,0 +1,35 @@
1
+ import React from 'react'
2
+ import { render } from '@testing-library/react'
3
+ import { RadioButton } from '@/atoms/RadioButton'
4
+
5
+ describe('RadioButton', () => {
6
+ const variants = ['primary']
7
+
8
+ it.each(variants)('renders with label and expected styles', (variant) => {
9
+ const { getAllByRole, getByText } = render(
10
+ <>
11
+ <RadioButton
12
+ accessibilityLabel="Marks if the user likes party videogames"
13
+ id="preference-2"
14
+ name="videogames-preference"
15
+ value="party"
16
+ label="Party games"
17
+ variant="primary"
18
+ />
19
+ <RadioButton
20
+ accessibilityLabel="Marks if the user likes platform videogames"
21
+ id="preference-3"
22
+ name="videogames-preference"
23
+ value="platform"
24
+ label="Platform games"
25
+ variant="primary"
26
+ />
27
+ </>,
28
+ )
29
+ expect(getAllByRole('generic')[1]).toHaveClass(`radio-group ${variant}`)
30
+ expect(getAllByRole('radio')[0]).toHaveClass(`radio ${variant}`)
31
+ expect(getAllByRole('radio')[1]).toHaveClass(`radio ${variant}`)
32
+ expect(getByText(/Party games/i)).toBeInTheDocument()
33
+ expect(getByText(/Platform games/i)).toBeInTheDocument()
34
+ })
35
+ })
package/tsconfig.json CHANGED
@@ -34,6 +34,6 @@
34
34
  "src/stories/Card.stories.js",
35
35
  "src/stories/Menu.stories.js",
36
36
  "src/stories/EmptyState.stories.js"
37
- , "src/stories/CheckableTag.stories.js" ],
37
+ , "src/stories/CheckableTag.stories.js", "src/stories/RadioButton.stories.js" ],
38
38
  "exclude": ["node_modules"]
39
39
  }