Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion packages/api-generator/src/locale/en/VRow.json
Comment thread
J-Sek marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
"justifySm": "Deprecated, use **justify-sm-\\*** class",
"justifyXl": "Deprecated, use **justify-xl-\\*** class",
"justifyXxl": "Deprecated, use **justify-xxl-\\*** class",
"gap": "Sets the gap between `v-col`s. Can be a single value for both row and column gap, or the array of two values [column gap, row gap].",
"gap": "Gap between columns, expects value in pixels. One value for both axes, or [column gap, row gap].",
"gapSm": "Overrides **gap** from the **sm** breakpoint up, in pixels.",
"gapMd": "Overrides **gap** from the **md** breakpoint up, in pixels.",
"gapLg": "Overrides **gap** from the **lg** breakpoint up, in pixels.",
"gapXl": "Overrides **gap** from the **xl** breakpoint up, in pixels.",
"gapXxl": "Overrides **gap** from the **xxl** breakpoint up, in pixels.",
"noGutters": "Removes the gutter between `v-col`s (same as `gap='0'`).",
"size": "Sets the number of columns."
}
Expand Down
5 changes: 5 additions & 0 deletions packages/docs/src/data/new-in.json
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,11 @@
},
"VRow": {
"props": {
"gapSm": "4.3.0",
"gapMd": "4.3.0",
"gapLg": "4.3.0",
"gapXl": "4.3.0",
"gapXxl": "4.3.0",
"size": "4.0.0"
}
},
Expand Down
5 changes: 5 additions & 0 deletions packages/vuetify/src/components/VGrid/VGrid.sass
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ $false: ' '
margin-inline-start: calc($offset * (100% + $gap) / $offsetCols)

@include make-grid-columns using ($infix)
// must stay after density and no-gutters rules to override them
.v-row--gap#{$infix}
--v-col-gap-x: var(--v-row-gap-x#{$infix})
--v-col-gap-y: var(--v-row-gap-y#{$infix})

@if $infix != ''
.v-col-#{$infix}
--v-col-is-size: #{$false}
Expand Down
44 changes: 27 additions & 17 deletions packages/vuetify/src/components/VGrid/VRow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import './VGrid.sass'
// Composables
import { makeComponentProps } from '@/composables/component'
import { makeDensityProps } from '@/composables/density'
import { breakpoints } from '@/composables/display'
import { makeTagProps } from '@/composables/tag'

// Utilities
Expand Down Expand Up @@ -32,6 +33,10 @@ const propMap = {
alignContent: ['alignContent', 'alignContentSm', 'alignContentMd', 'alignContentLg', 'alignContentXl', 'alignContentXxl'],
}

const gapProps = ['gap', 'gapSm', 'gapMd', 'gapLg', 'gapXl', 'gapXxl'] as const

type Gap = number | string | (string | number)[]

const classMap = {
align: 'align',
justify: 'justify',
Expand Down Expand Up @@ -94,7 +99,12 @@ export const makeVRowProps = propsFactory({
alignContentXxl: { type: String as PropType<typeof ALIGN_CONTENT_VALUES[number]>, default: null, validator: alignContentValidator },

noGutters: Boolean,
gap: [Number, String, Array] as PropType<number | string | (string | number)[]>,
gap: [Number, String, Array] as PropType<Gap>,
gapSm: [Number, String, Array] as PropType<Gap>,
gapMd: [Number, String, Array] as PropType<Gap>,
gapLg: [Number, String, Array] as PropType<Gap>,
gapXl: [Number, String, Array] as PropType<Gap>,
gapXxl: [Number, String, Array] as PropType<Gap>,
size: [Number, String],
...makeComponentProps(),
...makeDensityProps(),
Expand Down Expand Up @@ -137,30 +147,30 @@ export const VRow = genericComponent()({
return classList
})

const horizontalGap = computed(() => {
return (Array.isArray(props.gap))
? convertToUnit(props.gap[0] || 0)
: convertToUnit(props.gap)
})

const verticalGap = computed(() => {
return (Array.isArray(props.gap))
? convertToUnit(props.gap[1] || 0)
: horizontalGap.value
})
const gaps = computed(() => gapProps.flatMap((prop, i) => {
const value = props[prop]
if (value == null) return []
const infix = i ? `-${breakpoints[i - 1]}` : ''
const [x, y] = Array.isArray(value) ? [value[0] || 0, value[1] || 0] : [value, value]
return [{
class: `v-row--gap${infix}`,
style: {
[`--v-row-gap-x${infix}`]: convertToUnit(x),
[`--v-row-gap-y${infix}`]: convertToUnit(y),
},
}]
}))

return () => h(props.tag, {
class: [
'v-row',
classes.value,
gaps.value.map(gap => gap.class),
props.class,
],
style: [
{
'--v-col-gap-x': horizontalGap.value,
'--v-col-gap-y': verticalGap.value,
'--v-row-columns': props.size,
},
{ '--v-row-columns': props.size },
gaps.value.map(gap => gap.style),
props.style,
],
}, slots.default?.())
Expand Down
Comment thread
J-Sek marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { VRow } from '../VRow'
import { VCol } from '../VCol'

// Utilities
import { page, render, screen } from '@test'

describe('VRow', () => {
describe('responsive gap', () => {
function renderRow () {
render(() => (
<VRow gap={ 8 } gapLg={[32, 16]} noGutters>
<VCol cols="4" data-testid="col-1" />
<VCol cols="8" data-testid="col-2" />
<VCol cols="12" data-testid="col-3" />
</VRow>
))
return [1, 2, 3].map(i => screen.getByTestId(`col-${i}`).getBoundingClientRect())
}

it('uses base gap below the breakpoint', async () => {
await page.viewport(500, 800)
const [first, second, third] = renderRow()

expect(second.top).toBe(first.top)
expect(second.left - first.right).toBeCloseTo(8)
expect(third.top - first.bottom).toBeCloseTo(8)
})

it('switches gap at the breakpoint and keeps columns on one line', async () => {
await page.viewport(1400, 800)
const [first, second, third] = renderRow()

expect(second.top).toBe(first.top)
expect(second.left - first.right).toBeCloseTo(32)
expect(third.top - first.bottom).toBeCloseTo(16)
})

it('does not leak into nested rows', async () => {
await page.viewport(1400, 800)
render(() => (
<VRow gapLg="40">
<VCol>
<VRow>
<VCol data-testid="nested-1" />
<VCol data-testid="nested-2" />
</VRow>
</VCol>
</VRow>
))
const first = screen.getByTestId('nested-1').getBoundingClientRect()
const second = screen.getByTestId('nested-2').getBoundingClientRect()

expect(second.left - first.right).toBeCloseTo(24)
})
})
})
Loading