From 6a6c0fa124176fbc7f917a4a6e21f2ae68819ac3 Mon Sep 17 00:00:00 2001
From: morimorimokenpi <52128219+morimorimokenpi@users.noreply.github.com>
Date: Tue, 29 Sep 2026 14:48:03 +0900
Subject: [PATCH 1/4] fix(VTimeline): scope connector styles to direct items
---
.../src/components/VTimeline/VTimeline.sass | 111 ++++++++++--------
.../__tests__/VTimeline.spec.browser.tsx | 44 +++++++
.../src/components/VTimeline/_mixins.sass | 8 +-
3 files changed, 107 insertions(+), 56 deletions(-)
diff --git a/packages/vuetify/src/components/VTimeline/VTimeline.sass b/packages/vuetify/src/components/VTimeline/VTimeline.sass
index f13cb729e6d..ea1ea8ef5d9 100644
--- a/packages/vuetify/src/components/VTimeline/VTimeline.sass
+++ b/packages/vuetify/src/components/VTimeline/VTimeline.sass
@@ -156,47 +156,50 @@
background: canvastext
.v-timeline-item:first-child
- .v-timeline-divider__before
- @include vertical
- height: $timeline-line-size
- top: 0
-
- @include horizontal
- width: $timeline-line-size
- inset-inline-start: 0
- inset-inline-end: initial
-
- .v-timeline-divider__after
- @include vertical
- height: $timeline-line-size-first-last
-
- @include horizontal
- width: $timeline-line-size-first-last
- inset-inline-end: $timeline-line-start
- inset-inline-start: initial
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
+ @include vertical
+ height: $timeline-line-size
+ top: 0
+
+ @include horizontal
+ width: $timeline-line-size
+ inset-inline-start: 0
+ inset-inline-end: initial
+
+ > .v-timeline-divider__after
+ @include vertical
+ height: $timeline-line-size-first-last
+
+ @include horizontal
+ width: $timeline-line-size-first-last
+ inset-inline-end: $timeline-line-start
+ inset-inline-start: initial
.v-timeline-item:last-child
- .v-timeline-divider__before
- @include vertical
- height: $timeline-line-size-first-last
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
+ @include vertical
+ height: $timeline-line-size-first-last
- @include horizontal
- width: $timeline-line-size-first-last
+ @include horizontal
+ width: $timeline-line-size-first-last
- .v-timeline-divider__after
- @include vertical
- height: calc(var(--v-timeline-line-size-base) + #{math.div($timeline-item-padding, 2)} - var(--v-timeline-line-inset))
- bottom: 0
+ > .v-timeline-divider__after
+ @include vertical
+ height: calc(var(--v-timeline-line-size-base) + #{math.div($timeline-item-padding, 2)} - var(--v-timeline-line-inset))
+ bottom: 0
- @include horizontal
- width: calc(var(--v-timeline-line-size-base) + #{math.div($timeline-item-padding, 2)} - var(--v-timeline-line-inset))
- inset-inline-end: 0
- inset-inline-start: initial
+ @include horizontal
+ width: calc(var(--v-timeline-line-size-base) + #{math.div($timeline-item-padding, 2)} - var(--v-timeline-line-inset))
+ inset-inline-end: 0
+ inset-inline-start: initial
.v-timeline-item:only-child
- .v-timeline-divider__after
- @include vertical
- height: calc(var(--v-timeline-line-size-base) - var(--v-timeline-line-inset))
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__after
+ @include vertical
+ height: calc(var(--v-timeline-line-size-base) - var(--v-timeline-line-inset))
.v-timeline-divider__dot
z-index: 1
@@ -373,16 +376,18 @@
$timeline-line-size-before: calc(var(--v-timeline-line-size-offset) + var(--v-timeline-dot-size) / 2 - var(--v-timeline-line-inset))
$timeline-line-size-after: calc(var(--v-timeline-line-size-base) - var(--v-timeline-dot-size) / 2 + var(--v-timeline-line-size-offset) - var(--v-timeline-line-inset))
- .v-timeline-item:first-child
- .v-timeline-divider__before
- --v-timeline-line-size-offset: #{$timeline-item-padding}
+ > .v-timeline-item:first-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
+ --v-timeline-line-size-offset: #{$timeline-item-padding}
- .v-timeline-divider__after
- --v-timeline-line-size-offset: -#{math.div($timeline-item-padding, 2)}
+ > .v-timeline-divider__after
+ --v-timeline-line-size-offset: -#{math.div($timeline-item-padding, 2)}
- .v-timeline-item:last-child
- .v-timeline-divider__after
- --v-timeline-line-size-offset: 0px
+ > .v-timeline-item:last-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__after
+ --v-timeline-line-size-offset: 0px
@include horizontal(true)
justify-items: flex-start
@@ -410,12 +415,13 @@
// Truncate start
.v-timeline--truncate-line-start
- .v-timeline-item:first-child
- .v-timeline-divider__before
- display: none
+ > .v-timeline-item:first-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
+ display: none
- .v-timeline-divider__after
- --v-timeline-line-size-offset: #{math.div($timeline-item-padding, 2)}
+ > .v-timeline-divider__after
+ --v-timeline-line-size-offset: #{math.div($timeline-item-padding, 2)}
@include vertical(true)
@include timeline-first-item()
@@ -427,12 +433,13 @@
// Truncate end
.v-timeline--truncate-line-end
- .v-timeline-item:last-child
- .v-timeline-divider__after
- display: none
+ > .v-timeline-item:last-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__after
+ display: none
- .v-timeline-divider__before
- --v-timeline-line-size-offset: #{math.div($timeline-item-padding, 2)}
+ > .v-timeline-divider__before
+ --v-timeline-line-size-offset: #{math.div($timeline-item-padding, 2)}
@include vertical(true)
@include timeline-last-item()
diff --git a/packages/vuetify/src/components/VTimeline/__tests__/VTimeline.spec.browser.tsx b/packages/vuetify/src/components/VTimeline/__tests__/VTimeline.spec.browser.tsx
index a413f37b4a9..82f2487b61c 100644
--- a/packages/vuetify/src/components/VTimeline/__tests__/VTimeline.spec.browser.tsx
+++ b/packages/vuetify/src/components/VTimeline/__tests__/VTimeline.spec.browser.tsx
@@ -92,6 +92,50 @@ describe('VTimeline', () => {
expect(timeline).toHaveClass('v-timeline--truncate-line-end')
})
+ it('should keep nested timeline connectors continuous when parent lines are truncated', async () => {
+ render(() => (
+
+
+
+ First nested item
+ Second nested item
+
+
+
+
+ First nested item
+ Second nested item
+
+
+
+ ))
+
+ await nextTick()
+
+ for (const timeline of screen.getAllByCSS('.nested-timeline')) {
+ const dividers = timeline.querySelectorAll(':scope > .v-timeline-item > .v-timeline-divider')
+ const firstBefore = dividers[0].querySelector(':scope > .v-timeline-divider__before')!
+ const after = dividers[0].querySelector(':scope > .v-timeline-divider__after')!
+ const before = dividers[1].querySelector(':scope > .v-timeline-divider__before')!
+ const lastAfter = dividers[dividers.length - 1].querySelector(':scope > .v-timeline-divider__after')!
+
+ expect(getComputedStyle(firstBefore).display).not.toBe('none')
+ expect(getComputedStyle(after).display).not.toBe('none')
+ expect(getComputedStyle(before).display).not.toBe('none')
+ expect(getComputedStyle(lastAfter).display).not.toBe('none')
+ expect(firstBefore.getBoundingClientRect().height).toBeGreaterThan(0)
+ expect(after.getBoundingClientRect().bottom).toBe(before.getBoundingClientRect().top)
+ expect(lastAfter.getBoundingClientRect().height).toBeGreaterThan(0)
+ }
+
+ const lastDivider = screen.getByCSS('.v-timeline:not(.nested-timeline) > .v-timeline-item:last-child > .v-timeline-divider')
+ const lastBefore = lastDivider.querySelector(':scope > .v-timeline-divider__before')!
+ const lastDot = lastDivider.querySelector(':scope > .v-timeline-divider__dot')!
+ const dotRect = lastDot.getBoundingClientRect()
+
+ expect(lastBefore.getBoundingClientRect().bottom).toBe(dotRect.top + dotRect.height / 2)
+ })
+
it('should support align', async () => {
const align = ref('center')
diff --git a/packages/vuetify/src/components/VTimeline/_mixins.sass b/packages/vuetify/src/components/VTimeline/_mixins.sass
index 7fee9d96eaf..2738b4d449e 100644
--- a/packages/vuetify/src/components/VTimeline/_mixins.sass
+++ b/packages/vuetify/src/components/VTimeline/_mixins.sass
@@ -17,11 +17,11 @@
@content
@mixin timeline-first-item()
- .v-timeline-item:first-child
- .v-timeline-divider, .v-timeline-item__body, .v-timeline-item__opposite
+ > .v-timeline-item:first-child
+ > .v-timeline-divider, > .v-timeline-item__body, > .v-timeline-item__opposite
@content
@mixin timeline-last-item()
- .v-timeline-item:last-child
- .v-timeline-divider, .v-timeline-item__body, .v-timeline-item__opposite
+ > .v-timeline-item:last-child
+ > .v-timeline-divider, > .v-timeline-item__body, > .v-timeline-item__opposite
@content
From a0cbb8d25f2b30f601cc89f40cbb3b515cc652bf Mon Sep 17 00:00:00 2001
From: J-Sek
Date: Tue, 29 Sep 2026 12:50:38 +0200
Subject: [PATCH 2/4] to simple for tests
---
.../__tests__/VTimeline.spec.browser.tsx | 44 -------------------
1 file changed, 44 deletions(-)
diff --git a/packages/vuetify/src/components/VTimeline/__tests__/VTimeline.spec.browser.tsx b/packages/vuetify/src/components/VTimeline/__tests__/VTimeline.spec.browser.tsx
index 82f2487b61c..a413f37b4a9 100644
--- a/packages/vuetify/src/components/VTimeline/__tests__/VTimeline.spec.browser.tsx
+++ b/packages/vuetify/src/components/VTimeline/__tests__/VTimeline.spec.browser.tsx
@@ -92,50 +92,6 @@ describe('VTimeline', () => {
expect(timeline).toHaveClass('v-timeline--truncate-line-end')
})
- it('should keep nested timeline connectors continuous when parent lines are truncated', async () => {
- render(() => (
-
-
-
- First nested item
- Second nested item
-
-
-
-
- First nested item
- Second nested item
-
-
-
- ))
-
- await nextTick()
-
- for (const timeline of screen.getAllByCSS('.nested-timeline')) {
- const dividers = timeline.querySelectorAll(':scope > .v-timeline-item > .v-timeline-divider')
- const firstBefore = dividers[0].querySelector(':scope > .v-timeline-divider__before')!
- const after = dividers[0].querySelector(':scope > .v-timeline-divider__after')!
- const before = dividers[1].querySelector(':scope > .v-timeline-divider__before')!
- const lastAfter = dividers[dividers.length - 1].querySelector(':scope > .v-timeline-divider__after')!
-
- expect(getComputedStyle(firstBefore).display).not.toBe('none')
- expect(getComputedStyle(after).display).not.toBe('none')
- expect(getComputedStyle(before).display).not.toBe('none')
- expect(getComputedStyle(lastAfter).display).not.toBe('none')
- expect(firstBefore.getBoundingClientRect().height).toBeGreaterThan(0)
- expect(after.getBoundingClientRect().bottom).toBe(before.getBoundingClientRect().top)
- expect(lastAfter.getBoundingClientRect().height).toBeGreaterThan(0)
- }
-
- const lastDivider = screen.getByCSS('.v-timeline:not(.nested-timeline) > .v-timeline-item:last-child > .v-timeline-divider')
- const lastBefore = lastDivider.querySelector(':scope > .v-timeline-divider__before')!
- const lastDot = lastDivider.querySelector(':scope > .v-timeline-divider__dot')!
- const dotRect = lastDot.getBoundingClientRect()
-
- expect(lastBefore.getBoundingClientRect().bottom).toBe(dotRect.top + dotRect.height / 2)
- })
-
it('should support align', async () => {
const align = ref('center')
From 19baa277d83189a4fb27b537adab117ff7a09199 Mon Sep 17 00:00:00 2001
From: morimorimokenpi <52128219+morimorimokenpi@users.noreply.github.com>
Date: Tue, 29 Sep 2026 20:52:19 +0900
Subject: [PATCH 3/4] fix(VTimeline): isolate nested layout styles
---
.../src/components/VTimeline/VTimeline.sass | 219 ++++++++++--------
1 file changed, 118 insertions(+), 101 deletions(-)
diff --git a/packages/vuetify/src/components/VTimeline/VTimeline.sass b/packages/vuetify/src/components/VTimeline/VTimeline.sass
index ea1ea8ef5d9..6c2709803a0 100644
--- a/packages/vuetify/src/components/VTimeline/VTimeline.sass
+++ b/packages/vuetify/src/components/VTimeline/VTimeline.sass
@@ -36,12 +36,12 @@
.v-timeline--side-end > .v-timeline-item,
&:not(.v-timeline--side-start) > .v-timeline-item--side-end,
&:not(.v-timeline--side-start) > .v-timeline-item:nth-child(2n+1):not(.v-timeline-item--side-start)
- .v-timeline-item__body
+ > .v-timeline-item__body
grid-row: 3
align-self: flex-start
padding-block-start: $timeline-item-padding
- .v-timeline-item__opposite
+ > .v-timeline-item__opposite
grid-row: 1
align-self: flex-end
padding-block-end: $timeline-item-padding
@@ -49,12 +49,12 @@
.v-timeline--side-start > .v-timeline-item,
&:not(.v-timeline--side-end) > .v-timeline-item--side-start,
&:not(.v-timeline--side-end) > .v-timeline-item:nth-child(2n):not(.v-timeline-item--side-end)
- .v-timeline-item__body
+ > .v-timeline-item__body
grid-row: 1
align-self: flex-end
padding-block-end: $timeline-item-padding
- .v-timeline-item__opposite
+ > .v-timeline-item__opposite
grid-row: 3
align-self: flex-start
padding-block-start: $timeline-item-padding
@@ -72,12 +72,12 @@
.v-timeline--side-start > .v-timeline-item,
&:not(.v-timeline--side-end) > .v-timeline-item--side-start,
&:not(.v-timeline--side-end) > .v-timeline-item:nth-child(2n):not(.v-timeline-item--side-end)
- .v-timeline-item__body
+ > .v-timeline-item__body
grid-column: 1
justify-self: flex-end
padding-inline-end: $timeline-item-padding
- .v-timeline-item__opposite
+ > .v-timeline-item__opposite
grid-column: 3
justify-self: flex-start
padding-inline-start: $timeline-item-padding
@@ -85,12 +85,12 @@
.v-timeline--side-end > .v-timeline-item,
&:not(.v-timeline--side-start) > .v-timeline-item--side-end,
&:not(.v-timeline--side-start) > .v-timeline-item:nth-child(2n+1):not(.v-timeline-item--side-start)
- .v-timeline-item__body
+ > .v-timeline-item__body
grid-column: 3
justify-self: flex-start
padding-inline-start: $timeline-item-padding
- .v-timeline-item__opposite
+ > .v-timeline-item__opposite
grid-column: 1
justify-self: flex-end
padding-inline-end: $timeline-item-padding
@@ -105,15 +105,19 @@
display: flex
align-items: center
- @include horizontal
- flex-direction: row
- grid-row: 2
- width: 100%
+ .v-timeline--horizontal
+ > :where(.v-timeline-item)
+ > .v-timeline-divider
+ flex-direction: row
+ grid-row: 2
+ width: 100%
- @include vertical
- height: 100%
- flex-direction: column
- grid-column: 2
+ .v-timeline--vertical
+ > :where(.v-timeline-item)
+ > .v-timeline-divider
+ height: 100%
+ flex-direction: column
+ grid-column: 2
$timeline-line-size: calc(var(--v-timeline-line-size-base) + #{math.div($timeline-item-padding, 2)} - var(--v-timeline-line-inset))
$timeline-line-start: math.div(-$timeline-item-padding, 2)
@@ -123,17 +127,6 @@
background: $timeline-divider-line-background
position: absolute
- @include horizontal
- height: $timeline-divider-line-thickness
- width: $timeline-line-size
- inset-inline-start: $timeline-line-start
- inset-inline-end: initial
-
- @include vertical
- height: $timeline-line-size
- width: $timeline-divider-line-thickness
- top: $timeline-line-start
-
@media (forced-colors: active)
background: canvastext
@@ -141,66 +134,84 @@
background: $timeline-divider-line-background
position: absolute
- @include horizontal
- height: $timeline-divider-line-thickness
- width: $timeline-line-size
- inset-inline-end: $timeline-line-start
- inset-inline-start: initial
-
- @include vertical
- height: $timeline-line-size
- width: $timeline-divider-line-thickness
- bottom: $timeline-line-start
-
@media (forced-colors: active)
background: canvastext
- .v-timeline-item:first-child
- > :where(.v-timeline-divider)
- > .v-timeline-divider__before
- @include vertical
+ .v-timeline--horizontal
+ > :where(.v-timeline-item)
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
+ height: $timeline-divider-line-thickness
+ width: $timeline-line-size
+ inset-inline-start: $timeline-line-start
+ inset-inline-end: initial
+
+ > .v-timeline-divider__after
+ height: $timeline-divider-line-thickness
+ width: $timeline-line-size
+ inset-inline-end: $timeline-line-start
+ inset-inline-start: initial
+
+ .v-timeline--vertical
+ > :where(.v-timeline-item)
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
+ height: $timeline-line-size
+ width: $timeline-divider-line-thickness
+ top: $timeline-line-start
+
+ > .v-timeline-divider__after
+ height: $timeline-line-size
+ width: $timeline-divider-line-thickness
+ bottom: $timeline-line-start
+
+ .v-timeline--vertical
+ > .v-timeline-item:first-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
height: $timeline-line-size
top: 0
- @include horizontal
+ > .v-timeline-divider__after
+ height: $timeline-line-size-first-last
+
+ > .v-timeline-item:last-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
+ height: $timeline-line-size-first-last
+
+ > .v-timeline-divider__after
+ height: calc(var(--v-timeline-line-size-base) + #{math.div($timeline-item-padding, 2)} - var(--v-timeline-line-inset))
+ bottom: 0
+
+ > .v-timeline-item:only-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__after
+ height: calc(var(--v-timeline-line-size-base) - var(--v-timeline-line-inset))
+
+ .v-timeline--horizontal
+ > .v-timeline-item:first-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
width: $timeline-line-size
inset-inline-start: 0
inset-inline-end: initial
- > .v-timeline-divider__after
- @include vertical
- height: $timeline-line-size-first-last
-
- @include horizontal
+ > .v-timeline-divider__after
width: $timeline-line-size-first-last
inset-inline-end: $timeline-line-start
inset-inline-start: initial
- .v-timeline-item:last-child
- > :where(.v-timeline-divider)
- > .v-timeline-divider__before
- @include vertical
- height: $timeline-line-size-first-last
-
- @include horizontal
+ > .v-timeline-item:last-child
+ > :where(.v-timeline-divider)
+ > .v-timeline-divider__before
width: $timeline-line-size-first-last
- > .v-timeline-divider__after
- @include vertical
- height: calc(var(--v-timeline-line-size-base) + #{math.div($timeline-item-padding, 2)} - var(--v-timeline-line-inset))
- bottom: 0
-
- @include horizontal
+ > .v-timeline-divider__after
width: calc(var(--v-timeline-line-size-base) + #{math.div($timeline-item-padding, 2)} - var(--v-timeline-line-inset))
inset-inline-end: 0
inset-inline-start: initial
- .v-timeline-item:only-child
- > :where(.v-timeline-divider)
- > .v-timeline-divider__after
- @include vertical
- height: calc(var(--v-timeline-line-size-base) - var(--v-timeline-line-inset))
-
.v-timeline-divider__dot
z-index: 1
flex-shrink: 0
@@ -272,8 +283,9 @@
&.v-timeline--side-start
grid-template-rows: $timeline-density-compact-grid-template-start
- .v-timeline-item__body
- grid-row: 1
+ > :where(.v-timeline-item)
+ > .v-timeline-item__body
+ grid-row: 1
@include vertical(true)
&.v-timeline--side-end
@@ -282,60 +294,61 @@
&.v-timeline--side-start
grid-template-columns: $timeline-density-compact-grid-template-start
- .v-timeline-item__body
- grid-column: 3
+ > :where(.v-timeline-item)
+ > .v-timeline-item__body
+ grid-column: 3
// Side
.v-timeline.v-timeline--side-end
- .v-timeline-item
+ > .v-timeline-item
@include horizontal(true)
- .v-timeline-item__body
+ > .v-timeline-item__body
grid-row: 3
align-self: flex-start
padding-block-end: initial
padding-block-start: $timeline-item-padding
- .v-timeline-item__opposite
+ > .v-timeline-item__opposite
grid-row: 1
align-self: flex-end
padding-block-end: $timeline-item-padding
padding-block-start: initial
@include vertical(true)
- .v-timeline-item__body
+ > .v-timeline-item__body
grid-column: 3
justify-self: flex-start
padding-inline-start: $timeline-item-padding
padding-inline-end: initial
- .v-timeline-item__opposite
+ > .v-timeline-item__opposite
grid-column: 1
justify-self: flex-end
padding-inline-end: $timeline-item-padding
padding-inline-start: initial
.v-timeline.v-timeline--side-start
- .v-timeline-item
+ > .v-timeline-item
@include horizontal(true)
- .v-timeline-item__body
+ > .v-timeline-item__body
grid-row: 1
align-self: flex-end
padding-block-end: $timeline-item-padding
padding-block-start: initial
- .v-timeline-item__opposite
+ > .v-timeline-item__opposite
grid-row: 3
align-self: flex-start
padding-block-end: initial
padding-block-start: $timeline-item-padding
@include vertical(true)
- .v-timeline-item__body
+ > .v-timeline-item__body
grid-column: 1
justify-self: flex-end
padding-inline-end: $timeline-item-padding
- .v-timeline-item__opposite
+ > .v-timeline-item__opposite
grid-column: 3
justify-self: flex-start
padding-inline-start: $timeline-item-padding
@@ -354,20 +367,22 @@
@include horizontal(true)
justify-items: center
- .v-timeline-item__body
- padding-inline: math.div($timeline-item-padding, 2)
+ > :where(.v-timeline-item)
+ > .v-timeline-item__body
+ padding-inline: math.div($timeline-item-padding, 2)
- .v-timeline-item__opposite
- padding-inline: math.div($timeline-item-padding, 2)
+ > .v-timeline-item__opposite
+ padding-inline: math.div($timeline-item-padding, 2)
- .v-timeline-divider
- justify-content: center
+ > .v-timeline-divider
+ justify-content: center
@include vertical(true)
align-items: center
- .v-timeline-divider
- justify-content: center
+ > :where(.v-timeline-item)
+ > .v-timeline-divider
+ justify-content: center
.v-timeline--align-start
--v-timeline-line-size-base: 100%
@@ -392,26 +407,28 @@
@include horizontal(true)
justify-items: flex-start
- .v-timeline-divider
- justify-content: flex-start
+ > :where(.v-timeline-item)
+ > .v-timeline-divider
+ justify-content: flex-start
- .v-timeline-divider__before
- width: $timeline-line-size-before
+ > .v-timeline-divider__before
+ width: $timeline-line-size-before
- .v-timeline-divider__after
- width: $timeline-line-size-after
+ > .v-timeline-divider__after
+ width: $timeline-line-size-after
@include vertical(true)
align-items: flex-start
- .v-timeline-divider
- justify-content: flex-start
+ > :where(.v-timeline-item)
+ > .v-timeline-divider
+ justify-content: flex-start
- .v-timeline-divider__before
- height: $timeline-line-size-before
+ > .v-timeline-divider__before
+ height: $timeline-line-size-before
- .v-timeline-divider__after
- height: $timeline-line-size-after
+ > .v-timeline-divider__after
+ height: $timeline-line-size-after
// Truncate start
.v-timeline--truncate-line-start
From 17f653b8cf975f0bf5f21a84e83d7134f48c37eb Mon Sep 17 00:00:00 2001
From: J-Sek
Date: Tue, 29 Sep 2026 17:36:21 +0200
Subject: [PATCH 4/4] chore: simplify mixins
---
.../src/components/VTimeline/VTimeline.sass | 44 +++++++++----------
.../src/components/VTimeline/_mixins.sass | 18 ++------
2 files changed, 26 insertions(+), 36 deletions(-)
diff --git a/packages/vuetify/src/components/VTimeline/VTimeline.sass b/packages/vuetify/src/components/VTimeline/VTimeline.sass
index 6c2709803a0..f15a7a12899 100644
--- a/packages/vuetify/src/components/VTimeline/VTimeline.sass
+++ b/packages/vuetify/src/components/VTimeline/VTimeline.sass
@@ -29,7 +29,7 @@
grid-auto-flow: dense
position: relative
- @include horizontal(true)
+ @include horizontal
grid-column-gap: $timeline-item-padding
width: 100%
@@ -59,7 +59,7 @@
align-self: flex-start
padding-block-start: $timeline-item-padding
- @include vertical(true)
+ @include vertical
row-gap: $timeline-item-padding
height: 100%
@@ -242,22 +242,22 @@
// Justify
.v-timeline--justify-center
- @include horizontal(true)
+ @include horizontal
grid-template-rows: $timeline-item-grid-template-center
- @include vertical(true)
+ @include vertical
grid-template-columns: $timeline-item-grid-template-center
.v-timeline--justify-auto
- @include horizontal(true)
+ @include horizontal
grid-template-rows: $timeline-item-grid-template-auto
- @include vertical(true)
+ @include vertical
grid-template-columns: $timeline-item-grid-template-auto
// Density
.v-timeline--density-comfortable
- @include horizontal(true)
+ @include horizontal
height: 100%
&.v-timeline--side-end
@@ -266,7 +266,7 @@
&.v-timeline--side-start
grid-template-rows: $timeline-density-comfortable-grid-template-start
- @include vertical(true)
+ @include vertical
width: 100%
&.v-timeline--side-end
@@ -276,7 +276,7 @@
grid-template-columns: $timeline-density-comfortable-grid-template-start
.v-timeline--density-compact
- @include horizontal(true)
+ @include horizontal
&.v-timeline--side-end
grid-template-rows: $timeline-density-compact-grid-template-end
@@ -287,7 +287,7 @@
> .v-timeline-item__body
grid-row: 1
- @include vertical(true)
+ @include vertical
&.v-timeline--side-end
grid-template-columns: $timeline-density-compact-grid-template-end
@@ -301,7 +301,7 @@
// Side
.v-timeline.v-timeline--side-end
> .v-timeline-item
- @include horizontal(true)
+ @include horizontal
> .v-timeline-item__body
grid-row: 3
align-self: flex-start
@@ -314,7 +314,7 @@
padding-block-end: $timeline-item-padding
padding-block-start: initial
- @include vertical(true)
+ @include vertical
> .v-timeline-item__body
grid-column: 3
justify-self: flex-start
@@ -329,7 +329,7 @@
.v-timeline.v-timeline--side-start
> .v-timeline-item
- @include horizontal(true)
+ @include horizontal
> .v-timeline-item__body
grid-row: 1
align-self: flex-end
@@ -342,7 +342,7 @@
padding-block-end: initial
padding-block-start: $timeline-item-padding
- @include vertical(true)
+ @include vertical
> .v-timeline-item__body
grid-column: 1
justify-self: flex-end
@@ -364,7 +364,7 @@
--v-timeline-line-size-base: 50%
--v-timeline-line-size-offset: 0px
- @include horizontal(true)
+ @include horizontal
justify-items: center
> :where(.v-timeline-item)
@@ -377,7 +377,7 @@
> .v-timeline-divider
justify-content: center
- @include vertical(true)
+ @include vertical
align-items: center
> :where(.v-timeline-item)
@@ -404,7 +404,7 @@
> .v-timeline-divider__after
--v-timeline-line-size-offset: 0px
- @include horizontal(true)
+ @include horizontal
justify-items: flex-start
> :where(.v-timeline-item)
@@ -417,7 +417,7 @@
> .v-timeline-divider__after
width: $timeline-line-size-after
- @include vertical(true)
+ @include vertical
align-items: flex-start
> :where(.v-timeline-item)
@@ -440,11 +440,11 @@
> .v-timeline-divider__after
--v-timeline-line-size-offset: #{math.div($timeline-item-padding, 2)}
- @include vertical(true)
+ @include vertical
@include timeline-first-item()
padding-block-start: 0
- @include horizontal(true)
+ @include horizontal
@include timeline-first-item()
padding-inline-start: 0
@@ -458,10 +458,10 @@
> .v-timeline-divider__before
--v-timeline-line-size-offset: #{math.div($timeline-item-padding, 2)}
- @include vertical(true)
+ @include vertical
@include timeline-last-item()
padding-block-end: 0
- @include horizontal(true)
+ @include horizontal
@include timeline-last-item()
padding-inline-end: 0
diff --git a/packages/vuetify/src/components/VTimeline/_mixins.sass b/packages/vuetify/src/components/VTimeline/_mixins.sass
index 2738b4d449e..5fb7e48b4e2 100644
--- a/packages/vuetify/src/components/VTimeline/_mixins.sass
+++ b/packages/vuetify/src/components/VTimeline/_mixins.sass
@@ -1,19 +1,9 @@
-@mixin vertical($immediate: false)
- $selector: '.v-timeline--vertical'
- @if $immediate
- $selector: '#{$selector}#{&}'
- @else
- $selector: '#{$selector} #{&}'
- @at-root #{$selector}
+@mixin vertical()
+ @at-root .v-timeline--vertical#{&}
@content
-@mixin horizontal($immediate: false)
- $selector: '.v-timeline--horizontal'
- @if $immediate
- $selector: '#{$selector}#{&}'
- @else
- $selector: '#{$selector} #{&}'
- @at-root #{$selector}
+@mixin horizontal()
+ @at-root .v-timeline--horizontal#{&}
@content
@mixin timeline-first-item()