Skip to content

Commit

Permalink
feat: isVisible item handler for NavSection
Browse files Browse the repository at this point in the history
  • Loading branch information
devcatalin committed Sep 13, 2021
1 parent 40212a8 commit 7a8c596
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, {useMemo} from 'react';
import React from 'react';
import {NavSectionItemHandler} from '@models/navsection';
import {useNavSectionItem} from './useNavSectionItem';
import * as S from './styled';

function NavSectionItem<ItemType, ScopeType>(props: {
Expand All @@ -9,18 +10,7 @@ function NavSectionItem<ItemType, ScopeType>(props: {
level: number;
}) {
const {item, scope, handler, level} = props;

const name = useMemo(() => {
return handler.getName(item, scope);
}, [handler, scope, item]);

const isSelected = useMemo(() => {
return Boolean(handler.isSelected && handler.isSelected(item, scope));
}, [handler, scope, item]);

const isHighlighted = useMemo(() => {
return Boolean(handler.isHighlighted && handler.isHighlighted(item, scope));
}, [handler, scope, item]);
const {name, isSelected, isHighlighted} = useNavSectionItem(item, scope, handler);

return (
<S.ItemContainer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,25 @@
import React, {useCallback, useMemo} from 'react';
import React from 'react';
import {NavSection} from '@models/navsection';
import {useNavSection} from './useNavSection';
import NavSectionItem from './NavSectionItem';
import * as S from './styled';

function NavSectionRenderer<ItemType, ScopeType>(props: {navSection: NavSection<ItemType, ScopeType>; level: number}) {
const {navSection, level} = props;
const {name, getItems, getItemsGrouped, useScope, itemHandler, subsections} = navSection;
type NavSectionRendererProps<ItemType, ScopeType> = {
navSection: NavSection<ItemType, ScopeType>;
level: number;
};

const scope = useScope();
function NavSectionRenderer<ItemType, ScopeType>(props: NavSectionRendererProps<ItemType, ScopeType>) {
const {navSection, level} = props;

const items = useMemo(() => {
if (getItems) {
return getItems(scope);
}
return undefined;
}, [scope, getItems]);
const {name, scope, visibleItems, groupedVisibleItems, getItemIdentifier, itemHandler, subsections} = useNavSection<
ItemType,
ScopeType
>(navSection);

const groupedItems = useMemo(() => {
if (getItemsGrouped) {
return getItemsGrouped(scope);
}
return undefined;
}, [scope, getItemsGrouped]);

const getItemIdentifier = useCallback(
(item: ItemType) => {
if (!itemHandler) {
return null;
}
return itemHandler.getIdentifier(item, scope);
},
[scope, itemHandler]
);
if (!subsections && !groupedVisibleItems && visibleItems.length === 0) {
return null;
}

return (
<>
Expand All @@ -41,8 +29,7 @@ function NavSectionRenderer<ItemType, ScopeType>(props: {navSection: NavSection<
</S.Section.Name>
</S.Section.Container>
{itemHandler &&
items &&
items.map(item => (
visibleItems.map(item => (
<NavSectionItem<ItemType, ScopeType>
key={getItemIdentifier(item)}
item={item}
Expand All @@ -52,8 +39,8 @@ function NavSectionRenderer<ItemType, ScopeType>(props: {navSection: NavSection<
/>
))}
{itemHandler &&
groupedItems &&
Object.entries(groupedItems).map(([groupName, groupItems]) => (
groupedVisibleItems &&
Object.entries(groupedVisibleItems).map(([groupName, groupItems]) => (
<React.Fragment key={groupName}>
<S.Section.Container isSelected={false} isHighlighted={false} style={{color: 'red'}}>
<S.Section.Name isSelected={false} isHighlighted={false} level={level + 1}>
Expand All @@ -72,7 +59,9 @@ function NavSectionRenderer<ItemType, ScopeType>(props: {navSection: NavSection<
</React.Fragment>
))}
{subsections &&
subsections.map(child => <NavSectionRenderer key={child.name} navSection={child} level={level + 1} />)}
subsections.map(child => (
<NavSectionRenderer<ItemType, ScopeType> key={child.name} navSection={child} level={level + 1} />
))}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {useMemo, useCallback} from 'react';
import {NavSection} from '@models/navsection';

export function useNavSection<ItemType, ScopeType>(navSection: NavSection<ItemType, ScopeType>) {
const {name, getItems, getItemsGrouped, useScope, itemHandler, subsections} = navSection;

const scope = useScope();

const items = useMemo(() => {
if (getItems) {
return getItems(scope);
}
return undefined;
}, [scope, getItems]);

const groupedItems = useMemo(() => {
if (getItemsGrouped) {
return getItemsGrouped(scope);
}
return undefined;
}, [scope, getItemsGrouped]);

const getItemIdentifier = useCallback(
(item: ItemType) => {
if (!itemHandler) {
return null;
}
return itemHandler.getIdentifier(item, scope);
},
[scope, itemHandler]
);

const visibleItems = useMemo(() => {
if (!items) {
return [];
}
const isVisible = itemHandler?.isVisible;
if (!isVisible) {
return items;
}
return items.filter(item => isVisible(item, scope));
}, [scope, itemHandler, items]);

const groupedVisibleItems = useMemo<Record<string, ItemType[]> | undefined>(() => {
if (!groupedItems) {
return undefined;
}
const isVisible = itemHandler?.isVisible;
if (!isVisible) {
return groupedItems;
}
return Object.fromEntries(
Object.entries(([groupName, groupItems]: [string, ItemType[]]) => {
return [groupName, groupItems.filter(item => isVisible(item, scope))];
})
);
}, [scope, itemHandler, groupedItems]);

return {name, scope, subsections, visibleItems, groupedVisibleItems, getItemIdentifier, itemHandler};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {useMemo} from 'react';
import {NavSectionItemHandler} from '@models/navsection';

export function useNavSectionItem<ItemType, ScopeType>(
item: ItemType,
scope: ScopeType,
handler: NavSectionItemHandler<ItemType, ScopeType>
) {
const name = useMemo(() => {
return handler.getName(item, scope);
}, [handler, scope, item]);

const isSelected = useMemo(() => {
return Boolean(handler.isSelected && handler.isSelected(item, scope));
}, [handler, scope, item]);

const isHighlighted = useMemo(() => {
return Boolean(handler.isHighlighted && handler.isHighlighted(item, scope));
}, [handler, scope, item]);

return {name, isSelected, isHighlighted};
}
1 change: 1 addition & 0 deletions src/models/navsection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface NavSectionItemHandler<ItemType, ScopeType> {
getIdentifier: <S extends ScopeType>(item: ItemType, scope: S) => string;
isSelected?: <S extends ScopeType>(item: ItemType, scope: S) => boolean;
isHighlighted?: <S extends ScopeType>(item: ItemType, scope: S) => boolean;
isVisible?: <S extends ScopeType>(item: ItemType, scope: S) => boolean;
onClick?: <S extends ScopeType>(item: ItemType, scope: S) => void;
}

Expand Down

0 comments on commit 7a8c596

Please sign in to comment.