@next-core/react-runtime 1.9.0 → 1.10.1
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 +22 -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/esm/index.js +2 -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/types/index.d.ts +2 -0
- package/dist/types/useCheckPermissions.d.ts +69 -0
- package/dist/types/useControlledState.d.ts +98 -0
- package/package.json +4 -3
package/dist/cjs/index.js
CHANGED
|
@@ -190,4 +190,26 @@ Object.keys(_useSystemInfo).forEach(function (key) {
|
|
|
190
190
|
}
|
|
191
191
|
});
|
|
192
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
|
+
});
|
|
193
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","_useFeatureFlags","_useSystemInfo"],"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\";\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":[]}
|
package/dist/esm/index.js
CHANGED
|
@@ -15,4 +15,6 @@ export * from "./useAuth.js";
|
|
|
15
15
|
export * from "./useLocation.js";
|
|
16
16
|
export * from "./useFeatureFlags.js";
|
|
17
17
|
export * from "./useSystemInfo.js";
|
|
18
|
+
export * from "./useCheckPermissions.js";
|
|
19
|
+
export * from "./useControlledState.js";
|
|
18
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\";\nexport * from \"./useFeatureFlags.js\";\nexport * from \"./useSystemInfo.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","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":[]}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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>>];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@next-core/react-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"homepage": "https://github.com/easyops-cn/next-core/tree/v3/packages/react-runtime",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"repository": {
|
|
@@ -38,8 +38,9 @@
|
|
|
38
38
|
"test:ci": "cross-env NODE_ENV='test' CI=true test-next"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
+
"@next-core/easyops-runtime": "^0.15.29",
|
|
41
42
|
"@next-core/react-element": "^1.0.38",
|
|
42
|
-
"@next-core/runtime": "^1.72.
|
|
43
|
+
"@next-core/runtime": "^1.72.4",
|
|
43
44
|
"@next-core/types": "^1.19.0",
|
|
44
45
|
"react": "0.0.0-experimental-ee8509801-20230117",
|
|
45
46
|
"react-dom": "0.0.0-experimental-ee8509801-20230117"
|
|
@@ -49,5 +50,5 @@
|
|
|
49
50
|
"@next-core/test-next": "^2.0.1",
|
|
50
51
|
"jest-fetch-mock": "^3.0.3"
|
|
51
52
|
},
|
|
52
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "0566ebd9fc4ce062cb4e39b8ce89895b0bc43bde"
|
|
53
54
|
}
|