Skip to content

Commit 9e3604f

Browse files
authored
Merge pull request #32 from openscript-ch/refactor/improve-items-positioning
refactor!: position items without absolute styling
2 parents a29fe60 + 062c436 commit 9e3604f

File tree

7 files changed

+146
-151
lines changed

7 files changed

+146
-151
lines changed

README.md

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,17 @@ const items: TimelineItemsProps = [
4949

5050
The available properties of the `Timeline` component:
5151

52-
| Property | Type | Description | Default |
53-
| :---------------------- | :-------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- |
54-
| `items` | [`TimelineItemsProps`](#timelineitemsprops) | Array of timeline items | |
55-
| `positioning?` | `'alternating' \| 'left' \| 'right'` | How the items should be positioned relative to the timeline | `'alternating'` |
56-
| `gap?` | `number` | The horizontal gap between timeline items | 50 (`px`) |
57-
| `offset?` | `{ left?: number; right?: number } \| number` | Offset left or right items from the top (default offset when passing just a `number`: `right`) | 50 (`px`) |
58-
| `minMarkerGap?` | `number` | The minimum gap markers will have between each other | 50 (`px`) |
59-
| `defaultPointerOffset?` | `number` | The regular top offset pointers have to their item card | 40 (`px`) |
60-
| `dateLocal?` | `Local` | Date locale | |
61-
| `dateFormat?` | `string` | Specific date format according to date-fns [specification](https://date-fns.org/v2.29.3/docs/format). Ignored when passing a `string` as date | `'P'` |
62-
| `customMarker?` | `ReactElement` | Custom maker element replacing the default | |
63-
| `customPointer?` | `ReactElement` | Custom pointer element replacing the default | |
64-
| `styleConfig?` | [`StyleConfig`](#styleconfig) | Style config object for customizing timeline by setting css custom properties | |
65-
| `className?` | `string` | Additional class name | |
52+
| Property | Type | Description | Default |
53+
| :--------------- | :------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- |
54+
| `items` | [`TimelineItemsProps`](#timelineitemsprops) | Array of timeline items | |
55+
| `positioning?` | `'alternating' \| 'left' \| 'right'` | How the items should be positioned relative to the timeline | `'alternating'` |
56+
| `minMarkerGap?` | `number` | The minimum gap markers will have between each other | 50 (`px`) |
57+
| `dateLocal?` | `Local` | Date locale | |
58+
| `dateFormat?` | `string` | Specific date format according to date-fns [specification](https://date-fns.org/v2.29.3/docs/format). Ignored when passing a `string` as date | `'P'` |
59+
| `customMarker?` | `ReactElement` | Custom maker element replacing the default | |
60+
| `customPointer?` | `ReactElement` | Custom pointer element replacing the default | |
61+
| `styleConfig?` | [`StyleConfig`](#styleconfig) | Style config object for customizing timeline by setting css custom properties | |
62+
| `className?` | `string` | Additional class name | |
6663

6764
### TimelineItemsProps
6865

@@ -89,6 +86,11 @@ The style can either be passed as a javascript object...
8986
width?: string;
9087
color?: string;
9188
};
89+
gap?: string;
90+
offset?: {
91+
left?: string;
92+
right?: string;
93+
};
9294
marker?: {
9395
size?: string;
9496
color?: string;
@@ -97,6 +99,7 @@ The style can either be passed as a javascript object...
9799
pointer?: {
98100
height?: string;
99101
width?: string;
102+
offset?: string;
100103
};
101104
card?: {
102105
background?: string;
@@ -119,11 +122,15 @@ The style can either be passed as a javascript object...
119122
--marker-radius: 50%;
120123
--pointer-height: 2rem;
121124
--pointer-width: 1rem;
125+
--pointer-offset: 5rem;
122126
--card-background: whitesmoke;
123127
--card-radius: 0.1rem;
124128
--card-offset: 1rem;
125129
--card-shadow: unset;
126130
--card-padding: 1rem;
131+
--gap: 1rem;
132+
--offset-left: 0;
133+
--offset-right: 5rem;
127134
}
128135
```
129136

package-lock.json

Lines changed: 30 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/Timeline.css

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,57 @@
66
--marker-radius: 50%;
77
--pointer-height: 2rem;
88
--pointer-width: 1rem;
9+
--pointer-offset: 5rem;
910
--card-background: whitesmoke;
1011
--card-radius: 0.1rem;
1112
--card-offset: 1rem;
1213
--card-shadow: unset;
1314
--card-padding: 1rem;
15+
--gap: 1rem;
16+
--offset-left: 0;
17+
--offset-right: 5rem;
1418

1519
position: relative;
1620
}
1721

22+
.timeline {
23+
display: flex;
24+
}
25+
1826
.timeline__line {
19-
position: absolute;
2027
background-color: var(--line-color);
21-
width: var(--line-width);
22-
height: 100%;
23-
left: 50%;
24-
transform: translateX(-50%);
28+
min-width: var(--line-width);
29+
}
30+
31+
.timeline__items-container {
32+
display: flex;
33+
flex-direction: column;
34+
gap: var(--gap);
35+
flex: 1;
36+
}
37+
38+
.timeline__items-container--left {
39+
margin-top: var(--offset-left);
40+
}
41+
42+
.timeline__items-container--right {
43+
margin-top: var(--offset-right);
2544
}
2645

2746
.timeline-item {
28-
position: absolute;
29-
width: 50%;
47+
position: relative;
3048
display: flex;
3149
align-items: flex-start;
3250
transition: top 0.1s;
3351
gap: var(--card-offset);
3452
}
3553

36-
.timeline-item--left {
37-
left: 0;
54+
.timeline__items-container--left .timeline-item {
3855
flex-direction: row-reverse;
3956
}
4057

41-
.timeline-item--right {
42-
right: 0;
58+
.timeline-item__marker {
59+
margin-top: var(--pointer-offset);
4360
}
4461

4562
.timeline-item__marker:not(.timeline-item__marker--custom) {
@@ -49,11 +66,11 @@
4966
background-color: var(--marker-color);
5067
}
5168

52-
.timeline-item--left .timeline-item__marker {
53-
transform: translate(50%, -50%);
69+
.timeline__items-container--left .timeline-item .timeline-item__marker {
70+
transform: translate(calc(50% + var(--line-width) / 2), -50%);
5471
}
55-
.timeline-item--right .timeline-item__marker {
56-
transform: translate(-50%, -50%);
72+
.timeline__items-container--right .timeline-item .timeline-item__marker {
73+
transform: translate(calc(-50% - var(--line-width) / 2), -50%);
5774
}
5875

5976
.timeline-card {
@@ -81,8 +98,8 @@
8198
}
8299

83100
.timeline-card__pointer {
84-
transform: translate(100%, -50%);
85101
position: absolute;
102+
top: var(--pointer-offset);
86103
}
87104

88105
.timeline-card__pointer:not(.timeline-card__pointer--custom) {
@@ -92,33 +109,21 @@
92109
height: var(--pointer-height);
93110
}
94111

95-
.timeline-item--left .timeline-card__pointer {
112+
.timeline__items-container--left .timeline-item .timeline-card__pointer {
96113
right: 0;
114+
transform: translate(100%, -50%);
97115
}
98116

99-
.timeline-item--right .timeline-card__pointer {
117+
.timeline__items-container--right .timeline-item .timeline-card__pointer {
100118
transform: scaleX(-1) translate(100%, -50%);
101119
left: 0;
102120
}
103121

104-
/* left positioning */
105-
.timeline--left .timeline__line {
106-
left: 0;
107-
}
108-
109-
.timeline--left .timeline-item--right {
110-
left: 0;
111-
width: 100%;
122+
/* one sided positioning */
123+
.timeline--left .timeline__items-container--left {
124+
flex: 0;
112125
}
113126

114-
/* right positioning */
115-
.timeline--right .timeline__line {
116-
right: 0;
117-
left: unset;
118-
transform: translateX(50%);
119-
}
120-
121-
.timeline--right .timeline-item--left {
122-
right: 0;
123-
width: 100%;
127+
.timeline--right .timeline__items-container--right {
128+
flex: 0;
124129
}

src/components/Timeline.stories.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,17 @@ export const SpacingOptions: StoryObj<typeof Timeline> = {
160160
args: {
161161
items,
162162
...defaultTimelineConfig,
163-
gap: 100,
163+
styleConfig: {
164+
gap: '5rem',
165+
offset: {
166+
left: '10rem',
167+
right: '3rem',
168+
},
169+
pointer: {
170+
offset: '4rem',
171+
},
172+
},
164173
minMarkerGap: 150,
165-
offset: { left: 150, right: 50 },
166-
defaultPointerOffset: 60,
167174
},
168175
};
169176

0 commit comments

Comments
 (0)