fbredius/storybook

View on GitHub
examples/web-components-kitchen-sink/src/components/sb-button.ts

Summary

Maintainability
A
1 hr
Test Coverage
import { css, html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';

/**
 * @attr {string} label - Label of the button
 * @attr {string} size - Size of the button, can be "small", "medium" or "large"; default is "medium".
 * @attr {string} backgroundColor - Color of the button's background
 *
 * @cssprop [--sb-primary-color=#1ea7fd] - Controls the color of bar
 *
 * @prop {boolean} primary - Set button in primary mode
 *
 * @event {CustomEvent} sb-button:click - Custom event send when the button is clicked
 *
 * @summary This is a simple Storybook Button
 *
 * @tag sb-button
 */
@customElement('sb-button')
export class SbButton extends LitElement {
  static get styles() {
    return css`
      .storybook-button {
        font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
        font-weight: 700;
        border: 0;
        border-radius: 3em;
        cursor: pointer;
        display: inline-block;
        line-height: 1;
      }
      .storybook-button--primary {
        color: white;
        background-color: var(--sb-primary-color, #1ea7fd);
      }
      .storybook-button--secondary {
        color: #333;
        background-color: transparent;
        box-shadow: rgba(0, 0, 0, 0.15) 0 0 0 1px inset;
      }
      .storybook-button--small {
        font-size: 12px;
        padding: 10px 16px;
      }
      .storybook-button--medium {
        font-size: 14px;
        padding: 11px 20px;
      }
      .storybook-button--large {
        font-size: 16px;
        padding: 12px 24px;
      }
    `;
  }

  // Currently TS decorators are not reflected so we have to use static `properties` function
  // https://github.com/Polymer/lit-html/issues/1476
  static get properties() {
    return {
      label: { type: String, reflect: true },
      primary: { type: Boolean },
      size: { type: String },
      backgroundColor: { type: String, attribute: 'background-color' },
    };
  }

  primary?: boolean;

  backgroundColor?: string;

  // FIXME: default value is overridden by `undefined` when the attribute isn't
  // defined in Story's args
  size: 'small' | 'medium' | 'large' = 'medium';

  label = '';

  private onClick() {
    const options = {
      bubbles: true,
      composed: true,
    };
    this.dispatchEvent(new CustomEvent('sb-button:click', options));
  }

  render() {
    const mode = this.primary ? 'storybook-button--primary' : 'storybook-button--secondary';
    const style = styleMap({ backgroundColor: this.backgroundColor ?? null });

    return html`
      <button
        type="button"
        class=${['storybook-button', `storybook-button--${this.size ?? 'medium'}`, mode].join(' ')}
        style=${style}
        @click="${this.onClick}"
      >
        ${this.label}
      </button>
    `;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'sb-button': SbButton;
  }
}