agroptima-design-system 0.36.0-beta.3 → 0.36.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/Button/Button.tsx +6 -2
- package/src/atoms/Card/Card.scss +6 -6
- package/src/atoms/Card/CardContent.tsx +1 -1
- package/src/atoms/Card/CardFooter.tsx +1 -1
- package/src/atoms/Card/CardHeader.tsx +4 -2
- package/src/atoms/Checkbox.tsx +1 -1
- package/src/atoms/{Collapsible.scss → Collapsible/Collapsible.scss} +27 -45
- package/src/atoms/{Collapsible.tsx → Collapsible/Collapsible.tsx} +10 -10
- package/src/atoms/Collapsible/index.ts +5 -0
- package/src/atoms/DatePicker/DateRangePicker.tsx +3 -0
- package/src/atoms/DatePicker/DateSinglePicker.tsx +3 -0
- package/src/atoms/Input.scss +31 -0
- package/src/atoms/Input.tsx +7 -1
- package/src/atoms/InputWithButton/InputWithButton.scss +11 -0
- package/src/atoms/InputWithButton/InputWithButton.tsx +10 -0
- package/src/atoms/InputWithButton/index.tsx +3 -0
- package/src/atoms/Modal/ModalDialog.tsx +18 -0
- package/src/atoms/Multiselect.tsx +13 -0
- package/src/atoms/Popover/Popover.tsx +1 -1
- package/src/atoms/QuantitySelector.tsx +7 -1
- package/src/atoms/Select/Select.scss +14 -8
- package/src/atoms/Select/Select.tsx +13 -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/atoms/TextArea.tsx +3 -0
- package/src/hooks/useOpen.ts +1 -0
- package/src/icons/classic-view.svg +1 -0
- package/src/icons/duplicate.svg +1 -0
- package/src/icons/index.tsx +6 -0
- package/src/icons/new-view.svg +1 -0
- package/src/stories/Button.stories.ts +4 -0
- package/src/stories/Changelog.mdx +14 -1
- package/src/stories/{Collapsible.stories.js → Collapsible.stories.tsx} +64 -37
- package/src/stories/DateRangePicker.stories.ts +5 -0
- package/src/stories/DateSinglePicker.stories.ts +5 -0
- package/src/stories/Drawer.stories.js +2 -2
- package/src/stories/Input.stories.ts +32 -0
- package/src/stories/InputWithButton.stories.tsx +75 -0
- package/src/stories/Modal.stories.tsx +341 -0
- package/src/stories/Multiselect.stories.ts +4 -0
- package/src/stories/QuantitySelector.stories.ts +5 -0
- package/src/stories/Select.stories.ts +4 -0
- package/src/stories/TextArea.stories.ts +4 -0
- package/tests/Card.spec.tsx +3 -3
- package/tests/Modal.spec.tsx +79 -11
- package/tests/Select.spec.tsx +17 -0
- package/tsconfig.json +0 -1
- package/src/stories/Modal.stories.js +0 -444
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agroptima-design-system",
|
|
3
|
-
"version": "0.36.0
|
|
3
|
+
"version": "0.36.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>
|
|
@@ -13,6 +13,7 @@ interface CustomProps {
|
|
|
13
13
|
variant?: ButtonVariant
|
|
14
14
|
loading?: boolean
|
|
15
15
|
disabled?: boolean
|
|
16
|
+
fullWidth?: boolean
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export type ButtonProps = CustomProps & BaseButtonProps
|
|
@@ -43,13 +44,16 @@ export function Button({
|
|
|
43
44
|
leftIcon,
|
|
44
45
|
rightIcon,
|
|
45
46
|
disabled,
|
|
47
|
+
className,
|
|
46
48
|
variant = 'primary',
|
|
47
49
|
loading = false,
|
|
48
|
-
|
|
50
|
+
fullWidth = false,
|
|
49
51
|
...props
|
|
50
52
|
}: ButtonProps) {
|
|
51
53
|
const leftIconName = loading ? 'Loading' : leftIcon
|
|
52
|
-
const cssClasses = classNames(className, 'button', variant
|
|
54
|
+
const cssClasses = classNames(className, 'button', variant, {
|
|
55
|
+
'full-width': fullWidth,
|
|
56
|
+
})
|
|
53
57
|
|
|
54
58
|
return (
|
|
55
59
|
<BaseButton
|
package/src/atoms/Card/Card.scss
CHANGED
|
@@ -27,13 +27,13 @@ a.card {
|
|
|
27
27
|
gap: config.$space-4x;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
.header {
|
|
30
|
+
.card-header {
|
|
31
31
|
display: flex;
|
|
32
32
|
flex-direction: row;
|
|
33
33
|
justify-content: space-between;
|
|
34
34
|
gap: config.$space-1x;
|
|
35
35
|
|
|
36
|
-
.title {
|
|
36
|
+
.card-title {
|
|
37
37
|
overflow: hidden;
|
|
38
38
|
text-overflow: ellipsis;
|
|
39
39
|
line-clamp: 2;
|
|
@@ -41,16 +41,16 @@ 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
|
}
|
|
48
48
|
|
|
49
|
-
.content {
|
|
49
|
+
.card-content {
|
|
50
50
|
margin-bottom: config.$space-1x;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
.footer {
|
|
53
|
+
.card-footer {
|
|
54
54
|
display: flex;
|
|
55
55
|
flex-direction: column;
|
|
56
56
|
gap: config.$space-2x;
|
|
@@ -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
|
}
|
|
@@ -10,7 +10,7 @@ export function CardContent({
|
|
|
10
10
|
children,
|
|
11
11
|
...props
|
|
12
12
|
}: CardContentProps): React.JSX.Element {
|
|
13
|
-
const cssClasses = classNames('content', className)
|
|
13
|
+
const cssClasses = classNames('card-content', className)
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
16
|
<div className={cssClasses} {...props}>
|
|
@@ -10,7 +10,7 @@ export function CardFooter({
|
|
|
10
10
|
children,
|
|
11
11
|
...props
|
|
12
12
|
}: CardFooterProps): React.JSX.Element {
|
|
13
|
-
const cssClasses = classNames('footer', className)
|
|
13
|
+
const cssClasses = classNames('card-footer', className)
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
16
|
<div className={cssClasses} {...props}>
|
|
@@ -14,11 +14,13 @@ export function CardHeader({
|
|
|
14
14
|
children,
|
|
15
15
|
...props
|
|
16
16
|
}: CardHeaderProps): React.JSX.Element {
|
|
17
|
-
const cssClasses = classNames('header', className, { bold: isBold })
|
|
17
|
+
const cssClasses = classNames('card-header', className, { bold: isBold })
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
20
|
<div className={cssClasses} {...props}>
|
|
21
|
-
<span className={classNames('title', { bold: isBold })}>
|
|
21
|
+
<span className={classNames('card-title', { 'card-bold': isBold })}>
|
|
22
|
+
{title}
|
|
23
|
+
</span>
|
|
22
24
|
{children && <div className="actions">{children}</div>}
|
|
23
25
|
</div>
|
|
24
26
|
)
|
package/src/atoms/Checkbox.tsx
CHANGED
|
@@ -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;
|
|
@@ -18,33 +19,22 @@ details summary::-webkit-details-marker {
|
|
|
18
19
|
user-select: none;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
.header {
|
|
22
|
+
.collapsible-header {
|
|
22
23
|
display: flex;
|
|
23
|
-
align-items: center
|
|
24
|
+
align-items: center;
|
|
24
25
|
gap: config.$space-3x;
|
|
25
26
|
padding: config.$space-5x;
|
|
26
|
-
padding-bottom: config.$space-5x !important;
|
|
27
27
|
cursor: default;
|
|
28
28
|
|
|
29
|
-
.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
> svg {
|
|
33
|
-
width: 100%;
|
|
34
|
-
height: 100%;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.title {
|
|
39
|
-
font-size: 1rem !important;
|
|
40
|
-
font-weight: normal !important;
|
|
29
|
+
.collapsible-title {
|
|
30
|
+
font-size: 1rem;
|
|
31
|
+
font-weight: normal;
|
|
41
32
|
flex: 1;
|
|
42
33
|
}
|
|
43
34
|
}
|
|
44
35
|
|
|
45
|
-
.content {
|
|
46
|
-
padding: config.$space-7x;
|
|
47
|
-
padding-bottom: config.$space-3x;
|
|
36
|
+
.collapsible-content {
|
|
37
|
+
padding: config.$space-7x config.$space-7x config.$space-3x;
|
|
48
38
|
|
|
49
39
|
&.no-horizontal-padding {
|
|
50
40
|
padding-left: 0;
|
|
@@ -52,54 +42,46 @@ details summary::-webkit-details-marker {
|
|
|
52
42
|
}
|
|
53
43
|
}
|
|
54
44
|
|
|
55
|
-
&.primary {
|
|
45
|
+
&.primary, &.secondary {
|
|
56
46
|
&[open] {
|
|
57
|
-
.header {
|
|
47
|
+
.collapsible-header {
|
|
58
48
|
background: transparent;
|
|
59
49
|
border-bottom: 3px solid color_alias.$primary-color-600;
|
|
60
50
|
}
|
|
61
51
|
}
|
|
62
52
|
|
|
63
53
|
&.disabled {
|
|
64
|
-
.header {
|
|
54
|
+
.collapsible-header {
|
|
65
55
|
background: color_alias.$neutral-color-50;
|
|
66
56
|
border-bottom: 1px solid color_alias.$neutral-color-200;
|
|
67
57
|
color: color_alias.$neutral-color-200;
|
|
68
|
-
|
|
69
|
-
.icon {
|
|
70
|
-
> svg {
|
|
71
|
-
fill: color_alias.$neutral-color-200;
|
|
72
|
-
path {
|
|
73
|
-
fill: color_alias.$neutral-color-200;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
58
|
+
@include mixins.svg-color(color_alias.$neutral-color-200);
|
|
77
59
|
}
|
|
78
60
|
}
|
|
79
61
|
|
|
80
|
-
.header {
|
|
62
|
+
.collapsible-header {
|
|
81
63
|
color: color_alias.$neutral-color-1000;
|
|
82
64
|
background: transparent;
|
|
83
65
|
border-bottom: 1px solid color_alias.$neutral-color-200;
|
|
84
|
-
|
|
85
|
-
.icon {
|
|
86
|
-
> svg {
|
|
87
|
-
fill: color_alias.$primary-color-600;
|
|
88
|
-
path {
|
|
89
|
-
fill: color_alias.$primary-color-600;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
66
|
+
@include mixins.svg-color(color_alias.$primary-color-600);
|
|
93
67
|
|
|
94
68
|
&:hover {
|
|
95
69
|
background: color_alias.$primary-color-50;
|
|
96
70
|
}
|
|
97
71
|
}
|
|
98
72
|
}
|
|
73
|
+
|
|
74
|
+
&.secondary .collapsible-content {
|
|
75
|
+
padding: config.$space-3x config.$space-4x config.$space-6x;
|
|
76
|
+
border: 1px solid color_alias.$neutral-color-200;
|
|
77
|
+
border-top: none;
|
|
78
|
+
border-bottom-left-radius: config.$corner-radius-m;
|
|
79
|
+
border-bottom-right-radius: config.$corner-radius-m;
|
|
80
|
+
}
|
|
99
81
|
}
|
|
100
82
|
|
|
101
83
|
.collapsible[open] {
|
|
102
|
-
.arrow {
|
|
84
|
+
.collapsible-arrow {
|
|
103
85
|
transform: rotate(90deg);
|
|
104
86
|
}
|
|
105
87
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import './Collapsible.scss'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import type { ComponentPropsWithoutRef } from 'react'
|
|
3
|
+
import { classNames } from '../../utils/classNames'
|
|
4
|
+
import { Icon } from '../Icon'
|
|
4
5
|
|
|
5
|
-
export type Variant = 'primary'
|
|
6
|
+
export type Variant = 'primary' | 'secondary'
|
|
6
7
|
|
|
7
|
-
export interface CollapsibleProps
|
|
8
|
-
extends React.ComponentPropsWithoutRef<'details'> {
|
|
8
|
+
export interface CollapsibleProps extends ComponentPropsWithoutRef<'details'> {
|
|
9
9
|
title: string
|
|
10
10
|
variant?: Variant
|
|
11
11
|
name?: string
|
|
@@ -24,21 +24,21 @@ export function Collapsible({
|
|
|
24
24
|
form = false,
|
|
25
25
|
noHorizontalPadding = false,
|
|
26
26
|
...props
|
|
27
|
-
}: CollapsibleProps)
|
|
27
|
+
}: CollapsibleProps) {
|
|
28
28
|
const cssClasses = classNames('collapsible', variant, className, {
|
|
29
29
|
open: props.open,
|
|
30
30
|
disabled: disabled,
|
|
31
31
|
})
|
|
32
|
-
const contentCssClasses = classNames('content', {
|
|
32
|
+
const contentCssClasses = classNames('collapsible-content', {
|
|
33
33
|
'no-horizontal-padding': noHorizontalPadding,
|
|
34
34
|
form: form,
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
return (
|
|
38
38
|
<details name={name} className={cssClasses} aria-label={title} {...props}>
|
|
39
|
-
<summary className="header">
|
|
40
|
-
<Icon className="arrow" name="AngleRight" />
|
|
41
|
-
<span className="title">{title}</span>
|
|
39
|
+
<summary className="collapsible-header">
|
|
40
|
+
<Icon className="collapsible-arrow" name="AngleRight" size="4" />
|
|
41
|
+
<span className="collapsible-title">{title}</span>
|
|
42
42
|
</summary>
|
|
43
43
|
<div className={contentCssClasses}>{children}</div>
|
|
44
44
|
</details>
|
|
@@ -29,6 +29,7 @@ export type DateRangePickerProps = {
|
|
|
29
29
|
name?: string
|
|
30
30
|
helpText?: string
|
|
31
31
|
errors?: string[]
|
|
32
|
+
fullWidth?: boolean
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export type DateRange = {
|
|
@@ -48,10 +49,12 @@ export function DateRangePicker({
|
|
|
48
49
|
label = 'Date',
|
|
49
50
|
errors,
|
|
50
51
|
helpText,
|
|
52
|
+
fullWidth = false,
|
|
51
53
|
}: DateRangePickerProps): JSX.Element {
|
|
52
54
|
const cssClasses = classNames('date-picker', variant, className, {
|
|
53
55
|
toggle: withInput,
|
|
54
56
|
invalid: errors?.length,
|
|
57
|
+
'full-width': fullWidth,
|
|
55
58
|
})
|
|
56
59
|
const helpTexts = buildHelpText(helpText, errors)
|
|
57
60
|
|
|
@@ -28,6 +28,7 @@ export type DateSinglePickerProps = {
|
|
|
28
28
|
label?: string
|
|
29
29
|
helpText?: string
|
|
30
30
|
errors?: string[]
|
|
31
|
+
fullWidth?: boolean
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export function DateSinglePicker({
|
|
@@ -42,6 +43,7 @@ export function DateSinglePicker({
|
|
|
42
43
|
label = 'Date',
|
|
43
44
|
errors,
|
|
44
45
|
helpText,
|
|
46
|
+
fullWidth = false,
|
|
45
47
|
}: DateSinglePickerProps): JSX.Element {
|
|
46
48
|
const { isOpen, close, toggle } = useOpen(!withInput)
|
|
47
49
|
const pickerRef = useRef(null)
|
|
@@ -51,6 +53,7 @@ export function DateSinglePicker({
|
|
|
51
53
|
const cssClasses = classNames('date-picker', variant, className, {
|
|
52
54
|
toggle: withInput,
|
|
53
55
|
invalid: errors?.length,
|
|
56
|
+
'full-width': fullWidth,
|
|
54
57
|
})
|
|
55
58
|
|
|
56
59
|
const [selected, setSelected] = useState<Date | undefined>(
|
package/src/atoms/Input.scss
CHANGED
|
@@ -17,16 +17,20 @@
|
|
|
17
17
|
flex-direction: row;
|
|
18
18
|
width: 100%;
|
|
19
19
|
padding: config.$space-2x config.$space-3x config.$space-2x;
|
|
20
|
+
|
|
20
21
|
input[type='date'] {
|
|
21
22
|
min-width: -webkit-fill-available;
|
|
22
23
|
}
|
|
24
|
+
|
|
23
25
|
input[type='number'] {
|
|
24
26
|
text-align: right;
|
|
25
27
|
}
|
|
28
|
+
|
|
26
29
|
input::placeholder,
|
|
27
30
|
textarea::placeholder {
|
|
28
31
|
@include typography.input-placeholder-text;
|
|
29
32
|
}
|
|
33
|
+
|
|
30
34
|
input,
|
|
31
35
|
input:hover,
|
|
32
36
|
input:focus,
|
|
@@ -52,10 +56,12 @@
|
|
|
52
56
|
-moz-appearance: none;
|
|
53
57
|
appearance: none;
|
|
54
58
|
}
|
|
59
|
+
|
|
55
60
|
.input-suffix {
|
|
56
61
|
text-wrap: nowrap;
|
|
57
62
|
color: color_alias.$neutral-color-600;
|
|
58
63
|
}
|
|
64
|
+
|
|
59
65
|
.icon {
|
|
60
66
|
min-width: config.$icon-size-5x;
|
|
61
67
|
width: config.$icon-size-5x;
|
|
@@ -72,6 +78,7 @@
|
|
|
72
78
|
&.invalid .input-container {
|
|
73
79
|
border: 1px solid color_alias.$error-color-1000;
|
|
74
80
|
}
|
|
81
|
+
|
|
75
82
|
.input-container {
|
|
76
83
|
border-radius: config.$corner-radius-m;
|
|
77
84
|
border: 1px solid color_alias.$neutral-color-600;
|
|
@@ -87,6 +94,7 @@
|
|
|
87
94
|
&:has(textarea:disabled) {
|
|
88
95
|
border: 1px solid color_alias.$neutral-color-400;
|
|
89
96
|
background: color_alias.$neutral-color-50;
|
|
97
|
+
|
|
90
98
|
input {
|
|
91
99
|
color: color_alias.$neutral-color-400;
|
|
92
100
|
}
|
|
@@ -96,9 +104,11 @@
|
|
|
96
104
|
color: color_alias.$neutral-color-400;
|
|
97
105
|
}
|
|
98
106
|
}
|
|
107
|
+
|
|
99
108
|
.icon {
|
|
100
109
|
> svg {
|
|
101
110
|
fill: color_alias.$neutral-color-400;
|
|
111
|
+
|
|
102
112
|
path {
|
|
103
113
|
fill: color_alias.$neutral-color-400;
|
|
104
114
|
}
|
|
@@ -108,6 +118,7 @@
|
|
|
108
118
|
.password-icon {
|
|
109
119
|
> svg {
|
|
110
120
|
fill: color_alias.$neutral-color-600;
|
|
121
|
+
|
|
111
122
|
path {
|
|
112
123
|
fill: color_alias.$neutral-color-600;
|
|
113
124
|
}
|
|
@@ -115,20 +126,25 @@
|
|
|
115
126
|
}
|
|
116
127
|
}
|
|
117
128
|
}
|
|
129
|
+
|
|
118
130
|
&.file .input-container {
|
|
119
131
|
padding: 0;
|
|
120
132
|
border: transparent;
|
|
133
|
+
|
|
121
134
|
&:has(input:focus) {
|
|
122
135
|
border: transparent;
|
|
123
136
|
}
|
|
137
|
+
|
|
124
138
|
input {
|
|
125
139
|
color: color_alias.$neutral-color-600;
|
|
140
|
+
|
|
126
141
|
&::before {
|
|
127
142
|
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='12' fill='none'%3E%3Cpath d='M2.943 8.718h4.114V4.694H9.8L5 0 .2 4.694h2.743v4.024ZM5 1.898l1.488 1.455h-.802v4.023H4.314V3.353h-.802L5 1.898Zm-4.8 8.16h9.6V11.4H.2v-1.341Z' fill='%23EB004D'/%3E%3C/svg%3E");
|
|
128
143
|
position: absolute;
|
|
129
144
|
left: config.$space-3x;
|
|
130
145
|
bottom: config.$space-2x;
|
|
131
146
|
}
|
|
147
|
+
|
|
132
148
|
&::file-selector-button {
|
|
133
149
|
margin-right: config.$space-2x;
|
|
134
150
|
padding-left: config.$space-3x + config.$icon-size-2x + config.$space-1x;
|
|
@@ -136,8 +152,23 @@
|
|
|
136
152
|
}
|
|
137
153
|
}
|
|
138
154
|
}
|
|
155
|
+
|
|
139
156
|
&.hidden {
|
|
140
157
|
display: none;
|
|
141
158
|
}
|
|
142
159
|
|
|
160
|
+
&.ellipsis {
|
|
161
|
+
input {
|
|
162
|
+
text-overflow: ellipsis;
|
|
163
|
+
overflow: hidden;
|
|
164
|
+
white-space: nowrap;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
&.borderless {
|
|
169
|
+
.input-container {
|
|
170
|
+
padding-left: 0;
|
|
171
|
+
padding-right: 0;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
143
174
|
}
|
package/src/atoms/Input.tsx
CHANGED
|
@@ -7,7 +7,7 @@ import type { IconType } from './Icon'
|
|
|
7
7
|
import { Icon } from './Icon'
|
|
8
8
|
import { Label } from './Label'
|
|
9
9
|
|
|
10
|
-
export type InputVariant = 'primary'
|
|
10
|
+
export type InputVariant = 'primary' | 'borderless'
|
|
11
11
|
|
|
12
12
|
export interface InputProps extends React.ComponentPropsWithRef<'input'> {
|
|
13
13
|
label: string
|
|
@@ -20,6 +20,8 @@ export interface InputProps extends React.ComponentPropsWithRef<'input'> {
|
|
|
20
20
|
suffix?: string
|
|
21
21
|
errors?: string[]
|
|
22
22
|
rightIcon?: IconType
|
|
23
|
+
fullWidth?: boolean
|
|
24
|
+
ellipsis?: boolean
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export function Input({
|
|
@@ -37,6 +39,8 @@ export function Input({
|
|
|
37
39
|
id,
|
|
38
40
|
errors,
|
|
39
41
|
rightIcon,
|
|
42
|
+
fullWidth = false,
|
|
43
|
+
ellipsis = false,
|
|
40
44
|
...props
|
|
41
45
|
}: InputProps): React.JSX.Element {
|
|
42
46
|
const identifier = id || name
|
|
@@ -62,6 +66,8 @@ export function Input({
|
|
|
62
66
|
file: type === 'file',
|
|
63
67
|
invalid: errors?.length,
|
|
64
68
|
hidden: type === 'hidden',
|
|
69
|
+
'full-width': fullWidth,
|
|
70
|
+
ellipsis: ellipsis,
|
|
65
71
|
})}
|
|
66
72
|
>
|
|
67
73
|
{!hideLabel && (
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import './InputWithButton.scss'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
interface InputWithButtonProps {
|
|
5
|
+
children: React.ReactNode
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function InputWithButton({ children }: InputWithButtonProps) {
|
|
9
|
+
return <div className="input-with-button">{children}</div>
|
|
10
|
+
}
|
|
@@ -36,6 +36,22 @@ export function ModalDialog({
|
|
|
36
36
|
}
|
|
37
37
|
}, [])
|
|
38
38
|
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const dialog = dialogRef.current
|
|
41
|
+
if (!dialog) return
|
|
42
|
+
|
|
43
|
+
const handleCancel = (event: Event) => {
|
|
44
|
+
event.preventDefault()
|
|
45
|
+
onClose?.()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
dialog.addEventListener('cancel', handleCancel)
|
|
49
|
+
|
|
50
|
+
return () => {
|
|
51
|
+
dialog.removeEventListener('cancel', handleCancel)
|
|
52
|
+
}
|
|
53
|
+
}, [onClose])
|
|
54
|
+
|
|
39
55
|
useEffect(() => {
|
|
40
56
|
if (isOpen) {
|
|
41
57
|
dialogRef.current?.showModal()
|
|
@@ -46,6 +62,8 @@ export function ModalDialog({
|
|
|
46
62
|
|
|
47
63
|
return (
|
|
48
64
|
<dialog
|
|
65
|
+
role="dialog"
|
|
66
|
+
aria-modal="true"
|
|
49
67
|
ref={dialogRef}
|
|
50
68
|
className={classNames('modal', className, { 'modal-details': details })}
|
|
51
69
|
onClick={handleClick}
|
|
@@ -30,6 +30,7 @@ export interface MultiselectProps extends InputPropsWithoutOnChange {
|
|
|
30
30
|
onChange?: (value: string[]) => void
|
|
31
31
|
isSearchable?: boolean
|
|
32
32
|
searchLabel?: string
|
|
33
|
+
fullWidth?: boolean
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export function Multiselect({
|
|
@@ -50,15 +51,23 @@ export function Multiselect({
|
|
|
50
51
|
defaultValue = [],
|
|
51
52
|
isSearchable = false,
|
|
52
53
|
searchLabel = 'Search',
|
|
54
|
+
fullWidth = false,
|
|
53
55
|
...props
|
|
54
56
|
}: MultiselectProps): React.JSX.Element {
|
|
55
57
|
const { isOpen, close, toggle } = useOpen()
|
|
56
58
|
const selectRef = useRef(null)
|
|
59
|
+
const selectTriggerRef = useRef<HTMLButtonElement | null>(null)
|
|
57
60
|
useOutsideClick(selectRef, close)
|
|
58
61
|
const [selectedOptions, setSelectedOptions] = useState<string[]>(defaultValue)
|
|
59
62
|
const isInvalid = Boolean(errors?.length)
|
|
60
63
|
const hasSelectedOptions = selectedOptions.length > 0
|
|
61
64
|
|
|
65
|
+
const handleClose = () => {
|
|
66
|
+
if (!isOpen) return
|
|
67
|
+
close()
|
|
68
|
+
selectTriggerRef?.current?.focus()
|
|
69
|
+
}
|
|
70
|
+
|
|
62
71
|
function handleSelectOption({ id }: Option) {
|
|
63
72
|
const isOptionSelected = selectedOptions.includes(id)
|
|
64
73
|
const options = isOptionSelected
|
|
@@ -74,6 +83,7 @@ export function Multiselect({
|
|
|
74
83
|
setSelectedOptions([])
|
|
75
84
|
onChange([])
|
|
76
85
|
}
|
|
86
|
+
|
|
77
87
|
const identifier = id || name
|
|
78
88
|
return (
|
|
79
89
|
<div
|
|
@@ -81,6 +91,7 @@ export function Multiselect({
|
|
|
81
91
|
disabled,
|
|
82
92
|
filled: hasSelectedOptions,
|
|
83
93
|
invalid: isInvalid,
|
|
94
|
+
'full-width': fullWidth,
|
|
84
95
|
})}
|
|
85
96
|
ref={selectRef}
|
|
86
97
|
>
|
|
@@ -99,6 +110,7 @@ export function Multiselect({
|
|
|
99
110
|
onClick={toggle}
|
|
100
111
|
onClear={handleClear}
|
|
101
112
|
isEmpty={!hasSelectedOptions}
|
|
113
|
+
buttonRef={selectTriggerRef}
|
|
102
114
|
>
|
|
103
115
|
{hasSelectedOptions
|
|
104
116
|
? `${selectedOptions.length} ${selectedLabel}`
|
|
@@ -113,6 +125,7 @@ export function Multiselect({
|
|
|
113
125
|
selectOption={handleSelectOption}
|
|
114
126
|
isSearchable={isSearchable}
|
|
115
127
|
searchLabel={searchLabel}
|
|
128
|
+
onClose={handleClose}
|
|
116
129
|
/>
|
|
117
130
|
)}
|
|
118
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'
|
|
@@ -14,6 +14,7 @@ export interface QuantitySelectorProps extends Omit<InputProps, 'type'> {
|
|
|
14
14
|
hideLabel?: boolean
|
|
15
15
|
id?: string
|
|
16
16
|
variant?: Variant
|
|
17
|
+
fullWidth?: boolean
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export function QuantitySelector({
|
|
@@ -24,6 +25,7 @@ export function QuantitySelector({
|
|
|
24
25
|
disabled,
|
|
25
26
|
hideLabel = false,
|
|
26
27
|
variant = 'primary',
|
|
28
|
+
fullWidth = false,
|
|
27
29
|
...props
|
|
28
30
|
}: QuantitySelectorProps): React.JSX.Element {
|
|
29
31
|
const inputRef = useRef<HTMLInputElement>(null)
|
|
@@ -41,7 +43,11 @@ export function QuantitySelector({
|
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
return (
|
|
44
|
-
<div
|
|
46
|
+
<div
|
|
47
|
+
className={classNames('quantity-selector-group', variant, className, {
|
|
48
|
+
'full-width': fullWidth,
|
|
49
|
+
})}
|
|
50
|
+
>
|
|
45
51
|
{!hideLabel && (
|
|
46
52
|
<Label required={props.required} htmlFor={id}>
|
|
47
53
|
{label}
|