feat: side panels

Signed-off-by: Mitch Hijlkema <mitch@hijlkema.codes>
This commit is contained in:
2023-08-31 17:03:27 +02:00
parent 14c1b97622
commit 41830bbca5
15 changed files with 1525 additions and 1055 deletions

View File

@@ -0,0 +1,100 @@
import { Meta, StoryObj } from '@storybook/web-components';
import { html } from 'lit';
import './bottom-panel.component';
import BottomPanel from './bottom-panel.component';
export default {
title: 'Design System/Atoms/Panels/Bottom',
component: 'z-panels.bottom',
render: (args) => html`
<style>
html {
background-color: #ccc;
}
</style>
<z-panels.bottom ?open=${args.open}>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
<p>
Esse laborum pariatur irure in consequat deserunt officia. Eu aliquip ad duis. Voluptate velit fugiat ex Lorem et. Ea laborum ut
veniam est ad consequat pariatur.
</p>
</z-panels.bottom>
`,
parameters: {
layout: 'fullscreen',
},
argTypes: {
open: {
control: 'boolean',
},
},
args: {
open: false,
},
} satisfies Meta<BottomPanel>;
type Story = StoryObj<BottomPanel>;
export const Primary: Story = {};

View File

@@ -0,0 +1,58 @@
import { DestroyController } from '@z-elements/_internal/controllers';
import { LitElement, PropertyValues, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { filter, fromEvent, takeUntil, tap } from 'rxjs';
import { hostStyles, panelStyles } from './styles';
@customElement('z-panels.bottom')
export default class BottomPanel extends LitElement {
static override get styles() {
return [hostStyles, panelStyles];
}
/** Private variables */
private readonly _destroyController = new DestroyController(this);
/** Protected variables */
/** Public variables */
@property({ type: Boolean, reflect: true }) public open = false;
/** constructor & lifecylce */
override connectedCallback() {
super.connectedCallback();
fromEvent<MouseEvent>(this, 'click')
.pipe(
filter(() => this.open),
filter((event: MouseEvent) => event.target === this),
tap(() => (this.open = false)),
takeUntil(this._destroyController.destroy),
)
.subscribe();
}
override updated(changedProperties: PropertyValues) {
super.updated(changedProperties);
this.shadowRoot?.querySelector('aside')?.scrollTo(0, 0);
}
/** Public methods */
/** Protected methods */
protected override render(): unknown {
return html`
<aside>
<header><slot name="header"></slot></header>
<slot></slot>
</aside>
`;
}
/** Private methods */
}

View File

@@ -1,7 +0,0 @@
import { panelsBottomPanel } from './panels-bottom-panel';
describe('panelsBottomPanel', () => {
it('should work', () => {
expect(panelsBottomPanel()).toEqual('panels-bottom-panel');
});
});

View File

@@ -1,3 +0,0 @@
export function panelsBottomPanel(): string {
return 'panels-bottom-panel';
}

View File

@@ -0,0 +1,51 @@
import { css } from 'lit';
export const hostStyles = css`
:host {
display: block;
overflow: hidden;
position: fixed;
inset: 0;
pointer-events: none;
z-index: ${Number.MAX_SAFE_INTEGER};
}
:host([open]) {
pointer-events: auto;
}
:host(:not([open])) aside {
transform: translateY(100vh);
}
:host([open]) aside {
transform: translateY(0);
transition-timing-function: ease-in;
}
:host(:not([open])) aside::before {
opacity: 0;
}
:host([open]) aside {
opacity: 1;
transition-timing-function: ease-in;
}
`;
export const panelStyles = css`
aside {
position: absolute;
background-color: #fff;
box-shadow: 0 -3px 6px rgba(0, 0, 0, 0.04);
border-radius: 12px 12px 0 0;
padding: 2rem 1.5rem;
inset-inline: 0;
bottom: 0;
max-height: 60dvh;
pointer-events: auto;
transition: transform 0.3s ease-out;
overflow: scroll;
scroll-behavior: smooth;
}
`;