@charcoal-ui/react 2.8.0 → 2.10.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/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 +1 -0
- package/dist/components/Checkbox/index.d.ts.map +1 -1
- package/dist/components/Checkbox/index.story.d.ts +1 -0
- package/dist/components/Checkbox/index.story.d.ts.map +1 -1
- package/dist/components/LoadingSpinner/index.d.ts +8 -6
- package/dist/components/LoadingSpinner/index.d.ts.map +1 -1
- package/dist/components/LoadingSpinner/index.story.d.ts +2 -2
- package/dist/components/LoadingSpinner/index.story.d.ts.map +1 -1
- package/dist/components/Modal/index.d.ts +17 -26
- package/dist/components/Modal/index.d.ts.map +1 -1
- package/dist/components/Modal/index.story.d.ts +13 -2
- package/dist/components/Modal/index.story.d.ts.map +1 -1
- package/dist/components/MultiSelect/index.d.ts +15 -1
- package/dist/components/MultiSelect/index.d.ts.map +1 -1
- package/dist/components/MultiSelect/index.story.d.ts +15 -2
- package/dist/components/MultiSelect/index.story.d.ts.map +1 -1
- package/dist/components/Radio/index.d.ts +10 -1
- package/dist/components/Radio/index.d.ts.map +1 -1
- package/dist/components/Radio/index.story.d.ts +9 -2
- package/dist/components/Radio/index.story.d.ts.map +1 -1
- package/dist/components/SegmentedControl/index.d.ts +1 -0
- package/dist/components/SegmentedControl/index.d.ts.map +1 -1
- package/dist/components/Switch/index.d.ts +2 -1
- package/dist/components/Switch/index.d.ts.map +1 -1
- package/dist/components/Switch/index.story.d.ts +2 -2
- package/dist/components/Switch/index.story.d.ts.map +1 -1
- package/dist/index.cjs.js +170 -141
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +188 -154
- package/dist/index.esm.js.map +1 -1
- package/package.json +6 -6
- package/src/components/Button/__snapshots__/index.test.tsx.snap +385 -0
- package/src/components/Button/index.test.tsx +25 -0
- package/src/components/Checkbox/index.story.tsx +1 -0
- package/src/components/Checkbox/index.tsx +2 -1
- package/src/components/LoadingSpinner/index.story.tsx +7 -1
- package/src/components/LoadingSpinner/index.tsx +27 -11
- package/src/components/Modal/index.tsx +18 -12
- package/src/components/MultiSelect/index.story.tsx +11 -3
- package/src/components/MultiSelect/index.tsx +77 -61
- package/src/components/Radio/index.story.tsx +3 -0
- package/src/components/Radio/index.tsx +13 -9
- package/src/components/SegmentedControl/index.tsx +15 -5
- package/src/components/Switch/index.tsx +37 -32
- package/src/components/TextField/index.story.tsx +1 -1
- package/src/components/TextField/index.tsx +1 -0
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
ChangeEvent,
|
|
3
|
+
forwardRef,
|
|
4
|
+
memo,
|
|
5
|
+
useCallback,
|
|
6
|
+
useContext,
|
|
7
|
+
} from 'react'
|
|
2
8
|
import styled, { css } from 'styled-components'
|
|
3
9
|
import warning from 'warning'
|
|
4
10
|
import { theme } from '../../styled'
|
|
@@ -11,71 +17,81 @@ export type MultiSelectProps = React.PropsWithChildren<{
|
|
|
11
17
|
forceChecked?: boolean
|
|
12
18
|
disabled?: boolean
|
|
13
19
|
variant?: 'default' | 'overlay'
|
|
20
|
+
className?: string
|
|
14
21
|
onChange?: (payload: { value: string; selected: boolean }) => void
|
|
15
22
|
}>
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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 })
|
|
24
|
+
const MultiSelect = forwardRef<HTMLInputElement, MultiSelectProps>(
|
|
25
|
+
function MultiSelectInner(
|
|
26
|
+
{
|
|
27
|
+
value,
|
|
28
|
+
forceChecked = false,
|
|
29
|
+
disabled = false,
|
|
30
|
+
onChange,
|
|
31
|
+
variant = 'default',
|
|
32
|
+
className,
|
|
33
|
+
children,
|
|
50
34
|
},
|
|
51
|
-
|
|
52
|
-
)
|
|
35
|
+
ref
|
|
36
|
+
) {
|
|
37
|
+
const {
|
|
38
|
+
name,
|
|
39
|
+
selected,
|
|
40
|
+
disabled: parentDisabled,
|
|
41
|
+
readonly,
|
|
42
|
+
hasError,
|
|
43
|
+
onChange: parentOnChange,
|
|
44
|
+
} = useContext(MultiSelectGroupContext)
|
|
45
|
+
|
|
46
|
+
warning(
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
48
|
+
name !== undefined,
|
|
49
|
+
`"name" is not Provided for <MultiSelect>. Perhaps you forgot to wrap with <MultiSelectGroup> ?`
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
const isSelected = selected.includes(value) || forceChecked
|
|
53
|
+
const isDisabled = disabled || parentDisabled || readonly
|
|
54
|
+
|
|
55
|
+
const handleChange = useCallback(
|
|
56
|
+
(event: ChangeEvent<HTMLInputElement>) => {
|
|
57
|
+
if (!(event.currentTarget instanceof HTMLInputElement)) {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
if (onChange) onChange({ value, selected: event.currentTarget.checked })
|
|
61
|
+
parentOnChange({ value, selected: event.currentTarget.checked })
|
|
62
|
+
},
|
|
63
|
+
[onChange, parentOnChange, value]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<MultiSelectRoot aria-disabled={isDisabled} className={className}>
|
|
68
|
+
<MultiSelectInput
|
|
69
|
+
{...{
|
|
70
|
+
name,
|
|
71
|
+
value,
|
|
72
|
+
hasError,
|
|
73
|
+
}}
|
|
74
|
+
checked={isSelected}
|
|
75
|
+
disabled={isDisabled}
|
|
76
|
+
onChange={handleChange}
|
|
77
|
+
overlay={variant === 'overlay'}
|
|
78
|
+
aria-invalid={hasError}
|
|
79
|
+
ref={ref}
|
|
80
|
+
/>
|
|
81
|
+
<MultiSelectInputOverlay
|
|
82
|
+
overlay={variant === 'overlay'}
|
|
83
|
+
hasError={hasError}
|
|
84
|
+
aria-hidden={true}
|
|
85
|
+
>
|
|
86
|
+
<pixiv-icon name="24/Check" unsafe-non-guideline-scale={16 / 24} />
|
|
87
|
+
</MultiSelectInputOverlay>
|
|
88
|
+
{Boolean(children) && <MultiSelectLabel>{children}</MultiSelectLabel>}
|
|
89
|
+
</MultiSelectRoot>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
)
|
|
53
93
|
|
|
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
|
-
}
|
|
94
|
+
export default memo(MultiSelect)
|
|
79
95
|
|
|
80
96
|
const MultiSelectRoot = styled.label`
|
|
81
97
|
display: grid;
|
|
@@ -32,6 +32,7 @@ interface Props {
|
|
|
32
32
|
childDisabled: boolean
|
|
33
33
|
forceChecked: boolean
|
|
34
34
|
readonly: boolean
|
|
35
|
+
className?: string
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
const Template: Story<Partial<Props>> = ({
|
|
@@ -41,6 +42,7 @@ const Template: Story<Partial<Props>> = ({
|
|
|
41
42
|
parentDisabled,
|
|
42
43
|
childDisabled,
|
|
43
44
|
readonly,
|
|
45
|
+
className,
|
|
44
46
|
}) => (
|
|
45
47
|
<div
|
|
46
48
|
css={css`
|
|
@@ -66,6 +68,7 @@ const Template: Story<Partial<Props>> = ({
|
|
|
66
68
|
value={option}
|
|
67
69
|
disabled={childDisabled}
|
|
68
70
|
forceChecked={forceChecked}
|
|
71
|
+
className={className}
|
|
69
72
|
>
|
|
70
73
|
{name}({option})を選ぶ
|
|
71
74
|
</Radio>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useContext } from 'react'
|
|
1
|
+
import React, { forwardRef, memo, useCallback, useContext } from 'react'
|
|
2
2
|
import styled from 'styled-components'
|
|
3
3
|
import warning from 'warning'
|
|
4
4
|
import { theme } from '../../styled'
|
|
@@ -8,14 +8,13 @@ export type RadioProps = React.PropsWithChildren<{
|
|
|
8
8
|
value: string
|
|
9
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, forceChecked = false, disabled = false, children, className },
|
|
16
|
+
ref
|
|
17
|
+
) {
|
|
19
18
|
const {
|
|
20
19
|
name,
|
|
21
20
|
selected,
|
|
@@ -43,7 +42,7 @@ 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}
|
|
@@ -51,11 +50,14 @@ export default function Radio({
|
|
|
51
50
|
hasError={hasError}
|
|
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;
|
|
@@ -82,6 +84,8 @@ export const RadioInput = styled.input.attrs({ type: 'radio' })<{
|
|
|
82
84
|
width: 20px;
|
|
83
85
|
height: 20px;
|
|
84
86
|
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
|
|
85
89
|
${({ hasError = false }) =>
|
|
86
90
|
theme((o) => [
|
|
87
91
|
o.borderRadius('oval'),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef, memo, useMemo, useRef } from 'react'
|
|
1
|
+
import React, { ReactNode, forwardRef, memo, useMemo, useRef } from 'react'
|
|
2
2
|
import { useRadioGroupState } from 'react-stately'
|
|
3
3
|
import {
|
|
4
4
|
AriaRadioGroupProps,
|
|
@@ -24,6 +24,7 @@ export type SegmentedControlProps = {
|
|
|
24
24
|
readonly disabled?: boolean
|
|
25
25
|
readonly readonly?: boolean
|
|
26
26
|
readonly required?: boolean
|
|
27
|
+
readonly className?: string
|
|
27
28
|
|
|
28
29
|
readonly value?: string
|
|
29
30
|
readonly defaultValue?: string
|
|
@@ -54,7 +55,11 @@ const SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>(
|
|
|
54
55
|
}, [props.data])
|
|
55
56
|
|
|
56
57
|
return (
|
|
57
|
-
<SegmentedControlRoot
|
|
58
|
+
<SegmentedControlRoot
|
|
59
|
+
ref={ref}
|
|
60
|
+
{...radioGroupProps}
|
|
61
|
+
className={props.className}
|
|
62
|
+
>
|
|
58
63
|
<RadioProvider value={state}>
|
|
59
64
|
{segmentedControlItems.map((item) => (
|
|
60
65
|
<Segmented
|
|
@@ -76,13 +81,18 @@ export default memo(SegmentedControl)
|
|
|
76
81
|
type RadioProps = {
|
|
77
82
|
value: string
|
|
78
83
|
disabled?: boolean
|
|
84
|
+
children?: ReactNode
|
|
79
85
|
}
|
|
80
86
|
|
|
81
|
-
const Segmented
|
|
87
|
+
const Segmented = (props: RadioProps) => {
|
|
82
88
|
const state = useRadioContext()
|
|
83
89
|
const ref = useRef<HTMLInputElement>(null)
|
|
84
90
|
const ariaRadioProps = useMemo<AriaRadioProps>(
|
|
85
|
-
() => ({
|
|
91
|
+
() => ({
|
|
92
|
+
value: props.value,
|
|
93
|
+
isDisabled: props.disabled,
|
|
94
|
+
children: props.children,
|
|
95
|
+
}),
|
|
86
96
|
[props]
|
|
87
97
|
)
|
|
88
98
|
|
|
@@ -99,7 +109,7 @@ const Segmented: React.FC<RadioProps> = ({ children, ...props }) => {
|
|
|
99
109
|
>
|
|
100
110
|
<SegmentedInput {...inputProps} ref={ref} />
|
|
101
111
|
<RadioLabel>
|
|
102
|
-
<SegmentedLabelInner>{children}</SegmentedLabelInner>
|
|
112
|
+
<SegmentedLabelInner>{props.children}</SegmentedLabelInner>
|
|
103
113
|
</RadioLabel>
|
|
104
114
|
</SegmentedRoot>
|
|
105
115
|
)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { useSwitch } from '@react-aria/switch'
|
|
2
2
|
import type { AriaSwitchProps } from '@react-types/switch'
|
|
3
|
-
import React, {
|
|
3
|
+
import React, { useMemo, memo, forwardRef } from 'react'
|
|
4
4
|
import { useToggleState } from 'react-stately'
|
|
5
5
|
import styled from 'styled-components'
|
|
6
6
|
import { theme } from '../../styled'
|
|
7
7
|
import { disabledSelector } from '@charcoal-ui/utils'
|
|
8
|
+
import { useObjectRef } from '@react-aria/utils'
|
|
8
9
|
|
|
9
10
|
export type SwitchProps = {
|
|
10
11
|
name: string
|
|
@@ -23,37 +24,41 @@ export type SwitchProps = {
|
|
|
23
24
|
}
|
|
24
25
|
)
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
27
|
+
const SwitchCheckbox = forwardRef<HTMLInputElement, SwitchProps>(
|
|
28
|
+
function SwitchCheckboxInner(props, external) {
|
|
29
|
+
const { disabled, className } = props
|
|
30
|
+
|
|
31
|
+
const ariaSwitchProps: AriaSwitchProps = useMemo(
|
|
32
|
+
() => ({
|
|
33
|
+
...props,
|
|
34
|
+
|
|
35
|
+
// children がいない場合は aria-label をつけないといけない
|
|
36
|
+
'aria-label': 'children' in props ? undefined : props.label,
|
|
37
|
+
isDisabled: props.disabled,
|
|
38
|
+
isSelected: props.checked,
|
|
39
|
+
}),
|
|
40
|
+
[props]
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
const state = useToggleState(ariaSwitchProps)
|
|
44
|
+
const ref = useObjectRef<HTMLInputElement>(external)
|
|
45
|
+
const {
|
|
46
|
+
inputProps: { className: _className, type: _type, ...rest },
|
|
47
|
+
} = useSwitch(ariaSwitchProps, state, ref)
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Label className={className} aria-disabled={disabled}>
|
|
51
|
+
<SwitchInput {...rest} ref={ref} />
|
|
52
|
+
{'children' in props ? (
|
|
53
|
+
// eslint-disable-next-line react/destructuring-assignment
|
|
54
|
+
<LabelInner>{props.children}</LabelInner>
|
|
55
|
+
) : undefined}
|
|
56
|
+
</Label>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
export default memo(SwitchCheckbox)
|
|
57
62
|
|
|
58
63
|
const Label = styled.label`
|
|
59
64
|
display: inline-grid;
|
|
@@ -102,7 +102,7 @@ export const PrefixIcon: Story<Partial<SingleLineTextFieldProps>> = (args) => (
|
|
|
102
102
|
)
|
|
103
103
|
|
|
104
104
|
const PrefixIconWrap = styled.div`
|
|
105
|
-
color: ${({ theme }) => theme.color.
|
|
105
|
+
color: ${({ theme }) => theme.color.text3};
|
|
106
106
|
margin-top: 2px;
|
|
107
107
|
margin-right: 4px;
|
|
108
108
|
`
|