@symbo.ls/router 3.14.0 → 3.14.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/index.js CHANGED
@@ -195,14 +195,21 @@ export const router = async (path, el, state = {}, options = {}) => {
195
195
  lastPathname = pathname
196
196
 
197
197
  // Route matching - support both simple and param-based
198
- let route, content, params
198
+ let route, routePath, content, params
199
199
  if (opts.useParamsMatching) {
200
200
  const match = matchRoute(pathname, element.routes, opts.level)
201
- route = match.routePath
201
+ // FRAMEWORK-2: state.route must reflect the matched pattern key
202
+ // (e.g. `/players/:id`), not the literal first URL segment, so
203
+ // consumers and devtools can branch on which route handler fired.
204
+ // The first-segment value is still exposed as `routePath` for the
205
+ // rare consumer that needs the URL piece directly.
206
+ route = match.key
207
+ routePath = match.routePath
202
208
  content = match.content
203
209
  params = match.params
204
210
  } else {
205
211
  route = getActiveRoute(opts.level, pathname)
212
+ routePath = route
206
213
  content = element.routes[route || '/'] || element.routes['/*']
207
214
  params = {}
208
215
  }
@@ -243,7 +250,7 @@ export const router = async (path, el, state = {}, options = {}) => {
243
250
  }
244
251
 
245
252
  if (pathChanged || !hashChanged) {
246
- const stateUpdate = { route, hash, debugging: false }
253
+ const stateUpdate = { route, routePath, hash, debugging: false }
247
254
  if (Object.keys(params).length) stateUpdate.params = params
248
255
  if (Object.keys(query).length) stateUpdate.query = query
249
256
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/router",
3
- "version": "3.14.0",
3
+ "version": "3.14.1",
4
4
  "license": "CC-BY-NC-4.0",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -25,8 +25,8 @@
25
25
  "prepublish": "npm run build && npm run copy:package:cjs"
26
26
  },
27
27
  "dependencies": {
28
- "@symbo.ls/element": "^3.14.0",
29
- "@symbo.ls/utils": "^3.14.0"
28
+ "@symbo.ls/element": "^3.14.3",
29
+ "@symbo.ls/utils": "^3.14.2"
30
30
  },
31
31
  "gitHead": "9fc1b79b41cdc725ca6b24aec64920a599634681",
32
32
  "devDependencies": {
package/dist/cjs/index.js DELETED
@@ -1,281 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var index_exports = {};
20
- __export(index_exports, {
21
- default: () => index_default,
22
- getActiveRoute: () => getActiveRoute,
23
- lastLevel: () => lastLevel,
24
- lastPathname: () => lastPathname,
25
- matchRoute: () => matchRoute,
26
- parseQuery: () => parseQuery,
27
- parseRoutePattern: () => parseRoutePattern,
28
- router: () => router,
29
- runGuards: () => runGuards
30
- });
31
- module.exports = __toCommonJS(index_exports);
32
- var import_utils = require("@symbo.ls/utils");
33
- const paramPattern = /^:(.+)/;
34
- const wildcardPattern = /^\*$/;
35
- const routeCache = /* @__PURE__ */ new Map();
36
- const parseRoutePattern = (pattern) => {
37
- const cached = routeCache.get(pattern);
38
- if (cached) return cached;
39
- const segments = pattern.replace(/^\//, "").split("/");
40
- const params = [];
41
- let hasWildcard = false;
42
- for (let i = 0; i < segments.length; i++) {
43
- const match = segments[i].match(paramPattern);
44
- if (match) {
45
- params.push({ index: i, name: match[1] });
46
- } else if (wildcardPattern.test(segments[i])) {
47
- hasWildcard = true;
48
- }
49
- }
50
- const result = { segments, params, hasWildcard, pattern };
51
- routeCache.set(pattern, result);
52
- return result;
53
- };
54
- const matchRoute = (pathname, routes, level = 0) => {
55
- const pathSegments = pathname.replace(/^\//, "").split("/").filter(Boolean);
56
- const relevantSegments = pathSegments.slice(level);
57
- const routePath = "/" + (relevantSegments[0] || "");
58
- let bestMatch = null;
59
- let bestScore = -1;
60
- let matchedParams = {};
61
- for (const key in routes) {
62
- if (key === "/*") continue;
63
- const parsed = parseRoutePattern(key);
64
- const score = scoreMatch(relevantSegments, parsed);
65
- if (score > bestScore) {
66
- bestScore = score;
67
- bestMatch = key;
68
- matchedParams = extractParams(relevantSegments, parsed);
69
- }
70
- }
71
- if (!bestMatch && routes["/*"]) {
72
- bestMatch = "/*";
73
- }
74
- return {
75
- key: bestMatch,
76
- content: bestMatch ? routes[bestMatch] : null,
77
- params: matchedParams,
78
- routePath
79
- };
80
- };
81
- const scoreMatch = (pathSegments, parsed) => {
82
- const { segments, hasWildcard } = parsed;
83
- if (!hasWildcard && segments.length !== pathSegments.length && segments.length !== 1) {
84
- if (segments.length > pathSegments.length) return -1;
85
- }
86
- let score = 0;
87
- const len = Math.min(segments.length, pathSegments.length);
88
- for (let i = 0; i < len; i++) {
89
- if (segments[i] === pathSegments[i]) {
90
- score += 3;
91
- } else if (paramPattern.test(segments[i])) {
92
- score += 1;
93
- } else if (wildcardPattern.test(segments[i])) {
94
- score += 0.5;
95
- } else {
96
- return -1;
97
- }
98
- }
99
- return score;
100
- };
101
- const extractParams = (pathSegments, parsed) => {
102
- const params = {};
103
- for (const { index, name } of parsed.params) {
104
- if (pathSegments[index]) {
105
- params[name] = decodeURIComponent(pathSegments[index]);
106
- }
107
- }
108
- return params;
109
- };
110
- const parseQuery = (search) => {
111
- if (!search || search === "?") return {};
112
- const params = {};
113
- const searchParams = new URLSearchParams(search);
114
- searchParams.forEach((value, key) => {
115
- if (params[key] !== void 0) {
116
- if (!Array.isArray(params[key])) params[key] = [params[key]];
117
- params[key].push(value);
118
- } else {
119
- params[key] = value;
120
- }
121
- });
122
- return params;
123
- };
124
- const runGuards = async (guards, context) => {
125
- if (!guards || !guards.length) return true;
126
- for (const guard of guards) {
127
- const result = await guard(context);
128
- if (result === false) return false;
129
- if (typeof result === "string") return result;
130
- }
131
- return true;
132
- };
133
- const getActiveRoute = (level = 0, route) => {
134
- if (!route) route = typeof import_utils.window !== "undefined" ? import_utils.window.location.pathname : "/";
135
- const routeArray = route.split("/");
136
- const activeRoute = routeArray[level + 1];
137
- if (activeRoute) return `/${activeRoute}`;
138
- };
139
- let lastPathname;
140
- let lastLevel = 0;
141
- const normalizePath = (p) => !p || p === "srcdoc" || p === "about:srcdoc" ? "/" : p;
142
- const defaultOptions = {
143
- level: lastLevel,
144
- pushState: true,
145
- initialRender: false,
146
- scrollToTop: true,
147
- scrollToNode: false,
148
- scrollNode: import_utils.document && import_utils.document.documentElement,
149
- scrollBody: false,
150
- useFragment: false,
151
- updateState: true,
152
- scrollToOffset: 0,
153
- contentElementKey: "content",
154
- scrollToOptions: { behavior: "smooth" },
155
- useParamsMatching: true
156
- };
157
- const router = async (path, el, state = {}, options = {}) => {
158
- const element = el || void 0;
159
- const win = element?.context?.window || import_utils.window;
160
- const doc = element?.context?.document || import_utils.document;
161
- const opts = {
162
- ...defaultOptions,
163
- ...element.context.routerOptions,
164
- ...options
165
- };
166
- lastLevel = opts.lastLevel;
167
- const ref = element.__ref;
168
- if (opts.contentElementKey !== "content" && opts.contentElementKey !== ref.contentElementKey || !ref.contentElementKey) {
169
- ref.contentElementKey = opts.contentElementKey || "content";
170
- }
171
- const contentElementKey = ref.contentElementKey || opts.contentElementKey || "content";
172
- const origin = win.location.origin !== "null" ? win.location.origin : "http://localhost";
173
- path = normalizePath(path);
174
- const urlObj = new win.URL(origin + path);
175
- const { pathname, search, hash } = urlObj;
176
- const query = parseQuery(search);
177
- const rootNode = element.node;
178
- const hashChanged = hash && hash !== win.location.hash.slice(1);
179
- const pathChanged = pathname !== lastPathname;
180
- lastPathname = pathname;
181
- let route, content, params;
182
- if (opts.useParamsMatching) {
183
- const match = matchRoute(pathname, element.routes, opts.level);
184
- route = match.routePath;
185
- content = match.content;
186
- params = match.params;
187
- } else {
188
- route = getActiveRoute(opts.level, pathname);
189
- content = element.routes[route || "/"] || element.routes["/*"];
190
- params = {};
191
- }
192
- const scrollNode = opts.scrollToNode ? rootNode : opts.scrollNode;
193
- if (element.state?.root?.debugging) {
194
- element.state.root.debugging = false;
195
- return;
196
- }
197
- if (!content) {
198
- if (opts.onNotFound) {
199
- opts.onNotFound({ pathname, route, element });
200
- } else if (!opts.silent) {
201
- console.warn("[smbls/router] no content matched for path", pathname, "\u2014 available routes:", Object.keys(element.routes || {}));
202
- }
203
- return;
204
- }
205
- if (opts.guards && opts.guards.length) {
206
- const guardContext = { pathname, route, params, query, hash, element, state };
207
- const guardResult = await runGuards(opts.guards, guardContext);
208
- if (guardResult === false) return;
209
- if (typeof guardResult === "string") {
210
- return router(guardResult, el, state, { ...options, guards: [] });
211
- }
212
- }
213
- if (opts.pushState) {
214
- try {
215
- win.history.pushState(state, null, pathname + (search || "") + (hash || ""));
216
- } catch (e) {
217
- }
218
- }
219
- if (pathChanged || !hashChanged) {
220
- const stateUpdate = { route, hash, debugging: false };
221
- if (Object.keys(params).length) stateUpdate.params = params;
222
- if (Object.keys(query).length) stateUpdate.query = query;
223
- if (opts.updateState) {
224
- element.state.update(
225
- stateUpdate,
226
- { preventContentUpdate: true }
227
- );
228
- }
229
- if (contentElementKey && opts.removeOldElement) {
230
- element[contentElementKey].remove();
231
- }
232
- const originContent = element.__ref?.origin?.content;
233
- const contentStyles = {};
234
- if (originContent) {
235
- for (const k in originContent) {
236
- const v = originContent[k];
237
- if (k === "__ref" || k === "props" || k === "node" || k === "parent" || k === "key") continue;
238
- if (typeof v === "string" || typeof v === "number" || typeof v === "boolean" || typeof v === "object" && v !== null && !v.node && !v.__ref) {
239
- contentStyles[k] = v;
240
- }
241
- }
242
- }
243
- const nextContent = {
244
- ...contentStyles,
245
- ...typeof content === "object" ? content : { extends: content }
246
- };
247
- if (opts.useFragment) nextContent.tag = "fragment";
248
- try {
249
- element.set(nextContent, { contentElementKey });
250
- } catch (err) {
251
- console.error("[smbls/router] failed to render route content", pathname, err);
252
- }
253
- }
254
- if (opts.scrollToTop && scrollNode?.scrollTo) {
255
- scrollNode.scrollTo({
256
- ...opts.scrollToOptions || {},
257
- top: 0,
258
- left: 0
259
- });
260
- }
261
- if (opts.scrollToNode && content[contentElementKey]?.node?.scrollTo) {
262
- content[contentElementKey].node.scrollTo({
263
- ...opts.scrollToOptions || {},
264
- top: 0,
265
- left: 0
266
- });
267
- }
268
- if (hash) {
269
- const activeNode = doc.getElementById(hash);
270
- if (activeNode && scrollNode?.scrollTo) {
271
- const top = activeNode.getBoundingClientRect().top + rootNode.scrollTop - (opts.scrollToOffset || 0);
272
- scrollNode.scrollTo({
273
- ...opts.scrollToOptions || {},
274
- top,
275
- left: 0
276
- });
277
- }
278
- }
279
- (0, import_utils.triggerEventOn)("routeChanged", element, opts);
280
- };
281
- var index_default = router;
package/dist/esm/index.js DELETED
@@ -1,261 +0,0 @@
1
- import { document, window, triggerEventOn } from "@symbo.ls/utils";
2
- const paramPattern = /^:(.+)/;
3
- const wildcardPattern = /^\*$/;
4
- const routeCache = /* @__PURE__ */ new Map();
5
- const parseRoutePattern = (pattern) => {
6
- const cached = routeCache.get(pattern);
7
- if (cached) return cached;
8
- const segments = pattern.replace(/^\//, "").split("/");
9
- const params = [];
10
- let hasWildcard = false;
11
- for (let i = 0; i < segments.length; i++) {
12
- const match = segments[i].match(paramPattern);
13
- if (match) {
14
- params.push({ index: i, name: match[1] });
15
- } else if (wildcardPattern.test(segments[i])) {
16
- hasWildcard = true;
17
- }
18
- }
19
- const result = { segments, params, hasWildcard, pattern };
20
- routeCache.set(pattern, result);
21
- return result;
22
- };
23
- const matchRoute = (pathname, routes, level = 0) => {
24
- const pathSegments = pathname.replace(/^\//, "").split("/").filter(Boolean);
25
- const relevantSegments = pathSegments.slice(level);
26
- const routePath = "/" + (relevantSegments[0] || "");
27
- let bestMatch = null;
28
- let bestScore = -1;
29
- let matchedParams = {};
30
- for (const key in routes) {
31
- if (key === "/*") continue;
32
- const parsed = parseRoutePattern(key);
33
- const score = scoreMatch(relevantSegments, parsed);
34
- if (score > bestScore) {
35
- bestScore = score;
36
- bestMatch = key;
37
- matchedParams = extractParams(relevantSegments, parsed);
38
- }
39
- }
40
- if (!bestMatch && routes["/*"]) {
41
- bestMatch = "/*";
42
- }
43
- return {
44
- key: bestMatch,
45
- content: bestMatch ? routes[bestMatch] : null,
46
- params: matchedParams,
47
- routePath
48
- };
49
- };
50
- const scoreMatch = (pathSegments, parsed) => {
51
- const { segments, hasWildcard } = parsed;
52
- if (!hasWildcard && segments.length !== pathSegments.length && segments.length !== 1) {
53
- if (segments.length > pathSegments.length) return -1;
54
- }
55
- let score = 0;
56
- const len = Math.min(segments.length, pathSegments.length);
57
- for (let i = 0; i < len; i++) {
58
- if (segments[i] === pathSegments[i]) {
59
- score += 3;
60
- } else if (paramPattern.test(segments[i])) {
61
- score += 1;
62
- } else if (wildcardPattern.test(segments[i])) {
63
- score += 0.5;
64
- } else {
65
- return -1;
66
- }
67
- }
68
- return score;
69
- };
70
- const extractParams = (pathSegments, parsed) => {
71
- const params = {};
72
- for (const { index, name } of parsed.params) {
73
- if (pathSegments[index]) {
74
- params[name] = decodeURIComponent(pathSegments[index]);
75
- }
76
- }
77
- return params;
78
- };
79
- const parseQuery = (search) => {
80
- if (!search || search === "?") return {};
81
- const params = {};
82
- const searchParams = new URLSearchParams(search);
83
- searchParams.forEach((value, key) => {
84
- if (params[key] !== void 0) {
85
- if (!Array.isArray(params[key])) params[key] = [params[key]];
86
- params[key].push(value);
87
- } else {
88
- params[key] = value;
89
- }
90
- });
91
- return params;
92
- };
93
- const runGuards = async (guards, context) => {
94
- if (!guards || !guards.length) return true;
95
- for (const guard of guards) {
96
- const result = await guard(context);
97
- if (result === false) return false;
98
- if (typeof result === "string") return result;
99
- }
100
- return true;
101
- };
102
- const getActiveRoute = (level = 0, route) => {
103
- if (!route) route = typeof window !== "undefined" ? window.location.pathname : "/";
104
- const routeArray = route.split("/");
105
- const activeRoute = routeArray[level + 1];
106
- if (activeRoute) return `/${activeRoute}`;
107
- };
108
- let lastPathname;
109
- let lastLevel = 0;
110
- const normalizePath = (p) => !p || p === "srcdoc" || p === "about:srcdoc" ? "/" : p;
111
- const defaultOptions = {
112
- level: lastLevel,
113
- pushState: true,
114
- initialRender: false,
115
- scrollToTop: true,
116
- scrollToNode: false,
117
- scrollNode: document && document.documentElement,
118
- scrollBody: false,
119
- useFragment: false,
120
- updateState: true,
121
- scrollToOffset: 0,
122
- contentElementKey: "content",
123
- scrollToOptions: { behavior: "smooth" },
124
- useParamsMatching: true
125
- };
126
- const router = async (path, el, state = {}, options = {}) => {
127
- const element = el || void 0;
128
- const win = element?.context?.window || window;
129
- const doc = element?.context?.document || document;
130
- const opts = {
131
- ...defaultOptions,
132
- ...element.context.routerOptions,
133
- ...options
134
- };
135
- lastLevel = opts.lastLevel;
136
- const ref = element.__ref;
137
- if (opts.contentElementKey !== "content" && opts.contentElementKey !== ref.contentElementKey || !ref.contentElementKey) {
138
- ref.contentElementKey = opts.contentElementKey || "content";
139
- }
140
- const contentElementKey = ref.contentElementKey || opts.contentElementKey || "content";
141
- const origin = win.location.origin !== "null" ? win.location.origin : "http://localhost";
142
- path = normalizePath(path);
143
- const urlObj = new win.URL(origin + path);
144
- const { pathname, search, hash } = urlObj;
145
- const query = parseQuery(search);
146
- const rootNode = element.node;
147
- const hashChanged = hash && hash !== win.location.hash.slice(1);
148
- const pathChanged = pathname !== lastPathname;
149
- lastPathname = pathname;
150
- let route, content, params;
151
- if (opts.useParamsMatching) {
152
- const match = matchRoute(pathname, element.routes, opts.level);
153
- route = match.routePath;
154
- content = match.content;
155
- params = match.params;
156
- } else {
157
- route = getActiveRoute(opts.level, pathname);
158
- content = element.routes[route || "/"] || element.routes["/*"];
159
- params = {};
160
- }
161
- const scrollNode = opts.scrollToNode ? rootNode : opts.scrollNode;
162
- if (element.state?.root?.debugging) {
163
- element.state.root.debugging = false;
164
- return;
165
- }
166
- if (!content) {
167
- if (opts.onNotFound) {
168
- opts.onNotFound({ pathname, route, element });
169
- } else if (!opts.silent) {
170
- console.warn("[smbls/router] no content matched for path", pathname, "\u2014 available routes:", Object.keys(element.routes || {}));
171
- }
172
- return;
173
- }
174
- if (opts.guards && opts.guards.length) {
175
- const guardContext = { pathname, route, params, query, hash, element, state };
176
- const guardResult = await runGuards(opts.guards, guardContext);
177
- if (guardResult === false) return;
178
- if (typeof guardResult === "string") {
179
- return router(guardResult, el, state, { ...options, guards: [] });
180
- }
181
- }
182
- if (opts.pushState) {
183
- try {
184
- win.history.pushState(state, null, pathname + (search || "") + (hash || ""));
185
- } catch (e) {
186
- }
187
- }
188
- if (pathChanged || !hashChanged) {
189
- const stateUpdate = { route, hash, debugging: false };
190
- if (Object.keys(params).length) stateUpdate.params = params;
191
- if (Object.keys(query).length) stateUpdate.query = query;
192
- if (opts.updateState) {
193
- element.state.update(
194
- stateUpdate,
195
- { preventContentUpdate: true }
196
- );
197
- }
198
- if (contentElementKey && opts.removeOldElement) {
199
- element[contentElementKey].remove();
200
- }
201
- const originContent = element.__ref?.origin?.content;
202
- const contentStyles = {};
203
- if (originContent) {
204
- for (const k in originContent) {
205
- const v = originContent[k];
206
- if (k === "__ref" || k === "props" || k === "node" || k === "parent" || k === "key") continue;
207
- if (typeof v === "string" || typeof v === "number" || typeof v === "boolean" || typeof v === "object" && v !== null && !v.node && !v.__ref) {
208
- contentStyles[k] = v;
209
- }
210
- }
211
- }
212
- const nextContent = {
213
- ...contentStyles,
214
- ...typeof content === "object" ? content : { extends: content }
215
- };
216
- if (opts.useFragment) nextContent.tag = "fragment";
217
- try {
218
- element.set(nextContent, { contentElementKey });
219
- } catch (err) {
220
- console.error("[smbls/router] failed to render route content", pathname, err);
221
- }
222
- }
223
- if (opts.scrollToTop && scrollNode?.scrollTo) {
224
- scrollNode.scrollTo({
225
- ...opts.scrollToOptions || {},
226
- top: 0,
227
- left: 0
228
- });
229
- }
230
- if (opts.scrollToNode && content[contentElementKey]?.node?.scrollTo) {
231
- content[contentElementKey].node.scrollTo({
232
- ...opts.scrollToOptions || {},
233
- top: 0,
234
- left: 0
235
- });
236
- }
237
- if (hash) {
238
- const activeNode = doc.getElementById(hash);
239
- if (activeNode && scrollNode?.scrollTo) {
240
- const top = activeNode.getBoundingClientRect().top + rootNode.scrollTop - (opts.scrollToOffset || 0);
241
- scrollNode.scrollTo({
242
- ...opts.scrollToOptions || {},
243
- top,
244
- left: 0
245
- });
246
- }
247
- }
248
- triggerEventOn("routeChanged", element, opts);
249
- };
250
- var index_default = router;
251
- export {
252
- index_default as default,
253
- getActiveRoute,
254
- lastLevel,
255
- lastPathname,
256
- matchRoute,
257
- parseQuery,
258
- parseRoutePattern,
259
- router,
260
- runGuards
261
- };
@@ -1,754 +0,0 @@
1
- "use strict";
2
- var DomqlRouter = (() => {
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __esm = (fn, res) => function __init() {
8
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
- };
10
- var __export = (target, all) => {
11
- for (var name in all)
12
- __defProp(target, name, { get: all[name], enumerable: true });
13
- };
14
- var __copyProps = (to, from, except, desc) => {
15
- if (from && typeof from === "object" || typeof from === "function") {
16
- for (let key of __getOwnPropNames(from))
17
- if (!__hasOwnProp.call(to, key) && key !== except)
18
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
- }
20
- return to;
21
- };
22
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
-
24
- // ../../packages/utils/globals.js
25
- var window2, document2;
26
- var init_globals = __esm({
27
- "../../packages/utils/globals.js"() {
28
- "use strict";
29
- window2 = globalThis;
30
- document2 = window2.document;
31
- }
32
- });
33
-
34
- // ../../packages/utils/node.js
35
- var init_node = __esm({
36
- "../../packages/utils/node.js"() {
37
- "use strict";
38
- }
39
- });
40
-
41
- // ../../packages/utils/types.js
42
- var isFunction;
43
- var init_types = __esm({
44
- "../../packages/utils/types.js"() {
45
- "use strict";
46
- isFunction = (arg) => typeof arg === "function";
47
- }
48
- });
49
-
50
- // ../../packages/utils/array.js
51
- var init_array = __esm({
52
- "../../packages/utils/array.js"() {
53
- "use strict";
54
- }
55
- });
56
-
57
- // ../../packages/utils/string.js
58
- var init_string = __esm({
59
- "../../packages/utils/string.js"() {
60
- "use strict";
61
- }
62
- });
63
-
64
- // ../../packages/utils/keys.js
65
- var STATE_METHODS, PROPS_METHODS, METHODS, METHODS_EXL;
66
- var init_keys = __esm({
67
- "../../packages/utils/keys.js"() {
68
- "use strict";
69
- STATE_METHODS = /* @__PURE__ */ new Set([
70
- "update",
71
- "parse",
72
- "clean",
73
- "create",
74
- "destroy",
75
- "add",
76
- "toggle",
77
- "remove",
78
- "apply",
79
- "set",
80
- "reset",
81
- "replace",
82
- "quietReplace",
83
- "quietUpdate",
84
- "applyReplace",
85
- "applyFunction",
86
- "keys",
87
- "values",
88
- "ref",
89
- "rootUpdate",
90
- "parentUpdate",
91
- "parent",
92
- "__element",
93
- "__depends",
94
- "__ref",
95
- "__children",
96
- "root",
97
- "setByPath",
98
- "setPathCollection",
99
- "removeByPath",
100
- "removePathCollection",
101
- "getByPath"
102
- ]);
103
- PROPS_METHODS = /* @__PURE__ */ new Set(["update", "__element"]);
104
- METHODS = /* @__PURE__ */ new Set([
105
- "set",
106
- "reset",
107
- "update",
108
- "remove",
109
- "updateContent",
110
- "removeContent",
111
- "lookup",
112
- "lookdown",
113
- "lookdownAll",
114
- "getRef",
115
- "getPath",
116
- "setNodeStyles",
117
- "spotByPath",
118
- "keys",
119
- "parse",
120
- "setProps",
121
- "parseDeep",
122
- "variables",
123
- "if",
124
- "log",
125
- "verbose",
126
- "warn",
127
- "error",
128
- "call",
129
- "nextElement",
130
- "previousElement",
131
- "getRootState",
132
- "getRoot",
133
- "getRootData",
134
- "getRootContext",
135
- "getContext",
136
- "getQuery",
137
- "getDB",
138
- "getChildren",
139
- "preventContentUpdate",
140
- "preventContentRecreate"
141
- ]);
142
- METHODS_EXL = /* @__PURE__ */ new Set([
143
- "node",
144
- "context",
145
- "extends",
146
- "__element",
147
- "__ref",
148
- ...METHODS,
149
- ...STATE_METHODS,
150
- ...PROPS_METHODS
151
- ]);
152
- }
153
- });
154
-
155
- // ../../packages/utils/object.js
156
- var init_object = __esm({
157
- "../../packages/utils/object.js"() {
158
- "use strict";
159
- }
160
- });
161
-
162
- // ../../packages/utils/key.js
163
- var init_key = __esm({
164
- "../../packages/utils/key.js"() {
165
- "use strict";
166
- }
167
- });
168
-
169
- // ../../packages/utils/env.js
170
- var init_env = __esm({
171
- "../../packages/utils/env.js"() {
172
- "use strict";
173
- }
174
- });
175
-
176
- // ../../packages/utils/function.js
177
- var resolveHandler, runPluginHook;
178
- var init_function = __esm({
179
- "../../packages/utils/function.js"() {
180
- "use strict";
181
- resolveHandler = (handler, element) => {
182
- if (typeof handler === "function") return handler;
183
- const plugins = element?.context?.plugins;
184
- if (!plugins) return handler;
185
- for (const plugin of plugins) {
186
- if (plugin.resolveHandler) {
187
- const resolved = plugin.resolveHandler(handler, element);
188
- if (typeof resolved === "function") return resolved;
189
- }
190
- }
191
- return handler;
192
- };
193
- runPluginHook = (hookName, element, ...args) => {
194
- const plugins = element?.context?.plugins;
195
- if (!plugins) return false;
196
- let handled = false;
197
- for (const plugin of plugins) {
198
- if (typeof plugin[hookName] === "function") {
199
- plugin[hookName](element, ...args);
200
- handled = true;
201
- }
202
- }
203
- return handled;
204
- };
205
- }
206
- });
207
-
208
- // ../../packages/utils/if.js
209
- var init_if = __esm({
210
- "../../packages/utils/if.js"() {
211
- "use strict";
212
- }
213
- });
214
-
215
- // ../../packages/utils/log.js
216
- var init_log = __esm({
217
- "../../packages/utils/log.js"() {
218
- "use strict";
219
- }
220
- });
221
-
222
- // ../../packages/utils/cookie.js
223
- var isMobile;
224
- var init_cookie = __esm({
225
- "../../packages/utils/cookie.js"() {
226
- "use strict";
227
- isMobile = (() => typeof navigator === "undefined" ? false : /Mobi/.test(navigator.userAgent))();
228
- }
229
- });
230
-
231
- // ../../packages/utils/tags.js
232
- var init_tags = __esm({
233
- "../../packages/utils/tags.js"() {
234
- "use strict";
235
- }
236
- });
237
-
238
- // ../../packages/utils/extends.js
239
- var init_extends = __esm({
240
- "../../packages/utils/extends.js"() {
241
- "use strict";
242
- }
243
- });
244
-
245
- // ../../packages/utils/component.js
246
- var init_component = __esm({
247
- "../../packages/utils/component.js"() {
248
- "use strict";
249
- }
250
- });
251
-
252
- // ../../packages/utils/props.js
253
- var init_props = __esm({
254
- "../../packages/utils/props.js"() {
255
- "use strict";
256
- }
257
- });
258
-
259
- // ../../packages/utils/element.js
260
- var init_element = __esm({
261
- "../../packages/utils/element.js"() {
262
- "use strict";
263
- }
264
- });
265
-
266
- // ../../packages/utils/state.js
267
- var init_state = __esm({
268
- "../../packages/utils/state.js"() {
269
- "use strict";
270
- }
271
- });
272
-
273
- // ../../packages/utils/scope.js
274
- var init_scope = __esm({
275
- "../../packages/utils/scope.js"() {
276
- "use strict";
277
- }
278
- });
279
-
280
- // ../../packages/utils/triggerEvent.js
281
- var getOnOrPropsEvent, applyEvent, triggerEventOn;
282
- var init_triggerEvent = __esm({
283
- "../../packages/utils/triggerEvent.js"() {
284
- "use strict";
285
- init_types();
286
- init_function();
287
- getOnOrPropsEvent = (param, element) => {
288
- const propKey = "on" + param.charAt(0).toUpperCase() + param.slice(1);
289
- return element[propKey];
290
- };
291
- applyEvent = (param, element, state, context, options) => {
292
- param = resolveHandler(param, element);
293
- if (!isFunction(param)) return;
294
- try {
295
- const result = param.call(
296
- element,
297
- element,
298
- state || element.state,
299
- context || element.context,
300
- options
301
- );
302
- if (result && typeof result.then === "function") {
303
- result.catch((err) => {
304
- element.error = err;
305
- if (err instanceof ReferenceError) console.warn("[DOMQL] Async event warning:", err.message);
306
- else console.error("[DOMQL] Async event error:", err);
307
- });
308
- }
309
- return result;
310
- } catch (err) {
311
- element.error = err;
312
- if (err instanceof ReferenceError) {
313
- console.warn("[DOMQL] Event handler warning:", err.message);
314
- } else {
315
- console.error("[DOMQL] Event handler error:", err);
316
- }
317
- if (element.context?.strictMode) throw err;
318
- }
319
- };
320
- triggerEventOn = (param, element, options) => {
321
- if (!element) {
322
- throw new Error("Element is required");
323
- }
324
- runPluginHook(param, element, options);
325
- const appliedFunction = getOnOrPropsEvent(param, element);
326
- if (appliedFunction) {
327
- const { state, context } = element;
328
- return applyEvent(appliedFunction, element, state, context, options);
329
- }
330
- };
331
- }
332
- });
333
-
334
- // ../../packages/utils/cache.js
335
- var init_cache = __esm({
336
- "../../packages/utils/cache.js"() {
337
- "use strict";
338
- }
339
- });
340
-
341
- // ../../packages/utils/methods.js
342
- var init_methods = __esm({
343
- "../../packages/utils/methods.js"() {
344
- "use strict";
345
- }
346
- });
347
-
348
- // ../../packages/utils/update.js
349
- var init_update = __esm({
350
- "../../packages/utils/update.js"() {
351
- "use strict";
352
- }
353
- });
354
-
355
- // ../../packages/utils/projectKeys.js
356
- var init_projectKeys = __esm({
357
- "../../packages/utils/projectKeys.js"() {
358
- }
359
- });
360
-
361
- // ../../packages/utils/browser.js
362
- var init_browser = __esm({
363
- "../../packages/utils/browser.js"() {
364
- "use strict";
365
- }
366
- });
367
-
368
- // ../../packages/utils/cdn.js
369
- var init_cdn = __esm({
370
- "../../packages/utils/cdn.js"() {
371
- "use strict";
372
- }
373
- });
374
-
375
- // ../../packages/utils/date.js
376
- var init_date = __esm({
377
- "../../packages/utils/date.js"() {
378
- "use strict";
379
- }
380
- });
381
-
382
- // ../../packages/utils/detectHeight.js
383
- var init_detectHeight = __esm({
384
- "../../packages/utils/detectHeight.js"() {
385
- "use strict";
386
- }
387
- });
388
-
389
- // ../../packages/utils/fibonacci.js
390
- var init_fibonacci = __esm({
391
- "../../packages/utils/fibonacci.js"() {
392
- "use strict";
393
- }
394
- });
395
-
396
- // ../../packages/utils/files.js
397
- var init_files = __esm({
398
- "../../packages/utils/files.js"() {
399
- "use strict";
400
- }
401
- });
402
-
403
- // ../../packages/utils/load.js
404
- var init_load = __esm({
405
- "../../packages/utils/load.js"() {
406
- "use strict";
407
- }
408
- });
409
-
410
- // ../../packages/utils/metadata.js
411
- var init_metadata = __esm({
412
- "../../packages/utils/metadata.js"() {
413
- "use strict";
414
- }
415
- });
416
-
417
- // ../../packages/utils/scaling.js
418
- var init_scaling = __esm({
419
- "../../packages/utils/scaling.js"() {
420
- "use strict";
421
- }
422
- });
423
-
424
- // ../../packages/utils/sharedLibraries.js
425
- var init_sharedLibraries = __esm({
426
- "../../packages/utils/sharedLibraries.js"() {
427
- "use strict";
428
- }
429
- });
430
-
431
- // ../../packages/utils/string-extra.js
432
- var init_string_extra = __esm({
433
- "../../packages/utils/string-extra.js"() {
434
- "use strict";
435
- }
436
- });
437
-
438
- // ../../packages/utils/style.js
439
- var init_style = __esm({
440
- "../../packages/utils/style.js"() {
441
- "use strict";
442
- }
443
- });
444
-
445
- // ../../packages/utils/index.js
446
- var init_utils = __esm({
447
- "../../packages/utils/index.js"() {
448
- "use strict";
449
- init_key();
450
- init_env();
451
- init_types();
452
- init_object();
453
- init_function();
454
- init_array();
455
- init_node();
456
- init_if();
457
- init_log();
458
- init_string();
459
- init_globals();
460
- init_cookie();
461
- init_tags();
462
- init_component();
463
- init_props();
464
- init_extends();
465
- init_element();
466
- init_state();
467
- init_keys();
468
- init_scope();
469
- init_methods();
470
- init_cache();
471
- init_update();
472
- init_triggerEvent();
473
- init_projectKeys();
474
- init_browser();
475
- init_cdn();
476
- init_date();
477
- init_detectHeight();
478
- init_fibonacci();
479
- init_files();
480
- init_load();
481
- init_metadata();
482
- init_scaling();
483
- init_sharedLibraries();
484
- init_string_extra();
485
- init_style();
486
- }
487
- });
488
-
489
- // index.js
490
- var index_exports = {};
491
- __export(index_exports, {
492
- default: () => index_default,
493
- getActiveRoute: () => getActiveRoute,
494
- lastLevel: () => lastLevel,
495
- lastPathname: () => lastPathname,
496
- matchRoute: () => matchRoute,
497
- parseQuery: () => parseQuery,
498
- parseRoutePattern: () => parseRoutePattern,
499
- router: () => router,
500
- runGuards: () => runGuards
501
- });
502
- init_utils();
503
- var paramPattern = /^:(.+)/;
504
- var wildcardPattern = /^\*$/;
505
- var routeCache = /* @__PURE__ */ new Map();
506
- var parseRoutePattern = (pattern) => {
507
- const cached = routeCache.get(pattern);
508
- if (cached) return cached;
509
- const segments = pattern.replace(/^\//, "").split("/");
510
- const params = [];
511
- let hasWildcard = false;
512
- for (let i = 0; i < segments.length; i++) {
513
- const match = segments[i].match(paramPattern);
514
- if (match) {
515
- params.push({ index: i, name: match[1] });
516
- } else if (wildcardPattern.test(segments[i])) {
517
- hasWildcard = true;
518
- }
519
- }
520
- const result = { segments, params, hasWildcard, pattern };
521
- routeCache.set(pattern, result);
522
- return result;
523
- };
524
- var matchRoute = (pathname, routes, level = 0) => {
525
- const pathSegments = pathname.replace(/^\//, "").split("/").filter(Boolean);
526
- const relevantSegments = pathSegments.slice(level);
527
- const routePath = "/" + (relevantSegments[0] || "");
528
- let bestMatch = null;
529
- let bestScore = -1;
530
- let matchedParams = {};
531
- for (const key in routes) {
532
- if (key === "/*") continue;
533
- const parsed = parseRoutePattern(key);
534
- const score = scoreMatch(relevantSegments, parsed);
535
- if (score > bestScore) {
536
- bestScore = score;
537
- bestMatch = key;
538
- matchedParams = extractParams(relevantSegments, parsed);
539
- }
540
- }
541
- if (!bestMatch && routes["/*"]) {
542
- bestMatch = "/*";
543
- }
544
- return {
545
- key: bestMatch,
546
- content: bestMatch ? routes[bestMatch] : null,
547
- params: matchedParams,
548
- routePath
549
- };
550
- };
551
- var scoreMatch = (pathSegments, parsed) => {
552
- const { segments, hasWildcard } = parsed;
553
- if (!hasWildcard && segments.length !== pathSegments.length && segments.length !== 1) {
554
- if (segments.length > pathSegments.length) return -1;
555
- }
556
- let score = 0;
557
- const len = Math.min(segments.length, pathSegments.length);
558
- for (let i = 0; i < len; i++) {
559
- if (segments[i] === pathSegments[i]) {
560
- score += 3;
561
- } else if (paramPattern.test(segments[i])) {
562
- score += 1;
563
- } else if (wildcardPattern.test(segments[i])) {
564
- score += 0.5;
565
- } else {
566
- return -1;
567
- }
568
- }
569
- return score;
570
- };
571
- var extractParams = (pathSegments, parsed) => {
572
- const params = {};
573
- for (const { index, name } of parsed.params) {
574
- if (pathSegments[index]) {
575
- params[name] = decodeURIComponent(pathSegments[index]);
576
- }
577
- }
578
- return params;
579
- };
580
- var parseQuery = (search) => {
581
- if (!search || search === "?") return {};
582
- const params = {};
583
- const searchParams = new URLSearchParams(search);
584
- searchParams.forEach((value, key) => {
585
- if (params[key] !== void 0) {
586
- if (!Array.isArray(params[key])) params[key] = [params[key]];
587
- params[key].push(value);
588
- } else {
589
- params[key] = value;
590
- }
591
- });
592
- return params;
593
- };
594
- var runGuards = async (guards, context) => {
595
- if (!guards || !guards.length) return true;
596
- for (const guard of guards) {
597
- const result = await guard(context);
598
- if (result === false) return false;
599
- if (typeof result === "string") return result;
600
- }
601
- return true;
602
- };
603
- var getActiveRoute = (level = 0, route) => {
604
- if (!route) route = typeof window2 !== "undefined" ? window2.location.pathname : "/";
605
- const routeArray = route.split("/");
606
- const activeRoute = routeArray[level + 1];
607
- if (activeRoute) return `/${activeRoute}`;
608
- };
609
- var lastPathname;
610
- var lastLevel = 0;
611
- var normalizePath = (p) => !p || p === "srcdoc" || p === "about:srcdoc" ? "/" : p;
612
- var defaultOptions = {
613
- level: lastLevel,
614
- pushState: true,
615
- initialRender: false,
616
- scrollToTop: true,
617
- scrollToNode: false,
618
- scrollNode: document2 && document2.documentElement,
619
- scrollBody: false,
620
- useFragment: false,
621
- updateState: true,
622
- scrollToOffset: 0,
623
- contentElementKey: "content",
624
- scrollToOptions: { behavior: "smooth" },
625
- useParamsMatching: true
626
- };
627
- var router = async (path, el, state = {}, options = {}) => {
628
- const element = el || void 0;
629
- const win = element?.context?.window || window2;
630
- const doc = element?.context?.document || document2;
631
- const opts = {
632
- ...defaultOptions,
633
- ...element.context.routerOptions,
634
- ...options
635
- };
636
- lastLevel = opts.lastLevel;
637
- const ref = element.__ref;
638
- if (opts.contentElementKey !== "content" && opts.contentElementKey !== ref.contentElementKey || !ref.contentElementKey) {
639
- ref.contentElementKey = opts.contentElementKey || "content";
640
- }
641
- const contentElementKey = ref.contentElementKey || opts.contentElementKey || "content";
642
- const origin = win.location.origin !== "null" ? win.location.origin : "http://localhost";
643
- path = normalizePath(path);
644
- const urlObj = new win.URL(origin + path);
645
- const { pathname, search, hash } = urlObj;
646
- const query = parseQuery(search);
647
- const rootNode = element.node;
648
- const hashChanged = hash && hash !== win.location.hash.slice(1);
649
- const pathChanged = pathname !== lastPathname;
650
- lastPathname = pathname;
651
- let route, content, params;
652
- if (opts.useParamsMatching) {
653
- const match = matchRoute(pathname, element.routes, opts.level);
654
- route = match.routePath;
655
- content = match.content;
656
- params = match.params;
657
- } else {
658
- route = getActiveRoute(opts.level, pathname);
659
- content = element.routes[route || "/"] || element.routes["/*"];
660
- params = {};
661
- }
662
- const scrollNode = opts.scrollToNode ? rootNode : opts.scrollNode;
663
- if (element.state?.root?.debugging) {
664
- element.state.root.debugging = false;
665
- return;
666
- }
667
- if (!content) {
668
- if (opts.onNotFound) {
669
- opts.onNotFound({ pathname, route, element });
670
- } else if (!opts.silent) {
671
- console.warn("[smbls/router] no content matched for path", pathname, "\u2014 available routes:", Object.keys(element.routes || {}));
672
- }
673
- return;
674
- }
675
- if (opts.guards && opts.guards.length) {
676
- const guardContext = { pathname, route, params, query, hash, element, state };
677
- const guardResult = await runGuards(opts.guards, guardContext);
678
- if (guardResult === false) return;
679
- if (typeof guardResult === "string") {
680
- return router(guardResult, el, state, { ...options, guards: [] });
681
- }
682
- }
683
- if (opts.pushState) {
684
- try {
685
- win.history.pushState(state, null, pathname + (search || "") + (hash || ""));
686
- } catch (e) {
687
- }
688
- }
689
- if (pathChanged || !hashChanged) {
690
- const stateUpdate = { route, hash, debugging: false };
691
- if (Object.keys(params).length) stateUpdate.params = params;
692
- if (Object.keys(query).length) stateUpdate.query = query;
693
- if (opts.updateState) {
694
- element.state.update(
695
- stateUpdate,
696
- { preventContentUpdate: true }
697
- );
698
- }
699
- if (contentElementKey && opts.removeOldElement) {
700
- element[contentElementKey].remove();
701
- }
702
- const originContent = element.__ref?.origin?.content;
703
- const contentStyles = {};
704
- if (originContent) {
705
- for (const k in originContent) {
706
- const v = originContent[k];
707
- if (k === "__ref" || k === "props" || k === "node" || k === "parent" || k === "key") continue;
708
- if (typeof v === "string" || typeof v === "number" || typeof v === "boolean" || typeof v === "object" && v !== null && !v.node && !v.__ref) {
709
- contentStyles[k] = v;
710
- }
711
- }
712
- }
713
- const nextContent = {
714
- ...contentStyles,
715
- ...typeof content === "object" ? content : { extends: content }
716
- };
717
- if (opts.useFragment) nextContent.tag = "fragment";
718
- try {
719
- element.set(nextContent, { contentElementKey });
720
- } catch (err) {
721
- console.error("[smbls/router] failed to render route content", pathname, err);
722
- }
723
- }
724
- if (opts.scrollToTop && scrollNode?.scrollTo) {
725
- scrollNode.scrollTo({
726
- ...opts.scrollToOptions || {},
727
- top: 0,
728
- left: 0
729
- });
730
- }
731
- if (opts.scrollToNode && content[contentElementKey]?.node?.scrollTo) {
732
- content[contentElementKey].node.scrollTo({
733
- ...opts.scrollToOptions || {},
734
- top: 0,
735
- left: 0
736
- });
737
- }
738
- if (hash) {
739
- const activeNode = doc.getElementById(hash);
740
- if (activeNode && scrollNode?.scrollTo) {
741
- const top = activeNode.getBoundingClientRect().top + rootNode.scrollTop - (opts.scrollToOffset || 0);
742
- scrollNode.scrollTo({
743
- ...opts.scrollToOptions || {},
744
- top,
745
- left: 0
746
- });
747
- }
748
- }
749
- triggerEventOn("routeChanged", element, opts);
750
- };
751
- var index_default = router;
752
- return __toCommonJS(index_exports);
753
- })();
754
- // @preserve-env