Skip to content

Commit

Permalink
Refactor(web): Refactor placement transformation to allow input of lo…
Browse files Browse the repository at this point in the history
…gical placements
  • Loading branch information
adamkudrna committed May 10, 2024
1 parent e316f53 commit 1b9e665
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 43 deletions.
14 changes: 7 additions & 7 deletions packages/web/src/scss/tools/__tests__/_dictionaries.test.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,24 @@

inset: auto auto 100% 0;
translate: var(--test-offset-orthogonal, 0) calc(-1 * var(--test-offset, 0));
transform-origin: bottom;
transform-origin: bottom left;
}
}
}

@include true.assert {
@include true.output {
@include dictionaries.generate-placements('Test', ('top-start'));
@include dictionaries.generate-placements('Test', ('right-end'));
}

@include true.expect {
.Test[data-spirit-placement='top-start'],
.Test--topStart {
.Test[data-spirit-placement='right-end'],
.Test--rightEnd {
--test-offset: 0;

inset: auto auto 100% 0;
translate: var(--test-offset-orthogonal, 0) calc(-1 * var(--test-offset, 0));
transform-origin: bottom;
inset: auto auto 0 100%;
translate: var(--test-offset, 0) var(--test-offset-orthogonal, 0);
transform-origin: left bottom;
}
}
}
Expand Down
144 changes: 132 additions & 12 deletions packages/web/src/scss/tools/__tests__/_placement.test.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,143 @@
@use '../placement';

@include true.describe('placement functions and mixins') {
@include true.it('should return correct inverse placements') {
@include true.it('should return correct cross axis direction') {
@include true.assert {
@include true.output {
$inverse-top: placement.inverse('top');
$inverse-bottom-start: placement.inverse('bottom-start');
$inverse-left-end: placement.inverse('left-end');
--cross-axis-direction-left: #{placement.get-cross-axis-direction('left')};
--cross-axis-direction-bottom: #{placement.get-cross-axis-direction('bottom')};
}
@include true.expect {
--cross-axis-direction-left: vertical;
--cross-axis-direction-bottom: horizontal;
}
}
}

@include true.it('should return true for logical placements, false otherwise') {
@include true.assert {
@include true.output {
--is-logical-left: #{placement.is-logical('left')};
--is-logical-start: #{placement.is-logical('start')};
}
@include true.expect {
--is-logical-left: false;
--is-logical-start: true;
}
}
}

@include true.it('should return correct physical placement') {
@include true.assert {
@include true.output {
--logical-to-physical-start-horizontal: #{placement.translate-logical-to-physical('start', 'horizontal')};
--logical-to-physical-start-vertical: #{placement.translate-logical-to-physical('start', 'vertical')};
}
@include true.expect {
--logical-to-physical-start-horizontal: left;
--logical-to-physical-start-vertical: top;
}
}
}

// Testing with main-axis-only and hyphenation
$inverse-top-start-hyphen: placement.inverse('top-start', true, true);
$inverse-top-start-space: placement.inverse('top-start', true, false);
@include true.it('should return transformed axis') {
@include true.assert {
@include true.output {
--transform-axis-left: #{placement.transform-axis('left')};
--transform-axis-left-inverse: #{placement.transform-axis('left', $inverse: true)};
--transform-axis-left-physical: #{placement.transform-axis('left', $physical-direction: 'horizontal')};
--transform-axis-left-physical-inverse: #{placement.transform-axis(
'left',
$inverse: true,
$physical-direction: 'horizontal'
)};
--transform-axis-start: #{placement.transform-axis('start')};
--transform-axis-start-inverse: #{placement.transform-axis('start', $inverse: true)};
--transform-axis-start-physical: #{placement.transform-axis('start', $physical-direction: 'horizontal')};
--transform-axis-start-physical-inverse: #{placement.transform-axis(
'start',
$inverse: true,
$physical-direction: 'horizontal'
)};
}
@include true.expect {
$inverse-top: 'bottom';
$inverse-bottom-start: 'top';
$inverse-left-end: 'right';
$inverse-top-start-hyphen: 'bottom-start';
$inverse-top-start-space: 'bottom start';
--transform-axis-left: left;
--transform-axis-left-inverse: right;
--transform-axis-left-physical: left;
--transform-axis-left-physical-inverse: right;
--transform-axis-start: start;
--transform-axis-start-inverse: end;
--transform-axis-start-physical: left;
--transform-axis-start-physical-inverse: right;
}
}
}

@include true.describe('should return transformed placement') {
@include true.it('physical only') {
@include true.assert {
@include true.output {
--transform-left: #{placement.transform('left')};
--transform-left-top: #{placement.transform('left-top')};
--transform-left-top-main-axis-inverse: #{placement.transform('left-top', $main-axis-inverse: true)};
--transform-left-top-main-axis-inverse-cross-axis-inverse: #{placement.transform(
'left-top',
$main-axis-inverse: true,
$cross-axis-inverse: true
)};
--transform-left-top-main-axis-inverse-cross-axis-inverse-physical: #{placement.transform(
'left-top',
$main-axis-inverse: true,
$cross-axis-inverse: true,
$cross-axis-physical: true
)};
--transform-left-top-spaces: #{placement.transform('left-top', $join-with: ' ')};
}
@include true.expect {
--transform-left: left;
--transform-left-top: left-top;
--transform-left-top-main-axis-inverse: right-top;
--transform-left-top-main-axis-inverse-cross-axis-inverse: right-bottom;
--transform-left-top-main-axis-inverse-cross-axis-inverse-physical: right-bottom;
--transform-left-top-spaces: left top;
}
}
}

@include true.it('physical and logical') {
@include true.assert {
@include true.output {
--transform-top-start: #{placement.transform('top-start')};
--transform-top-start-main-axis-inverse: #{placement.transform(
'top-start',
$main-axis-inverse: true
)};
--transform-top-start-main-axis-inverse-cross-axis-inverse: #{placement.transform(
'top-start',
$main-axis-inverse: true,
$cross-axis-inverse: true
)};
--transform-top-start-main-axis-inverse-cross-axis-physical: #{placement.transform(
'top-start',
$main-axis-inverse: true,
$cross-axis-physical: true
)};
--transform-top-start-main-axis-inverse-cross-axis-inverse-physical: #{placement.transform(
'top-start',
$main-axis-inverse: true,
$cross-axis-inverse: true,
$cross-axis-physical: true
)};
--transform-top-start-spaces: #{placement.transform('top-start', $join-with: ' ')};
}
@include true.expect {
--transform-top-start: top-start;
--transform-top-start-main-axis-inverse: bottom-start;
--transform-top-start-main-axis-inverse-cross-axis-inverse: bottom-end;
--transform-top-start-main-axis-inverse-cross-axis-physical: bottom-left;
--transform-top-start-main-axis-inverse-cross-axis-inverse-physical: bottom-right;
--transform-top-start-spaces: top start;
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/scss/tools/_dictionaries.scss
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@
// @deprecated CSS modifier classes are deprecated and will be removed in the next major version
// Migration: delete this selector
.#{$class-name}--#{$placement-modifier} > .#{$class-name}__arrow {
@include placement.arrow-variant($prefix, placement.inverse($placement, $main-axis-only: true));
@include placement.arrow-variant($prefix, placement.transform($placement, $main-axis-inverse: true));
}
}
}
Expand Down
117 changes: 94 additions & 23 deletions packages/web/src/scss/tools/_placement.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
@use 'sass:string';
@use 'list' as spirit-list;

$_hyphen: '-';

$_arrow-rotate-map: (
top: 0deg,
top-start: 0deg,
Expand Down Expand Up @@ -50,13 +52,29 @@ $_inset-map: (
right-end: auto auto 0 100%,
);

$_placement-inverse-map: (
$_physical-placement-inverse-map: (
top: bottom,
bottom: top,
left: right,
right: left,
);

$_logical-placement-inverse-map: (
start: end,
end: start,
);

$_logical-to-physical-placement-map: (
horizontal: (
start: left,
end: right,
),
vertical: (
start: top,
end: bottom,
),
);

@function -get-arrow-translate-map($prefix) {
@return (
top: -50% 0%,
Expand Down Expand Up @@ -102,31 +120,82 @@ $_placement-inverse-map: (
);
}

// Function to return an inverse placement name
// Example: inverse('top') will return 'bottom'
// Example: inverse('top-start') will return 'bottom'
// Example: inverse('top-start', true) will return 'bottom-start'
// Example: inverse('top-start', true, false) will return 'bottom start'
@function inverse($placement, $main-axis-only: false, $hyphenate: true) {
$hyphen: '-';
$placement-chunks: string.split($placement, $hyphen);
$placement-inverse-chunks: ();
$join-with: if($hyphenate, $hyphen, ' ');

@for $i from 1 through list.length($placement-chunks) {
$chunk: list.nth($placement-chunks, $i);
$new-chunk: null;

@if $main-axis-only and $i > 1 {
$new-chunk: $chunk;
} @else {
$new-chunk: map.get($_placement-inverse-map, $chunk);
// Function to get the cross-axis direction
// Example: get-cross-axis-direction('left') will return 'vertical'
// Example: get-cross-axis-direction('bottom') will return 'horizontal'
@function get-cross-axis-direction($main-axis) {
@return if(string.index($main-axis, 'left') or string.index($main-axis, 'right'), 'vertical', 'horizontal');
}

// Function to check if a placement is logical
// Example: is-logical('top') will return false
// Example: is-logical('start') will return true
@function is-logical($placement) {
@return if(string.index($placement, 'start') or string.index($placement, 'end'), true, false);
}

// Function to translate logical placement to its physical equivalent
// Example: translate-logical-to-physical('start', $direction: 'horizontal') will return 'left'
@function translate-logical-to-physical($logical, $direction) {
@return map.get($_logical-to-physical-placement-map, $direction, $logical);
}

// Function to transform axis
// Example: transform-axis('left') will return 'left' (no transformation)
// Example: transform-axis('left', $inverse: true) will return 'right'
// Example: transform-axis('start', $inverse: false, $physical-direction: 'horizontal') will return 'left'
// Example: transform-axis('start', $inverse: true, $physical-direction: 'horizontal') will return 'right'
@function transform-axis($axis, $inverse: false, $physical-direction: null) {
$axis-transformed: $axis;

@if is-logical($axis-transformed) {
@if $inverse {
$axis-transformed: map.get($_logical-placement-inverse-map, $axis);
}

@if $physical-direction {
$axis-transformed: translate-logical-to-physical($axis-transformed, $physical-direction);
}
} @else if $inverse {
$axis-transformed: map.get($_physical-placement-inverse-map, $axis);
}

@return $axis-transformed;
}

// Function to transform placement
// Example: transform('top-start') will return 'top-start' (no transformation)
// Example: transform('top-start', $main-axis-inverse: true) will return 'bottom-start'
// Example: transform('top-start', $main-axis-inverse: true, $cross-axis-inverse: true) will return 'bottom-end'
// Example: transform('top-start', $main-axis-inverse: true, $cross-axis-inverse: true, $cross-axis-physical: true) will return 'bottom-right'
// Example: transform('top-start', $join-with: ' ') will return 'top start'
@function transform(
$placement,
$main-axis-inverse: false,
$cross-axis-inverse: false,
$cross-axis-physical: false,
$join-with: $_hyphen
) {
$placement-chunks: string.split($placement, $_hyphen);
$main-axis: list.nth($placement-chunks, 1);
$main-axis-transformed: transform-axis(
$axis: $main-axis,
$inverse: $main-axis-inverse,
);

$placement-inverse-chunks: list.append($placement-inverse-chunks, $new-chunk);
@if list.length($placement-chunks) > 1 {
$cross-axis: list.nth($placement-chunks, 2);
$cross-axis-direction: get-cross-axis-direction($main-axis);
$cross-axis-transformed: transform-axis(
$axis: $cross-axis,
$inverse: $cross-axis-inverse,
$physical-direction: if($cross-axis-physical, $cross-axis-direction, null),
);

@return spirit-list.to-string(($main-axis-transformed, $cross-axis-transformed), $join-with);
}

@return spirit-list.to-string($placement-inverse-chunks, $join-with);
@return $main-axis-transformed;
}

@mixin parent() {
Expand All @@ -143,7 +212,9 @@ $_placement-inverse-map: (

inset: map.get($_inset-map, $placement); // 1.2
translate: map.get(-get-child-translate-map($prefix), $placement); // 1.3
transform-origin: string.unquote(inverse($placement, $hyphenate: false));
transform-origin: string.unquote(
transform($placement, $main-axis-inverse: true, $cross-axis-physical: true, $join-with: ' ')
);
}

@mixin child-controlled($prefix, $offset) {
Expand Down

0 comments on commit 1b9e665

Please sign in to comment.