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

[material-next][OutlinedInput] Copy v5 OutlinedInput #39698

Merged
merged 5 commits into from
Nov 3, 2023
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
18 changes: 18 additions & 0 deletions packages/mui-material-next/src/OutlinedInput/NotchedOutline.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
// TODO v6: port to material-next
import { InternalStandardProps as StandardProps } from '@mui/material';

export interface NotchedOutlineProps
extends StandardProps<React.FieldsetHTMLAttributes<HTMLFieldSetElement>> {
disabled?: boolean;
error?: boolean;
focused?: boolean;
label?: React.ReactNode;
notched: boolean;
}

export type NotchedOutlineClassKey = keyof NonNullable<NotchedOutlineProps['classes']>;

declare const NotchedOutline: React.JSXElementConstructor<NotchedOutlineProps>;

export default NotchedOutline;
119 changes: 119 additions & 0 deletions packages/mui-material-next/src/OutlinedInput/NotchedOutline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import styled, { rootShouldForwardProp } from '../styles/styled';

const NotchedOutlineRoot = styled('fieldset', { shouldForwardProp: rootShouldForwardProp })({
textAlign: 'left',
position: 'absolute',
bottom: 0,
right: 0,
top: -5,
left: 0,
margin: 0,
padding: '0 8px',
pointerEvents: 'none',
borderRadius: 'inherit',
borderStyle: 'solid',
borderWidth: 1,
overflow: 'hidden',
minWidth: '0%',
});

const NotchedOutlineLegend = styled('legend', { shouldForwardProp: rootShouldForwardProp })(
({ ownerState, theme }) => ({
float: 'unset', // Fix conflict with bootstrap
width: 'auto', // Fix conflict with bootstrap
overflow: 'hidden', // Fix Horizontal scroll when label too long
...(!ownerState.withLabel && {
padding: 0,
lineHeight: '11px', // sync with `height` in `legend` styles
transition: theme.transitions.create('width', {
duration: 150,
easing: theme.transitions.easing.easeOut,
}),
}),
...(ownerState.withLabel && {
display: 'block', // Fix conflict with normalize.css and sanitize.css
padding: 0,
height: 11, // sync with `lineHeight` in `legend` styles
fontSize: '0.75em',
visibility: 'hidden',
maxWidth: 0.01,
transition: theme.transitions.create('max-width', {
duration: 50,
easing: theme.transitions.easing.easeOut,
}),
whiteSpace: 'nowrap',
'& > span': {
paddingLeft: 5,
paddingRight: 5,
display: 'inline-block',
opacity: 0,
visibility: 'visible',
},
...(ownerState.notched && {
maxWidth: '100%',
transition: theme.transitions.create('max-width', {
duration: 100,
easing: theme.transitions.easing.easeOut,
delay: 50,
}),
}),
}),
}),
);

/**
* @ignore - internal component.
*/
export default function NotchedOutline(props) {
const { children, classes, className, label, notched, ...other } = props;
const withLabel = label != null && label !== '';
const ownerState = {
...props,
notched,
withLabel,
};
return (
<NotchedOutlineRoot aria-hidden className={className} ownerState={ownerState} {...other}>
<NotchedOutlineLegend ownerState={ownerState}>
{/* Use the nominal use case of the legend, avoid rendering artefacts. */}
{withLabel ? (
<span>{label}</span>
) : (
// notranslate needed while Google Translate will not fix zero-width space issue
<span className="notranslate">&#8203;</span>
)}
</NotchedOutlineLegend>
</NotchedOutlineRoot>
);
}

NotchedOutline.propTypes = {
/**
* The content of the component.
*/
children: PropTypes.node,
/**
* Override or extend the styles applied to the component.
* See [CSS API](#css) below for more details.
*/
classes: PropTypes.object,
/**
* @ignore
*/
className: PropTypes.string,
/**
* The label.
*/
label: PropTypes.node,
/**
* If `true`, the outline is notched to accommodate the label.
*/
notched: PropTypes.bool.isRequired,
/**
* @ignore
*/
style: PropTypes.object,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from 'react';
import { expect } from 'chai';
import { createRenderer } from '@mui-internal/test-utils';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import NotchedOutline from './NotchedOutline';

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

const defaultProps = {
notched: true,
label: 'My label',
};

it('should pass props', () => {
const { container } = render(
<NotchedOutline
{...defaultProps}
className="notched-outline"
style={{
width: 17,
}}
/>,
);

expect(container.querySelector('fieldset')).to.have.class('notched-outline');
expect(container.querySelector('fieldset').style.width).to.equal('17px');
});

it('should set alignment rtl', () => {
const { container: container1 } = render(
<ThemeProvider
theme={createTheme({
direction: 'ltr',
})}
>
<NotchedOutline {...defaultProps} />
</ThemeProvider>,
);
expect(container1.querySelector('fieldset')).toHaveComputedStyle({
paddingLeft: '8px',
});

const { container: container2 } = render(
<ThemeProvider
theme={createTheme({
direction: 'rtl',
})}
>
<NotchedOutline {...defaultProps} />
</ThemeProvider>,
);
expect(container2.querySelector('fieldset')).toHaveComputedStyle({
paddingRight: '8px',
});
});
it('should not set padding (notch) for empty, null or undefined label props', function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
this.skip();
}
const spanStyle = { paddingLeft: '0px', paddingRight: '0px' };
['', undefined, null].forEach((prop) => {
const { container: container1 } = render(<NotchedOutline {...defaultProps} label={prop} />);
expect(container1.querySelector('span')).toHaveComputedStyle(spanStyle);
});
});
});
41 changes: 41 additions & 0 deletions packages/mui-material-next/src/OutlinedInput/OutlinedInput.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from 'react';
import { SxProps, Theme } from '@mui/system';
// TODO v6: port to material-next
import { InternalStandardProps as StandardProps } from '@mui/material';
import { InputBaseProps } from '@mui/material/InputBase';
import { OutlinedInputClasses } from './outlinedInputClasses';

export interface OutlinedInputProps extends StandardProps<InputBaseProps> {
/**
* Override or extend the styles applied to the component.
*/
classes?: Partial<OutlinedInputClasses>;
/**
* The label of the `input`. It is only used for layout. The actual labelling
* is handled by `InputLabel`.
*/
label?: React.ReactNode;
/**
* If `true`, the outline is notched to accommodate the label.
*/
notched?: boolean;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
}

/**
*
* Demos:
*
* - [Text Field](https://mui.com/material-ui/react-text-field/)
*
* API:
*
* - [OutlinedInput API](https://mui.com/material-ui/api/outlined-input/)
* - inherits [InputBase API](https://mui.com/material-ui/api/input-base/)
*/
declare const OutlinedInput: ((props: OutlinedInputProps) => JSX.Element) & { muiName: string };

export default OutlinedInput;
Loading
Loading