diff --git a/canon-docs/src/app/(docs)/components/field/page.mdx b/canon-docs/src/app/(docs)/components/field/page.mdx
new file mode 100644
index 0000000000..1526ce8c9f
--- /dev/null
+++ b/canon-docs/src/app/(docs)/components/field/page.mdx
@@ -0,0 +1,99 @@
+import { PropsTable } from '@/components/PropsTable';
+import { Snippet } from '@/components/Snippet';
+import { Tabs } from '@/components/Tabs';
+import { CodeBlock } from '@/components/CodeBlock';
+import { FieldSnippet } from '@/snippets/stories-snippets';
+import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
+import {
+ fieldRootPropDefs,
+ fieldLabelPropDefs,
+ fieldDescriptionPropDefs,
+ fieldErrorPropDefs,
+} from './props';
+
+# Field
+
+A wrapper around `Input` or `Select` component to add label, description and error messages..
+
+ }
+ code={` `}
+/>
+
+
+
+ Usage
+ Theming
+
+
+
+ Name
+
+ Visible on your profile
+
+`}
+ />
+
+
+ We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with
+ your brand. For additional flexibility, you can use the provided class names for each element listed below.
+
+
+
+
+`}
+ />
+
+
+
+## API reference
+
+
+
+### Field.Root
+
+Groups all parts of the field. Renders a `
` element.
+
+
+
+### Field.Label
+
+An accessible label that is automatically associated with the field control. Renders a `
` element.
+
+
+
+### Field.Description
+
+A paragraph with additional information about the field. Renders a `` element.
+
+
+
+### Field.Error
+
+An error message displayed if the field control fails validation. Renders a `
` element.
+
+
+
+## Examples
+
+### With Label and Description
+
+Here's a simple input with a label and description.
+
+
}
+ code={`
+ Name
+ Visible on your profile
+
+ `}
+/>
diff --git a/canon-docs/src/app/(docs)/components/field/props.ts b/canon-docs/src/app/(docs)/components/field/props.ts
new file mode 100644
index 0000000000..aaadafee50
--- /dev/null
+++ b/canon-docs/src/app/(docs)/components/field/props.ts
@@ -0,0 +1,69 @@
+import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
+import type { PropDef } from '../../../../utils/propDefs';
+
+export const fieldRootPropDefs: Record
= {
+ name: {
+ type: 'string',
+ responsive: false,
+ },
+ disabled: {
+ type: 'boolean',
+ responsive: false,
+ },
+ invalid: {
+ type: 'boolean',
+ responsive: false,
+ },
+ validate: {
+ type: 'enum',
+ values: ['(value) => string | string[] | null | Promise'],
+ responsive: false,
+ },
+ validationMode: {
+ type: 'enum',
+ values: ['onBlur', 'onChange'],
+ responsive: false,
+ },
+ validationDebounceTime: {
+ type: 'number',
+ responsive: false,
+ },
+ ...classNamePropDefs,
+ ...stylePropDefs,
+};
+
+export const fieldLabelPropDefs: Record = {
+ ...classNamePropDefs,
+ ...stylePropDefs,
+};
+
+export const fieldDescriptionPropDefs: Record = {
+ ...classNamePropDefs,
+ ...stylePropDefs,
+};
+
+export const fieldErrorPropDefs: Record = {
+ match: {
+ type: 'enum',
+ values: [
+ 'badInput',
+ 'customError',
+ 'patternMismatch',
+ 'rangeOverflow',
+ 'rangeUnderflow',
+ 'stepMismatch',
+ 'tooLong',
+ 'tooShort',
+ 'typeMismatch',
+ 'valid',
+ 'valueMissing',
+ ],
+ responsive: false,
+ },
+ forceShow: {
+ type: 'boolean',
+ responsive: false,
+ },
+ ...classNamePropDefs,
+ ...stylePropDefs,
+};
diff --git a/canon-docs/src/app/(docs)/components/text-field/page.mdx b/canon-docs/src/app/(docs)/components/input/page.mdx
similarity index 51%
rename from canon-docs/src/app/(docs)/components/text-field/page.mdx
rename to canon-docs/src/app/(docs)/components/input/page.mdx
index bd5fa31025..0ecaaa5409 100644
--- a/canon-docs/src/app/(docs)/components/text-field/page.mdx
+++ b/canon-docs/src/app/(docs)/components/input/page.mdx
@@ -2,19 +2,19 @@ import { PropsTable } from '@/components/PropsTable';
import { Snippet } from '@/components/Snippet';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
-import { TextFieldSnippet } from '@/snippets/stories-snippets';
+import { InputSnippet } from '@/snippets/stories-snippets';
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
import { inputPropDefs } from './props';
-# TextField
+# Input
-A text field component for your forms.
+A input component tfor your forms.
}
- code={` `}
+ preview={ }
+ code={` `}
/>
@@ -24,9 +24,9 @@ A text field component for your forms.
+
`}
/>
@@ -34,40 +34,30 @@ A text field component for your forms.
We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with
your brand. For additional flexibility, you can use the provided class names for each element listed below.
`}
+ code={` `}
/>
## API reference
+
+
## Examples
### Sizes
-We support two different sizes: `small`, `medium`.
+Here's a simple input with a label and description.
}
- code={`
-
-
- `}
-/>
-
-### With description
-
-Here's a simple TextField with a description.
-
- }
- code={` `}
+ preview={ }
+ code={`
+
+
+ `}
/>
diff --git a/canon-docs/src/app/(docs)/components/text-field/props.ts b/canon-docs/src/app/(docs)/components/input/props.ts
similarity index 100%
rename from canon-docs/src/app/(docs)/components/text-field/props.ts
rename to canon-docs/src/app/(docs)/components/input/props.ts
diff --git a/canon-docs/src/snippets/stories-snippets.tsx b/canon-docs/src/snippets/stories-snippets.tsx
index 3b7834eea0..9dec825ad2 100644
--- a/canon-docs/src/snippets/stories-snippets.tsx
+++ b/canon-docs/src/snippets/stories-snippets.tsx
@@ -5,11 +5,12 @@ import * as BoxStories from '../../../packages/canon/src/components/Box/Box.stor
import * as ButtonStories from '../../../packages/canon/src/components/Button/Button.stories';
import * as CheckboxStories from '../../../packages/canon/src/components/Checkbox/Checkbox.stories';
import * as ContainerStories from '../../../packages/canon/src/components/Container/Container.stories';
-import * as TextFieldStories from '../../../packages/canon/src/components/TextField/TextField.stories';
+import * as FieldStories from '../../../packages/canon/src/components/Field/Field.stories';
import * as GridStories from '../../../packages/canon/src/components/Grid/Grid.stories';
import * as HeadingStories from '../../../packages/canon/src/components/Heading/Heading.stories';
import * as IconButtonStories from '../../../packages/canon/src/components/IconButton/IconButton.stories';
import * as IconStories from '../../../packages/canon/src/components/Icon/Icon.stories';
+import * as InputStories from '../../../packages/canon/src/components/Input/Input.stories';
import * as TextStories from '../../../packages/canon/src/components/Text/Text.stories';
import * as FlexStories from '../../../packages/canon/src/components/Flex/Flex.stories';
import * as SelectStories from '../../../packages/canon/src/components/Select/Select.stories';
@@ -61,12 +62,12 @@ export const FlexSnippet = ({ story }: { story: keyof typeof FlexStories }) => {
return StoryComponent ? : null;
};
-export const TextFieldSnippet = ({
+export const FieldSnippet = ({
story,
}: {
- story: keyof typeof TextFieldStories;
+ story: keyof typeof FieldStories;
}) => {
- const stories = composeStories(TextFieldStories);
+ const stories = composeStories(FieldStories);
const StoryComponent = stories[story as keyof typeof stories];
return StoryComponent ? : null;
@@ -108,6 +109,17 @@ export const IconSnippet = ({ story }: { story: keyof typeof IconStories }) => {
return StoryComponent ? : null;
};
+export const InputSnippet = ({
+ story,
+}: {
+ story: keyof typeof InputStories;
+}) => {
+ const stories = composeStories(InputStories);
+ const StoryComponent = stories[story as keyof typeof stories];
+
+ return StoryComponent ? : null;
+};
+
export const TextSnippet = ({ story }: { story: keyof typeof TextStories }) => {
const stories = composeStories(TextStories);
const StoryComponent = stories[story as keyof typeof stories];
diff --git a/canon-docs/src/utils/data.ts b/canon-docs/src/utils/data.ts
index fd4625cd20..c253089022 100644
--- a/canon-docs/src/utils/data.ts
+++ b/canon-docs/src/utils/data.ts
@@ -76,6 +76,11 @@ export const components: Page[] = [
slug: 'checkbox',
status: 'alpha',
},
+ {
+ title: 'Field',
+ slug: 'field',
+ status: 'alpha',
+ },
{
title: 'Heading',
slug: 'heading',
@@ -91,6 +96,11 @@ export const components: Page[] = [
slug: 'icon-button',
status: 'alpha',
},
+ {
+ title: 'Input',
+ slug: 'input',
+ status: 'alpha',
+ },
{
title: 'Select',
slug: 'select',
@@ -106,11 +116,6 @@ export const components: Page[] = [
slug: 'text',
status: 'alpha',
},
- {
- title: 'TextField',
- slug: 'text-field',
- status: 'alpha',
- },
];
export type ScreenSize = {
diff --git a/packages/canon/src/components/TextField/TextField.stories.tsx b/packages/canon/src/components/TextField/TextField.stories.tsx
index ca33c28020..dd5558437b 100644
--- a/packages/canon/src/components/TextField/TextField.stories.tsx
+++ b/packages/canon/src/components/TextField/TextField.stories.tsx
@@ -33,9 +33,6 @@ export const Default: Story = {
args: {
name: 'url',
placeholder: 'Enter a URL',
- style: {
- maxWidth: '300px',
- },
},
};
@@ -74,7 +71,7 @@ export const Sizes: Story = {
description: 'Description',
},
render: args => (
-
+
diff --git a/packages/canon/src/components/TextField/TextField.tsx b/packages/canon/src/components/TextField/TextField.tsx
index d4c95ae8b5..ccea9e8c65 100644
--- a/packages/canon/src/components/TextField/TextField.tsx
+++ b/packages/canon/src/components/TextField/TextField.tsx
@@ -31,7 +31,6 @@ export const TextField = forwardRef(
label,
description,
name,
- style,
...rest
} = props;
@@ -39,11 +38,7 @@ export const TextField = forwardRef(
const responsiveSize = useResponsiveValue(size);
return (
-
+
{label && (
{label}
)}