kjantzer / bui

‹B› Web components, classes, and utilities for creating single-page PWAs – built with Lit by Blackstone Publishing
https://bui.js.org
89 stars 5 forks source link

Easier grid control #9

Open silberGuy opened 3 years ago

silberGuy commented 3 years ago

Hey 😄 I was wondering, why b-grid has only the statically configured columns values (1-8, 1,2 1,2,2...) and not a dynamic value? I guess this could be achieved nicely with a style tag computed within the template.

kjantzer commented 3 years ago

That's an interesting idea.

b-grid was originally introduced to reduce the work for common "basic" layouts with the thought that more complex "one-off" layouts would be coded in the custom element itself.

What kind other sort of configurations are you thinking of?

silberGuy commented 3 years ago

Well, anything actually. For instance "1 3 1" is not possible currently. I couldn't open a PR, but this is what I thought:

import { LitElement, html, css } from 'lit-element'
import isNumeric from '../util/isNumeric'

customElements.define('b-grid', class extends LitElement{
    static get properties() {
        return { 
            cols: { type: String, reflect: true },
            rows: { type: String, reflect: true },
            colsMobile: { type: String, reflect: true, attribute: 'cols-mobile' },
            rowsMobile: { type: String, reflect: true, attribute: 'rows-mobile' },
            gap: { type: String, reflect: true },
        }
    }

    static get styles(){return css`
        :host {
            display: grid;
            grid-template-columns: ${this.stringToGridTemplate(this.cols)};
            grid-template-rows: ${this.stringToGridTemplate(this.rows)};
            align-content: flex-start;
            gap: 1em;
            min-width: 0;
        }

        ::slotted(*) {
            min-width: 0;
            min-height: 0;
        }

        @media (max-width:699px){
            :host {
                grid-template-columns: ${this.stringToGridTemplate(this.colsMobile || this.cols)};
                grid-template-rows: ${this.stringToGridTemplate(this.rowsMobile || this.rows)};
            }
        }

        :host([gap]) {
            gap: ${ this.computedGap };
        }

        :host([align="start"]) { justify-items: flex-start; }
        :host([align="center"]) { justify-items: center; }
        :host([align="end"]) { justify-items: flex-end; }

        ::slotted([colspan]) { grid-column: 1/-1; }
        ::slotted([colspan="2"]) { grid-column: span 2; }
        ::slotted([colspan="3"]) { grid-column: span 3; }
        ::slotted([colspan="4"]) { grid-column: span 4; }
        ::slotted([colspan="5"]) { grid-column: span 5; }
        ::slotted([colspan="6"]) { grid-column: span 6; }

        @media (max-width:699px){
            ::slotted([colspan-mobile]) { grid-column: 1/-1; }
            ::slotted([colspan-mobile="2"]) { grid-column: span 2; }
            ::slotted([colspan-mobile="3"]) { grid-column: span 3; }
            ::slotted([colspan-mobile="4"]) { grid-column: span 4; }
            ::slotted([colspan-mobile="5"]) { grid-column: span 5; }
            ::slotted([colspan-mobile="6"]) { grid-column: span 6; }
        }
    `}

    constructor() {
        super();
        this.cols = '2';
        this.rows = 'max-content';
    }

    get computedGap() {
        if (this.gap === 'none' || this.gap === 0) {
            return '0';
        }
        return `${this.gap}em`;
    }

    render(){return html`
        <slot></slot>
    `}

    stringToGridTemplate(str) {
        const parts = str.toString().split(',');
        if (parts.length === 1) {
            if (isNumeric(parts[0])) {
                return `repeat(${parts[0]}, 1fr);`
            }
            return parts[0];
        }
        return parts.map(part => isNumeric(part) ? `${part}fr` : part.toString).join(' ')
    }
})

export default customElements.get('b-grid')