Skip to content

Commit

Permalink
Refactor(web): Unify generation of responsive spacing and alignment i…
Browse files Browse the repository at this point in the history
…n layout components #DS-1423

In `Flex`, `Grid`, and `Stack` components:

- responsive spacing is now generated exclusively with the spacing tools,
- responsive alignment is now generated exclusively with the dictionary tools.
  • Loading branch information
adamkudrna authored and crishpeen committed Nov 5, 2024
1 parent cbc0e86 commit f546b9c
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 130 deletions.
5 changes: 2 additions & 3 deletions packages/web/src/scss/components/Flex/_Flex.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// 2. Use `display: grid` so the orientation of alignmentX and alignmentY does not change as it would with `flex-direction: column`.
// 3. Generate both `wrap` and `noWrap` classes to enable mobile-first and breakpoint-specific wrapping at the same time.

@use 'sass:string';
@use '../../tools/breakpoint';
@use '../../tools/dictionaries';
@use '../../tools/reset';
Expand All @@ -12,8 +11,8 @@
.Flex {
@include reset.list();
@include spacing.create(
$input-property-base-name: '--flex-spacing',
$output-property-name: '--flex-gap',
$responsive-property-base-name: '--flex-spacing',
$breakpoints: theme.$breakpoints,
$default-spacing: theme.$gap
);
Expand All @@ -26,7 +25,7 @@
// stylelint-disable-next-line selector-max-universal -- Let's be bold and tweak all direct descendants regardless of their type to avoid inheritance of spacing for nested Flex.
.Flex > * {
@include spacing.prevent-inheritance(
$responsive-property-base-name: '--flex-spacing',
$input-property-base-names: '--flex-spacing',
$breakpoints: theme.$breakpoints
);
}
Expand Down
83 changes: 62 additions & 21 deletions packages/web/src/scss/components/Grid/_Grid.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
@use 'sass:map';
// 1. For each breakpoint, generate:
//
// a) responsive alignment classes for both axes,
// b) `grid-template-columns` values for the equal-column Grid variant,
// c) responsive GridItem classes.

@use '../../tools/breakpoint';
@use '../../tools/dictionaries';
@use '../../tools/reset';
@use '../../tools/string' as spirit-string;
@use '../../tools/spacing';
@use 'theme';
@use 'tools';

Expand All @@ -11,39 +17,74 @@
width: 100%;

@include reset.list();
@include tools.spacings(theme.$grid-spacings, theme.$breakpoints);
@include spacing.create(
$input-property-base-name: '--grid-spacing-x',
$output-property-name: '--grid-column-gap',
$property: 'column-gap',
$breakpoints: theme.$breakpoints,
$default-spacing: theme.$grid-spacings
);
@include spacing.create(
$input-property-base-name: '--grid-spacing-y',
$output-property-name: '--grid-row-gap',
$property: 'row-gap',
$breakpoints: theme.$breakpoints,
$default-spacing: theme.$grid-spacings
);
}

// stylelint-disable-next-line selector-max-universal -- Let's be bold and reset spacing for all direct descendants regardless of their type to avoid inheritance of spacing for nested Grid.
.Grid > * {
@each $breakpoint-name, $breakpoint-value in theme.$breakpoints {
@if $breakpoint-value > 0 {
--grid-spacing-x-#{$breakpoint-name}: initial;
--grid-spacing-y-#{$breakpoint-name}: initial;
} @else {
--grid-spacing-x: initial;
--grid-spacing-y: initial;
}
}
@include spacing.prevent-inheritance(
$input-property-base-names: (
'--grid-spacing-x',
'--grid-spacing-y',
),
$breakpoints: theme.$breakpoints
);
}

// 1.
@each $breakpoint-name, $breakpoint-value in theme.$breakpoints {
$infix: breakpoint.get-modifier('infix', $breakpoint-name, $breakpoint-value);

@include breakpoint.up($breakpoint-value) {
@each $alignment-name, $alignment-value in theme.$alignments-x {
.Grid--#{$infix}#{spirit-string.convert-kebab-case-to-camel-case(alignment-x-#{$alignment-name})} {
justify-items: $alignment-value;
}
}
// 1.a
@include dictionaries.generate-alignments(
$class-name: 'Grid',
$dictionary-values: theme.$alignment-x-dictionary,
$axis: 'x',
$property: 'justify-items',
$infix: $infix
);
@include dictionaries.generate-alignments(
$class-name: 'Grid',
$dictionary-values: theme.$alignment-y-dictionary,
$axis: 'y',
$infix: $infix
);

@each $alignment-name, $alignment-value in theme.$alignments-y {
.Grid--#{$infix}#{spirit-string.convert-kebab-case-to-camel-case(alignment-y-#{$alignment-name})} {
align-items: $alignment-value;
// 1.b
@each $column in theme.$grid-equal-columns {
.Grid--#{breakpoint.get-modifier('infix', $breakpoint-name, $breakpoint-value)}cols-#{$column} {
grid-template-columns: repeat(#{$column}, 1fr);
}
}
}
}

@include tools.equal-columns(theme.$grid-equal-columns, theme.$breakpoints);
// 1.c
@include tools.item(theme.$breakpoints);

// stylelint-disable-next-line selector-max-universal -- Let's be bold and reset spacing for all direct descendants regardless of their type to avoid inheritance of spacing for nested GridItem.
.GridItem > * {
@include spacing.prevent-inheritance(
$input-property-base-names: (
'--grid-item-column-start',
'--grid-item-column-end',
'--grid-item-row-start',
'--grid-item-row-end',
),
$breakpoints: theme.$breakpoints
);
}
14 changes: 2 additions & 12 deletions packages/web/src/scss/components/Grid/_theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,8 @@
@use '@tokens' as tokens;
@use '../../settings/dictionaries';

$alignments-x: (
stretch: stretch,
left: start,
center: center,
right: end,
);
$alignments-y: (
stretch: stretch,
top: start,
center: center,
bottom: end,
);
$alignment-x-dictionary: dictionaries.$alignments-x-extended;
$alignment-y-dictionary: dictionaries.$alignments-y-extended;

$breakpoints: tokens.$breakpoints;

Expand Down
66 changes: 0 additions & 66 deletions packages/web/src/scss/components/Grid/_tools.scss
Original file line number Diff line number Diff line change
@@ -1,60 +1,5 @@
@use 'sass:map';
@use 'sass:string';
@use '../../tools/breakpoint';

// Generates column-gap and row-gap values for each breakpoint
// Parameters are:
// * $spacings: the gaps map
// * $breakpoints: the breakpoints map
@mixin spacings($spacings, $breakpoints) {
$gap-fallback: map.get($spacings, 'mobile');

$column-property-name: '--grid-spacing-x';
$row-property-name: '--grid-spacing-y';

$column-fallback: var(--grid-default-gap, #{$gap-fallback});
$row-fallback: var(--grid-default-gap, #{$gap-fallback});

@each $breakpoint-name, $breakpoint-value in $breakpoints {
@if not map.has-key($spacings, $breakpoint-name) {
@error 'Invalid breakpoint specified! #{$breakpoint-name} doesn\'t exist. Use one of #{map.keys($breakpoints)}';
}

@if $breakpoint-value > 0 {
$column-property-name: --grid-spacing-x-#{$breakpoint-name};
$row-property-name: --grid-spacing-y-#{$breakpoint-name};
}

@include breakpoint.up($breakpoint-value) {
--grid-default-gap: #{map.get($spacings, $breakpoint-name)};
--grid-column-gap: var(#{string.unquote($column-property-name)}, #{$column-fallback});
--grid-row-gap: var(#{string.unquote($row-property-name)}, #{$row-fallback});
}

$column-fallback: var(#{string.unquote($column-property-name)}, #{$column-fallback});
$row-fallback: var(#{string.unquote($row-property-name)}, #{$row-fallback});
}

grid-column-gap: var(--grid-column-gap);
grid-row-gap: var(--grid-row-gap);
}

// Generates grid-template-columns values for each breakpoint in equal columns Grid
// Parameters are:
// * $grid-equal-columns: the list of columns to generate
// * $breakpoints: the breakpoints map
@mixin equal-columns($column-count, $breakpoints) {
@each $breakpoint-name, $breakpoint-value in $breakpoints {
@include breakpoint.up($breakpoint-value) {
@each $column in $column-count {
.Grid--#{breakpoint.get-modifier('infix', $breakpoint-name, $breakpoint-value)}cols-#{$column} {
grid-template-columns: repeat(#{$column}, 1fr);
}
}
}
}
}

// Generates grid-column values for each breakpoint with fallbacks to the previous breakpoint.
// Parameters are:
// * $breakpoints: the breakpoints map
Expand All @@ -81,15 +26,4 @@
}
}
}

:where(.GridItem .GridItem) {
@each $breakpoint-name, $breakpoint-value in $breakpoints {
$suffix: breakpoint.get-modifier('suffix', $breakpoint-name, $breakpoint-value);

--grid-item-column-start#{$suffix}: initial;
--grid-item-column-end#{$suffix}: initial;
--grid-item-row-start#{$suffix}: initial;
--grid-item-row-end#{$suffix}: initial;
}
}
}
7 changes: 2 additions & 5 deletions packages/web/src/scss/components/Stack/_Stack.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
@use 'sass:math';
@use 'sass:string';
@use '../../tools/breakpoint';
@use '../../tools/reset';
@use '../../tools/spacing';
@use 'theme';
Expand All @@ -13,8 +10,8 @@

.Stack--hasSpacing {
@include spacing.create(
$input-property-base-name: '--stack-spacing',
$output-property-name: '--stack-gap',
$responsive-property-base-name: '--stack-spacing',
$breakpoints: theme.$breakpoints,
$default-spacing: theme.$spacing-fallback
);
Expand All @@ -37,7 +34,7 @@

.Stack--hasSpacing > * {
@include spacing.prevent-inheritance(
$responsive-property-base-name: '--stack-spacing',
$input-property-base-names: '--stack-spacing',
$breakpoints: theme.$breakpoints
);
}
Expand Down
7 changes: 4 additions & 3 deletions packages/web/src/scss/tools/__tests__/_dictionaries.test.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@
@include dictionaries.generate-alignments(
$class-name: 'Test',
$dictionary-values: (
'space-between',
'stretch',
),
$axis: 'x',
$property: 'justify-items',
$infix: 'tablet--'
);
}

@include test.expect() {
.Test--tablet--alignmentXSpaceBetween {
justify-content: space-between;
.Test--tablet--alignmentXStretch {
justify-items: stretch;
}
}
}
Expand Down
76 changes: 71 additions & 5 deletions packages/web/src/scss/tools/__tests__/_spacing.test.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
@include test.output() {
.test {
@include spacing.create(
$input-property-base-name: '--test-input',
$output-property-name: '--test-output',
$responsive-property-base-name: '--test-spacing',
$breakpoints: (
'mobile': 0,
'tablet': 768px,
Expand All @@ -20,26 +20,64 @@

@include test.expect() {
.test {
--test-output: var(--test-spacing, 16px);
--test-output: var(--test-input, 16px);

gap: var(--test-output);
}

@media (width >= 768px) {
.test {
--test-output: var(--test-spacing-tablet, var(--test-spacing, 16px));
--test-output: var(--test-input-tablet, var(--test-input, 16px));
}
}
}
}
}

@include test.it('should set up correct prevention of nested spacing') {
@include test.it('should return correct spacing cascade with responsive default spacing') {
@include test.assert() {
@include test.output() {
.test {
@include spacing.create(
$input-property-base-name: '--test-input',
$output-property-name: '--test-output',
$property: 'column-gap',
$breakpoints: (
'mobile': 0,
'tablet': 768px,
),
$default-spacing: (
'mobile': 16px,
'tablet': 32px,
)
);
}
}

@include test.expect() {
.test {
--test-output-default: 16px;
--test-output: var(--test-input, var(--test-output-default, 16px));

column-gap: var(--test-output);
}

@media (width >= 768px) {
.test {
--test-output-default: 32px;
--test-output: var(--test-input-tablet, var(--test-input, var(--test-output-default, 16px)));
}
}
}
}
}

@include test.it('should set up correct prevention of spacing inheritance') {
@include test.assert() {
@include test.output() {
.nested {
@include spacing.prevent-inheritance(
$responsive-property-base-name: '--test-spacing',
$input-property-base-names: '--test-spacing',
$breakpoints: (
'mobile': 0,
'tablet': 768px,
Expand All @@ -56,4 +94,32 @@
}
}
}

@include test.it('should set up correct prevention of spacing inheritance with multiple properties') {
@include test.assert() {
@include test.output() {
.nested {
@include spacing.prevent-inheritance(
$input-property-base-names: (
'--test-spacing-x',
'--test-spacing-y',
),
$breakpoints: (
'mobile': 0,
'tablet': 768px,
)
);
}
}

@include test.expect() {
.nested {
--test-spacing-x: initial;
--test-spacing-y: initial;
--test-spacing-x-tablet: initial;
--test-spacing-y-tablet: initial;
}
}
}
}
}
Loading

0 comments on commit f546b9c

Please sign in to comment.