Skip to content

Commit

Permalink
feat(textbox): Update structure and add support for prefix and postfi…
Browse files Browse the repository at this point in the history
…x text (#354)

Co-authored-by: Timur Manyanov <[email protected]>
  • Loading branch information
HenriqueLimas and darkwebdev committed Jul 12, 2024
1 parent 6578351 commit abee925
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 14 deletions.
3 changes: 2 additions & 1 deletion src/common/floating-label-utils/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,14 @@ export function useFloatingLabel({
if (!label) {
return
}
setFloating(isFocused || hasValue(inputRef()?.current) || isAutofilled(inputRef()?.current))
setFloating(isFocused || hasValue(inputRef()?.current) || isAutofilled(inputRef()?.current?.parentNode))
}, [isFocused, inputValue])

const labelClassName = classNames(className, classPrefix, {
[`${classPrefix}--disabled`]: disabled,
[`${classPrefix}--animate`]: shouldAnimate,
[`${classPrefix}--inline`]: !isFloating && type !== 'date',
[`${classPrefix}--focus`]: isFocused,
[`${classPrefix}--invalid`]: invalid
})

Expand Down
6 changes: 3 additions & 3 deletions src/ebay-date-textbox/__tests__/render.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('ebay-date-textbox rendering', () => {
expect(dateTextbox).toHaveAttribute('id', 'testid')

const textbox = dateTextbox.querySelector('.textbox')
expect(textbox).toHaveClass('ebay-date-textbox--main textbox--icon-end')
expect(textbox).toHaveClass('ebay-date-textbox--main')

const input = within(dateTextbox).getByRole('textbox')
expect(input).toHaveAttribute('type', 'text')
Expand Down Expand Up @@ -46,7 +46,7 @@ describe('ebay-date-textbox rendering', () => {
expect(dateTextbox).toHaveAttribute('id', 'testid')

const [textboxStart, textboxEnd] = dateTextbox.querySelectorAll('.textbox')
expect(textboxEnd).toHaveClass('ebay-date-textbox--main textbox--icon-end')
expect(textboxEnd).toHaveClass('ebay-date-textbox--main')

const inputStart = within(textboxStart as HTMLElement).getByRole('textbox')
expect(inputStart).toHaveAttribute('type', 'text')
Expand Down Expand Up @@ -83,7 +83,7 @@ describe('ebay-date-textbox rendering', () => {
expect(dateTextbox).toHaveAttribute('id', 'testid')

const textbox = dateTextbox.querySelector('.textbox')
expect(textbox).toHaveClass('ebay-date-textbox--main textbox--icon-end')
expect(textbox).toHaveClass('ebay-date-textbox--main')

const input = within(dateTextbox).getByRole('textbox')
expect(input).toHaveAttribute('type', 'text')
Expand Down
43 changes: 43 additions & 0 deletions src/ebay-textbox/__tests__/__snapshots__/render.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,46 @@ exports[`ebay-textbox rendering renders with icon story correctly 1`] = `
/>
</svg>
`;

exports[`ebay-textbox rendering renders with pre/post fix text correctly 1`] = `
<div>
<div>
<p>
<span
class="textbox"
>
<span
id="prefix"
>
$
</span>
<input
aria-describedby="prefix"
class="textbox__control"
placeholder="0.00"
type="text"
value=""
/>
</span>
</p>
<p>
<span
class="textbox"
>
<input
aria-describedby="postfix"
class="textbox__control"
placeholder="0"
type="text"
value=""
/>
<span
id="postfix"
>
in.
</span>
</span>
</p>
</div>
</div>
`;
21 changes: 20 additions & 1 deletion src/ebay-textbox/__tests__/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ChangeEvent, FC, useState, KeyboardEvent, MouseEvent } from 'react'
import { action } from '@storybook/addon-actions'
import { EbayButton } from '../../ebay-button'
import { EbayTextbox, EbayTextboxPostfixIcon, EbayTextboxPrefixIcon } from '../index'
import { EbayTextbox, EbayTextboxPostfixIcon, EbayTextboxPostfixText, EbayTextboxPrefixIcon, EbayTextboxPrefixText } from '../index'

export default {
title: 'form input/ebay-textbox'
Expand Down Expand Up @@ -194,6 +194,25 @@ export const WithIcon = {
name: 'With icon'
}

export const WithPrePostfixText = {
render: () => (
<div>
<p>
<EbayTextbox placeholder="0.00">
<EbayTextboxPrefixText id="prefix">$</EbayTextboxPrefixText>
</EbayTextbox>
</p>
<p>
<EbayTextbox placeholder="0">
<EbayTextboxPostfixText id="postfix">in.</EbayTextboxPostfixText>
</EbayTextbox>
</p>
</div>
),

name: 'With Pre/Post fix text'
}

export const ControlValueFromOutside = {
render: () => {
const Component = () => {
Expand Down
12 changes: 10 additions & 2 deletions src/ebay-textbox/__tests__/render.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
MultilineTextbox,
PasswordTextbox,
WithIcon,
WithPrePostfixText,
PlaceholderTextbox,
FloatingLabel,
FloatingLabelInvalid,
Expand Down Expand Up @@ -41,7 +42,8 @@ describe('ebay-textbox rendering', () => {

const textbox = screen.getByRole('textbox')
expect(textbox).toHaveAttribute('value', '')
expect(textbox).toHaveClass('textbox__control textbox__control--fluid')
expect(textbox).toHaveClass('textbox__control')
expect(textbox.parentNode).toHaveClass('textbox--fluid')
})

it('renders invalid story correctly', () => {
Expand All @@ -57,7 +59,8 @@ describe('ebay-textbox rendering', () => {

const textbox = screen.getByRole('textbox')
expect(textbox).toHaveAttribute('value', '')
expect(textbox).toHaveClass('textbox__control textbox__control--large')
expect(textbox).toHaveClass('textbox__control')
expect(textbox.parentNode).toHaveClass('textbox--large')
})

it('renders multiline story correctly', () => {
Expand Down Expand Up @@ -88,6 +91,11 @@ describe('ebay-textbox rendering', () => {
expect(icon).toMatchSnapshot()
})

it('renders with pre/post fix text correctly', () => {
const { container } = render(<WithPrePostfixText />)
expect(container).toMatchSnapshot()
})

it('renders placeholder story correctly', () => {
render(<PlaceholderTextbox />)

Expand Down
2 changes: 2 additions & 0 deletions src/ebay-textbox/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { default as EbayTextbox, EbayTextboxProps } from './textbox'
export { default as EbayTextboxPrefixIcon } from './prefix-icon'
export { default as EbayTextboxPrefixText } from './prefix-text'
export { default as EbayTextboxPostfixIcon } from './postfix-icon'
export { default as EbayTextboxPostfixText } from './postfix-text'
export { Size } from './types'
8 changes: 8 additions & 0 deletions src/ebay-textbox/postfix-text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React, { FC } from 'react'
import { EbayTextboxPostfixTextProps } from './types'

const EbayTextboxPostfixText: FC<EbayTextboxPostfixTextProps> = (props: EbayTextboxPostfixTextProps) => (
<span {...props} />
)

export default EbayTextboxPostfixText
8 changes: 8 additions & 0 deletions src/ebay-textbox/prefix-text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React, { FC } from 'react'
import { EbayTextboxPrefixTextProps } from './types'

const EbayTextboxPrefixText: FC<EbayTextboxPrefixTextProps> = (props: EbayTextboxPrefixTextProps) => (
<span {...props} />
)

export default EbayTextboxPrefixText
27 changes: 20 additions & 7 deletions src/ebay-textbox/textbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import React, {
} from 'react'
import classNames from 'classnames'
import { findComponent, withForwardRef } from '../common/component-utils'
import { EbayTextboxPostfixIcon, EbayTextboxPrefixIcon, Size } from './index'
import EbayTextboxPostfixIcon from './postfix-icon'
import EbayTextboxPostfixText from './postfix-text'
import EbayTextboxPrefixIcon from './prefix-icon'
import EbayTextboxPrefixText from './prefix-text'
import { useFloatingLabel } from '../common/floating-label-utils/hooks'
import {
EbayChangeEventHandler,
EbayEventHandler,
EbayFocusEventHandler,
EbayKeyboardEventHandler, EbayMouseEventHandler
} from '../common/event-utils/types'
import type { Size } from './types'

export const isControlled = (value?: unknown): boolean => typeof value !== 'undefined'

Expand Down Expand Up @@ -148,24 +152,32 @@ const EbayTextbox: FC<EbayTextboxProps> = ({
const Wrapper = fluid ? 'div' : 'span'

const prefixIcon = findComponent(children, EbayTextboxPrefixIcon)
const prefixText = findComponent(children, EbayTextboxPrefixText)
const prefixId = prefixText?.props?.id
const postfixIcon = findComponent(children, EbayTextboxPostfixIcon)
const postfixText = findComponent(children, EbayTextboxPostfixText)
const postfixId = postfixText?.props?.id

const inputClassName = classNames('textbox__control', {
'textbox__control--fluid': fluid,
'textbox__control--large': inputSize === 'large'
})
const wrapperClassName = classNames('textbox', rest.className, {
'textbox--icon-end': postfixIcon
'textbox--fluid': fluid,
'textbox--large': inputSize === 'large',
/** start remove after `:has` support */
'textbox--disabled': rest.disabled,
'textbox--invalid': invalid,
'textbox--readonly': rest.readOnly
/** end remove after `:has` support */
})

return (
<Container>
{label}
<Wrapper className={wrapperClassName}>
{prefixIcon}
{prefixText}
<Input
aria-describedby={[prefixId, postfixId].filter(Boolean).join(' ') || undefined}
{...rest}
className={inputClassName}
className="textbox__control"
type={type}
aria-invalid={invalid}
value={isControlled(controlledValue) ? controlledValue : inputValue}
Expand All @@ -180,6 +192,7 @@ const EbayTextbox: FC<EbayTextboxProps> = ({
ref={ref}
placeholder={floatingLabelPlaceholder}
/>
{postfixText}
{postfixIcon && cloneElement(postfixIcon, {
...postfixIcon.props,
onClick: (e) => {
Expand Down
8 changes: 8 additions & 0 deletions src/ebay-textbox/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ export type EbayTextboxIconProps = ComponentProps<'button'> & ComponentProps<'a'
buttonAriaLabel?: string
onClick?: (e: KeyboardEvent | MouseEvent) => void
}

export type EbayTextboxPrefixTextProps = ComponentProps<'span'> & {
id: string
}

export type EbayTextboxPostfixTextProps = ComponentProps<'span'> & {
id: string
}

0 comments on commit abee925

Please sign in to comment.