Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TextInput] Create new component #760

Merged
merged 2 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/data/api/text-input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"props": {
"className": { "type": { "name": "union", "description": "func<br>&#124;&nbsp;string" } },
"render": { "type": { "name": "union", "description": "element<br>&#124;&nbsp;func" } }
},
"name": "TextInput",
"imports": ["import { TextInput } from '@base_ui/react/TextInput';"],
"classes": [],
"spread": true,
"themeDefaultProps": true,
"muiName": "TextInput",
"forwardsRefTo": "HTMLInputElement",
"filename": "/packages/mui-base/src/TextInput/TextInput.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/components/react-text-input/\">Text Input</a></li></ul>",
"cssComponent": false
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
'use client';
import * as React from 'react';
import { Field } from '@base_ui/react/Field';
import { TextInput } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

export default function UnstyledFieldIntroduction() {
return (
<FieldRoot validate={(value) => (value === 'admin' ? 'Name not allowed' : null)}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<Field.Label>Name</Field.Label>
<FieldControl required pattern="[a-zA-Z0-9]+" />
<Input required pattern="[a-zA-Z0-9]+" />
</div>
<Field.Validity>
{({ validity, value }) => {
Expand Down Expand Up @@ -40,7 +41,7 @@ const FieldRoot = styled(Field.Root)`
width: 275px;
`;

const FieldControl = styled(Field.Control)`
const Input = styled(TextInput)`
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
'use client';
import * as React from 'react';
import { Field } from '@base_ui/react/Field';
import { TextInput } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

export default function UnstyledFieldIntroduction() {
return (
<FieldRoot validate={(value) => (value === 'admin' ? 'Name not allowed' : null)}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<Field.Label>Name</Field.Label>
<FieldControl required pattern="[a-zA-Z0-9]+" />
<Input required pattern="[a-zA-Z0-9]+" />
</div>
<Field.Validity>
{({ validity, value }) => {
Expand Down Expand Up @@ -40,7 +41,7 @@ const FieldRoot = styled(Field.Root)`
width: 275px;
`;

const FieldControl = styled(Field.Control)`
const Input = styled(TextInput)`
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
Expand Down
5 changes: 3 additions & 2 deletions docs/data/components/field/UnstyledFieldPassword.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';
import * as React from 'react';
import { Field } from '@base_ui/react/Field';
import { TextInput } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

function validate(value) {
Expand Down Expand Up @@ -31,7 +32,7 @@ export default function UnstyledFieldPassword() {
return (
<FieldRoot invalid={errors.length > 0}>
<Field.Label>Password</Field.Label>
<FieldControl
<Input
type="password"
value={value}
onChange={(event) => setValue(event.currentTarget.value)}
Expand All @@ -51,7 +52,7 @@ const FieldRoot = styled(Field.Root)`
width: 275px;
`;

const FieldControl = styled(Field.Control)`
const Input = styled(TextInput)`
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
Expand Down
5 changes: 3 additions & 2 deletions docs/data/components/field/UnstyledFieldPassword.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';
import * as React from 'react';
import { Field } from '@base_ui/react/Field';
import { TextInput } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

function validate(value: string) {
Expand Down Expand Up @@ -31,7 +32,7 @@ export default function UnstyledFieldPassword() {
return (
<FieldRoot invalid={errors.length > 0}>
<Field.Label>Password</Field.Label>
<FieldControl
<Input
type="password"
value={value}
onChange={(event) => setValue(event.currentTarget.value)}
Expand All @@ -51,7 +52,7 @@ const FieldRoot = styled(Field.Root)`
width: 275px;
`;

const FieldControl = styled(Field.Control)`
const Input = styled(TextInput)`
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<FieldRoot invalid={errors.length > 0}>
<Field.Label>Password</Field.Label>
<FieldControl
<Input
type="password"
value={value}
onChange={(event) => setValue(event.currentTarget.value)}
Expand Down
5 changes: 3 additions & 2 deletions docs/data/components/field/UnstyledFieldServerError.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';
import * as React from 'react';
import { Field } from '@base_ui/react/Field';
import { TextInput } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

export default function UnstyledFieldServerError() {
Expand Down Expand Up @@ -40,7 +41,7 @@ export default function UnstyledFieldServerError() {
<form onSubmit={handleSubmit} noValidate>
<FieldRoot invalid={error} name="email">
<Field.Label>Email address</Field.Label>
<FieldControl
<Input
ref={controlRef}
type="email"
required
Expand Down Expand Up @@ -89,7 +90,7 @@ const FieldRoot = styled(Field.Root)`
width: 275px;
`;

const FieldControl = styled(Field.Control)`
const Input = styled(TextInput)`
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
Expand Down
5 changes: 3 additions & 2 deletions docs/data/components/field/UnstyledFieldServerError.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';
import * as React from 'react';
import { Field } from '@base_ui/react/Field';
import { TextInput } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

type Status = 'initial' | 'loading' | 'success' | 'error';
Expand Down Expand Up @@ -42,7 +43,7 @@ export default function UnstyledFieldServerError() {
<form onSubmit={handleSubmit} noValidate>
<FieldRoot invalid={error} name="email">
<Field.Label>Email address</Field.Label>
<FieldControl
<Input
ref={controlRef}
type="email"
required
Expand Down Expand Up @@ -91,7 +92,7 @@ const FieldRoot = styled(Field.Root)`
width: 275px;
`;

const FieldControl = styled(Field.Control)`
const Input = styled(TextInput)`
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
Expand Down
4 changes: 2 additions & 2 deletions docs/data/components/field/field.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ packageName: '@base_ui/react'
Fields are implemented using a collection of related components:

- `<Field.Root />` is a top-level component that wraps all other components.
- `<Field.Control />` renders the control when not using a native Base UI input component.
- `<Field.Control />` renders a control when not using a native Base UI input component.
- `<Field.Label />` renders a label for the control.
- `<Field.Description />` renders an optional description for the control to provide additional information.
- `<Field.Error />` renders error messages for the control.
Expand Down Expand Up @@ -54,7 +54,7 @@ All Base UI input components are aware of Base UI's `Field` component. The lab
</Field.Root>
```

When using a native control like `input` or a custom component which is not aware of Base UI's `Field`, use `Field.Control`:
When using a custom component which is not aware of Base UI's `Field`, use `Field.Control`:

```jsx
<Field.Root>
Expand Down
7 changes: 4 additions & 3 deletions docs/data/components/form/FormIntroduction/system/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as React from 'react';
import { Form } from '@base_ui/react/Form';
import { Fieldset } from '@base_ui/react/Fieldset';
import { Field } from '@base_ui/react/Field';
import { TextInput } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

export default function FormIntroduction() {
Expand Down Expand Up @@ -53,12 +54,12 @@ export default function FormIntroduction() {
</p>
<Field.Root name="username">
<Field.Label>Username</Field.Label>
<FieldControl required />
<Input required />
<FieldError />
</Field.Root>
<Field.Root name="password">
<Field.Label>Password</Field.Label>
<FieldControl type="password" required />
<Input type="password" required />
<FieldError />
</Field.Root>
</FieldsetRoot>
Expand All @@ -78,7 +79,7 @@ const FormRoot = styled(Form.Root)`
width: 275px;
`;

const FieldControl = styled(Field.Control)`
const Input = styled(TextInput)`
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
Expand Down
7 changes: 4 additions & 3 deletions docs/data/components/form/FormIntroduction/system/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as React from 'react';
import { Form } from '@base_ui/react/Form';
import { Fieldset } from '@base_ui/react/Fieldset';
import { Field } from '@base_ui/react/Field';
import { TextInput } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

type Status = 'initial' | 'loading' | 'success' | 'error';
Expand Down Expand Up @@ -55,12 +56,12 @@ export default function FormIntroduction() {
</p>
<Field.Root name="username">
<Field.Label>Username</Field.Label>
<FieldControl required />
<Input required />
<FieldError />
</Field.Root>
<Field.Root name="password">
<Field.Label>Password</Field.Label>
<FieldControl type="password" required />
<Input type="password" required />
<FieldError />
</Field.Root>
</FieldsetRoot>
Expand All @@ -80,7 +81,7 @@ const FormRoot = styled(Form.Root)`
width: 275px;
`;

const FieldControl = styled(Field.Control)`
const Input = styled(TextInput)`
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client';
import * as React from 'react';
import { TextInput as TextInputPrimitive } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

export default function TextFieldIntroduction() {
return <TextInput />;
}

const TextInput = styled(TextInputPrimitive)`
border: 1px solid #ccc;
border-radius: 4px;
padding: 8px;
font-size: 16px;
width: 200px;

&:focus {
outline: 0;
border-color: #0070f3;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client';
import * as React from 'react';
import { TextInput as TextInputPrimitive } from '@base_ui/react/TextInput';
import { styled } from '@mui/system';

export default function TextFieldIntroduction() {
return <TextInput />;
}

const TextInput = styled(TextInputPrimitive)`
border: 1px solid #ccc;
border-radius: 4px;
padding: 8px;
font-size: 16px;
width: 200px;

&:focus {
outline: 0;
border-color: #0070f3;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<TextInput />
28 changes: 28 additions & 0 deletions docs/data/components/text-input/text-input.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
productId: base-ui
title: React TextInput component
description: Text Input is a UI element that lets users input single line text.
components: TextInput
githubLabel: 'component: text-input'
packageName: '@base_ui/react'
---

# Text Input

<Description />

<ComponentLinkHeader design={false} />

<Demo demo="TextInputIntroduction" defaultCodeOpen="false" bg="gradient" />

## Installation

<InstallationInstructions componentName="TextInput" />

## Anatomy

`<TextInput />` renders an `<input>`, enhanced with field context when placed inside a [`Field`](/components/react-field/).

```tsx
<TextInput />
```
1 change: 1 addition & 0 deletions docs/data/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const pages: readonly RouteMetadata[] = [
{ pathname: '/components/react-slider', title: 'Slider' },
{ pathname: '/components/react-switch', title: 'Switch' },
{ pathname: '/components/react-tabs', title: 'Tabs' },
{ pathname: '/components/react-text-input', title: 'Text Input' },
{ pathname: '/components/react-tooltip', title: 'Tooltip' },
],
},
Expand Down
10 changes: 10 additions & 0 deletions docs/data/translations/api-docs/text-input/text-input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"componentDescription": "",
"propDescriptions": {
"className": {
"description": "Class names applied to the element or a function that returns them based on the component&#39;s state."
},
"render": { "description": "A function to customize rendering of the component." }
},
"classDescriptions": {}
}
4 changes: 2 additions & 2 deletions packages/mui-base/src/Field/Control/FieldControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const FieldControl = React.forwardRef(function FieldControl(
ownerState: fieldOwnerState,
name: fieldName,
disabled: fieldDisabled,
} = useFieldRootContext(false);
} = useFieldRootContext();

const disabled = fieldDisabled || disabledProp;
const name = fieldName ?? nameProp;
Expand Down Expand Up @@ -77,7 +77,7 @@ const FieldControl = React.forwardRef(function FieldControl(
namespace FieldControl {
export type OwnerState = FieldRoot.OwnerState;

export interface Props extends BaseUIComponentProps<'input', OwnerState> {
export interface Props extends BaseUIComponentProps<'input' | 'textarea' | 'select', OwnerState> {
/**
* Callback fired when the `value` changes. Use when controlled.
*/
Expand Down
13 changes: 13 additions & 0 deletions packages/mui-base/src/TextInput/TextInput.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from 'react';
import { TextInput } from '@base_ui/react/TextInput';
import { createRenderer } from '@mui/internal-test-utils';
import { describeConformance } from '../../test/describeConformance';

describe('<TextInput />', () => {
const { render } = createRenderer();

describeConformance(<TextInput />, () => ({
refInstanceof: window.HTMLInputElement,
render,
}));
});
Loading