-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(timeline): create package (#4054)
* feat(timeline): add base component * feat(timeline): add basic styling * feat(timeline): add stories * feat(timeline): add collapsible item * feat(timeline): add grouped item * feat(timeline): add collapsibleHeading prop * feat(timeline): refactor Timeline component and add element prop * feat(timeline): update lock file * feat(timeline): add element prop to all components * feat(timeline): add customization story * feat(timeline): add tests * feat(timeline): add missing packages * feat(timeline): update yarn lock * feat(timeline): add changeset * feat(timeline): hide orientation prop * feat(timeline): implement changes from review * feat(timeline): fix storybook a11y issue * feat(timeline): add improvements from review * feat(timeline): add changes from chromatic review * feat(timeline): add changes from chromatic review * feat(timeline): add changes from github review * feat(timeline): update skeleton for infinte scroll * feat(timeline): remove paragraph and skeleton loader from package * feat(timeline): update yarn lock * feat(timeline): resolve comments --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
- Loading branch information
1 parent
200baeb
commit 43bd80a
Showing
23 changed files
with
993 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@twilio-paste/timeline": major | ||
"@twilio-paste/core": minor | ||
--- | ||
|
||
[Timeline]: Added a new Timeline component to the library to display events in chronological order |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@twilio-paste/codemods": minor | ||
--- | ||
|
||
[Codemods] new export (timeline) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
177 changes: 177 additions & 0 deletions
177
packages/paste-core/components/timeline/__tests__/index.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
import { render } from "@testing-library/react"; | ||
import { UserIcon } from "@twilio-paste/icons/esm/UserIcon"; | ||
import * as React from "react"; | ||
|
||
import { Timeline, TimelineItem } from "../src"; | ||
import { TimelineItemGroup } from "../src/TimelineItemGroup"; | ||
|
||
const ExampleTimeline: React.FC<{ | ||
element?: string; | ||
}> = ({ element = "TIMELINE" }) => ( | ||
<Timeline element={element} data-testid="timeline"> | ||
<TimelineItem data-testid="timelineItem" element={`${element}_ITEM`} title="Start" timestamp="2018-03-01:10:00"> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItem title="Inprogress" timestamp="2018-03-01:12:00"> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItem title="Complete" timestamp="2018-03-01:14:00"> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItem data-testid="timelineItemNoTimestamp" title="Item without timestamp"> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItem | ||
title="Icon Item" | ||
timestamp="2018-03-01:12:00" | ||
icon={UserIcon} | ||
data-testid="timelineItemIcon" | ||
element={`${element}_ITEM`} | ||
> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItemGroup timestamp="2018-03-01" data-testid="timelineItemGroup" element={`${element}_ITEM_GROUP`}> | ||
<TimelineItem title="Inprogress" timestamp="12:00"> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItem title="Complete" timestamp="14:00"> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItem title="Item without timestamp">Event details</TimelineItem> | ||
</TimelineItemGroup> | ||
|
||
<TimelineItem | ||
title="Start" | ||
timestamp="2018-03-01:10:00" | ||
collapsible | ||
data-testid="timelineItemCollapsible" | ||
element={`${element}_ITEM`} | ||
> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItem | ||
title="Item without timestamp" | ||
collapsible | ||
collapsibleHeading="custom heading" | ||
data-testid="timelineItemCollapsibleNoTimestamp" | ||
> | ||
Event details | ||
</TimelineItem> | ||
|
||
<TimelineItem | ||
title="Item with timestamp and collapsibleHeading" | ||
timestamp="2018-03-01:10:00" | ||
collapsible | ||
collapsibleHeading="custom heading" | ||
data-testid="timelineItemCollapsibleHeading" | ||
> | ||
Event details | ||
</TimelineItem> | ||
</Timeline> | ||
); | ||
|
||
describe("Timeline", () => { | ||
it("should render", () => { | ||
expect(document.querySelector("ol")).toBeDefined(); | ||
expect(document.querySelector("li")).toBeDefined(); | ||
}); | ||
|
||
it("should display title and timestamp", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect(getByTestId("timelineItem")).toHaveTextContent("Start"); | ||
expect(getByTestId("timelineItem")).toHaveTextContent("2018-03-01:10:00"); | ||
}); | ||
|
||
it("should display content", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect(getByTestId("timelineItem")).toHaveTextContent("Event details"); | ||
}); | ||
|
||
it("should display item without timestamp", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect( | ||
getByTestId("timelineItemNoTimestamp").querySelector("[data-paste-element='TIMELINE_ITEM_TIMESTAMP']"), | ||
).toBeNull(); | ||
}); | ||
|
||
it("should display icon item", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect(getByTestId("timelineItem").querySelector("[data-paste-element='TIMELINE_ITEM_ICON']")).toBeDefined(); | ||
}); | ||
|
||
it("should display grouped items", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect(getByTestId("timelineItemGroup")).toBeDefined(); | ||
}); | ||
|
||
it("should display group item timestamp", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect( | ||
getByTestId("timelineItem").querySelector("[data-paste-element='TIMELINE_ITEM_GROUP_TIMESTAMP_DETAIL_TEXT']"), | ||
).toBeDefined(); | ||
}); | ||
|
||
it("should display collapsible items", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect(getByTestId("timelineItemCollapsible")).toBeDefined(); | ||
}); | ||
|
||
it("should display custom collapsible heading", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect(getByTestId("timelineItemCollapsibleNoTimestamp")).toHaveTextContent("custom heading"); | ||
}); | ||
|
||
it("should not display custom collapsible heading text when timestamp is p", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect(getByTestId("timelineItemCollapsibleHeading")).toHaveTextContent("2018-03-01:10:00"); | ||
}); | ||
|
||
describe("Customization", () => { | ||
it("should set element data attribute", () => { | ||
const { getByTestId } = render(<ExampleTimeline />); | ||
expect(getByTestId("timeline").getAttribute("data-paste-element")).toEqual("TIMELINE"); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_GROUP']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_SEPARATOR']`)).toBeTruthy(); | ||
expect( | ||
getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_CONTENT_WRAPPER']`), | ||
).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_ICON']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_ICON_WRAPPER']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_ICON_DOT']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_TITLE']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_TIMESTAMP']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_CONTENT']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='TIMELINE_ITEM_SUMMARY_DETAIL']`)).toBeTruthy(); | ||
}); | ||
|
||
it("should set custom element data attribute", () => { | ||
const { getByTestId } = render(<ExampleTimeline element="CUSTOMIZED" />); | ||
|
||
expect(getByTestId("timeline").getAttribute("data-paste-element")).toEqual("CUSTOMIZED"); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_GROUP']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_SEPARATOR']`)).toBeTruthy(); | ||
expect( | ||
getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_CONTENT_WRAPPER']`), | ||
).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_ICON']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_ICON_WRAPPER']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_ICON_DOT']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_TITLE']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_TIMESTAMP']`)).toBeTruthy(); | ||
expect(getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_CONTENT']`)).toBeTruthy(); | ||
expect( | ||
getByTestId("timeline").querySelector(`[data-paste-element='CUSTOMIZED_ITEM_SUMMARY_DETAIL']`), | ||
).toBeTruthy(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
const { build } = require("../../../../tools/build/esbuild"); | ||
|
||
build(require("./package.json")); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
{ | ||
"name": "@twilio-paste/timeline", | ||
"version": "0.0.0", | ||
"category": "layout", | ||
"status": "production", | ||
"description": "A Timeline is a visual representation of events displayed in chronological order.", | ||
"author": "Twilio Inc.", | ||
"license": "MIT", | ||
"main:dev": "src/index.tsx", | ||
"main": "dist/index.js", | ||
"module": "dist/index.es.js", | ||
"types": "dist/index.d.ts", | ||
"sideEffects": false, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"build": "yarn clean && NODE_ENV=production node build.js && tsc", | ||
"build:js": "NODE_ENV=development node build.js", | ||
"build:typedocs": "tsx ../../../../tools/build/generate-type-docs", | ||
"clean": "rm -rf ./dist", | ||
"tsc": "tsc" | ||
}, | ||
"peerDependencies": { | ||
"@twilio-paste/anchor": "^12.0.0", | ||
"@twilio-paste/animation-library": "^2.0.0", | ||
"@twilio-paste/box": "^10.2.0", | ||
"@twilio-paste/button": "^14.0.0", | ||
"@twilio-paste/card": "^9.1.0", | ||
"@twilio-paste/color-contrast-utils": "^5.0.0", | ||
"@twilio-paste/customization": "^8.1.1", | ||
"@twilio-paste/design-tokens": "^10.3.0", | ||
"@twilio-paste/detail-text": "^3.1.0", | ||
"@twilio-paste/disclosure-primitive": "^2.1.1", | ||
"@twilio-paste/icons": "^12.0.0", | ||
"@twilio-paste/reakit-library": "^2.0.0", | ||
"@twilio-paste/spinner": "^14.0.0", | ||
"@twilio-paste/stack": "^8.0.0", | ||
"@twilio-paste/style-props": "^9.1.1", | ||
"@twilio-paste/styling-library": "^3.0.0", | ||
"@twilio-paste/summary-detail": "^1.0.0", | ||
"@twilio-paste/text": "^10.0.0", | ||
"@twilio-paste/theme": "^11.0.1", | ||
"@twilio-paste/types": "^6.0.0", | ||
"@twilio-paste/uid-library": "^2.0.0", | ||
"@types/react": "^16.8.6 || ^17.0.2 || ^18.0.27", | ||
"@types/react-dom": "^16.8.6 || ^17.0.2 || ^18.0.10", | ||
"react": "^16.8.6 || ^17.0.2 || ^18.0.0", | ||
"react-dom": "^16.8.6 || ^17.0.2 || ^18.0.0" | ||
}, | ||
"devDependencies": { | ||
"@twilio-paste/anchor": "^12.0.0", | ||
"@twilio-paste/animation-library": "^2.0.0", | ||
"@twilio-paste/box": "^10.2.0", | ||
"@twilio-paste/button": "^14.1.0", | ||
"@twilio-paste/card": "^9.1.0", | ||
"@twilio-paste/color-contrast-utils": "^5.0.0", | ||
"@twilio-paste/customization": "^8.1.1", | ||
"@twilio-paste/design-tokens": "^10.3.0", | ||
"@twilio-paste/detail-text": "^3.1.0", | ||
"@twilio-paste/disclosure-primitive": "^2.1.1", | ||
"@twilio-paste/icons": "^12.2.0", | ||
"@twilio-paste/reakit-library": "^2.0.0", | ||
"@twilio-paste/spinner": "^14.0.0", | ||
"@twilio-paste/stack": "^8.0.0", | ||
"@twilio-paste/style-props": "^9.1.1", | ||
"@twilio-paste/styling-library": "^3.0.0", | ||
"@twilio-paste/summary-detail": "^1.0.0", | ||
"@twilio-paste/text": "^10.1.1", | ||
"@twilio-paste/theme": "^11.0.1", | ||
"@twilio-paste/types": "^6.0.0", | ||
"@twilio-paste/uid-library": "^2.0.0", | ||
"@types/react": "^18.0.27", | ||
"@types/react-dom": "^18.0.10", | ||
"react": "^18.0.0", | ||
"react-dom": "^18.0.0", | ||
"tsx": "^4.0.0", | ||
"typescript": "^4.9.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Box } from "@twilio-paste/box"; | ||
import { css, styled } from "@twilio-paste/styling-library"; | ||
import React from "react"; | ||
|
||
import type { TimelineProps } from "./types"; | ||
|
||
const Timeline = React.forwardRef<HTMLOListElement, TimelineProps>( | ||
({ children, element = "TIMELINE", ...props }, ref) => { | ||
const ContainerStyled = styled.ol( | ||
css({ | ||
listStyleType: "none", | ||
margin: "0", | ||
padding: "0", | ||
"li>div:first-child::after": { | ||
content: "''", | ||
borderLeftWidth: "borderWidth10", | ||
borderLeftStyle: "solid", | ||
borderLeftColor: "colorBorderWeaker", | ||
minHeight: "sizeBase80", | ||
flexGrow: "1", | ||
}, | ||
}), | ||
); | ||
|
||
return ( | ||
<Box | ||
ref={ref} | ||
/* @ts-expect-error we don't have polymorphic box typings yet */ | ||
as={ContainerStyled} | ||
element={element} | ||
{...props} | ||
> | ||
{children} | ||
</Box> | ||
); | ||
}, | ||
); | ||
|
||
Timeline.displayName = "Timeline"; | ||
|
||
export { Timeline }; |
3 changes: 3 additions & 0 deletions
3
packages/paste-core/components/timeline/src/TimelineContext.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import * as React from "react"; | ||
|
||
export const TimelineGroupContext = React.createContext<boolean>(false); |
Oops, something went wrong.