diff --git a/.eslintrc.js b/.eslintrc.js index bdace1247ab77d..e15c9c6197d333 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -67,13 +67,6 @@ module.exports = { { patterns: [ '@mui/*/*/*', - // Begin block: Packages with files instead of packages in the top level - // Importing from the top level pulls in CommonJS instead of ES modules - // Allowing /icons as to reduce cold-start of dev builds significantly. - // There's nothing to tree-shake when importing from /icons this way: - // '@mui/icons-material/*/', - '@mui/utils/*', - // End block // Macros are fine since their import path is transpiled away '!@mui/utils/macros', '@mui/utils/macros/*', @@ -333,7 +326,7 @@ module.exports = { 'error', { patterns: [ - // Allow deeper imports for TypeScript types. TODO? + // Allow deeper imports for TypeScript types. TODO remove '@mui/*/*/*/*', // Macros are fine since they're transpiled into something else '!@mui/utils/macros/*.macro', diff --git a/docs/data/base/components/autocomplete/UseAutocompletePopper.js b/docs/data/base/components/autocomplete/UseAutocompletePopper.js index b6512af0934b97..8897b328599234 100644 --- a/docs/data/base/components/autocomplete/UseAutocompletePopper.js +++ b/docs/data/base/components/autocomplete/UseAutocompletePopper.js @@ -2,7 +2,7 @@ import * as React from 'react'; import { useAutocomplete } from '@mui/base/useAutocomplete'; import { Popper } from '@mui/base/Popper'; import { styled } from '@mui/system'; -import { unstable_useForkRef as useForkRef } from '@mui/utils'; +import useForkRef from '@mui/utils/useForkRef'; // TODO import from @mui/base, private package const Autocomplete = React.forwardRef(function Autocomplete(props, ref) { const { diff --git a/docs/data/base/components/autocomplete/UseAutocompletePopper.tsx b/docs/data/base/components/autocomplete/UseAutocompletePopper.tsx index 3b2d59777f5396..174e88c038c654 100644 --- a/docs/data/base/components/autocomplete/UseAutocompletePopper.tsx +++ b/docs/data/base/components/autocomplete/UseAutocompletePopper.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { useAutocomplete, UseAutocompleteProps } from '@mui/base/useAutocomplete'; import { Popper } from '@mui/base/Popper'; import { styled } from '@mui/system'; -import { unstable_useForkRef as useForkRef } from '@mui/utils'; +import useForkRef from '@mui/utils/useForkRef'; // TODO import from @mui/base, private package const Autocomplete = React.forwardRef(function Autocomplete( props: UseAutocompleteProps<(typeof top100Films)[number], false, false, false>, diff --git a/packages/mui-base/src/FormControl/FormControl.tsx b/packages/mui-base/src/FormControl/FormControl.tsx index f5959d15700ab1..ac8d39dcebd98a 100644 --- a/packages/mui-base/src/FormControl/FormControl.tsx +++ b/packages/mui-base/src/FormControl/FormControl.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { unstable_useControlled as useControlled } from '@mui/utils'; +import useControlled from '@mui/utils/useControlled'; // TODO import from ../useControlled import { PolymorphicComponent } from '../utils/PolymorphicComponent'; import { FormControlContext } from './FormControlContext'; import { getFormControlUtilityClass } from './formControlClasses'; diff --git a/packages/mui-base/tsconfig.build.json b/packages/mui-base/tsconfig.build.json index a45de38c5d2fd4..501142bc852849 100644 --- a/packages/mui-base/tsconfig.build.json +++ b/packages/mui-base/tsconfig.build.json @@ -11,5 +11,6 @@ "rootDir": "./src" }, "include": ["src/**/*.ts*"], - "exclude": ["src/**/*.spec.ts*", "src/**/*.test.ts*"] + "exclude": ["src/**/*.spec.ts*", "src/**/*.test.ts*"], + "references": [{ "path": "../mui-utils/tsconfig.build.json" }] } diff --git a/packages/mui-lab/package.json b/packages/mui-lab/package.json index 1c17af3557ae94..290039d3bed151 100644 --- a/packages/mui-lab/package.json +++ b/packages/mui-lab/package.json @@ -65,7 +65,7 @@ "@mui/system": "^5.14.7", "@mui/types": "^7.2.4", "@mui/utils": "^5.14.7", - "@mui/x-tree-view": "https://pkg.csb.dev/mui/mui-x/commit/1f23b33d/@mui/x-tree-view", + "@mui/x-tree-view": "^6.0.0-alpha.1", "clsx": "^2.0.0", "prop-types": "^15.8.1", "react-is": "^18.2.0" diff --git a/packages/mui-lab/tsconfig.build.json b/packages/mui-lab/tsconfig.build.json index f3c9573d726cf3..c6951939ebf57c 100644 --- a/packages/mui-lab/tsconfig.build.json +++ b/packages/mui-lab/tsconfig.build.json @@ -1,7 +1,7 @@ { // This config is for emitting declarations (.d.ts) only // Actual .ts source files are transpiled via babel - "extends": "./tsconfig.json", + "extends": "./tsconfig", "compilerOptions": { "noEmit": false, "declaration": true, diff --git a/packages/mui-material/scripts/rollup.config.mjs b/packages/mui-material/scripts/rollup.config.mjs index eb89d37c285116..7130eceb36e99c 100644 --- a/packages/mui-material/scripts/rollup.config.mjs +++ b/packages/mui-material/scripts/rollup.config.mjs @@ -101,6 +101,10 @@ const nestedFolder = { return resolveNestedImport('mui-base', importee); } + if (importee.indexOf('@mui/utils/') === 0) { + return resolveNestedImport('mui-utils', importee); + } + if (importee.indexOf('@mui/private-theming/') === 0) { return resolveNestedImport('mui-private-theming', importee); } diff --git a/packages/mui-material/src/ListSubheader/listSubheaderClasses.ts b/packages/mui-material/src/ListSubheader/listSubheaderClasses.ts index 908966f5d0d709..d8ae4c3f5199ed 100644 --- a/packages/mui-material/src/ListSubheader/listSubheaderClasses.ts +++ b/packages/mui-material/src/ListSubheader/listSubheaderClasses.ts @@ -1,4 +1,4 @@ -import { unstable_generateUtilityClasses as generateUtilityClasses } from '@mui/utils'; +import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; // TODO import from @mui/base, private package import generateUtilityClass from '../generateUtilityClass'; export interface ListSubheaderClasses { diff --git a/packages/mui-system/tsconfig.build.json b/packages/mui-system/tsconfig.build.json index a45de38c5d2fd4..501142bc852849 100644 --- a/packages/mui-system/tsconfig.build.json +++ b/packages/mui-system/tsconfig.build.json @@ -11,5 +11,6 @@ "rootDir": "./src" }, "include": ["src/**/*.ts*"], - "exclude": ["src/**/*.spec.ts*", "src/**/*.test.ts*"] + "exclude": ["src/**/*.spec.ts*", "src/**/*.test.ts*"], + "references": [{ "path": "../mui-utils/tsconfig.build.json" }] } diff --git a/packages/mui-utils/src/integerPropType.d.ts b/packages/mui-utils/src/integerPropType.d.ts new file mode 100644 index 00000000000000..d884377a0c94b3 --- /dev/null +++ b/packages/mui-utils/src/integerPropType.d.ts @@ -0,0 +1,15 @@ +import PropTypes from 'prop-types'; + +declare function integerPropType( + props: { [key: string]: any }, + propName: string, + componentName: string, + location: string, + propFullName: string, +): Error | null; + +declare module integerPropType { + let isRequired: PropTypes.Validator; +} + +export default integerPropType; diff --git a/packages/mui-utils/tsconfig.build.json b/packages/mui-utils/tsconfig.build.json index f10360d400e902..649cf77258fe4d 100644 --- a/packages/mui-utils/tsconfig.build.json +++ b/packages/mui-utils/tsconfig.build.json @@ -3,6 +3,7 @@ // Actual .ts source files are transpiled via babel "extends": "./tsconfig", "compilerOptions": { + "composite": true, "declaration": true, "noEmit": false, "emitDeclarationOnly": true, diff --git a/scripts/buildTypes.mjs b/scripts/buildTypes.mjs index 66495ecf56b368..4d1ef870ee8918 100644 --- a/scripts/buildTypes.mjs +++ b/scripts/buildTypes.mjs @@ -32,6 +32,73 @@ function rewriteImportPath(importPath) { throw new Error(`Don't know where to rewrite '${importPath}' to`); } +async function rewriteImportPaths(declarationFile, publishDir) { + const code = await fse.readFile(declarationFile, { encoding: 'utf8' }); + const basename = path.basename(declarationFile); + + if ( + // Only consider React components + basename[0] === basename[0].toUpperCase() && + code.indexOf("import PropTypes from 'prop-types';") !== -1 + ) { + throw new Error( + [ + `${declarationFile} imports from 'prop-types', this is wrong.`, + "It's likely missing a cast to any on the propTypes declaration:", + 'ComponentName.propTypes = { /* prop */ } as any;', + ].join('\n'), + ); + } + + let fixedCode = code; + const changes = []; + + // find all type `import()` + // not to be confused with `import type` + const importTypeRegExp = /import\(([^)]+)\)/g; + + let importTypeMatch; + // eslint-disable-next-line no-cond-assign -- Waiting for RegExp.prototype.matchAll + while ((importTypeMatch = importTypeRegExp.exec(code)) !== null) { + // First and last character are quotes. + // TypeScript mixes single and double quotes. + const importPath = importTypeMatch[1].slice(1, -1); + // In filesystem semantics `@mui/material` is a relative path. + // But when resolving imports these specifiers are considered "bare specifiers" and work differently. + // We're only interested in imports that are considered "relative path imports". + const isBareImportSpecifier = !importPath.startsWith('.'); + if (!isBareImportSpecifier) { + const resolvedImport = path.resolve(declarationFile, importPath); + const importPathFromPublishDir = path.relative(publishDir, resolvedImport); + const isImportReachableWhenPublished = !importPathFromPublishDir.startsWith('.'); + + if (!isImportReachableWhenPublished) { + try { + const fixedImportPath = rewriteImportPath( + // ensure relative POSIX path + importPathFromPublishDir.replace(/\\/g, '/'), + ); + const originalImportType = importTypeMatch[0]; + const fixedImportType = importTypeMatch[0].replace(importPath, fixedImportPath); + + // Make it easy to visually scan for the created lines. + changes.push(`-${chalk.bgRed(originalImportType)}\n+${chalk.bgGreen(fixedImportType)}`); + fixedCode = fixedCode.replace(originalImportType, fixedImportType); + } catch (error) { + throw new Error(`${declarationFile}: ${error}`); + } + } + } + } + + const changed = changes.length > 0; + if (changed) { + await fse.writeFile(declarationFile, fixedCode); + } + + return changes; +} + async function main() { const packageRoot = process.cwd(); @@ -52,73 +119,6 @@ async function main() { throw new Error(`Unable to find declaration files in '${publishDir}'`); } - async function rewriteImportPaths(declarationFile) { - const code = await fse.readFile(declarationFile, { encoding: 'utf8' }); - const basename = path.basename(declarationFile); - - if ( - // Only consider React components - basename[0] === basename[0].toUpperCase() && - code.indexOf("import PropTypes from 'prop-types';") !== -1 - ) { - throw new Error( - [ - `${declarationFile} imports from 'prop-types', this is wrong.`, - "It's likely missing a cast to any on the propTypes declaration:", - 'ComponentName.propTypes = { /* prop */ } as any;', - ].join('\n'), - ); - } - - let fixedCode = code; - const changes = []; - - // find all type `import()` - // not to be confused with `import type` - const importTypeRegExp = /import\(([^)]+)\)/g; - - let importTypeMatch; - // eslint-disable-next-line no-cond-assign -- Waiting for RegExp.prototype.matchAll - while ((importTypeMatch = importTypeRegExp.exec(code)) !== null) { - // First and last character are quotes. - // TypeScript mixes single and double quotes. - const importPath = importTypeMatch[1].slice(1, -1); - // In filesystem semantics `@mui/material` is a relative path. - // But when resolving imports these specifiers are considered "bare specifiers" and work differently. - // We're only interested in imports that are considered "relative path imports". - const isBareImportSpecifier = !importPath.startsWith('.'); - if (!isBareImportSpecifier) { - const resolvedImport = path.resolve(declarationFile, importPath); - const importPathFromPublishDir = path.relative(publishDir, resolvedImport); - const isImportReachableWhenPublished = !importPathFromPublishDir.startsWith('.'); - - if (!isImportReachableWhenPublished) { - try { - const fixedImportPath = rewriteImportPath( - // ensure relative POSIX path - importPathFromPublishDir.replace(/\\/g, '/'), - ); - const originalImportType = importTypeMatch[0]; - const fixedImportType = importTypeMatch[0].replace(importPath, fixedImportPath); - - // Make it easy to visually scan for the created lines. - changes.push(`-${chalk.bgRed(originalImportType)}\n+${chalk.bgGreen(fixedImportType)}`); - fixedCode = fixedCode.replace(originalImportType, fixedImportType); - } catch (error) { - throw new Error(`${declarationFile}: ${error}`); - } - } - } - } - - const changed = changes.length > 0; - if (changed) { - await fse.writeFile(declarationFile, fixedCode); - } - - return changes; - } - let rewrittenTally = 0; let errorTally = 0; await Promise.all( diff --git a/tsconfig.json b/tsconfig.json index 7caf992444606a..e78be423ebc0c1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,6 +33,8 @@ "@mui/types": ["./packages/mui-types"], "@mui/base": ["./packages/mui-base/src"], "@mui/base/*": ["./packages/mui-base/src/*"], + "@mui/utils": ["./packages/mui-utils/src"], + "@mui/utils/*": ["./packages/mui-utils/src/*"], "@mui/docs": ["./packages/mui-docs/src"], "@mui/docs/*": ["./packages/mui-docs/src/*"], "@mui/material-next": ["./packages/mui-material-next/src"], diff --git a/yarn.lock b/yarn.lock index de59cf0e6fd822..1df78f6726785c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2199,14 +2199,15 @@ "@babel/runtime" "^7.22.6" "@mui/utils" "^5.13.7" -"@mui/x-tree-view@https://pkg.csb.dev/mui/mui-x/commit/1f23b33d/@mui/x-tree-view": - version "6.0.0-alpha.0" - resolved "https://pkg.csb.dev/mui/mui-x/commit/1f23b33d/@mui/x-tree-view#93cbc61c818ed2d6c40554cdbada969f7dcbaab1" +"@mui/x-tree-view@^6.0.0-alpha.1": + version "6.0.0-alpha.1" + resolved "https://registry.yarnpkg.com/@mui/x-tree-view/-/x-tree-view-6.0.0-alpha.1.tgz#fe499f8c43c01d28aca95cfb17491746ffcc3080" + integrity sha512-JUG3HmBrmGEALbCFg1b+i7h726e1dWYZs4db3syO1j+Q++E3nbvE4Lehp5yGTFm+8esH0Tny50tuJaa4WX6VSA== dependencies: "@babel/runtime" "^7.22.6" - "@mui/utils" "^5.13.7" + "@mui/utils" "^5.14.3" "@types/react-transition-group" "^4.4.6" - clsx "^1.2.1" + clsx "^2.0.0" prop-types "^15.8.1" react-transition-group "^4.4.5" @@ -5829,7 +5830,7 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -clsx@^1.1.0, clsx@^1.1.1, clsx@^1.2.1: +clsx@^1.1.0, clsx@^1.1.1: version "1.2.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==