diff --git a/packages/shared/components/src/Input/index.tsx b/packages/shared/components/src/Input/index.tsx new file mode 100644 index 0000000..eaa766b --- /dev/null +++ b/packages/shared/components/src/Input/index.tsx @@ -0,0 +1,98 @@ +import { favolink, forwardRef } from '@favolink/system'; +import { classNames } from '@favolink/utils'; +import { type ComponentPropsWithoutRef } from 'react'; +import * as styles from './styles.css'; + +const INPUT_CLASSNAME = 'favolink-input'; + +export type InputGroupProps = ComponentPropsWithoutRef<'div'>; + +export const InputGroup = forwardRef( + function InputGroup(props, ref) { + const { children, className, ...restProps } = props; + + return ( + + {children} + + ); + }, +); + +type InputElementProps = ComponentPropsWithoutRef<'div'>; + +export type InputLeftElementProps = InputElementProps; + +export const InputLeftElement = forwardRef( + function InputElement(props, ref) { + const { children, className, ...restProps } = props; + + return ( + + {children} + + ); + }, +); + +export type InputRightElementProps = InputElementProps; + +export const InputRightElement = forwardRef( + function InputElement(props, ref) { + const { children, className, ...restProps } = props; + + return ( + + {children} + + ); + }, +); + +export type InputProps = ComponentPropsWithoutRef<'input'> & { + variant?: styles.Variant; +}; + +const Input = forwardRef(function Input(props, ref) { + const { className, variant = 'outline', ...restPorps } = props; + + return ( + + ); +}); + +export default Input; diff --git a/packages/shared/components/src/Input/styles.css.ts b/packages/shared/components/src/Input/styles.css.ts new file mode 100644 index 0000000..0c96130 --- /dev/null +++ b/packages/shared/components/src/Input/styles.css.ts @@ -0,0 +1,79 @@ +import { body3Medium } from '@favolink/styles/text.css'; +import { vars } from '@favolink/styles/theme.css'; +import { style, styleVariants } from '@vanilla-extract/css'; + +export const groupBase = style({ + position: 'relative', +}); + +export const elementBase = style({ + width: 42, + position: 'absolute', + height: '100%', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); + +export const elementDirection = styleVariants({ + right: [elementBase, { top: 0, right: 0 }], + left: [elementBase, { top: 0, left: 0 }], +}); + +export const base = style([ + body3Medium, + { + boxSizing: 'border-box', + width: '100%', + color: vars.color.gray1000, + transition: 'border 0.2s ease', + outline: 'none', + }, +]); + +export const variant = styleVariants({ + outline: { + border: `1px solid ${vars.color.gray300}`, + borderRadius: 8, + padding: '10px 12px', + + selectors: { + '&:disabled': { + backgroundColor: vars.color.gray300, + }, + '&:focus': { + border: `1px solid ${vars.color.gray900}`, + }, + '&::placeholder': { + color: vars.color.gray500, + }, + }, + }, + flushed: { + border: 'none', + borderBottom: `1px solid ${vars.color.gray300}`, + padding: '10px 0', + + selectors: { + '&:focus': { + borderBottom: `1px solid ${vars.color.gray900}`, + }, + '&::placeholder': { + color: vars.color.gray500, + }, + }, + }, +}); + +export type Variant = keyof typeof variant; + +export const withElement = style({ + selectors: { + [`${elementDirection.left} ~ &`]: { + paddingLeft: 42, + }, + [`&:has(~ ${elementDirection.right})`]: { + paddingRight: 42, + }, + }, +}); diff --git a/packages/shared/components/src/index.ts b/packages/shared/components/src/index.ts index 5f3072e..8b79096 100644 --- a/packages/shared/components/src/index.ts +++ b/packages/shared/components/src/index.ts @@ -5,6 +5,16 @@ export { default as Box } from './Box'; export { default as Button, type ButtonProps } from './Button'; export { default as Heading, type HeadingProps } from './Heading'; export { default as Icon, type IconProps } from './Icon'; +export { + default as Input, + type InputProps, + InputGroup, + type InputGroupProps, + InputLeftElement, + type InputLeftElementProps, + InputRightElement, + type InputRightElementProps, +} from './Input'; export { default as Link, type LinkProps } from './Link'; export { default as Modal,