@next-core/react-runtime 1.8.0 → 1.10.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/dist/cjs/index.js +44 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/useCheckPermissions.js +86 -0
- package/dist/cjs/useCheckPermissions.js.map +1 -0
- package/dist/cjs/useControlledState.js +144 -0
- package/dist/cjs/useControlledState.js.map +1 -0
- package/dist/cjs/useFeatureFlags.js +51 -0
- package/dist/cjs/useFeatureFlags.js.map +1 -0
- package/dist/cjs/useSystemInfo.js +74 -0
- package/dist/cjs/useSystemInfo.js.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/useCheckPermissions.js +83 -0
- package/dist/esm/useCheckPermissions.js.map +1 -0
- package/dist/esm/useControlledState.js +139 -0
- package/dist/esm/useControlledState.js.map +1 -0
- package/dist/esm/useFeatureFlags.js +44 -0
- package/dist/esm/useFeatureFlags.js.map +1 -0
- package/dist/esm/useSystemInfo.js +68 -0
- package/dist/esm/useSystemInfo.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/useCheckPermissions.d.ts +69 -0
- package/dist/types/useControlledState.d.ts +98 -0
- package/dist/types/useFeatureFlags.d.ts +40 -0
- package/dist/types/useSystemInfo.d.ts +62 -0
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -168,4 +168,48 @@ Object.keys(_useLocation).forEach(function (key) {
|
|
|
168
168
|
}
|
|
169
169
|
});
|
|
170
170
|
});
|
|
171
|
+
var _useFeatureFlags = require("./useFeatureFlags.js");
|
|
172
|
+
Object.keys(_useFeatureFlags).forEach(function (key) {
|
|
173
|
+
if (key === "default" || key === "__esModule") return;
|
|
174
|
+
if (key in exports && exports[key] === _useFeatureFlags[key]) return;
|
|
175
|
+
Object.defineProperty(exports, key, {
|
|
176
|
+
enumerable: true,
|
|
177
|
+
get: function () {
|
|
178
|
+
return _useFeatureFlags[key];
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
var _useSystemInfo = require("./useSystemInfo.js");
|
|
183
|
+
Object.keys(_useSystemInfo).forEach(function (key) {
|
|
184
|
+
if (key === "default" || key === "__esModule") return;
|
|
185
|
+
if (key in exports && exports[key] === _useSystemInfo[key]) return;
|
|
186
|
+
Object.defineProperty(exports, key, {
|
|
187
|
+
enumerable: true,
|
|
188
|
+
get: function () {
|
|
189
|
+
return _useSystemInfo[key];
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
var _useCheckPermissions = require("./useCheckPermissions.js");
|
|
194
|
+
Object.keys(_useCheckPermissions).forEach(function (key) {
|
|
195
|
+
if (key === "default" || key === "__esModule") return;
|
|
196
|
+
if (key in exports && exports[key] === _useCheckPermissions[key]) return;
|
|
197
|
+
Object.defineProperty(exports, key, {
|
|
198
|
+
enumerable: true,
|
|
199
|
+
get: function () {
|
|
200
|
+
return _useCheckPermissions[key];
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
var _useControlledState = require("./useControlledState.js");
|
|
205
|
+
Object.keys(_useControlledState).forEach(function (key) {
|
|
206
|
+
if (key === "default" || key === "__esModule") return;
|
|
207
|
+
if (key in exports && exports[key] === _useControlledState[key]) return;
|
|
208
|
+
Object.defineProperty(exports, key, {
|
|
209
|
+
enumerable: true,
|
|
210
|
+
get: function () {
|
|
211
|
+
return _useControlledState[key];
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
});
|
|
171
215
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_ReactUseBrick","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_useCurrentTheme","_useCurrentApp","_useRecentApps","_useRouteRender","_useProvider","_asyncWrapBrick","_useNavConfig","_useLazyWrapBrick","_usePathParams","_useSearchParams","_useParams","_useHistory","_useAuth","_useLocation"],"sources":["../../src/index.ts"],"sourcesContent":["export * from \"./ReactUseBrick.js\";\nexport * from \"./useCurrentTheme.js\";\nexport * from \"./useCurrentApp.js\";\nexport * from \"./useRecentApps.js\";\nexport * from \"./useRouteRender.js\";\nexport * from \"./useProvider/useProvider.js\";\nexport * from \"./asyncWrapBrick.js\";\nexport * from \"./useNavConfig.js\";\nexport * from \"./useLazyWrapBrick.js\";\nexport * from \"./usePathParams.js\";\nexport * from \"./useSearchParams.js\";\nexport * from \"./useParams.js\";\nexport * from \"./useHistory.js\";\nexport * from \"./useAuth.js\";\nexport * from \"./useLocation.js\";\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":["_ReactUseBrick","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_useCurrentTheme","_useCurrentApp","_useRecentApps","_useRouteRender","_useProvider","_asyncWrapBrick","_useNavConfig","_useLazyWrapBrick","_usePathParams","_useSearchParams","_useParams","_useHistory","_useAuth","_useLocation","_useFeatureFlags","_useSystemInfo","_useCheckPermissions","_useControlledState"],"sources":["../../src/index.ts"],"sourcesContent":["export * from \"./ReactUseBrick.js\";\nexport * from \"./useCurrentTheme.js\";\nexport * from \"./useCurrentApp.js\";\nexport * from \"./useRecentApps.js\";\nexport * from \"./useRouteRender.js\";\nexport * from \"./useProvider/useProvider.js\";\nexport * from \"./asyncWrapBrick.js\";\nexport * from \"./useNavConfig.js\";\nexport * from \"./useLazyWrapBrick.js\";\nexport * from \"./usePathParams.js\";\nexport * from \"./useSearchParams.js\";\nexport * from \"./useParams.js\";\nexport * from \"./useHistory.js\";\nexport * from \"./useAuth.js\";\nexport * from \"./useLocation.js\";\nexport * from \"./useFeatureFlags.js\";\nexport * from \"./useSystemInfo.js\";\nexport * from \"./useCheckPermissions.js\";\nexport * from \"./useControlledState.js\";\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.useCheckPermissions = useCheckPermissions;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _easyopsRuntime = require("@next-core/easyops-runtime");
|
|
10
|
+
/**
|
|
11
|
+
* 检查用户权限的 React hooks。
|
|
12
|
+
*
|
|
13
|
+
* 此 hook 用于检查当前登录用户是否拥有指定的权限操作。
|
|
14
|
+
* 权限必须在 storyboard 配置的 `permissionsPreCheck` 中预先声明,
|
|
15
|
+
* 否则会返回 false 并在控制台输出错误。
|
|
16
|
+
*
|
|
17
|
+
* **工作原理:**
|
|
18
|
+
* - 权限会在路由渲染时自动预检查(通过 `preCheckPermissions`)
|
|
19
|
+
* - 此 hook 查询已缓存的权限结果(同步操作)
|
|
20
|
+
* - 管理员用户始终返回 true
|
|
21
|
+
* - 未登录用户始终返回 false
|
|
22
|
+
*
|
|
23
|
+
* **注意事项:**
|
|
24
|
+
* 1. 权限必须在 `permissionsPreCheck` 中声明
|
|
25
|
+
* 2. 所有传入的 actions 都必须有权限才返回 true
|
|
26
|
+
* 3. 权限检查结果会被缓存,避免重复计算
|
|
27
|
+
*
|
|
28
|
+
* @param actions - 需要检查的权限操作列表
|
|
29
|
+
* @returns 是否拥有所有指定的权限
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
*
|
|
33
|
+
* ```tsx
|
|
34
|
+
* // 检查单个权限
|
|
35
|
+
* function DeleteButton() {
|
|
36
|
+
* const canDelete = useCheckPermissions("my-app:user.delete");
|
|
37
|
+
*
|
|
38
|
+
* if (!canDelete) {
|
|
39
|
+
* return null;
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* return <button onClick={handleDelete}>Delete</button>;
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* // 检查多个权限(需要全部拥有)
|
|
50
|
+
* function AdminPanel() {
|
|
51
|
+
* const hasAccess = useCheckPermissions(
|
|
52
|
+
* "my-app:admin.read",
|
|
53
|
+
* "my-app:admin.write"
|
|
54
|
+
* );
|
|
55
|
+
*
|
|
56
|
+
* if (!hasAccess) {
|
|
57
|
+
* return <div>Access Denied</div>;
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* return <div>Admin Panel Content</div>;
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
*
|
|
66
|
+
* ```tsx
|
|
67
|
+
* // 在 storyboard 中配置权限预检查
|
|
68
|
+
* // routes.yaml
|
|
69
|
+
* routes:
|
|
70
|
+
* - path: /users
|
|
71
|
+
* permissionsPreCheck:
|
|
72
|
+
* - "my-app:user.read"
|
|
73
|
+
* - "my-app:user.delete"
|
|
74
|
+
* bricks:
|
|
75
|
+
* - brick: "my-brick"
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
function useCheckPermissions(...actions) {
|
|
79
|
+
// 使用 useMemo 缓存权限检查结果
|
|
80
|
+
// 因为权限在会话期间是稳定的,只依赖于 actions 列表
|
|
81
|
+
return _react.default.useMemo(() => _easyopsRuntime.checkPermissions.checkPermissions(...actions),
|
|
82
|
+
// 序列化 actions 作为依赖,避免数组引用变化导致重新计算
|
|
83
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
84
|
+
[JSON.stringify(actions)]);
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=useCheckPermissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCheckPermissions.js","names":["_react","_interopRequireDefault","require","_easyopsRuntime","useCheckPermissions","actions","React","useMemo","checkPermissions","JSON","stringify"],"sources":["../../src/useCheckPermissions.ts"],"sourcesContent":["import React from \"react\";\nimport { checkPermissions } from \"@next-core/easyops-runtime\";\n\n/**\n * 检查用户权限的 React hooks。\n *\n * 此 hook 用于检查当前登录用户是否拥有指定的权限操作。\n * 权限必须在 storyboard 配置的 `permissionsPreCheck` 中预先声明,\n * 否则会返回 false 并在控制台输出错误。\n *\n * **工作原理:**\n * - 权限会在路由渲染时自动预检查(通过 `preCheckPermissions`)\n * - 此 hook 查询已缓存的权限结果(同步操作)\n * - 管理员用户始终返回 true\n * - 未登录用户始终返回 false\n *\n * **注意事项:**\n * 1. 权限必须在 `permissionsPreCheck` 中声明\n * 2. 所有传入的 actions 都必须有权限才返回 true\n * 3. 权限检查结果会被缓存,避免重复计算\n *\n * @param actions - 需要检查的权限操作列表\n * @returns 是否拥有所有指定的权限\n *\n * @example\n *\n * ```tsx\n * // 检查单个权限\n * function DeleteButton() {\n * const canDelete = useCheckPermissions(\"my-app:user.delete\");\n *\n * if (!canDelete) {\n * return null;\n * }\n *\n * return <button onClick={handleDelete}>Delete</button>;\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 检查多个权限(需要全部拥有)\n * function AdminPanel() {\n * const hasAccess = useCheckPermissions(\n * \"my-app:admin.read\",\n * \"my-app:admin.write\"\n * );\n *\n * if (!hasAccess) {\n * return <div>Access Denied</div>;\n * }\n *\n * return <div>Admin Panel Content</div>;\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 在 storyboard 中配置权限预检查\n * // routes.yaml\n * routes:\n * - path: /users\n * permissionsPreCheck:\n * - \"my-app:user.read\"\n * - \"my-app:user.delete\"\n * bricks:\n * - brick: \"my-brick\"\n * ```\n */\nexport function useCheckPermissions(...actions: string[]): boolean {\n // 使用 useMemo 缓存权限检查结果\n // 因为权限在会话期间是稳定的,只依赖于 actions 列表\n return React.useMemo(\n () => checkPermissions.checkPermissions(...actions),\n // 序列化 actions 作为依赖,避免数组引用变化导致重新计算\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(actions)]\n );\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,eAAA,GAAAD,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,mBAAmBA,CAAC,GAAGC,OAAiB,EAAW;EACjE;EACA;EACA,OAAOC,cAAK,CAACC,OAAO,CAClB,MAAMC,gCAAgB,CAACA,gBAAgB,CAAC,GAAGH,OAAO,CAAC;EACnD;EACA;EACA,CAACI,IAAI,CAACC,SAAS,CAACL,OAAO,CAAC,CAC1B,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.useControlledState = useControlledState;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _lodash = require("lodash");
|
|
10
|
+
/**
|
|
11
|
+
* 受控/非受控混合模式的通用 Hook。
|
|
12
|
+
*
|
|
13
|
+
* 此 hook 允许组件既支持受控模式(由父组件通过 props 控制状态),
|
|
14
|
+
* 也支持非受控模式(组件自己管理内部状态)。
|
|
15
|
+
*
|
|
16
|
+
* **工作原理:**
|
|
17
|
+
* - 当 `propValue !== undefined` 时,组件处于**受控模式**,状态跟随 prop 更新
|
|
18
|
+
* - 当 `propValue === undefined` 时,组件处于**非受控模式**,使用内部状态
|
|
19
|
+
* - 支持深度比较选项,避免复杂对象引用变化导致的不必要更新
|
|
20
|
+
*
|
|
21
|
+
* **使用场景:**
|
|
22
|
+
* 1. 表单组件需要支持受控和非受控两种模式
|
|
23
|
+
* 2. 组件状态可能由父组件控制,也可能自己管理
|
|
24
|
+
* 3. 复杂对象状态需要避免不必要的重新渲染
|
|
25
|
+
*
|
|
26
|
+
* @template T - 状态值的类型
|
|
27
|
+
* @param propValue - 来自 props 的值(undefined 表示非受控模式)
|
|
28
|
+
* @param defaultValue - 默认值(props 为 undefined 时使用)
|
|
29
|
+
* @param deepCompare - 是否使用深度比较(用于复杂对象,默认 false)
|
|
30
|
+
* @returns 返回 [当前值, 设置值的函数],类似 useState
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
*
|
|
34
|
+
* ```tsx
|
|
35
|
+
* // 简单值(字符串、数字)
|
|
36
|
+
* function MyComponent({ deployed }: { deployed?: string }) {
|
|
37
|
+
* const [value, setValue] = useControlledState(deployed, 'host');
|
|
38
|
+
*
|
|
39
|
+
* return (
|
|
40
|
+
* <select value={value} onChange={(e) => setValue(e.target.value)}>
|
|
41
|
+
* <option value="host">Host</option>
|
|
42
|
+
* <option value="container">Container</option>
|
|
43
|
+
* </select>
|
|
44
|
+
* );
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* // 使用方式 1:受控模式
|
|
48
|
+
* <MyComponent deployed="container" />
|
|
49
|
+
*
|
|
50
|
+
* // 使用方式 2:非受控模式
|
|
51
|
+
* <MyComponent />
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
*
|
|
56
|
+
* ```tsx
|
|
57
|
+
* // 复杂对象(启用深度比较)
|
|
58
|
+
* interface Config {
|
|
59
|
+
* host: string;
|
|
60
|
+
* port: number;
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* function ConfigEditor({ config }: { config?: Config }) {
|
|
64
|
+
* const [value, setValue] = useControlledState<Config | null>(
|
|
65
|
+
* config,
|
|
66
|
+
* null,
|
|
67
|
+
* true // 启用深度比较
|
|
68
|
+
* );
|
|
69
|
+
*
|
|
70
|
+
* return <div>{JSON.stringify(value)}</div>;
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
*
|
|
76
|
+
* ```tsx
|
|
77
|
+
* // 与 onChange 回调结合
|
|
78
|
+
* function Input({
|
|
79
|
+
* value,
|
|
80
|
+
* defaultValue = '',
|
|
81
|
+
* onChange
|
|
82
|
+
* }: {
|
|
83
|
+
* value?: string;
|
|
84
|
+
* defaultValue?: string;
|
|
85
|
+
* onChange?: (val: string) => void;
|
|
86
|
+
* }) {
|
|
87
|
+
* const [internalValue, setInternalValue] = useControlledState(
|
|
88
|
+
* value,
|
|
89
|
+
* defaultValue
|
|
90
|
+
* );
|
|
91
|
+
*
|
|
92
|
+
* const handleChange = (newValue: string) => {
|
|
93
|
+
* setInternalValue(newValue);
|
|
94
|
+
* onChange?.(newValue);
|
|
95
|
+
* };
|
|
96
|
+
*
|
|
97
|
+
* return (
|
|
98
|
+
* <input
|
|
99
|
+
* value={internalValue}
|
|
100
|
+
* onChange={(e) => handleChange(e.target.value)}
|
|
101
|
+
* />
|
|
102
|
+
* );
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
function useControlledState(propValue, defaultValue, deepCompare = false) {
|
|
107
|
+
// 初始化内部状态
|
|
108
|
+
// 如果 propValue 不是 undefined,使用 propValue;否则使用 defaultValue
|
|
109
|
+
const [internalValue, setInternalValue] = _react.default.useState(propValue !== undefined ? propValue : defaultValue);
|
|
110
|
+
const isControlled = propValue !== undefined;
|
|
111
|
+
|
|
112
|
+
// 在受控模式下同步 propValue 到 internalValue
|
|
113
|
+
_react.default.useEffect(() => {
|
|
114
|
+
if (isControlled) {
|
|
115
|
+
if (deepCompare) {
|
|
116
|
+
// 深度比较模式:只有值真正变化时才更新
|
|
117
|
+
setInternalValue(prev => (0, _lodash.isEqual)(prev, propValue) ? prev : propValue);
|
|
118
|
+
} else {
|
|
119
|
+
// 浅比较模式:直接更新(React 会自动优化相同值)
|
|
120
|
+
setInternalValue(propValue);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// 注意:当 propValue 变为 undefined 时,不更新 internalValue
|
|
124
|
+
// 这样可以保持最后一次的值,实现从受控切换到非受控的平滑过渡
|
|
125
|
+
}, [isControlled, propValue, deepCompare]);
|
|
126
|
+
|
|
127
|
+
// 计算最终返回的值
|
|
128
|
+
let value;
|
|
129
|
+
if (isControlled) {
|
|
130
|
+
if (deepCompare) {
|
|
131
|
+
// 深度比较模式:如果内容相同,返回 internalValue 保持引用稳定
|
|
132
|
+
// 否则返回 propValue
|
|
133
|
+
value = (0, _lodash.isEqual)(internalValue, propValue) ? internalValue : propValue;
|
|
134
|
+
} else {
|
|
135
|
+
// 浅比较模式:直接返回 propValue,确保受控模式下值始终同步
|
|
136
|
+
value = propValue;
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
// 非受控模式:返回 internalValue
|
|
140
|
+
value = internalValue;
|
|
141
|
+
}
|
|
142
|
+
return [value, setInternalValue];
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=useControlledState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useControlledState.js","names":["_react","_interopRequireDefault","require","_lodash","useControlledState","propValue","defaultValue","deepCompare","internalValue","setInternalValue","React","useState","undefined","isControlled","useEffect","prev","isEqual","value"],"sources":["../../src/useControlledState.ts"],"sourcesContent":["import React from \"react\";\nimport { isEqual } from \"lodash\";\n\n/**\n * 受控/非受控混合模式的通用 Hook。\n *\n * 此 hook 允许组件既支持受控模式(由父组件通过 props 控制状态),\n * 也支持非受控模式(组件自己管理内部状态)。\n *\n * **工作原理:**\n * - 当 `propValue !== undefined` 时,组件处于**受控模式**,状态跟随 prop 更新\n * - 当 `propValue === undefined` 时,组件处于**非受控模式**,使用内部状态\n * - 支持深度比较选项,避免复杂对象引用变化导致的不必要更新\n *\n * **使用场景:**\n * 1. 表单组件需要支持受控和非受控两种模式\n * 2. 组件状态可能由父组件控制,也可能自己管理\n * 3. 复杂对象状态需要避免不必要的重新渲染\n *\n * @template T - 状态值的类型\n * @param propValue - 来自 props 的值(undefined 表示非受控模式)\n * @param defaultValue - 默认值(props 为 undefined 时使用)\n * @param deepCompare - 是否使用深度比较(用于复杂对象,默认 false)\n * @returns 返回 [当前值, 设置值的函数],类似 useState\n *\n * @example\n *\n * ```tsx\n * // 简单值(字符串、数字)\n * function MyComponent({ deployed }: { deployed?: string }) {\n * const [value, setValue] = useControlledState(deployed, 'host');\n *\n * return (\n * <select value={value} onChange={(e) => setValue(e.target.value)}>\n * <option value=\"host\">Host</option>\n * <option value=\"container\">Container</option>\n * </select>\n * );\n * }\n *\n * // 使用方式 1:受控模式\n * <MyComponent deployed=\"container\" />\n *\n * // 使用方式 2:非受控模式\n * <MyComponent />\n * ```\n *\n * @example\n *\n * ```tsx\n * // 复杂对象(启用深度比较)\n * interface Config {\n * host: string;\n * port: number;\n * }\n *\n * function ConfigEditor({ config }: { config?: Config }) {\n * const [value, setValue] = useControlledState<Config | null>(\n * config,\n * null,\n * true // 启用深度比较\n * );\n *\n * return <div>{JSON.stringify(value)}</div>;\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 与 onChange 回调结合\n * function Input({\n * value,\n * defaultValue = '',\n * onChange\n * }: {\n * value?: string;\n * defaultValue?: string;\n * onChange?: (val: string) => void;\n * }) {\n * const [internalValue, setInternalValue] = useControlledState(\n * value,\n * defaultValue\n * );\n *\n * const handleChange = (newValue: string) => {\n * setInternalValue(newValue);\n * onChange?.(newValue);\n * };\n *\n * return (\n * <input\n * value={internalValue}\n * onChange={(e) => handleChange(e.target.value)}\n * />\n * );\n * }\n * ```\n */\nexport function useControlledState<T>(\n propValue: T | undefined,\n defaultValue: T,\n deepCompare = false\n): [T, React.Dispatch<React.SetStateAction<T>>] {\n // 初始化内部状态\n // 如果 propValue 不是 undefined,使用 propValue;否则使用 defaultValue\n const [internalValue, setInternalValue] = React.useState<T>(\n propValue !== undefined ? propValue : defaultValue\n );\n\n const isControlled = propValue !== undefined;\n\n // 在受控模式下同步 propValue 到 internalValue\n React.useEffect(() => {\n if (isControlled) {\n if (deepCompare) {\n // 深度比较模式:只有值真正变化时才更新\n setInternalValue((prev) =>\n isEqual(prev, propValue) ? prev : propValue\n );\n } else {\n // 浅比较模式:直接更新(React 会自动优化相同值)\n setInternalValue(propValue);\n }\n }\n // 注意:当 propValue 变为 undefined 时,不更新 internalValue\n // 这样可以保持最后一次的值,实现从受控切换到非受控的平滑过渡\n }, [isControlled, propValue, deepCompare]);\n\n // 计算最终返回的值\n let value: T;\n if (isControlled) {\n if (deepCompare) {\n // 深度比较模式:如果内容相同,返回 internalValue 保持引用稳定\n // 否则返回 propValue\n value = isEqual(internalValue, propValue) ? internalValue : propValue;\n } else {\n // 浅比较模式:直接返回 propValue,确保受控模式下值始终同步\n value = propValue;\n }\n } else {\n // 非受控模式:返回 internalValue\n value = internalValue;\n }\n\n return [value, setInternalValue];\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,kBAAkBA,CAChCC,SAAwB,EACxBC,YAAe,EACfC,WAAW,GAAG,KAAK,EAC2B;EAC9C;EACA;EACA,MAAM,CAACC,aAAa,EAAEC,gBAAgB,CAAC,GAAGC,cAAK,CAACC,QAAQ,CACtDN,SAAS,KAAKO,SAAS,GAAGP,SAAS,GAAGC,YACxC,CAAC;EAED,MAAMO,YAAY,GAAGR,SAAS,KAAKO,SAAS;;EAE5C;EACAF,cAAK,CAACI,SAAS,CAAC,MAAM;IACpB,IAAID,YAAY,EAAE;MAChB,IAAIN,WAAW,EAAE;QACf;QACAE,gBAAgB,CAAEM,IAAI,IACpB,IAAAC,eAAO,EAACD,IAAI,EAAEV,SAAS,CAAC,GAAGU,IAAI,GAAGV,SACpC,CAAC;MACH,CAAC,MAAM;QACL;QACAI,gBAAgB,CAACJ,SAAS,CAAC;MAC7B;IACF;IACA;IACA;EACF,CAAC,EAAE,CAACQ,YAAY,EAAER,SAAS,EAAEE,WAAW,CAAC,CAAC;;EAE1C;EACA,IAAIU,KAAQ;EACZ,IAAIJ,YAAY,EAAE;IAChB,IAAIN,WAAW,EAAE;MACf;MACA;MACAU,KAAK,GAAG,IAAAD,eAAO,EAACR,aAAa,EAAEH,SAAS,CAAC,GAAGG,aAAa,GAAGH,SAAS;IACvE,CAAC,MAAM;MACL;MACAY,KAAK,GAAGZ,SAAS;IACnB;EACF,CAAC,MAAM;IACL;IACAY,KAAK,GAAGT,aAAa;EACvB;EAEA,OAAO,CAACS,KAAK,EAAER,gBAAgB,CAAC;AAClC","ignoreList":[]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.useFeatureFlags = useFeatureFlags;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _runtime = require("@next-core/runtime");
|
|
10
|
+
/**
|
|
11
|
+
* 获取特性开关配置的 React hooks。
|
|
12
|
+
*
|
|
13
|
+
* 特性开关用于控制功能的启用或禁用,可以在全局设置或应用级别配置。
|
|
14
|
+
* 使用 useMemo 确保返回的对象引用稳定,避免不必要的组件重渲染。
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
*
|
|
18
|
+
* ```tsx
|
|
19
|
+
* function MyReactComponent() {
|
|
20
|
+
* const flags = useFeatureFlags();
|
|
21
|
+
*
|
|
22
|
+
* if (flags["my-new-feature"]) {
|
|
23
|
+
* return <NewFeature />;
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* return <OldFeature />;
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
*
|
|
32
|
+
* ```tsx
|
|
33
|
+
* // 检查特定功能是否启用
|
|
34
|
+
* function FeatureToggle() {
|
|
35
|
+
* const flags = useFeatureFlags();
|
|
36
|
+
* const isEnabled = flags["experimental-mode"] ?? false;
|
|
37
|
+
*
|
|
38
|
+
* return (
|
|
39
|
+
* <div>
|
|
40
|
+
* Experimental Mode: {isEnabled ? "ON" : "OFF"}
|
|
41
|
+
* </div>
|
|
42
|
+
* );
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @returns 特性开关配置对象,键为特性名称,值为布尔值。
|
|
47
|
+
*/
|
|
48
|
+
function useFeatureFlags() {
|
|
49
|
+
return _react.default.useMemo(() => (0, _runtime.getRuntime)().getFeatureFlags(), []);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=useFeatureFlags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeatureFlags.js","names":["_react","_interopRequireDefault","require","_runtime","useFeatureFlags","React","useMemo","getRuntime","getFeatureFlags"],"sources":["../../src/useFeatureFlags.ts"],"sourcesContent":["import React from \"react\";\nimport { getRuntime } from \"@next-core/runtime\";\nimport type { FeatureFlags } from \"@next-core/types\";\n\n/**\n * 获取特性开关配置的 React hooks。\n *\n * 特性开关用于控制功能的启用或禁用,可以在全局设置或应用级别配置。\n * 使用 useMemo 确保返回的对象引用稳定,避免不必要的组件重渲染。\n *\n * @example\n *\n * ```tsx\n * function MyReactComponent() {\n * const flags = useFeatureFlags();\n *\n * if (flags[\"my-new-feature\"]) {\n * return <NewFeature />;\n * }\n *\n * return <OldFeature />;\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 检查特定功能是否启用\n * function FeatureToggle() {\n * const flags = useFeatureFlags();\n * const isEnabled = flags[\"experimental-mode\"] ?? false;\n *\n * return (\n * <div>\n * Experimental Mode: {isEnabled ? \"ON\" : \"OFF\"}\n * </div>\n * );\n * }\n * ```\n *\n * @returns 特性开关配置对象,键为特性名称,值为布尔值。\n */\nexport function useFeatureFlags(): FeatureFlags {\n return React.useMemo(() => getRuntime().getFeatureFlags(), []);\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,eAAeA,CAAA,EAAiB;EAC9C,OAAOC,cAAK,CAACC,OAAO,CAAC,MAAM,IAAAC,mBAAU,EAAC,CAAC,CAACC,eAAe,CAAC,CAAC,EAAE,EAAE,CAAC;AAChE","ignoreList":[]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.useSystemInfo = useSystemInfo;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _runtime = require("@next-core/runtime");
|
|
10
|
+
var _easyopsRuntime = require("@next-core/easyops-runtime");
|
|
11
|
+
/**
|
|
12
|
+
* 系统信息接口,包含认证信息、页面信息和品牌设置。
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 获取系统信息的 React hooks。
|
|
17
|
+
*
|
|
18
|
+
* 系统信息包括:
|
|
19
|
+
* - 用户认证信息(username, userInstanceId, org 等)
|
|
20
|
+
* - 页面信息(isInIframe, isInIframeOfNext 等)
|
|
21
|
+
* - 品牌设置(base_title 等)
|
|
22
|
+
*
|
|
23
|
+
* **注意**: 使用 useMemo 确保返回的对象引用稳定,
|
|
24
|
+
* 避免不必要的组件重渲染。系统信息在会话期间保持稳定。
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
*
|
|
28
|
+
* ```tsx
|
|
29
|
+
* function MyReactComponent() {
|
|
30
|
+
* const sys = useSystemInfo();
|
|
31
|
+
*
|
|
32
|
+
* return (
|
|
33
|
+
* <div>
|
|
34
|
+
* <p>User: {sys.username}</p>
|
|
35
|
+
* <p>Org: {sys.org}</p>
|
|
36
|
+
* <p>In iframe: {sys.isInIframe ? "Yes" : "No"}</p>
|
|
37
|
+
* <p>Brand: {sys.settings.brand.base_title}</p>
|
|
38
|
+
* </div>
|
|
39
|
+
* );
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
*
|
|
45
|
+
* ```tsx
|
|
46
|
+
* // 检查是否在 iframe 中
|
|
47
|
+
* function IframeDetector() {
|
|
48
|
+
* const sys = useSystemInfo();
|
|
49
|
+
*
|
|
50
|
+
* if (sys.isInIframe) {
|
|
51
|
+
* return <div>Running in iframe mode</div>;
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* return <div>Running in standalone mode</div>;
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @returns 系统信息对象。
|
|
59
|
+
*/
|
|
60
|
+
function useSystemInfo() {
|
|
61
|
+
return _react.default.useMemo(() => {
|
|
62
|
+
const authInfo = _easyopsRuntime.auth.getAuth();
|
|
63
|
+
const pageInfo = (0, _runtime.getPageInfo)();
|
|
64
|
+
const brandSettings = (0, _runtime.getRuntime)().getBrandSettings();
|
|
65
|
+
return {
|
|
66
|
+
...authInfo,
|
|
67
|
+
...pageInfo,
|
|
68
|
+
settings: {
|
|
69
|
+
brand: brandSettings
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}, []);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=useSystemInfo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSystemInfo.js","names":["_react","_interopRequireDefault","require","_runtime","_easyopsRuntime","useSystemInfo","React","useMemo","authInfo","auth","getAuth","pageInfo","getPageInfo","brandSettings","getRuntime","getBrandSettings","settings","brand"],"sources":["../../src/useSystemInfo.ts"],"sourcesContent":["import React from \"react\";\nimport { getRuntime, getPageInfo } from \"@next-core/runtime\";\nimport { auth } from \"@next-core/easyops-runtime\";\nimport type { PageInfo } from \"@next-core/runtime\";\n\n/**\n * 系统信息接口,包含认证信息、页面信息和品牌设置。\n */\nexport interface SystemInfo extends PageInfo {\n /** 用户认证信息 */\n username?: string;\n userInstanceId?: string;\n org?: number;\n [key: string]: unknown;\n\n /** 系统设置 */\n settings: {\n /** 品牌设置 */\n brand: Record<string, string>;\n };\n}\n\n/**\n * 获取系统信息的 React hooks。\n *\n * 系统信息包括:\n * - 用户认证信息(username, userInstanceId, org 等)\n * - 页面信息(isInIframe, isInIframeOfNext 等)\n * - 品牌设置(base_title 等)\n *\n * **注意**: 使用 useMemo 确保返回的对象引用稳定,\n * 避免不必要的组件重渲染。系统信息在会话期间保持稳定。\n *\n * @example\n *\n * ```tsx\n * function MyReactComponent() {\n * const sys = useSystemInfo();\n *\n * return (\n * <div>\n * <p>User: {sys.username}</p>\n * <p>Org: {sys.org}</p>\n * <p>In iframe: {sys.isInIframe ? \"Yes\" : \"No\"}</p>\n * <p>Brand: {sys.settings.brand.base_title}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 检查是否在 iframe 中\n * function IframeDetector() {\n * const sys = useSystemInfo();\n *\n * if (sys.isInIframe) {\n * return <div>Running in iframe mode</div>;\n * }\n *\n * return <div>Running in standalone mode</div>;\n * }\n * ```\n *\n * @returns 系统信息对象。\n */\nexport function useSystemInfo(): SystemInfo {\n return React.useMemo(() => {\n const authInfo = auth.getAuth();\n const pageInfo = getPageInfo();\n const brandSettings = getRuntime().getBrandSettings();\n\n return {\n ...authInfo,\n ...pageInfo,\n settings: {\n brand: brandSettings,\n },\n };\n }, []);\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,eAAA,GAAAF,OAAA;AAGA;AACA;AACA;;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,aAAaA,CAAA,EAAe;EAC1C,OAAOC,cAAK,CAACC,OAAO,CAAC,MAAM;IACzB,MAAMC,QAAQ,GAAGC,oBAAI,CAACC,OAAO,CAAC,CAAC;IAC/B,MAAMC,QAAQ,GAAG,IAAAC,oBAAW,EAAC,CAAC;IAC9B,MAAMC,aAAa,GAAG,IAAAC,mBAAU,EAAC,CAAC,CAACC,gBAAgB,CAAC,CAAC;IAErD,OAAO;MACL,GAAGP,QAAQ;MACX,GAAGG,QAAQ;MACXK,QAAQ,EAAE;QACRC,KAAK,EAAEJ;MACT;IACF,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;AACR","ignoreList":[]}
|
package/dist/esm/index.js
CHANGED
|
@@ -13,4 +13,8 @@ export * from "./useParams.js";
|
|
|
13
13
|
export * from "./useHistory.js";
|
|
14
14
|
export * from "./useAuth.js";
|
|
15
15
|
export * from "./useLocation.js";
|
|
16
|
+
export * from "./useFeatureFlags.js";
|
|
17
|
+
export * from "./useSystemInfo.js";
|
|
18
|
+
export * from "./useCheckPermissions.js";
|
|
19
|
+
export * from "./useControlledState.js";
|
|
16
20
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["export * from \"./ReactUseBrick.js\";\nexport * from \"./useCurrentTheme.js\";\nexport * from \"./useCurrentApp.js\";\nexport * from \"./useRecentApps.js\";\nexport * from \"./useRouteRender.js\";\nexport * from \"./useProvider/useProvider.js\";\nexport * from \"./asyncWrapBrick.js\";\nexport * from \"./useNavConfig.js\";\nexport * from \"./useLazyWrapBrick.js\";\nexport * from \"./usePathParams.js\";\nexport * from \"./useSearchParams.js\";\nexport * from \"./useParams.js\";\nexport * from \"./useHistory.js\";\nexport * from \"./useAuth.js\";\nexport * from \"./useLocation.js\";\n"],"mappings":"AAAA,cAAc,oBAAoB;AAClC,cAAc,sBAAsB;AACpC,cAAc,oBAAoB;AAClC,cAAc,oBAAoB;AAClC,cAAc,qBAAqB;AACnC,cAAc,8BAA8B;AAC5C,cAAc,qBAAqB;AACnC,cAAc,mBAAmB;AACjC,cAAc,uBAAuB;AACrC,cAAc,oBAAoB;AAClC,cAAc,sBAAsB;AACpC,cAAc,gBAAgB;AAC9B,cAAc,iBAAiB;AAC/B,cAAc,cAAc;AAC5B,cAAc,kBAAkB","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["export * from \"./ReactUseBrick.js\";\nexport * from \"./useCurrentTheme.js\";\nexport * from \"./useCurrentApp.js\";\nexport * from \"./useRecentApps.js\";\nexport * from \"./useRouteRender.js\";\nexport * from \"./useProvider/useProvider.js\";\nexport * from \"./asyncWrapBrick.js\";\nexport * from \"./useNavConfig.js\";\nexport * from \"./useLazyWrapBrick.js\";\nexport * from \"./usePathParams.js\";\nexport * from \"./useSearchParams.js\";\nexport * from \"./useParams.js\";\nexport * from \"./useHistory.js\";\nexport * from \"./useAuth.js\";\nexport * from \"./useLocation.js\";\nexport * from \"./useFeatureFlags.js\";\nexport * from \"./useSystemInfo.js\";\nexport * from \"./useCheckPermissions.js\";\nexport * from \"./useControlledState.js\";\n"],"mappings":"AAAA,cAAc,oBAAoB;AAClC,cAAc,sBAAsB;AACpC,cAAc,oBAAoB;AAClC,cAAc,oBAAoB;AAClC,cAAc,qBAAqB;AACnC,cAAc,8BAA8B;AAC5C,cAAc,qBAAqB;AACnC,cAAc,mBAAmB;AACjC,cAAc,uBAAuB;AACrC,cAAc,oBAAoB;AAClC,cAAc,sBAAsB;AACpC,cAAc,gBAAgB;AAC9B,cAAc,iBAAiB;AAC/B,cAAc,cAAc;AAC5B,cAAc,kBAAkB;AAChC,cAAc,sBAAsB;AACpC,cAAc,oBAAoB;AAClC,cAAc,0BAA0B;AACxC,cAAc,yBAAyB","ignoreList":[]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { checkPermissions } from "@next-core/easyops-runtime";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 检查用户权限的 React hooks。
|
|
6
|
+
*
|
|
7
|
+
* 此 hook 用于检查当前登录用户是否拥有指定的权限操作。
|
|
8
|
+
* 权限必须在 storyboard 配置的 `permissionsPreCheck` 中预先声明,
|
|
9
|
+
* 否则会返回 false 并在控制台输出错误。
|
|
10
|
+
*
|
|
11
|
+
* **工作原理:**
|
|
12
|
+
* - 权限会在路由渲染时自动预检查(通过 `preCheckPermissions`)
|
|
13
|
+
* - 此 hook 查询已缓存的权限结果(同步操作)
|
|
14
|
+
* - 管理员用户始终返回 true
|
|
15
|
+
* - 未登录用户始终返回 false
|
|
16
|
+
*
|
|
17
|
+
* **注意事项:**
|
|
18
|
+
* 1. 权限必须在 `permissionsPreCheck` 中声明
|
|
19
|
+
* 2. 所有传入的 actions 都必须有权限才返回 true
|
|
20
|
+
* 3. 权限检查结果会被缓存,避免重复计算
|
|
21
|
+
*
|
|
22
|
+
* @param actions - 需要检查的权限操作列表
|
|
23
|
+
* @returns 是否拥有所有指定的权限
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
*
|
|
27
|
+
* ```tsx
|
|
28
|
+
* // 检查单个权限
|
|
29
|
+
* function DeleteButton() {
|
|
30
|
+
* const canDelete = useCheckPermissions("my-app:user.delete");
|
|
31
|
+
*
|
|
32
|
+
* if (!canDelete) {
|
|
33
|
+
* return null;
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* return <button onClick={handleDelete}>Delete</button>;
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
*
|
|
42
|
+
* ```tsx
|
|
43
|
+
* // 检查多个权限(需要全部拥有)
|
|
44
|
+
* function AdminPanel() {
|
|
45
|
+
* const hasAccess = useCheckPermissions(
|
|
46
|
+
* "my-app:admin.read",
|
|
47
|
+
* "my-app:admin.write"
|
|
48
|
+
* );
|
|
49
|
+
*
|
|
50
|
+
* if (!hasAccess) {
|
|
51
|
+
* return <div>Access Denied</div>;
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* return <div>Admin Panel Content</div>;
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
*
|
|
60
|
+
* ```tsx
|
|
61
|
+
* // 在 storyboard 中配置权限预检查
|
|
62
|
+
* // routes.yaml
|
|
63
|
+
* routes:
|
|
64
|
+
* - path: /users
|
|
65
|
+
* permissionsPreCheck:
|
|
66
|
+
* - "my-app:user.read"
|
|
67
|
+
* - "my-app:user.delete"
|
|
68
|
+
* bricks:
|
|
69
|
+
* - brick: "my-brick"
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export function useCheckPermissions() {
|
|
73
|
+
for (var _len = arguments.length, actions = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
74
|
+
actions[_key] = arguments[_key];
|
|
75
|
+
}
|
|
76
|
+
// 使用 useMemo 缓存权限检查结果
|
|
77
|
+
// 因为权限在会话期间是稳定的,只依赖于 actions 列表
|
|
78
|
+
return React.useMemo(() => checkPermissions.checkPermissions(...actions),
|
|
79
|
+
// 序列化 actions 作为依赖,避免数组引用变化导致重新计算
|
|
80
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
81
|
+
[JSON.stringify(actions)]);
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=useCheckPermissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCheckPermissions.js","names":["React","checkPermissions","useCheckPermissions","_len","arguments","length","actions","Array","_key","useMemo","JSON","stringify"],"sources":["../../src/useCheckPermissions.ts"],"sourcesContent":["import React from \"react\";\nimport { checkPermissions } from \"@next-core/easyops-runtime\";\n\n/**\n * 检查用户权限的 React hooks。\n *\n * 此 hook 用于检查当前登录用户是否拥有指定的权限操作。\n * 权限必须在 storyboard 配置的 `permissionsPreCheck` 中预先声明,\n * 否则会返回 false 并在控制台输出错误。\n *\n * **工作原理:**\n * - 权限会在路由渲染时自动预检查(通过 `preCheckPermissions`)\n * - 此 hook 查询已缓存的权限结果(同步操作)\n * - 管理员用户始终返回 true\n * - 未登录用户始终返回 false\n *\n * **注意事项:**\n * 1. 权限必须在 `permissionsPreCheck` 中声明\n * 2. 所有传入的 actions 都必须有权限才返回 true\n * 3. 权限检查结果会被缓存,避免重复计算\n *\n * @param actions - 需要检查的权限操作列表\n * @returns 是否拥有所有指定的权限\n *\n * @example\n *\n * ```tsx\n * // 检查单个权限\n * function DeleteButton() {\n * const canDelete = useCheckPermissions(\"my-app:user.delete\");\n *\n * if (!canDelete) {\n * return null;\n * }\n *\n * return <button onClick={handleDelete}>Delete</button>;\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 检查多个权限(需要全部拥有)\n * function AdminPanel() {\n * const hasAccess = useCheckPermissions(\n * \"my-app:admin.read\",\n * \"my-app:admin.write\"\n * );\n *\n * if (!hasAccess) {\n * return <div>Access Denied</div>;\n * }\n *\n * return <div>Admin Panel Content</div>;\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 在 storyboard 中配置权限预检查\n * // routes.yaml\n * routes:\n * - path: /users\n * permissionsPreCheck:\n * - \"my-app:user.read\"\n * - \"my-app:user.delete\"\n * bricks:\n * - brick: \"my-brick\"\n * ```\n */\nexport function useCheckPermissions(...actions: string[]): boolean {\n // 使用 useMemo 缓存权限检查结果\n // 因为权限在会话期间是稳定的,只依赖于 actions 列表\n return React.useMemo(\n () => checkPermissions.checkPermissions(...actions),\n // 序列化 actions 作为依赖,避免数组引用变化导致重新计算\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(actions)]\n );\n}\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,gBAAgB,QAAQ,4BAA4B;;AAE7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CAAA,EAAgC;EAAA,SAAAC,IAAA,GAAAC,SAAA,CAAAC,MAAA,EAA5BC,OAAO,OAAAC,KAAA,CAAAJ,IAAA,GAAAK,IAAA,MAAAA,IAAA,GAAAL,IAAA,EAAAK,IAAA;IAAPF,OAAO,CAAAE,IAAA,IAAAJ,SAAA,CAAAI,IAAA;EAAA;EAC5C;EACA;EACA,OAAOR,KAAK,CAACS,OAAO,CAClB,MAAMR,gBAAgB,CAACA,gBAAgB,CAAC,GAAGK,OAAO,CAAC;EACnD;EACA;EACA,CAACI,IAAI,CAACC,SAAS,CAACL,OAAO,CAAC,CAC1B,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { isEqual } from "lodash";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 受控/非受控混合模式的通用 Hook。
|
|
6
|
+
*
|
|
7
|
+
* 此 hook 允许组件既支持受控模式(由父组件通过 props 控制状态),
|
|
8
|
+
* 也支持非受控模式(组件自己管理内部状态)。
|
|
9
|
+
*
|
|
10
|
+
* **工作原理:**
|
|
11
|
+
* - 当 `propValue !== undefined` 时,组件处于**受控模式**,状态跟随 prop 更新
|
|
12
|
+
* - 当 `propValue === undefined` 时,组件处于**非受控模式**,使用内部状态
|
|
13
|
+
* - 支持深度比较选项,避免复杂对象引用变化导致的不必要更新
|
|
14
|
+
*
|
|
15
|
+
* **使用场景:**
|
|
16
|
+
* 1. 表单组件需要支持受控和非受控两种模式
|
|
17
|
+
* 2. 组件状态可能由父组件控制,也可能自己管理
|
|
18
|
+
* 3. 复杂对象状态需要避免不必要的重新渲染
|
|
19
|
+
*
|
|
20
|
+
* @template T - 状态值的类型
|
|
21
|
+
* @param propValue - 来自 props 的值(undefined 表示非受控模式)
|
|
22
|
+
* @param defaultValue - 默认值(props 为 undefined 时使用)
|
|
23
|
+
* @param deepCompare - 是否使用深度比较(用于复杂对象,默认 false)
|
|
24
|
+
* @returns 返回 [当前值, 设置值的函数],类似 useState
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
*
|
|
28
|
+
* ```tsx
|
|
29
|
+
* // 简单值(字符串、数字)
|
|
30
|
+
* function MyComponent({ deployed }: { deployed?: string }) {
|
|
31
|
+
* const [value, setValue] = useControlledState(deployed, 'host');
|
|
32
|
+
*
|
|
33
|
+
* return (
|
|
34
|
+
* <select value={value} onChange={(e) => setValue(e.target.value)}>
|
|
35
|
+
* <option value="host">Host</option>
|
|
36
|
+
* <option value="container">Container</option>
|
|
37
|
+
* </select>
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* // 使用方式 1:受控模式
|
|
42
|
+
* <MyComponent deployed="container" />
|
|
43
|
+
*
|
|
44
|
+
* // 使用方式 2:非受控模式
|
|
45
|
+
* <MyComponent />
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
*
|
|
50
|
+
* ```tsx
|
|
51
|
+
* // 复杂对象(启用深度比较)
|
|
52
|
+
* interface Config {
|
|
53
|
+
* host: string;
|
|
54
|
+
* port: number;
|
|
55
|
+
* }
|
|
56
|
+
*
|
|
57
|
+
* function ConfigEditor({ config }: { config?: Config }) {
|
|
58
|
+
* const [value, setValue] = useControlledState<Config | null>(
|
|
59
|
+
* config,
|
|
60
|
+
* null,
|
|
61
|
+
* true // 启用深度比较
|
|
62
|
+
* );
|
|
63
|
+
*
|
|
64
|
+
* return <div>{JSON.stringify(value)}</div>;
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
*
|
|
70
|
+
* ```tsx
|
|
71
|
+
* // 与 onChange 回调结合
|
|
72
|
+
* function Input({
|
|
73
|
+
* value,
|
|
74
|
+
* defaultValue = '',
|
|
75
|
+
* onChange
|
|
76
|
+
* }: {
|
|
77
|
+
* value?: string;
|
|
78
|
+
* defaultValue?: string;
|
|
79
|
+
* onChange?: (val: string) => void;
|
|
80
|
+
* }) {
|
|
81
|
+
* const [internalValue, setInternalValue] = useControlledState(
|
|
82
|
+
* value,
|
|
83
|
+
* defaultValue
|
|
84
|
+
* );
|
|
85
|
+
*
|
|
86
|
+
* const handleChange = (newValue: string) => {
|
|
87
|
+
* setInternalValue(newValue);
|
|
88
|
+
* onChange?.(newValue);
|
|
89
|
+
* };
|
|
90
|
+
*
|
|
91
|
+
* return (
|
|
92
|
+
* <input
|
|
93
|
+
* value={internalValue}
|
|
94
|
+
* onChange={(e) => handleChange(e.target.value)}
|
|
95
|
+
* />
|
|
96
|
+
* );
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export function useControlledState(propValue, defaultValue) {
|
|
101
|
+
let deepCompare = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
102
|
+
// 初始化内部状态
|
|
103
|
+
// 如果 propValue 不是 undefined,使用 propValue;否则使用 defaultValue
|
|
104
|
+
const [internalValue, setInternalValue] = React.useState(propValue !== undefined ? propValue : defaultValue);
|
|
105
|
+
const isControlled = propValue !== undefined;
|
|
106
|
+
|
|
107
|
+
// 在受控模式下同步 propValue 到 internalValue
|
|
108
|
+
React.useEffect(() => {
|
|
109
|
+
if (isControlled) {
|
|
110
|
+
if (deepCompare) {
|
|
111
|
+
// 深度比较模式:只有值真正变化时才更新
|
|
112
|
+
setInternalValue(prev => isEqual(prev, propValue) ? prev : propValue);
|
|
113
|
+
} else {
|
|
114
|
+
// 浅比较模式:直接更新(React 会自动优化相同值)
|
|
115
|
+
setInternalValue(propValue);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// 注意:当 propValue 变为 undefined 时,不更新 internalValue
|
|
119
|
+
// 这样可以保持最后一次的值,实现从受控切换到非受控的平滑过渡
|
|
120
|
+
}, [isControlled, propValue, deepCompare]);
|
|
121
|
+
|
|
122
|
+
// 计算最终返回的值
|
|
123
|
+
let value;
|
|
124
|
+
if (isControlled) {
|
|
125
|
+
if (deepCompare) {
|
|
126
|
+
// 深度比较模式:如果内容相同,返回 internalValue 保持引用稳定
|
|
127
|
+
// 否则返回 propValue
|
|
128
|
+
value = isEqual(internalValue, propValue) ? internalValue : propValue;
|
|
129
|
+
} else {
|
|
130
|
+
// 浅比较模式:直接返回 propValue,确保受控模式下值始终同步
|
|
131
|
+
value = propValue;
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
// 非受控模式:返回 internalValue
|
|
135
|
+
value = internalValue;
|
|
136
|
+
}
|
|
137
|
+
return [value, setInternalValue];
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=useControlledState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useControlledState.js","names":["React","isEqual","useControlledState","propValue","defaultValue","deepCompare","arguments","length","undefined","internalValue","setInternalValue","useState","isControlled","useEffect","prev","value"],"sources":["../../src/useControlledState.ts"],"sourcesContent":["import React from \"react\";\nimport { isEqual } from \"lodash\";\n\n/**\n * 受控/非受控混合模式的通用 Hook。\n *\n * 此 hook 允许组件既支持受控模式(由父组件通过 props 控制状态),\n * 也支持非受控模式(组件自己管理内部状态)。\n *\n * **工作原理:**\n * - 当 `propValue !== undefined` 时,组件处于**受控模式**,状态跟随 prop 更新\n * - 当 `propValue === undefined` 时,组件处于**非受控模式**,使用内部状态\n * - 支持深度比较选项,避免复杂对象引用变化导致的不必要更新\n *\n * **使用场景:**\n * 1. 表单组件需要支持受控和非受控两种模式\n * 2. 组件状态可能由父组件控制,也可能自己管理\n * 3. 复杂对象状态需要避免不必要的重新渲染\n *\n * @template T - 状态值的类型\n * @param propValue - 来自 props 的值(undefined 表示非受控模式)\n * @param defaultValue - 默认值(props 为 undefined 时使用)\n * @param deepCompare - 是否使用深度比较(用于复杂对象,默认 false)\n * @returns 返回 [当前值, 设置值的函数],类似 useState\n *\n * @example\n *\n * ```tsx\n * // 简单值(字符串、数字)\n * function MyComponent({ deployed }: { deployed?: string }) {\n * const [value, setValue] = useControlledState(deployed, 'host');\n *\n * return (\n * <select value={value} onChange={(e) => setValue(e.target.value)}>\n * <option value=\"host\">Host</option>\n * <option value=\"container\">Container</option>\n * </select>\n * );\n * }\n *\n * // 使用方式 1:受控模式\n * <MyComponent deployed=\"container\" />\n *\n * // 使用方式 2:非受控模式\n * <MyComponent />\n * ```\n *\n * @example\n *\n * ```tsx\n * // 复杂对象(启用深度比较)\n * interface Config {\n * host: string;\n * port: number;\n * }\n *\n * function ConfigEditor({ config }: { config?: Config }) {\n * const [value, setValue] = useControlledState<Config | null>(\n * config,\n * null,\n * true // 启用深度比较\n * );\n *\n * return <div>{JSON.stringify(value)}</div>;\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 与 onChange 回调结合\n * function Input({\n * value,\n * defaultValue = '',\n * onChange\n * }: {\n * value?: string;\n * defaultValue?: string;\n * onChange?: (val: string) => void;\n * }) {\n * const [internalValue, setInternalValue] = useControlledState(\n * value,\n * defaultValue\n * );\n *\n * const handleChange = (newValue: string) => {\n * setInternalValue(newValue);\n * onChange?.(newValue);\n * };\n *\n * return (\n * <input\n * value={internalValue}\n * onChange={(e) => handleChange(e.target.value)}\n * />\n * );\n * }\n * ```\n */\nexport function useControlledState<T>(\n propValue: T | undefined,\n defaultValue: T,\n deepCompare = false\n): [T, React.Dispatch<React.SetStateAction<T>>] {\n // 初始化内部状态\n // 如果 propValue 不是 undefined,使用 propValue;否则使用 defaultValue\n const [internalValue, setInternalValue] = React.useState<T>(\n propValue !== undefined ? propValue : defaultValue\n );\n\n const isControlled = propValue !== undefined;\n\n // 在受控模式下同步 propValue 到 internalValue\n React.useEffect(() => {\n if (isControlled) {\n if (deepCompare) {\n // 深度比较模式:只有值真正变化时才更新\n setInternalValue((prev) =>\n isEqual(prev, propValue) ? prev : propValue\n );\n } else {\n // 浅比较模式:直接更新(React 会自动优化相同值)\n setInternalValue(propValue);\n }\n }\n // 注意:当 propValue 变为 undefined 时,不更新 internalValue\n // 这样可以保持最后一次的值,实现从受控切换到非受控的平滑过渡\n }, [isControlled, propValue, deepCompare]);\n\n // 计算最终返回的值\n let value: T;\n if (isControlled) {\n if (deepCompare) {\n // 深度比较模式:如果内容相同,返回 internalValue 保持引用稳定\n // 否则返回 propValue\n value = isEqual(internalValue, propValue) ? internalValue : propValue;\n } else {\n // 浅比较模式:直接返回 propValue,确保受控模式下值始终同步\n value = propValue;\n }\n } else {\n // 非受控模式:返回 internalValue\n value = internalValue;\n }\n\n return [value, setInternalValue];\n}\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,OAAO,QAAQ,QAAQ;;AAEhC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,kBAAkBA,CAChCC,SAAwB,EACxBC,YAAe,EAE+B;EAAA,IAD9CC,WAAW,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,KAAK;EAEnB;EACA;EACA,MAAM,CAACG,aAAa,EAAEC,gBAAgB,CAAC,GAAGV,KAAK,CAACW,QAAQ,CACtDR,SAAS,KAAKK,SAAS,GAAGL,SAAS,GAAGC,YACxC,CAAC;EAED,MAAMQ,YAAY,GAAGT,SAAS,KAAKK,SAAS;;EAE5C;EACAR,KAAK,CAACa,SAAS,CAAC,MAAM;IACpB,IAAID,YAAY,EAAE;MAChB,IAAIP,WAAW,EAAE;QACf;QACAK,gBAAgB,CAAEI,IAAI,IACpBb,OAAO,CAACa,IAAI,EAAEX,SAAS,CAAC,GAAGW,IAAI,GAAGX,SACpC,CAAC;MACH,CAAC,MAAM;QACL;QACAO,gBAAgB,CAACP,SAAS,CAAC;MAC7B;IACF;IACA;IACA;EACF,CAAC,EAAE,CAACS,YAAY,EAAET,SAAS,EAAEE,WAAW,CAAC,CAAC;;EAE1C;EACA,IAAIU,KAAQ;EACZ,IAAIH,YAAY,EAAE;IAChB,IAAIP,WAAW,EAAE;MACf;MACA;MACAU,KAAK,GAAGd,OAAO,CAACQ,aAAa,EAAEN,SAAS,CAAC,GAAGM,aAAa,GAAGN,SAAS;IACvE,CAAC,MAAM;MACL;MACAY,KAAK,GAAGZ,SAAS;IACnB;EACF,CAAC,MAAM;IACL;IACAY,KAAK,GAAGN,aAAa;EACvB;EAEA,OAAO,CAACM,KAAK,EAAEL,gBAAgB,CAAC;AAClC","ignoreList":[]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { getRuntime } from "@next-core/runtime";
|
|
3
|
+
/**
|
|
4
|
+
* 获取特性开关配置的 React hooks。
|
|
5
|
+
*
|
|
6
|
+
* 特性开关用于控制功能的启用或禁用,可以在全局设置或应用级别配置。
|
|
7
|
+
* 使用 useMemo 确保返回的对象引用稳定,避免不必要的组件重渲染。
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* function MyReactComponent() {
|
|
13
|
+
* const flags = useFeatureFlags();
|
|
14
|
+
*
|
|
15
|
+
* if (flags["my-new-feature"]) {
|
|
16
|
+
* return <NewFeature />;
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* return <OldFeature />;
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* // 检查特定功能是否启用
|
|
27
|
+
* function FeatureToggle() {
|
|
28
|
+
* const flags = useFeatureFlags();
|
|
29
|
+
* const isEnabled = flags["experimental-mode"] ?? false;
|
|
30
|
+
*
|
|
31
|
+
* return (
|
|
32
|
+
* <div>
|
|
33
|
+
* Experimental Mode: {isEnabled ? "ON" : "OFF"}
|
|
34
|
+
* </div>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @returns 特性开关配置对象,键为特性名称,值为布尔值。
|
|
40
|
+
*/
|
|
41
|
+
export function useFeatureFlags() {
|
|
42
|
+
return React.useMemo(() => getRuntime().getFeatureFlags(), []);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=useFeatureFlags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeatureFlags.js","names":["React","getRuntime","useFeatureFlags","useMemo","getFeatureFlags"],"sources":["../../src/useFeatureFlags.ts"],"sourcesContent":["import React from \"react\";\nimport { getRuntime } from \"@next-core/runtime\";\nimport type { FeatureFlags } from \"@next-core/types\";\n\n/**\n * 获取特性开关配置的 React hooks。\n *\n * 特性开关用于控制功能的启用或禁用,可以在全局设置或应用级别配置。\n * 使用 useMemo 确保返回的对象引用稳定,避免不必要的组件重渲染。\n *\n * @example\n *\n * ```tsx\n * function MyReactComponent() {\n * const flags = useFeatureFlags();\n *\n * if (flags[\"my-new-feature\"]) {\n * return <NewFeature />;\n * }\n *\n * return <OldFeature />;\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 检查特定功能是否启用\n * function FeatureToggle() {\n * const flags = useFeatureFlags();\n * const isEnabled = flags[\"experimental-mode\"] ?? false;\n *\n * return (\n * <div>\n * Experimental Mode: {isEnabled ? \"ON\" : \"OFF\"}\n * </div>\n * );\n * }\n * ```\n *\n * @returns 特性开关配置对象,键为特性名称,值为布尔值。\n */\nexport function useFeatureFlags(): FeatureFlags {\n return React.useMemo(() => getRuntime().getFeatureFlags(), []);\n}\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,UAAU,QAAQ,oBAAoB;AAG/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAAA,EAAiB;EAC9C,OAAOF,KAAK,CAACG,OAAO,CAAC,MAAMF,UAAU,CAAC,CAAC,CAACG,eAAe,CAAC,CAAC,EAAE,EAAE,CAAC;AAChE","ignoreList":[]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { getRuntime, getPageInfo } from "@next-core/runtime";
|
|
3
|
+
import { auth } from "@next-core/easyops-runtime";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 系统信息接口,包含认证信息、页面信息和品牌设置。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 获取系统信息的 React hooks。
|
|
11
|
+
*
|
|
12
|
+
* 系统信息包括:
|
|
13
|
+
* - 用户认证信息(username, userInstanceId, org 等)
|
|
14
|
+
* - 页面信息(isInIframe, isInIframeOfNext 等)
|
|
15
|
+
* - 品牌设置(base_title 等)
|
|
16
|
+
*
|
|
17
|
+
* **注意**: 使用 useMemo 确保返回的对象引用稳定,
|
|
18
|
+
* 避免不必要的组件重渲染。系统信息在会话期间保持稳定。
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
*
|
|
22
|
+
* ```tsx
|
|
23
|
+
* function MyReactComponent() {
|
|
24
|
+
* const sys = useSystemInfo();
|
|
25
|
+
*
|
|
26
|
+
* return (
|
|
27
|
+
* <div>
|
|
28
|
+
* <p>User: {sys.username}</p>
|
|
29
|
+
* <p>Org: {sys.org}</p>
|
|
30
|
+
* <p>In iframe: {sys.isInIframe ? "Yes" : "No"}</p>
|
|
31
|
+
* <p>Brand: {sys.settings.brand.base_title}</p>
|
|
32
|
+
* </div>
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
*
|
|
39
|
+
* ```tsx
|
|
40
|
+
* // 检查是否在 iframe 中
|
|
41
|
+
* function IframeDetector() {
|
|
42
|
+
* const sys = useSystemInfo();
|
|
43
|
+
*
|
|
44
|
+
* if (sys.isInIframe) {
|
|
45
|
+
* return <div>Running in iframe mode</div>;
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* return <div>Running in standalone mode</div>;
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @returns 系统信息对象。
|
|
53
|
+
*/
|
|
54
|
+
export function useSystemInfo() {
|
|
55
|
+
return React.useMemo(() => {
|
|
56
|
+
const authInfo = auth.getAuth();
|
|
57
|
+
const pageInfo = getPageInfo();
|
|
58
|
+
const brandSettings = getRuntime().getBrandSettings();
|
|
59
|
+
return {
|
|
60
|
+
...authInfo,
|
|
61
|
+
...pageInfo,
|
|
62
|
+
settings: {
|
|
63
|
+
brand: brandSettings
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}, []);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=useSystemInfo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSystemInfo.js","names":["React","getRuntime","getPageInfo","auth","useSystemInfo","useMemo","authInfo","getAuth","pageInfo","brandSettings","getBrandSettings","settings","brand"],"sources":["../../src/useSystemInfo.ts"],"sourcesContent":["import React from \"react\";\nimport { getRuntime, getPageInfo } from \"@next-core/runtime\";\nimport { auth } from \"@next-core/easyops-runtime\";\nimport type { PageInfo } from \"@next-core/runtime\";\n\n/**\n * 系统信息接口,包含认证信息、页面信息和品牌设置。\n */\nexport interface SystemInfo extends PageInfo {\n /** 用户认证信息 */\n username?: string;\n userInstanceId?: string;\n org?: number;\n [key: string]: unknown;\n\n /** 系统设置 */\n settings: {\n /** 品牌设置 */\n brand: Record<string, string>;\n };\n}\n\n/**\n * 获取系统信息的 React hooks。\n *\n * 系统信息包括:\n * - 用户认证信息(username, userInstanceId, org 等)\n * - 页面信息(isInIframe, isInIframeOfNext 等)\n * - 品牌设置(base_title 等)\n *\n * **注意**: 使用 useMemo 确保返回的对象引用稳定,\n * 避免不必要的组件重渲染。系统信息在会话期间保持稳定。\n *\n * @example\n *\n * ```tsx\n * function MyReactComponent() {\n * const sys = useSystemInfo();\n *\n * return (\n * <div>\n * <p>User: {sys.username}</p>\n * <p>Org: {sys.org}</p>\n * <p>In iframe: {sys.isInIframe ? \"Yes\" : \"No\"}</p>\n * <p>Brand: {sys.settings.brand.base_title}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @example\n *\n * ```tsx\n * // 检查是否在 iframe 中\n * function IframeDetector() {\n * const sys = useSystemInfo();\n *\n * if (sys.isInIframe) {\n * return <div>Running in iframe mode</div>;\n * }\n *\n * return <div>Running in standalone mode</div>;\n * }\n * ```\n *\n * @returns 系统信息对象。\n */\nexport function useSystemInfo(): SystemInfo {\n return React.useMemo(() => {\n const authInfo = auth.getAuth();\n const pageInfo = getPageInfo();\n const brandSettings = getRuntime().getBrandSettings();\n\n return {\n ...authInfo,\n ...pageInfo,\n settings: {\n brand: brandSettings,\n },\n };\n }, []);\n}\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,UAAU,EAAEC,WAAW,QAAQ,oBAAoB;AAC5D,SAASC,IAAI,QAAQ,4BAA4B;;AAGjD;AACA;AACA;;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,aAAaA,CAAA,EAAe;EAC1C,OAAOJ,KAAK,CAACK,OAAO,CAAC,MAAM;IACzB,MAAMC,QAAQ,GAAGH,IAAI,CAACI,OAAO,CAAC,CAAC;IAC/B,MAAMC,QAAQ,GAAGN,WAAW,CAAC,CAAC;IAC9B,MAAMO,aAAa,GAAGR,UAAU,CAAC,CAAC,CAACS,gBAAgB,CAAC,CAAC;IAErD,OAAO;MACL,GAAGJ,QAAQ;MACX,GAAGE,QAAQ;MACXG,QAAQ,EAAE;QACRC,KAAK,EAAEH;MACT;IACF,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;AACR","ignoreList":[]}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -13,3 +13,7 @@ export * from "./useParams.js";
|
|
|
13
13
|
export * from "./useHistory.js";
|
|
14
14
|
export * from "./useAuth.js";
|
|
15
15
|
export * from "./useLocation.js";
|
|
16
|
+
export * from "./useFeatureFlags.js";
|
|
17
|
+
export * from "./useSystemInfo.js";
|
|
18
|
+
export * from "./useCheckPermissions.js";
|
|
19
|
+
export * from "./useControlledState.js";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查用户权限的 React hooks。
|
|
3
|
+
*
|
|
4
|
+
* 此 hook 用于检查当前登录用户是否拥有指定的权限操作。
|
|
5
|
+
* 权限必须在 storyboard 配置的 `permissionsPreCheck` 中预先声明,
|
|
6
|
+
* 否则会返回 false 并在控制台输出错误。
|
|
7
|
+
*
|
|
8
|
+
* **工作原理:**
|
|
9
|
+
* - 权限会在路由渲染时自动预检查(通过 `preCheckPermissions`)
|
|
10
|
+
* - 此 hook 查询已缓存的权限结果(同步操作)
|
|
11
|
+
* - 管理员用户始终返回 true
|
|
12
|
+
* - 未登录用户始终返回 false
|
|
13
|
+
*
|
|
14
|
+
* **注意事项:**
|
|
15
|
+
* 1. 权限必须在 `permissionsPreCheck` 中声明
|
|
16
|
+
* 2. 所有传入的 actions 都必须有权限才返回 true
|
|
17
|
+
* 3. 权限检查结果会被缓存,避免重复计算
|
|
18
|
+
*
|
|
19
|
+
* @param actions - 需要检查的权限操作列表
|
|
20
|
+
* @returns 是否拥有所有指定的权限
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
*
|
|
24
|
+
* ```tsx
|
|
25
|
+
* // 检查单个权限
|
|
26
|
+
* function DeleteButton() {
|
|
27
|
+
* const canDelete = useCheckPermissions("my-app:user.delete");
|
|
28
|
+
*
|
|
29
|
+
* if (!canDelete) {
|
|
30
|
+
* return null;
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* return <button onClick={handleDelete}>Delete</button>;
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
*
|
|
39
|
+
* ```tsx
|
|
40
|
+
* // 检查多个权限(需要全部拥有)
|
|
41
|
+
* function AdminPanel() {
|
|
42
|
+
* const hasAccess = useCheckPermissions(
|
|
43
|
+
* "my-app:admin.read",
|
|
44
|
+
* "my-app:admin.write"
|
|
45
|
+
* );
|
|
46
|
+
*
|
|
47
|
+
* if (!hasAccess) {
|
|
48
|
+
* return <div>Access Denied</div>;
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* return <div>Admin Panel Content</div>;
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
*
|
|
57
|
+
* ```tsx
|
|
58
|
+
* // 在 storyboard 中配置权限预检查
|
|
59
|
+
* // routes.yaml
|
|
60
|
+
* routes:
|
|
61
|
+
* - path: /users
|
|
62
|
+
* permissionsPreCheck:
|
|
63
|
+
* - "my-app:user.read"
|
|
64
|
+
* - "my-app:user.delete"
|
|
65
|
+
* bricks:
|
|
66
|
+
* - brick: "my-brick"
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function useCheckPermissions(...actions: string[]): boolean;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* 受控/非受控混合模式的通用 Hook。
|
|
4
|
+
*
|
|
5
|
+
* 此 hook 允许组件既支持受控模式(由父组件通过 props 控制状态),
|
|
6
|
+
* 也支持非受控模式(组件自己管理内部状态)。
|
|
7
|
+
*
|
|
8
|
+
* **工作原理:**
|
|
9
|
+
* - 当 `propValue !== undefined` 时,组件处于**受控模式**,状态跟随 prop 更新
|
|
10
|
+
* - 当 `propValue === undefined` 时,组件处于**非受控模式**,使用内部状态
|
|
11
|
+
* - 支持深度比较选项,避免复杂对象引用变化导致的不必要更新
|
|
12
|
+
*
|
|
13
|
+
* **使用场景:**
|
|
14
|
+
* 1. 表单组件需要支持受控和非受控两种模式
|
|
15
|
+
* 2. 组件状态可能由父组件控制,也可能自己管理
|
|
16
|
+
* 3. 复杂对象状态需要避免不必要的重新渲染
|
|
17
|
+
*
|
|
18
|
+
* @template T - 状态值的类型
|
|
19
|
+
* @param propValue - 来自 props 的值(undefined 表示非受控模式)
|
|
20
|
+
* @param defaultValue - 默认值(props 为 undefined 时使用)
|
|
21
|
+
* @param deepCompare - 是否使用深度比较(用于复杂对象,默认 false)
|
|
22
|
+
* @returns 返回 [当前值, 设置值的函数],类似 useState
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
*
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // 简单值(字符串、数字)
|
|
28
|
+
* function MyComponent({ deployed }: { deployed?: string }) {
|
|
29
|
+
* const [value, setValue] = useControlledState(deployed, 'host');
|
|
30
|
+
*
|
|
31
|
+
* return (
|
|
32
|
+
* <select value={value} onChange={(e) => setValue(e.target.value)}>
|
|
33
|
+
* <option value="host">Host</option>
|
|
34
|
+
* <option value="container">Container</option>
|
|
35
|
+
* </select>
|
|
36
|
+
* );
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* // 使用方式 1:受控模式
|
|
40
|
+
* <MyComponent deployed="container" />
|
|
41
|
+
*
|
|
42
|
+
* // 使用方式 2:非受控模式
|
|
43
|
+
* <MyComponent />
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* // 复杂对象(启用深度比较)
|
|
50
|
+
* interface Config {
|
|
51
|
+
* host: string;
|
|
52
|
+
* port: number;
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* function ConfigEditor({ config }: { config?: Config }) {
|
|
56
|
+
* const [value, setValue] = useControlledState<Config | null>(
|
|
57
|
+
* config,
|
|
58
|
+
* null,
|
|
59
|
+
* true // 启用深度比较
|
|
60
|
+
* );
|
|
61
|
+
*
|
|
62
|
+
* return <div>{JSON.stringify(value)}</div>;
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
*
|
|
68
|
+
* ```tsx
|
|
69
|
+
* // 与 onChange 回调结合
|
|
70
|
+
* function Input({
|
|
71
|
+
* value,
|
|
72
|
+
* defaultValue = '',
|
|
73
|
+
* onChange
|
|
74
|
+
* }: {
|
|
75
|
+
* value?: string;
|
|
76
|
+
* defaultValue?: string;
|
|
77
|
+
* onChange?: (val: string) => void;
|
|
78
|
+
* }) {
|
|
79
|
+
* const [internalValue, setInternalValue] = useControlledState(
|
|
80
|
+
* value,
|
|
81
|
+
* defaultValue
|
|
82
|
+
* );
|
|
83
|
+
*
|
|
84
|
+
* const handleChange = (newValue: string) => {
|
|
85
|
+
* setInternalValue(newValue);
|
|
86
|
+
* onChange?.(newValue);
|
|
87
|
+
* };
|
|
88
|
+
*
|
|
89
|
+
* return (
|
|
90
|
+
* <input
|
|
91
|
+
* value={internalValue}
|
|
92
|
+
* onChange={(e) => handleChange(e.target.value)}
|
|
93
|
+
* />
|
|
94
|
+
* );
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare function useControlledState<T>(propValue: T | undefined, defaultValue: T, deepCompare?: boolean): [T, React.Dispatch<React.SetStateAction<T>>];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { FeatureFlags } from "@next-core/types";
|
|
2
|
+
/**
|
|
3
|
+
* 获取特性开关配置的 React hooks。
|
|
4
|
+
*
|
|
5
|
+
* 特性开关用于控制功能的启用或禁用,可以在全局设置或应用级别配置。
|
|
6
|
+
* 使用 useMemo 确保返回的对象引用稳定,避免不必要的组件重渲染。
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* function MyReactComponent() {
|
|
12
|
+
* const flags = useFeatureFlags();
|
|
13
|
+
*
|
|
14
|
+
* if (flags["my-new-feature"]) {
|
|
15
|
+
* return <NewFeature />;
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* return <OldFeature />;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
*
|
|
24
|
+
* ```tsx
|
|
25
|
+
* // 检查特定功能是否启用
|
|
26
|
+
* function FeatureToggle() {
|
|
27
|
+
* const flags = useFeatureFlags();
|
|
28
|
+
* const isEnabled = flags["experimental-mode"] ?? false;
|
|
29
|
+
*
|
|
30
|
+
* return (
|
|
31
|
+
* <div>
|
|
32
|
+
* Experimental Mode: {isEnabled ? "ON" : "OFF"}
|
|
33
|
+
* </div>
|
|
34
|
+
* );
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @returns 特性开关配置对象,键为特性名称,值为布尔值。
|
|
39
|
+
*/
|
|
40
|
+
export declare function useFeatureFlags(): FeatureFlags;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { PageInfo } from "@next-core/runtime";
|
|
2
|
+
/**
|
|
3
|
+
* 系统信息接口,包含认证信息、页面信息和品牌设置。
|
|
4
|
+
*/
|
|
5
|
+
export interface SystemInfo extends PageInfo {
|
|
6
|
+
/** 用户认证信息 */
|
|
7
|
+
username?: string;
|
|
8
|
+
userInstanceId?: string;
|
|
9
|
+
org?: number;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
/** 系统设置 */
|
|
12
|
+
settings: {
|
|
13
|
+
/** 品牌设置 */
|
|
14
|
+
brand: Record<string, string>;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 获取系统信息的 React hooks。
|
|
19
|
+
*
|
|
20
|
+
* 系统信息包括:
|
|
21
|
+
* - 用户认证信息(username, userInstanceId, org 等)
|
|
22
|
+
* - 页面信息(isInIframe, isInIframeOfNext 等)
|
|
23
|
+
* - 品牌设置(base_title 等)
|
|
24
|
+
*
|
|
25
|
+
* **注意**: 使用 useMemo 确保返回的对象引用稳定,
|
|
26
|
+
* 避免不必要的组件重渲染。系统信息在会话期间保持稳定。
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
*
|
|
30
|
+
* ```tsx
|
|
31
|
+
* function MyReactComponent() {
|
|
32
|
+
* const sys = useSystemInfo();
|
|
33
|
+
*
|
|
34
|
+
* return (
|
|
35
|
+
* <div>
|
|
36
|
+
* <p>User: {sys.username}</p>
|
|
37
|
+
* <p>Org: {sys.org}</p>
|
|
38
|
+
* <p>In iframe: {sys.isInIframe ? "Yes" : "No"}</p>
|
|
39
|
+
* <p>Brand: {sys.settings.brand.base_title}</p>
|
|
40
|
+
* </div>
|
|
41
|
+
* );
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
*
|
|
47
|
+
* ```tsx
|
|
48
|
+
* // 检查是否在 iframe 中
|
|
49
|
+
* function IframeDetector() {
|
|
50
|
+
* const sys = useSystemInfo();
|
|
51
|
+
*
|
|
52
|
+
* if (sys.isInIframe) {
|
|
53
|
+
* return <div>Running in iframe mode</div>;
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* return <div>Running in standalone mode</div>;
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @returns 系统信息对象。
|
|
61
|
+
*/
|
|
62
|
+
export declare function useSystemInfo(): SystemInfo;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@next-core/react-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"homepage": "https://github.com/easyops-cn/next-core/tree/v3/packages/react-runtime",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"repository": {
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"@next-core/test-next": "^2.0.1",
|
|
50
50
|
"jest-fetch-mock": "^3.0.3"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "8147d007b09c62b6f52349bc3d3daf98173a01f8"
|
|
53
53
|
}
|