Skip to content

Commit

Permalink
Add doc example
Browse files Browse the repository at this point in the history
  • Loading branch information
flaviendelangle committed Aug 30, 2023
1 parent d91f391 commit 4cd98b0
Show file tree
Hide file tree
Showing 12 changed files with 366 additions and 54 deletions.
126 changes: 126 additions & 0 deletions docs/data/tree-view/headless/HeadlessTreeView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import * as React from 'react';
import { styled, useThemeProps } from '@mui/material/styles';
import { useSlotProps } from '@mui/base/utils';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
// eslint-disable-next-line
import { DEFAULT_TREE_VIEW_PLUGINS } from '@mui/x-tree-view/internals/plugins/defaultPlugins';
// eslint-disable-next-line

import { useTreeView } from '@mui/x-tree-view/internals/useTreeView';
import { TreeViewProvider } from '@mui/x-tree-view/internals/TreeViewProvider';

import { TreeItem } from '@mui/x-tree-view/TreeItem';

const useTreeViewLogExpanded = ({ params, models }) => {
React.useEffect(() => {
if (params.log) {
const log = console.log;
log('Expanded items: ', models.expanded.value);
}
}, [models.expanded.value, params.log]);
};

// Sets the default value of this plugin parameters.
useTreeViewLogExpanded.getDefaultizedParams = (params) => ({
...params,
log: false,
});

// This could be exported from the package in the future
const TreeViewRoot = styled('ul', {
name: 'MuiTreeView',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
})({
padding: 0,
margin: 0,
listStyle: 'none',
outline: 0,
});

const plugins = [...DEFAULT_TREE_VIEW_PLUGINS, useTreeViewLogExpanded];

function TreeView(inProps) {
const themeProps = useThemeProps({ props: inProps, name: 'MuiTreeView' });
const ownerState = themeProps;

const {
// Headless implementation
disabledItemsFocusable,
expanded,
defaultExpanded,
onNodeToggle,
onNodeFocus,
disableSelection,
defaultSelected,
selected,
multiSelect,
onNodeSelect,
id,
defaultCollapseIcon,
defaultEndIcon,
defaultExpandIcon,
defaultParentIcon,
log,
// Component implementation
children,
...other
} = themeProps;

const { getRootProps, contextValue } = useTreeView({
disabledItemsFocusable,
expanded,
defaultExpanded,
onNodeToggle,
onNodeFocus,
disableSelection,
defaultSelected,
selected,
multiSelect,
onNodeSelect,
id,
defaultCollapseIcon,
defaultEndIcon,
defaultExpandIcon,
defaultParentIcon,
log,
plugins,
});

const rootProps = useSlotProps({
elementType: TreeViewRoot,
externalSlotProps: {},
externalForwardedProps: other,
getSlotProps: getRootProps,
ownerState,
});

return (
<TreeViewProvider value={contextValue}>
<TreeViewRoot {...rootProps}>{children}</TreeViewRoot>
</TreeViewProvider>
);
}

export default function HeadlessTreeView() {
return (
<TreeView
log
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}
>
<TreeItem nodeId="1" label="Applications">
<TreeItem nodeId="2" label="Calendar" />
</TreeItem>
<TreeItem nodeId="5" label="Documents">
<TreeItem nodeId="10" label="OSS" />
<TreeItem nodeId="6" label="MUI">
<TreeItem nodeId="8" label="index.js" />
</TreeItem>
</TreeItem>
</TreeView>
);
}
166 changes: 166 additions & 0 deletions docs/data/tree-view/headless/HeadlessTreeView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import * as React from 'react';
import { styled, useThemeProps } from '@mui/material/styles';
import { useSlotProps } from '@mui/base/utils';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
// eslint-disable-next-line
import {
DefaultTreeViewPluginParameters,
DEFAULT_TREE_VIEW_PLUGINS,
} from '@mui/x-tree-view/internals/plugins/defaultPlugins';
// eslint-disable-next-line
import { UseTreeViewExpansionSignature } from '@mui/x-tree-view/internals/plugins/useTreeViewExpansion';
import { useTreeView } from '@mui/x-tree-view/internals/useTreeView';
import { TreeViewProvider } from '@mui/x-tree-view/internals/TreeViewProvider';
import { TreeViewPropsBase } from '@mui/x-tree-view/TreeView';
import { TreeItem } from '@mui/x-tree-view/TreeItem';
import {
TreeViewPlugin,
TreeViewPluginSignature,
} from '@mui/x-tree-view/internals/models';

interface TreeViewLogExpandedParameters {
log?: boolean;
}

interface TreeViewLogExpandedDefaultizedParameters {
log: boolean;
}

type TreeViewLogExpandedSignature = TreeViewPluginSignature<
// The parameters of this plugin as they are passed to `usedTreeView`
TreeViewLogExpandedParameters,
// The parameters of this plugin as they are passed to the plugin after calling `plugin.getDefaultizedParams`
TreeViewLogExpandedDefaultizedParameters,
// Instance methods of this plugin: we don't have any
{},
// State of this plugin: we don't have any
{},
// Models of this plugin: we don't have any
never,
// Dependencies of this plugin (we need the expansion plugin to access its model)
[UseTreeViewExpansionSignature]
>;

const useTreeViewLogExpanded: TreeViewPlugin<TreeViewLogExpandedSignature> = ({
params,
models,
}) => {
React.useEffect(() => {
if (params.log) {
const log = console.log;
log('Expanded items: ', models.expanded.value);
}
}, [models.expanded.value, params.log]);
};

// Sets the default value of this plugin parameters.
useTreeViewLogExpanded.getDefaultizedParams = (params) => ({
...params,
log: false,
});

// This could be exported from the package in the future
const TreeViewRoot = styled('ul', {
name: 'MuiTreeView',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
})<{ ownerState: TreeViewProps<any> }>({
padding: 0,
margin: 0,
listStyle: 'none',
outline: 0,
});

export interface TreeViewProps<Multiple extends boolean | undefined>
extends DefaultTreeViewPluginParameters<Multiple>,
TreeViewLogExpandedParameters,
TreeViewPropsBase {}

const plugins = [...DEFAULT_TREE_VIEW_PLUGINS, useTreeViewLogExpanded] as const;

function TreeView<Multiple extends boolean | undefined>(
inProps: TreeViewProps<Multiple>,
) {
const themeProps = useThemeProps({ props: inProps, name: 'MuiTreeView' });
const ownerState = themeProps as TreeViewProps<any>;

const {
// Headless implementation
disabledItemsFocusable,
expanded,
defaultExpanded,
onNodeToggle,
onNodeFocus,
disableSelection,
defaultSelected,
selected,
multiSelect,
onNodeSelect,
id,
defaultCollapseIcon,
defaultEndIcon,
defaultExpandIcon,
defaultParentIcon,
log,
// Component implementation
children,
...other
} = themeProps as TreeViewProps<any>;

const { getRootProps, contextValue } = useTreeView({
disabledItemsFocusable,
expanded,
defaultExpanded,
onNodeToggle,
onNodeFocus,
disableSelection,
defaultSelected,
selected,
multiSelect,
onNodeSelect,
id,
defaultCollapseIcon,
defaultEndIcon,
defaultExpandIcon,
defaultParentIcon,
log,
plugins,
});

const rootProps = useSlotProps({
elementType: TreeViewRoot,
externalSlotProps: {},
externalForwardedProps: other,
getSlotProps: getRootProps,
ownerState,
});

return (
<TreeViewProvider value={contextValue}>
<TreeViewRoot {...rootProps}>{children}</TreeViewRoot>
</TreeViewProvider>
);
}

export default function HeadlessTreeView() {
return (
<TreeView
log
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}
>
<TreeItem nodeId="1" label="Applications">
<TreeItem nodeId="2" label="Calendar" />
</TreeItem>
<TreeItem nodeId="5" label="Documents">
<TreeItem nodeId="10" label="OSS" />
<TreeItem nodeId="6" label="MUI">
<TreeItem nodeId="8" label="index.js" />
</TreeItem>
</TreeItem>
</TreeView>
);
}
14 changes: 14 additions & 0 deletions docs/data/tree-view/headless/headless.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
productId: material-ui
title: Tree View Headless usage
githubLabel: 'component: tree view'
packageName: '@mui/x-tree-view'
---

# Tree View - Headless

<p class="description">Experiment with headless tree view</p>

Open the console and interact with the tree view to see the expanded items being logged:

{{"demo": "HeadlessTreeView.js"}}
7 changes: 7 additions & 0 deletions docs/pages/x/react-tree-view/experiments/headless.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
import * as pageProps from 'docsx/data/tree-view/headless/headless.md?@mui/markdown';

export default function Page() {
return <MarkdownDocs {...pageProps} />;
}
13 changes: 6 additions & 7 deletions packages/x-tree-view/src/internals/models/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import { TreeViewModel } from './treeView';
import type { TreeViewContextValue } from '../TreeViewProvider';
import type { MergePluginsProperty } from './helpers';

export interface TreeViewPluginParams<TSignature extends TreeViewAnyPluginSignature> {
export interface TreeViewPluginOptions<TSignature extends TreeViewAnyPluginSignature> {
instance: TreeViewUsedInstance<TSignature>;
// TODO: Rename 'params'
props: TreeViewUsedDefaultizedParams<TSignature>;
params: TreeViewUsedDefaultizedParams<TSignature>;
state: TreeViewUsedState<TSignature>;
models: TreeViewUsedModels<TSignature>;
setState: React.Dispatch<React.SetStateAction<TreeViewUsedState<TSignature>>>;
Expand Down Expand Up @@ -36,16 +35,16 @@ export type TreeViewPluginSignature<
TModelNames extends keyof TDefaultizedParams,
TDependantPlugins extends readonly TreeViewAnyPluginSignature[],
> = {
state: TState;
instance: TInstance;
params: TParams;
defaultizedParams: TDefaultizedParams;
dependantPlugins: TDependantPlugins;
instance: TInstance;
state: TState;
models: {
[TControlled in TModelNames]-?: TreeViewModel<
Exclude<TDefaultizedParams[TControlled], undefined>
>;
};
dependantPlugins: TDependantPlugins;
};

export type TreeViewAnyPluginSignature = {
Expand Down Expand Up @@ -74,7 +73,7 @@ export type TreeViewUsedModels<TSignature extends TreeViewAnyPluginSignature> =
TSignature['models'] & MergePluginsProperty<TSignature['dependantPlugins'], 'models'>;

export type TreeViewPlugin<TSignature extends TreeViewAnyPluginSignature> = {
(options: TreeViewPluginParams<TSignature>): void | TreeViewResponse;
(options: TreeViewPluginOptions<TSignature>): void | TreeViewResponse;
getDefaultizedParams?: (
params: TreeViewUsedParams<TSignature>,
) => TSignature['defaultizedParams'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { UseTreeViewContextValueBuilderSignature } from './useTreeViewContextVal

export const useTreeViewContextValueBuilder: TreeViewPlugin<
UseTreeViewContextValueBuilderSignature
> = ({ instance, props }) => {
const treeId = useId(props.id);
> = ({ instance, params }) => {
const treeId = useId(params.id);

return {
getRootProps: () => ({
Expand All @@ -14,13 +14,13 @@ export const useTreeViewContextValueBuilder: TreeViewPlugin<
contextValue: {
treeId,
instance: instance as TreeViewInstance<any>,
multiSelect: props.multiSelect,
disabledItemsFocusable: props.disabledItemsFocusable,
multiSelect: params.multiSelect,
disabledItemsFocusable: params.disabledItemsFocusable,
icons: {
defaultCollapseIcon: props.defaultCollapseIcon,
defaultEndIcon: props.defaultEndIcon,
defaultExpandIcon: props.defaultExpandIcon,
defaultParentIcon: props.defaultParentIcon,
defaultCollapseIcon: params.defaultCollapseIcon,
defaultEndIcon: params.defaultEndIcon,
defaultExpandIcon: params.defaultExpandIcon,
defaultParentIcon: params.defaultParentIcon,
},
},
};
Expand Down
Loading

0 comments on commit 4cd98b0

Please sign in to comment.