what-framework 0.1.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/index.d.ts +252 -0
- package/package.json +56 -0
- package/router.d.ts +128 -0
- package/server.d.ts +113 -0
- package/src/index.js +144 -0
- package/src/router.js +18 -0
- package/src/server.js +21 -0
- package/src/testing.js +4 -0
- package/testing.d.ts +103 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// What Framework - TypeScript Definitions
|
|
2
|
+
|
|
3
|
+
// --- Reactive Primitives ---
|
|
4
|
+
|
|
5
|
+
/** A reactive value container */
|
|
6
|
+
export interface Signal<T> {
|
|
7
|
+
/** Read the current value (tracks dependency if inside effect) */
|
|
8
|
+
(): T;
|
|
9
|
+
/** Update the value */
|
|
10
|
+
set(value: T | ((prev: T) => T)): void;
|
|
11
|
+
/** Read without tracking */
|
|
12
|
+
peek(): T;
|
|
13
|
+
/** Subscribe to changes */
|
|
14
|
+
subscribe(fn: (value: T) => void): () => void;
|
|
15
|
+
/** Internal marker */
|
|
16
|
+
_signal: true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Create a reactive signal */
|
|
20
|
+
export function signal<T>(initial: T): Signal<T>;
|
|
21
|
+
|
|
22
|
+
/** A derived reactive value (lazy evaluation) */
|
|
23
|
+
export interface Computed<T> {
|
|
24
|
+
(): T;
|
|
25
|
+
peek(): T;
|
|
26
|
+
_signal: true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Create a computed signal */
|
|
30
|
+
export function computed<T>(fn: () => T): Computed<T>;
|
|
31
|
+
|
|
32
|
+
/** Create a side effect that re-runs when dependencies change */
|
|
33
|
+
export function effect(fn: () => void | (() => void)): () => void;
|
|
34
|
+
|
|
35
|
+
/** Batch multiple signal updates into one flush */
|
|
36
|
+
export function batch<T>(fn: () => T): T;
|
|
37
|
+
|
|
38
|
+
/** Read signals without subscribing */
|
|
39
|
+
export function untrack<T>(fn: () => T): T;
|
|
40
|
+
|
|
41
|
+
// --- Virtual DOM ---
|
|
42
|
+
|
|
43
|
+
export interface VNode<P = any> {
|
|
44
|
+
tag: string | Component<P>;
|
|
45
|
+
props: P;
|
|
46
|
+
children: VNodeChild[];
|
|
47
|
+
key: string | number | null;
|
|
48
|
+
_vnode: true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type VNodeChild = VNode | string | number | boolean | null | undefined | VNodeChild[];
|
|
52
|
+
|
|
53
|
+
export type Component<P = {}> = (props: P & { children?: VNodeChild }) => VNode | VNodeChild;
|
|
54
|
+
|
|
55
|
+
/** Create a virtual DOM node */
|
|
56
|
+
export function h<P extends {}>(
|
|
57
|
+
tag: string | Component<P>,
|
|
58
|
+
props?: P | null,
|
|
59
|
+
...children: VNodeChild[]
|
|
60
|
+
): VNode<P>;
|
|
61
|
+
|
|
62
|
+
/** Fragment component */
|
|
63
|
+
export function Fragment(props: { children?: VNodeChild }): VNodeChild;
|
|
64
|
+
|
|
65
|
+
/** Tagged template for JSX-like syntax without build step */
|
|
66
|
+
export function html(strings: TemplateStringsArray, ...values: any[]): VNode | VNode[];
|
|
67
|
+
|
|
68
|
+
// --- DOM Mounting ---
|
|
69
|
+
|
|
70
|
+
/** Mount a VNode tree into a container */
|
|
71
|
+
export function mount(vnode: VNode, container: string | Element): () => void;
|
|
72
|
+
|
|
73
|
+
// --- Hooks ---
|
|
74
|
+
|
|
75
|
+
/** State hook - returns [value, setter] */
|
|
76
|
+
export function useState<T>(initial: T | (() => T)): [T, (value: T | ((prev: T) => T)) => void];
|
|
77
|
+
|
|
78
|
+
/** Signal hook - returns raw signal */
|
|
79
|
+
export function useSignal<T>(initial: T | (() => T)): Signal<T>;
|
|
80
|
+
|
|
81
|
+
/** Computed hook */
|
|
82
|
+
export function useComputed<T>(fn: () => T): Computed<T>;
|
|
83
|
+
|
|
84
|
+
/** Effect hook with optional dependencies */
|
|
85
|
+
export function useEffect(fn: () => void | (() => void), deps?: any[]): void;
|
|
86
|
+
|
|
87
|
+
/** Memoized value hook */
|
|
88
|
+
export function useMemo<T>(fn: () => T, deps: any[]): T;
|
|
89
|
+
|
|
90
|
+
/** Memoized callback hook */
|
|
91
|
+
export function useCallback<T extends (...args: any[]) => any>(fn: T, deps: any[]): T;
|
|
92
|
+
|
|
93
|
+
/** Ref hook */
|
|
94
|
+
export function useRef<T>(initial: T): { current: T };
|
|
95
|
+
|
|
96
|
+
/** Context hook */
|
|
97
|
+
export function useContext<T>(context: Context<T>): T;
|
|
98
|
+
|
|
99
|
+
/** Reducer hook */
|
|
100
|
+
export function useReducer<S, A>(
|
|
101
|
+
reducer: (state: S, action: A) => S,
|
|
102
|
+
initialState: S,
|
|
103
|
+
init?: (initial: S) => S
|
|
104
|
+
): [S, (action: A) => void];
|
|
105
|
+
|
|
106
|
+
/** Create a context */
|
|
107
|
+
export interface Context<T> {
|
|
108
|
+
_value: T;
|
|
109
|
+
Provider: Component<{ value: T; children?: VNodeChild }>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function createContext<T>(defaultValue: T): Context<T>;
|
|
113
|
+
|
|
114
|
+
// --- Component Utilities ---
|
|
115
|
+
|
|
116
|
+
/** Skip re-render if props are equal */
|
|
117
|
+
export function memo<P>(
|
|
118
|
+
component: Component<P>,
|
|
119
|
+
areEqual?: (prev: P, next: P) => boolean
|
|
120
|
+
): Component<P>;
|
|
121
|
+
|
|
122
|
+
/** Lazy-load a component */
|
|
123
|
+
export function lazy<P>(
|
|
124
|
+
loader: () => Promise<{ default: Component<P> } | Component<P>>
|
|
125
|
+
): Component<P>;
|
|
126
|
+
|
|
127
|
+
/** Suspense boundary for lazy components */
|
|
128
|
+
export function Suspense(props: {
|
|
129
|
+
fallback: VNodeChild;
|
|
130
|
+
children?: VNodeChild;
|
|
131
|
+
}): VNode;
|
|
132
|
+
|
|
133
|
+
/** Error boundary for catching component errors */
|
|
134
|
+
export function ErrorBoundary(props: {
|
|
135
|
+
fallback: VNodeChild | ((props: { error: Error; reset: () => void }) => VNodeChild);
|
|
136
|
+
onError?: (error: Error) => void;
|
|
137
|
+
children?: VNodeChild;
|
|
138
|
+
}): VNode;
|
|
139
|
+
|
|
140
|
+
// --- Store ---
|
|
141
|
+
|
|
142
|
+
export interface StoreDefinition {
|
|
143
|
+
[key: string]: any;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type Store<T extends StoreDefinition> = {
|
|
147
|
+
[K in keyof T]: T[K] extends (...args: any[]) => any ? T[K] : T[K];
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/** Create a global reactive store */
|
|
151
|
+
export function createStore<T extends StoreDefinition>(definition: T): () => Store<T>;
|
|
152
|
+
|
|
153
|
+
/** Create a simple global atom */
|
|
154
|
+
export function atom<T>(initial: T): Signal<T>;
|
|
155
|
+
|
|
156
|
+
// --- Utilities ---
|
|
157
|
+
|
|
158
|
+
/** Conditional rendering helper */
|
|
159
|
+
export function show<T extends VNodeChild>(condition: boolean, vnode: T, fallback?: VNodeChild): T | VNodeChild;
|
|
160
|
+
|
|
161
|
+
/** List rendering helper with optional key function */
|
|
162
|
+
export function each<T>(
|
|
163
|
+
list: T[],
|
|
164
|
+
fn: (item: T, index: number) => VNode,
|
|
165
|
+
keyFn?: (item: T, index: number) => string | number
|
|
166
|
+
): VNode[];
|
|
167
|
+
|
|
168
|
+
/** Conditional class names */
|
|
169
|
+
export function cls(...args: (string | false | null | undefined | Record<string, boolean>)[]): string;
|
|
170
|
+
|
|
171
|
+
/** Convert style object to string */
|
|
172
|
+
export function style(obj: string | Record<string, string | number | null | undefined>): string;
|
|
173
|
+
|
|
174
|
+
/** Debounce a function */
|
|
175
|
+
export function debounce<T extends (...args: any[]) => any>(fn: T, ms: number): T;
|
|
176
|
+
|
|
177
|
+
/** Throttle a function */
|
|
178
|
+
export function throttle<T extends (...args: any[]) => any>(fn: T, ms: number): T;
|
|
179
|
+
|
|
180
|
+
/** Reactive media query */
|
|
181
|
+
export function useMediaQuery(query: string): Signal<boolean>;
|
|
182
|
+
|
|
183
|
+
/** Signal synced with localStorage */
|
|
184
|
+
export function useLocalStorage<T>(key: string, initial: T): Signal<T>;
|
|
185
|
+
|
|
186
|
+
/** Render children in a different DOM container */
|
|
187
|
+
export function Portal(props: { target: string | Element; children?: VNodeChild }): VNode | null;
|
|
188
|
+
|
|
189
|
+
/** CSS transition helper */
|
|
190
|
+
export function transition(name: string, active: boolean): { class: string };
|
|
191
|
+
|
|
192
|
+
// --- Head Management ---
|
|
193
|
+
|
|
194
|
+
/** Manage document head */
|
|
195
|
+
export function Head(props: {
|
|
196
|
+
title?: string;
|
|
197
|
+
meta?: Record<string, string>[];
|
|
198
|
+
link?: Record<string, string>[];
|
|
199
|
+
script?: Record<string, string>[];
|
|
200
|
+
children?: VNodeChild;
|
|
201
|
+
}): null;
|
|
202
|
+
|
|
203
|
+
/** Clear managed head elements */
|
|
204
|
+
export function clearHead(): void;
|
|
205
|
+
|
|
206
|
+
// --- DOM Scheduler ---
|
|
207
|
+
|
|
208
|
+
/** Schedule a DOM read operation */
|
|
209
|
+
export function scheduleRead(fn: () => void): () => void;
|
|
210
|
+
|
|
211
|
+
/** Schedule a DOM write operation */
|
|
212
|
+
export function scheduleWrite(fn: () => void): () => void;
|
|
213
|
+
|
|
214
|
+
/** Flush all pending scheduler operations */
|
|
215
|
+
export function flushScheduler(): void;
|
|
216
|
+
|
|
217
|
+
/** Measure DOM (returns promise) */
|
|
218
|
+
export function measure<T>(fn: () => T): Promise<T>;
|
|
219
|
+
|
|
220
|
+
/** Mutate DOM (returns promise) */
|
|
221
|
+
export function mutate(fn: () => void): Promise<void>;
|
|
222
|
+
|
|
223
|
+
/** Effect that batches DOM operations */
|
|
224
|
+
export function useScheduledEffect(
|
|
225
|
+
readFn: () => any,
|
|
226
|
+
writeFn?: (data: any) => void
|
|
227
|
+
): () => void;
|
|
228
|
+
|
|
229
|
+
/** Returns promise that resolves on next animation frame */
|
|
230
|
+
export function nextFrame(): Promise<void> & { cancel: () => void };
|
|
231
|
+
|
|
232
|
+
/** Debounced requestAnimationFrame */
|
|
233
|
+
export function raf(key: string, fn: () => void): void;
|
|
234
|
+
|
|
235
|
+
/** Observe element resize */
|
|
236
|
+
export function onResize(
|
|
237
|
+
element: Element,
|
|
238
|
+
callback: (rect: DOMRectReadOnly) => void
|
|
239
|
+
): () => void;
|
|
240
|
+
|
|
241
|
+
/** Observe element intersection */
|
|
242
|
+
export function onIntersect(
|
|
243
|
+
element: Element,
|
|
244
|
+
callback: (entry: IntersectionObserverEntry) => void,
|
|
245
|
+
options?: IntersectionObserverInit
|
|
246
|
+
): () => void;
|
|
247
|
+
|
|
248
|
+
/** Smooth scroll to element */
|
|
249
|
+
export function smoothScrollTo(
|
|
250
|
+
element: Element,
|
|
251
|
+
options?: { duration?: number; easing?: (t: number) => number }
|
|
252
|
+
): Promise<void>;
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "what-framework",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The closest framework to vanilla JS — signals, components, islands, SSR",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"module": "src/index.js",
|
|
8
|
+
"types": "index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./index.d.ts",
|
|
12
|
+
"import": "./src/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./router": {
|
|
15
|
+
"types": "./router.d.ts",
|
|
16
|
+
"import": "./src/router.js"
|
|
17
|
+
},
|
|
18
|
+
"./server": {
|
|
19
|
+
"types": "./server.d.ts",
|
|
20
|
+
"import": "./src/server.js"
|
|
21
|
+
},
|
|
22
|
+
"./testing": {
|
|
23
|
+
"types": "./testing.d.ts",
|
|
24
|
+
"import": "./src/testing.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"src",
|
|
29
|
+
"index.d.ts",
|
|
30
|
+
"router.d.ts",
|
|
31
|
+
"server.d.ts",
|
|
32
|
+
"testing.d.ts"
|
|
33
|
+
],
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"keywords": [
|
|
36
|
+
"framework",
|
|
37
|
+
"signals",
|
|
38
|
+
"reactive",
|
|
39
|
+
"islands",
|
|
40
|
+
"ssr",
|
|
41
|
+
"vanilla-js",
|
|
42
|
+
"lightweight",
|
|
43
|
+
"router",
|
|
44
|
+
"components"
|
|
45
|
+
],
|
|
46
|
+
"author": "",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/aspect/what-fw.git"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/aspect/what-fw/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/aspect/what-fw#readme"
|
|
56
|
+
}
|
package/router.d.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// What Framework Router - TypeScript Definitions
|
|
2
|
+
|
|
3
|
+
import { VNode, VNodeChild, Component, Signal, Computed } from './index';
|
|
4
|
+
|
|
5
|
+
// --- Route State ---
|
|
6
|
+
|
|
7
|
+
export interface RouteState {
|
|
8
|
+
/** Current full URL */
|
|
9
|
+
readonly url: string;
|
|
10
|
+
/** Current pathname */
|
|
11
|
+
readonly path: string;
|
|
12
|
+
/** Route parameters */
|
|
13
|
+
readonly params: Record<string, string>;
|
|
14
|
+
/** Query parameters */
|
|
15
|
+
readonly query: Record<string, string>;
|
|
16
|
+
/** URL hash */
|
|
17
|
+
readonly hash: string;
|
|
18
|
+
/** Navigation in progress */
|
|
19
|
+
readonly isNavigating: boolean;
|
|
20
|
+
/** Navigation error if any */
|
|
21
|
+
readonly error: Error | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const route: RouteState;
|
|
25
|
+
|
|
26
|
+
// --- Navigation ---
|
|
27
|
+
|
|
28
|
+
export interface NavigateOptions {
|
|
29
|
+
/** Replace current history entry */
|
|
30
|
+
replace?: boolean;
|
|
31
|
+
/** History state object */
|
|
32
|
+
state?: any;
|
|
33
|
+
/** Use View Transitions API */
|
|
34
|
+
transition?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Navigate to a new URL */
|
|
38
|
+
export function navigate(to: string, options?: NavigateOptions): Promise<void>;
|
|
39
|
+
|
|
40
|
+
/** Redirect (throws to navigate) */
|
|
41
|
+
export function redirect(to: string, options?: NavigateOptions): never;
|
|
42
|
+
|
|
43
|
+
// --- Route Configuration ---
|
|
44
|
+
|
|
45
|
+
export interface RouteConfig {
|
|
46
|
+
/** URL path pattern */
|
|
47
|
+
path: string;
|
|
48
|
+
/** Page component */
|
|
49
|
+
component: Component<RouteComponentProps>;
|
|
50
|
+
/** Layout wrapper */
|
|
51
|
+
layout?: Component<LayoutProps>;
|
|
52
|
+
/** Loading component */
|
|
53
|
+
loading?: Component<{}>;
|
|
54
|
+
/** Error component */
|
|
55
|
+
error?: Component<{ error: Error }>;
|
|
56
|
+
/** Route middleware */
|
|
57
|
+
middleware?: RouteMiddleware[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface RouteComponentProps {
|
|
61
|
+
params: Record<string, string>;
|
|
62
|
+
query: Record<string, string>;
|
|
63
|
+
route: RouteConfig;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface LayoutProps {
|
|
67
|
+
params: Record<string, string>;
|
|
68
|
+
query: Record<string, string>;
|
|
69
|
+
children?: VNodeChild;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type RouteMiddleware = (props: RouteComponentProps) => boolean | Promise<boolean>;
|
|
73
|
+
|
|
74
|
+
// --- Router Component ---
|
|
75
|
+
|
|
76
|
+
export interface RouterProps {
|
|
77
|
+
routes: RouteConfig[];
|
|
78
|
+
fallback?: Component<{}>;
|
|
79
|
+
globalLayout?: Component<{ children?: VNodeChild }>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function Router(props: RouterProps): VNode;
|
|
83
|
+
|
|
84
|
+
// --- Link Component ---
|
|
85
|
+
|
|
86
|
+
export interface LinkProps {
|
|
87
|
+
href: string;
|
|
88
|
+
class?: string;
|
|
89
|
+
className?: string;
|
|
90
|
+
replace?: boolean;
|
|
91
|
+
prefetch?: boolean;
|
|
92
|
+
activeClass?: string;
|
|
93
|
+
exactActiveClass?: string;
|
|
94
|
+
transition?: boolean;
|
|
95
|
+
children?: VNodeChild;
|
|
96
|
+
[key: string]: any;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function Link(props: LinkProps): VNode;
|
|
100
|
+
export function NavLink(props: LinkProps): VNode;
|
|
101
|
+
|
|
102
|
+
// --- Route Helpers ---
|
|
103
|
+
|
|
104
|
+
/** Define routes from object config */
|
|
105
|
+
export function defineRoutes(config: Record<string, Component | Partial<RouteConfig>>): RouteConfig[];
|
|
106
|
+
|
|
107
|
+
// --- Prefetch ---
|
|
108
|
+
|
|
109
|
+
export function prefetchRoute(href: string): void;
|
|
110
|
+
|
|
111
|
+
// --- Navigation Hooks ---
|
|
112
|
+
|
|
113
|
+
export function beforeNavigate(fn: (to: string, from: string) => boolean | Promise<boolean>): () => void;
|
|
114
|
+
export function afterNavigate(fn: (to: string, from: string) => void): () => void;
|
|
115
|
+
|
|
116
|
+
// --- useRoute Hooks ---
|
|
117
|
+
|
|
118
|
+
export function useRoute(): {
|
|
119
|
+
path: Computed<string>;
|
|
120
|
+
params: Computed<Record<string, string>>;
|
|
121
|
+
query: Computed<Record<string, string>>;
|
|
122
|
+
hash: Computed<string>;
|
|
123
|
+
isNavigating: Computed<boolean>;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export function useParams<T extends Record<string, string> = Record<string, string>>(): T;
|
|
127
|
+
export function useSearch<T extends Record<string, string> = Record<string, string>>(): T;
|
|
128
|
+
export function useNavigate(): typeof navigate;
|
package/server.d.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// What Framework Server - TypeScript Definitions
|
|
2
|
+
|
|
3
|
+
import { VNode, VNodeChild, Signal } from './index';
|
|
4
|
+
|
|
5
|
+
// --- SSR ---
|
|
6
|
+
|
|
7
|
+
/** Render VNode tree to HTML string */
|
|
8
|
+
export function renderToString(vnode: VNode): string;
|
|
9
|
+
|
|
10
|
+
/** Render VNode tree as async iterator for streaming */
|
|
11
|
+
export function renderToStream(vnode: VNode): AsyncGenerator<string>;
|
|
12
|
+
|
|
13
|
+
/** Render a full page with document wrapper */
|
|
14
|
+
export function renderPage(vnode: VNode, options?: {
|
|
15
|
+
title?: string;
|
|
16
|
+
meta?: Record<string, string>;
|
|
17
|
+
scripts?: string[];
|
|
18
|
+
styles?: string[];
|
|
19
|
+
mode?: 'static' | 'server' | 'client' | 'hybrid';
|
|
20
|
+
}): string;
|
|
21
|
+
|
|
22
|
+
// --- Page Configuration ---
|
|
23
|
+
|
|
24
|
+
export interface PageConfig {
|
|
25
|
+
/** Rendering mode */
|
|
26
|
+
mode?: 'static' | 'server' | 'client' | 'hybrid';
|
|
27
|
+
/** Page title */
|
|
28
|
+
title?: string;
|
|
29
|
+
/** Meta tags */
|
|
30
|
+
meta?: Record<string, string>;
|
|
31
|
+
/** Page component */
|
|
32
|
+
component: (data?: any) => VNode;
|
|
33
|
+
/** Islands to hydrate */
|
|
34
|
+
islands?: string[];
|
|
35
|
+
/** Scripts to load */
|
|
36
|
+
scripts?: string[];
|
|
37
|
+
/** Stylesheets to load */
|
|
38
|
+
styles?: string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function definePage(config: Partial<PageConfig>): PageConfig;
|
|
42
|
+
|
|
43
|
+
// --- Islands ---
|
|
44
|
+
|
|
45
|
+
export type IslandMode = 'static' | 'idle' | 'visible' | 'load' | 'media' | 'action';
|
|
46
|
+
|
|
47
|
+
export const IslandModes: {
|
|
48
|
+
STATIC: 'static';
|
|
49
|
+
IDLE: 'idle';
|
|
50
|
+
VISIBLE: 'visible';
|
|
51
|
+
LOAD: 'load';
|
|
52
|
+
MEDIA: 'media';
|
|
53
|
+
ACTION: 'action';
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export interface IslandOptions {
|
|
57
|
+
/** Hydration mode */
|
|
58
|
+
mode?: IslandMode;
|
|
59
|
+
/** Media query for 'media' mode */
|
|
60
|
+
media?: string;
|
|
61
|
+
/** Priority (higher = hydrate first) */
|
|
62
|
+
priority?: number;
|
|
63
|
+
/** Shared stores this island uses */
|
|
64
|
+
stores?: string[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Register an island component */
|
|
68
|
+
export function island(
|
|
69
|
+
name: string,
|
|
70
|
+
loader: () => Promise<any>,
|
|
71
|
+
options?: IslandOptions
|
|
72
|
+
): void;
|
|
73
|
+
|
|
74
|
+
/** Island component wrapper for SSR */
|
|
75
|
+
export function Island(props: {
|
|
76
|
+
name: string;
|
|
77
|
+
props?: Record<string, any>;
|
|
78
|
+
mode?: IslandMode;
|
|
79
|
+
priority?: number;
|
|
80
|
+
stores?: string[];
|
|
81
|
+
children?: VNodeChild;
|
|
82
|
+
}): VNode;
|
|
83
|
+
|
|
84
|
+
/** Hydrate all islands on the page */
|
|
85
|
+
export function hydrateIslands(): void;
|
|
86
|
+
|
|
87
|
+
// --- Server Actions ---
|
|
88
|
+
|
|
89
|
+
export interface ActionOptions {
|
|
90
|
+
id?: string;
|
|
91
|
+
onError?: (error: Error) => void;
|
|
92
|
+
onSuccess?: (result: any) => void;
|
|
93
|
+
revalidate?: string[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Create a server action */
|
|
97
|
+
export function createAction<T extends any[], R>(
|
|
98
|
+
fn: (...args: T) => Promise<R>,
|
|
99
|
+
options?: ActionOptions
|
|
100
|
+
): (...args: T) => Promise<R>;
|
|
101
|
+
|
|
102
|
+
/** Hook for using server actions */
|
|
103
|
+
export interface UseActionResult<T extends any[], R> {
|
|
104
|
+
trigger: (...args: T) => Promise<R>;
|
|
105
|
+
isPending: () => boolean;
|
|
106
|
+
error: () => Error | null;
|
|
107
|
+
data: () => R | null;
|
|
108
|
+
reset: () => void;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function useAction<T extends any[], R>(
|
|
112
|
+
actionFn: (...args: T) => Promise<R>
|
|
113
|
+
): UseActionResult<T, R>;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// What Framework - The closest framework to vanilla JS
|
|
2
|
+
// Main entry point - exports everything from core
|
|
3
|
+
|
|
4
|
+
// Reactivity
|
|
5
|
+
export {
|
|
6
|
+
signal,
|
|
7
|
+
computed,
|
|
8
|
+
effect,
|
|
9
|
+
batch,
|
|
10
|
+
untrack,
|
|
11
|
+
} from '../../core/src/reactive.js';
|
|
12
|
+
|
|
13
|
+
// Virtual DOM
|
|
14
|
+
export {
|
|
15
|
+
h,
|
|
16
|
+
Fragment,
|
|
17
|
+
jsx,
|
|
18
|
+
jsxs,
|
|
19
|
+
jsxDEV,
|
|
20
|
+
} from '../../core/src/h.js';
|
|
21
|
+
|
|
22
|
+
// DOM operations
|
|
23
|
+
export {
|
|
24
|
+
mount,
|
|
25
|
+
hydrate,
|
|
26
|
+
render,
|
|
27
|
+
createPortal,
|
|
28
|
+
} from '../../core/src/dom.js';
|
|
29
|
+
|
|
30
|
+
// Hooks
|
|
31
|
+
export {
|
|
32
|
+
useState,
|
|
33
|
+
useSignal,
|
|
34
|
+
useEffect,
|
|
35
|
+
useMemo,
|
|
36
|
+
useCallback,
|
|
37
|
+
useRef,
|
|
38
|
+
useReducer,
|
|
39
|
+
useContext,
|
|
40
|
+
createContext,
|
|
41
|
+
} from '../../core/src/hooks.js';
|
|
42
|
+
|
|
43
|
+
// Components
|
|
44
|
+
export {
|
|
45
|
+
lazy,
|
|
46
|
+
Suspense,
|
|
47
|
+
ErrorBoundary,
|
|
48
|
+
} from '../../core/src/components.js';
|
|
49
|
+
|
|
50
|
+
// Store
|
|
51
|
+
export {
|
|
52
|
+
createStore,
|
|
53
|
+
} from '../../core/src/store.js';
|
|
54
|
+
|
|
55
|
+
// Helpers
|
|
56
|
+
export {
|
|
57
|
+
show,
|
|
58
|
+
each,
|
|
59
|
+
cls,
|
|
60
|
+
createPersisted,
|
|
61
|
+
} from '../../core/src/helpers.js';
|
|
62
|
+
|
|
63
|
+
// Head management
|
|
64
|
+
export {
|
|
65
|
+
Head,
|
|
66
|
+
useHead,
|
|
67
|
+
} from '../../core/src/head.js';
|
|
68
|
+
|
|
69
|
+
// Animation
|
|
70
|
+
export {
|
|
71
|
+
spring,
|
|
72
|
+
tween,
|
|
73
|
+
easings,
|
|
74
|
+
useGesture,
|
|
75
|
+
createTransitionClasses,
|
|
76
|
+
} from '../../core/src/animation.js';
|
|
77
|
+
|
|
78
|
+
// Accessibility
|
|
79
|
+
export {
|
|
80
|
+
useFocusTrap,
|
|
81
|
+
useAriaLive,
|
|
82
|
+
announce,
|
|
83
|
+
clearAnnouncements,
|
|
84
|
+
useId,
|
|
85
|
+
useIds,
|
|
86
|
+
ariaLive,
|
|
87
|
+
Keys,
|
|
88
|
+
onKey,
|
|
89
|
+
onKeys,
|
|
90
|
+
trapFocus,
|
|
91
|
+
releaseFocus,
|
|
92
|
+
getFocusableElements,
|
|
93
|
+
getFirstFocusable,
|
|
94
|
+
getLastFocusable,
|
|
95
|
+
focusFirst,
|
|
96
|
+
focusLast,
|
|
97
|
+
wrapFocus,
|
|
98
|
+
} from '../../core/src/a11y.js';
|
|
99
|
+
|
|
100
|
+
// Skeleton loaders
|
|
101
|
+
export {
|
|
102
|
+
Skeleton,
|
|
103
|
+
SkeletonText,
|
|
104
|
+
SkeletonCircle,
|
|
105
|
+
SkeletonCard,
|
|
106
|
+
SkeletonAvatar,
|
|
107
|
+
SkeletonButton,
|
|
108
|
+
SkeletonInput,
|
|
109
|
+
SkeletonImage,
|
|
110
|
+
Spinner,
|
|
111
|
+
} from '../../core/src/skeleton.js';
|
|
112
|
+
|
|
113
|
+
// Data fetching
|
|
114
|
+
export {
|
|
115
|
+
useFetch,
|
|
116
|
+
useSWR,
|
|
117
|
+
useQuery,
|
|
118
|
+
useInfiniteQuery,
|
|
119
|
+
useMutation,
|
|
120
|
+
cache,
|
|
121
|
+
prefetch,
|
|
122
|
+
} from '../../core/src/data.js';
|
|
123
|
+
|
|
124
|
+
// Forms
|
|
125
|
+
export {
|
|
126
|
+
useForm,
|
|
127
|
+
useField,
|
|
128
|
+
useFieldArray,
|
|
129
|
+
rules,
|
|
130
|
+
simpleResolver,
|
|
131
|
+
zodResolver,
|
|
132
|
+
yupResolver,
|
|
133
|
+
} from '../../core/src/form.js';
|
|
134
|
+
|
|
135
|
+
// Scheduler
|
|
136
|
+
export {
|
|
137
|
+
raf,
|
|
138
|
+
cancelRaf,
|
|
139
|
+
onIdle,
|
|
140
|
+
cancelIdle,
|
|
141
|
+
nextTick,
|
|
142
|
+
scheduleTask,
|
|
143
|
+
TaskPriority,
|
|
144
|
+
} from '../../core/src/scheduler.js';
|
package/src/router.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// What Framework - Router
|
|
2
|
+
// Re-exports from router package
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
Router,
|
|
6
|
+
Link,
|
|
7
|
+
NavLink,
|
|
8
|
+
navigate,
|
|
9
|
+
redirect,
|
|
10
|
+
useRoute,
|
|
11
|
+
useParams,
|
|
12
|
+
useSearch,
|
|
13
|
+
useNavigate,
|
|
14
|
+
defineRoutes,
|
|
15
|
+
prefetchRoute,
|
|
16
|
+
beforeNavigate,
|
|
17
|
+
afterNavigate,
|
|
18
|
+
} from '../../router/src/index.js';
|
package/src/server.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// What Framework - Server
|
|
2
|
+
// Re-exports from server package (SSR, islands, streaming)
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
renderToString,
|
|
6
|
+
renderToStream,
|
|
7
|
+
renderPage,
|
|
8
|
+
definePage,
|
|
9
|
+
} from '../../server/src/index.js';
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
island,
|
|
13
|
+
Island,
|
|
14
|
+
hydrateIslands,
|
|
15
|
+
IslandModes,
|
|
16
|
+
} from '../../server/src/islands.js';
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
createAction,
|
|
20
|
+
useAction,
|
|
21
|
+
} from '../../server/src/actions.js';
|
package/src/testing.js
ADDED
package/testing.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// What Framework - Testing Utilities Type Definitions
|
|
2
|
+
|
|
3
|
+
import { VNode, Signal } from './index';
|
|
4
|
+
|
|
5
|
+
// Setup and Cleanup
|
|
6
|
+
export function setupDOM(): HTMLElement | null;
|
|
7
|
+
export function cleanup(): void;
|
|
8
|
+
|
|
9
|
+
// Render
|
|
10
|
+
export interface RenderResult {
|
|
11
|
+
container: HTMLElement;
|
|
12
|
+
unmount: () => void;
|
|
13
|
+
getByText: (text: string | RegExp) => HTMLElement | null;
|
|
14
|
+
getByTestId: (id: string) => HTMLElement | null;
|
|
15
|
+
getByRole: (role: string) => HTMLElement | null;
|
|
16
|
+
getAllByText: (text: string | RegExp) => HTMLElement[];
|
|
17
|
+
queryByText: (text: string | RegExp) => HTMLElement | null;
|
|
18
|
+
queryByTestId: (id: string) => HTMLElement | null;
|
|
19
|
+
debug: () => void;
|
|
20
|
+
findByText: (text: string | RegExp, timeout?: number) => Promise<HTMLElement>;
|
|
21
|
+
findByTestId: (id: string, timeout?: number) => Promise<HTMLElement>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface RenderOptions {
|
|
25
|
+
container?: HTMLElement;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function render(vnode: VNode, options?: RenderOptions): RenderResult;
|
|
29
|
+
|
|
30
|
+
// Fire Events
|
|
31
|
+
export interface FireEvent {
|
|
32
|
+
click(element: HTMLElement): MouseEvent;
|
|
33
|
+
change(element: HTMLInputElement, value: string): Event;
|
|
34
|
+
input(element: HTMLInputElement, value: string): Event;
|
|
35
|
+
submit(element: HTMLFormElement): Event;
|
|
36
|
+
focus(element: HTMLElement): FocusEvent;
|
|
37
|
+
blur(element: HTMLElement): FocusEvent;
|
|
38
|
+
keyDown(element: HTMLElement, key: string, options?: KeyboardEventInit): KeyboardEvent;
|
|
39
|
+
keyUp(element: HTMLElement, key: string, options?: KeyboardEventInit): KeyboardEvent;
|
|
40
|
+
mouseEnter(element: HTMLElement): MouseEvent;
|
|
41
|
+
mouseLeave(element: HTMLElement): MouseEvent;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const fireEvent: FireEvent;
|
|
45
|
+
|
|
46
|
+
// Wait Utilities
|
|
47
|
+
export interface WaitOptions {
|
|
48
|
+
timeout?: number;
|
|
49
|
+
interval?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function waitFor<T>(callback: () => T, options?: WaitOptions): Promise<T>;
|
|
53
|
+
export function waitForElementToBeRemoved(callback: () => HTMLElement | null, options?: WaitOptions): Promise<void>;
|
|
54
|
+
|
|
55
|
+
// Act
|
|
56
|
+
export function act<T>(callback: () => T | Promise<T>): Promise<T>;
|
|
57
|
+
|
|
58
|
+
// Signal Testing Helpers
|
|
59
|
+
export interface TestSignal<T> {
|
|
60
|
+
signal: Signal<T>;
|
|
61
|
+
value: T;
|
|
62
|
+
history: T[];
|
|
63
|
+
reset(): void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function createTestSignal<T>(initial: T): TestSignal<T>;
|
|
67
|
+
|
|
68
|
+
// Mocking
|
|
69
|
+
export interface MockComponent {
|
|
70
|
+
(props: Record<string, any>): VNode;
|
|
71
|
+
displayName: string;
|
|
72
|
+
calls: Array<{ props: Record<string, any>; timestamp: number }>;
|
|
73
|
+
lastCall(): { props: Record<string, any>; timestamp: number } | undefined;
|
|
74
|
+
reset(): void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function mockComponent(name?: string): MockComponent;
|
|
78
|
+
|
|
79
|
+
// Assertions
|
|
80
|
+
export interface Expect {
|
|
81
|
+
toBeInTheDocument(element: HTMLElement | null): void;
|
|
82
|
+
toHaveTextContent(element: HTMLElement | null, text: string | RegExp): void;
|
|
83
|
+
toHaveAttribute(element: HTMLElement | null, attr: string, value?: string): void;
|
|
84
|
+
toHaveClass(element: HTMLElement | null, className: string): void;
|
|
85
|
+
toBeVisible(element: HTMLElement | null): void;
|
|
86
|
+
toBeDisabled(element: HTMLElement | null): void;
|
|
87
|
+
toHaveValue(element: HTMLInputElement | null, value: string): void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const expect: Expect;
|
|
91
|
+
|
|
92
|
+
// Screen
|
|
93
|
+
export interface Screen {
|
|
94
|
+
getByText(text: string | RegExp): HTMLElement | null;
|
|
95
|
+
getByTestId(id: string): HTMLElement | null;
|
|
96
|
+
getByRole(role: string): HTMLElement | null;
|
|
97
|
+
getAllByText(text: string | RegExp): HTMLElement[];
|
|
98
|
+
queryByText(text: string | RegExp): HTMLElement | null;
|
|
99
|
+
queryByTestId(id: string): HTMLElement | null;
|
|
100
|
+
debug(): void;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const screen: Screen;
|