jinrai 1.1.2 → 1.1.4
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/front.config.json +2 -1
- package/index.ts +4 -1
- package/lib/bin/bin.js +123 -59
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -1
- package/lib/src/bin/agent/agent.d.ts +2 -0
- package/lib/src/bin/agent/agent.js +4 -0
- package/lib/src/bin/playwright/pageCollector.d.ts +2 -0
- package/lib/src/bin/playwright/pageTestCollector.d.ts +6 -0
- package/lib/src/bin/playwright/templates.d.ts +6 -1
- package/lib/src/bin/routes/Parser.d.ts +25 -2
- package/lib/src/bin/routes/Parser.js +5 -0
- package/lib/src/bin/routes/getRoutes.d.ts +1 -0
- package/lib/src/front/server/useIsServer.d.ts +1 -0
- package/lib/src/front/server/useIsServer.js +7 -0
- package/lib/src/front/server-state/DataProxy.d.ts +2 -1
- package/lib/src/front/server-state/DataProxy.js +122 -60
- package/lib/src/front/server-state/SSR.d.ts +3 -0
- package/lib/src/front/server-state/SSR.js +18 -3
- package/lib/src/front/server-state/orig.d.ts +2 -0
- package/lib/src/front/server-state/{real.js → orig.js} +18 -3
- package/lib/src/front/server-state/serverStates.d.ts +3 -1
- package/lib/src/front/server-state/serverStates.js +24 -17
- package/lib/src/front/server-state/testState.d.ts +3 -0
- package/lib/src/front/server-state/testState.js +14 -0
- package/lib/src/front/server-state/useServerState.d.ts +1 -1
- package/lib/src/front/server-state/useServerState.js +5 -9
- package/lib/src/front/translate/TranslateConfig.d.ts +21 -0
- package/lib/src/front/translate/TranslateConfig.js +108 -0
- package/lib/src/front/url/JinraiContext.d.ts +1 -0
- package/lib/src/front/url/JinraiContext.js +1 -0
- package/lib/src/front/url/adapter/def.js +1 -1
- package/lib/src/front/url/adapter/rrd6.js +2 -2
- package/lib/src/front/url/adapter/rrd7.js +2 -2
- package/lib/src/front/url/params/useParamsIndex.js +2 -1
- package/lib/src/front/url/search/useSearch.js +4 -4
- package/lib/src/front/url/search/useSearchValue.d.ts +11 -5
- package/lib/src/front/url/search/useSearchValue.js +13 -8
- package/lib/src/front/wrapper/Custom.d.ts +3 -3
- package/lib/src/front/wrapper/Custom.js +18 -1
- package/lib/vite/plugin.js +26 -154
- package/package.json +9 -1
- package/rollup.config.mjs +2 -1
- package/src/bin/agent/agent.ts +2 -0
- package/src/bin/build/build.ts +23 -10
- package/src/bin/playwright/pageCollector.ts +8 -6
- package/src/bin/playwright/pageTestCollector.ts +15 -0
- package/src/bin/playwright/templates.ts +16 -5
- package/src/bin/routes/Parser.ts +100 -32
- package/src/bin/routes/getRoutes.ts +5 -1
- package/src/front/server/useIsServer.ts +5 -0
- package/src/front/server-state/DataProxy.ts +140 -61
- package/src/front/server-state/SSR.ts +22 -2
- package/src/front/server-state/{real.ts → orig.ts} +19 -2
- package/src/front/server-state/serverStates.ts +33 -18
- package/src/front/server-state/testState.ts +15 -0
- package/src/front/server-state/useServerState.ts +6 -11
- package/src/front/translate/TranslateConfig.tsx +153 -0
- package/src/front/url/JinraiContext.tsx +2 -0
- package/src/front/url/adapter/def.tsx +1 -1
- package/src/front/url/adapter/rrd6.tsx +2 -3
- package/src/front/url/adapter/rrd7.tsx +2 -2
- package/src/front/url/search/useSearch.ts +3 -4
- package/src/front/url/search/useSearchValue.ts +25 -13
- package/src/front/wrapper/Custom.tsx +28 -4
- package/tests/data-proxy/create-dataproxy.test.ts +116 -0
- package/tests/{custom.test.ts → parse/custom.test.ts} +2 -2
- package/tests/{parse.test.ts → parse/parse.test.ts} +7 -7
- package/tsconfig.types.json +1 -0
- package/vite/plugin.ts +40 -22
- package/lib/src/front/server-state/real.d.ts +0 -1
- /package/tests/{content → parse/content}/1.html +0 -0
- /package/tests/{content → parse/content}/1_result.json +0 -0
- /package/tests/{content → parse/content}/2.html +0 -0
- /package/tests/{content → parse/content}/2_result.json +0 -0
- /package/tests/{content → parse/content}/3.html +0 -0
- /package/tests/{content → parse/content}/3_result.json +0 -0
- /package/tests/{content → parse/content}/4.html +0 -0
- /package/tests/{content → parse/content}/4_result.json +0 -0
- /package/tests/{content → parse/content}/custom.html +0 -0
- /package/tests/{content → parse/content}/custom.json +0 -0
- /package/tests/{content → parse/content}/index.html +0 -0
- /package/tests/{content → parse/content}/index.json +0 -0
- /package/tests/{content → parse/content}/index_with_templates.json +0 -0
- /package/tests/{content → parse/content}/templates.json +0 -0
|
@@ -13,92 +13,154 @@ const getTarget = (data, path) => {
|
|
|
13
13
|
case "undefined":
|
|
14
14
|
case "symbol":
|
|
15
15
|
// эти типы можно просто завернуть
|
|
16
|
-
return {
|
|
16
|
+
return { $__ROOT__: data };
|
|
17
17
|
default:
|
|
18
18
|
return () => `{{${path}}}`;
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
|
-
|
|
21
|
+
function createDataProxy(data, path = "") {
|
|
22
22
|
if (path.endsWith("@"))
|
|
23
23
|
sources.set(path.slice(0, -1), data);
|
|
24
24
|
return new Proxy(getTarget(data, path), {
|
|
25
|
-
get: (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
get: (_target, prop) => {
|
|
26
|
+
if (ssr.exportToJV) {
|
|
27
|
+
return {
|
|
28
|
+
$JV: {
|
|
29
|
+
key: path + "/" + String(prop),
|
|
30
|
+
type: "proxy",
|
|
31
|
+
def: data,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------
|
|
36
|
+
// 1. Обработка символов
|
|
37
|
+
// ---------------------------
|
|
38
|
+
if (typeof prop === "symbol") {
|
|
29
39
|
switch (prop) {
|
|
30
|
-
// @ts-ignore
|
|
31
40
|
case Symbol.toPrimitive:
|
|
32
41
|
return (hint) => {
|
|
33
42
|
console.log("PROXYDATA", hint);
|
|
34
43
|
return `{{${path}}}`;
|
|
35
44
|
};
|
|
36
|
-
// @ts-ignore
|
|
37
45
|
case Symbol.toStringTag:
|
|
38
46
|
return "Object";
|
|
39
|
-
// @ts-ignore
|
|
40
47
|
case Symbol.iterator:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
if (typeof data === "object" && data !== null && Symbol.iterator in data) {
|
|
49
|
+
return data[Symbol.iterator];
|
|
50
|
+
}
|
|
44
51
|
return undefined;
|
|
45
|
-
case "_debugInfo":
|
|
46
|
-
return {
|
|
47
|
-
note: `State From Request (${path})`,
|
|
48
|
-
kind: typeof data,
|
|
49
|
-
timestamp: Date.now(),
|
|
50
|
-
preview: data,
|
|
51
|
-
};
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------
|
|
55
|
+
// 2. DEV tools
|
|
56
|
+
// ---------------------------
|
|
57
|
+
if (!(typeof data === "object" && data !== null && prop in data)) {
|
|
58
|
+
if (prop === "$$typeof" || prop === "type") {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
if (prop === "_debugInfo") {
|
|
62
|
+
return {
|
|
63
|
+
note: `State From Request (${path})`,
|
|
64
|
+
kind: typeof data,
|
|
65
|
+
timestamp: Date.now(),
|
|
66
|
+
preview: data,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------
|
|
71
|
+
// 3. SELF: $key → returns function
|
|
72
|
+
// ---------------------------
|
|
73
|
+
if (typeof prop === "string" && prop.startsWith("$")) {
|
|
55
74
|
return (key) => `{{${path + "/" + key}${"\\" + prop}}}`;
|
|
56
|
-
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------
|
|
77
|
+
// 4. Types special cases
|
|
78
|
+
// ---------------------------
|
|
57
79
|
switch (typeof data) {
|
|
58
80
|
case "string":
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
81
|
+
if (prop === "length" || prop === "entries")
|
|
82
|
+
return undefined;
|
|
83
|
+
break;
|
|
64
84
|
case "number":
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
85
|
+
if (prop === "@@iterator")
|
|
86
|
+
return undefined;
|
|
87
|
+
break;
|
|
69
88
|
default:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return undefined;
|
|
73
|
-
}
|
|
89
|
+
if (prop === "then")
|
|
90
|
+
return undefined;
|
|
74
91
|
}
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.map(([key, itm]) => callback(createDataProxy(itm, `${path}/[ITEM=${key}]`))),
|
|
86
|
-
]);
|
|
87
|
-
case "getValue":
|
|
88
|
-
return () => data;
|
|
89
|
-
case "toJSON":
|
|
90
|
-
return () => {
|
|
91
|
-
console.log("dataproxy toJSON", path, data);
|
|
92
|
-
return ssr.exportParams ? `{{${path}}}` : data;
|
|
93
|
-
};
|
|
94
|
-
default:
|
|
95
|
-
if (data && (typeof data[prop] == "object" || Array.isArray(data[prop]))) {
|
|
96
|
-
return createDataProxy(data[prop], path + "/" + prop);
|
|
97
|
-
}
|
|
98
|
-
return `{{${path + "/" + prop}}}`;
|
|
92
|
+
// ---------------------------
|
|
93
|
+
// 5. Array-like handlers
|
|
94
|
+
// ---------------------------
|
|
95
|
+
if (prop === "find") {
|
|
96
|
+
return data[prop];
|
|
97
|
+
}
|
|
98
|
+
if (prop === "length") {
|
|
99
|
+
if (Array.isArray(data)) {
|
|
100
|
+
return data.length;
|
|
101
|
+
}
|
|
99
102
|
}
|
|
103
|
+
if (prop === "map" || prop === "forEach") {
|
|
104
|
+
return (callback) => React.createElement("loopwrapper", null, [
|
|
105
|
+
`ArrayDataKey=${path}|`,
|
|
106
|
+
Object.entries(data)
|
|
107
|
+
.slice(0, 1)
|
|
108
|
+
.map(([key, itm]) => callback(createDataProxy(itm, `${path}/[ITEM=${key}]`))),
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
// ---------------------------
|
|
112
|
+
// 6. getValue
|
|
113
|
+
// ---------------------------
|
|
114
|
+
if (prop === "getValue") {
|
|
115
|
+
return () => data;
|
|
116
|
+
}
|
|
117
|
+
// ---------------------------
|
|
118
|
+
// 7. toJSON
|
|
119
|
+
// ---------------------------
|
|
120
|
+
if (prop === "toJSON") {
|
|
121
|
+
return () => {
|
|
122
|
+
console.log("dataproxy toJSON", path, data);
|
|
123
|
+
return ssr.exportParams
|
|
124
|
+
? `{{${path}}}`
|
|
125
|
+
: {
|
|
126
|
+
$JV: {
|
|
127
|
+
key: path,
|
|
128
|
+
type: "proxy",
|
|
129
|
+
def: data,
|
|
130
|
+
separator: "",
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------
|
|
136
|
+
// 8. Nested object
|
|
137
|
+
// ---------------------------
|
|
138
|
+
if (data === null) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
const value = data[prop];
|
|
142
|
+
if (!ssr.exportParams) {
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
if (value && (typeof value === "object" || Array.isArray(value))) {
|
|
146
|
+
return createDataProxy(value, path + "/" + String(prop));
|
|
147
|
+
}
|
|
148
|
+
// if (ssr.exportParams) {
|
|
149
|
+
// if (typeof value == "string") {
|
|
150
|
+
// const key = `{{${path + "/" + String(prop)}}}`
|
|
151
|
+
// const jv = getJinraiValue(key, "proxyValue", "", value)
|
|
152
|
+
// return value.bindSource(jv)
|
|
153
|
+
// }
|
|
154
|
+
// return key
|
|
155
|
+
// } else {
|
|
156
|
+
// return value
|
|
157
|
+
// }
|
|
158
|
+
// ---------------------------
|
|
159
|
+
// 9. Final primitive fallback
|
|
160
|
+
// ---------------------------
|
|
161
|
+
return `{{${path + "/" + String(prop)}}}`;
|
|
100
162
|
},
|
|
101
163
|
});
|
|
102
|
-
}
|
|
164
|
+
}
|
|
103
165
|
|
|
104
166
|
export { createDataProxy as default, sources };
|
|
@@ -1,6 +1,21 @@
|
|
|
1
|
+
import { ViteAgent, JinraiAgent } from '../../bin/agent/agent.js';
|
|
2
|
+
|
|
1
3
|
const ssr = {
|
|
2
|
-
current:
|
|
3
|
-
|
|
4
|
+
current: navigator.userAgent == JinraiAgent,
|
|
5
|
+
// current: true,
|
|
6
|
+
test: navigator.userAgent == ViteAgent,
|
|
7
|
+
exportParams: true,
|
|
8
|
+
exportToJV: false,
|
|
9
|
+
};
|
|
10
|
+
if (window != undefined) {
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
window.__ssr = ssr;
|
|
13
|
+
}
|
|
14
|
+
const stringifyInput = (input) => {
|
|
15
|
+
ssr.exportParams = false;
|
|
16
|
+
const result = JSON.stringify(input);
|
|
17
|
+
ssr.exportParams = true;
|
|
18
|
+
return result;
|
|
4
19
|
};
|
|
5
20
|
|
|
6
|
-
export { ssr };
|
|
21
|
+
export { ssr, stringifyInput };
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { ssr } from './SSR.js';
|
|
1
2
|
import { sources } from './DataProxy.js';
|
|
3
|
+
import { getJinraiValue } from '../url/search/useSearchValue.js';
|
|
2
4
|
|
|
3
|
-
function
|
|
5
|
+
function orig(value) {
|
|
6
|
+
if (!ssr.current)
|
|
7
|
+
return value;
|
|
4
8
|
switch (typeof value) {
|
|
5
9
|
case "number":
|
|
6
10
|
return value;
|
|
7
11
|
case "string":
|
|
8
|
-
|
|
12
|
+
if (value.startsWith("{{") && value.endsWith("}}")) {
|
|
13
|
+
const result = getArrayByPath(value.slice(2, -2));
|
|
14
|
+
return wrapSource(result, getJinraiValue(value, "proxy", "", result));
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
9
17
|
case "object":
|
|
10
18
|
// @ts-ignore
|
|
11
19
|
if (value && typeof value.getValue === "function") {
|
|
@@ -17,6 +25,13 @@ function real(value) {
|
|
|
17
25
|
return value;
|
|
18
26
|
}
|
|
19
27
|
}
|
|
28
|
+
const original = orig;
|
|
29
|
+
const wrapSource = (value, source) => {
|
|
30
|
+
if (typeof value == "string") {
|
|
31
|
+
return value.bindSource(source);
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
};
|
|
20
35
|
const getArrayByPath = (path) => {
|
|
21
36
|
const [sourceIndex, requestPath] = path.split("@", 2);
|
|
22
37
|
const keys = requestPath.split("/");
|
|
@@ -30,4 +45,4 @@ const getArrayByPath = (path) => {
|
|
|
30
45
|
return link;
|
|
31
46
|
};
|
|
32
47
|
|
|
33
|
-
export {
|
|
48
|
+
export { orig, original };
|
|
@@ -11,8 +11,10 @@ export type ServerValue = {
|
|
|
11
11
|
request?: Request;
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
|
+
key: ServerKey;
|
|
14
15
|
};
|
|
15
16
|
export declare const serverStates: Map<string, ServerValue>;
|
|
17
|
+
export declare const getIdent: (key: ServerKey) => string;
|
|
16
18
|
export declare const getServerValue: (key?: ServerKey, def?: ServerValue["value"], options?: ServerValue["options"]) => any[];
|
|
17
|
-
export declare const setServerValue: (key: ServerKey, value: ServerValue["value"], options?: ServerValue["options"]) =>
|
|
19
|
+
export declare const setServerValue: (key: ServerKey, value: ServerValue["value"], options?: ServerValue["options"]) => any;
|
|
18
20
|
export {};
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import { encode } from 'js-base64';
|
|
2
1
|
import createDataProxy from './DataProxy.js';
|
|
3
|
-
import { ssr } from './SSR.js';
|
|
4
2
|
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
const initialState = { ...(window?.__appc__?.state ?? {}) };
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
const serverErrors = [...(window?.__appc__?.errors ?? [])];
|
|
7
|
+
if (serverErrors.length) {
|
|
8
|
+
console.error("SERVER:", serverErrors);
|
|
9
|
+
}
|
|
10
|
+
if (window != undefined) {
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
delete window.__appc__;
|
|
13
|
+
}
|
|
5
14
|
const serverStates = new Map();
|
|
6
15
|
if (window != undefined) {
|
|
7
16
|
console.log("init $exportServerStates");
|
|
@@ -9,32 +18,30 @@ if (window != undefined) {
|
|
|
9
18
|
window.$exportServerStates = serverStates;
|
|
10
19
|
}
|
|
11
20
|
const getIdent = (key) => {
|
|
12
|
-
|
|
13
|
-
ssr.exportParams = true;
|
|
14
|
-
}
|
|
15
|
-
const result = Array.isArray(key) ? JSON.stringify(key) : key.toString();
|
|
16
|
-
{
|
|
17
|
-
ssr.exportParams = false;
|
|
18
|
-
}
|
|
19
|
-
return encode(result);
|
|
21
|
+
return Array.isArray(key) ? key.join("-") : key;
|
|
20
22
|
};
|
|
21
23
|
const getServerValue = (key, def, options) => {
|
|
22
24
|
if (key == undefined) {
|
|
23
25
|
return [def, false];
|
|
24
26
|
}
|
|
25
27
|
const ident = getIdent(key);
|
|
26
|
-
serverStates.set(ident, { options, value: !options?.source ? def : undefined });
|
|
27
|
-
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
serverStates.set(ident, { options, value: !options?.source ? def : undefined, key });
|
|
29
|
+
console.log("CHECK", ident);
|
|
30
|
+
if (ident in initialState) {
|
|
31
|
+
const result = initialState[ident];
|
|
32
|
+
// delete initialState[ident]
|
|
33
|
+
console.log("HAS", ident, result);
|
|
34
|
+
if (result != null && typeof result == 'object' && "data" in result) {
|
|
35
|
+
return [result.data, true];
|
|
36
|
+
}
|
|
37
|
+
return [result, true];
|
|
31
38
|
}
|
|
32
39
|
return [def, false];
|
|
33
40
|
};
|
|
34
41
|
const setServerValue = (key, value, options) => {
|
|
35
42
|
const ident = getIdent(key);
|
|
36
|
-
serverStates.set(ident, { options, value: !options?.source ? value : undefined });
|
|
43
|
+
serverStates.set(ident, { options, value: !options?.source ? value : undefined, key });
|
|
37
44
|
return createDataProxy(value, `${ident}@`);
|
|
38
45
|
};
|
|
39
46
|
|
|
40
|
-
export { getServerValue, serverStates, setServerValue };
|
|
47
|
+
export { getIdent, getServerValue, serverStates, setServerValue };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getIdent } from './serverStates.js';
|
|
2
|
+
import { ssr } from './SSR.js';
|
|
3
|
+
|
|
4
|
+
const test_states = new Map();
|
|
5
|
+
if (window != undefined && ssr.test) {
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
window.$testStates = test_states;
|
|
8
|
+
}
|
|
9
|
+
const setTestState = (key, value, options) => {
|
|
10
|
+
const ident = getIdent(key);
|
|
11
|
+
test_states.set(ident, value);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export { setTestState };
|
|
@@ -2,4 +2,4 @@ import { Dispatch, SetStateAction } from "react";
|
|
|
2
2
|
import { ServerValue } from "./serverStates";
|
|
3
3
|
export type ServerStateMap = Record<string, ServerValue>;
|
|
4
4
|
export type ServerKey = string | string[];
|
|
5
|
-
export declare const useServerState: <T extends ServerValue["value"]>(serverKey: ServerKey | undefined, initialValue: T, options?: ServerValue["options"]) => [T, Dispatch<SetStateAction<T>>,
|
|
5
|
+
export declare const useServerState: <T extends ServerValue["value"]>(serverKey: ServerKey | undefined, initialValue: T, options?: ServerValue["options"]) => [T, Dispatch<SetStateAction<T>>, boolean];
|
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import { ssr } from './SSR.js';
|
|
3
3
|
import { getServerValue, setServerValue } from './serverStates.js';
|
|
4
|
+
import { setTestState } from './testState.js';
|
|
4
5
|
|
|
5
6
|
const useServerState = (serverKey, initialValue, options) => {
|
|
6
7
|
const [serverValue, isInitOnServer] = getServerValue(serverKey, initialValue, options);
|
|
7
8
|
const [value, setStateValue] = useState(serverValue);
|
|
8
|
-
const [isInit, setIsInit] = useState(isInitOnServer);
|
|
9
9
|
const setValue = (value) => {
|
|
10
10
|
setStateValue((prev) => {
|
|
11
11
|
const result = value instanceof Function ? value(prev) : value;
|
|
12
12
|
if (serverKey != undefined && ssr.current) {
|
|
13
13
|
return setServerValue(serverKey, result, options);
|
|
14
14
|
}
|
|
15
|
+
if (serverKey != undefined && ssr.test) {
|
|
16
|
+
setTestState(serverKey, result);
|
|
17
|
+
}
|
|
15
18
|
return result;
|
|
16
19
|
});
|
|
17
20
|
};
|
|
18
|
-
|
|
19
|
-
if (isInit) {
|
|
20
|
-
setIsInit(false);
|
|
21
|
-
return true;
|
|
22
|
-
}
|
|
23
|
-
return false;
|
|
24
|
-
};
|
|
25
|
-
return [value, setValue, initOnServer];
|
|
21
|
+
return [value, setValue, isInitOnServer];
|
|
26
22
|
};
|
|
27
23
|
|
|
28
24
|
export { useServerState };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type DefaultLangType = {
|
|
3
|
+
defaultLang: string;
|
|
4
|
+
langBaseUrl: string;
|
|
5
|
+
source: TranslateSource;
|
|
6
|
+
};
|
|
7
|
+
interface TranslateContextProps {
|
|
8
|
+
translate: (text: string, context?: string) => string;
|
|
9
|
+
changeLang: (lang: string) => void;
|
|
10
|
+
lang: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const useTranslate: () => TranslateContextProps;
|
|
13
|
+
interface TranslateSource {
|
|
14
|
+
from: "cookie" | "url";
|
|
15
|
+
key: string;
|
|
16
|
+
}
|
|
17
|
+
type TranslateConfigProps = DefaultLangType & {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
};
|
|
20
|
+
export declare const TranslateConfig: ({ children, defaultLang, langBaseUrl, source }: TranslateConfigProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { createContext, useContext, useState, useEffect } from 'react';
|
|
3
|
+
import { ssr } from '../server-state/SSR.js';
|
|
4
|
+
|
|
5
|
+
const TranslateContext = createContext(null);
|
|
6
|
+
const useTranslate = () => {
|
|
7
|
+
const context = useContext(TranslateContext);
|
|
8
|
+
if (!context)
|
|
9
|
+
throw new Error("not in context (<TranslateConfig>)");
|
|
10
|
+
return context;
|
|
11
|
+
};
|
|
12
|
+
const ONE_DAY = 1000 * 60 * 60 * 24;
|
|
13
|
+
const getCookie = (key) => {
|
|
14
|
+
const match = document.cookie.match(new RegExp(`(?:^|; )${key.replace(/([$?*|{}()[\]\\/+^])/g, "\\$1")}=([^;]*)`));
|
|
15
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
16
|
+
};
|
|
17
|
+
const setCookie = (key, value, days = 365) => {
|
|
18
|
+
const expires = new Date(Date.now() + days * 864e5).toUTCString();
|
|
19
|
+
document.cookie = `${key}=${encodeURIComponent(value)}; expires=${expires}; path=/`;
|
|
20
|
+
};
|
|
21
|
+
const getStorageKey = (lang) => `lang:${lang}`;
|
|
22
|
+
const loadFromStorage = (lang) => {
|
|
23
|
+
try {
|
|
24
|
+
const raw = localStorage.getItem(getStorageKey(lang));
|
|
25
|
+
if (!raw)
|
|
26
|
+
return null;
|
|
27
|
+
const parsed = JSON.parse(raw);
|
|
28
|
+
if (Date.now() > parsed.expires) {
|
|
29
|
+
localStorage.removeItem(getStorageKey(lang));
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return parsed.data;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const saveToStorage = (lang, data) => {
|
|
39
|
+
localStorage.setItem(getStorageKey(lang), JSON.stringify({
|
|
40
|
+
data,
|
|
41
|
+
expires: Date.now() + ONE_DAY,
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
const TranslateConfig = ({ children, defaultLang, langBaseUrl, source }) => {
|
|
45
|
+
const [lang, setLang] = useState(defaultLang);
|
|
46
|
+
const [langMap, setLangMap] = useState(null);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
window.$langDefaultConfig = {
|
|
50
|
+
defaultLang,
|
|
51
|
+
langBaseUrl,
|
|
52
|
+
source,
|
|
53
|
+
};
|
|
54
|
+
}, []);
|
|
55
|
+
// initial lang from cookie
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (source.from === "cookie") {
|
|
58
|
+
const fromCookie = getCookie(source.key);
|
|
59
|
+
if (fromCookie)
|
|
60
|
+
setLang(fromCookie);
|
|
61
|
+
}
|
|
62
|
+
}, [source.from, source.key]);
|
|
63
|
+
// load translations on lang change
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (lang === defaultLang) {
|
|
66
|
+
setLangMap(null);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const cached = loadFromStorage(lang);
|
|
70
|
+
if (cached) {
|
|
71
|
+
setLangMap(cached);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
fetch(langBaseUrl.replace("*", lang))
|
|
75
|
+
.then(res => {
|
|
76
|
+
if (!res.ok)
|
|
77
|
+
throw new Error("Failed to load lang map");
|
|
78
|
+
return res.json();
|
|
79
|
+
})
|
|
80
|
+
.then((data) => {
|
|
81
|
+
saveToStorage(lang, data);
|
|
82
|
+
setLangMap(data);
|
|
83
|
+
})
|
|
84
|
+
.catch(() => {
|
|
85
|
+
setLangMap(null);
|
|
86
|
+
});
|
|
87
|
+
}, [lang, defaultLang, langBaseUrl]);
|
|
88
|
+
const translate = (text, context) => {
|
|
89
|
+
const key = context ? `${text}(context:${context})` : text;
|
|
90
|
+
if (ssr.current) {
|
|
91
|
+
return `{!${key}!}`;
|
|
92
|
+
}
|
|
93
|
+
if (!langMap)
|
|
94
|
+
return text;
|
|
95
|
+
return langMap[key] ?? langMap[text] ?? text;
|
|
96
|
+
};
|
|
97
|
+
const changeLang = (nextLang) => {
|
|
98
|
+
if (nextLang === lang)
|
|
99
|
+
return;
|
|
100
|
+
if (source.from === "cookie") {
|
|
101
|
+
setCookie(source.key, nextLang);
|
|
102
|
+
}
|
|
103
|
+
setLang(nextLang);
|
|
104
|
+
};
|
|
105
|
+
return jsx(TranslateContext.Provider, { value: { translate, changeLang, lang }, children: children });
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export { TranslateConfig, useTranslate };
|
|
@@ -3,7 +3,7 @@ import { JinraiContext } from '../JinraiContext.js';
|
|
|
3
3
|
import { NuqsAdapter } from 'nuqs/adapters/react';
|
|
4
4
|
|
|
5
5
|
const Adapter = (props) => {
|
|
6
|
-
return (jsx(NuqsAdapter, { children: jsx(JinraiContext.Provider, { value: { deps: props.deps ?? [] }, ...props }) }));
|
|
6
|
+
return (jsx(NuqsAdapter, { children: jsx(JinraiContext.Provider, { value: { deps: props.deps ?? [], search: "" }, ...props }) }));
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export { Adapter };
|
|
@@ -7,8 +7,8 @@ const Adapter = (props) => {
|
|
|
7
7
|
// useLocation требует, чтобы компонент был внутри RouterProvider
|
|
8
8
|
// NuqsAdapter должен быть установлен на верхнем уровне, но может работать внутри роутера
|
|
9
9
|
// для React Router v6 адаптера
|
|
10
|
-
const { pathname } = useLocation();
|
|
11
|
-
return (jsx(NuqsAdapter, { children: jsx(JinraiContext.Provider, { value: { deps: [...(props.deps ?? []), pathname] }, ...props }) }));
|
|
10
|
+
const { pathname, search } = useLocation();
|
|
11
|
+
return (jsx(NuqsAdapter, { children: jsx(JinraiContext.Provider, { value: { deps: [...(props.deps ?? []), pathname], search: search.substring(1) }, ...props }) }));
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export { Adapter };
|
|
@@ -7,8 +7,8 @@ const Adapter = (props) => {
|
|
|
7
7
|
// useLocation требует, чтобы компонент был внутри RouterProvider
|
|
8
8
|
// NuqsAdapter должен быть установлен на верхнем уровне, но может работать внутри роутера
|
|
9
9
|
// для React Router v7 адаптера
|
|
10
|
-
const { pathname } = useLocation();
|
|
11
|
-
return (jsx(NuqsAdapter, { children: jsx(JinraiContext.Provider, { value: { deps: [...(props.deps ?? []), pathname] }, ...props }) }));
|
|
10
|
+
const { pathname, search } = useLocation();
|
|
11
|
+
return (jsx(NuqsAdapter, { children: jsx(JinraiContext.Provider, { value: { deps: [...(props.deps ?? []), pathname], search }, ...props }) }));
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export { Adapter };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { useContext, useMemo } from 'react';
|
|
2
2
|
import { getJinraiValue } from '../search/useSearchValue.js';
|
|
3
3
|
import { JinraiContext } from '../JinraiContext.js';
|
|
4
|
+
import { ssr } from '../../server-state/SSR.js';
|
|
4
5
|
|
|
5
6
|
const useParamsIndex = (index, def = "") => {
|
|
6
7
|
const { deps } = useContext(JinraiContext);
|
|
7
8
|
const value = useMemo(() => location.pathname.split("/")[index + 1] ?? def, deps ? deps : []);
|
|
8
9
|
const stableValue = useMemo(() => {
|
|
9
|
-
return value.bindSource(getJinraiValue(index.toString(), "paramsIndex", "", def)) ;
|
|
10
|
+
return ssr.current ? value.bindSource(getJinraiValue(index.toString(), "paramsIndex", "", def)) : value;
|
|
10
11
|
}, [value]);
|
|
11
12
|
return stableValue;
|
|
12
13
|
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { useContext, useMemo } from 'react';
|
|
2
2
|
import { JinraiContext } from '../JinraiContext.js';
|
|
3
|
+
import { ssr } from '../../server-state/SSR.js';
|
|
3
4
|
import { getJinraiValue } from './useSearchValue.js';
|
|
4
5
|
|
|
5
6
|
const useSearch = () => {
|
|
6
|
-
const {
|
|
7
|
-
const value = useMemo(() => location.search.substring(1), deps ? deps : []);
|
|
7
|
+
const { search } = useContext(JinraiContext);
|
|
8
8
|
const stableValue = useMemo(() => {
|
|
9
|
-
return
|
|
10
|
-
}, [
|
|
9
|
+
return ssr.current ? search.bindSource(getJinraiValue("", "searchFull", "", "")) : search;
|
|
10
|
+
}, [search]);
|
|
11
11
|
return stableValue;
|
|
12
12
|
};
|
|
13
13
|
|