Skip to content

Commit

Permalink
[material-next][OutlinedInput] Copy v5 OutlinedInput (mui#39698)
Browse files Browse the repository at this point in the history
  • Loading branch information
mj12albert authored Nov 3, 2023
1 parent 0f4e02c commit a459e2f
Show file tree
Hide file tree
Showing 10 changed files with 821 additions and 0 deletions.
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

0 comments on commit a459e2f

Please sign in to comment.