diff --git a/CHANGELOG.md b/CHANGELOG.md index 907d512c67a2..80650ca0926e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,95 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 7.21.0 + +_Oct 17, 2024_ + +We'd like to offer a big thanks to the 13 contributors who made this release possible. Here are some highlights ✨: + +- 💫 Added [`dataset` prop support for the Scatter Chart component](https://mui.com/x/react-charts/scatter/#using-a-dataset) +- 🐞 Bugfixes +- 📚 Documentation improvements + +Special thanks go out to the community contributors who have helped make this release possible: +@k-rajat19, @kalyan90, @rotembarsela, @wangkailang. +Following are all team members who have contributed to this release: +@arthurbalduini, @cherniavskii, @flaviendelangle, @JCQuintas, @LukasTy, @MBilalShafi, @arminmeh, @romgrk, @KenanYusuf, @oliviertassinari, @samuelsycamore. + + + +### Data Grid + +#### `@mui/x-data-grid@7.21.0` + +- [DataGrid] Fix `onRowSelectionModelChange` firing unnecessarily on initial render (#14909) @MBilalShafi +- [DataGrid] Fix `onRowSelectionModelChange` not being called after row is removed (#14972) @arminmeh +- [DataGrid] Fix pagination scrollbar issue on small zoom (#14911) @cherniavskii +- [DataGrid] Fix scroll jumping (#14929) @romgrk +- [DataGrid] Fix excessive white space at the end of the Data Grid (#14864) @kalyan90 + +#### `@mui/x-data-grid-pro@7.21.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-data-grid@7.21.0`, plus: + +- [DataGridPro] Fix indeterminate checkbox state for server-side data (#14956) @MBilalShafi +- [DataGridPro] Fix scrolling performance when `rowHeight={undefined}` (#14983) @cherniavskii +- [DataGridPro] List view (#14393) @KenanYusuf @cherniavskii + +#### `@mui/x-data-grid-premium@7.21.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan') + +Same changes as in `@mui/x-data-grid-pro@7.21.0`. + +### Date and Time Pickers + +#### `@mui/x-date-pickers@7.21.0` + +- [pickers] Cleanup `PageUp` and `PageDown` event handlers on time components (#14928) @arthurbalduini +- [pickers] Create the new picker's `ownerState` object (#14889) @flaviendelangle +- [pickers] Fix `PickerValidDate` usage in the Date Range Picker Toolbar (#14925) @flaviendelangle + +#### `@mui/x-date-pickers-pro@7.21.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-date-pickers@7.21.0`. + +### Charts + +#### `@mui/x-charts@7.21.0` + +- [charts] Allow `dataset` to be used with the Scatter Chart (#14915) @JCQuintas +- [charts] Ensure `reduce motion` preference disables animation on page load (#14417) @JCQuintas + +#### `@mui/x-charts-pro@7.0.0-beta.5` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-charts@7.21.0`. + +### Tree View + +#### `@mui/x-tree-view@7.21.0` + +- [TreeView] Fix `alpha` usage with CSS variables (#14969) @wangkailang +- [TreeView] Fix usage of the `aria-selected` attribute (#14991) @flaviendelangle +- [TreeView] Fix hydration error (#15002) @flaviendelangle + +### `@mui/x-codemod@7.21.0` + +- [codemod] Add a new utility to rename imports (#14919) @flaviendelangle + +### Docs + +- [docs] Add recipe showing how to toggle detail panels on row click (#14666) @k-rajat19 +- [docs] Fix broken link to the validation section in the Data grid component (#14973) @arminmeh +- [docs] Update v5 migration codesandbox @oliviertassinari +- [docs] Enforce component style rules for the Tree View (#14963) @samuelsycamore + +### Core + +- [core] Fix shortcut with localization keyboard (#14220) @rotembarsela +- [core] Fix docs deploy command (#14920) @arminmeh +- [code-infra] Prepare some tests to work in `vitest/playwright` (#14926) @JCQuintas +- [test] Fix `AdapterDayjs` coverage calculation (#14957) @LukasTy +- [test] Fix split infinitive API convention use @oliviertassinari + ## 7.20.0 _Oct 11, 2024_ @@ -79,7 +168,7 @@ Same changes as in `@mui/x-charts@7.20.0`. - [docs] Add custom columns panel demo (#14825) @cherniavskii - [docs] Capitalize all instances of "Data Grid" (#14884) @samuelsycamore - [docs] Divide charts `tooltip` and `highlighting` pages (#14824) @JCQuintas -- [docs] Document the `TreeItem2` component and the `useTreeItem2` hook (#14551) @noraleonte +- [docs] Document the `` component and the `useTreeItem2` hook (#14551) @noraleonte - [docs] Fix column pinning for "Disable detail panel content scroll" section (#14854 and #14885) @kalyan90 - [docs] Fix detail panel demo not working well with pinned columns (#14883) @cherniavskii - [docs] New recipe of a read-only field (#14606) @flaviendelangle @@ -367,7 +456,7 @@ Same changes as in `@mui/x-charts@7.17.0`. ### Docs -- [docs] Add missing callout on "Imperative API" tree view sections (#14503) @flaviendelangle +- [docs] Add missing callout on "Imperative API" Tree View sections (#14503) @flaviendelangle - [docs] Fix broken redirection to MUI X v5 @oliviertassinari - [docs] Fix multiple `console.error` messages on `charts` docs (#14554) @JCQuintas - [docs] Fixed typo in Row Grouping recipes (#14549) @Miodini @@ -708,7 +797,7 @@ Same changes as in `@mui/x-charts@7.13.0`. - [core] Fix ESLint issue (#14207) @LukasTy - [core] Fix Netlify build cache issue (#14182) @cherniavskii - [code-infra] Refactor Netlify `cache-docs` plugin setup (#14105) @LukasTy -- [internals] Move utils needed for tree view virtualization to shared package (#14202) @flaviendelangle +- [internals] Move utils needed for Tree View virtualization to shared package (#14202) @flaviendelangle ## 7.12.1 @@ -799,7 +888,7 @@ This expansion of the Pro plan comes with some adjustments to our pricing strate We'd like to offer a big thanks to the 12 contributors who made this release possible. Here are some highlights ✨: -- 🎁 Introduce [item reordering using drag and drop](https://mui.com/x/react-tree-view/rich-tree-view/ordering/) on the `RichTreeViewPro` component +- 🎁 Introduce [item reordering using drag and drop](https://mui.com/x/react-tree-view/rich-tree-view/ordering/) on the `` component Item reordering using drag and drop @@ -1292,7 +1381,7 @@ Same changes as in `@mui/x-date-pickers@7.8.0`. - [core] Add eslint rule to restrict import from `../internals` root (#13633) @JCQuintas - [docs-infra] Sync `\_app` folder with monorepo (#13582) @Janpot -- [license] Allow usage of charts and tree view pro package for old premium licenses (#13619) @flaviendelangle +- [license] Allow usage of Charts and Tree View Pro package for old premium licenses (#13619) @flaviendelangle ## 7.7.1 @@ -1360,7 +1449,7 @@ Same changes as in `@mui/x-date-pickers@7.7.1`, plus: - [TreeView] Improve typing to support optional dependencies in plugins and in the item (#13523) @flaviendelangle - [TreeView] Move `useTreeViewId` to the core plugins (#13566) @flaviendelangle - [TreeView] Remove unused state from `useTreeViewId` (#13579) @flaviendelangle -- [TreeView] Support `itemId` with escaping characters when using `SimpleTreeView` (#13487) @oukunan +- [TreeView] Support `itemId` with escaping characters when using Simple Tree View (#13487) @oukunan ### Docs @@ -1440,7 +1529,7 @@ Same changes as in `@mui/x-date-pickers@7.7.0`. - [TreeView] Improve TypeScript for plugins (#13380) @flaviendelangle - [TreeView] Improve the typing of the cancelable events (#13152) @flaviendelangle - [TreeView] Prepare support for PigmentCSS (#13412) @flaviendelangle -- [TreeView] Refactor the tree view internals to prepare for headless API (#13311) @flaviendelangle +- [TreeView] Refactor the Tree View internals to prepare for headless API (#13311) @flaviendelangle ### Docs @@ -1455,7 +1544,7 @@ Same changes as in `@mui/x-date-pickers@7.7.0`. - [core] Add `eslint-plugin-react-compiler` experimental version and rules (#13415) @JCQuintas - [core] Minor setup cleanup (#13467) @LukasTy - [infra] Adjust CI setup (#13448) @LukasTy -- [test] Add tests for the custom slots of `TreeItem2` (#13314) @flaviendelangle +- [test] Add tests for the custom slots of `` (#13314) @flaviendelangle ## 7.6.2 @@ -1640,7 +1729,7 @@ _May 23, 2024_ We'd like to offer a big thanks to the 6 contributors who made this release possible. Here are some highlights ✨: -- 🧰 Improve tree view testing +- 🧰 Improve Tree View testing - 📊 Add `label` to be displayed in BarChart ### Data Grid @@ -1816,7 +1905,7 @@ Same changes as in `@mui/x-date-pickers@7.4.0`. #### `@mui/x-tree-view@7.4.0` -- [TreeView] Fix props propagation and theme entry in `TreeItem2` (#12889) @flaviendelangle +- [TreeView] Fix props propagation and theme entry in `` (#12889) @flaviendelangle ### Docs @@ -2126,7 +2215,7 @@ Same changes as in `@mui/x-date-pickers@7.2.0`, plus: ### Docs - [docs] Add `AxisFormatter` documentation for customizing tick/tooltip value formatting (#12700) @JCQuintas -- [docs] Add file explorer example to rich tree view customization docs (#12707) @noraleonte +- [docs] Add file explorer example to rich Tree View customization docs (#12707) @noraleonte - [docs] Do not use import of depth 3 in the doc (#12716) @flaviendelangle - [docs] Explain how to clip plots with composition (#12679) @alexfauquette - [docs] Fix typo in Data Grid v7 migration page (#12720) @bfaulk96 @@ -2202,7 +2291,7 @@ Same changes as in `@mui/x-date-pickers@7.1.1`, plus: #### `@mui/x-tree-view@7.1.1` - [TreeView] Add JSDoc to all `publicAPI` methods (#12649) @flaviendelangle -- [TreeView] Create `RichTreeViewPro` component (not released yet) (#12610) @flaviendelangle +- [TreeView] Create `` component (not released yet) (#12610) @flaviendelangle - [TreeView] Create Pro package (not released yet) (#12240) @flaviendelangle - [TreeView] Fix typo in errors (#12623) @alissa-tung - [TreeView] New API method: `setItemExpansion` (#12595) @flaviendelangle @@ -2222,13 +2311,13 @@ Same changes as in `@mui/x-date-pickers@7.1.1`, plus: - [docs] Move Data Grid interfaces to standard API page layout (#12016) @alexfauquette - [docs] Remove ` around @default values (#12158) @alexfauquette - [docs] Remove `day` from the default `dayOfWeekFormatter` function params (#12644) @LukasTy -- [docs] Use `TreeItem2` for icon expansion example on `RichTreeView` (#12563) @flaviendelangle +- [docs] Use `` for icon expansion example on `` (#12563) @flaviendelangle ### Core - [core] Add cherry-pick `master` to `v6` action (#12648) @LukasTy - [core] Fix typo in `@mui/x-tree-view-pro/themeAugmentation` (#12674) @flaviendelangle -- [core] Introduce `describeTreeView` to run test on `SimpleTreeView` and `RichTreeView`, using `TreeItem` and `TreeItem2` + migrate expansion tests (#12428) @flaviendelangle +- [core] Introduce `describeTreeView` to run test on `` and ``, using `` and `` + migrate expansion tests (#12428) @flaviendelangle - [core] Limit `test-types` CI step allowed memory (#12651) @LukasTy - [core] Remove explicit `express` package (#12602) @LukasTy - [core] Update to new embedded translations in the docs package (#12232) @Janpot @@ -2293,7 +2382,7 @@ Same changes as in `@mui/x-date-pickers@7.1.0`, plus: #### `@mui/x-tree-view@7.1.0` -- [TreeView] Do not use outdated version of the state to compute new label first char in `RichTreeView` (#12512) @flaviendelangle +- [TreeView] Do not use outdated version of the state to compute new label first char in Rich Tree View (#12512) @flaviendelangle ### Docs @@ -2420,7 +2509,7 @@ Same changes as in `@mui/x-date-pickers@7.0.0`, plus: #### Breaking changes -- The required `nodeId` prop used by the `TreeItem` has been renamed to `itemId` for consistency: +- The required `nodeId` prop used by `` has been renamed to `itemId` for consistency: ```diff @@ -2573,7 +2662,7 @@ The `onNodeFocus` callback has been renamed to `onItemFocus` for consistency: #### `@mui/x-tree-view@7.0.0-beta.7` - [TreeView] Clean the usage of the term "item" and "node" in API introduced during v7 (#12368) @noraleonte -- [TreeView] Introduce a new `TreeItem2` component and a new `useTreeItem2` hook (#11721) @flaviendelangle +- [TreeView] Introduce a new `` component and a new `useTreeItem2` hook (#11721) @flaviendelangle - [TreeView] Rename `onNodeFocus` to `onItemFocus` (#12419) @noraleonte ### Docs @@ -2631,9 +2720,9 @@ Same changes as in `@mui/x-data-grid-pro@7.0.0-beta.6`. #### Breaking changes -- The component used to animate the item children is now defined as a slot on the `TreeItem` component. +- The component used to animate the item children is now defined as a slot on the `` component. - If you were passing a `TransitionComponent` or `TransitionProps` to your `TreeItem` component, + If you were passing a `TransitionComponent` or `TransitionProps` to your `` component, you need to use the new `groupTransition` slot on this component: ```diff @@ -2649,7 +2738,7 @@ Same changes as in `@mui/x-data-grid-pro@7.0.0-beta.6`. ``` -- The `group` class of the `TreeItem` component has been renamed to `groupTransition` to match with its new slot name. +- The `group` class of the `` component has been renamed to `groupTransition` to match with its new slot name. ```diff const StyledTreeItem = styled(TreeItem)({ @@ -2663,14 +2752,14 @@ Same changes as in `@mui/x-data-grid-pro@7.0.0-beta.6`. #### `@mui/x-tree-view@7.0.0-beta.6` - [TreeView] Fix invalid nodes state when updating `props.items` (#12359) @flaviendelangle -- [TreeView] In the `RichTreeView`, do not use the item id as the HTML id attribute (#12319) @flaviendelangle +- [TreeView] In the Rich Tree View, do not use the item id as the HTML id attribute (#12319) @flaviendelangle - [TreeView] New instance and publicAPI method: `getItem` (#12251) @flaviendelangle - [TreeView] Replace `TransitionComponent` and `TransitionProps` with a `groupTransition` slot (#12336) @flaviendelangle ### Docs - [docs] Add a note about `z-index` usage in SVG (#12337) @alexfauquette -- [docs] `RichTreeView` customization docs (#12231) @noraleonte +- [docs] Rich Tree View customization docs (#12231) @noraleonte ### Core @@ -3324,7 +3413,7 @@ Same changes as in `@mui/x-date-pickers@7.0.0-beta.0`, plus: ### Docs -- [docs] Add `contextValue` to the headless tree view doc (#11705) @flaviendelangle +- [docs] Add `contextValue` to the headless Tree View doc (#11705) @flaviendelangle - [docs] Add section for the `disableSelection` prop (#11821) @flaviendelangle - [docs] Fix brand name non-breaking space (#11758) @oliviertassinari - [docs] Fix typo in Data Grid components page (#11775) @flaviendelangle @@ -3347,7 +3436,7 @@ We'd like to offer a big thanks to the 11 contributors who made this release pos - 🎁 The Data Grid headers have been refactored to bring immense improvements to scrolling, state management, and overall performance of the grid. - ⚙️ The Data Grid disabled column-specific features like filtering, sorting, grouping, etc. could now be accessed programmatically. See the related [docs](https://next.mui.com/x/react-data-grid/api-object/#access-the-disabled-column-features) section. -- 🚀 Uplift the `SimpleTreeView` customization examples (#11424) @noraleonte +- 🚀 Uplift the Simple Tree View customization examples (#11424) @noraleonte - 🌍 Add Croatian (hr-HR), Portuguese (pt-PT), and Chinese (Hong Kong) (zh-HK) locales (#11668) on the Data Grid @BCaspari - 🐞 Bugfixes - 💔 Bump `@mui/material` peer dependency for all packages (#11692) @LukasTy @@ -3558,7 +3647,7 @@ Same changes as in `@mui/x-date-pickers@7.0.0-alpha.9`. ``` - The `useTreeItem` hook has been renamed `useTreeItemState`. - This will help create a new headless version of the `TreeItem` component based on a future `useTreeItem` hook. + This will help create a new headless version of the Tree Item component based on a future `useTreeItem` hook. ```diff -import { TreeItem, useTreeItem } from '@mui/x-tree-view/TreeItem'; @@ -3658,13 +3747,13 @@ Same changes as in `@mui/x-date-pickers@7.0.0-alpha.9`. - [docs] Cleanup and fix Pickers Playground styling (#11700) @LukasTy - [docs] First draft of the Tree View custom plugin doc (#11564) @flaviendelangle - [docs] Fix Pickers migration syntax and diffs (#11695) @LukasTy -- [docs] Fix generated tree view API docs (#11737) @LukasTy +- [docs] Fix generated Tree View API docs (#11737) @LukasTy - [docs] Generate docs for Tree View slots (#11730) @flaviendelangle - [docs] Improve codemod for v7 (#11650) @oliviertassinari - [docs] Improve Data Grid `pageSizeOptions` prop documentation (#11682) @oliviertassinari - [docs] Parse markdown on API docs demo titles (#11728) @LukasTy - [docs] Remove the description from the `className` prop (#11693) @oliviertassinari -- [docs] Uplift `SimpleTreeView` customization examples (#11424) @noraleonte +- [docs] Uplift Simple Tree View customization examples (#11424) @noraleonte - [docs] Uplift the Date Pickers playground (#11555) @danilo-leal ### Core @@ -3741,8 +3830,8 @@ Same changes as in `@mui/x-date-pickers@7.0.0-alpha.8`. ### Tree View / `@mui/x-tree-view@7.0.0-alpha.8` -- [tree view] Cleanup `onKeyDown` handler (#11481) @flaviendelangle -- [tree view] Define the parameters used by each plugin to avoid listing them in each component (#11473) @flaviendelangle +- [TreeView] Cleanup `onKeyDown` handler (#11481) @flaviendelangle +- [TreeView] Define the parameters used by each plugin to avoid listing them in each component (#11473) @flaviendelangle ### Docs @@ -3769,7 +3858,7 @@ We'd like to offer a big thanks to the 7 contributors who made this release poss - 🎁 New component to create a Tree View from a structured data source: - You can now directly pass your data to the `RichTreeView` component instead of manually converting it into JSX `TreeItem` components: + You can now directly pass your data to the `` component instead of manually converting it into JSX `` components: ```tsx const ITEMS = [ @@ -5100,7 +5189,7 @@ Here is an example of the renaming for the `` component. ### Core -- [core] Adds migration docs for charts, pickers and tree view (#10926) @michelengelen +- [core] Adds migration docs for Charts, Pickers, and Tree View (#10926) @michelengelen - [core] Bump monorepo (#10959) @LukasTy - [core] Changed prettier branch value to next (#10917) @michelengelen - [core] Fix GitHub title tag consistency @oliviertassinari diff --git a/changelogOld/CHANGELOG.v6.md b/changelogOld/CHANGELOG.v6.md index 0401e317fe08..985e7aba0905 100644 --- a/changelogOld/CHANGELOG.v6.md +++ b/changelogOld/CHANGELOG.v6.md @@ -1485,7 +1485,7 @@ Same changes as in `@mui/x-date-pickers@6.13.0`, plus: - [docs] Fix charts demo using too deep import (#10263) @LukasTy - [docs] Fix `e.g.` typo @oliviertassinari - [docs] Fix npm package indentation @oliviertassinari -- [docs] Fix typo in tree view docs @oliviertassinari +- [docs] Fix typo in Tree View docs @oliviertassinari - [docs] Improve the week picker example (#8257) @flaviendelangle - [docs] Include code links in the Data Grid demo (#10219) @cherniavskii - [docs] Polish page for SEO (#10216) @oliviertassinari @@ -1546,7 +1546,7 @@ Same changes as in `@mui/x-date-pickers@6.12.1`. - [docs] Add `DemoContainer` and `DemoItem` JSDoc (#10186) @LukasTy - [docs] Add link to `custom layout` page (#10184) @LukasTy -- [docs] Add tree view nav item (#10181) @LukasTy +- [docs] Add Tree View nav item (#10181) @LukasTy - [docs] Fix wrong chart tooltip reference (#10169) @oliviertassinari - [docs] Improve chart SEO (#10170) @oliviertassinari - [docs] Precise expired license key condition (#10165) @oliviertassinari @@ -1748,7 +1748,7 @@ _Aug 4, 2023_ We'd like to offer a big thanks to the 12 contributors who made this release possible. Here are some highlights ✨: -- ⌚️ Move the tree view component from `@mui/lab` package +- ⌚️ Move the Tree View component from `@mui/lab` package The `` component has been moved to the MUI X repository. It is now accessible from its own package: `@mui/x-tree-view`. @@ -1804,7 +1804,7 @@ Same changes as in `@mui/x-date-pickers@6.11.0`. ### Tree View / `@mui/x-tree-view@6.0.0-alpha.0` - [TreeView] Add missing exported types (#9862) @flaviendelangle -- [TreeView] Add tree view to changelog generator script (#9903) @MBilalShafi +- [TreeView] Add Tree View to changelog generator script (#9903) @MBilalShafi - [TreeView] Create the package on the X repository (#9798) @flaviendelangle - [TreeView] Improve props typing (#9855) @flaviendelangle diff --git a/docs/data/common-concepts/custom-components/custom-components.md b/docs/data/common-concepts/custom-components/custom-components.md index cd89c78cbe62..1875037ac5bf 100644 --- a/docs/data/common-concepts/custom-components/custom-components.md +++ b/docs/data/common-concepts/custom-components/custom-components.md @@ -11,7 +11,7 @@ This is the role of all the `baseXXX` component on the Data Grid component (`bas These slots receive props that should be as generic as possible so that it is easy to interface any other design system. Other slots allow you to override parts of the MUI X UI components with a custom UI built specifically for this component. -This is the role of slots like `calendarHeader` on the `DateCalendar` component or `item` on the `RichTreeView` component. +This is the role of slots like `calendarHeader` on the `DateCalendar` component or `item` on the Rich Tree View component. These slots receive props specific to this part of the UI and will most likely not be re-use throughout your application. ## Basic usage diff --git a/docs/data/data-grid/list-view/ListView.js b/docs/data/data-grid/list-view/ListView.js new file mode 100644 index 000000000000..a7ab930852af --- /dev/null +++ b/docs/data/data-grid/list-view/ListView.js @@ -0,0 +1,107 @@ +import * as React from 'react'; +import { DataGridPro } from '@mui/x-data-grid-pro'; +import Box from '@mui/material/Box'; +import { useDemoData } from '@mui/x-data-grid-generator'; +import Stack from '@mui/material/Stack'; +import Avatar from '@mui/material/Avatar'; +import Typography from '@mui/material/Typography'; +import Checkbox from '@mui/material/Checkbox'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import IconButton from '@mui/material/IconButton'; +import MessageIcon from '@mui/icons-material/Message'; + +function MessageAction(params) { + const handleMessage = () => { + console.log(`send message to ${params.row.phone}`); + }; + return ( + + + + ); +} + +function ListViewCell(params) { + return ( + + + + + {params.row.name} + + + {params.row.position} + + + + + ); +} + +const listColDef = { + field: 'listColumn', + renderCell: ListViewCell, +}; + +const VISIBLE_FIELDS = ['avatar', 'name', 'position']; + +export default function ListView() { + const [isListView, setIsListView] = React.useState(true); + + const { data } = useDemoData({ + dataSet: 'Employee', + rowLength: 20, + visibleFields: VISIBLE_FIELDS, + }); + + const columns = React.useMemo(() => { + return [ + ...data.columns, + { + type: 'actions', + field: 'actions', + width: 75, + getActions: (params) => [], + }, + ]; + }, [data.columns]); + + const rowHeight = isListView ? 64 : 52; + + return ( + + setIsListView(event.target.checked)} + /> + } + label="Enable list view" + /> + + + + + ); +} diff --git a/docs/data/data-grid/list-view/ListView.tsx b/docs/data/data-grid/list-view/ListView.tsx new file mode 100644 index 000000000000..40239d5a8e41 --- /dev/null +++ b/docs/data/data-grid/list-view/ListView.tsx @@ -0,0 +1,113 @@ +import * as React from 'react'; +import { + DataGridPro, + GridRenderCellParams, + GridListColDef, + GridColDef, + GridRowParams, +} from '@mui/x-data-grid-pro'; +import Box from '@mui/material/Box'; +import { useDemoData } from '@mui/x-data-grid-generator'; +import Stack from '@mui/material/Stack'; +import Avatar from '@mui/material/Avatar'; +import Typography from '@mui/material/Typography'; +import Checkbox from '@mui/material/Checkbox'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import IconButton from '@mui/material/IconButton'; +import MessageIcon from '@mui/icons-material/Message'; + +function MessageAction(params: Pick) { + const handleMessage = () => { + console.log(`send message to ${params.row.phone}`); + }; + return ( + + + + ); +} + +function ListViewCell(params: GridRenderCellParams) { + return ( + + + + + {params.row.name} + + + {params.row.position} + + + + + ); +} + +const listColDef: GridListColDef = { + field: 'listColumn', + renderCell: ListViewCell, +}; + +const VISIBLE_FIELDS = ['avatar', 'name', 'position']; + +export default function ListView() { + const [isListView, setIsListView] = React.useState(true); + + const { data } = useDemoData({ + dataSet: 'Employee', + rowLength: 20, + visibleFields: VISIBLE_FIELDS, + }); + + const columns: GridColDef[] = React.useMemo(() => { + return [ + ...data.columns, + { + type: 'actions', + field: 'actions', + width: 75, + getActions: (params) => [], + }, + ]; + }, [data.columns]); + + const rowHeight = isListView ? 64 : 52; + + return ( + + setIsListView(event.target.checked)} + /> + } + label="Enable list view" + /> + + + + + ); +} diff --git a/docs/data/data-grid/list-view/ListViewAdvanced.js b/docs/data/data-grid/list-view/ListViewAdvanced.js new file mode 100644 index 000000000000..b27633b63270 --- /dev/null +++ b/docs/data/data-grid/list-view/ListViewAdvanced.js @@ -0,0 +1,355 @@ +import * as React from 'react'; +import { + GridActionsCellItem, + useGridApiRef, + DataGridPremium, + gridClasses, +} from '@mui/x-data-grid-premium'; +import EditIcon from '@mui/icons-material/Edit'; +import DeleteIcon from '@mui/icons-material/Delete'; +import Avatar from '@mui/material/Avatar'; +import Stack from '@mui/material/Stack'; +import OpenIcon from '@mui/icons-material/Visibility'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import CSSBaseline from '@mui/material/CssBaseline'; +import { randomId } from '@mui/x-data-grid-generator'; +import { FileIcon } from './components/FileIcon'; +import { DetailsDrawer } from './components/DetailsDrawer'; +import { ListCell } from './components/ListCell'; +import { Toolbar } from './components/Toolbar'; +import { INITIAL_ROWS } from './data'; +import { FILE_TYPES } from './constants'; + +import { formatDate, formatSize, stringAvatar } from './utils'; +import { ActionDrawer } from './components/ActionDrawer'; +import { RenameDialog } from './components/RenameDialog'; + +export default function ListViewAdvanced() { + // This is used only for the example - renders the drawer inside the container + const containerRef = React.useRef(null); + const container = () => containerRef.current; + + const isListView = useMediaQuery('(min-width: 700px)'); + + const apiRef = useGridApiRef(); + + const [rows, setRows] = React.useState(INITIAL_ROWS); + + const [loading, setLoading] = React.useState(false); + + const [overlayState, setOverlayState] = React.useState({ + overlay: null, + params: null, + }); + + const handleCloseOverlay = () => { + setOverlayState({ overlay: null, params: null }); + }; + + const handleDelete = React.useCallback((ids) => { + setRows((prevRows) => prevRows.filter((row) => !ids.includes(row.id))); + }, []); + + const handleUpdate = React.useCallback((id, field, value) => { + setRows((prevRows) => + prevRows.map((row) => + row.id === id + ? { ...row, [field]: value, updatedAt: new Date().toISOString() } + : row, + ), + ); + }, []); + + const handleUpload = React.useCallback((event) => { + if (!event.target.files) { + return; + } + + const file = event.target.files[0]; + const createdAt = new Date().toISOString(); + + const fileType = file.type.split('/')[1]; + + // validate file type + if (!FILE_TYPES.includes(fileType)) { + alert('Invalid file type'); + return; + } + + const row = { + id: randomId(), + name: file.name, + description: '', + type: fileType, + size: file.size, + createdBy: 'Kenan Yusuf', + createdAt, + updatedAt: createdAt, + state: 'pending', + }; + + event.target.value = ''; + + // Add temporary row + setLoading(true); + setRows((prevRows) => [...prevRows, row]); + + // Simulate server response time + const timeout = Math.floor(Math.random() * 3000) + 2000; + setTimeout(() => { + const uploadedRow = { ...row, state: 'uploaded' }; + setRows((prevRows) => + prevRows.map((r) => (r.id === row.id ? uploadedRow : r)), + ); + setOverlayState({ overlay: 'actions', params: { row } }); + setLoading(false); + }, timeout); + }, []); + + const columns = React.useMemo( + () => [ + { + field: 'name', + headerName: 'Name', + width: 350, + editable: true, + hideable: false, + renderCell: (params) => { + return ( + + + {params.value} + + ); + }, + }, + { + field: 'createdBy', + headerName: 'Owner', + width: 200, + renderCell: (params) => { + const avatarProps = stringAvatar(params.value); + return ( + + + {params.value} + + ); + }, + }, + { + field: 'createdAt', + headerName: 'Added', + type: 'date', + width: 200, + valueFormatter: formatDate, + }, + { + field: 'updatedAt', + headerName: 'Modified', + type: 'date', + width: 200, + valueFormatter: formatDate, + }, + { + field: 'type', + headerName: 'Type', + width: 150, + }, + { + field: 'size', + headerName: 'Size', + width: 120, + valueFormatter: formatSize, + }, + { + type: 'actions', + field: 'actions', + resizable: false, + width: 50, + getActions: (params) => [ + } + onClick={() => { + setOverlayState({ overlay: 'actions', params }); + }} + showInMenu + />, + } + onClick={() => + apiRef.current?.startCellEditMode({ + id: params.id, + field: 'name', + }) + } + showInMenu + />, + } + onClick={() => handleDelete([params.id])} + showInMenu + />, + ], + }, + ], + [handleDelete, apiRef], + ); + + const listColDef = React.useMemo( + () => ({ + field: 'listCell', + renderCell: (params) => ( + { + setOverlayState({ overlay: 'actions', params }); + }} + /> + ), + }), + [], + ); + + const getEstimatedRowHeight = () => { + const density = apiRef.current?.state?.density; + + if (isListView) { + switch (density) { + case 'compact': + return 47; + case 'standard': + return 67; + case 'comfortable': + return 97; + default: + return 67; + } + } else { + switch (density) { + case 'compact': + return 47; + case 'standard': + return 55; + case 'comfortable': + return 63; + default: + return 55; + } + } + }; + + const getRowHeight = React.useCallback( + () => (isListView ? 'auto' : undefined), + [isListView], + ); + + return ( + + +
+ + setOverlayState({ overlay: 'actions', params }) + } + hideFooterSelectedRowCount + /> + handleUpdate(id, 'description', value)} + onClose={handleCloseOverlay} + /> + + setOverlayState({ overlay: 'details', params: overlayState.params }) + } + onRename={() => + setOverlayState({ overlay: 'rename', params: overlayState.params }) + } + onDelete={(id) => { + handleDelete([id]); + handleCloseOverlay(); + }} + onClose={handleCloseOverlay} + /> + handleUpdate(id, 'name', value)} + onClose={handleCloseOverlay} + /> +
+
+ ); +} diff --git a/docs/data/data-grid/list-view/ListViewAdvanced.tsx b/docs/data/data-grid/list-view/ListViewAdvanced.tsx new file mode 100644 index 000000000000..e7b9c692bede --- /dev/null +++ b/docs/data/data-grid/list-view/ListViewAdvanced.tsx @@ -0,0 +1,375 @@ +import * as React from 'react'; +import { + GridActionsCellItem, + GridColDef, + useGridApiRef, + GridRowParams, + DataGridPremium, + GridRowId, + gridClasses, + GridRowModel, +} from '@mui/x-data-grid-premium'; +import EditIcon from '@mui/icons-material/Edit'; +import DeleteIcon from '@mui/icons-material/Delete'; +import Avatar from '@mui/material/Avatar'; +import Stack from '@mui/material/Stack'; +import OpenIcon from '@mui/icons-material/Visibility'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import CSSBaseline from '@mui/material/CssBaseline'; +import { randomId } from '@mui/x-data-grid-generator'; +import { FileIcon } from './components/FileIcon'; +import { DetailsDrawer } from './components/DetailsDrawer'; +import { ListCell } from './components/ListCell'; +import { Toolbar } from './components/Toolbar'; +import { INITIAL_ROWS } from './data'; +import { FILE_TYPES } from './constants'; +import { RowModel, FileType } from './types'; +import { formatDate, formatSize, stringAvatar } from './utils'; +import { ActionDrawer } from './components/ActionDrawer'; +import { RenameDialog } from './components/RenameDialog'; + +export default function ListViewAdvanced() { + // This is used only for the example - renders the drawer inside the container + const containerRef = React.useRef(null); + const container = () => containerRef.current as HTMLElement; + + const isListView = useMediaQuery('(min-width: 700px)'); + + const apiRef = useGridApiRef(); + + const [rows, setRows] = React.useState[]>(INITIAL_ROWS); + + const [loading, setLoading] = React.useState(false); + + const [overlayState, setOverlayState] = React.useState<{ + overlay: 'actions' | 'details' | 'rename' | null; + params: Pick, 'row'> | null; + }>({ + overlay: null, + params: null, + }); + + const handleCloseOverlay = () => { + setOverlayState({ overlay: null, params: null }); + }; + + const handleDelete = React.useCallback((ids: GridRowId[]) => { + setRows((prevRows) => prevRows.filter((row) => !ids.includes(row.id))); + }, []); + + const handleUpdate = React.useCallback( + ( + id: GridRowId, + field: GridRowParams['columns'][number]['field'], + value: string, + ) => { + setRows((prevRows) => + prevRows.map((row) => + row.id === id + ? { ...row, [field]: value, updatedAt: new Date().toISOString() } + : row, + ), + ); + }, + [], + ); + + const handleUpload = React.useCallback( + (event: React.ChangeEvent) => { + if (!event.target.files) { + return; + } + + const file = event.target.files[0]; + const createdAt = new Date().toISOString(); + + const fileType = file.type.split('/')[1]; + + // validate file type + if (!FILE_TYPES.includes(fileType as FileType)) { + alert('Invalid file type'); + return; + } + + const row: RowModel = { + id: randomId(), + name: file.name, + description: '', + type: fileType as FileType, + size: file.size, + createdBy: 'Kenan Yusuf', + createdAt, + updatedAt: createdAt, + state: 'pending', + }; + + event.target.value = ''; + + // Add temporary row + setLoading(true); + setRows((prevRows) => [...prevRows, row]); + + // Simulate server response time + const timeout = Math.floor(Math.random() * 3000) + 2000; + setTimeout(() => { + const uploadedRow: RowModel = { ...row, state: 'uploaded' }; + setRows((prevRows) => + prevRows.map((r) => (r.id === row.id ? uploadedRow : r)), + ); + setOverlayState({ overlay: 'actions', params: { row } }); + setLoading(false); + }, timeout); + }, + [], + ); + + const columns: GridColDef[] = React.useMemo( + () => [ + { + field: 'name', + headerName: 'Name', + width: 350, + editable: true, + hideable: false, + renderCell: (params) => { + return ( + + + {params.value} + + ); + }, + }, + { + field: 'createdBy', + headerName: 'Owner', + width: 200, + renderCell: (params) => { + const avatarProps = stringAvatar(params.value); + return ( + + + {params.value} + + ); + }, + }, + { + field: 'createdAt', + headerName: 'Added', + type: 'date', + width: 200, + valueFormatter: formatDate, + }, + { + field: 'updatedAt', + headerName: 'Modified', + type: 'date', + width: 200, + valueFormatter: formatDate, + }, + { + field: 'type', + headerName: 'Type', + width: 150, + }, + { + field: 'size', + headerName: 'Size', + width: 120, + valueFormatter: formatSize, + }, + { + type: 'actions', + field: 'actions', + resizable: false, + width: 50, + getActions: (params) => [ + } + onClick={() => { + setOverlayState({ overlay: 'actions', params }); + }} + showInMenu + />, + } + onClick={() => + apiRef.current?.startCellEditMode({ + id: params.id, + field: 'name', + }) + } + showInMenu + />, + } + onClick={() => handleDelete([params.id])} + showInMenu + />, + ], + }, + ], + [handleDelete, apiRef], + ); + + const listColDef: GridColDef = React.useMemo( + () => ({ + field: 'listCell', + renderCell: (params) => ( + { + setOverlayState({ overlay: 'actions', params }); + }} + /> + ), + }), + [], + ); + + const getEstimatedRowHeight = () => { + const density = apiRef.current?.state?.density; + + if (isListView) { + switch (density) { + case 'compact': + return 47; + case 'standard': + return 67; + case 'comfortable': + return 97; + default: + return 67; + } + } else { + switch (density) { + case 'compact': + return 47; + case 'standard': + return 55; + case 'comfortable': + return 63; + default: + return 55; + } + } + }; + + const getRowHeight = React.useCallback( + () => (isListView ? 'auto' : undefined), + [isListView], + ); + + return ( + + +
+ + setOverlayState({ overlay: 'actions', params }) + } + hideFooterSelectedRowCount + /> + + handleUpdate(id, 'description', value)} + onClose={handleCloseOverlay} + /> + + + setOverlayState({ overlay: 'details', params: overlayState.params }) + } + onRename={() => + setOverlayState({ overlay: 'rename', params: overlayState.params }) + } + onDelete={(id) => { + handleDelete([id]); + handleCloseOverlay(); + }} + onClose={handleCloseOverlay} + /> + + handleUpdate(id, 'name', value)} + onClose={handleCloseOverlay} + /> +
+
+ ); +} diff --git a/docs/data/data-grid/list-view/components/ActionDrawer.js b/docs/data/data-grid/list-view/components/ActionDrawer.js new file mode 100644 index 000000000000..8c4e29e9955d --- /dev/null +++ b/docs/data/data-grid/list-view/components/ActionDrawer.js @@ -0,0 +1,88 @@ +import * as React from 'react'; + +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import EditIcon from '@mui/icons-material/Edit'; +import DeleteIcon from '@mui/icons-material/Delete'; +import OpenIcon from '@mui/icons-material/Visibility'; +import { FileIcon } from './FileIcon'; +import { formatDate, formatSize } from '../utils'; +import { Drawer, DrawerHeader } from './Drawer'; + +function DrawerContent(props) { + const { params, onDelete, onPreview, onRename } = props; + return ( + + + + + {params.row.name} + + + {params.row.createdBy} + + + · + + + {formatSize(params.row.size)} + + + + {params.row.updatedAt + ? `Updated ${formatDate(params.row.updatedAt)}` + : `Added ${formatDate(params.row.createdAt)}`} + + + + + + + + + + + Preview + + + + + + + + Rename + + + + onDelete(params.row.id)}> + + + + Delete + + + + + ); +} + +export function ActionDrawer(props) { + const { params, onPreview, onRename, onDelete, ...other } = props; + return ( + + {params && ( + + )} + + ); +} diff --git a/docs/data/data-grid/list-view/components/ActionDrawer.tsx b/docs/data/data-grid/list-view/components/ActionDrawer.tsx new file mode 100644 index 000000000000..533c8cddad5f --- /dev/null +++ b/docs/data/data-grid/list-view/components/ActionDrawer.tsx @@ -0,0 +1,101 @@ +import * as React from 'react'; +import { GridRowId, GridRowParams } from '@mui/x-data-grid-premium'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import EditIcon from '@mui/icons-material/Edit'; +import DeleteIcon from '@mui/icons-material/Delete'; +import OpenIcon from '@mui/icons-material/Visibility'; +import { FileIcon } from './FileIcon'; +import { formatDate, formatSize } from '../utils'; +import { Drawer, DrawerHeader, DrawerProps } from './Drawer'; +import { RowModel } from '../types'; + +interface ActionDrawerProps extends DrawerProps { + params: Pick, 'row'> | null; + onPreview: () => void; + onRename: () => void; + onDelete: (id: GridRowId) => void; +} + +function DrawerContent( + props: { params: Pick, 'row'> } & Pick< + ActionDrawerProps, + 'onDelete' | 'onPreview' | 'onRename' + >, +) { + const { params, onDelete, onPreview, onRename } = props; + return ( + + + + + {params.row.name} + + + {params.row.createdBy} + + + · + + + {formatSize(params.row.size)} + + + + {params.row.updatedAt + ? `Updated ${formatDate(params.row.updatedAt)}` + : `Added ${formatDate(params.row.createdAt)}`} + + + + + + + + + + + Preview + + + + + + + + Rename + + + + onDelete(params.row.id)}> + + + + Delete + + + + + ); +} + +export function ActionDrawer(props: ActionDrawerProps) { + const { params, onPreview, onRename, onDelete, ...other } = props; + return ( + + {params && ( + + )} + + ); +} diff --git a/docs/data/data-grid/list-view/components/Card.js b/docs/data/data-grid/list-view/components/Card.js new file mode 100644 index 000000000000..5d2e880bf605 --- /dev/null +++ b/docs/data/data-grid/list-view/components/Card.js @@ -0,0 +1,70 @@ +import * as React from 'react'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; + +export function Card(props) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardMedia(props) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardContent(props) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardTitle(props) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardDetailList(props) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardDetail(props) { + const { children, ...other } = props; + return ( + + {children} + + ); +} diff --git a/docs/data/data-grid/list-view/components/Card.tsx b/docs/data/data-grid/list-view/components/Card.tsx new file mode 100644 index 000000000000..bd0df76f5db1 --- /dev/null +++ b/docs/data/data-grid/list-view/components/Card.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import Stack, { StackProps } from '@mui/material/Stack'; +import Typography, { TypographyProps } from '@mui/material/Typography'; + +export function Card(props: StackProps) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardMedia(props: StackProps) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardContent(props: StackProps) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardTitle(props: TypographyProps) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardDetailList(props: StackProps) { + const { children, ...other } = props; + return ( + + {children} + + ); +} + +export function CardDetail(props: TypographyProps) { + const { children, ...other } = props; + return ( + + {children} + + ); +} diff --git a/docs/data/data-grid/list-view/components/DetailsDrawer.js b/docs/data/data-grid/list-view/components/DetailsDrawer.js new file mode 100644 index 000000000000..44b1808c622b --- /dev/null +++ b/docs/data/data-grid/list-view/components/DetailsDrawer.js @@ -0,0 +1,142 @@ +import * as React from 'react'; + +import Divider from '@mui/material/Divider'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import TextField from '@mui/material/TextField'; +import Avatar from '@mui/material/Avatar'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; +import { Drawer, DrawerHeader } from './Drawer'; +import { FileIcon } from './FileIcon'; +import { formatDate, formatSize, stringAvatar } from '../utils'; + +function Thumbnail() { + return ( + ({ + aspectRatio: '16/9', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: 'text.secondary', + borderRadius: 2, + gap: 1, + backgroundColor: 'grey.200', + ...theme.applyStyles('dark', { + backgroundColor: 'grey.800', + }), + })} + > + + + No preview available + + + ); +} + +function DrawerContent(props) { + const { params, onDescriptionChange, onClose } = props; + const [description, setDescription] = React.useState(params.row.description || ''); + const avatarProps = stringAvatar(params.row.createdBy); + + const handleSave = (event) => { + onDescriptionChange(params.row.id, description); + onClose(event); + }; + + return ( + + + + {params.row.name} + + + + + + setDescription(event.target.value)} + sx={{ mt: 1 }} + multiline + /> + + + + Type + + {params.row.type} + + + + + Size + + {formatSize(params.row.size)} + + + + + Created + + {formatDate(params.row.createdAt)} + + + + + Modified + + {formatDate(params.row.updatedAt)} + + + + + Owner + + + + + {params.row.createdBy} + + + + ); +} + +export function DetailsDrawer(props) { + const { params, listView, onDescriptionChange, onClose, ...other } = props; + return ( + + {params && ( + + )} + + ); +} diff --git a/docs/data/data-grid/list-view/components/DetailsDrawer.tsx b/docs/data/data-grid/list-view/components/DetailsDrawer.tsx new file mode 100644 index 000000000000..6e4f2545dfeb --- /dev/null +++ b/docs/data/data-grid/list-view/components/DetailsDrawer.tsx @@ -0,0 +1,158 @@ +import * as React from 'react'; +import { GridRowId, GridRowParams } from '@mui/x-data-grid-premium'; +import Divider from '@mui/material/Divider'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import TextField from '@mui/material/TextField'; +import Avatar from '@mui/material/Avatar'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; +import { Drawer, DrawerHeader, DrawerProps } from './Drawer'; +import { FileIcon } from './FileIcon'; +import { formatDate, formatSize, stringAvatar } from '../utils'; +import { RowModel } from '../types'; + +interface DetailsDrawerProps extends DrawerProps { + params: Pick, 'row'> | null; + listView: boolean; + onDescriptionChange: (id: GridRowId, value: string) => void; +} + +function Thumbnail() { + return ( + ({ + aspectRatio: '16/9', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: 'text.secondary', + borderRadius: 2, + gap: 1, + backgroundColor: 'grey.200', + ...theme.applyStyles('dark', { + backgroundColor: 'grey.800', + }), + })} + > + + + No preview available + + + ); +} + +function DrawerContent( + props: { params: Pick, 'row'> } & Pick< + DetailsDrawerProps, + 'onDescriptionChange' | 'onClose' + >, +) { + const { params, onDescriptionChange, onClose } = props; + const [description, setDescription] = React.useState(params.row.description || ''); + const avatarProps = stringAvatar(params.row.createdBy); + + const handleSave = (event: React.MouseEvent) => { + onDescriptionChange(params.row.id, description); + onClose(event); + }; + + return ( + + + + {params.row.name} + + + + + + + setDescription(event.target.value)} + sx={{ mt: 1 }} + multiline + /> + + + + + + Type + + {params.row.type} + + + + + Size + + {formatSize(params.row.size)} + + + + + Created + + {formatDate(params.row.createdAt)} + + + + + Modified + + {formatDate(params.row.updatedAt)} + + + + + + Owner + + + + + {params.row.createdBy} + + + + ); +} + +export function DetailsDrawer(props: DetailsDrawerProps) { + const { params, listView, onDescriptionChange, onClose, ...other } = props; + return ( + + {params && ( + + )} + + ); +} diff --git a/docs/data/data-grid/list-view/components/Drawer.js b/docs/data/data-grid/list-view/components/Drawer.js new file mode 100644 index 000000000000..fcf9d182a6a3 --- /dev/null +++ b/docs/data/data-grid/list-view/components/Drawer.js @@ -0,0 +1,88 @@ +import * as React from 'react'; +import MUISwipeableDrawer from '@mui/material/SwipeableDrawer'; +import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; +import Paper from '@mui/material/Paper'; +import { useMediaQuery } from '@mui/system'; + +function SwipeIndicator() { + return ( + + + + ); +} + +export function DrawerHeader(props) { + const { children, ...other } = props; + + return ( + + + {children} + + + ); +} + +export function Drawer(props) { + const { children, anchor, width = 320, container, ...other } = props; + const isBottomDrawer = anchor === 'bottom'; + const isTouch = useMediaQuery('(hover: none)'); + + return ( + {}} // required by SwipeableDrawer but not used in this demo + > + {isTouch && isBottomDrawer && } + {children} + + ); +} diff --git a/docs/data/data-grid/list-view/components/Drawer.tsx b/docs/data/data-grid/list-view/components/Drawer.tsx new file mode 100644 index 000000000000..a859781e4417 --- /dev/null +++ b/docs/data/data-grid/list-view/components/Drawer.tsx @@ -0,0 +1,97 @@ +import * as React from 'react'; +import MUISwipeableDrawer, { + SwipeableDrawerProps as MUISwipeableDrawerProps, +} from '@mui/material/SwipeableDrawer'; +import Box from '@mui/material/Box'; +import Stack, { StackProps } from '@mui/material/Stack'; +import Paper from '@mui/material/Paper'; +import { useMediaQuery } from '@mui/system'; + +function SwipeIndicator() { + return ( + + + + ); +} + +export interface DrawerHeaderProps extends StackProps {} + +export function DrawerHeader(props: DrawerHeaderProps) { + const { children, ...other } = props; + + return ( + + + {children} + + + ); +} + +export interface DrawerProps extends Omit { + width?: number; + container?: () => HTMLElement; +} + +export function Drawer(props: DrawerProps) { + const { children, anchor, width = 320, container, ...other } = props; + const isBottomDrawer = anchor === 'bottom'; + const isTouch = useMediaQuery('(hover: none)'); + + return ( + {}} // required by SwipeableDrawer but not used in this demo + > + {isTouch && isBottomDrawer && } + {children} + + ); +} diff --git a/docs/data/data-grid/list-view/components/FileIcon.js b/docs/data/data-grid/list-view/components/FileIcon.js new file mode 100644 index 000000000000..bc1818bb50f4 --- /dev/null +++ b/docs/data/data-grid/list-view/components/FileIcon.js @@ -0,0 +1,47 @@ +import * as React from 'react'; +import SvgIcon from '@mui/material/SvgIcon'; +import TextSnippetIcon from '@mui/icons-material/TextSnippet'; +import VideocamIcon from '@mui/icons-material/Videocam'; +import ImageIcon from '@mui/icons-material/Image'; +import FolderZipIcon from '@mui/icons-material/FolderZip'; + +const FILE_TYPE_ICONS = { + video: { + component: VideocamIcon, + color: 'error', + }, + image: { + component: ImageIcon, + color: 'error', + }, + document: { + component: TextSnippetIcon, + color: 'primary', + }, + archive: { + component: FolderZipIcon, + color: 'inherit', + }, +}; + +const FILE_ICON = { + pdf: FILE_TYPE_ICONS.document, + docx: FILE_TYPE_ICONS.document, + txt: FILE_TYPE_ICONS.document, + mp4: FILE_TYPE_ICONS.video, + mov: FILE_TYPE_ICONS.video, + webm: FILE_TYPE_ICONS.video, + jpg: FILE_TYPE_ICONS.image, + jpeg: FILE_TYPE_ICONS.image, + png: FILE_TYPE_ICONS.image, + gif: FILE_TYPE_ICONS.image, + tiff: FILE_TYPE_ICONS.image, + webp: FILE_TYPE_ICONS.image, + zip: FILE_TYPE_ICONS.archive, +}; + +export function FileIcon(props) { + const { type } = props; + const iconProps = FILE_ICON[type]; + return ; +} diff --git a/docs/data/data-grid/list-view/components/FileIcon.tsx b/docs/data/data-grid/list-view/components/FileIcon.tsx new file mode 100644 index 000000000000..ac70cced33bf --- /dev/null +++ b/docs/data/data-grid/list-view/components/FileIcon.tsx @@ -0,0 +1,54 @@ +import * as React from 'react'; +import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; +import TextSnippetIcon from '@mui/icons-material/TextSnippet'; +import VideocamIcon from '@mui/icons-material/Videocam'; +import ImageIcon from '@mui/icons-material/Image'; +import FolderZipIcon from '@mui/icons-material/FolderZip'; +import { FileType } from '../types'; + +const FILE_TYPE_ICONS = { + video: { + component: VideocamIcon, + color: 'error', + }, + image: { + component: ImageIcon, + color: 'error', + }, + document: { + component: TextSnippetIcon, + color: 'primary', + }, + archive: { + component: FolderZipIcon, + color: 'inherit', + }, +} satisfies Record< + string, + { component: React.ElementType; color: SvgIconProps['color'] } +>; + +const FILE_ICON: Record< + FileType, + { component: React.ElementType; color: SvgIconProps['color'] } +> = { + pdf: FILE_TYPE_ICONS.document, + docx: FILE_TYPE_ICONS.document, + txt: FILE_TYPE_ICONS.document, + mp4: FILE_TYPE_ICONS.video, + mov: FILE_TYPE_ICONS.video, + webm: FILE_TYPE_ICONS.video, + jpg: FILE_TYPE_ICONS.image, + jpeg: FILE_TYPE_ICONS.image, + png: FILE_TYPE_ICONS.image, + gif: FILE_TYPE_ICONS.image, + tiff: FILE_TYPE_ICONS.image, + webp: FILE_TYPE_ICONS.image, + zip: FILE_TYPE_ICONS.archive, +}; + +export function FileIcon(props: SvgIconProps & { type: FileType }) { + const { type } = props; + const iconProps = FILE_ICON[type]; + return ; +} diff --git a/docs/data/data-grid/list-view/components/ListCell.js b/docs/data/data-grid/list-view/components/ListCell.js new file mode 100644 index 000000000000..19c1688b1d74 --- /dev/null +++ b/docs/data/data-grid/list-view/components/ListCell.js @@ -0,0 +1,110 @@ +import * as React from 'react'; +import { + gridColumnVisibilityModelSelector, + gridDensitySelector, + useGridApiContext, + useGridSelector, +} from '@mui/x-data-grid-premium'; +import IconButton from '@mui/material/IconButton'; +import Box from '@mui/material/Box'; +import GridMoreVertIcon from '@mui/icons-material/MoreVert'; +import { + Card, + CardContent, + CardDetailList, + CardDetail, + CardTitle, + CardMedia, +} from './Card'; +import { FileIcon } from './FileIcon'; +import { formatDate, formatSize } from '../utils'; + +const ICON_SIZE_BY_DENSITY = { + compact: 24, + standard: 32, + comfortable: 16, +}; + +function Thumbnail(props) { + const { fileIcon } = props; + return ( + ({ + position: 'relative', + borderRadius: 1, + width: 64, + height: 64, + overflow: 'hidden', + backgroundColor: 'grey.200', + ...theme.applyStyles('dark', { + backgroundColor: 'grey.800', + }), + })} + > + + {fileIcon} + + + ); +} + +export function ListCell(props) { + const { onOpenActions, ...params } = props; + const apiRef = useGridApiContext(); + const density = useGridSelector(apiRef, gridDensitySelector); + const columnVisibilityModel = useGridSelector( + apiRef, + gridColumnVisibilityModelSelector, + ); + + const showCreatedBy = columnVisibilityModel.createdBy !== false; + const showSize = columnVisibilityModel.size !== false; + const showCreatedAt = columnVisibilityModel.createdAt !== false; + const showUpdatedAt = columnVisibilityModel.updatedAt !== false; + const showThumbnail = density === 'comfortable'; + + const icon = ( + + ); + + return ( + + {showThumbnail ? : icon} + + {params.row.name} + {density !== 'compact' && (showCreatedBy || showSize) && ( + + {showCreatedBy && {params.row.createdBy}} + {showSize && {formatSize(params.row.size)}} + + )} + {density === 'comfortable' && (showCreatedAt || showUpdatedAt) && ( + + {showUpdatedAt && `Updated ${formatDate(params.row.updatedAt)}`} + + )} + + + { + event.stopPropagation(); + onOpenActions(); + }} + sx={{ mr: -0.75 }} + > + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ListCell.tsx b/docs/data/data-grid/list-view/components/ListCell.tsx new file mode 100644 index 000000000000..250d5b82c217 --- /dev/null +++ b/docs/data/data-grid/list-view/components/ListCell.tsx @@ -0,0 +1,117 @@ +import * as React from 'react'; +import { + gridColumnVisibilityModelSelector, + GridDensity, + gridDensitySelector, + GridRenderCellParams, + useGridApiContext, + useGridSelector, +} from '@mui/x-data-grid-premium'; +import IconButton from '@mui/material/IconButton'; +import Box from '@mui/material/Box'; +import GridMoreVertIcon from '@mui/icons-material/MoreVert'; +import { + Card, + CardContent, + CardDetailList, + CardDetail, + CardTitle, + CardMedia, +} from './Card'; +import { FileIcon } from './FileIcon'; +import { formatDate, formatSize } from '../utils'; +import { RowModel } from '../types'; + +interface ListCellProps extends GridRenderCellParams { + onOpenActions: () => void; +} + +const ICON_SIZE_BY_DENSITY: Record = { + compact: 24, + standard: 32, + comfortable: 16, +}; + +function Thumbnail(props: { fileIcon: React.ReactNode }) { + const { fileIcon } = props; + return ( + ({ + position: 'relative', + borderRadius: 1, + width: 64, + height: 64, + overflow: 'hidden', + backgroundColor: 'grey.200', + ...theme.applyStyles('dark', { + backgroundColor: 'grey.800', + }), + })} + > + + {fileIcon} + + + ); +} + +export function ListCell(props: ListCellProps) { + const { onOpenActions, ...params } = props; + const apiRef = useGridApiContext(); + const density = useGridSelector(apiRef, gridDensitySelector); + const columnVisibilityModel = useGridSelector( + apiRef, + gridColumnVisibilityModelSelector, + ); + + const showCreatedBy = columnVisibilityModel.createdBy !== false; + const showSize = columnVisibilityModel.size !== false; + const showCreatedAt = columnVisibilityModel.createdAt !== false; + const showUpdatedAt = columnVisibilityModel.updatedAt !== false; + const showThumbnail = density === 'comfortable'; + + const icon = ( + + ); + + return ( + + {showThumbnail ? : icon} + + {params.row.name} + {density !== 'compact' && (showCreatedBy || showSize) && ( + + {showCreatedBy && {params.row.createdBy}} + {showSize && {formatSize(params.row.size)}} + + )} + {density === 'comfortable' && (showCreatedAt || showUpdatedAt) && ( + + {showUpdatedAt && `Updated ${formatDate(params.row.updatedAt)}`} + + )} + + + { + event.stopPropagation(); + onOpenActions(); + }} + sx={{ mr: -0.75 }} + > + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/RenameDialog.js b/docs/data/data-grid/list-view/components/RenameDialog.js new file mode 100644 index 000000000000..b7d1a49972c4 --- /dev/null +++ b/docs/data/data-grid/list-view/components/RenameDialog.js @@ -0,0 +1,58 @@ +import * as React from 'react'; + +import Dialog from '@mui/material/Dialog'; +import DialogTitle from '@mui/material/DialogTitle'; +import DialogContent from '@mui/material/DialogContent'; +import DialogActions from '@mui/material/DialogActions'; +import Button from '@mui/material/Button'; +import TextField from '@mui/material/TextField'; + +export function RenameDialog(props) { + const { params, open, container, onSave, onClose } = props; + + const handleSave = (event) => { + event.preventDefault(); + + const formData = new FormData(event.currentTarget); + const value = formData.get('name'); + + onSave(params.row.id, value); + + onClose(); + }; + + return ( + + {params && ( + + Rename file + + + + + + + + + )} + + ); +} diff --git a/docs/data/data-grid/list-view/components/RenameDialog.tsx b/docs/data/data-grid/list-view/components/RenameDialog.tsx new file mode 100644 index 000000000000..670e77c81ecd --- /dev/null +++ b/docs/data/data-grid/list-view/components/RenameDialog.tsx @@ -0,0 +1,67 @@ +import * as React from 'react'; +import { GridRowId, GridRowParams } from '@mui/x-data-grid-premium'; +import Dialog from '@mui/material/Dialog'; +import DialogTitle from '@mui/material/DialogTitle'; +import DialogContent from '@mui/material/DialogContent'; +import DialogActions from '@mui/material/DialogActions'; +import Button from '@mui/material/Button'; +import TextField from '@mui/material/TextField'; +import { RowModel } from '../types'; + +export interface RenameDialogProps { + params: Pick, 'row'> | null; + open: boolean; + container?: () => HTMLElement; + onSave: (id: GridRowId, value: string) => void; + onClose: () => void; +} + +export function RenameDialog(props: RenameDialogProps) { + const { params, open, container, onSave, onClose } = props; + + const handleSave = (event: React.FormEvent) => { + event.preventDefault(); + + const formData = new FormData(event.currentTarget); + const value = formData.get('name') as string; + + onSave(params!.row.id, value); + + onClose(); + }; + + return ( + + {params && ( + + Rename file + + + + + + + + + )} + + ); +} diff --git a/docs/data/data-grid/list-view/components/Toolbar.js b/docs/data/data-grid/list-view/components/Toolbar.js new file mode 100644 index 000000000000..412b5dc9f3c5 --- /dev/null +++ b/docs/data/data-grid/list-view/components/Toolbar.js @@ -0,0 +1,105 @@ +import * as React from 'react'; +import { + GridClearIcon, + GridDeleteIcon, + GridToolbarContainer, + GridToolbarQuickFilter, + selectedGridRowsSelector, + useGridApiContext, + useGridSelector, +} from '@mui/x-data-grid-premium'; +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; +import { outlinedInputClasses } from '@mui/material/OutlinedInput'; +import { iconButtonClasses } from '@mui/material/IconButton'; +import { ToolbarAddItem } from './ToolbarAddItem'; +import { ToolbarColumnsItem } from './ToolbarColumnsItem'; +import { ToolbarSortItem } from './ToolbarSortItem'; +import { ToolbarDensityItem } from './ToolbarDensityItem'; +import { ToolbarFilterItem } from './ToolbarFilterItem'; +import { ToolbarButton } from './ToolbarButton'; + +export function Toolbar(props) { + const { listView = false, container, handleUpload, handleDelete } = props; + const apiRef = useGridApiContext(); + const selectedRows = useGridSelector(apiRef, selectedGridRowsSelector); + const selectionCount = selectedRows.size; + const showSelectionOptions = selectionCount > 0; + + const handleClearSelection = () => { + apiRef.current.setRowSelectionModel([]); + }; + + const handleDeleteSelectedRows = () => { + handleClearSelection(); + handleDelete?.(Array.from(selectedRows.keys())); + }; + + const itemProps = { + listView, + container, + }; + + return ( + + {showSelectionOptions ? ( + + + + + + {selectionCount} selected + + + + + + ) : ( + + + + + + + + + + + + )} + + ); +} diff --git a/docs/data/data-grid/list-view/components/Toolbar.tsx b/docs/data/data-grid/list-view/components/Toolbar.tsx new file mode 100644 index 000000000000..62980799d4b2 --- /dev/null +++ b/docs/data/data-grid/list-view/components/Toolbar.tsx @@ -0,0 +1,115 @@ +import * as React from 'react'; +import { + GridClearIcon, + GridDeleteIcon, + GridRowId, + GridToolbarContainer, + GridToolbarProps, + GridToolbarQuickFilter, + selectedGridRowsSelector, + useGridApiContext, + useGridSelector, +} from '@mui/x-data-grid-premium'; +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; +import { outlinedInputClasses } from '@mui/material/OutlinedInput'; +import { iconButtonClasses } from '@mui/material/IconButton'; +import { ToolbarAddItem } from './ToolbarAddItem'; +import { ToolbarColumnsItem } from './ToolbarColumnsItem'; +import { ToolbarSortItem } from './ToolbarSortItem'; +import { ToolbarDensityItem } from './ToolbarDensityItem'; +import { ToolbarFilterItem } from './ToolbarFilterItem'; +import { ToolbarButton } from './ToolbarButton'; +import { DrawerProps } from './Drawer'; + +export interface ToolbarProps extends GridToolbarProps { + container?: DrawerProps['container']; + listView?: boolean; + handleDelete?: (ids: GridRowId[]) => void; + handleUpload?: (event: React.ChangeEvent) => void; +} + +export function Toolbar(props: ToolbarProps) { + const { listView = false, container, handleUpload, handleDelete } = props; + const apiRef = useGridApiContext(); + const selectedRows = useGridSelector(apiRef, selectedGridRowsSelector); + const selectionCount = selectedRows.size; + const showSelectionOptions = selectionCount > 0; + + const handleClearSelection = () => { + apiRef.current.setRowSelectionModel([]); + }; + + const handleDeleteSelectedRows = () => { + handleClearSelection(); + handleDelete?.(Array.from(selectedRows.keys())); + }; + + const itemProps = { + listView, + container, + }; + + return ( + + {showSelectionOptions ? ( + + + + + + {selectionCount} selected + + + + + + ) : ( + + + + + + + + + + + + )} + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarAddItem.js b/docs/data/data-grid/list-view/components/ToolbarAddItem.js new file mode 100644 index 000000000000..48053f1bb08f --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarAddItem.js @@ -0,0 +1,75 @@ +import * as React from 'react'; +import AddIcon from '@mui/icons-material/Add'; +import CloudUploadIcon from '@mui/icons-material/CloudUpload'; +import NewFolderIcon from '@mui/icons-material/CreateNewFolder'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import Typography from '@mui/material/Typography'; + +import { ToolbarButton } from './ToolbarButton'; +import { Drawer, DrawerHeader } from './Drawer'; + +const ListItemUploadButton = React.forwardRef( + function ListItemUploadButton(props, ref) { + const { children, ...other } = props; + return ( + + {children} + + ); + }, +); + +export function ToolbarAddItem(props) { + const { container } = props; + const [open, setOpen] = React.useState(false); + const { handleUpload, listView } = props; + + const handleFileSelect = (event) => { + handleUpload?.(event); + setOpen(false); + }; + + return ( + + setOpen(true)}> + + + + setOpen(false)} + > + + Add new + + + + + + + + + Upload file + + + + + + {}} disabled> + + + + New folder + + + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarAddItem.tsx b/docs/data/data-grid/list-view/components/ToolbarAddItem.tsx new file mode 100644 index 000000000000..a3c43ffda857 --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarAddItem.tsx @@ -0,0 +1,81 @@ +import * as React from 'react'; +import AddIcon from '@mui/icons-material/Add'; +import CloudUploadIcon from '@mui/icons-material/CloudUpload'; +import NewFolderIcon from '@mui/icons-material/CreateNewFolder'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import Typography from '@mui/material/Typography'; +import { ButtonProps } from '@mui/material/Button'; +import { ToolbarButton } from './ToolbarButton'; +import { Drawer, DrawerHeader, DrawerProps } from './Drawer'; + +const ListItemUploadButton = React.forwardRef( + function ListItemUploadButton(props, ref) { + const { children, ...other } = props; + return ( + + {children} + + ); + }, +); + +export interface ToolbarAddItemProps { + container: DrawerProps['container']; + listView: boolean; + handleUpload?: (event: React.ChangeEvent) => void; +} + +export function ToolbarAddItem(props: ToolbarAddItemProps) { + const { container } = props; + const [open, setOpen] = React.useState(false); + const { handleUpload, listView } = props; + + const handleFileSelect = (event: React.ChangeEvent) => { + handleUpload?.(event); + setOpen(false); + }; + + return ( + + setOpen(true)}> + + + + setOpen(false)} + > + + Add new + + + + + + + + + Upload file + + + + + + {}} disabled> + + + + New folder + + + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarButton.js b/docs/data/data-grid/list-view/components/ToolbarButton.js new file mode 100644 index 000000000000..7ed7b6f21a51 --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarButton.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import IconButton from '@mui/material/IconButton'; + +export function ToolbarButton(props) { + const { className, children, ...other } = props; + return {children}; +} diff --git a/docs/data/data-grid/list-view/components/ToolbarButton.tsx b/docs/data/data-grid/list-view/components/ToolbarButton.tsx new file mode 100644 index 000000000000..48b5dcf1ed30 --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarButton.tsx @@ -0,0 +1,8 @@ +import * as React from 'react'; +import IconButton from '@mui/material/IconButton'; +import { ButtonProps } from '@mui/material/Button'; + +export function ToolbarButton(props: ButtonProps) { + const { className, children, ...other } = props; + return {children}; +} diff --git a/docs/data/data-grid/list-view/components/ToolbarColumnsItem.js b/docs/data/data-grid/list-view/components/ToolbarColumnsItem.js new file mode 100644 index 000000000000..e6fe57471fd5 --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarColumnsItem.js @@ -0,0 +1,78 @@ +import * as React from 'react'; +import { + GridColumnIcon, + useGridApiContext, + useGridSelector, + gridColumnDefinitionsSelector, + gridColumnVisibilityModelSelector, +} from '@mui/x-data-grid-premium'; +import CheckBoxIcon from '@mui/icons-material/CheckBox'; +import CheckBoxBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; +import Typography from '@mui/material/Typography'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import { ToolbarButton } from './ToolbarButton'; +import { Drawer, DrawerHeader } from './Drawer'; + +export function ToolbarColumnsItem(props) { + const { listView, container } = props; + const [open, setOpen] = React.useState(false); + const apiRef = useGridApiContext(); + const columns = useGridSelector(apiRef, gridColumnDefinitionsSelector); + const columnVisibilityModel = useGridSelector( + apiRef, + gridColumnVisibilityModelSelector, + ); + + const toggleFieldVisibility = (field) => { + apiRef.current.setColumnVisibility( + field, + columnVisibilityModel[field] === false, + ); + }; + + return ( + + setOpen(true)}> + + + + setOpen(false)} + > + + Fields + + + + {columns.map((column) => { + const isVisible = columnVisibilityModel[column.field] !== false; + return ( + + toggleFieldVisibility(column.field)} + disabled={column.hideable === false} + > + + {isVisible ? ( + + ) : ( + + )} + + {column.headerName || column.field} + + + ); + })} + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarColumnsItem.tsx b/docs/data/data-grid/list-view/components/ToolbarColumnsItem.tsx new file mode 100644 index 000000000000..f4f55499d06e --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarColumnsItem.tsx @@ -0,0 +1,83 @@ +import * as React from 'react'; +import { + GridColumnIcon, + useGridApiContext, + useGridSelector, + gridColumnDefinitionsSelector, + gridColumnVisibilityModelSelector, +} from '@mui/x-data-grid-premium'; +import CheckBoxIcon from '@mui/icons-material/CheckBox'; +import CheckBoxBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; +import Typography from '@mui/material/Typography'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import { ToolbarButton } from './ToolbarButton'; +import { Drawer, DrawerHeader, DrawerProps } from './Drawer'; + +interface ToolbarColumnsItemProps { + listView: boolean; + container: DrawerProps['container']; +} + +export function ToolbarColumnsItem(props: ToolbarColumnsItemProps) { + const { listView, container } = props; + const [open, setOpen] = React.useState(false); + const apiRef = useGridApiContext(); + const columns = useGridSelector(apiRef, gridColumnDefinitionsSelector); + const columnVisibilityModel = useGridSelector( + apiRef, + gridColumnVisibilityModelSelector, + ); + + const toggleFieldVisibility = (field: string) => { + apiRef.current.setColumnVisibility( + field, + columnVisibilityModel[field] === false, + ); + }; + + return ( + + setOpen(true)}> + + + + setOpen(false)} + > + + Fields + + + + {columns.map((column) => { + const isVisible = columnVisibilityModel[column.field] !== false; + return ( + + toggleFieldVisibility(column.field)} + disabled={column.hideable === false} + > + + {isVisible ? ( + + ) : ( + + )} + + {column.headerName || column.field} + + + ); + })} + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarDensityItem.js b/docs/data/data-grid/list-view/components/ToolbarDensityItem.js new file mode 100644 index 000000000000..afb8447721ee --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarDensityItem.js @@ -0,0 +1,87 @@ +import * as React from 'react'; +import { + GridViewStreamIcon, + useGridApiContext, + useGridSelector, + gridDensitySelector, + GridCheckIcon, + GridViewHeadlineIcon, + GridTableRowsIcon, +} from '@mui/x-data-grid-premium'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import Typography from '@mui/material/Typography'; +import { Drawer, DrawerHeader } from './Drawer'; +import { ToolbarButton } from './ToolbarButton'; + +const DENSITY_ICONS = { + compact: GridViewHeadlineIcon, + standard: GridTableRowsIcon, + comfortable: GridViewStreamIcon, +}; + +const DENSITY_OPTIONS = [ + { + label: 'Compact', + value: 'compact', + }, + { + label: 'Standard', + value: 'standard', + }, + { + label: 'Comfortable', + value: 'comfortable', + }, +]; + +export function ToolbarDensityItem(props) { + const { listView, container } = props; + const [open, setOpen] = React.useState(false); + const apiRef = useGridApiContext(); + const density = useGridSelector(apiRef, gridDensitySelector); + + const handleDensityChange = (value) => { + apiRef.current.setDensity(value); + setOpen(false); + }; + + const Icon = DENSITY_ICONS[density]; + + return ( + + setOpen(true)}> + + + + setOpen(false)} + > + + Density + + + + {DENSITY_OPTIONS.map((option) => { + const isActive = density === option.value; + + return ( + + handleDensityChange(option.value)}> + {isActive ? : null} + {option.label} + + + ); + })} + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarDensityItem.tsx b/docs/data/data-grid/list-view/components/ToolbarDensityItem.tsx new file mode 100644 index 000000000000..8f9ce7a1846e --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarDensityItem.tsx @@ -0,0 +1,94 @@ +import * as React from 'react'; +import { + GridViewStreamIcon, + useGridApiContext, + useGridSelector, + GridDensityOption, + gridDensitySelector, + GridCheckIcon, + GridDensity, + GridViewHeadlineIcon, + GridTableRowsIcon, +} from '@mui/x-data-grid-premium'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import Typography from '@mui/material/Typography'; +import { Drawer, DrawerHeader, DrawerProps } from './Drawer'; +import { ToolbarButton } from './ToolbarButton'; + +const DENSITY_ICONS = { + compact: GridViewHeadlineIcon, + standard: GridTableRowsIcon, + comfortable: GridViewStreamIcon, +}; + +const DENSITY_OPTIONS: Omit[] = [ + { + label: 'Compact', + value: 'compact', + }, + { + label: 'Standard', + value: 'standard', + }, + { + label: 'Comfortable', + value: 'comfortable', + }, +]; + +interface ToolbarDensityItemProps { + listView: boolean; + container: DrawerProps['container']; +} + +export function ToolbarDensityItem(props: ToolbarDensityItemProps) { + const { listView, container } = props; + const [open, setOpen] = React.useState(false); + const apiRef = useGridApiContext(); + const density = useGridSelector(apiRef, gridDensitySelector); + + const handleDensityChange = (value: GridDensity) => { + apiRef.current.setDensity(value); + setOpen(false); + }; + + const Icon = DENSITY_ICONS[density]; + + return ( + + setOpen(true)}> + + + + setOpen(false)} + > + + Density + + + + {DENSITY_OPTIONS.map((option) => { + const isActive = density === option.value; + + return ( + + handleDensityChange(option.value)}> + {isActive ? : null} + {option.label} + + + ); + })} + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarFilterItem.js b/docs/data/data-grid/list-view/components/ToolbarFilterItem.js new file mode 100644 index 000000000000..06cdb3c4690e --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarFilterItem.js @@ -0,0 +1,217 @@ +import * as React from 'react'; +import { + GridFilterListIcon, + useGridApiContext, + useGridSelector, + gridFilterActiveItemsSelector, + GridCheckIcon, +} from '@mui/x-data-grid-premium'; +import Badge from '@mui/material/Badge'; +import Typography from '@mui/material/Typography'; +import Divider from '@mui/material/Divider'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; +import ListSubheader from '@mui/material/ListSubheader'; +import CheckBoxIcon from '@mui/icons-material/CheckBox'; +import CheckBoxBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; +import FilterAltOffIcon from '@mui/icons-material/FilterAltOff'; +import { Drawer, DrawerHeader } from './Drawer'; +import { ToolbarButton } from './ToolbarButton'; + +import { FILE_TYPES } from '../constants'; + +const DATE_MODIFIED_FILTERS = [ + { + label: 'All', + id: 'all', + }, + { + label: 'Today', + id: 'today', + operator: 'onOrAfter', + value: new Date(new Date().setHours(0, 0, 0, 0)).toISOString(), + }, + { + label: 'Last week', + id: 'last-week', + operator: 'onOrAfter', + value: new Date( + new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0), + ).toISOString(), + }, + { + label: 'Last month', + id: 'last-month', + operator: 'onOrAfter', + value: new Date( + new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0), + ).toISOString(), + }, + { + label: 'Last 3 months', + id: 'last-3-months', + operator: 'onOrAfter', + value: new Date( + new Date(Date.now() - 3 * 30 * 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0), + ).toISOString(), + }, +]; + +export function ToolbarFilterItem(props) { + const { listView, container } = props; + const [open, setOpen] = React.useState(false); + const apiRef = useGridApiContext(); + const activeFilters = useGridSelector(apiRef, gridFilterActiveItemsSelector); + const currentFileTypeFilter = + activeFilters.filter((filter) => filter.field === 'type')?.[0]?.value ?? []; + const currentDateModifiedFilter = activeFilters.find( + (filter) => filter.field === 'updatedAt', + ); + + const applyDateModifiedFilter = (filterItem) => { + if (currentDateModifiedFilter) { + apiRef.current.deleteFilterItem(currentDateModifiedFilter); + } + + apiRef.current.upsertFilterItem({ + field: 'updatedAt', + ...filterItem, + }); + }; + + const resetDateModifiedFilter = () => { + if (currentDateModifiedFilter) { + apiRef.current.deleteFilterItem(currentDateModifiedFilter); + } + }; + + const applyFileTypeFilter = (fileType, enable) => { + apiRef.current.upsertFilterItem({ + id: 'file-type', + field: 'type', + operator: 'isAnyOf', + value: enable + ? [...currentFileTypeFilter, fileType] + : currentFileTypeFilter.filter((type) => type !== fileType), + }); + }; + + const clearFilters = () => { + apiRef.current.setFilterModel({ + items: [], + }); + }; + + return ( + + setOpen(true)}> + + + + + + setOpen(false)} + > + + Filters + + + + Date modified + + } + > + {DATE_MODIFIED_FILTERS.map((option) => { + const isActive = + option.id === 'all' + ? !currentDateModifiedFilter + : activeFilters.some((filter) => filter.id === option.id); + + return ( + + + option.id === 'all' + ? resetDateModifiedFilter() + : applyDateModifiedFilter({ + id: option.id, + operator: option.operator, + value: option.value, + }) + } + > + {isActive ? : null} + {option.label} + + + ); + })} + + + + + File types + + } + > + {FILE_TYPES.map((type) => { + const isActive = currentFileTypeFilter.includes(type); + + return ( + + applyFileTypeFilter(type, !isActive)}> + + {isActive ? ( + + ) : ( + + )} + + {type} + + + ); + })} + + + + + + + + + + Clear filters + + + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarFilterItem.tsx b/docs/data/data-grid/list-view/components/ToolbarFilterItem.tsx new file mode 100644 index 000000000000..2bb3040df9cd --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarFilterItem.tsx @@ -0,0 +1,225 @@ +import * as React from 'react'; +import { + GridFilterListIcon, + useGridApiContext, + useGridSelector, + gridFilterActiveItemsSelector, + GridCheckIcon, + GridFilterItem, +} from '@mui/x-data-grid-premium'; +import Badge from '@mui/material/Badge'; +import Typography from '@mui/material/Typography'; +import Divider from '@mui/material/Divider'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; +import ListSubheader from '@mui/material/ListSubheader'; +import CheckBoxIcon from '@mui/icons-material/CheckBox'; +import CheckBoxBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; +import FilterAltOffIcon from '@mui/icons-material/FilterAltOff'; +import { Drawer, DrawerHeader, DrawerProps } from './Drawer'; +import { ToolbarButton } from './ToolbarButton'; +import { FileType } from '../types'; +import { FILE_TYPES } from '../constants'; + +const DATE_MODIFIED_FILTERS = [ + { + label: 'All', + id: 'all', + }, + { + label: 'Today', + id: 'today', + operator: 'onOrAfter', + value: new Date(new Date().setHours(0, 0, 0, 0)).toISOString(), + }, + { + label: 'Last week', + id: 'last-week', + operator: 'onOrAfter', + value: new Date( + new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0), + ).toISOString(), + }, + { + label: 'Last month', + id: 'last-month', + operator: 'onOrAfter', + value: new Date( + new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0), + ).toISOString(), + }, + { + label: 'Last 3 months', + id: 'last-3-months', + operator: 'onOrAfter', + value: new Date( + new Date(Date.now() - 3 * 30 * 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0), + ).toISOString(), + }, +]; + +interface ToolbarFilterItemProps { + listView: boolean; + container: DrawerProps['container']; +} + +export function ToolbarFilterItem(props: ToolbarFilterItemProps) { + const { listView, container } = props; + const [open, setOpen] = React.useState(false); + const apiRef = useGridApiContext(); + const activeFilters = useGridSelector(apiRef, gridFilterActiveItemsSelector); + const currentFileTypeFilter = + activeFilters.filter((filter) => filter.field === 'type')?.[0]?.value ?? []; + const currentDateModifiedFilter = activeFilters.find( + (filter) => filter.field === 'updatedAt', + ); + + const applyDateModifiedFilter = (filterItem: Omit) => { + if (currentDateModifiedFilter) { + apiRef.current.deleteFilterItem(currentDateModifiedFilter); + } + + apiRef.current.upsertFilterItem({ + field: 'updatedAt', + ...filterItem, + }); + }; + + const resetDateModifiedFilter = () => { + if (currentDateModifiedFilter) { + apiRef.current.deleteFilterItem(currentDateModifiedFilter); + } + }; + + const applyFileTypeFilter = (fileType: FileType, enable: boolean) => { + apiRef.current.upsertFilterItem({ + id: 'file-type', + field: 'type', + operator: 'isAnyOf', + value: enable + ? [...currentFileTypeFilter, fileType] + : currentFileTypeFilter.filter((type: string) => type !== fileType), + }); + }; + + const clearFilters = () => { + apiRef.current.setFilterModel({ + items: [], + }); + }; + + return ( + + setOpen(true)}> + + + + + + setOpen(false)} + > + + Filters + + + + Date modified + + } + > + {DATE_MODIFIED_FILTERS.map((option) => { + const isActive = + option.id === 'all' + ? !currentDateModifiedFilter + : activeFilters.some((filter) => filter.id === option.id); + + return ( + + + option.id === 'all' + ? resetDateModifiedFilter() + : applyDateModifiedFilter({ + id: option.id, + operator: option.operator!, + value: option.value, + }) + } + > + {isActive ? : null} + {option.label} + + + ); + })} + + + + + + File types + + } + > + {FILE_TYPES.map((type) => { + const isActive = currentFileTypeFilter.includes(type); + + return ( + + applyFileTypeFilter(type, !isActive)}> + + {isActive ? ( + + ) : ( + + )} + + {type} + + + ); + })} + + + + + + + + + + + Clear filters + + + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarSortItem.js b/docs/data/data-grid/list-view/components/ToolbarSortItem.js new file mode 100644 index 000000000000..91c07622847f --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarSortItem.js @@ -0,0 +1,93 @@ +import * as React from 'react'; +import { + useGridApiContext, + GridArrowUpwardIcon, + GridArrowDownwardIcon, + useGridSelector, + gridSortModelSelector, + gridColumnDefinitionsSelector, +} from '@mui/x-data-grid-premium'; +import SwapVertIcon from '@mui/icons-material/SwapVert'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import Typography from '@mui/material/Typography'; +import Badge from '@mui/material/Badge'; +import { Drawer, DrawerHeader } from './Drawer'; +import { ToolbarButton } from './ToolbarButton'; + +export function ToolbarSortItem(props) { + const { listView, container } = props; + const [open, setOpen] = React.useState(false); + const apiRef = useGridApiContext(); + const fields = useGridSelector(apiRef, gridColumnDefinitionsSelector); + const sortModel = useGridSelector(apiRef, gridSortModelSelector); + const sortableFields = fields.filter((field) => field.sortable); + const sortCount = sortModel.length; + + const handleSortChange = (field, sort) => { + apiRef.current.sortColumn(field, sort, true); + }; + + return ( + + setOpen(true)}> + + + + + + setOpen(false)} + > + + Sort by + + + + {sortableFields.map((field) => { + const fieldIndexInSortModel = sortModel.findIndex( + (sort) => sort.field === field.field, + ); + const fieldInSortModel = sortModel[fieldIndexInSortModel]; + let nextSort = 'asc'; + + if (fieldInSortModel) { + nextSort = fieldInSortModel.sort === 'asc' ? 'desc' : null; + } + + return ( + + handleSortChange(field.field, nextSort)} + > + + {fieldInSortModel && ( + 1 ? fieldIndexInSortModel + 1 : null + } + > + {fieldInSortModel.sort === 'asc' ? ( + + ) : ( + + )} + + )} + + {field.headerName} + + + ); + })} + + + + ); +} diff --git a/docs/data/data-grid/list-view/components/ToolbarSortItem.tsx b/docs/data/data-grid/list-view/components/ToolbarSortItem.tsx new file mode 100644 index 000000000000..4c3633f6ec3d --- /dev/null +++ b/docs/data/data-grid/list-view/components/ToolbarSortItem.tsx @@ -0,0 +1,99 @@ +import * as React from 'react'; +import { + useGridApiContext, + GridArrowUpwardIcon, + GridArrowDownwardIcon, + useGridSelector, + gridSortModelSelector, + gridColumnDefinitionsSelector, + GridSortDirection, +} from '@mui/x-data-grid-premium'; +import SwapVertIcon from '@mui/icons-material/SwapVert'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import Typography from '@mui/material/Typography'; +import Badge from '@mui/material/Badge'; +import { Drawer, DrawerHeader, DrawerProps } from './Drawer'; +import { ToolbarButton } from './ToolbarButton'; + +interface ToolbarSortItemProps { + listView: boolean; + container: DrawerProps['container']; +} + +export function ToolbarSortItem(props: ToolbarSortItemProps) { + const { listView, container } = props; + const [open, setOpen] = React.useState(false); + const apiRef = useGridApiContext(); + const fields = useGridSelector(apiRef, gridColumnDefinitionsSelector); + const sortModel = useGridSelector(apiRef, gridSortModelSelector); + const sortableFields = fields.filter((field) => field.sortable); + const sortCount = sortModel.length; + + const handleSortChange = (field: string, sort: GridSortDirection) => { + apiRef.current.sortColumn(field, sort, true); + }; + + return ( + + setOpen(true)}> + + + + + + setOpen(false)} + > + + Sort by + + + + {sortableFields.map((field) => { + const fieldIndexInSortModel = sortModel.findIndex( + (sort) => sort.field === field.field, + ); + const fieldInSortModel = sortModel[fieldIndexInSortModel]; + let nextSort: GridSortDirection = 'asc'; + + if (fieldInSortModel) { + nextSort = fieldInSortModel.sort === 'asc' ? 'desc' : null; + } + + return ( + + handleSortChange(field.field, nextSort)} + > + + {fieldInSortModel && ( + 1 ? fieldIndexInSortModel + 1 : null + } + > + {fieldInSortModel.sort === 'asc' ? ( + + ) : ( + + )} + + )} + + {field.headerName} + + + ); + })} + + + + ); +} diff --git a/docs/data/data-grid/list-view/constants.ts b/docs/data/data-grid/list-view/constants.ts new file mode 100644 index 000000000000..ee67fc4fb92c --- /dev/null +++ b/docs/data/data-grid/list-view/constants.ts @@ -0,0 +1,17 @@ +import { FileType } from './types'; + +export const FILE_TYPES: FileType[] = [ + 'pdf', + 'docx', + 'txt', + 'mp4', + 'mov', + 'webm', + 'jpg', + 'jpeg', + 'png', + 'gif', + 'tiff', + 'webp', + 'zip', +]; diff --git a/docs/data/data-grid/list-view/data.ts b/docs/data/data-grid/list-view/data.ts new file mode 100644 index 000000000000..3e54d301d2c7 --- /dev/null +++ b/docs/data/data-grid/list-view/data.ts @@ -0,0 +1,204 @@ +import { randomId } from '@mui/x-data-grid-generator'; +import { GridRowModel } from '@mui/x-data-grid-premium'; +import { RowModel } from './types'; + +export const INITIAL_ROWS: GridRowModel[] = [ + { + id: randomId(), + type: 'zip', + name: 'archive.zip', + description: 'Compressed archive of project files', + size: 128_313_213, + createdBy: 'Kenan Yusuf', + createdAt: new Date('2023-09-15T08:30:00').toISOString(), + updatedAt: new Date('2023-09-15T08:30:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'docx', + name: 'invoice-322.docx', + description: 'Invoice document for client 322', + size: 1_694_986, + createdBy: 'José Freitas', + createdAt: new Date('2024-01-18T11:30:00').toISOString(), + updatedAt: new Date().toISOString(), // Today + state: 'uploaded', + }, + { + id: randomId(), + type: 'png', + name: 'screenshot_2024-02-14_12-34-56.png', + description: 'Screenshot of application interface', + size: 522_078, + createdBy: 'José Freitas', + createdAt: new Date('2024-02-14T12:35:16').toISOString(), + updatedAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(), // Last week + state: 'uploaded', + }, + { + id: randomId(), + type: 'mp4', + name: 'strategy-meeting.mp4', + description: 'Recording of the strategy planning meeting', + size: 2_442_044, + createdBy: 'José Freitas', + createdAt: new Date('2023-12-05T15:40:30').toISOString(), + updatedAt: new Date(Date.now() - 20 * 24 * 60 * 60 * 1000).toISOString(), // Last month + state: 'uploaded', + }, + { + id: randomId(), + type: 'docx', + name: 'project-proposal.docx', + description: 'Detailed project proposal document', + size: 3_567_890, + createdBy: 'Olivier Tassinari', + createdAt: new Date('2024-03-01T09:15:00').toISOString(), + updatedAt: new Date('2024-03-02T14:30:45').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'png', + name: 'logo-design-final.png', + description: 'Final version of the company logo design', + size: 1_234_567, + createdBy: 'Kenan Yusuf', + createdAt: new Date('2024-02-28T16:20:00').toISOString(), + updatedAt: new Date('2024-02-28T16:20:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'mp4', + name: 'product-demo.mp4', + description: 'Video demonstration of the new product features', + size: 15_789_012, + createdBy: 'Olivier Tassinari', + createdAt: new Date('2024-02-25T11:45:00').toISOString(), + updatedAt: new Date(Date.now() - 60 * 24 * 60 * 60 * 1000).toISOString(), // Last 3 months + state: 'uploaded', + }, + { + id: randomId(), + type: 'zip', + name: 'project-assets.zip', + description: 'Compressed folder containing all project assets', + size: 87_654_321, + createdBy: 'José Freitas', + createdAt: new Date('2024-03-03T13:00:00').toISOString(), + updatedAt: new Date('2024-03-03T13:00:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'docx', + name: 'meeting-minutes-2024-03-10.docx', + description: 'Minutes from the team meeting on March 10, 2024', + size: 567_890, + createdBy: 'Kenan Yusuf', + createdAt: new Date('2024-03-10T14:00:00').toISOString(), + updatedAt: new Date('2024-03-10T16:30:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'png', + name: 'ui-mockup-v2.png', + description: 'Updated user interface mockup', + size: 3_456_789, + createdBy: 'Olivier Tassinari', + createdAt: new Date('2024-03-05T10:20:00').toISOString(), + updatedAt: new Date('2024-03-05T10:20:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'mp4', + name: 'user-feedback-session.mp4', + description: 'Recording of user feedback session', + size: 234_567_890, + createdBy: 'José Freitas', + createdAt: new Date('2024-03-08T13:45:00').toISOString(), + updatedAt: new Date('2024-03-08T15:30:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'zip', + name: 'legacy-codebase.zip', + description: 'Archive of the legacy project codebase', + size: 567_890_123, + createdBy: 'Kenan Yusuf', + createdAt: new Date('2024-02-20T09:00:00').toISOString(), + updatedAt: new Date('2024-02-20T09:00:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'docx', + name: 'q1-2024-report.docx', + description: 'Quarterly report for Q1 2024', + size: 4_567_890, + createdBy: 'Olivier Tassinari', + createdAt: new Date('2024-03-31T23:59:59').toISOString(), + updatedAt: new Date('2024-04-01T10:15:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'png', + name: 'data-visualization.png', + description: 'Chart showing project progress', + size: 789_012, + createdBy: 'José Freitas', + createdAt: new Date('2024-03-15T11:30:00').toISOString(), + updatedAt: new Date('2024-03-15T11:30:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'mp4', + name: 'code-review-session.mp4', + description: 'Recording of code review meeting', + size: 345_678_901, + createdBy: 'Kenan Yusuf', + createdAt: new Date('2024-03-20T14:00:00').toISOString(), + updatedAt: new Date('2024-03-20T16:45:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'zip', + name: 'design-assets-v3.zip', + description: 'Compressed folder of updated design assets', + size: 98_765_432, + createdBy: 'Olivier Tassinari', + createdAt: new Date('2024-03-25T09:30:00').toISOString(), + updatedAt: new Date('2024-03-25T09:30:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'docx', + name: 'api-documentation.docx', + description: 'Comprehensive API documentation', + size: 2_345_678, + createdBy: 'José Freitas', + createdAt: new Date('2024-03-28T16:20:00').toISOString(), + updatedAt: new Date('2024-03-29T11:45:00').toISOString(), + state: 'uploaded', + }, + { + id: randomId(), + type: 'png', + name: 'error-screenshot.png', + description: 'Screenshot of error message for debugging', + size: 345_678, + createdBy: 'Kenan Yusuf', + createdAt: new Date('2024-03-30T08:15:00').toISOString(), + updatedAt: new Date('2024-03-30T08:15:00').toISOString(), + state: 'uploaded', + }, +]; diff --git a/docs/data/data-grid/list-view/list-view.md b/docs/data/data-grid/list-view/list-view.md new file mode 100644 index 000000000000..11f4b7ca3e88 --- /dev/null +++ b/docs/data/data-grid/list-view/list-view.md @@ -0,0 +1,29 @@ +--- +title: Data Grid - List view +--- + +# Data Grid - List view [](/x/introduction/licensing/#pro-plan 'Pro plan') + +

Display data in a single-column list view. Can be used to present a more compact grid on smaller screens and mobile devices.

+ +List view can be enabled by providing the `unstable_listView` prop. + +Unlike the default grid view, the list view makes no assumptions on how data is presented to end users. + +In order to display data in a list view, a `unstable_listColumn` prop must be provided with a `renderCell` function. + +:::warning +This feature is under development and is marked as **unstable**. While you can use the list view feature in production, the API could change in the future. +::: + +{{"demo": "ListView.js", "bg": "inline"}} + +## Advanced usage + +The list view feature can be combined with [custom subcomponents](/x/react-data-grid/components/) to provide an improved user experience on small screens. + +{{"demo": "ListViewAdvanced.js", "bg": "inline", "iframe": true, "maxWidth": 360, "height": 600, "hideToolbar": true}} + +:::info +See the code for this demo in [CodeSandbox](https://codesandbox.io/p/sandbox/x-react-data-grid-list-view-zmkzhz). +::: diff --git a/docs/data/data-grid/list-view/types.ts b/docs/data/data-grid/list-view/types.ts new file mode 100644 index 000000000000..fd0975f3a0b9 --- /dev/null +++ b/docs/data/data-grid/list-view/types.ts @@ -0,0 +1,30 @@ +import { GridRowId } from '@mui/x-data-grid-premium'; + +export type FileType = + | 'pdf' + | 'docx' + | 'txt' + | 'mp4' + | 'mov' + | 'webm' + | 'jpg' + | 'jpeg' + | 'png' + | 'gif' + | 'tiff' + | 'webp' + | 'zip'; + +export type FileState = 'uploaded' | 'pending'; + +export type RowModel = { + id: GridRowId; + type: FileType; + name: string; + description: string; + size: number; + createdBy: string; + createdAt: string; + updatedAt: string; + state: FileState; +}; diff --git a/docs/data/data-grid/list-view/utils.ts b/docs/data/data-grid/list-view/utils.ts new file mode 100644 index 000000000000..08c93be0d27c --- /dev/null +++ b/docs/data/data-grid/list-view/utils.ts @@ -0,0 +1,56 @@ +export function formatDate(value: string | null) { + if (!value) { + return '—'; + } + const date = new Date(value); + const formatter = new Intl.DateTimeFormat('en-US', { + month: 'short', + day: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }); + return formatter.format(date); +} + +export function formatSize(size: number) { + const units = ['B', 'KB', 'MB', 'GB', 'TB']; + let unitIndex = 0; + let formattedSize = size; + + while (formattedSize >= 1024 && unitIndex < units.length - 1) { + formattedSize /= 1024; + unitIndex += 1; + } + + return `${formattedSize.toFixed(2)} ${units[unitIndex]}`; +} + +export function stringToColor(string: string) { + let hash = 0; + let i: number; + + /* eslint-disable no-bitwise */ + for (i = 0; i < string.length; i += 1) { + hash = string.charCodeAt(i) + ((hash << 5) - hash); + } + + let color = '#'; + + for (i = 0; i < 3; i += 1) { + const value = (hash >> (i * 8)) & 0xff; + color += `00${value.toString(16)}`.slice(-2); + } + /* eslint-enable no-bitwise */ + + return color; +} + +export function stringAvatar(name: string) { + return { + sx: { + bgcolor: stringToColor(name), + }, + children: `${name.split(' ')[0][0]}${name.split(' ')[1][0]}`, + }; +} diff --git a/docs/data/migration/migration-tree-view-lab/migration-tree-view-lab.md b/docs/data/migration/migration-tree-view-lab/migration-tree-view-lab.md index 2b1a932e33ff..3fc640a64832 100644 --- a/docs/data/migration/migration-tree-view-lab/migration-tree-view-lab.md +++ b/docs/data/migration/migration-tree-view-lab/migration-tree-view-lab.md @@ -8,7 +8,7 @@ productId: x-tree-view ## Introduction -This is a reference for migrating your site's tree view from `@mui/lab` to `@mui/x-tree-view`. +This is a reference for migrating your site's Tree View from `@mui/lab` to `@mui/x-tree-view`. This migration is about the npm packages used, it **does not** affect the behavior of the components in your application. [//]: # 'You can find why we are moving in this direction in the [announcement blog post](/blog/lab-tree-view-to-mui-x/).' diff --git a/docs/data/migration/migration-tree-view-v6/migration-tree-view-v6.md b/docs/data/migration/migration-tree-view-v6/migration-tree-view-v6.md index 7d979f8af087..2efbd13455fd 100644 --- a/docs/data/migration/migration-tree-view-v6/migration-tree-view-v6.md +++ b/docs/data/migration/migration-tree-view-v6/migration-tree-view-v6.md @@ -13,7 +13,7 @@ To read more about the changes from the new major, check out [the blog post abou ## Start using the new release -In `package.json`, change the version of the tree view package to `^7.0.0`. +In `package.json`, change the version of the Tree View package to `^7.0.0`. ```diff -"@mui/x-tree-view": "^6.0.0", @@ -113,7 +113,7 @@ Here is an example of how you can transpile these features on Webpack 4 using th ### ✅ Rename `nodeId` to `itemId` -The required `nodeId` prop used by the `TreeItem` has been renamed to `itemId` for consistency: +The required `nodeId` prop used by the Tree Item has been renamed to `itemId` for consistency: ```diff @@ -140,10 +140,10 @@ The same change has been applied to the `ContentComponent` prop: } ``` -### ✅ Use `SimpleTreeView` instead of `TreeView` +### ✅ Use Simple Tree View instead of Tree View -The `TreeView` component has been deprecated and will be removed in the next major. -You can start replacing it with the new `SimpleTreeView` component which has exactly the same API: +The `` component has been deprecated and will be removed in the next major. +You can start replacing it with the new `` component which has exactly the same API: ```diff -import { TreeView } from '@mui/x-tree-view'; @@ -193,7 +193,7 @@ If you were using the `treeViewClasses` object, you can replace it with the new #### Define `expandIcon` The icon used to expand the children of an item (rendered when this item is collapsed) -is now defined as a slot both on the Tree View and the `TreeItem` components. +is now defined as a slot both on the `` and the `` components. If you were using the `ChevronRight` icon from `@mui/icons-material`, you can stop passing it to your component because it is now the default value: @@ -224,7 +224,7 @@ you need to use the new `expandIcon` slot on this component: Note that the `slots` prop expects a React component, not the JSX element returned when rendering this component. ::: -If you were passing another icon to your `TreeItem` component, +If you were passing another icon to your `` component, you need to use the new `expandIcon` slot on this component: ```diff @@ -241,7 +241,7 @@ you need to use the new `expandIcon` slot on this component: #### Define `collapseIcon` The icon used to collapse the children of an item (rendered when this item is expanded) -is now defined as a slot both on the Tree View and the `TreeItem` components. +is now defined as a slot both on the `` and `` components. If you were using the `ExpandMore` icon from `@mui/icons-material`, you can stop passing it to your component because it is now the default value: @@ -272,7 +272,7 @@ you need to use the new `collapseIcon` slot on this component: Note that the `slots` prop expects a React component, not the JSX element returned when rendering this component. ::: -If you were passing another icon to your `TreeItem` component, +If you were passing another icon to your `` component, you need to use the new `collapseIcon` slot on this component: ```diff @@ -306,7 +306,7 @@ by passing the same icon to both the `collapseIcon` and the `expandIcon` slots o #### Define `endIcon` The icon rendered next to an item without children -is now defined as a slot both on the Tree View and the `TreeItem` components. +is now defined as a slot both on the `` and `` components. If you were passing an icon to your Tree View component, you need to use the new `endIcon` slot on this component: @@ -324,7 +324,7 @@ you need to use the new `endIcon` slot on this component: Note that the `slots` prop expects a React component, not the JSX element returned when rendering this component. ::: -If you were passing an icon to your `TreeItem` component, +If you were passing an icon to your `` component, you need to use the new `endIcon` slot on this component: ```diff @@ -341,9 +341,9 @@ you need to use the new `endIcon` slot on this component: #### Define `icon` The icon rendered next to an item -is now defined as a slot on the `TreeItem` component. +is now defined as a slot on the `` component. -If you were passing an icon to your `TreeItem` component, +If you were passing an icon to your `` component, you need to use the new `icon` slot on this component: ```diff @@ -364,9 +364,9 @@ Note that the `slots` prop expects a React component, not the JSX element return ### ✅ Use slots to define the group transition The component used to animate the item children -is now defined as a slot on the `TreeItem` component. +is now defined as a slot on the `` component. -If you were passing a `TransitionComponent` or `TransitionProps` to your `TreeItem` component, +If you were passing a `TransitionComponent` or `TransitionProps` to your `` component, you need to use the new `groupTransition` slot on this component: ```diff @@ -382,9 +382,9 @@ you need to use the new `groupTransition` slot on this component: ``` -### Rename the `group` class of the `TreeItem` component +### Rename the `group` class of the Tree Item component -The `group` class of the `TreeItem` component has been renamed to `groupTransition` to match with its new slot name. +The `group` class of the `` component has been renamed to `groupTransition` to match with its new slot name. ```diff const StyledTreeItem = styled(TreeItem)({ @@ -423,7 +423,7 @@ If you were using the `onNodeToggle` prop to react to the expansion or collapse you can use the new `onItemExpansionToggle` prop which is called whenever an item is expanded or collapsed with its id and expansion status ```tsx -// It is also available on the deprecated `TreeView` component +// It is also available on the deprecated Tree View component console.log(itemId, isExpanded) @@ -461,7 +461,7 @@ If you were using the `onNodeSelect` prop to react to the selection or deselecti you can use the new `onItemSelectionToggle` prop which is called whenever an item is selected or deselected with its id and selection status. ```tsx -// It is also available on the deprecated `TreeView` component +// It is also available on the deprecated `` component console.log(itemId, isSelected) @@ -512,7 +512,7 @@ For example, if you were writing a test with `react-testing-library`, here is wh ### ✅ Use `useTreeItemState` instead of `useTreeItem` The `useTreeItem` hook has been renamed `useTreeItemState`. -This will help create a new headless version of the `TreeItem` component based on a future `useTreeItem` hook. +This will help create a new headless version of the Tree Item component based on a future `useTreeItem` hook. ```diff -import { TreeItem, useTreeItem } from '@mui/x-tree-view/TreeItem'; diff --git a/docs/data/pages.ts b/docs/data/pages.ts index 53353c8b702f..883180a608eb 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -110,6 +110,12 @@ const pages: MuiPage[] = [ { pathname: '/x/react-data-grid/row-grouping', plan: 'premium' }, { pathname: '/x/react-data-grid/aggregation', plan: 'premium' }, { pathname: '/x/react-data-grid/pivoting', plan: 'premium', planned: true }, + { + pathname: '/x/react-data-grid/list-view', + title: 'List view', + plan: 'pro', + unstable: true, + }, { pathname: '/x/react-data-grid/server-side-data-group', title: 'Server-side data', diff --git a/docs/data/tree-view/accessibility/accessibility.md b/docs/data/tree-view/accessibility/accessibility.md index b1fc45bfc690..cc9c2306612b 100644 --- a/docs/data/tree-view/accessibility/accessibility.md +++ b/docs/data/tree-view/accessibility/accessibility.md @@ -54,7 +54,7 @@ Type-ahead is supported for single characters. When typing a character, focus mo ## Selection -The tree view supports both single and multi-selection. To learn more about the selection API, visit the dedicated page for the [Simple Tree View](/x/react-tree-view/simple-tree-view/selection/) or the [Rich Tree View](/x/react-tree-view/rich-tree-view/selection/). +The Tree View supports both single and multi-selection. To learn more about the selection API, visit the dedicated page for the [Simple Tree View](/x/react-tree-view/simple-tree-view/selection/) or the [Rich Tree View](/x/react-tree-view/rich-tree-view/selection/). To read more about the distinction between selection and focus, you can refer to the [WAI-ARIA Authoring Practices guide](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_focus_vs_selection). diff --git a/docs/data/tree-view/getting-started/getting-started.md b/docs/data/tree-view/getting-started/getting-started.md index 79dc191bdc92..6acc9e5382c1 100644 --- a/docs/data/tree-view/getting-started/getting-started.md +++ b/docs/data/tree-view/getting-started/getting-started.md @@ -72,7 +72,7 @@ Take a look at the [Styled engine guide](/material-ui/integrations/styled-compon ## Render your first component -To make sure that everything is set up correctly, try rendering a `SimpleTreeView` component: +To make sure that everything is set up correctly, try rendering a Simple Tree View component: {{"demo": "FirstComponent.js"}} @@ -82,7 +82,7 @@ To make sure that everything is set up correctly, try rendering a `SimpleTreeVie The component follows the WAI-ARIA authoring practices. -To have an accessible tree view you must use `aria-labelledby` +To have an accessible Tree View you must use `aria-labelledby` or `aria-label` to reference or provide a label on the TreeView, otherwise, screen readers will announce it as "tree", making it hard to understand the context of a specific tree item. diff --git a/docs/data/tree-view/overview/overview.md b/docs/data/tree-view/overview/overview.md index 64c374965652..05a98d903ddf 100644 --- a/docs/data/tree-view/overview/overview.md +++ b/docs/data/tree-view/overview/overview.md @@ -46,15 +46,15 @@ At the moment, the Simple and Rich Tree Views are similar in terms of feature su The `@mui/x-tree-view` package exposes two different components to define your tree items: -- `TreeItem` -- `TreeItem2` +- `` +- `` -#### `TreeItem` +#### Tree Item This is the long-standing component that is very similar to the one used in previous versions (`@mui/x-tree-view@6` and `@mui/lab`). -When using `SimpleTreeView`, -you can import it from `@mui/x-tree-view/TreeItem` and use it as a child of the `SimpleTreeView` component: +When using Simple Tree View, +you can import it from `@mui/x-tree-view/TreeItem` and use it as a child of the Simple Tree View component: ```tsx import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; @@ -70,7 +70,7 @@ export default function App() { } ``` -When using `RichTreeView`, +When using Rich Tree View, you don't have to import anything; it's the default component used to render the items: ```tsx @@ -81,12 +81,12 @@ export default function App() { } ``` -#### `TreeItem2` +#### Tree Item 2 -This is a new component that provides a more powerful customization API, and will eventually replace `TreeItem`. +This is a new component that provides a more powerful customization API, and will eventually replace ``. -When using `SimpleTreeView`, -you can import it from `@mui/x-tree-view/TreeItem2` and use it as a child of the `SimpleTreeView` component: +When using Simple Tree View, +you can import it from `@mui/x-tree-view/TreeItem2` and use it as a child of the Simple Tree View component: ```tsx import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; @@ -102,8 +102,8 @@ export default function App() { } ``` -When using `RichTreeView`, -you can import it from `@mui/x-tree-view/TreeItem2` and pass it as a slot of the `RichTreeView` component: +When using Rich Tree View, +you can import it from `@mui/x-tree-view/TreeItem2` and pass it as a slot of the Rich Tree View component: ```tsx import { RichTreeView } from '@mui/x-tree-view/RichTreeView'; diff --git a/docs/data/tree-view/rich-tree-view/customization/customization.md b/docs/data/tree-view/rich-tree-view/customization/customization.md index adfe395f9c19..bb6aba1d2453 100644 --- a/docs/data/tree-view/rich-tree-view/customization/customization.md +++ b/docs/data/tree-view/rich-tree-view/customization/customization.md @@ -26,7 +26,7 @@ The demo below shows how to add icons using both an existing icon library, such ### Custom toggle animations -Use the `groupTransition` slot on the `TreeItem` to pass a component that handles your animation. +Use the `groupTransition` slot on the `` to pass a component that handles your animation. The demo below is animated using Material UI's [Collapse](/material-ui/transitions/#collapse) component together with the [react-spring](https://www.react-spring.dev/) library. @@ -55,7 +55,7 @@ The demo below shows how to add an avatar and custom typography elements. ### File explorer :::warning -This example is built using the new `TreeItem2` component +This example is built using the new `` component which adds several slots to modify the content of the Tree Item or change its behavior. You can learn more about this new component in the [Overview page](/x/react-tree-view/#tree-item-components). diff --git a/docs/data/tree-view/rich-tree-view/editing/editing.md b/docs/data/tree-view/rich-tree-view/editing/editing.md index 73e923bb7cff..158a5728e25b 100644 --- a/docs/data/tree-view/rich-tree-view/editing/editing.md +++ b/docs/data/tree-view/rich-tree-view/editing/editing.md @@ -45,8 +45,8 @@ Use the `onItemLabelChange` prop to trigger an action when the label of an item ## Change the default behavior -By default, blurring the tree item saves the new value if there is one. -To modify this behavior, use the `slotProps` of the `TreeItem2`. +By default, blurring the Tree Item saves the new value if there is one. +To modify this behavior, use the `slotProps` of the ``. {{"demo": "CustomBehavior.js"}} diff --git a/docs/data/tree-view/rich-tree-view/headless/headless.md b/docs/data/tree-view/rich-tree-view/headless/headless.md index 8d1c35ea57f0..ece539bc73d5 100644 --- a/docs/data/tree-view/rich-tree-view/headless/headless.md +++ b/docs/data/tree-view/rich-tree-view/headless/headless.md @@ -8,7 +8,7 @@ waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/ # Rich Tree View - Headless -

Create your custom tree view.

+

Create your custom Tree View.

:::warning The `useTreeView` hook is not public API for now, @@ -143,7 +143,7 @@ Once `focusedItemId` becomes a model, we could consider removing the notion of s ### Populate the Tree View instance -The Tree View instance is an object accessible in all the plugins and in the `TreeItem`. +The Tree View instance is an object accessible in all the plugins and in the Tree Item. It is the main way a plugin can provide features to the rest of the component. ```ts @@ -268,7 +268,7 @@ type UseCustomPluginSignature = TreeViewPluginSignature<{ params: UseCustomPluginParams; // The params specific to your plugins after running `getDefaultizedParams` defaultizedParams: UseCustomPluginDefaultizedParams; - // The methods added to the tree view instance by your plugin + // The methods added to the Tree View instance by your plugin instance: UseCustomPluginInstance; // The events emitted by your plugin events: UseCustomPluginEvents; @@ -325,6 +325,6 @@ type UseCustomPluginSignature = TreeViewPluginSignature<{ ### Log expanded items -Interact with the tree view to see the expanded items being logged: +Interact with the Tree View to see the expanded items being logged: {{"demo": "LogExpandedItems.js"}} diff --git a/docs/data/tree-view/rich-tree-view/items/items.md b/docs/data/tree-view/rich-tree-view/items/items.md index fbf179e3685e..964ee3b266f2 100644 --- a/docs/data/tree-view/rich-tree-view/items/items.md +++ b/docs/data/tree-view/rich-tree-view/items/items.md @@ -28,7 +28,7 @@ Each item must have a unique identifier. This identifier is used internally to identify the item in the various models and to track the item across updates. -By default, the `RichTreeView` component looks for a property named `id` in the data set to get that identifier: +By default, the Rich Tree View component looks for a property named `id` in the data set to get that identifier: ```tsx const ITEMS = [{ id: 'tree-view-community' }]; @@ -36,7 +36,7 @@ const ITEMS = [{ id: 'tree-view-community' }]; ; ``` -If the item's identifier is not called `id`, then you need to use the `getItemId` prop to tell the `RichTreeView` component where it is located. +If the item's identifier is not called `id`, then you need to use the `getItemId` prop to tell the Rich Tree View component where it is located. The following demo shows how to use `getItemId` to grab the unique identifier from a property named `internalId`: @@ -63,7 +63,7 @@ It could be achieved by either defining the prop outside the component scope or Each item must have a label which does not need to be unique. -By default, the `RichTreeView` component looks for a property named `label` in the data set to get that label: +By default, the Rich Tree View component looks for a property named `label` in the data set to get that label: ```tsx const ITEMS = [{ label: '@mui/x-tree-view' }]; @@ -71,7 +71,7 @@ const ITEMS = [{ label: '@mui/x-tree-view' }]; ; ``` -If the item's label is not called `label`, then you need to use the `getItemLabel` prop to tell the `RichTreeView` component where it's located: +If the item's label is not called `label`, then you need to use the `getItemLabel` prop to tell the Rich Tree View component where it's located: The following demo shows how to use `getItemLabel` to grab the unique identifier from a property named `name`: @@ -95,7 +95,7 @@ It could be achieved by either defining the prop outside the component scope or ::: :::warning -Unlike the `SimpleTreeView` component, the `RichTreeView` component only supports string labels, you cannot pass React nodes to it. +Unlike the Simple Tree View component, the Rich Tree View component only supports string labels, you cannot pass React nodes to it. ::: ## Disabled items diff --git a/docs/data/tree-view/rich-tree-view/ordering/ordering.md b/docs/data/tree-view/rich-tree-view/ordering/ordering.md index ed28ace0806b..891f3588e634 100644 --- a/docs/data/tree-view/rich-tree-view/ordering/ordering.md +++ b/docs/data/tree-view/rich-tree-view/ordering/ordering.md @@ -50,7 +50,7 @@ You can use the `onItemPositionChange` to send the new position of an item to yo {{"demo": "OnItemPositionChange.js"}} If you want to send the entire dataset to your backend, you can use the [`getItemTree`](/x/react-tree-view/rich-tree-view/items/#get-the-current-item-tree) API method. -The following demo demonstrates it by synchronizing the first tree view with the second one whenever you do a re-ordering: +The following demo demonstrates it by synchronizing the first Tree View with the second one whenever you do a re-ordering: {{"demo": "SendAllItemsToServer.js"}} diff --git a/docs/data/tree-view/simple-tree-view/customization/customization.md b/docs/data/tree-view/simple-tree-view/customization/customization.md index 4a18e36b438b..26da29b34139 100644 --- a/docs/data/tree-view/simple-tree-view/customization/customization.md +++ b/docs/data/tree-view/simple-tree-view/customization/customization.md @@ -26,7 +26,7 @@ The demo below shows how to add icons using both an existing icon library, such ### Custom toggle animations -Use the `groupTransition` slot on the `TreeItem` to pass a component that handles your animation. +Use the `groupTransition` slot on the Tree Item to pass a component that handles your animation. The demo below is animated using Material UI's [Collapse](/material-ui/transitions/#collapse) component together with the [react-spring](https://www.react-spring.dev/) library. @@ -62,7 +62,7 @@ Target the `treeItemClasses.groupTransition` class to add connection borders bet ### Gmail clone :::warning -This example is built using the new `TreeItem2` component +This example is built using the new `` component which adds several slots to modify the content of the Tree Item or change its behavior. You can learn more about this new component in the [Overview page](/x/react-tree-view/#tree-item-components). diff --git a/docs/data/tree-view/tree-item-customization/tree-item-customization.md b/docs/data/tree-view/tree-item-customization/tree-item-customization.md index 93c39d69cd27..6864d0d2b477 100644 --- a/docs/data/tree-view/tree-item-customization/tree-item-customization.md +++ b/docs/data/tree-view/tree-item-customization/tree-item-customization.md @@ -81,7 +81,7 @@ By default, a nested item is indented by `12px` from its parent item. {{"demo": "ItemChildrenIndentationProp.js"}} :::success -This feature is compatible with both the `TreeItem` and `TreeItem2` components +This feature is compatible with both the `` and `` components If you are using a custom Tree Item component, and you want to override the padding, then apply the following padding to your `groupTransition` element: @@ -116,7 +116,7 @@ It will become the default behavior in the next major version of the Tree View c {{"demo": "IndentationAtItemLevel.js"}} :::success -This feature is compatible with both the `TreeItem` and `TreeItem2` components and with the `itemChildrenIndentation` prop. +This feature is compatible with both the `` and `` components and with the `itemChildrenIndentation` prop. If you are using a custom Tree Item component, and you want to override the padding, then apply the following padding to your `content` element: diff --git a/docs/package.json b/docs/package.json index f1559e60742d..cfe7ab58704a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -27,7 +27,7 @@ "@emotion/react": "^11.13.3", "@emotion/server": "^11.11.0", "@emotion/styled": "^11.13.0", - "@mui/docs": "6.1.2", + "@mui/docs": "6.1.4", "@mui/icons-material": "^5.16.7", "@mui/joy": "^5.0.0-beta.48", "@mui/lab": "^5.0.0-alpha.173", @@ -102,7 +102,7 @@ "@babel/plugin-transform-react-constant-elements": "^7.25.7", "@babel/preset-typescript": "^7.25.7", "@mui/internal-docs-utils": "^1.0.14", - "@mui/internal-scripts": "^1.0.22", + "@mui/internal-scripts": "^1.0.24", "@types/chance": "^1.1.6", "@types/d3-scale": "^4.0.8", "@types/d3-scale-chromatic": "^3.0.3", diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index b9c22994df5f..478f8854a196 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -649,6 +649,13 @@ }, "throttleRowsMs": { "type": { "name": "number" }, "default": "0" }, "treeData": { "type": { "name": "bool" }, "default": "false" }, + "unstable_listColumn": { + "type": { + "name": "shape", + "description": "{ align?: 'center'
| 'left'
| 'right', cellClassName?: func
| string, display?: 'flex'
| 'text', field: string, renderCell?: func }" + } + }, + "unstable_listView": { "type": { "name": "bool" } }, "unstable_rowSpanning": { "type": { "name": "bool" }, "default": "false" } }, "name": "DataGridPremium", diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index f0e2cc6f48c4..54a8ab54294e 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -580,6 +580,13 @@ }, "throttleRowsMs": { "type": { "name": "number" }, "default": "0" }, "treeData": { "type": { "name": "bool" }, "default": "false" }, + "unstable_listColumn": { + "type": { + "name": "shape", + "description": "{ align?: 'center'
| 'left'
| 'right', cellClassName?: func
| string, display?: 'flex'
| 'text', field: string, renderCell?: func }" + } + }, + "unstable_listView": { "type": { "name": "bool" } }, "unstable_rowSpanning": { "type": { "name": "bool" }, "default": "false" } }, "name": "DataGridPro", diff --git a/docs/pages/x/api/tree-view/rich-tree-view-pro.json b/docs/pages/x/api/tree-view/rich-tree-view-pro.json index 7cd100636eb8..fb4b208b9f1d 100644 --- a/docs/pages/x/api/tree-view/rich-tree-view-pro.json +++ b/docs/pages/x/api/tree-view/rich-tree-view-pro.json @@ -178,7 +178,7 @@ }, { "name": "endIcon", - "description": "The default icon displayed next to an end item.\nThis is applied to all tree items and can be overridden by the TreeItem `icon` slot prop.", + "description": "The default icon displayed next to an end item.\nThis is applied to all Tree Items and can be overridden by the TreeItem `icon` slot prop.", "class": null } ], diff --git a/docs/pages/x/api/tree-view/rich-tree-view.json b/docs/pages/x/api/tree-view/rich-tree-view.json index 53335f98fc5e..98191cec2fc0 100644 --- a/docs/pages/x/api/tree-view/rich-tree-view.json +++ b/docs/pages/x/api/tree-view/rich-tree-view.json @@ -153,7 +153,7 @@ }, { "name": "endIcon", - "description": "The default icon displayed next to an end item.\nThis is applied to all tree items and can be overridden by the TreeItem `icon` slot prop.", + "description": "The default icon displayed next to an end item.\nThis is applied to all Tree Items and can be overridden by the TreeItem `icon` slot prop.", "class": null } ], diff --git a/docs/pages/x/api/tree-view/simple-tree-view.json b/docs/pages/x/api/tree-view/simple-tree-view.json index 0e9d838a7327..b3507fdce74d 100644 --- a/docs/pages/x/api/tree-view/simple-tree-view.json +++ b/docs/pages/x/api/tree-view/simple-tree-view.json @@ -108,7 +108,7 @@ }, { "name": "endIcon", - "description": "The default icon displayed next to an end item.\nThis is applied to all tree items and can be overridden by the TreeItem `icon` slot prop.", + "description": "The default icon displayed next to an end item.\nThis is applied to all Tree Items and can be overridden by the TreeItem `icon` slot prop.", "class": null } ], diff --git a/docs/pages/x/api/tree-view/tree-item-2.json b/docs/pages/x/api/tree-view/tree-item-2.json index 547383a665af..2b9cb932216b 100644 --- a/docs/pages/x/api/tree-view/tree-item-2.json +++ b/docs/pages/x/api/tree-view/tree-item-2.json @@ -67,7 +67,7 @@ }, { "name": "dragAndDropOverlay", - "description": "The component that renders the overlay when an item reordering is ongoing.\nWarning: This slot is only useful when using the `RichTreeViewPro` component.", + "description": "The component that renders the overlay when an item reordering is ongoing.\nWarning: This slot is only useful when using the `` component.", "default": "TreeItem2DragAndDropOverlay", "class": "MuiTreeItem2-dragAndDropOverlay" }, @@ -76,7 +76,7 @@ { "name": "endIcon", "description": "The icon displayed next to an end item.", "class": null }, { "name": "icon", - "description": "The icon to display next to the tree item's label.", + "description": "The icon to display next to the Tree Item's label.", "class": null } ], diff --git a/docs/pages/x/api/tree-view/tree-item.json b/docs/pages/x/api/tree-view/tree-item.json index 33853fb02fb1..1d0f0081cc6a 100644 --- a/docs/pages/x/api/tree-view/tree-item.json +++ b/docs/pages/x/api/tree-view/tree-item.json @@ -7,12 +7,12 @@ "type": { "name": "custom", "description": "element type" }, "default": "TreeItemContent", "deprecated": true, - "deprecationInfo": "Consider using the TreeItem2 component or the useTreeItem2 hook instead. For more detail, see https://mui.com/x/react-tree-view/tree-item-customization/." + "deprecationInfo": "Consider using the <TreeItem2 /> component or the useTreeItem2 hook instead. For more details, see https://mui.com/x/react-tree-view/tree-item-customization/." }, "ContentProps": { "type": { "name": "object" }, "deprecated": true, - "deprecationInfo": "Consider using the TreeItem2 component or the useTreeItem2 hook instead. For more detail, see https://mui.com/x/react-tree-view/tree-item-customization/." + "deprecationInfo": "Consider using the <TreeItem2 /> component or the useTreeItem2 hook instead. For more details, see https://mui.com/x/react-tree-view/tree-item-customization/." }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "label": { "type": { "name": "node" } }, @@ -44,7 +44,7 @@ { "name": "endIcon", "description": "The icon displayed next to an end item.", "class": null }, { "name": "icon", - "description": "The icon to display next to the tree item's label.", + "description": "The icon to display next to the Tree Item's label.", "class": null }, { @@ -106,7 +106,7 @@ { "key": "iconContainer", "className": "MuiTreeItem-iconContainer", - "description": "Styles applied to the tree item icon.", + "description": "Styles applied to the Tree Item icon.", "isGlobal": false }, { diff --git a/docs/pages/x/api/tree-view/tree-view.json b/docs/pages/x/api/tree-view/tree-view.json index c03fa0e611a9..dc8fc5e8013f 100644 --- a/docs/pages/x/api/tree-view/tree-view.json +++ b/docs/pages/x/api/tree-view/tree-view.json @@ -108,7 +108,7 @@ }, { "name": "endIcon", - "description": "The default icon displayed next to an end item.\nThis is applied to all tree items and can be overridden by the TreeItem `icon` slot prop.", + "description": "The default icon displayed next to an end item.\nThis is applied to all Tree Items and can be overridden by the TreeItem `icon` slot prop.", "class": null } ], diff --git a/docs/pages/x/react-data-grid/list-view.js b/docs/pages/x/react-data-grid/list-view.js new file mode 100644 index 000000000000..cb417266ff2e --- /dev/null +++ b/docs/pages/x/react-data-grid/list-view.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docsx/data/data-grid/list-view/list-view.md?muiMarkdown'; + +export default function Page() { + return ; +} diff --git a/docs/src/modules/components/TreeItem2Anatomy.js b/docs/src/modules/components/TreeItem2Anatomy.js index 2f46bb4dce94..0dded349e5b0 100644 --- a/docs/src/modules/components/TreeItem2Anatomy.js +++ b/docs/src/modules/components/TreeItem2Anatomy.js @@ -15,7 +15,7 @@ export default function TreeItem2Anatomy() { ); diff --git a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json index 78865102281c..5e463ec7b112 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json @@ -661,6 +661,12 @@ "treeData": { "description": "If true, the rows will be gathered in a tree structure according to the getTreeDataPath prop." }, + "unstable_listColumn": { + "description": "Definition of the column rendered when the unstable_listView prop is enabled." + }, + "unstable_listView": { + "description": "If true, displays the data in a list view. Use in combination with unstable_listColumn." + }, "unstable_rowSpanning": { "description": "If true, the Data Grid will auto span the cells over the rows having the same value." } diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index a0509f2e4549..b2b762362095 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -599,6 +599,12 @@ "treeData": { "description": "If true, the rows will be gathered in a tree structure according to the getTreeDataPath prop." }, + "unstable_listColumn": { + "description": "Definition of the column rendered when the unstable_listView prop is enabled." + }, + "unstable_listView": { + "description": "If true, displays the data in a list view. Use in combination with unstable_listColumn." + }, "unstable_rowSpanning": { "description": "If true, the Data Grid will auto span the cells over the rows having the same value." } diff --git a/docs/translations/api-docs/tree-view/rich-tree-view-pro/rich-tree-view-pro.json b/docs/translations/api-docs/tree-view/rich-tree-view-pro/rich-tree-view-pro.json index 3a33b96c08bd..d7edf9c18d6d 100644 --- a/docs/translations/api-docs/tree-view/rich-tree-view-pro/rich-tree-view-pro.json +++ b/docs/translations/api-docs/tree-view/rich-tree-view-pro/rich-tree-view-pro.json @@ -15,7 +15,7 @@ } }, "checkboxSelection": { - "description": "If true, the tree view renders a checkbox at the left of its label that allows selecting it." + "description": "If true, the Tree View renders a checkbox at the left of its label that allows selecting it." }, "classes": { "description": "Override or extend the styles applied to the component." }, "defaultExpandedItems": { @@ -75,21 +75,21 @@ "description": "If true, ctrl and shift will trigger multiselect." }, "onExpandedItemsChange": { - "description": "Callback fired when tree items are expanded/collapsed.", + "description": "Callback fired when Tree Items are expanded/collapsed.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemIds": "The ids of the expanded items." } }, "onItemClick": { - "description": "Callback fired when the content slot of a given tree item is clicked.", + "description": "Callback fired when the content slot of a given Tree Item is clicked.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The id of the focused item." } }, "onItemExpansionToggle": { - "description": "Callback fired when a tree item is expanded or collapsed.", + "description": "Callback fired when a Tree Item is expanded or collapsed.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The itemId of the modified item.", @@ -97,7 +97,7 @@ } }, "onItemFocus": { - "description": "Callback fired when a given tree item is focused.", + "description": "Callback fired when a given Tree Item is focused.", "typeDescriptions": { "event": "The DOM event that triggered the change. Warning: This is a generic event not a focus event.", "itemId": "The id of the focused item." @@ -111,7 +111,7 @@ } }, "onItemPositionChange": { - "description": "Callback fired when a tree item is moved in the tree.", + "description": "Callback fired when a Tree Item is moved in the tree.", "typeDescriptions": { "params": "The params describing the item re-ordering.", "params.itemId": "The id of the item moved.", @@ -120,7 +120,7 @@ } }, "onItemSelectionToggle": { - "description": "Callback fired when a tree item is selected or deselected.", + "description": "Callback fired when a Tree Item is selected or deselected.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The itemId of the modified item.", @@ -128,7 +128,7 @@ } }, "onSelectedItemsChange": { - "description": "Callback fired when tree items are selected/deselected.", + "description": "Callback fired when Tree Items are selected/deselected.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemIds": "The ids of the selected items. When multiSelect is true, this is an array of strings; when false (default) a string." @@ -146,7 +146,7 @@ "classDescriptions": {}, "slotDescriptions": { "collapseIcon": "The default icon used to collapse the item.", - "endIcon": "The default icon displayed next to an end item. This is applied to all tree items and can be overridden by the TreeItem icon slot prop.", + "endIcon": "The default icon displayed next to an end item. This is applied to all Tree Items and can be overridden by the TreeItem icon slot prop.", "expandIcon": "The default icon used to expand the item.", "item": "Custom component for the item.", "root": "Element rendered at the root." diff --git a/docs/translations/api-docs/tree-view/rich-tree-view/rich-tree-view.json b/docs/translations/api-docs/tree-view/rich-tree-view/rich-tree-view.json index 3ba5993e5187..feba556e087c 100644 --- a/docs/translations/api-docs/tree-view/rich-tree-view/rich-tree-view.json +++ b/docs/translations/api-docs/tree-view/rich-tree-view/rich-tree-view.json @@ -5,7 +5,7 @@ "description": "The ref object that allows Tree View manipulation. Can be instantiated with useTreeViewApiRef()." }, "checkboxSelection": { - "description": "If true, the tree view renders a checkbox at the left of its label that allows selecting it." + "description": "If true, the Tree View renders a checkbox at the left of its label that allows selecting it." }, "classes": { "description": "Override or extend the styles applied to the component." }, "defaultExpandedItems": { @@ -55,21 +55,21 @@ "description": "If true, ctrl and shift will trigger multiselect." }, "onExpandedItemsChange": { - "description": "Callback fired when tree items are expanded/collapsed.", + "description": "Callback fired when Tree Items are expanded/collapsed.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemIds": "The ids of the expanded items." } }, "onItemClick": { - "description": "Callback fired when the content slot of a given tree item is clicked.", + "description": "Callback fired when the content slot of a given Tree Item is clicked.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The id of the focused item." } }, "onItemExpansionToggle": { - "description": "Callback fired when a tree item is expanded or collapsed.", + "description": "Callback fired when a Tree Item is expanded or collapsed.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The itemId of the modified item.", @@ -77,7 +77,7 @@ } }, "onItemFocus": { - "description": "Callback fired when a given tree item is focused.", + "description": "Callback fired when a given Tree Item is focused.", "typeDescriptions": { "event": "The DOM event that triggered the change. Warning: This is a generic event not a focus event.", "itemId": "The id of the focused item." @@ -91,7 +91,7 @@ } }, "onItemSelectionToggle": { - "description": "Callback fired when a tree item is selected or deselected.", + "description": "Callback fired when a Tree Item is selected or deselected.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The itemId of the modified item.", @@ -99,7 +99,7 @@ } }, "onSelectedItemsChange": { - "description": "Callback fired when tree items are selected/deselected.", + "description": "Callback fired when Tree Items are selected/deselected.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemIds": "The ids of the selected items. When multiSelect is true, this is an array of strings; when false (default) a string." @@ -117,7 +117,7 @@ "classDescriptions": {}, "slotDescriptions": { "collapseIcon": "The default icon used to collapse the item.", - "endIcon": "The default icon displayed next to an end item. This is applied to all tree items and can be overridden by the TreeItem icon slot prop.", + "endIcon": "The default icon displayed next to an end item. This is applied to all Tree Items and can be overridden by the TreeItem icon slot prop.", "expandIcon": "The default icon used to expand the item.", "item": "Custom component for the item.", "root": "Element rendered at the root." diff --git a/docs/translations/api-docs/tree-view/simple-tree-view/simple-tree-view.json b/docs/translations/api-docs/tree-view/simple-tree-view/simple-tree-view.json index a56fd8d2d75a..1d9142ee23a9 100644 --- a/docs/translations/api-docs/tree-view/simple-tree-view/simple-tree-view.json +++ b/docs/translations/api-docs/tree-view/simple-tree-view/simple-tree-view.json @@ -5,7 +5,7 @@ "description": "The ref object that allows Tree View manipulation. Can be instantiated with useTreeViewApiRef()." }, "checkboxSelection": { - "description": "If true, the tree view renders a checkbox at the left of its label that allows selecting it." + "description": "If true, the Tree View renders a checkbox at the left of its label that allows selecting it." }, "children": { "description": "The content of the component." }, "classes": { "description": "Override or extend the styles applied to the component." }, @@ -38,21 +38,21 @@ "description": "If true, ctrl and shift will trigger multiselect." }, "onExpandedItemsChange": { - "description": "Callback fired when tree items are expanded/collapsed.", + "description": "Callback fired when Tree Items are expanded/collapsed.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemIds": "The ids of the expanded items." } }, "onItemClick": { - "description": "Callback fired when the content slot of a given tree item is clicked.", + "description": "Callback fired when the content slot of a given Tree Item is clicked.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The id of the focused item." } }, "onItemExpansionToggle": { - "description": "Callback fired when a tree item is expanded or collapsed.", + "description": "Callback fired when a Tree Item is expanded or collapsed.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The itemId of the modified item.", @@ -60,14 +60,14 @@ } }, "onItemFocus": { - "description": "Callback fired when a given tree item is focused.", + "description": "Callback fired when a given Tree Item is focused.", "typeDescriptions": { "event": "The DOM event that triggered the change. Warning: This is a generic event not a focus event.", "itemId": "The id of the focused item." } }, "onItemSelectionToggle": { - "description": "Callback fired when a tree item is selected or deselected.", + "description": "Callback fired when a Tree Item is selected or deselected.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The itemId of the modified item.", @@ -75,7 +75,7 @@ } }, "onSelectedItemsChange": { - "description": "Callback fired when tree items are selected/deselected.", + "description": "Callback fired when Tree Items are selected/deselected.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemIds": "The ids of the selected items. When multiSelect is true, this is an array of strings; when false (default) a string." @@ -93,7 +93,7 @@ "classDescriptions": {}, "slotDescriptions": { "collapseIcon": "The default icon used to collapse the item.", - "endIcon": "The default icon displayed next to an end item. This is applied to all tree items and can be overridden by the TreeItem icon slot prop.", + "endIcon": "The default icon displayed next to an end item. This is applied to all Tree Items and can be overridden by the TreeItem icon slot prop.", "expandIcon": "The default icon used to expand the item.", "root": "Element rendered at the root." } diff --git a/docs/translations/api-docs/tree-view/tree-item-2/tree-item-2.json b/docs/translations/api-docs/tree-view/tree-item-2/tree-item-2.json index 1ec2e89e98d8..5177a55030aa 100644 --- a/docs/translations/api-docs/tree-view/tree-item-2/tree-item-2.json +++ b/docs/translations/api-docs/tree-view/tree-item-2/tree-item-2.json @@ -52,11 +52,11 @@ "checkbox": "The component that renders the item checkbox for selection.", "collapseIcon": "The icon used to collapse the item.", "content": "The component that renders the content of the item. (e.g.: everything related to this item, not to its children).", - "dragAndDropOverlay": "The component that renders the overlay when an item reordering is ongoing. Warning: This slot is only useful when using the RichTreeViewPro component.", + "dragAndDropOverlay": "The component that renders the overlay when an item reordering is ongoing. Warning: This slot is only useful when using the <RichTreeViewPro /> component.", "endIcon": "The icon displayed next to an end item.", "expandIcon": "The icon used to expand the item.", "groupTransition": "The component that renders the children of the item.", - "icon": "The icon to display next to the tree item's label.", + "icon": "The icon to display next to the Tree Item's label.", "iconContainer": "The component that renders the icon.", "label": "The component that renders the item label.", "labelInput": "The component that renders the input to edit the label when the item is editable and is currently being edited.", diff --git a/docs/translations/api-docs/tree-view/tree-item/tree-item.json b/docs/translations/api-docs/tree-view/tree-item/tree-item.json index f0febee14167..19addf4e001f 100644 --- a/docs/translations/api-docs/tree-view/tree-item/tree-item.json +++ b/docs/translations/api-docs/tree-view/tree-item/tree-item.json @@ -10,7 +10,7 @@ "ContentProps": { "description": "Props applied to ContentComponent." }, "disabled": { "description": "If true, the item is disabled." }, "itemId": { "description": "The id of the item." }, - "label": { "description": "The tree item label." }, + "label": { "description": "The Tree Item label." }, "onFocus": { "description": "This prop isn't supported. Use the onItemFocus callback on the tree if you need to monitor a item's focus." }, @@ -62,7 +62,7 @@ }, "iconContainer": { "description": "Styles applied to {{nodeName}}.", - "nodeName": "the tree item icon" + "nodeName": "the Tree Item icon" }, "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the label element" }, "labelInput": { @@ -82,6 +82,6 @@ "endIcon": "The icon displayed next to an end item.", "expandIcon": "The icon used to expand the item.", "groupTransition": "The component that animates the appearance / disappearance of the item's children.", - "icon": "The icon to display next to the tree item's label." + "icon": "The icon to display next to the Tree Item's label." } } diff --git a/docs/translations/api-docs/tree-view/tree-view/tree-view.json b/docs/translations/api-docs/tree-view/tree-view/tree-view.json index 765c53c0efd9..069ba6b9dbc6 100644 --- a/docs/translations/api-docs/tree-view/tree-view/tree-view.json +++ b/docs/translations/api-docs/tree-view/tree-view/tree-view.json @@ -1,11 +1,11 @@ { - "componentDescription": "This component has been deprecated in favor of the new `SimpleTreeView` component.\nYou can have a look at how to migrate to the new component in the v7 [migration guide](https://mui.com/x/migration/migration-tree-view-v6/#use-simpletreeview-instead-of-treeview)", + "componentDescription": "This component has been deprecated in favor of the new Simple Tree View component.\nYou can have a look at how to migrate to the new component in the v7 [migration guide](https://mui.com/x/migration/migration-tree-view-v6/#use-simpletreeview-instead-of-treeview)", "propDescriptions": { "apiRef": { "description": "The ref object that allows Tree View manipulation. Can be instantiated with useTreeViewApiRef()." }, "checkboxSelection": { - "description": "If true, the tree view renders a checkbox at the left of its label that allows selecting it." + "description": "If true, the Tree View renders a checkbox at the left of its label that allows selecting it." }, "children": { "description": "The content of the component." }, "classes": { "description": "Override or extend the styles applied to the component." }, @@ -38,21 +38,21 @@ "description": "If true, ctrl and shift will trigger multiselect." }, "onExpandedItemsChange": { - "description": "Callback fired when tree items are expanded/collapsed.", + "description": "Callback fired when Tree Items are expanded/collapsed.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemIds": "The ids of the expanded items." } }, "onItemClick": { - "description": "Callback fired when the content slot of a given tree item is clicked.", + "description": "Callback fired when the content slot of a given Tree Item is clicked.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The id of the focused item." } }, "onItemExpansionToggle": { - "description": "Callback fired when a tree item is expanded or collapsed.", + "description": "Callback fired when a Tree Item is expanded or collapsed.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The itemId of the modified item.", @@ -60,14 +60,14 @@ } }, "onItemFocus": { - "description": "Callback fired when a given tree item is focused.", + "description": "Callback fired when a given Tree Item is focused.", "typeDescriptions": { "event": "The DOM event that triggered the change. Warning: This is a generic event not a focus event.", "itemId": "The id of the focused item." } }, "onItemSelectionToggle": { - "description": "Callback fired when a tree item is selected or deselected.", + "description": "Callback fired when a Tree Item is selected or deselected.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemId": "The itemId of the modified item.", @@ -75,7 +75,7 @@ } }, "onSelectedItemsChange": { - "description": "Callback fired when tree items are selected/deselected.", + "description": "Callback fired when Tree Items are selected/deselected.", "typeDescriptions": { "event": "The DOM event that triggered the change.", "itemIds": "The ids of the selected items. When multiSelect is true, this is an array of strings; when false (default) a string." @@ -93,7 +93,7 @@ "classDescriptions": {}, "slotDescriptions": { "collapseIcon": "The default icon used to collapse the item.", - "endIcon": "The default icon displayed next to an end item. This is applied to all tree items and can be overridden by the TreeItem icon slot prop.", + "endIcon": "The default icon displayed next to an end item. This is applied to all Tree Items and can be overridden by the TreeItem icon slot prop.", "expandIcon": "The default icon used to expand the item.", "root": "Element rendered at the root." } diff --git a/package.json b/package.json index 02e54753d4f5..d154be195aa8 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "7.20.0", + "version": "7.21.0", "private": true, "scripts": { "preinstall": "npx only-allow pnpm", @@ -92,8 +92,8 @@ "@emotion/styled": "^11.13.0", "@mui/icons-material": "^5.16.7", "@mui/internal-babel-plugin-resolve-imports": "1.0.18", - "@mui/internal-markdown": "^1.0.15", - "@mui/internal-test-utils": "^1.0.15", + "@mui/internal-markdown": "^1.0.17", + "@mui/internal-test-utils": "^1.0.17", "@mui/material": "^5.16.7", "@mui/monorepo": "github:mui/material-ui#010de4505361345951824d905d1508d6f258ba67", "@mui/utils": "^5.16.6", diff --git a/packages/x-charts-pro/package.json b/packages/x-charts-pro/package.json index 946258e4fc7c..628ad50ae463 100644 --- a/packages/x-charts-pro/package.json +++ b/packages/x-charts-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts-pro", - "version": "7.0.0-beta.4", + "version": "7.0.0-beta.5", "description": "The Pro plan edition of the Charts components (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index 0c3af2884f47..887cd1058746 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -24,6 +24,46 @@ function BarChartPlotZoom(props: BarPlotProps) { return ; } +BarChartPlotZoom.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * If provided, the function will be used to format the label of the bar. + * It can be set to 'value' to display the current value. + * @param {BarItem} item The item to format. + * @param {BarLabelContext} context data about the bar. + * @returns {string} The formatted label. + */ + barLabel: PropTypes.oneOfType([PropTypes.oneOf(['value']), PropTypes.func]), + /** + * Defines the border radius of the bar element. + */ + borderRadius: PropTypes.number, + /** + * Callback fired when a bar item is clicked. + * @param {React.MouseEvent} event The event source of the callback. + * @param {BarItemIdentifier} barItemIdentifier The bar item identifier. + */ + onItemClick: PropTypes.func, + /** + * If `true`, animations are skipped. + * @default undefined + */ + skipAnimation: PropTypes.bool, + /** + * The props used for each component slot. + * @default {} + */ + slotProps: PropTypes.object, + /** + * Overridable component slots. + * @default {} + */ + slots: PropTypes.object, +} as any; + export interface BarChartProProps extends BarChartProps, ZoomProps {} /** diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index 732756fe1731..b7d66add50ba 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -31,16 +31,106 @@ function AreaPlotZoom(props: AreaPlotProps) { return ; } +AreaPlotZoom.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * Callback fired when a line area item is clicked. + * @param {React.MouseEvent} event The event source of the callback. + * @param {LineItemIdentifier} lineItemIdentifier The line item identifier. + */ + onItemClick: PropTypes.func, + /** + * If `true`, animations are skipped. + * @default false + */ + skipAnimation: PropTypes.bool, + /** + * The props used for each component slot. + * @default {} + */ + slotProps: PropTypes.object, + /** + * Overridable component slots. + * @default {} + */ + slots: PropTypes.object, +} as any; + function LinePlotZoom(props: LinePlotProps) { const { isInteracting } = useZoom(); return ; } +LinePlotZoom.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * Callback fired when a line item is clicked. + * @param {React.MouseEvent} event The event source of the callback. + * @param {LineItemIdentifier} lineItemIdentifier The line item identifier. + */ + onItemClick: PropTypes.func, + /** + * If `true`, animations are skipped. + * @default false + */ + skipAnimation: PropTypes.bool, + /** + * The props used for each component slot. + * @default {} + */ + slotProps: PropTypes.object, + /** + * Overridable component slots. + * @default {} + */ + slots: PropTypes.object, +} as any; + function MarkPlotZoom(props: MarkPlotProps) { const { isInteracting } = useZoom(); return ; } +MarkPlotZoom.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * If `true` the mark element will only be able to render circle. + * Giving fewer customization options, but saving around 40ms per 1.000 marks. + * @default false + */ + experimentalRendering: PropTypes.bool, + /** + * Callback fired when a line mark item is clicked. + * @param {React.MouseEvent} event The event source of the callback. + * @param {LineItemIdentifier} lineItemIdentifier The line mark item identifier. + */ + onItemClick: PropTypes.func, + /** + * If `true`, animations are skipped. + * @default false + */ + skipAnimation: PropTypes.bool, + /** + * The props used for each component slot. + * @default {} + */ + slotProps: PropTypes.object, + /** + * Overridable component slots. + * @default {} + */ + slots: PropTypes.object, +} as any; + export interface LineChartProProps extends LineChartProps, ZoomProps {} /** diff --git a/packages/x-charts/package.json b/packages/x-charts/package.json index 65038b813fb0..02d47aedb6be 100644 --- a/packages/x-charts/package.json +++ b/packages/x-charts/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts", - "version": "7.20.0", + "version": "7.21.0", "description": "The community edition of the Charts components (MUI X).", "author": "MUI Team", "main": "src/index.js", @@ -65,7 +65,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.15", + "@mui/internal-test-utils": "^1.0.17", "@mui/material": "^5.16.7", "@mui/system": "^5.16.7", "@react-spring/core": "^9.7.5", diff --git a/packages/x-codemod/README.md b/packages/x-codemod/README.md index 453f783b567d..32eb12c7aa55 100644 --- a/packages/x-codemod/README.md +++ b/packages/x-codemod/README.md @@ -227,9 +227,9 @@ npx @mui/x-codemod@latest v7.0.0/data-grid/remove-stabilized-experimentalFeature ### Tree View codemods -#### `preset-safe` for tree view v7.0.0 +#### `preset-safe` for Tree View v7.0.0 -The `preset-safe` codemods for tree view. +The `preset-safe` codemods for Tree View. ```bash npx @mui/x-codemod@latest v7.0.0/tree-view/preset-safe @@ -247,7 +247,7 @@ The list includes these transformers #### `rename-tree-view-simple-tree-view` -Renames the `TreeView` component to `SimpleTreeView` +Renames the Tree View component to Simple Tree View ```diff -import { TreeView } from '@mui/x-tree-view'; diff --git a/packages/x-codemod/package.json b/packages/x-codemod/package.json index 4f9a0b5687a4..c9a7f1934e1d 100644 --- a/packages/x-codemod/package.json +++ b/packages/x-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-codemod", - "version": "7.20.0", + "version": "7.21.0", "bin": "./codemod.js", "private": false, "author": "MUI Team", diff --git a/packages/x-data-grid-generator/package.json b/packages/x-data-grid-generator/package.json index cf21b769479f..a9b08defc290 100644 --- a/packages/x-data-grid-generator/package.json +++ b/packages/x-data-grid-generator/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-generator", - "version": "7.20.0", + "version": "7.21.0", "description": "Generate fake data for demo purposes only.", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-data-grid-generator/src/columns/employees.columns.tsx b/packages/x-data-grid-generator/src/columns/employees.columns.tsx index 1f4ea311b299..4f29ce843a4a 100644 --- a/packages/x-data-grid-generator/src/columns/employees.columns.tsx +++ b/packages/x-data-grid-generator/src/columns/employees.columns.tsx @@ -170,7 +170,7 @@ export const getEmployeeColumns = (): GridColDefGenerator[] => [ if (!value || typeof value !== 'number') { return value; } - return `${value.toLocaleString()}$`; + return `$${value.toLocaleString()}`; }, }, ]; diff --git a/packages/x-data-grid-premium/package.json b/packages/x-data-grid-premium/package.json index 2831040fbfb4..228a3581e84a 100644 --- a/packages/x-data-grid-premium/package.json +++ b/packages/x-data-grid-premium/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-premium", - "version": "7.20.0", + "version": "7.21.0", "description": "The Premium plan edition of the Data Grid Components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -72,7 +72,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.15", + "@mui/internal-test-utils": "^1.0.17", "@mui/material": "^5.16.7", "@mui/system": "^5.16.7", "@types/prop-types": "^15.7.13", diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 86be3303b736..0f05ca94e442 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -1106,6 +1106,21 @@ DataGridPremiumRaw.propTypes = { get: PropTypes.func.isRequired, set: PropTypes.func.isRequired, }), + /** + * Definition of the column rendered when the `unstable_listView` prop is enabled. + */ + unstable_listColumn: PropTypes.shape({ + align: PropTypes.oneOf(['center', 'left', 'right']), + cellClassName: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), + display: PropTypes.oneOf(['flex', 'text']), + field: PropTypes.string.isRequired, + renderCell: PropTypes.func, + }), + /** + * If `true`, displays the data in a list view. + * Use in combination with `unstable_listColumn`. + */ + unstable_listView: PropTypes.bool, unstable_onDataSourceError: PropTypes.func, /** * If `true`, the Data Grid will auto span the cells over the rows having the same value. diff --git a/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx b/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx index 12899dd06ce2..8106dec99163 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx @@ -70,6 +70,8 @@ import { dataSourceStateInitializer, useGridRowSpanning, rowSpanningStateInitializer, + useGridListView, + listViewStateInitializer, } from '@mui/x-data-grid-pro/internals'; import { GridApiPremium, GridPrivateApiPremium } from '../models/gridApiPremium'; import { DataGridPremiumProcessedProps } from '../models/dataGridPremiumProps'; @@ -143,6 +145,7 @@ export const useDataGridPremiumComponent = ( useGridInitializeState(columnGroupsStateInitializer, apiRef, props); useGridInitializeState(virtualizationStateInitializer, apiRef, props); useGridInitializeState(dataSourceStateInitializer, apiRef, props); + useGridInitializeState(listViewStateInitializer, apiRef, props); useGridRowGrouping(apiRef, props); useGridHeaderFiltering(apiRef, props); @@ -156,7 +159,7 @@ export const useDataGridPremiumComponent = ( useGridColumns(apiRef, props); useGridRows(apiRef, props); useGridRowSpanning(apiRef, props); - useGridParamsApi(apiRef); + useGridParamsApi(apiRef, props); useGridDetailPanel(apiRef, props); useGridColumnSpanning(apiRef); useGridColumnGrouping(apiRef, props); @@ -185,6 +188,7 @@ export const useDataGridPremiumComponent = ( useGridStatePersistence(apiRef); useGridDataSource(apiRef, props); useGridVirtualization(apiRef, props); + useGridListView(apiRef, props); return apiRef; }; diff --git a/packages/x-data-grid-pro/package.json b/packages/x-data-grid-pro/package.json index b6833d5bf47d..8810d0971ce6 100644 --- a/packages/x-data-grid-pro/package.json +++ b/packages/x-data-grid-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-pro", - "version": "7.20.0", + "version": "7.21.0", "description": "The Pro plan edition of the Data Grid components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -70,7 +70,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.15", + "@mui/internal-test-utils": "^1.0.17", "@mui/material": "^5.16.7", "@mui/system": "^5.16.7", "@types/prop-types": "^15.7.13", diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 8cea3a676d0d..cf10a788ce68 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -1005,6 +1005,21 @@ DataGridProRaw.propTypes = { get: PropTypes.func.isRequired, set: PropTypes.func.isRequired, }), + /** + * Definition of the column rendered when the `unstable_listView` prop is enabled. + */ + unstable_listColumn: PropTypes.shape({ + align: PropTypes.oneOf(['center', 'left', 'right']), + cellClassName: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), + display: PropTypes.oneOf(['flex', 'text']), + field: PropTypes.string.isRequired, + renderCell: PropTypes.func, + }), + /** + * If `true`, displays the data in a list view. + * Use in combination with `unstable_listColumn`. + */ + unstable_listView: PropTypes.bool, unstable_onDataSourceError: PropTypes.func, /** * If `true`, the Data Grid will auto span the cells over the rows having the same value. diff --git a/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx b/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx index 6b8b06fc21bb..0240d83802fc 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx @@ -49,6 +49,8 @@ import { columnResizeStateInitializer, useGridRowSpanning, rowSpanningStateInitializer, + useGridListView, + listViewStateInitializer, } from '@mui/x-data-grid/internals'; import { GridApiPro, GridPrivateApiPro } from '../models/gridApiPro'; import { DataGridProProcessedProps } from '../models/dataGridProProps'; @@ -132,6 +134,7 @@ export const useDataGridProComponent = ( useGridInitializeState(columnGroupsStateInitializer, apiRef, props); useGridInitializeState(virtualizationStateInitializer, apiRef, props); useGridInitializeState(dataSourceStateInitializer, apiRef, props); + useGridInitializeState(listViewStateInitializer, apiRef, props); useGridHeaderFiltering(apiRef, props); useGridTreeData(apiRef, props); @@ -142,7 +145,7 @@ export const useDataGridProComponent = ( useGridColumns(apiRef, props); useGridRows(apiRef, props); useGridRowSpanning(apiRef, props); - useGridParamsApi(apiRef); + useGridParamsApi(apiRef, props); useGridDetailPanel(apiRef, props); useGridColumnSpanning(apiRef); useGridColumnGrouping(apiRef, props); @@ -169,6 +172,7 @@ export const useDataGridProComponent = ( useGridStatePersistence(apiRef); useGridVirtualization(apiRef, props); useGridDataSource(apiRef, props); + useGridListView(apiRef, props); return apiRef; }; diff --git a/packages/x-data-grid-pro/src/DataGridPro/useDataGridProProps.ts b/packages/x-data-grid-pro/src/DataGridPro/useDataGridProProps.ts index a54285727759..295702230804 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/useDataGridProProps.ts +++ b/packages/x-data-grid-pro/src/DataGridPro/useDataGridProProps.ts @@ -55,6 +55,7 @@ export const DATA_GRID_PRO_PROPS_DEFAULT_VALUES: DataGridProPropsWithDefaultValu rowsLoadingMode: 'client', scrollEndThreshold: 80, treeData: false, + unstable_listView: false, }; const defaultSlots = DATA_GRID_PRO_DEFAULT_SLOTS_COMPONENTS; diff --git a/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterCell.tsx b/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterCell.tsx index 58ba0623f1bd..2c8c8cbce7a9 100644 --- a/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterCell.tsx +++ b/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterCell.tsx @@ -193,7 +193,9 @@ const GridHeaderFilterCell = React.forwardRef; } diff --git a/packages/x-data-grid/package.json b/packages/x-data-grid/package.json index 61dbcb5a3321..1076a0532ca3 100644 --- a/packages/x-data-grid/package.json +++ b/packages/x-data-grid/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid", - "version": "7.20.0", + "version": "7.21.0", "description": "The Community plan edition of the Data Grid components (MUI X).", "author": "MUI Team", "main": "src/index.ts", @@ -71,7 +71,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.15", + "@mui/internal-test-utils": "^1.0.17", "@mui/joy": "^5.0.0-beta.48", "@mui/material": "^5.16.7", "@mui/system": "^5.16.7", diff --git a/packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx b/packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx index 85f9a09cb3ea..2c888c05b238 100644 --- a/packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx +++ b/packages/x-data-grid/src/DataGrid/useDataGridComponent.tsx @@ -57,6 +57,10 @@ import { rowSpanningStateInitializer, useGridRowSpanning, } from '../hooks/features/rows/useGridRowSpanning'; +import { + listViewStateInitializer, + useGridListView, +} from '../hooks/features/listView/useGridListView'; export const useDataGridComponent = ( inputApiRef: React.MutableRefObject | undefined, @@ -93,13 +97,14 @@ export const useDataGridComponent = ( useGridInitializeState(columnMenuStateInitializer, apiRef, props); useGridInitializeState(columnGroupsStateInitializer, apiRef, props); useGridInitializeState(virtualizationStateInitializer, apiRef, props); + useGridInitializeState(listViewStateInitializer, apiRef, props); useGridKeyboardNavigation(apiRef, props); useGridRowSelection(apiRef, props); useGridColumns(apiRef, props); useGridRows(apiRef, props); useGridRowSpanning(apiRef, props); - useGridParamsApi(apiRef); + useGridParamsApi(apiRef, props); useGridColumnSpanning(apiRef); useGridColumnGrouping(apiRef, props); useGridEditing(apiRef, props); @@ -120,6 +125,7 @@ export const useDataGridComponent = ( useGridEvents(apiRef, props); useGridStatePersistence(apiRef); useGridVirtualization(apiRef, props); + useGridListView(apiRef, props); return apiRef; }; diff --git a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts index 1ae57fbf5d8f..7a2d045607e5 100644 --- a/packages/x-data-grid/src/DataGrid/useDataGridProps.ts +++ b/packages/x-data-grid/src/DataGrid/useDataGridProps.ts @@ -22,6 +22,7 @@ const DATA_GRID_FORCED_PROPS: { [key in DataGridForcedPropsKey]?: DataGridProces disableColumnReorder: true, keepColumnPositionIfDraggedOutside: false, signature: 'DataGrid', + unstable_listView: false, }; const defaultSlots = DATA_GRID_DEFAULT_SLOTS_COMPONENTS; diff --git a/packages/x-data-grid/src/components/GridRow.tsx b/packages/x-data-grid/src/components/GridRow.tsx index f326364029d1..8358424a82a7 100644 --- a/packages/x-data-grid/src/components/GridRow.tsx +++ b/packages/x-data-grid/src/components/GridRow.tsx @@ -81,6 +81,14 @@ function EmptyCell({ width }: { width: number }) { ); } +EmptyCell.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + width: PropTypes.number.isRequired, +} as any; + const GridRow = React.forwardRef(function GridRow(props, refProp) { const { selected, @@ -411,12 +419,18 @@ const GridRow = React.forwardRef(function GridRow( ), ); } + for (let i = renderContext.firstColumnIndex; i < renderContext.lastColumnIndex; i += 1) { const column = visibleColumns[i]; const indexInSection = i - pinnedColumns.left.length; + if (!column) { + continue; + } + cells.push(getCell(column, indexInSection, i, middleColumnsLength)); } + if (hasVirtualFocusCellRight) { cells.push( getCell( diff --git a/packages/x-data-grid/src/components/base/GridOverlays.tsx b/packages/x-data-grid/src/components/base/GridOverlays.tsx index e21561bcdf27..79baf162939d 100644 --- a/packages/x-data-grid/src/components/base/GridOverlays.tsx +++ b/packages/x-data-grid/src/components/base/GridOverlays.tsx @@ -93,6 +93,15 @@ function GridOverlayWrapper(props: React.PropsWithChildren) { ); } +GridOverlayWrapper.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + loadingOverlayVariant: PropTypes.oneOf(['circular-progress', 'linear-progress', 'skeleton']), + overlayType: PropTypes.oneOf(['loadingOverlay', 'noResultsOverlay', 'noRowsOverlay']), +} as any; + GridOverlays.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | diff --git a/packages/x-data-grid/src/components/containers/GridRootStyles.ts b/packages/x-data-grid/src/components/containers/GridRootStyles.ts index f66edba975ea..86b93de0962d 100644 --- a/packages/x-data-grid/src/components/containers/GridRootStyles.ts +++ b/packages/x-data-grid/src/components/containers/GridRootStyles.ts @@ -535,6 +535,7 @@ export const GridRootStyles = styled('div', { /* Cell styles */ [`& .${c.cell}`]: { + flex: '0 0 auto', height: 'var(--height)', width: 'var(--width)', lineHeight: 'calc(var(--height) - 1px)', // -1px for the border diff --git a/packages/x-data-grid/src/components/menu/columnMenu/GridColumnMenu.tsx b/packages/x-data-grid/src/components/menu/columnMenu/GridColumnMenu.tsx index 3842fe844f93..b5a94ecc60df 100644 --- a/packages/x-data-grid/src/components/menu/columnMenu/GridColumnMenu.tsx +++ b/packages/x-data-grid/src/components/menu/columnMenu/GridColumnMenu.tsx @@ -42,6 +42,39 @@ const GridGenericColumnMenu = React.forwardRef( function GridColumnMenu(props, ref) { return ( diff --git a/packages/x-data-grid/src/components/toolbar/GridToolbarExport.tsx b/packages/x-data-grid/src/components/toolbar/GridToolbarExport.tsx index 855233ca9ecc..672e5e32dbe1 100644 --- a/packages/x-data-grid/src/components/toolbar/GridToolbarExport.tsx +++ b/packages/x-data-grid/src/components/toolbar/GridToolbarExport.tsx @@ -35,7 +35,7 @@ export interface GridToolbarExportProps { [key: string]: any; } -export function GridCsvExportMenuItem(props: GridCsvExportMenuItemProps) { +function GridCsvExportMenuItem(props: GridCsvExportMenuItemProps) { const apiRef = useGridApiContext(); const { hideMenu, options, ...other } = props; @@ -52,7 +52,28 @@ export function GridCsvExportMenuItem(props: GridCsvExportMenuItemProps) { ); } -export function GridPrintExportMenuItem(props: GridPrintExportMenuItemProps) { +GridCsvExportMenuItem.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + hideMenu: PropTypes.func, + options: PropTypes.shape({ + allColumns: PropTypes.bool, + delimiter: PropTypes.string, + disableToolbarButton: PropTypes.bool, + escapeFormulas: PropTypes.bool, + fields: PropTypes.arrayOf(PropTypes.string), + fileName: PropTypes.string, + getRowsToExport: PropTypes.func, + includeColumnGroupsHeaders: PropTypes.bool, + includeHeaders: PropTypes.bool, + shouldAppendQuotes: PropTypes.bool, + utf8WithBom: PropTypes.bool, + }), +} as any; + +function GridPrintExportMenuItem(props: GridPrintExportMenuItemProps) { const apiRef = useGridApiContext(); const { hideMenu, options, ...other } = props; @@ -69,6 +90,42 @@ export function GridPrintExportMenuItem(props: GridPrintExportMenuItemProps) { ); } +GridPrintExportMenuItem.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + hideMenu: PropTypes.func, + options: PropTypes.shape({ + allColumns: PropTypes.bool, + bodyClassName: PropTypes.string, + copyStyles: PropTypes.bool, + disableToolbarButton: PropTypes.bool, + fields: PropTypes.arrayOf(PropTypes.string), + fileName: PropTypes.string, + getRowsToExport: PropTypes.func, + hideFooter: PropTypes.bool, + hideToolbar: PropTypes.bool, + includeCheckboxes: PropTypes.bool, + pageStyle: PropTypes.oneOfType([ + PropTypes.shape({ + '__@hasInstance@646': PropTypes.func.isRequired, + '__@metadata@648': PropTypes.any, + apply: PropTypes.func.isRequired, + arguments: PropTypes.any.isRequired, + bind: PropTypes.func.isRequired, + call: PropTypes.func.isRequired, + caller: PropTypes.object.isRequired, + length: PropTypes.number.isRequired, + name: PropTypes.string.isRequired, + prototype: PropTypes.any.isRequired, + toString: PropTypes.func.isRequired, + }), + PropTypes.string, + ]), + }), +} as any; + const GridToolbarExport = React.forwardRef( function GridToolbarExport(props, ref) { const { csvOptions = {}, printOptions = {}, excelOptions, ...other } = props; @@ -107,4 +164,4 @@ GridToolbarExport.propTypes = { slotProps: PropTypes.object, } as any; -export { GridToolbarExport }; +export { GridToolbarExport, GridCsvExportMenuItem, GridPrintExportMenuItem }; diff --git a/packages/x-data-grid/src/components/virtualization/GridVirtualScrollbar.tsx b/packages/x-data-grid/src/components/virtualization/GridVirtualScrollbar.tsx index e5bf5410f4cc..c832d1414553 100644 --- a/packages/x-data-grid/src/components/virtualization/GridVirtualScrollbar.tsx +++ b/packages/x-data-grid/src/components/virtualization/GridVirtualScrollbar.tsx @@ -148,6 +148,11 @@ const GridVirtualScrollbar = React.forwardRef