From 4fde6999ffad458b2eec9644352f5f82e9fa9bb1 Mon Sep 17 00:00:00 2001 From: Krzysztof_Lukawski Date: Thu, 17 Feb 2022 12:08:39 +0100 Subject: [PATCH 1/7] feat(text-input): add component --- src/models/base-input-props.model.ts | 9 ++++++ src/models/index.ts | 2 ++ src/models/input-size.model.ts | 1 + src/ui/index.ts | 1 + src/ui/text-input/index.ts | 1 + src/ui/text-input/text-input.component.tsx | 32 ++++++++++++++++++++++ src/ui/text-input/text-input.stories.tsx | 19 +++++++++++++ src/utils/text-based-input.utils.ts | 26 ++++++++++++++++++ 8 files changed, 91 insertions(+) create mode 100644 src/models/base-input-props.model.ts create mode 100644 src/models/input-size.model.ts create mode 100644 src/ui/text-input/index.ts create mode 100644 src/ui/text-input/text-input.component.tsx create mode 100644 src/ui/text-input/text-input.stories.tsx create mode 100644 src/utils/text-based-input.utils.ts diff --git a/src/models/base-input-props.model.ts b/src/models/base-input-props.model.ts new file mode 100644 index 0000000..7d2d1ba --- /dev/null +++ b/src/models/base-input-props.model.ts @@ -0,0 +1,9 @@ +import { InputSize } from '.'; + +export type BaseInputProps = { + size?: InputSize; + disabled?: boolean; + readOnly?: boolean; + error?: boolean; + className?: string; +}; diff --git a/src/models/index.ts b/src/models/index.ts index 00c67bc..3fa0eba 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1 +1,3 @@ export * from './queryable-component.model'; +export * from './base-input-props.model'; +export * from './input-size.model'; diff --git a/src/models/input-size.model.ts b/src/models/input-size.model.ts new file mode 100644 index 0000000..e73ce83 --- /dev/null +++ b/src/models/input-size.model.ts @@ -0,0 +1 @@ +export type InputSize = 'md' | 'sm'; diff --git a/src/ui/index.ts b/src/ui/index.ts index a9c7a65..7014993 100644 --- a/src/ui/index.ts +++ b/src/ui/index.ts @@ -4,3 +4,4 @@ export * from './pagination'; export * from './property-item'; export * from './table'; export * from './typography'; +export * from './text-input'; diff --git a/src/ui/text-input/index.ts b/src/ui/text-input/index.ts new file mode 100644 index 0000000..1b40755 --- /dev/null +++ b/src/ui/text-input/index.ts @@ -0,0 +1 @@ +export * from './text-input.component'; diff --git a/src/ui/text-input/text-input.component.tsx b/src/ui/text-input/text-input.component.tsx new file mode 100644 index 0000000..f9f6294 --- /dev/null +++ b/src/ui/text-input/text-input.component.tsx @@ -0,0 +1,32 @@ +import React, { ComponentPropsWithRef, forwardRef } from 'react'; +import clsx from 'clsx'; + +import { BaseInputProps } from '../../models'; +import { getTextBasedInputClasses } from '../../utils/text-based-input.utils'; + +type TextInputProps = BaseInputProps & ComponentPropsWithRef<'input'>; + +export const TextInput = forwardRef( + ({ disabled, readOnly, error, size, className, ...rest }, ref) => { + return ( + <> + + + ); + } +); diff --git a/src/ui/text-input/text-input.stories.tsx b/src/ui/text-input/text-input.stories.tsx new file mode 100644 index 0000000..c6d4a30 --- /dev/null +++ b/src/ui/text-input/text-input.stories.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; + +import { TextInput } from './text-input.component'; + +export default { + title: 'Atoms/TextInput', + component: TextInput, +} as ComponentMeta; + +export const Default: ComponentStory = () => ; + +export const Disabled: ComponentStory = () => ( + +); + +export const Readonly: ComponentStory = () => ( + +); diff --git a/src/utils/text-based-input.utils.ts b/src/utils/text-based-input.utils.ts new file mode 100644 index 0000000..d277265 --- /dev/null +++ b/src/utils/text-based-input.utils.ts @@ -0,0 +1,26 @@ +import clsx from 'clsx'; + +import { InputSize } from '../models'; + +type TextBasedInputClassProps = { + disabled?: boolean; + error?: boolean; + size?: InputSize; +}; + +export const getTextBasedInputClasses = ({ + disabled, + error, + size = 'md', +}: TextBasedInputClassProps) => + clsx( + 'appearance-none border rounded focus:outline-none placeholder-primary-300 bg-slate-100', + { + 'py-1 px-2 text-sm': size === 'sm', + 'py-3 px-4 text-base': size === 'md', + // 'text-primary-400': disabled, + // 'text-primary-500': !disabled, + // 'border-red-500 focus:ring-1 focus:ring-red-500': error, + 'border-primary-150 focus:shadow-primary-100': !error, + } + ); From 5fdb558e2ae915260d1bbca7a17938458a42344b Mon Sep 17 00:00:00 2001 From: Krzysztof_Lukawski Date: Thu, 17 Feb 2022 13:49:21 +0100 Subject: [PATCH 2/7] feat(text-input): add story --- src/ui/text-input/text-input.component.tsx | 6 ++++-- src/ui/text-input/text-input.stories.tsx | 20 +++++++++++++++++--- src/utils/text-based-input.utils.ts | 9 ++++++--- tailwind.config.js | 5 +++++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/ui/text-input/text-input.component.tsx b/src/ui/text-input/text-input.component.tsx index f9f6294..9a9f7f6 100644 --- a/src/ui/text-input/text-input.component.tsx +++ b/src/ui/text-input/text-input.component.tsx @@ -4,7 +4,8 @@ import clsx from 'clsx'; import { BaseInputProps } from '../../models'; import { getTextBasedInputClasses } from '../../utils/text-based-input.utils'; -type TextInputProps = BaseInputProps & ComponentPropsWithRef<'input'>; +type TextInputProps = Omit, 'size'> & + BaseInputProps; export const TextInput = forwardRef( ({ disabled, readOnly, error, size, className, ...rest }, ref) => { @@ -18,7 +19,8 @@ export const TextInput = forwardRef( aria-invalid={error || undefined} className={clsx( getTextBasedInputClasses({ - disabled: disabled || readOnly, + disabled, + readOnly, error, size, }), diff --git a/src/ui/text-input/text-input.stories.tsx b/src/ui/text-input/text-input.stories.tsx index c6d4a30..454acf4 100644 --- a/src/ui/text-input/text-input.stories.tsx +++ b/src/ui/text-input/text-input.stories.tsx @@ -8,12 +8,26 @@ export default { component: TextInput, } as ComponentMeta; -export const Default: ComponentStory = () => ; +export const Default: ComponentStory = () => ( + +); + +export const WithPlaceholder: ComponentStory = () => ( + +); + +export const Small: ComponentStory = () => ( + +); + +export const WithError: ComponentStory = () => ( + +); export const Disabled: ComponentStory = () => ( - + ); export const Readonly: ComponentStory = () => ( - + ); diff --git a/src/utils/text-based-input.utils.ts b/src/utils/text-based-input.utils.ts index d277265..62e0ec9 100644 --- a/src/utils/text-based-input.utils.ts +++ b/src/utils/text-based-input.utils.ts @@ -4,12 +4,14 @@ import { InputSize } from '../models'; type TextBasedInputClassProps = { disabled?: boolean; + readOnly?: boolean; error?: boolean; size?: InputSize; }; export const getTextBasedInputClasses = ({ disabled, + readOnly, error, size = 'md', }: TextBasedInputClassProps) => @@ -18,9 +20,10 @@ export const getTextBasedInputClasses = ({ { 'py-1 px-2 text-sm': size === 'sm', 'py-3 px-4 text-base': size === 'md', - // 'text-primary-400': disabled, - // 'text-primary-500': !disabled, - // 'border-red-500 focus:ring-1 focus:ring-red-500': error, 'border-primary-150 focus:shadow-primary-100': !error, + 'border-error-100 focus:shadow-error-100': error, + 'pointer-events-none': readOnly, + 'text-neutral-200': disabled, + 'text-black': !disabled, } ); diff --git a/tailwind.config.js b/tailwind.config.js index f0e7853..9435640 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -28,10 +28,15 @@ module.exports = { }, neutral: { 100: '#dfe0dd', + 200: '#636161', }, black: '#1C2B36', white: '#FFFFFF', }, + boxShadow: { + 'primary-100': '0px 0px 5px #45a3db', + 'error-100': '0px 0px 5px #e74c3c', + } }, }, plugins: [], From c949e155366831ad6363a9cd997f8ac71628b9ae Mon Sep 17 00:00:00 2001 From: Krzysztof_Lukawski Date: Thu, 17 Feb 2022 14:17:51 +0100 Subject: [PATCH 3/7] refactor(text-input): rewrite stories to utilize args --- src/ui/text-input/text-input.stories.tsx | 56 +++++++++++++++--------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/ui/text-input/text-input.stories.tsx b/src/ui/text-input/text-input.stories.tsx index 454acf4..7f0bd52 100644 --- a/src/ui/text-input/text-input.stories.tsx +++ b/src/ui/text-input/text-input.stories.tsx @@ -8,26 +8,40 @@ export default { component: TextInput, } as ComponentMeta; -export const Default: ComponentStory = () => ( - +const Template: ComponentStory = (args) => ( + ); -export const WithPlaceholder: ComponentStory = () => ( - -); - -export const Small: ComponentStory = () => ( - -); - -export const WithError: ComponentStory = () => ( - -); - -export const Disabled: ComponentStory = () => ( - -); - -export const Readonly: ComponentStory = () => ( - -); +export const Default = Template.bind({}); +Default.args = { + defaultValue: 'Default', +}; + +export const WithPlaceholder = Template.bind({}); +WithPlaceholder.args = { + placeholder: 'Placeholder', +}; + +export const Small = Template.bind({}); +Small.args = { + size: 'sm', + defaultValue: 'Small', +}; + +export const WithError = Template.bind({}); +WithError.args = { + error: true, + defaultValue: 'Error', +}; + +export const Disabled = Template.bind({}); +Disabled.args = { + disabled: true, + defaultValue: 'Disabled', +}; + +export const Readonly = Template.bind({}); +Readonly.args = { + readOnly: true, + defaultValue: 'Readonly', +}; From 3bd9362edbaab507b48a60d574823005feaceeaa Mon Sep 17 00:00:00 2001 From: Krzysztof_Lukawski Date: Fri, 18 Feb 2022 09:09:06 +0100 Subject: [PATCH 4/7] refactor(text-input): add lint rule and rename files --- .eslintrc | 1 + src/models/index.ts | 2 - src/models/input-size.model.ts | 1 - src/ui/input/index.ts | 2 + .../input/input.model.ts} | 2 +- src/ui/input/input.util.ts | 29 ++++++++++++ src/ui/text-input/text-input.component.tsx | 47 +++++++++---------- src/utils/text-based-input.utils.ts | 29 ------------ 8 files changed, 55 insertions(+), 58 deletions(-) delete mode 100644 src/models/input-size.model.ts create mode 100644 src/ui/input/index.ts rename src/{models/base-input-props.model.ts => ui/input/input.model.ts} (79%) create mode 100644 src/ui/input/input.util.ts diff --git a/.eslintrc b/.eslintrc index dfbc19f..1193c31 100644 --- a/.eslintrc +++ b/.eslintrc @@ -12,6 +12,7 @@ "no-nested-ternary": "error", "react/self-closing-comp": "warn", "react/button-has-type": "warn", + "arrow-body-style": "error", "jest/no-focused-tests": "error", "import/first": "error", "import/no-duplicates": "error", diff --git a/src/models/index.ts b/src/models/index.ts index 3fa0eba..00c67bc 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1,3 +1 @@ export * from './queryable-component.model'; -export * from './base-input-props.model'; -export * from './input-size.model'; diff --git a/src/models/input-size.model.ts b/src/models/input-size.model.ts deleted file mode 100644 index e73ce83..0000000 --- a/src/models/input-size.model.ts +++ /dev/null @@ -1 +0,0 @@ -export type InputSize = 'md' | 'sm'; diff --git a/src/ui/input/index.ts b/src/ui/input/index.ts new file mode 100644 index 0000000..5258f1f --- /dev/null +++ b/src/ui/input/index.ts @@ -0,0 +1,2 @@ +export * from './input.model'; +export * from './input.util'; diff --git a/src/models/base-input-props.model.ts b/src/ui/input/input.model.ts similarity index 79% rename from src/models/base-input-props.model.ts rename to src/ui/input/input.model.ts index 7d2d1ba..8be7ca1 100644 --- a/src/models/base-input-props.model.ts +++ b/src/ui/input/input.model.ts @@ -1,4 +1,4 @@ -import { InputSize } from '.'; +export type InputSize = 'md' | 'sm'; export type BaseInputProps = { size?: InputSize; diff --git a/src/ui/input/input.util.ts b/src/ui/input/input.util.ts new file mode 100644 index 0000000..05a52a8 --- /dev/null +++ b/src/ui/input/input.util.ts @@ -0,0 +1,29 @@ +import clsx from 'clsx'; + +import { InputSize } from './input.model'; + +type TextBasedInputClassProps = { + disabled?: boolean; + readOnly?: boolean; + error?: boolean; + size?: InputSize; +}; + +export const getTextBasedInputClasses = ({ + disabled, + readOnly, + error, + size = 'md', +}: TextBasedInputClassProps) => + clsx( + 'appearance-none border rounded focus:outline-none placeholder-primary-300 bg-slate-100', + { + 'py-1 px-2 text-sm': size === 'sm', + 'py-3 px-4 text-base': size === 'md', + 'border-primary-150 focus:shadow-primary-100': !error, + 'border-error-100 focus:shadow-error-100': error, + 'pointer-events-none': readOnly, + 'text-neutral-200': disabled, + 'text-black': !disabled, + } + ); diff --git a/src/ui/text-input/text-input.component.tsx b/src/ui/text-input/text-input.component.tsx index 9a9f7f6..99f31e1 100644 --- a/src/ui/text-input/text-input.component.tsx +++ b/src/ui/text-input/text-input.component.tsx @@ -1,34 +1,31 @@ import React, { ComponentPropsWithRef, forwardRef } from 'react'; import clsx from 'clsx'; -import { BaseInputProps } from '../../models'; -import { getTextBasedInputClasses } from '../../utils/text-based-input.utils'; +import { BaseInputProps, getTextBasedInputClasses } from '../input/'; type TextInputProps = Omit, 'size'> & BaseInputProps; export const TextInput = forwardRef( - ({ disabled, readOnly, error, size, className, ...rest }, ref) => { - return ( - <> - - - ); - } + ({ disabled, readOnly, error, size, className, ...rest }, ref) => ( + <> + + + ) ); diff --git a/src/utils/text-based-input.utils.ts b/src/utils/text-based-input.utils.ts index 62e0ec9..e69de29 100644 --- a/src/utils/text-based-input.utils.ts +++ b/src/utils/text-based-input.utils.ts @@ -1,29 +0,0 @@ -import clsx from 'clsx'; - -import { InputSize } from '../models'; - -type TextBasedInputClassProps = { - disabled?: boolean; - readOnly?: boolean; - error?: boolean; - size?: InputSize; -}; - -export const getTextBasedInputClasses = ({ - disabled, - readOnly, - error, - size = 'md', -}: TextBasedInputClassProps) => - clsx( - 'appearance-none border rounded focus:outline-none placeholder-primary-300 bg-slate-100', - { - 'py-1 px-2 text-sm': size === 'sm', - 'py-3 px-4 text-base': size === 'md', - 'border-primary-150 focus:shadow-primary-100': !error, - 'border-error-100 focus:shadow-error-100': error, - 'pointer-events-none': readOnly, - 'text-neutral-200': disabled, - 'text-black': !disabled, - } - ); From 4bc4902047e5688c35f6d76e7b0b565e0d2951da Mon Sep 17 00:00:00 2001 From: Krzysztof_Lukawski Date: Fri, 18 Feb 2022 09:19:56 +0100 Subject: [PATCH 5/7] refactor(components): remove build warn and errors --- src/utils/text-based-input.utils.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/utils/text-based-input.utils.ts diff --git a/src/utils/text-based-input.utils.ts b/src/utils/text-based-input.utils.ts deleted file mode 100644 index e69de29..0000000 From 0b2bb5ab1c8d9f4976ced7111502a61d79e96eb8 Mon Sep 17 00:00:00 2001 From: Krzysztof_Lukawski Date: Fri, 18 Feb 2022 10:04:24 +0100 Subject: [PATCH 6/7] refactor(text-input): remove fragment --- src/ui/text-input/text-input.component.tsx | 36 ++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/ui/text-input/text-input.component.tsx b/src/ui/text-input/text-input.component.tsx index 99f31e1..8cf4551 100644 --- a/src/ui/text-input/text-input.component.tsx +++ b/src/ui/text-input/text-input.component.tsx @@ -8,24 +8,22 @@ type TextInputProps = Omit, 'size'> & export const TextInput = forwardRef( ({ disabled, readOnly, error, size, className, ...rest }, ref) => ( - <> - - + ) ); From 64cfb6261777720562f90818d9153d2d1743143c Mon Sep 17 00:00:00 2001 From: Krzysztof_Lukawski Date: Wed, 23 Feb 2022 10:33:12 +0100 Subject: [PATCH 7/7] feature(text-input): add spec file --- src/ui/text-input/text-input.spec.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/ui/text-input/text-input.spec.tsx diff --git a/src/ui/text-input/text-input.spec.tsx b/src/ui/text-input/text-input.spec.tsx new file mode 100644 index 0000000..ad543eb --- /dev/null +++ b/src/ui/text-input/text-input.spec.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { axe } from 'jest-axe'; + +import { TextInput } from './text-input.component'; + +describe('Text-Input', () => { + test('renders an accessible text-input', async () => { + const { container } = render( + + ); + + expect(screen.getByRole('textbox')).toBeInTheDocument(); + expect(await axe(container)).toHaveNoViolations(); + }); +});