@devwaren/vanilla-ts 1.0.0
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/README.md +0 -0
- package/dist/animate-4M3FYXLV.css +4072 -0
- package/dist/animate-BLFDHCG3.js +1 -0
- package/dist/chunk-NFFXL46F.js +6 -0
- package/dist/esm-KRNKVVL7.js +6 -0
- package/dist/esm-OZEFBEGB.js +1 -0
- package/dist/index.cjs +162 -0
- package/dist/index.css +12 -0
- package/dist/index.d.cts +228 -0
- package/dist/index.d.ts +228 -0
- package/dist/index.js +157 -0
- package/package.json +56 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { Config } from 'dompurify';
|
|
3
|
+
import * as zustand_vanilla from 'zustand/vanilla';
|
|
4
|
+
|
|
5
|
+
type Subscriber<T> = (value: T) => void;
|
|
6
|
+
type Signal<T> = {
|
|
7
|
+
(): T;
|
|
8
|
+
set: (fn: T | ((prev: T) => T)) => void;
|
|
9
|
+
bind: (el: HTMLElement) => void;
|
|
10
|
+
subscribe: (fn: Subscriber<T>) => void;
|
|
11
|
+
};
|
|
12
|
+
declare function createSignal<T>(initial: T): Signal<T>;
|
|
13
|
+
|
|
14
|
+
declare function html(strings: TemplateStringsArray, ...values: unknown[]): string;
|
|
15
|
+
|
|
16
|
+
declare const mapper: <T>(items: T[], cb: (item: T, index: number) => string) => string;
|
|
17
|
+
|
|
18
|
+
type ServerFunctions = Record<string, (input: unknown) => Promise<unknown> | unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* -----------------------------
|
|
21
|
+
* CREATE SERVER FUNCTIONS
|
|
22
|
+
* -----------------------------
|
|
23
|
+
* Returns typed server function registry.
|
|
24
|
+
*/
|
|
25
|
+
declare function createTSServerFunc<T extends ServerFunctions>(funcs: T): T;
|
|
26
|
+
/**
|
|
27
|
+
* -----------------------------
|
|
28
|
+
* CREATE CLIENT FUNCTIONS
|
|
29
|
+
* -----------------------------
|
|
30
|
+
* Provides typed client access to server functions
|
|
31
|
+
*/
|
|
32
|
+
declare function createClientFunc<T extends ServerFunctions>(fetcher: <K extends keyof T>(funcName: K, input: Parameters<T[K]>[0]) => Promise<ReturnType<T[K]>>): { [K in keyof T]: (input: Parameters<T[K]>[0]) => Promise<Awaited<ReturnType<T[K]>>>; };
|
|
33
|
+
|
|
34
|
+
declare const TSFilebasedRouter: () => Plugin;
|
|
35
|
+
|
|
36
|
+
type TSPurifier = (input: string | HTMLElement, config?: Config) => string;
|
|
37
|
+
declare const useTSPurifier: TSPurifier;
|
|
38
|
+
|
|
39
|
+
type TSEvent = <K extends keyof HTMLElementEventMap>(target: string | HTMLElement | Document, eventType: K, handler: (event: HTMLElementEventMap[K]) => void) => void;
|
|
40
|
+
declare const useTSEvent: TSEvent;
|
|
41
|
+
|
|
42
|
+
type MustURL$1 = `/${string}`;
|
|
43
|
+
declare function useTSExtractParams(pattern: MustURL$1): {
|
|
44
|
+
[x: string]: string;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type MustURL = `/${string}`;
|
|
48
|
+
type ParamStore = {
|
|
49
|
+
params: Record<string, string>;
|
|
50
|
+
query: Record<string, string>;
|
|
51
|
+
setFromPattern: (pattern: MustURL) => void;
|
|
52
|
+
setFromPatternValues: (keys: string[], values: string[]) => void;
|
|
53
|
+
setQuery: (query: Record<string, string>) => void;
|
|
54
|
+
getParam: (key: string) => string | undefined;
|
|
55
|
+
getQuery: (key: string) => string | undefined;
|
|
56
|
+
};
|
|
57
|
+
declare const useTSParams: zustand_vanilla.StoreApi<ParamStore>;
|
|
58
|
+
|
|
59
|
+
declare const useTSEventAll: <T extends Event>(selector: string, eventType: keyof HTMLElementEventMap, handler: (event: T) => void) => () => void;
|
|
60
|
+
|
|
61
|
+
type Cleanup$1 = () => void;
|
|
62
|
+
type RenderResult = {
|
|
63
|
+
html?: string;
|
|
64
|
+
cleanup?: Cleanup$1;
|
|
65
|
+
};
|
|
66
|
+
declare const useTSElements: (root: HTMLElement | undefined, template: string, handlers?: Record<string, (el: HTMLElement) => void>, config?: Config) => RenderResult;
|
|
67
|
+
|
|
68
|
+
type TSInitialDOM = (id: string, mount: (el: HTMLElement) => void) => void;
|
|
69
|
+
declare const useInitialDOM: TSInitialDOM;
|
|
70
|
+
|
|
71
|
+
declare global {
|
|
72
|
+
interface Window {
|
|
73
|
+
__anchorSinglePopstateHandlerAttached?: boolean;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
type AnchorSingle = (element: HTMLAnchorElement | null, href: string, ariaLabel: string, className?: string, childElement?: HTMLElement | null) => void;
|
|
77
|
+
declare const useAnchorSingle: AnchorSingle;
|
|
78
|
+
|
|
79
|
+
type SEOConfig = {
|
|
80
|
+
name?: string;
|
|
81
|
+
title?: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
author?: string;
|
|
84
|
+
favicon?: string;
|
|
85
|
+
};
|
|
86
|
+
type CSPConfig = {
|
|
87
|
+
scriptSrc?: string;
|
|
88
|
+
styleSrc?: string;
|
|
89
|
+
objectSrc?: string;
|
|
90
|
+
connectSrc?: string[];
|
|
91
|
+
reportOnly?: boolean;
|
|
92
|
+
};
|
|
93
|
+
type SEOHandler = {
|
|
94
|
+
setName: (name: string) => void;
|
|
95
|
+
setTitle: (title: string) => void;
|
|
96
|
+
setDescription: (description: string) => void;
|
|
97
|
+
setAuthor: (author: string) => void;
|
|
98
|
+
setFavicon: (url: string) => void;
|
|
99
|
+
getName: () => string | undefined;
|
|
100
|
+
getTitle: () => string | undefined;
|
|
101
|
+
getDescription: () => string;
|
|
102
|
+
getAuthor: () => string;
|
|
103
|
+
getFavicon: () => string | undefined;
|
|
104
|
+
getAllMetaData: () => SEOConfig;
|
|
105
|
+
appendMetaTagsToHead: () => void;
|
|
106
|
+
};
|
|
107
|
+
declare const useTSMetaData: (config: SEOConfig, cspConfig?: CSPConfig) => SEOHandler;
|
|
108
|
+
|
|
109
|
+
type TSComponent = (id: string, parent: HTMLElement, element: Function, params?: any, params2?: any) => void;
|
|
110
|
+
declare const useTSComponent: TSComponent;
|
|
111
|
+
|
|
112
|
+
type TSCollection = (collections: string[], DOM: HTMLElement, elements: Function[], params?: any[]) => void;
|
|
113
|
+
declare const useTSCollection: TSCollection;
|
|
114
|
+
|
|
115
|
+
type TSSelect = <T extends Element = HTMLElement>(selector: string, scope?: HTMLElement) => T | null;
|
|
116
|
+
declare const useTSSelect: TSSelect;
|
|
117
|
+
|
|
118
|
+
declare const useTSAuth: (_Component: HTMLElement | void, loginUrl: string) => null;
|
|
119
|
+
|
|
120
|
+
type TSElementEach = (elements: NodeListOf<HTMLElement> | HTMLElement[], events: (keyof HTMLElementEventMap)[], callback: (element: HTMLElement, event: Event) => void) => void;
|
|
121
|
+
declare const useTSElementEach: TSElementEach;
|
|
122
|
+
|
|
123
|
+
declare const useTSNavigate: () => {
|
|
124
|
+
back: () => void;
|
|
125
|
+
forward: () => void;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
type OutletComponent = (DOM: HTMLElement) => void;
|
|
129
|
+
type ChildRoute = {
|
|
130
|
+
path: string;
|
|
131
|
+
outlet: string;
|
|
132
|
+
element: OutletComponent;
|
|
133
|
+
};
|
|
134
|
+
type Route = {
|
|
135
|
+
path: string;
|
|
136
|
+
element: (DOM: HTMLElement) => void;
|
|
137
|
+
children?: ChildRoute[];
|
|
138
|
+
};
|
|
139
|
+
interface RouterInstance {
|
|
140
|
+
routes: Route[];
|
|
141
|
+
}
|
|
142
|
+
type OutletOptions = {
|
|
143
|
+
path: string;
|
|
144
|
+
component: OutletComponent;
|
|
145
|
+
};
|
|
146
|
+
declare const useTSOutlet: (selector: string, outlets: OutletOptions[]) => void;
|
|
147
|
+
declare function renderChildRoutes(DOM: HTMLElement, router: RouterInstance): void;
|
|
148
|
+
|
|
149
|
+
declare global {
|
|
150
|
+
interface Window {
|
|
151
|
+
brython: Function;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
declare const useTSloadBrython: () => Promise<void>;
|
|
155
|
+
type RequirePy = `${string}.py`;
|
|
156
|
+
type LoadPy = (src: RequirePy) => Promise<void>;
|
|
157
|
+
declare const loadPyFiles: LoadPy;
|
|
158
|
+
|
|
159
|
+
declare function useTSLazy<T extends (...args: any[]) => any>(factory: () => Promise<{
|
|
160
|
+
default: T;
|
|
161
|
+
} | T>): (el?: HTMLElement, props?: Parameters<T>[1]) => Promise<any>;
|
|
162
|
+
|
|
163
|
+
declare const useTSSSRHydration: (DOM: HTMLElement) => {
|
|
164
|
+
isDOM: null;
|
|
165
|
+
} | {
|
|
166
|
+
isDOM: HTMLElement;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
declare const useTSNoReload: (DOM: HTMLElement) => void;
|
|
170
|
+
|
|
171
|
+
type AnchorInput = NodeListOf<HTMLAnchorElement> | HTMLAnchorElement[] | HTMLAnchorElement | null | undefined;
|
|
172
|
+
declare const useAnchor: (anchors?: AnchorInput) => void;
|
|
173
|
+
|
|
174
|
+
type Cleanup = void | (() => void);
|
|
175
|
+
declare function useTSReactor(effect: () => Cleanup, deps: any[]): void;
|
|
176
|
+
|
|
177
|
+
type State = {
|
|
178
|
+
params: Record<string, string>;
|
|
179
|
+
query: Record<string, string>;
|
|
180
|
+
};
|
|
181
|
+
type Listener = (s: State) => void;
|
|
182
|
+
declare const useTSQuery: {
|
|
183
|
+
getState(): {
|
|
184
|
+
params: Record<string, string>;
|
|
185
|
+
query: Record<string, string>;
|
|
186
|
+
getParam: (key: string) => string;
|
|
187
|
+
getQuery: (key: string) => string;
|
|
188
|
+
setFromPattern(pattern: `/${string}`): void;
|
|
189
|
+
setFromPatternValues(keys: string[], values: string[]): void;
|
|
190
|
+
setQuery(query: Record<string, string>): void;
|
|
191
|
+
replaceQuery(query: Record<string, string>): void;
|
|
192
|
+
removeQuery(key: string): void;
|
|
193
|
+
clearQuery(): void;
|
|
194
|
+
setQueryFromURL(search: string): void;
|
|
195
|
+
subscribe(fn: Listener): () => boolean;
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
type RouteCallback = (errorElement?: HTMLElement, params?: Record<string, string>, query?: Record<string, string>) => void;
|
|
200
|
+
interface RouteConfig {
|
|
201
|
+
path: string;
|
|
202
|
+
routeto?: string;
|
|
203
|
+
element: RouteCallback;
|
|
204
|
+
errorElement?: RouteCallback;
|
|
205
|
+
children?: RouteConfig[];
|
|
206
|
+
params?: Record<string, string>;
|
|
207
|
+
}
|
|
208
|
+
type APIFetcher<T extends ServerFunctions> = <K extends keyof T>(funcName: K, input: Parameters<T[K]>[0]) => Promise<Awaited<ReturnType<T[K]>>>;
|
|
209
|
+
declare class TSRouter<TServer extends ServerFunctions = {}> {
|
|
210
|
+
private routes;
|
|
211
|
+
private expectedParams;
|
|
212
|
+
private apiFetcher?;
|
|
213
|
+
constructor(routes: RouteConfig[], expectedParams: string[], apiFetcher?: APIFetcher<TServer>);
|
|
214
|
+
private handlePopState;
|
|
215
|
+
private renderChildren;
|
|
216
|
+
private parseQueryParams;
|
|
217
|
+
private findMatchingRoute;
|
|
218
|
+
private filterAndSanitizeParams;
|
|
219
|
+
navigate(path: string): void;
|
|
220
|
+
addRoute(route: RouteConfig): void;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
type TSRoute = {
|
|
224
|
+
navigate: (fullPath: string, push?: boolean) => Promise<void>;
|
|
225
|
+
};
|
|
226
|
+
declare const initializeRoute: (router: TSRoute) => Promise<void>;
|
|
227
|
+
|
|
228
|
+
export { type Signal, TSFilebasedRouter, TSRouter, createClientFunc, createSignal, createTSServerFunc, html, initializeRoute, loadPyFiles, mapper, renderChildRoutes, useAnchor, useAnchorSingle, useInitialDOM, useTSAuth, useTSCollection, useTSComponent, useTSElementEach, useTSElements, useTSEvent, useTSEventAll, useTSExtractParams, useTSLazy, useTSMetaData, useTSNavigate, useTSNoReload, useTSOutlet, useTSParams, useTSPurifier, useTSQuery, useTSReactor, useTSSSRHydration, useTSSelect, useTSloadBrython };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { Config } from 'dompurify';
|
|
3
|
+
import * as zustand_vanilla from 'zustand/vanilla';
|
|
4
|
+
|
|
5
|
+
type Subscriber<T> = (value: T) => void;
|
|
6
|
+
type Signal<T> = {
|
|
7
|
+
(): T;
|
|
8
|
+
set: (fn: T | ((prev: T) => T)) => void;
|
|
9
|
+
bind: (el: HTMLElement) => void;
|
|
10
|
+
subscribe: (fn: Subscriber<T>) => void;
|
|
11
|
+
};
|
|
12
|
+
declare function createSignal<T>(initial: T): Signal<T>;
|
|
13
|
+
|
|
14
|
+
declare function html(strings: TemplateStringsArray, ...values: unknown[]): string;
|
|
15
|
+
|
|
16
|
+
declare const mapper: <T>(items: T[], cb: (item: T, index: number) => string) => string;
|
|
17
|
+
|
|
18
|
+
type ServerFunctions = Record<string, (input: unknown) => Promise<unknown> | unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* -----------------------------
|
|
21
|
+
* CREATE SERVER FUNCTIONS
|
|
22
|
+
* -----------------------------
|
|
23
|
+
* Returns typed server function registry.
|
|
24
|
+
*/
|
|
25
|
+
declare function createTSServerFunc<T extends ServerFunctions>(funcs: T): T;
|
|
26
|
+
/**
|
|
27
|
+
* -----------------------------
|
|
28
|
+
* CREATE CLIENT FUNCTIONS
|
|
29
|
+
* -----------------------------
|
|
30
|
+
* Provides typed client access to server functions
|
|
31
|
+
*/
|
|
32
|
+
declare function createClientFunc<T extends ServerFunctions>(fetcher: <K extends keyof T>(funcName: K, input: Parameters<T[K]>[0]) => Promise<ReturnType<T[K]>>): { [K in keyof T]: (input: Parameters<T[K]>[0]) => Promise<Awaited<ReturnType<T[K]>>>; };
|
|
33
|
+
|
|
34
|
+
declare const TSFilebasedRouter: () => Plugin;
|
|
35
|
+
|
|
36
|
+
type TSPurifier = (input: string | HTMLElement, config?: Config) => string;
|
|
37
|
+
declare const useTSPurifier: TSPurifier;
|
|
38
|
+
|
|
39
|
+
type TSEvent = <K extends keyof HTMLElementEventMap>(target: string | HTMLElement | Document, eventType: K, handler: (event: HTMLElementEventMap[K]) => void) => void;
|
|
40
|
+
declare const useTSEvent: TSEvent;
|
|
41
|
+
|
|
42
|
+
type MustURL$1 = `/${string}`;
|
|
43
|
+
declare function useTSExtractParams(pattern: MustURL$1): {
|
|
44
|
+
[x: string]: string;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type MustURL = `/${string}`;
|
|
48
|
+
type ParamStore = {
|
|
49
|
+
params: Record<string, string>;
|
|
50
|
+
query: Record<string, string>;
|
|
51
|
+
setFromPattern: (pattern: MustURL) => void;
|
|
52
|
+
setFromPatternValues: (keys: string[], values: string[]) => void;
|
|
53
|
+
setQuery: (query: Record<string, string>) => void;
|
|
54
|
+
getParam: (key: string) => string | undefined;
|
|
55
|
+
getQuery: (key: string) => string | undefined;
|
|
56
|
+
};
|
|
57
|
+
declare const useTSParams: zustand_vanilla.StoreApi<ParamStore>;
|
|
58
|
+
|
|
59
|
+
declare const useTSEventAll: <T extends Event>(selector: string, eventType: keyof HTMLElementEventMap, handler: (event: T) => void) => () => void;
|
|
60
|
+
|
|
61
|
+
type Cleanup$1 = () => void;
|
|
62
|
+
type RenderResult = {
|
|
63
|
+
html?: string;
|
|
64
|
+
cleanup?: Cleanup$1;
|
|
65
|
+
};
|
|
66
|
+
declare const useTSElements: (root: HTMLElement | undefined, template: string, handlers?: Record<string, (el: HTMLElement) => void>, config?: Config) => RenderResult;
|
|
67
|
+
|
|
68
|
+
type TSInitialDOM = (id: string, mount: (el: HTMLElement) => void) => void;
|
|
69
|
+
declare const useInitialDOM: TSInitialDOM;
|
|
70
|
+
|
|
71
|
+
declare global {
|
|
72
|
+
interface Window {
|
|
73
|
+
__anchorSinglePopstateHandlerAttached?: boolean;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
type AnchorSingle = (element: HTMLAnchorElement | null, href: string, ariaLabel: string, className?: string, childElement?: HTMLElement | null) => void;
|
|
77
|
+
declare const useAnchorSingle: AnchorSingle;
|
|
78
|
+
|
|
79
|
+
type SEOConfig = {
|
|
80
|
+
name?: string;
|
|
81
|
+
title?: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
author?: string;
|
|
84
|
+
favicon?: string;
|
|
85
|
+
};
|
|
86
|
+
type CSPConfig = {
|
|
87
|
+
scriptSrc?: string;
|
|
88
|
+
styleSrc?: string;
|
|
89
|
+
objectSrc?: string;
|
|
90
|
+
connectSrc?: string[];
|
|
91
|
+
reportOnly?: boolean;
|
|
92
|
+
};
|
|
93
|
+
type SEOHandler = {
|
|
94
|
+
setName: (name: string) => void;
|
|
95
|
+
setTitle: (title: string) => void;
|
|
96
|
+
setDescription: (description: string) => void;
|
|
97
|
+
setAuthor: (author: string) => void;
|
|
98
|
+
setFavicon: (url: string) => void;
|
|
99
|
+
getName: () => string | undefined;
|
|
100
|
+
getTitle: () => string | undefined;
|
|
101
|
+
getDescription: () => string;
|
|
102
|
+
getAuthor: () => string;
|
|
103
|
+
getFavicon: () => string | undefined;
|
|
104
|
+
getAllMetaData: () => SEOConfig;
|
|
105
|
+
appendMetaTagsToHead: () => void;
|
|
106
|
+
};
|
|
107
|
+
declare const useTSMetaData: (config: SEOConfig, cspConfig?: CSPConfig) => SEOHandler;
|
|
108
|
+
|
|
109
|
+
type TSComponent = (id: string, parent: HTMLElement, element: Function, params?: any, params2?: any) => void;
|
|
110
|
+
declare const useTSComponent: TSComponent;
|
|
111
|
+
|
|
112
|
+
type TSCollection = (collections: string[], DOM: HTMLElement, elements: Function[], params?: any[]) => void;
|
|
113
|
+
declare const useTSCollection: TSCollection;
|
|
114
|
+
|
|
115
|
+
type TSSelect = <T extends Element = HTMLElement>(selector: string, scope?: HTMLElement) => T | null;
|
|
116
|
+
declare const useTSSelect: TSSelect;
|
|
117
|
+
|
|
118
|
+
declare const useTSAuth: (_Component: HTMLElement | void, loginUrl: string) => null;
|
|
119
|
+
|
|
120
|
+
type TSElementEach = (elements: NodeListOf<HTMLElement> | HTMLElement[], events: (keyof HTMLElementEventMap)[], callback: (element: HTMLElement, event: Event) => void) => void;
|
|
121
|
+
declare const useTSElementEach: TSElementEach;
|
|
122
|
+
|
|
123
|
+
declare const useTSNavigate: () => {
|
|
124
|
+
back: () => void;
|
|
125
|
+
forward: () => void;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
type OutletComponent = (DOM: HTMLElement) => void;
|
|
129
|
+
type ChildRoute = {
|
|
130
|
+
path: string;
|
|
131
|
+
outlet: string;
|
|
132
|
+
element: OutletComponent;
|
|
133
|
+
};
|
|
134
|
+
type Route = {
|
|
135
|
+
path: string;
|
|
136
|
+
element: (DOM: HTMLElement) => void;
|
|
137
|
+
children?: ChildRoute[];
|
|
138
|
+
};
|
|
139
|
+
interface RouterInstance {
|
|
140
|
+
routes: Route[];
|
|
141
|
+
}
|
|
142
|
+
type OutletOptions = {
|
|
143
|
+
path: string;
|
|
144
|
+
component: OutletComponent;
|
|
145
|
+
};
|
|
146
|
+
declare const useTSOutlet: (selector: string, outlets: OutletOptions[]) => void;
|
|
147
|
+
declare function renderChildRoutes(DOM: HTMLElement, router: RouterInstance): void;
|
|
148
|
+
|
|
149
|
+
declare global {
|
|
150
|
+
interface Window {
|
|
151
|
+
brython: Function;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
declare const useTSloadBrython: () => Promise<void>;
|
|
155
|
+
type RequirePy = `${string}.py`;
|
|
156
|
+
type LoadPy = (src: RequirePy) => Promise<void>;
|
|
157
|
+
declare const loadPyFiles: LoadPy;
|
|
158
|
+
|
|
159
|
+
declare function useTSLazy<T extends (...args: any[]) => any>(factory: () => Promise<{
|
|
160
|
+
default: T;
|
|
161
|
+
} | T>): (el?: HTMLElement, props?: Parameters<T>[1]) => Promise<any>;
|
|
162
|
+
|
|
163
|
+
declare const useTSSSRHydration: (DOM: HTMLElement) => {
|
|
164
|
+
isDOM: null;
|
|
165
|
+
} | {
|
|
166
|
+
isDOM: HTMLElement;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
declare const useTSNoReload: (DOM: HTMLElement) => void;
|
|
170
|
+
|
|
171
|
+
type AnchorInput = NodeListOf<HTMLAnchorElement> | HTMLAnchorElement[] | HTMLAnchorElement | null | undefined;
|
|
172
|
+
declare const useAnchor: (anchors?: AnchorInput) => void;
|
|
173
|
+
|
|
174
|
+
type Cleanup = void | (() => void);
|
|
175
|
+
declare function useTSReactor(effect: () => Cleanup, deps: any[]): void;
|
|
176
|
+
|
|
177
|
+
type State = {
|
|
178
|
+
params: Record<string, string>;
|
|
179
|
+
query: Record<string, string>;
|
|
180
|
+
};
|
|
181
|
+
type Listener = (s: State) => void;
|
|
182
|
+
declare const useTSQuery: {
|
|
183
|
+
getState(): {
|
|
184
|
+
params: Record<string, string>;
|
|
185
|
+
query: Record<string, string>;
|
|
186
|
+
getParam: (key: string) => string;
|
|
187
|
+
getQuery: (key: string) => string;
|
|
188
|
+
setFromPattern(pattern: `/${string}`): void;
|
|
189
|
+
setFromPatternValues(keys: string[], values: string[]): void;
|
|
190
|
+
setQuery(query: Record<string, string>): void;
|
|
191
|
+
replaceQuery(query: Record<string, string>): void;
|
|
192
|
+
removeQuery(key: string): void;
|
|
193
|
+
clearQuery(): void;
|
|
194
|
+
setQueryFromURL(search: string): void;
|
|
195
|
+
subscribe(fn: Listener): () => boolean;
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
type RouteCallback = (errorElement?: HTMLElement, params?: Record<string, string>, query?: Record<string, string>) => void;
|
|
200
|
+
interface RouteConfig {
|
|
201
|
+
path: string;
|
|
202
|
+
routeto?: string;
|
|
203
|
+
element: RouteCallback;
|
|
204
|
+
errorElement?: RouteCallback;
|
|
205
|
+
children?: RouteConfig[];
|
|
206
|
+
params?: Record<string, string>;
|
|
207
|
+
}
|
|
208
|
+
type APIFetcher<T extends ServerFunctions> = <K extends keyof T>(funcName: K, input: Parameters<T[K]>[0]) => Promise<Awaited<ReturnType<T[K]>>>;
|
|
209
|
+
declare class TSRouter<TServer extends ServerFunctions = {}> {
|
|
210
|
+
private routes;
|
|
211
|
+
private expectedParams;
|
|
212
|
+
private apiFetcher?;
|
|
213
|
+
constructor(routes: RouteConfig[], expectedParams: string[], apiFetcher?: APIFetcher<TServer>);
|
|
214
|
+
private handlePopState;
|
|
215
|
+
private renderChildren;
|
|
216
|
+
private parseQueryParams;
|
|
217
|
+
private findMatchingRoute;
|
|
218
|
+
private filterAndSanitizeParams;
|
|
219
|
+
navigate(path: string): void;
|
|
220
|
+
addRoute(route: RouteConfig): void;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
type TSRoute = {
|
|
224
|
+
navigate: (fullPath: string, push?: boolean) => Promise<void>;
|
|
225
|
+
};
|
|
226
|
+
declare const initializeRoute: (router: TSRoute) => Promise<void>;
|
|
227
|
+
|
|
228
|
+
export { type Signal, TSFilebasedRouter, TSRouter, createClientFunc, createSignal, createTSServerFunc, html, initializeRoute, loadPyFiles, mapper, renderChildRoutes, useAnchor, useAnchorSingle, useInitialDOM, useTSAuth, useTSCollection, useTSComponent, useTSElementEach, useTSElements, useTSEvent, useTSEventAll, useTSExtractParams, useTSLazy, useTSMetaData, useTSNavigate, useTSNoReload, useTSOutlet, useTSParams, useTSPurifier, useTSQuery, useTSReactor, useTSSSRHydration, useTSSelect, useTSloadBrython };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import Ae from"dompurify";var I=null;function Ce(){return typeof window>"u"?null:(I||(I=Ae(window)),I)}var He=["div","span","p","a","button","ul","li","img","input","form","label","h1","h2","h3","h4","h5","h6","section","main","article","svg","path","circle","rect","line","polyline","polygon","g"],Oe=["class","id","href","src","alt","title","type","value","name","placeholder","target","rel","data-click","data-change","data-select","data-effect","data-hover","data-submit","data-key","data-event","data-component","data-stagger","data-input"];function De(n){return/^(https?:\/\/|\/|#)/i.test(n.trim())}function Fe(n){if(typeof window>"u")return n;let e=document.createElement("template");return e.innerHTML=n,e.content.querySelectorAll("*").forEach(t=>{[...t.attributes].forEach(r=>{let o=r.name.toLowerCase();if(o.startsWith("on")||o.startsWith("xlink")||o.startsWith("xml")){t.removeAttribute(r.name);return}(o==="href"||o==="src")&&!De(r.value)&&t.setAttribute(o,"#")}),t.tagName==="A"&&t.getAttribute("target")==="_blank"&&t.setAttribute("rel","noopener noreferrer")}),e.innerHTML}function V(n,...e){let t=Ce(),r=n.reduce((s,i,a)=>{let l=a<e.length?String(e[a]??""):"";return s+i+l},"");if(!t)return r;let o=t.sanitize(r,{ALLOWED_TAGS:He,ALLOWED_ATTR:Oe,RETURN_DOM:!1});return Fe(o)}var $e=(n,e)=>n.reduce((t,r,o)=>t+e(r,o),"");function ke(n){return n}function qe(n){return new Proxy({},{get(e,t){return async r=>n(t,r)}})}import G from"dompurify";var Y=(n,e)=>{let r={...{ADD_TAGS:["my-custom-tag"]},...e};return typeof n=="string"?G.sanitize(n,r):G.sanitize(n.innerHTML,r)};var X=(n,e,t)=>{if(!(typeof window>"u"||typeof document>"u"))if(typeof n=="string"){let r=document.getElementById(n);r?r.addEventListener(e,t):console.warn(`Element with id '${n}' not found.`)}else n instanceof HTMLElement?n.addEventListener(e,t):n===document?document.addEventListener(e,t):console.warn("Invalid target parameter provided.")};import{createStore as Ne}from"zustand/vanilla";import Ie from"dompurify";function O(n){return Ie.sanitize(n??"")}function H(n,e){let t=Object.keys(n),r=Object.keys(e);if(t.length!==r.length)return!1;for(let o of t)if(n[o]!==e[o])return!1;return!0}function ze(n,e){let t=[],r=n.replace(/:[^/]+/g,a=>(t.push(a.slice(1)),"([^/]+)")),o=new RegExp(`^${r}$`),s=e.match(o),i={};return s&&t.forEach((a,l)=>{i[a]=O(s[l+1]??"")}),i}function _e(n){let e={},t=new URLSearchParams(n);for(let[r,o]of t.entries())e[r]=O(o);return e}var D=Ne((n,e)=>({params:{},query:{},setFromPattern:t=>{let r=window.location.pathname,o=ze(t,r),s=_e(window.location.search),i=e();(!H(i.params,o)||!H(i.query,s))&&n({params:o,query:s})},setFromPatternValues:(t,r)=>{let o={};t.forEach((i,a)=>{o[i]=O(r[a]??"")});let s=e();H(s.params,o)||n({params:o})},setQuery:t=>{let r={};for(let s in t)r[s]=O(t[s]);let o=e();H(o.query,r)||n({query:r})},getParam:t=>e().params[t],getQuery:t=>e().query[t]}));function J(n){let e=D.getState();e.setFromPattern(n);let t=e.params,r=e.query;return{...t,...r}}var Z=(n,e,t)=>{let r=document.querySelectorAll(n);return r.forEach(o=>{o.addEventListener(e,t)}),()=>{r.forEach(o=>{o.removeEventListener(e,t)})}};import{animate as Ue}from"motion";import je from"dompurify";var z=typeof window<"u"&&typeof document<"u",ee=["div","span","p","a","button","ul","li","img","input","form","label","h1","h2","h3","h4","h5","h6","section","main","article"],te=["class","id","href","src","alt","title","type","value","name","placeholder","data-click","data-change","data-select","data-effect","data-hover","data-submit","data-key","data-event","data-component","data-stagger","data-input","data-children","data-slot","target","rel"],ne=z?je(window):{sanitize:(n,e)=>n};function We(n){return/^(https?:\/\/|\/|#)/i.test(n.trim())}function Qe(n){z&&n.querySelectorAll("*").forEach(e=>{[...e.attributes].forEach(t=>{let r=t.name.toLowerCase();if(r.startsWith("on")){e.removeAttribute(t.name);return}(r==="href"||r==="src")&&!We(t.value)&&e.setAttribute(r,"#")}),e.tagName==="A"&&e.getAttribute("target")==="_blank"&&e.setAttribute("rel","noopener noreferrer")})}function re(n){let e={},t={},r=400,o=0,s="ease-in-out",i=0,a=!1,l,u;return n.split(/\s+/).forEach(c=>{c==="fade-in"&&(e.opacity=0,t.opacity=1),c==="fade-out"&&(e.opacity=1,t.opacity=0),c==="slide-up"&&(e.y=20,t.y=0),c==="slide-down"&&(e.y=-20,t.y=0),c==="slide-left"&&(e.x=20,t.x=0),c==="slide-right"&&(e.x=-20,t.x=0),c.startsWith("duration-")&&(r=+c.replace("duration-","")),c.startsWith("delay-")&&(o=+c.replace("delay-","")),(c==="linear"||c.startsWith("ease"))&&(s=c),c==="infinite"&&(i=1/0),c==="replay"&&(a=!0),c.startsWith("parallax-y-")&&(l=+c.replace("parallax-y-","")),c.startsWith("parallax-x-")&&(u=+c.replace("parallax-x-",""))}),{from:e,to:t,duration:r,easing:s,delay:o,repeat:i,replay:a,parallaxY:l,parallaxX:u}}function Ke(n,e){n.querySelectorAll("[data-component]").forEach(t=>{let r=t.dataset.component;e[r]?.(t)})}var oe=(n,e,t={},r)=>{if(!z||!n)return{html:ne.sanitize(e,{ALLOWED_TAGS:ee,ALLOWED_ATTR:te,...r})};let o=ne.sanitize(e,{ALLOWED_TAGS:ee,ALLOWED_ATTR:te,...r});n.innerHTML=o,Qe(n);let s=c=>{let d=c.target.closest("[data-click]");d&&t[d.dataset.click]?.(d)};n.addEventListener("click",s),n.querySelectorAll("[data-input]").forEach(c=>{let d=c.dataset.input;t[d]?.(c),c.addEventListener("input",()=>{t[d]?.(c)})}),Ke(n,t);let i=[];n.querySelectorAll("[data-effect]").forEach(c=>{let d=re(c.dataset.effect||"");(d.parallaxX||d.parallaxY)&&i.push({el:c,...d})});let a=!1,l=()=>{a||(a=!0,requestAnimationFrame(()=>{let c=window.scrollY;i.forEach(({el:d,parallaxX:g,parallaxY:p})=>{d.style.transform=`translate3d(${(g||0)*c}px, ${(p||0)*c}px, 0)`}),a=!1}))};window.addEventListener("scroll",l);let u=new IntersectionObserver(c=>{c.forEach(d=>{let g=d.target,p=re(g.dataset.effect||"");d.isIntersecting?(Object.assign(g.style,p.from),setTimeout(()=>{Ue(g,p.to,{duration:p.duration/1e3,easing:p.easing,repeat:p.repeat})},p.delay),p.replay||u.unobserve(g)):p.replay&&Object.assign(g.style,p.from)})});return n.querySelectorAll("[data-effect]").forEach(c=>u.observe(c)),{cleanup(){u.disconnect(),window.removeEventListener("scroll",l),n.removeEventListener("click",s)}}};import se from"dompurify";var F=null,ie=(n,e)=>{if(typeof document>"u")return;let t=document.getElementById(n);if(!t)return;se.addHook("uponSanitizeAttribute",(i,a)=>{let l=(a.attrName||"").toLowerCase(),u=(a.attrValue??"").toString().trim();if(l.startsWith("on")){a.keepAttr=!1;return}if((l==="href"||l==="src")&&/^(javascript:|vbscript:|data:|file:|about:)/i.test(u)){a.keepAttr=!1;return}if(l==="class"){let d=u.split(/\s+/).filter(Boolean).filter(g=>{if(/^[a-zA-Z0-9\-\:\/_\[\]\(\)]+$/.test(g)){if(/^bg-\[url\(.*\)\]$/.test(g)){let p=g.replace(/^bg-\[url\(/,"").replace(/\)\]$/,"").replace(/^['"]|['"]$/g,"");return p===""||/^https?:\/\//i.test(p)||/^\/(?!\/)/.test(p)||/^\.{0,2}\//.test(p)}return!0}return!1});a.attrValue=d.join(" ");return}if(l==="style"){a.keepAttr=!1;return}});let r=t.cloneNode(!0),o=se.sanitize(r.innerHTML,{USE_PROFILES:{html:!0},ALLOWED_TAGS:["div","span","p","h1","h2","h3","h4","h5","h6","ul","ol","li","strong","em","a","img","br","form","button","input","label"],ALLOWED_ATTR:["href","src","alt","title","class","id","type","name","value","placeholder","data-click","data-change","data-submit","data-select","data-hover","data-classlist"],FORBID_TAGS:["script","iframe","object","embed","body","html","svg","math","link","meta"],ALLOW_DATA_ATTR:!0,KEEP_CONTENT:!1,RETURN_DOM_FRAGMENT:!0}),s=Array.from(o.childNodes).map(i=>i.outerHTML||i.textContent||"").join("");if(F!==null&&s!==F){let i=document.createElement("div");e(i);let l=new DOMParser().parseFromString(F,"text/html");for(;t.firstChild;)t.removeChild(t.firstChild);l.body.childNodes.forEach(u=>t.appendChild(u.cloneNode(!0)))}else{for(F=s;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(o),e(t)}};import ae from"dompurify";typeof window<"u"&&!window.__anchorSinglePopstateHandlerAttached&&(window.addEventListener("popstate",n=>{let e=n.state;e?.scrollPosition!==void 0&&window.scrollTo(0,e.scrollPosition)}),window.__anchorSinglePopstateHandlerAttached=!0);var ce=(n,e,t,r="",o=null)=>{if(!n)return;let s=ae.sanitize(e,{ALLOWED_URI_REGEXP:/^(https?:|\/)/}),i=ae.sanitize(t,{USE_PROFILES:{html:!1}});n.setAttribute("href",s),n.setAttribute("aria-label",i),r&&(n.className=r.trim()),o&&n.replaceChildren(o),typeof window<"u"&&n.addEventListener("click",a=>{a.preventDefault();let u=a.currentTarget.getAttribute("href");if(u){let c=window.scrollY;window.scrollTo(0,0),window.history.pushState({scrollPosition:c},"",u),dispatchEvent(new PopStateEvent("popstate"))}})};import E from"dompurify";var le=(n="'self' 'nonce-rAnd0m123' 'unsafe-inline' 'unsafe-eval'",e="'self' 'nonce-rAnd0m123'",t="'none'",r="'self' https://fonts.googleapis.com https://fonts.gstatic.com",o="'self' https://blogger.googleusercontent.com",s=["'self'","https://fonts.googleapis.com","https://fonts.gstatic.com","https://www.google.com/maps/"],i="'self' https://www.youtube.com",a="'self'",l="/csp-report",u=!1)=>{let c=()=>{try{let d=document.querySelector('meta[http-equiv="Content-Security-Policy"]');d||(d=document.createElement("meta"),d.setAttribute("http-equiv","Content-Security-Policy"),document.head.appendChild(d));let g=u?`report-uri ${l};`:"";d.setAttribute("content",`default-src 'self'; script-src ${n}; style-src ${e}; object-src ${t}; font-src ${r}; img-src ${o}; connect-src ${s.join(" ")}; frame-src ${i}; base-uri ${a}; ${g}`)}catch(d){console.error("Error adding CSP meta element:",d)}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",c):c()};var ue=(n,e)=>{let t={name:E.sanitize(n.name||""),title:E.sanitize(n.title||""),description:E.sanitize(n.description||"Default description"),author:E.sanitize(n.author||""),favicon:n.favicon},r=T=>{t.name=E.sanitize(T),v("name",t.name)},o=T=>{t.title=E.sanitize(T),document.title=t.title},s=T=>{t.description=E.sanitize(T),v("description",t.description)},i=T=>{t.author=E.sanitize(T),v("author",t.author)},a=T=>{t.favicon=E.sanitize(T);let m=document.querySelector('link[rel="icon"]');m||(m=document.createElement("link"),m.rel="icon",document.head.appendChild(m)),m.href=t.favicon},l=()=>t.name,u=()=>t.title,c=()=>t.description,d=()=>t.author,g=()=>t.favicon,p=()=>t,A=(T,m)=>{let h=document.createElement("meta");h.setAttribute("name",T),h.setAttribute("content",m),document.head.appendChild(h)},v=(T,m)=>{let h=document.querySelector(`meta[name="${T}"]`);h?h.setAttribute("content",m):A(T,m)},M=()=>{t.title&&(document.title=t.title),t.name&&v("name",t.name),t.description&&v("description",t.description),t.author&&v("author",t.author),t.favicon&&a(t.favicon)};return e&&le(e.scriptSrc,e.styleSrc,e.objectSrc,Array.isArray(e.connectSrc)?e.connectSrc.join(" "):e.connectSrc,e.reportOnly!==void 0?String(e.reportOnly):void 0),M(),{setName:r,setTitle:o,setDescription:s,setAuthor:i,setFavicon:a,getName:l,getTitle:u,getDescription:c,getAuthor:d,getFavicon:g,getAllMetaData:p,appendMetaTagsToHead:M}};import Be from"dompurify";var $=(n,e,t,r,o)=>{let s=`#${n}`,i=e.querySelectorAll(s);if(i.length===0)throw new Error(`[useTSComponent] No element found with id '${n}' in the given parent.`);if(i.length>1)throw new Error(`[useTSComponent] Duplicate id '${n}' detected. Found ${i.length} elements.`);let a=i[0];a.innerHTML=Be.sanitize(a.innerHTML,{USE_PROFILES:{html:!0}}),t(a,r,o)};var de=(n,e,t,r=[])=>{let o=new Set;n.forEach((s,i)=>{if(o.has(s)){console.warn(`[useTSCollection] Duplicate ID in collection array: "${s}" \u2014 skipping.`);return}o.add(s);let a=e.querySelectorAll(`#${s}`);if(a.length>1){console.warn(`[useTSCollection] Duplicate ID in DOM: "${s}" (${a.length} elements found) \u2014 skipping component mount.`);return}let l=t[i],u=Array.isArray(r)?r[i]:void 0;typeof l=="function"?$(s,e,l,u):console.warn(`[useTSCollection] No valid component function found for ID: "${s}"`)})};var P=(n,e)=>{let r=(e??document).querySelectorAll(n);if(r.length===0)return process.env.NODE_ENV!=="production"&&console.warn(`[useTSSelect] No element found for selector: '${n}'`),null;if(n.startsWith("#")&&r.length>1){if(process.env.NODE_ENV!=="production")throw new Error(`[useTSSelect] Duplicate ID detected: '${n}'. Found ${r.length} elements with this ID.`);return r[0]}return r.length>1&&process.env.NODE_ENV!=="production"&&console.warn(`[useTSSelect] Multiple elements found for selector: '${n}'. Returning the first one.`),r[0]};import{jwtDecode as Ve}from"jwt-decode";var me=(n,e)=>{let t=localStorage.getItem("token");if(!t)return window.location.href=e,null;try{let r=Ve(t),o=Date.now()/1e3;return r.exp&&r.exp<o&&(console.error("Token has expired"),window.localStorage.removeItem("token"),window.location.href=e),null}catch(r){return console.error("Invalid token:",r),window.location.href=e,null}};var _=(n,e,t)=>{n.forEach(r=>{e.forEach(o=>{r.addEventListener(o,s=>{t(r,s)})})})};var pe=()=>({back:()=>window.history.back(),forward:()=>window.history.forward()});var fe=(n,e)=>{let t=document.querySelector(`#${n}`)||document.querySelector(`.${n}`);if(!t)return;let r=window.location.pathname.replace(/\/$/,"");for(let o of e){let s=o.path.replace(/\/$/,"");if(r===s||r.startsWith(`${s}/`)){o.component(t);break}}};function ge(n,e){let t=window.location.pathname.replace(/\/$/,"");e.routes.forEach(r=>{r.children?.length&&r.children.forEach(o=>{let s=o.path.replace(/\/$/,"");if(t===s||t.startsWith(`${s}/`)){let i=n.querySelector(`#${o.outlet}`)||n.querySelector(`.${o.outlet}`);i instanceof HTMLElement&&o.element&&o.element(i)}})})}var he=async()=>{let n="https://cdn.jsdelivr.net/npm/brython@3/brython.min.js",e="https://cdn.jsdelivr.net/npm/brython@3/brython_stdlib.js",t=r=>new Promise((o,s)=>{let i=document.createElement("script");i.src=r,i.onload=()=>o(),i.onerror=()=>s(new Error(`Failed to load ${r}`)),document.head.appendChild(i)});await t(n),await t(e),typeof window.brython=="function"?window.brython():console.error("Brython did not load correctly.")},ye=n=>new Promise((e,t)=>{let r=document.createElement("script");r.type="text/python",r.src=`/src/python/${n}`,r.onload=()=>e(),r.onerror=()=>t(new Error(`Failed to load ${n}`)),document.body.appendChild(r)});function Te(n){let e=null;return async(t,r)=>{try{if(!e){let o=await n();e=o.default||o}if(typeof e=="function")return e(t,r);if(e instanceof HTMLElement){let o=e.cloneNode(!0);return t?.appendChild(o),o}if(typeof e=="object"&&e!==null&&"render"in e&&typeof e.render=="function")return e.render(t,r);console.warn("useTSLazy: Unsupported module type",e)}catch(o){console.error("useTSLazy failed:",o)}}}var Se=n=>typeof window>"u"?{isDOM:null}:{isDOM:n||document.body};import{debounce as Ge}from"lodash-es";var U=n=>n;typeof window<"u"&&typeof document<"u"&&(U=n=>{let e=document.createElement("div");return e.innerText=n,e.innerHTML});var Ye=n=>{(n?Array.isArray(n)?n:n instanceof HTMLAnchorElement?[n]:Array.from(n):Array.from(document.querySelectorAll("a"))).forEach(t=>{if(!t||t.dataset.anchorEnhanced==="true")return;t.dataset.anchorEnhanced="true";let r=t.getAttribute("class")||"";t.setAttribute("class",U(r));let o=t.getAttribute("aria-label");o&&t.setAttribute("aria-label",U(o));let s=t.querySelector(":scope > *");s&&(t.innerHTML="",t.appendChild(s));let i=t.getAttribute("href")||"";if(!i.startsWith("#")){try{if(new URL(i,window.location.href).origin!==window.location.origin)return}catch{return}t.addEventListener("click",a=>{a.preventDefault();let l=t.getAttribute("href")||"";try{let u=new URL(l,window.location.href);window.history.pushState({},"",u.pathname+u.search+u.hash),window.dispatchEvent(new PopStateEvent("popstate"))}catch(u){console.error("Invalid URL in anchor:",l,u)}})}})},Xe=Ge(Ye,50),k=n=>{Xe(n)};var Ee=n=>{if(!n)return;let e=P("a",n);k(e)};var ve=n=>{let e=n,t=[];return[()=>e,i=>{e=typeof i=="function"?i(e):i,t.forEach(a=>a(e))},i=>{t.push(i),i(e)}]};function we(n,e,t){let r=()=>{n.textContent=e().toString(),t?.(e())};r();let o=e.set;o&&(e.set=s=>{o(s),r()})}function Le(n){let[e,t,r]=ve(n),o=[],s=(()=>e());return s.set=i=>{t(i),o.forEach(a=>a(s()))},s.bind=i=>we(i,s),s.subscribe=i=>{o.push(i),i(s())},s}function Re(n,e){let t={deps:e.map(o=>typeof o=="function"?o():o)},r=n();typeof r=="function"&&(t.cleanup=r),e.forEach((o,s)=>{typeof o=="function"&&"bind"in o&&o.subscribe?.(()=>{let a=o(),l=t.deps[s];if(a!==l){t.cleanup?.(),t.deps[s]=a;let u=n();typeof u=="function"&&(t.cleanup=u)}})})}var f={params:{},query:{}},j=new Set;function Je(){return{params:{...f.params},query:{...f.query}}}function x(n,e){let t=Object.keys(n),r=Object.keys(e);if(t.length!==r.length)return!1;for(let o of t)if(n[o]!==e[o])return!1;return!0}function L(){let n=Je();j.forEach(e=>e(n))}function Ze(n){let e={};if(!n)return e;let t=n.startsWith("?")?n.slice(1):n;for(let r of t.split("&")){if(!r)continue;let[o,s]=r.split("=");o&&(e[decodeURIComponent(o)]=decodeURIComponent(s||""))}return e}function et(n){let e=new URLSearchParams;for(let r in n){let o=n[r];o!=null&&o!==""&&e.set(r,o)}let t=e.toString();return t?`?${t}`:""}function q(){if(typeof window>"u")return;let n=window.location.pathname,e=window.location.hash,t=et(f.query);history.replaceState({},"",n+t+e)}var W={getState(){return{params:f.params,query:f.query,getParam:n=>f.params[n],getQuery:n=>f.query[n],setFromPattern(n){if(typeof window>"u")return;let e=n.match(/:([^/]+)/g)?.map(o=>o.slice(1))||[],t=window.location.pathname.split("/").filter(Boolean),r={};e.forEach((o,s)=>{r[o]=t[s]}),x(f.params,r)||(f.params=r,L())},setFromPatternValues(n,e){let t={};n.forEach((r,o)=>{t[r]=e[o]}),x(f.params,t)||(f.params=t,L())},setQuery(n){let e={...f.query,...n};x(f.query,e)||(f.query=e,q(),L())},replaceQuery(n){x(f.query,n)||(f.query={...n},q(),L())},removeQuery(n){if(!(n in f.query))return;let e={...f.query};delete e[n],f.query=e,q(),L()},clearQuery(){Object.keys(f.query).length!==0&&(f.query={},q(),L())},setQueryFromURL(n){let e=Ze(n);x(f.query,e)||(f.query=e,L())},subscribe(n){return j.add(n),()=>j.delete(n)}}}};typeof window<"u"&&window.addEventListener("popstate",()=>{W.getState().setQueryFromURL(window.location.search)});import be from"dompurify";import{createStore as tt}from"zustand/vanilla";import nt from"dompurify";var w=tt(n=>({params:{},query:{},setParams:e=>n(()=>({params:Me(e)})),setQuery:e=>n(()=>({query:Me(e)}))}));function Me(n){let e={};for(let t in n)e[t]=nt.sanitize(n[t]);return e}var Q=class{routes=[];expectedParams;apiFetcher;constructor(e,t,r){this.routes=e,this.expectedParams=new Set(t),this.apiFetcher=r,window.addEventListener("popstate",this.handlePopState.bind(this)),this.handlePopState()}handlePopState(){let e=window.location.pathname,t=window.location.search,r=this.parseQueryParams(t);if(e.startsWith("/api")&&this.apiFetcher){let i=e.replace("/api/","").split("/")[0],a=Object.fromEntries(new URLSearchParams(t));this.apiFetcher(i,a).then(l=>console.log("API response:",l)).catch(l=>console.error("API error:",l));return}let o=this.findMatchingRoute(e,this.routes);if(o){if(o.routeto){this.navigate(o.routeto);return}let s=this.filterAndSanitizeParams(o.params);w.getState().setParams(s),w.getState().setQuery(r);let i=document.createElement("div");if(o.element?.(i,s,r),o.children){let a=e.slice(o.path.length),l=i.querySelector("#child");l&&this.renderChildren(o.children,a,l,s,r)}}else{let s=this.findMatchingRoute("*",this.routes);if(s){let i=this.filterAndSanitizeParams(s.params);w.getState().setParams(i),w.getState().setQuery(r);let a=document.createElement("div");s.element?.(a,i,r)}}}renderChildren(e,t,r,o,s){if(!e||e.length===0){let a=r.querySelector("#child");a&&a.remove();return}let i=this.findMatchingRoute(t,e);if(i){let a=document.createElement("div");a.id="child";let l={...o,...i.params},u=this.filterAndSanitizeParams(l);if(w.getState().setParams(u),w.getState().setQuery(s),i.element?.(a,u,s),r.appendChild(a),i.children){let c=t.slice(i.path.length);this.renderChildren(i.children,c,a,u,s)}}}parseQueryParams(e){let t={},r=new URLSearchParams(e);for(let[o,s]of r.entries())this.expectedParams.has(o)&&(t[o]=be.sanitize(s));return t}findMatchingRoute(e,t,r={}){for(let o of t){let s=o.path;if(s==="*")return o;{let a=[],l=s.replace(/:[^\s/]+/g,d=>(a.push(d.substring(1)),"([^\\s/]+)")),u=new RegExp(`^${l}(?:/|$)`),c=e.match(u);if(c){let d={...r};if(a.forEach((g,p)=>{d[g]=c[p+1]??""}),o.children){let g=e.slice(c[0].length),p=this.findMatchingRoute(g,o.children,d);if(p)return p}return{...o,params:d}}}}}filterAndSanitizeParams(e){if(!e)return{};let t={};for(let r in e)this.expectedParams.has(r)&&(t[r]=be.sanitize(e[r]??""));return t}navigate(e){history.pushState(null,"",e),this.handlePopState()}addRoute(e){this.routes.push(e)}};var rt=()=>({name:"ts-filebased-router",async buildStart(){let n=await import("fs/promises"),e=await import("path"),t=await import("./esm-KRNKVVL7.js"),r=e.resolve("src/pages"),o=e.resolve("src/gen"),s=e.resolve("src/routes"),i=e.join(o,"types.ts"),a=e.join(o,"tsrouter.gen.ts"),l=e.join(s,"__root.ts"),u=process.env.NODE_ENV!=="production",c=async m=>n.mkdir(m,{recursive:!0}).catch(()=>{}),d=m=>m.charAt(0).toUpperCase()+m.slice(1),g=m=>{let h="/"+e.relative(r,m).replace(/\\/g,"/");return h=h.replace(/\.ts$/,"").replace(/\/index$/,"")||"/",h.replace(/\[\.\.\.(.+?)\]/g,"*").replace(/\[(.+?)\]/g,":$1")},p=m=>m.replace(/^\//,"").split("/").map(h=>h.startsWith(":")?d(h.slice(1)):h.replace(/\b\w/g,S=>S.toUpperCase()).replace(/[-_]/g,"")).filter(Boolean).join("")||"Index",A=async m=>{let h=await n.readdir(m,{withFileTypes:!0}),S=[];for(let R of h){let b=e.join(m,R.name);R.isDirectory()?S=S.concat(await A(b)):R.isFile()&&R.name.endsWith(".ts")&&S.push({file:b,route:g(b),name:p(g(b))})}return S},v=async()=>{let m=`// AUTO-GENERATED TYPES
|
|
2
|
+
export type Cleanup = void | (() => void);
|
|
3
|
+
export type RenderResult = Cleanup | Promise<Cleanup> | string;
|
|
4
|
+
export type Component = (DOM: HTMLElement) => RenderResult;
|
|
5
|
+
export type Module = { default: Component };
|
|
6
|
+
`;await c(o),await n.writeFile(i,m,"utf-8")},M=async()=>{let m=await A(r),h=m.find(y=>y.route==="/notfound"),S=m.filter(y=>y.route!=="/notfound");for(let y of m)if(!(await n.readFile(y.file,"utf-8")).trim()){let C=y.route.includes(":"),B=C?y.route.split("/").filter(N=>N.startsWith(":")).map(N=>N.slice(1)):[],xe=C?`const { ${B.join(", ")} } = useTSExtractParams("${y.route}");`:"";await n.writeFile(y.file,`import { html, useTSElements, useTSMetaData${C?", useTSExtractParams":""} } from "@devwareng/vanilla-ts";
|
|
7
|
+
import type { RenderResult, Module } from "../gen/types";
|
|
8
|
+
|
|
9
|
+
const ${y.name}: Module["default"] = (DOM: HTMLElement): RenderResult => {
|
|
10
|
+
useTSMetaData({
|
|
11
|
+
title: "${y.name.toLowerCase()}",
|
|
12
|
+
description: "${y.name.toLowerCase()}",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
${xe}
|
|
16
|
+
|
|
17
|
+
return useTSElements(DOM, html\`
|
|
18
|
+
<div>
|
|
19
|
+
<h1>${y.name.toLowerCase()}</h1>
|
|
20
|
+
${C?`<pre>\${${B.join("}, ${")}}</pre>`:""}
|
|
21
|
+
</div>
|
|
22
|
+
\`);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default ${y.name};
|
|
26
|
+
`,"utf-8")}let R=S.map(y=>{let K="../pages/"+e.relative(r,y.file).replace(/\\/g,"/").replace(/\.ts$/,"");return`{ path: "${y.route}", name: "${y.name}", component: () => import("${K}") as Promise<Module> }`}).join(`,
|
|
27
|
+
`),Pe=`// AUTO-GENERATED ROUTER
|
|
28
|
+
import { useTSElements, useTSParams, html } from "@devwareng/vanilla-ts";
|
|
29
|
+
import type { Module, Component } from "./types";
|
|
30
|
+
|
|
31
|
+
// -----------------------------
|
|
32
|
+
${h?`export const NotFound = async (DOM: HTMLElement) => {
|
|
33
|
+
const mod = await import("../pages/${e.relative(r,h.file).replace(/\\/g,"/").replace(/\\.ts$/,"")}") as import("./types").Module;
|
|
34
|
+
return mod.default(DOM);
|
|
35
|
+
};`:"export const NotFound = (DOM: HTMLElement) =>\n useTSElements(DOM, html`<h1>404 - Page Not Found</h1>`);"}
|
|
36
|
+
|
|
37
|
+
// -----------------------------
|
|
38
|
+
export const routeTree: {
|
|
39
|
+
path: string;
|
|
40
|
+
name: string;
|
|
41
|
+
component: () => Promise<Module>;
|
|
42
|
+
}[] = [
|
|
43
|
+
${R}
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
// -----------------------------
|
|
47
|
+
function matchRoute(pathname: string) {
|
|
48
|
+
for (const r of routeTree) {
|
|
49
|
+
const routeSegments = r.path.split("/").filter(Boolean);
|
|
50
|
+
const pathSegments = pathname.split("/").filter(Boolean);
|
|
51
|
+
|
|
52
|
+
if (
|
|
53
|
+
routeSegments.length !== pathSegments.length &&
|
|
54
|
+
!routeSegments.includes("*")
|
|
55
|
+
)
|
|
56
|
+
continue;
|
|
57
|
+
|
|
58
|
+
let matched = true;
|
|
59
|
+
const params: Record<string, string> = {};
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
62
|
+
const routeSeg = routeSegments[i];
|
|
63
|
+
const pathSeg = pathSegments[i];
|
|
64
|
+
|
|
65
|
+
if (!routeSeg) continue;
|
|
66
|
+
if (routeSeg === "*") break;
|
|
67
|
+
|
|
68
|
+
if (!pathSeg) {
|
|
69
|
+
matched = false;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (routeSeg.startsWith(":")) {
|
|
74
|
+
params[routeSeg.slice(1)] = pathSeg;
|
|
75
|
+
} else if (routeSeg !== pathSeg) {
|
|
76
|
+
matched = false;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (matched) return { route: r, params };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// -----------------------------
|
|
88
|
+
export async function createRouter(DOM: HTMLElement) {
|
|
89
|
+
const moduleCache = new WeakMap<Function, Component>();
|
|
90
|
+
|
|
91
|
+
async function loadModule(loader: () => Promise<Module>): Promise<Component> {
|
|
92
|
+
const cached = moduleCache.get(loader);
|
|
93
|
+
if (cached) return cached;
|
|
94
|
+
|
|
95
|
+
const mod = await loader();
|
|
96
|
+
const component = mod.default;
|
|
97
|
+
|
|
98
|
+
moduleCache.set(loader, component);
|
|
99
|
+
return component;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let currentComponentUnmount: (() => void) | null = null;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
navigate: async (fullPath: string, push = true) => {
|
|
106
|
+
const url = new URL(fullPath, window.location.origin);
|
|
107
|
+
const pathname = url.pathname;
|
|
108
|
+
|
|
109
|
+
const matched = matchRoute(pathname);
|
|
110
|
+
|
|
111
|
+
let componentLoader: () => Promise<Module>;
|
|
112
|
+
let params: Record<string, string> = {};
|
|
113
|
+
|
|
114
|
+
if (matched) {
|
|
115
|
+
componentLoader = matched.route.component;
|
|
116
|
+
params = matched.params;
|
|
117
|
+
} else {
|
|
118
|
+
componentLoader = async () => ({ default: NotFound } as Module);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (push) history.pushState(null, "", url.pathname + url.search);
|
|
122
|
+
|
|
123
|
+
useTSParams.getState().setFromPatternValues(
|
|
124
|
+
Object.keys(params),
|
|
125
|
+
Object.values(params)
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const query: Record<string, string> = {};
|
|
129
|
+
url.searchParams.forEach((v, k) => (query[k] = v));
|
|
130
|
+
useTSParams.getState().setQuery(query);
|
|
131
|
+
|
|
132
|
+
currentComponentUnmount?.();
|
|
133
|
+
|
|
134
|
+
const componentFn = await loadModule(componentLoader);
|
|
135
|
+
const result = await componentFn(DOM);
|
|
136
|
+
|
|
137
|
+
if (typeof result === "string") {
|
|
138
|
+
DOM.innerHTML = result;
|
|
139
|
+
currentComponentUnmount = null;
|
|
140
|
+
} else {
|
|
141
|
+
currentComponentUnmount =
|
|
142
|
+
typeof result === "function" ? result : null;
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
`;await c(o),await c(s),await n.writeFile(a,Pe,"utf-8"),await n.writeFile(l,T(),"utf-8")},T=()=>`
|
|
148
|
+
import { createRouter } from "../gen/tsrouter.gen";
|
|
149
|
+
import { useTSParams, initializeRoute } from "@devwareng/vanilla-ts";
|
|
150
|
+
|
|
151
|
+
export const Router = async (DOM: HTMLElement) => {
|
|
152
|
+
useTSParams.getState();
|
|
153
|
+
const router = await createRouter(DOM);
|
|
154
|
+
await initializeRoute(router);
|
|
155
|
+
return router;
|
|
156
|
+
};
|
|
157
|
+
`;await c(r),await v(),await M(),u&&t.watch(r,{ignoreInitial:!0}).on("all",async(h,S)=>{S.endsWith(".ts")&&(await M(),console.log("\u267B\uFE0F TS Router regenerated"))}),console.log("\u{1F7E2} TS Filebased Router initialized")}});var ot=async n=>{typeof window>"u"||typeof document>"u"||(await n.navigate(window.location.pathname+window.location.search,!1),window.addEventListener("popstate",()=>{n.navigate(window.location.pathname+window.location.search,!1)}),document.addEventListener("click",e=>{let t=e;if(t.defaultPrevented||t.button!==0||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return;let r=t.target.closest("a");if(!r)return;let o=new URL(r.href);o.origin===window.location.origin&&(t.preventDefault(),n.navigate(o.pathname+o.search))}))};export{rt as TSFilebasedRouter,Q as TSRouter,qe as createClientFunc,Le as createSignal,ke as createTSServerFunc,V as html,ot as initializeRoute,ye as loadPyFiles,$e as mapper,ge as renderChildRoutes,k as useAnchor,ce as useAnchorSingle,ie as useInitialDOM,me as useTSAuth,de as useTSCollection,$ as useTSComponent,_ as useTSElementEach,oe as useTSElements,X as useTSEvent,Z as useTSEventAll,J as useTSExtractParams,Te as useTSLazy,ue as useTSMetaData,pe as useTSNavigate,Ee as useTSNoReload,fe as useTSOutlet,D as useTSParams,Y as useTSPurifier,W as useTSQuery,Re as useTSReactor,Se as useTSSSRHydration,P as useTSSelect,he as useTSloadBrython};
|