From edc85c96c6c70adebbc4af1e2d05a913f249f2d3 Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Tue, 29 Mar 2022 16:01:19 -0400 Subject: [PATCH] Add trailingAction to TextInput (#1947) * adds loading indicator to text inputs * removes style debugging div * updates stories and docs * updates tests * fixes silly test mistakes * revert default textinput story * adds changeset * Update src/TextInput.tsx Co-authored-by: Pavithra Kodmad * updates component API * adds trailing action to text input, tweaks formcontrol * addresses PR feedback * fixes linting error * indicate a busy status to assistive technology * updates snaps * renames 'isLoading' prop to 'loading' * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis * Update docs/content/TextInput.mdx Co-authored-by: Cole Bemis * updates snapshots * nests examples under an 'Examples' heading * export TextInput non-pass-through props * fix undefined type usage * fixes story types * rm unnecessary width style from formcontrol, fix formcontrol import * rm forgotten comment * adds changeset * silences linting error and rms bad imports * addresses PR feedback * rms redundant stories * removes excess right padding when we pass 'trailingAction' and 'loading' * change iconLabel to aria-label in docs example * empy commit to make CI run * disable html-addon to prevent Storybook from timing out Chromatic Co-authored-by: Pavithra Kodmad Co-authored-by: Cole Bemis --- .changeset/chatty-moose-wait.md | 5 + docs/content/TextInput.mdx | 159 ++- src/FormControl/FormControl.tsx | 4 +- src/TextInput.tsx | 41 +- src/_InputLabel.tsx | 1 + src/_TextInputInnerAction.tsx | 84 ++ src/_TextInputWrapper.tsx | 76 +- src/__tests__/TextInput.test.tsx | 43 + .../__snapshots__/Autocomplete.test.tsx.snap | 21 +- .../__snapshots__/TextInput.test.tsx.snap | 1222 ++++++++++++++++- .../TextInputWithTokens.test.tsx.snap | 75 +- .../ChoiceFieldset.test.tsx.snap | 18 + src/stories/TextInput.stories.tsx | 148 +- 13 files changed, 1703 insertions(+), 194 deletions(-) create mode 100644 .changeset/chatty-moose-wait.md create mode 100644 src/_TextInputInnerAction.tsx diff --git a/.changeset/chatty-moose-wait.md b/.changeset/chatty-moose-wait.md new file mode 100644 index 00000000000..2f99878480c --- /dev/null +++ b/.changeset/chatty-moose-wait.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +Adds the option to render a trailing action inside of the TextInput component diff --git a/docs/content/TextInput.mdx b/docs/content/TextInput.mdx index bb98bb7113c..4ec34745bc8 100644 --- a/docs/content/TextInput.mdx +++ b/docs/content/TextInput.mdx @@ -108,6 +108,42 @@ const WithIconAndLoadingIndicator = () => { render() ``` +### With trailing action + +```jsx live + + + Icon action + { + alert('clear input') + }} + icon={XIcon} + aria-label="Clear input" + sx={{color: 'fg.subtle'}} + /> + } + /> + + + Text action + { + alert('clear input') + }} + > + Clear + + } + /> + + +``` + ### With error and warning states ```jsx live @@ -160,61 +196,63 @@ render() - + - - - - -
Which position to render the loading indicator
-
    -
  • - 'auto' (default): at the end of the input, unless a `leadingVisual` is passed. Then, it will render at the - beginning -
  • -
  • 'leading': at the beginning of the input
  • -
  • 'trailing': at the end of the input
  • -
- - } -/> -string | React.ComponentType} - description="Visual positioned on the left edge inside the input" -/> - -string | React.ComponentType} - description="Visual positioned on the right edge inside the input" -/> - - - + + + +
Which position to render the loading indicator
+
    +
  • + 'auto' (default): at the end of the input, unless a `leadingVisual` is passed. Then, it will render at the + beginning +
  • +
  • 'leading': at the beginning of the input
  • +
  • 'trailing': at the end of the input
  • +
+ + } + /> + string | React.ComponentType} + description="Visual positioned on the left edge inside the input" + /> + + string | React.ComponentType} + description="Visual positioned on the right edge inside the input" + /> + + + ) />
+### TextInput.Action + + + + + + MDN + } + /> + + ## Status ( ref={ref} display="flex" flexDirection="column" - width="100%" sx={{...(isLabelHidden ? {'> *:not(label) + *': {marginTop: 1}} : {'> * + *': {marginTop: 1}}), ...sx}} > {slots.Label} @@ -184,7 +183,8 @@ const FormControl = React.forwardRef( required, disabled, validationStatus, - ['aria-describedby']: [validationMessageId, captionId].filter(Boolean).join(' ') + ['aria-describedby']: [validationMessageId, captionId].filter(Boolean).join(' '), + ...InputComponent.props })} {React.Children.toArray(children).filter( child => diff --git a/src/TextInput.tsx b/src/TextInput.tsx index 08f59f3ea89..af50cade0f3 100644 --- a/src/TextInput.tsx +++ b/src/TextInput.tsx @@ -1,4 +1,4 @@ -import React, {MouseEventHandler} from 'react' +import React, {MouseEventHandler, useCallback, useState} from 'react' import {ForwardRefComponent as PolymorphicForwardRefComponent} from '@radix-ui/react-polymorphic' import classnames from 'classnames' @@ -7,6 +7,7 @@ import {useProvidedRefOrCreate} from './hooks' import {Merge} from './utils/types' import TextInputWrapper, {StyledWrapperProps} from './_TextInputWrapper' import UnstyledTextInput from './_UnstyledTextInput' +import TextInputAction from './_TextInputInnerAction' export type TextInputNonPassthroughProps = { /** @deprecated Use `leadingVisual` or `trailingVisual` prop instead */ @@ -28,6 +29,10 @@ export type TextInputNonPassthroughProps = { * A visual that renders inside the input after the typing area */ trailingVisual?: string | React.ComponentType<{className?: string}> + /** + * A visual that renders inside the input after the typing area + */ + trailingAction?: React.ReactElement> } & Pick< StyledWrapperProps, | 'block' @@ -52,6 +57,7 @@ const TextInput = React.forwardRef( icon: IconComponent, leadingVisual: LeadingVisual, trailingVisual: TrailingVisual, + trailingAction, block, className, contrast, @@ -62,6 +68,8 @@ const TextInput = React.forwardRef( validationStatus, sx: sxProp, size: sizeProp, + onFocus, + onBlur, // start deprecated props width: widthProp, minWidth: minWidthProp, @@ -72,6 +80,7 @@ const TextInput = React.forwardRef( }, ref ) => { + const [isInputFocused, setIsInputFocused] = useState(false) const inputRef = useProvidedRefOrCreate(ref as React.RefObject) // this class is necessary to style FilterSearch, plz no touchy! const wrapperClasses = classnames(className, 'TextInput-wrapper') @@ -82,6 +91,20 @@ const TextInput = React.forwardRef( const focusInput: MouseEventHandler = () => { inputRef.current?.focus() } + const handleInputFocus = useCallback( + e => { + setIsInputFocused(true) + onFocus && onFocus(e) + }, + [onFocus] + ) + const handleInputBlur = useCallback( + e => { + setIsInputFocused(false) + onBlur && onBlur(e) + }, + [onBlur] + ) return ( ( variant={variantProp} hasLeadingVisual={Boolean(LeadingVisual || showLeadingLoadingIndicator)} hasTrailingVisual={Boolean(TrailingVisual || showTrailingLoadingIndicator)} + hasTrailingAction={Boolean(trailingAction)} + isInputFocused={isInputFocused} onClick={focusInput} aria-live="polite" aria-busy={Boolean(loading)} @@ -111,7 +136,14 @@ const TextInput = React.forwardRef( > {typeof LeadingVisual === 'function' ? : LeadingVisual} - + ( > {typeof TrailingVisual === 'function' ? : TrailingVisual} + {trailingAction} ) } @@ -131,4 +164,6 @@ TextInput.defaultProps = { TextInput.displayName = 'TextInput' -export default TextInput +export default Object.assign(TextInput, { + Action: TextInputAction +}) diff --git a/src/_InputLabel.tsx b/src/_InputLabel.tsx index 6118c7c9633..2b6a51554bf 100644 --- a/src/_InputLabel.tsx +++ b/src/_InputLabel.tsx @@ -21,6 +21,7 @@ const InputLabel: React.FC = ({children, disabled, required, vis display: 'block', color: disabled ? 'fg.muted' : 'fg.default', cursor: disabled ? 'default' : 'pointer', + alignSelf: 'flex-start', ...sx }} > diff --git a/src/_TextInputInnerAction.tsx b/src/_TextInputInnerAction.tsx new file mode 100644 index 00000000000..a9382b0cf2e --- /dev/null +++ b/src/_TextInputInnerAction.tsx @@ -0,0 +1,84 @@ +import React, {forwardRef} from 'react' +import {IconProps} from '@primer/octicons-react' +import {Box, Button, IconButton, Tooltip} from '.' +import {ButtonProps} from './Button' +import {BetterSystemStyleObject, merge, SxProp} from './sx' + +type TextInputActionProps = Omit, 'aria-label' | 'size'> & { + /** Text that appears in a tooltip. If an icon is passed, this is also used as the label used by assistive technologies. */ + ['aria-label']?: string + /** The icon to render inside the button */ + icon?: React.FunctionComponent + /** + * Determine's the styles on a button one of 'default' | 'primary' | 'invisible' | 'danger' + */ + variant?: ButtonProps['variant'] +} & SxProp + +const invisibleButtonStyleOverrides = { + color: 'fg.default' +} + +const ConditionalTooltip: React.FC<{ + ['aria-label']?: string + children: React.ReactNode +}> = ({'aria-label': ariaLabel, children}) => ( + <> + {ariaLabel ? ( + + {children} + + ) : ( + children + )} + +) + +const TextInputAction = forwardRef( + ({'aria-label': ariaLabel, children, icon, sx: sxProp, variant, ...rest}, forwardedRef) => { + const sx = + variant === 'invisible' ? merge(invisibleButtonStyleOverrides, sxProp || {}) : sxProp + + if ((icon && !ariaLabel) || (!children && !ariaLabel)) { + // eslint-disable-next-line no-console + console.warn('Use the `aria-label` prop to provide an accessible label for assistive technology') + } + + return ( + + {icon && !children ? ( + + + + ) : ( + + + + )} + + ) + } +) + +TextInputAction.defaultProps = { + variant: 'invisible' +} + +export default TextInputAction diff --git a/src/_TextInputWrapper.tsx b/src/_TextInputWrapper.tsx index 3b59af94162..29962499ee6 100644 --- a/src/_TextInputWrapper.tsx +++ b/src/_TextInputWrapper.tsx @@ -45,6 +45,8 @@ export type StyledBaseWrapperProps = { block?: boolean contrast?: boolean disabled?: boolean + hasTrailingAction?: boolean + isInputFocused?: boolean monospace?: boolean validationStatus?: FormValidationStatus } & WidthProps & @@ -63,6 +65,24 @@ export type StyledWrapperProps = { const textInputBasePadding = '12px' export const textInputHorizPadding = textInputBasePadding +// TODO: figure out how to type a themed CSS function (e.g.: css`color: blue;`) +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const renderFocusStyles = (hasTrailingAction: boolean, isInputFocused: boolean, focusStyles: any) => { + if (hasTrailingAction) { + return ( + isInputFocused && + css` + ${focusStyles} + ` + ) + } + return css` + &:focus-within { + ${focusStyles} + } + ` +} + export const TextInputBaseWrapper = styled.span` font-size: ${get('fontSizes.1')}; line-height: 20px; @@ -82,10 +102,15 @@ export const TextInputBaseWrapper = styled.span` color: ${get('colors.fg.subtle')}; } - &:focus-within { - border-color: ${get('colors.accent.emphasis')}; - box-shadow: ${get('shadows.primer.shadow.focus')}; - } + ${props => + renderFocusStyles( + Boolean(props.hasTrailingAction), + Boolean(props.isInputFocused), + css` + border-color: ${get('colors.accent.emphasis')}; + box-shadow: ${get('shadows.primer.shadow.focus')}; + ` + )} > textarea { padding: ${textInputBasePadding}; @@ -116,10 +141,14 @@ export const TextInputBaseWrapper = styled.span` props.validationStatus === 'error' && css` border-color: ${get('colors.danger.emphasis')}; - &:focus-within { - border-color: ${get('colors.danger.emphasis')}; - box-shadow: ${get('shadows.btn.danger.focusShadow')}; - } + ${renderFocusStyles( + Boolean(props.hasTrailingAction), + Boolean(props.isInputFocused), + css` + border-color: ${get('colors.danger.emphasis')}; + box-shadow: ${get('shadows.btn.danger.focusShadow')}; + ` + )} `} @@ -127,10 +156,14 @@ export const TextInputBaseWrapper = styled.span` props.validationStatus === 'success' && css` border-color: ${get('colors.success.emphasis')}; - &:focus-within { - border-color: ${get('colors.success.emphasis')}; - box-shadow: 0 0 0 3px ${get('colors.success.muted')}; - } + ${renderFocusStyles( + Boolean(props.hasTrailingAction), + Boolean(props.isInputFocused), + css` + border-color: ${get('colors.success.emphasis')}; + box-shadow: 0 0 0 3px ${get('colors.success.muted')}; + ` + )} `} ${props => @@ -161,7 +194,8 @@ const TextInputWrapper = styled(TextInputBaseWrapper)` margin-right: ${get('space.2')}; } - .TextInput-icon { + .TextInput-icon, + .TextInput-action { align-self: center; color: ${get('colors.fg.muted')}; flex-shrink: 0; @@ -170,12 +204,12 @@ const TextInputWrapper = styled(TextInputBaseWrapper)` ${props => css` padding-left: ${props.hasLeadingVisual ? textInputHorizPadding : 0}; - padding-right: ${props.hasTrailingVisual ? textInputHorizPadding : 0}; + padding-right: ${props.hasTrailingVisual && !props.hasTrailingAction ? textInputHorizPadding : 0}; > input, > select { padding-left: ${!props.hasLeadingVisual ? textInputHorizPadding : 0}; - padding-right: ${!props.hasTrailingVisual ? textInputHorizPadding : 0}; + padding-right: ${!props.hasTrailingVisual && !props.hasTrailingAction ? textInputHorizPadding : 0}; } `} @@ -183,10 +217,14 @@ const TextInputWrapper = styled(TextInputBaseWrapper)` props.validationStatus === 'warning' && css` border-color: ${get('colors.attention.emphasis')}; - &:focus-within { - border-color: ${get('colors.attention.emphasis')}; - box-shadow: 0 0 0 3px ${get('colors.attention.muted')}; - } + ${renderFocusStyles( + Boolean(props.hasTrailingAction), + Boolean(props.isInputFocused), + css` + border-color: ${get('colors.attention.emphasis')}; + box-shadow: 0 0 0 3px ${get('colors.attention.muted')}; + ` + )} `} ${sx}; diff --git a/src/__tests__/TextInput.test.tsx b/src/__tests__/TextInput.test.tsx index a99c5eee014..1516917ca2b 100644 --- a/src/__tests__/TextInput.test.tsx +++ b/src/__tests__/TextInput.test.tsx @@ -64,6 +64,49 @@ describe('TextInput', () => { expect(render()).toMatchSnapshot() }) + it('renders trailingAction text button', () => { + const handleAction = jest.fn() + expect( + render( + Clear} + /> + ) + ).toMatchSnapshot() + }) + + it('renders trailingAction text button with a tooltip', () => { + const handleAction = jest.fn() + expect( + render( + + Clear + + } + /> + ) + ).toMatchSnapshot() + }) + + it('renders trailingAction icon button', () => { + const handleAction = jest.fn() + expect( + render( + } + /> + ) + ).toMatchSnapshot() + }) + it('focuses the text input if you do not click the input element', () => { const {container, getByLabelText} = HTMLRender( <> diff --git a/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap b/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap index 41a43e1d331..56c84fb8419 100644 --- a/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap +++ b/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap @@ -57,7 +57,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -207,7 +208,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -392,7 +394,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -1340,7 +1343,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -2198,7 +2202,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -3067,7 +3072,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -4066,7 +4072,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap index 9b90d3ef97f..6c82e7e7ba0 100644 --- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap +++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap @@ -56,7 +56,8 @@ exports[`TextInput renders 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -102,6 +103,8 @@ exports[`TextInput renders 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} type="text" /> @@ -168,7 +171,8 @@ exports[`TextInput renders block 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -214,6 +218,8 @@ exports[`TextInput renders block 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} type="text" /> @@ -275,7 +281,8 @@ exports[`TextInput renders consistently 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -320,6 +327,8 @@ exports[`TextInput renders consistently 1`] = ` @@ -382,7 +391,8 @@ exports[`TextInput renders contrast 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -428,6 +438,8 @@ exports[`TextInput renders contrast 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} type="text" /> @@ -495,7 +507,8 @@ exports[`TextInput renders error 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -541,6 +554,8 @@ exports[`TextInput renders error 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} type="text" /> @@ -607,7 +622,8 @@ exports[`TextInput renders large 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -654,6 +670,8 @@ exports[`TextInput renders large 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} type="text" /> @@ -715,7 +733,8 @@ exports[`TextInput renders leadingVisual 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -787,6 +806,8 @@ exports[`TextInput renders leadingVisual 1`] = ` className="c1" data-component="input" name="search" + onBlur={[Function]} + onFocus={[Function]} placeholder="Search" type="text" /> @@ -850,7 +871,8 @@ exports[`TextInput renders monospace 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -896,6 +918,8 @@ exports[`TextInput renders monospace 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} type="text" /> @@ -957,7 +981,8 @@ exports[`TextInput renders placeholder 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -1003,6 +1028,8 @@ exports[`TextInput renders placeholder 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} placeholder="560076" type="text" /> @@ -1072,7 +1099,8 @@ exports[`TextInput renders small 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -1119,11 +1147,1110 @@ exports[`TextInput renders small 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} type="text" /> `; +exports[`TextInput renders trailingAction icon button 1`] = ` +.c4 { + display: inline-block; +} + +.c3 { + border-radius: 6px; + border: 0; + border-color: rgba(27,31,36,0.15); + font-family: inherit; + font-weight: 600; + line-height: 20px; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-text-decoration: none; + text-decoration: none; + text-align: center; + padding-top: 6px; + padding-bottom: 6px; + padding-left: 8px; + padding-right: 8px; + font-size: 14px; + color: #24292f; + background-color: transparent; + box-shadow: none; +} + +.c3:focus { + outline: none; +} + +.c3:disabled { + cursor: default; + color: #8c959f; +} + +.c3:disabled [data-component=ButtonCounter] { + color: inherit; +} + +.c3:disabled svg { + opacity: 0.6; +} + +.c3 [data-component=ButtonCounter] { + font-size: 14px; +} + +.c3:hover:not([disabled]) { + background-color: #f3f4f6; +} + +.c3:focus:not([disabled]) { + box-shadow: 0 0 0 3px rgba(9,105,218,0.3); +} + +.c3:active:not([disabled]) { + background-color: hsla(220,14%,94%,1); +} + +.c3[aria-expanded=true] { + background-color: hsla(220,14%,94%,1); +} + +.c0 { + font-size: 14px; + line-height: 20px; + color: #24292f; + vertical-align: middle; + background-color: #ffffff; + border: 1px solid #d0d7de; + border-radius: 6px; + outline: none; + box-shadow: inset 0 1px 0 rgba(208,215,222,0.2); + cursor: text; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: stretch; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + min-height: 32px; + background-repeat: no-repeat; + background-position: right 8px center; + padding-left: 0; + padding-right: 0; +} + +.c0::-webkit-input-placeholder { + color: #6e7781; +} + +.c0::-moz-placeholder { + color: #6e7781; +} + +.c0:-ms-input-placeholder { + color: #6e7781; +} + +.c0::placeholder { + color: #6e7781; +} + +.c0 > textarea { + padding: 12px; +} + +.c0 >:not(:last-child) { + margin-right: 8px; +} + +.c0 .TextInput-icon, +.c0 .TextInput-action { + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; + color: #57606a; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.c0 > input, +.c0 > select { + padding-left: 12px; + padding-right: 0; +} + +.c1 { + border: 0; + font-size: inherit; + font-family: inherit; + background-color: transparent; + -webkit-appearance: none; + color: inherit; + width: 100%; +} + +.c1:focus { + outline: 0; +} + +.c2 { + position: relative; +} + +.c2::before { + position: absolute; + z-index: 1000001; + display: none; + width: 0px; + height: 0px; + color: #24292f; + pointer-events: none; + content: ''; + border: 6px solid transparent; + opacity: 0; +} + +.c2::after { + position: absolute; + z-index: 1000000; + display: none; + padding: 0.5em 0.75em; + font: normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; + -webkit-font-smoothing: subpixel-antialiased; + color: #ffffff; + text-align: center; + -webkit-text-decoration: none; + text-decoration: none; + text-shadow: none; + text-transform: none; + -webkit-letter-spacing: normal; + -moz-letter-spacing: normal; + -ms-letter-spacing: normal; + letter-spacing: normal; + word-wrap: break-word; + white-space: pre; + pointer-events: none; + content: attr(aria-label); + background: #24292f; + border-radius: 3px; + opacity: 0; +} + +.c2:hover::before, +.c2:active::before, +.c2:focus::before, +.c2:hover::after, +.c2:active::after, +.c2:focus::after { + display: inline-block; + -webkit-text-decoration: none; + text-decoration: none; + -webkit-animation-name: tooltip-appear; + animation-name: tooltip-appear; + -webkit-animation-duration: 0.1s; + animation-duration: 0.1s; + -webkit-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + -webkit-animation-delay: 0.4s; + animation-delay: 0.4s; +} + +.c2.tooltipped-no-delay:hover::before, +.c2.tooltipped-no-delay:active::before, +.c2.tooltipped-no-delay:focus::before, +.c2.tooltipped-no-delay:hover::after, +.c2.tooltipped-no-delay:active::after, +.c2.tooltipped-no-delay:focus::after { + -webkit-animation-delay: 0s; + animation-delay: 0s; +} + +.c2.tooltipped-multiline:hover::after, +.c2.tooltipped-multiline:active::after, +.c2.tooltipped-multiline:focus::after { + display: table-cell; +} + +.c2.tooltipped-s::after, +.c2.tooltipped-se::after, +.c2.tooltipped-sw::after { + top: 100%; + right: 50%; + margin-top: 6px; +} + +.c2.tooltipped-s::before, +.c2.tooltipped-se::before, +.c2.tooltipped-sw::before { + top: auto; + right: 50%; + bottom: -7px; + margin-right: -6px; + border-bottom-color: #24292f; +} + +.c2.tooltipped-se::after { + right: auto; + left: 50%; + margin-left: -16px; +} + +.c2.tooltipped-sw::after { + margin-right: -16px; +} + +.c2.tooltipped-n::after, +.c2.tooltipped-ne::after, +.c2.tooltipped-nw::after { + right: 50%; + bottom: 100%; + margin-bottom: 6px; +} + +.c2.tooltipped-n::before, +.c2.tooltipped-ne::before, +.c2.tooltipped-nw::before { + top: -7px; + right: 50%; + bottom: auto; + margin-right: -6px; + border-top-color: #24292f; +} + +.c2.tooltipped-ne::after { + right: auto; + left: 50%; + margin-left: -16px; +} + +.c2.tooltipped-nw::after { + margin-right: -16px; +} + +.c2.tooltipped-s::after, +.c2.tooltipped-n::after { + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); +} + +.c2.tooltipped-w::after { + right: 100%; + bottom: 50%; + margin-right: 6px; + -webkit-transform: translateY(50%); + -ms-transform: translateY(50%); + transform: translateY(50%); +} + +.c2.tooltipped-w::before { + top: 50%; + bottom: 50%; + left: -7px; + margin-top: -6px; + border-left-color: #24292f; +} + +.c2.tooltipped-e::after { + bottom: 50%; + left: 100%; + margin-left: 6px; + -webkit-transform: translateY(50%); + -ms-transform: translateY(50%); + transform: translateY(50%); +} + +.c2.tooltipped-e::before { + top: 50%; + right: -7px; + bottom: 50%; + margin-top: -6px; + border-right-color: #24292f; +} + +.c2.tooltipped-multiline::after { + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; + max-width: 250px; + word-wrap: break-word; + white-space: pre-line; + border-collapse: separate; +} + +.c2.tooltipped-multiline.tooltipped-s::after, +.c2.tooltipped-multiline.tooltipped-n::after { + right: auto; + left: 50%; + -webkit-transform: translateX(-50%); + -ms-transform: translateX(-50%); + transform: translateX(-50%); +} + +.c2.tooltipped-multiline.tooltipped-w::after, +.c2.tooltipped-multiline.tooltipped-e::after { + right: 100%; +} + +.c2.tooltipped-align-right-2::after { + right: 0; + margin-right: 0; +} + +.c2.tooltipped-align-right-2::before { + right: 15px; +} + +.c2.tooltipped-align-left-2::after { + left: 0; + margin-left: 0; +} + +.c2.tooltipped-align-left-2::before { + left: 10px; +} + +@media (forced-colors:active) { + .c3:focus { + outline: solid 1px transparent; + } +} + +@media (min-width:768px) { + .c0 { + font-size: 14px; + } +} + + + + + + + + + +`; + +exports[`TextInput renders trailingAction text button 1`] = ` +.c2 { + border-radius: 6px; + border: 0; + border-color: rgba(27,31,36,0.15); + font-family: inherit; + font-weight: 600; + line-height: 20px; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-text-decoration: none; + text-decoration: none; + text-align: center; + display: grid; + grid-template-areas: "leadingIcon text trailingIcon"; + padding-top: 4px; + padding-bottom: 4px; + padding-left: 12px; + padding-right: 12px; + font-size: 12px; + color: #24292f; + background-color: transparent; + box-shadow: none; +} + +.c2:focus { + outline: none; +} + +.c2:disabled { + cursor: default; + color: #8c959f; +} + +.c2:disabled [data-component=ButtonCounter] { + color: inherit; +} + +.c2:disabled svg { + opacity: 0.6; +} + +.c2 > :not(:last-child) { + margin-right: 8px; +} + +.c2 [data-component="leadingIcon"] { + grid-area: leadingIcon; +} + +.c2 [data-component="text"] { + grid-area: text; +} + +.c2 [data-component="trailingIcon"] { + grid-area: trailingIcon; +} + +.c2 [data-component=ButtonCounter] { + font-size: 12px; +} + +.c2:hover:not([disabled]) { + background-color: #f3f4f6; +} + +.c2:focus:not([disabled]) { + box-shadow: 0 0 0 3px rgba(9,105,218,0.3); +} + +.c2:active:not([disabled]) { + background-color: hsla(220,14%,94%,1); +} + +.c2[aria-expanded=true] { + background-color: hsla(220,14%,94%,1); +} + +.c0 { + font-size: 14px; + line-height: 20px; + color: #24292f; + vertical-align: middle; + background-color: #ffffff; + border: 1px solid #d0d7de; + border-radius: 6px; + outline: none; + box-shadow: inset 0 1px 0 rgba(208,215,222,0.2); + cursor: text; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: stretch; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + min-height: 32px; + background-repeat: no-repeat; + background-position: right 8px center; + padding-left: 0; + padding-right: 0; +} + +.c0::-webkit-input-placeholder { + color: #6e7781; +} + +.c0::-moz-placeholder { + color: #6e7781; +} + +.c0:-ms-input-placeholder { + color: #6e7781; +} + +.c0::placeholder { + color: #6e7781; +} + +.c0 > textarea { + padding: 12px; +} + +.c0 >:not(:last-child) { + margin-right: 8px; +} + +.c0 .TextInput-icon, +.c0 .TextInput-action { + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; + color: #57606a; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.c0 > input, +.c0 > select { + padding-left: 12px; + padding-right: 0; +} + +.c1 { + border: 0; + font-size: inherit; + font-family: inherit; + background-color: transparent; + -webkit-appearance: none; + color: inherit; + width: 100%; +} + +.c1:focus { + outline: 0; +} + +@media (forced-colors:active) { + .c2:focus { + outline: solid 1px transparent; + } +} + +@media (min-width:768px) { + .c0 { + font-size: 14px; + } +} + + + + + + + +`; + +exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` +.c3 { + border-radius: 6px; + border: 0; + border-color: rgba(27,31,36,0.15); + font-family: inherit; + font-weight: 600; + line-height: 20px; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-text-decoration: none; + text-decoration: none; + text-align: center; + display: grid; + grid-template-areas: "leadingIcon text trailingIcon"; + padding-top: 4px; + padding-bottom: 4px; + padding-left: 12px; + padding-right: 12px; + font-size: 12px; + color: #24292f; + background-color: transparent; + box-shadow: none; +} + +.c3:focus { + outline: none; +} + +.c3:disabled { + cursor: default; + color: #8c959f; +} + +.c3:disabled [data-component=ButtonCounter] { + color: inherit; +} + +.c3:disabled svg { + opacity: 0.6; +} + +.c3 > :not(:last-child) { + margin-right: 8px; +} + +.c3 [data-component="leadingIcon"] { + grid-area: leadingIcon; +} + +.c3 [data-component="text"] { + grid-area: text; +} + +.c3 [data-component="trailingIcon"] { + grid-area: trailingIcon; +} + +.c3 [data-component=ButtonCounter] { + font-size: 12px; +} + +.c3:hover:not([disabled]) { + background-color: #f3f4f6; +} + +.c3:focus:not([disabled]) { + box-shadow: 0 0 0 3px rgba(9,105,218,0.3); +} + +.c3:active:not([disabled]) { + background-color: hsla(220,14%,94%,1); +} + +.c3[aria-expanded=true] { + background-color: hsla(220,14%,94%,1); +} + +.c0 { + font-size: 14px; + line-height: 20px; + color: #24292f; + vertical-align: middle; + background-color: #ffffff; + border: 1px solid #d0d7de; + border-radius: 6px; + outline: none; + box-shadow: inset 0 1px 0 rgba(208,215,222,0.2); + cursor: text; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: stretch; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; + min-height: 32px; + background-repeat: no-repeat; + background-position: right 8px center; + padding-left: 0; + padding-right: 0; +} + +.c0::-webkit-input-placeholder { + color: #6e7781; +} + +.c0::-moz-placeholder { + color: #6e7781; +} + +.c0:-ms-input-placeholder { + color: #6e7781; +} + +.c0::placeholder { + color: #6e7781; +} + +.c0 > textarea { + padding: 12px; +} + +.c0 >:not(:last-child) { + margin-right: 8px; +} + +.c0 .TextInput-icon, +.c0 .TextInput-action { + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; + color: #57606a; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; +} + +.c0 > input, +.c0 > select { + padding-left: 12px; + padding-right: 0; +} + +.c1 { + border: 0; + font-size: inherit; + font-family: inherit; + background-color: transparent; + -webkit-appearance: none; + color: inherit; + width: 100%; +} + +.c1:focus { + outline: 0; +} + +.c2 { + position: relative; + display: inline-block; +} + +.c2::before { + position: absolute; + z-index: 1000001; + display: none; + width: 0px; + height: 0px; + color: #24292f; + pointer-events: none; + content: ''; + border: 6px solid transparent; + opacity: 0; +} + +.c2::after { + position: absolute; + z-index: 1000000; + display: none; + padding: 0.5em 0.75em; + font: normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; + -webkit-font-smoothing: subpixel-antialiased; + color: #ffffff; + text-align: center; + -webkit-text-decoration: none; + text-decoration: none; + text-shadow: none; + text-transform: none; + -webkit-letter-spacing: normal; + -moz-letter-spacing: normal; + -ms-letter-spacing: normal; + letter-spacing: normal; + word-wrap: break-word; + white-space: pre; + pointer-events: none; + content: attr(aria-label); + background: #24292f; + border-radius: 3px; + opacity: 0; +} + +.c2:hover::before, +.c2:active::before, +.c2:focus::before, +.c2:hover::after, +.c2:active::after, +.c2:focus::after { + display: inline-block; + -webkit-text-decoration: none; + text-decoration: none; + -webkit-animation-name: tooltip-appear; + animation-name: tooltip-appear; + -webkit-animation-duration: 0.1s; + animation-duration: 0.1s; + -webkit-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + -webkit-animation-delay: 0.4s; + animation-delay: 0.4s; +} + +.c2.tooltipped-no-delay:hover::before, +.c2.tooltipped-no-delay:active::before, +.c2.tooltipped-no-delay:focus::before, +.c2.tooltipped-no-delay:hover::after, +.c2.tooltipped-no-delay:active::after, +.c2.tooltipped-no-delay:focus::after { + -webkit-animation-delay: 0s; + animation-delay: 0s; +} + +.c2.tooltipped-multiline:hover::after, +.c2.tooltipped-multiline:active::after, +.c2.tooltipped-multiline:focus::after { + display: table-cell; +} + +.c2.tooltipped-s::after, +.c2.tooltipped-se::after, +.c2.tooltipped-sw::after { + top: 100%; + right: 50%; + margin-top: 6px; +} + +.c2.tooltipped-s::before, +.c2.tooltipped-se::before, +.c2.tooltipped-sw::before { + top: auto; + right: 50%; + bottom: -7px; + margin-right: -6px; + border-bottom-color: #24292f; +} + +.c2.tooltipped-se::after { + right: auto; + left: 50%; + margin-left: -16px; +} + +.c2.tooltipped-sw::after { + margin-right: -16px; +} + +.c2.tooltipped-n::after, +.c2.tooltipped-ne::after, +.c2.tooltipped-nw::after { + right: 50%; + bottom: 100%; + margin-bottom: 6px; +} + +.c2.tooltipped-n::before, +.c2.tooltipped-ne::before, +.c2.tooltipped-nw::before { + top: -7px; + right: 50%; + bottom: auto; + margin-right: -6px; + border-top-color: #24292f; +} + +.c2.tooltipped-ne::after { + right: auto; + left: 50%; + margin-left: -16px; +} + +.c2.tooltipped-nw::after { + margin-right: -16px; +} + +.c2.tooltipped-s::after, +.c2.tooltipped-n::after { + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); +} + +.c2.tooltipped-w::after { + right: 100%; + bottom: 50%; + margin-right: 6px; + -webkit-transform: translateY(50%); + -ms-transform: translateY(50%); + transform: translateY(50%); +} + +.c2.tooltipped-w::before { + top: 50%; + bottom: 50%; + left: -7px; + margin-top: -6px; + border-left-color: #24292f; +} + +.c2.tooltipped-e::after { + bottom: 50%; + left: 100%; + margin-left: 6px; + -webkit-transform: translateY(50%); + -ms-transform: translateY(50%); + transform: translateY(50%); +} + +.c2.tooltipped-e::before { + top: 50%; + right: -7px; + bottom: 50%; + margin-top: -6px; + border-right-color: #24292f; +} + +.c2.tooltipped-multiline::after { + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; + max-width: 250px; + word-wrap: break-word; + white-space: pre-line; + border-collapse: separate; +} + +.c2.tooltipped-multiline.tooltipped-s::after, +.c2.tooltipped-multiline.tooltipped-n::after { + right: auto; + left: 50%; + -webkit-transform: translateX(-50%); + -ms-transform: translateX(-50%); + transform: translateX(-50%); +} + +.c2.tooltipped-multiline.tooltipped-w::after, +.c2.tooltipped-multiline.tooltipped-e::after { + right: 100%; +} + +.c2.tooltipped-align-right-2::after { + right: 0; + margin-right: 0; +} + +.c2.tooltipped-align-right-2::before { + right: 15px; +} + +.c2.tooltipped-align-left-2::after { + left: 0; + margin-left: 0; +} + +.c2.tooltipped-align-left-2::before { + left: 10px; +} + +@media (forced-colors:active) { + .c3:focus { + outline: solid 1px transparent; + } +} + +@media (min-width:768px) { + .c0 { + font-size: 14px; + } +} + + + + + + + + + +`; + exports[`TextInput renders trailingVisual 1`] = ` .c0 { font-size: 14px; @@ -1180,7 +2307,8 @@ exports[`TextInput renders trailingVisual 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -1226,6 +2354,8 @@ exports[`TextInput renders trailingVisual 1`] = ` className="c1" data-component="input" name="search" + onBlur={[Function]} + onFocus={[Function]} placeholder="Search" type="text" /> @@ -1315,7 +2445,8 @@ exports[`TextInput renders warning 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -1366,6 +2497,8 @@ exports[`TextInput renders warning 1`] = ` className="c1" data-component="input" name="zipcode" + onBlur={[Function]} + onFocus={[Function]} type="text" /> @@ -1436,7 +2569,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -1487,6 +2621,8 @@ Array [ diff --git a/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap b/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap index c4f02a602bc..377d1bbc37d 100644 --- a/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap +++ b/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap @@ -100,7 +100,8 @@ exports[`TextInputWithTokens renders a leadingVisual and trailingVisual 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -826,7 +827,8 @@ exports[`TextInputWithTokens renders a truncated set of tokens 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -1240,7 +1242,8 @@ exports[`TextInputWithTokens renders as block layout 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -1406,7 +1409,8 @@ exports[`TextInputWithTokens renders at a maximum height when specified 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -2087,7 +2091,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -2768,7 +2773,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 2`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -3442,7 +3448,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 3`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -4116,7 +4123,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 4`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -4792,7 +4800,8 @@ exports[`TextInputWithTokens renders tokens on a single line when specified 1`] margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -5466,7 +5475,8 @@ exports[`TextInputWithTokens renders tokens without a remove button when specifi margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -5857,7 +5867,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -6580,7 +6591,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -7347,7 +7359,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -8074,7 +8087,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -8881,7 +8895,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -9688,7 +9703,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -10495,7 +10511,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -11258,7 +11275,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -12065,7 +12083,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -12839,7 +12858,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -13686,7 +13706,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -14533,7 +14554,8 @@ Array [ margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -15368,7 +15390,8 @@ exports[`TextInputWithTokens renders with tokens 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -16042,7 +16065,8 @@ exports[`TextInputWithTokens renders with tokens using a custom token component margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; @@ -16721,7 +16745,8 @@ exports[`TextInputWithTokens renders without tokens 1`] = ` margin-right: 8px; } -.c0 .TextInput-icon { +.c0 .TextInput-icon, +.c0 .TextInput-action { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; diff --git a/src/__tests__/deprecated/__snapshots__/ChoiceFieldset.test.tsx.snap b/src/__tests__/deprecated/__snapshots__/ChoiceFieldset.test.tsx.snap index 8fa82204b62..6d04bc63ff4 100644 --- a/src/__tests__/deprecated/__snapshots__/ChoiceFieldset.test.tsx.snap +++ b/src/__tests__/deprecated/__snapshots__/ChoiceFieldset.test.tsx.snap @@ -46,6 +46,9 @@ exports[`ChoiceFieldset renders a disabled list 1`] = ` display: block; color: #57606a; cursor: default; + -webkit-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } .c6 { @@ -209,6 +212,9 @@ exports[`ChoiceFieldset renders a fieldset with a description 1`] = ` display: block; color: #24292f; cursor: pointer; + -webkit-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } .c7 { @@ -396,6 +402,9 @@ exports[`ChoiceFieldset renders a list of items with leading visuals and caption display: block; color: #24292f; cursor: pointer; + -webkit-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } .c6 { @@ -699,6 +708,9 @@ exports[`ChoiceFieldset renders with a hidden legend 1`] = ` display: block; color: #24292f; cursor: pointer; + -webkit-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } .c1 { @@ -894,6 +906,9 @@ exports[`ChoiceFieldset renders with a success validation message 1`] = ` display: block; color: fg.default; cursor: pointer; + -webkit-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } .c6 { @@ -1137,6 +1152,9 @@ exports[`ChoiceFieldset renders with an error validation message 1`] = ` display: block; color: fg.default; cursor: pointer; + -webkit-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } .c6 { diff --git a/src/stories/TextInput.stories.tsx b/src/stories/TextInput.stories.tsx index c4f102f2161..741447fdfc3 100644 --- a/src/stories/TextInput.stories.tsx +++ b/src/stories/TextInput.stories.tsx @@ -1,9 +1,9 @@ -import React, {useState, ReactNode} from 'react' +import React, {useState} from 'react' import {Meta} from '@storybook/react' -import {BaseStyles, Box, ThemeProvider, Text} from '..' +import {BaseStyles, Box, ThemeProvider, FormControl} from '..' import TextInput, {TextInputProps} from '../TextInput' -import {CalendarIcon, CheckIcon} from '@primer/octicons-react' +import {CalendarIcon, CheckIcon, XCircleFillIcon} from '@primer/octicons-react' export default { title: 'Forms/Text Input', @@ -81,12 +81,6 @@ export default { } } as Meta -const Label = ({htmlFor, children}: {htmlFor: string; children: ReactNode}) => ( - - {children} - -) - export const Default = (args: TextInputProps) => { const [value, setValue] = useState('') @@ -94,18 +88,12 @@ export const Default = (args: TextInputProps) => { setValue(event.target.value) } - const inputId = 'basic-text-input' - return (
-
-
- -
-
- -
-
+ + Example label + +
) } @@ -117,16 +105,16 @@ export const WithLeadingVisual = (args: TextInputProps) => { setValue(event.target.value) } - const iconInputId = 'text-input-with-leading-icon' - const leadingTextId = 'text-input-with-leading-text' - return (
- - -
- - + + Example label + + + + Enter monies + + ) } @@ -138,24 +126,66 @@ export const WithTrailingIcon = (args: TextInputProps) => { setValue(event.target.value) } - const iconInputId = 'text-input-with-trailing-icon' - const trailingTextInputId = 'text-input-with-trailing-text' + return ( +
+ + Example label + + + + Enter monies + + +
+ ) +} + +export const WithTrailingAction = (args: TextInputProps) => { + const [value, setValue] = useState('') + + const handleChange = (event: React.ChangeEvent) => { + setValue(event.target.value) + } return (
- - -
- - + + + Icon action + { + setValue('') + }} + icon={XCircleFillIcon} + aria-label="Clear input" + sx={{color: 'fg.subtle'}} + /> + } + value={value} + onChange={handleChange} + {...args} + /> + + + Text action + { + setValue('') + }} + > + Clear + + } + value={value} + onChange={handleChange} + {...args} + /> + + ) } @@ -250,13 +280,12 @@ export const ContrastTextInput = (args: TextInputProps) => { setValue(event.target.value) } - const inputId = 'contrast-text-input' - return (
- -
- + + Example label + + ) } @@ -268,13 +297,12 @@ export const Password = (args: TextInputProps) => { setValue(event.target.value) } - const inputId = 'basic-text-input-as-password' - return (
- -
- + + Password + + ) } @@ -286,20 +314,12 @@ export const TextInputInWarningState = (args: TextInputProps) => { setValue(event.target.value) } - const inputId = 'text-input-with-warning' - return (
- -
- + + Password + + ) }