From 6e7385b118416094ee46bf72a0b519240afeac77 Mon Sep 17 00:00:00 2001 From: Vivian Phung Date: Mon, 13 May 2024 13:13:20 -0400 Subject: [PATCH] input forward ref react-hook-form --- .../src/components/shared/Input/Input.tsx | 192 ++++++++++-------- .../src/components/shared/Table/Table.tsx | 51 +++++ .../src/components/shared/Table/index.ts | 1 + .../id/settings/domains/add/Config.tsx | 56 ++--- .../src/stories/Components/Table.stories.tsx | 48 +++++ 5 files changed, 239 insertions(+), 109 deletions(-) create mode 100644 packages/frontend/src/components/shared/Table/Table.tsx create mode 100644 packages/frontend/src/components/shared/Table/index.ts create mode 100644 packages/frontend/src/stories/Components/Table.stories.tsx diff --git a/packages/frontend/src/components/shared/Input/Input.tsx b/packages/frontend/src/components/shared/Input/Input.tsx index e8252281..503e3d32 100644 --- a/packages/frontend/src/components/shared/Input/Input.tsx +++ b/packages/frontend/src/components/shared/Input/Input.tsx @@ -1,11 +1,18 @@ -import { ReactNode, useMemo } from 'react'; -import { ComponentPropsWithoutRef } from 'react'; -import { InputTheme, inputTheme } from './Input.theme'; +import { + forwardRef, + ReactNode, + useMemo, + ComponentPropsWithoutRef, +} from 'react'; +import { FieldValues, UseFormRegister } from 'react-hook-form'; + import { WarningIcon } from 'components/shared/CustomIcon'; import { cloneIcon } from 'utils/cloneIcon'; import { cn } from 'utils/classnames'; -export interface InputProps +import { InputTheme, inputTheme } from './Input.theme'; + +export interface InputProps extends InputTheme, Omit, 'size'> { label?: string; @@ -13,93 +20,108 @@ export interface InputProps leftIcon?: ReactNode; rightIcon?: ReactNode; helperText?: string; + + // react-hook-form optional register + register?: ReturnType>; } -export const Input = ({ - className, - label, - description, - leftIcon, - rightIcon, - helperText, - size, - state, - appearance, - ...props -}: InputProps) => { - const styleProps = useMemo( - () => ({ - size: size || 'md', - state: state || 'default', - appearance, // Pass appearance to inputTheme - }), - [size, state, appearance], - ); +const Input = forwardRef( + ( + { + className, + label, + description, + leftIcon, + rightIcon, + helperText, + register, + size, + state, + appearance, + ...props + }, + ref, + ) => { + const styleProps = useMemo( + () => ({ + size: size || 'md', + state: state || 'default', + appearance, // Pass appearance to inputTheme + }), + [size, state, appearance], + ); - const { - container: containerCls, - label: labelCls, - description: descriptionCls, - input: inputCls, - icon: iconCls, - iconContainer: iconContainerCls, - helperText: helperTextCls, - helperIcon: helperIconCls, - } = inputTheme({ ...styleProps }); + const { + container: containerCls, + label: labelCls, + description: descriptionCls, + input: inputCls, + icon: iconCls, + iconContainer: iconContainerCls, + helperText: helperTextCls, + helperIcon: helperIconCls, + } = inputTheme({ ...styleProps }); + + const renderLabels = useMemo(() => { + if (!label && !description) return null; + return ( +
+

{label}

+

{description}

+
+ ); + }, [labelCls, descriptionCls, label, description]); + + const renderLeftIcon = useMemo(() => { + return ( +
+ {cloneIcon(leftIcon, { className: iconCls(), 'aria-hidden': true })} +
+ ); + }, [cloneIcon, iconCls, iconContainerCls, leftIcon]); + + const renderRightIcon = useMemo(() => { + return ( +
+ {cloneIcon(rightIcon, { className: iconCls(), 'aria-hidden': true })} +
+ ); + }, [cloneIcon, iconCls, iconContainerCls, rightIcon]); + + const renderHelperText = useMemo(() => { + if (!helperText) return null; + return ( +
+ {state && + cloneIcon(, { + 'aria-hidden': true, + })} +

{helperText}

+
+ ); + }, [cloneIcon, state, helperIconCls, helperText, helperTextCls]); - const renderLabels = useMemo(() => { - if (!label && !description) return null; return ( -
-

{label}

-

{description}

+
+ {renderLabels} +
+ {leftIcon && renderLeftIcon} + + {rightIcon && renderRightIcon} +
+ {renderHelperText}
); - }, [labelCls, descriptionCls, label, description]); + }, +); - const renderLeftIcon = useMemo(() => { - return ( -
- {cloneIcon(leftIcon, { className: iconCls(), 'aria-hidden': true })} -
- ); - }, [cloneIcon, iconCls, iconContainerCls, leftIcon]); +Input.displayName = 'Input'; - const renderRightIcon = useMemo(() => { - return ( -
- {cloneIcon(rightIcon, { className: iconCls(), 'aria-hidden': true })} -
- ); - }, [cloneIcon, iconCls, iconContainerCls, rightIcon]); - - const renderHelperText = useMemo(() => { - if (!helperText) return null; - return ( -
- {state && - cloneIcon(, { - 'aria-hidden': true, - })} -

{helperText}

-
- ); - }, [cloneIcon, state, helperIconCls, helperText, helperTextCls]); - - return ( -
- {renderLabels} -
- {leftIcon && renderLeftIcon} - - {rightIcon && renderRightIcon} -
- {renderHelperText} -
- ); -}; +export { Input }; diff --git a/packages/frontend/src/components/shared/Table/Table.tsx b/packages/frontend/src/components/shared/Table/Table.tsx new file mode 100644 index 00000000..7f5fd5bc --- /dev/null +++ b/packages/frontend/src/components/shared/Table/Table.tsx @@ -0,0 +1,51 @@ +import React from 'react'; + +const Header: React.FC<{ children: React.ReactNode }> = ({ children }) => ( + {children} +); +const Body: React.FC<{ children: React.ReactNode }> = ({ children }) => ( + {children} +); +const Row: React.FC<{ children: React.ReactNode }> = ({ children }) => ( + {children} +); +const ColumnHeaderCell: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => ( + + {children} + +); +const RowHeaderCell: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => ( + + {children} + +); +const Cell: React.FC<{ children: React.ReactNode }> = ({ children }) => ( + + {children} + +); + +const Table: React.FC<{ children: React.ReactNode }> & { + Header: typeof Header; + Body: typeof Body; + Row: typeof Row; + ColumnHeaderCell: typeof ColumnHeaderCell; + RowHeaderCell: typeof RowHeaderCell; + Cell: typeof Cell; +} = ({ children }) => {children}
; + +Table.Header = Header; +Table.Body = Body; +Table.Row = Row; +Table.ColumnHeaderCell = ColumnHeaderCell; +Table.RowHeaderCell = RowHeaderCell; +Table.Cell = Cell; + +export { Table }; diff --git a/packages/frontend/src/components/shared/Table/index.ts b/packages/frontend/src/components/shared/Table/index.ts new file mode 100644 index 00000000..75193adc --- /dev/null +++ b/packages/frontend/src/components/shared/Table/index.ts @@ -0,0 +1 @@ +export * from './Table'; diff --git a/packages/frontend/src/pages/org-slug/projects/id/settings/domains/add/Config.tsx b/packages/frontend/src/pages/org-slug/projects/id/settings/domains/add/Config.tsx index e0b1edd2..ea850e94 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/settings/domains/add/Config.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/settings/domains/add/Config.tsx @@ -1,12 +1,13 @@ import toast from 'react-hot-toast'; import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; import { - Typography, Alert, Button, } from '@snowballtools/material-tailwind-react-fork'; import { useGQLClient } from '../../../../../../../context/GQLClientContext'; +import { Heading } from 'components/shared/Heading'; +import { Table } from 'components/shared/Table'; const Config = () => { const { id, orgSlug } = useParams(); @@ -38,37 +39,44 @@ const Config = () => { } }; + // TODO: Figure out DNS Provider if possible and update appropriatly return (
- Configure DNS - + + Setup domain name + +

Add the following records to your domain.  - Go to NameCheap ^ + Go to NameCheap - +

- - - - - - - - - - - - - - - - - - -
TypeNameValue
A@56.49.19.21
CNAMEwwwcname.snowballtools.xyz
+ + + + Type + Host + Value + + + + + + A + @ + 56.49.19.21 + + + + CNAME + www + cname.snowballtools.xyz + + +
^It can take up to 48 hours for these updates to reflect diff --git a/packages/frontend/src/stories/Components/Table.stories.tsx b/packages/frontend/src/stories/Components/Table.stories.tsx new file mode 100644 index 00000000..ce6aa33d --- /dev/null +++ b/packages/frontend/src/stories/Components/Table.stories.tsx @@ -0,0 +1,48 @@ +import { StoryObj, Meta } from '@storybook/react'; + +import { Table } from 'components/shared/Table'; + +const meta: Meta = { + title: 'Components/Table', + component: Table, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: ({}) => ( + + + + Full name + Email + Group + + + + + + Danilo Sousa + danilo@example.com + Developer + + + + Zahra Ambessa + zahra@example.com + Admin + + + + Jasper Eriksson + jasper@example.com + Developer + + +
+ ), + args: {}, +};