Skip to content

Commit

Permalink
feat: make input field clearable and add prefix icon (#1619)
Browse files Browse the repository at this point in the history
* feat: make input clearable and add prefix icon
* feat: use onChange handler to clear text
  • Loading branch information
d-rita authored Nov 18, 2024
1 parent 13b4e09 commit 7f87fb4
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 3 deletions.
9 changes: 9 additions & 0 deletions components/input/src/input-field/input-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class InputField extends React.Component {
validationText,
inputWidth,
autoComplete,
clearable,
prefixIcon,
dataTest = 'dhis2-uiwidgets-inputfield',
} = this.props

Expand Down Expand Up @@ -79,6 +81,9 @@ class InputField extends React.Component {
initialFocus={initialFocus}
readOnly={readOnly}
autoComplete={autoComplete}
clearable={clearable}
prefixIcon={prefixIcon}
width={inputWidth}
/>
</Box>
</Field>
Expand All @@ -90,6 +95,8 @@ const InputFieldProps = {
/** The [native `autocomplete` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autocomplete) */
autoComplete: PropTypes.string,
className: PropTypes.string,
/** Makes the input field clearable */
clearable: PropTypes.bool,
dataTest: PropTypes.string,
/** Makes the input smaller */
dense: PropTypes.bool,
Expand All @@ -115,6 +122,8 @@ const InputFieldProps = {
name: PropTypes.string,
/** Placeholder text for the input */
placeholder: PropTypes.string,
/** Add prefix icon */
prefixIcon: PropTypes.element,
/** Makes the input read-only */
readOnly: PropTypes.bool,
/** Indicates this input is required */
Expand Down
39 changes: 38 additions & 1 deletion components/input/src/input-field/input-field.prod.stories.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { sharedPropTypes } from '@dhis2/ui-constants'
import React from 'react'
import { IconLocation16, IconSearch16 } from '@dhis2/ui-icons'
import React, { useState } from 'react'
import { InputField } from './index.js'

const subtitle = 'Allows a user to enter data, usually text'
Expand Down Expand Up @@ -156,3 +157,39 @@ ValueTextOverflow.args = {

export const Required = Template.bind({})
Required.args = { required: true }

export const InputWithPrefixIcon = (args) => (
<>
<InputField
{...args}
name="prefix-icon-input"
label="Search"
placeholder={'Search'}
prefixIcon={<IconSearch16 />}
/>
<InputField
{...args}
name="prefix-icon-input"
label="Location"
placeholder={'Enter Location'}
prefixIcon={<IconLocation16 />}
inputWidth={'200px'}
/>
</>
)

export const ClearableInput = (args) => {
const [value, setValue] = useState('value')
return (
<InputField
{...args}
name="clearable-input"
label="This field can be cleared"
placeholder={''}
onChange={(e) => setValue(e.value)}
clearable
clearText={() => setValue('')}
value={value}
/>
)
}
79 changes: 77 additions & 2 deletions components/input/src/input/input.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { theme, colors, spacers, sharedPropTypes } from '@dhis2/ui-constants'
import { IconCross16 } from '@dhis2/ui-icons'
import { StatusIcon } from '@dhis2-ui/status-icon'
import cx from 'classnames'
import PropTypes from 'prop-types'
Expand All @@ -8,8 +9,9 @@ import { inputTypes } from './inputTypes.js'

const styles = css`
.input {
display: flex;
display: inline-flex;
align-items: center;
position: relative;
gap: ${spacers.dp8};
}
Expand Down Expand Up @@ -127,6 +129,15 @@ export class Input extends Component {
}
}

handleClear = () => {
if (this.props.onChange) {
this.props.onChange({
value: '',
name: this.props.name,
})
}
}

createHandlerPayload(e) {
return {
value: e.target.value,
Expand Down Expand Up @@ -155,10 +166,22 @@ export class Input extends Component {
step,
autoComplete,
dataTest = 'dhis2-uicore-input',
clearable,
prefixIcon,
width,
} = this.props

return (
<div className={cx('input', className)} data-test={dataTest}>
<div
className={cx(
'input',
className,
{ 'input-prefix-icon': prefixIcon },
{ 'input-clearable': clearable }
)}
data-test={dataTest}
>
{prefixIcon && <span className="prefix">{prefixIcon}</span>}
<input
role={role}
id={name}
Expand Down Expand Up @@ -187,6 +210,15 @@ export class Input extends Component {
'read-only': readOnly,
})}
/>
{clearable && value?.length ? (
<button
type="button"
onClick={this.handleClear}
className="clear-button"
>
<IconCross16 color={colors.white} />
</button>
) : null}
<StatusIcon
error={error}
valid={valid}
Expand All @@ -196,9 +228,46 @@ export class Input extends Component {

<style jsx>{styles}</style>
<style jsx>{`
.input {
width: ${width ? width : `100%`};
}
input {
width: 100%;
}
.input-prefix-icon input {
padding-inline-start: 30px;
}
.input-clearable input {
padding-inline-end: 30px;
}
.prefix {
position: absolute;
display: flex;
align-items: center;
pointer-events: none;
left: 10px;
padding: 0;
color: ${colors.grey600};
}
.clear-button {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
border: none;
cursor: pointer;
height: 16px;
width: 16px;
border-radius: 50%;
right: 10px;
background: ${colors.grey500};
padding: 1px;
}
`}</style>
</div>
)
Expand All @@ -209,6 +278,8 @@ Input.propTypes = {
/** The [native `autocomplete` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autocomplete) */
autoComplete: PropTypes.string,
className: PropTypes.string,
/** Makes the input field clearable */
clearable: PropTypes.bool,
dataTest: PropTypes.string,
/** Makes the input smaller */
dense: PropTypes.bool,
Expand All @@ -228,6 +299,8 @@ Input.propTypes = {
name: PropTypes.string,
/** Placeholder text for the input */
placeholder: PropTypes.string,
/** Add prefix icon */
prefixIcon: PropTypes.element,
/** Makes the input read-only */
readOnly: PropTypes.bool,
/** Sets a role attribute on the input */
Expand All @@ -243,6 +316,8 @@ Input.propTypes = {
value: PropTypes.string,
/** Applies 'warning' appearance for validation feedback. Mutually exclusive with `valid` and `error` props */
warning: sharedPropTypes.statusPropType,
/** Defines the width of the input. Can be any valid CSS measurement */
width: PropTypes.string,
/** Called with signature `({ name: string, value: string }, event)` */
onBlur: PropTypes.func,
/** Called with signature `({ name: string, value: string }, event)` */
Expand Down
16 changes: 16 additions & 0 deletions components/input/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export interface InputProps {
*/
autoComplete?: string
className?: string
/**
* Makes the input clearable
*/
clearable?: boolean
dataTest?: string
/**
* Makes the input smaller
Expand Down Expand Up @@ -78,6 +82,10 @@ export interface InputProps {
* Placeholder text for the input
*/
placeholder?: string
/**
* Add prefix icon
*/
prefixIcon?: Element
/**
* Makes the input read-only
*/
Expand Down Expand Up @@ -135,6 +143,10 @@ export interface InputFieldProps {
*/
autoComplete?: string
className?: string
/**
* Makes the input field clearable
*/
clearable?: boolean
dataTest?: string
/**
* Makes the input smaller
Expand Down Expand Up @@ -184,6 +196,10 @@ export interface InputFieldProps {
* Placeholder text for the input
*/
placeholder?: string
/**
* Add prefix icon to input
*/
prefixIcon?: Element
/**
* Makes the input read-only
*/
Expand Down

0 comments on commit 7f87fb4

Please sign in to comment.