agroptima-design-system 0.35.0-beta.9 → 0.35.0
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 +3 -3
- package/src/atoms/Button/BaseButton.tsx +2 -1
- package/src/atoms/Card/Card.scss +2 -2
- package/src/atoms/Card/CardHeader.tsx +1 -1
- package/src/atoms/{Collapsible.scss → Collapsible/Collapsible.scss} +9 -26
- package/src/atoms/{Collapsible.tsx → Collapsible/Collapsible.tsx} +2 -2
- package/src/atoms/Collapsible/index.ts +5 -0
- package/src/atoms/Divider.scss +16 -6
- package/src/atoms/Divider.tsx +20 -11
- package/src/atoms/Modal/ModalDialog.tsx +2 -0
- package/src/atoms/Multiselect.tsx +10 -0
- package/src/atoms/Popover/Popover.tsx +1 -1
- package/src/atoms/Select/Select.scss +4 -5
- package/src/atoms/Select/Select.tsx +10 -2
- package/src/atoms/Select/SelectItem.tsx +18 -3
- package/src/atoms/Select/SelectItems.tsx +19 -2
- package/src/atoms/Select/SelectTrigger.tsx +4 -0
- package/src/hooks/useOpen.ts +1 -0
- package/src/icons/duplicate.svg +1 -0
- package/src/icons/index.tsx +2 -0
- package/src/stories/Changelog.mdx +13 -6
- package/src/stories/Collapsible.stories.tsx +2 -1
- package/src/stories/{Divider.stories.ts → Divider.stories.tsx} +26 -1
- package/src/stories/Drawer.stories.js +2 -2
- package/src/stories/InputWithButton.stories.tsx +1 -1
- package/src/stories/Modal.stories.tsx +163 -59
- package/tests/Divider.spec.tsx +30 -6
- package/tests/Modal.spec.tsx +79 -11
- package/tests/Select.spec.tsx +17 -0
- package/tsconfig.json +0 -1
- package/src/stories/ModalOld.stories.js +0 -177
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agroptima-design-system",
|
|
3
|
-
"version": "0.35.0
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "npm run storybook",
|
|
6
6
|
"storybook": "storybook dev -p 6006 --ci",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"@storybook/test": "^8.6.12",
|
|
37
37
|
"@svgr/webpack": "^8.1.0",
|
|
38
38
|
"@testing-library/jest-dom": "^6.6.3",
|
|
39
|
-
"@testing-library/react": "^16.
|
|
40
|
-
"@testing-library/user-event": "^14.
|
|
39
|
+
"@testing-library/react": "^16.3.0",
|
|
40
|
+
"@testing-library/user-event": "^14.6.1",
|
|
41
41
|
"@types/jest": "^29.5.14",
|
|
42
42
|
"@types/jest-axe": "^3.5.9",
|
|
43
43
|
"@types/node": "^22.10.5",
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import NextLink, { type LinkProps } from 'next/link'
|
|
2
|
-
import type { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react'
|
|
2
|
+
import type { AnchorHTMLAttributes, ButtonHTMLAttributes, Ref } from 'react'
|
|
3
3
|
|
|
4
4
|
interface CommonProps {
|
|
5
5
|
disabled?: boolean
|
|
6
6
|
visible?: boolean
|
|
7
7
|
prefetch?: boolean
|
|
8
|
+
ref?: Ref<HTMLAnchorElement | HTMLButtonElement | null>
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
type HtmlButtonProps = ButtonHTMLAttributes<HTMLButtonElement>
|
package/src/atoms/Card/Card.scss
CHANGED
|
@@ -41,7 +41,7 @@ a.card {
|
|
|
41
41
|
display: -webkit-box;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
> .bold {
|
|
44
|
+
> .card-bold {
|
|
45
45
|
@include typography.body-bold;
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -77,7 +77,7 @@ a.card {
|
|
|
77
77
|
@include typography.body-regular-disabled;
|
|
78
78
|
background: color_alias.$neutral-color-50;
|
|
79
79
|
|
|
80
|
-
.header .bold {
|
|
80
|
+
.card-header .card-bold {
|
|
81
81
|
color: color_alias.$neutral-color-400;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -18,7 +18,7 @@ export function CardHeader({
|
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
20
|
<div className={cssClasses} {...props}>
|
|
21
|
-
<span className={classNames('card-title', { bold: isBold })}>
|
|
21
|
+
<span className={classNames('card-title', { 'card-bold': isBold })}>
|
|
22
22
|
{title}
|
|
23
23
|
</span>
|
|
24
24
|
{children && <div className="actions">{children}</div>}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
@use '
|
|
2
|
-
@use '
|
|
3
|
-
@use '
|
|
4
|
-
@use '
|
|
1
|
+
@use '../../settings/color_alias';
|
|
2
|
+
@use '../../settings/typography/content' as typography;
|
|
3
|
+
@use '../../settings/config';
|
|
4
|
+
@use '../../settings/depth';
|
|
5
|
+
@use '../../settings/mixins';
|
|
5
6
|
|
|
6
7
|
details summary::-webkit-details-marker {
|
|
7
8
|
display: none;
|
|
@@ -32,7 +33,7 @@ details summary::-webkit-details-marker {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
.content {
|
|
36
|
+
.collapsible-content {
|
|
36
37
|
padding: config.$space-7x config.$space-7x config.$space-3x;
|
|
37
38
|
|
|
38
39
|
&.no-horizontal-padding {
|
|
@@ -54,16 +55,7 @@ details summary::-webkit-details-marker {
|
|
|
54
55
|
background: color_alias.$neutral-color-50;
|
|
55
56
|
border-bottom: 1px solid color_alias.$neutral-color-200;
|
|
56
57
|
color: color_alias.$neutral-color-200;
|
|
57
|
-
|
|
58
|
-
.icon {
|
|
59
|
-
> svg {
|
|
60
|
-
fill: color_alias.$neutral-color-200;
|
|
61
|
-
|
|
62
|
-
path {
|
|
63
|
-
fill: color_alias.$neutral-color-200;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
58
|
+
@include mixins.svg-color(color_alias.$neutral-color-200);
|
|
67
59
|
}
|
|
68
60
|
}
|
|
69
61
|
|
|
@@ -71,16 +63,7 @@ details summary::-webkit-details-marker {
|
|
|
71
63
|
color: color_alias.$neutral-color-1000;
|
|
72
64
|
background: transparent;
|
|
73
65
|
border-bottom: 1px solid color_alias.$neutral-color-200;
|
|
74
|
-
|
|
75
|
-
.icon {
|
|
76
|
-
> svg {
|
|
77
|
-
fill: color_alias.$primary-color-600;
|
|
78
|
-
|
|
79
|
-
path {
|
|
80
|
-
fill: color_alias.$primary-color-600;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
66
|
+
@include mixins.svg-color(color_alias.$primary-color-600);
|
|
84
67
|
|
|
85
68
|
&:hover {
|
|
86
69
|
background: color_alias.$primary-color-50;
|
|
@@ -88,7 +71,7 @@ details summary::-webkit-details-marker {
|
|
|
88
71
|
}
|
|
89
72
|
}
|
|
90
73
|
|
|
91
|
-
&.secondary .content {
|
|
74
|
+
&.secondary .collapsible-content {
|
|
92
75
|
padding: config.$space-3x config.$space-4x config.$space-6x;
|
|
93
76
|
border: 1px solid color_alias.$neutral-color-200;
|
|
94
77
|
border-top: none;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import './Collapsible.scss'
|
|
2
2
|
import type { ComponentPropsWithoutRef } from 'react'
|
|
3
|
-
import { classNames } from '
|
|
4
|
-
import { Icon } from '
|
|
3
|
+
import { classNames } from '../../utils/classNames'
|
|
4
|
+
import { Icon } from '../Icon'
|
|
5
5
|
|
|
6
6
|
export type Variant = 'primary' | 'secondary'
|
|
7
7
|
|
package/src/atoms/Divider.scss
CHANGED
|
@@ -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
|
-
|
|
15
|
-
|
|
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
|
}
|
package/src/atoms/Divider.tsx
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import './Divider.scss'
|
|
2
|
-
import
|
|
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
|
-
|
|
7
|
+
type DividerIconTypes = IconType | 'Line'
|
|
8
|
+
|
|
9
|
+
export interface DividerProps extends ComponentPropsWithoutRef<'div'> {
|
|
8
10
|
title: string
|
|
9
11
|
variant?: string
|
|
10
|
-
icon?:
|
|
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
|
-
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
}
|
|
@@ -51,6 +51,7 @@ export function ModalDialog({
|
|
|
51
51
|
dialog.removeEventListener('cancel', handleCancel)
|
|
52
52
|
}
|
|
53
53
|
}, [onClose])
|
|
54
|
+
|
|
54
55
|
useEffect(() => {
|
|
55
56
|
if (isOpen) {
|
|
56
57
|
dialogRef.current?.showModal()
|
|
@@ -61,6 +62,7 @@ export function ModalDialog({
|
|
|
61
62
|
|
|
62
63
|
return (
|
|
63
64
|
<dialog
|
|
65
|
+
role="dialog"
|
|
64
66
|
aria-modal="true"
|
|
65
67
|
ref={dialogRef}
|
|
66
68
|
className={classNames('modal', className, { 'modal-details': details })}
|
|
@@ -56,11 +56,18 @@ export function Multiselect({
|
|
|
56
56
|
}: MultiselectProps): React.JSX.Element {
|
|
57
57
|
const { isOpen, close, toggle } = useOpen()
|
|
58
58
|
const selectRef = useRef(null)
|
|
59
|
+
const selectTriggerRef = useRef<HTMLButtonElement | null>(null)
|
|
59
60
|
useOutsideClick(selectRef, close)
|
|
60
61
|
const [selectedOptions, setSelectedOptions] = useState<string[]>(defaultValue)
|
|
61
62
|
const isInvalid = Boolean(errors?.length)
|
|
62
63
|
const hasSelectedOptions = selectedOptions.length > 0
|
|
63
64
|
|
|
65
|
+
const handleClose = () => {
|
|
66
|
+
if (!isOpen) return
|
|
67
|
+
close()
|
|
68
|
+
selectTriggerRef?.current?.focus()
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
function handleSelectOption({ id }: Option) {
|
|
65
72
|
const isOptionSelected = selectedOptions.includes(id)
|
|
66
73
|
const options = isOptionSelected
|
|
@@ -76,6 +83,7 @@ export function Multiselect({
|
|
|
76
83
|
setSelectedOptions([])
|
|
77
84
|
onChange([])
|
|
78
85
|
}
|
|
86
|
+
|
|
79
87
|
const identifier = id || name
|
|
80
88
|
return (
|
|
81
89
|
<div
|
|
@@ -102,6 +110,7 @@ export function Multiselect({
|
|
|
102
110
|
onClick={toggle}
|
|
103
111
|
onClear={handleClear}
|
|
104
112
|
isEmpty={!hasSelectedOptions}
|
|
113
|
+
buttonRef={selectTriggerRef}
|
|
105
114
|
>
|
|
106
115
|
{hasSelectedOptions
|
|
107
116
|
? `${selectedOptions.length} ${selectedLabel}`
|
|
@@ -116,6 +125,7 @@ export function Multiselect({
|
|
|
116
125
|
selectOption={handleSelectOption}
|
|
117
126
|
isSearchable={isSearchable}
|
|
118
127
|
searchLabel={searchLabel}
|
|
128
|
+
onClose={handleClose}
|
|
119
129
|
/>
|
|
120
130
|
)}
|
|
121
131
|
<HelpText helpText={helpText} errors={errors} />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
import './Popover.scss'
|
|
3
|
-
import { useRef } from 'react'
|
|
3
|
+
import React, { useRef } from 'react'
|
|
4
4
|
import { useOpen } from '../../hooks/useOpen'
|
|
5
5
|
import { useOutsideClick } from '../../hooks/useOutsideClick'
|
|
6
6
|
import { classNames } from '../../utils/classNames'
|
|
@@ -66,8 +66,7 @@ $elements-space: config.$space-2x;
|
|
|
66
66
|
background: color_alias.$neutral-white;
|
|
67
67
|
@include mixins.icon-color(color_alias.$primary-color-600);
|
|
68
68
|
|
|
69
|
-
&:focus {
|
|
70
|
-
outline: color_alias.$primary-color-600;
|
|
69
|
+
&:has(.select:focus) {
|
|
71
70
|
border: 1px solid color_alias.$primary-color-600;
|
|
72
71
|
}
|
|
73
72
|
}
|
|
@@ -75,9 +74,9 @@ $elements-space: config.$space-2x;
|
|
|
75
74
|
.select-options {
|
|
76
75
|
border-radius: config.$corner-radius-xxs;
|
|
77
76
|
background: color_alias.$neutral-white;
|
|
78
|
-
box-shadow:
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
box-shadow: 0 9px 28px 8px rgba(0, 0, 0, 0.05),
|
|
78
|
+
0 6px 16px 0 rgba(0, 0, 0, 0.08),
|
|
79
|
+
0 3px 6px -4px rgba(0, 0, 0, 0.12);
|
|
81
80
|
|
|
82
81
|
.option {
|
|
83
82
|
background: color_alias.$neutral-white;
|
|
@@ -61,7 +61,13 @@ export function Select({
|
|
|
61
61
|
const isEmpty = selectedOption.id === EMPTY_OPTION.id
|
|
62
62
|
const isInvalid = Boolean(errors?.length)
|
|
63
63
|
const selectRef = useRef(null)
|
|
64
|
-
|
|
64
|
+
const selectTriggerRef = useRef<HTMLButtonElement | null>(null)
|
|
65
|
+
const handleClose = () => {
|
|
66
|
+
if (!isOpen) return
|
|
67
|
+
close()
|
|
68
|
+
selectTriggerRef?.current?.focus()
|
|
69
|
+
}
|
|
70
|
+
useOutsideClick(selectRef, handleClose)
|
|
65
71
|
|
|
66
72
|
function handleSelectOption(option: Option) {
|
|
67
73
|
setSelectedOption(option)
|
|
@@ -93,6 +99,7 @@ export function Select({
|
|
|
93
99
|
|
|
94
100
|
<SelectTrigger
|
|
95
101
|
id={identifier}
|
|
102
|
+
buttonRef={selectTriggerRef}
|
|
96
103
|
label={label}
|
|
97
104
|
accessibilityLabel={accessibilityLabel}
|
|
98
105
|
invalid={isInvalid}
|
|
@@ -110,9 +117,10 @@ export function Select({
|
|
|
110
117
|
options={options}
|
|
111
118
|
selectedOptions={[selectedOption.id]}
|
|
112
119
|
selectOption={handleSelectOption}
|
|
113
|
-
onClick={
|
|
120
|
+
onClick={handleClose}
|
|
114
121
|
isSearchable={isSearchable}
|
|
115
122
|
searchLabel={searchLabel}
|
|
123
|
+
onClose={handleClose}
|
|
116
124
|
/>
|
|
117
125
|
)}
|
|
118
126
|
<HelpText helpText={helpText} errors={errors} />
|
|
@@ -6,15 +6,29 @@ interface OptionProps {
|
|
|
6
6
|
option: Option
|
|
7
7
|
multiple?: boolean
|
|
8
8
|
isSelected: boolean
|
|
9
|
-
|
|
9
|
+
onSelectOption: (option: Option) => void
|
|
10
|
+
onClose: () => void
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
const ENTER_KEY = 'Enter'
|
|
14
|
+
const SPACE_KEY = ' '
|
|
15
|
+
|
|
12
16
|
export function SelectItem({
|
|
13
17
|
option,
|
|
14
18
|
isSelected,
|
|
15
|
-
|
|
19
|
+
onSelectOption,
|
|
16
20
|
multiple,
|
|
21
|
+
onClose,
|
|
17
22
|
}: OptionProps) {
|
|
23
|
+
const handleKeyDown = (e: React.KeyboardEvent<HTMLLIElement>) => {
|
|
24
|
+
if (e.key === ENTER_KEY || e.key === SPACE_KEY) {
|
|
25
|
+
e.preventDefault()
|
|
26
|
+
onSelectOption(option)
|
|
27
|
+
if (!multiple) {
|
|
28
|
+
onClose()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
18
32
|
return (
|
|
19
33
|
<li
|
|
20
34
|
className="option"
|
|
@@ -22,7 +36,8 @@ export function SelectItem({
|
|
|
22
36
|
role="option"
|
|
23
37
|
aria-selected={isSelected}
|
|
24
38
|
data-option={option}
|
|
25
|
-
onClick={() =>
|
|
39
|
+
onClick={() => onSelectOption(option)}
|
|
40
|
+
onKeyDown={handleKeyDown}
|
|
26
41
|
>
|
|
27
42
|
{multiple && <CheckboxIcon selected={isSelected} />}
|
|
28
43
|
{option.label}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { useEffect } from 'react'
|
|
2
2
|
import { useSearch } from '../../hooks/useSearch'
|
|
3
3
|
import { Input } from '../Input'
|
|
4
4
|
import type { Option } from './Select'
|
|
@@ -13,8 +13,11 @@ interface OptionListProps {
|
|
|
13
13
|
onClick?: () => void
|
|
14
14
|
isSearchable: boolean
|
|
15
15
|
searchLabel: string
|
|
16
|
+
onClose: () => void
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
const ESCAPE_KEY = 'Escape'
|
|
20
|
+
|
|
18
21
|
export function SelectItems({
|
|
19
22
|
id,
|
|
20
23
|
options,
|
|
@@ -24,8 +27,21 @@ export function SelectItems({
|
|
|
24
27
|
onClick,
|
|
25
28
|
isSearchable,
|
|
26
29
|
searchLabel,
|
|
30
|
+
onClose,
|
|
27
31
|
}: OptionListProps) {
|
|
28
32
|
const { findItems, search } = useSearch(options, 'label')
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
35
|
+
if (event.key === ESCAPE_KEY) {
|
|
36
|
+
onClose()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
document.addEventListener('keydown', handleKeyDown)
|
|
40
|
+
return () => {
|
|
41
|
+
document.removeEventListener('keydown', handleKeyDown)
|
|
42
|
+
}
|
|
43
|
+
}, [onClose])
|
|
44
|
+
|
|
29
45
|
return (
|
|
30
46
|
<div className="select-options-container">
|
|
31
47
|
<div className="select-options" id={id}>
|
|
@@ -47,7 +63,8 @@ export function SelectItems({
|
|
|
47
63
|
key={option.id}
|
|
48
64
|
option={option}
|
|
49
65
|
isSelected={selectedOptions.includes(option.id)}
|
|
50
|
-
|
|
66
|
+
onSelectOption={selectOption}
|
|
67
|
+
onClose={onClose}
|
|
51
68
|
/>
|
|
52
69
|
))}
|
|
53
70
|
</ul>
|
|
@@ -13,6 +13,7 @@ export interface SelectTriggerProps {
|
|
|
13
13
|
onClick: () => void
|
|
14
14
|
onClear: (event: React.MouseEvent) => void
|
|
15
15
|
children: React.ReactNode
|
|
16
|
+
buttonRef: React.RefObject<HTMLButtonElement | null>
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export function SelectTrigger({
|
|
@@ -26,6 +27,7 @@ export function SelectTrigger({
|
|
|
26
27
|
onClear,
|
|
27
28
|
isEmpty,
|
|
28
29
|
children,
|
|
30
|
+
buttonRef,
|
|
29
31
|
}: SelectTriggerProps) {
|
|
30
32
|
const handleClear = (event: React.MouseEvent) => {
|
|
31
33
|
if (disabled) return
|
|
@@ -35,6 +37,7 @@ export function SelectTrigger({
|
|
|
35
37
|
<div className="select-container">
|
|
36
38
|
<button
|
|
37
39
|
id={id}
|
|
40
|
+
ref={buttonRef}
|
|
38
41
|
type="button"
|
|
39
42
|
role="combobox"
|
|
40
43
|
className="select"
|
|
@@ -56,6 +59,7 @@ export function SelectTrigger({
|
|
|
56
59
|
</button>
|
|
57
60
|
<IconButton
|
|
58
61
|
type="button"
|
|
62
|
+
tabIndex={-1}
|
|
59
63
|
size="3"
|
|
60
64
|
icon="Close"
|
|
61
65
|
className="clear-button"
|
package/src/hooks/useOpen.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M8 16c-.55 0-1.02-.196-1.412-.588A1.926 1.926 0 0 1 6 14V2c0-.55.196-1.02.588-1.413A1.926 1.926 0 0 1 8 0h9c.55 0 1.02.196 1.413.588C18.803.979 19 1.45 19 2v12c0 .55-.196 1.02-.587 1.412A1.926 1.926 0 0 1 17 16H8Zm0-2h9V2H8v12Zm-4 6c-.55 0-1.02-.196-1.413-.587A1.926 1.926 0 0 1 2 18V4h2v14h11v2H4Z" fill="#161C26"/></svg>
|
package/src/icons/index.tsx
CHANGED
|
@@ -24,6 +24,7 @@ import Done from './done.svg'
|
|
|
24
24
|
import DoubleArrowLeft from './double-arrow-left.svg'
|
|
25
25
|
import DoubleArrowRight from './double-arrow-right.svg'
|
|
26
26
|
import Download from './download.svg'
|
|
27
|
+
import Duplicate from './duplicate.svg'
|
|
27
28
|
import Edit from './edit.svg'
|
|
28
29
|
import EditColumns from './edit-columns.svg'
|
|
29
30
|
import ElectronicInvoice from './electronic-invoice.svg'
|
|
@@ -80,6 +81,7 @@ export {
|
|
|
80
81
|
DoubleArrowLeft,
|
|
81
82
|
DoubleArrowRight,
|
|
82
83
|
Download,
|
|
84
|
+
Duplicate,
|
|
83
85
|
Edit,
|
|
84
86
|
EditColumns,
|
|
85
87
|
ElectronicInvoice,
|
|
@@ -4,16 +4,23 @@ import { Meta } from "@storybook/blocks";
|
|
|
4
4
|
|
|
5
5
|
# Changelog
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
## 0.35.0
|
|
8
9
|
|
|
9
10
|
* Add `fullWidth` prop to Select, Button, Input, MultiSelect, TextArea, QuantitySelector, DateRangePicker, DateSinglePicker components
|
|
10
|
-
* Fix extra space when
|
|
11
|
-
* Add
|
|
12
|
-
* Add
|
|
13
|
-
* Add
|
|
14
|
-
* Add `classic-view` and `new-view` to icons
|
|
11
|
+
* Fix extra space when opening Select and MultiSelect components
|
|
12
|
+
* Add `Borderless` variant to Input component
|
|
13
|
+
* Add `ellipsis` prop to Input component
|
|
14
|
+
* Add `Secondary` variant to Collapsible component
|
|
15
|
+
* Add `duplicate`, `classic-view` and `new-view` to icons
|
|
15
16
|
* Add InputWithButton component
|
|
16
|
-
* Fix close modal when
|
|
17
|
+
* Fix close modal when pressing `Escape` key
|
|
18
|
+
* Return focus on Select and MultiSelect components after close
|
|
19
|
+
* Focus in Select and MultiSelect components after close
|
|
20
|
+
|
|
21
|
+
## 0.34.9
|
|
22
|
+
|
|
23
|
+
* Add icon logic to Divider component
|
|
17
24
|
|
|
18
25
|
## 0.34.8
|
|
19
26
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { StoryObj } from '@storybook/react'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { Button } from '../atoms/Button'
|
|
4
|
-
import { Collapsible } from '../atoms/Collapsible'
|
|
4
|
+
import { Collapsible } from '../atoms/Collapsible/Collapsible'
|
|
5
5
|
import { Divider } from '../atoms/Divider'
|
|
6
6
|
import { Actions, Form as FormComponent, FormContainer } from '../atoms/Form'
|
|
7
7
|
import { Input } from '../atoms/Input'
|
|
@@ -245,6 +245,7 @@ export const PrimaryDisabled: Story = {
|
|
|
245
245
|
export const Form: Story = {
|
|
246
246
|
args: {
|
|
247
247
|
form: true,
|
|
248
|
+
open: true,
|
|
248
249
|
title: 'User',
|
|
249
250
|
name: 'user-form',
|
|
250
251
|
variant: 'primary',
|
|
@@ -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
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { CheckableTag, CheckableTagGroup } from '../atoms/CheckableTag'
|
|
3
|
-
import { Collapsible } from '../atoms/Collapsible'
|
|
3
|
+
import { Collapsible } from '../atoms/Collapsible/Collapsible'
|
|
4
4
|
import { DateRangePicker } from '../atoms/DatePicker/DateRangePicker'
|
|
5
5
|
import { Drawer } from '../atoms/Drawer'
|
|
6
6
|
|
|
@@ -26,7 +26,7 @@ const meta = {
|
|
|
26
26
|
description: 'Component title text',
|
|
27
27
|
},
|
|
28
28
|
buttons: {
|
|
29
|
-
description: 'Array of
|
|
29
|
+
description: 'Array of buttons to be shown on the footer',
|
|
30
30
|
},
|
|
31
31
|
},
|
|
32
32
|
parameters: {
|
|
@@ -19,7 +19,7 @@ const meta = {
|
|
|
19
19
|
' <li>Ensure the input and button are visually grouped and aligned</li>' +
|
|
20
20
|
' <li>Support help and error text as in a standard input</li>' +
|
|
21
21
|
' <li>Pass the button or other actionable element through the <code>children</code> prop</li>' +
|
|
22
|
-
' <li>Do not overload with multiple actions
|
|
22
|
+
' <li>Do not overload with multiple actions: Only one clear purpose per instance</li>' +
|
|
23
23
|
'</ul>',
|
|
24
24
|
},
|
|
25
25
|
},
|