@devwareng/vanilla-ts 1.0.4 → 1.0.5

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/index.d.cts CHANGED
@@ -1,2 +1,116 @@
1
+ import { Config } from 'dompurify';
1
2
 
2
- export { }
3
+ // --- Core Types ---
4
+
5
+ type TSCollection = (
6
+ collections: string[],
7
+ DOM: HTMLElement,
8
+ elements: Function[],
9
+ params?: any
10
+ ) => void;
11
+
12
+ type TSInitialDOM = (
13
+ id: string,
14
+ mount: (el: HTMLElement) => void
15
+ ) => void;
16
+
17
+ type TSVerify = (
18
+ DOM: HTMLElement | void,
19
+ authUrl: string,
20
+ loginUrl: string
21
+ ) => string | null;
22
+
23
+ type TSAuth = (
24
+ Component: HTMLElement | void,
25
+ loginUrl: string
26
+ ) => HTMLElement | null;
27
+
28
+ type FetchFunction<T> = () => Promise<T>;
29
+
30
+ type FetchResult<T> = {
31
+ data: T | null;
32
+ isLoading: boolean;
33
+ error: Error | null;
34
+ };
35
+
36
+ type SanitizeInput = (input: string) => string;
37
+
38
+ type AnchorSingle = (
39
+ element: HTMLElement,
40
+ href: string,
41
+ ariaLabel: string,
42
+ className?: string,
43
+ childElement?: HTMLElement | null
44
+ ) => void;
45
+
46
+ type TSURLState = () => Record<string, string>;
47
+
48
+ type TSComponent = (
49
+ id: string,
50
+ DOM: HTMLElement,
51
+ element: Function,
52
+ params?: any,
53
+ params2?: any
54
+ ) => void;
55
+
56
+ type TSEvent = <
57
+ K extends keyof HTMLElementEventMap = keyof HTMLElementEventMap
58
+ >(
59
+ id: string,
60
+ eventType: K,
61
+ handler: (event: HTMLElementEventMap[K]) => void
62
+ ) => void;
63
+
64
+ type TSSelect = <T extends Element = HTMLElement>(
65
+ selector: string
66
+ ) => T | null;
67
+
68
+ type TSPurifier = (
69
+ input: string | HTMLElement,
70
+ config?: Config
71
+ ) => string;
72
+
73
+ // --- SEO & CSP ---
74
+
75
+ type SEOConfig = {
76
+ name?: string;
77
+ description?: string;
78
+ author?: string;
79
+ };
80
+
81
+ type SEOHandler = {
82
+ setName: (name: string) => void;
83
+ setDescription: (description: string) => void;
84
+ setAuthor: (author: string) => void;
85
+ getName: () => string;
86
+ getDescription: () => string;
87
+ getAuthor: () => string;
88
+ getAllMetaData: () => SEOConfig;
89
+ appendMetaTagsToHead: () => void;
90
+ };
91
+
92
+ type CSPConfig = {
93
+ scriptSrc?: string;
94
+ styleSrc?: string;
95
+ objectSrc?: string;
96
+ connectSrc?: string[];
97
+ reportOnly?: boolean;
98
+ };
99
+
100
+ // --- Input & Events ---
101
+
102
+ type InputElementType = "input" | "select" | "textarea" | "form";
103
+
104
+ type TSInput = (
105
+ id: string,
106
+ elementType: InputElementType,
107
+ form?: HTMLFormElement
108
+ ) => string;
109
+
110
+ type TSElementEach = (
111
+ elements: NodeListOf<HTMLElement> | HTMLElement[],
112
+ events: (keyof HTMLElementEventMap)[],
113
+ callback: (element: HTMLElement, event: Event) => void
114
+ ) => void;
115
+
116
+ export type { AnchorSingle, CSPConfig, FetchFunction, FetchResult, InputElementType, SEOConfig, SEOHandler, SanitizeInput, TSAuth, TSCollection, TSComponent, TSElementEach, TSEvent, TSInitialDOM, TSInput, TSPurifier, TSSelect, TSURLState, TSVerify };
package/dist/index.d.ts CHANGED
@@ -1,74 +1,116 @@
1
- import { Config } from "dompurify";
1
+ import { Config } from 'dompurify';
2
2
 
3
- type TSCollection = (collections: string[], DOM: HTMLElement, elements: Function[], params?: any) => void;
4
- type TSInitialDOM = (id: string, mount: (el: HTMLElement) => void) => void;
5
- type TSVerify = (DOM: HTMLElement | void, authUrl: string, loginUrl: string) => string | null;
6
- type TSAuth = (Component: HTMLElement | void, loginUrl: string) => HTMLElement | null;
7
- type FetchFunction<T> = () => Promise<T>;
8
- type FetchResult<T> = {
9
- data: T | null;
10
- isLoading: boolean;
11
- error: Error | null;
12
- }
13
- type SanitizeInput = (input: string) => string;
14
- type AnchorSingle = (
15
- element: HTMLElement,
16
- href: string,
17
- ariaLabel: string,
18
- className?: string,
19
- childElement?: HTMLElement | null
3
+ // --- Core Types ---
4
+
5
+ type TSCollection = (
6
+ collections: string[],
7
+ DOM: HTMLElement,
8
+ elements: Function[],
9
+ params?: any
10
+ ) => void;
11
+
12
+ type TSInitialDOM = (
13
+ id: string,
14
+ mount: (el: HTMLElement) => void
15
+ ) => void;
16
+
17
+ type TSVerify = (
18
+ DOM: HTMLElement | void,
19
+ authUrl: string,
20
+ loginUrl: string
21
+ ) => string | null;
22
+
23
+ type TSAuth = (
24
+ Component: HTMLElement | void,
25
+ loginUrl: string
26
+ ) => HTMLElement | null;
27
+
28
+ type FetchFunction<T> = () => Promise<T>;
29
+
30
+ type FetchResult<T> = {
31
+ data: T | null;
32
+ isLoading: boolean;
33
+ error: Error | null;
34
+ };
35
+
36
+ type SanitizeInput = (input: string) => string;
37
+
38
+ type AnchorSingle = (
39
+ element: HTMLElement,
40
+ href: string,
41
+ ariaLabel: string,
42
+ className?: string,
43
+ childElement?: HTMLElement | null
44
+ ) => void;
45
+
46
+ type TSURLState = () => Record<string, string>;
47
+
48
+ type TSComponent = (
49
+ id: string,
50
+ DOM: HTMLElement,
51
+ element: Function,
52
+ params?: any,
53
+ params2?: any
54
+ ) => void;
55
+
56
+ type TSEvent = <
57
+ K extends keyof HTMLElementEventMap = keyof HTMLElementEventMap
58
+ >(
59
+ id: string,
60
+ eventType: K,
61
+ handler: (event: HTMLElementEventMap[K]) => void
62
+ ) => void;
63
+
64
+ type TSSelect = <T extends Element = HTMLElement>(
65
+ selector: string
66
+ ) => T | null;
67
+
68
+ type TSPurifier = (
69
+ input: string | HTMLElement,
70
+ config?: Config
71
+ ) => string;
72
+
73
+ // --- SEO & CSP ---
74
+
75
+ type SEOConfig = {
76
+ name?: string;
77
+ description?: string;
78
+ author?: string;
79
+ };
80
+
81
+ type SEOHandler = {
82
+ setName: (name: string) => void;
83
+ setDescription: (description: string) => void;
84
+ setAuthor: (author: string) => void;
85
+ getName: () => string;
86
+ getDescription: () => string;
87
+ getAuthor: () => string;
88
+ getAllMetaData: () => SEOConfig;
89
+ appendMetaTagsToHead: () => void;
90
+ };
91
+
92
+ type CSPConfig = {
93
+ scriptSrc?: string;
94
+ styleSrc?: string;
95
+ objectSrc?: string;
96
+ connectSrc?: string[];
97
+ reportOnly?: boolean;
98
+ };
99
+
100
+ // --- Input & Events ---
101
+
102
+ type InputElementType = "input" | "select" | "textarea" | "form";
103
+
104
+ type TSInput = (
105
+ id: string,
106
+ elementType: InputElementType,
107
+ form?: HTMLFormElement
108
+ ) => string;
109
+
110
+ type TSElementEach = (
111
+ elements: NodeListOf<HTMLElement> | HTMLElement[],
112
+ events: (keyof HTMLElementEventMap)[],
113
+ callback: (element: HTMLElement, event: Event) => void
20
114
  ) => void;
21
115
 
22
- type TSURLState = () => Record<string, string>;
23
-
24
- type TSComponent = (
25
- id: string,
26
- DOM: HTMLElement,
27
- element: Function,
28
- params?: any,
29
- params2?: any
30
- ) => void;
31
-
32
- type TSEvent = (
33
- id: string,
34
- eventType: keyof HTMLElementEventMap,
35
- handler: (event: HTMLElementEventMap[keyof HTMLElementEventMap]) => void
36
- ) => void;
37
-
38
- type TSSelect = <T extends Element = HTMLElement>(selector: string) => T | null;
39
- type TSPurifier = (input: string | HTMLElement, config?: Config) => string;
40
-
41
- type SEOConfig = {
42
- name?: string;
43
- description?: string;
44
- author?: string;
45
- }
46
-
47
- type CSPConfig = {
48
- scriptSrc?: string;
49
- styleSrc?: string;
50
- objectSrc?: string;
51
- connectSrc?: string[];
52
- reportOnly?: boolean;
53
- }
54
-
55
- type SEOHandler = {
56
- setName: (name: string) => void;
57
- setDescription: (description: string) => void;
58
- setAuthor: (author: string) => void;
59
- getName: () => string;
60
- getDescription: () => string;
61
- getAuthor: () => string;
62
- getAllMetaData: () => SEOConfig;
63
- appendMetaTagsToHead: () => void;
64
- }
65
-
66
- type InputElementType = "input" | "select" | "textarea" | "form";
67
-
68
- type TSInput = (id: string, elementType: InputElementType, form?: HTMLFormElement) => string;
69
-
70
- type TSElementEach = (
71
- elements: NodeListOf<HTMLElement> | HTMLElement[],
72
- events: (keyof HTMLElementEventMap)[],
73
- callback: (element: HTMLElement, event: Event) => void
74
- ) => void;
116
+ export type { AnchorSingle, CSPConfig, FetchFunction, FetchResult, InputElementType, SEOConfig, SEOHandler, SanitizeInput, TSAuth, TSCollection, TSComponent, TSElementEach, TSEvent, TSInitialDOM, TSInput, TSPurifier, TSSelect, TSURLState, TSVerify };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devwareng/vanilla-ts",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Framework-less TypeScript hooks for SPA development.",
5
5
  "author": "Waren Arapoc Gador",
6
6
  "license": "MIT",
@@ -42,4 +42,4 @@
42
42
  "@types/lodash": "^4.17.20",
43
43
  "tsup": "^8.5.0"
44
44
  }
45
- }
45
+ }
package/dist/index.d.mts DELETED
@@ -1,2 +0,0 @@
1
-
2
- export { }
package/dist/index.mjs DELETED
@@ -1,458 +0,0 @@
1
- // src/define/html.ts
2
- function html(strings, ...values) {
3
- return strings.reduce((result, str, i) => {
4
- return result + str + (values[i] || "");
5
- }, "");
6
- }
7
-
8
- // src/hooks/useTSPurifier.ts
9
- import DOMPurify from "dompurify";
10
- var useTSPurifier = (input, config) => {
11
- const defaultConfig = {
12
- ADD_TAGS: ["my-custom-tag"]
13
- };
14
- const mergedConfig = { ...defaultConfig, ...config };
15
- if (typeof input === "string") {
16
- return DOMPurify.sanitize(input, mergedConfig);
17
- } else {
18
- return DOMPurify.sanitize(input.innerHTML, mergedConfig);
19
- }
20
- };
21
-
22
- // src/hooks/useTSEvent.ts
23
- var useTSEvent = (id, eventType, handler) => {
24
- const element = document.querySelector(`#${id}`);
25
- if (element) {
26
- element.addEventListener(
27
- eventType,
28
- handler
29
- );
30
- } else {
31
- console.warn(`Element with id '${id}' not found.`);
32
- }
33
- };
34
-
35
- // src/hooks/useTSParams.ts
36
- import { createStore } from "zustand/vanilla";
37
- import DOMPurify2 from "dompurify";
38
- function extractPatternParams(pattern, path) {
39
- const paramNames = [];
40
- const regexPattern = pattern.replace(/:[^/]+/g, (match2) => {
41
- paramNames.push(match2.slice(1));
42
- return "([^/]+)";
43
- });
44
- const regex = new RegExp(`^${regexPattern}$`);
45
- const match = path.match(regex);
46
- const result = {};
47
- if (match) {
48
- paramNames.forEach((name, i) => {
49
- result[name] = DOMPurify2.sanitize(match[i + 1] ?? "");
50
- });
51
- }
52
- return result;
53
- }
54
- function extractQueryParams(search) {
55
- const result = {};
56
- const urlSearchParams = new URLSearchParams(search);
57
- for (const [key, value] of urlSearchParams.entries()) {
58
- result[key] = DOMPurify2.sanitize(value);
59
- }
60
- return result;
61
- }
62
- var useTSParams = createStore((set, get) => ({
63
- params: {},
64
- query: {},
65
- setFromPattern: (pattern) => {
66
- const path = window.location.pathname;
67
- const params = extractPatternParams(pattern, path);
68
- const query = extractQueryParams(window.location.search);
69
- set({ params, query });
70
- },
71
- getParam: (key) => get().params[key],
72
- getQuery: (key) => get().query[key]
73
- }));
74
-
75
- // src/hooks/useTSExtract.ts
76
- function useTSExtractParams(pattern) {
77
- const store = useTSParams.getState();
78
- store.setFromPattern(pattern);
79
- const params = store.params;
80
- const query = store.query;
81
- return { ...params, ...query };
82
- }
83
-
84
- // src/hooks/useTSAllElements.ts
85
- var useTSEventAll = (selector, eventType, handler) => {
86
- const elements = document.querySelectorAll(selector);
87
- elements.forEach((element) => {
88
- element.addEventListener(eventType, handler);
89
- });
90
- return () => {
91
- elements.forEach((element) => {
92
- element.removeEventListener(eventType, handler);
93
- });
94
- };
95
- };
96
-
97
- // src/hooks/useTSElements.ts
98
- import DOMPurify3 from "dompurify";
99
- var useTSElements = (htmlElement, element, config) => {
100
- const defaultConfig = {
101
- ALLOWED_TAGS: ["main", "div", "h1", "p", "button", "span", "a", "img", "input"],
102
- ALLOWED_ATTR: ["class", "id", "href", "style", "src", "alt"],
103
- ...config
104
- // allow user overrides
105
- };
106
- const sanitizedContent = DOMPurify3.sanitize(
107
- /*html*/
108
- element,
109
- defaultConfig
110
- );
111
- if (htmlElement.innerHTML !== String(sanitizedContent)) {
112
- return htmlElement.innerHTML = String(sanitizedContent);
113
- }
114
- };
115
-
116
- // src/hooks/useIntialDOM.ts
117
- import DOMPurify4 from "dompurify";
118
- var previousHTML = null;
119
- var useInitialDOM = (id, mount) => {
120
- if (typeof document === "undefined") return;
121
- const targetElement = document.getElementById(id);
122
- if (!targetElement) return;
123
- const currentHTML = targetElement.innerHTML;
124
- const sanitizedHTML = DOMPurify4.sanitize(currentHTML);
125
- if (previousHTML !== null && sanitizedHTML !== previousHTML) {
126
- const fallbackEl = document.createElement("div");
127
- mount(fallbackEl);
128
- targetElement.innerHTML = previousHTML;
129
- } else {
130
- previousHTML = sanitizedHTML;
131
- mount(targetElement);
132
- }
133
- };
134
-
135
- // src/hooks/useTSAnchorSingle.ts
136
- var sanitizeInput = (input) => {
137
- const element = document.createElement("div");
138
- element.innerText = input;
139
- return element.innerHTML;
140
- };
141
- var useAnchorSingle = (element, href, ariaLabel, className = "", childElement = null) => {
142
- if (!element) return;
143
- const sanitizedHref = sanitizeInput(href);
144
- const sanitizedAriaLabel = sanitizeInput(ariaLabel);
145
- const sanitizedClassName = className ? sanitizeInput(className) : void 0;
146
- element.setAttribute("href", sanitizedHref);
147
- element.setAttribute("aria-label", sanitizedAriaLabel);
148
- if (sanitizedClassName) {
149
- element.className = sanitizedClassName;
150
- }
151
- if (childElement) {
152
- element.innerHTML = "";
153
- element.appendChild(childElement);
154
- }
155
- element.addEventListener("click", (e) => {
156
- e.preventDefault();
157
- const target = e.currentTarget;
158
- const href2 = target.getAttribute("href");
159
- if (href2) {
160
- const scrollPosition = window.scrollY;
161
- window.scrollTo(0, 0);
162
- window.history.pushState({ scrollPosition }, "", href2);
163
- const navEvent = new PopStateEvent("popstate");
164
- dispatchEvent(navEvent);
165
- }
166
- });
167
- window.addEventListener("popstate", (e) => {
168
- const state = e.state;
169
- if (state && state.scrollPosition !== void 0) {
170
- window.scrollTo(0, state.scrollPosition);
171
- }
172
- });
173
- };
174
-
175
- // src/hooks/useTSAnchor.ts
176
- import debounce from "lodash";
177
- var sanitizeInput2 = (input) => input;
178
- if (typeof window !== "undefined" && typeof document !== "undefined") {
179
- sanitizeInput2 = (input) => {
180
- const element = document.createElement("div");
181
- element.innerText = input;
182
- return element.innerHTML;
183
- };
184
- }
185
- var useAnchor = typeof window !== "undefined" ? debounce((anchors) => {
186
- anchors.forEach((anchor) => {
187
- if (!anchor) return;
188
- const originalHref = anchor.getAttribute("href") || "#";
189
- const originalClassName = anchor.getAttribute("class") || "";
190
- const sanitizedHref = sanitizeInput2(originalHref);
191
- const sanitizedClassName = anchor.getAttribute("class") ? sanitizeInput2(anchor.getAttribute("class")) : originalClassName;
192
- anchor.setAttribute("href", sanitizedHref);
193
- anchor.setAttribute("class", sanitizedClassName);
194
- if (anchor.getAttribute("aria-label")) {
195
- anchor.setAttribute(
196
- "aria-label",
197
- sanitizeInput2(anchor.getAttribute("aria-label"))
198
- );
199
- }
200
- const childElement = anchor.querySelector(":scope > *");
201
- if (childElement) {
202
- anchor.innerHTML = "";
203
- anchor.appendChild(childElement);
204
- }
205
- anchor.addEventListener("click", (e) => {
206
- const target = e.currentTarget;
207
- const href = target.getAttribute("href");
208
- try {
209
- const url = new URL(href, window.location.href);
210
- if (url.origin !== window.location.origin) return;
211
- } catch (error) {
212
- console.error("Invalid URL:", error);
213
- return;
214
- }
215
- e.preventDefault();
216
- window.history.pushState({}, "", href);
217
- const navEvent = new PopStateEvent("popstate");
218
- window.dispatchEvent(navEvent);
219
- });
220
- });
221
- }) : () => {
222
- };
223
-
224
- // src/hooks/useTSMetaData.ts
225
- import DOMPurify5 from "dompurify";
226
-
227
- // src/hooks/useTSComponent.ts
228
- import DOMPurify6 from "dompurify";
229
- var useTSComponent = (id, DOM, element, params, params2) => {
230
- DOMPurify6.sanitize(DOM);
231
- element(DOM.querySelector(`#${id}`), params, params2);
232
- };
233
-
234
- // src/hooks/useTSSelect.ts
235
- var useTSSelect = (selector) => {
236
- const element = document.querySelector(selector);
237
- if (!element) {
238
- console.warn(`[useTSSelect] No element found for selector: '${selector}'`);
239
- return null;
240
- }
241
- return element;
242
- };
243
-
244
- // src/hooks/useTSAuth.ts
245
- import { jwtDecode } from "jwt-decode";
246
- var useTSAuth = (_Component, loginUrl) => {
247
- const token = localStorage.getItem("token");
248
- if (!token) {
249
- window.location.href = loginUrl;
250
- return null;
251
- }
252
- try {
253
- const decodedToken = jwtDecode(token);
254
- const currentTime = Date.now() / 1e3;
255
- if (decodedToken.exp && decodedToken.exp < currentTime) {
256
- console.error("Token has expired");
257
- window.localStorage.removeItem("token");
258
- window.location.href = loginUrl;
259
- return null;
260
- }
261
- return null;
262
- } catch (error) {
263
- console.error("Invalid token:", error);
264
- window.location.href = loginUrl;
265
- return null;
266
- }
267
- };
268
-
269
- // src/hooks/useTSForEach.ts
270
- var useTSElementEach = (elements, events, callback) => {
271
- elements.forEach((element) => {
272
- events.forEach((eventType) => {
273
- element.addEventListener(eventType, (event) => {
274
- callback(element, event);
275
- });
276
- });
277
- });
278
- };
279
-
280
- // src/routes/class/Router.class.ts
281
- import DOMPurify8 from "dompurify";
282
-
283
- // src/store/useTSParam.store.ts
284
- import { createStore as createStore2 } from "zustand/vanilla";
285
- import DOMPurify7 from "dompurify";
286
- var tsParamsStore = createStore2((set) => ({
287
- params: {},
288
- query: {},
289
- setParams: (params) => set(() => ({
290
- params: sanitize(params)
291
- })),
292
- setQuery: (query) => set(() => ({
293
- query: sanitize(query)
294
- }))
295
- }));
296
- function sanitize(obj) {
297
- const output = {};
298
- for (const key in obj) {
299
- output[key] = DOMPurify7.sanitize(obj[key]);
300
- }
301
- return output;
302
- }
303
-
304
- // src/routes/class/Router.class.ts
305
- var TSRouter = class {
306
- constructor(routes, expectedParams) {
307
- this.routes = [];
308
- this.routes = routes;
309
- this.expectedParams = new Set(expectedParams);
310
- window.addEventListener("popstate", this.handlePopState.bind(this));
311
- this.handlePopState();
312
- }
313
- handlePopState() {
314
- const currentPath = window.location.pathname;
315
- const currentSearch = window.location.search;
316
- const queryParams = this.parseQueryParams(currentSearch);
317
- const matchingRoute = this.findMatchingRoute(currentPath, this.routes);
318
- if (matchingRoute) {
319
- if (matchingRoute.routeto) {
320
- this.navigate(matchingRoute.routeto);
321
- return;
322
- }
323
- const sanitizedParams = this.filterAndSanitizeParams(matchingRoute.params);
324
- tsParamsStore.getState().setParams(sanitizedParams);
325
- tsParamsStore.getState().setQuery(queryParams);
326
- const errorElement = document.createElement("div");
327
- matchingRoute.element?.(errorElement, sanitizedParams, queryParams);
328
- if (matchingRoute.children) {
329
- const nestedPath = currentPath.slice(matchingRoute.path.length);
330
- const childElement = errorElement.querySelector("#child");
331
- if (childElement) {
332
- this.renderChildren(
333
- matchingRoute.children,
334
- nestedPath,
335
- childElement,
336
- sanitizedParams,
337
- queryParams
338
- );
339
- }
340
- }
341
- } else {
342
- const notFoundRoute = this.findMatchingRoute("*", this.routes);
343
- if (notFoundRoute) {
344
- const fallbackParams = this.filterAndSanitizeParams(notFoundRoute.params);
345
- tsParamsStore.getState().setParams(fallbackParams);
346
- tsParamsStore.getState().setQuery(queryParams);
347
- const errorElement = document.createElement("div");
348
- notFoundRoute.element?.(errorElement, fallbackParams, queryParams);
349
- }
350
- }
351
- }
352
- renderChildren(children, nestedPath, parentElement, parentParams, queryParams) {
353
- if (!children || children.length === 0) {
354
- const childElement = parentElement.querySelector("#child");
355
- if (childElement) childElement.remove();
356
- return;
357
- }
358
- const matchingChild = this.findMatchingRoute(nestedPath, children);
359
- if (matchingChild) {
360
- const childElement = document.createElement("div");
361
- childElement.id = "child";
362
- const mergedParams = { ...parentParams, ...matchingChild.params };
363
- const sanitizedParams = this.filterAndSanitizeParams(mergedParams);
364
- tsParamsStore.getState().setParams(sanitizedParams);
365
- tsParamsStore.getState().setQuery(queryParams);
366
- matchingChild.element?.(childElement, sanitizedParams, queryParams);
367
- parentElement.appendChild(childElement);
368
- if (matchingChild.children) {
369
- const nextNestedPath = nestedPath.slice(matchingChild.path.length);
370
- this.renderChildren(
371
- matchingChild.children,
372
- nextNestedPath,
373
- childElement,
374
- sanitizedParams,
375
- queryParams
376
- );
377
- }
378
- }
379
- }
380
- parseQueryParams(search) {
381
- const queryParams = {};
382
- const urlSearchParams = new URLSearchParams(search);
383
- for (const [key, value] of urlSearchParams.entries()) {
384
- if (this.expectedParams.has(key)) {
385
- queryParams[key] = DOMPurify8.sanitize(value);
386
- }
387
- }
388
- return queryParams;
389
- }
390
- findMatchingRoute(path, routes, inheritedParams = {}) {
391
- for (const route of routes) {
392
- const routePath = route.path;
393
- const isDefaultRoute = routePath === "*";
394
- if (!isDefaultRoute) {
395
- const paramNames = [];
396
- const regexPattern = routePath.replace(/:[^\s/]+/g, (match2) => {
397
- paramNames.push(match2.substring(1));
398
- return "([^\\s/]+)";
399
- });
400
- const regex = new RegExp(`^${regexPattern}(?:/|$)`);
401
- const match = path.match(regex);
402
- if (match) {
403
- const params = { ...inheritedParams };
404
- paramNames.forEach((name, index) => {
405
- params[name] = match[index + 1] ?? "";
406
- });
407
- if (route.children) {
408
- const nestedPath = path.slice(match[0].length);
409
- const matchingChild = this.findMatchingRoute(
410
- nestedPath,
411
- route.children,
412
- params
413
- );
414
- if (matchingChild) return matchingChild;
415
- }
416
- return { ...route, params };
417
- }
418
- } else {
419
- return route;
420
- }
421
- }
422
- return void 0;
423
- }
424
- filterAndSanitizeParams(params) {
425
- if (!params) return {};
426
- const sanitizedParams = {};
427
- for (const key in params) {
428
- if (this.expectedParams.has(key)) {
429
- sanitizedParams[key] = DOMPurify8.sanitize(params[key] ?? "");
430
- }
431
- }
432
- return sanitizedParams;
433
- }
434
- navigate(path) {
435
- history.pushState(null, "", path);
436
- this.handlePopState();
437
- }
438
- addRoute(route) {
439
- this.routes.push(route);
440
- }
441
- };
442
- export {
443
- TSRouter,
444
- html,
445
- useAnchor,
446
- useAnchorSingle,
447
- useInitialDOM,
448
- useTSAuth,
449
- useTSComponent,
450
- useTSElementEach,
451
- useTSElements,
452
- useTSEvent,
453
- useTSEventAll,
454
- useTSExtractParams,
455
- useTSParams,
456
- useTSPurifier,
457
- useTSSelect
458
- };