@charcoal-ui/react 3.4.0 → 3.6.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.d.ts.map +1 -1
- 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/DropdownSelector/DropdownMenuItem.d.ts.map +1 -1
- package/dist/components/DropdownSelector/ListItem/index.d.ts.map +1 -1
- package/dist/components/DropdownSelector/Popover/index.d.ts.map +1 -1
- package/dist/components/DropdownSelector/index.d.ts.map +1 -1
- package/dist/components/FieldLabel/index.d.ts.map +1 -1
- package/dist/components/IconButton/index.d.ts.map +1 -1
- package/dist/components/LoadingSpinner/index.d.ts.map +1 -1
- package/dist/components/Modal/ModalPlumbing.d.ts.map +1 -1
- package/dist/components/Modal/index.d.ts.map +1 -1
- package/dist/components/Modal/index.story.d.ts +1 -0
- package/dist/components/Modal/index.story.d.ts.map +1 -1
- package/dist/components/MultiSelect/index.d.ts.map +1 -1
- package/dist/components/MultiSelect/index.story.d.ts +2 -0
- package/dist/components/MultiSelect/index.story.d.ts.map +1 -1
- package/dist/components/Radio/index.d.ts.map +1 -1
- package/dist/components/SegmentedControl/index.d.ts.map +1 -1
- package/dist/components/Switch/index.d.ts.map +1 -1
- package/dist/components/TagItem/index.d.ts.map +1 -1
- package/dist/components/TextArea/index.d.ts.map +1 -1
- package/dist/components/TextField/TextField.story.d.ts.map +1 -1
- package/dist/components/TextField/index.d.ts +4 -0
- package/dist/components/TextField/index.d.ts.map +1 -1
- package/dist/components/TextField/useFocusWithClick.d.ts +3 -0
- package/dist/components/TextField/useFocusWithClick.d.ts.map +1 -0
- package/dist/index.cjs.js +935 -494
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +863 -422
- package/dist/index.esm.js.map +1 -1
- package/dist/styled.d.ts +4 -4
- package/package.json +9 -9
- package/src/components/Button/__snapshots__/index.story.storyshot +312 -592
- package/src/components/Button/index.tsx +50 -14
- package/src/components/Checkbox/__snapshots__/index.story.storyshot +209 -40
- package/src/components/Checkbox/__snapshots__/snapshot.test.tsx.snap +410 -80
- package/src/components/Checkbox/index.story.tsx +24 -0
- package/src/components/Checkbox/index.tsx +47 -17
- package/src/components/Clickable/__snapshots__/index.story.storyshot +4 -0
- package/src/components/Clickable/index.tsx +1 -0
- package/src/components/DropdownSelector/DropdownMenuItem.tsx +19 -3
- package/src/components/DropdownSelector/ListItem/__snapshots__/index.story.storyshot +3 -10
- package/src/components/DropdownSelector/ListItem/index.tsx +6 -4
- package/src/components/DropdownSelector/MenuItemGroup/index.tsx +1 -1
- package/src/components/DropdownSelector/MenuList/__snapshots__/index.story.storyshot +4 -13
- package/src/components/DropdownSelector/Popover/__snapshots__/index.story.storyshot +20 -37
- package/src/components/DropdownSelector/Popover/index.tsx +5 -8
- package/src/components/DropdownSelector/__snapshots__/index.story.storyshot +60 -191
- package/src/components/DropdownSelector/index.tsx +70 -20
- package/src/components/FieldLabel/index.tsx +77 -12
- package/src/components/IconButton/__snapshots__/index.story.storyshot +30 -54
- package/src/components/IconButton/index.tsx +51 -26
- package/src/components/LoadingSpinner/index.tsx +3 -6
- package/src/components/Modal/Dialog/index.tsx +1 -1
- package/src/components/Modal/ModalPlumbing.tsx +26 -5
- package/src/components/Modal/__snapshots__/index.story.storyshot +2454 -108
- package/src/components/Modal/index.story.tsx +27 -0
- package/src/components/Modal/index.tsx +19 -4
- package/src/components/MultiSelect/__snapshots__/index.story.storyshot +528 -25
- package/src/components/MultiSelect/index.story.tsx +60 -0
- package/src/components/MultiSelect/index.tsx +82 -22
- package/src/components/Radio/__snapshots__/index.story.storyshot +32 -49
- package/src/components/Radio/index.tsx +71 -23
- package/src/components/SegmentedControl/__snapshots__/index.story.storyshot +18 -19
- package/src/components/SegmentedControl/index.tsx +35 -15
- package/src/components/Switch/__snapshots__/index.story.storyshot +6 -18
- package/src/components/Switch/index.tsx +10 -15
- package/src/components/TagItem/__snapshots__/index.story.storyshot +39 -158
- package/src/components/TagItem/index.tsx +84 -19
- package/src/components/TextArea/__snapshots__/TextArea.story.storyshot +126 -321
- package/src/components/TextArea/index.tsx +38 -43
- package/src/components/TextField/TextField.story.tsx +35 -19
- package/src/components/TextField/__snapshots__/TextField.story.storyshot +309 -563
- package/src/components/TextField/index.tsx +85 -84
- package/src/components/TextField/useFocusWithClick.tsx +22 -0
|
@@ -2,11 +2,11 @@ import { useTextField } from '@react-aria/textfield'
|
|
|
2
2
|
import { useVisuallyHidden } from '@react-aria/visually-hidden'
|
|
3
3
|
import { ReactNode, useCallback, useEffect, useRef, useState } from 'react'
|
|
4
4
|
import * as React from 'react'
|
|
5
|
-
import styled from 'styled-components'
|
|
5
|
+
import styled, { css } from 'styled-components'
|
|
6
6
|
import FieldLabel, { FieldLabelProps } from '../FieldLabel'
|
|
7
7
|
import { countCodePointsInString, mergeRefs } from '../../_lib'
|
|
8
|
-
import { theme } from '../../styled'
|
|
9
8
|
import { ReactAreaUseTextFieldCompat } from '../../_lib/compat'
|
|
9
|
+
import { useFocusWithClick } from './useFocusWithClick'
|
|
10
10
|
|
|
11
11
|
type DOMProps = Omit<
|
|
12
12
|
React.InputHTMLAttributes<HTMLInputElement>,
|
|
@@ -64,13 +64,9 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
64
64
|
|
|
65
65
|
const { visuallyHiddenProps } = useVisuallyHidden()
|
|
66
66
|
const ariaRef = useRef<HTMLInputElement>(null)
|
|
67
|
-
const prefixRef = useRef<HTMLSpanElement>(null)
|
|
68
|
-
const suffixRef = useRef<HTMLSpanElement>(null)
|
|
69
67
|
const [count, setCount] = useState(
|
|
70
68
|
countCodePointsInString(props.value ?? '')
|
|
71
69
|
)
|
|
72
|
-
const [prefixWidth, setPrefixWidth] = useState(0)
|
|
73
|
-
const [suffixWidth, setSuffixWidth] = useState(0)
|
|
74
70
|
|
|
75
71
|
const nonControlled = props.value === undefined
|
|
76
72
|
const handleChange = useCallback(
|
|
@@ -106,26 +102,9 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
106
102
|
ariaRef
|
|
107
103
|
)
|
|
108
104
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
})
|
|
113
|
-
const suffixObserver = new ResizeObserver((entries) => {
|
|
114
|
-
setSuffixWidth(entries[0].contentRect.width)
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
if (prefixRef.current !== null) {
|
|
118
|
-
prefixObserver.observe(prefixRef.current)
|
|
119
|
-
}
|
|
120
|
-
if (suffixRef.current !== null) {
|
|
121
|
-
suffixObserver.observe(suffixRef.current)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return () => {
|
|
125
|
-
suffixObserver.disconnect()
|
|
126
|
-
prefixObserver.disconnect()
|
|
127
|
-
}
|
|
128
|
-
}, [])
|
|
105
|
+
const containerRef = useRef(null)
|
|
106
|
+
|
|
107
|
+
useFocusWithClick(containerRef, ariaRef)
|
|
129
108
|
|
|
130
109
|
return (
|
|
131
110
|
<TextFieldRoot className={className} isDisabled={disabled}>
|
|
@@ -137,25 +116,29 @@ const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
137
116
|
{...labelProps}
|
|
138
117
|
{...(!showLabel ? visuallyHiddenProps : {})}
|
|
139
118
|
/>
|
|
140
|
-
<StyledInputContainer
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
119
|
+
<StyledInputContainer
|
|
120
|
+
ref={containerRef}
|
|
121
|
+
invalid={invalid}
|
|
122
|
+
aria-disabled={disabled === true ? true : undefined}
|
|
123
|
+
hasPrefix={prefix != null}
|
|
124
|
+
hasSuffix={suffix != null || showCount}
|
|
125
|
+
>
|
|
126
|
+
{prefix && <PrefixContainer>{prefix}</PrefixContainer>}
|
|
144
127
|
<StyledInput
|
|
145
128
|
ref={mergeRefs(forwardRef, ariaRef)}
|
|
146
129
|
invalid={invalid}
|
|
147
|
-
extraLeftPadding={prefixWidth}
|
|
148
|
-
extraRightPadding={suffixWidth}
|
|
149
130
|
{...inputProps}
|
|
150
131
|
/>
|
|
151
|
-
|
|
152
|
-
<
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
132
|
+
{(suffix || showCount) && (
|
|
133
|
+
<SuffixContainer>
|
|
134
|
+
{suffix}
|
|
135
|
+
{showCount && (
|
|
136
|
+
<SingleLineCounter>
|
|
137
|
+
{maxLength !== undefined ? `${count}/${maxLength}` : count}
|
|
138
|
+
</SingleLineCounter>
|
|
139
|
+
)}
|
|
140
|
+
</SuffixContainer>
|
|
141
|
+
)}
|
|
159
142
|
</StyledInputContainer>
|
|
160
143
|
{assistiveText != null && assistiveText.length !== 0 && (
|
|
161
144
|
<AssistiveText
|
|
@@ -179,44 +162,68 @@ const TextFieldRoot = styled.div<{ isDisabled: boolean }>`
|
|
|
179
162
|
${(p) => p.isDisabled && { opacity: p.theme.elementEffect.disabled.opacity }}
|
|
180
163
|
`
|
|
181
164
|
|
|
182
|
-
const TextFieldLabel = styled(FieldLabel)`
|
|
183
|
-
|
|
165
|
+
export const TextFieldLabel = styled(FieldLabel)`
|
|
166
|
+
margin-bottom: 8px;
|
|
184
167
|
`
|
|
185
168
|
|
|
186
|
-
const StyledInputContainer = styled.div
|
|
187
|
-
|
|
169
|
+
const StyledInputContainer = styled.div<{
|
|
170
|
+
invalid: boolean
|
|
171
|
+
hasPrefix: boolean
|
|
172
|
+
hasSuffix: boolean
|
|
173
|
+
}>`
|
|
188
174
|
display: grid;
|
|
189
|
-
|
|
175
|
+
grid-template-columns: ${(p) =>
|
|
176
|
+
[p.hasPrefix && 'auto', '1fr', p.hasSuffix && 'auto']
|
|
177
|
+
.filter(Boolean)
|
|
178
|
+
.join(' ')};
|
|
179
|
+
height: 40px;
|
|
180
|
+
transition: 0.2s background-color, 0.2s box-shadow;
|
|
181
|
+
color: var(--charcoal-text2);
|
|
182
|
+
background-color: var(--charcoal-surface3);
|
|
183
|
+
border-radius: 4px;
|
|
184
|
+
gap: 4px;
|
|
185
|
+
padding: 0 8px;
|
|
186
|
+
line-height: 22px;
|
|
187
|
+
font-size: 14px;
|
|
188
|
+
|
|
189
|
+
:not(:disabled):not([aria-disabled]):hover,
|
|
190
|
+
[aria-disabled='false']:hover {
|
|
191
|
+
background-color: var(--charcoal-surface3-hover);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
:not(:disabled):not([aria-disabled]):active,
|
|
195
|
+
[aria-disabled='false']:active {
|
|
196
|
+
outline: none;
|
|
197
|
+
box-shadow: 0 0 0 4px
|
|
198
|
+
${(p) => (p.invalid ? `rgba(255,43,0,0.32)` : `rgba(0, 150, 250, 0.32);`)};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
:focus-within {
|
|
202
|
+
outline: none;
|
|
203
|
+
box-shadow: 0 0 0 4px
|
|
204
|
+
${(p) => (p.invalid ? `rgba(255,43,0,0.32)` : `rgba(0, 150, 250, 0.32);`)};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
${(p) =>
|
|
208
|
+
p.invalid &&
|
|
209
|
+
css`
|
|
210
|
+
box-shadow: 0 0 0 4px rgba(255, 43, 0, 0.32);
|
|
211
|
+
`}
|
|
190
212
|
`
|
|
191
213
|
|
|
192
|
-
const PrefixContainer = styled.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
left: 8px;
|
|
196
|
-
transform: translateY(-50%);
|
|
197
|
-
z-index: 1;
|
|
214
|
+
const PrefixContainer = styled.div`
|
|
215
|
+
display: flex;
|
|
216
|
+
align-items: center;
|
|
198
217
|
`
|
|
199
218
|
|
|
200
219
|
const SuffixContainer = styled.span`
|
|
201
|
-
position: absolute;
|
|
202
|
-
top: 50%;
|
|
203
|
-
right: 8px;
|
|
204
|
-
transform: translateY(-50%);
|
|
205
|
-
|
|
206
220
|
display: flex;
|
|
221
|
+
align-items: center;
|
|
207
222
|
gap: 8px;
|
|
208
223
|
`
|
|
209
224
|
|
|
210
|
-
const Affix = styled.span`
|
|
211
|
-
user-select: none;
|
|
212
|
-
|
|
213
|
-
${theme((o) => [o.typography(14).preserveHalfLeading, o.font.text2])}
|
|
214
|
-
`
|
|
215
|
-
|
|
216
225
|
const StyledInput = styled.input<{
|
|
217
226
|
invalid: boolean
|
|
218
|
-
extraLeftPadding: number
|
|
219
|
-
extraRightPadding: number
|
|
220
227
|
}>`
|
|
221
228
|
border: none;
|
|
222
229
|
box-sizing: border-box;
|
|
@@ -230,36 +237,30 @@ const StyledInput = styled.input<{
|
|
|
230
237
|
height: calc(100% / 0.875);
|
|
231
238
|
font-size: calc(14px / 0.875);
|
|
232
239
|
line-height: calc(22px / 0.875);
|
|
233
|
-
padding-left:
|
|
234
|
-
padding-right:
|
|
240
|
+
padding-left: 0;
|
|
241
|
+
padding-right: 0;
|
|
235
242
|
border-radius: calc(4px / 0.875);
|
|
236
243
|
|
|
237
244
|
/* Display box-shadow for iOS Safari */
|
|
238
245
|
appearance: none;
|
|
246
|
+
background: transparent;
|
|
239
247
|
|
|
240
|
-
|
|
241
|
-
theme((o) => [
|
|
242
|
-
o.bg.surface3.hover,
|
|
243
|
-
o.outline.default.focus,
|
|
244
|
-
p.invalid && o.outline.assertive,
|
|
245
|
-
o.font.text2,
|
|
246
|
-
])}
|
|
247
|
-
|
|
248
|
+
color: var(--charcoal-text2);
|
|
248
249
|
&::placeholder {
|
|
249
|
-
|
|
250
|
+
color: var(--charcoal-text3);
|
|
250
251
|
}
|
|
251
252
|
`
|
|
252
253
|
|
|
253
254
|
const SingleLineCounter = styled.span`
|
|
254
|
-
|
|
255
|
+
line-height: 22px;
|
|
256
|
+
font-size: 14px;
|
|
257
|
+
color: var(--charcoal-text3);
|
|
255
258
|
`
|
|
256
259
|
|
|
257
|
-
const AssistiveText = styled.p<{ invalid: boolean }>`
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
o.font[p.invalid ? 'assertive' : 'text1'],
|
|
264
|
-
])}
|
|
260
|
+
export const AssistiveText = styled.p<{ invalid: boolean }>`
|
|
261
|
+
font-size: 14px;
|
|
262
|
+
line-height: 22px;
|
|
263
|
+
margin-top: 4px;
|
|
264
|
+
margin-bottom: -4px;
|
|
265
|
+
color: ${(p) => `var(--charcoal-${p.invalid ? `assertive` : `text2`})`};
|
|
265
266
|
`
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
|
|
4
|
+
export function useFocusWithClick(
|
|
5
|
+
containerRef: React.RefObject<HTMLDivElement>,
|
|
6
|
+
inputRef: React.RefObject<HTMLInputElement | HTMLTextAreaElement>
|
|
7
|
+
) {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const el = containerRef.current
|
|
10
|
+
if (el) {
|
|
11
|
+
const handleDown = (e: MouseEvent) => {
|
|
12
|
+
if (e.target !== inputRef.current) {
|
|
13
|
+
inputRef.current?.focus()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
el.addEventListener('click', handleDown)
|
|
17
|
+
return () => {
|
|
18
|
+
el.removeEventListener('click', handleDown)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
}
|