xxf_react 0.5.6 → 0.5.8

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.
@@ -0,0 +1,147 @@
1
+ import React, { ReactNode, HTMLAttributes } from 'react';
2
+ /**
3
+ * XHover 组件属性
4
+ */
5
+ export interface XHoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onMouseEnter' | 'onMouseLeave'> {
6
+ /**
7
+ * 子组件
8
+ */
9
+ children: ReactNode;
10
+ /**
11
+ * 悬浮触发延迟时间(毫秒)
12
+ *
13
+ * 鼠标进入后,需要持续悬浮该时间才会触发 onHover 回调和显示 hoverLayer。
14
+ * - 设为 0 或不设置:鼠标进入立即触发
15
+ * - 设为正数:鼠标需要停留指定毫秒后才触发
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // 悬浮 2 秒后触发
20
+ * <XHover hoverDelay={2000} onHover={handleHover}>
21
+ *
22
+ * // 立即触发(默认)
23
+ * <XHover onHover={handleHover}>
24
+ * ```
25
+ *
26
+ * @default 0
27
+ */
28
+ hoverDelay?: number;
29
+ /**
30
+ * 鼠标进入时立即触发的回调(不等待 hoverDelay)
31
+ *
32
+ * 适用于需要在鼠标进入时立即做一些事情的场景,如显示边框高亮等
33
+ */
34
+ onEnter?: () => void;
35
+ /**
36
+ * 悬浮回调
37
+ *
38
+ * 当鼠标悬浮达到 hoverDelay 时间后触发
39
+ */
40
+ onHover?: () => void;
41
+ /**
42
+ * 鼠标离开回调
43
+ *
44
+ * @param triggered - 是否已触发过 onHover(用于判断是否需要隐藏 tooltip 等)
45
+ */
46
+ onLeave?: (triggered: boolean) => void;
47
+ /**
48
+ * 悬浮覆盖层
49
+ *
50
+ * 当悬浮触发(达到 hoverDelay 时间)后,显示在 children 上方的内容。
51
+ * 鼠标离开后自动隐藏。
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * <XHover
56
+ * hoverDelay={1000}
57
+ * hoverLayer={() => (
58
+ * <div className="absolute inset-0 bg-black/50 flex items-center justify-center">
59
+ * <span className="text-white">悬浮提示</span>
60
+ * </div>
61
+ * )}
62
+ * >
63
+ * <img src="..." />
64
+ * </XHover>
65
+ * ```
66
+ */
67
+ hoverLayer?: () => ReactNode;
68
+ /**
69
+ * 是否禁用悬浮检测
70
+ *
71
+ * @default false
72
+ */
73
+ disabled?: boolean;
74
+ /**
75
+ * 容器元素类型
76
+ *
77
+ * @default 'div'
78
+ */
79
+ as?: 'div' | 'span';
80
+ }
81
+ /**
82
+ * 悬浮触发组件
83
+ *
84
+ * 支持延迟触发悬浮回调,适用于需要用户停留一段时间后才响应的场景。
85
+ *
86
+ * @example
87
+ * ```tsx
88
+ * // 基础用法:鼠标悬浮 2 秒后触发
89
+ * <XHover hoverDelay={2000} onHover={() => console.log('悬浮触发')}>
90
+ * <div>悬浮我</div>
91
+ * </XHover>
92
+ *
93
+ * // 无延迟:立即触发
94
+ * <XHover onHover={() => console.log('立即触发')}>
95
+ * <div>悬浮我</div>
96
+ * </XHover>
97
+ *
98
+ * // 带离开回调,判断是否触发过
99
+ * <XHover
100
+ * hoverDelay={1000}
101
+ * onHover={() => setShowTooltip(true)}
102
+ * onLeave={(triggered) => {
103
+ * if (triggered) setShowTooltip(false)
104
+ * }}
105
+ * >
106
+ * <Button>悬浮显示提示</Button>
107
+ * </XHover>
108
+ *
109
+ * // 使用 hoverLayer 显示悬浮覆盖层
110
+ * <XHover
111
+ * hoverDelay={1000}
112
+ * hoverLayer={() => (
113
+ * <div className="absolute inset-0 bg-black/50 flex items-center justify-center">
114
+ * <PlayIcon className="text-white w-12 h-12" />
115
+ * </div>
116
+ * )}
117
+ * >
118
+ * <img src="thumbnail.jpg" />
119
+ * </XHover>
120
+ *
121
+ * // 使用 span 作为容器(适用于 inline 场景)
122
+ * <XHover as="span" hoverDelay={500} onHover={handleHover}>
123
+ * <span>inline 文本</span>
124
+ * </XHover>
125
+ *
126
+ * // 禁用状态
127
+ * <XHover disabled={isLoading} hoverDelay={1000} onHover={handleHover}>
128
+ * <div>内容</div>
129
+ * </XHover>
130
+ *
131
+ * // 使用 onEnter 立即响应 + onHover 延迟响应
132
+ * <XHover
133
+ * hoverDelay={1000}
134
+ * onEnter={() => setHighlight(true)}
135
+ * onHover={() => setShowDetail(true)}
136
+ * onLeave={() => {
137
+ * setHighlight(false)
138
+ * setShowDetail(false)
139
+ * }}
140
+ * >
141
+ * <Card />
142
+ * </XHover>
143
+ * ```
144
+ */
145
+ export declare function XHover({ children, hoverDelay, onEnter, onHover, onLeave, hoverLayer, disabled, as: Component, style, ...rest }: XHoverProps): React.JSX.Element;
146
+ export default XHover;
147
+ //# sourceMappingURL=XHover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XHover.d.ts","sourceRoot":"","sources":["../../../src/layout/hover/XHover.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAA2C,SAAS,EAAE,cAAc,EAAC,MAAM,OAAO,CAAA;AAEhG;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,cAAc,CAAC;IACtG;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAA;IAEnB;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAEpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAEpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;IAEtC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,UAAU,CAAC,EAAE,MAAM,SAAS,CAAA;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;;;OAIG;IACH,EAAE,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,wBAAgB,MAAM,CAAC,EACnB,QAAQ,EACR,UAAc,EACd,OAAO,EACP,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAgB,EAChB,EAAE,EAAE,SAAiB,EACrB,KAAK,EACL,GAAG,IAAI,EACV,EAAE,WAAW,qBA0Eb;AAED,eAAe,MAAM,CAAA"}
@@ -0,0 +1,128 @@
1
+ import React, { useCallback, useRef, useEffect, useState } from 'react';
2
+ /**
3
+ * 悬浮触发组件
4
+ *
5
+ * 支持延迟触发悬浮回调,适用于需要用户停留一段时间后才响应的场景。
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * // 基础用法:鼠标悬浮 2 秒后触发
10
+ * <XHover hoverDelay={2000} onHover={() => console.log('悬浮触发')}>
11
+ * <div>悬浮我</div>
12
+ * </XHover>
13
+ *
14
+ * // 无延迟:立即触发
15
+ * <XHover onHover={() => console.log('立即触发')}>
16
+ * <div>悬浮我</div>
17
+ * </XHover>
18
+ *
19
+ * // 带离开回调,判断是否触发过
20
+ * <XHover
21
+ * hoverDelay={1000}
22
+ * onHover={() => setShowTooltip(true)}
23
+ * onLeave={(triggered) => {
24
+ * if (triggered) setShowTooltip(false)
25
+ * }}
26
+ * >
27
+ * <Button>悬浮显示提示</Button>
28
+ * </XHover>
29
+ *
30
+ * // 使用 hoverLayer 显示悬浮覆盖层
31
+ * <XHover
32
+ * hoverDelay={1000}
33
+ * hoverLayer={() => (
34
+ * <div className="absolute inset-0 bg-black/50 flex items-center justify-center">
35
+ * <PlayIcon className="text-white w-12 h-12" />
36
+ * </div>
37
+ * )}
38
+ * >
39
+ * <img src="thumbnail.jpg" />
40
+ * </XHover>
41
+ *
42
+ * // 使用 span 作为容器(适用于 inline 场景)
43
+ * <XHover as="span" hoverDelay={500} onHover={handleHover}>
44
+ * <span>inline 文本</span>
45
+ * </XHover>
46
+ *
47
+ * // 禁用状态
48
+ * <XHover disabled={isLoading} hoverDelay={1000} onHover={handleHover}>
49
+ * <div>内容</div>
50
+ * </XHover>
51
+ *
52
+ * // 使用 onEnter 立即响应 + onHover 延迟响应
53
+ * <XHover
54
+ * hoverDelay={1000}
55
+ * onEnter={() => setHighlight(true)}
56
+ * onHover={() => setShowDetail(true)}
57
+ * onLeave={() => {
58
+ * setHighlight(false)
59
+ * setShowDetail(false)
60
+ * }}
61
+ * >
62
+ * <Card />
63
+ * </XHover>
64
+ * ```
65
+ */
66
+ export function XHover({ children, hoverDelay = 0, onEnter, onHover, onLeave, hoverLayer, disabled = false, as: Component = 'div', style, ...rest }) {
67
+ const timerRef = useRef(null);
68
+ const hasTriggeredRef = useRef(false);
69
+ // 只有 hoverLayer 存在时才需要状态
70
+ const [showLayer, setShowLayer] = useState(false);
71
+ const clearTimer = useCallback(() => {
72
+ if (timerRef.current) {
73
+ clearTimeout(timerRef.current);
74
+ timerRef.current = null;
75
+ }
76
+ }, []);
77
+ // 组件卸载时清理定时器
78
+ useEffect(() => {
79
+ return clearTimer;
80
+ }, [clearTimer]);
81
+ // disabled 变化时清理定时器和状态
82
+ useEffect(() => {
83
+ if (disabled) {
84
+ clearTimer();
85
+ if (hoverLayer) {
86
+ setShowLayer(false);
87
+ }
88
+ }
89
+ }, [disabled, clearTimer, hoverLayer]);
90
+ const handleMouseEnter = useCallback(() => {
91
+ if (disabled)
92
+ return;
93
+ hasTriggeredRef.current = false;
94
+ clearTimer();
95
+ // 立即触发 onEnter
96
+ onEnter === null || onEnter === void 0 ? void 0 : onEnter();
97
+ if (hoverDelay <= 0) {
98
+ hasTriggeredRef.current = true;
99
+ if (hoverLayer)
100
+ setShowLayer(true);
101
+ onHover === null || onHover === void 0 ? void 0 : onHover();
102
+ }
103
+ else {
104
+ timerRef.current = setTimeout(() => {
105
+ hasTriggeredRef.current = true;
106
+ if (hoverLayer)
107
+ setShowLayer(true);
108
+ onHover === null || onHover === void 0 ? void 0 : onHover();
109
+ }, hoverDelay);
110
+ }
111
+ }, [hoverDelay, onEnter, onHover, clearTimer, disabled, hoverLayer]);
112
+ const handleMouseLeave = useCallback(() => {
113
+ if (disabled)
114
+ return;
115
+ clearTimer();
116
+ if (hoverLayer)
117
+ setShowLayer(false);
118
+ onLeave === null || onLeave === void 0 ? void 0 : onLeave(hasTriggeredRef.current);
119
+ }, [clearTimer, onLeave, disabled, hoverLayer]);
120
+ // 如果有 hoverLayer,需要使用 relative 定位(用户 style 可覆盖)
121
+ const containerStyle = hoverLayer
122
+ ? { position: 'relative', ...style }
123
+ : style;
124
+ return (React.createElement(Component, { ...rest, style: containerStyle, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
125
+ children,
126
+ hoverLayer && showLayer && hoverLayer()));
127
+ }
128
+ export default XHover;
@@ -6,4 +6,5 @@ export * from './resize/impl/SizedLayout';
6
6
  export * from './image/XImage';
7
7
  export * from './visibility/ElementVisibilityHooks';
8
8
  export * from './virtualized/VirtualizedConfig';
9
+ export * from './hover/XHover';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qCAAqC,CAAA;AACnD,cAAc,iCAAiC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qCAAqC,CAAA;AACnD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gBAAgB,CAAA"}
@@ -6,3 +6,4 @@ export * from './resize/impl/SizedLayout';
6
6
  export * from './image/XImage';
7
7
  export * from './visibility/ElementVisibilityHooks';
8
8
  export * from './virtualized/VirtualizedConfig';
9
+ export * from './hover/XHover';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xxf_react",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",