uraniyum 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/helpers.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  type Component = (() => HTMLElement) | {
2
2
  render: () => void;
3
+ element?: HTMLElement;
3
4
  };
4
- export declare function add(...components: Component[]): void;
5
+ export declare function add(component: Component): void;
5
6
  export {};
package/dist/index.esm.js CHANGED
@@ -41,47 +41,62 @@ const tags = new Proxy({}, {
41
41
  });
42
42
 
43
43
  function router(routes) {
44
- const getRoute = (path) => {
45
- return routes[path] || routes["*"];
46
- };
44
+ const container = document.createElement("div");
45
+ const routePatterns = [];
46
+ for (const path in routes) {
47
+ const keys = [];
48
+ const pattern = path
49
+ .replace(/\/:[^\/]+/g, (match) => {
50
+ keys.push(match.slice(2));
51
+ return "/([^/]+)";
52
+ })
53
+ .replace(/\*/g, ".*");
54
+ const regex = new RegExp(`^${pattern}$`);
55
+ routePatterns.push({ regex, keys, handler: routes[path] });
56
+ }
47
57
  const renderRoute = () => {
48
58
  const path = window.location.pathname;
49
- const pageFn = getRoute(path);
50
- const page = pageFn();
51
- const app = document.getElementById("app");
52
- if (!app)
53
- throw new Error("No #app element found");
54
- app.innerHTML = "";
55
- app.appendChild(page);
59
+ let matched = false;
60
+ for (const { regex, keys, handler } of routePatterns) {
61
+ const match = path.match(regex);
62
+ if (match) {
63
+ const params = {};
64
+ keys.forEach((key, i) => {
65
+ params[key] = match[i + 1];
66
+ });
67
+ container.innerHTML = "";
68
+ container.appendChild(handler(params));
69
+ matched = true;
70
+ break;
71
+ }
72
+ }
73
+ if (!matched && routes["*"]) {
74
+ container.innerHTML = "";
75
+ container.appendChild(routes["*"]());
76
+ }
56
77
  };
57
78
  window.addEventListener("popstate", renderRoute);
79
+ renderRoute();
58
80
  return {
59
81
  render: renderRoute,
60
- navigate: (path) => {
61
- history.pushState(null, "", path);
62
- renderRoute();
63
- }
82
+ element: container
64
83
  };
65
84
  }
66
85
 
67
- function add(...components) {
68
- const app = document.getElementById("app");
69
- if (!app)
70
- throw new Error("No #app element found");
71
- for (const c of components) {
72
- if (typeof c === "function") {
73
- const el = c();
74
- if (!(el instanceof Node)) {
75
- throw new Error("Component function must return an HTMLElement");
76
- }
77
- app.appendChild(el);
78
- }
79
- else if ("render" in c && typeof c.render === "function") {
80
- c.render();
81
- }
82
- else {
83
- throw new Error("Invalid component passed to add()");
86
+ function add(component) {
87
+ if (typeof component === "function") {
88
+ const el = component();
89
+ if (!(el instanceof Node)) {
90
+ throw new Error("Component function must return an HTMLElement");
84
91
  }
92
+ document.body.appendChild(el);
93
+ }
94
+ else if ("render" in component && typeof component.render === "function") {
95
+ document.body.appendChild(component.element || document.createElement("div"));
96
+ component.render();
97
+ }
98
+ else {
99
+ throw new Error("Invalid component passed to add()");
85
100
  }
86
101
  }
87
102
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/state.ts","../src/tags.ts","../src/router.ts","../src/helpers.ts"],"sourcesContent":["export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}","export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","export function router(routes: Record<string, () => HTMLElement>) {\r\n const getRoute = (path: string) => {\r\n return routes[path] || routes[\"*\"]\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n const pageFn = getRoute(path)\r\n const page = pageFn()\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n app.innerHTML = \"\"\r\n app.appendChild(page)\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n\r\n return {\r\n render: renderRoute,\r\n navigate: (path: string) => {\r\n history.pushState(null, \"\", path)\r\n renderRoute()\r\n }\r\n }\r\n}","type Component = (() => HTMLElement) | { render: () => void }\r\n\r\nexport function add(...components: Component[]) {\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n\r\n for (const c of components) {\r\n if (typeof c === \"function\") {\r\n const el = c()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n app.appendChild(el)\r\n } else if (\"render\" in c && typeof c.render === \"function\") {\r\n c.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/state.ts","../src/tags.ts","../src/router.ts","../src/helpers.ts"],"sourcesContent":["export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}","export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","type RouteHandler = (params?: Record<string, string>) => HTMLElement\r\n\r\nexport function router(routes: Record<string, RouteHandler>) {\r\n const container = document.createElement(\"div\")\r\n const routePatterns: {\r\n regex: RegExp\r\n keys: string[]\r\n handler: RouteHandler\r\n }[] = []\r\n\r\n for (const path in routes) {\r\n const keys: string[] = []\r\n const pattern = path\r\n .replace(/\\/:[^\\/]+/g, (match) => {\r\n keys.push(match.slice(2))\r\n return \"/([^/]+)\"\r\n })\r\n .replace(/\\*/g, \".*\")\r\n const regex = new RegExp(`^${pattern}$`)\r\n routePatterns.push({ regex, keys, handler: routes[path] })\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n let matched = false\r\n\r\n for (const { regex, keys, handler } of routePatterns) {\r\n const match = path.match(regex)\r\n if (match) {\r\n const params: Record<string, string> = {}\r\n keys.forEach((key, i) => {\r\n params[key] = match[i + 1]\r\n })\r\n container.innerHTML = \"\"\r\n container.appendChild(handler(params))\r\n matched = true\r\n break\r\n }\r\n }\r\n\r\n if (!matched && routes[\"*\"]) {\r\n container.innerHTML = \"\"\r\n container.appendChild(routes[\"*\"]())\r\n }\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n renderRoute()\r\n\r\n return {\r\n render: renderRoute,\r\n element: container\r\n }\r\n}\r\n","type Component = (() => HTMLElement) | { render: () => void; element?: HTMLElement }\r\n\r\nexport function add(component: Component) {\r\n if (typeof component === \"function\") {\r\n const el = component()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n document.body.appendChild(el)\r\n } else if (\"render\" in component && typeof component.render === \"function\") {\r\n document.body.appendChild(component.element || document.createElement(\"div\"))\r\n component.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n}"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -45,47 +45,62 @@ const tags = new Proxy({}, {
45
45
  });
46
46
 
47
47
  function router(routes) {
48
- const getRoute = (path) => {
49
- return routes[path] || routes["*"];
50
- };
48
+ const container = document.createElement("div");
49
+ const routePatterns = [];
50
+ for (const path in routes) {
51
+ const keys = [];
52
+ const pattern = path
53
+ .replace(/\/:[^\/]+/g, (match) => {
54
+ keys.push(match.slice(2));
55
+ return "/([^/]+)";
56
+ })
57
+ .replace(/\*/g, ".*");
58
+ const regex = new RegExp(`^${pattern}$`);
59
+ routePatterns.push({ regex, keys, handler: routes[path] });
60
+ }
51
61
  const renderRoute = () => {
52
62
  const path = window.location.pathname;
53
- const pageFn = getRoute(path);
54
- const page = pageFn();
55
- const app = document.getElementById("app");
56
- if (!app)
57
- throw new Error("No #app element found");
58
- app.innerHTML = "";
59
- app.appendChild(page);
63
+ let matched = false;
64
+ for (const { regex, keys, handler } of routePatterns) {
65
+ const match = path.match(regex);
66
+ if (match) {
67
+ const params = {};
68
+ keys.forEach((key, i) => {
69
+ params[key] = match[i + 1];
70
+ });
71
+ container.innerHTML = "";
72
+ container.appendChild(handler(params));
73
+ matched = true;
74
+ break;
75
+ }
76
+ }
77
+ if (!matched && routes["*"]) {
78
+ container.innerHTML = "";
79
+ container.appendChild(routes["*"]());
80
+ }
60
81
  };
61
82
  window.addEventListener("popstate", renderRoute);
83
+ renderRoute();
62
84
  return {
63
85
  render: renderRoute,
64
- navigate: (path) => {
65
- history.pushState(null, "", path);
66
- renderRoute();
67
- }
86
+ element: container
68
87
  };
69
88
  }
70
89
 
71
- function add(...components) {
72
- const app = document.getElementById("app");
73
- if (!app)
74
- throw new Error("No #app element found");
75
- for (const c of components) {
76
- if (typeof c === "function") {
77
- const el = c();
78
- if (!(el instanceof Node)) {
79
- throw new Error("Component function must return an HTMLElement");
80
- }
81
- app.appendChild(el);
82
- }
83
- else if ("render" in c && typeof c.render === "function") {
84
- c.render();
85
- }
86
- else {
87
- throw new Error("Invalid component passed to add()");
90
+ function add(component) {
91
+ if (typeof component === "function") {
92
+ const el = component();
93
+ if (!(el instanceof Node)) {
94
+ throw new Error("Component function must return an HTMLElement");
88
95
  }
96
+ document.body.appendChild(el);
97
+ }
98
+ else if ("render" in component && typeof component.render === "function") {
99
+ document.body.appendChild(component.element || document.createElement("div"));
100
+ component.render();
101
+ }
102
+ else {
103
+ throw new Error("Invalid component passed to add()");
89
104
  }
90
105
  }
91
106
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/state.ts","../src/tags.ts","../src/router.ts","../src/helpers.ts"],"sourcesContent":["export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}","export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","export function router(routes: Record<string, () => HTMLElement>) {\r\n const getRoute = (path: string) => {\r\n return routes[path] || routes[\"*\"]\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n const pageFn = getRoute(path)\r\n const page = pageFn()\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n app.innerHTML = \"\"\r\n app.appendChild(page)\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n\r\n return {\r\n render: renderRoute,\r\n navigate: (path: string) => {\r\n history.pushState(null, \"\", path)\r\n renderRoute()\r\n }\r\n }\r\n}","type Component = (() => HTMLElement) | { render: () => void }\r\n\r\nexport function add(...components: Component[]) {\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n\r\n for (const c of components) {\r\n if (typeof c === \"function\") {\r\n const el = c()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n app.appendChild(el)\r\n } else if (\"render\" in c && typeof c.render === \"function\") {\r\n c.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/state.ts","../src/tags.ts","../src/router.ts","../src/helpers.ts"],"sourcesContent":["export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}","export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","type RouteHandler = (params?: Record<string, string>) => HTMLElement\r\n\r\nexport function router(routes: Record<string, RouteHandler>) {\r\n const container = document.createElement(\"div\")\r\n const routePatterns: {\r\n regex: RegExp\r\n keys: string[]\r\n handler: RouteHandler\r\n }[] = []\r\n\r\n for (const path in routes) {\r\n const keys: string[] = []\r\n const pattern = path\r\n .replace(/\\/:[^\\/]+/g, (match) => {\r\n keys.push(match.slice(2))\r\n return \"/([^/]+)\"\r\n })\r\n .replace(/\\*/g, \".*\")\r\n const regex = new RegExp(`^${pattern}$`)\r\n routePatterns.push({ regex, keys, handler: routes[path] })\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n let matched = false\r\n\r\n for (const { regex, keys, handler } of routePatterns) {\r\n const match = path.match(regex)\r\n if (match) {\r\n const params: Record<string, string> = {}\r\n keys.forEach((key, i) => {\r\n params[key] = match[i + 1]\r\n })\r\n container.innerHTML = \"\"\r\n container.appendChild(handler(params))\r\n matched = true\r\n break\r\n }\r\n }\r\n\r\n if (!matched && routes[\"*\"]) {\r\n container.innerHTML = \"\"\r\n container.appendChild(routes[\"*\"]())\r\n }\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n renderRoute()\r\n\r\n return {\r\n render: renderRoute,\r\n element: container\r\n }\r\n}\r\n","type Component = (() => HTMLElement) | { render: () => void; element?: HTMLElement }\r\n\r\nexport function add(component: Component) {\r\n if (typeof component === \"function\") {\r\n const el = component()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n document.body.appendChild(el)\r\n } else if (\"render\" in component && typeof component.render === \"function\") {\r\n document.body.appendChild(component.element || document.createElement(\"div\"))\r\n component.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n}"],"names":[],"mappings":"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"}
package/dist/index.min.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).MiniUI={})}(this,function(e){"use strict";const n=new Proxy({},{get:(e,n)=>(e,...t)=>{const o=document.createElement(n);if(!e||"object"!=typeof e||Array.isArray(e)||e instanceof Node)null!=e&&t.unshift(e);else for(const[n,t]of Object.entries(e))o.setAttribute(n,t);for(const e of t.flat())e instanceof Node?o.appendChild(e):o.appendChild(document.createTextNode(String(e)));return o}});e.add=function(...e){const n=document.getElementById("app");if(!n)throw new Error("No #app element found");for(const t of e)if("function"==typeof t){const e=t();if(!(e instanceof Node))throw new Error("Component function must return an HTMLElement");n.appendChild(e)}else{if(!("render"in t)||"function"!=typeof t.render)throw new Error("Invalid component passed to add()");t.render()}},e.router=function(e){const n=()=>{const n=(n=>e[n]||e["*"])(window.location.pathname),t=n(),o=document.getElementById("app");if(!o)throw new Error("No #app element found");o.innerHTML="",o.appendChild(t)};return window.addEventListener("popstate",n),{render:n,navigate:e=>{history.pushState(null,"",e),n()}}},e.state=function(e){let n=e;const t=[];return{get:()=>n,set:e=>{n=e,t.forEach(e=>e(n))},subscribe:e=>(t.push(e),()=>{const n=t.indexOf(e);n>-1&&t.splice(n,1)})}},e.tags=n,Object.defineProperty(e,"__esModule",{value:!0})});
1
+ !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).MiniUI={})}(this,function(e){"use strict";const n=new Proxy({},{get:(e,n)=>(e,...t)=>{const o=document.createElement(n);if(!e||"object"!=typeof e||Array.isArray(e)||e instanceof Node)null!=e&&t.unshift(e);else for(const[n,t]of Object.entries(e))o.setAttribute(n,t);for(const e of t.flat())e instanceof Node?o.appendChild(e):o.appendChild(document.createTextNode(String(e)));return o}});e.add=function(e){if("function"==typeof e){const n=e();if(!(n instanceof Node))throw new Error("Component function must return an HTMLElement");document.body.appendChild(n)}else{if(!("render"in e)||"function"!=typeof e.render)throw new Error("Invalid component passed to add()");document.body.appendChild(e.element||document.createElement("div")),e.render()}},e.router=function(e){const n=document.createElement("div"),t=[];for(const n in e){const o=[],r=n.replace(/\/:[^\/]+/g,e=>(o.push(e.slice(2)),"/([^/]+)")).replace(/\*/g,".*"),i=new RegExp(`^${r}$`);t.push({regex:i,keys:o,handler:e[n]})}const o=()=>{const o=window.location.pathname;let r=!1;for(const{regex:e,keys:i,handler:d}of t){const t=o.match(e);if(t){const e={};i.forEach((n,o)=>{e[n]=t[o+1]}),n.innerHTML="",n.appendChild(d(e)),r=!0;break}}!r&&e["*"]&&(n.innerHTML="",n.appendChild(e["*"]()))};return window.addEventListener("popstate",o),o(),{render:o,element:n}},e.state=function(e){let n=e;const t=[];return{get:()=>n,set:e=>{n=e,t.forEach(e=>e(n))},subscribe:e=>(t.push(e),()=>{const n=t.indexOf(e);n>-1&&t.splice(n,1)})}},e.tags=n,Object.defineProperty(e,"__esModule",{value:!0})});
2
2
  //# sourceMappingURL=index.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.min.js","sources":["../src/tags.ts","../src/helpers.ts","../src/router.ts","../src/state.ts"],"sourcesContent":["export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","type Component = (() => HTMLElement) | { render: () => void }\r\n\r\nexport function add(...components: Component[]) {\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n\r\n for (const c of components) {\r\n if (typeof c === \"function\") {\r\n const el = c()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n app.appendChild(el)\r\n } else if (\"render\" in c && typeof c.render === \"function\") {\r\n c.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n }\r\n}\r\n","export function router(routes: Record<string, () => HTMLElement>) {\r\n const getRoute = (path: string) => {\r\n return routes[path] || routes[\"*\"]\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n const pageFn = getRoute(path)\r\n const page = pageFn()\r\n const app = document.getElementById(\"app\")\r\n if (!app) throw new Error(\"No #app element found\")\r\n app.innerHTML = \"\"\r\n app.appendChild(page)\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n\r\n return {\r\n render: renderRoute,\r\n navigate: (path: string) => {\r\n history.pushState(null, \"\", path)\r\n renderRoute()\r\n }\r\n }\r\n}","export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}"],"names":["tags","Proxy","get","_","tag","attrsOrChild","children","el","document","createElement","Array","isArray","Node","unshift","k","v","Object","entries","setAttribute","child","flat","appendChild","createTextNode","String","components","app","getElementById","Error","c","render","routes","renderRoute","pageFn","path","getRoute","window","location","pathname","page","innerHTML","addEventListener","navigate","history","pushState","initial","value","listeners","set","newValue","forEach","fn","subscribe","push","index","indexOf","splice"],"mappings":"mPAAaA,EAAO,IAAIC,MAAM,GAAI,CAC9BC,IAAG,CAACC,EAAGC,IACI,CAACC,KAAuBC,KAC3B,MAAMC,EAAKC,SAASC,cAAcL,GAClC,IAAIC,GAAwC,iBAAjBA,GAA8BK,MAAMC,QAAQN,IAAmBA,aAAwBO,KAIvF,MAAhBP,GACPC,EAASO,QAAQR,QAJjB,IAAK,MAAOS,EAAGC,KAAMC,OAAOC,QAAQZ,GAChCE,EAAGW,aAAaJ,EAAGC,GAM3B,IAAK,MAAMI,KAASb,EAASc,OACrBD,aAAiBP,KAAML,EAAGc,YAAYF,GACrCZ,EAAGc,YAAYb,SAASc,eAAeC,OAAOJ,KAEvD,OAAOZ,WCdH,YAAOiB,GACnB,MAAMC,EAAMjB,SAASkB,eAAe,OACpC,IAAKD,EAAK,MAAM,IAAIE,MAAM,yBAE1B,IAAK,MAAMC,KAAKJ,EACZ,GAAiB,mBAANI,EAAkB,CACzB,MAAMrB,EAAKqB,IACX,KAAMrB,aAAcK,MAChB,MAAM,IAAIe,MAAM,iDAEpBF,EAAIJ,YAAYd,EACnB,KAAM,MAAI,WAAYqB,IAAyB,mBAAbA,EAAEC,OAGjC,MAAM,IAAIF,MAAM,qCAFhBC,EAAEC,QAGL,CAET,WCnBM,SAAiBC,GACnB,MAIMC,EAAc,KAChB,MACMC,EANO,CAACC,GACPH,EAAOG,IAASH,EAAO,KAKfI,CADFC,OAAOC,SAASC,UAEvBC,EAAON,IACPP,EAAMjB,SAASkB,eAAe,OACpC,IAAKD,EAAK,MAAM,IAAIE,MAAM,yBAC1BF,EAAIc,UAAY,GAChBd,EAAIJ,YAAYiB,IAKpB,OAFAH,OAAOK,iBAAiB,WAAYT,GAE7B,CACHF,OAAQE,EACRU,SAAWR,IACPS,QAAQC,UAAU,KAAM,GAAIV,GAC5BF,KAGZ,UCxBM,SAAmBa,GACrB,IAAIC,EAAQD,EACZ,MAAME,EAAwB,GAiB9B,MAAO,CAAE5C,IAVG,IAAM2C,EAUJE,IAfDC,IACTH,EAAQG,EACRF,EAAUG,QAAQC,GAAMA,EAAGL,KAaZM,UARAD,IACfJ,EAAUM,KAAKF,GACR,KACH,MAAMG,EAAQP,EAAUQ,QAAQJ,GAC5BG,GAAS,GAAGP,EAAUS,OAAOF,EAAO,KAKpD"}
1
+ {"version":3,"file":"index.min.js","sources":["../src/tags.ts","../src/helpers.ts","../src/router.ts","../src/state.ts"],"sourcesContent":["export const tags = new Proxy({}, {\r\n get(_, tag: string) {\r\n return (attrsOrChild?: any, ...children: any[]) => {\r\n const el = document.createElement(tag)\r\n if (attrsOrChild && typeof attrsOrChild === 'object' && !Array.isArray(attrsOrChild) && !(attrsOrChild instanceof Node)) {\r\n for (const [k, v] of Object.entries(attrsOrChild)) {\r\n el.setAttribute(k, v as string)\r\n }\r\n } else if (attrsOrChild != null) {\r\n children.unshift(attrsOrChild)\r\n }\r\n\r\n for (const child of children.flat()) {\r\n if (child instanceof Node) el.appendChild(child)\r\n else el.appendChild(document.createTextNode(String(child)))\r\n }\r\n return el\r\n }\r\n }\r\n})","type Component = (() => HTMLElement) | { render: () => void; element?: HTMLElement }\r\n\r\nexport function add(component: Component) {\r\n if (typeof component === \"function\") {\r\n const el = component()\r\n if (!(el instanceof Node)) {\r\n throw new Error(\"Component function must return an HTMLElement\")\r\n }\r\n document.body.appendChild(el)\r\n } else if (\"render\" in component && typeof component.render === \"function\") {\r\n document.body.appendChild(component.element || document.createElement(\"div\"))\r\n component.render()\r\n } else {\r\n throw new Error(\"Invalid component passed to add()\")\r\n }\r\n}","type RouteHandler = (params?: Record<string, string>) => HTMLElement\r\n\r\nexport function router(routes: Record<string, RouteHandler>) {\r\n const container = document.createElement(\"div\")\r\n const routePatterns: {\r\n regex: RegExp\r\n keys: string[]\r\n handler: RouteHandler\r\n }[] = []\r\n\r\n for (const path in routes) {\r\n const keys: string[] = []\r\n const pattern = path\r\n .replace(/\\/:[^\\/]+/g, (match) => {\r\n keys.push(match.slice(2))\r\n return \"/([^/]+)\"\r\n })\r\n .replace(/\\*/g, \".*\")\r\n const regex = new RegExp(`^${pattern}$`)\r\n routePatterns.push({ regex, keys, handler: routes[path] })\r\n }\r\n\r\n const renderRoute = () => {\r\n const path = window.location.pathname\r\n let matched = false\r\n\r\n for (const { regex, keys, handler } of routePatterns) {\r\n const match = path.match(regex)\r\n if (match) {\r\n const params: Record<string, string> = {}\r\n keys.forEach((key, i) => {\r\n params[key] = match[i + 1]\r\n })\r\n container.innerHTML = \"\"\r\n container.appendChild(handler(params))\r\n matched = true\r\n break\r\n }\r\n }\r\n\r\n if (!matched && routes[\"*\"]) {\r\n container.innerHTML = \"\"\r\n container.appendChild(routes[\"*\"]())\r\n }\r\n }\r\n\r\n window.addEventListener(\"popstate\", renderRoute)\r\n renderRoute()\r\n\r\n return {\r\n render: renderRoute,\r\n element: container\r\n }\r\n}\r\n","export function state<T>(initial: T) {\r\n let value = initial\r\n const listeners: Function[] = []\r\n\r\n const set = (newValue: T) => {\r\n value = newValue\r\n listeners.forEach(fn => fn(value))\r\n }\r\n\r\n const get = () => value\r\n\r\n const subscribe = (fn: Function) => {\r\n listeners.push(fn)\r\n return () => {\r\n const index = listeners.indexOf(fn)\r\n if (index > -1) listeners.splice(index, 1)\r\n }\r\n }\r\n\r\n return { get, set, subscribe }\r\n}"],"names":["tags","Proxy","get","_","tag","attrsOrChild","children","el","document","createElement","Array","isArray","Node","unshift","k","v","Object","entries","setAttribute","child","flat","appendChild","createTextNode","String","component","Error","body","render","element","routes","container","routePatterns","path","keys","pattern","replace","match","push","slice","regex","RegExp","handler","renderRoute","window","location","pathname","matched","params","forEach","key","i","innerHTML","addEventListener","initial","value","listeners","set","newValue","fn","subscribe","index","indexOf","splice"],"mappings":"mPAAaA,EAAO,IAAIC,MAAM,GAAI,CAC9BC,IAAG,CAACC,EAAGC,IACI,CAACC,KAAuBC,KAC3B,MAAMC,EAAKC,SAASC,cAAcL,GAClC,IAAIC,GAAwC,iBAAjBA,GAA8BK,MAAMC,QAAQN,IAAmBA,aAAwBO,KAIvF,MAAhBP,GACPC,EAASO,QAAQR,QAJjB,IAAK,MAAOS,EAAGC,KAAMC,OAAOC,QAAQZ,GAChCE,EAAGW,aAAaJ,EAAGC,GAM3B,IAAK,MAAMI,KAASb,EAASc,OACrBD,aAAiBP,KAAML,EAAGc,YAAYF,GACrCZ,EAAGc,YAAYb,SAASc,eAAeC,OAAOJ,KAEvD,OAAOZ,WCdb,SAAciB,GAChB,GAAyB,mBAAdA,EAA0B,CACjC,MAAMjB,EAAKiB,IACX,KAAMjB,aAAcK,MAChB,MAAM,IAAIa,MAAM,iDAEpBjB,SAASkB,KAAKL,YAAYd,EAC7B,KAAM,MAAI,WAAYiB,IAAyC,mBAArBA,EAAUG,OAIjD,MAAM,IAAIF,MAAM,qCAHhBjB,SAASkB,KAAKL,YAAYG,EAAUI,SAAWpB,SAASC,cAAc,QACtEe,EAAUG,QAGb,CACL,WCbM,SAAiBE,GACnB,MAAMC,EAAYtB,SAASC,cAAc,OACnCsB,EAIA,GAEN,IAAK,MAAMC,KAAQH,EAAQ,CACvB,MAAMI,EAAiB,GACjBC,EAAUF,EACXG,QAAQ,aAAeC,IACpBH,EAAKI,KAAKD,EAAME,MAAM,IACf,aAEVH,QAAQ,MAAO,MACdI,EAAQ,IAAIC,OAAO,IAAIN,MAC7BH,EAAcM,KAAK,CAAEE,QAAON,OAAMQ,QAASZ,EAAOG,IACrD,CAED,MAAMU,EAAc,KAChB,MAAMV,EAAOW,OAAOC,SAASC,SAC7B,IAAIC,GAAU,EAEd,IAAK,MAAMP,MAAEA,EAAKN,KAAEA,EAAIQ,QAAEA,KAAaV,EAAe,CAClD,MAAMK,EAAQJ,EAAKI,MAAMG,GACzB,GAAIH,EAAO,CACP,MAAMW,EAAiC,CAAA,EACvCd,EAAKe,QAAQ,CAACC,EAAKC,KACfH,EAAOE,GAAOb,EAAMc,EAAI,KAE5BpB,EAAUqB,UAAY,GACtBrB,EAAUT,YAAYoB,EAAQM,IAC9BD,GAAU,EACV,KACH,CACJ,EAEIA,GAAWjB,EAAO,OACnBC,EAAUqB,UAAY,GACtBrB,EAAUT,YAAYQ,EAAO,UAOrC,OAHAc,OAAOS,iBAAiB,WAAYV,GACpCA,IAEO,CACHf,OAAQe,EACRd,QAASE,EAEjB,UCrDM,SAAmBuB,GACrB,IAAIC,EAAQD,EACZ,MAAME,EAAwB,GAiB9B,MAAO,CAAErD,IAVG,IAAMoD,EAUJE,IAfDC,IACTH,EAAQG,EACRF,EAAUP,QAAQU,GAAMA,EAAGJ,KAaZK,UARAD,IACfH,EAAUlB,KAAKqB,GACR,KACH,MAAME,EAAQL,EAAUM,QAAQH,GAC5BE,GAAS,GAAGL,EAAUO,OAAOF,EAAO,KAKpD"}
package/dist/router.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- export declare function router(routes: Record<string, () => HTMLElement>): {
1
+ type RouteHandler = (params?: Record<string, string>) => HTMLElement;
2
+ export declare function router(routes: Record<string, RouteHandler>): {
2
3
  render: () => void;
3
- navigate: (path: string) => void;
4
+ element: HTMLDivElement;
4
5
  };
6
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uraniyum",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.esm.js",
6
6
  "browser": "dist/index.min.js",
@@ -30,4 +30,4 @@
30
30
  "dependencies": {
31
31
  "tslib": "^2.8.1"
32
32
  }
33
- }
33
+ }
package/src/helpers.ts CHANGED
@@ -1,20 +1,16 @@
1
- type Component = (() => HTMLElement) | { render: () => void }
1
+ type Component = (() => HTMLElement) | { render: () => void; element?: HTMLElement }
2
2
 
3
- export function add(...components: Component[]) {
4
- const app = document.getElementById("app")
5
- if (!app) throw new Error("No #app element found")
6
-
7
- for (const c of components) {
8
- if (typeof c === "function") {
9
- const el = c()
10
- if (!(el instanceof Node)) {
11
- throw new Error("Component function must return an HTMLElement")
12
- }
13
- app.appendChild(el)
14
- } else if ("render" in c && typeof c.render === "function") {
15
- c.render()
16
- } else {
17
- throw new Error("Invalid component passed to add()")
3
+ export function add(component: Component) {
4
+ if (typeof component === "function") {
5
+ const el = component()
6
+ if (!(el instanceof Node)) {
7
+ throw new Error("Component function must return an HTMLElement")
18
8
  }
9
+ document.body.appendChild(el)
10
+ } else if ("render" in component && typeof component.render === "function") {
11
+ document.body.appendChild(component.element || document.createElement("div"))
12
+ component.render()
13
+ } else {
14
+ throw new Error("Invalid component passed to add()")
19
15
  }
20
- }
16
+ }
package/src/router.ts CHANGED
@@ -1,25 +1,54 @@
1
- export function router(routes: Record<string, () => HTMLElement>) {
2
- const getRoute = (path: string) => {
3
- return routes[path] || routes["*"]
1
+ type RouteHandler = (params?: Record<string, string>) => HTMLElement
2
+
3
+ export function router(routes: Record<string, RouteHandler>) {
4
+ const container = document.createElement("div")
5
+ const routePatterns: {
6
+ regex: RegExp
7
+ keys: string[]
8
+ handler: RouteHandler
9
+ }[] = []
10
+
11
+ for (const path in routes) {
12
+ const keys: string[] = []
13
+ const pattern = path
14
+ .replace(/\/:[^\/]+/g, (match) => {
15
+ keys.push(match.slice(2))
16
+ return "/([^/]+)"
17
+ })
18
+ .replace(/\*/g, ".*")
19
+ const regex = new RegExp(`^${pattern}$`)
20
+ routePatterns.push({ regex, keys, handler: routes[path] })
4
21
  }
5
22
 
6
23
  const renderRoute = () => {
7
24
  const path = window.location.pathname
8
- const pageFn = getRoute(path)
9
- const page = pageFn()
10
- const app = document.getElementById("app")
11
- if (!app) throw new Error("No #app element found")
12
- app.innerHTML = ""
13
- app.appendChild(page)
25
+ let matched = false
26
+
27
+ for (const { regex, keys, handler } of routePatterns) {
28
+ const match = path.match(regex)
29
+ if (match) {
30
+ const params: Record<string, string> = {}
31
+ keys.forEach((key, i) => {
32
+ params[key] = match[i + 1]
33
+ })
34
+ container.innerHTML = ""
35
+ container.appendChild(handler(params))
36
+ matched = true
37
+ break
38
+ }
39
+ }
40
+
41
+ if (!matched && routes["*"]) {
42
+ container.innerHTML = ""
43
+ container.appendChild(routes["*"]())
44
+ }
14
45
  }
15
46
 
16
47
  window.addEventListener("popstate", renderRoute)
48
+ renderRoute()
17
49
 
18
50
  return {
19
51
  render: renderRoute,
20
- navigate: (path: string) => {
21
- history.pushState(null, "", path)
22
- renderRoute()
23
- }
52
+ element: container
24
53
  }
25
- }
54
+ }