Skip to content
Snippets Groups Projects
hy-box.tsx 4.08 KiB
Newer Older
  • Learn to ignore specific revisions
  • Markus Kaarto's avatar
    Markus Kaarto committed
    import {Component, h, Prop, Host} from '@stencil/core';
    import {css} from 'emotion';
    
    const toRemValue = (val?: number) => {
      return typeof val === 'number' ? `${val}rem` : undefined;
    };
    
    interface P {
      p?: number[];
      pt?: number[];
      pl?: number[];
      pb?: number[];
      pr?: number[];
      h?: number;
      bg?: string;
      width: string[];
      justify: string;
      align: string;
    }
    
    const breakpoints = ['30rem', '48rem', '60rem', '76rem', '80rem'];
    
    const mq = breakpoints.map((b) => `@media (min-width: ${b})`);
    const createCssClass = ({pt, pb, pl, pr, h, bg, width, justify, align}: P) => {
      const last = width[width.length - 1];
    
      return css`
        padding-top: ${toRemValue(pt[0])};
        padding-right: ${toRemValue(pr[0])};
        padding-bottom: ${toRemValue(pb[0])};
        padding-left: ${toRemValue(pl[0])};
        height: ${toRemValue(h)};
        background-color: ${!!bg ? `var(--${bg})` : 'transparent'};
        width: ${width[0]};
        display: flex;
        justify-content: ${justify || 'flex-start'};
        align-items: ${align || 'flex-start'};
    
        ${mq[0]} {
          width: ${width[1]};
    
          padding-top: ${toRemValue(pt[1])};
          padding-right: ${toRemValue(pr[1])};
          padding-bottom: ${toRemValue(pb[1])};
          padding-left: ${toRemValue(pl[1])};
        }
        ${mq[1]} {
          width: ${width[2] || last};
    
          padding-top: ${toRemValue(pt[2])};
          padding-right: ${toRemValue(pr[2])};
          padding-bottom: ${toRemValue(pb[2])};
          padding-left: ${toRemValue(pl[2])};
        }
        ${mq[2]} {
          width: ${width[3] || last};
    
          padding-top: ${toRemValue(pt[3])};
          padding-right: ${toRemValue(pr[3])};
          padding-bottom: ${toRemValue(pb[3])};
          padding-left: ${toRemValue(pl[3])};
        }
        ${mq[3]} {
          width: ${width[4] || last};
    
          padding-top: ${toRemValue(pt[4])};
          padding-right: ${toRemValue(pr[4])};
          padding-bottom: ${toRemValue(pb[4])};
          padding-left: ${toRemValue(pl[4])};
        }
        ${mq[4]} {
          width: ${width[5] || last};
          padding-top: ${toRemValue(pt[5])};
          padding-right: ${toRemValue(pr[5])};
          padding-bottom: ${toRemValue(pb[5])};
          padding-left: ${toRemValue(pl[5])};
        }
      `;
    };
    
    const toNumArray = (value?: string) =>
      value
        ?.split(',')
        .map((v) => `${v.trim()}`)
        .map((v) => parseFloat(v));
    
    @Component({
      tag: 'hy-box',
      styleUrl: 'hy-box.scss',
    
    Markus Kaarto's avatar
    Markus Kaarto committed
    })
    export class HyBox {
      /**
       * All sides padding value in rems. Responsive when given Comma separated values.
       */
      @Prop() p?: string;
    
      /**
       * Left padding in rems. Responsive when given Comma separated values.
       */
      @Prop() pl?: string;
      /**
       * Right padding in rems. Responsive when given Comma separated values.
       */
      @Prop() pr?: string;
      /**
       * Bottom padding in rems. Responsive when given Comma separated values.
       */
      @Prop() pb?: string;
      /**
       * Top padding in rems. Responsive when given Comma separated values.
       */
      @Prop() pt?: string;
      /**
       * Value for horisontal alignment (justify-content)
       */
      @Prop() justify: string = 'flex-start';
      /**
       * value for vertical alignment (align-items)
       */
      @Prop() align: string = 'baseline';
    
      /**
       * fixed height for the container, useful for extra spacing containers
       */
      @Prop() h?: number;
      /**
       * background color. Must use one of css variable names from color tokens
       */
    
      @Prop() bg: string = 'transparent';
    
    Markus Kaarto's avatar
    Markus Kaarto committed
      /**
       * Responsive width. Must be a comma separated string of percentage values for breakpoints. First item is the default value.
       */
      @Prop() width: string = '100';
    
      render() {
        const pt = toNumArray(this.pt) ?? toNumArray(this.p) ?? [0];
        const pb = toNumArray(this.pb) ?? toNumArray(this.p) ?? [0];
        const pr = toNumArray(this.pr) ?? toNumArray(this.p) ?? [0];
        const pl = toNumArray(this.pl) ?? toNumArray(this.p) ?? [0];
    
        return (
          <Host
            class={createCssClass({
              pt,
              pl,
              pr,
              pb,
              h: this.h,
              bg: this.bg,
              width: this.width.split(',').map((v) => `${v.trim()}%`),
              justify: this.justify,
    
    Markus Kaarto's avatar
    Markus Kaarto committed
            })}
          >
            <slot></slot>
          </Host>
        );
      }
    }