@charcoal-ui/react 3.0.0-beta.2 → 3.0.0-beta.4
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/dist/_lib/compat.d.ts +19 -1
- package/dist/_lib/compat.d.ts.map +1 -1
- package/dist/_lib/index.d.ts +7 -0
- package/dist/_lib/index.d.ts.map +1 -1
- package/dist/components/Button/index.d.ts +1 -2
- package/dist/components/Button/index.d.ts.map +1 -1
- package/dist/components/Button/index.story.d.ts +1 -2
- package/dist/components/Button/index.story.d.ts.map +1 -1
- package/dist/components/Button/index.test.d.ts +4 -0
- package/dist/components/Button/index.test.d.ts.map +1 -0
- package/dist/components/Checkbox/index.d.ts +2 -1
- package/dist/components/Checkbox/index.d.ts.map +1 -1
- package/dist/components/Checkbox/index.story.d.ts +2 -2
- package/dist/components/Checkbox/index.story.d.ts.map +1 -1
- package/dist/components/Clickable/index.d.ts +1 -1
- package/dist/components/Clickable/index.d.ts.map +1 -1
- package/dist/components/Clickable/index.story.d.ts +1 -2
- package/dist/components/Clickable/index.story.d.ts.map +1 -1
- package/dist/components/DropdownSelector/Divider.d.ts +3 -0
- package/dist/components/DropdownSelector/Divider.d.ts.map +1 -1
- package/dist/components/DropdownSelector/DropdownMenuItem.d.ts +7 -0
- package/dist/components/DropdownSelector/DropdownMenuItem.d.ts.map +1 -0
- package/dist/components/DropdownSelector/DropdownPopover.d.ts +8 -8
- package/dist/components/DropdownSelector/DropdownPopover.d.ts.map +1 -1
- package/dist/components/DropdownSelector/ListItem/index.d.ts +18 -0
- package/dist/components/DropdownSelector/ListItem/index.d.ts.map +1 -0
- package/dist/components/DropdownSelector/ListItem/index.story.d.ts +9 -0
- package/dist/components/DropdownSelector/ListItem/index.story.d.ts.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/index.d.ts +11 -0
- package/dist/components/DropdownSelector/MenuItem/index.d.ts.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/internals/handleFocusByKeyBoard.d.ts +9 -0
- package/dist/components/DropdownSelector/MenuItem/internals/handleFocusByKeyBoard.d.ts.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/internals/useMenuItemHandleKeyDown.d.ts +10 -0
- package/dist/components/DropdownSelector/MenuItem/internals/useMenuItemHandleKeyDown.d.ts.map +1 -0
- package/dist/components/DropdownSelector/MenuItemGroup/index.d.ts +14 -0
- package/dist/components/DropdownSelector/MenuItemGroup/index.d.ts.map +1 -0
- package/dist/components/DropdownSelector/MenuList/MenuListContext.d.ts +10 -0
- package/dist/components/DropdownSelector/MenuList/MenuListContext.d.ts.map +1 -0
- package/dist/components/DropdownSelector/MenuList/index.d.ts +18 -0
- package/dist/components/DropdownSelector/MenuList/index.d.ts.map +1 -0
- package/dist/components/DropdownSelector/MenuList/index.story.d.ts +11 -0
- package/dist/components/DropdownSelector/MenuList/index.story.d.ts.map +1 -0
- package/dist/components/DropdownSelector/MenuList/internals/getValuesRecursive.d.ts +11 -0
- package/dist/components/DropdownSelector/MenuList/internals/getValuesRecursive.d.ts.map +1 -0
- package/dist/components/DropdownSelector/Popover/index.d.ts +17 -0
- package/dist/components/DropdownSelector/Popover/index.d.ts.map +1 -0
- package/dist/components/DropdownSelector/Popover/index.story.d.ts +9 -0
- package/dist/components/DropdownSelector/Popover/index.story.d.ts.map +1 -0
- package/dist/components/DropdownSelector/index.d.ts +3 -10
- package/dist/components/DropdownSelector/index.d.ts.map +1 -1
- package/dist/components/DropdownSelector/index.story.d.ts +4 -4
- package/dist/components/DropdownSelector/index.story.d.ts.map +1 -1
- package/dist/components/DropdownSelector/utils/findPreviewRecursive.d.ts +12 -0
- package/dist/components/DropdownSelector/utils/findPreviewRecursive.d.ts.map +1 -0
- package/dist/components/FieldLabel/index.d.ts +1 -1
- package/dist/components/FieldLabel/index.d.ts.map +1 -1
- package/dist/components/Icon/index.d.ts +1 -1
- package/dist/components/Icon/index.d.ts.map +1 -1
- package/dist/components/Icon/index.story.d.ts +2 -3
- package/dist/components/Icon/index.story.d.ts.map +1 -1
- package/dist/components/IconButton/index.d.ts +1 -2
- package/dist/components/IconButton/index.d.ts.map +1 -1
- package/dist/components/IconButton/index.story.d.ts +1 -2
- package/dist/components/IconButton/index.story.d.ts.map +1 -1
- package/dist/components/LoadingSpinner/index.d.ts +9 -8
- package/dist/components/LoadingSpinner/index.d.ts.map +1 -1
- package/dist/components/LoadingSpinner/index.story.d.ts +1 -2
- package/dist/components/LoadingSpinner/index.story.d.ts.map +1 -1
- package/dist/components/Modal/ModalPlumbing.d.ts.map +1 -1
- package/dist/components/Modal/index.d.ts +18 -27
- package/dist/components/Modal/index.d.ts.map +1 -1
- package/dist/components/Modal/index.story.d.ts +12 -2
- package/dist/components/Modal/index.story.d.ts.map +1 -1
- package/dist/components/MultiSelect/context.d.ts +1 -1
- package/dist/components/MultiSelect/context.d.ts.map +1 -1
- package/dist/components/MultiSelect/index.d.ts +18 -6
- package/dist/components/MultiSelect/index.d.ts.map +1 -1
- package/dist/components/MultiSelect/index.story.d.ts +21 -16
- package/dist/components/MultiSelect/index.story.d.ts.map +1 -1
- package/dist/components/Radio/index.d.ts +13 -6
- package/dist/components/Radio/index.d.ts.map +1 -1
- package/dist/components/Radio/index.story.d.ts +11 -8
- package/dist/components/Radio/index.story.d.ts.map +1 -1
- package/dist/components/SegmentedControl/RadioGroupContext.d.ts +1 -1
- package/dist/components/SegmentedControl/RadioGroupContext.d.ts.map +1 -1
- package/dist/components/SegmentedControl/index.d.ts +2 -1
- package/dist/components/SegmentedControl/index.d.ts.map +1 -1
- package/dist/components/SegmentedControl/index.story.d.ts +1 -2
- package/dist/components/SegmentedControl/index.story.d.ts.map +1 -1
- package/dist/components/Switch/index.d.ts +3 -2
- package/dist/components/Switch/index.d.ts.map +1 -1
- package/dist/components/Switch/index.story.d.ts +1 -2
- package/dist/components/Switch/index.story.d.ts.map +1 -1
- package/dist/components/TagItem/index.d.ts +3 -3
- package/dist/components/TagItem/index.d.ts.map +1 -1
- package/dist/components/TagItem/index.story.d.ts +2 -3
- package/dist/components/TagItem/index.story.d.ts.map +1 -1
- package/dist/components/TextArea/TextArea.story.d.ts +28 -0
- package/dist/components/TextArea/TextArea.story.d.ts.map +1 -0
- package/dist/components/TextArea/index.d.ts +21 -0
- package/dist/components/TextArea/index.d.ts.map +1 -0
- package/dist/components/TextField/TextField.story.d.ts +28 -0
- package/dist/components/TextField/TextField.story.d.ts.map +1 -0
- package/dist/components/TextField/index.d.ts +8 -30
- package/dist/components/TextField/index.d.ts.map +1 -1
- package/dist/core/CharcoalProvider.d.ts +1 -1
- package/dist/core/CharcoalProvider.d.ts.map +1 -1
- package/dist/core/ComponentAbstraction.d.ts +1 -1
- package/dist/core/ComponentAbstraction.d.ts.map +1 -1
- package/dist/index.cjs.js +1064 -771
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1028 -750
- package/dist/index.esm.js.map +1 -1
- package/dist/styled.d.ts +13 -13
- package/package.json +7 -7
- package/src/_lib/compat.ts +20 -1
- package/src/_lib/index.ts +23 -0
- package/src/components/Button/__snapshots__/index.test.tsx.snap +385 -0
- package/src/components/Button/index.story.tsx +1 -1
- package/src/components/Button/index.test.tsx +24 -0
- package/src/components/Button/index.tsx +2 -2
- package/src/components/Checkbox/index.story.tsx +1 -1
- package/src/components/Checkbox/index.tsx +4 -2
- package/src/components/Clickable/index.story.tsx +0 -1
- package/src/components/Clickable/index.tsx +1 -1
- package/src/components/DropdownSelector/Divider.tsx +3 -0
- package/src/components/DropdownSelector/DropdownMenuItem.tsx +40 -0
- package/src/components/DropdownSelector/DropdownPopover.tsx +21 -42
- package/src/components/DropdownSelector/ListItem/index.story.tsx +51 -0
- package/src/components/DropdownSelector/ListItem/index.tsx +58 -0
- package/src/components/DropdownSelector/MenuItem/index.tsx +31 -0
- package/src/components/DropdownSelector/MenuItem/internals/handleFocusByKeyBoard.tsx +43 -0
- package/src/components/DropdownSelector/MenuItem/internals/useMenuItemHandleKeyDown.tsx +55 -0
- package/src/components/DropdownSelector/MenuItemGroup/index.tsx +42 -0
- package/src/components/DropdownSelector/MenuList/MenuListContext.ts +17 -0
- package/src/components/DropdownSelector/MenuList/index.story.tsx +51 -0
- package/src/components/DropdownSelector/MenuList/index.tsx +51 -0
- package/src/components/DropdownSelector/MenuList/internals/getValuesRecursive.tsx +35 -0
- package/src/components/DropdownSelector/Popover/index.story.tsx +65 -0
- package/src/components/DropdownSelector/Popover/index.tsx +69 -0
- package/src/components/DropdownSelector/index.story.tsx +56 -21
- package/src/components/DropdownSelector/index.tsx +19 -60
- package/src/components/DropdownSelector/utils/findPreviewRecursive.tsx +39 -0
- package/src/components/FieldLabel/index.tsx +1 -1
- package/src/components/Icon/index.story.tsx +0 -1
- package/src/components/Icon/index.tsx +1 -1
- package/src/components/IconButton/index.story.tsx +0 -1
- package/src/components/IconButton/index.tsx +2 -2
- package/src/components/LoadingSpinner/index.story.tsx +8 -2
- package/src/components/LoadingSpinner/index.tsx +44 -29
- package/src/components/Modal/ModalPlumbing.tsx +0 -1
- package/src/components/Modal/index.story.tsx +0 -1
- package/src/components/Modal/index.tsx +19 -12
- package/src/components/MultiSelect/context.ts +2 -2
- package/src/components/MultiSelect/index.story.tsx +26 -27
- package/src/components/MultiSelect/index.test.tsx +5 -23
- package/src/components/MultiSelect/index.tsx +83 -78
- package/src/components/Radio/index.story.tsx +7 -9
- package/src/components/Radio/index.test.tsx +3 -4
- package/src/components/Radio/index.tsx +24 -23
- package/src/components/SegmentedControl/RadioGroupContext.tsx +2 -1
- package/src/components/SegmentedControl/index.story.tsx +0 -1
- package/src/components/SegmentedControl/index.tsx +16 -5
- package/src/components/Switch/index.story.tsx +1 -1
- package/src/components/Switch/index.tsx +38 -32
- package/src/components/TagItem/index.story.tsx +0 -1
- package/src/components/TagItem/index.tsx +1 -6
- package/src/components/TextArea/TextArea.story.tsx +61 -0
- package/src/components/TextArea/index.tsx +246 -0
- package/src/components/TextField/{index.story.tsx → TextField.story.tsx} +6 -29
- package/src/components/TextField/index.tsx +148 -378
- package/src/components/a11y.test.tsx +0 -1
- package/src/core/CharcoalProvider.tsx +1 -1
- package/src/core/ComponentAbstraction.tsx +2 -1
- package/src/index.ts +8 -6
- package/dist/components/DropdownSelector/OptionItem.d.ts +0 -7
- package/dist/components/DropdownSelector/OptionItem.d.ts.map +0 -1
- package/dist/components/DropdownSelector/utils/focusIfHTMLLIElement.d.ts +0 -6
- package/dist/components/DropdownSelector/utils/focusIfHTMLLIElement.d.ts.map +0 -1
- package/dist/components/DropdownSelector/utils/handleFocusByKeyBoard.d.ts +0 -6
- package/dist/components/DropdownSelector/utils/handleFocusByKeyBoard.d.ts.map +0 -1
- package/src/components/DropdownSelector/OptionItem.tsx +0 -85
- package/src/components/DropdownSelector/utils/focusIfHTMLLIElement.tsx +0 -12
- package/src/components/DropdownSelector/utils/handleFocusByKeyBoard.tsx +0 -20
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState } from 'react'
|
|
2
2
|
import { Story } from '../../_lib/compat'
|
|
3
3
|
import styled from 'styled-components'
|
|
4
4
|
import { MultiSelectGroup, default as MultiSelect } from '.'
|
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
type: 'text',
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
|
-
|
|
15
|
+
label: {
|
|
16
16
|
control: {
|
|
17
17
|
type: 'text',
|
|
18
18
|
},
|
|
@@ -22,11 +22,6 @@ export default {
|
|
|
22
22
|
type: 'boolean',
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
|
-
firstOptionForceChecked: {
|
|
26
|
-
control: {
|
|
27
|
-
type: 'boolean',
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
25
|
disabled: {
|
|
31
26
|
control: {
|
|
32
27
|
type: 'boolean',
|
|
@@ -37,7 +32,7 @@ export default {
|
|
|
37
32
|
type: 'boolean',
|
|
38
33
|
},
|
|
39
34
|
},
|
|
40
|
-
|
|
35
|
+
invalid: {
|
|
41
36
|
control: {
|
|
42
37
|
type: 'boolean',
|
|
43
38
|
},
|
|
@@ -53,14 +48,14 @@ export default {
|
|
|
53
48
|
|
|
54
49
|
type Props = {
|
|
55
50
|
name: string
|
|
56
|
-
|
|
51
|
+
label: string
|
|
57
52
|
selected: boolean
|
|
58
|
-
firstOptionForceChecked: boolean
|
|
59
53
|
onChange: (selected: string[]) => void
|
|
60
54
|
disabled?: boolean
|
|
61
55
|
readonly?: boolean
|
|
62
|
-
|
|
56
|
+
invalid?: boolean
|
|
63
57
|
variant?: 'default' | 'overlay'
|
|
58
|
+
className?: string
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
const StyledMultiSelectGroup = styled(MultiSelectGroup)`
|
|
@@ -71,34 +66,33 @@ const StyledMultiSelectGroup = styled(MultiSelectGroup)`
|
|
|
71
66
|
|
|
72
67
|
const Template: Story<Props> = ({
|
|
73
68
|
name,
|
|
74
|
-
|
|
69
|
+
label,
|
|
75
70
|
selected,
|
|
76
|
-
firstOptionForceChecked,
|
|
77
71
|
onChange,
|
|
78
72
|
disabled,
|
|
79
73
|
readonly,
|
|
80
|
-
|
|
74
|
+
invalid,
|
|
81
75
|
variant,
|
|
76
|
+
className,
|
|
82
77
|
}) => {
|
|
83
78
|
return (
|
|
84
79
|
<StyledMultiSelectGroup
|
|
85
80
|
{...{
|
|
86
81
|
name,
|
|
87
|
-
|
|
82
|
+
label,
|
|
88
83
|
onChange,
|
|
89
84
|
disabled,
|
|
90
85
|
readonly,
|
|
91
|
-
|
|
86
|
+
invalid,
|
|
92
87
|
}}
|
|
93
|
-
className={''}
|
|
94
88
|
selected={selected ? ['選択肢1', '選択肢3'] : []}
|
|
95
89
|
>
|
|
96
90
|
{[1, 2, 3, 4].map((idx) => (
|
|
97
91
|
<MultiSelect
|
|
98
92
|
value={`選択肢${idx}`}
|
|
99
|
-
forceChecked={firstOptionForceChecked && idx === 1}
|
|
100
93
|
variant={variant}
|
|
101
94
|
key={idx}
|
|
95
|
+
className={className}
|
|
102
96
|
>
|
|
103
97
|
選択肢{idx}
|
|
104
98
|
</MultiSelect>
|
|
@@ -110,12 +104,11 @@ const Template: Story<Props> = ({
|
|
|
110
104
|
export const Default = Template.bind({})
|
|
111
105
|
Default.args = {
|
|
112
106
|
name: '',
|
|
113
|
-
|
|
107
|
+
label: '',
|
|
114
108
|
selected: true,
|
|
115
|
-
firstOptionForceChecked: false,
|
|
116
109
|
disabled: false,
|
|
117
110
|
readonly: false,
|
|
118
|
-
|
|
111
|
+
invalid: false,
|
|
119
112
|
variant: 'default',
|
|
120
113
|
// eslint-disable-next-line no-console
|
|
121
114
|
onChange: (selected) => console.log(selected),
|
|
@@ -123,14 +116,15 @@ Default.args = {
|
|
|
123
116
|
|
|
124
117
|
type PlaygroundProps = {
|
|
125
118
|
name: string
|
|
126
|
-
|
|
119
|
+
label: string
|
|
127
120
|
disabled?: boolean
|
|
128
121
|
readonly?: boolean
|
|
129
|
-
|
|
122
|
+
invalid?: boolean
|
|
123
|
+
className?: string
|
|
130
124
|
variant?: 'default' | 'overlay'
|
|
131
125
|
}
|
|
132
126
|
|
|
133
|
-
export const Playground: Story<PlaygroundProps> = (props) => {
|
|
127
|
+
export const Playground: Story<PlaygroundProps> = ({ className, ...props }) => {
|
|
134
128
|
const [selected, setSelected] = useState<string[]>([])
|
|
135
129
|
|
|
136
130
|
return (
|
|
@@ -140,7 +134,12 @@ export const Playground: Story<PlaygroundProps> = (props) => {
|
|
|
140
134
|
onChange={setSelected}
|
|
141
135
|
>
|
|
142
136
|
{[1, 2, 3, 4].map((idx) => (
|
|
143
|
-
<MultiSelect
|
|
137
|
+
<MultiSelect
|
|
138
|
+
value={`選択肢${idx}`}
|
|
139
|
+
variant={props.variant}
|
|
140
|
+
key={idx}
|
|
141
|
+
className={className}
|
|
142
|
+
>
|
|
144
143
|
選択肢{idx}
|
|
145
144
|
</MultiSelect>
|
|
146
145
|
))}
|
|
@@ -149,9 +148,9 @@ export const Playground: Story<PlaygroundProps> = (props) => {
|
|
|
149
148
|
}
|
|
150
149
|
Playground.args = {
|
|
151
150
|
name: 'defaultName',
|
|
152
|
-
|
|
151
|
+
label: '',
|
|
153
152
|
disabled: false,
|
|
154
153
|
readonly: false,
|
|
155
|
-
|
|
154
|
+
invalid: false,
|
|
156
155
|
variant: 'default',
|
|
157
156
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { fireEvent, render, screen } from '@testing-library/react'
|
|
2
|
-
import React from 'react'
|
|
3
2
|
import { ThemeProvider } from 'styled-components'
|
|
4
3
|
import { default as MultiSelect, MultiSelectGroup } from '.'
|
|
5
4
|
import { light } from '@charcoal-ui/theme'
|
|
@@ -184,7 +183,7 @@ describe('MultiSelect', () => {
|
|
|
184
183
|
let allOptions: HTMLInputElement[]
|
|
185
184
|
|
|
186
185
|
beforeEach(() => {
|
|
187
|
-
render(<TestComponent selected={['option1']}
|
|
186
|
+
render(<TestComponent selected={['option1']} invalid={true} />)
|
|
188
187
|
|
|
189
188
|
option1 = screen.getByDisplayValue('option1')
|
|
190
189
|
option2 = screen.getByDisplayValue('option2')
|
|
@@ -199,20 +198,6 @@ describe('MultiSelect', () => {
|
|
|
199
198
|
})
|
|
200
199
|
})
|
|
201
200
|
|
|
202
|
-
describe('option1 is force checked', () => {
|
|
203
|
-
let option1: HTMLInputElement
|
|
204
|
-
|
|
205
|
-
beforeEach(() => {
|
|
206
|
-
render(<TestComponent selected={[]} firstOptionForceChecked={true} />)
|
|
207
|
-
|
|
208
|
-
option1 = screen.getByDisplayValue('option1')
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
it('option1 is force checked', () => {
|
|
212
|
-
expect(option1.checked).toBeTruthy()
|
|
213
|
-
})
|
|
214
|
-
})
|
|
215
|
-
|
|
216
201
|
describe('option1 is disabled', () => {
|
|
217
202
|
let option1: HTMLInputElement
|
|
218
203
|
let option2: HTMLInputElement
|
|
@@ -239,8 +224,7 @@ const TestComponent = ({
|
|
|
239
224
|
childOnChange,
|
|
240
225
|
parentDisabled = false,
|
|
241
226
|
readonly = false,
|
|
242
|
-
|
|
243
|
-
firstOptionForceChecked = false,
|
|
227
|
+
invalid = false,
|
|
244
228
|
firstOptionDisabled = false,
|
|
245
229
|
}: {
|
|
246
230
|
selected: string[]
|
|
@@ -248,23 +232,21 @@ const TestComponent = ({
|
|
|
248
232
|
childOnChange?: (payload: { value: string; selected: boolean }) => void
|
|
249
233
|
parentDisabled?: boolean
|
|
250
234
|
readonly?: boolean
|
|
251
|
-
|
|
252
|
-
firstOptionForceChecked?: boolean
|
|
235
|
+
invalid?: boolean
|
|
253
236
|
firstOptionDisabled?: boolean
|
|
254
237
|
}) => {
|
|
255
238
|
return (
|
|
256
239
|
<ThemeProvider theme={light}>
|
|
257
240
|
<MultiSelectGroup
|
|
258
241
|
name="defaultName"
|
|
259
|
-
|
|
242
|
+
label="defaultAriaLabel"
|
|
260
243
|
disabled={parentDisabled}
|
|
261
244
|
onChange={parentOnChange}
|
|
262
|
-
{...{ selected, readonly,
|
|
245
|
+
{...{ selected, readonly, invalid }}
|
|
263
246
|
>
|
|
264
247
|
<MultiSelect
|
|
265
248
|
value="option1"
|
|
266
249
|
disabled={firstOptionDisabled}
|
|
267
|
-
forceChecked={firstOptionForceChecked}
|
|
268
250
|
onChange={childOnChange}
|
|
269
251
|
>
|
|
270
252
|
Option 1
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ChangeEvent, useCallback, useContext, forwardRef, memo } from 'react'
|
|
2
|
+
import * as React from 'react'
|
|
2
3
|
import styled, { css } from 'styled-components'
|
|
3
4
|
import warning from 'warning'
|
|
4
5
|
import { theme } from '../../styled'
|
|
@@ -8,74 +9,82 @@ import { MultiSelectGroupContext } from './context'
|
|
|
8
9
|
|
|
9
10
|
export type MultiSelectProps = React.PropsWithChildren<{
|
|
10
11
|
value: string
|
|
11
|
-
forceChecked?: boolean
|
|
12
12
|
disabled?: boolean
|
|
13
13
|
variant?: 'default' | 'overlay'
|
|
14
|
+
className?: string
|
|
14
15
|
onChange?: (payload: { value: string; selected: boolean }) => void
|
|
15
16
|
}>
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
name,
|
|
27
|
-
selected,
|
|
28
|
-
disabled: parentDisabled,
|
|
29
|
-
readonly,
|
|
30
|
-
hasError,
|
|
31
|
-
onChange: parentOnChange,
|
|
32
|
-
} = useContext(MultiSelectGroupContext)
|
|
33
|
-
|
|
34
|
-
warning(
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
36
|
-
name !== undefined,
|
|
37
|
-
`"name" is not Provided for <MultiSelect>. Perhaps you forgot to wrap with <MultiSelectGroup> ?`
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
const isSelected = selected.includes(value) || forceChecked
|
|
41
|
-
const isDisabled = disabled || parentDisabled || readonly
|
|
42
|
-
|
|
43
|
-
const handleChange = useCallback(
|
|
44
|
-
(event: ChangeEvent<HTMLInputElement>) => {
|
|
45
|
-
if (!(event.currentTarget instanceof HTMLInputElement)) {
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
if (onChange) onChange({ value, selected: event.currentTarget.checked })
|
|
49
|
-
parentOnChange({ value, selected: event.currentTarget.checked })
|
|
18
|
+
const MultiSelect = forwardRef<HTMLInputElement, MultiSelectProps>(
|
|
19
|
+
function MultiSelectInner(
|
|
20
|
+
{
|
|
21
|
+
value,
|
|
22
|
+
disabled = false,
|
|
23
|
+
onChange,
|
|
24
|
+
variant = 'default',
|
|
25
|
+
className,
|
|
26
|
+
children,
|
|
50
27
|
},
|
|
51
|
-
|
|
52
|
-
)
|
|
28
|
+
ref
|
|
29
|
+
) {
|
|
30
|
+
const {
|
|
31
|
+
name,
|
|
32
|
+
selected,
|
|
33
|
+
disabled: parentDisabled,
|
|
34
|
+
readonly,
|
|
35
|
+
invalid,
|
|
36
|
+
onChange: parentOnChange,
|
|
37
|
+
} = useContext(MultiSelectGroupContext)
|
|
38
|
+
|
|
39
|
+
warning(
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
41
|
+
name !== undefined,
|
|
42
|
+
`"name" is not Provided for <MultiSelect>. Perhaps you forgot to wrap with <MultiSelectGroup> ?`
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
const isSelected = selected.includes(value)
|
|
46
|
+
const isDisabled = disabled || parentDisabled || readonly
|
|
47
|
+
|
|
48
|
+
const handleChange = useCallback(
|
|
49
|
+
(event: ChangeEvent<HTMLInputElement>) => {
|
|
50
|
+
if (!(event.currentTarget instanceof HTMLInputElement)) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
if (onChange) onChange({ value, selected: event.currentTarget.checked })
|
|
54
|
+
parentOnChange({ value, selected: event.currentTarget.checked })
|
|
55
|
+
},
|
|
56
|
+
[onChange, parentOnChange, value]
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<MultiSelectRoot aria-disabled={isDisabled} className={className}>
|
|
61
|
+
<MultiSelectInput
|
|
62
|
+
{...{
|
|
63
|
+
name,
|
|
64
|
+
value,
|
|
65
|
+
invalid,
|
|
66
|
+
}}
|
|
67
|
+
checked={isSelected}
|
|
68
|
+
disabled={isDisabled}
|
|
69
|
+
onChange={handleChange}
|
|
70
|
+
overlay={variant === 'overlay'}
|
|
71
|
+
aria-invalid={invalid}
|
|
72
|
+
ref={ref}
|
|
73
|
+
/>
|
|
74
|
+
<MultiSelectInputOverlay
|
|
75
|
+
overlay={variant === 'overlay'}
|
|
76
|
+
invalid={invalid}
|
|
77
|
+
aria-hidden={true}
|
|
78
|
+
>
|
|
79
|
+
<pixiv-icon name="24/Check" unsafe-non-guideline-scale={16 / 24} />
|
|
80
|
+
</MultiSelectInputOverlay>
|
|
81
|
+
{Boolean(children) && <MultiSelectLabel>{children}</MultiSelectLabel>}
|
|
82
|
+
</MultiSelectRoot>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
)
|
|
53
86
|
|
|
54
|
-
|
|
55
|
-
<MultiSelectRoot aria-disabled={isDisabled}>
|
|
56
|
-
<MultiSelectInput
|
|
57
|
-
{...{
|
|
58
|
-
name,
|
|
59
|
-
value,
|
|
60
|
-
hasError,
|
|
61
|
-
}}
|
|
62
|
-
checked={isSelected}
|
|
63
|
-
disabled={isDisabled}
|
|
64
|
-
onChange={handleChange}
|
|
65
|
-
overlay={variant === 'overlay'}
|
|
66
|
-
aria-invalid={hasError}
|
|
67
|
-
/>
|
|
68
|
-
<MultiSelectInputOverlay
|
|
69
|
-
overlay={variant === 'overlay'}
|
|
70
|
-
hasError={hasError}
|
|
71
|
-
aria-hidden={true}
|
|
72
|
-
>
|
|
73
|
-
<pixiv-icon name="24/Check" unsafe-non-guideline-scale={16 / 24} />
|
|
74
|
-
</MultiSelectInputOverlay>
|
|
75
|
-
{Boolean(children) && <MultiSelectLabel>{children}</MultiSelectLabel>}
|
|
76
|
-
</MultiSelectRoot>
|
|
77
|
-
)
|
|
78
|
-
}
|
|
87
|
+
export default memo(MultiSelect)
|
|
79
88
|
|
|
80
89
|
const MultiSelectRoot = styled.label`
|
|
81
90
|
display: grid;
|
|
@@ -97,7 +106,7 @@ const MultiSelectLabel = styled.div`
|
|
|
97
106
|
`
|
|
98
107
|
|
|
99
108
|
const MultiSelectInput = styled.input.attrs({ type: 'checkbox' })<{
|
|
100
|
-
|
|
109
|
+
invalid: boolean
|
|
101
110
|
overlay: boolean
|
|
102
111
|
}>`
|
|
103
112
|
&[type='checkbox'] {
|
|
@@ -111,11 +120,11 @@ const MultiSelectInput = styled.input.attrs({ type: 'checkbox' })<{
|
|
|
111
120
|
${theme((o) => o.bg.brand.hover.press)}
|
|
112
121
|
}
|
|
113
122
|
|
|
114
|
-
${({
|
|
123
|
+
${({ invalid, overlay }) =>
|
|
115
124
|
theme((o) => [
|
|
116
125
|
o.bg.text3.hover.press,
|
|
117
126
|
o.borderRadius('oval'),
|
|
118
|
-
|
|
127
|
+
invalid && !overlay && o.outline.assertive,
|
|
119
128
|
overlay && o.bg.surface4,
|
|
120
129
|
])};
|
|
121
130
|
}
|
|
@@ -123,7 +132,7 @@ const MultiSelectInput = styled.input.attrs({ type: 'checkbox' })<{
|
|
|
123
132
|
|
|
124
133
|
const MultiSelectInputOverlay = styled.div<{
|
|
125
134
|
overlay: boolean
|
|
126
|
-
|
|
135
|
+
invalid: boolean
|
|
127
136
|
}>`
|
|
128
137
|
position: absolute;
|
|
129
138
|
top: -2px;
|
|
@@ -133,13 +142,13 @@ const MultiSelectInputOverlay = styled.div<{
|
|
|
133
142
|
align-items: center;
|
|
134
143
|
justify-content: center;
|
|
135
144
|
|
|
136
|
-
${({
|
|
145
|
+
${({ invalid, overlay }) =>
|
|
137
146
|
theme((o) => [
|
|
138
147
|
o.width.px(24),
|
|
139
148
|
o.height.px(24),
|
|
140
149
|
o.borderRadius('oval'),
|
|
141
150
|
o.font.text5,
|
|
142
|
-
|
|
151
|
+
invalid && overlay && o.outline.assertive,
|
|
143
152
|
])}
|
|
144
153
|
|
|
145
154
|
${({ overlay }) =>
|
|
@@ -154,23 +163,23 @@ const MultiSelectInputOverlay = styled.div<{
|
|
|
154
163
|
export type MultiSelectGroupProps = React.PropsWithChildren<{
|
|
155
164
|
className?: string
|
|
156
165
|
name: string
|
|
157
|
-
|
|
166
|
+
label: string
|
|
158
167
|
selected: string[]
|
|
159
168
|
onChange: (selected: string[]) => void
|
|
160
169
|
disabled?: boolean
|
|
161
170
|
readonly?: boolean
|
|
162
|
-
|
|
171
|
+
invalid?: boolean
|
|
163
172
|
}>
|
|
164
173
|
|
|
165
174
|
export function MultiSelectGroup({
|
|
166
175
|
className,
|
|
167
176
|
name,
|
|
168
|
-
|
|
177
|
+
label,
|
|
169
178
|
selected,
|
|
170
179
|
onChange,
|
|
171
180
|
disabled = false,
|
|
172
181
|
readonly = false,
|
|
173
|
-
|
|
182
|
+
invalid = false,
|
|
174
183
|
children,
|
|
175
184
|
}: MultiSelectGroupProps) {
|
|
176
185
|
const handleChange = useCallback(
|
|
@@ -197,15 +206,11 @@ export function MultiSelectGroup({
|
|
|
197
206
|
selected: Array.from(new Set(selected)),
|
|
198
207
|
disabled,
|
|
199
208
|
readonly,
|
|
200
|
-
|
|
209
|
+
invalid,
|
|
201
210
|
onChange: handleChange,
|
|
202
211
|
}}
|
|
203
212
|
>
|
|
204
|
-
<div
|
|
205
|
-
className={className}
|
|
206
|
-
aria-label={ariaLabel}
|
|
207
|
-
data-testid="SelectGroup"
|
|
208
|
-
>
|
|
213
|
+
<div className={className} aria-label={label} data-testid="SelectGroup">
|
|
209
214
|
{children}
|
|
210
215
|
</div>
|
|
211
216
|
</MultiSelectGroupContext.Provider>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { action } from '@storybook/addon-actions'
|
|
2
|
-
import React from 'react'
|
|
3
2
|
import { css } from 'styled-components'
|
|
4
3
|
import { Story } from '../../_lib/compat'
|
|
5
4
|
import Radio, { RadioGroup } from '.'
|
|
@@ -17,30 +16,29 @@ export default {
|
|
|
17
16
|
},
|
|
18
17
|
},
|
|
19
18
|
args: {
|
|
20
|
-
|
|
19
|
+
invalid: false,
|
|
21
20
|
parentDisabled: false,
|
|
22
21
|
childDisabled: false,
|
|
23
|
-
forceChecked: false,
|
|
24
22
|
readonly: false,
|
|
25
23
|
},
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
interface Props {
|
|
29
27
|
value?: string
|
|
30
|
-
|
|
28
|
+
invalid: boolean
|
|
31
29
|
parentDisabled: boolean
|
|
32
30
|
childDisabled: boolean
|
|
33
|
-
forceChecked: boolean
|
|
34
31
|
readonly: boolean
|
|
32
|
+
className?: string
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
const Template: Story<Partial<Props>> = ({
|
|
38
36
|
value,
|
|
39
|
-
|
|
40
|
-
hasError,
|
|
37
|
+
invalid,
|
|
41
38
|
parentDisabled,
|
|
42
39
|
childDisabled,
|
|
43
40
|
readonly,
|
|
41
|
+
className,
|
|
44
42
|
}) => (
|
|
45
43
|
<div
|
|
46
44
|
css={css`
|
|
@@ -58,14 +56,14 @@ const Template: Story<Partial<Props>> = ({
|
|
|
58
56
|
onChange={action('onChange')}
|
|
59
57
|
disabled={parentDisabled}
|
|
60
58
|
readonly={readonly}
|
|
61
|
-
|
|
59
|
+
invalid={invalid}
|
|
62
60
|
>
|
|
63
61
|
{options.map((option) => (
|
|
64
62
|
<Radio
|
|
65
63
|
key={option}
|
|
66
64
|
value={option}
|
|
67
65
|
disabled={childDisabled}
|
|
68
|
-
|
|
66
|
+
className={className}
|
|
69
67
|
>
|
|
70
68
|
{name}({option})を選ぶ
|
|
71
69
|
</Radio>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { fireEvent, render, screen } from '@testing-library/react'
|
|
2
|
-
import React from 'react'
|
|
3
2
|
import { ThemeProvider } from 'styled-components'
|
|
4
3
|
import Radio, { RadioGroup } from '.'
|
|
5
4
|
import { light } from '@charcoal-ui/theme'
|
|
@@ -112,7 +111,7 @@ function TestComponent({
|
|
|
112
111
|
onChange = jest.fn(),
|
|
113
112
|
radioGroupDisabled = false,
|
|
114
113
|
readonly = false,
|
|
115
|
-
|
|
114
|
+
invalid = false,
|
|
116
115
|
option1Disabled = false,
|
|
117
116
|
option2Disabled = false,
|
|
118
117
|
}: {
|
|
@@ -120,7 +119,7 @@ function TestComponent({
|
|
|
120
119
|
onChange?: () => void
|
|
121
120
|
radioGroupDisabled?: boolean
|
|
122
121
|
readonly?: boolean
|
|
123
|
-
|
|
122
|
+
invalid?: boolean
|
|
124
123
|
option1Disabled?: boolean
|
|
125
124
|
option2Disabled?: boolean
|
|
126
125
|
}) {
|
|
@@ -133,7 +132,7 @@ function TestComponent({
|
|
|
133
132
|
onChange={onChange}
|
|
134
133
|
disabled={radioGroupDisabled}
|
|
135
134
|
readonly={readonly}
|
|
136
|
-
|
|
135
|
+
invalid={invalid}
|
|
137
136
|
>
|
|
138
137
|
<Radio value="option1" disabled={option1Disabled}>
|
|
139
138
|
option1を選ぶ
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { memo, forwardRef, useCallback, useContext } from 'react'
|
|
2
|
+
import * as React from 'react'
|
|
2
3
|
import styled from 'styled-components'
|
|
3
4
|
import warning from 'warning'
|
|
4
5
|
import { theme } from '../../styled'
|
|
@@ -6,22 +7,20 @@ import { px } from '@charcoal-ui/utils'
|
|
|
6
7
|
|
|
7
8
|
export type RadioProps = React.PropsWithChildren<{
|
|
8
9
|
value: string
|
|
9
|
-
forceChecked?: boolean
|
|
10
10
|
disabled?: boolean
|
|
11
|
+
className?: string
|
|
11
12
|
}>
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
value,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
children,
|
|
18
|
-
}: RadioProps) {
|
|
14
|
+
const Radio = forwardRef<HTMLInputElement, RadioProps>(function RadioInner(
|
|
15
|
+
{ value, disabled = false, children, className },
|
|
16
|
+
ref
|
|
17
|
+
) {
|
|
19
18
|
const {
|
|
20
19
|
name,
|
|
21
20
|
selected,
|
|
22
21
|
disabled: isParentDisabled,
|
|
23
22
|
readonly,
|
|
24
|
-
|
|
23
|
+
invalid,
|
|
25
24
|
onChange,
|
|
26
25
|
} = useContext(RadioGroupContext)
|
|
27
26
|
|
|
@@ -43,19 +42,22 @@ export default function Radio({
|
|
|
43
42
|
)
|
|
44
43
|
|
|
45
44
|
return (
|
|
46
|
-
<RadioRoot aria-disabled={isDisabled || isReadonly}>
|
|
45
|
+
<RadioRoot aria-disabled={isDisabled || isReadonly} className={className}>
|
|
47
46
|
<RadioInput
|
|
48
47
|
name={name}
|
|
49
48
|
value={value}
|
|
50
|
-
checked={
|
|
51
|
-
|
|
49
|
+
checked={isSelected}
|
|
50
|
+
invalid={invalid}
|
|
52
51
|
onChange={handleChange}
|
|
53
52
|
disabled={isDisabled || isReadonly}
|
|
53
|
+
ref={ref}
|
|
54
54
|
/>
|
|
55
55
|
{children != null && <RadioLabel>{children}</RadioLabel>}
|
|
56
56
|
</RadioRoot>
|
|
57
57
|
)
|
|
58
|
-
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
export default memo(Radio)
|
|
59
61
|
|
|
60
62
|
const RadioRoot = styled.label`
|
|
61
63
|
display: grid;
|
|
@@ -68,7 +70,7 @@ const RadioRoot = styled.label`
|
|
|
68
70
|
`
|
|
69
71
|
|
|
70
72
|
export const RadioInput = styled.input.attrs({ type: 'radio' })<{
|
|
71
|
-
|
|
73
|
+
invalid?: boolean
|
|
72
74
|
}>`
|
|
73
75
|
/** Make prior to browser default style */
|
|
74
76
|
&[type='radio'] {
|
|
@@ -81,14 +83,13 @@ export const RadioInput = styled.input.attrs({ type: 'radio' })<{
|
|
|
81
83
|
|
|
82
84
|
width: 20px;
|
|
83
85
|
height: 20px;
|
|
84
|
-
|
|
85
86
|
cursor: pointer;
|
|
86
87
|
|
|
87
|
-
${({
|
|
88
|
+
${({ invalid = false }) =>
|
|
88
89
|
theme((o) => [
|
|
89
90
|
o.borderRadius('oval'),
|
|
90
91
|
o.bg.surface1.hover.press,
|
|
91
|
-
|
|
92
|
+
invalid && o.outline.assertive,
|
|
92
93
|
])};
|
|
93
94
|
|
|
94
95
|
&:not(:checked) {
|
|
@@ -130,7 +131,7 @@ export type RadioGroupProps = React.PropsWithChildren<{
|
|
|
130
131
|
onChange(next: string): void
|
|
131
132
|
disabled?: boolean
|
|
132
133
|
readonly?: boolean
|
|
133
|
-
|
|
134
|
+
invalid?: boolean
|
|
134
135
|
}>
|
|
135
136
|
|
|
136
137
|
// TODO: use (or polyfill) flex gap
|
|
@@ -145,7 +146,7 @@ interface RadioGroupContext {
|
|
|
145
146
|
selected?: string
|
|
146
147
|
disabled: boolean
|
|
147
148
|
readonly: boolean
|
|
148
|
-
|
|
149
|
+
invalid: boolean
|
|
149
150
|
onChange: (next: string) => void
|
|
150
151
|
}
|
|
151
152
|
|
|
@@ -154,7 +155,7 @@ const RadioGroupContext = React.createContext<RadioGroupContext>({
|
|
|
154
155
|
selected: undefined,
|
|
155
156
|
disabled: false,
|
|
156
157
|
readonly: false,
|
|
157
|
-
|
|
158
|
+
invalid: false,
|
|
158
159
|
onChange() {
|
|
159
160
|
throw new Error(
|
|
160
161
|
'Cannot find onChange() handler. Perhaps you forgot to wrap with <RadioGroup> ?'
|
|
@@ -170,7 +171,7 @@ export function RadioGroup({
|
|
|
170
171
|
onChange,
|
|
171
172
|
disabled,
|
|
172
173
|
readonly,
|
|
173
|
-
|
|
174
|
+
invalid,
|
|
174
175
|
children,
|
|
175
176
|
}: RadioGroupProps) {
|
|
176
177
|
const handleChange = useCallback(
|
|
@@ -187,7 +188,7 @@ export function RadioGroup({
|
|
|
187
188
|
selected: value,
|
|
188
189
|
disabled: disabled ?? false,
|
|
189
190
|
readonly: readonly ?? false,
|
|
190
|
-
|
|
191
|
+
invalid: invalid ?? false,
|
|
191
192
|
onChange: handleChange,
|
|
192
193
|
}}
|
|
193
194
|
>
|
|
@@ -195,7 +196,7 @@ export function RadioGroup({
|
|
|
195
196
|
role="radiogroup"
|
|
196
197
|
aria-orientation="vertical"
|
|
197
198
|
aria-label={label}
|
|
198
|
-
aria-invalid={
|
|
199
|
+
aria-invalid={invalid}
|
|
199
200
|
className={className}
|
|
200
201
|
>
|
|
201
202
|
{children}
|