Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] fix(Timeline): render as unordered list #5176

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ad58ebd
fix(Timeline): render as unordered list
francinelucca Oct 25, 2024
69ba69b
Merge branch 'main' of github.com:primer/react into francinelucca/335…
francinelucca Oct 28, 2024
559c974
feat(TimeList): introduce TimelineGroup
francinelucca Oct 28, 2024
efea6c2
Test(timeline): update tests
francinelucca Oct 28, 2024
f063d38
Create famous-trainers-allow.md
francinelucca Oct 28, 2024
57434d7
test(vrt): update snapshots
francinelucca Oct 28, 2024
3ae1346
fix(Timeline);
francinelucca Oct 28, 2024
9d48dfd
Revert "test(vrt): update snapshots"
francinelucca Oct 28, 2024
1490aad
test(Timeline): update snapshot
francinelucca Oct 28, 2024
0ba8ebf
Merge branch 'main' of github.com:primer/react into francinelucca/335…
francinelucca Oct 29, 2024
b32291b
fix(Timeline): render as div when Timeline.Group as children
francinelucca Oct 29, 2024
326732f
fix(Timeline): remove console logs
francinelucca Oct 29, 2024
2077751
test(Timeline): update snapshot
francinelucca Oct 29, 2024
85b544a
fix(Timeline): add display name
francinelucca Oct 29, 2024
fa2059e
Merge branch 'main' of github.com:primer/react into francinelucca/335…
francinelucca Nov 5, 2024
5622e81
feat(timeline): put as list rendering under a feature flag
francinelucca Nov 5, 2024
9f7e953
fix(Timeline): add warning on group misuse
francinelucca Nov 5, 2024
a95a860
test(Timeline): update tests, add tests for group
francinelucca Nov 5, 2024
2265fc8
Merge branch 'main' of github.com:primer/react into francinelucca/335…
francinelucca Nov 5, 2024
e684e79
docs(Timeline): add group subcomponent
francinelucca Nov 5, 2024
ee0ad14
fix(Timeline): render group as div is FF is off
francinelucca Nov 5, 2024
3f15458
Update Timeline rendering under Feature Flag
francinelucca Nov 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/famous-trainers-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

fix(Timeline): render as unordered list under Feature Flag
1 change: 1 addition & 0 deletions packages/react/src/FeatureFlags/DefaultFeatureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export const DefaultFeatureFlags = FeatureFlagScope.create({
primer_react_action_list_item_as_button: false,
primer_react_select_panel_with_modern_action_list: false,
primer_react_overlay_overflow: false,
primer_react_timeline_as_list: false,
})
4 changes: 4 additions & 0 deletions packages/react/src/Timeline/Timeline.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@
"type": "SystemStyleObject"
}
]
},
{
"name": "Timeline.Group",
"props": []
}
]
}
139 changes: 79 additions & 60 deletions packages/react/src/Timeline/Timeline.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Timeline from './Timeline'
import Octicon from '../Octicon'
import {GitBranchIcon, GitCommitIcon, GitMergeIcon} from '@primer/octicons-react'
import Link from '../Link'
import {FeatureFlags} from '../FeatureFlags'

export default {
title: 'Components/Timeline/Features',
Expand All @@ -18,73 +19,91 @@ export default {
} as Meta<ComponentProps<typeof Timeline>>

export const ClipSidebar = () => (
<Timeline clipSidebar>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline>
<FeatureFlags flags={{primer_react_timeline_as_list: true}}>
<Timeline clipSidebar>
<Timeline.Group>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline.Group>
</Timeline>
</FeatureFlags>
)

export const CondensedItems = () => (
<Timeline>
<Timeline.Item condensed>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item condensed>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline>
<FeatureFlags flags={{primer_react_timeline_as_list: true}}>
<Timeline>
<Timeline.Group>
<Timeline.Item condensed>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item condensed>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline.Group>
</Timeline>
</FeatureFlags>
)

export const TimelineBreak = () => (
<Timeline>
<Timeline.Item>
<Timeline.Badge sx={{bg: 'done.emphasis'}}>
<Octicon icon={GitMergeIcon} color="fg.onEmphasis" aria-label="Merged" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Break />
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitBranchIcon} aria-label="Branch" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline>
<FeatureFlags flags={{primer_react_timeline_as_list: true}}>
<Timeline>
<Timeline.Group>
<Timeline.Item>
<Timeline.Badge sx={{bg: 'done.emphasis'}}>
<Octicon icon={GitMergeIcon} color="fg.onEmphasis" aria-label="Merged" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline.Group>
<Timeline.Break />
<Timeline.Group>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitBranchIcon} aria-label="Branch" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline.Group>
</Timeline>
</FeatureFlags>
)

export const WithInlineLinks = () => (
<Timeline>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>
<Link
href="#"
sx={{fontWeight: 'bold', color: 'fg.default', mr: 1, '&:hover': {color: 'var(--fgColor-accent)'}}}
muted
>
Monalisa
</Link>
enabled auto-merge (squash)
</Timeline.Body>
</Timeline.Item>
</Timeline>
<FeatureFlags flags={{primer_react_timeline_as_list: true}}>
<Timeline>
<Timeline.Group>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>
<Link
href="#"
sx={{fontWeight: 'bold', color: 'fg.default', mr: 1, '&:hover': {color: 'var(--fgColor-accent)'}}}
muted
>
Monalisa
</Link>
enabled auto-merge (squash)
</Timeline.Body>
</Timeline.Item>
</Timeline.Group>
</Timeline>
</FeatureFlags>
)
89 changes: 49 additions & 40 deletions packages/react/src/Timeline/Timeline.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {ComponentProps} from '../utils/types'
import Timeline from './Timeline'
import Octicon from '../Octicon'
import {GitCommitIcon} from '@primer/octicons-react'
import {FeatureFlags} from '../FeatureFlags'

export default {
title: 'Components/Timeline',
Expand All @@ -17,49 +18,57 @@ export default {
} as Meta<ComponentProps<typeof Timeline>>

export const Default = () => (
<Timeline>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline>
<FeatureFlags flags={{primer_react_timeline_as_list: true}}>
<Timeline>
<Timeline.Group>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline.Group>
</Timeline>
</FeatureFlags>
)

export const Playground: StoryFn<ComponentProps<typeof Timeline>> = args => (
<Timeline {...args}>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline>
<FeatureFlags flags={{primer_react_timeline_as_list: true}}>
<Timeline {...args}>
<Timeline.Group>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
<Timeline.Item>
<Timeline.Badge>
<Octicon icon={GitCommitIcon} aria-label="Commit" />
</Timeline.Badge>
<Timeline.Body>This is a message</Timeline.Body>
</Timeline.Item>
</Timeline.Group>
</Timeline>
</FeatureFlags>
)

Playground.args = {
Expand Down
47 changes: 44 additions & 3 deletions packages/react/src/Timeline/Timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@ import {get} from '../constants'
import type {SxProp} from '../sx'
import sx from '../sx'
import type {ComponentProps} from '../utils/types'
import {useFeatureFlag} from '../FeatureFlags'
import {warning} from '../utils/warning'

const Timeline = styled.div<{clipSidebar?: boolean} & SxProp>`
display: flex;
flex-direction: column;
list-style: none;

.Timeline-Group {
padding-inline-start: 0;
margin-block-start: 0;
margin-block-end: 0;
}

${props =>
props.clipSidebar &&
css`
Expand All @@ -27,7 +37,7 @@ const Timeline = styled.div<{clipSidebar?: boolean} & SxProp>`

type StyledTimelineItemProps = {condensed?: boolean} & SxProp

const TimelineItem = styled.div.attrs<StyledTimelineItemProps>(props => ({
const StyledTimelineItem = styled.div.attrs<StyledTimelineItemProps>(props => ({
className: clsx('Timeline-Item', props.className),
}))<StyledTimelineItemProps>`
display: flex;
Expand Down Expand Up @@ -68,6 +78,16 @@ const TimelineItem = styled.div.attrs<StyledTimelineItemProps>(props => ({
${sx};
`

export type TimelineItemsProps<As extends React.ElementType> = {
as?: As
} & SxProp &
React.ComponentProps<As>

function TimelineItem<As extends React.ElementType>(props: TimelineItemsProps<As>) {
const asList = useFeatureFlag('primer_react_timeline_as_list')
return <StyledTimelineItem as={asList ? 'li' : 'div'} {...props} />
}

export type TimelineBadgeProps = {children?: React.ReactNode} & SxProp

const TimelineBadge = (props: TimelineBadgeProps) => {
Expand Down Expand Up @@ -108,7 +128,7 @@ const TimelineBody = styled.div<SxProp>`
${sx};
`

const TimelineBreak = styled.div<SxProp>`
const StyledTimelineBreak = styled.div<SxProp>`
position: relative;
z-index: 1;
height: 24px;
Expand All @@ -121,6 +141,26 @@ const TimelineBreak = styled.div<SxProp>`
${sx};
`

function TimelineBreak(props: ComponentProps<typeof StyledTimelineBreak>) {
const asList = useFeatureFlag('primer_react_timeline_as_list')
return <StyledTimelineBreak aria-hidden={asList ? true : undefined} {...props} />
}

function TimelineGroup({children, ...props}: React.ComponentPropsWithoutRef<'ul'>) {
const asList = useFeatureFlag('primer_react_timeline_as_list')
warning(
!asList,
`Timeline.Group is only meant to be used with the timeline as list feature, you may want to turn on the 'primer_react_timeline_as_list' feature flag. Using Timeline.Group without this feature may have unintended consequences`,
)
return (
<Box as={asList ? 'ul' : 'div'} className="Timeline-Group" {...props}>
{children}
</Box>
)
}

TimelineGroup.displayName = 'Timeline.Group'

TimelineItem.displayName = 'Timeline.Item'

TimelineBadge.displayName = 'Timeline.Badge'
Expand All @@ -130,12 +170,13 @@ TimelineBody.displayName = 'Timeline.Body'
TimelineBreak.displayName = 'Timeline.Break'

export type TimelineProps = ComponentProps<typeof Timeline>
export type TimelineItemsProps = ComponentProps<typeof TimelineItem>
export type TimelineBodyProps = ComponentProps<typeof TimelineBody>
export type TimelineBreakProps = ComponentProps<typeof TimelineBreak>
export type TimelineGroupProps = ComponentProps<typeof TimelineGroup>
export default Object.assign(Timeline, {
Item: TimelineItem,
Badge: TimelineBadge,
Body: TimelineBody,
Break: TimelineBreak,
Group: TimelineGroup,
})
Loading
Loading