native-spa-route
Version:
provide SPA route's experience with native web component
158 lines (157 loc) • 5.34 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { html, LitElement, nothing } from 'lit';
import { customElement, property, queryAll, state } from 'lit/decorators.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import debug from 'debug';
import { hook_route_change, unhook_route_change } from '../lib/hooks';
const dlog = debug('native-spa-route');
let RouteContainer = class RouteContainer extends LitElement {
constructor() {
super(...arguments);
/**
* config container work route path, default is `/`
* @default '/'
*/
this.rootPath = '/';
/**
* config should cacht event where the target has `href` attribute
* if enable this, click a link will auto use `history.pushState`.
* @default true
*/
this.autoCatchHrefClick = true;
/**
* config is this component use shadow dom.
* @default false
*/
this.disableShadow = false;
this.status = 'common';
this.active = false;
this._route_change_callback = async () => {
this.active = location.pathname.startsWith(this.rootPath);
if (this.active) {
const isMatch = await this._is_match_route();
if (isMatch) {
this.status = 'common';
}
else {
this.status = '404';
}
}
else {
this.status = 'common';
}
};
}
// constructor() {
// super();
// }
/**
* get current container's status
*/
getStatus() {
return this.status;
}
/**
* if disabled shadow dom, this is the only way to add 404 status content
*/
set404Content(content) {
this.contentOf404 = content;
}
_render_404() {
if (!this.contentOf404)
return nothing;
let type = typeof this.contentOf404;
if (type === 'string') {
return html `${unsafeHTML(this.contentOf404)}`;
}
if (type === 'function') {
return html `${unsafeHTML(this.contentOf404() ?? '')}`;
}
return nothing;
}
_render_with_light_dom() {
if (this.active && this.status === '404') {
return this._render_404();
}
return nothing;
}
_render_with_shadow_dom() {
if (this.active && this.status === '404') {
return html `<slot name="404">${this._render_404()}</slot>`;
}
return html `<slot></slot>`;
}
render() {
if (this.disableShadow) {
return this._render_with_light_dom();
}
else {
return this._render_with_shadow_dom();
}
}
async _is_match_route() {
// if (!location.pathname.startsWith(this.rootPath)) return true; // not render 404 will this container is not active
const scopedRoutes = this.querySelectorAll('native-route');
await Promise.all(Array.from(scopedRoutes).map((r) => r.updateComplete));
for (const route of scopedRoutes) {
if (!route.virtualNode && route.isActive()) {
dlog('this route is active: ', route);
return true;
}
}
return false;
}
updated(_changedProperties) {
// if (_changedProperties.has('active')) {
// }
}
createRenderRoot() {
if (!this.disableShadow) {
return super.createRenderRoot();
}
return this;
}
connectedCallback() {
super.connectedCallback();
// this._listen_route_active_status_change();
this._route_change_callback();
hook_route_change(this._route_change_callback);
}
disconnectedCallback() {
super.disconnectedCallback();
unhook_route_change(this._route_change_callback);
}
};
__decorate([
property({ type: String, attribute: 'root-path', reflect: true })
], RouteContainer.prototype, "rootPath", void 0);
__decorate([
property({ type: Boolean })
], RouteContainer.prototype, "autoCatchHrefClick", void 0);
__decorate([
property({ type: Boolean })
], RouteContainer.prototype, "disableShadow", void 0);
__decorate([
queryAll('native-route')
], RouteContainer.prototype, "allRouteNode", void 0);
__decorate([
state()
], RouteContainer.prototype, "statusRenderMap", void 0);
__decorate([
state()
], RouteContainer.prototype, "status", void 0);
__decorate([
state()
], RouteContainer.prototype, "contentOf404", void 0);
__decorate([
state()
], RouteContainer.prototype, "active", void 0);
RouteContainer = __decorate([
customElement('native-route-container')
], RouteContainer);
export { RouteContainer };