Skip to content

Commit

Permalink
[TreeView] Make each plugin responsible for its context value (#11623)
Browse files Browse the repository at this point in the history
  • Loading branch information
flaviendelangle authored Jan 12, 2024
1 parent fed0300 commit 58d50ad
Show file tree
Hide file tree
Showing 26 changed files with 122 additions and 82 deletions.
2 changes: 2 additions & 0 deletions docs/data/tree-view/headless/HeadlessTreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 5 additions & 2 deletions packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue<any> = {
const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue<DefaultTreeViewPlugins> = {
instance: {
isNodeExpandable: () => false,
isNodeExpanded: () => false,
Expand All @@ -26,14 +27,16 @@ const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue<any> = {
mapFirstCharFromJSX: () => {},
} as any,
runItemPlugins: ({ props, ref }) => ({ props, ref, wrapItem: (children) => children }),
multiSelect: false,
disabledItemsFocusable: false,
icons: {
defaultCollapseIcon: null,
defaultExpandIcon: null,
defaultParentIcon: null,
defaultEndIcon: null,
},
selection: {
multiSelect: false,
},
};

describe('<TreeItem />', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/x-tree-view/src/TreeItem/TreeItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export const TreeItem = React.forwardRef(function TreeItem(
const {
icons: contextIcons,
runItemPlugins,
multiSelect,
selection: { multiSelect },
disabledItemsFocusable,
instance,
} = useTreeViewContext<DefaultTreeViewPlugins>();
Expand Down
5 changes: 4 additions & 1 deletion packages/x-tree-view/src/TreeItem/useTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewCon
import { DefaultTreeViewPlugins } from '../internals/plugins';

export function useTreeItem(nodeId: string) {
const { instance, multiSelect } = useTreeViewContext<DefaultTreeViewPlugins>();
const {
instance,
selection: { multiSelect },
} = useTreeViewContext<DefaultTreeViewPlugins>();

const expandable = instance.isNodeExpandable(nodeId);
const expanded = instance.isNodeExpanded(nodeId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import * as React from 'react';
import {
MergePluginsProperty,
TreeViewAnyPluginSignature,
TreeViewInstance,
TreeViewItemPluginOptions,
TreeViewItemPluginResponse,
} from '../models';

export interface TreeViewContextValue<TPlugins extends readonly TreeViewAnyPluginSignature[]> {
instance: TreeViewInstance<TPlugins>;
runItemPlugins: (options: TreeViewItemPluginOptions) => Required<TreeViewItemPluginResponse>;
multiSelect: boolean;
disabledItemsFocusable: boolean;
icons: {
defaultCollapseIcon: React.ReactNode;
defaultExpandIcon: React.ReactNode;
defaultParentIcon: React.ReactNode;
defaultEndIcon: React.ReactNode;
export type TreeViewContextValue<TPlugins extends readonly TreeViewAnyPluginSignature[]> =
MergePluginsProperty<TPlugins, 'contextValue'> & {
instance: TreeViewInstance<TPlugins>;
runItemPlugins: (options: TreeViewItemPluginOptions) => Required<TreeViewItemPluginResponse>;
};
}

export interface TreeViewProviderProps<TPlugins extends readonly TreeViewAnyPluginSignature[]> {
value: TreeViewContextValue<TPlugins>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type UseTreeViewInstanceEventsSignature = TreeViewPluginSignature<
UseTreeViewInstanceEventsInstance,
{},
{},
{},
never,
[]
>;
1 change: 1 addition & 0 deletions packages/x-tree-view/src/internals/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { DefaultTreeViewPlugins } from './plugins';
11 changes: 10 additions & 1 deletion packages/x-tree-view/src/internals/models/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TreeViewAnyPluginSignature, TreeViewPlugin } from './plugin';
import type { TreeViewAnyPluginSignature, TreeViewPlugin } from './plugin';

export type DefaultizedProps<
P extends {},
Expand All @@ -8,6 +8,14 @@ export type DefaultizedProps<
Required<Pick<P, RequiredProps>> &
AdditionalProps;

type IsAny<T> = 0 extends 1 & T ? true : false;

export type OptionalIfEmpty<A extends string, B> = keyof B extends never
? Partial<Record<A, B>>
: IsAny<B> extends true
? Partial<Record<A, B>>
: Record<A, B>;

export type MergePluginsProperty<
TPlugins extends readonly any[],
TProperty extends keyof TreeViewAnyPluginSignature,
Expand All @@ -30,6 +38,7 @@ export interface MergePlugins<TPlugins extends readonly any[]> {
params: MergePluginsProperty<TPlugins, 'params'>;
defaultizedParams: MergePluginsProperty<TPlugins, 'defaultizedParams'>;
dependantPlugins: MergePluginsProperty<TPlugins, 'dependantPlugins'>;
contextValue: MergePluginsProperty<TPlugins, 'contextValue'>;
events: MergePluginsProperty<TPlugins, 'events'>;
models: MergePluginsProperty<TPlugins, 'models'>;
}
13 changes: 7 additions & 6 deletions packages/x-tree-view/src/internals/models/plugin.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -23,19 +22,19 @@ type TreeViewModelsInitializer<TSignature extends TreeViewAnyPluginSignature> =
};
};

interface TreeViewResponse {
type TreeViewResponse<TSignature extends TreeViewAnyPluginSignature> = {
getRootProps?: <TOther extends EventHandlers = {}>(
otherHandlers: TOther,
) => React.HTMLAttributes<HTMLUListElement>;
contextValue?: TreeViewContextValue<any>;
}
} & OptionalIfEmpty<'contextValue', TSignature['contextValue']>;

export type TreeViewPluginSignature<
TParams extends {},
TDefaultizedParams extends {},
TInstance extends {},
TEvents extends { [key in keyof TEvents]: TreeViewEventLookupElement },
TState extends {},
TContextValue extends {},
TModelNames extends keyof TDefaultizedParams,
TDependantPlugins extends readonly TreeViewAnyPluginSignature[],
> = {
Expand All @@ -49,6 +48,7 @@ export type TreeViewPluginSignature<
>;
};
events: TEvents;
contextValue: TContextValue;
dependantPlugins: TDependantPlugins;
};

Expand All @@ -59,6 +59,7 @@ export type TreeViewAnyPluginSignature = {
defaultizedParams: any;
dependantPlugins: any;
events: any;
contextValue: any;
models: any;
};

Expand Down Expand Up @@ -119,7 +120,7 @@ export type TreeViewItemPlugin = (
) => void | TreeViewItemPluginResponse;

export type TreeViewPlugin<TSignature extends TreeViewAnyPluginSignature> = {
(options: TreeViewPluginOptions<TSignature>): void | TreeViewResponse;
(options: TreeViewPluginOptions<TSignature>): void | TreeViewResponse<TSignature>;
getDefaultizedParams?: (
params: TreeViewUsedParams<TSignature>,
) => TSignature['defaultizedParams'];
Expand Down
9 changes: 3 additions & 6 deletions packages/x-tree-view/src/internals/plugins/defaultPlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -17,7 +14,7 @@ export const DEFAULT_TREE_VIEW_PLUGINS = [
useTreeViewSelection,
useTreeViewFocus,
useTreeViewKeyboardNavigation,
useTreeViewContextValueBuilder,
useTreeViewIcons,
] as const;

export type DefaultTreeViewPlugins = ConvertPluginsIntoSignatures<typeof DEFAULT_TREE_VIEW_PLUGINS>;
Expand All @@ -29,4 +26,4 @@ export interface DefaultTreeViewPluginParameters<R extends {}, Multiple extends
UseTreeViewExpansionParameters,
UseTreeViewFocusParameters,
UseTreeViewSelectionParameters<Multiple>,
UseTreeViewContextValueBuilderParameters {}
UseTreeViewIconsParameters {}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export type UseTreeViewExpansionSignature = TreeViewPluginSignature<
UseTreeViewExpansionInstance,
{},
{},
{},
'expandedNodes',
[UseTreeViewNodesSignature]
>;
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,6 @@ export const useTreeViewFocus: TreeViewPlugin<UseTreeViewFocusSignature> = ({

useTreeViewFocus.getInitialState = () => ({ focusedNodeId: null });

useTreeViewFocus.getDefaultizedParams = (params) => ({
...params,
disabledItemsFocusable: params.disabledItemsFocusable ?? false,
});

useTreeViewFocus.params = {
onNodeFocus: true,
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type UseTreeViewFocusSignature = TreeViewPluginSignature<
UseTreeViewFocusInstance,
{},
UseTreeViewFocusState,
{},
never,
[
UseTreeViewIdSignature,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export { useTreeViewIcons } from './useTreeViewIcons';
export type {
UseTreeViewIconsSignature,
UseTreeViewIconsParameters,
UseTreeViewIconsDefaultizedParameters,
} from './useTreeViewIcons.types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { TreeViewPlugin } from '../../models';
import { UseTreeViewIconsSignature } from './useTreeViewIcons.types';

export const useTreeViewIcons: TreeViewPlugin<UseTreeViewIconsSignature> = ({ params }) => {
return {
contextValue: {
icons: {
defaultCollapseIcon: params.defaultCollapseIcon,
defaultEndIcon: params.defaultEndIcon,
defaultExpandIcon: params.defaultExpandIcon,
defaultParentIcon: params.defaultParentIcon,
},
},
};
};

useTreeViewIcons.params = {
defaultCollapseIcon: true,
defaultEndIcon: true,
defaultExpandIcon: true,
defaultParentIcon: true,
};
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -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]
>;
Original file line number Diff line number Diff line change
Expand Up @@ -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,
[]
>;
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type UseTreeViewJSXNodesSignature = TreeViewPluginSignature<
UseTreeViewNodesInstance,
{},
{},
{},
never,
[UseTreeViewNodesSignature, UseTreeViewKeyboardNavigationSignature]
>;
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type UseTreeViewKeyboardNavigationSignature = TreeViewPluginSignature<
UseTreeViewKeyboardNavigationInstance,
{},
{},
{},
never,
[
UseTreeViewNodesSignature,
Expand Down
Loading

0 comments on commit 58d50ad

Please sign in to comment.