@nent/core
Version:
242 lines (241 loc) • 6.8 kB
JavaScript
/*!
* NENT 2022
*/
import { Component, Element, h, Host, Prop, State, } from '@stencil/core';
import { isValue, logIf } from '../../services/common';
import { getChildInputValidity } from '../n-view-prompt/services/elements';
import { onRoutingChange, routingState, } from '../n-views/services/state';
/**
* The element should be used in-place of an `a` tag to navigate without
* refreshing the page. This element supports an active-class that will
* be applied when the route in **href** matches the route of the app.
*
* This is helpful for displaying active routes in menus, bread-crumbs and tabs.
*
* @system routing
*/
export class ViewLink {
constructor() {
/**
* The class to add when the matching route is active
* in the browser
*/
this.activeClass = 'active';
/**
* Only active on the exact href match,
* and not on child routes
*/
this.exact = false;
/**
* Only active on the exact href match
* using every aspect of the URL including
* parameters.
*/
this.strict = true;
/**
* Provide log messages for path matching.
*/
this.debug = false;
/**
* Validates any current-route inputs before navigating. Disables
* navigation if any inputs are invalid.
*/
this.validate = false;
}
get parentUrl() {
var _a, _b;
return (((_a = this.el.closest('n-view-prompt')) === null || _a === void 0 ? void 0 : _a.path) ||
((_b = this.el.closest('n-view')) === null || _b === void 0 ? void 0 : _b.path));
}
componentWillLoad() {
this.routeSubscription = onRoutingChange('location', () => {
if (routingState.router) {
this.path = routingState.router.resolvePathname(this.path, this.parentUrl || '/');
const match = routingState.router.matchPath({
path: this.path,
exact: this.exact,
strict: this.strict,
});
this.match = match ? Object.assign({}, match) : null;
}
});
}
handleClick(e, path) {
const router = routingState.router;
if (router == null ||
router.isModifiedEvent(e) ||
path == undefined) {
return true;
}
else {
e.stopImmediatePropagation();
e.preventDefault();
if (this.validate == false ||
getChildInputValidity(router.exactRoute.routeElement)) {
router.goToRoute(path);
}
return false;
}
}
render() {
const { router } = routingState;
const path = router === null || router === void 0 ? void 0 : router.resolvePathname(this.path, this.parentUrl);
const match = router === null || router === void 0 ? void 0 : router.matchPath({
path: path,
exact: this.exact,
strict: this.strict,
});
const classes = {
[this.activeClass]: isValue(match),
[this.linkClass || '']: true,
};
logIf(this.debug, 'n-view-link re-render ' + path);
let anchorAttributes = {
title: this.el.title,
role: this.el.getAttribute('aria-role'),
id: this.el.id,
};
return (h(Host, null,
h("a", Object.assign({ href: path }, anchorAttributes, { "n-attached-click": true, "n-attached-key-press": true, class: classes, onClick: (e) => {
return this.handleClick(e, path);
}, onKeyPress: (e) => {
return this.handleClick(e, path);
} }),
h("slot", null))));
}
disconnectedCallback() {
var _a;
(_a = this.routeSubscription) === null || _a === void 0 ? void 0 : _a.call(this);
}
static get is() { return "n-view-link"; }
static get properties() { return {
"path": {
"type": "string",
"mutable": true,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": true,
"optional": false,
"docs": {
"tags": [],
"text": "The destination route for this link"
},
"attribute": "path",
"reflect": false
},
"linkClass": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "The class to add to the anchor tag."
},
"attribute": "link-class",
"reflect": false
},
"activeClass": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The class to add when the matching route is active\nin the browser"
},
"attribute": "active-class",
"reflect": false,
"defaultValue": "'active'"
},
"exact": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Only active on the exact href match,\nand not on child routes"
},
"attribute": "exact",
"reflect": false,
"defaultValue": "false"
},
"strict": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Only active on the exact href match\nusing every aspect of the URL including\nparameters."
},
"attribute": "strict",
"reflect": false,
"defaultValue": "true"
},
"debug": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Provide log messages for path matching."
},
"attribute": "debug",
"reflect": false,
"defaultValue": "false"
},
"validate": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Validates any current-route inputs before navigating. Disables\nnavigation if any inputs are invalid."
},
"attribute": "validate",
"reflect": true,
"defaultValue": "false"
}
}; }
static get states() { return {
"match": {}
}; }
static get elementRef() { return "el"; }
}