From b2cdd7cf0ac4039f36b5fbc3b1c18779f392357c Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Wed, 30 Nov 2022 16:17:41 +0100 Subject: [PATCH 01/25] feat: add native props & placeholder to input --- src/components/forms/Input.tsx | 25 +++++++++++++++++++++++++ src/components/forms/index.ts | 1 + stories/components/input.stories.tsx | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/components/forms/Input.tsx create mode 100644 src/components/forms/index.ts create mode 100644 stories/components/input.stories.tsx diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx new file mode 100644 index 00000000..dd35e5c8 --- /dev/null +++ b/src/components/forms/Input.tsx @@ -0,0 +1,25 @@ +/** @jsxImportSource @emotion/react */ +import { css } from '@emotion/react'; + +const styles = { + input: css` + box-sizing: border-box; + margin: 0px; + padding: 4px 11px; + color: rgba(0, 0, 0, 0.88); + font-size: 14px; + line-height: 1.5714285714285714; + position: relative; + display: inline-block; + width: 100%; + min-width: 0px; + background-color: #fff; + border-radius: 6px; + transition: all 0.2s; + border: 1px solid #d9d9d9; + `, +}; + +export function Input(props: React.InputHTMLAttributes) { + return ; +} diff --git a/src/components/forms/index.ts b/src/components/forms/index.ts new file mode 100644 index 00000000..ba9fe7eb --- /dev/null +++ b/src/components/forms/index.ts @@ -0,0 +1 @@ +export * from './Input'; diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx new file mode 100644 index 00000000..978787a0 --- /dev/null +++ b/stories/components/input.stories.tsx @@ -0,0 +1,19 @@ +import { ChangeEvent, useState } from 'react'; + +import { Input } from '../../src/components/forms/Input'; + +export default { + title: 'Forms / Input', +}; + +export function BasicExample() { + const [state, setState] = useState('Hello, World!'); + + function onChange(event: ChangeEvent) { + setState(event.target.value); + } + + return ( + + ); +} From ec4e2c3822b20cc30e446bf3154922780aea0219 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Wed, 30 Nov 2022 16:46:42 +0100 Subject: [PATCH 02/25] feat: add label on input --- src/components/forms/Input.tsx | 13 ++++- .../forms/context/FieldsContext.tsx | 51 +++++++++++++++++++ stories/components/input.stories.tsx | 20 ++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/components/forms/context/FieldsContext.tsx diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index dd35e5c8..e4f48111 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -1,6 +1,8 @@ /** @jsxImportSource @emotion/react */ import { css } from '@emotion/react'; +import { useFieldsContext } from './context/FieldsContext'; + const styles = { input: css` box-sizing: border-box; @@ -21,5 +23,14 @@ const styles = { }; export function Input(props: React.InputHTMLAttributes) { - return ; + const fieldsContext = useFieldsContext(); + + return ( + + ); } diff --git a/src/components/forms/context/FieldsContext.tsx b/src/components/forms/context/FieldsContext.tsx new file mode 100644 index 00000000..bf0b856e --- /dev/null +++ b/src/components/forms/context/FieldsContext.tsx @@ -0,0 +1,51 @@ +/** @jsxImportSource @emotion/react */ +import { css } from '@emotion/react'; +import { createContext, ReactNode, useContext } from 'react'; + +interface FieldsProps { + children: ReactNode; +} + +interface FieldProps extends FieldsProps { + name: string; + label: string; +} + +const context = createContext(null); + +const styles = { + root: css` + display: flex; + flex-direction: row; + gap: 5px; + align-items: center; + `, +}; + +export function useFieldsContext() { + const ctx = useContext(context); + + if (!ctx) { + return undefined; + } + + return ctx; +} + +export function Fields(props: FieldsProps) { + const { children } = props; + return <>{children}; +} + +export function Field(props: FieldProps) { + const { label, name, children } = props; + + return ( + +
+ + {children} +
+
+ ); +} diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 978787a0..f08aafec 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -1,6 +1,10 @@ import { ChangeEvent, useState } from 'react'; import { Input } from '../../src/components/forms/Input'; +import { + Field, + Fields, +} from '../../src/components/forms/context/FieldsContext'; export default { title: 'Forms / Input', @@ -17,3 +21,19 @@ export function BasicExample() { ); } + +export function LabelExample() { + const [state, setState] = useState('Hello, World!'); + + function onChange(event: ChangeEvent) { + setState(event.target.value); + } + + return ( + + + + + + ); +} From 126ab6aecb94b43db9b04e6ac731b5eba16b8bd3 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Thu, 1 Dec 2022 10:41:52 +0100 Subject: [PATCH 03/25] refactor: change inputs export --- src/components/forms/context/index.ts | 1 + src/components/forms/index.ts | 1 + src/components/index.ts | 1 + stories/components/input.stories.tsx | 6 +----- 4 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 src/components/forms/context/index.ts diff --git a/src/components/forms/context/index.ts b/src/components/forms/context/index.ts new file mode 100644 index 00000000..e9ef42cc --- /dev/null +++ b/src/components/forms/context/index.ts @@ -0,0 +1 @@ +export * from './FieldsContext'; diff --git a/src/components/forms/index.ts b/src/components/forms/index.ts index ba9fe7eb..094475af 100644 --- a/src/components/forms/index.ts +++ b/src/components/forms/index.ts @@ -1 +1,2 @@ export * from './Input'; +export * from './context'; diff --git a/src/components/index.ts b/src/components/index.ts index 8aecc792..f079a0aa 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -3,6 +3,7 @@ export * from './button/index'; export * from './color-picker/index'; export * from './drop-zone/index'; export * from './dropdown-menu/index'; +export * from './forms/index'; export * from './fullscreen/index'; export * from './header/index'; export * from './hooks/index'; diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index f08aafec..7461096b 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -1,10 +1,6 @@ import { ChangeEvent, useState } from 'react'; -import { Input } from '../../src/components/forms/Input'; -import { - Field, - Fields, -} from '../../src/components/forms/context/FieldsContext'; +import { Input, Fields, Field } from '../../src/components'; export default { title: 'Forms / Input', From 16209428af890f3cb834416d65f005ed60d8ab3c Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Thu, 1 Dec 2022 11:00:21 +0100 Subject: [PATCH 04/25] feat: add size on Input component --- src/components/forms/Input.tsx | 52 +++++++++++++++------------- stories/components/input.stories.tsx | 17 +++++++++ 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index e4f48111..e0791a73 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -1,36 +1,40 @@ -/** @jsxImportSource @emotion/react */ -import { css } from '@emotion/react'; +import styled from '@emotion/styled'; +import { InputHTMLAttributes } from 'react'; import { useFieldsContext } from './context/FieldsContext'; -const styles = { - input: css` - box-sizing: border-box; - margin: 0px; - padding: 4px 11px; - color: rgba(0, 0, 0, 0.88); - font-size: 14px; - line-height: 1.5714285714285714; - position: relative; - display: inline-block; - width: 100%; - min-width: 0px; - background-color: #fff; - border-radius: 6px; - transition: all 0.2s; - border: 1px solid #d9d9d9; - `, -}; +const InputStyled = styled.input<{ inputSize: 'default' | 'small' }>` + box-sizing: border-box; + margin: 0px; + padding: ${(props) => (props.inputSize === 'default' ? '4px 11px' : '0 7px')}; + color: rgba(0, 0, 0, 0.88); + font-size: 14px; + line-height: 1.5714285714285714; + position: relative; + display: inline-block; + width: 100%; + min-width: 0px; + background-color: #fff; + border-radius: ${(props) => (props.inputSize === 'default' ? '6px' : '4px')}; + transition: all 0.2s; + border: 1px solid #d9d9d9; +`; -export function Input(props: React.InputHTMLAttributes) { +export interface InputProps + extends Omit, 'size'> { + inputSize?: 'default' | 'small'; +} + +export function Input(props: InputProps) { + const { inputSize = 'default', ...otherProps } = props; const fieldsContext = useFieldsContext(); return ( - ); } diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 7461096b..ae1caa68 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -33,3 +33,20 @@ export function LabelExample() { ); } + +export function SmallExample() { + const [state, setState] = useState('Hello, World!'); + + function onChange(event: ChangeEvent) { + setState(event.target.value); + } + + return ( + + ); +} From a0bdbcb62d4256270490633f3ae04fcb9b926eec Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Fri, 2 Dec 2022 11:04:21 +0100 Subject: [PATCH 05/25] refactor: change style to be from ant --- src/components/forms/Input.tsx | 17 +++++++++++------ stories/components/input.stories.tsx | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index e0791a73..d0c31a99 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -3,10 +3,10 @@ import { InputHTMLAttributes } from 'react'; import { useFieldsContext } from './context/FieldsContext'; -const InputStyled = styled.input<{ inputSize: 'default' | 'small' }>` +const InputStyled = styled.input<{ variant: 'default' | 'small' }>` box-sizing: border-box; margin: 0px; - padding: ${(props) => (props.inputSize === 'default' ? '4px 11px' : '0 7px')}; + padding: ${(props) => (props.variant === 'default' ? '4px 11px' : '0 7px')}; color: rgba(0, 0, 0, 0.88); font-size: 14px; line-height: 1.5714285714285714; @@ -15,25 +15,30 @@ const InputStyled = styled.input<{ inputSize: 'default' | 'small' }>` width: 100%; min-width: 0px; background-color: #fff; - border-radius: ${(props) => (props.inputSize === 'default' ? '6px' : '4px')}; + border-radius: ${(props) => (props.variant === 'default' ? '6px' : '4px')}; transition: all 0.2s; border: 1px solid #d9d9d9; + + :hover { + border-color: #4096ff; + border-inline-end-width: 1px; + } `; export interface InputProps extends Omit, 'size'> { - inputSize?: 'default' | 'small'; + variant?: 'default' | 'small'; } export function Input(props: InputProps) { - const { inputSize = 'default', ...otherProps } = props; + const { variant = 'default', ...otherProps } = props; const fieldsContext = useFieldsContext(); return ( ); diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index ae1caa68..ac240fbc 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -46,7 +46,7 @@ export function SmallExample() { placeholder="Basic example" value={state} onChange={onChange} - inputSize="small" + variant="small" /> ); } From e4fc7fd84497eed78cb3cc3f62da4edc7ecc30e6 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Fri, 2 Dec 2022 11:31:08 +0100 Subject: [PATCH 06/25] feat: add variant on context --- src/components/forms/Input.tsx | 8 ++-- .../forms/context/FieldsContext.tsx | 20 ++++++--- stories/components/input.stories.tsx | 41 +++++++++++++------ 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index d0c31a99..26d5ae31 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -32,13 +32,13 @@ export interface InputProps export function Input(props: InputProps) { const { variant = 'default', ...otherProps } = props; - const fieldsContext = useFieldsContext(); + const { name, variant: variantContext } = useFieldsContext(); return ( ); diff --git a/src/components/forms/context/FieldsContext.tsx b/src/components/forms/context/FieldsContext.tsx index bf0b856e..f874ec26 100644 --- a/src/components/forms/context/FieldsContext.tsx +++ b/src/components/forms/context/FieldsContext.tsx @@ -1,17 +1,23 @@ /** @jsxImportSource @emotion/react */ import { css } from '@emotion/react'; -import { createContext, ReactNode, useContext } from 'react'; +import { createContext, ReactNode, useContext, useMemo } from 'react'; interface FieldsProps { children: ReactNode; } +interface FieldContext { + name: string; + variant: 'default' | 'small'; +} + interface FieldProps extends FieldsProps { name: string; label: string; + variant?: 'default' | 'small'; } -const context = createContext(null); +const context = createContext(null); const styles = { root: css` @@ -26,7 +32,7 @@ export function useFieldsContext() { const ctx = useContext(context); if (!ctx) { - return undefined; + return { name: undefined, variant: undefined }; } return ctx; @@ -38,10 +44,14 @@ export function Fields(props: FieldsProps) { } export function Field(props: FieldProps) { - const { label, name, children } = props; + const { label, name, children, variant = 'default' } = props; + + const memoized = useMemo(() => { + return { name, variant }; + }, [name, variant]); return ( - +
{children} diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index ac240fbc..2a1fdb6c 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -34,19 +34,36 @@ export function LabelExample() { ); } -export function SmallExample() { - const [state, setState] = useState('Hello, World!'); - - function onChange(event: ChangeEvent) { - setState(event.target.value); - } +export function VariantExample() { + return ( +
+
+ +
+
+ +
+
+ ); +} +export function VariantContext() { return ( - +
+
+ + + + + +
+
+ + + + + +
+
); } From 9fcb5a89449f0a13decacbe61e79e8bb051cd903 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Tue, 6 Dec 2022 16:17:34 +0100 Subject: [PATCH 07/25] empty commit From 9aa3a084046804c49f8cf29ba4828f0c3c51ed99 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Wed, 7 Dec 2022 11:09:06 +0100 Subject: [PATCH 08/25] refactor: change some styles --- src/components/forms/Input.tsx | 10 ++--- .../forms/context/FieldsContext.tsx | 8 ++-- stories/components/input.stories.tsx | 42 ++++++++++++------- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 26d5ae31..d4c2957a 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -18,6 +18,7 @@ const InputStyled = styled.input<{ variant: 'default' | 'small' }>` border-radius: ${(props) => (props.variant === 'default' ? '6px' : '4px')}; transition: all 0.2s; border: 1px solid #d9d9d9; + outline: none; :hover { border-color: #4096ff; @@ -32,14 +33,9 @@ export interface InputProps export function Input(props: InputProps) { const { variant = 'default', ...otherProps } = props; - const { name, variant: variantContext } = useFieldsContext(); + const { name } = useFieldsContext(); return ( - + ); } diff --git a/src/components/forms/context/FieldsContext.tsx b/src/components/forms/context/FieldsContext.tsx index f874ec26..91fc66b0 100644 --- a/src/components/forms/context/FieldsContext.tsx +++ b/src/components/forms/context/FieldsContext.tsx @@ -8,13 +8,11 @@ interface FieldsProps { interface FieldContext { name: string; - variant: 'default' | 'small'; } interface FieldProps extends FieldsProps { name: string; label: string; - variant?: 'default' | 'small'; } const context = createContext(null); @@ -44,11 +42,11 @@ export function Fields(props: FieldsProps) { } export function Field(props: FieldProps) { - const { label, name, children, variant = 'default' } = props; + const { label, name, children } = props; const memoized = useMemo(() => { - return { name, variant }; - }, [name, variant]); + return { name }; + }, [name]); return ( diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 2a1fdb6c..6302d395 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -47,23 +47,35 @@ export function VariantExample() { ); } -export function VariantContext() { +export function VariantWithLabelExample() { + const [state, setState] = useState('Hello, World!'); + + function onChange(event: ChangeEvent) { + setState(event.target.value); + } + return (
-
- - - - - -
-
- - - - - -
+ + + + + + + + + +
); } From ecda2dc71dd531616e027c301a5a705aa4f10ebc Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Thu, 8 Dec 2022 15:44:05 +0100 Subject: [PATCH 09/25] feat: add trailing addon --- src/components/forms/Input.tsx | 77 ++++++++++++++++++++++------ stories/components/input.stories.tsx | 22 +++++++- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index d4c2957a..04c9b352 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -1,41 +1,84 @@ import styled from '@emotion/styled'; -import { InputHTMLAttributes } from 'react'; +import { InputHTMLAttributes, ReactNode } from 'react'; import { useFieldsContext } from './context/FieldsContext'; -const InputStyled = styled.input<{ variant: 'default' | 'small' }>` - box-sizing: border-box; - margin: 0px; - padding: ${(props) => (props.variant === 'default' ? '4px 11px' : '0 7px')}; - color: rgba(0, 0, 0, 0.88); +const InputStyled = styled.input<{ + variant: 'default' | 'small'; + hasTrailing: boolean; +}>` + border: solid 1px rgb(217, 217, 217); font-size: 14px; - line-height: 1.5714285714285714; - position: relative; - display: inline-block; - width: 100%; - min-width: 0px; - background-color: #fff; - border-radius: ${(props) => (props.variant === 'default' ? '6px' : '4px')}; - transition: all 0.2s; - border: 1px solid #d9d9d9; + line-height: 22px; + margin: 0px -1px 0px 0px; outline: none; + width: 100%; :hover { border-color: #4096ff; border-inline-end-width: 1px; } + + border-radius: ${(props) => + props.variant === 'default' + ? props.hasTrailing + ? '6px 0px 0px 6px' + : '6px' + : props.hasTrailing + ? '4px 0px 0px 4px' + : '4px'}; + + padding: ${(props) => + props.variant === 'default' + ? props.hasTrailing + ? '4px 11px 4px 11px' + : '4px 11px' + : props.hasTrailing + ? '0px 7px 0px 7px' + : '0 7px'}; +`; + +const TrailingStyled = styled.div<{ variant: 'default' | 'small' }>` + border: 1px solid rgb(217, 217, 217); + display: inline-block; + font-size: 14px; + line-height: 22px; + text-align: center; + + max-width: 150px; + width: 100%; + + border-radius: ${(props) => + props.variant === 'default' ? '0px 6px 6px 0px' : '0px 4px 4px 0px'}; + + padding: ${(props) => + props.variant === 'default' ? '4px 11px 4px 11px' : '0px 7px 0px 7px'}; `; export interface InputProps extends Omit, 'size'> { variant?: 'default' | 'small'; + trailingAddon?: ReactNode; } export function Input(props: InputProps) { - const { variant = 'default', ...otherProps } = props; + const { variant = 'default', trailingAddon, ...otherProps } = props; const { name } = useFieldsContext(); return ( - +
+ + {trailingAddon && ( + {trailingAddon} + )} +
); } diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 6302d395..1d545793 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -1,6 +1,6 @@ import { ChangeEvent, useState } from 'react'; -import { Input, Fields, Field } from '../../src/components'; +import { Input, Fields, Field, Button } from '../../src/components'; export default { title: 'Forms / Input', @@ -79,3 +79,23 @@ export function VariantWithLabelExample() {
); } + +export function WithTrailingAddonDefaultVariant() { + return

} />; +} + +export function WithTrailingAddonSmallVariant() { + return ( +

} + variant="small" + /> + ); +} + +export function WithTrailingAddonButton() { + return ( + Hello, World!

} /> + ); +} From b6586a7e9c572fe91eeb3ffd2b51efedfdf9de41 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Thu, 8 Dec 2022 15:46:01 +0100 Subject: [PATCH 10/25] refactor: change to use styled --- src/components/forms/Input.tsx | 11 +++++++---- stories/components/input.stories.tsx | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 04c9b352..e202ef61 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -55,6 +55,11 @@ const TrailingStyled = styled.div<{ variant: 'default' | 'small' }>` props.variant === 'default' ? '4px 11px 4px 11px' : '0px 7px 0px 7px'}; `; +const GroupStyled = styled.div` + display: flex; + align-items: center; +`; + export interface InputProps extends Omit, 'size'> { variant?: 'default' | 'small'; @@ -66,9 +71,7 @@ export function Input(props: InputProps) { const { name } = useFieldsContext(); return ( -
+ {trailingAddon} )} -
+ ); } diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 1d545793..57136aa9 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -1,6 +1,6 @@ import { ChangeEvent, useState } from 'react'; -import { Input, Fields, Field, Button } from '../../src/components'; +import { Input, Fields, Field } from '../../src/components'; export default { title: 'Forms / Input', From b165d5e4f185927519c25bc1afaf842b57cc0571 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Fri, 9 Dec 2022 14:35:17 +0100 Subject: [PATCH 11/25] feat: add required --- src/components/forms/context/FieldsContext.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/forms/context/FieldsContext.tsx b/src/components/forms/context/FieldsContext.tsx index 91fc66b0..aa2dccdb 100644 --- a/src/components/forms/context/FieldsContext.tsx +++ b/src/components/forms/context/FieldsContext.tsx @@ -13,6 +13,8 @@ interface FieldContext { interface FieldProps extends FieldsProps { name: string; label: string; + + required?: boolean; } const context = createContext(null); @@ -24,6 +26,9 @@ const styles = { gap: 5px; align-items: center; `, + required: css` + color: red; + `, }; export function useFieldsContext() { @@ -42,7 +47,7 @@ export function Fields(props: FieldsProps) { } export function Field(props: FieldProps) { - const { label, name, children } = props; + const { label, name, children, required } = props; const memoized = useMemo(() => { return { name }; @@ -51,7 +56,9 @@ export function Field(props: FieldProps) { return (
- + {children}
From 9d078f6d6469e28a70739908f5a8f0bda5796163 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Mon, 12 Dec 2022 13:59:56 +0100 Subject: [PATCH 12/25] feat: add addon on input --- src/components/forms/Input.tsx | 101 +++++++++++++++---- stories/components/input.stories.tsx | 142 ++++++++++++++++++++------- 2 files changed, 188 insertions(+), 55 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index e202ef61..28e8c4e3 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -3,13 +3,17 @@ import { InputHTMLAttributes, ReactNode } from 'react'; import { useFieldsContext } from './context/FieldsContext'; -const InputStyled = styled.input<{ +interface StyledProps { variant: 'default' | 'small'; hasTrailing: boolean; -}>` + hasLeading: boolean; +} + +const lineHeight = 4 / 7; +const InputStyled = styled.input` border: solid 1px rgb(217, 217, 217); font-size: 14px; - line-height: 22px; + line-height: ${lineHeight}px; margin: 0px -1px 0px 0px; outline: none; width: 100%; @@ -19,14 +23,13 @@ const InputStyled = styled.input<{ border-inline-end-width: 1px; } + :focus { + border-color: #4096ff; + border-inline-end-width: 1px; + } + border-radius: ${(props) => - props.variant === 'default' - ? props.hasTrailing - ? '6px 0px 0px 6px' - : '6px' - : props.hasTrailing - ? '4px 0px 0px 4px' - : '4px'}; + getBorderStyle(props.hasLeading, props.hasTrailing, props.variant)}; padding: ${(props) => props.variant === 'default' @@ -38,15 +41,43 @@ const InputStyled = styled.input<{ : '0 7px'}; `; -const TrailingStyled = styled.div<{ variant: 'default' | 'small' }>` +function getBorderStyle( + hasLeading: boolean, + hasTrailing: boolean, + variant: StyledProps['variant'], +) { + const isSmall = variant === 'small'; + + if (hasTrailing && hasLeading) { + return '0px'; + } + + if (isSmall) { + if (hasTrailing) { + return '4px 0px 0px 4px'; + } else if (hasLeading) { + return '0px 4px 4px 0px'; + } else { + return '4px'; + } + } else if (hasTrailing) { + return '7px 0px 0px 7px'; + } else if (hasLeading) { + return '0px 7px 7px 0px'; + } else { + return '7px'; + } +} + +const TrailingAddonStyled = styled.div>` border: 1px solid rgb(217, 217, 217); + border-left: none; display: inline-block; font-size: 14px; - line-height: 22px; text-align: center; - max-width: 150px; - width: 100%; + line-height: 17px; + width: min-content; border-radius: ${(props) => props.variant === 'default' ? '0px 6px 6px 0px' : '0px 4px 4px 0px'}; @@ -55,32 +86,66 @@ const TrailingStyled = styled.div<{ variant: 'default' | 'small' }>` props.variant === 'default' ? '4px 11px 4px 11px' : '0px 7px 0px 7px'}; `; +const LeadingAddonStyled = styled.div>` + border: 1px solid rgb(217, 217, 217); + border-right: none; + display: inline-block; + font-size: 14px; + text-align: center; + + line-height: 17px; + width: min-content; + + border-radius: ${(props) => + props.variant === 'default' ? '6px 0px 0px 6px' : '4px 0px 0px 4px'}; + + padding: ${(props) => + props.variant === 'default' ? '4px 11px 4px 11px' : '0px 7px 0px 7px'}; +`; + const GroupStyled = styled.div` display: flex; align-items: center; `; -export interface InputProps - extends Omit, 'size'> { +export interface InputProps extends InputHTMLAttributes { variant?: 'default' | 'small'; + + leadingAddon?: ReactNode; + leadingInlineAddon?: ReactNode; trailingAddon?: ReactNode; + trailingInlineAddon?: ReactNode; } export function Input(props: InputProps) { - const { variant = 'default', trailingAddon, ...otherProps } = props; + const { + variant = 'default', + trailingAddon, + leadingAddon, + leadingInlineAddon, + ...otherProps + } = props; const { name } = useFieldsContext(); return ( + {leadingAddon && ( + + {leadingAddon} + + )} {trailingAddon && ( - {trailingAddon} + + {trailingAddon} + )} ); diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 57136aa9..be6ea407 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -1,3 +1,4 @@ +import styled from '@emotion/styled'; import { ChangeEvent, useState } from 'react'; import { Input, Fields, Field } from '../../src/components'; @@ -6,7 +7,19 @@ export default { title: 'Forms / Input', }; -export function BasicExample() { +const ExampleContainerAddonGroup = styled.div` + display: flex; + flex-direction: column; + gap: 10px; +`; + +const ExampleGroup = styled.div` + display: flex; + flex-direction: row; + gap: 5px; +`; + +export function Basic() { const [state, setState] = useState('Hello, World!'); function onChange(event: ChangeEvent) { @@ -14,11 +27,19 @@ export function BasicExample() { } return ( - + + + + ); } -export function LabelExample() { +export function Required() { const [state, setState] = useState('Hello, World!'); function onChange(event: ChangeEvent) { @@ -27,27 +48,28 @@ export function LabelExample() { return ( - - - + + + + + + + + ); } -export function VariantExample() { - return ( -
-
- -
-
- -
-
- ); -} - -export function VariantWithLabelExample() { +export function Label() { const [state, setState] = useState('Hello, World!'); function onChange(event: ChangeEvent) { @@ -55,18 +77,15 @@ export function VariantWithLabelExample() { } return ( -
- + + - - - -
+ + ); } -export function WithTrailingAddonDefaultVariant() { - return

} />; +export function WithTrailingAddon() { + return ( + + +

} /> + +

} + variant="small" + /> +
+ +

} /> + +

} + variant="small" + /> +
+
+ ); } -export function WithTrailingAddonSmallVariant() { +export function WithLeadingAddon() { return ( -

} - variant="small" - /> + + +

} /> + +

} + variant="small" + /> +
+ +

} /> + +

} + variant="small" + /> +
+
); } -export function WithTrailingAddonButton() { +export function WithLeadingAndTrailingAddon() { return ( - Hello, World!

} /> + +

} + trailingAddon={

} + /> + +

} + trailingAddon={

} + variant="small" + /> +
); } From f94f2fefd49a7787a7a051c2899bfa2fd2318c7b Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Tue, 13 Dec 2022 11:38:59 +0100 Subject: [PATCH 13/25] feat: add inline & trailing addon --- src/components/forms/Input.tsx | 76 +++++++++++++++++++++------- stories/components/input.stories.tsx | 71 +++++++++++++++++++++----- 2 files changed, 118 insertions(+), 29 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 28e8c4e3..6efc0e7c 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -7,11 +7,22 @@ interface StyledProps { variant: 'default' | 'small'; hasTrailing: boolean; hasLeading: boolean; + + hasInlineTrailing: boolean; + hasInlineLeading: boolean; } const lineHeight = 4 / 7; const InputStyled = styled.input` - border: solid 1px rgb(217, 217, 217); + border-top: solid 1px rgb(217, 217, 217); + border-bottom: solid 1px rgb(217, 217, 217); + + border-left: ${(props) => + props.hasInlineLeading ? 'none' : 'solid 1px rgb(217, 217, 217)'}; + + border-right: ${(props) => + props.hasInlineTrailing ? 'none' : 'solid 1px rgb(217, 217, 217)'}; + font-size: 14px; line-height: ${lineHeight}px; margin: 0px -1px 0px 0px; @@ -29,7 +40,11 @@ const InputStyled = styled.input` } border-radius: ${(props) => - getBorderStyle(props.hasLeading, props.hasTrailing, props.variant)}; + getBorderStyle( + props.hasLeading || props.hasInlineLeading, + props.hasTrailing || props.hasInlineTrailing, + props.variant, + )}; padding: ${(props) => props.variant === 'default' @@ -108,13 +123,16 @@ const GroupStyled = styled.div` align-items: center; `; +interface RenderAddon { + render: () => ReactNode; + inline?: boolean; +} + export interface InputProps extends InputHTMLAttributes { variant?: 'default' | 'small'; - leadingAddon?: ReactNode; - leadingInlineAddon?: ReactNode; - trailingAddon?: ReactNode; - trailingInlineAddon?: ReactNode; + leadingAddon?: RenderAddon; + trailingAddon?: RenderAddon; } export function Input(props: InputProps) { @@ -122,31 +140,55 @@ export function Input(props: InputProps) { variant = 'default', trailingAddon, leadingAddon, - leadingInlineAddon, ...otherProps } = props; + const { name } = useFieldsContext(); return ( - {leadingAddon && ( - - {leadingAddon} - - )} + {renderLeadingAddon(variant, leadingAddon)} + - {trailingAddon && ( - - {trailingAddon} - - )} + + {renderTrailingAddon(variant, trailingAddon)} ); } + +function renderLeadingAddon( + variant: StyledProps['variant'], + addon?: RenderAddon, +) { + if (!addon) { + return null; + } + + const { render } = addon; + + return {render()}; +} + +function renderTrailingAddon( + variant: StyledProps['variant'], + addon?: RenderAddon, +) { + if (!addon) { + return null; + } + + const { render } = addon; + + return ( + {render()} + ); +} diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index be6ea407..6c0ef21f 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -103,20 +103,26 @@ export function WithTrailingAddon() { return ( -

} /> +

A

}} + />

} + trailingAddon={{ render: () =>

A

}} variant="small" />
-

} /> +

A

, inline: true }} + />

} + trailingAddon={{ render: () =>

A

, inline: true }} variant="small" />
@@ -128,20 +134,26 @@ export function WithLeadingAddon() { return ( -

} /> +

A

}} + />

} + leadingAddon={{ render: () =>

A

}} variant="small" />
-

} /> +

A

, inline: true }} + />

} + leadingAddon={{ render: () =>

A

, inline: true }} variant="small" />
@@ -150,18 +162,53 @@ export function WithLeadingAddon() { } export function WithLeadingAndTrailingAddon() { + return ( + + +

A

}} + trailingAddon={{ render: () =>

A

}} + /> + +

A

}} + trailingAddon={{ render: () =>

A

}} + variant="small" + /> +
+ +

A

, inline: true }} + trailingAddon={{ render: () =>

A

, inline: true }} + /> + +

A

, inline: true }} + trailingAddon={{ render: () =>

A

, inline: true }} + variant="small" + /> +
+
+ ); +} + +export function WithInlineAndNormalAddon() { return (

} - trailingAddon={

} + leadingAddon={{ render: () =>

, inline: true }} + trailingAddon={{ render: () =>

, inline: true }} />

} - trailingAddon={

} + leadingAddon={{ render: () =>

, inline: true }} + trailingAddon={{ render: () =>

, inline: true }} variant="small" />
From 8cb19f4e0dfc49a0d9da5e8c0a89118c0d81c73c Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Tue, 13 Dec 2022 15:40:11 +0100 Subject: [PATCH 14/25] refactor: resolve border color with css vars --- src/components/forms/Input.tsx | 89 ++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 6efc0e7c..49cc52b9 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -12,16 +12,26 @@ interface StyledProps { hasInlineLeading: boolean; } +const GroupStyled = styled.div` + display: flex; + align-items: center; + + --custom-border-color: rgb(217, 217, 217); + :hover { + --custom-border-color: #4096ff; + } +`; + const lineHeight = 4 / 7; const InputStyled = styled.input` - border-top: solid 1px rgb(217, 217, 217); - border-bottom: solid 1px rgb(217, 217, 217); + border-top: solid 1px var(--custom-border-color); + border-bottom: solid 1px var(--custom-border-color); border-left: ${(props) => - props.hasInlineLeading ? 'none' : 'solid 1px rgb(217, 217, 217)'}; + props.hasInlineLeading ? 'none' : 'solid 1px var(--custom-border-color)'}; border-right: ${(props) => - props.hasInlineTrailing ? 'none' : 'solid 1px rgb(217, 217, 217)'}; + props.hasInlineTrailing ? 'none' : 'solid 1px var(--custom-border-color)'}; font-size: 14px; line-height: ${lineHeight}px; @@ -30,12 +40,14 @@ const InputStyled = styled.input` width: 100%; :hover { - border-color: #4096ff; + // --custom-border-color: #4096ff; + + border-color: var(--custom-border-color); border-inline-end-width: 1px; } :focus { - border-color: #4096ff; + border-color: var(--custom-border-color); border-inline-end-width: 1px; } @@ -56,36 +68,8 @@ const InputStyled = styled.input` : '0 7px'}; `; -function getBorderStyle( - hasLeading: boolean, - hasTrailing: boolean, - variant: StyledProps['variant'], -) { - const isSmall = variant === 'small'; - - if (hasTrailing && hasLeading) { - return '0px'; - } - - if (isSmall) { - if (hasTrailing) { - return '4px 0px 0px 4px'; - } else if (hasLeading) { - return '0px 4px 4px 0px'; - } else { - return '4px'; - } - } else if (hasTrailing) { - return '7px 0px 0px 7px'; - } else if (hasLeading) { - return '0px 7px 7px 0px'; - } else { - return '7px'; - } -} - const TrailingAddonStyled = styled.div>` - border: 1px solid rgb(217, 217, 217); + border: 1px solid var(--custom-border-color); border-left: none; display: inline-block; font-size: 14px; @@ -102,7 +86,7 @@ const TrailingAddonStyled = styled.div>` `; const LeadingAddonStyled = styled.div>` - border: 1px solid rgb(217, 217, 217); + border: 1px solid var(--custom-border-color); border-right: none; display: inline-block; font-size: 14px; @@ -118,11 +102,6 @@ const LeadingAddonStyled = styled.div>` props.variant === 'default' ? '4px 11px 4px 11px' : '0px 7px 0px 7px'}; `; -const GroupStyled = styled.div` - display: flex; - align-items: center; -`; - interface RenderAddon { render: () => ReactNode; inline?: boolean; @@ -192,3 +171,31 @@ function renderTrailingAddon( {render()} ); } + +function getBorderStyle( + hasLeading: boolean, + hasTrailing: boolean, + variant: StyledProps['variant'], +) { + const isSmall = variant === 'small'; + + if (hasTrailing && hasLeading) { + return '0px'; + } + + if (isSmall) { + if (hasTrailing) { + return '4px 0px 0px 4px'; + } else if (hasLeading) { + return '0px 4px 4px 0px'; + } else { + return '4px'; + } + } else if (hasTrailing) { + return '7px 0px 0px 7px'; + } else if (hasLeading) { + return '0px 7px 7px 0px'; + } else { + return '7px'; + } +} From 9b862c1127eca3b8498fb0900af1c8b091050ccb Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Tue, 13 Dec 2022 15:42:49 +0100 Subject: [PATCH 15/25] refactor: add focus on input --- src/components/forms/Input.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 49cc52b9..7d74f931 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -40,13 +40,13 @@ const InputStyled = styled.input` width: 100%; :hover { - // --custom-border-color: #4096ff; - border-color: var(--custom-border-color); border-inline-end-width: 1px; } :focus { + --custom-border-color: #4096ff; + border-color: var(--custom-border-color); border-inline-end-width: 1px; } From 5328dccf463d24feb8128fb8baa87e3a23699a6d Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Tue, 13 Dec 2022 16:22:23 +0100 Subject: [PATCH 16/25] refactor: change focus color to use within --- src/components/forms/Input.tsx | 18 ++++++------ stories/components/input.stories.tsx | 43 +++++++++++++--------------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 7d74f931..be7c7fa0 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -17,7 +17,9 @@ const GroupStyled = styled.div` align-items: center; --custom-border-color: rgb(217, 217, 217); - :hover { + + :hover, + :focus-within { --custom-border-color: #4096ff; } `; @@ -45,7 +47,7 @@ const InputStyled = styled.input` } :focus { - --custom-border-color: #4096ff; + // --custom-border-color: #4096ff; border-color: var(--custom-border-color); border-inline-end-width: 1px; @@ -103,7 +105,7 @@ const LeadingAddonStyled = styled.div>` `; interface RenderAddon { - render: () => ReactNode; + addon: ReactNode; inline?: boolean; } @@ -152,9 +154,9 @@ function renderLeadingAddon( return null; } - const { render } = addon; + const { addon: render } = addon; - return {render()}; + return {render}; } function renderTrailingAddon( @@ -165,11 +167,9 @@ function renderTrailingAddon( return null; } - const { render } = addon; + const { addon: render } = addon; - return ( - {render()} - ); + return {render}; } function getBorderStyle( diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 6c0ef21f..aa2ac32b 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -105,24 +105,24 @@ export function WithTrailingAddon() {

A

}} + trailingAddon={{ addon:

A

}} />

A

}} + trailingAddon={{ addon:

A

}} variant="small" />

A

, inline: true }} + trailingAddon={{ addon:

A

, inline: true }} />

A

, inline: true }} + trailingAddon={{ addon:

A

, inline: true }} variant="small" />
@@ -134,26 +134,23 @@ export function WithLeadingAddon() { return ( -

A

}} - /> + A

}} />

A

}} + leadingAddon={{ addon:

A

}} variant="small" />

A

, inline: true }} + leadingAddon={{ addon:

A

, inline: true }} />

A

, inline: true }} + leadingAddon={{ addon:

A

, inline: true }} variant="small" />
@@ -167,28 +164,28 @@ export function WithLeadingAndTrailingAddon() {

A

}} - trailingAddon={{ render: () =>

A

}} + leadingAddon={{ addon:

A

}} + trailingAddon={{ addon:

A

}} />

A

}} - trailingAddon={{ render: () =>

A

}} + leadingAddon={{ addon:

A

}} + trailingAddon={{ addon:

A

}} variant="small" />

A

, inline: true }} - trailingAddon={{ render: () =>

A

, inline: true }} + leadingAddon={{ addon:

A

, inline: true }} + trailingAddon={{ addon:

A

, inline: true }} />

A

, inline: true }} - trailingAddon={{ render: () =>

A

, inline: true }} + leadingAddon={{ addon:

A

, inline: true }} + trailingAddon={{ addon:

A

, inline: true }} variant="small" />
@@ -201,14 +198,14 @@ export function WithInlineAndNormalAddon() {

, inline: true }} - trailingAddon={{ render: () =>

, inline: true }} + leadingAddon={{ addon:

A

, inline: true }} + trailingAddon={{ addon:

A

, inline: true }} />

, inline: true }} - trailingAddon={{ render: () =>

, inline: true }} + leadingAddon={{ addon:

A

, inline: true }} + trailingAddon={{ addon:

A

, inline: true }} variant="small" />
From 81a4d2d6c4278a27c7972354f9e1d0e8c374dc55 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Wed, 14 Dec 2022 12:20:16 +0100 Subject: [PATCH 17/25] feat: change line height by variant --- src/components/forms/Input.tsx | 6 +++--- stories/components/input.stories.tsx | 19 ------------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index be7c7fa0..1748f06a 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -35,7 +35,7 @@ const InputStyled = styled.input` border-right: ${(props) => props.hasInlineTrailing ? 'none' : 'solid 1px var(--custom-border-color)'}; - font-size: 14px; + font-size: ${(props) => (props.variant === 'small' ? '1em' : '1.125em')}; line-height: ${lineHeight}px; margin: 0px -1px 0px 0px; outline: none; @@ -77,7 +77,7 @@ const TrailingAddonStyled = styled.div>` font-size: 14px; text-align: center; - line-height: 17px; + line-height: ${(props) => (props.variant === 'small' ? '15px' : '17px')}; width: min-content; border-radius: ${(props) => @@ -94,7 +94,7 @@ const LeadingAddonStyled = styled.div>` font-size: 14px; text-align: center; - line-height: 17px; + line-height: ${(props) => (props.variant === 'small' ? '15px' : '17px')}; width: min-content; border-radius: ${(props) => diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index aa2ac32b..5b1d4633 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -192,22 +192,3 @@ export function WithLeadingAndTrailingAddon() {
); } - -export function WithInlineAndNormalAddon() { - return ( - - A

, inline: true }} - trailingAddon={{ addon:

A

, inline: true }} - /> - - A

, inline: true }} - trailingAddon={{ addon:

A

, inline: true }} - variant="small" - /> -
- ); -} From 424bd83f0e76c794e75985fe641c046744bc7da9 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Thu, 15 Dec 2022 16:22:26 +0100 Subject: [PATCH 18/25] refactor: remove Fields --- .../forms/context/FieldsContext.tsx | 12 +--- stories/components/input.stories.tsx | 66 ++++++++----------- 2 files changed, 29 insertions(+), 49 deletions(-) diff --git a/src/components/forms/context/FieldsContext.tsx b/src/components/forms/context/FieldsContext.tsx index aa2dccdb..6f5c2fa3 100644 --- a/src/components/forms/context/FieldsContext.tsx +++ b/src/components/forms/context/FieldsContext.tsx @@ -2,17 +2,14 @@ import { css } from '@emotion/react'; import { createContext, ReactNode, useContext, useMemo } from 'react'; -interface FieldsProps { - children: ReactNode; -} - interface FieldContext { name: string; } -interface FieldProps extends FieldsProps { +interface FieldProps { name: string; label: string; + children: ReactNode; required?: boolean; } @@ -41,11 +38,6 @@ export function useFieldsContext() { return ctx; } -export function Fields(props: FieldsProps) { - const { children } = props; - return <>{children}; -} - export function Field(props: FieldProps) { const { label, name, children, required } = props; diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 5b1d4633..170975e6 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; import { ChangeEvent, useState } from 'react'; -import { Input, Fields, Field } from '../../src/components'; +import { Input, Field } from '../../src/components'; export default { title: 'Forms / Input', @@ -47,25 +47,19 @@ export function Required() { } return ( - - - - - - - - - - + + + + + + + + ); } @@ -77,25 +71,19 @@ export function Label() { } return ( - - - - - - - - - - + + + + + + + + ); } From 1afb6f38396791bddcb7fd783445519dd2eddfb0 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Thu, 15 Dec 2022 16:35:50 +0100 Subject: [PATCH 19/25] feat: add variant on Field --- src/components/forms/Input.tsx | 8 ++++---- src/components/forms/context/FieldsContext.tsx | 9 +++++---- stories/components/input.stories.tsx | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 1748f06a..9ea70990 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -74,7 +74,7 @@ const TrailingAddonStyled = styled.div>` border: 1px solid var(--custom-border-color); border-left: none; display: inline-block; - font-size: 14px; + font-size: ${(props) => (props.variant === 'small' ? '1em' : '1.125em')}; text-align: center; line-height: ${(props) => (props.variant === 'small' ? '15px' : '17px')}; @@ -91,7 +91,7 @@ const LeadingAddonStyled = styled.div>` border: 1px solid var(--custom-border-color); border-right: none; display: inline-block; - font-size: 14px; + font-size: ${(props) => (props.variant === 'small' ? '1em' : '1.125em')}; text-align: center; line-height: ${(props) => (props.variant === 'small' ? '15px' : '17px')}; @@ -124,7 +124,7 @@ export function Input(props: InputProps) { ...otherProps } = props; - const { name } = useFieldsContext(); + const { name, variant: contextVariant } = useFieldsContext(); return ( @@ -133,7 +133,7 @@ export function Input(props: InputProps) { { - return { name }; - }, [name]); + return { name, variant: variant || 'default' }; + }, [name, variant]); return ( diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 170975e6..1e19a5e8 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -180,3 +180,18 @@ export function WithLeadingAndTrailingAddon() {
); } + +export function TwoInputWithOneLabel() { + return ( + + + + + + + + + + + ); +} From f4905fee49819309a9158447e9e99673b15c82f0 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Thu, 22 Dec 2022 14:40:55 +0100 Subject: [PATCH 20/25] refactor: move variant to be with default value --- src/components/forms/Input.tsx | 13 ++++--------- src/components/forms/context/FieldsContext.tsx | 6 +++--- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 9ea70990..04c957af 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -117,23 +117,18 @@ export interface InputProps extends InputHTMLAttributes { } export function Input(props: InputProps) { - const { - variant = 'default', - trailingAddon, - leadingAddon, - ...otherProps - } = props; + const { variant, trailingAddon, leadingAddon, ...otherProps } = props; const { name, variant: contextVariant } = useFieldsContext(); return ( - {renderLeadingAddon(variant, leadingAddon)} + {renderLeadingAddon(variant || contextVariant, leadingAddon)} - {renderTrailingAddon(variant, trailingAddon)} + {renderTrailingAddon(variant || contextVariant, trailingAddon)} ); } diff --git a/src/components/forms/context/FieldsContext.tsx b/src/components/forms/context/FieldsContext.tsx index fe3493ec..0cc2775e 100644 --- a/src/components/forms/context/FieldsContext.tsx +++ b/src/components/forms/context/FieldsContext.tsx @@ -3,7 +3,7 @@ import { css } from '@emotion/react'; import { createContext, ReactNode, useContext, useMemo } from 'react'; interface FieldContext { - name: string; + name?: string; variant: 'default' | 'small'; } @@ -29,11 +29,11 @@ const styles = { `, }; -export function useFieldsContext() { +export function useFieldsContext(): FieldContext { const ctx = useContext(context); if (!ctx) { - return { name: undefined, variant: undefined }; + return { name: undefined, variant: 'default' }; } return ctx; From a014f9378f4c7e92f81d007e4a37e3f3b39f031c Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Fri, 23 Dec 2022 14:17:26 +0100 Subject: [PATCH 21/25] fix: resolve line-height bug that affect the height of the input --- src/components/forms/Input.tsx | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 04c957af..da892d77 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -24,7 +24,13 @@ const GroupStyled = styled.div` } `; -const lineHeight = 4 / 7; +function getSpecialSize(props: any) { + return { + fontSize: props.variant === 'small' ? '1em' : '1.125em', + lineHeight: props.variant === 'small' ? '15px' : '17px', + }; +} + const InputStyled = styled.input` border-top: solid 1px var(--custom-border-color); border-bottom: solid 1px var(--custom-border-color); @@ -35,8 +41,8 @@ const InputStyled = styled.input` border-right: ${(props) => props.hasInlineTrailing ? 'none' : 'solid 1px var(--custom-border-color)'}; - font-size: ${(props) => (props.variant === 'small' ? '1em' : '1.125em')}; - line-height: ${lineHeight}px; + font-size: ${(props) => getSpecialSize(props).fontSize}; + line-height: ${(props) => getSpecialSize(props).lineHeight}; margin: 0px -1px 0px 0px; outline: none; width: 100%; @@ -47,8 +53,6 @@ const InputStyled = styled.input` } :focus { - // --custom-border-color: #4096ff; - border-color: var(--custom-border-color); border-inline-end-width: 1px; } @@ -74,10 +78,11 @@ const TrailingAddonStyled = styled.div>` border: 1px solid var(--custom-border-color); border-left: none; display: inline-block; - font-size: ${(props) => (props.variant === 'small' ? '1em' : '1.125em')}; text-align: center; - line-height: ${(props) => (props.variant === 'small' ? '15px' : '17px')}; + font-size: ${(props) => getSpecialSize(props).fontSize}; + line-height: ${(props) => getSpecialSize(props).lineHeight}; + width: min-content; border-radius: ${(props) => @@ -91,10 +96,10 @@ const LeadingAddonStyled = styled.div>` border: 1px solid var(--custom-border-color); border-right: none; display: inline-block; - font-size: ${(props) => (props.variant === 'small' ? '1em' : '1.125em')}; text-align: center; - line-height: ${(props) => (props.variant === 'small' ? '15px' : '17px')}; + font-size: ${(props) => getSpecialSize(props).fontSize}; + line-height: ${(props) => getSpecialSize(props).lineHeight}; width: min-content; border-radius: ${(props) => From b2101d5af03e9dbeb261149ac7a74479fbaf5c15 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Fri, 23 Dec 2022 16:48:11 +0100 Subject: [PATCH 22/25] refactor: remove not needed any --- src/components/forms/Input.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index da892d77..3e5f1fb5 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -24,7 +24,7 @@ const GroupStyled = styled.div` } `; -function getSpecialSize(props: any) { +function getSpecialSize(props: Pick) { return { fontSize: props.variant === 'small' ? '1em' : '1.125em', lineHeight: props.variant === 'small' ? '15px' : '17px', From 60dc91e17c7e56877ecfadbdc5cb722f83750687 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Tue, 3 Jan 2023 12:04:01 +0100 Subject: [PATCH 23/25] refactor: change addon to be icon --- stories/components/input.stories.tsx | 36 +++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/stories/components/input.stories.tsx b/stories/components/input.stories.tsx index 1e19a5e8..3cce0354 100644 --- a/stories/components/input.stories.tsx +++ b/stories/components/input.stories.tsx @@ -1,5 +1,6 @@ import styled from '@emotion/styled'; import { ChangeEvent, useState } from 'react'; +import { FaMeteor } from 'react-icons/fa'; import { Input, Field } from '../../src/components'; @@ -93,24 +94,24 @@ export function WithTrailingAddon() { A

}} + trailingAddon={{ addon: }} /> A

}} + trailingAddon={{ addon: }} variant="small" />
A

, inline: true }} + trailingAddon={{ addon: , inline: true }} /> A

, inline: true }} + trailingAddon={{ addon: , inline: true }} variant="small" />
@@ -122,23 +123,26 @@ export function WithLeadingAddon() { return ( - A

}} /> + }} + /> A

}} + leadingAddon={{ addon: }} variant="small" />
A

, inline: true }} + leadingAddon={{ addon: , inline: true }} /> A

, inline: true }} + leadingAddon={{ addon: , inline: true }} variant="small" />
@@ -152,28 +156,28 @@ export function WithLeadingAndTrailingAddon() { A

}} - trailingAddon={{ addon:

A

}} + leadingAddon={{ addon: }} + trailingAddon={{ addon: }} /> A

}} - trailingAddon={{ addon:

A

}} + leadingAddon={{ addon: }} + trailingAddon={{ addon: }} variant="small" />
A

, inline: true }} - trailingAddon={{ addon:

A

, inline: true }} + leadingAddon={{ addon: , inline: true }} + trailingAddon={{ addon: , inline: true }} /> A

, inline: true }} - trailingAddon={{ addon:

A

, inline: true }} + leadingAddon={{ addon: , inline: true }} + trailingAddon={{ addon: , inline: true }} variant="small" />
From 73fdc929c0d1cb3effa4768afea09294d05a8722 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Tue, 3 Jan 2023 15:18:22 +0100 Subject: [PATCH 24/25] refactor: change the entire Input component to change the DOM --- src/components/forms/Input.tsx | 242 +++++++++++++++------------------ 1 file changed, 108 insertions(+), 134 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 3e5f1fb5..740fec52 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -12,18 +12,6 @@ interface StyledProps { hasInlineLeading: boolean; } -const GroupStyled = styled.div` - display: flex; - align-items: center; - - --custom-border-color: rgb(217, 217, 217); - - :hover, - :focus-within { - --custom-border-color: #4096ff; - } -`; - function getSpecialSize(props: Pick) { return { fontSize: props.variant === 'small' ? '1em' : '1.125em', @@ -31,39 +19,11 @@ function getSpecialSize(props: Pick) { }; } -const InputStyled = styled.input` - border-top: solid 1px var(--custom-border-color); - border-bottom: solid 1px var(--custom-border-color); - - border-left: ${(props) => - props.hasInlineLeading ? 'none' : 'solid 1px var(--custom-border-color)'}; - - border-right: ${(props) => - props.hasInlineTrailing ? 'none' : 'solid 1px var(--custom-border-color)'}; - - font-size: ${(props) => getSpecialSize(props).fontSize}; - line-height: ${(props) => getSpecialSize(props).lineHeight}; - margin: 0px -1px 0px 0px; - outline: none; - width: 100%; - - :hover { - border-color: var(--custom-border-color); - border-inline-end-width: 1px; - } - - :focus { - border-color: var(--custom-border-color); - border-inline-end-width: 1px; - } - - border-radius: ${(props) => - getBorderStyle( - props.hasLeading || props.hasInlineLeading, - props.hasTrailing || props.hasInlineTrailing, - props.variant, - )}; - +const LabelStyled = styled.label<{ + hasLeading: boolean; + hasTrailing: boolean; + variant: 'small' | 'default'; +}>` padding: ${(props) => props.variant === 'default' ? props.hasTrailing @@ -72,41 +32,97 @@ const InputStyled = styled.input` : props.hasTrailing ? '0px 7px 0px 7px' : '0 7px'}; -`; - -const TrailingAddonStyled = styled.div>` - border: 1px solid var(--custom-border-color); - border-left: none; - display: inline-block; - text-align: center; font-size: ${(props) => getSpecialSize(props).fontSize}; line-height: ${(props) => getSpecialSize(props).lineHeight}; - width: min-content; + background-color: white; + border-width: 1px; + align-items: center; + flex-direction: row; + flex: 1 1 0%; + display: flex; + position: relative; + + border-top-right-radius: ${(props) => + props.hasLeading && !props.hasTrailing && '0.375rem'}; + + border-bottom-right-radius: ${(props) => + props.hasLeading && !props.hasTrailing && '0.375rem'}; + + border-top-left-radius: ${(props) => + props.hasTrailing && !props.hasLeading && '0.375rem'}; + + border-bottom-left-radius: ${(props) => + props.hasTrailing && !props.hasLeading && '0.375rem'}; border-radius: ${(props) => - props.variant === 'default' ? '0px 6px 6px 0px' : '0px 4px 4px 0px'}; + !props.hasLeading && !props.hasTrailing && '0.375rem'}; - padding: ${(props) => - props.variant === 'default' ? '4px 11px 4px 11px' : '0px 7px 0px 7px'}; + border-color: var(--custom-border-color); `; -const LeadingAddonStyled = styled.div>` - border: 1px solid var(--custom-border-color); +const GroupStyled = styled.div` + display: flex; + border-radius: 0.375rem; + margin-top: 0.25rem; + + --custom-border-color: rgb(217, 217, 217); + + :hover, + :focus-within { + --custom-border-color: #4096ff; + } +`; + +const InputStyled = styled.input` + padding: 0; + flex: 1 1 0%; + border: none; + position: relative; + outline: none; +`; + +const LeadingAddonStyled = styled.div` + padding-left: 0.75rem; + padding-right: 0.75rem; + border-right-width: 0px; + border-width: 1px; + border-top-left-radius: 0.375rem; + border-bottom-left-radius: 0.375rem; + align-items: center; + display: inline-flex; + border-right: none; - display: inline-block; - text-align: center; - font-size: ${(props) => getSpecialSize(props).fontSize}; - line-height: ${(props) => getSpecialSize(props).lineHeight}; - width: min-content; + border-color: var(--custom-border-color); +`; - border-radius: ${(props) => - props.variant === 'default' ? '6px 0px 0px 6px' : '4px 0px 0px 4px'}; +const TrailingAddonStyled = styled.div` + padding-left: 0.75rem; + padding-right: 0.75rem; + border-left-width: 0px; + border-width: 1px; + border-top-right-radius: 0.375rem; + border-bottom-right-radius: 0.375rem; + align-items: center; + display: inline-flex; - padding: ${(props) => - props.variant === 'default' ? '4px 11px 4px 11px' : '0px 7px 0px 7px'}; + border-left: none; + + border-color: var(--custom-border-color); +`; + +const LeadingInlineAddonStyled = styled.div` + display: flex; + align-items: center; + padding-right: 0.5rem; +`; + +const TrailingInlineAddonStyled = styled.div` + display: flex; + align-items: center; + padding-left: 0.5rem; `; interface RenderAddon { @@ -126,76 +142,34 @@ export function Input(props: InputProps) { const { name, variant: contextVariant } = useFieldsContext(); + const hasLeading = (leadingAddon && !leadingAddon.inline) || false; + const hasTrailing = (trailingAddon && !trailingAddon.inline) || false; + return ( - {renderLeadingAddon(variant || contextVariant, leadingAddon)} - - {leadingAddon.addon} + )} + - - {renderTrailingAddon(variant || contextVariant, trailingAddon)} + hasLeading={hasLeading} + hasTrailing={hasTrailing} + > + {leadingAddon?.inline && ( + + {leadingAddon.addon} + + )} + + {trailingAddon?.inline && ( + + {trailingAddon.addon} + + )} + + {trailingAddon && !trailingAddon.inline && ( + {trailingAddon.addon} + )} ); } - -function renderLeadingAddon( - variant: StyledProps['variant'], - addon?: RenderAddon, -) { - if (!addon) { - return null; - } - - const { addon: render } = addon; - - return {render}; -} - -function renderTrailingAddon( - variant: StyledProps['variant'], - addon?: RenderAddon, -) { - if (!addon) { - return null; - } - - const { addon: render } = addon; - - return {render}; -} - -function getBorderStyle( - hasLeading: boolean, - hasTrailing: boolean, - variant: StyledProps['variant'], -) { - const isSmall = variant === 'small'; - - if (hasTrailing && hasLeading) { - return '0px'; - } - - if (isSmall) { - if (hasTrailing) { - return '4px 0px 0px 4px'; - } else if (hasLeading) { - return '0px 4px 4px 0px'; - } else { - return '4px'; - } - } else if (hasTrailing) { - return '7px 0px 0px 7px'; - } else if (hasLeading) { - return '0px 7px 7px 0px'; - } else { - return '7px'; - } -} From 7cebeceaeb3cf24c9bd6a2b0cb1aaca5ae790d74 Mon Sep 17 00:00:00 2001 From: Sebastien-Ahkrin Date: Tue, 3 Jan 2023 15:20:34 +0100 Subject: [PATCH 25/25] refactor: add types and remove unused pick --- src/components/forms/Input.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 740fec52..890b9ce5 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -5,11 +5,8 @@ import { useFieldsContext } from './context/FieldsContext'; interface StyledProps { variant: 'default' | 'small'; - hasTrailing: boolean; hasLeading: boolean; - - hasInlineTrailing: boolean; - hasInlineLeading: boolean; + hasTrailing: boolean; } function getSpecialSize(props: Pick) { @@ -19,11 +16,7 @@ function getSpecialSize(props: Pick) { }; } -const LabelStyled = styled.label<{ - hasLeading: boolean; - hasTrailing: boolean; - variant: 'small' | 'default'; -}>` +const LabelStyled = styled.label` padding: ${(props) => props.variant === 'default' ? props.hasTrailing