Skip to content

Commit

Permalink
feat: add animations
Browse files Browse the repository at this point in the history
  • Loading branch information
dauriamarco committed Mar 15, 2024
1 parent 6392c44 commit ed60a52
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 29 deletions.
4 changes: 4 additions & 0 deletions src/components/stepper/step-label/step-label.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
transition: background-color var(--sbb-animation-duration-6x) ease;
}

.sbb-step-label__text {
text-wrap: nowrap;
}

sbb-icon {
z-index: 1;
background-color: var(--sbb-step-label-prefix-background-color);
Expand Down
4 changes: 2 additions & 2 deletions src/components/stepper/step-label/step-label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ export class SbbStepLabelElement extends SbbIconNameMixin(
protected override render(): TemplateResult {
return html`
<div class="sbb-step-label">
<div class="sbb-step-label__prefix">${this.renderIconSlot()}</div>
<slot></slot>
<span class="sbb-step-label__prefix">${this.renderIconSlot()}</span>
<span class="sbb-step-label__text"><slot></slot></span>
</div>
`;
}
Expand Down
55 changes: 52 additions & 3 deletions src/components/stepper/step/step.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,62 @@
@include sbb.host-component-properties;

:host {
--sbb-step-display: none;
--sbb-step-position: initial;
--sbb-step-inset-block-start: unset;
--sbb-step-opacity: 0;
--sbb-step-visibility: hidden;
--sbb-step-height: 0;
--sbb-step-animation-duration: var(--sbb-animation-duration-2x);
--sbb-step-animation-delay: 0;

display: contents;
}

:host([data-selected]) {
--sbb-step-display: block;
--sbb-step-opacity: 1;
--sbb-step-visibility: visible;
--sbb-step-height: fit-content;
--sbb-step-animation-duration: var(--sbb-animation-duration-4x);
--sbb-step-animation-delay: var(--sbb-step-animation-duration);
}

:host([data-orientation='horizontal']) {
--sbb-step-position: absolute;
--sbb-step-inset-block-start: 0;
}

.sbb-step--wrapper {
:host([data-orientation='vertical']) & {
opacity: 0;
height: 0;
transition:
height var(--sbb-stepper-animation-duration) var(--sbb-animation-easing),
opacity var(--sbb-step-animation-duration) var(--sbb-animation-easing);
}

:host([data-selected][data-orientation='vertical']) & {
opacity: 1;
height: var(--sbb-stepper-content-height);
transition:
height var(--sbb-stepper-animation-duration) var(--sbb-animation-easing),
opacity var(--sbb-step-animation-duration) var(--sbb-stepper-animation-duration)
var(--sbb-animation-easing);
}
}

.sbb-step {
display: var(--sbb-step-display);
@include sbb.text-m--regular;

position: var(--sbb-step-position);
inset-block-start: var(--sbb-step-inset-block-start);
opacity: var(--sbb-step-opacity);
visibility: var(--sbb-step-visibility);
height: var(--sbb-step-height);
color: var(--sbb-color-iron);
transition: {
property: opacity, visibility;
duration: var(--sbb-step-animation-duration);
delay: var(--sbb-step-animation-delay);
timing-function: var(--sbb-animation-easing);
}
}
26 changes: 24 additions & 2 deletions src/components/stepper/step/step.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { customElement } from 'lit/decorators.js';
import { hostAttributes } from '../../core/common-behaviors';
import { isValidAttribute } from '../../core/dom';
import { ConnectedAbortController, EventEmitter } from '../../core/eventing';
import { AgnosticResizeObserver } from '../../core/observers';
import type { SbbStepLabelElement } from '../step-label';
import type { SbbStepperElement } from '../stepper';

Expand Down Expand Up @@ -43,6 +44,9 @@ export class SbbStepElement extends LitElement {
private _abort = new ConnectedAbortController(this);
private _stepper: SbbStepperElement | null = null;
private _label: SbbStepLabelElement | null = null;
private _stepResizeObserver = new AgnosticResizeObserver((entries) =>
this._onStepElementResize(entries),
);

public get label(): SbbStepLabelElement | null {
return this._label;
Expand Down Expand Up @@ -71,6 +75,16 @@ export class SbbStepElement extends LitElement {
return element.hasAttribute('sbb-stepper-previous') && !isValidAttribute(element, 'disabled');
}

private _onStepElementResize(entries: ResizeObserverEntry[]): void {
if (!this.hasAttribute('data-selected')) {
return;
}
for (const entry of entries) {
const contentHeight = Math.floor(entry.contentRect.height);
this._stepper?.style?.setProperty('--sbb-stepper-content-height', `${contentHeight}px`);
}
}

public override connectedCallback(): void {
super.connectedCallback();
const signal = this._abort.signal;
Expand All @@ -83,15 +97,23 @@ export class SbbStepElement extends LitElement {
}

protected override firstUpdated(): void {
this._stepResizeObserver.observe(this.shadowRoot!.querySelector('.sbb-step')!);
if (this.label) {
this.setAttribute('aria-labelledby', this.label.id);
}
}

public override disconnectedCallback(): void {
super.disconnectedCallback();
this._stepResizeObserver.disconnect();
}

protected override render(): TemplateResult {
return html`
<div class="sbb-step">
<slot></slot>
<div class="sbb-step--wrapper">
<div class="sbb-step">
<slot></slot>
</div>
</div>
`;
}
Expand Down
27 changes: 24 additions & 3 deletions src/components/stepper/stepper/stepper.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

.sbb-stepper {
width: 100%;
text-wrap: nowrap;
}

.sbb-stepper__labels {
Expand All @@ -45,7 +44,7 @@
inset-block-end: 0;
height: #{sbb.px-to-rem-build(3)};
width: var(--sbb-stepper-marker-size);
transition: width var(--sbb-animation-duration-6x) ease-in-out;
transition: width var(--sbb-stepper-animation-duration) var(--sbb-animation-easing);
}
}

Expand All @@ -57,17 +56,33 @@
inset-block-start: 0;
width: #{sbb.px-to-rem-build(3)};
height: var(--sbb-stepper-marker-size);
transition: height var(--sbb-animation-duration-6x) ease-in-out;
transition: height var(--sbb-stepper-animation-duration) var(--sbb-animation-easing);
}
}
}

.sbb-stepper__steps {
position: relative;

:host([orientation='horizontal']) & {
height: var(--sbb-stepper-content-height);
transition: height var(--sbb-stepper-animation-duration) var(--sbb-animation-easing);
}
}

::slotted(sbb-step-label) {
@include sbb.text-xxs--regular;

max-width: fit-content;

:host([orientation='vertical']) & {
transition: margin var(--sbb-stepper-animation-duration) var(--sbb-animation-easing);
}

&::before {
content: counter(step-label);
counter-increment: step-label;
cursor: pointer;
position: absolute;
inset-block-start: calc(var(--sbb-step-label-prefix-size) / 2);
inset-inline-start: calc(var(--sbb-step-label-prefix-size) / 2);
Expand All @@ -76,6 +91,12 @@
}
}

::slotted(sbb-step) {
:host([orientation='vertical']) & {
transition: margin var(--sbb-stepper-animation-duration) var(--sbb-animation-easing);
}
}

::slotted(sbb-step-label[data-selected]) {
@include sbb.text-xxs--bold;

Expand Down
51 changes: 46 additions & 5 deletions src/components/stepper/stepper/stepper.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { withActions } from '@storybook/addon-actions/decorator';
import type { InputType } from '@storybook/types';
import type { Args, ArgTypes, Decorator, Meta, StoryObj } from '@storybook/web-components';
import { html, type TemplateResult } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';

import { sbbSpread } from '../../core/dom';
import { SbbStepElement } from '../step';
Expand Down Expand Up @@ -45,31 +46,71 @@ const defaultArgs: Args = {
'horizontal-from': 'unset',
};

const textBlockStyle: Args = {
position: 'relative',
marginBlockStart: 'var(--sbb-spacing-fixed-8x)',
padding: 'var(--sbb-spacing-fixed-4x)',
backgroundColor: 'var(--sbb-color-milk)',
border: 'var(--sbb-border-width-1x) solid var(--sbb-color-cloud)',
borderRadius: 'var(--sbb-border-radius-4x)',
zIndex: '100',
};

const textBlock = (): TemplateResult => html`
<div style=${styleMap(textBlockStyle)}>
Page content: lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
</div>
`;

const Template = (args: Args): TemplateResult => html`
<sbb-stepper ${sbbSpread(args)} aria-label="Purpose of this flow" selected-index="0">
<sbb-step-label>Step 1</sbb-step-label>
<sbb-step>
First step content. &nbsp;
<div style="margin-block-end: var(--sbb-spacing-fixed-4x)">
First step content: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
sanctus est Lorem ipsum dolor sit amet.
</div>
<sbb-button size="m" sbb-stepper-next>Next</sbb-button>
</sbb-step>
<sbb-step-label>Step 2</sbb-step-label>
<sbb-step>
Second step content. &nbsp;
<div style="margin-block-end: var(--sbb-spacing-fixed-4x)">
Second step content: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea
takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur
sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam
erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita
kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</div>
<sbb-secondary-button size="m" sbb-stepper-previous>Back</sbb-secondary-button>
<sbb-button size="m" sbb-stepper-next>Next</sbb-button>
</sbb-step>
<sbb-step-label icon-name="tick-small">Step 3</sbb-step-label>
<sbb-step>
Third step content. &nbsp;
<div style="margin-block-end: var(--sbb-spacing-fixed-4x)">
Third step content: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
</div>
<sbb-secondary-button size="m" sbb-stepper-previous>Back</sbb-secondary-button>
<sbb-button size="m" sbb-stepper-next>Next</sbb-button>
</sbb-step>
<sbb-step-label>Step 4</sbb-step-label>
<sbb-step>
Forth step content. &nbsp;
<div style="margin-block-end: var(--sbb-spacing-fixed-4x)">
Forth step content: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing
elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed
diam voluptua.
</div>
<sbb-secondary-button size="m" sbb-stepper-previous>Back</sbb-secondary-button>
<sbb-button size="m" sbb-stepper-next>Submit</sbb-button>
</sbb-step>
Expand Down Expand Up @@ -106,7 +147,7 @@ export const HorizontalFromSmall: StoryObj = {

const meta: Meta = {
decorators: [
(story) => html` <div style="padding: 2rem;">${story()}</div> `,
(story) => html` <div style="padding: 2rem;">${story()} ${textBlock()}</div> `,
withActions as Decorator,
],
parameters: {
Expand Down
35 changes: 21 additions & 14 deletions src/components/stepper/stepper/stepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,17 @@ export class SbbStepperElement extends LitElement {
}

private _setMarkerSize(): void {
if (!this.selected || !this.selected.label) {
if (!this.selected || this.selectedIndex === undefined || !this.selected.label) {
return;
}
const offset =
this.orientation === 'horizontal'
? this.selected.label.offsetLeft + this.selected.label.offsetWidth
: this.selected.label.offsetTop + this.selected.label.offsetHeight;
this.style?.setProperty('--sbb-stepper-marker-size', `${offset}px`);
: this.selected.label.offsetHeight * (this.selectedIndex + 1) +
parseFloat(getComputedStyle(this).getPropertyValue('--sbb-spacing-responsive-m')) *
16 *
this.selectedIndex;
this.style.setProperty('--sbb-stepper-marker-size', `${offset}px`);
}

private _configure(): void {
Expand All @@ -150,33 +153,37 @@ export class SbbStepperElement extends LitElement {
}

private _checkOrientation(): void {
this.orientation = isBreakpoint(this.horizontalFrom) ? 'horizontal' : 'vertical';
this.steps.forEach((s) => (s.slot = this.orientation === 'horizontal' ? 'step' : 'step-label'));
if (this.horizontalFrom) {
this.orientation = isBreakpoint(this.horizontalFrom) ? 'horizontal' : 'vertical';
this.steps.forEach(
(s) => (s.slot = this.orientation === 'horizontal' ? 'step' : 'step-label'),
);
}
setTimeout(() => this._setMarkerSize(), 0);
}

public override connectedCallback(): void {
super.connectedCallback();
const signal = this._abort.signal;
if (this.horizontalFrom) {
window.addEventListener('resize', () => this._checkOrientation(), {
signal,
passive: true,
});
}
window.addEventListener('resize', () => this._checkOrientation(), {
signal,
passive: true,
});
}

protected override async firstUpdated(): Promise<void> {
this._configure();
await this.updateComplete;
this.selectedIndex = !this.linear ? Number(this.getAttribute('selected-index')) || 0 : 0;
this._checkOrientation();
}

protected override willUpdate(changedProperties: PropertyValues<this>): void {
if (changedProperties.has('orientation') && !this.horizontalFrom) {
this.steps.forEach(
(s) => (s.slot = this.orientation === 'horizontal' ? 'step' : 'step-label'),
);
this.steps.forEach((step) => {
step.slot = this.orientation === 'horizontal' ? 'step' : 'step-label';
step.setAttribute('data-orientation', this.orientation);
});
this._setMarkerSize();
}
}
Expand Down

0 comments on commit ed60a52

Please sign in to comment.