Skip to content

Commit 594038d

Browse files
author
Luke Bowerman
authored
fix(NavList): Properly style Trees within NavList (#2338)
Also addresses issue where non-StyledIcon wouldn't receive proper gap within ListItem
1 parent 34c653b commit 594038d

File tree

14 files changed

+105
-62
lines changed

14 files changed

+105
-62
lines changed

packages/components/src/Form/Inputs/Select/SelectOptions.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ const OptionLayout = ({ option, ...rest }: OptionLayoutProps) => {
109109
const { hasIcons } = useContext(SelectOptionsContext)
110110
const { indicatorPropRef } = useContext(ComboboxContext)
111111
const iconPlaceholder = hasIcons ? (
112-
<IconPlaceholder size="small" data-testid="option-icon-placeholder" />
112+
<IconPlaceholder
113+
mr="xsmall"
114+
size="small"
115+
data-testid="option-icon-placeholder"
116+
/>
113117
) : undefined
114118

115119
const indicator = option.icon ? (

packages/components/src/Icon/IconPlaceholder.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,9 @@ export interface IconPlaceholderProps
3838
SizeProps,
3939
SpaceProps {}
4040

41-
export const IconPlaceholder = styled.div.attrs<IconPlaceholderProps>(
42-
({ mr = 'xsmall' }) => ({
43-
'aria-hidden': true,
44-
mr,
45-
})
46-
)<IconPlaceholderProps>`
41+
export const IconPlaceholder = styled.div.attrs<IconPlaceholderProps>(() => ({
42+
'aria-hidden': true,
43+
}))<IconPlaceholderProps>`
4744
${size}
4845
${space}
4946
`

packages/components/src/List/ListItemLayout.tsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const ListItemLayoutInternal: FC<ListItemLayoutProps> = ({
5656
}) => {
5757
const content = (
5858
<>
59-
{icon}
59+
{icon && <ListItemIconPlacement>{icon}</ListItemIconPlacement>}
6060
<Flex flexDirection="column" minWidth={0} flexGrow={1}>
6161
{children}
6262
{description}
@@ -71,16 +71,24 @@ const ListItemLayoutInternal: FC<ListItemLayoutProps> = ({
7171
})
7272
}
7373

74+
export const ListItemIconPlacement = styled.div``
75+
7476
export const listItemIconCSS = css<ListItemLayoutProps>`
75-
& > svg,
76-
& > ${StyledIconBase}, & > ${IconPlaceholder} {
77-
${colorHelper}
77+
${ListItemIconPlacement} {
78+
/* align-items: center; */
7879
align-self: center;
79-
flex-grow: 0;
80-
flex-shrink: 0;
81-
height: ${({ iconSize, theme }) => theme.sizes[iconSize]};
80+
display: flex;
8281
margin-right: ${({ iconGap, theme }) => theme.space[iconGap]};
83-
width: ${({ iconSize, theme }) => theme.sizes[iconSize]};
82+
83+
& > svg,
84+
${StyledIconBase}, ${IconPlaceholder} {
85+
${colorHelper}
86+
flex-grow: 0;
87+
flex-shrink: 0;
88+
height: ${({ iconSize, theme }) => theme.sizes[iconSize]};
89+
/* justify-content: center; */
90+
width: ${({ iconSize, theme }) => theme.sizes[iconSize]};
91+
}
8492
}
8593
`
8694

packages/components/src/List/ListItemLayoutAccessory.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@
2727
import React, { FC } from 'react'
2828
import styled from 'styled-components'
2929
import { Flex } from '../Layout'
30-
import { listItemIconCSS, ListItemLayoutProps } from './ListItemLayout'
30+
import {
31+
listItemIconCSS,
32+
ListItemIconPlacement,
33+
ListItemLayoutProps,
34+
} from './ListItemLayout'
3135
import { listItemPadding } from './utils'
3236

3337
export const ListItemLayoutAccessoryInternal: FC<ListItemLayoutProps> = ({
@@ -40,7 +44,7 @@ export const ListItemLayoutAccessoryInternal: FC<ListItemLayoutProps> = ({
4044
}) => {
4145
const content = (
4246
<>
43-
{icon}
47+
{icon && <ListItemIconPlacement>{icon}</ListItemIconPlacement>}
4448
<Flex flexDirection="column" minWidth={0} flexGrow={1}>
4549
{children}
4650
{description}

packages/components/src/List/ListItemWrapper.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { StyledIconBase } from '@styled-icons/styled-icon'
2929
import omit from 'lodash/omit'
3030
import React, { forwardRef, ReactNode, Ref } from 'react'
3131
import styled from 'styled-components'
32+
import { ListItemIconPlacement } from './ListItemLayout'
3233
import { ListColor, ListItemDimensions, listItemDimensionKeys } from './types'
3334

3435
export interface ListItemWrapperProps
@@ -83,10 +84,14 @@ export const ListItemWrapper = styled(ListItemWrapperInternal)
8384
}
8485
`}
8586
86-
${StyledIconBase}, svg {
87+
${ListItemIconPlacement} {
8788
align-self: ${({ description }) => (description ? 'flex-start' : 'center')};
88-
transition: color
89-
${({ theme }) => `${theme.transitions.quick}ms ${theme.easings.ease}`};
89+
90+
${StyledIconBase},
91+
svg {
92+
transition: color ${({ theme }) =>
93+
`${theme.transitions.quick}ms ${theme.easings.ease}`};
94+
}
9095
}
9196
9297
&[aria-current='true'] {

packages/components/src/NavList/NavList.story.tsx

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,69 @@
2626

2727
import React, { useState } from 'react'
2828
import { Home } from '@styled-icons/material-outlined/Home'
29-
import { DateRange } from '@styled-icons/material-outlined/DateRange'
29+
import { Info } from '@styled-icons/material-outlined/Info'
3030
import { ListItem } from '../List/ListItem'
31+
import { ProgressCircular } from '../ProgressCircular'
32+
import { Tree, TreeItem } from '../Tree'
3133
import { NavList } from './NavList'
3234

3335
export default {
3436
component: NavList,
3537
title: 'NavList',
3638
}
3739

38-
export const NavListExample = () => {
40+
export const Basic = () => {
3941
const [selected, setSelected] = useState(false)
4042
const handleClick = () => {
4143
setSelected(!selected)
4244
}
4345
return (
4446
<NavList>
4547
<ListItem
46-
description="Orange-y"
47-
detail="Netherlands"
48+
description="Description"
49+
detail="Interesting details"
4850
icon={<Home />}
4951
selected
5052
>
5153
Explore
5254
</ListItem>
53-
<ListItem icon={<DateRange />} onClick={handleClick} selected={selected}>
55+
<ListItem icon={<Info />} onClick={handleClick} selected={selected}>
5456
Develop
5557
</ListItem>
5658
</NavList>
5759
)
5860
}
61+
62+
export const MixedNavigation = () => (
63+
<NavList>
64+
<ListItem icon={<Home />} selected>
65+
Home
66+
</ListItem>
67+
<ListItem icon={<Home />}>Not really home</ListItem>
68+
<Tree icon={<Info />} label="Tree" selected isOpen>
69+
<TreeItem icon={<Info />}>Meh</TreeItem>
70+
<TreeItem
71+
description="description"
72+
detail="detail"
73+
icon={<Info />}
74+
selected
75+
>
76+
My Awesome Item
77+
</TreeItem>
78+
<Tree
79+
forceLabelPadding
80+
branchFontWeight
81+
defaultOpen
82+
label="Blah"
83+
icon={<Info />}
84+
>
85+
<TreeItem color="text2">
86+
<em>Not yet available</em>
87+
</TreeItem>
88+
<TreeItem icon={<ProgressCircular size="xsmall" progress={0.75} />}>
89+
Loading...
90+
</TreeItem>
91+
</Tree>
92+
</Tree>
93+
</NavList>
94+
)

packages/components/src/NavList/NavList.test.tsx

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,36 +25,19 @@
2525
*/
2626

2727
import React from 'react'
28-
import { Home } from '@styled-icons/material/Home'
2928
import { renderWithTheme } from '@looker/components-test-utils'
3029
import { screen } from '@testing-library/react'
31-
import { ListItem } from '../List/ListItem'
32-
import { NavList } from './NavList'
30+
import { Basic } from './NavList.story'
3331

3432
describe('NavList', () => {
3533
test('display with keyColor', () => {
36-
renderWithTheme(
37-
<NavList>
38-
<ListItem
39-
description="Orange-y"
40-
detail="Netherlands"
41-
icon={<Home />}
42-
selected
43-
>
44-
Explore
45-
</ListItem>
46-
</NavList>
47-
)
34+
renderWithTheme(<Basic />)
4835

4936
const listItem = screen.getByText('Explore')
50-
51-
// NavList label
52-
expect(listItem).toHaveStyle(`color: #6C43E0;`)
53-
54-
// NavList description
55-
expect(screen.getByText('Orange-y')).toHaveStyle(`color: #6C43E0;`)
56-
57-
// NavList detail
58-
expect(screen.getByText('Netherlands')).toHaveStyle(`color: #6C43E0;`)
37+
expect(listItem).toHaveStyle('color: #6c43e0;')
38+
expect(screen.getByText('Interesting details')).toHaveStyle(
39+
'color: #6c43e0'
40+
)
41+
expect(screen.getByText('Description')).toHaveStyle('color: #6c43e0;')
5942
})
6043
})

packages/components/src/NavList/NavList.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,19 @@
2525
*/
2626

2727
import styled from 'styled-components'
28-
import { StyledIconBase } from '@styled-icons/styled-icon'
2928
import { AccordionDisclosureStyle } from '../Accordion/AccordionDisclosure'
3029
import { TextBase } from '../Text/TextBase'
3130
import { ListItemDetail } from '../List/ListItemDetail'
32-
import { List, ListItemLabel } from '../List'
31+
import { List, ListItem, ListItemLabel } from '../List'
32+
import { ListItemIconPlacement } from '../List/ListItemLayout'
3333

3434
/**
3535
* `NavList` is a variation of `List`
3636
* - `ListItem` border-radius circular on the right side
3737
* - `ListItem` selected or "active"
3838
* - text color is `keyColor`
3939
* - background color is `keySubtle`
40+
* - `ListItem` at the root are indented to align properly with `Tree`(s) at the root as well
4041
*
4142
*
4243
* @status: EXPERIMENTAL
@@ -45,18 +46,22 @@ import { List, ListItemLabel } from '../List'
4546
* SemVer major version change. _It is not recommended to use this component
4647
* at this time.
4748
*/
48-
49-
export const NavList = styled(List)`
49+
export const NavList = styled(List).attrs(({ color = 'key' }) => ({ color }))`
5050
${AccordionDisclosureStyle}, ${ListItemLabel} {
5151
border-bottom-right-radius: 5rem;
5252
border-top-right-radius: 5rem;
5353
5454
&[aria-selected='true'] {
55-
background-color: ${({ theme }) => theme.colors.keySubtle};
56-
color: ${({ theme }) => theme.colors.key};
57-
${ListItemDetail}, ${StyledIconBase}, ${TextBase} {
55+
${ListItemDetail},
56+
${TextBase},
57+
${ListItemIconPlacement} svg {
5858
color: ${({ theme }) => theme.colors.key};
5959
}
6060
}
6161
}
62+
& > ${ListItem} {
63+
${ListItemLabel} {
64+
padding-left: ${({ theme }) => `${theme.sizes.medium}`};
65+
}
66+
}
6267
`

packages/components/src/NavList/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@
2424
2525
*/
2626

27-
export * from './NavList'
27+
export { NavList } from './NavList'

packages/components/src/Tree/Tree.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import React, {
3636
import { Accordion } from '../Accordion'
3737
import { undefinedCoalesce, useWrapEvent } from '../utils'
3838
import { List } from '../List'
39+
import { ListItemContext } from '../List/ListItemContext'
3940
import { listItemDimensions, getDetailOptions } from '../List/utils'
4041
import { TreeContext } from './TreeContext'
4142
import { indicatorDefaults } from './utils'
@@ -69,11 +70,12 @@ const TreeLayout: FC<TreeProps> = ({
6970
const detailRef = useRef<HTMLDivElement>(null)
7071
const [hovered, setHovered] = useState(false)
7172

73+
const { color: listColor } = useContext(ListItemContext)
7274
const treeContext = useContext(TreeContext)
7375
const hasBorder = undefinedCoalesce([propsBorder, treeContext.border])
7476

7577
if (keyColor) propsColor = 'key'
76-
const color = undefinedCoalesce([propsColor, treeContext.color])
78+
const color = undefinedCoalesce([propsColor, treeContext.color, listColor])
7779

7880
const hasLabelBackgroundOnly = undefinedCoalesce([
7981
propsLabelBackgroundOnly,

0 commit comments

Comments
 (0)