Skip to content

Commit

Permalink
Merge pull request #46 from webcomponents-preview/feature/26-router-b…
Browse files Browse the repository at this point in the history
…ased-preview-frame-tabs
  • Loading branch information
davidenke authored Jun 1, 2023
2 parents 7718b6a + 0a20631 commit 1672b78
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 70 deletions.
7 changes: 7 additions & 0 deletions src/components/feature/navigation/navigation.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@

:host {
display: block;
}

// set the border on top of the whole element if no headline is given;
// otherwise, the headline will have this border, which is then part
// of the sticky headline element 🍭🍭🍭
:host(:not([headline])) {
border-top: 1px solid var(---wcp-navigation-border-color);
}

Expand All @@ -36,6 +42,7 @@ h3 {
padding: var(---wcp-navigation-spacing-headline);

background-color: var(---wcp-navigation-headline-background);
border-top: 1px solid var(---wcp-navigation-border-color);
font-size: var(---wcp-navigation-headline-size);
font-weight: var(---wcp-navigation-headline-weight);
letter-spacing: var(---wcp-navigation-headline-spacing);
Expand Down
14 changes: 10 additions & 4 deletions src/components/feature/preview-frame/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@
<wcp-preview-frame></wcp-preview-frame>
```

## Properties
## Methods

| Property | Attribute |
|---------------------|-----------------------|
| `initialPreviewTab` | `initial-preview-tab` |
| Method | Type |
|--------------------------|----------------------------------------------|
| `emitActivePluginChange` | `(activePlugin?: string \| undefined): void` |

## Events

| Event |
|------------------------------------------|
| `wcp-preview-frame:active-plugin-change` |

## Slots

Expand Down
70 changes: 36 additions & 34 deletions src/components/feature/preview-frame/preview-frame.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { map } from 'lit/directives/map.js';
import { when } from 'lit/directives/when.js';

import { ColorSchemable } from '@/utils/color-scheme.utils.js';
import type { Config } from '@/utils/config.utils.js';
import { type PreviewFramePlugin, findAllPlugins } from '@/utils/plugin.utils.js';

import styles from './preview-frame.component.scss';
Expand All @@ -14,7 +13,7 @@ import styles from './preview-frame.component.scss';
* ```html
* <wcp-preview-frame></wcp-preview-frame>
* ```
*
*
* @slot - The preview frame can be filled with any number of plugins. The plugins will be rendered as tabs.
*
* @cssprop --wcp-preview-frame-dark-background - Background color of the preview frame in dark mode
Expand All @@ -40,11 +39,18 @@ export class PreviewFrame extends ColorSchemable(LitElement) {
@state()
private _tabs: HTMLElementTagNameMap['wcp-tabs']['tabs'] = {};

@state()
private _activeTab?: HTMLElementTagNameMap['wcp-tabs']['activeTab'];

@property({ type: String, reflect: true, attribute: 'initial-preview-tab' })
initialPreviewTab?: Config['initialPreviewTab'];
@property({ type: String, reflect: true, attribute: 'active-plugin' })
private activePlugin?: string;

emitActivePluginChange(activePlugin?: string) {
const event = new CustomEvent('wcp-preview-frame:active-plugin-change', {
detail: activePlugin,
bubbles: true,
cancelable: true,
composed: true,
});
this.dispatchEvent(event);
}

@eventOptions({ passive: true })
protected handleSlotChange(event: Event) {
Expand All @@ -58,7 +64,7 @@ export class PreviewFrame extends ColorSchemable(LitElement) {
this._plugins.forEach((tab) => tab.setAttribute('slot', tab.name));

this.preparePluginTabs();
this.alignActiveTab();
this.alignActivePlugin();
}
}

Expand All @@ -67,19 +73,16 @@ export class PreviewFrame extends ColorSchemable(LitElement) {
// this event has been triggered by a plugin changing its availability
// state, therefore we need to re-evaluate the tabs
this.preparePluginTabs();
this.alignActiveTab();
this.alignActivePlugin();
}

@eventOptions({ passive: true })
protected handleActiveTabChange(event: CustomEvent<string>) {
const { detail: activeTab, currentTarget, target } = event;

// ignored bubbled events as they occur from nested tabs
if (currentTarget !== target) return;
const { currentTarget, target, detail: activePlugin } = event;

// only update the active tab if it has changed
if (this._activeTab !== activeTab) {
this._activeTab = activeTab;
// re-emit as our own event
if (currentTarget === target) {
this.emitActivePluginChange(activePlugin);
}
}

Expand All @@ -90,27 +93,23 @@ export class PreviewFrame extends ColorSchemable(LitElement) {
);
}

protected alignActiveTab() {
protected alignActivePlugin() {
let alignedActivePlugin = this.activePlugin;

// either the active tab is not set...
if (this._activeTab === undefined) {
// ... then we try to set the configured initial one...
if (
this.initialPreviewTab &&
this._plugins.some(({ available, name }) => available && name === this.initialPreviewTab)
) {
this._activeTab = this.initialPreviewTab;
return;
}
// ... or the first available one...
else if (this._plugins.length > 0) {
this._activeTab = this._plugins.filter(({ available }) => available)?.[0]?.name;
return;
}
if (this.activePlugin === undefined && this._plugins.length > 0) {
// ... then we try to set the first available...
alignedActivePlugin = this._plugins.filter(({ available }) => available)?.[0]?.name;
}
// ... or the active tab is not available anymore...
else if (!this._plugins.find(({ name }) => name === this._activeTab)?.available) {
else if (!this._plugins.find(({ name }) => name === this.activePlugin)?.available) {
// ... then we need to set the first available tab
this._activeTab = this._plugins.find(({ available }) => available)?.name;
alignedActivePlugin = this._plugins.find(({ available }) => available)?.name;
}

// if there are changes, let them know! 🏳️‍🌈
if (alignedActivePlugin !== this.activePlugin) {
this.emitActivePluginChange(alignedActivePlugin);
}
}

Expand All @@ -121,7 +120,7 @@ export class PreviewFrame extends ColorSchemable(LitElement) {
() => html`
<wcp-tabs
.tabs="${this._tabs}"
active-tab="${this._activeTab}"
active-tab="${this.activePlugin}"
@wcp-tabs:active-tab-change="${this.handleActiveTabChange}"
@wcp-preview-frame-plugin:availability-change="${this.handleAvailabilityChange}"
>
Expand All @@ -135,6 +134,9 @@ export class PreviewFrame extends ColorSchemable(LitElement) {
}

declare global {
interface HTMLElementEventMap {
'wcp-preview-frame:active-plugin-change': CustomEvent<string>;
}
interface HTMLElementTagNameMap {
'wcp-preview-frame': PreviewFrame;
}
Expand Down
7 changes: 4 additions & 3 deletions src/components/layout/aside/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ window.dispatchEvent(new CustomEvent('wcp-aside:toggle', { detail: true }));

## Slots

| Name | Description |
|------|------------------------------------------|
| | Projects elements aside the main content |
| Name | Description |
|----------|----------------------------------------------|
| | Projects elements aside the main content |
| `header` | Elements in the fixed header of the side bar |

## CSS Custom Properties

Expand Down
11 changes: 7 additions & 4 deletions src/components/layout/aside/aside.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,15 @@
inset: 0;
z-index: 3;

display: block;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: var(---wcp-aside-spacing);

height: 100%;
max-width: 100%;
min-width: 100%;

overflow: auto;
overflow-x: hidden;

background-color: var(---wcp-aside-background);
color: var(---wcp-aside-color);

Expand Down Expand Up @@ -67,6 +65,11 @@ header {
z-index: 4;
}

section {
overflow: auto;
overflow-x: hidden;
}

wcp-button {
position: absolute;
top: utils.size(0.4);
Expand Down
6 changes: 5 additions & 1 deletion src/components/layout/aside/aside.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import styles from './aside.component.scss';
* ```
*
* @slot - Projects elements aside the main content
* @slot header - Elements in the fixed header of the side bar
*
* @event wcp-aside-toggled - Dispatches this event when the side bar has been toggled. Do not get confused with the `wcp-aside:toggle` event.
*
Expand Down Expand Up @@ -80,11 +81,14 @@ export class Aside extends ColorSchemable(LitElement) {
protected override render(): TemplateResult {
return html`
<header>
<slot name="header"></slot>
<wcp-button kind="icon" @click="${this.handleButtonClick}">
<wcp-icon name="close"></wcp-icon>
</wcp-button>
</header>
<slot></slot>
<section>
<slot></slot>
</section>
`;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/components/layout/layout/layout.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export class Layout extends LitElement {
protected override render(): TemplateResult {
return html`
<wcp-aside>
<slot name="title" slot="header"></slot>
<slot name="aside"></slot>
</wcp-aside>
Expand Down
2 changes: 1 addition & 1 deletion src/components/root/root.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class Root extends Routable()(ColorSchemable(LitElement)) {
protected override render(): TemplateResult {
return html`
<wcp-layout>
<wcp-title slot="aside" title="${this.config?.title}">
<wcp-title slot="title" title="${this.config?.title}">
<slot name="logo" slot="logo">
<img src="${logo}" height="20px" />
</slot>
Expand Down
46 changes: 33 additions & 13 deletions src/components/root/root.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { until } from 'lit/directives/until.js';
import type { Config } from '@/utils/config.utils.js';
import { prefixRelativeUrls } from '@/utils/markdown.utils.js';
import type { Manifest } from '@/utils/parser.types.js';
import type { Route, Router } from '@/utils/routable.utils.js';
import { areParamsEqual, mergeParams, type Route, type Router } from '@/utils/routable.utils.js';

export const prepareRoutes = (router: Router, config: Config, manifest: Manifest): Route[] => [
{
Expand Down Expand Up @@ -51,19 +51,39 @@ export const prepareRoutes = (router: Router, config: Config, manifest: Manifest
},
{
path: '/element/:tagName/:plugin?',
render: ({ tagName = '', plugin = config.initialPreviewTab }) => html`
<wcp-preview-frame
initial-preview-tab="${ifDefined(plugin)}"
@wcp-tabs:active-tab-change="${({ detail }: CustomEvent<string>) =>
router.update(`/element/${tagName}/${detail}`)}"
>
${map(
config.previewFramePlugins ?? [],
(plugin) => withStatic(html)`
// fill in existing params if not provided for next route
enter: (params, router, outgoingParams) => {
// check if the params can be taken over (current route is
// the same path with different params)
const hasOutgoingParams = outgoingParams !== undefined;
const isSamePath = router.currentPath?.startsWith('/element/');
const alignedParams = mergeParams(outgoingParams ?? {}, params);
const haveParamsChanged = !areParamsEqual(params, alignedParams);

// digest these insights; redirect and block current route
if (hasOutgoingParams && haveParamsChanged && isSamePath) {
router.redirect(`/element/${alignedParams.tagName}/${alignedParams.plugin}`);
return false;
}

// everything okay here, just go on
return true;
},
render: ({ tagName = '', plugin = config.initialPreviewTab }) => {
return html`
<wcp-preview-frame
active-plugin="${ifDefined(plugin)}"
@wcp-preview-frame:active-plugin-change="${({ detail: plugin }: CustomEvent<string>) =>
router.redirect(`/element/${tagName}/${plugin}`)}"
>
${map(
config.previewFramePlugins ?? [],
(plugin) => withStatic(html)`
<${unsafeStatic(plugin)} .element="${manifest.elements.get(tagName)}"></${unsafeStatic(plugin)}>
`
)}
</wcp-preview-frame>
`,
)}
</wcp-preview-frame>
`;
},
},
];
1 change: 1 addition & 0 deletions src/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"$schema": "./config.schema.json",
"title": "Web Component Preview",
"excludeElements": ["wcp-root"],
"initialActiveElement": "wcp-button",
"initialPreviewTab": "viewer",
Expand Down
Loading

0 comments on commit 1672b78

Please sign in to comment.