swisspost / design-system

The Swiss Post Design System pattern library for a consistent and accessible user experience across the web platform.
https://design-system.post.ch
Apache License 2.0
120 stars 14 forks source link

[component]: Toggle button #3744

Open gfellerph opened 4 days ago

gfellerph commented 4 days ago

Create a toggle button component. A toggle button can toggle between two states, like a play/pause button, and display two different sets of content for each state.

Design

Not yet designed as a separate component, but can be seen in the Header design: https://www.figma.com/design/JIT5AdGYqv6bDRpfBPV8XR/Foundations-%26-Components-Next-Level?node-id=2932-36996&t=LkHqwQB91Cng98Vy-4

Requirements

Proposed markup

<post-togglebutton>
  <span slot=toggled>X Menu</span>
  <span slot=untoggled>= Menu</span> <!-- Default slot -->
</post-togglebutton>

The idea of this component is the possibility to switch the content based on it's state.

gfellerph commented 2 days ago

POC component:

post-togglebutton.tsx

import {
  Component,
  Host,
  Prop,
  Watch,
  h,
  Element,
  Listen,
  Event,
  EventEmitter,
} from '@stencil/core';
import { version } from '@root/package.json';

@Component({
  tag: 'post-togglebutton',
  styleUrl: 'post-togglebutton.scss',
  shadow: true,
})
export class PostTogglebutton {
  @Element() host: HTMLPostTogglebuttonElement;

  /**
   * Emit a toggled event containing the current state as payload on `event.details`
   */
  @Event() toggledEvent: EventEmitter<boolean>;

  /**
   * Button state
   */
  // eslint-disable-next-line @stencil-community/strict-mutable
  @Prop({ reflect: true, mutable: true }) toggled: boolean;
  @Watch('toggled')
  toggleChange() {
    this.host.setAttribute('aria-pressed', `${this.toggled}`);
    this.toggledEvent.emit(this.toggled);
  }

  @Listen('click', { passive: true })
  handleClick() {
    this.toggled = !this.toggled;
  }

  @Listen('keydown', { passive: true })
  handleKeydown(event: KeyboardEvent) {
    if (event.key === 'Enter') {
      this.toggled = !this.toggled;
    }
  }

  render() {
    return (
      <Host slot="post-togglebutton" tabindex="0" role="button" version={version}>
        <slot name="untoggled"></slot>
        <slot name="toggled"></slot>
      </Host>
    );
  }
}

post-togglebutton.scss

:host {
  cursor: default;
}

slot[name='toggled'] {
  display: none;
}

:host-context([toggled]) {
  slot[name='untoggled'] {
    display: none;
  }

  slot[name='toggled'] {
    display: contents;
  }
}