From f1d4f4a31bd2721fcbdbe3b59e427cbf80e6031a Mon Sep 17 00:00:00 2001 From: upstream Date: Sat, 17 Oct 2026 03:26:00 +0200 Subject: [PATCH] Upstream mui/material-ui state of the touched files before bd76bf2479 --- .../src/OutlinedInput/NotchedOutline.js | 139 ++++++++++++++++++ .../src/OutlinedInput/NotchedOutline.test.js | 67 +++++++++ 2 files changed, 206 insertions(+) create mode 100644 packages/mui-material/src/OutlinedInput/NotchedOutline.js create mode 100644 packages/mui-material/src/OutlinedInput/NotchedOutline.test.js diff --git a/packages/mui-material/src/OutlinedInput/NotchedOutline.js b/packages/mui-material/src/OutlinedInput/NotchedOutline.js new file mode 100644 index 0000000..e4b314e --- /dev/null +++ b/packages/mui-material/src/OutlinedInput/NotchedOutline.js @@ -0,0 +1,139 @@ +'use client'; +import PropTypes from 'prop-types'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled } from '../zero-styled'; +import memoTheme from '../utils/memoTheme'; +import { getTransitionStyles } from '../transitions/utils'; + +const NotchedOutlineRoot = styled('fieldset', { + name: 'MuiNotchedOutlined', + 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', { + name: 'MuiNotchedOutlined', + shouldForwardProp: rootShouldForwardProp, +})( + memoTheme(({ theme }) => ({ + float: 'unset', // Fix conflict with bootstrap + width: 'auto', // Fix conflict with bootstrap + overflow: 'hidden', // Fix Horizontal scroll when label too long + variants: [ + { + props: ({ ownerState }) => !ownerState.withLabel, + style: { + padding: 0, + lineHeight: '11px', // sync with `height` in `legend` styles + ...getTransitionStyles(theme, 'width', { + duration: 150, + easing: theme.transitions.easing.easeOut, + }), + }, + }, + { + props: ({ ownerState }) => ownerState.withLabel, + style: { + 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, + ...getTransitionStyles(theme, 'max-width', { + duration: 50, + easing: theme.transitions.easing.easeOut, + }), + whiteSpace: 'nowrap', + '& > span': { + paddingLeft: 5, + paddingRight: 5, + display: 'inline-block', + opacity: 0, + visibility: 'visible', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.withLabel && ownerState.notched, + style: { + maxWidth: '100%', + ...getTransitionStyles(theme, '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 ( + + + {/* Use the nominal use case of the legend, avoid rendering artefacts. */} + {withLabel ? ( + {label} + ) : ( + // notranslate needed while Google Translate will not fix zero-width space issue + + ​ + + )} + + + ); +} + +NotchedOutline.propTypes /* remove-proptypes */ = { + /** + * The content of the component. + */ + children: PropTypes.node, + /** + * Override or extend the styles applied to the component. + */ + 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, +}; diff --git a/packages/mui-material/src/OutlinedInput/NotchedOutline.test.js b/packages/mui-material/src/OutlinedInput/NotchedOutline.test.js new file mode 100644 index 0000000..456229c --- /dev/null +++ b/packages/mui-material/src/OutlinedInput/NotchedOutline.test.js @@ -0,0 +1,67 @@ +import { describe, it, expect } from 'vitest'; +import { createRenderer, isJsdom } from '@mui/internal-test-utils'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; +import NotchedOutline from './NotchedOutline'; + +describe('', () => { + const { render } = createRenderer(); + + const defaultProps = { + notched: true, + label: 'My label', + }; + + it('should pass props', () => { + const { container } = render( + , + ); + + 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( + + + , + ); + expect(container1.querySelector('fieldset')).toHaveComputedStyle({ + paddingLeft: '8px', + }); + + const { container: container2 } = render( + + + , + ); + expect(container2.querySelector('fieldset')).toHaveComputedStyle({ + paddingRight: '8px', + }); + }); + + it.skipIf(isJsdom())( + 'should not set padding (notch) for empty, null or undefined label props', + function test() { + const spanStyle = { paddingLeft: '0px', paddingRight: '0px' }; + ['', undefined, null].forEach((prop) => { + const { container: container1 } = render(); + expect(container1.querySelector('span')).toHaveComputedStyle(spanStyle); + }); + }, + ); +});