Skip to content

Commit

Permalink
feat: Input and Label primitives (#4384)
Browse files Browse the repository at this point in the history
Co-authored-by: Danny Banks <djb@amazon.com>
Co-authored-by: Heather Buchel <buchel@amazon.com>
  • Loading branch information
3 people committed Aug 29, 2023
1 parent c35fe91 commit 2407ac2
Show file tree
Hide file tree
Showing 47 changed files with 1,941 additions and 32 deletions.
15 changes: 15 additions & 0 deletions .changeset/three-baboons-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@aws-amplify/ui": patch
"@aws-amplify/ui-react": patch
---

feat: Input and Label primitives

```jx
export const InputLabelExample = () => (
<>
<Label htmlFor="first_name">First Name:</Label>
<Input id="first_name" name="first_name" />
</>
);
```
16 changes: 16 additions & 0 deletions docs/__tests__/__snapshots__/cssvars-table.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3410,6 +3410,22 @@ exports[`CSS Variables Table 1`] = `
\\"variable\\": \\"--amplify-components-inappmessaging-header-font-weight\\",
\\"value\\": \\"var(--amplify-font-weights-extrabold)\\"
},
{
\\"variable\\": \\"--amplify-components-input-border-color\\",
\\"value\\": \\"var(--amplify-components-fieldcontrol-border-color)\\"
},
{
\\"variable\\": \\"--amplify-components-input-color\\",
\\"value\\": \\"var(--amplify-components-fieldcontrol-color)\\"
},
{
\\"variable\\": \\"--amplify-components-input-focus-border-color\\",
\\"value\\": \\"var(--amplify-components-fieldcontrol-focus-border-color)\\"
},
{
\\"variable\\": \\"--amplify-components-input-font-size\\",
\\"value\\": \\"var(--amplify-components-fieldcontrol-font-size)\\"
},
{
\\"variable\\": \\"--amplify-components-link-active-color\\",
\\"value\\": \\"var(--amplify-colors-font-active)\\"
Expand Down
430 changes: 430 additions & 0 deletions docs/__tests__/__snapshots__/props-table.test.ts.snap

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/__tests__/__snapshots__/sitemap.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ exports[`Sitemap Snapshot 1`] = `
/react/components/highlightmatch,
/react/components/icon,
/react/components/image,
/react/components/input,
/react/components/label,
/react/components/link,
/react/components/loader,
/react/components/menu,
Expand Down
6 changes: 3 additions & 3 deletions docs/src/components/AppDirectoryAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ const AppDirectoryAlert = () => (
<Alert variation="info" role="none">
<Text>
Next.js 13.4+ introduces{' '}
<Link href="https://nextjs.org/docs/app/building-your-application/routing#the-app-directory">
<Link href="https://nextjs.org/docs/app/building-your-application/routing#the-app-router">
App Router
</Link>{' '}
with the usage of{' '}
<Link href="https://nextjs.org/docs/getting-started/react-essentials#server-components">
<Link href="https://nextjs.org/docs/app/building-your-application/rendering/server-components">
Server Components.
</Link>{' '}
Amplify UI components are interactive and designed to work on the client
side. To use them inside of Server Components you must wrap them in a
Client Component with <code>&quot;use client&quot;</code>. For more info,
visit{' '}
<Link href="https://nextjs.org/docs/getting-started/react-essentials#third-party-packages">
<Link href="https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#using-third-party-packages-and-providers">
Next.js third party package documentation.
</Link>
</Text>
Expand Down
17 changes: 16 additions & 1 deletion docs/src/data/links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
MdCheckCircle,
MdHighlight,
MdChevronRight,
MdLabel,
} from 'react-icons/md';

export interface ComponentNavItem {
Expand Down Expand Up @@ -278,6 +279,20 @@ export const inputComponents: ComponentNavItem[] = [
platforms: ['react'],
icon: MdSearch,
},
{
href: '/components/input',
label: 'Input',
body: `Input primitive allows creating interactive form controls`,
platforms: ['react'],
icon: MdInput,
},
{
href: '/components/label',
label: 'Label',
body: `Label primitive enables captioning a user interface item`,
platforms: ['react'],
icon: MdLabel,
},
{
href: '/components/textareafield',
label: 'TextArea Field',
Expand All @@ -288,7 +303,7 @@ export const inputComponents: ComponentNavItem[] = [
{
href: '/components/textfield',
label: 'Text Field',
body: `The TextField form primitive can be used allow users to input text content.`,
body: `The TextField form primitive allows users to input text content.`,
platforms: ['react'],
icon: MdInput,
},
Expand Down
89 changes: 89 additions & 0 deletions docs/src/pages/[platform]/components/input/InputPropControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {
InputProps,
TextField,
SelectField,
SwitchField,
Flex,
} from '@aws-amplify/ui-react';
import * as React from 'react';

export interface InputPropControlsProps extends InputProps {
setVariation: (value: React.SetStateAction<InputProps['variation']>) => void;
setSize: (value: React.SetStateAction<InputProps['size']>) => void;
setPlaceholder: (
value: React.SetStateAction<InputProps['placeholder']>
) => void;
setHasError: (value: React.SetStateAction<InputProps['hasError']>) => void;
setIsDisabled: (
value: React.SetStateAction<InputProps['isDisabled']>
) => void;
}

interface InputPropControlsInterface {
(props: InputPropControlsProps): JSX.Element;
}

export const InputPropControls: InputPropControlsInterface = ({
variation,
setVariation,
size,
setSize,
placeholder,
setPlaceholder,
hasError,
setHasError,
isDisabled,
setIsDisabled,
}) => {
return (
<Flex direction="column">
<SelectField
label="variation"
value={variation}
onChange={(event) =>
setVariation(event.target.value as InputProps['variation'])
}
>
<option value="">default</option>
<option value="quiet">quiet</option>
</SelectField>

<SelectField
label="size"
value={size}
defaultValue="default"
onChange={(event) => setSize(event.target.value as InputProps['size'])}
>
<option value="small">small</option>
<option value="default">default</option>
<option value="large">large</option>
</SelectField>

<TextField
label="placeholder"
value={placeholder as string}
onChange={(event) =>
setPlaceholder(event.target.value as InputProps['placeholder'])
}
/>

<SwitchField
label="hasError"
isChecked={hasError}
labelPosition="end"
onChange={(event) => {
setHasError(event.target.checked as InputProps['hasError']);
}}
/>

<SwitchField
label="isDisabled"
isChecked={isDisabled}
labelPosition="end"
onChange={(event) => {
setIsDisabled(event.target.checked as InputProps['isDisabled']);
}}
/>
</Flex>
);
};
45 changes: 45 additions & 0 deletions docs/src/pages/[platform]/components/input/demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as React from 'react';
import { Input, InputProps } from '@aws-amplify/ui-react';
import { Demo } from '@/components/Demo';
import { InputPropControls } from './InputPropControls';
import { useInputProps } from './useInputProps';
import { demoState } from '@/utils/demoState';
import { getPropString } from '../utils/getPropString';

const propsToCode = (props) => {
return (
`<Input` +
getPropString(props.variation, 'variation') +
getPropString(props.size, 'size') +
getPropString(props.placeholder, 'placeholder') +
(props.hasError ? '\n hasError' : '') +
(props.isDisabled ? '\n isDisabled' : '') +
`\n/>`
);
};

const defaultInputProps: InputProps = {
placeholder: 'Baggins',
};

export const InputDemo = () => {
const InputProps = useInputProps(
(demoState.get('Input') as InputProps) || defaultInputProps
);

return (
<Demo
code={propsToCode(InputProps)}
propControls={<InputPropControls {...InputProps} />}
>
<Input
aria-label="Demo input"
variation={InputProps.variation}
size={InputProps.size}
placeholder={InputProps.placeholder}
hasError={InputProps.hasError}
isDisabled={InputProps.isDisabled}
/>
</Demo>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Input, Label } from '@aws-amplify/ui-react';

export const DefaultInputExample = () => (
<>
<Label htmlFor="first_name">First Name:</Label>
<Input id="first_name" name="first_name" />
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Button, Flex, Input, Label } from '@aws-amplify/ui-react';

export const DefaultRequiredInputExample = () => {
return (
<Flex as="form" direction="column" width="20rem">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" isRequired />
<Button type="submit">Submit</Button>
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Input, Label } from '@aws-amplify/ui-react';

export const InputEventHandlersExample = () => (
<>
<Label htmlFor="events">Event handlers</Label>
<Input
id="events"
onSelect={(e) => console.info('onSelect fired:', e.currentTarget.value)}
onInput={(e) => console.info('onInput fired:', e.currentTarget.value)}
onChange={(e) => console.info('onChange fired:', e.currentTarget.value)}
onCopy={(e) => console.info('onCopy fired:', e.currentTarget.value)}
onPaste={(e) => console.info('onPaste fired:', e.currentTarget.value)}
onCut={(e) => console.info('onCut fired:', e.currentTarget.value)}
/>
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Flex, Input, Label } from '@aws-amplify/ui-react';

export const InputSizeExample = () => {
return (
<Flex direction="column">
<Label htmlFor="small">Small</Label>
<Input id="small" size="small" width="50%" />
<Label htmlFor="default">Default</Label>
<Input id="default" width="75%" />
<Label htmlFor="large">Large</Label>
<Input id="large" size="large" width="100%" />
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Flex, Input, Label } from '@aws-amplify/ui-react';

export const InputStatesExample = () => {
return (
<Flex direction="column" gap="1rem">
<Label htmlFor="disabled">Disabled</Label>
<Input id="disabled" defaultValue="Disabled" isDisabled />
<Label htmlFor="readonly">Readonly</Label>
<Input id="readonly" defaultValue="You can't edit me!" isReadOnly />
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Text, Input, Label, useTheme } from '@aws-amplify/ui-react';

export const InputStylePropsExample = () => {
const { tokens } = useTheme();
return (
<>
<Label htmlFor="name">
<Text
fontWeight={tokens.fontWeights.bold}
fontSize={tokens.fontSizes.xl}
>
Name:
</Text>
</Label>
<Input
id="name"
fontWeight={tokens.fontWeights.bold}
fontSize={tokens.fontSizes.xl}
padding="xl"
border={`1px solid ${tokens.colors.brand.primary[60]}`}
/>
<Label htmlFor="special">Special Field</Label>
<Input
id="special"
backgroundColor="brand.primary.10"
border={`1px solid ${tokens.colors.brand.primary[60]}`}
/>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Input, Label, ThemeProvider, Theme } from '@aws-amplify/ui-react';

const theme: Theme = {
name: 'input-theme',
tokens: {
components: {
input: {
color: { value: '{colors.blue.90}' },
_focus: {
borderColor: { value: '{colors.blue.40}' },
},
},
},
},
};

export const InputThemeExample = () => (
<ThemeProvider theme={theme} colorMode="light">
<Label htmlFor="name">Name</Label>
<Input id="name" />
</ThemeProvider>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import { Input, Label } from '@aws-amplify/ui-react';

export const InputValidationErrorExample = () => {
const [hasError, setHasError] = React.useState(true);

const validateUsername = (e) => {
const containsDigit = /\d/.test(e.currentTarget.value);
setHasError(!containsDigit);
};

return (
<>
<Label htmlFor="username">Username</Label>
<Input id="username" hasError={hasError} onChange={validateUsername} />
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Input, Label } from '@aws-amplify/ui-react';

export const InputVariationExample = () => {
return (
<>
<Label htmlFor="Default">Default</Label>
<Input id="default" />
<Label htmlFor="Quiet">Default</Label>
<Input id="quiet" variation="quiet" />
</>
);
};
Loading

0 comments on commit 2407ac2

Please sign in to comment.