Skip to content

Commit

Permalink
Merge pull request #279 from omnifed/278-feature-update-icon-to-suppo…
Browse files Browse the repository at this point in the history
…rt-starticon

278 feature update icon to support starticon
  • Loading branch information
caseybaggz committed Jul 16, 2024
2 parents 30fdd04 + 9fc2b51 commit f5feb6d
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 19 deletions.
23 changes: 22 additions & 1 deletion docs/app/react/input/components/input-preview.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Search } from '@cerberus-design/icons'
import { Field, FieldMessage, Label, Input } from '@cerberus-design/react'
import { css, cx } from '@cerberus/styled-system/css'
import { css } from '@cerberus/styled-system/css'
import { vstack } from '@cerberus/styled-system/patterns'

const overrideStyles = css({
Expand Down Expand Up @@ -55,6 +56,26 @@ export function InputDisabledPreview() {
)
}

export function InputWithIconPreview() {
return (
<div className={overrideStyles}>
<Field>
<Label htmlFor="global_search">Global Search</Label>
<Input
describedBy="help:global_search"
id="global_search"
placeholder="Search the world"
startIcon={<Search />}
type="text"
/>
<FieldMessage id="help:global_search">
Search the world for the best results.
</FieldMessage>
</Field>
</div>
)
}

export function InputSizesPreview() {
return (
<div
Expand Down
34 changes: 33 additions & 1 deletion docs/app/react/input/dev.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
InputBasicPreview,
InputInvalidPreview,
InputDisabledPreview,
InputWithIconPreview,
InputSizesPreview,
InputCustomPreview
} from '@/app/react/input/components/input-preview'
Expand Down Expand Up @@ -85,6 +86,33 @@ function InputDisabledPreview() {
```
</CodePreview>

## With Icon

<CodePreview preview={<InputWithIconPreview />}>
```tsx title="search-input.tsx" {13}
import { Field, Label, Input } from '@cerberus-design/react'
import { Search } from '@cerberus/icons'

function InputWithIconPreview() {
return (
<Field>
<Label htmlFor="global_search">Global Search</Label>
<Input
describedBy="help:global_search"
id="global_search"
type="text"
placeholder="Search the world"
startIcon={<Search />}
/>
<FieldMessage id="help:global_search">
Search the world for the best results.
</FieldMessage>
</Field>
)
}
```
</CodePreview>

## Sizes

<CodePreview preview={<InputSizesPreview />}>
Expand Down Expand Up @@ -153,7 +181,7 @@ function InputCustomPreview() {

## API

<NoteAdmonition description="The Label component must be used within a Field provider." />
<NoteAdmonition description="The Input component must be used within a Field provider." />

```ts showLineNumbers=false
export interface FieldProps {
Expand All @@ -171,6 +199,8 @@ export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
describedBy?: string
id: string
size?: 'sm' | 'md' | 'lg'
startIcon?: ReactNode
endIcon?: ReactNode
}
define function Input(props: InputProps): ReactNode
Expand All @@ -185,3 +215,5 @@ The `InputProps` component accepts the following props:
| describedBy | | The `id` attribute of the FieldMessage the Input is associated with. |
| id | | An identifier that is shared with the Label `htmlFor` attribute. |
| size | `lg` | The size of the input field. |
| startIcon | | An icon that appears at the start of the input field. |
| endIcon | | An icon that appears at the end of the input field when the state is valid. |
2 changes: 2 additions & 0 deletions docs/app/react/input/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
InputBasicPreview,
InputInvalidPreview,
InputDisabledPreview,
InputWithIconPreview,
InputSizesPreview,
} from '@/app/react/input/components/input-preview'

Expand All @@ -25,6 +26,7 @@ import {
<CodePreview preview={<InputBasicPreview />} />
<CodePreview preview={<InputInvalidPreview />} />
<CodePreview preview={<InputDisabledPreview />} />
<CodePreview preview={<InputWithIconPreview />} />
<CodePreview preview={<InputSizesPreview />} />

## Resources
Expand Down
4 changes: 2 additions & 2 deletions docs/app/react/side-nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"id": "2:d",
"label": "Input",
"route": "/react/input",
"tag": "",
"tag": "next",
"type": "route"
},
{
Expand Down Expand Up @@ -69,7 +69,7 @@
"id": "2:h",
"label": "Tag",
"route": "/react/tags",
"tag": "",
"tag": "next",
"type": "route"
},
{
Expand Down
44 changes: 44 additions & 0 deletions figma/src/input.figma.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,20 @@ const props = {
disabled: 'disabled',
readonly: 'readonly',
}),
style: figma.enum('Style', {
text: 'text',
search: 'search',
date: 'date',
tel: 'tel',
number: 'number',
password: 'password',
}),
required: figma.boolean('required'),
label: figma.children('Label'),
fieldMessage: figma.children('FieldMessage'),
placeholder: figma.string('placeholder-text'),
icon: figma.children('Icon'),
passwordButton: figma.children('Icon Button'),
}

figma.connect(Input, SELECTION, {
Expand All @@ -37,6 +47,8 @@ figma.connect(Input, SELECTION, {
id="ADD_UUID"
placeholder={props.placeholder}
size={props.size}
startIcon={props.icon}
type={props.style}
/>
{props.fieldMessage}
</Field>
Expand All @@ -58,6 +70,8 @@ figma.connect(Input, SELECTION, {
id="ADD_UUID"
placeholder={props.placeholder}
size={props.size}
startIcon={props.icon}
type={props.style}
/>
{props.fieldMessage}
</Field>
Expand All @@ -79,6 +93,8 @@ figma.connect(Input, SELECTION, {
id="ADD_UUID"
placeholder={props.placeholder}
size={props.size}
startIcon={props.icon}
type={props.style}
/>
{props.fieldMessage}
</Field>
Expand All @@ -100,6 +116,8 @@ figma.connect(Input, SELECTION, {
id="ADD_UUID"
placeholder={props.placeholder}
size={props.size}
startIcon={props.icon}
type={props.style}
/>
{props.fieldMessage}
</Field>
Expand All @@ -121,6 +139,32 @@ figma.connect(Input, SELECTION, {
id="ADD_UUID"
placeholder={props.placeholder}
size={props.size}
startIcon={props.icon}
type={props.style}
/>
{props.fieldMessage}
</Field>
)
},
})

figma.connect(Input, SELECTION, {
imports,
variant: {
State: 'valid',
Style: 'password',
},
props,
example: (props) => {
return (
<Field required={props.required}>
{props.label}
<Input
endIcon={props.passwordButton}
id="ADD_UUID"
placeholder={props.placeholder}
size={props.size}
type={props.style}
/>
{props.fieldMessage}
</Field>
Expand Down
13 changes: 12 additions & 1 deletion packages/panda-preset/src/recipes/slots/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { focusStates, formStates } from '../shared/states'
* @definition [Input docs](https://cerberus.digitalu.design/react/input)
*/
export const input: Partial<SlotRecipeConfig> = defineSlotRecipe({
slots: ['root', 'input', 'icon'],
slots: ['root', 'input', 'icon', 'startIcon'],
className: 'input',

base: {
Expand Down Expand Up @@ -41,6 +41,10 @@ export const input: Partial<SlotRecipeConfig> = defineSlotRecipe({
_placeholderShown: {
color: 'neutral.text.100',
},
_startIcon: {
display: 'inline-block',
paddingInlineStart: '7',
},
},
icon: {
position: 'absolute',
Expand All @@ -52,6 +56,13 @@ export const input: Partial<SlotRecipeConfig> = defineSlotRecipe({
color: 'danger.text.100',
},
},
startIcon: {
position: 'absolute',
left: '0.5rem',
top: '50%',
transform: 'translateY(-50%)',
zIndex: 'decorator',
},
},

variants: {
Expand Down
17 changes: 14 additions & 3 deletions packages/react/src/components/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,49 @@
'use client'

import type { InputHTMLAttributes } from 'react'
import type { InputHTMLAttributes, ReactNode } from 'react'
import { WarningFilled } from '@cerberus/icons'
import { input } from '@cerberus/styled-system/recipes'
import { cx, type RecipeVariantProps } from '@cerberus/styled-system/css'
import { useFieldContext } from '../context/field'
import { Show } from './Show'

export type InputRecipeProps = RecipeVariantProps<typeof input>

export interface InputBaseProps
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'id' | 'size'> {
describedBy?: string
id: string
startIcon?: ReactNode
endIcon?: ReactNode
}
export type InputProps = InputBaseProps & InputRecipeProps

export function Input(props: InputProps) {
const { describedBy, size, ...nativeProps } = props
const { describedBy, size, startIcon, endIcon, ...nativeProps } = props
const inputStyles = input({ size })
const { invalid, ...fieldStates } = useFieldContext()
const hasEndIcon = Boolean(endIcon)

return (
<div className={inputStyles.root}>
<Show when={Boolean(startIcon)}>
<span className={inputStyles.startIcon}>{startIcon}</span>
</Show>

<input
{...nativeProps}
{...fieldStates}
{...(describedBy && { 'aria-describedby': describedBy })}
{...(invalid && { 'aria-invalid': true })}
data-start-icon={Boolean(startIcon)}
className={cx('peer', nativeProps.className, inputStyles.input)}
/>

<Show when={invalid}>
<WarningFilled className={inputStyles.icon} />
</Show>
<Show when={hasEndIcon && !invalid}>
<span className={inputStyles.icon}>{endIcon}</span>
</Show>
</div>
)
}
Loading

0 comments on commit f5feb6d

Please sign in to comment.