@conectate/ct-router
v4.0.0
Published
It's a simple routing system that changes the viewport depending on the route given
Downloads
118
Maintainers
Readme
ct-router
It's a simple routing system that changes the viewport depending on the route given
Installation
To include this, type:
$ yarn add @conectate/ct-router
or
$ npm i @conectate/ct-router
TLDR;
Bind properties to templated elements in LitElement
You can insert JavaScript expressions as placeholders for HTML text content, attributes, Boolean attributes, properties, and event handlers.
- Text content:
<p>${...}</p>
- Attribute:
<p id="${...}"></p>
- Boolean attribute:
?disabled="${...}"
- Property:
.value="${...}"
- Event handler:
@event="${...}"
Usage
Step 1
Add to your html`` (Litelement Template) like this:
<ct-router id="ctrouter" ?auth="${this.isLogged}" @login-needed="${this.loginNeeded}" @loading="${this.isLoading}" @location-changed="${this.pathChanged}"> </ct-router>
Step 2
Full LitElement example in Typescript
import "@conectate/ct-router";
import { CtLit, customElement, html, property, state } from "@conectate/ct-lit"; /* or 'lit' */
import { href } from "@conectate/ct-router";
@customElement("my-router")
class MyRouter extends CtLit {
@property({ type: Boolean }) isLogged = false;
@query("#ctrouter") $ctrouter!: HTMLElementTagNameMap["ct-router"];
/*
You can use lit-html @event bindings in your template inside the render function to add event listeners to your component.
You can use lit-html '?' bindings in your template inside the render function to add boolean property.
*/
@state() private pages = [
{
path: "/page1",
element: html`<page-number1></page-number1>`, // you cand use html``
from: () => import("./src/page-number1"),
auth: false,
title: () => `Page 1 • Example.com`
},
{
path: "/profile",
element: "<my-profile></my-profile>", // or you cand use a simple string
from: () => import("./src/my-profile"),
auth: true,
title: () => `Profile • Example.com`
},
{
path: "/404",
element: html`<page-404></page-404>`,
from: () => import("./src/page-404"),
auth: false,
title: () => null
}
];
render() {
return html` <ct-router
id="ctrouter"
loginFallback="/404"
.pages=${this.pages}
?auth=${this.isLogged}
@login-needed=${this.loginNeeded}
@loading=${this.isLoading}
@location-changed=${this.pathChanged}
>
</ct-router>`;
}
firstUpdated(_changedProperties: Map<string, any>) {
// set if user is not isAnonymous
this.isLogged = true; // !firebase.auth().currentUser.isAnonymous
}
/* =================== (optional) DEBUG ROUTER =================== */
/* You can view state of you web */
printCurrentState() {
// More details in interface LocationChanged
console.log("Current patternMatched", this.$ctrouter.path);
console.log("Current pathname", this.$ctrouter.pathname);
console.log("Current queryParams", this.$ctrouter.queryParams);
console.log("Current params", this.$ctrouter.params);
console.log("is Logged?", this.$ctrouter.auth);
}
loginNeeded(e: CustomEvent<{ path: string }>) {
let path = e.detail.path;
alert(`loginNeeded on: ${path}`);
}
isLoading(e: CustomEvent<boolean>) {
console.log("loading...", e.detail);
}
pathChanged(e: CustomEvent<LocationChanged>) {
console.log("path changed", location.href);
console.log("patternMatched", this.$ctrouter.path, "==", e.detail.path);
console.log("pathname", this.$ctrouter.pathname, "==", e.detail.pathname, "==", location.pathname);
console.log(this.$ctrouter.queryParams, "==", e.detail.queryParams);
console.log(this.$ctrouter.params, "==", e.detail.params);
}
}
interface LocationChanged {
//patternMatched like a: /:profile/preferences
path: string;
// pathname like a: /herberthobregon/preferences
pathname: string;
// if path is /home?hello=word then queryParams is { hello : "world" }
queryParams?: { [x: string]: string };
// if href is /herberth/preference and path is /:username/preference then params is { username : "herberth" }
params?: { [x: string]: string };
}
Example in React
Important! Disable HMR in your Dev server. I recommend use
vitejs
for best performance.
function App() {
let pages: Page[] = [
{
path: "/",
renderRoot: root => ReactDOM.render(<MainApp />, root!),
auth: false,
title: () => `Page 1 • Example.com`
},
{
path: "/page2",
renderRoot: root => ReactDOM.render(<Page2 />, root!),
auth: false,
title: () => `Page 2 • Example.com`
},
{
path: "/404",
renderRoot: root => ReactDOM.render(<Page404 />, root!),
auth: false,
title: () => `404 Not Found • Example.com`
}
];
const router = useRef<HTMLElement>(null);
useEffect(() => {
const ctrouter = router.current;
// ctrouter.addEventListener('login-needed',this.loginNeeded);
// ctrouter.addEventListener('loading',this.isLoading);
// ctrouter.addEventListener('location-changed',this.pathChanged);
});
return (
<div>
<header>My App</header>
<CtRouter ref={router} pages={pages} unmountComponentAtNode={root => ReactDOM.unmountComponentAtNode(root)}></CtRouter>
</div>
);
}
export default App;
If you plan to manage the dynamic imports, skip from
attr
this.$ctrouter.pages = [
{
path: "/page1",
element: html`<page-number1></page-number1>`,
from: () => null,
auth: false,
title: () => `Page 1 • Example.com`
}
]
Dinamic Routing
You can use :id
to varible path and *
for any path or your own regexp
{
path: "/page/:id",
element: html`<page-number1></page-number1>`,
from: () => null,
auth: false,
title: () => `Page 1 • Example.com`
}
or
{
path: "/register/:page?",
// in this regexp use /(group 1)/(group 2)
regex : /^\/(register|registro)\/([^\/]+)(?:\/)?$/i,
groups : ['_group1','page'],
element: html`<login-register></login-register>`,
from: () => import("./src/login-register"),
auth: null,
title: () => `${window.register} • Example.com`
}
Auth
There are pages that only a user with session started can see.
for this it passes a Boolean parameter to auth of ct-router
?auth=${this.isLogged}
Add beforeunload
listener example
The beforeunload event is fired when the location
has changed, The document and its resources are about to be unloaded. The document is still visible and the event is still cancelable at this point.
⚠️⚠️⚠️ This listener mimics the behavior of window.onbeforeunload
but is not the same. If you need to know if it reloads the page or if you are exiting your web page, use the window.onbeforeunload
method.
import {CtLit, html, property, customElement, internalProperty } from 'lit'; /* or 'lit' */
import { showCtConfirm } from '@conectate/ct-dialog/ct-confirm';
import '@conectate/ct-router';
@customElement('my-router')
class MyRouter extends LitElement{
listenerID = 0;
render(){
return html`...`
}
firstUpdated(_changedProperties: Map<string, any>) {
// get data from server
// ...
this.listenerID = window.ctrouter?.on('beforeunload', async () => {
let rsp:boolean = await showCtConfirm('Reload site?', 'Changes you made may not be saved.', "Reload" , "Stay", undefined, { history: false });
if (rsp) window.ctrouter.deleteListener(this.listenerID);
return rsp;
});
}
saveData(){
window.ctrouter.deleteListener(this.listenerID);
// To-Do Save info
}
Follow me
https://twitter.com/herberthobregon
https://www.conectate.today/herberthobregon
Contributing
- Fork it!
- Create your feature branch:
git checkout -b my-new-feature
- Commit your changes:
git commit -m 'Add some feature'
- Push to the branch:
git push origin my-new-feature
- Submit a pull request :D
License
See LICENSE