datocms-react-ui 0.3.27 → 0.3.28
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 -2
- package/src/Button/index.tsx +173 -0
- package/src/Button/styles.module.css +149 -0
- package/src/Button/styles.module.css.json +1 -0
- package/src/ButtonGroup/Button/index.tsx +40 -0
- package/src/ButtonGroup/Button/styles.module.css +72 -0
- package/src/ButtonGroup/Button/styles.module.css.json +1 -0
- package/src/ButtonGroup/Group/index.tsx +31 -0
- package/src/ButtonGroup/Group/styles.module.css +6 -0
- package/src/ButtonGroup/Group/styles.module.css.json +1 -0
- package/src/ButtonGroup/index.ts +4 -0
- package/src/Canvas/index.tsx +556 -0
- package/src/Canvas/styles.module.css +75 -0
- package/src/Canvas/styles.module.css.json +1 -0
- package/src/ContextInspector/index.tsx +316 -0
- package/src/ContextInspector/styles.module.css +90 -0
- package/src/ContextInspector/styles.module.css.json +1 -0
- package/src/Dropdown/Dropdown.tsx +171 -0
- package/src/Dropdown/DropdownContext.tsx +10 -0
- package/src/Dropdown/Group.tsx +16 -0
- package/src/Dropdown/Menu.tsx +351 -0
- package/src/Dropdown/MenuContext.tsx +18 -0
- package/src/Dropdown/Option.tsx +148 -0
- package/src/Dropdown/OptionAction.tsx +42 -0
- package/src/Dropdown/Portal.tsx +46 -0
- package/src/Dropdown/Separator.tsx +13 -0
- package/src/Dropdown/Text.tsx +8 -0
- package/src/Dropdown/index.tsx +26 -0
- package/src/Dropdown/styles.module.css +331 -0
- package/src/Dropdown/styles.module.css.json +1 -0
- package/src/FieldError/index.tsx +10 -0
- package/src/FieldError/styles.module.css +6 -0
- package/src/FieldError/styles.module.css.json +1 -0
- package/src/FieldGroup/index.tsx +25 -0
- package/src/FieldGroup/styles.module.css +12 -0
- package/src/FieldGroup/styles.module.css.json +1 -0
- package/src/FieldHint/index.tsx +10 -0
- package/src/FieldHint/styles.module.css +6 -0
- package/src/FieldHint/styles.module.css.json +1 -0
- package/src/Form/index.tsx +145 -0
- package/src/Form/styles.module.css +19 -0
- package/src/Form/styles.module.css.json +1 -0
- package/src/FormLabel/index.tsx +36 -0
- package/src/FormLabel/styles.module.css +31 -0
- package/src/FormLabel/styles.module.css.json +1 -0
- package/src/Section/index.tsx +104 -0
- package/src/Section/styles.module.css +100 -0
- package/src/Section/styles.module.css.json +1 -0
- package/src/SelectField/index.tsx +244 -0
- package/src/SelectInput/index.tsx +233 -0
- package/src/SidebarPanel/index.tsx +110 -0
- package/src/SidebarPanel/styles.module.css +49 -0
- package/src/SidebarPanel/styles.module.css.json +1 -0
- package/src/Spinner/index.tsx +68 -0
- package/src/Spinner/styles.module.css +31 -0
- package/src/Spinner/styles.module.css.json +1 -0
- package/src/SwitchField/index.tsx +67 -0
- package/src/SwitchField/styles.module.css +25 -0
- package/src/SwitchField/styles.module.css.json +1 -0
- package/src/SwitchInput/index.tsx +74 -0
- package/src/SwitchInput/styles.module.css +100 -0
- package/src/SwitchInput/styles.module.css.json +1 -0
- package/src/TextField/index.tsx +58 -0
- package/src/TextField/styles.module.css +0 -0
- package/src/TextField/styles.module.css.json +1 -0
- package/src/TextInput/index.tsx +73 -0
- package/src/TextInput/styles.module.css +52 -0
- package/src/TextInput/styles.module.css.json +1 -0
- package/src/Toolbar/Button/index.tsx +32 -0
- package/src/Toolbar/Button/styles.module.css +43 -0
- package/src/Toolbar/Button/styles.module.css.json +1 -0
- package/src/Toolbar/Stack/index.tsx +33 -0
- package/src/Toolbar/Stack/styles.module.css +18 -0
- package/src/Toolbar/Stack/styles.module.css.json +1 -0
- package/src/Toolbar/Title/index.tsx +17 -0
- package/src/Toolbar/Title/styles.module.css +12 -0
- package/src/Toolbar/Title/styles.module.css.json +1 -0
- package/src/Toolbar/Toolbar/index.tsx +112 -0
- package/src/Toolbar/Toolbar/styles.module.css +15 -0
- package/src/Toolbar/Toolbar/styles.module.css.json +1 -0
- package/src/Toolbar/index.ts +8 -0
- package/src/base.css +89 -0
- package/src/generateStyleFromCtx/index.ts +25 -0
- package/src/global.css +23 -0
- package/src/icons.tsx +108 -0
- package/src/index.ts +23 -0
- package/src/mergeRefs/index.ts +8 -0
- package/src/useClickOutside/index.ts +30 -0
- package/src/useMediaQuery/index.ts +185 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React, { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import s from './styles.module.css.json';
|
|
4
|
+
|
|
5
|
+
type SectionProps = {
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
highlighted?: boolean;
|
|
9
|
+
collapsible?: { isOpen: boolean; onToggle: () => void };
|
|
10
|
+
headerClassName?: string;
|
|
11
|
+
titleClassName?: string;
|
|
12
|
+
headerStyle?: CSSProperties;
|
|
13
|
+
titleStyle?: CSSProperties;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @example Basic usage
|
|
18
|
+
*
|
|
19
|
+
* ```jsx
|
|
20
|
+
* <Canvas ctx={ctx}>
|
|
21
|
+
* <Section title="Section title">
|
|
22
|
+
* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
23
|
+
* eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
|
24
|
+
* ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
|
25
|
+
* aliquip ex ea commodo consequat.
|
|
26
|
+
* </Section>
|
|
27
|
+
* </Canvas>;
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example Highlighted
|
|
31
|
+
*
|
|
32
|
+
* ```jsx
|
|
33
|
+
* <Canvas ctx={ctx}>
|
|
34
|
+
* <Section title="Section title" highlighted>
|
|
35
|
+
* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
36
|
+
* eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
|
37
|
+
* ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
|
38
|
+
* aliquip ex ea commodo consequat.
|
|
39
|
+
* </Section>
|
|
40
|
+
* </Canvas>;
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example Collapsible
|
|
44
|
+
*
|
|
45
|
+
* ```jsx
|
|
46
|
+
* <Canvas ctx={ctx}>
|
|
47
|
+
* <StateManager initial={true}>
|
|
48
|
+
* {(isOpen, setOpen) => (
|
|
49
|
+
* <Section
|
|
50
|
+
* title="Section title"
|
|
51
|
+
* collapsible={{ isOpen, onToggle: () => setOpen((v) => !v) }}
|
|
52
|
+
* >
|
|
53
|
+
* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
54
|
+
* eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
|
55
|
+
* enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
|
56
|
+
* nisi ut aliquip ex ea commodo consequat.
|
|
57
|
+
* </Section>
|
|
58
|
+
* )}
|
|
59
|
+
* </StateManager>
|
|
60
|
+
* </Canvas>;
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function Section({
|
|
64
|
+
title,
|
|
65
|
+
children,
|
|
66
|
+
highlighted,
|
|
67
|
+
collapsible,
|
|
68
|
+
headerClassName,
|
|
69
|
+
titleClassName,
|
|
70
|
+
headerStyle,
|
|
71
|
+
titleStyle,
|
|
72
|
+
}: SectionProps): JSX.Element {
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
className={cn(s['Section'], { [s['Section--highlighted']]: highlighted })}
|
|
76
|
+
>
|
|
77
|
+
<div
|
|
78
|
+
className={cn(s['Section__header'], headerClassName)}
|
|
79
|
+
style={headerStyle}
|
|
80
|
+
>
|
|
81
|
+
<div
|
|
82
|
+
className={cn(
|
|
83
|
+
s['Section__title'],
|
|
84
|
+
|
|
85
|
+
titleClassName,
|
|
86
|
+
)}
|
|
87
|
+
style={titleStyle}
|
|
88
|
+
>
|
|
89
|
+
{collapsible && (
|
|
90
|
+
<button
|
|
91
|
+
type="button"
|
|
92
|
+
className={cn(s['Section__arrow'], {
|
|
93
|
+
[s['Section__arrow--is-open']]: collapsible.isOpen,
|
|
94
|
+
})}
|
|
95
|
+
onClick={collapsible.onToggle}
|
|
96
|
+
/>
|
|
97
|
+
)}
|
|
98
|
+
<div className={s['Section__title__content']}>{title}</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
{(!collapsible || collapsible.isOpen) && children}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
.Section {
|
|
2
|
+
position: relative;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.Section--highlighted:before {
|
|
6
|
+
content: '';
|
|
7
|
+
position: absolute;
|
|
8
|
+
top: -20px;
|
|
9
|
+
right: -30px;
|
|
10
|
+
bottom: -20px;
|
|
11
|
+
left: -30px;
|
|
12
|
+
box-shadow: 0 0 0 4px var(--accent-color);
|
|
13
|
+
border-radius: 4px;
|
|
14
|
+
animation: pageContentSectionHighligh 4s 0.25s ease-in-out forwards;
|
|
15
|
+
pointer-events: none;
|
|
16
|
+
z-index: 10;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.Section__header {
|
|
20
|
+
margin-left: var(--negative-spacing-l);
|
|
21
|
+
margin-right: var(--negative-spacing-l);
|
|
22
|
+
margin-bottom: var(--spacing-l);
|
|
23
|
+
position: relative;
|
|
24
|
+
|
|
25
|
+
&:before {
|
|
26
|
+
content: '';
|
|
27
|
+
display: block;
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 50%;
|
|
30
|
+
left: 0;
|
|
31
|
+
right: 0;
|
|
32
|
+
height: 1px;
|
|
33
|
+
background-color: var(--border-color);
|
|
34
|
+
z-index: 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.Section__title {
|
|
39
|
+
font-size: var(--font-size-l);
|
|
40
|
+
font-weight: var(--font-weight-bold);
|
|
41
|
+
margin-left: var(--spacing-m);
|
|
42
|
+
margin-right: var(--spacing-l);
|
|
43
|
+
padding-left: var(--spacing-m);
|
|
44
|
+
padding-right: var(--spacing-m);
|
|
45
|
+
background-color: white;
|
|
46
|
+
position: relative;
|
|
47
|
+
z-index: 2;
|
|
48
|
+
display: inline-flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.Section__title__content {
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.Section__arrow {
|
|
56
|
+
all: initial;
|
|
57
|
+
width: 15px;
|
|
58
|
+
align-self: stretch;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
margin-right: 0.3em;
|
|
61
|
+
|
|
62
|
+
&:before {
|
|
63
|
+
content: '';
|
|
64
|
+
position: absolute;
|
|
65
|
+
height: 0;
|
|
66
|
+
width: 0;
|
|
67
|
+
border-top: 6px solid transparent;
|
|
68
|
+
border-bottom: 6px solid transparent;
|
|
69
|
+
border-left: 6px solid var(--base-body-color);
|
|
70
|
+
left: 14px;
|
|
71
|
+
top: 50%;
|
|
72
|
+
margin-top: -6px;
|
|
73
|
+
transition: transform 0.2s ease-out;
|
|
74
|
+
transform-origin: 50% 50%;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&:hover:before {
|
|
78
|
+
opacity: 0.7;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.Section__arrow--is-open:before {
|
|
83
|
+
transform: rotate(90deg);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@keyframes pageContentSectionHighligh {
|
|
87
|
+
0% {
|
|
88
|
+
box-shadow: 0 0 0 4px var(--accent-color),
|
|
89
|
+
0 0 0 4px rgba(var(--accent-color-rgb-components), 0.7);
|
|
90
|
+
}
|
|
91
|
+
15% {
|
|
92
|
+
box-shadow: 0 0 0 4px var(--accent-color), 0 0 0 80px transparent;
|
|
93
|
+
}
|
|
94
|
+
75% {
|
|
95
|
+
box-shadow: 0 0 0 4px var(--accent-color), 0 0 0 80px transparent;
|
|
96
|
+
}
|
|
97
|
+
100% {
|
|
98
|
+
box-shadow: 0 0 0 4px transparent, 0 0 0 80px transparent;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"Section":"_Section_zh95u_1","Section--highlighted":"_Section--highlighted_zh95u_5","pageContentSectionHighligh":"_pageContentSectionHighligh_zh95u_1","Section__header":"_Section__header_zh95u_19","Section__title":"_Section__title_zh95u_38","Section__title__content":"_Section__title__content_zh95u_52","Section__arrow":"_Section__arrow_zh95u_55","Section__arrow--is-open":"_Section__arrow--is-open_zh95u_82"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
AsyncCreatableSelectInput,
|
|
4
|
+
AsyncCreatableSelectInputProps,
|
|
5
|
+
AsyncSelectInput,
|
|
6
|
+
AsyncSelectInputProps,
|
|
7
|
+
CreatableSelectInput,
|
|
8
|
+
CreatableSelectInputProps,
|
|
9
|
+
FieldError,
|
|
10
|
+
FieldHint,
|
|
11
|
+
FormLabel,
|
|
12
|
+
FormLabelProps,
|
|
13
|
+
SelectInput,
|
|
14
|
+
SelectInputProps,
|
|
15
|
+
} from '..';
|
|
16
|
+
import { GroupBase } from 'react-select';
|
|
17
|
+
|
|
18
|
+
type SelectFieldProps<
|
|
19
|
+
Option,
|
|
20
|
+
IsMulti extends boolean,
|
|
21
|
+
Group extends GroupBase<Option>
|
|
22
|
+
> = {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
label: ReactNode;
|
|
26
|
+
hint?: ReactNode;
|
|
27
|
+
placeholder?: string;
|
|
28
|
+
error?: ReactNode;
|
|
29
|
+
required?: boolean;
|
|
30
|
+
formLabelProps?: FormLabelProps;
|
|
31
|
+
value: SelectInputProps<Option, IsMulti, Group>['value'];
|
|
32
|
+
onChange: SelectInputProps<Option, IsMulti, Group>['onChange'];
|
|
33
|
+
selectInputProps?: SelectInputProps<Option, IsMulti, Group>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export function SelectField<
|
|
37
|
+
Option,
|
|
38
|
+
IsMulti extends boolean,
|
|
39
|
+
Group extends GroupBase<Option>
|
|
40
|
+
>({
|
|
41
|
+
id,
|
|
42
|
+
name,
|
|
43
|
+
label,
|
|
44
|
+
hint,
|
|
45
|
+
error,
|
|
46
|
+
required,
|
|
47
|
+
placeholder,
|
|
48
|
+
formLabelProps,
|
|
49
|
+
value,
|
|
50
|
+
onChange,
|
|
51
|
+
selectInputProps,
|
|
52
|
+
}: SelectFieldProps<Option, IsMulti, Group>): JSX.Element {
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<FormLabel {...formLabelProps} htmlFor={id} required={required} error={!!error}>
|
|
56
|
+
{label}
|
|
57
|
+
</FormLabel>
|
|
58
|
+
|
|
59
|
+
<SelectInput<Option, IsMulti, Group>
|
|
60
|
+
{...selectInputProps}
|
|
61
|
+
id={id}
|
|
62
|
+
name={name}
|
|
63
|
+
value={value}
|
|
64
|
+
placeholder={placeholder}
|
|
65
|
+
onChange={onChange}
|
|
66
|
+
error={!!error}
|
|
67
|
+
/>
|
|
68
|
+
|
|
69
|
+
{error && <FieldError>{error}</FieldError>}
|
|
70
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
type AsyncSelectFieldProps<
|
|
76
|
+
Option,
|
|
77
|
+
IsMulti extends boolean,
|
|
78
|
+
Group extends GroupBase<Option>
|
|
79
|
+
> = {
|
|
80
|
+
id: string;
|
|
81
|
+
name: string;
|
|
82
|
+
label: ReactNode;
|
|
83
|
+
hint?: ReactNode;
|
|
84
|
+
placeholder?: string;
|
|
85
|
+
error?: ReactNode;
|
|
86
|
+
required?: boolean;
|
|
87
|
+
formLabelProps?: FormLabelProps;
|
|
88
|
+
value: AsyncSelectInputProps<Option, IsMulti, Group>['value'];
|
|
89
|
+
onChange: AsyncSelectInputProps<Option, IsMulti, Group>['onChange'];
|
|
90
|
+
selectInputProps?: AsyncSelectInputProps<Option, IsMulti, Group>;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export function AsyncSelectField<
|
|
94
|
+
Option,
|
|
95
|
+
IsMulti extends boolean,
|
|
96
|
+
Group extends GroupBase<Option>
|
|
97
|
+
>({
|
|
98
|
+
id,
|
|
99
|
+
name,
|
|
100
|
+
label,
|
|
101
|
+
hint,
|
|
102
|
+
error,
|
|
103
|
+
required,
|
|
104
|
+
placeholder,
|
|
105
|
+
formLabelProps,
|
|
106
|
+
value,
|
|
107
|
+
onChange,
|
|
108
|
+
selectInputProps,
|
|
109
|
+
}: AsyncSelectFieldProps<Option, IsMulti, Group>): JSX.Element {
|
|
110
|
+
return (
|
|
111
|
+
<>
|
|
112
|
+
<FormLabel {...formLabelProps} htmlFor={id} required={required} error={!!error}>
|
|
113
|
+
{label}
|
|
114
|
+
</FormLabel>
|
|
115
|
+
|
|
116
|
+
<AsyncSelectInput<Option, IsMulti, Group>
|
|
117
|
+
{...selectInputProps}
|
|
118
|
+
id={id}
|
|
119
|
+
name={name}
|
|
120
|
+
value={value}
|
|
121
|
+
placeholder={placeholder}
|
|
122
|
+
onChange={onChange}
|
|
123
|
+
error={!!error}
|
|
124
|
+
/>
|
|
125
|
+
|
|
126
|
+
{error && <FieldError>{error}</FieldError>}
|
|
127
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
128
|
+
</>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
type CreatableSelectFieldProps<
|
|
133
|
+
Option,
|
|
134
|
+
IsMulti extends boolean,
|
|
135
|
+
Group extends GroupBase<Option>
|
|
136
|
+
> = {
|
|
137
|
+
id: string;
|
|
138
|
+
name: string;
|
|
139
|
+
label: ReactNode;
|
|
140
|
+
hint?: ReactNode;
|
|
141
|
+
placeholder?: string;
|
|
142
|
+
error?: ReactNode;
|
|
143
|
+
required?: boolean;
|
|
144
|
+
formLabelProps?: FormLabelProps;
|
|
145
|
+
value: CreatableSelectInputProps<Option, IsMulti, Group>['value'];
|
|
146
|
+
onChange: CreatableSelectInputProps<Option, IsMulti, Group>['onChange'];
|
|
147
|
+
selectInputProps?: CreatableSelectInputProps<Option, IsMulti, Group>;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export function CreatableSelectField<
|
|
151
|
+
Option,
|
|
152
|
+
IsMulti extends boolean,
|
|
153
|
+
Group extends GroupBase<Option>
|
|
154
|
+
>({
|
|
155
|
+
id,
|
|
156
|
+
name,
|
|
157
|
+
label,
|
|
158
|
+
hint,
|
|
159
|
+
error,
|
|
160
|
+
required,
|
|
161
|
+
placeholder,
|
|
162
|
+
formLabelProps,
|
|
163
|
+
value,
|
|
164
|
+
onChange,
|
|
165
|
+
selectInputProps,
|
|
166
|
+
}: CreatableSelectFieldProps<Option, IsMulti, Group>): JSX.Element {
|
|
167
|
+
return (
|
|
168
|
+
<>
|
|
169
|
+
<FormLabel {...formLabelProps} htmlFor={id} required={required} error={!!error}>
|
|
170
|
+
{label}
|
|
171
|
+
</FormLabel>
|
|
172
|
+
|
|
173
|
+
<CreatableSelectInput<Option, IsMulti, Group>
|
|
174
|
+
{...selectInputProps}
|
|
175
|
+
id={id}
|
|
176
|
+
name={name}
|
|
177
|
+
value={value}
|
|
178
|
+
placeholder={placeholder}
|
|
179
|
+
onChange={onChange}
|
|
180
|
+
error={!!error}
|
|
181
|
+
/>
|
|
182
|
+
|
|
183
|
+
{error && <FieldError>{error}</FieldError>}
|
|
184
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
185
|
+
</>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
type AsyncCreatableSelectFieldProps<
|
|
190
|
+
Option,
|
|
191
|
+
IsMulti extends boolean,
|
|
192
|
+
Group extends GroupBase<Option>
|
|
193
|
+
> = {
|
|
194
|
+
id: string;
|
|
195
|
+
name: string;
|
|
196
|
+
label: ReactNode;
|
|
197
|
+
hint?: ReactNode;
|
|
198
|
+
placeholder?: string;
|
|
199
|
+
error?: ReactNode;
|
|
200
|
+
required?: boolean;
|
|
201
|
+
formLabelProps?: FormLabelProps;
|
|
202
|
+
value: AsyncCreatableSelectInputProps<Option, IsMulti, Group>['value'];
|
|
203
|
+
onChange: AsyncCreatableSelectInputProps<Option, IsMulti, Group>['onChange'];
|
|
204
|
+
selectInputProps?: AsyncCreatableSelectInputProps<Option, IsMulti, Group>;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export function AsyncCreatableSelectField<
|
|
208
|
+
Option,
|
|
209
|
+
IsMulti extends boolean,
|
|
210
|
+
Group extends GroupBase<Option>
|
|
211
|
+
>({
|
|
212
|
+
id,
|
|
213
|
+
name,
|
|
214
|
+
label,
|
|
215
|
+
hint,
|
|
216
|
+
error,
|
|
217
|
+
required,
|
|
218
|
+
placeholder,
|
|
219
|
+
formLabelProps,
|
|
220
|
+
value,
|
|
221
|
+
onChange,
|
|
222
|
+
selectInputProps,
|
|
223
|
+
}: AsyncCreatableSelectFieldProps<Option, IsMulti, Group>): JSX.Element {
|
|
224
|
+
return (
|
|
225
|
+
<>
|
|
226
|
+
<FormLabel {...formLabelProps} htmlFor={id} required={required} error={!!error}>
|
|
227
|
+
{label}
|
|
228
|
+
</FormLabel>
|
|
229
|
+
|
|
230
|
+
<AsyncCreatableSelectInput<Option, IsMulti, Group>
|
|
231
|
+
{...selectInputProps}
|
|
232
|
+
id={id}
|
|
233
|
+
name={name}
|
|
234
|
+
value={value}
|
|
235
|
+
placeholder={placeholder}
|
|
236
|
+
onChange={onChange}
|
|
237
|
+
error={!!error}
|
|
238
|
+
/>
|
|
239
|
+
|
|
240
|
+
{error && <FieldError>{error}</FieldError>}
|
|
241
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
242
|
+
</>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import RawSelect, {
|
|
3
|
+
Props as RawSelectProps,
|
|
4
|
+
GroupBase,
|
|
5
|
+
StylesConfig,
|
|
6
|
+
ThemeConfig,
|
|
7
|
+
} from 'react-select';
|
|
8
|
+
import RawAsyncSelect, { AsyncProps } from 'react-select/async';
|
|
9
|
+
import RawAsyncCreatableSelect, {
|
|
10
|
+
AsyncCreatableProps,
|
|
11
|
+
} from 'react-select/async-creatable';
|
|
12
|
+
import RawCreatableSelect, { CreatableProps } from 'react-select/creatable';
|
|
13
|
+
|
|
14
|
+
const themeConfig: ThemeConfig = (existing) => ({
|
|
15
|
+
...existing,
|
|
16
|
+
borderRadius: 0,
|
|
17
|
+
colors: {
|
|
18
|
+
...existing.colors,
|
|
19
|
+
primary25: 'var(--semi-transparent-accent-color)',
|
|
20
|
+
// disabled
|
|
21
|
+
neutral10: 'var(--border-color)',
|
|
22
|
+
// normal
|
|
23
|
+
neutral20: 'var(--border-color)',
|
|
24
|
+
// focused
|
|
25
|
+
primary: 'var(--accent-color)',
|
|
26
|
+
// hover
|
|
27
|
+
neutral30: 'var(--darker-border-color)',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const useStyles = (isDisabled?: boolean, error?: boolean) => {
|
|
32
|
+
return useMemo<StylesConfig>(() => {
|
|
33
|
+
return {
|
|
34
|
+
placeholder: (provided) => ({
|
|
35
|
+
...provided,
|
|
36
|
+
color: 'var(--placeholder-body-color)',
|
|
37
|
+
}),
|
|
38
|
+
container: (provided) => {
|
|
39
|
+
return {
|
|
40
|
+
...provided,
|
|
41
|
+
fontSize: 'inherit',
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
control: (provided, { isFocused }) => {
|
|
46
|
+
let result = provided;
|
|
47
|
+
|
|
48
|
+
result = {
|
|
49
|
+
...result,
|
|
50
|
+
minHeight: 40,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
if (isFocused) {
|
|
54
|
+
return {
|
|
55
|
+
...result,
|
|
56
|
+
borderColor: error ? 'var(--alert-color)' : 'var(--accent-color)',
|
|
57
|
+
backgroundColor: isDisabled ? 'var(--disabled-color)' : 'white',
|
|
58
|
+
boxShadow: `0 0 0 3px ${
|
|
59
|
+
error
|
|
60
|
+
? 'rgba(var(--alert-color-rgb-components), 0.2)'
|
|
61
|
+
: 'var(--semi-transparent-accent-color)'
|
|
62
|
+
}`,
|
|
63
|
+
'&:hover': {
|
|
64
|
+
borderColor: error ? 'var(--alert-color)' : 'var(--accent-color)',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
...result,
|
|
71
|
+
borderColor: error ? 'var(--alert-color)' : 'var(--border-color)',
|
|
72
|
+
backgroundColor: isDisabled ? 'var(--disabled-color)' : 'white',
|
|
73
|
+
'&:hover': {
|
|
74
|
+
borderColor: error
|
|
75
|
+
? 'var(--alert-color)'
|
|
76
|
+
: 'var(--darker-border-color)',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
multiValueRemove: (provided) => ({
|
|
81
|
+
...provided,
|
|
82
|
+
cursor: 'pointer',
|
|
83
|
+
}),
|
|
84
|
+
menu: (provided) => {
|
|
85
|
+
return {
|
|
86
|
+
...provided,
|
|
87
|
+
zIndex: 1000,
|
|
88
|
+
minWidth: 250,
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
input: (provided) => {
|
|
92
|
+
const result = {
|
|
93
|
+
...provided,
|
|
94
|
+
boxShadow: 'none',
|
|
95
|
+
'input:focus': {
|
|
96
|
+
boxShadow: 'none',
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return result;
|
|
101
|
+
},
|
|
102
|
+
multiValue: (provided) => {
|
|
103
|
+
return {
|
|
104
|
+
...provided,
|
|
105
|
+
zIndex: 100,
|
|
106
|
+
backgroundColor: 'var(--light-color)',
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
multiValueLabel: (provided) => ({
|
|
110
|
+
...provided,
|
|
111
|
+
fontSize: 'inherit',
|
|
112
|
+
padding: 3,
|
|
113
|
+
}),
|
|
114
|
+
};
|
|
115
|
+
}, [isDisabled, error]);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
type ErrorProp = { error?: boolean };
|
|
119
|
+
|
|
120
|
+
export type SelectInputProps<
|
|
121
|
+
Option,
|
|
122
|
+
IsMulti extends boolean,
|
|
123
|
+
Group extends GroupBase<Option>
|
|
124
|
+
> = Omit<RawSelectProps<Option, IsMulti, Group>, 'theme' | 'styles'> &
|
|
125
|
+
ErrorProp;
|
|
126
|
+
|
|
127
|
+
export function SelectInput<
|
|
128
|
+
Option = unknown,
|
|
129
|
+
IsMulti extends boolean = false,
|
|
130
|
+
Group extends GroupBase<Option> = GroupBase<Option>
|
|
131
|
+
>({
|
|
132
|
+
isDisabled,
|
|
133
|
+
error,
|
|
134
|
+
...other
|
|
135
|
+
}: SelectInputProps<Option, IsMulti, Group>): JSX.Element {
|
|
136
|
+
const styles = useStyles(isDisabled, error);
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<RawSelect<Option, IsMulti, Group>
|
|
140
|
+
{...other}
|
|
141
|
+
isDisabled={isDisabled}
|
|
142
|
+
theme={themeConfig}
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
144
|
+
styles={styles as any}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export type AsyncSelectInputProps<
|
|
150
|
+
Option,
|
|
151
|
+
IsMulti extends boolean,
|
|
152
|
+
Group extends GroupBase<Option>
|
|
153
|
+
> = Omit<AsyncProps<Option, IsMulti, Group>, 'theme' | 'styles'> & ErrorProp;
|
|
154
|
+
|
|
155
|
+
export function AsyncSelectInput<
|
|
156
|
+
Option = unknown,
|
|
157
|
+
IsMulti extends boolean = false,
|
|
158
|
+
Group extends GroupBase<Option> = GroupBase<Option>
|
|
159
|
+
>({
|
|
160
|
+
isDisabled,
|
|
161
|
+
error,
|
|
162
|
+
...other
|
|
163
|
+
}: AsyncSelectInputProps<Option, IsMulti, Group>): JSX.Element {
|
|
164
|
+
const styles = useStyles(isDisabled, error);
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<RawAsyncSelect<Option, IsMulti, Group>
|
|
168
|
+
{...other}
|
|
169
|
+
isDisabled={isDisabled}
|
|
170
|
+
theme={themeConfig}
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
|
+
styles={styles as any}
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export type CreatableSelectInputProps<
|
|
178
|
+
Option,
|
|
179
|
+
IsMulti extends boolean,
|
|
180
|
+
Group extends GroupBase<Option>
|
|
181
|
+
> = Omit<CreatableProps<Option, IsMulti, Group>, 'theme' | 'styles'> &
|
|
182
|
+
ErrorProp;
|
|
183
|
+
|
|
184
|
+
export function CreatableSelectInput<
|
|
185
|
+
Option = unknown,
|
|
186
|
+
IsMulti extends boolean = false,
|
|
187
|
+
Group extends GroupBase<Option> = GroupBase<Option>
|
|
188
|
+
>({
|
|
189
|
+
isDisabled,
|
|
190
|
+
error,
|
|
191
|
+
...other
|
|
192
|
+
}: CreatableSelectInputProps<Option, IsMulti, Group>): JSX.Element {
|
|
193
|
+
const styles = useStyles(isDisabled, error);
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<RawCreatableSelect<Option, IsMulti, Group>
|
|
197
|
+
{...other}
|
|
198
|
+
isDisabled={isDisabled}
|
|
199
|
+
theme={themeConfig}
|
|
200
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
201
|
+
styles={styles as any}
|
|
202
|
+
/>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export type AsyncCreatableSelectInputProps<
|
|
207
|
+
Option,
|
|
208
|
+
IsMulti extends boolean,
|
|
209
|
+
Group extends GroupBase<Option>
|
|
210
|
+
> = Omit<AsyncCreatableProps<Option, IsMulti, Group>, 'theme' | 'styles'> &
|
|
211
|
+
ErrorProp;
|
|
212
|
+
|
|
213
|
+
export function AsyncCreatableSelectInput<
|
|
214
|
+
Option = unknown,
|
|
215
|
+
IsMulti extends boolean = false,
|
|
216
|
+
Group extends GroupBase<Option> = GroupBase<Option>
|
|
217
|
+
>({
|
|
218
|
+
isDisabled,
|
|
219
|
+
error,
|
|
220
|
+
...other
|
|
221
|
+
}: AsyncCreatableSelectInputProps<Option, IsMulti, Group>): JSX.Element {
|
|
222
|
+
const styles = useStyles(isDisabled, error);
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<RawAsyncCreatableSelect<Option, IsMulti, Group>
|
|
226
|
+
{...other}
|
|
227
|
+
isDisabled={isDisabled}
|
|
228
|
+
theme={themeConfig}
|
|
229
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
230
|
+
styles={styles as any}
|
|
231
|
+
/>
|
|
232
|
+
);
|
|
233
|
+
}
|