diff --git a/docs/data/api/text-field.json b/docs/data/api/text-field.json new file mode 100644 index 0000000000..b43f106f19 --- /dev/null +++ b/docs/data/api/text-field.json @@ -0,0 +1,14 @@ +{ + "props": {}, + "name": "TextField", + "imports": ["import { TextField } from '@base_ui/react/TextField';"], + "classes": [], + "spread": true, + "themeDefaultProps": true, + "muiName": "TextField", + "forwardsRefTo": "HTMLInputElement", + "filename": "/packages/mui-base/src/TextField/TextField.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/data/api/text-input.json b/docs/data/api/text-input.json new file mode 100644 index 0000000000..f46e551d5e --- /dev/null +++ b/docs/data/api/text-input.json @@ -0,0 +1,14 @@ +{ + "props": {}, + "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": "", + "cssComponent": false +} diff --git a/docs/data/components/field/UnstyledFieldIntroduction/system/index.js b/docs/data/components/field/UnstyledFieldIntroduction/system/index.js index a1dd1e4513..1b380121f1 100644 --- a/docs/data/components/field/UnstyledFieldIntroduction/system/index.js +++ b/docs/data/components/field/UnstyledFieldIntroduction/system/index.js @@ -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 UnstyledFieldIntroduction() { @@ -8,7 +9,7 @@ export default function UnstyledFieldIntroduction() { (value === 'admin' ? 'Name not allowed' : null)}>
Name - +
{({ validity, value }) => { @@ -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%; diff --git a/docs/data/components/field/UnstyledFieldIntroduction/system/index.tsx b/docs/data/components/field/UnstyledFieldIntroduction/system/index.tsx index a1dd1e4513..1b380121f1 100644 --- a/docs/data/components/field/UnstyledFieldIntroduction/system/index.tsx +++ b/docs/data/components/field/UnstyledFieldIntroduction/system/index.tsx @@ -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 UnstyledFieldIntroduction() { @@ -8,7 +9,7 @@ export default function UnstyledFieldIntroduction() { (value === 'admin' ? 'Name not allowed' : null)}>
Name - +
{({ validity, value }) => { @@ -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%; diff --git a/docs/data/components/field/UnstyledFieldPassword.js b/docs/data/components/field/UnstyledFieldPassword.js index 2e233b17f1..3219a6ec76 100644 --- a/docs/data/components/field/UnstyledFieldPassword.js +++ b/docs/data/components/field/UnstyledFieldPassword.js @@ -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) { @@ -31,7 +32,7 @@ export default function UnstyledFieldPassword() { return ( 0}> Password - setValue(event.currentTarget.value)} @@ -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%; diff --git a/docs/data/components/field/UnstyledFieldPassword.tsx b/docs/data/components/field/UnstyledFieldPassword.tsx index 63adfbdf95..7ef09bb191 100644 --- a/docs/data/components/field/UnstyledFieldPassword.tsx +++ b/docs/data/components/field/UnstyledFieldPassword.tsx @@ -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) { @@ -31,7 +32,7 @@ export default function UnstyledFieldPassword() { return ( 0}> Password - setValue(event.currentTarget.value)} @@ -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%; diff --git a/docs/data/components/field/UnstyledFieldPassword.tsx.preview b/docs/data/components/field/UnstyledFieldPassword.tsx.preview index 6dcd33da03..c8d04c1250 100644 --- a/docs/data/components/field/UnstyledFieldPassword.tsx.preview +++ b/docs/data/components/field/UnstyledFieldPassword.tsx.preview @@ -1,6 +1,6 @@ 0}> Password - setValue(event.currentTarget.value)} diff --git a/docs/data/components/field/UnstyledFieldServerError.js b/docs/data/components/field/UnstyledFieldServerError.js index 24e281a835..1d0a45e1ec 100644 --- a/docs/data/components/field/UnstyledFieldServerError.js +++ b/docs/data/components/field/UnstyledFieldServerError.js @@ -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() { @@ -40,7 +41,7 @@ export default function UnstyledFieldServerError() {
Email address - Email address - ` is a top-level component that wraps all other components. -- `` renders the control when not using a native Base UI input component. +- `` renders a control when not using a native Base UI input component. - `` renders a label for the control. - `` renders an optional description for the control to provide additional information. - `` renders error messages for the control. @@ -54,7 +54,7 @@ All Base UI input components are aware of Base UI's `Field` component. The lab ``` -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 diff --git a/docs/data/components/form/FormIntroduction/system/index.js b/docs/data/components/form/FormIntroduction/system/index.js index a36554850a..3460d62b77 100644 --- a/docs/data/components/form/FormIntroduction/system/index.js +++ b/docs/data/components/form/FormIntroduction/system/index.js @@ -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() { @@ -53,12 +54,12 @@ export default function FormIntroduction() {

Username - + Password - + @@ -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%; diff --git a/docs/data/components/form/FormIntroduction/system/index.tsx b/docs/data/components/form/FormIntroduction/system/index.tsx index e4b3bb49ec..cce4d579d9 100644 --- a/docs/data/components/form/FormIntroduction/system/index.tsx +++ b/docs/data/components/form/FormIntroduction/system/index.tsx @@ -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'; @@ -55,12 +56,12 @@ export default function FormIntroduction() {

Username - + Password - + @@ -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%; diff --git a/docs/data/components/text-input/TextInputIntroduction/system/index.js b/docs/data/components/text-input/TextInputIntroduction/system/index.js new file mode 100644 index 0000000000..541130bd63 --- /dev/null +++ b/docs/data/components/text-input/TextInputIntroduction/system/index.js @@ -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 ; +} + +const TextInput = styled(TextInputPrimitive)` + border: 1px solid #ccc; + border-radius: 4px; + padding: 8px; + font-size: 16px; + width: 200px; + + &:focus { + outline: 0; + border-color: #0070f3; + } +`; diff --git a/docs/data/components/text-input/TextInputIntroduction/system/index.tsx b/docs/data/components/text-input/TextInputIntroduction/system/index.tsx new file mode 100644 index 0000000000..541130bd63 --- /dev/null +++ b/docs/data/components/text-input/TextInputIntroduction/system/index.tsx @@ -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 ; +} + +const TextInput = styled(TextInputPrimitive)` + border: 1px solid #ccc; + border-radius: 4px; + padding: 8px; + font-size: 16px; + width: 200px; + + &:focus { + outline: 0; + border-color: #0070f3; + } +`; diff --git a/docs/data/components/text-input/TextInputIntroduction/system/index.tsx.preview b/docs/data/components/text-input/TextInputIntroduction/system/index.tsx.preview new file mode 100644 index 0000000000..86eb4b6ff5 --- /dev/null +++ b/docs/data/components/text-input/TextInputIntroduction/system/index.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/components/text-input/text-field.mdx b/docs/data/components/text-input/text-field.mdx new file mode 100644 index 0000000000..222c9ae9fc --- /dev/null +++ b/docs/data/components/text-input/text-field.mdx @@ -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 + + + + + + + +## Installation + + + +## Anatomy + +`` renders an ``, enhanced with field context when placed inside a [`Field`](/components/react-field/). + +```tsx + +``` diff --git a/docs/data/pages.ts b/docs/data/pages.ts index e26c851b42..a191980c8d 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -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-field', title: 'Text Field' }, { pathname: '/components/react-tooltip', title: 'Tooltip' }, ], }, diff --git a/docs/data/translations/api-docs/text-input/text-input.json b/docs/data/translations/api-docs/text-input/text-input.json new file mode 100644 index 0000000000..f93d4cbd8c --- /dev/null +++ b/docs/data/translations/api-docs/text-input/text-input.json @@ -0,0 +1 @@ +{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} } diff --git a/packages/mui-base/src/Field/Control/FieldControl.tsx b/packages/mui-base/src/Field/Control/FieldControl.tsx index 73339b9baa..6f7a78c2ad 100644 --- a/packages/mui-base/src/Field/Control/FieldControl.tsx +++ b/packages/mui-base/src/Field/Control/FieldControl.tsx @@ -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; @@ -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. */ diff --git a/packages/mui-base/src/TextInput/TextInput.test.tsx b/packages/mui-base/src/TextInput/TextInput.test.tsx new file mode 100644 index 0000000000..cd487f933b --- /dev/null +++ b/packages/mui-base/src/TextInput/TextInput.test.tsx @@ -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('', () => { + const { render } = createRenderer(); + + describeConformance(, () => ({ + refInstanceof: window.HTMLInputElement, + render, + })); +}); diff --git a/packages/mui-base/src/TextInput/TextInput.tsx b/packages/mui-base/src/TextInput/TextInput.tsx new file mode 100644 index 0000000000..ac3459d2fd --- /dev/null +++ b/packages/mui-base/src/TextInput/TextInput.tsx @@ -0,0 +1,41 @@ +'use client'; +import * as React from 'react'; +import PropTypes from 'prop-types'; +import type { BaseUIComponentProps } from '../utils/types'; +import { Field } from '../Field'; + +/** + * + * Demos: + * + * - [Text Input](https://base-ui.netlify.app/components/react-text-input/) + * + * API: + * + * - [TextInput API](https://base-ui.netlify.app/components/react-text-input/#api-reference-TextInput) + */ +const TextInput = React.forwardRef(function TextInput( + props: TextInput.Props, + forwardedRef: React.ForwardedRef, +) { + return ; +}); + +TextInput.propTypes /* remove-proptypes */ = { + // ┌────────────────────────────── Warning ──────────────────────────────┐ + // │ These PropTypes are generated from the TypeScript type definitions. │ + // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │ + // └─────────────────────────────────────────────────────────────────────┘ + /** + * @ignore + */ + children: PropTypes.node, +} as any; + +namespace TextInput { + export interface Props extends BaseUIComponentProps<'input', OwnerState> {} + + export interface OwnerState {} +} + +export { TextInput }; diff --git a/packages/mui-base/src/TextInput/index.ts b/packages/mui-base/src/TextInput/index.ts new file mode 100644 index 0000000000..26de90a7e3 --- /dev/null +++ b/packages/mui-base/src/TextInput/index.ts @@ -0,0 +1 @@ +export { TextInput } from './TextInput'; diff --git a/packages/mui-base/src/index.ts b/packages/mui-base/src/index.ts index 5c2fbaeff3..d87a16fe34 100644 --- a/packages/mui-base/src/index.ts +++ b/packages/mui-base/src/index.ts @@ -16,4 +16,5 @@ export * from './Separator'; export * from './Slider'; export * from './Switch'; export * from './Tabs'; +export * from './TextInput'; export * from './Tooltip';