@windrun-huaiin/third-ui 14.0.2 → 14.1.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.
@@ -21,6 +21,7 @@ function useFingerprint(config) {
21
21
  isLoading: false,
22
22
  isInitialized: false,
23
23
  error: 'Server-side rendering is not supported',
24
+ clearError: () => { },
24
25
  initializeAnonymousUser: () => tslib_es6.__awaiter(this, void 0, void 0, function* () { }),
25
26
  refreshUserData: () => tslib_es6.__awaiter(this, void 0, void 0, function* () { }),
26
27
  };
@@ -32,6 +33,11 @@ function useFingerprint(config) {
32
33
  const [isLoading, setIsLoading] = React.useState(true);
33
34
  const [isInitialized, setIsInitialized] = React.useState(false);
34
35
  const [error, setError] = React.useState(null);
36
+ const isInitializingAnonymousUserRef = React.useRef(false);
37
+ const requestedAnonymousFingerprintRef = React.useRef(null);
38
+ const clearError = React.useCallback(() => {
39
+ setError(null);
40
+ }, []);
35
41
  /**
36
42
  * 第一阶段:初始化fingerprint ID
37
43
  */
@@ -60,7 +66,17 @@ function useFingerprint(config) {
60
66
  setError('Cannot initialize user: Missing fingerprint ID');
61
67
  return;
62
68
  }
69
+ if (isInitializingAnonymousUserRef.current) {
70
+ console.log('Skipping anonymous user initialization because a request is already in flight:', fingerprintId);
71
+ return;
72
+ }
73
+ if (requestedAnonymousFingerprintRef.current === fingerprintId && isInitialized) {
74
+ console.log('Skipping anonymous user initialization because fingerprint is already initialized:', fingerprintId);
75
+ return;
76
+ }
63
77
  try {
78
+ isInitializingAnonymousUserRef.current = true;
79
+ requestedAnonymousFingerprintRef.current = fingerprintId;
64
80
  setIsLoading(true);
65
81
  setError(null);
66
82
  console.log('Initializing anonymous user with fingerprintId:', fingerprintId);
@@ -92,13 +108,15 @@ function useFingerprint(config) {
92
108
  }
93
109
  }
94
110
  catch (err) {
111
+ requestedAnonymousFingerprintRef.current = null;
95
112
  console.error('Failed to initialize anonymous user:', err);
96
113
  setError(err instanceof Error ? err.message : 'Unknown error');
97
114
  }
98
115
  finally {
116
+ isInitializingAnonymousUserRef.current = false;
99
117
  setIsLoading(false);
100
118
  }
101
- }), [fingerprintId, config.apiEndpoint]);
119
+ }), [fingerprintId, config.apiEndpoint, isInitialized]);
102
120
  /**
103
121
  * 刷新用户数据 - 使用POST请求(后端支持upsert逻辑)
104
122
  */
@@ -157,6 +175,7 @@ function useFingerprint(config) {
157
175
  isLoading,
158
176
  isInitialized,
159
177
  error,
178
+ clearError,
160
179
  initializeAnonymousUser,
161
180
  refreshUserData,
162
181
  };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { __awaiter } from '../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
3
- import { useState, useCallback, useEffect } from 'react';
3
+ import { useState, useRef, useCallback, useEffect } from 'react';
4
4
  import { getOrCreateFirstTouchData, getOrGenerateFingerprintId, createFingerprintHeaders } from './fingerprint-client.mjs';
5
5
  import { FINGERPRINT_SOURCE_REFER } from './fingerprint-shared.mjs';
6
6
 
@@ -19,6 +19,7 @@ function useFingerprint(config) {
19
19
  isLoading: false,
20
20
  isInitialized: false,
21
21
  error: 'Server-side rendering is not supported',
22
+ clearError: () => { },
22
23
  initializeAnonymousUser: () => __awaiter(this, void 0, void 0, function* () { }),
23
24
  refreshUserData: () => __awaiter(this, void 0, void 0, function* () { }),
24
25
  };
@@ -30,6 +31,11 @@ function useFingerprint(config) {
30
31
  const [isLoading, setIsLoading] = useState(true);
31
32
  const [isInitialized, setIsInitialized] = useState(false);
32
33
  const [error, setError] = useState(null);
34
+ const isInitializingAnonymousUserRef = useRef(false);
35
+ const requestedAnonymousFingerprintRef = useRef(null);
36
+ const clearError = useCallback(() => {
37
+ setError(null);
38
+ }, []);
33
39
  /**
34
40
  * 第一阶段:初始化fingerprint ID
35
41
  */
@@ -58,7 +64,17 @@ function useFingerprint(config) {
58
64
  setError('Cannot initialize user: Missing fingerprint ID');
59
65
  return;
60
66
  }
67
+ if (isInitializingAnonymousUserRef.current) {
68
+ console.log('Skipping anonymous user initialization because a request is already in flight:', fingerprintId);
69
+ return;
70
+ }
71
+ if (requestedAnonymousFingerprintRef.current === fingerprintId && isInitialized) {
72
+ console.log('Skipping anonymous user initialization because fingerprint is already initialized:', fingerprintId);
73
+ return;
74
+ }
61
75
  try {
76
+ isInitializingAnonymousUserRef.current = true;
77
+ requestedAnonymousFingerprintRef.current = fingerprintId;
62
78
  setIsLoading(true);
63
79
  setError(null);
64
80
  console.log('Initializing anonymous user with fingerprintId:', fingerprintId);
@@ -90,13 +106,15 @@ function useFingerprint(config) {
90
106
  }
91
107
  }
92
108
  catch (err) {
109
+ requestedAnonymousFingerprintRef.current = null;
93
110
  console.error('Failed to initialize anonymous user:', err);
94
111
  setError(err instanceof Error ? err.message : 'Unknown error');
95
112
  }
96
113
  finally {
114
+ isInitializingAnonymousUserRef.current = false;
97
115
  setIsLoading(false);
98
116
  }
99
- }), [fingerprintId, config.apiEndpoint]);
117
+ }), [fingerprintId, config.apiEndpoint, isInitialized]);
100
118
  /**
101
119
  * 刷新用户数据 - 使用POST请求(后端支持upsert逻辑)
102
120
  */
@@ -155,6 +173,7 @@ function useFingerprint(config) {
155
173
  isLoading,
156
174
  isInitialized,
157
175
  error,
176
+ clearError,
158
177
  initializeAnonymousUser,
159
178
  refreshUserData,
160
179
  };
@@ -8,8 +8,9 @@ export interface GradientButtonProps {
8
8
  iconClassName?: string;
9
9
  href?: string;
10
10
  openInNewTab?: boolean;
11
+ preserveReferrer?: boolean;
11
12
  onClick?: () => void | Promise<void>;
12
13
  loadingText?: React.ReactNode;
13
14
  preventDoubleClick?: boolean;
14
15
  }
15
- export declare function GradientButton({ title, icon, align, disabled, className, href, openInNewTab, onClick, loadingText, preventDoubleClick, iconClassName, }: GradientButtonProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function GradientButton({ title, icon, align, disabled, className, href, openInNewTab, preserveReferrer, onClick, loadingText, preventDoubleClick, iconClassName, }: GradientButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -9,7 +9,7 @@ var lib = require('@windrun-huaiin/base-ui/lib');
9
9
  var Link = require('next/link');
10
10
  var React = require('react');
11
11
 
12
- function GradientButton({ title, icon, align = 'left', disabled = false, className = "", href, openInNewTab = true, onClick, loadingText, preventDoubleClick = true, iconClassName, }) {
12
+ function GradientButton({ title, icon, align = 'left', disabled = false, className = "", href, openInNewTab = true, preserveReferrer = false, onClick, loadingText, preventDoubleClick = true, iconClassName, }) {
13
13
  const [isLoading, setIsLoading] = React.useState(false);
14
14
  const actualLoadingText = loadingText || (title === null || title === void 0 ? void 0 : title.toString().trim()) || 'Loading...';
15
15
  const defaultIconClass = "h-4 w-4";
@@ -84,7 +84,7 @@ function GradientButton({ title, icon, align = 'left', disabled = false, classNa
84
84
  // for click
85
85
  jsxRuntime.jsx("button", { type: "button", className: buttonClassName, onClick: handleClick, disabled: isDisabled, children: buttonContent })) : (
86
86
  // for Link
87
- jsxRuntime.jsx(Link, Object.assign({ href: href || "#", className: utils.cn(buttonClassName, "no-underline hover:no-underline") }, (openInNewTab ? { target: "_blank", rel: "noopener noreferrer" } : {}), { onClick: isDisabled ? (e) => e.preventDefault() : undefined, "aria-disabled": isDisabled, children: buttonContent }))) }));
87
+ jsxRuntime.jsx(Link, Object.assign({ href: href || "#", className: utils.cn(buttonClassName, "no-underline hover:no-underline") }, (openInNewTab ? { target: "_blank", rel: preserveReferrer ? 'noopener' : 'noopener noreferrer' } : {}), { onClick: isDisabled ? (e) => e.preventDefault() : undefined, "aria-disabled": isDisabled, children: buttonContent }))) }));
88
88
  }
89
89
 
90
90
  exports.GradientButton = GradientButton;
@@ -7,7 +7,7 @@ import { themeButtonGradientClass, themeButtonGradientHoverClass } from '@windru
7
7
  import Link from 'next/link';
8
8
  import React, { useState } from 'react';
9
9
 
10
- function GradientButton({ title, icon, align = 'left', disabled = false, className = "", href, openInNewTab = true, onClick, loadingText, preventDoubleClick = true, iconClassName, }) {
10
+ function GradientButton({ title, icon, align = 'left', disabled = false, className = "", href, openInNewTab = true, preserveReferrer = false, onClick, loadingText, preventDoubleClick = true, iconClassName, }) {
11
11
  const [isLoading, setIsLoading] = useState(false);
12
12
  const actualLoadingText = loadingText || (title === null || title === void 0 ? void 0 : title.toString().trim()) || 'Loading...';
13
13
  const defaultIconClass = "h-4 w-4";
@@ -82,7 +82,7 @@ function GradientButton({ title, icon, align = 'left', disabled = false, classNa
82
82
  // for click
83
83
  jsx("button", { type: "button", className: buttonClassName, onClick: handleClick, disabled: isDisabled, children: buttonContent })) : (
84
84
  // for Link
85
- jsx(Link, Object.assign({ href: href || "#", className: cn(buttonClassName, "no-underline hover:no-underline") }, (openInNewTab ? { target: "_blank", rel: "noopener noreferrer" } : {}), { onClick: isDisabled ? (e) => e.preventDefault() : undefined, "aria-disabled": isDisabled, children: buttonContent }))) }));
85
+ jsx(Link, Object.assign({ href: href || "#", className: cn(buttonClassName, "no-underline hover:no-underline") }, (openInNewTab ? { target: "_blank", rel: preserveReferrer ? 'noopener' : 'noopener noreferrer' } : {}), { onClick: isDisabled ? (e) => e.preventDefault() : undefined, "aria-disabled": isDisabled, children: buttonContent }))) }));
86
86
  }
87
87
 
88
88
  export { GradientButton };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "14.0.2",
3
+ "version": "14.1.0",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",