UNPKG

native-spa-route

Version:

provide SPA route's experience with native web component

158 lines (157 loc) 5.34 kB
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 };