From 4fabbc722c0c68723051e1bd895ae26e7b09c750 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 19 Dec 2023 12:02:26 +0100 Subject: [PATCH 01/26] [tree view] Add support for checkbox selection --- docs/pages/x/api/tree-view/tree-view.json | 1 + .../api-docs/tree-view/tree-view.json | 7 ++++++- .../src/TreeItem/TreeItemContent.tsx | 20 ++++++++++++++++++- .../x-tree-view/src/TreeItem/useTreeItem.ts | 14 +++++++++---- .../x-tree-view/src/TreeView/TreeView.tsx | 9 ++++++++- .../TreeViewProvider/TreeViewContext.ts | 1 + .../TreeViewProvider.types.ts | 1 + .../useTreeViewContextValueBuilder.ts | 1 + .../useTreeViewSelection.ts | 1 + .../useTreeViewSelection.types.ts | 9 +++++++-- 10 files changed, 55 insertions(+), 9 deletions(-) diff --git a/docs/pages/x/api/tree-view/tree-view.json b/docs/pages/x/api/tree-view/tree-view.json index fdb60b7484676..3e02cd04aabbb 100644 --- a/docs/pages/x/api/tree-view/tree-view.json +++ b/docs/pages/x/api/tree-view/tree-view.json @@ -1,5 +1,6 @@ { "props": { + "checkboxSelection": { "type": { "name": "bool" } }, "children": { "type": { "name": "node" } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "className": { "type": { "name": "string" } }, diff --git a/docs/translations/api-docs/tree-view/tree-view.json b/docs/translations/api-docs/tree-view/tree-view.json index 515b716f54b1c..a812d4ce32d3f 100644 --- a/docs/translations/api-docs/tree-view/tree-view.json +++ b/docs/translations/api-docs/tree-view/tree-view.json @@ -1,6 +1,11 @@ { "componentDescription": "", "propDescriptions": { + "checkboxSelection": { + "description": "If true, the tree view renders a checkbox at the left of its label that allows selecting it.", + "deprecated": "", + "typeDescriptions": {} + }, "children": { "description": "The content of the component.", "deprecated": "", @@ -67,7 +72,7 @@ "typeDescriptions": {} }, "multiSelect": { - "description": "If true ctrl and shift will trigger multiselect.", + "description": "If true, ctrl and shift will trigger multiselect.", "deprecated": "", "typeDescriptions": {} }, diff --git a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx index 257fad0a123b9..f1b631fcdb018 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; +import Checkbox from '@mui/material/Checkbox'; import { useTreeItem } from './useTreeItem'; export interface TreeItemContentProps extends React.HTMLAttributes { @@ -76,12 +77,14 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( expanded, selected, focused, + checkboxSelection, handleExpansion, handleSelection, preventSelection, } = useTreeItem(nodeId); const icon = iconProp || expansionIcon || displayIcon; + const checkboxRef = React.useRef(null); const handleMouseDown = (event: React.MouseEvent) => { preventSelection(event); @@ -92,14 +95,25 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( }; const handleClick = (event: React.MouseEvent) => { + if (checkboxRef.current?.contains(event.target as HTMLElement)) { + return; + } + handleExpansion(event); - handleSelection(event); + + if (!checkboxSelection) { + handleSelection(event); + } if (onClick) { onClick(event); } }; + const handleCheckboxSelectionChange = (event: React.ChangeEvent) => { + handleSelection(event); + }; + return ( /* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions -- Key event is handled by the TreeView */
{icon}
+ {checkboxSelection && ( + + )} +
{label}
); diff --git a/packages/x-tree-view/src/TreeItem/useTreeItem.ts b/packages/x-tree-view/src/TreeItem/useTreeItem.ts index 6c67d101dca11..3aa79321a98a8 100644 --- a/packages/x-tree-view/src/TreeItem/useTreeItem.ts +++ b/packages/x-tree-view/src/TreeItem/useTreeItem.ts @@ -3,7 +3,7 @@ import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewCon import { DefaultTreeViewPlugins } from '../internals/plugins'; export function useTreeItem(nodeId: string) { - const { instance, multiSelect } = useTreeViewContext(); + const { instance, multiSelect, checkboxSelection } = useTreeViewContext(); const expandable = instance ? instance.isNodeExpandable(nodeId) : false; const expanded = instance ? instance.isNodeExpanded(nodeId) : false; @@ -26,16 +26,21 @@ export function useTreeItem(nodeId: string) { } }; - const handleSelection = (event: React.MouseEvent) => { + const handleSelection = (event: React.ChangeEvent | React.MouseEvent) => { if (instance && !disabled) { if (!focused) { instance.focusNode(event, nodeId); } - const multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey); + const nativeEvent = (event.type === 'change' + ? event.nativeEvent + : event) as unknown as React.MouseEvent; + + const multiple = + multiSelect && (nativeEvent.shiftKey || nativeEvent.ctrlKey || nativeEvent.metaKey); if (multiple) { - if (event.shiftKey) { + if (nativeEvent.shiftKey) { instance.selectRange(event, { end: nodeId }); } else { instance.selectNode(event, nodeId, true); @@ -58,6 +63,7 @@ export function useTreeItem(nodeId: string) { expanded, selected, focused, + checkboxSelection, handleExpansion, handleSelection, preventSelection, diff --git a/packages/x-tree-view/src/TreeView/TreeView.tsx b/packages/x-tree-view/src/TreeView/TreeView.tsx index abb4a9d327390..7a38ce3ce85cf 100644 --- a/packages/x-tree-view/src/TreeView/TreeView.tsx +++ b/packages/x-tree-view/src/TreeView/TreeView.tsx @@ -63,6 +63,7 @@ const TreeView = React.forwardRef(function TreeView< defaultSelected, selected, multiSelect, + checkboxSelection, onNodeSelect, id, defaultCollapseIcon, @@ -84,6 +85,7 @@ const TreeView = React.forwardRef(function TreeView< defaultSelected, selected, multiSelect, + checkboxSelection, onNodeSelect, id, defaultCollapseIcon, @@ -117,6 +119,11 @@ TreeView.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * If `true`, the tree view renders a checkbox at the left of its label that allows selecting it. + * @default false + */ + checkboxSelection: PropTypes.bool, /** * The content of the component. */ @@ -183,7 +190,7 @@ TreeView.propTypes = { */ id: PropTypes.string, /** - * If true `ctrl` and `shift` will trigger multiselect. + * If `true`, `ctrl` and `shift` will trigger multiselect. * @default false */ multiSelect: PropTypes.bool, diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewContext.ts b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewContext.ts index 9d47c2a4cda7f..68698b8a934df 100644 --- a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewContext.ts +++ b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewContext.ts @@ -4,6 +4,7 @@ import { TreeViewContextValue } from './TreeViewProvider.types'; export const DEFAULT_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue = { instance: null, multiSelect: false, + checkboxSelection: false, disabledItemsFocusable: false, treeId: undefined, icons: { diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts index 4838c0704a62d..a0fb478cce4ba 100644 --- a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts +++ b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts @@ -5,6 +5,7 @@ export interface TreeViewContextValue | null; multiSelect: boolean; + checkboxSelection: boolean; disabledItemsFocusable: boolean; icons: { defaultCollapseIcon: React.ReactNode; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts index a0e27dfa8c356..e6d2b4ccab295 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts @@ -15,6 +15,7 @@ export const useTreeViewContextValueBuilder: TreeViewPlugin< treeId, instance: instance as TreeViewInstance, multiSelect: params.multiSelect, + checkboxSelection: params.checkboxSelection, disabledItemsFocusable: params.disabledItemsFocusable, icons: { defaultCollapseIcon: params.defaultCollapseIcon, diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts index e932f98cdf0a6..16f0937c7ec44 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts @@ -206,5 +206,6 @@ useTreeViewSelection.getDefaultizedParams = (params) => ({ ...params, disableSelection: params.disableSelection ?? false, multiSelect: params.multiSelect ?? false, + checkboxSelection: params.checkboxSelection ?? false, defaultSelected: params.defaultSelected ?? (params.multiSelect ? DEFAULT_SELECTED : null), }); diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts index f9fde5d9f9c06..e011c73c02a29 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts @@ -33,10 +33,15 @@ export interface UseTreeViewSelectionParameters; /** - * If true `ctrl` and `shift` will trigger multiselect. + * If `true`, `ctrl` and `shift` will trigger multiselect. * @default false */ multiSelect?: Multiple; + /** + * If `true`, the tree view renders a checkbox at the left of its label that allows selecting it. + * @default false + */ + checkboxSelection?: boolean; /** * Callback fired when tree items are selected/unselected. * @param {React.SyntheticEvent} event The event source of the callback @@ -51,7 +56,7 @@ export interface UseTreeViewSelectionParameters = DefaultizedProps< UseTreeViewSelectionParameters, - 'disableSelection' | 'defaultSelected' | 'multiSelect' + 'disableSelection' | 'defaultSelected' | 'multiSelect' | 'checkboxSelection' >; export type UseTreeViewSelectionSignature = From 54a5400c6c559bcf047e52df6930cc0540a50b10 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 19 Dec 2023 13:41:41 +0100 Subject: [PATCH 02/26] Add doc --- .../overview/CheckboxMultiSelection.js | 28 +++++++++++++++++++ .../overview/CheckboxMultiSelection.tsx | 28 +++++++++++++++++++ .../tree-view/overview/CheckboxSelection.js | 27 ++++++++++++++++++ .../tree-view/overview/CheckboxSelection.tsx | 27 ++++++++++++++++++ docs/data/tree-view/overview/overview.md | 10 +++++++ 5 files changed, 120 insertions(+) create mode 100644 docs/data/tree-view/overview/CheckboxMultiSelection.js create mode 100644 docs/data/tree-view/overview/CheckboxMultiSelection.tsx create mode 100644 docs/data/tree-view/overview/CheckboxSelection.js create mode 100644 docs/data/tree-view/overview/CheckboxSelection.tsx diff --git a/docs/data/tree-view/overview/CheckboxMultiSelection.js b/docs/data/tree-view/overview/CheckboxMultiSelection.js new file mode 100644 index 0000000000000..e210f8324c624 --- /dev/null +++ b/docs/data/tree-view/overview/CheckboxMultiSelection.js @@ -0,0 +1,28 @@ +import * as React from 'react'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import { TreeView } from '@mui/x-tree-view/TreeView'; +import { TreeItem } from '@mui/x-tree-view/TreeItem'; + +export default function CheckboxMultiSelection() { + return ( + } + defaultExpandIcon={} + checkboxSelection + multiSelect + sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }} + > + + + + + + + + + + + ); +} diff --git a/docs/data/tree-view/overview/CheckboxMultiSelection.tsx b/docs/data/tree-view/overview/CheckboxMultiSelection.tsx new file mode 100644 index 0000000000000..e210f8324c624 --- /dev/null +++ b/docs/data/tree-view/overview/CheckboxMultiSelection.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import { TreeView } from '@mui/x-tree-view/TreeView'; +import { TreeItem } from '@mui/x-tree-view/TreeItem'; + +export default function CheckboxMultiSelection() { + return ( + } + defaultExpandIcon={} + checkboxSelection + multiSelect + sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }} + > + + + + + + + + + + + ); +} diff --git a/docs/data/tree-view/overview/CheckboxSelection.js b/docs/data/tree-view/overview/CheckboxSelection.js new file mode 100644 index 0000000000000..3b1974004d8c6 --- /dev/null +++ b/docs/data/tree-view/overview/CheckboxSelection.js @@ -0,0 +1,27 @@ +import * as React from 'react'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import { TreeView } from '@mui/x-tree-view/TreeView'; +import { TreeItem } from '@mui/x-tree-view/TreeItem'; + +export default function CheckboxSelection() { + return ( + } + defaultExpandIcon={} + checkboxSelection + sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }} + > + + + + + + + + + + + ); +} diff --git a/docs/data/tree-view/overview/CheckboxSelection.tsx b/docs/data/tree-view/overview/CheckboxSelection.tsx new file mode 100644 index 0000000000000..3b1974004d8c6 --- /dev/null +++ b/docs/data/tree-view/overview/CheckboxSelection.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import { TreeView } from '@mui/x-tree-view/TreeView'; +import { TreeItem } from '@mui/x-tree-view/TreeItem'; + +export default function CheckboxSelection() { + return ( + } + defaultExpandIcon={} + checkboxSelection + sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }} + > + + + + + + + + + + + ); +} diff --git a/docs/data/tree-view/overview/overview.md b/docs/data/tree-view/overview/overview.md index dabd994c8d325..23deb6d0a7b3e 100644 --- a/docs/data/tree-view/overview/overview.md +++ b/docs/data/tree-view/overview/overview.md @@ -25,6 +25,16 @@ Tree views also support multi-selection. {{"demo": "MultiSelectTreeView.js"}} +## Checkbox selection + +To activate checkbox selection set `checkboxSelection={true}`: + +{{"demo": "CheckboxSelection.js"}} + +This is also compatible with multi selection: + +{{"demo": "CheckboxMultiSelection.js"}} + ## Controlled tree view The tree view also offers a controlled API. From 19a94feba0b714c0de3e59b095569fda0f74b969 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 2 Jan 2024 10:32:33 +0100 Subject: [PATCH 03/26] Fix --- .../tree-view/simple-tree-view/selection/CheckboxSelection.js | 2 +- .../tree-view/simple-tree-view/selection/CheckboxSelection.tsx | 2 +- packages/x-tree-view/src/TreeItem/TreeItem.test.tsx | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js index 1777d06da4b7a..9b0b25848798c 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js @@ -5,7 +5,7 @@ import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; import { TreeItem } from '@mui/x-tree-view/TreeItem'; -export default function MultiSelectTreeView() { +export default function CheckboxSelection() { return ( = { } as any, runItemPlugins: ({ props, ref }) => ({ props, ref, wrapItem: (children) => children }), multiSelect: false, + checkboxSelection: false, disabledItemsFocusable: false, icons: { defaultCollapseIcon: null, From 8baa24e52858dbaa72680802a3cc95933d23c37a Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 3 Jan 2024 16:35:12 +0100 Subject: [PATCH 04/26] Review Jose --- packages/x-tree-view/src/TreeItem/TreeItemContent.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx index f1b631fcdb018..906b571977ecc 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx @@ -17,7 +17,7 @@ export interface TreeItemContentProps extends React.HTMLAttributes root: string; /** State class applied to the content element when expanded. */ expanded: string; - /** State class applied to the content element when selected. */ + /** State class applied to the content element when selected and not using the checkbox selection. */ selected: string; /** State class applied to the content element when focused. */ focused: string; @@ -120,7 +120,7 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( {...other} className={clsx(className, classes.root, { [classes.expanded]: expanded, - [classes.selected]: selected, + [classes.selected]: selected && !checkboxSelection, [classes.focused]: focused, [classes.disabled]: disabled, })} From 3486d4f0a3f9c49d21c8be34d5aa4088ebd69fc1 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 4 Jan 2024 11:04:34 +0100 Subject: [PATCH 05/26] Remove context builder hook --- .../tree-view/headless/HeadlessTreeView.tsx | 2 ++ .../x-tree-view/src/TreeItem/TreeItem.tsx | 14 +++++++----- .../src/TreeItem/TreeItemContent.tsx | 12 +++++++++- .../src/TreeItem/treeItemClasses.ts | 5 ++++- .../x-tree-view/src/TreeItem/useTreeItem.ts | 7 +++++- .../TreeViewProvider.types.ts | 17 +++++--------- .../useTreeViewInstanceEvents.types.ts | 1 + .../src/internals/models/helpers.ts | 7 +++++- .../src/internals/models/plugin.ts | 13 ++++++----- .../src/internals/plugins/defaultPlugins.ts | 9 +++----- .../useTreeViewContextValueBuilder/index.ts | 6 ----- .../useTreeViewContextValueBuilder.ts | 22 ------------------- .../useTreeViewExpansion.types.ts | 1 + .../useTreeViewFocus/useTreeViewFocus.ts | 5 ----- .../useTreeViewFocus.types.ts | 1 + .../plugins/useTreeViewIcons/index.ts | 6 +++++ .../useTreeViewIcons/useTreeViewIcons.ts | 15 +++++++++++++ .../useTreeViewIcons.types.ts} | 21 +++++++++++++----- .../useTreeViewId/useTreeViewId.types.ts | 7 ++---- .../useTreeViewJSXNodes.types.ts | 1 + .../useTreeViewKeyboardNavigation.types.ts | 1 + .../useTreeViewNodes/useTreeViewNodes.ts | 9 ++++++++ .../useTreeViewNodes.types.ts | 4 ++++ .../useTreeViewSelection.ts | 7 ++++++ .../useTreeViewSelection.types.ts | 8 +++++++ .../src/internals/useTreeView/useTreeView.ts | 18 +++++++++++---- 26 files changed, 138 insertions(+), 81 deletions(-) delete mode 100644 packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/index.ts delete mode 100644 packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts create mode 100644 packages/x-tree-view/src/internals/plugins/useTreeViewIcons/index.ts create mode 100644 packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.ts rename packages/x-tree-view/src/internals/plugins/{useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.types.ts => useTreeViewIcons/useTreeViewIcons.types.ts} (63%) diff --git a/docs/data/tree-view/headless/HeadlessTreeView.tsx b/docs/data/tree-view/headless/HeadlessTreeView.tsx index 0d5f611d1374c..1c5b2f6e467b3 100644 --- a/docs/data/tree-view/headless/HeadlessTreeView.tsx +++ b/docs/data/tree-view/headless/HeadlessTreeView.tsx @@ -51,6 +51,8 @@ type TreeViewLogExpandedSignature = TreeViewPluginSignature< {}, // State defined by this plugin: we don't have any {}, + // Context value defined by this plugin: we don't have any + {}, // Models defined by plugin: we don't have any never, // Dependencies of this plugin (we need the expansion plugin to access its model) diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.tsx index 617c712b27de4..6a081290c1dc7 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.tsx @@ -21,6 +21,7 @@ const useUtilityClasses = (ownerState: TreeItemOwnerState) => { expanded: ['expanded'], selected: ['selected'], focused: ['focused'], + interactive: ['interactive'], disabled: ['disabled'], iconContainer: ['iconContainer'], label: ['label'], @@ -61,9 +62,11 @@ const StyledTreeItemContent = styled(TreeItemContent, { boxSizing: 'border-box', // prevent width + padding to overflow display: 'flex', alignItems: 'center', - cursor: 'pointer', + [`&.${treeItemClasses.interactive}`]: { + cursor: 'pointer', + }, WebkitTapHighlightColor: 'transparent', - '&:hover': { + [`&.${treeItemClasses.interactive}:hover`]: { backgroundColor: (theme.vars || theme).palette.action.hover, // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { @@ -77,11 +80,11 @@ const StyledTreeItemContent = styled(TreeItemContent, { [`&.${treeItemClasses.focused}`]: { backgroundColor: (theme.vars || theme).palette.action.focus, }, - [`&.${treeItemClasses.selected}`]: { + [`.${treeItemClasses.selected}`]: { backgroundColor: theme.vars ? `rgba(${theme.vars.palette.primary.mainChannel} / ${theme.vars.palette.action.selectedOpacity})` : alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity), - '&:hover': { + [`&.${treeItemClasses.interactive}:hover`]: { backgroundColor: theme.vars ? `rgba(${theme.vars.palette.primary.mainChannel} / calc(${theme.vars.palette.action.selectedOpacity} + ${theme.vars.palette.action.hoverOpacity}))` : alpha( @@ -152,7 +155,7 @@ export const TreeItem = React.forwardRef(function TreeItem( const { icons: contextIcons, runItemPlugins, - multiSelect, + selection: { multiSelect }, disabledItemsFocusable, instance, } = useTreeViewContext(); @@ -260,6 +263,7 @@ export const TreeItem = React.forwardRef(function TreeItem( root: classes.content, expanded: classes.expanded, selected: classes.selected, + interactive: classes.interactive, focused: classes.focused, disabled: classes.disabled, iconContainer: classes.iconContainer, diff --git a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx index 906b571977ecc..96c2a8169cf41 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx @@ -19,6 +19,8 @@ export interface TreeItemContentProps extends React.HTMLAttributes expanded: string; /** State class applied to the content element when selected and not using the checkbox selection. */ selected: string; + /** State class applied to the content element when clicking it causes an action. */ + interactive: string; /** State class applied to the content element when focused. */ focused: string; /** State class applied to the element when disabled. */ @@ -75,8 +77,10 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( const { disabled, expanded, + expandable, selected, focused, + disableSelection, checkboxSelection, handleExpansion, handleSelection, @@ -121,6 +125,7 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( className={clsx(className, classes.root, { [classes.expanded]: expanded, [classes.selected]: selected && !checkboxSelection, + [classes.interactive]: (!checkboxSelection && !disableSelection) || expandable, [classes.focused]: focused, [classes.disabled]: disabled, })} @@ -130,7 +135,12 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( >
{icon}
{checkboxSelection && ( - + )}
{label}
diff --git a/packages/x-tree-view/src/TreeItem/treeItemClasses.ts b/packages/x-tree-view/src/TreeItem/treeItemClasses.ts index 1578b5c5c9eec..d4d0bcbc216dd 100644 --- a/packages/x-tree-view/src/TreeItem/treeItemClasses.ts +++ b/packages/x-tree-view/src/TreeItem/treeItemClasses.ts @@ -10,8 +10,10 @@ export interface TreeItemClasses { content: string; /** State class applied to the content element when expanded. */ expanded: string; - /** State class applied to the content element when selected. */ + /** State class applied to the content element when selected and not using the checkbox selection. */ selected: string; + /** State class applied to the content element when clicking it causes an action. */ + interactive: string; /** State class applied to the content element when focused. */ focused: string; /** State class applied to the element when disabled. */ @@ -34,6 +36,7 @@ export const treeItemClasses: TreeItemClasses = generateUtilityClasses('MuiTreeI 'content', 'expanded', 'selected', + 'interactive', 'focused', 'disabled', 'iconContainer', diff --git a/packages/x-tree-view/src/TreeItem/useTreeItem.ts b/packages/x-tree-view/src/TreeItem/useTreeItem.ts index 0810438dba919..cea02393692e0 100644 --- a/packages/x-tree-view/src/TreeItem/useTreeItem.ts +++ b/packages/x-tree-view/src/TreeItem/useTreeItem.ts @@ -3,7 +3,10 @@ import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewCon import { DefaultTreeViewPlugins } from '../internals/plugins'; export function useTreeItem(nodeId: string) { - const { instance, multiSelect, checkboxSelection } = useTreeViewContext(); + const { + instance, + selection: { multiSelect, checkboxSelection, disableSelection }, + } = useTreeViewContext(); const expandable = instance.isNodeExpandable(nodeId); const expanded = instance.isNodeExpanded(nodeId); @@ -59,10 +62,12 @@ export function useTreeItem(nodeId: string) { }; return { + expandable, disabled, expanded, selected, focused, + disableSelection, checkboxSelection, handleExpansion, handleSelection, diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts index 94efc6a2d9d69..0ef0c989b4ba4 100644 --- a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts +++ b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts @@ -1,24 +1,17 @@ import * as React from 'react'; import { + MergePluginsProperty, TreeViewAnyPluginSignature, TreeViewInstance, TreeViewItemPluginOptions, TreeViewItemPluginResponse, } from '../models'; -export interface TreeViewContextValue { - instance: TreeViewInstance; - runItemPlugins: (options: TreeViewItemPluginOptions) => Required; - multiSelect: boolean; - checkboxSelection: boolean; - disabledItemsFocusable: boolean; - icons: { - defaultCollapseIcon: React.ReactNode; - defaultExpandIcon: React.ReactNode; - defaultParentIcon: React.ReactNode; - defaultEndIcon: React.ReactNode; +export type TreeViewContextValue = + MergePluginsProperty & { + instance: TreeViewInstance; + runItemPlugins: (options: TreeViewItemPluginOptions) => Required; }; -} export interface TreeViewProviderProps { value: TreeViewContextValue; diff --git a/packages/x-tree-view/src/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.types.ts b/packages/x-tree-view/src/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.types.ts index 495e26e0c0edb..dc7ac193be879 100644 --- a/packages/x-tree-view/src/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.types.ts +++ b/packages/x-tree-view/src/internals/corePlugins/useTreeViewInstanceEvents/useTreeViewInstanceEvents.types.ts @@ -25,6 +25,7 @@ export type UseTreeViewInstanceEventsSignature = TreeViewPluginSignature< UseTreeViewInstanceEventsInstance, {}, {}, + {}, never, [] >; diff --git a/packages/x-tree-view/src/internals/models/helpers.ts b/packages/x-tree-view/src/internals/models/helpers.ts index d04446baf3a03..115a91d9d21d5 100644 --- a/packages/x-tree-view/src/internals/models/helpers.ts +++ b/packages/x-tree-view/src/internals/models/helpers.ts @@ -1,4 +1,4 @@ -import { TreeViewAnyPluginSignature, TreeViewPlugin } from './plugin'; +import type { TreeViewAnyPluginSignature, TreeViewPlugin } from './plugin'; export type DefaultizedProps< P extends {}, @@ -8,6 +8,10 @@ export type DefaultizedProps< Required> & AdditionalProps; +export type OptionalIfEmpty = keyof B extends never + ? Partial> + : Record; + export type MergePluginsProperty< TPlugins extends readonly any[], TProperty extends keyof TreeViewAnyPluginSignature, @@ -30,6 +34,7 @@ export interface MergePlugins { params: MergePluginsProperty; defaultizedParams: MergePluginsProperty; dependantPlugins: MergePluginsProperty; + contextValue: MergePluginsProperty; events: MergePluginsProperty; models: MergePluginsProperty; } diff --git a/packages/x-tree-view/src/internals/models/plugin.ts b/packages/x-tree-view/src/internals/models/plugin.ts index 366035c79b5f5..ae794f7455e2b 100644 --- a/packages/x-tree-view/src/internals/models/plugin.ts +++ b/packages/x-tree-view/src/internals/models/plugin.ts @@ -1,8 +1,7 @@ import * as React from 'react'; import { EventHandlers } from '@mui/base/utils'; import { TreeViewModel } from './treeView'; -import type { TreeViewContextValue } from '../TreeViewProvider'; -import type { MergePluginsProperty } from './helpers'; +import type { MergePluginsProperty, OptionalIfEmpty } from './helpers'; import { TreeViewEventLookupElement } from './events'; import type { TreeViewCorePluginsSignature } from '../corePlugins'; import type { TreeItemProps } from '../../TreeItem'; @@ -23,12 +22,11 @@ type TreeViewModelsInitializer = }; }; -interface TreeViewResponse { +type TreeViewResponse = { getRootProps?: ( otherHandlers: TOther, ) => React.HTMLAttributes; - contextValue?: TreeViewContextValue; -} +} & OptionalIfEmpty<'contextValue', TSignature['contextValue']>; export type TreeViewPluginSignature< TParams extends {}, @@ -36,6 +34,7 @@ export type TreeViewPluginSignature< TInstance extends {}, TEvents extends { [key in keyof TEvents]: TreeViewEventLookupElement }, TState extends {}, + TContextValue extends {}, TModelNames extends keyof TDefaultizedParams, TDependantPlugins extends readonly TreeViewAnyPluginSignature[], > = { @@ -49,6 +48,7 @@ export type TreeViewPluginSignature< >; }; events: TEvents; + contextValue: TContextValue; dependantPlugins: TDependantPlugins; }; @@ -59,6 +59,7 @@ export type TreeViewAnyPluginSignature = { defaultizedParams: any; dependantPlugins: any; events: any; + contextValue: {}; models: any; }; @@ -119,7 +120,7 @@ export type TreeViewItemPlugin = ( ) => void | TreeViewItemPluginResponse; export type TreeViewPlugin = { - (options: TreeViewPluginOptions): void | TreeViewResponse; + (options: TreeViewPluginOptions): void | TreeViewResponse; getDefaultizedParams?: ( params: TreeViewUsedParams, ) => TSignature['defaultizedParams']; diff --git a/packages/x-tree-view/src/internals/plugins/defaultPlugins.ts b/packages/x-tree-view/src/internals/plugins/defaultPlugins.ts index 5b0637f019466..c050ccad4d01f 100644 --- a/packages/x-tree-view/src/internals/plugins/defaultPlugins.ts +++ b/packages/x-tree-view/src/internals/plugins/defaultPlugins.ts @@ -4,10 +4,7 @@ import { useTreeViewExpansion, UseTreeViewExpansionParameters } from './useTreeV import { useTreeViewSelection, UseTreeViewSelectionParameters } from './useTreeViewSelection'; import { useTreeViewFocus, UseTreeViewFocusParameters } from './useTreeViewFocus'; import { useTreeViewKeyboardNavigation } from './useTreeViewKeyboardNavigation'; -import { - useTreeViewContextValueBuilder, - UseTreeViewContextValueBuilderParameters, -} from './useTreeViewContextValueBuilder'; +import { useTreeViewIcons, UseTreeViewIconsParameters } from './useTreeViewIcons'; import { ConvertPluginsIntoSignatures } from '../models'; export const DEFAULT_TREE_VIEW_PLUGINS = [ @@ -17,7 +14,7 @@ export const DEFAULT_TREE_VIEW_PLUGINS = [ useTreeViewSelection, useTreeViewFocus, useTreeViewKeyboardNavigation, - useTreeViewContextValueBuilder, + useTreeViewIcons, ] as const; export type DefaultTreeViewPlugins = ConvertPluginsIntoSignatures; @@ -29,4 +26,4 @@ export interface DefaultTreeViewPluginParameters, - UseTreeViewContextValueBuilderParameters {} + UseTreeViewIconsParameters {} diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/index.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/index.ts deleted file mode 100644 index 30bfda12c2ad2..0000000000000 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { useTreeViewContextValueBuilder } from './useTreeViewContextValueBuilder'; -export type { - UseTreeViewContextValueBuilderSignature, - UseTreeViewContextValueBuilderParameters, - UseTreeViewContextValueBuilderDefaultizedParameters, -} from './useTreeViewContextValueBuilder.types'; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts deleted file mode 100644 index 77af6651093af..0000000000000 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { TreeViewInstance, TreeViewPlugin } from '../../models'; -import { UseTreeViewContextValueBuilderSignature } from './useTreeViewContextValueBuilder.types'; - -export const useTreeViewContextValueBuilder: TreeViewPlugin< - UseTreeViewContextValueBuilderSignature -> = ({ instance, params }) => { - return { - contextValue: { - instance: instance as TreeViewInstance, - multiSelect: params.multiSelect, - checkboxSelection: params.checkboxSelection, - runItemPlugins: ({ props, ref }) => ({ props, ref, wrapItem: (children) => children }), - disabledItemsFocusable: params.disabledItemsFocusable, - icons: { - defaultCollapseIcon: params.defaultCollapseIcon, - defaultEndIcon: params.defaultEndIcon, - defaultExpandIcon: params.defaultExpandIcon, - defaultParentIcon: params.defaultParentIcon, - }, - }, - }; -}; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts index 06757c9538203..b9784f6903192 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts @@ -51,6 +51,7 @@ export type UseTreeViewExpansionSignature = TreeViewPluginSignature< UseTreeViewExpansionInstance, {}, {}, + {}, 'expandedNodes', [UseTreeViewNodesSignature] >; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.ts index 8211cf5735a12..cf5a54693a999 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.ts @@ -107,8 +107,3 @@ export const useTreeViewFocus: TreeViewPlugin = ({ }; useTreeViewFocus.getInitialState = () => ({ focusedNodeId: null }); - -useTreeViewFocus.getDefaultizedParams = (params) => ({ - ...params, - disabledItemsFocusable: params.disabledItemsFocusable ?? false, -}); diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.ts index 81605d985aca7..33a0151a603b2 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewFocus/useTreeViewFocus.types.ts @@ -33,6 +33,7 @@ export type UseTreeViewFocusSignature = TreeViewPluginSignature< UseTreeViewFocusInstance, {}, UseTreeViewFocusState, + {}, never, [ UseTreeViewIdSignature, diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/index.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/index.ts new file mode 100644 index 0000000000000..83596f56cfb78 --- /dev/null +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/index.ts @@ -0,0 +1,6 @@ +export { useTreeViewIcons } from './useTreeViewIcons'; +export type { + UseTreeViewIconsSignature, + UseTreeViewIconsParameters, + UseTreeViewIconsDefaultizedParameters, +} from './useTreeViewIcons.types'; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.ts new file mode 100644 index 0000000000000..7255872c97022 --- /dev/null +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.ts @@ -0,0 +1,15 @@ +import { TreeViewPlugin } from '../../models'; +import { UseTreeViewIconsSignature } from './useTreeViewIcons.types'; + +export const useTreeViewIcons: TreeViewPlugin = ({ params }) => { + return { + contextValue: { + icons: { + defaultCollapseIcon: params.defaultCollapseIcon, + defaultEndIcon: params.defaultEndIcon, + defaultExpandIcon: params.defaultExpandIcon, + defaultParentIcon: params.defaultParentIcon, + }, + }, + }; +}; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.ts similarity index 63% rename from packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.types.ts rename to packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.ts index 03d9fc3d529a2..2ad068c7ababf 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewContextValueBuilder/useTreeViewContextValueBuilder.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewIcons/useTreeViewIcons.types.ts @@ -3,7 +3,7 @@ import { TreeViewPluginSignature } from '../../models'; import { UseTreeViewNodesSignature } from '../useTreeViewNodes'; import { UseTreeViewSelectionSignature } from '../useTreeViewSelection'; -export interface UseTreeViewContextValueBuilderParameters { +export interface UseTreeViewIconsParameters { /** * The default icon used to collapse the node. */ @@ -24,15 +24,24 @@ export interface UseTreeViewContextValueBuilderParameters { defaultParentIcon?: React.ReactNode; } -export type UseTreeViewContextValueBuilderDefaultizedParameters = - UseTreeViewContextValueBuilderParameters; +export type UseTreeViewIconsDefaultizedParameters = UseTreeViewIconsParameters; -export type UseTreeViewContextValueBuilderSignature = TreeViewPluginSignature< - UseTreeViewContextValueBuilderParameters, - UseTreeViewContextValueBuilderDefaultizedParameters, +interface UseTreeViewIconsContextValue { + icons: { + defaultCollapseIcon: React.ReactNode; + defaultExpandIcon: React.ReactNode; + defaultParentIcon: React.ReactNode; + defaultEndIcon: React.ReactNode; + }; +} + +export type UseTreeViewIconsSignature = TreeViewPluginSignature< + UseTreeViewIconsParameters, + UseTreeViewIconsDefaultizedParameters, {}, {}, {}, + UseTreeViewIconsContextValue, never, [UseTreeViewNodesSignature, UseTreeViewSelectionSignature] >; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewId/useTreeViewId.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewId/useTreeViewId.types.ts index e88c154e54598..c8e1689847648 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewId/useTreeViewId.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewId/useTreeViewId.types.ts @@ -14,16 +14,13 @@ export interface UseTreeViewIdParameters { export type UseTreeViewIdDefaultizedParameters = UseTreeViewIdParameters; -export interface UseTreeViewIdState { - focusedNodeId: string | null; -} - export type UseTreeViewIdSignature = TreeViewPluginSignature< UseTreeViewIdParameters, UseTreeViewIdDefaultizedParameters, UseTreeViewIdInstance, {}, - UseTreeViewIdState, + {}, + {}, never, [] >; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.ts index 5215094002fe5..98b7807618ff3 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewJSXNodes/useTreeViewJSXNodes.types.ts @@ -18,6 +18,7 @@ export type UseTreeViewJSXNodesSignature = TreeViewPluginSignature< UseTreeViewNodesInstance, {}, {}, + {}, never, [UseTreeViewNodesSignature, UseTreeViewKeyboardNavigationSignature] >; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.ts index fd52915b3f52b..4bd6abe40d1bb 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.ts @@ -14,6 +14,7 @@ export type UseTreeViewKeyboardNavigationSignature = TreeViewPluginSignature< UseTreeViewKeyboardNavigationInstance, {}, {}, + {}, never, [ UseTreeViewNodesSignature, diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.ts index bdc8bab5e1f86..1a2afdee3df29 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.ts @@ -179,6 +179,10 @@ export const useTreeViewNodes: TreeViewPlugin = ({ getNavigableChildrenIds, isNodeDisabled, }); + + return { + contextValue: { disabledItemsFocusable: params.disabledItemsFocusable }, + }; }; useTreeViewNodes.getInitialState = (params) => @@ -188,3 +192,8 @@ useTreeViewNodes.getInitialState = (params) => getItemId: params.getItemId, getItemLabel: params.getItemLabel, }); + +useTreeViewNodes.getDefaultizedParams = (params) => ({ + ...params, + disabledItemsFocusable: params.disabledItemsFocusable ?? false, +}); diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.ts index f5578ebac6446..43792f3b33f56 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewNodes/useTreeViewNodes.types.ts @@ -71,12 +71,16 @@ export interface UseTreeViewNodesState { nodeMap: TreeViewNodeMap; } +interface UseTreeViewNodesContextValue + extends Pick, 'disabledItemsFocusable'> {} + export type UseTreeViewNodesSignature = TreeViewPluginSignature< UseTreeViewNodesParameters, UseTreeViewNodesDefaultizedParameters, UseTreeViewNodesInstance, UseTreeViewNodesEventLookup, UseTreeViewNodesState, + UseTreeViewNodesContextValue, never, [] >; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts index 048b822122984..278a33d608149 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts @@ -201,6 +201,13 @@ export const useTreeViewSelection: TreeViewPlugin getRootProps: () => ({ 'aria-multiselectable': params.multiSelect, }), + contextValue: { + selection: { + multiSelect: params.multiSelect, + checkboxSelection: params.checkboxSelection, + disableSelection: params.disableSelection, + }, + }, }; }; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts index a25804fb8b8f2..c3d6f4d996b44 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts @@ -70,12 +70,20 @@ export type UseTreeViewSelectionDefaultizedParameters 'disableSelection' | 'defaultSelectedNodes' | 'multiSelect' | 'checkboxSelection' >; +interface UseTreeViewSelectionContextValue { + selection: Pick< + UseTreeViewSelectionDefaultizedParameters, + 'multiSelect' | 'checkboxSelection' | 'disableSelection' + >; +} + export type UseTreeViewSelectionSignature = TreeViewPluginSignature< UseTreeViewSelectionParameters, UseTreeViewSelectionDefaultizedParameters, UseTreeViewSelectionInstance, {}, {}, + UseTreeViewSelectionContextValue, 'selectedNodes', [UseTreeViewNodesSignature, UseTreeViewExpansionSignature, UseTreeViewNodesSignature] >; diff --git a/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts b/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts index cf181b64919f4..2cfd721942411 100644 --- a/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts +++ b/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts @@ -60,9 +60,9 @@ export const useTreeView = ( otherHandlers: TOther, ) => React.HTMLAttributes)[] = []; - let contextValue = {} as TreeViewContextValue; + const contextValue = {} as TreeViewContextValue; - const runPlugin = (plugin: TreeViewPlugin) => { + const runPlugin = (plugin: TreeViewPlugin) => { const pluginResponse = plugin({ instance, params, state, setState, rootRef: innerRootRef, models }) || {}; @@ -71,12 +71,17 @@ export const useTreeView = , + runItemPlugins: ({ props, ref }) => ({ props, ref, wrapItem: (children) => children }), + }); + contextValue.runItemPlugins = ({ props, ref }) => { let finalProps = props; let finalRef = ref; @@ -130,5 +135,10 @@ export const useTreeView = Date: Thu, 4 Jan 2024 11:33:13 +0100 Subject: [PATCH 06/26] Work --- docs/pages/x/api/tree-view/tree-item.json | 1 + docs/translations/api-docs/tree-view/tree-item.json | 7 ++++++- packages/x-tree-view/src/TreeItem/TreeItem.test.tsx | 10 +++++++--- packages/x-tree-view/src/internals/models/helpers.ts | 4 ++++ packages/x-tree-view/src/internals/models/plugin.ts | 2 +- .../src/internals/useTreeView/useTreeView.ts | 10 ++++------ 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/pages/x/api/tree-view/tree-item.json b/docs/pages/x/api/tree-view/tree-item.json index 6a3781c83e520..1b781be922be9 100644 --- a/docs/pages/x/api/tree-view/tree-item.json +++ b/docs/pages/x/api/tree-view/tree-item.json @@ -39,6 +39,7 @@ "content", "expanded", "selected", + "interactive", "focused", "disabled", "iconContainer", diff --git a/docs/translations/api-docs/tree-view/tree-item.json b/docs/translations/api-docs/tree-view/tree-item.json index e6de60468e6c4..6539a9c00e76b 100644 --- a/docs/translations/api-docs/tree-view/tree-item.json +++ b/docs/translations/api-docs/tree-view/tree-item.json @@ -93,7 +93,12 @@ "selected": { "description": "State class applied to {{nodeName}} when {{conditions}}.", "nodeName": "the content element", - "conditions": "selected" + "conditions": "selected and not using the checkbox selection" + }, + "interactive": { + "description": "State class applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the content element", + "conditions": "clicking it causes an action" }, "focused": { "description": "State class applied to {{nodeName}} when {{conditions}}.", diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx index 50e72b93a9241..0207a5a1e39f9 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx @@ -14,8 +14,9 @@ import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; import { TreeItem, treeItemClasses as classes } from '@mui/x-tree-view/TreeItem'; import { TreeViewContextValue } from '@mui/x-tree-view/internals/TreeViewProvider'; import { TreeViewContext } from '@mui/x-tree-view/internals/TreeViewProvider/TreeViewContext'; +import { DefaultTreeViewPlugins } from '@mui/x-tree-view/internals/plugins'; -const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue = { +const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue = { instance: { isNodeExpandable: () => false, isNodeExpanded: () => false, @@ -26,8 +27,6 @@ const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue = { mapFirstCharFromJSX: () => {}, } as any, runItemPlugins: ({ props, ref }) => ({ props, ref, wrapItem: (children) => children }), - multiSelect: false, - checkboxSelection: false, disabledItemsFocusable: false, icons: { defaultCollapseIcon: null, @@ -35,6 +34,11 @@ const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue = { defaultParentIcon: null, defaultEndIcon: null, }, + selection: { + multiSelect: false, + checkboxSelection: false, + disableSelection: false, + }, }; describe('', () => { diff --git a/packages/x-tree-view/src/internals/models/helpers.ts b/packages/x-tree-view/src/internals/models/helpers.ts index 115a91d9d21d5..652e08c6bba03 100644 --- a/packages/x-tree-view/src/internals/models/helpers.ts +++ b/packages/x-tree-view/src/internals/models/helpers.ts @@ -8,7 +8,11 @@ export type DefaultizedProps< Required> & AdditionalProps; +type IsAny = 0 extends 1 & T ? true : false; + export type OptionalIfEmpty = keyof B extends never + ? Partial> + : IsAny extends true ? Partial> : Record; diff --git a/packages/x-tree-view/src/internals/models/plugin.ts b/packages/x-tree-view/src/internals/models/plugin.ts index ae794f7455e2b..fef3c7c464acf 100644 --- a/packages/x-tree-view/src/internals/models/plugin.ts +++ b/packages/x-tree-view/src/internals/models/plugin.ts @@ -59,7 +59,7 @@ export type TreeViewAnyPluginSignature = { defaultizedParams: any; dependantPlugins: any; events: any; - contextValue: {}; + contextValue: any; models: any; }; diff --git a/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts b/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts index 2cfd721942411..2df1e3b1ddedb 100644 --- a/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts +++ b/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts @@ -60,7 +60,10 @@ export const useTreeView = ( otherHandlers: TOther, ) => React.HTMLAttributes)[] = []; - const contextValue = {} as TreeViewContextValue; + const contextValue = { + instance: instance as TreeViewInstance, + runItemPlugins: ({ props, ref }) => ({ props, ref, wrapItem: (children) => children }), + } as TreeViewContextValue; const runPlugin = (plugin: TreeViewPlugin) => { const pluginResponse = @@ -77,11 +80,6 @@ export const useTreeView = , - runItemPlugins: ({ props, ref }) => ({ props, ref, wrapItem: (children) => children }), - }); - contextValue.runItemPlugins = ({ props, ref }) => { let finalProps = props; let finalRef = ref; From e046107c9c62bd00f8d92bc8bfcb233b77c0224c Mon Sep 17 00:00:00 2001 From: delangle Date: Mon, 8 Jan 2024 15:43:02 +0100 Subject: [PATCH 07/26] Fix --- .../plugins/useTreeViewSelection/useTreeViewSelection.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts index 4f7c2154dbbb5..251b097ba853e 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts @@ -229,6 +229,7 @@ useTreeViewSelection.getDefaultizedParams = (params) => ({ useTreeViewSelection.params = { disableSelection: true, multiSelect: true, + checkboxSelection: true, defaultSelectedNodes: true, selectedNodes: true, onSelectedNodesChange: true, From b871e6676df6b9b2ba53cc3015d67fb830550aad Mon Sep 17 00:00:00 2001 From: delangle Date: Mon, 8 Jan 2024 17:46:57 +0100 Subject: [PATCH 08/26] Fix --- docs/data/tree-view/headless/HeadlessTreeView.tsx | 2 ++ packages/x-tree-view/src/RichTreeView/RichTreeView.tsx | 7 ++++++- packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx | 7 ++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/data/tree-view/headless/HeadlessTreeView.tsx b/docs/data/tree-view/headless/HeadlessTreeView.tsx index 01578d0076740..2770be0203321 100644 --- a/docs/data/tree-view/headless/HeadlessTreeView.tsx +++ b/docs/data/tree-view/headless/HeadlessTreeView.tsx @@ -52,6 +52,8 @@ type TreeViewLogExpandedSignature = TreeViewPluginSignature< {}, // State defined by this plugin: we don't have any {}, + // Context defined by this plugin: we don't have any + {}, // Models defined by plugin: we don't have any never, // Dependencies of this plugin (we need the expansion plugin to access its model) diff --git a/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx b/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx index 679b5228739cf..711356abc2252 100644 --- a/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx +++ b/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx @@ -144,6 +144,11 @@ RichTreeView.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * If `true`, the tree view renders a checkbox at the left of its label that allows selecting it. + * @default false + */ + checkboxSelection: PropTypes.bool, /** * Override or extend the styles applied to the component. */ @@ -229,7 +234,7 @@ RichTreeView.propTypes = { isItemDisabled: PropTypes.func, items: PropTypes.array.isRequired, /** - * If true `ctrl` and `shift` will trigger multiselect. + * If `true`, `ctrl` and `shift` will trigger multiselect. * @default false */ multiSelect: PropTypes.bool, diff --git a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx index ee73933480447..ac57e2988b7f0 100644 --- a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx +++ b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx @@ -103,6 +103,11 @@ SimpleTreeView.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * If `true`, the tree view renders a checkbox at the left of its label that allows selecting it. + * @default false + */ + checkboxSelection: PropTypes.bool, /** * The content of the component. */ @@ -184,7 +189,7 @@ SimpleTreeView.propTypes = { */ id: PropTypes.string, /** - * If true `ctrl` and `shift` will trigger multiselect. + * If `true`, `ctrl` and `shift` will trigger multiselect. * @default false */ multiSelect: PropTypes.bool, From 95d59aac826e693b5ef58f00c8a5208bcd449f34 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 10 Jan 2024 19:52:58 +0100 Subject: [PATCH 09/26] Merge --- .../x/api/date-pickers/date-range-picker.json | 48 +++++++++---------- .../desktop-date-range-picker.json | 48 +++++++++---------- .../mobile-date-range-picker.json | 24 +++++----- .../date-range-picker/date-range-picker.json | 8 ++-- .../desktop-date-range-picker.json | 8 ++-- .../mobile-date-range-picker.json | 4 +- 6 files changed, 70 insertions(+), 70 deletions(-) diff --git a/docs/pages/x/api/date-pickers/date-range-picker.json b/docs/pages/x/api/date-pickers/date-range-picker.json index e081cc2fea228..3fe7d9a103c79 100644 --- a/docs/pages/x/api/date-pickers/date-range-picker.json +++ b/docs/pages/x/api/date-pickers/date-range-picker.json @@ -209,6 +209,30 @@ "default": "ArrowDropDown", "class": null }, + { + "name": "desktopPaper", + "description": "Custom component for the paper rendered inside the desktop picker's Popper.", + "default": "PickersPopperPaper", + "class": null + }, + { + "name": "desktopTransition", + "description": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", + "default": "Grow or Fade from '@mui/material' when `reduceAnimations` is `true`.", + "class": null + }, + { + "name": "desktopTrapFocus", + "description": "Custom component for trapping the focus inside the views on desktop.", + "default": "FocusTrap from '@mui/base'.", + "class": null + }, + { + "name": "popper", + "description": "Custom component for the popper inside which the views are rendered on desktop.", + "default": "Popper from '@mui/material'.", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", @@ -254,30 +278,6 @@ "default": "IconButton", "class": null }, - { - "name": "desktopPaper", - "description": "Custom component for the paper rendered inside the desktop picker's Popper.", - "default": "PickersPopperPaper", - "class": null - }, - { - "name": "desktopTransition", - "description": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", - "default": "Grow or Fade from '@mui/material' when `reduceAnimations` is `true`.", - "class": null - }, - { - "name": "desktopTrapFocus", - "description": "Custom component for trapping the focus inside the views on desktop.", - "default": "FocusTrap from '@mui/base'.", - "class": null - }, - { - "name": "popper", - "description": "Custom component for the popper inside which the views are rendered on desktop.", - "default": "Popper from '@mui/material'.", - "class": null - }, { "name": "field", "description": "", "class": null }, { "name": "dialog", diff --git a/docs/pages/x/api/date-pickers/desktop-date-range-picker.json b/docs/pages/x/api/date-pickers/desktop-date-range-picker.json index 2000ea340b62a..bdb27c8d0cf7e 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-range-picker.json @@ -205,6 +205,30 @@ "default": "ArrowDropDown", "class": null }, + { + "name": "desktopPaper", + "description": "Custom component for the paper rendered inside the desktop picker's Popper.", + "default": "PickersPopperPaper", + "class": null + }, + { + "name": "desktopTransition", + "description": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", + "default": "Grow or Fade from '@mui/material' when `reduceAnimations` is `true`.", + "class": null + }, + { + "name": "desktopTrapFocus", + "description": "Custom component for trapping the focus inside the views on desktop.", + "default": "FocusTrap from '@mui/base'.", + "class": null + }, + { + "name": "popper", + "description": "Custom component for the popper inside which the views are rendered on desktop.", + "default": "Popper from '@mui/material'.", + "class": null + }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", @@ -250,30 +274,6 @@ "default": "IconButton", "class": null }, - { - "name": "desktopPaper", - "description": "Custom component for the paper rendered inside the desktop picker's Popper.", - "default": "PickersPopperPaper", - "class": null - }, - { - "name": "desktopTransition", - "description": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", - "default": "Grow or Fade from '@mui/material' when `reduceAnimations` is `true`.", - "class": null - }, - { - "name": "desktopTrapFocus", - "description": "Custom component for trapping the focus inside the views on desktop.", - "default": "FocusTrap from '@mui/base'.", - "class": null - }, - { - "name": "popper", - "description": "Custom component for the popper inside which the views are rendered on desktop.", - "default": "Popper from '@mui/material'.", - "class": null - }, { "name": "field", "description": "", "class": null } ], "classes": [], diff --git a/docs/pages/x/api/date-pickers/mobile-date-range-picker.json b/docs/pages/x/api/date-pickers/mobile-date-range-picker.json index b35595da00631..3f5c1bf31af49 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-range-picker.json @@ -211,18 +211,6 @@ "default": "PickersModalDialogRoot", "class": null }, - { - "name": "mobilePaper", - "description": "Custom component for the paper rendered inside the mobile picker's Dialog.", - "default": "Paper from '@mui/material'.", - "class": null - }, - { - "name": "mobileTransition", - "description": "Custom component for the mobile dialog [Transition](https://mui.com/material-ui/transitions/).", - "default": "Fade from '@mui/material'.", - "class": null - }, { "name": "actionBar", "description": "Custom component for the action bar, it is placed below the picker views.", @@ -268,6 +256,18 @@ "default": "IconButton", "class": null }, + { + "name": "mobilePaper", + "description": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "default": "Paper from '@mui/material'.", + "class": null + }, + { + "name": "mobileTransition", + "description": "Custom component for the mobile dialog [Transition](https://mui.com/material-ui/transitions/).", + "default": "Fade from '@mui/material'.", + "class": null + }, { "name": "field", "description": "", "class": null } ], "classes": [], diff --git a/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json b/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json index 8cf2e1c28f5a6..8d37c419b2006 100644 --- a/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json @@ -161,6 +161,10 @@ "rightArrowIcon": "Icon displayed in the right view switch button.", "switchViewButton": "Button displayed to switch between different calendar views.", "switchViewIcon": "Icon displayed in the SwitchViewButton. Rotated by 180° when the open view is 'year'.", + "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", + "desktopTransition": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", + "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", + "popper": "Custom component for the popper inside which the views are rendered on desktop.", "actionBar": "Custom component for the action bar, it is placed below the picker views.", "shortcuts": "Custom component for the shortcuts.", "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", @@ -169,10 +173,6 @@ "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as `@mui/material/TextField`.", "clearIcon": "Icon to display inside the clear button.", "clearButton": "Button to clear the value.", - "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", - "desktopTransition": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", - "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", - "popper": "Custom component for the popper inside which the views are rendered on desktop.", "field": "", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json index 484526e8e6330..3650742662c7a 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json @@ -158,6 +158,10 @@ "rightArrowIcon": "Icon displayed in the right view switch button.", "switchViewButton": "Button displayed to switch between different calendar views.", "switchViewIcon": "Icon displayed in the SwitchViewButton. Rotated by 180° when the open view is 'year'.", + "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", + "desktopTransition": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", + "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", + "popper": "Custom component for the popper inside which the views are rendered on desktop.", "actionBar": "Custom component for the action bar, it is placed below the picker views.", "shortcuts": "Custom component for the shortcuts.", "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", @@ -166,10 +170,6 @@ "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as `@mui/material/TextField`.", "clearIcon": "Icon to display inside the clear button.", "clearButton": "Button to clear the value.", - "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", - "desktopTransition": "Custom component for the desktop popper [Transition](https://mui.com/material-ui/transitions/).", - "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", - "popper": "Custom component for the popper inside which the views are rendered on desktop.", "field": "" } } diff --git a/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json index 07d3c945c0385..ba6edf6783368 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json @@ -159,8 +159,6 @@ "switchViewButton": "Button displayed to switch between different calendar views.", "switchViewIcon": "Icon displayed in the SwitchViewButton. Rotated by 180° when the open view is 'year'.", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", - "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", - "mobileTransition": "Custom component for the mobile dialog [Transition](https://mui.com/material-ui/transitions/).", "actionBar": "Custom component for the action bar, it is placed below the picker views.", "shortcuts": "Custom component for the shortcuts.", "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", @@ -169,6 +167,8 @@ "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as `@mui/material/TextField`.", "clearIcon": "Icon to display inside the clear button.", "clearButton": "Button to clear the value.", + "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "mobileTransition": "Custom component for the mobile dialog [Transition](https://mui.com/material-ui/transitions/).", "field": "" } } From 9d6634d0c94d207ddd724b87d9991d0cbdf425d4 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 11 Jan 2024 11:20:45 +0100 Subject: [PATCH 10/26] Fix --- .../data-grid-premium/data-grid-premium.json | 92 ++++++++++--------- .../data-grid-pro/data-grid-pro.json | 90 +++++++++--------- .../data-grid/data-grid/data-grid.json | 78 ++++++++-------- .../grid-filter-form/grid-filter-form.json | 12 ++- 4 files changed, 142 insertions(+), 130 deletions(-) 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 ed0122d9c29fc..1d8f78d2507f5 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 @@ -42,12 +42,14 @@ "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, - "columns": { "description": "Set of columns of type [[GridColDef]][]." }, + "columns": { + "description": "Set of columns of type GridColDef[]." + }, "columnThreshold": { "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { - "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in [[GridColDef]]." + "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." }, "defaultGroupingExpansionDepth": { "description": "If above 0, the row children will be expanded up to this depth. If equal to -1, all the row children will be expanded." @@ -122,50 +124,50 @@ "getCellClassName": { "description": "Function that applies CSS classes dynamically on cells.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "string": "The CSS class to apply to the cell." } }, "getDetailPanelContent": { "description": "Function that returns the element to render in row detail.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "React.JSX.Element": "The row detail element." } }, "getDetailPanelHeight": { "description": "Function that returns the height of the row detail panel.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "number | string": "The height in pixels or "auto" to use the content height." } }, "getEstimatedRowHeight": { "description": "Function that returns the estimated height for a row. Only works if dynamic row height is used. Once the row height is measured this value is discarded.", "typeDescriptions": { - "params": "With all properties from [[GridRowHeightParams]].", + "params": "With all properties from GridRowHeightParams.", "number | null": "The estimated row height value. If null or undefined then the default row height, based on the density, is applied." } }, "getRowClassName": { "description": "Function that applies CSS classes dynamically on rows.", "typeDescriptions": { - "params": "With all properties from [[GridRowClassNameParams]].", + "params": "With all properties from GridRowClassNameParams.", "string": "The CSS class to apply to the row." } }, "getRowHeight": { "description": "Function that sets the row height per row.", "typeDescriptions": { - "params": "With all properties from [[GridRowHeightParams]].", + "params": "With all properties from GridRowHeightParams.", "GridRowHeightReturnValue": "The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content." } }, - "getRowId": { "description": "Return the id of a given [[GridRowModel]]." }, + "getRowId": { "description": "Return the id of a given GridRowModel." }, "getRowSpacing": { "description": "Function that allows to specify the spacing between rows.", "typeDescriptions": { - "params": "With all properties from [[GridRowSpacingParams]].", + "params": "With all properties from GridRowSpacingParams.", "GridRowSpacing": "The row spacing values." } }, @@ -202,7 +204,7 @@ "isCellEditable": { "description": "Callback fired when a cell is rendered, returns true if the cell is editable.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "boolean": "A boolean indicating if the cell is editable." } }, @@ -216,7 +218,7 @@ "isRowSelectable": { "description": "Determines if a row can be selected.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "boolean": "A boolean indicating if the cell is selectable." } }, @@ -231,7 +233,7 @@ "description": "Set the locale text of the Data Grid. You can find all the translation keys supported in the source in the GitHub repository." }, "logger": { - "description": "Pass a custom logger in the components that implements the [[Logger]] interface." + "description": "Pass a custom logger in the components that implements the Logger interface." }, "logLevel": { "description": "Allows to pass the logging level or false to turn off logging." }, "nonce": { @@ -247,7 +249,7 @@ "onCellClick": { "description": "Callback fired when any cell is clicked.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -255,7 +257,7 @@ "onCellDoubleClick": { "description": "Callback fired when a double click event comes from a cell element.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -263,21 +265,21 @@ "onCellEditStart": { "description": "Callback fired when the cell turns to edit mode.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event that caused this prop to be called." } }, "onCellEditStop": { "description": "Callback fired when the cell turns to view mode.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event that caused this prop to be called." } }, "onCellKeyDown": { "description": "Callback fired when a keydown event comes from a cell element.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -292,7 +294,7 @@ "onCellSelectionModelChange": { "description": "Callback fired when the selection state of one or multiple cells changes.", "typeDescriptions": { - "cellSelectionModel": "Object in the shape of [[GridCellSelectionModel]] containing the selected cells.", + "cellSelectionModel": "Object in the shape of GridCellSelectionModel containing the selected cells.", "details": "Additional details for this callback." } }, @@ -309,7 +311,7 @@ "onColumnHeaderClick": { "description": "Callback fired when a click event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -317,7 +319,7 @@ "onColumnHeaderDoubleClick": { "description": "Callback fired when a double click event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -325,7 +327,7 @@ "onColumnHeaderEnter": { "description": "Callback fired when a mouse enter event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -333,7 +335,7 @@ "onColumnHeaderLeave": { "description": "Callback fired when a mouse leave event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -341,7 +343,7 @@ "onColumnHeaderOut": { "description": "Callback fired when a mouseout event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -349,7 +351,7 @@ "onColumnHeaderOver": { "description": "Callback fired when a mouseover event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -357,7 +359,7 @@ "onColumnOrderChange": { "description": "Callback fired when a column is reordered.", "typeDescriptions": { - "params": "With all properties from [[GridColumnOrderChangeParams]].", + "params": "With all properties from GridColumnOrderChangeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -365,7 +367,7 @@ "onColumnResize": { "description": "Callback fired while a column is being resized.", "typeDescriptions": { - "params": "With all properties from [[GridColumnResizeParams]].", + "params": "With all properties from GridColumnResizeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -380,7 +382,7 @@ "onColumnWidthChange": { "description": "Callback fired when the width of a column is changed.", "typeDescriptions": { - "params": "With all properties from [[GridColumnResizeParams]].", + "params": "With all properties from GridColumnResizeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -399,7 +401,7 @@ "onFetchRows": { "description": "Callback fired when rowCount is set and the next batch of virtualized rows is rendered.", "typeDescriptions": { - "params": "With all properties from [[GridFetchRowsParams]].", + "params": "With all properties from GridFetchRowsParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -407,14 +409,14 @@ "onFilterModelChange": { "description": "Callback fired when the Filter model changes before the filters are applied.", "typeDescriptions": { - "model": "With all properties from [[GridFilterModel]].", + "model": "With all properties from GridFilterModel.", "details": "Additional details for this callback." } }, "onMenuClose": { "description": "Callback fired when the menu is closed.", "typeDescriptions": { - "params": "With all properties from [[GridMenuParams]].", + "params": "With all properties from GridMenuParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -422,7 +424,7 @@ "onMenuOpen": { "description": "Callback fired when the menu is opened.", "typeDescriptions": { - "params": "With all properties from [[GridMenuParams]].", + "params": "With all properties from GridMenuParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -444,7 +446,7 @@ "onPreferencePanelClose": { "description": "Callback fired when the preferences panel is closed.", "typeDescriptions": { - "params": "With all properties from [[GridPreferencePanelParams]].", + "params": "With all properties from GridPreferencePanelParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -452,7 +454,7 @@ "onPreferencePanelOpen": { "description": "Callback fired when the preferences panel is opened.", "typeDescriptions": { - "params": "With all properties from [[GridPreferencePanelParams]].", + "params": "With all properties from GridPreferencePanelParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -464,7 +466,7 @@ "onResize": { "description": "Callback fired when the Data Grid is resized.", "typeDescriptions": { - "containerSize": "With all properties from [[ElementSize]].", + "containerSize": "With all properties from ElementSize.", "event": "The event object.", "details": "Additional details for this callback." } @@ -472,7 +474,7 @@ "onRowClick": { "description": "Callback fired when a row is clicked. Not called if the target clicked is an interactive element added by the built-in columns.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -480,7 +482,7 @@ "onRowDoubleClick": { "description": "Callback fired when a double click event comes from a row container element.", "typeDescriptions": { - "params": "With all properties from [[RowParams]].", + "params": "With all properties from RowParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -495,14 +497,14 @@ "onRowEditStart": { "description": "Callback fired when the row turns to edit mode.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event that caused this prop to be called." } }, "onRowEditStop": { "description": "Callback fired when the row turns to view mode.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event that caused this prop to be called." } }, @@ -523,7 +525,7 @@ "onRowOrderChange": { "description": "Callback fired when a row is being reordered.", "typeDescriptions": { - "params": "With all properties from [[GridRowOrderChangeParams]].", + "params": "With all properties from GridRowOrderChangeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -531,14 +533,14 @@ "onRowSelectionModelChange": { "description": "Callback fired when the selection state of one or multiple rows changes.", "typeDescriptions": { - "rowSelectionModel": "With all the row ids [[GridSelectionModel]].", + "rowSelectionModel": "With all the row ids GridSelectionModel.", "details": "Additional details for this callback." } }, "onRowsScrollEnd": { "description": "Callback fired when scrolling to the bottom of the grid viewport.", "typeDescriptions": { - "params": "With all properties from [[GridRowScrollEndParams]].", + "params": "With all properties from GridRowScrollEndParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -546,7 +548,7 @@ "onSortModelChange": { "description": "Callback fired when the sort model changes before a column is sorted.", "typeDescriptions": { - "model": "With all properties from [[GridSortModel]].", + "model": "With all properties from GridSortModel.", "details": "Additional details for this callback." } }, @@ -556,7 +558,7 @@ "description": "Pagination can be processed on the server or client-side. Set it to 'client' if you would like to handle the pagination on the client-side. Set it to 'server' if you would like to handle the pagination on the server-side." }, "paginationModel": { - "description": "The pagination model of type [[GridPaginationModel]] which refers to current page and pageSize." + "description": "The pagination model of type GridPaginationModel which refers to current page and pageSize." }, "pinnedColumns": { "description": "The column fields to display pinned to left or right." }, "pinnedRows": { "description": "Rows data to pin on top or bottom." }, @@ -584,7 +586,7 @@ "description": "The milliseconds delay to wait after measuring the row height before recalculating row positions. Setting it to a lower value could be useful when using dynamic row height, but might reduce performance when displaying a large number of rows." }, "rowReordering": { "description": "If true, the reordering of rows is enabled." }, - "rows": { "description": "Set of rows of type [[GridRowsProp]]." }, + "rows": { "description": "Set of rows of type GridRowsProp." }, "rowSelection": { "description": "If false, the row selection mode is disabled." }, "rowSelectionModel": { "description": "Sets the row selection model of the Data Grid." }, "rowsLoadingMode": { 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 ca8207876ade8..e87189c79ffc9 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 @@ -35,12 +35,14 @@ "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, - "columns": { "description": "Set of columns of type [[GridColDef]][]." }, + "columns": { + "description": "Set of columns of type GridColDef[]." + }, "columnThreshold": { "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { - "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in [[GridColDef]]." + "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." }, "defaultGroupingExpansionDepth": { "description": "If above 0, the row children will be expanded up to this depth. If equal to -1, all the row children will be expanded." @@ -103,50 +105,50 @@ "getCellClassName": { "description": "Function that applies CSS classes dynamically on cells.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "string": "The CSS class to apply to the cell." } }, "getDetailPanelContent": { "description": "Function that returns the element to render in row detail.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "React.JSX.Element": "The row detail element." } }, "getDetailPanelHeight": { "description": "Function that returns the height of the row detail panel.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "number | string": "The height in pixels or "auto" to use the content height." } }, "getEstimatedRowHeight": { "description": "Function that returns the estimated height for a row. Only works if dynamic row height is used. Once the row height is measured this value is discarded.", "typeDescriptions": { - "params": "With all properties from [[GridRowHeightParams]].", + "params": "With all properties from GridRowHeightParams.", "number | null": "The estimated row height value. If null or undefined then the default row height, based on the density, is applied." } }, "getRowClassName": { "description": "Function that applies CSS classes dynamically on rows.", "typeDescriptions": { - "params": "With all properties from [[GridRowClassNameParams]].", + "params": "With all properties from GridRowClassNameParams.", "string": "The CSS class to apply to the row." } }, "getRowHeight": { "description": "Function that sets the row height per row.", "typeDescriptions": { - "params": "With all properties from [[GridRowHeightParams]].", + "params": "With all properties from GridRowHeightParams.", "GridRowHeightReturnValue": "The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content." } }, - "getRowId": { "description": "Return the id of a given [[GridRowModel]]." }, + "getRowId": { "description": "Return the id of a given GridRowModel." }, "getRowSpacing": { "description": "Function that allows to specify the spacing between rows.", "typeDescriptions": { - "params": "With all properties from [[GridRowSpacingParams]].", + "params": "With all properties from GridRowSpacingParams.", "GridRowSpacing": "The row spacing values." } }, @@ -183,7 +185,7 @@ "isCellEditable": { "description": "Callback fired when a cell is rendered, returns true if the cell is editable.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "boolean": "A boolean indicating if the cell is editable." } }, @@ -197,7 +199,7 @@ "isRowSelectable": { "description": "Determines if a row can be selected.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "boolean": "A boolean indicating if the cell is selectable." } }, @@ -212,7 +214,7 @@ "description": "Set the locale text of the Data Grid. You can find all the translation keys supported in the source in the GitHub repository." }, "logger": { - "description": "Pass a custom logger in the components that implements the [[Logger]] interface." + "description": "Pass a custom logger in the components that implements the Logger interface." }, "logLevel": { "description": "Allows to pass the logging level or false to turn off logging." }, "nonce": { @@ -221,7 +223,7 @@ "onCellClick": { "description": "Callback fired when any cell is clicked.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -229,7 +231,7 @@ "onCellDoubleClick": { "description": "Callback fired when a double click event comes from a cell element.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -237,21 +239,21 @@ "onCellEditStart": { "description": "Callback fired when the cell turns to edit mode.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event that caused this prop to be called." } }, "onCellEditStop": { "description": "Callback fired when the cell turns to view mode.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event that caused this prop to be called." } }, "onCellKeyDown": { "description": "Callback fired when a keydown event comes from a cell element.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -270,7 +272,7 @@ "onColumnHeaderClick": { "description": "Callback fired when a click event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -278,7 +280,7 @@ "onColumnHeaderDoubleClick": { "description": "Callback fired when a double click event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -286,7 +288,7 @@ "onColumnHeaderEnter": { "description": "Callback fired when a mouse enter event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -294,7 +296,7 @@ "onColumnHeaderLeave": { "description": "Callback fired when a mouse leave event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -302,7 +304,7 @@ "onColumnHeaderOut": { "description": "Callback fired when a mouseout event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -310,7 +312,7 @@ "onColumnHeaderOver": { "description": "Callback fired when a mouseover event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -318,7 +320,7 @@ "onColumnOrderChange": { "description": "Callback fired when a column is reordered.", "typeDescriptions": { - "params": "With all properties from [[GridColumnOrderChangeParams]].", + "params": "With all properties from GridColumnOrderChangeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -326,7 +328,7 @@ "onColumnResize": { "description": "Callback fired while a column is being resized.", "typeDescriptions": { - "params": "With all properties from [[GridColumnResizeParams]].", + "params": "With all properties from GridColumnResizeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -341,7 +343,7 @@ "onColumnWidthChange": { "description": "Callback fired when the width of a column is changed.", "typeDescriptions": { - "params": "With all properties from [[GridColumnResizeParams]].", + "params": "With all properties from GridColumnResizeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -356,7 +358,7 @@ "onFetchRows": { "description": "Callback fired when rowCount is set and the next batch of virtualized rows is rendered.", "typeDescriptions": { - "params": "With all properties from [[GridFetchRowsParams]].", + "params": "With all properties from GridFetchRowsParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -364,14 +366,14 @@ "onFilterModelChange": { "description": "Callback fired when the Filter model changes before the filters are applied.", "typeDescriptions": { - "model": "With all properties from [[GridFilterModel]].", + "model": "With all properties from GridFilterModel.", "details": "Additional details for this callback." } }, "onMenuClose": { "description": "Callback fired when the menu is closed.", "typeDescriptions": { - "params": "With all properties from [[GridMenuParams]].", + "params": "With all properties from GridMenuParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -379,7 +381,7 @@ "onMenuOpen": { "description": "Callback fired when the menu is opened.", "typeDescriptions": { - "params": "With all properties from [[GridMenuParams]].", + "params": "With all properties from GridMenuParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -401,7 +403,7 @@ "onPreferencePanelClose": { "description": "Callback fired when the preferences panel is closed.", "typeDescriptions": { - "params": "With all properties from [[GridPreferencePanelParams]].", + "params": "With all properties from GridPreferencePanelParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -409,7 +411,7 @@ "onPreferencePanelOpen": { "description": "Callback fired when the preferences panel is opened.", "typeDescriptions": { - "params": "With all properties from [[GridPreferencePanelParams]].", + "params": "With all properties from GridPreferencePanelParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -421,7 +423,7 @@ "onResize": { "description": "Callback fired when the Data Grid is resized.", "typeDescriptions": { - "containerSize": "With all properties from [[ElementSize]].", + "containerSize": "With all properties from ElementSize.", "event": "The event object.", "details": "Additional details for this callback." } @@ -429,7 +431,7 @@ "onRowClick": { "description": "Callback fired when a row is clicked. Not called if the target clicked is an interactive element added by the built-in columns.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -437,7 +439,7 @@ "onRowDoubleClick": { "description": "Callback fired when a double click event comes from a row container element.", "typeDescriptions": { - "params": "With all properties from [[RowParams]].", + "params": "With all properties from RowParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -452,14 +454,14 @@ "onRowEditStart": { "description": "Callback fired when the row turns to edit mode.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event that caused this prop to be called." } }, "onRowEditStop": { "description": "Callback fired when the row turns to view mode.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event that caused this prop to be called." } }, @@ -473,7 +475,7 @@ "onRowOrderChange": { "description": "Callback fired when a row is being reordered.", "typeDescriptions": { - "params": "With all properties from [[GridRowOrderChangeParams]].", + "params": "With all properties from GridRowOrderChangeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -481,14 +483,14 @@ "onRowSelectionModelChange": { "description": "Callback fired when the selection state of one or multiple rows changes.", "typeDescriptions": { - "rowSelectionModel": "With all the row ids [[GridSelectionModel]].", + "rowSelectionModel": "With all the row ids GridSelectionModel.", "details": "Additional details for this callback." } }, "onRowsScrollEnd": { "description": "Callback fired when scrolling to the bottom of the grid viewport.", "typeDescriptions": { - "params": "With all properties from [[GridRowScrollEndParams]].", + "params": "With all properties from GridRowScrollEndParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -496,7 +498,7 @@ "onSortModelChange": { "description": "Callback fired when the sort model changes before a column is sorted.", "typeDescriptions": { - "model": "With all properties from [[GridSortModel]].", + "model": "With all properties from GridSortModel.", "details": "Additional details for this callback." } }, @@ -506,7 +508,7 @@ "description": "Pagination can be processed on the server or client-side. Set it to 'client' if you would like to handle the pagination on the client-side. Set it to 'server' if you would like to handle the pagination on the server-side." }, "paginationModel": { - "description": "The pagination model of type [[GridPaginationModel]] which refers to current page and pageSize." + "description": "The pagination model of type GridPaginationModel which refers to current page and pageSize." }, "pinnedColumns": { "description": "The column fields to display pinned to left or right." }, "pinnedRows": { "description": "Rows data to pin on top or bottom." }, @@ -530,7 +532,7 @@ "description": "The milliseconds delay to wait after measuring the row height before recalculating row positions. Setting it to a lower value could be useful when using dynamic row height, but might reduce performance when displaying a large number of rows." }, "rowReordering": { "description": "If true, the reordering of rows is enabled." }, - "rows": { "description": "Set of rows of type [[GridRowsProp]]." }, + "rows": { "description": "Set of rows of type GridRowsProp." }, "rowSelection": { "description": "If false, the row selection mode is disabled." }, "rowSelectionModel": { "description": "Sets the row selection model of the Data Grid." }, "rowsLoadingMode": { diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index 7886b50d1d3fc..2c81acf1cd97a 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -28,12 +28,14 @@ "columnHeaderHeight": { "description": "Sets the height in pixel of the column headers in the Data Grid." }, - "columns": { "description": "Set of columns of type [[GridColDef]][]." }, + "columns": { + "description": "Set of columns of type GridColDef[]." + }, "columnThreshold": { "description": "Number of rows from the columnBuffer that can be visible before a new slice is rendered." }, "columnVisibilityModel": { - "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in [[GridColDef]]." + "description": "Set the column visibility model of the Data Grid. If defined, the Data Grid will ignore the hide property in GridColDef." }, "density": { "description": "Set the density of the Data Grid." }, "disableColumnFilter": { "description": "If true, column filters are disabled." }, @@ -70,43 +72,43 @@ "getCellClassName": { "description": "Function that applies CSS classes dynamically on cells.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "string": "The CSS class to apply to the cell." } }, "getDetailPanelContent": { "description": "Function that returns the element to render in row detail.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "React.JSX.Element": "The row detail element." } }, "getEstimatedRowHeight": { "description": "Function that returns the estimated height for a row. Only works if dynamic row height is used. Once the row height is measured this value is discarded.", "typeDescriptions": { - "params": "With all properties from [[GridRowHeightParams]].", + "params": "With all properties from GridRowHeightParams.", "number | null": "The estimated row height value. If null or undefined then the default row height, based on the density, is applied." } }, "getRowClassName": { "description": "Function that applies CSS classes dynamically on rows.", "typeDescriptions": { - "params": "With all properties from [[GridRowClassNameParams]].", + "params": "With all properties from GridRowClassNameParams.", "string": "The CSS class to apply to the row." } }, "getRowHeight": { "description": "Function that sets the row height per row.", "typeDescriptions": { - "params": "With all properties from [[GridRowHeightParams]].", + "params": "With all properties from GridRowHeightParams.", "GridRowHeightReturnValue": "The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content." } }, - "getRowId": { "description": "Return the id of a given [[GridRowModel]]." }, + "getRowId": { "description": "Return the id of a given GridRowModel." }, "getRowSpacing": { "description": "Function that allows to specify the spacing between rows.", "typeDescriptions": { - "params": "With all properties from [[GridRowSpacingParams]].", + "params": "With all properties from GridRowSpacingParams.", "GridRowSpacing": "The row spacing values." } }, @@ -129,14 +131,14 @@ "isCellEditable": { "description": "Callback fired when a cell is rendered, returns true if the cell is editable.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "boolean": "A boolean indicating if the cell is editable." } }, "isRowSelectable": { "description": "Determines if a row can be selected.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "boolean": "A boolean indicating if the cell is selectable." } }, @@ -148,7 +150,7 @@ "description": "Set the locale text of the Data Grid. You can find all the translation keys supported in the source in the GitHub repository." }, "logger": { - "description": "Pass a custom logger in the components that implements the [[Logger]] interface." + "description": "Pass a custom logger in the components that implements the Logger interface." }, "logLevel": { "description": "Allows to pass the logging level or false to turn off logging." }, "nonce": { @@ -157,7 +159,7 @@ "onCellClick": { "description": "Callback fired when any cell is clicked.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -165,7 +167,7 @@ "onCellDoubleClick": { "description": "Callback fired when a double click event comes from a cell element.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -173,21 +175,21 @@ "onCellEditStart": { "description": "Callback fired when the cell turns to edit mode.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event that caused this prop to be called." } }, "onCellEditStop": { "description": "Callback fired when the cell turns to view mode.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event that caused this prop to be called." } }, "onCellKeyDown": { "description": "Callback fired when a keydown event comes from a cell element.", "typeDescriptions": { - "params": "With all properties from [[GridCellParams]].", + "params": "With all properties from GridCellParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -206,7 +208,7 @@ "onColumnHeaderClick": { "description": "Callback fired when a click event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -214,7 +216,7 @@ "onColumnHeaderDoubleClick": { "description": "Callback fired when a double click event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -222,7 +224,7 @@ "onColumnHeaderEnter": { "description": "Callback fired when a mouse enter event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -230,7 +232,7 @@ "onColumnHeaderLeave": { "description": "Callback fired when a mouse leave event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -238,7 +240,7 @@ "onColumnHeaderOut": { "description": "Callback fired when a mouseout event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -246,7 +248,7 @@ "onColumnHeaderOver": { "description": "Callback fired when a mouseover event comes from a column header element.", "typeDescriptions": { - "params": "With all properties from [[GridColumnHeaderParams]].", + "params": "With all properties from GridColumnHeaderParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -254,7 +256,7 @@ "onColumnOrderChange": { "description": "Callback fired when a column is reordered.", "typeDescriptions": { - "params": "With all properties from [[GridColumnOrderChangeParams]].", + "params": "With all properties from GridColumnOrderChangeParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -269,14 +271,14 @@ "onFilterModelChange": { "description": "Callback fired when the Filter model changes before the filters are applied.", "typeDescriptions": { - "model": "With all properties from [[GridFilterModel]].", + "model": "With all properties from GridFilterModel.", "details": "Additional details for this callback." } }, "onMenuClose": { "description": "Callback fired when the menu is closed.", "typeDescriptions": { - "params": "With all properties from [[GridMenuParams]].", + "params": "With all properties from GridMenuParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -284,7 +286,7 @@ "onMenuOpen": { "description": "Callback fired when the menu is opened.", "typeDescriptions": { - "params": "With all properties from [[GridMenuParams]].", + "params": "With all properties from GridMenuParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -299,7 +301,7 @@ "onPreferencePanelClose": { "description": "Callback fired when the preferences panel is closed.", "typeDescriptions": { - "params": "With all properties from [[GridPreferencePanelParams]].", + "params": "With all properties from GridPreferencePanelParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -307,7 +309,7 @@ "onPreferencePanelOpen": { "description": "Callback fired when the preferences panel is opened.", "typeDescriptions": { - "params": "With all properties from [[GridPreferencePanelParams]].", + "params": "With all properties from GridPreferencePanelParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -319,7 +321,7 @@ "onResize": { "description": "Callback fired when the Data Grid is resized.", "typeDescriptions": { - "containerSize": "With all properties from [[ElementSize]].", + "containerSize": "With all properties from ElementSize.", "event": "The event object.", "details": "Additional details for this callback." } @@ -327,7 +329,7 @@ "onRowClick": { "description": "Callback fired when a row is clicked. Not called if the target clicked is an interactive element added by the built-in columns.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -335,7 +337,7 @@ "onRowDoubleClick": { "description": "Callback fired when a double click event comes from a row container element.", "typeDescriptions": { - "params": "With all properties from [[RowParams]].", + "params": "With all properties from RowParams.", "event": "The event object.", "details": "Additional details for this callback." } @@ -350,14 +352,14 @@ "onRowEditStart": { "description": "Callback fired when the row turns to edit mode.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event that caused this prop to be called." } }, "onRowEditStop": { "description": "Callback fired when the row turns to view mode.", "typeDescriptions": { - "params": "With all properties from [[GridRowParams]].", + "params": "With all properties from GridRowParams.", "event": "The event that caused this prop to be called." } }, @@ -371,14 +373,14 @@ "onRowSelectionModelChange": { "description": "Callback fired when the selection state of one or multiple rows changes.", "typeDescriptions": { - "rowSelectionModel": "With all the row ids [[GridSelectionModel]].", + "rowSelectionModel": "With all the row ids GridSelectionModel.", "details": "Additional details for this callback." } }, "onSortModelChange": { "description": "Callback fired when the sort model changes before a column is sorted.", "typeDescriptions": { - "model": "With all properties from [[GridSortModel]].", + "model": "With all properties from GridSortModel.", "details": "Additional details for this callback." } }, @@ -387,7 +389,7 @@ "description": "Pagination can be processed on the server or client-side. Set it to 'client' if you would like to handle the pagination on the client-side. Set it to 'server' if you would like to handle the pagination on the server-side." }, "paginationModel": { - "description": "The pagination model of type [[GridPaginationModel]] which refers to current page and pageSize." + "description": "The pagination model of type GridPaginationModel which refers to current page and pageSize." }, "processRowUpdate": { "description": "Callback called before updating a row with new values in the row and cell editing.", @@ -408,7 +410,7 @@ "rowPositionsDebounceMs": { "description": "The milliseconds delay to wait after measuring the row height before recalculating row positions. Setting it to a lower value could be useful when using dynamic row height, but might reduce performance when displaying a large number of rows." }, - "rows": { "description": "Set of rows of type [[GridRowsProp]]." }, + "rows": { "description": "Set of rows of type GridRowsProp." }, "rowSelection": { "description": "If false, the row selection mode is disabled." }, "rowSelectionModel": { "description": "Sets the row selection model of the Data Grid." }, "rowSpacingType": { diff --git a/docs/translations/api-docs/data-grid/grid-filter-form/grid-filter-form.json b/docs/translations/api-docs/data-grid/grid-filter-form/grid-filter-form.json index 6c191e9343db0..a89dd786bdc07 100644 --- a/docs/translations/api-docs/data-grid/grid-filter-form/grid-filter-form.json +++ b/docs/translations/api-docs/data-grid/grid-filter-form/grid-filter-form.json @@ -3,7 +3,9 @@ "propDescriptions": { "applyFilterChanges": { "description": "Callback called when the operator, column field or value is changed.", - "typeDescriptions": { "item": "The updated [[GridFilterItem]]." } + "typeDescriptions": { + "item": "The updated GridFilterItem." + } }, "applyMultiFilterOperatorChanges": { "description": "Callback called when the logic operator is changed.", @@ -15,7 +17,9 @@ }, "deleteFilter": { "description": "Callback called when the delete button is clicked.", - "typeDescriptions": { "item": "The deleted [[GridFilterItem]]." } + "typeDescriptions": { + "item": "The deleted GridFilterItem." + } }, "deleteIconProps": { "description": "Props passed to the delete icon." }, "disableMultiFilterOperator": { @@ -31,7 +35,9 @@ "hasMultipleFilters": { "description": "If true, the logic operator field is rendered. The field will be invisible if showMultiFilterOperators is also true." }, - "item": { "description": "The [[GridFilterItem]] representing this form." }, + "item": { + "description": "The GridFilterItem representing this form." + }, "logicOperatorInputProps": { "description": "Props passed to the logic operator input component." }, From c1e8338b036aa68625fd8e9bc72205901e42b1a7 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 18 Jan 2024 11:14:08 +0100 Subject: [PATCH 11/26] Fix doc --- .../rich-tree-view/selection/CheckboxMultiSelection.js | 10 +--------- .../selection/CheckboxMultiSelection.tsx | 10 +--------- .../selection/CheckboxMultiSelection.tsx.preview | 8 +------- .../rich-tree-view/selection/CheckboxSelection.js | 9 +-------- .../rich-tree-view/selection/CheckboxSelection.tsx | 9 +-------- .../selection/CheckboxSelection.tsx.preview | 7 +------ 6 files changed, 6 insertions(+), 47 deletions(-) diff --git a/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.js b/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.js index 151183c33f144..2ee4cd92bb214 100644 --- a/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.js +++ b/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.js @@ -1,7 +1,5 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { RichTreeView } from '@mui/x-tree-view'; const MUI_X_PRODUCTS = [ @@ -37,13 +35,7 @@ const MUI_X_PRODUCTS = [ export default function CheckboxMultiSelection() { return ( - } - defaultExpandIcon={} - /> + ); } diff --git a/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.tsx b/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.tsx index 5b94a8a356a99..c8803fc153b3c 100644 --- a/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.tsx +++ b/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.tsx @@ -1,7 +1,5 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { RichTreeView, TreeViewBaseItem } from '@mui/x-tree-view'; const MUI_X_PRODUCTS: TreeViewBaseItem[] = [ @@ -37,13 +35,7 @@ const MUI_X_PRODUCTS: TreeViewBaseItem[] = [ export default function CheckboxMultiSelection() { return ( - } - defaultExpandIcon={} - /> + ); } diff --git a/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.tsx.preview b/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.tsx.preview index 9880c13860468..7d1afb61bd4c0 100644 --- a/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.tsx.preview +++ b/docs/data/tree-view/rich-tree-view/selection/CheckboxMultiSelection.tsx.preview @@ -1,7 +1 @@ -} - defaultExpandIcon={} -/> \ No newline at end of file + \ No newline at end of file diff --git a/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.js b/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.js index 6892f8d5c8f89..17a520a2a7756 100644 --- a/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.js +++ b/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.js @@ -1,7 +1,5 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { RichTreeView } from '@mui/x-tree-view'; const MUI_X_PRODUCTS = [ @@ -37,12 +35,7 @@ const MUI_X_PRODUCTS = [ export default function CheckboxSelection() { return ( - } - defaultExpandIcon={} - /> + ); } diff --git a/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.tsx b/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.tsx index 48ba1e9d79f38..28bda421ad18e 100644 --- a/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.tsx +++ b/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.tsx @@ -1,7 +1,5 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { RichTreeView, TreeViewBaseItem } from '@mui/x-tree-view'; const MUI_X_PRODUCTS: TreeViewBaseItem[] = [ @@ -37,12 +35,7 @@ const MUI_X_PRODUCTS: TreeViewBaseItem[] = [ export default function CheckboxSelection() { return ( - } - defaultExpandIcon={} - /> + ); } diff --git a/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.tsx.preview b/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.tsx.preview index ae08b509c8b73..5498dc5442391 100644 --- a/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.tsx.preview +++ b/docs/data/tree-view/rich-tree-view/selection/CheckboxSelection.tsx.preview @@ -1,6 +1 @@ -} - defaultExpandIcon={} -/> \ No newline at end of file + \ No newline at end of file From af55ea52eb596e605af1df31cfa1e2abc6e67d91 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 18 Jan 2024 11:24:48 +0100 Subject: [PATCH 12/26] Fix doc --- .../simple-tree-view/selection/CheckboxMultiSelection.js | 9 +-------- .../selection/CheckboxMultiSelection.tsx | 9 +-------- .../simple-tree-view/selection/CheckboxSelection.js | 8 +------- 3 files changed, 3 insertions(+), 23 deletions(-) diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.js b/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.js index 46adcd50a1e94..47dc834d03b33 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.js +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.js @@ -1,19 +1,12 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; import { TreeItem } from '@mui/x-tree-view/TreeItem'; export default function CheckboxMultiSelection() { return ( - } - defaultExpandIcon={} - > + diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.tsx b/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.tsx index 46adcd50a1e94..47dc834d03b33 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.tsx +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.tsx @@ -1,19 +1,12 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; import { TreeItem } from '@mui/x-tree-view/TreeItem'; export default function CheckboxMultiSelection() { return ( - } - defaultExpandIcon={} - > + diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js index 9b0b25848798c..13655257f8868 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js @@ -1,18 +1,12 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; import { TreeItem } from '@mui/x-tree-view/TreeItem'; export default function CheckboxSelection() { return ( - } - defaultExpandIcon={} - > + From fa13038a5b0c70d77cdbb2f07210e799f5e59eae Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 18 Jan 2024 11:44:31 +0100 Subject: [PATCH 13/26] Fix doc --- .../simple-tree-view/selection/CheckboxSelection.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.tsx b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.tsx index 9b0b25848798c..13655257f8868 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.tsx +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.tsx @@ -1,18 +1,12 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; import { TreeItem } from '@mui/x-tree-view/TreeItem'; export default function CheckboxSelection() { return ( - } - defaultExpandIcon={} - > + From 16a3b09978a2e97ed95e533d26d0444f2c8057a1 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 20 Mar 2024 14:28:15 +0100 Subject: [PATCH 14/26] Remove padding on checkbox --- .../selection/CheckboxMultiSelection.js | 22 +++++++++---------- .../selection/CheckboxMultiSelection.tsx | 22 +++++++++---------- .../selection/CheckboxSelection.js | 22 +++++++++---------- .../selection/CheckboxSelection.tsx | 22 +++++++++---------- .../x-tree-view/src/TreeItem/TreeItem.tsx | 5 +++++ .../src/TreeItem/TreeItemContent.tsx | 3 +++ .../src/TreeItem/treeItemClasses.ts | 3 +++ 7 files changed, 55 insertions(+), 44 deletions(-) diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.js b/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.js index 47dc834d03b33..4c5cc2874d520 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.js +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.js @@ -7,20 +7,20 @@ export default function CheckboxMultiSelection() { return ( - - - - + + + + - - - + + + - - + + - - + + diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.tsx b/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.tsx index 47dc834d03b33..4c5cc2874d520 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.tsx +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxMultiSelection.tsx @@ -7,20 +7,20 @@ export default function CheckboxMultiSelection() { return ( - - - - + + + + - - - + + + - - + + - - + + diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js index 13655257f8868..1b1d057131b7d 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.js @@ -7,20 +7,20 @@ export default function CheckboxSelection() { return ( - - - - + + + + - - - + + + - - + + - - + + diff --git a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.tsx b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.tsx index 13655257f8868..1b1d057131b7d 100644 --- a/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.tsx +++ b/docs/data/tree-view/simple-tree-view/selection/CheckboxSelection.tsx @@ -7,20 +7,20 @@ export default function CheckboxSelection() { return ( - - - - + + + + - - - + + + - - + + - - + + diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.tsx index 71f44268b5251..0840cfab9e67e 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.tsx @@ -31,6 +31,7 @@ const useUtilityClasses = (ownerState: TreeItemOwnerState) => { iconContainer: ['iconContainer'], label: ['label'], groupTransition: ['groupTransition'], + checkbox: ['checkbox'], }; return composeClasses(slots, getTreeItemUtilityClass, classes); @@ -131,6 +132,9 @@ const StyledTreeItemContent = styled(TreeItemContent, { position: 'relative', ...theme.typography.body1, }, + [`& .${treeItemClasses.checkbox}`]: { + padding: 0, + }, })); const TreeItemGroup = styled(Collapse, { @@ -340,6 +344,7 @@ export const TreeItem = React.forwardRef(function TreeItem( disabled: classes.disabled, iconContainer: classes.iconContainer, label: classes.label, + checkbox: classes.checkbox, }} label={label} itemId={itemId} diff --git a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx index b5417786f0203..e994fe9eb08c4 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx @@ -26,6 +26,8 @@ export interface TreeItemContentProps extends React.HTMLAttributes iconContainer: string; /** Styles applied to the label element. */ label: string; + /** Styles applied to the checkbox element. */ + checkbox: string; }; /** * The tree item label. @@ -133,6 +135,7 @@ const TreeItemContent = React.forwardRef(function TreeItemContent(
{icon}
{checkboxSelection && ( Date: Wed, 20 Mar 2024 14:55:12 +0100 Subject: [PATCH 15/26] Work --- docs/pages/x/api/tree-view/tree-item-2.json | 8 ++++++- docs/pages/x/api/tree-view/tree-item.json | 8 ++++++- .../tree-view/tree-item-2/tree-item-2.json | 6 ++++- .../tree-view/tree-item/tree-item.json | 6 ++++- .../x-tree-view/src/TreeItem/TreeItem.tsx | 2 +- .../src/TreeItem/TreeItemContent.tsx | 7 +++--- .../src/TreeItem/treeItemClasses.ts | 2 +- .../src/TreeItem/useTreeItemState.ts | 24 ++++++++++++------- 8 files changed, 46 insertions(+), 17 deletions(-) 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 cbb43fc111182..64dfc33ebb2df 100644 --- a/docs/pages/x/api/tree-view/tree-item-2.json +++ b/docs/pages/x/api/tree-view/tree-item-2.json @@ -60,6 +60,12 @@ } ], "classes": [ + { + "key": "checkbox", + "className": "MuiTreeItem2-checkbox", + "description": "Styles applied to the checkbox element.", + "isGlobal": false + }, { "key": "disabled", "className": "Mui-disabled", @@ -87,7 +93,7 @@ { "key": "selected", "className": "Mui-selected", - "description": "State class applied to the content element when selected and not using the checkbox selection.", + "description": "State class applied to the content element when selected.", "isGlobal": true } ], diff --git a/docs/pages/x/api/tree-view/tree-item.json b/docs/pages/x/api/tree-view/tree-item.json index 06fd8b6cd7a4c..7f3b5d23bd1f9 100644 --- a/docs/pages/x/api/tree-view/tree-item.json +++ b/docs/pages/x/api/tree-view/tree-item.json @@ -47,6 +47,12 @@ } ], "classes": [ + { + "key": "checkbox", + "className": "MuiTreeItem-checkbox", + "description": "Styles applied to the checkbox element.", + "isGlobal": false + }, { "key": "content", "className": "MuiTreeItem-content", @@ -98,7 +104,7 @@ { "key": "selected", "className": "Mui-selected", - "description": "State class applied to the content element when selected and not using the checkbox selection.", + "description": "State class applied to the content element when selected.", "isGlobal": true } ], 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 04137a8505f8e..d18e816d2f4e0 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 @@ -14,6 +14,10 @@ "slots": { "description": "Overridable component slots." } }, "classDescriptions": { + "checkbox": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the checkbox element" + }, "disabled": { "description": "State class applied to {{nodeName}} when {{conditions}}.", "nodeName": "the element", @@ -37,7 +41,7 @@ "selected": { "description": "State class applied to {{nodeName}} when {{conditions}}.", "nodeName": "the content element", - "conditions": "selected and not using the checkbox selection" + "conditions": "selected" } }, "slotDescriptions": { 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 000938e2d4301..2045a4da23373 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 @@ -21,6 +21,10 @@ } }, "classDescriptions": { + "checkbox": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the checkbox element" + }, "content": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the content element" @@ -54,7 +58,7 @@ "selected": { "description": "State class applied to {{nodeName}} when {{conditions}}.", "nodeName": "the content element", - "conditions": "selected and not using the checkbox selection" + "conditions": "selected" } }, "slotDescriptions": { diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.tsx index 0840cfab9e67e..b916756b75333 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.tsx @@ -88,7 +88,7 @@ const StyledTreeItemContent = styled(TreeItemContent, { [`&.${treeItemClasses.focused}`]: { backgroundColor: (theme.vars || theme).palette.action.focus, }, - [`.${treeItemClasses.selected}`]: { + [`&.${treeItemClasses.selected}`]: { backgroundColor: theme.vars ? `rgba(${theme.vars.palette.primary.mainChannel} / ${theme.vars.palette.action.selectedOpacity})` : alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity), diff --git a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx index e994fe9eb08c4..e455dce72e6bb 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx @@ -14,7 +14,7 @@ export interface TreeItemContentProps extends React.HTMLAttributes root: string; /** State class applied to the content element when expanded. */ expanded: string; - /** State class applied to the content element when selected and not using the checkbox selection. */ + /** State class applied to the content element when selected. */ selected: string; /** State class applied to the content element when clicking it causes an action. */ interactive: string; @@ -83,6 +83,7 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( checkboxSelection, handleExpansion, handleSelection, + handleCheckboxSelection, preventSelection, } = useTreeItemState(itemId); @@ -114,7 +115,7 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( }; const handleCheckboxSelectionChange = (event: React.ChangeEvent) => { - handleSelection(event); + handleCheckboxSelection(event); }; return ( @@ -123,7 +124,7 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( {...other} className={clsx(className, classes.root, { [classes.expanded]: expanded, - [classes.selected]: selected && !checkboxSelection, + [classes.selected]: selected, [classes.interactive]: (!checkboxSelection && !disableSelection) || expandable, [classes.focused]: focused, [classes.disabled]: disabled, diff --git a/packages/x-tree-view/src/TreeItem/treeItemClasses.ts b/packages/x-tree-view/src/TreeItem/treeItemClasses.ts index a6c3fe9e69908..4399be9f458ad 100644 --- a/packages/x-tree-view/src/TreeItem/treeItemClasses.ts +++ b/packages/x-tree-view/src/TreeItem/treeItemClasses.ts @@ -10,7 +10,7 @@ export interface TreeItemClasses { content: string; /** State class applied to the content element when expanded. */ expanded: string; - /** State class applied to the content element when selected and not using the checkbox selection. */ + /** State class applied to the content element when selected. */ selected: string; /** State class applied to the content element when clicking it causes an action. */ interactive: string; diff --git a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts index c0ce53266c003..a5cff3e9a622a 100644 --- a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts +++ b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts @@ -29,21 +29,16 @@ export function useTreeItemState(itemId: string) { } }; - const handleSelection = (event: React.ChangeEvent | React.MouseEvent) => { + const handleSelection = (event: React.MouseEvent) => { if (!disabled) { if (!focused) { instance.focusItem(event, itemId); } - const nativeEvent = (event.type === 'change' - ? event.nativeEvent - : event) as unknown as React.MouseEvent; - - const multiple = - multiSelect && (nativeEvent.shiftKey || nativeEvent.ctrlKey || nativeEvent.metaKey); + const multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey); if (multiple) { - if (nativeEvent.shiftKey) { + if (event.shiftKey) { instance.selectRange(event, { end: itemId }); } else { instance.selectNode(event, itemId, true); @@ -54,6 +49,18 @@ export function useTreeItemState(itemId: string) { } }; + const handleCheckboxSelection = (event: React.ChangeEvent) => { + if (multiSelect) { + if ((event.nativeEvent as PointerEvent).shiftKey) { + instance.selectRange(event, { end: itemId }); + } else { + instance.selectNode(event, itemId, multiSelect); + } + } else { + instance.selectNode(event, itemId); + } + }; + const preventSelection = (event: React.MouseEvent) => { if (event.shiftKey || event.ctrlKey || event.metaKey || disabled) { // Prevent text selection @@ -71,6 +78,7 @@ export function useTreeItemState(itemId: string) { checkboxSelection, handleExpansion, handleSelection, + handleCheckboxSelection, preventSelection, }; } From fe94a0cdd1638937b1edfd5111fc1bfd0f1da9d5 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 20 Mar 2024 15:01:49 +0100 Subject: [PATCH 16/26] Fix --- packages/x-tree-view/src/TreeItem/TreeItemContent.tsx | 1 + packages/x-tree-view/src/TreeItem/useTreeItemState.ts | 2 +- .../useTreeViewKeyboardNavigation.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx index e455dce72e6bb..2b65d2cad9481 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx @@ -141,6 +141,7 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( onChange={handleCheckboxSelectionChange} disabled={disableSelection} ref={checkboxRef} + tabIndex={-1} /> )} diff --git a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts index a5cff3e9a622a..f018ba846ebe8 100644 --- a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts +++ b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts @@ -54,7 +54,7 @@ export function useTreeItemState(itemId: string) { if ((event.nativeEvent as PointerEvent).shiftKey) { instance.selectRange(event, { end: itemId }); } else { - instance.selectNode(event, itemId, multiSelect); + instance.selectNode(event, itemId, true); } } else { instance.selectNode(event, itemId); diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts index 762573b4dada2..bff823a3e462a 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts @@ -121,7 +121,7 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin< return; } - if (event.altKey || event.currentTarget !== event.target) { + if (event.altKey) { return; } From eeaeac5e54f0c2d0bffaad205804495ff3aa2597 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 23 Apr 2024 14:08:47 +0200 Subject: [PATCH 17/26] Fix --- packages/x-tree-view/src/TreeItem/useTreeItemState.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts index 50adf7a6951e1..b784bb1ad6423 100644 --- a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts +++ b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts @@ -52,12 +52,12 @@ export function useTreeItemState(itemId: string) { const handleCheckboxSelection = (event: React.ChangeEvent) => { if (multiSelect) { if ((event.nativeEvent as PointerEvent).shiftKey) { - instance.selectRange(event, { end: itemId }); + instance.expandSelectionRange(event, itemId); } else { - instance.selectNode(event, itemId, true); + instance.selectItem(event, itemId, true); } } else { - instance.selectNode(event, itemId); + instance.selectItem(event, itemId); } }; From 223160d6e68259e63a7dd2bf831523389d3833b8 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 23 Apr 2024 14:40:58 +0200 Subject: [PATCH 18/26] Add support for TreeItem2 --- docs/pages/x/api/tree-view/tree-item-2.json | 12 +++--- .../tree-view/tree-item-2/tree-item-2.json | 5 +-- .../x-tree-view/src/TreeItem/TreeItem.tsx | 2 +- .../src/TreeItem/useTreeItemState.ts | 11 ++---- .../x-tree-view/src/TreeItem2/TreeItem2.tsx | 28 +++++++++++++ .../src/TreeItem2/TreeItem2.types.ts | 6 +++ .../useTreeItem2Utils/useTreeItem2Utils.tsx | 16 +++++++- .../src/useTreeItem2/useTreeItem2.ts | 39 +++++++++++++++++-- .../src/useTreeItem2/useTreeItem2.types.ts | 20 ++++++++++ 9 files changed, 117 insertions(+), 22 deletions(-) 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 041e24d1d58e4..2824ba89028e0 100644 --- a/docs/pages/x/api/tree-view/tree-item-2.json +++ b/docs/pages/x/api/tree-view/tree-item-2.json @@ -44,6 +44,12 @@ "default": "TreeItem2IconContainer", "class": "MuiTreeItem2-iconContainer" }, + { + "name": "checkbox", + "description": "The component that renders the item checkbox for selection.", + "default": "TreeItem2Checkbox", + "class": "MuiTreeItem2-checkbox" + }, { "name": "label", "description": "The component that renders the item label.", @@ -60,12 +66,6 @@ } ], "classes": [ - { - "key": "checkbox", - "className": "MuiTreeItem2-checkbox", - "description": "Styles applied to the checkbox element.", - "isGlobal": false - }, { "key": "disabled", "className": "Mui-disabled", 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 5cf38ec357b68..59ac25c4bb118 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 @@ -14,10 +14,6 @@ "slots": { "description": "Overridable component slots." } }, "classDescriptions": { - "checkbox": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the checkbox element" - }, "disabled": { "description": "State class applied to {{nodeName}} when {{conditions}}.", "nodeName": "the element", @@ -45,6 +41,7 @@ } }, "slotDescriptions": { + "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).", "endIcon": "The icon displayed next to an end item.", diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.tsx index bfd67e21f042f..71dd7799887f5 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.tsx @@ -29,9 +29,9 @@ const useUtilityClasses = (ownerState: TreeItemOwnerState) => { interactive: ['interactive'], disabled: ['disabled'], iconContainer: ['iconContainer'], + checkbox: ['checkbox'], label: ['label'], groupTransition: ['groupTransition'], - checkbox: ['checkbox'], }; return composeClasses(slots, getTreeItemUtilityClass, classes); diff --git a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts index b784bb1ad6423..7fac6c7621bed 100644 --- a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts +++ b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts @@ -50,14 +50,11 @@ export function useTreeItemState(itemId: string) { }; const handleCheckboxSelection = (event: React.ChangeEvent) => { - if (multiSelect) { - if ((event.nativeEvent as PointerEvent).shiftKey) { - instance.expandSelectionRange(event, itemId); - } else { - instance.selectItem(event, itemId, true); - } + const hasShift = (event.nativeEvent as PointerEvent).shiftKey; + if (multiSelect && hasShift) { + instance.expandSelectionRange(event, itemId); } else { - instance.selectItem(event, itemId); + instance.selectItem(event, itemId, multiSelect); } }; diff --git a/packages/x-tree-view/src/TreeItem2/TreeItem2.tsx b/packages/x-tree-view/src/TreeItem2/TreeItem2.tsx index c48addd333286..f3091eb750579 100644 --- a/packages/x-tree-view/src/TreeItem2/TreeItem2.tsx +++ b/packages/x-tree-view/src/TreeItem2/TreeItem2.tsx @@ -4,6 +4,7 @@ import clsx from 'clsx'; import unsupportedProp from '@mui/utils/unsupportedProp'; import { alpha, styled, useThemeProps } from '@mui/material/styles'; import Collapse from '@mui/material/Collapse'; +import MuiCheckbox, { CheckboxProps } from '@mui/material/Checkbox'; import { useSlotProps } from '@mui/base/utils'; import { shouldForwardProp } from '@mui/system'; import composeClasses from '@mui/utils/composeClasses'; @@ -139,6 +140,21 @@ export const TreeItem2GroupTransition = styled(Collapse, { paddingLeft: 12, }); +export const TreeItem2Checkbox = styled( + React.forwardRef( + (props: CheckboxProps & { visible: boolean }, ref: React.Ref) => { + const { visible, ...other } = props; + if (!visible) { + return null; + } + + return ; + }, + ), +)({ + padding: 0, +}); + const useUtilityClasses = (ownerState: TreeItem2OwnerState) => { const { classes } = ownerState; @@ -150,6 +166,7 @@ const useUtilityClasses = (ownerState: TreeItem2OwnerState) => { focused: ['focused'], disabled: ['disabled'], iconContainer: ['iconContainer'], + checkbox: ['checkbox'], label: ['label'], groupTransition: ['groupTransition'], }; @@ -183,6 +200,7 @@ export const TreeItem2 = React.forwardRef(function TreeItem2( getRootProps, getContentProps, getIconContainerProps, + getCheckboxProps, getLabelProps, getGroupTransitionProps, status, @@ -246,6 +264,15 @@ export const TreeItem2 = React.forwardRef(function TreeItem2( className: classes.label, }); + const Checkbox: React.ElementType = slots.label ?? TreeItem2Checkbox; + const checkboxProps = useSlotProps({ + elementType: Checkbox, + getSlotProps: getCheckboxProps, + externalSlotProps: slotProps.checkbox, + ownerState: {}, + className: classes.checkbox, + }); + const GroupTransition: React.ElementType | undefined = slots.groupTransition ?? undefined; const groupTransitionProps = useSlotProps({ elementType: GroupTransition, @@ -262,6 +289,7 @@ export const TreeItem2 = React.forwardRef(function TreeItem2( +
diff --git a/docs/data/tree-view/rich-tree-view/customization/CustomContentTreeView.tsx b/docs/data/tree-view/rich-tree-view/customization/CustomContentTreeView.tsx index 7651bb7ed31ef..0caea393d6977 100644 --- a/docs/data/tree-view/rich-tree-view/customization/CustomContentTreeView.tsx +++ b/docs/data/tree-view/rich-tree-view/customization/CustomContentTreeView.tsx @@ -14,6 +14,7 @@ import { TreeItem2GroupTransition, TreeItem2Label, TreeItem2Root, + TreeItem2Checkbox, } from '@mui/x-tree-view/TreeItem2'; import { TreeItem2Icon } from '@mui/x-tree-view/TreeItem2Icon'; import { TreeItem2Provider } from '@mui/x-tree-view/TreeItem2Provider'; @@ -56,6 +57,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem( getRootProps, getContentProps, getIconContainerProps, + getCheckboxProps, getLabelProps, getGroupTransitionProps, status, @@ -79,6 +81,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem( > {(label as string)[0]} +
diff --git a/docs/data/tree-view/rich-tree-view/customization/FileExplorer.js b/docs/data/tree-view/rich-tree-view/customization/FileExplorer.js index 2ac57640beea8..78192d2b26c21 100644 --- a/docs/data/tree-view/rich-tree-view/customization/FileExplorer.js +++ b/docs/data/tree-view/rich-tree-view/customization/FileExplorer.js @@ -17,6 +17,7 @@ import { RichTreeView } from '@mui/x-tree-view/RichTreeView'; import { treeItemClasses } from '@mui/x-tree-view/TreeItem'; import { unstable_useTreeItem2 as useTreeItem2 } from '@mui/x-tree-view/useTreeItem2'; import { + TreeItem2Checkbox, TreeItem2Content, TreeItem2IconContainer, TreeItem2Label, @@ -211,6 +212,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) { getRootProps, getContentProps, getIconContainerProps, + getCheckboxProps, getLabelProps, getGroupTransitionProps, status, @@ -242,7 +244,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) { - + diff --git a/docs/data/tree-view/rich-tree-view/customization/FileExplorer.tsx b/docs/data/tree-view/rich-tree-view/customization/FileExplorer.tsx index d12cf981003ac..ef5e8e5384abc 100644 --- a/docs/data/tree-view/rich-tree-view/customization/FileExplorer.tsx +++ b/docs/data/tree-view/rich-tree-view/customization/FileExplorer.tsx @@ -20,6 +20,7 @@ import { UseTreeItem2Parameters, } from '@mui/x-tree-view/useTreeItem2'; import { + TreeItem2Checkbox, TreeItem2Content, TreeItem2IconContainer, TreeItem2Label, @@ -247,6 +248,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem( getRootProps, getContentProps, getIconContainerProps, + getCheckboxProps, getLabelProps, getGroupTransitionProps, status, @@ -278,7 +280,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem( - + diff --git a/docs/data/tree-view/simple-tree-view/customization/CustomContentTreeView.js b/docs/data/tree-view/simple-tree-view/customization/CustomContentTreeView.js index 2076a1e87f939..c16dc8ac924a5 100644 --- a/docs/data/tree-view/simple-tree-view/customization/CustomContentTreeView.js +++ b/docs/data/tree-view/simple-tree-view/customization/CustomContentTreeView.js @@ -10,6 +10,7 @@ import { TreeItem2GroupTransition, TreeItem2Label, TreeItem2Root, + TreeItem2Checkbox, } from '@mui/x-tree-view/TreeItem2'; import { TreeItem2Icon } from '@mui/x-tree-view/TreeItem2Icon'; import { TreeItem2Provider } from '@mui/x-tree-view/TreeItem2Provider'; @@ -25,6 +26,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) { getRootProps, getContentProps, getIconContainerProps, + getCheckboxProps, getLabelProps, getGroupTransitionProps, status, @@ -37,6 +39,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) { + ({ diff --git a/docs/data/tree-view/simple-tree-view/customization/CustomContentTreeView.tsx b/docs/data/tree-view/simple-tree-view/customization/CustomContentTreeView.tsx index a7e41eb533c37..c4d333d40f08a 100644 --- a/docs/data/tree-view/simple-tree-view/customization/CustomContentTreeView.tsx +++ b/docs/data/tree-view/simple-tree-view/customization/CustomContentTreeView.tsx @@ -13,6 +13,7 @@ import { TreeItem2GroupTransition, TreeItem2Label, TreeItem2Root, + TreeItem2Checkbox, } from '@mui/x-tree-view/TreeItem2'; import { TreeItem2Icon } from '@mui/x-tree-view/TreeItem2Icon'; import { TreeItem2Provider } from '@mui/x-tree-view/TreeItem2Provider'; @@ -35,6 +36,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem( getRootProps, getContentProps, getIconContainerProps, + getCheckboxProps, getLabelProps, getGroupTransitionProps, status, @@ -47,6 +49,7 @@ const CustomTreeItem = React.forwardRef(function CustomTreeItem( + ({ diff --git a/packages/x-tree-view/src/TreeItem2/index.ts b/packages/x-tree-view/src/TreeItem2/index.ts index f8fddaaa0c83e..9bc803abb6c8e 100644 --- a/packages/x-tree-view/src/TreeItem2/index.ts +++ b/packages/x-tree-view/src/TreeItem2/index.ts @@ -4,6 +4,7 @@ export { TreeItem2Content, TreeItem2IconContainer, TreeItem2GroupTransition, + TreeItem2Checkbox, TreeItem2Label, } from './TreeItem2'; export type { TreeItem2Props, TreeItem2Slots, TreeItem2SlotProps } from './TreeItem2.types'; From f816031e8691d6e557e2e03e5bfd83220838dc70 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 24 Apr 2024 09:38:59 +0200 Subject: [PATCH 24/26] Fix --- scripts/x-tree-view.exports.json | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/x-tree-view.exports.json b/scripts/x-tree-view.exports.json index d976b52c03da6..aba988ecc2335 100644 --- a/scripts/x-tree-view.exports.json +++ b/scripts/x-tree-view.exports.json @@ -24,6 +24,7 @@ { "name": "SingleSelectTreeViewProps", "kind": "TypeAlias" }, { "name": "TreeItem", "kind": "Variable" }, { "name": "TreeItem2", "kind": "Variable" }, + { "name": "TreeItem2Checkbox", "kind": "Variable" }, { "name": "TreeItem2Content", "kind": "Variable" }, { "name": "TreeItem2GroupTransition", "kind": "Variable" }, { "name": "TreeItem2Icon", "kind": "Function" }, From 59c5454955944614527ee51c37e57c2fa3ead06d Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 24 Apr 2024 13:50:56 +0200 Subject: [PATCH 25/26] Add test and fine tune behaviors --- .../src/TreeItem/TreeItemContent.tsx | 2 +- .../src/TreeItem/useTreeItemState.ts | 10 +- .../useTreeItem2Utils/useTreeItem2Utils.tsx | 8 +- .../useTreeViewKeyboardNavigation.ts | 4 +- .../useTreeViewSelection.test.tsx | 322 +++++++++++++++++- .../useTreeViewSelection.ts | 28 +- .../useTreeViewSelection.types.ts | 10 +- .../src/useTreeItem2/useTreeItem2.ts | 9 +- .../describeTreeView/describeTreeView.tsx | 8 + .../describeTreeView.types.ts | 12 + 10 files changed, 392 insertions(+), 21 deletions(-) diff --git a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx index eb445a143b431..161d3d3afef6a 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItemContent.tsx @@ -131,7 +131,7 @@ const TreeItemContent = React.forwardRef(function TreeItemContent( className={classes.checkbox} checked={selected} onChange={handleCheckboxSelection} - disabled={disableSelection} + disabled={disabled || disableSelection} ref={checkboxRef} tabIndex={-1} /> diff --git a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts index 380fe346f33fa..f429ac981d20b 100644 --- a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts +++ b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts @@ -44,17 +44,21 @@ export function useTreeItemState(itemId: string) { instance.selectItem(event, itemId, true); } } else { - instance.selectItem(event, itemId); + instance.selectItem(event, itemId, false); } } }; - const handleCheckboxSelection = (event: React.ChangeEvent) => { + const handleCheckboxSelection = (event: React.ChangeEvent) => { + if (disableSelection || disabled) { + return; + } + const hasShift = (event.nativeEvent as PointerEvent).shiftKey; if (multiSelect && hasShift) { instance.expandSelectionRange(event, itemId); } else { - instance.selectItem(event, itemId, multiSelect); + instance.selectItem(event, itemId, multiSelect, event.target.checked); } }; diff --git a/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx b/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx index 7c098ef12c7b3..b76e3fcf96aa4 100644 --- a/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx +++ b/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx @@ -6,7 +6,7 @@ import type { UseTreeItem2Status } from '../../useTreeItem2'; interface UseTreeItem2Interactions { handleExpansion: (event: React.MouseEvent) => void; handleSelection: (event: React.MouseEvent) => void; - handleCheckboxSelection: (event: React.ChangeEvent) => void; + handleCheckboxSelection: (event: React.ChangeEvent) => void; } interface UseTreeItem2UtilsReturnValue { @@ -69,16 +69,16 @@ export const useTreeItem2Utils = ({ instance.selectItem(event, itemId, true); } } else { - instance.selectItem(event, itemId); + instance.selectItem(event, itemId, false); } }; - const handleCheckboxSelection = (event: React.ChangeEvent) => { + const handleCheckboxSelection = (event: React.ChangeEvent) => { const hasShift = (event.nativeEvent as PointerEvent).shiftKey; if (multiSelect && hasShift) { instance.expandSelectionRange(event, itemId); } else { - instance.selectItem(event, itemId, multiSelect); + instance.selectItem(event, itemId, multiSelect, event.target.checked); } }; diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts index 6d4730b82bd7a..57a3e650ad803 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.ts @@ -109,7 +109,7 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin< } else if (params.multiSelect) { instance.selectItem(event, itemId, true); } else { - instance.selectItem(event, itemId); + instance.selectItem(event, itemId, false); } break; } @@ -125,7 +125,7 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin< event.preventDefault(); instance.selectItem(event, itemId, true); } else if (!instance.isItemSelected(itemId)) { - instance.selectItem(event, itemId); + instance.selectItem(event, itemId, false); event.preventDefault(); } } diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx index c6d5e885ec2c8..eb018f5f53ed9 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx @@ -10,7 +10,7 @@ import { UseTreeViewSelectionSignature } from '@mui/x-tree-view/internals'; */ describeTreeView<[UseTreeViewSelectionSignature]>('useTreeViewSelection plugin', ({ render }) => { describe('model props (selectedItems, defaultSelectedItems, onSelectedItemsChange)', () => { - it('should not select items when no default state and no control state are defined', () => { + it('should not select items when no defaulat state and no control state are defined', () => { const response = render({ items: [{ id: '1' }, { id: '2' }], }); @@ -212,7 +212,7 @@ describeTreeView<[UseTreeViewSelectionSignature]>('useTreeViewSelection plugin', }); describe('multi selection', () => { - it('should select un-selected item when clicking on an item content', () => { + it('should select un-selected item and remove other selected items when clicking on an item content', () => { const response = render({ multiSelect: true, items: [{ id: '1' }, { id: '2' }], @@ -460,6 +460,324 @@ describeTreeView<[UseTreeViewSelectionSignature]>('useTreeViewSelection plugin', }); }); + describe('checkbox interaction', () => { + describe('render checkbox when needed', () => { + it('should not render a checkbox when checkboxSelection is not defined', () => { + const response = render({ + items: [{ id: '1' }], + }); + + expect(response.getItemCheckbox('1')).to.equal(null); + }); + + it('should not render a checkbox when checkboxSelection is false', () => { + const response = render({ + checkboxSelection: false, + items: [{ id: '1' }], + }); + + expect(response.getItemCheckbox('1')).to.equal(null); + }); + + it('should render a checkbox when checkboxSelection is true', () => { + const response = render({ + checkboxSelection: true, + items: [{ id: '1' }], + }); + + expect(response.getItemCheckbox('1')).not.to.equal(null); + }); + }); + + describe('single selection', () => { + it('should not change selection when clicking on an item content', () => { + const response = render({ + checkboxSelection: true, + items: [{ id: '1' }], + }); + + expect(response.isItemSelected('1')).to.equal(false); + + fireEvent.click(response.getItemContent('1')); + expect(response.isItemSelected('1')).to.equal(false); + }); + + it('should select un-selected item when clicking on an item checkbox', () => { + const response = render({ + items: [{ id: '1' }, { id: '2' }], + checkboxSelection: true, + }); + + expect(response.isItemSelected('1')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(true); + }); + + it('should un-select selected item when clicking on an item checkbox', () => { + const response = render({ + items: [{ id: '1' }, { id: '2' }], + defaultSelectedItems: '1', + checkboxSelection: true, + }); + + expect(response.isItemSelected('1')).to.equal(true); + + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(false); + }); + + it('should not select an item when click and disableSelection', () => { + const response = render({ + items: [{ id: '1' }, { id: '2' }], + disableSelection: true, + checkboxSelection: true, + }); + + expect(response.isItemSelected('1')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(false); + }); + + it('should not select an item when clicking on a disabled item checkbox', () => { + const response = render({ + items: [{ id: '1', disabled: true }, { id: '2' }], + checkboxSelection: true, + }); + + expect(response.isItemSelected('1')).to.equal(false); + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(false); + }); + }); + + describe('multi selection', () => { + it('should not change selection when clicking on an item content', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1' }], + }); + + expect(response.isItemSelected('1')).to.equal(false); + + fireEvent.click(response.getItemContent('1')); + expect(response.isItemSelected('1')).to.equal(false); + }); + + it('should select un-selected item and keep other items selected when clicking on an item checkbox', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1' }, { id: '2' }], + defaultSelectedItems: ['2'], + }); + + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(true); + + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(true); + expect(response.isItemSelected('2')).to.equal(true); + }); + + it('should un-select selected item when clicking on an item checkbox', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1' }, { id: '2' }], + defaultSelectedItems: ['1'], + }); + + expect(response.isItemSelected('1')).to.equal(true); + + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(false); + }); + + it('should not select an item when click and disableSelection', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1' }, { id: '2' }], + disableSelection: true, + }); + + expect(response.isItemSelected('1')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(false); + }); + + it('should not select an item when clicking on a disabled item content', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1', disabled: true }, { id: '2' }], + }); + + expect(response.isItemSelected('1')).to.equal(false); + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(false); + }); + + it('should expand the selection range when clicking on an item checkbox below the last selected item while holding Shift', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1' }, { id: '2' }, { id: '2.1' }, { id: '3' }, { id: '4' }], + }); + + fireEvent.click(response.getItemCheckboxInput('2')); + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(true); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + expect(response.isItemSelected('4')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('3'), { shiftKey: true }); + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(true); + expect(response.isItemSelected('2.1')).to.equal(true); + expect(response.isItemSelected('3')).to.equal(true); + expect(response.isItemSelected('4')).to.equal(false); + }); + + it('should expand the selection range when clicking on an item checkbox above the last selected item while holding Shift', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1' }, { id: '2' }, { id: '2.1' }, { id: '3' }, { id: '4' }], + }); + + fireEvent.click(response.getItemCheckboxInput('3')); + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(false); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(true); + expect(response.isItemSelected('4')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('2'), { shiftKey: true }); + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(true); + expect(response.isItemSelected('2.1')).to.equal(true); + expect(response.isItemSelected('3')).to.equal(true); + expect(response.isItemSelected('4')).to.equal(false); + }); + + it('should expand the selection range when clicking on an item checkbox while holding Shift after un-selecting another item', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1' }, { id: '2' }, { id: '2.1' }, { id: '3' }, { id: '4' }], + }); + + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(true); + expect(response.isItemSelected('2')).to.equal(false); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + expect(response.isItemSelected('4')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('2')); + expect(response.isItemSelected('1')).to.equal(true); + expect(response.isItemSelected('2')).to.equal(true); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + expect(response.isItemSelected('4')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('2')); + expect(response.isItemSelected('1')).to.equal(true); + expect(response.isItemSelected('2')).to.equal(false); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + expect(response.isItemSelected('4')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('3'), { shiftKey: true }); + expect(response.isItemSelected('1')).to.equal(true); + expect(response.isItemSelected('2')).to.equal(true); + expect(response.isItemSelected('2.1')).to.equal(true); + expect(response.isItemSelected('3')).to.equal(true); + expect(response.isItemSelected('4')).to.equal(false); + }); + + it('should not expand the selection range when clicking on a disabled item checkbox then clicking on an item checkbox while holding Shift', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [ + { id: '1' }, + { id: '2', disabled: true }, + { id: '2.1' }, + { id: '3' }, + { id: '4' }, + ], + }); + + fireEvent.click(response.getItemCheckboxInput('2')); + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(false); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + expect(response.isItemSelected('4')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('3'), { shiftKey: true }); + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(false); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + expect(response.isItemSelected('4')).to.equal(false); + }); + + it('should not expand the selection range when clicking on an item checkbox then clicking a disabled item checkbox while holding Shift', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [ + { id: '1' }, + { id: '2' }, + { id: '2.1' }, + { id: '3', disabled: true }, + { id: '4' }, + ], + }); + + fireEvent.click(response.getItemCheckboxInput('2')); + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(true); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + expect(response.isItemSelected('4')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('3'), { shiftKey: true }); + expect(response.isItemSelected('1')).to.equal(false); + expect(response.isItemSelected('2')).to.equal(true); + expect(response.isItemSelected('2.1')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + expect(response.isItemSelected('4')).to.equal(false); + }); + + it('should not select disabled items that are part of the selected range', () => { + const response = render({ + multiSelect: true, + checkboxSelection: true, + items: [{ id: '1' }, { id: '2', disabled: true }, { id: '3' }], + }); + + fireEvent.click(response.getItemCheckboxInput('1')); + expect(response.isItemSelected('1')).to.equal(true); + expect(response.isItemSelected('2')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(false); + + fireEvent.click(response.getItemCheckboxInput('3'), { shiftKey: true }); + expect(response.isItemSelected('1')).to.equal(true); + expect(response.isItemSelected('2')).to.equal(false); + expect(response.isItemSelected('3')).to.equal(true); + }); + }); + }); + describe('aria-multiselectable tree attribute', () => { it('should have the attribute `aria-multiselectable=false if using single select`', () => { const response = render({ diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts index f75e4ffb0800b..1de3cebb122d4 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.ts @@ -8,7 +8,10 @@ import { getLastNavigableItem, getNonDisabledItemsInRange, } from '../../utils/tree'; -import { UseTreeViewSelectionSignature } from './useTreeViewSelection.types'; +import { + UseTreeViewSelectionInstance, + UseTreeViewSelectionSignature, +} from './useTreeViewSelection.types'; import { convertSelectedItemsToArray, getLookupFromArray } from './useTreeViewSelection.utils'; export const useTreeViewSelection: TreeViewPlugin = ({ @@ -71,21 +74,34 @@ export const useTreeViewSelection: TreeViewPlugin const isItemSelected = (itemId: string) => selectedItemsMap.has(itemId); - const selectItem = (event: React.SyntheticEvent, itemId: string, multiple = false) => { + const selectItem: UseTreeViewSelectionInstance['selectItem'] = ( + event, + itemId, + keepExistingSelection, + newValue, + ) => { if (params.disableSelection) { return; } let newSelected: typeof models.selectedItems.value; - if (multiple) { + if (keepExistingSelection) { const cleanSelectedItems = convertSelectedItemsToArray(models.selectedItems.value); - if (instance.isItemSelected(itemId)) { + const isSelectedBefore = instance.isItemSelected(itemId); + if (isSelectedBefore && (newValue === false || newValue == null)) { newSelected = cleanSelectedItems.filter((id) => id !== itemId); - } else { + } else if (!isSelectedBefore && (newValue === true || newValue == null)) { newSelected = [itemId].concat(cleanSelectedItems); + } else { + newSelected = cleanSelectedItems; } } else { - newSelected = params.multiSelect ? [itemId] : itemId; + // eslint-disable-next-line no-lonely-if + if (newValue === false) { + newSelected = params.multiSelect ? [] : null; + } else { + newSelected = params.multiSelect ? [itemId] : itemId; + } } setSelectedItems(event, newSelected); diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts index 83064630cce8b..005ab581ce1ec 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.types.ts @@ -5,10 +5,18 @@ import { UseTreeViewExpansionSignature } from '../useTreeViewExpansion'; export interface UseTreeViewSelectionInstance { isItemSelected: (itemId: string) => boolean; + /** + * Select or deselect an item. + * @param {React.SyntheticEvent} event The event source of the callback. + * @param {string} itemId The id of the item to select or deselect. + * @param {boolean} keepExistingSelection If `true`, don't remove the other selected items. + * @param {boolean | undefined} newValue The new selection status of the item. If not defined, the new state will be the opposite of the current state. + */ selectItem: ( event: React.SyntheticEvent, itemId: string, - keepExistingSelection?: boolean, + keepExistingSelection: boolean, + newValue?: boolean, ) => void; /** * Select all the navigable items in the tree. diff --git a/packages/x-tree-view/src/useTreeItem2/useTreeItem2.ts b/packages/x-tree-view/src/useTreeItem2/useTreeItem2.ts index 2cea91f75fa25..fb73eb8572bf5 100644 --- a/packages/x-tree-view/src/useTreeItem2/useTreeItem2.ts +++ b/packages/x-tree-view/src/useTreeItem2/useTreeItem2.ts @@ -99,12 +99,17 @@ export const useTreeItem2 = (event: React.ChangeEvent & MuiCancellableEvent) => { + (otherHandlers: EventHandlers) => + (event: React.ChangeEvent & MuiCancellableEvent) => { otherHandlers.onChange?.(event); if (event.defaultMuiPrevented) { return; } + if (disableSelection || status.disabled) { + return; + } + interactions.handleCheckboxSelection(event); }; @@ -173,7 +178,7 @@ export const useTreeItem2 = ( const getItemContent = (id: string) => getItemRoot(id).querySelector(`.${treeItemClasses.content}`)!; + const getItemCheckbox = (id: string) => + getItemRoot(id).querySelector(`.${treeItemClasses.checkbox}`)!; + + const getItemCheckboxInput = (id: string) => + getItemCheckbox(id).querySelector(`input`)!; + const getItemLabel = (id: string) => getItemRoot(id).querySelector(`.${treeItemClasses.label}`)!; @@ -58,6 +64,8 @@ const innerDescribeTreeView = ( getFocusedItemId, getItemRoot, getItemContent, + getItemCheckbox, + getItemCheckboxInput, getItemLabel, getItemIconContainer, isItemExpanded, diff --git a/test/utils/tree-view/describeTreeView/describeTreeView.types.ts b/test/utils/tree-view/describeTreeView/describeTreeView.types.ts index ba15ccee9e59e..e53749b4706b8 100644 --- a/test/utils/tree-view/describeTreeView/describeTreeView.types.ts +++ b/test/utils/tree-view/describeTreeView/describeTreeView.types.ts @@ -56,6 +56,18 @@ export interface DescribeTreeViewRendererReturnValue< * @returns {HTMLElement} `content` slot of the item with the given id. */ getItemContent: (id: string) => HTMLElement; + /** + * Returns the `checkbox` slot of the item with the given id. + * @param {string} id The id of the item to retrieve. + * @returns {HTMLElement} `checkbox` slot of the item with the given id. + */ + getItemCheckbox: (id: string) => HTMLElement; + /** + * Returns the input element inside the `checkbox` slot of the item with the given id. + * @param {string} id The id of the item to retrieve. + * @returns {HTMLInputElement} input element inside the `checkbox` slot of the item with the given id. + */ + getItemCheckboxInput: (id: string) => HTMLInputElement; /** * Returns the `label` slot of the item with the given id. * @param {string} id The id of the item to retrieve. From 48d325905a8227a8bab96ad814026a696c94b174 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 24 Apr 2024 14:10:38 +0200 Subject: [PATCH 26/26] Fix --- .../plugins/useTreeViewSelection/useTreeViewSelection.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx index eb018f5f53ed9..63324c7ed7c39 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewSelection/useTreeViewSelection.test.tsx @@ -10,7 +10,7 @@ import { UseTreeViewSelectionSignature } from '@mui/x-tree-view/internals'; */ describeTreeView<[UseTreeViewSelectionSignature]>('useTreeViewSelection plugin', ({ render }) => { describe('model props (selectedItems, defaultSelectedItems, onSelectedItemsChange)', () => { - it('should not select items when no defaulat state and no control state are defined', () => { + it('should not select items when no default state and no control state are defined', () => { const response = render({ items: [{ id: '1' }, { id: '2' }], });