@charcoal-ui/react 4.0.0-beta.3 → 4.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.
Files changed (103) hide show
  1. package/dist/components/Checkbox/index.d.ts +9 -20
  2. package/dist/components/Checkbox/index.d.ts.map +1 -1
  3. package/dist/components/CheckboxInput/index.d.ts +9 -0
  4. package/dist/components/CheckboxInput/index.d.ts.map +1 -0
  5. package/dist/components/DropdownSelector/Popover/index.d.ts +1 -2
  6. package/dist/components/DropdownSelector/Popover/index.d.ts.map +1 -1
  7. package/dist/components/Modal/index.d.ts +1 -1
  8. package/dist/components/Modal/index.d.ts.map +1 -1
  9. package/dist/components/Modal/useCustomModalOverlay.d.ts.map +1 -1
  10. package/dist/components/MultiSelect/index.d.ts.map +1 -1
  11. package/dist/components/Radio/index.d.ts +4 -4
  12. package/dist/components/Radio/index.d.ts.map +1 -1
  13. package/dist/components/TextArea/index.d.ts.map +1 -1
  14. package/dist/components/TextField/index.d.ts.map +1 -1
  15. package/dist/core/CharcoalProvider.d.ts +1 -1
  16. package/dist/core/CharcoalProvider.d.ts.map +1 -1
  17. package/dist/index.cjs.js +177 -414
  18. package/dist/index.cjs.js.map +1 -1
  19. package/dist/index.css +86 -0
  20. package/dist/index.css.map +1 -1
  21. package/dist/index.esm.js +152 -389
  22. package/dist/index.esm.js.map +1 -1
  23. package/package.json +14 -17
  24. package/src/components/Checkbox/__snapshots__/index.story.storyshot +163 -517
  25. package/src/components/Checkbox/index.css +21 -0
  26. package/src/components/Checkbox/index.story.tsx +44 -79
  27. package/src/components/Checkbox/index.tsx +19 -157
  28. package/src/components/CheckboxInput/__snapshots__/index.story.storyshot +109 -0
  29. package/src/components/CheckboxInput/index.css +77 -0
  30. package/src/components/CheckboxInput/index.story.tsx +35 -0
  31. package/src/components/CheckboxInput/index.tsx +53 -0
  32. package/src/components/DropdownSelector/Popover/index.tsx +1 -2
  33. package/src/components/IconButton/__snapshots__/index.story.storyshot +6 -8
  34. package/src/components/IconButton/index.story.tsx +14 -37
  35. package/src/components/LoadingSpinner/__snapshots__/index.story.storyshot +139 -1
  36. package/src/components/LoadingSpinner/index.story.tsx +18 -7
  37. package/src/components/Modal/index.tsx +1 -1
  38. package/src/components/Modal/useCustomModalOverlay.tsx +5 -4
  39. package/src/components/MultiSelect/__snapshots__/index.story.storyshot +32 -44
  40. package/src/components/MultiSelect/index.story.tsx +88 -192
  41. package/src/components/MultiSelect/index.tsx +2 -1
  42. package/src/components/Radio/__snapshots__/index.story.storyshot +1 -1
  43. package/src/components/Radio/index.story.tsx +20 -21
  44. package/src/components/Radio/index.tsx +14 -13
  45. package/src/components/Switch/__snapshots__/index.story.storyshot +8 -9
  46. package/src/components/Switch/index.story.tsx +10 -18
  47. package/src/components/TagItem/__snapshots__/index.story.storyshot +791 -665
  48. package/src/components/TagItem/index.story.tsx +44 -161
  49. package/src/components/TextArea/TextArea.story.tsx +62 -24
  50. package/src/components/TextArea/__snapshots__/TextArea.story.storyshot +1858 -472
  51. package/src/components/TextArea/index.tsx +2 -0
  52. package/src/components/TextField/TextField.story.tsx +77 -67
  53. package/src/components/TextField/__snapshots__/TextField.story.storyshot +2004 -786
  54. package/src/components/TextField/index.tsx +2 -0
  55. package/src/components/a11y.test.tsx +1 -1
  56. package/src/core/CharcoalProvider.tsx +1 -1
  57. package/dist/components/Button/index.story.d.ts +0 -22
  58. package/dist/components/Button/index.story.d.ts.map +0 -1
  59. package/dist/components/Button/index.test.d.ts +0 -2
  60. package/dist/components/Button/index.test.d.ts.map +0 -1
  61. package/dist/components/Checkbox/index.story.d.ts +0 -8
  62. package/dist/components/Checkbox/index.story.d.ts.map +0 -1
  63. package/dist/components/Clickable/index.story.d.ts +0 -6
  64. package/dist/components/Clickable/index.story.d.ts.map +0 -1
  65. package/dist/components/DropdownSelector/ListItem/index.story.d.ts +0 -9
  66. package/dist/components/DropdownSelector/ListItem/index.story.d.ts.map +0 -1
  67. package/dist/components/DropdownSelector/MenuList/index.story.d.ts +0 -8
  68. package/dist/components/DropdownSelector/MenuList/index.story.d.ts.map +0 -1
  69. package/dist/components/DropdownSelector/Popover/index.story.d.ts +0 -5
  70. package/dist/components/DropdownSelector/Popover/index.story.d.ts.map +0 -1
  71. package/dist/components/DropdownSelector/index.story.d.ts +0 -19
  72. package/dist/components/DropdownSelector/index.story.d.ts.map +0 -1
  73. package/dist/components/Icon/index.story.d.ts +0 -6
  74. package/dist/components/Icon/index.story.d.ts.map +0 -1
  75. package/dist/components/IconButton/index.story.d.ts +0 -9
  76. package/dist/components/IconButton/index.story.d.ts.map +0 -1
  77. package/dist/components/LoadingSpinner/LoadingSpinnerIcon.story.d.ts +0 -8
  78. package/dist/components/LoadingSpinner/LoadingSpinnerIcon.story.d.ts.map +0 -1
  79. package/dist/components/LoadingSpinner/index.story.d.ts +0 -6
  80. package/dist/components/LoadingSpinner/index.story.d.ts.map +0 -1
  81. package/dist/components/Modal/index.story.d.ts +0 -21
  82. package/dist/components/Modal/index.story.d.ts.map +0 -1
  83. package/dist/components/MultiSelect/index.story.d.ts +0 -82
  84. package/dist/components/MultiSelect/index.story.d.ts.map +0 -1
  85. package/dist/components/MultiSelect/index.test.d.ts +0 -2
  86. package/dist/components/MultiSelect/index.test.d.ts.map +0 -1
  87. package/dist/components/Radio/index.story.d.ts +0 -26
  88. package/dist/components/Radio/index.story.d.ts.map +0 -1
  89. package/dist/components/Radio/index.test.d.ts +0 -2
  90. package/dist/components/Radio/index.test.d.ts.map +0 -1
  91. package/dist/components/SegmentedControl/index.story.d.ts +0 -7
  92. package/dist/components/SegmentedControl/index.story.d.ts.map +0 -1
  93. package/dist/components/Switch/index.story.d.ts +0 -9
  94. package/dist/components/Switch/index.story.d.ts.map +0 -1
  95. package/dist/components/TagItem/index.story.d.ts +0 -16
  96. package/dist/components/TagItem/index.story.d.ts.map +0 -1
  97. package/dist/components/TextArea/TextArea.story.d.ts +0 -9
  98. package/dist/components/TextArea/TextArea.story.d.ts.map +0 -1
  99. package/dist/components/TextField/TextField.story.d.ts +0 -22
  100. package/dist/components/TextField/TextField.story.d.ts.map +0 -1
  101. package/dist/components/a11y.test.d.ts +0 -2
  102. package/dist/components/a11y.test.d.ts.map +0 -1
  103. package/src/components/LoadingSpinner/LoadingSpinnerIcon.story.tsx +0 -13
@@ -0,0 +1,21 @@
1
+ .charcoal-checkbox__label {
2
+ position: relative;
3
+ cursor: pointer;
4
+ display: flex;
5
+ }
6
+
7
+ .charcoal-checkbox__label[aria-disabled='true'] {
8
+ cursor: default;
9
+ opacity: 0.32;
10
+ }
11
+
12
+ .charcoal-checkbox__label[aria-disabled='true'] > input {
13
+ opacity: 1;
14
+ }
15
+
16
+ .charcoal-checkbox__text {
17
+ color: var(--charcoal-text2);
18
+ font-size: 14px;
19
+ line-height: 20px;
20
+ margin-left: 4px;
21
+ }
@@ -1,103 +1,68 @@
1
- import { action } from '@storybook/addon-actions'
2
1
  import Checkbox from '.'
3
2
  import { Meta, StoryObj } from '@storybook/react'
3
+ import { useCallback, useState } from 'react'
4
+ import { action } from '@storybook/addon-actions'
4
5
 
5
6
  export default {
6
7
  title: 'Checkbox',
7
8
  component: Checkbox,
8
9
  } as Meta<typeof Checkbox>
9
10
 
10
- export const Labelled: StoryObj<typeof Checkbox> = {
11
- args: {
12
- checked: false,
13
- defaultChecked: false,
14
- disabled: false,
15
- readonly: false,
16
- invalid: false,
17
- },
18
- render: (props) => {
19
- return (
20
- <div>
21
- <div style={{ marginBottom: '1em' }}>
22
- <Checkbox
23
- {...props}
24
- name="labelled"
25
- label="label"
26
- onBlur={action('blur')}
27
- onClick={action('click')}
28
- onChange={action('change')}
29
- onFocus={action('focus')}
30
- >
31
- 同意する
32
- </Checkbox>
33
- </div>
34
-
35
- <div>
36
- <Checkbox
37
- {...props}
38
- name="labelled"
39
- label="label"
40
- onBlur={action('blur')}
41
- onClick={action('click')}
42
- onChange={action('change')}
43
- onFocus={action('focus')}
44
- >
45
- <span style={{ width: 200, display: 'block' }}>
46
- 同意する同意する同意する同意する同意する同意する同意する同意する同意する同意する同意する同意する同意する
47
- </span>
48
- </Checkbox>
49
- </div>
50
- </div>
51
- )
52
- },
53
- }
11
+ export const Default: StoryObj<typeof Checkbox> = {
12
+ render: function Render(props) {
13
+ const [checked, setChecked] = useState(props.checked)
14
+ const handleChange = useCallback((isSelected: boolean) => {
15
+ setChecked(isSelected)
16
+ action('change')(isSelected)
17
+ }, [])
54
18
 
55
- export const Invalid: StoryObj<typeof Checkbox> = {
56
- args: {
57
- checked: false,
58
- defaultChecked: false,
59
- disabled: false,
60
- readonly: false,
61
- },
62
- render: (props) => {
63
19
  return (
64
20
  <Checkbox
65
21
  {...props}
66
- name="labelled"
67
- label="label"
68
- invalid
22
+ checked={checked ?? props.checked}
69
23
  onBlur={action('blur')}
70
24
  onClick={action('click')}
71
- onChange={action('change')}
25
+ onChange={handleChange}
72
26
  onFocus={action('focus')}
73
- >
74
- 同意する
75
- </Checkbox>
27
+ />
76
28
  )
77
29
  },
78
30
  }
79
31
 
80
- export const Unlabelled: StoryObj<typeof Checkbox> = {
81
- args: {
82
- checked: false,
83
- defaultChecked: false,
84
- disabled: false,
85
- readonly: false,
86
- invalid: false,
32
+ export const Label: StoryObj<typeof Checkbox> = {
33
+ render: () => {
34
+ return <Checkbox>Accelerate creativity.</Checkbox>
35
+ },
36
+ }
37
+
38
+ export const Checked: StoryObj<typeof Checkbox> = {
39
+ render: () => {
40
+ return <Checkbox checked>Accelerate creativity.</Checkbox>
87
41
  },
88
- render: (props) => {
42
+ }
43
+
44
+ export const Disabled: StoryObj<typeof Checkbox> = {
45
+ render: () => {
46
+ return <Checkbox disabled>Accelerate creativity.</Checkbox>
47
+ },
48
+ }
49
+
50
+ export const ReadOnly: StoryObj<typeof Checkbox> = {
51
+ render: () => {
89
52
  return (
90
- <div>
91
- <Checkbox
92
- {...props}
93
- name="unlabelled"
94
- label="label"
95
- onBlur={action('blur')}
96
- onClick={action('click')}
97
- onChange={action('change')}
98
- onFocus={action('focus')}
99
- />
100
- </div>
53
+ <Checkbox name="labelled" readOnly>
54
+ Accelerate creativity.
55
+ </Checkbox>
56
+ )
57
+ },
58
+ }
59
+
60
+ export const Invalid: StoryObj<typeof Checkbox> = {
61
+ render: () => {
62
+ return (
63
+ <Checkbox name="labelled" invalid>
64
+ Accelerate creativity.
65
+ </Checkbox>
101
66
  )
102
67
  },
103
68
  }
@@ -1,169 +1,31 @@
1
- import { forwardRef, memo, useMemo } from 'react'
2
- import * as React from 'react'
3
- import styled, { css } from 'styled-components'
4
- import { useCheckbox } from '@react-aria/checkbox'
5
- import { useObjectRef } from '@react-aria/utils'
6
- import { useToggleState } from 'react-stately'
1
+ import './index.css'
7
2
 
8
- import type { AriaCheckboxProps } from '@react-types/checkbox'
9
- import Icon from '../Icon'
10
- import { focusVisibleFocusRingCss } from '@charcoal-ui/styled'
3
+ import React, { forwardRef, memo } from 'react'
4
+ import { useId } from '@react-aria/utils'
5
+ import CheckboxInput, { CheckboxInputProps } from '../CheckboxInput'
6
+ import { useClassNames } from '../../_lib/useClassNames'
11
7
 
12
- type CheckboxLabelProps =
13
- | {
14
- children: React.ReactNode
15
- }
16
- | {
17
- label: string
18
- }
19
-
20
- export type CheckboxProps = CheckboxLabelProps & {
21
- readonly id?: string
22
- readonly name?: string
23
- readonly className?: string
24
-
25
- readonly checked?: boolean
26
- readonly defaultChecked?: boolean
27
- readonly disabled?: boolean
28
- readonly readonly?: boolean
29
- readonly invalid?: boolean
30
-
31
- readonly onClick?: () => void
32
- readonly onChange?: (isSelected: boolean) => void
33
- readonly onBlur?: () => void
34
- readonly onFocus?: () => void
8
+ export type CheckboxProps = CheckboxInputProps & {
9
+ children?: React.ReactNode
35
10
  }
36
11
 
37
12
  const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
38
- function CheckboxInner({ invalid = false, ...props }, ref) {
39
- const ariaCheckboxProps = useMemo<AriaCheckboxProps>(
40
- () => ({
41
- ...props,
42
- isInValid: invalid,
43
- isSelected: props.checked,
44
- defaultSelected: props.defaultChecked,
45
- validationState: invalid ? 'invalid' : 'valid',
46
- // children がいない場合は aria-label をつけないといけない
47
- 'aria-label': 'children' in props ? undefined : props.label,
48
- isDisabled: props.disabled,
49
- }),
50
- [invalid, props]
13
+ function CheckboxInner({ disabled, className, id, children, ...props }, ref) {
14
+ const classNames = useClassNames('charcoal-checkbox__label', className)
15
+ const htmlId = useId(id)
16
+ const input = (
17
+ <CheckboxInput {...props} id={htmlId} disabled={disabled} ref={ref} />
51
18
  )
52
- const state = useToggleState(ariaCheckboxProps)
53
- const objectRef = useObjectRef(ref)
54
-
55
- const { inputProps } = useCheckbox(ariaCheckboxProps, state, objectRef)
56
- const isDisabled = (props.disabled ?? false) || (props.readonly ?? false)
57
-
19
+ if (children === undefined) {
20
+ return input
21
+ }
58
22
  return (
59
- <InputRoot aria-disabled={isDisabled} className={props.className}>
60
- <CheckboxRoot>
61
- <CheckboxInput
62
- type="checkbox"
63
- {...inputProps}
64
- readOnly={props.readonly}
65
- />
66
- <CheckboxInputOverlay aria-hidden={true} checked={inputProps.checked}>
67
- <Icon name="24/Check" unsafeNonGuidelineScale={2 / 3} />
68
- </CheckboxInputOverlay>
69
- </CheckboxRoot>
70
-
71
- {'children' in props && <InputLabel>{props.children}</InputLabel>}
72
- </InputRoot>
23
+ <label htmlFor={htmlId} aria-disabled={disabled} className={classNames}>
24
+ {input}
25
+ <div className="charcoal-checkbox__text">{children}</div>
26
+ </label>
73
27
  )
74
28
  }
75
29
  )
76
30
 
77
31
  export default memo(Checkbox)
78
-
79
- const hiddenCss = css`
80
- visibility: hidden;
81
- `
82
-
83
- const InputRoot = styled.label`
84
- position: relative;
85
- display: flex;
86
-
87
- cursor: pointer;
88
-
89
- gap: 4px;
90
- &:disabled,
91
- &[aria-disabled]:not([aria-disabled='false']) {
92
- cursor: default;
93
- opacity: 0.32;
94
- }
95
- `
96
-
97
- const CheckboxRoot = styled.div`
98
- position: relative;
99
- `
100
-
101
- const CheckboxInput = styled.input`
102
- &[type='checkbox'] {
103
- appearance: none;
104
- display: block;
105
- cursor: pointer;
106
- margin: 0;
107
- width: 20px;
108
- height: 20px;
109
- border-radius: 4px;
110
- transition: 0.2s box-shadow, 0.2s background-color;
111
-
112
- &:disabled {
113
- cursor: default;
114
- }
115
- &:read-only {
116
- cursor: default;
117
- }
118
-
119
- &:checked {
120
- background-color: var(--charcoal-brand);
121
-
122
- &:not(:disabled):not([aria-disabled]),
123
- &[aria-disabled='false'] {
124
- &:hover {
125
- background-color: var(--charcoal-brand-hover);
126
- }
127
- &:active {
128
- background-color: var(--charcoal-brand-press);
129
- }
130
- }
131
- }
132
-
133
- &:not(:disabled):not([aria-disabled]),
134
- &[aria-disabled='false'] {
135
- ${focusVisibleFocusRingCss}
136
- &[aria-invalid='true'] {
137
- box-shadow: 0 0 0 4px rgba(255, 43, 0, 0.32);
138
- }
139
- }
140
-
141
- &:not(:checked) {
142
- border-width: 2px;
143
- border-style: solid;
144
- border-color: var(--charcoal-text4);
145
- }
146
- }
147
- `
148
-
149
- const CheckboxInputOverlay = styled.div<{ checked?: boolean }>`
150
- position: absolute;
151
- top: -2px;
152
- left: -2px;
153
- box-sizing: border-box;
154
- display: flex;
155
- align-items: center;
156
- justify-content: center;
157
- width: 24px;
158
- height: 24px;
159
- color: var(--charcoal-text5);
160
-
161
- ${({ checked }) => checked !== true && hiddenCss};
162
- `
163
-
164
- const InputLabel = styled.div`
165
- color: var(--charcoal-text2);
166
- font-size: 14px;
167
- /** checkbox の height が 20px なのでcheckbox と text が揃っているように見せるために行ボックスの高さを 20px にしている */
168
- line-height: 20px;
169
- `
@@ -0,0 +1,109 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Storybook Tests React/Internal/CheckboxInput Checked 1`] = `
4
+ <div
5
+ data-dark={false}
6
+ >
7
+ <div
8
+ className="charcoal-checkbox-input__root"
9
+ >
10
+ <input
11
+ checked={true}
12
+ className="charcoal-checkbox-input__input"
13
+ onChange={[Function]}
14
+ type="checkbox"
15
+ />
16
+ <div
17
+ aria-hidden={true}
18
+ className="charcoal-checkbox-input__overlay"
19
+ data-checked={true}
20
+ >
21
+ <pixiv-icon
22
+ name="24/Check"
23
+ unsafe-non-guideline-scale={0.6666666666666666}
24
+ />
25
+ </div>
26
+ </div>
27
+ </div>
28
+ `;
29
+
30
+ exports[`Storybook Tests React/Internal/CheckboxInput Default 1`] = `
31
+ <div
32
+ data-dark={false}
33
+ >
34
+ <div
35
+ className="charcoal-checkbox-input__root"
36
+ >
37
+ <input
38
+ className="charcoal-checkbox-input__input"
39
+ onChange={[Function]}
40
+ type="checkbox"
41
+ />
42
+ <div
43
+ aria-hidden={true}
44
+ className="charcoal-checkbox-input__overlay"
45
+ >
46
+ <pixiv-icon
47
+ name="24/Check"
48
+ unsafe-non-guideline-scale={0.6666666666666666}
49
+ />
50
+ </div>
51
+ </div>
52
+ </div>
53
+ `;
54
+
55
+ exports[`Storybook Tests React/Internal/CheckboxInput Disabled 1`] = `
56
+ <div
57
+ data-dark={false}
58
+ >
59
+ <div
60
+ className="charcoal-checkbox-input__root"
61
+ >
62
+ <input
63
+ checked={false}
64
+ className="charcoal-checkbox-input__input"
65
+ disabled={true}
66
+ onChange={[Function]}
67
+ type="checkbox"
68
+ />
69
+ <div
70
+ aria-hidden={true}
71
+ className="charcoal-checkbox-input__overlay"
72
+ data-checked={false}
73
+ >
74
+ <pixiv-icon
75
+ name="24/Check"
76
+ unsafe-non-guideline-scale={0.6666666666666666}
77
+ />
78
+ </div>
79
+ </div>
80
+ </div>
81
+ `;
82
+
83
+ exports[`Storybook Tests React/Internal/CheckboxInput Invalid 1`] = `
84
+ <div
85
+ data-dark={false}
86
+ >
87
+ <div
88
+ className="charcoal-checkbox-input__root"
89
+ >
90
+ <input
91
+ aria-invalid={true}
92
+ checked={false}
93
+ className="charcoal-checkbox-input__input"
94
+ onChange={[Function]}
95
+ type="checkbox"
96
+ />
97
+ <div
98
+ aria-hidden={true}
99
+ className="charcoal-checkbox-input__overlay"
100
+ data-checked={false}
101
+ >
102
+ <pixiv-icon
103
+ name="24/Check"
104
+ unsafe-non-guideline-scale={0.6666666666666666}
105
+ />
106
+ </div>
107
+ </div>
108
+ </div>
109
+ `;
@@ -0,0 +1,77 @@
1
+ /* root div */
2
+
3
+ .charcoal-checkbox-input__root {
4
+ position: relative;
5
+ }
6
+
7
+ /* input */
8
+
9
+ .charcoal-checkbox-input__input {
10
+ appearance: none;
11
+ display: block;
12
+ cursor: pointer;
13
+ margin: 0;
14
+ width: 20px;
15
+ height: 20px;
16
+ border-radius: 4px;
17
+ transition: 0.2s box-shadow, 0.2s background-color;
18
+ }
19
+
20
+ .charcoal-checkbox-input__input:disabled,
21
+ .charcoal-checkbox-input__input[readonly] {
22
+ opacity: 0.32;
23
+ cursor: default;
24
+ }
25
+
26
+ .charcoal-checkbox-input__input:checked {
27
+ background-color: var(--charcoal-brand);
28
+ }
29
+
30
+ .charcoal-checkbox-input__input:not(:checked) {
31
+ border-width: 2px;
32
+ border-style: solid;
33
+ border-color: var(--charcoal-text4);
34
+ }
35
+
36
+ .charcoal-checkbox-input__input:not(:disabled):focus {
37
+ outline: none;
38
+ box-shadow: 0 0 0 4px rgba(0, 150, 250, 0.32);
39
+ }
40
+ .charcoal-checkbox-input__input:not(:disabled):focus-visible {
41
+ box-shadow: 0 0 0 4px rgba(0, 150, 250, 0.32);
42
+ }
43
+ .charcoal-checkbox-input__input:not(:disabled):focus:not(:focus-visible) {
44
+ box-shadow: none;
45
+ }
46
+
47
+ .charcoal-checkbox-input__input:checked:not(:disabled):hover {
48
+ background-color: var(--charcoal-brand-hover);
49
+ }
50
+ .charcoal-checkbox-input__input:checked:not(:disabled):active {
51
+ background-color: var(--charcoal-brand-press);
52
+ }
53
+
54
+ .charcoal-checkbox-input__input[aria-invalid='true'],
55
+ .charcoal-checkbox-input__input[aria-invalid='true']:not(:disabled):focus {
56
+ box-shadow: 0 0 0 4px rgba(255, 43, 0, 0.32);
57
+ }
58
+
59
+ /* overlay div */
60
+
61
+ .charcoal-checkbox-input__overlay {
62
+ position: absolute;
63
+ top: -2px;
64
+ left: -2px;
65
+ box-sizing: border-box;
66
+ align-items: center;
67
+ justify-content: center;
68
+ width: 24px;
69
+ height: 24px;
70
+ color: var(--charcoal-text5);
71
+ display: none;
72
+ pointer-events: none;
73
+ }
74
+
75
+ .charcoal-checkbox-input__input:checked + .charcoal-checkbox-input__overlay {
76
+ display: flex;
77
+ }
@@ -0,0 +1,35 @@
1
+ import CheckboxInput from '.'
2
+ import { Meta, StoryObj } from '@storybook/react'
3
+ import { useState } from 'react'
4
+
5
+ export default {
6
+ title: 'React/Internal/CheckboxInput',
7
+ component: CheckboxInput,
8
+ } as Meta<typeof CheckboxInput>
9
+
10
+ export const Default: StoryObj<typeof CheckboxInput> = {
11
+ render: function Render(args) {
12
+ return <CheckboxInput {...args} />
13
+ },
14
+ }
15
+
16
+ export const Checked: StoryObj<typeof CheckboxInput> = {
17
+ render: function Render() {
18
+ const [checked, setChecked] = useState(true)
19
+ return <CheckboxInput checked={checked} onChange={setChecked} />
20
+ },
21
+ }
22
+
23
+ export const Disabled: StoryObj<typeof CheckboxInput> = {
24
+ render: function Render() {
25
+ const [checked, setChecked] = useState(false)
26
+ return <CheckboxInput checked={checked} onChange={setChecked} disabled />
27
+ },
28
+ }
29
+
30
+ export const Invalid: StoryObj<typeof CheckboxInput> = {
31
+ render: function Render() {
32
+ const [checked, setChecked] = useState(false)
33
+ return <CheckboxInput checked={checked} onChange={setChecked} invalid />
34
+ },
35
+ }
@@ -0,0 +1,53 @@
1
+ import './index.css'
2
+
3
+ import { forwardRef, memo, useCallback } from 'react'
4
+ import Icon from '../Icon'
5
+ import { useClassNames } from '../../_lib/useClassNames'
6
+
7
+ type CharcoalCheckboxInputProps = {
8
+ invalid?: boolean
9
+ onChange?: (checked: boolean) => void
10
+ }
11
+
12
+ export type CheckboxInputProps = CharcoalCheckboxInputProps &
13
+ Omit<React.ComponentProps<'input'>, keyof CharcoalCheckboxInputProps>
14
+
15
+ const CheckboxInput = forwardRef<HTMLInputElement, CheckboxInputProps>(
16
+ function CheckboxInput({ onChange, checked, invalid, ...props }, ref) {
17
+ const handleChange = useCallback(
18
+ (e: React.ChangeEvent<HTMLInputElement>) => {
19
+ const el = e.currentTarget
20
+ onChange?.(el.checked)
21
+ },
22
+ [onChange]
23
+ )
24
+
25
+ const classNames = useClassNames(
26
+ 'charcoal-checkbox-input__root',
27
+ props.className
28
+ )
29
+
30
+ return (
31
+ <div className={classNames}>
32
+ <input
33
+ ref={ref}
34
+ className="charcoal-checkbox-input__input"
35
+ type="checkbox"
36
+ onChange={handleChange}
37
+ aria-invalid={invalid}
38
+ checked={checked}
39
+ {...props}
40
+ />
41
+ <div
42
+ className="charcoal-checkbox-input__overlay"
43
+ aria-hidden={true}
44
+ data-checked={checked}
45
+ >
46
+ <Icon name="24/Check" unsafeNonGuidelineScale={2 / 3} />
47
+ </div>
48
+ </div>
49
+ )
50
+ }
51
+ )
52
+
53
+ export default memo(CheckboxInput)
@@ -1,5 +1,4 @@
1
- import { RefObject, useContext, useRef } from 'react'
2
- import { ReactNode } from 'react'
1
+ import { RefObject, useContext, useRef, ReactNode } from 'react'
3
2
  import { DismissButton, Overlay, usePopover } from '@react-aria/overlays'
4
3
  import styled from 'styled-components'
5
4
  import { ModalBackgroundContext } from '../../Modal/ModalBackgroundContext'
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`Storybook Tests IconButton DefaultM 1`] = `
3
+ exports[`Storybook Tests IconButton Default 1`] = `
4
4
  .c0 {
5
5
  cursor: pointer;
6
6
  -webkit-appearance: none;
@@ -103,10 +103,10 @@ exports[`Storybook Tests IconButton DefaultM 1`] = `
103
103
  >
104
104
  <button
105
105
  className="c0 c1"
106
- title="close"
106
+ title="add"
107
107
  >
108
108
  <pixiv-icon
109
- name="24/Close"
109
+ name="16/Add"
110
110
  />
111
111
  </button>
112
112
  </div>
@@ -209,16 +209,15 @@ exports[`Storybook Tests IconButton IsActive 1`] = `
209
209
  >
210
210
  <button
211
211
  className="c0 c1"
212
- title="close"
213
212
  >
214
213
  <pixiv-icon
215
- name="24/Close"
214
+ name="16/Add"
216
215
  />
217
216
  </button>
218
217
  </div>
219
218
  `;
220
219
 
221
- exports[`Storybook Tests IconButton OverlayM 1`] = `
220
+ exports[`Storybook Tests IconButton Overlay 1`] = `
222
221
  .c0 {
223
222
  cursor: pointer;
224
223
  -webkit-appearance: none;
@@ -321,10 +320,9 @@ exports[`Storybook Tests IconButton OverlayM 1`] = `
321
320
  >
322
321
  <button
323
322
  className="c0 c1"
324
- title="close"
325
323
  >
326
324
  <pixiv-icon
327
- name="24/Close"
325
+ name="16/Add"
328
326
  />
329
327
  </button>
330
328
  </div>