xxf_react 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,4 +5,4 @@ declare global {
5
5
  }
6
6
  export declare function isSafariLoadFailed(error: unknown): boolean;
7
7
  export declare function initPromiseErrorExtension(): void;
8
- //# sourceMappingURL=promise_ext.d.ts.map
8
+ //# sourceMappingURL=PromiseExt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromiseExt.d.ts","sourceRoot":"","sources":["../../src/flow/PromiseExt.ts"],"names":[],"mappings":"AAIA,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,OAAO,CAAC,CAAC;QACf,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACjE;CACJ;AAGD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM1D;AAED,wBAAgB,yBAAyB,IAAI,IAAI,CAgDhD"}
@@ -0,0 +1,33 @@
1
+ export interface PromiseLifecycle<T> {
2
+ /** 开始执行时(同步调用) */
3
+ doOnStart?: () => void;
4
+ /** 成功时 */
5
+ doOnSuccess?: (value: T) => void;
6
+ /** 失败时 */
7
+ doOnError?: (error: unknown) => void;
8
+ /** 无论成功失败都会调用(类似 doFinally) */
9
+ doFinally?: () => void;
10
+ }
11
+ /**
12
+ * 为 Promise 添加生命周期钩子
13
+ *
14
+ * @param promiseFn - 返回 Promise 的函数(使用回调形式以确保 doOnStart 在 Promise 执行前调用)
15
+ * @param lifecycle - 生命周期回调配置
16
+ * @returns 原始 Promise 的结果
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * // 基本用法:管理 loading 状态
21
+ * withLifecycle(
22
+ * () => fetchUserData(userId),
23
+ * {
24
+ * doOnStart: () => setLoading(true),
25
+ * doOnSuccess: (user) => setUser(user),
26
+ * doOnError: (err) => setError(err.message),
27
+ * doFinally: () => setLoading(false)
28
+ * }
29
+ * );
30
+ * ```
31
+ */
32
+ export declare function withLifecycle<T>(promiseFn: () => Promise<T>, lifecycle: PromiseLifecycle<T>): Promise<T>;
33
+ //# sourceMappingURL=PromiseLifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromiseLifecycle.d.ts","sourceRoot":"","sources":["../../src/flow/PromiseLifecycle.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAC/B,kBAAkB;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,UAAU;IACV,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACjC,UAAU;IACV,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,+BAA+B;IAC/B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC3B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 为 Promise 添加生命周期钩子
3
+ *
4
+ * @param promiseFn - 返回 Promise 的函数(使用回调形式以确保 doOnStart 在 Promise 执行前调用)
5
+ * @param lifecycle - 生命周期回调配置
6
+ * @returns 原始 Promise 的结果
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // 基本用法:管理 loading 状态
11
+ * withLifecycle(
12
+ * () => fetchUserData(userId),
13
+ * {
14
+ * doOnStart: () => setLoading(true),
15
+ * doOnSuccess: (user) => setUser(user),
16
+ * doOnError: (err) => setError(err.message),
17
+ * doFinally: () => setLoading(false)
18
+ * }
19
+ * );
20
+ * ```
21
+ */
22
+ export function withLifecycle(promiseFn, lifecycle) {
23
+ const { doOnStart, doOnSuccess, doOnError, doFinally } = lifecycle;
24
+ doOnStart === null || doOnStart === void 0 ? void 0 : doOnStart();
25
+ return promiseFn()
26
+ .then((value) => {
27
+ doOnSuccess === null || doOnSuccess === void 0 ? void 0 : doOnSuccess(value);
28
+ return value;
29
+ })
30
+ .catch((error) => {
31
+ doOnError === null || doOnError === void 0 ? void 0 : doOnError(error);
32
+ throw error; // 继续抛出,不吞掉错误
33
+ })
34
+ .finally(() => {
35
+ doFinally === null || doFinally === void 0 ? void 0 : doFinally();
36
+ });
37
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 为 Promise 自动绑定 loading 状态
3
+ *
4
+ * @param promiseFn - 返回 Promise 的函数
5
+ * @param setLoading - React 的 setState 函数,用于设置 loading 状态
6
+ * @returns 原始 Promise 的结果
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const [loading, setLoading] = useState(false);
11
+ *
12
+ * // 自动管理 loading 状态
13
+ * const handleSubmit = () => {
14
+ * withLoading(() => submitForm(data), setLoading);
15
+ * };
16
+ *
17
+ * // 等价于
18
+ * withLifecycle(() => submitForm(data), {
19
+ * doOnStart: () => setLoading(true),
20
+ * doFinally: () => setLoading(false)
21
+ * });
22
+ * ```
23
+ */
24
+ export declare function withLoading<T>(promiseFn: () => Promise<T>, setLoading: (loading: boolean) => void): Promise<T>;
25
+ //# sourceMappingURL=PromiseLoading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromiseLoading.d.ts","sourceRoot":"","sources":["../../src/flow/PromiseLoading.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,CAAC,EACzB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GACvC,OAAO,CAAC,CAAC,CAAC,CAKZ"}
@@ -0,0 +1,30 @@
1
+ import { withLifecycle } from "./PromiseLifecycle";
2
+ /**
3
+ * 为 Promise 自动绑定 loading 状态
4
+ *
5
+ * @param promiseFn - 返回 Promise 的函数
6
+ * @param setLoading - React 的 setState 函数,用于设置 loading 状态
7
+ * @returns 原始 Promise 的结果
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const [loading, setLoading] = useState(false);
12
+ *
13
+ * // 自动管理 loading 状态
14
+ * const handleSubmit = () => {
15
+ * withLoading(() => submitForm(data), setLoading);
16
+ * };
17
+ *
18
+ * // 等价于
19
+ * withLifecycle(() => submitForm(data), {
20
+ * doOnStart: () => setLoading(true),
21
+ * doFinally: () => setLoading(false)
22
+ * });
23
+ * ```
24
+ */
25
+ export function withLoading(promiseFn, setLoading) {
26
+ return withLifecycle(promiseFn, {
27
+ doOnStart: () => setLoading(true),
28
+ doFinally: () => setLoading(false)
29
+ });
30
+ }
@@ -1,2 +1,4 @@
1
- export * from './promise_ext';
1
+ export * from './PromiseExt';
2
+ export * from './PromiseLifecycle';
3
+ export * from './PromiseLoading';
2
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/flow/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/flow/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC"}
@@ -1 +1,3 @@
1
- export * from './promise_ext';
1
+ export * from './PromiseExt';
2
+ export * from './PromiseLifecycle';
3
+ export * from './PromiseLoading';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { initPromiseErrorExtension } from "./flow/promise_ext";
1
+ import { initPromiseErrorExtension } from "./flow/PromiseExt";
2
2
  export * from './sse';
3
3
  export * from './fetch';
4
4
  export * from './utils';
@@ -26,11 +26,13 @@ export interface XButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
26
26
  */
27
27
  loadingGravity?: LoadingGravity;
28
28
  /**
29
- * 自定义加载指示器
30
- * - 不传则使用默认的旋转圆环
29
+ * 自定义加载指示器(回调形式,懒创建)
30
+ * - 只有 loading=true 时才会调用
31
+ * - 不传则使用默认的 XSpinner
31
32
  * - 尺寸建议使用 `em` 单位以跟随字体大小
33
+ * @example () => <MySpinner className="w-5 h-5" />
32
34
  */
33
- loadingIndicator?: ReactNode;
35
+ loadingIndicator?: () => ReactNode;
34
36
  /**
35
37
  * 指示器与内容的间距(像素)
36
38
  * - 仅在 `loadingGravity` 为 `start` 或 `end` 时生效
@@ -77,8 +79,8 @@ export interface XButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
77
79
  * 加载中...
78
80
  * </XButton>
79
81
  *
80
- * // 自定义加载指示器
81
- * <XButton loading loadingIndicator={<MySpinner />}>
82
+ * // 自定义加载指示器(回调形式,懒创建)
83
+ * <XButton loading loadingIndicator={() => <MySpinner />}>
82
84
  * 处理中
83
85
  * </XButton>
84
86
  *
@@ -1 +1 @@
1
- {"version":3,"file":"XButton.d.ts","sourceRoot":"","sources":["../../../src/layout/button/XButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAa,oBAAoB,EAAE,SAAS,EAAgB,MAAM,OAAO,CAAC;AAIxF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IACzE;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAE7B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,OAAO,wFAyInB,CAAC"}
1
+ {"version":3,"file":"XButton.d.ts","sourceRoot":"","sources":["../../../src/layout/button/XButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAa,oBAAoB,EAAE,SAAS,EAAgB,MAAM,OAAO,CAAC;AAIxF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IACzE;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,SAAS,CAAC;IAEnC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,OAAO,wFA6InB,CAAC"}
@@ -26,8 +26,8 @@ import { XSpinner } from "../spinner/XSpinner";
26
26
  * 加载中...
27
27
  * </XButton>
28
28
  *
29
- * // 自定义加载指示器
30
- * <XButton loading loadingIndicator={<MySpinner />}>
29
+ * // 自定义加载指示器(回调形式,懒创建)
30
+ * <XButton loading loadingIndicator={() => <MySpinner />}>
31
31
  * 处理中
32
32
  * </XButton>
33
33
  *
@@ -43,8 +43,11 @@ import { XSpinner } from "../spinner/XSpinner";
43
43
  * ```
44
44
  */
45
45
  export const XButton = forwardRef(function XButton({ loading = false, loadingGravity = 'start', loadingIndicator, loadingGap = 8, debounceWait = 500, stopPropagation = false, children, onClick, disabled, style, type = 'button', ...rest }, ref) {
46
- /** 使用自定义指示器或默认指示器 */
47
- const indicator = loadingIndicator !== null && loadingIndicator !== void 0 ? loadingIndicator : React.createElement(XSpinner, null);
46
+ /**
47
+ * 获取加载指示器(懒创建)
48
+ * - 只在 loading=true 时才实际创建节点
49
+ */
50
+ const getIndicator = () => { var _a; return (_a = loadingIndicator === null || loadingIndicator === void 0 ? void 0 : loadingIndicator()) !== null && _a !== void 0 ? _a : React.createElement(XSpinner, null); };
48
51
  /**
49
52
  * 防抖处理后的点击回调
50
53
  * - leading: true 首次点击立即执行
@@ -98,6 +101,7 @@ export const XButton = forwardRef(function XButton({ loading = false, loadingGra
98
101
  if (!loading) {
99
102
  return children;
100
103
  }
104
+ const indicator = getIndicator();
101
105
  switch (loadingGravity) {
102
106
  case 'start':
103
107
  return (React.createElement(React.Fragment, null,
@@ -1 +1 @@
1
- {"version":3,"file":"XSpinner.d.ts","sourceRoot":"","sources":["../../../src/layout/spinner/XSpinner.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,QAAQ,GAAI,gBAAa,aAAkB,sBAevD,CAAC"}
1
+ {"version":3,"file":"XSpinner.d.ts","sourceRoot":"","sources":["../../../src/layout/spinner/XSpinner.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,QAAQ,GAAI,gBAAa,aAAkB,sBAoBvD,CAAC"}
@@ -30,11 +30,15 @@ import { cn } from "tailwind-variants";
30
30
  *
31
31
  * @see XButton - 内置 XSpinner 作为默认加载指示器
32
32
  */
33
- export const XSpinner = ({ className } = {}) => (React.createElement("div", { className: cn(
34
- // 尺寸:1em 跟随字体大小
35
- "w-[1em] h-[1em]",
33
+ export const XSpinner = ({ className } = {}) => (React.createElement("div", { style: {
34
+ // 使用内联样式确保 em 单位正确跟随 font-size
35
+ width: '1em',
36
+ height: '1em',
37
+ // 边框粗细也跟随字体大小
38
+ borderWidth: '0.125em',
39
+ }, className: cn(
36
40
  // 边框样式:白色圆环,顶部透明形成缺口
37
- "border-2 border-white border-t-transparent rounded-full",
41
+ "border-solid border-current border-t-transparent rounded-full",
38
42
  // 动画:无限旋转
39
43
  "animate-spin",
40
44
  // 透明度:略微降低避免过亮
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xxf_react",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"file":"promise_ext.d.ts","sourceRoot":"","sources":["../../src/flow/promise_ext.ts"],"names":[],"mappings":"AAIA,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,OAAO,CAAC,CAAC;QACf,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACjE;CACJ;AAGD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM1D;AAED,wBAAgB,yBAAyB,IAAI,IAAI,CAgDhD"}
File without changes