weifuwu 0.17.24 → 0.17.26
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 +18 -9
- package/dist/client-state.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +25 -54
- package/dist/react.d.ts +2 -2
- package/dist/react.js +36 -40
- package/dist/tsx-context.d.ts +8 -6
- package/dist/tsx-instance.d.ts +2 -2
- package/dist/tsx.d.ts +2 -2
- package/dist/types.d.ts +0 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -439,15 +439,16 @@ ui/
|
|
|
439
439
|
|
|
440
440
|
```tsx
|
|
441
441
|
// page.tsx
|
|
442
|
-
export default function Page(
|
|
443
|
-
const { t } =
|
|
444
|
-
|
|
442
|
+
export default function Page() {
|
|
443
|
+
const { t } = useLocale()
|
|
444
|
+
const data = useLoaderData()
|
|
445
|
+
return <h1>{t('title') ?? data.title}</h1>
|
|
445
446
|
}
|
|
446
447
|
```
|
|
447
448
|
|
|
448
449
|
```tsx
|
|
449
450
|
// layout.tsx
|
|
450
|
-
export default function RootLayout({ children
|
|
451
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
451
452
|
return <html><head/><body><main>{children}</main></body></html>
|
|
452
453
|
}
|
|
453
454
|
```
|
|
@@ -479,8 +480,8 @@ const loading = useNavigating() // reactive loading state
|
|
|
479
480
|
### Client-side hooks
|
|
480
481
|
|
|
481
482
|
```tsx
|
|
482
|
-
import { useWebsocket, useAction,
|
|
483
|
-
import { useLocale, useTheme, applyTheme, addInterceptor } from 'weifuwu/react'
|
|
483
|
+
import { useWebsocket, useAction, useFetch, useQueryState, createStore, Head } from 'weifuwu/react'
|
|
484
|
+
import { useLocale, useTheme, applyTheme, addInterceptor, useLoaderData } from 'weifuwu/react'
|
|
484
485
|
|
|
485
486
|
// WebSocket — auto-reconnecting
|
|
486
487
|
const { send, lastMessage, readyState } = useWebsocket('/ws/chat', { onMessage: (d) => console.log(d), reconnect: { maxRetries: 10, delay: 3000 } })
|
|
@@ -490,7 +491,7 @@ const { submit, data, error, pending } = useAction('/api/feedback', { method: 'P
|
|
|
490
491
|
// Auto-reads _csrf cookie, sends as X-CSRF-Token
|
|
491
492
|
|
|
492
493
|
// Data fetching — cache + dedup + mutate
|
|
493
|
-
const { data, error, loading, mutate } =
|
|
494
|
+
const { data, error, loading, mutate } = useFetch('/api/posts', { fallback: loadData })
|
|
494
495
|
|
|
495
496
|
// URL query state
|
|
496
497
|
const [q, setQ] = useQueryState('q', '')
|
|
@@ -503,8 +504,6 @@ const count = useStore(s => s.count)
|
|
|
503
504
|
// Per-page meta tags
|
|
504
505
|
<Head><title>Page Title</title><meta name="description" content="..." /></Head>
|
|
505
506
|
|
|
506
|
-
// Update context (locale switch etc.)
|
|
507
|
-
setCtx({ locale: 'en', prefs: { locale: 'en' } })
|
|
508
507
|
```
|
|
509
508
|
|
|
510
509
|
### Locale & Theme
|
|
@@ -548,6 +547,16 @@ function ThemeToggle() {
|
|
|
548
547
|
|
|
549
548
|
**`applyTheme(theme)`** — DOM-only theme application. Sets `data-theme` on `<html>`, registers `matchMedia` listener for `'system'`. Used by the interceptor; exported for custom scenarios.
|
|
550
549
|
|
|
550
|
+
**`useLoaderData()`** — Returns the data returned by `load.ts`. Update-triggered; re-renders on SPA navigation.
|
|
551
|
+
|
|
552
|
+
```tsx
|
|
553
|
+
import { useLoaderData } from 'weifuwu/react'
|
|
554
|
+
function Page() {
|
|
555
|
+
const data = useLoaderData<{ post: { title: string } }>()
|
|
556
|
+
return <h1>{data.post.title}</h1>
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
551
560
|
**`addInterceptor(fn)`** — Register a URL interceptor. Interceptors run before SPA navigation; if one returns `true`, `navigate()` skips the fetch-and-swap.
|
|
552
561
|
|
|
553
562
|
```ts
|
package/dist/client-state.d.ts
CHANGED
|
@@ -7,16 +7,16 @@ export interface StoreApi<T> {
|
|
|
7
7
|
subscribe: (listener: () => void) => () => void;
|
|
8
8
|
}
|
|
9
9
|
export declare function createStore<T extends Record<string, unknown>>(initial: T): StoreApi<T>;
|
|
10
|
-
interface
|
|
10
|
+
interface UseFetchResult<T> {
|
|
11
11
|
data: T | undefined;
|
|
12
12
|
error: Error | undefined;
|
|
13
13
|
loading: boolean;
|
|
14
14
|
mutate: (data?: T) => Promise<void>;
|
|
15
15
|
}
|
|
16
|
-
interface
|
|
16
|
+
interface UseFetchOptions<T> {
|
|
17
17
|
fallback?: T;
|
|
18
18
|
ttl?: number;
|
|
19
19
|
}
|
|
20
|
-
export declare function
|
|
20
|
+
export declare function useFetch<T = unknown>(url: string | null, options?: UseFetchOptions<T>): UseFetchResult<T>;
|
|
21
21
|
export declare function useQueryState(key: string, defaultValue?: string): [string, (val: string | ((prev: string) => string)) => void];
|
|
22
22
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { serve, createTestServer } from './serve.ts';
|
|
|
4
4
|
export type { ServeOptions, Server } from './serve.ts';
|
|
5
5
|
export { Router } from './router.ts';
|
|
6
6
|
export type { WebSocketHandler } from './router.ts';
|
|
7
|
-
export { tsx, TsxContext
|
|
7
|
+
export { tsx, TsxContext } from './tsx.ts';
|
|
8
8
|
export type { TsxOptions } from './tsx.ts';
|
|
9
9
|
export { auth, cors, logger } from './middleware.ts';
|
|
10
10
|
export type { AuthOptions, CORSOptions, LoggerOptions } from './middleware.ts';
|
package/dist/index.js
CHANGED
|
@@ -575,10 +575,9 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
575
575
|
import chokidar from "chokidar";
|
|
576
576
|
|
|
577
577
|
// tsx-context.ts
|
|
578
|
-
import {
|
|
579
|
-
var
|
|
580
|
-
var
|
|
581
|
-
var KEY = "__WEIFUWU_CTX";
|
|
578
|
+
import { createContext } from "react";
|
|
579
|
+
var DEFAULT_CTX = { params: {}, query: {}, parsed: {}, prefs: {}, loaderData: {}, env: {}, user: {} };
|
|
580
|
+
var KEY = "__WEIFUWU_CTX_STORE";
|
|
582
581
|
function getStore() {
|
|
583
582
|
if (typeof globalThis !== "undefined" && globalThis[KEY]) {
|
|
584
583
|
return globalThis[KEY];
|
|
@@ -595,14 +594,6 @@ function getStore() {
|
|
|
595
594
|
return s;
|
|
596
595
|
}
|
|
597
596
|
var store = getStore();
|
|
598
|
-
var subscribe = (cb) => {
|
|
599
|
-
store._listeners.add(cb);
|
|
600
|
-
return () => {
|
|
601
|
-
store._listeners.delete(cb);
|
|
602
|
-
};
|
|
603
|
-
};
|
|
604
|
-
var getSnapshot = () => store._snapshot;
|
|
605
|
-
var getServerSnapshot = getSnapshot;
|
|
606
597
|
function __registerAls(getStore2) {
|
|
607
598
|
store._alsGetStore = getStore2;
|
|
608
599
|
}
|
|
@@ -611,28 +602,6 @@ function setCtx(value) {
|
|
|
611
602
|
store._snapshot = { params: store._ctx.params, query: store._ctx.query, user: store._ctx.user, parsed: store._ctx.parsed, prefs: store._ctx.prefs, env: store._ctx.env };
|
|
612
603
|
store._listeners.forEach((fn) => fn());
|
|
613
604
|
}
|
|
614
|
-
function _buildT() {
|
|
615
|
-
const messages2 = typeof window !== "undefined" ? window.__LOCALE_DATA__ : globalThis.__LOCALE_DATA__;
|
|
616
|
-
if (!messages2) return fallbackT;
|
|
617
|
-
return (key, params, fallback) => {
|
|
618
|
-
const msg = key.split(".").reduce((o, k) => o?.[k], messages2);
|
|
619
|
-
if (msg === void 0 || msg === null) return fallback ?? key;
|
|
620
|
-
if (!params) return String(msg);
|
|
621
|
-
let result = String(msg);
|
|
622
|
-
for (const [k, v] of Object.entries(params)) result = result.replace(`{${k}}`, v);
|
|
623
|
-
return result;
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
function _readCtx() {
|
|
627
|
-
const alsStore = store._alsGetStore?.();
|
|
628
|
-
const base = alsStore ?? store._ctx;
|
|
629
|
-
const data = typeof window !== "undefined" ? window.__WEIFUWU_CTX : null;
|
|
630
|
-
return { ...base, ...data, t: _buildT() };
|
|
631
|
-
}
|
|
632
|
-
function useCtx() {
|
|
633
|
-
useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
634
|
-
return _readCtx();
|
|
635
|
-
}
|
|
636
605
|
var TsxContext = createContext(DEFAULT_CTX);
|
|
637
606
|
|
|
638
607
|
// tsx-instance.ts
|
|
@@ -929,7 +898,7 @@ var TsxInstance = class {
|
|
|
929
898
|
user: ctx.user ?? {},
|
|
930
899
|
parsed: ctx.parsed ?? {},
|
|
931
900
|
prefs: ctx.prefs ?? {},
|
|
932
|
-
|
|
901
|
+
loaderData: {},
|
|
933
902
|
env: ctx.env ?? {}
|
|
934
903
|
};
|
|
935
904
|
return als.run(ctxValue, async () => {
|
|
@@ -1032,24 +1001,27 @@ ${src}`;
|
|
|
1032
1001
|
async buildClientBundle(entryPath, layoutPaths, pagesDir) {
|
|
1033
1002
|
try {
|
|
1034
1003
|
const layoutImports = layoutPaths.map((p) => `import${JSON.stringify(p)};`).join("");
|
|
1004
|
+
const _sc = `(function(){var k='__WEIFUWU_CTX_STORE';var s=typeof globalThis!='undefined'&&globalThis[k];if(!s)return function(){};return function(v){s._ctx={...s._ctx,...v};s._snapshot={params:s._ctx.params,query:s._ctx.query,user:s._ctx.user,parsed:s._ctx.parsed,prefs:s._ctx.prefs,env:s._ctx.env};s._listeners.forEach(function(fn){fn()})}})()`;
|
|
1035
1005
|
const code = [
|
|
1036
1006
|
layoutImports,
|
|
1037
1007
|
`import{hydrateRoot}from'react-dom/client';`,
|
|
1038
1008
|
`import{createElement,useState,useEffect}from'react';`,
|
|
1039
1009
|
`import{TsxContext}from'weifuwu/react';`,
|
|
1040
1010
|
`import P from${JSON.stringify(entryPath)};`,
|
|
1011
|
+
`var setCtx=${_sc};`,
|
|
1041
1012
|
`const c=document.getElementById('__weifuwu_root');`,
|
|
1013
|
+
`if(window.__WEIFUWU_PROPS)setCtx({loaderData:window.__WEIFUWU_PROPS});`,
|
|
1042
1014
|
`if(!window.__WFW_ROOT){`,
|
|
1043
1015
|
`function App(){`,
|
|
1044
|
-
`const[p,setP]=useState({C:P
|
|
1045
|
-
`useEffect(()=>{window.__WFW_SET_PAGE=(C
|
|
1046
|
-
`const ctx=window.__WEIFUWU_CTX||{
|
|
1016
|
+
`const[p,setP]=useState({C:P});`,
|
|
1017
|
+
`useEffect(()=>{window.__WFW_SET_PAGE=(C)=>{setCtx({loaderData:window.__WEIFUWU_PROPS});setP({C})}},[]);`,
|
|
1018
|
+
`const ctx=window.__WEIFUWU_CTX||{};`,
|
|
1047
1019
|
`return createElement(TsxContext.Provider,{value:ctx},`,
|
|
1048
|
-
`createElement(p.C,
|
|
1020
|
+
`createElement(p.C,null))`,
|
|
1049
1021
|
`}`,
|
|
1050
1022
|
`window.__WFW_ROOT=hydrateRoot(c,createElement(App));`,
|
|
1051
1023
|
`}else{`,
|
|
1052
|
-
`window.__WFW_SET_PAGE?.(P
|
|
1024
|
+
`window.__WFW_SET_PAGE?.(P);`,
|
|
1053
1025
|
`}`
|
|
1054
1026
|
].join("");
|
|
1055
1027
|
const publicEnv = {};
|
|
@@ -1119,28 +1091,27 @@ ${src}`;
|
|
|
1119
1091
|
const pageMod = this.pageModules.get(entryPath);
|
|
1120
1092
|
if (!pageMod) return new Response("", { status: 500 });
|
|
1121
1093
|
const Component = pageMod.default;
|
|
1094
|
+
const loadMod = loadPath ? this.loadModules.get(loadPath) : void 0;
|
|
1095
|
+
const loadFn = loadMod?.default;
|
|
1096
|
+
const loadProps = loadFn ? await loadFn({ params: ctx.params, query: ctx.query }) : {};
|
|
1122
1097
|
const ctxValue = {
|
|
1123
1098
|
params: ctx.params,
|
|
1124
1099
|
query: ctx.query,
|
|
1125
1100
|
user: ctx.user ?? {},
|
|
1126
1101
|
parsed: ctx.parsed ?? {},
|
|
1127
1102
|
prefs: ctx.prefs ?? {},
|
|
1128
|
-
|
|
1103
|
+
loaderData: loadProps,
|
|
1129
1104
|
env: ctx.env ?? {}
|
|
1130
1105
|
};
|
|
1131
1106
|
return als.run(ctxValue, async () => {
|
|
1132
1107
|
setCtx(ctxValue);
|
|
1133
|
-
const loadMod = loadPath ? this.loadModules.get(loadPath) : void 0;
|
|
1134
|
-
const loadFn = loadMod?.default;
|
|
1135
|
-
const loadProps = loadFn ? await loadFn({ params: ctx.params, query: ctx.query }) : {};
|
|
1136
|
-
const allProps = { ...loadProps, params: ctx.params, query: ctx.query };
|
|
1137
1108
|
let element = createElement(
|
|
1138
1109
|
TsxContext.Provider,
|
|
1139
1110
|
{ value: ctxValue },
|
|
1140
1111
|
createElement(
|
|
1141
1112
|
"div",
|
|
1142
1113
|
{ id: "__weifuwu_root" },
|
|
1143
|
-
createElement(Component,
|
|
1114
|
+
createElement(Component, null)
|
|
1144
1115
|
)
|
|
1145
1116
|
);
|
|
1146
1117
|
if (layoutPaths.length === 0) {
|
|
@@ -1165,7 +1136,7 @@ ${src}`;
|
|
|
1165
1136
|
const isRoot = i === 0;
|
|
1166
1137
|
element = createElement(
|
|
1167
1138
|
Layout,
|
|
1168
|
-
|
|
1139
|
+
{ children: element }
|
|
1169
1140
|
);
|
|
1170
1141
|
}
|
|
1171
1142
|
}
|
|
@@ -1177,7 +1148,7 @@ ${src}`;
|
|
|
1177
1148
|
compiledTailwindCss: this.compiledTailwindCss,
|
|
1178
1149
|
isDev,
|
|
1179
1150
|
bundle,
|
|
1180
|
-
|
|
1151
|
+
loaderData: loadProps
|
|
1181
1152
|
});
|
|
1182
1153
|
});
|
|
1183
1154
|
};
|
|
@@ -1456,12 +1427,13 @@ function buildHeadPayload(opts) {
|
|
|
1456
1427
|
return result;
|
|
1457
1428
|
}
|
|
1458
1429
|
function buildBodyScripts(opts) {
|
|
1459
|
-
if (!opts.bundle) return "";
|
|
1460
1430
|
const parts = [];
|
|
1461
|
-
if (opts.
|
|
1462
|
-
parts.push(`<script>window.__WEIFUWU_PROPS=${JSON.stringify(opts.
|
|
1431
|
+
if (opts.loaderData && Object.keys(opts.loaderData).length > 0) {
|
|
1432
|
+
parts.push(`<script>window.__WEIFUWU_PROPS=${JSON.stringify(opts.loaderData)}</script>`);
|
|
1433
|
+
}
|
|
1434
|
+
if (opts.bundle) {
|
|
1435
|
+
parts.push(`<script type="module" src="${opts.base}${opts.bundle.url}"></script>`);
|
|
1463
1436
|
}
|
|
1464
|
-
parts.push(`<script type="module" src="${opts.base}${opts.bundle.url}"></script>`);
|
|
1465
1437
|
return parts.join("\n");
|
|
1466
1438
|
}
|
|
1467
1439
|
|
|
@@ -7235,6 +7207,7 @@ function preferences(options) {
|
|
|
7235
7207
|
globalThis.__LOCALE_DATA__ = msgs;
|
|
7236
7208
|
ctx.parsed = { ...ctx.parsed, __localeData: msgs };
|
|
7237
7209
|
}
|
|
7210
|
+
;
|
|
7238
7211
|
ctx.setPref = (name, value) => {
|
|
7239
7212
|
const cookieOpts = [`${name}=${encodeURIComponent(value)}`, "Path=/", "SameSite=Lax"];
|
|
7240
7213
|
const referer = req.headers.get("referer") || "/";
|
|
@@ -8665,7 +8638,6 @@ export {
|
|
|
8665
8638
|
serve,
|
|
8666
8639
|
serveStatic,
|
|
8667
8640
|
setCookie,
|
|
8668
|
-
setCtx,
|
|
8669
8641
|
smoothStream,
|
|
8670
8642
|
streamObject,
|
|
8671
8643
|
streamText,
|
|
@@ -8673,7 +8645,6 @@ export {
|
|
|
8673
8645
|
tool2 as tool,
|
|
8674
8646
|
tsx,
|
|
8675
8647
|
upload,
|
|
8676
|
-
useCtx,
|
|
8677
8648
|
user,
|
|
8678
8649
|
validate
|
|
8679
8650
|
};
|
package/dist/react.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ export type { UseWebsocketOptions, UseWebsocketReturn } from './use-websocket.ts
|
|
|
3
3
|
export { useAction } from './use-action.ts';
|
|
4
4
|
export type { UseActionOptions, UseActionReturn } from './use-action.ts';
|
|
5
5
|
export { Link, useNavigate, navigate, useNavigating, addInterceptor } from './client-router.ts';
|
|
6
|
-
export { TsxContext,
|
|
6
|
+
export { TsxContext, useLoaderData } from './tsx-context.ts';
|
|
7
7
|
export { Head } from './head.tsx';
|
|
8
|
-
export { createStore,
|
|
8
|
+
export { createStore, useFetch, useQueryState } from './client-state.ts';
|
|
9
9
|
export type { StoreApi } from './client-state.ts';
|
|
10
10
|
export { useLocale } from './client-locale.ts';
|
|
11
11
|
export { useTheme, applyTheme } from './client-theme.ts';
|
package/dist/react.js
CHANGED
|
@@ -331,10 +331,9 @@ async function prefetchPage(href) {
|
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
// tsx-context.ts
|
|
334
|
-
import {
|
|
335
|
-
var
|
|
336
|
-
var
|
|
337
|
-
var KEY = "__WEIFUWU_CTX";
|
|
334
|
+
import { createContext } from "react";
|
|
335
|
+
var DEFAULT_CTX = { params: {}, query: {}, parsed: {}, prefs: {}, loaderData: {}, env: {}, user: {} };
|
|
336
|
+
var KEY = "__WEIFUWU_CTX_STORE";
|
|
338
337
|
function getStore() {
|
|
339
338
|
if (typeof globalThis !== "undefined" && globalThis[KEY]) {
|
|
340
339
|
return globalThis[KEY];
|
|
@@ -351,40 +350,22 @@ function getStore() {
|
|
|
351
350
|
return s;
|
|
352
351
|
}
|
|
353
352
|
var store = getStore();
|
|
354
|
-
var subscribe = (cb) => {
|
|
355
|
-
store._listeners.add(cb);
|
|
356
|
-
return () => {
|
|
357
|
-
store._listeners.delete(cb);
|
|
358
|
-
};
|
|
359
|
-
};
|
|
360
|
-
var getSnapshot = () => store._snapshot;
|
|
361
|
-
var getServerSnapshot = getSnapshot;
|
|
362
353
|
function setCtx(value) {
|
|
363
354
|
store._ctx = { ...store._ctx, ...value };
|
|
364
355
|
store._snapshot = { params: store._ctx.params, query: store._ctx.query, user: store._ctx.user, parsed: store._ctx.parsed, prefs: store._ctx.prefs, env: store._ctx.env };
|
|
365
356
|
store._listeners.forEach((fn) => fn());
|
|
366
357
|
}
|
|
367
|
-
function
|
|
368
|
-
const messages = typeof window !== "undefined" ? window.__LOCALE_DATA__ : globalThis.__LOCALE_DATA__;
|
|
369
|
-
if (!messages) return fallbackT;
|
|
370
|
-
return (key, params, fallback) => {
|
|
371
|
-
const msg = key.split(".").reduce((o, k) => o?.[k], messages);
|
|
372
|
-
if (msg === void 0 || msg === null) return fallback ?? key;
|
|
373
|
-
if (!params) return String(msg);
|
|
374
|
-
let result = String(msg);
|
|
375
|
-
for (const [k, v] of Object.entries(params)) result = result.replace(`{${k}}`, v);
|
|
376
|
-
return result;
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
function _readCtx() {
|
|
358
|
+
function useCtx() {
|
|
380
359
|
const alsStore = store._alsGetStore?.();
|
|
381
360
|
const base = alsStore ?? store._ctx;
|
|
382
361
|
const data = typeof window !== "undefined" ? window.__WEIFUWU_CTX : null;
|
|
383
|
-
return { ...base, ...data
|
|
362
|
+
return { ...base, ...data };
|
|
384
363
|
}
|
|
385
|
-
function
|
|
386
|
-
|
|
387
|
-
|
|
364
|
+
function useLoaderData() {
|
|
365
|
+
const alsStore = store._alsGetStore?.();
|
|
366
|
+
const base = alsStore ?? store._ctx;
|
|
367
|
+
const data = typeof window !== "undefined" ? window.__WEIFUWU_CTX : null;
|
|
368
|
+
return { ...base, ...data }.loaderData;
|
|
388
369
|
}
|
|
389
370
|
var TsxContext = createContext(DEFAULT_CTX);
|
|
390
371
|
|
|
@@ -405,25 +386,25 @@ function createStore(initial) {
|
|
|
405
386
|
state = { ...state, ...next };
|
|
406
387
|
listeners.forEach((fn) => fn());
|
|
407
388
|
};
|
|
408
|
-
const
|
|
389
|
+
const subscribe = (listener) => {
|
|
409
390
|
listeners.add(listener);
|
|
410
391
|
return () => {
|
|
411
392
|
listeners.delete(listener);
|
|
412
393
|
};
|
|
413
394
|
};
|
|
414
395
|
const useStore = ((selector) => useSyncExternalStore2(
|
|
415
|
-
|
|
396
|
+
subscribe,
|
|
416
397
|
() => selector ? selector(state) : state
|
|
417
398
|
));
|
|
418
399
|
useStore.getState = getState;
|
|
419
400
|
useStore.setState = setState;
|
|
420
|
-
useStore.subscribe =
|
|
401
|
+
useStore.subscribe = subscribe;
|
|
421
402
|
return useStore;
|
|
422
403
|
}
|
|
423
404
|
var dataCache = /* @__PURE__ */ new Map();
|
|
424
405
|
var inflight = /* @__PURE__ */ new Map();
|
|
425
406
|
var CACHE_TTL = 6e4;
|
|
426
|
-
function
|
|
407
|
+
function useFetch(url, options) {
|
|
427
408
|
const ttl = options?.ttl ?? CACHE_TTL;
|
|
428
409
|
const [state, setState] = useState4({
|
|
429
410
|
data: options?.fallback,
|
|
@@ -497,7 +478,7 @@ function notifyQueryListeners() {
|
|
|
497
478
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
498
479
|
}
|
|
499
480
|
function useQueryState(key, defaultValue = "") {
|
|
500
|
-
function
|
|
481
|
+
function getSnapshot() {
|
|
501
482
|
if (typeof window === "undefined") return defaultValue;
|
|
502
483
|
const params = new URLSearchParams(window.location.search);
|
|
503
484
|
return params.get(key) ?? defaultValue;
|
|
@@ -509,12 +490,12 @@ function useQueryState(key, defaultValue = "") {
|
|
|
509
490
|
window.addEventListener("popstate", cb);
|
|
510
491
|
return () => window.removeEventListener("popstate", cb);
|
|
511
492
|
},
|
|
512
|
-
|
|
493
|
+
getSnapshot,
|
|
513
494
|
() => defaultValue
|
|
514
495
|
);
|
|
515
496
|
const setValue = useCallback4((val) => {
|
|
516
497
|
if (typeof window === "undefined") return;
|
|
517
|
-
const resolved = typeof val === "function" ? val(
|
|
498
|
+
const resolved = typeof val === "function" ? val(getSnapshot()) : val;
|
|
518
499
|
const url = new URL(window.location.href);
|
|
519
500
|
if (resolved === defaultValue || resolved === "") {
|
|
520
501
|
url.searchParams.delete(key);
|
|
@@ -528,6 +509,18 @@ function useQueryState(key, defaultValue = "") {
|
|
|
528
509
|
}
|
|
529
510
|
|
|
530
511
|
// client-locale.ts
|
|
512
|
+
function buildT() {
|
|
513
|
+
const messages = typeof window !== "undefined" ? window.__LOCALE_DATA__ : globalThis.__LOCALE_DATA__;
|
|
514
|
+
if (!messages) return (key, _p, fb) => fb ?? key;
|
|
515
|
+
return (key, params, fallback) => {
|
|
516
|
+
const msg = key.split(".").reduce((o, k) => o?.[k], messages);
|
|
517
|
+
if (msg === void 0 || msg === null) return fallback ?? key;
|
|
518
|
+
if (!params) return String(msg);
|
|
519
|
+
let result = String(msg);
|
|
520
|
+
for (const [k, v] of Object.entries(params)) result = result.replace(`{${k}}`, v);
|
|
521
|
+
return result;
|
|
522
|
+
};
|
|
523
|
+
}
|
|
531
524
|
addInterceptor(async (url) => {
|
|
532
525
|
const m = url.pathname.match(/^\/__lang\/(\w+)$/);
|
|
533
526
|
if (!m) return false;
|
|
@@ -551,11 +544,12 @@ function useLocale() {
|
|
|
551
544
|
return {
|
|
552
545
|
locale: ctx.prefs.locale,
|
|
553
546
|
setLocale: (locale) => navigate("/__lang/" + locale),
|
|
554
|
-
t:
|
|
547
|
+
t: buildT()
|
|
555
548
|
};
|
|
556
549
|
}
|
|
557
550
|
|
|
558
551
|
// client-theme.ts
|
|
552
|
+
import { useEffect as useEffect4 } from "react";
|
|
559
553
|
function resolveTheme(theme) {
|
|
560
554
|
if (theme === "system") {
|
|
561
555
|
if (typeof window === "undefined") return "light";
|
|
@@ -601,6 +595,9 @@ addInterceptor(async (url) => {
|
|
|
601
595
|
function useTheme() {
|
|
602
596
|
const ctx = useCtx();
|
|
603
597
|
const theme = ctx.prefs.theme ?? "system";
|
|
598
|
+
useEffect4(() => {
|
|
599
|
+
applyTheme(theme);
|
|
600
|
+
}, [theme]);
|
|
604
601
|
return {
|
|
605
602
|
theme,
|
|
606
603
|
resolvedTheme: resolveTheme(theme),
|
|
@@ -615,10 +612,9 @@ export {
|
|
|
615
612
|
applyTheme,
|
|
616
613
|
createStore,
|
|
617
614
|
navigate,
|
|
618
|
-
setCtx,
|
|
619
615
|
useAction,
|
|
620
|
-
|
|
621
|
-
|
|
616
|
+
useFetch,
|
|
617
|
+
useLoaderData,
|
|
622
618
|
useLocale,
|
|
623
619
|
useNavigate,
|
|
624
620
|
useNavigating,
|
package/dist/tsx-context.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface PageContext {
|
|
2
2
|
params: Record<string, string>;
|
|
3
3
|
query: Record<string, string>;
|
|
4
4
|
user: {
|
|
@@ -6,11 +6,13 @@ export interface CtxValue {
|
|
|
6
6
|
};
|
|
7
7
|
parsed: Record<string, unknown>;
|
|
8
8
|
prefs: Record<string, string>;
|
|
9
|
-
|
|
9
|
+
loaderData: Record<string, unknown>;
|
|
10
10
|
env: Record<string, string>;
|
|
11
11
|
}
|
|
12
12
|
/** @internal Injected by tsx-instance.ts for async-safe context isolation */
|
|
13
|
-
export declare function __registerAls(getStore: () =>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export declare
|
|
13
|
+
export declare function __registerAls(getStore: () => PageContext | undefined): void;
|
|
14
|
+
declare function setCtx(value: Partial<PageContext>): void;
|
|
15
|
+
declare function useCtx(): PageContext;
|
|
16
|
+
export declare function useLoaderData<T = Record<string, unknown>>(): T;
|
|
17
|
+
export declare const TsxContext: import("react").Context<PageContext>;
|
|
18
|
+
export { useCtx, setCtx };
|
package/dist/tsx-instance.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router } from './router.ts';
|
|
2
|
-
import { TsxContext
|
|
3
|
-
export { TsxContext
|
|
2
|
+
import { TsxContext } from './tsx-context.ts';
|
|
3
|
+
export { TsxContext };
|
|
4
4
|
export interface TsxOptions {
|
|
5
5
|
dir: string;
|
|
6
6
|
}
|
package/dist/tsx.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { TsxContext
|
|
1
|
+
import { TsxContext } from './tsx-instance.ts';
|
|
2
2
|
import type { TsxOptions } from './tsx-instance.ts';
|
|
3
3
|
import type { Router } from './router.ts';
|
|
4
|
-
export { TsxContext
|
|
4
|
+
export { TsxContext };
|
|
5
5
|
export type { TsxOptions };
|
|
6
6
|
export declare function tsx(options: TsxOptions): Promise<Router & {
|
|
7
7
|
stop: () => void;
|
package/dist/types.d.ts
CHANGED
|
@@ -4,12 +4,8 @@ export interface Context {
|
|
|
4
4
|
user?: unknown;
|
|
5
5
|
parsed?: Record<string, unknown>;
|
|
6
6
|
mountPath?: string;
|
|
7
|
-
locale?: string;
|
|
8
7
|
t?: (key: string, params?: Record<string, string>, fallback?: string) => string;
|
|
9
|
-
requestId?: string;
|
|
10
8
|
prefs?: Record<string, string>;
|
|
11
|
-
theme?: string;
|
|
12
|
-
setPref?: (name: string, value: string) => Response;
|
|
13
9
|
env?: Record<string, string>;
|
|
14
10
|
}
|
|
15
11
|
export type Handler = (req: Request, ctx: Context) => Response | Promise<Response>;
|