Skip to content

Commit

Permalink
feat: split AsideHeader to compound components
Browse files Browse the repository at this point in the history
  • Loading branch information
ldrv565 committed Oct 24, 2023
1 parent b498557 commit 5bf365f
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 47 deletions.
4 changes: 4 additions & 0 deletions src/components/AsideHeader/AsideHeader.scss
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ $block: '.#{variables.$ns}aside-header';
flex-direction: row;
}

&_reverse #{$block}__pane-container {
flex-direction: row-reverse;
}

&__content {
width: calc(100% - var(--gn-aside-header-size));
z-index: 95;
Expand Down
69 changes: 28 additions & 41 deletions src/components/AsideHeader/AsideHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,31 @@
import React, {useMemo} from 'react';
import React from 'react';

import {Content} from '../Content';

import {AsideHeaderContextProvider, AsideHeaderInnerContextProvider} from './AsideHeaderContext';
import {AsideHeaderProps} from './types';
import {PageLayout} from './PageLayout/PageLayout';
import {PageLayoutAside} from './PageLayout/PageLayoutAside';

import {FirstPanel} from './components';
import {b} from './utils';

import './AsideHeader.scss';
import {ASIDE_HEADER_COMPACT_WIDTH, ASIDE_HEADER_EXPANDED_WIDTH} from '../constants';
import {useAsideHeaderInnerContextValue} from './useAsideHeaderInnerContextValue';

export const AsideHeader = React.forwardRef<HTMLDivElement, AsideHeaderProps>((props, ref) => {
const {className, compact} = props;

const size = compact ? ASIDE_HEADER_COMPACT_WIDTH : ASIDE_HEADER_EXPANDED_WIDTH;
const asideHeaderContextValue = useMemo(() => ({size, compact}), [compact, size]);
const asideHeaderInnerContextValue = useAsideHeaderInnerContextValue({...props, size});
return (
<AsideHeaderContextProvider value={asideHeaderContextValue}>
<AsideHeaderInnerContextProvider value={asideHeaderInnerContextValue}>
<div
className={b({compact}, className)}
style={{
...({'--gn-aside-header-size': `${size}px`} as React.CSSProperties),
}}
>
<div className={b('pane-container')}>
{/* First Panel */}
<FirstPanel ref={ref} />
{/* Second Panel */}
<Content
size={size}
renderContent={props.renderContent}
className={b('content')}
/>
</div>
</div>
</AsideHeaderInnerContextProvider>
</AsideHeaderContextProvider>
);
});
/**
* Simply usage of AsideHeader:
* @example
* <AsideHeader renderContent={renderContent} {...props} />
*
* Advanced usage of AsideHeader:
* @example
* <PageLayout reverse >
* <PageLayout.Content>
* <Content />
* </PageLayout.Content>
*
* <PageLayoutAside {...props} />
* </PageLayout>
*/
export const AsideHeader = React.forwardRef<HTMLDivElement, AsideHeaderProps>(
({compact, className, ...props}, ref) => {
return (
<PageLayout compact={compact} className={className}>
<PageLayoutAside ref={ref} {...props} />
<PageLayout.Content renderContent={props.renderContent} />
</PageLayout>
);
},
);
3 changes: 1 addition & 2 deletions src/components/AsideHeader/AsideHeaderContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {AsideHeaderInnerProps} from './types';
export interface AsideHeaderInnerContextType extends AsideHeaderInnerProps {
menuItems: MenuItem[];
allPagesIsAvailable: boolean;
size: number;
onItemClick: (
item: MenuItem,
collapsed: boolean,
Expand All @@ -30,7 +29,7 @@ export const useAsideHeaderInnerContext = (): AsideHeaderInnerContextType => {
};

export interface AsideHeaderContextType {
compact?: boolean;
compact: boolean;
size: number;
}

Expand Down
50 changes: 50 additions & 0 deletions src/components/AsideHeader/PageLayout/PageLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, {PropsWithChildren, useMemo} from 'react';
import {AsideHeaderContextProvider, useAsideHeaderContext} from '../AsideHeaderContext';
import {Content, ContentProps} from '../../Content';
import {ASIDE_HEADER_COMPACT_WIDTH, ASIDE_HEADER_EXPANDED_WIDTH} from '../../constants';
import {PageLayoutProps} from '../types';
import {b} from '../utils';

import '../AsideHeader.scss';

const PageLayout = ({
compact,
reverse,
className,
children,
}: PropsWithChildren<PageLayoutProps> & {
reverse?: boolean;
}) => {
const size = compact ? ASIDE_HEADER_COMPACT_WIDTH : ASIDE_HEADER_EXPANDED_WIDTH;
const asideHeaderContextValue = useMemo(() => ({size, compact}), [compact, size]);

return (
<AsideHeaderContextProvider value={asideHeaderContextValue}>
<div
className={b({compact, reverse}, className)}
style={{
...({'--gn-aside-header-size': `${size}px`} as React.CSSProperties),
}}
>
<div className={b('pane-container')}>{children}</div>
</div>
</AsideHeaderContextProvider>
);
};

const ConnectedContent: React.FC<Pick<ContentProps, 'renderContent'>> = ({
children,
renderContent,
}) => {
const {size} = useAsideHeaderContext();

return (
<Content size={size} className={b('content')} renderContent={renderContent}>
{children}
</Content>
);
};

PageLayout.Content = ConnectedContent;

export {PageLayout};
19 changes: 19 additions & 0 deletions src/components/AsideHeader/PageLayout/PageLayoutAside.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import {FirstPanel} from '../components';
import {useAsideHeaderInnerContextValue} from '../useAsideHeaderInnerContextValue';
import {AsideHeaderInnerContextProvider, useAsideHeaderContext} from '../AsideHeaderContext';
import {AsideHeaderProps} from '../types';

type Props = Omit<AsideHeaderProps, 'compact' | 'size'>;

export const PageLayoutAside = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
const {size, compact} = useAsideHeaderContext();

const asideHeaderInnerContextValue = useAsideHeaderInnerContextValue({size, compact, ...props});

return (
<AsideHeaderInnerContextProvider value={asideHeaderInnerContextValue}>
<FirstPanel ref={ref} />
</AsideHeaderInnerContextProvider>
);
});
33 changes: 33 additions & 0 deletions src/components/AsideHeader/__stories__/AsideHeader.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import type {Meta, StoryFn} from '@storybook/react';

import {AsideHeader} from '../AsideHeader';
import {AsideHeaderShowcase} from './AsideHeaderShowcase';
import {PageLayout} from '../PageLayout/PageLayout';
import {PageLayoutAside} from '../PageLayout/PageLayoutAside';
import logoIcon from '../../../../.storybook/assets/logo.svg';
import {menuItemsShowcase} from './moc';

export default {
title: 'components/AsideHeader',
Expand All @@ -25,3 +29,32 @@ MultipleTooltip.args = {
multipleTooltip: true,
initialCompact: true,
};

const AdvancedUsageTemplate: StoryFn = (args) => {
const [compact, setCompact] = React.useState(args.initialCompact);

return (
<PageLayout reverse compact={compact}>
<PageLayout.Content>PageContent</PageLayout.Content>
<PageLayoutAside
headerDecoration
menuItems={menuItemsShowcase}
logo={{
text: 'Service',
icon: logoIcon,
href: '#',
onClick: () => alert('click on logo'),
}}
onChangeCompact={setCompact}
{...args}
/>
</PageLayout>
);
};

export const AdvancedUsage = AdvancedUsageTemplate.bind({});

AdvancedUsage.args = {
multipleTooltip: false,
initialCompact: true,
};
14 changes: 12 additions & 2 deletions src/components/AsideHeader/types.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import {RenderContentType} from '../Content';
import {DrawerItemProps} from '../Drawer/Drawer';
import {LogoProps, MenuItem, SubheaderMenuItem, OpenModalSubscriber} from '../types';
import {AsideHeaderContextType} from './AsideHeaderContext';

export interface PageLayoutProps {
compact: boolean;
className?: string;
}

export interface AsideHeaderGeneralProps {
logo: LogoProps;
compact: boolean;
multipleTooltip?: boolean;
reverse?: boolean;
className?: string;
collapseTitle?: string;
expandTitle?: string;
Expand All @@ -29,9 +35,13 @@ export interface AsideHeaderDefaultProps {
headerDecoration?: boolean;
}

export type AsideHeaderInnerProps = AsideHeaderGeneralProps & AsideHeaderDefaultProps;
export type AsideHeaderInnerProps = AsideHeaderGeneralProps &
AsideHeaderDefaultProps &
AsideHeaderContextType;

export interface AsideHeaderProps
extends AsideHeaderGeneralProps,
PageLayoutProps,
Partial<AsideHeaderDefaultProps> {}

export enum InnerPanels {
Expand Down
7 changes: 5 additions & 2 deletions src/components/Content/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react';

export type RenderContentType = (data: {size: number}) => React.ReactNode;

interface ContentProps {
export interface ContentProps {
size: number;
className?: string;
cssSizeVariableName?: string;
Expand All @@ -27,14 +27,17 @@ export const Content: React.FC<ContentProps> = ({
className,
cssSizeVariableName = '--gn-aside-header-size',
renderContent,
children,
}) => {
return (
<div
className={className}
style={{...({[cssSizeVariableName]: `${size}px`} as React.CSSProperties)}}
>
{typeof renderContent === 'function' && (
{typeof renderContent === 'function' ? (
<RenderContent size={size} renderContent={renderContent} />
) : (
children
)}
</div>
);
Expand Down

0 comments on commit 5bf365f

Please sign in to comment.