Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(documentation, styles): Add animated button icon on the left #2865

Merged
Merged
6 changes: 6 additions & 0 deletions .changeset/six-owls-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@swisspost/design-system-documentation': minor
'@swisspost/design-system-styles': minor
---

Added the option for a Button animation to the left.
davidritter-dotcom marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const meta: MetaComponent = {
type: 'button',
variant: 'btn-primary',
size: 'null',
animated: true,
animated: 'btn-animated',
icon: 'null',
iconOnly: false,
iconPosition: 'start',
Expand Down Expand Up @@ -121,14 +121,20 @@ const meta: MetaComponent = {
},
animated: {
name: 'Animated',
description: 'When set to `true`, the component animates on hover.',
description: 'Sets an animation on hover.',
if: {
arg: 'icon',
eq: 'null',
},
control: {
type: 'boolean',
type: 'inline-radio',
labels: {
'null': 'None',
'btn-animated': 'End',
'btn-animated-start': 'Start',
},
},
options: ['null', 'btn-animated', 'btn-animated-start'],
table: {
category: 'General',
},
Expand Down Expand Up @@ -215,7 +221,7 @@ type Story = StoryObj;
const Template = {
render: (args: Args) => {
const tagName = unsafeStatic(args.tag);
const isAnimated = args.tag !== 'input' && args.animated;
const isAnimated = args.tag !== 'input' && args.animated !== 'none';
const props = createProps(args, isAnimated);

if (args.tag === 'input') {
Expand Down Expand Up @@ -244,7 +250,7 @@ function createProps(args: Args, isAnimated: boolean) {
'btn',
args.variant,
args.size,
isAnimated && 'btn-animated',
args.animated,
args.iconOnly && 'btn-icon',
...additionalClasses,
]
Expand Down
101 changes: 74 additions & 27 deletions packages/styles/src/components/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@use './../variables/type';
@use './../variables/spacing';
@use './../mixins/color' as color-mx;
@use './../mixins/icons';
@use './../mixins/icons' as icon-mx;
@use './../mixins/utilities';
@use './../mixins/forms';
@use './../mixins/button' as button-mx;
Expand Down Expand Up @@ -138,37 +138,60 @@
}

// Animated

.btn-animated,
.btn-animated-start {
&:not(.btn-link, .btn-tertiary) {
&::after {
@include icon-mx.icon(2111);
content: '';
display: block;
height: 2em;
width: 2em;
position: absolute;
transition:
opacity 250ms,
transform 250ms;
opacity: 0;
}

> span {
transition: transform 250ms;
}

@media (prefers-reduced-motion: no-preference) {
@include utilities.not-disabled-focus-hover() {
&::after {
transform: translateX(0);
opacity: 1;
}
}

> span {
// Initially transform to place text in the right rendering context for a smooth animation
transform: translateX(0);
}
}
}
}

.btn-animated:not(.btn-link, .btn-tertiary) {
&::after {
content: '';
position: absolute;
right: button.$btn-padding-x-md - button.$btn-animation-distance-md;
width: 0.625em;
height: 0.625em;
transform: rotateZ(315deg)
translate(button.$btn-border-width * -1, button.$btn-border-width * -1);
transform-origin: center center;
transition:
opacity 250ms,
transform 250ms;
border-right: button.$btn-border-width solid currentColor;
border-bottom: button.$btn-border-width solid currentColor;
opacity: 0;
right: button.$btn-padding-x-md - button.$btn-animation-distance-md -
(button.$btn-font-size-md * 2 / 3);
transform: translateX(button.$btn-border-width * -1);
}

@each $size in button.$btn-non-default-sizes {
&.btn-#{$size}::after {
right: map.get(button.$btn-padding-x-map, $size) - map.get(
button.$btn-animation-distance-map,
$size
);
) -
(map.get(button.$btn-font-size-map, $size) * 2 / 3);
}
}

> span {
transition: transform 250ms;
}

// Only animate when user prefers to see animations
@media (prefers-reduced-motion: no-preference) {
@include utilities.not-disabled-focus-hover() {
Expand All @@ -181,16 +204,40 @@
transform: translateX(map.get(button.$btn-animation-distance-map, $size) * -1);
}
}
}
}
}

&::after {
transform: rotateZ(315deg) translate(0, 0);
opacity: 1;
}
.btn-animated-start:not(.btn-link, .btn-tertiary) {
&::after {
@include icon-mx.icon(2110);
left: button.$btn-padding-x-md - button.$btn-animation-distance-md -
(button.$btn-font-size-md * 2 / 3);
transform: translateX(button.$btn-border-width);
}

@each $size in button.$btn-non-default-sizes {
&.btn-#{$size}::after {
left: map.get(button.$btn-padding-x-map, $size) - map.get(
button.$btn-animation-distance-map,
$size
) -
(map.get(button.$btn-font-size-map, $size) * 2 / 3);
}
}

> span {
// Initially transform to place text in the right rendering context for a smooth animation
transform: translateX(0);
// Only animate when user prefers to see animations
@media (prefers-reduced-motion: no-preference) {
@include utilities.not-disabled-focus-hover() {
> span {
transform: translateX(map.get(button.$btn-animation-distance-map, md));
}

@each $size in button.$btn-non-default-sizes {
&.btn-#{$size} > span {
transform: translateX(map.get(button.$btn-animation-distance-map, $size));
}
}
}
}
}
Expand Down
Loading