From 1724c00b67f106d72c8495d5cec6dd9452e74220 Mon Sep 17 00:00:00 2001 From: Brett Dorrans Date: Thu, 26 Oct 2023 19:20:46 +0100 Subject: [PATCH] feat: add Timeline component (#1556) * feat: add Timeline component * wip * upgrade storybook * upgrade deps * use node 20 --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 2 +- package-lock.json | 138 +++---- package.json | 42 +-- src/components/Logo/Logo.mdx | 2 +- src/components/Timeline/Timeline.mdx | 44 +++ src/components/Timeline/Timeline.module.scss | 18 + src/components/Timeline/Timeline.spec.tsx | 57 +++ src/components/Timeline/Timeline.stories.tsx | 56 +++ .../__snapshots__/Timeline.spec.tsx.snap | 337 ++++++++++++++++++ src/components/Timeline/index.tsx | 65 ++++ src/index.ts | 1 + 12 files changed, 679 insertions(+), 85 deletions(-) create mode 100644 src/components/Timeline/Timeline.mdx create mode 100644 src/components/Timeline/Timeline.module.scss create mode 100644 src/components/Timeline/Timeline.spec.tsx create mode 100644 src/components/Timeline/Timeline.stories.tsx create mode 100644 src/components/Timeline/__snapshots__/Timeline.spec.tsx.snap create mode 100644 src/components/Timeline/index.tsx diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03d44d68..29121908 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Get node.js cache directory id: node-cache-dir diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a0cdea80..2f9f26d8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Get node.js cache directory id: node-cache-dir diff --git a/package-lock.json b/package-lock.json index b27985f1..942c2050 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,48 +12,48 @@ "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/react-fontawesome": "^0.2.0", - "@lapidist/styles": "^6.1.0", + "@lapidist/styles": "^6.2.0", "classnames": "^2.3.2", "react": "18.x", "react-dom": "18.x" }, "devDependencies": { - "@babel/core": "^7.22.10", - "@lapidist/linting": "^3.9.23", - "@storybook/addon-a11y": "^7.2.1", + "@babel/core": "^7.23.2", + "@lapidist/linting": "^3.11.7", + "@storybook/addon-a11y": "^7.5.1", "@storybook/addon-backgrounds": "7.5.1", "@storybook/addon-controls": "7.5.1", - "@storybook/addon-docs": "^7.2.1", + "@storybook/addon-docs": "^7.5.1", "@storybook/addon-highlight": "7.5.1", - "@storybook/addon-links": "^7.2.1", + "@storybook/addon-links": "^7.5.1", "@storybook/addon-measure": "7.5.1", "@storybook/addon-outline": "7.5.1", "@storybook/addon-toolbars": "7.5.1", "@storybook/addon-viewport": "7.5.1", "@storybook/addons": "7.5.1", "@storybook/api": "7.5.1", - "@storybook/blocks": "^7.2.1", - "@storybook/cli": "^7.2.1", + "@storybook/blocks": "^7.5.1", + "@storybook/cli": "^7.5.1", "@storybook/core-common": "7.5.1", "@storybook/node-logger": "7.5.1", - "@storybook/react-vite": "^7.2.1", - "@storybook/theming": "^7.2.1", + "@storybook/react-vite": "^7.5.1", + "@storybook/theming": "^7.5.1", "@testing-library/react": "^14.0.0", - "@types/react": "^18.2.18", - "@types/react-dom": "^18.2.7", - "@vitejs/plugin-react": "^4.0.4", - "@vitest/coverage-v8": "^0.34.1", + "@types/react": "^18.2.33", + "@types/react-dom": "^18.2.14", + "@vitejs/plugin-react": "^4.1.0", + "@vitest/coverage-v8": "^0.34.6", "axe-playwright": "^1.2.3", "babel-loader": "^9.1.3", "husky": "^8.0.3", "jsdom": "^22.1.0", - "lint-staged": "^14.0.0", - "sass": "^1.64.2", - "storybook": "^7.2.1", - "typescript": "^5.1.6", - "vite": "^4.4.9", - "vite-plugin-dts": "^3.5.1", - "vitest": "^0.34.1" + "lint-staged": "^15.0.2", + "sass": "^1.69.5", + "storybook": "^7.5.1", + "typescript": "^5.2.2", + "vite": "^4.5.0", + "vite-plugin-dts": "^3.6.1", + "vitest": "^0.34.6" }, "engines": { "node": "^20.0.0" @@ -3688,11 +3688,11 @@ } }, "node_modules/@lapidist/styles": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@lapidist/styles/-/styles-6.1.0.tgz", - "integrity": "sha512-yg+HK+41VG/BDHkwcVXtWW0nR4m2PvigdflMeb8jTNCdOg136Q+wM71qSDLv7FrnyKqKAFrBen3yOq7j8S4Ogg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@lapidist/styles/-/styles-6.2.0.tgz", + "integrity": "sha512-Jn5tUO7JP76jPGlcf57ympD3HvhPWaRNCXqwBKACgOuSDiUg8X51HyavNpxvn+v3bQ4zIz9SB1FAxy/IRfCnTA==", "engines": { - "node": "^18.0.0" + "node": "^20.0.0" } }, "node_modules/@mdn/browser-compat-data": { @@ -15939,27 +15939,27 @@ "dev": true }, "node_modules/lint-staged": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.1.tgz", - "integrity": "sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==", + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.0.2.tgz", + "integrity": "sha512-vnEy7pFTHyVuDmCAIFKR5QDO8XLVlPFQQyujQ/STOxe40ICWqJ6knS2wSJ/ffX/Lw0rz83luRDh+ET7toN+rOw==", "dev": true, "dependencies": { "chalk": "5.3.0", - "commander": "11.0.0", + "commander": "11.1.0", "debug": "4.3.4", - "execa": "7.2.0", + "execa": "8.0.1", "lilconfig": "2.1.0", - "listr2": "6.6.1", + "listr2": "7.0.2", "micromatch": "4.0.5", "pidtree": "0.6.0", "string-argv": "0.3.2", - "yaml": "2.3.1" + "yaml": "2.3.3" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=18.12.0" }, "funding": { "url": "https://opencollective.com/lint-staged" @@ -15978,44 +15978,56 @@ } }, "node_modules/lint-staged/node_modules/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, "engines": { "node": ">=16" } }, "node_modules/lint-staged/node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^3.0.7", + "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" }, "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + "node": ">=16.17" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lint-staged/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, "engines": { - "node": ">=14.18.0" + "node": ">=16.17.0" } }, "node_modules/lint-staged/node_modules/is-stream": { @@ -16084,6 +16096,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/lint-staged/node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -16097,9 +16121,9 @@ } }, "node_modules/listr2": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", - "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", + "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", "dev": true, "dependencies": { "cli-truncate": "^3.1.0", @@ -16111,14 +16135,6 @@ }, "engines": { "node": ">=16.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } } }, "node_modules/load-plugin": { @@ -23740,9 +23756,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", + "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", "dev": true, "engines": { "node": ">= 14" diff --git a/package.json b/package.json index ea27c18c..2f80e81a 100644 --- a/package.json +++ b/package.json @@ -61,48 +61,48 @@ "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/react-fontawesome": "^0.2.0", - "@lapidist/styles": "^6.1.0", + "@lapidist/styles": "^6.2.0", "classnames": "^2.3.2", "react": "18.x", "react-dom": "18.x" }, "devDependencies": { - "@babel/core": "^7.22.10", - "@lapidist/linting": "^3.9.23", - "@storybook/addon-a11y": "^7.2.1", + "@babel/core": "^7.23.2", + "@lapidist/linting": "^3.11.7", + "@storybook/addon-a11y": "^7.5.1", "@storybook/addon-backgrounds": "7.5.1", "@storybook/addon-controls": "7.5.1", - "@storybook/addon-docs": "^7.2.1", + "@storybook/addon-docs": "^7.5.1", "@storybook/addon-highlight": "7.5.1", - "@storybook/addon-links": "^7.2.1", + "@storybook/addon-links": "^7.5.1", "@storybook/addon-measure": "7.5.1", "@storybook/addon-outline": "7.5.1", "@storybook/addon-toolbars": "7.5.1", "@storybook/addon-viewport": "7.5.1", "@storybook/addons": "7.5.1", "@storybook/api": "7.5.1", - "@storybook/blocks": "^7.2.1", - "@storybook/cli": "^7.2.1", + "@storybook/blocks": "^7.5.1", + "@storybook/cli": "^7.5.1", "@storybook/core-common": "7.5.1", "@storybook/node-logger": "7.5.1", - "@storybook/react-vite": "^7.2.1", - "@storybook/theming": "^7.2.1", + "@storybook/react-vite": "^7.5.1", + "@storybook/theming": "^7.5.1", "@testing-library/react": "^14.0.0", - "@types/react": "^18.2.18", - "@types/react-dom": "^18.2.7", - "@vitejs/plugin-react": "^4.0.4", - "@vitest/coverage-v8": "^0.34.1", + "@types/react": "^18.2.33", + "@types/react-dom": "^18.2.14", + "@vitejs/plugin-react": "^4.1.0", + "@vitest/coverage-v8": "^0.34.6", "axe-playwright": "^1.2.3", "babel-loader": "^9.1.3", "husky": "^8.0.3", "jsdom": "^22.1.0", - "lint-staged": "^14.0.0", - "sass": "^1.64.2", - "storybook": "^7.2.1", - "typescript": "^5.1.6", - "vite": "^4.4.9", - "vite-plugin-dts": "^3.5.1", - "vitest": "^0.34.1" + "lint-staged": "^15.0.2", + "sass": "^1.69.5", + "storybook": "^7.5.1", + "typescript": "^5.2.2", + "vite": "^4.5.0", + "vite-plugin-dts": "^3.6.1", + "vitest": "^0.34.6" }, "peerDependencies": { "react": "18.x", diff --git a/src/components/Logo/Logo.mdx b/src/components/Logo/Logo.mdx index 81f97371..3391a391 100644 --- a/src/components/Logo/Logo.mdx +++ b/src/components/Logo/Logo.mdx @@ -14,7 +14,7 @@ import * as LogoStories from './Logo.stories.tsx'; ## Controlling animation -The `animation` prop controls the way the logo appears. There are two available gutters, defined as `fade` and `slide`. +The `animation` prop controls the way the logo appears. There are two available animations, defined as `fade` and `slide`. ### Fade diff --git a/src/components/Timeline/Timeline.mdx b/src/components/Timeline/Timeline.mdx new file mode 100644 index 00000000..1fc7e42a --- /dev/null +++ b/src/components/Timeline/Timeline.mdx @@ -0,0 +1,44 @@ +import { Meta, ArgsTable, Story, Source, Canvas } from '@storybook/blocks'; +import * as TimelineStories from './Timeline.stories.tsx'; + + + +# Timeline + +> A primitive for displaying chronological data. + +## Example + + + +## Controlling font size + +The `size` prop controls font size. There are three available font sizes, defined as `small`, `medium` and `large`. + +### Small + +> The `small` size sets the font size to `--font-size-200` + + + + + +### Medium + +> The `medium` size sets the font size to `--font-size-300` + + + + + +### Large + +> The `large` size sets the font size to `--font-size-400` + + + + + +## Props + + diff --git a/src/components/Timeline/Timeline.module.scss b/src/components/Timeline/Timeline.module.scss new file mode 100644 index 00000000..23b3c7ad --- /dev/null +++ b/src/components/Timeline/Timeline.module.scss @@ -0,0 +1,18 @@ +@import '../global.module'; + +.item, .meta { + display: grid; + align-items: flex-start; +} + +.item { + grid-template-columns: 1fr 1fr; + + @media screen and (width >= 800px) { + grid-template-columns: .5fr 1fr; + } +} + +.meta { + grid-template-columns: 1fr; +} diff --git a/src/components/Timeline/Timeline.spec.tsx b/src/components/Timeline/Timeline.spec.tsx new file mode 100644 index 00000000..eaed38c0 --- /dev/null +++ b/src/components/Timeline/Timeline.spec.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { describe, expect, test, afterEach } from 'vitest'; +import { cleanup, render, screen } from '@testing-library/react'; + +import { SizeType } from '../types'; +import Timeline from './index'; + +const setup = (Component: React.ReactElement) => render(Component); + +const mockItems = [ + { + urlTitle: 'LendInvest', + title: 'Senior Software Engineer', + from: 'Apr 2021', + to: 'Present', + url: 'https://www.lendinvest.com/' + }, + { + urlTitle: 'Golden Charter', + title: 'Frontend Software Developer', + from: 'Feb 2020', + to: 'Apr 2021', + url: 'https://www.goldencharter.co.uk/' + } +]; + +afterEach(cleanup); + +const sizes: SizeType[] = ['small', 'medium', 'large']; +describe('Timeline', () => { + test('it works with defaults', () => { + const { container } = setup(); + expect(container.firstChild).toMatchSnapshot(); + }); + + test.each(sizes)('it works with sizes', (size) => { + const { container } = setup(); + expect(container.firstChild).toMatchSnapshot(); + }); + + test('it works with default testId', () => { + setup(); + expect(screen.getByTestId('Timeline')).toBeTruthy(); + }); + + test('it works with specified testId', () => { + setup(); + expect(screen.getByTestId('TestId')).toBeTruthy(); + }); + + test('it works with className', () => { + setup(); + expect( + screen.getByTestId('Timeline').classList.contains('test') + ).toBeTruthy(); + }); +}); diff --git a/src/components/Timeline/Timeline.stories.tsx b/src/components/Timeline/Timeline.stories.tsx new file mode 100644 index 00000000..98d5eaa2 --- /dev/null +++ b/src/components/Timeline/Timeline.stories.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import type { Meta, StoryObj, StoryFn } from '@storybook/react'; +import { BaseProps } from '../types'; +import ThemeProvider from '../ThemeProvider'; +import Timeline, { TimelineProps } from './index'; + +export default { + title: 'Primitives/Timeline', + component: Timeline, + decorators: [(getStory) => {getStory()}] +} as Meta; + +const defaultArgs: BaseProps & TimelineProps = { + items: [ + { + urlTitle: 'LendInvest', + title: 'Senior Software Engineer', + from: 'Apr 2021', + to: 'Present', + url: 'https://www.lendinvest.com/' + }, + { + urlTitle: 'Golden Charter', + title: 'Frontend Software Developer', + from: 'Feb 2020', + to: 'Apr 2021', + url: 'https://www.goldencharter.co.uk/' + } + ], + testId: 'Timeline', + size: 'medium' +}; + +const DefaultTemplate: StoryFn = (args) => ( + +); + +export const SmallSize: StoryObj = + DefaultTemplate.bind({}); +SmallSize.args = { + ...defaultArgs, + size: 'small' +}; +export const MediumSize: StoryObj = + DefaultTemplate.bind({}); +MediumSize.args = { + ...defaultArgs, + size: 'medium' +}; + +export const LargeSize: StoryObj = + DefaultTemplate.bind({}); +LargeSize.args = { + ...defaultArgs, + size: 'large' +}; diff --git a/src/components/Timeline/__snapshots__/Timeline.spec.tsx.snap b/src/components/Timeline/__snapshots__/Timeline.spec.tsx.snap new file mode 100644 index 00000000..d15b31ab --- /dev/null +++ b/src/components/Timeline/__snapshots__/Timeline.spec.tsx.snap @@ -0,0 +1,337 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Timeline > it works with defaults 1`] = ` +
    +
  1. +
    + Apr 2021 + – + Present +
    +
    +
    + Senior Software Engineer +
    + +
    +
  2. +
  3. +
    + Feb 2020 + – + Apr 2021 +
    +
    +
    + Frontend Software Developer +
    + +
    +
  4. +
+`; + +exports[`Timeline > it works with sizes 1`] = ` +
    +
  1. +
    + Apr 2021 + – + Present +
    +
    +
    + Senior Software Engineer +
    + +
    +
  2. +
  3. +
    + Feb 2020 + – + Apr 2021 +
    +
    +
    + Frontend Software Developer +
    + +
    +
  4. +
+`; + +exports[`Timeline > it works with sizes 2`] = ` +
    +
  1. +
    + Apr 2021 + – + Present +
    +
    +
    + Senior Software Engineer +
    + +
    +
  2. +
  3. +
    + Feb 2020 + – + Apr 2021 +
    +
    +
    + Frontend Software Developer +
    + +
    +
  4. +
+`; + +exports[`Timeline > it works with sizes 3`] = ` +
    +
  1. +
    + Apr 2021 + – + Present +
    +
    +
    + Senior Software Engineer +
    + +
    +
  2. +
  3. +
    + Feb 2020 + – + Apr 2021 +
    +
    +
    + Frontend Software Developer +
    + +
    +
  4. +
+`; diff --git a/src/components/Timeline/index.tsx b/src/components/Timeline/index.tsx new file mode 100644 index 00000000..92bff2c2 --- /dev/null +++ b/src/components/Timeline/index.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import type { BaseProps, SizeType } from '../types'; +import Box from '../Box'; +import Link from '../Link'; +import Text from '../Text'; +import styles from './Timeline.module.scss'; + +export interface TimelineItem { + readonly from: string; + readonly to: string; + readonly urlTitle: string; + readonly url: string; + readonly title: string; +} + +export interface TimelineProps { + readonly size?: SizeType; + readonly items: TimelineItem[]; +} + +const Timeline = ({ + className, + testId = 'Timeline', + size = 'medium', + items, + ...restProps +}: BaseProps & TimelineProps) => ( + + {items.map((item) => ( + + + {item.from} – {item.to} + + + {item.title} + + + {item.urlTitle} + + + + + ))} + +); + +Timeline.displayName = 'Timeline'; +export default Timeline; diff --git a/src/index.ts b/src/index.ts index 193becd1..0915abb2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,4 +6,5 @@ export { default as Logo } from './components/Logo'; export { default as Tag } from './components/Tag'; export { default as Text } from './components/Text'; export { default as ThemeProvider } from './components/ThemeProvider'; +export { default as Timeline } from './components/Timeline'; export { default as Toggle } from './components/Toggle';