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.
Files changed (85) hide show
  1. package/front.config.json +2 -1
  2. package/index.ts +4 -1
  3. package/lib/bin/bin.js +123 -59
  4. package/lib/index.d.ts +3 -1
  5. package/lib/index.js +3 -1
  6. package/lib/src/bin/agent/agent.d.ts +2 -0
  7. package/lib/src/bin/agent/agent.js +4 -0
  8. package/lib/src/bin/playwright/pageCollector.d.ts +2 -0
  9. package/lib/src/bin/playwright/pageTestCollector.d.ts +6 -0
  10. package/lib/src/bin/playwright/templates.d.ts +6 -1
  11. package/lib/src/bin/routes/Parser.d.ts +25 -2
  12. package/lib/src/bin/routes/Parser.js +5 -0
  13. package/lib/src/bin/routes/getRoutes.d.ts +1 -0
  14. package/lib/src/front/server/useIsServer.d.ts +1 -0
  15. package/lib/src/front/server/useIsServer.js +7 -0
  16. package/lib/src/front/server-state/DataProxy.d.ts +2 -1
  17. package/lib/src/front/server-state/DataProxy.js +122 -60
  18. package/lib/src/front/server-state/SSR.d.ts +3 -0
  19. package/lib/src/front/server-state/SSR.js +18 -3
  20. package/lib/src/front/server-state/orig.d.ts +2 -0
  21. package/lib/src/front/server-state/{real.js → orig.js} +18 -3
  22. package/lib/src/front/server-state/serverStates.d.ts +3 -1
  23. package/lib/src/front/server-state/serverStates.js +24 -17
  24. package/lib/src/front/server-state/testState.d.ts +3 -0
  25. package/lib/src/front/server-state/testState.js +14 -0
  26. package/lib/src/front/server-state/useServerState.d.ts +1 -1
  27. package/lib/src/front/server-state/useServerState.js +5 -9
  28. package/lib/src/front/translate/TranslateConfig.d.ts +21 -0
  29. package/lib/src/front/translate/TranslateConfig.js +108 -0
  30. package/lib/src/front/url/JinraiContext.d.ts +1 -0
  31. package/lib/src/front/url/JinraiContext.js +1 -0
  32. package/lib/src/front/url/adapter/def.js +1 -1
  33. package/lib/src/front/url/adapter/rrd6.js +2 -2
  34. package/lib/src/front/url/adapter/rrd7.js +2 -2
  35. package/lib/src/front/url/params/useParamsIndex.js +2 -1
  36. package/lib/src/front/url/search/useSearch.js +4 -4
  37. package/lib/src/front/url/search/useSearchValue.d.ts +11 -5
  38. package/lib/src/front/url/search/useSearchValue.js +13 -8
  39. package/lib/src/front/wrapper/Custom.d.ts +3 -3
  40. package/lib/src/front/wrapper/Custom.js +18 -1
  41. package/lib/vite/plugin.js +26 -154
  42. package/package.json +9 -1
  43. package/rollup.config.mjs +2 -1
  44. package/src/bin/agent/agent.ts +2 -0
  45. package/src/bin/build/build.ts +23 -10
  46. package/src/bin/playwright/pageCollector.ts +8 -6
  47. package/src/bin/playwright/pageTestCollector.ts +15 -0
  48. package/src/bin/playwright/templates.ts +16 -5
  49. package/src/bin/routes/Parser.ts +100 -32
  50. package/src/bin/routes/getRoutes.ts +5 -1
  51. package/src/front/server/useIsServer.ts +5 -0
  52. package/src/front/server-state/DataProxy.ts +140 -61
  53. package/src/front/server-state/SSR.ts +22 -2
  54. package/src/front/server-state/{real.ts → orig.ts} +19 -2
  55. package/src/front/server-state/serverStates.ts +33 -18
  56. package/src/front/server-state/testState.ts +15 -0
  57. package/src/front/server-state/useServerState.ts +6 -11
  58. package/src/front/translate/TranslateConfig.tsx +153 -0
  59. package/src/front/url/JinraiContext.tsx +2 -0
  60. package/src/front/url/adapter/def.tsx +1 -1
  61. package/src/front/url/adapter/rrd6.tsx +2 -3
  62. package/src/front/url/adapter/rrd7.tsx +2 -2
  63. package/src/front/url/search/useSearch.ts +3 -4
  64. package/src/front/url/search/useSearchValue.ts +25 -13
  65. package/src/front/wrapper/Custom.tsx +28 -4
  66. package/tests/data-proxy/create-dataproxy.test.ts +116 -0
  67. package/tests/{custom.test.ts → parse/custom.test.ts} +2 -2
  68. package/tests/{parse.test.ts → parse/parse.test.ts} +7 -7
  69. package/tsconfig.types.json +1 -0
  70. package/vite/plugin.ts +40 -22
  71. package/lib/src/front/server-state/real.d.ts +0 -1
  72. /package/tests/{content → parse/content}/1.html +0 -0
  73. /package/tests/{content → parse/content}/1_result.json +0 -0
  74. /package/tests/{content → parse/content}/2.html +0 -0
  75. /package/tests/{content → parse/content}/2_result.json +0 -0
  76. /package/tests/{content → parse/content}/3.html +0 -0
  77. /package/tests/{content → parse/content}/3_result.json +0 -0
  78. /package/tests/{content → parse/content}/4.html +0 -0
  79. /package/tests/{content → parse/content}/4_result.json +0 -0
  80. /package/tests/{content → parse/content}/custom.html +0 -0
  81. /package/tests/{content → parse/content}/custom.json +0 -0
  82. /package/tests/{content → parse/content}/index.html +0 -0
  83. /package/tests/{content → parse/content}/index.json +0 -0
  84. /package/tests/{content → parse/content}/index_with_templates.json +0 -0
  85. /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 { value: data };
16
+ return { $__ROOT__: data };
17
17
  default:
18
18
  return () => `{{${path}}}`;
19
19
  }
20
20
  };
21
- const createDataProxy = (data, path = "") => {
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: (_, prop) => {
26
- // if (typeof prop == "symbol") return data[prop]
27
- if (!(typeof data == "object" && data !== null && prop in data))
28
- // DEV TOOLS
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
- return data[Symbol.iterator];
42
- case "$$typeof":
43
- case "type":
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
- // SELF
54
- if (prop.startsWith("$"))
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
- // TYPES
75
+ }
76
+ // ---------------------------
77
+ // 4. Types special cases
78
+ // ---------------------------
57
79
  switch (typeof data) {
58
80
  case "string":
59
- switch (prop) {
60
- case "length":
61
- case "entries":
62
- return undefined;
63
- }
81
+ if (prop === "length" || prop === "entries")
82
+ return undefined;
83
+ break;
64
84
  case "number":
65
- switch (prop) {
66
- case "@@iterator":
67
- return undefined;
68
- }
85
+ if (prop === "@@iterator")
86
+ return undefined;
87
+ break;
69
88
  default:
70
- switch (prop) {
71
- case "then":
72
- return undefined;
73
- }
89
+ if (prop === "then")
90
+ return undefined;
74
91
  }
75
- // OTHER
76
- switch (prop) {
77
- case "find":
78
- return data[prop];
79
- case "map":
80
- case "forEach":
81
- return (callback) => React.createElement("loopwrapper", null, [
82
- `ArrayDataKey=${path}|`,
83
- Object.entries(data)
84
- .slice(0, 1)
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,4 +1,7 @@
1
1
  export declare const ssr: {
2
2
  current: boolean;
3
+ test: boolean;
3
4
  exportParams: boolean;
5
+ exportToJV: boolean;
4
6
  };
7
+ export declare const stringifyInput: (input: any) => string;
@@ -1,6 +1,21 @@
1
+ import { ViteAgent, JinraiAgent } from '../../bin/agent/agent.js';
2
+
1
3
  const ssr = {
2
- current: true, //navigator.userAgent == "____JINRAI_CLIENT____",
3
- exportParams: false,
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 };
@@ -0,0 +1,2 @@
1
+ export declare function orig<T>(value: T): T;
2
+ export declare const original: typeof orig;
@@ -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 real(value) {
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
- return value.startsWith("{{") && value.endsWith("}}") ? getArrayByPath(value.slice(2, -2)) : value;
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 { real };
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"]) => import("./DataProxy").DataProxy;
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
- // @ts-ignore
28
- if (window != undefined && window?.__serverInitialStates__ && ident in window.__serverInitialStates__) {
29
- // @ts-ignore
30
- return [window.__serverInitialStates__[ident], true];
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,3 @@
1
+ import { ServerValue } from "./serverStates";
2
+ import { ServerKey } from "./useServerState";
3
+ export declare const setTestState: (key: ServerKey, value: ServerValue["value"], options?: ServerValue["options"]) => void;
@@ -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>>, () => boolean];
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
- const initOnServer = () => {
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 };
@@ -2,5 +2,6 @@ import { DependencyList, ReactNode } from "react";
2
2
  export interface JinraiProps {
3
3
  deps?: DependencyList;
4
4
  children?: ReactNode;
5
+ search: string;
5
6
  }
6
7
  export declare const JinraiContext: import("react").Context<JinraiProps>;
@@ -3,6 +3,7 @@ import { createContext } from 'react';
3
3
  const JinraiContext = createContext({
4
4
  deps: [],
5
5
  children: undefined,
6
+ search: ""
6
7
  });
7
8
 
8
9
  export { JinraiContext };
@@ -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 { deps } = useContext(JinraiContext);
7
- const value = useMemo(() => location.search.substring(1), deps ? deps : []);
7
+ const { search } = useContext(JinraiContext);
8
8
  const stableValue = useMemo(() => {
9
- return value.bindSource(getJinraiValue("", "search", "", "")) ;
10
- }, [value]);
9
+ return ssr.current ? search.bindSource(getJinraiValue("", "searchFull", "", "")) : search;
10
+ }, [search]);
11
11
  return stableValue;
12
12
  };
13
13