xxf_react 0.5.0 → 0.5.2
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/event-bus/EventBus.d.ts +172 -0
- package/dist/event-bus/EventBus.d.ts.map +1 -0
- package/dist/event-bus/EventBus.js +267 -0
- package/dist/event-bus/EventDemo.d.ts +71 -0
- package/dist/event-bus/EventDemo.d.ts.map +1 -0
- package/dist/event-bus/EventDemo.js +76 -0
- package/dist/event-bus/EventHooks.d.ts +48 -0
- package/dist/event-bus/EventHooks.d.ts.map +1 -0
- package/dist/event-bus/EventHooks.js +73 -0
- package/dist/event-bus/index.d.ts +3 -0
- package/dist/event-bus/index.d.ts.map +1 -0
- package/dist/event-bus/index.js +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +6 -2
- package/dist/utils/SizedContainer.d.ts +0 -60
- package/dist/utils/SizedContainer.d.ts.map +0 -1
- package/dist/utils/SizedContainer.js +0 -60
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 事件处理器类型
|
|
3
|
+
*/
|
|
4
|
+
type Handler<T> = (event: T) => void;
|
|
5
|
+
/**
|
|
6
|
+
* 类构造器类型
|
|
7
|
+
*/
|
|
8
|
+
type Constructor<T = any> = new (...args: any[]) => T;
|
|
9
|
+
/**
|
|
10
|
+
* 事件基类
|
|
11
|
+
* 所有事件都需要继承此类
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* export class PaymentSuccessEvent extends BaseEvent {
|
|
16
|
+
* static readonly type = 'PaymentSuccessEvent'
|
|
17
|
+
* constructor(public orderId: string, public amount: number) {
|
|
18
|
+
* super()
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare abstract class BaseEvent {
|
|
24
|
+
/**
|
|
25
|
+
* 事件类型标识(子类必须覆盖此属性)
|
|
26
|
+
* 使用静态属性避免生产环境类名混淆问题
|
|
27
|
+
*/
|
|
28
|
+
static readonly type: string;
|
|
29
|
+
/**
|
|
30
|
+
* 获取事件类型标识
|
|
31
|
+
*/
|
|
32
|
+
static getType(): string;
|
|
33
|
+
/**
|
|
34
|
+
* 发送当前事件
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* // 发送事件
|
|
39
|
+
* new PaymentSuccessEvent('order-123', 99.99).post()
|
|
40
|
+
*
|
|
41
|
+
* // 监听方式1:直接订阅
|
|
42
|
+
* eventBus.on(PaymentSuccessEvent, (event) => {
|
|
43
|
+
* console.log(event.orderId, event.amount)
|
|
44
|
+
* })
|
|
45
|
+
*
|
|
46
|
+
* // 监听方式2:React Hook
|
|
47
|
+
* useEvent(PaymentSuccessEvent, (event) => {
|
|
48
|
+
* console.log(event.orderId, event.amount)
|
|
49
|
+
* })
|
|
50
|
+
*
|
|
51
|
+
* // 监听方式3:一次性监听
|
|
52
|
+
* useEventOnce(PaymentSuccessEvent, (event) => {
|
|
53
|
+
* console.log('只触发一次')
|
|
54
|
+
* })
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
post(): Promise<void>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 事件总线
|
|
61
|
+
* 基于 BroadcastChannel 实现跨浏览器 Tab 通信
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* // 发送事件
|
|
66
|
+
* eventBus.emit(new PaymentSuccessEvent('order-123', 99.99))
|
|
67
|
+
*
|
|
68
|
+
* // 订阅事件
|
|
69
|
+
* eventBus.on(PaymentSuccessEvent, (event) => {
|
|
70
|
+
* console.log(event.orderId)
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare class EventBus {
|
|
75
|
+
private static instance;
|
|
76
|
+
private channel;
|
|
77
|
+
private handlers;
|
|
78
|
+
private eventRegistry;
|
|
79
|
+
private isInitialized;
|
|
80
|
+
private channelName;
|
|
81
|
+
private constructor();
|
|
82
|
+
/**
|
|
83
|
+
* 获取单例实例
|
|
84
|
+
* @param name 频道名称,默认 'nexus-app'
|
|
85
|
+
*/
|
|
86
|
+
static getInstance(name?: string): EventBus;
|
|
87
|
+
/**
|
|
88
|
+
* 初始化频道(延迟初始化,仅在浏览器环境)
|
|
89
|
+
*/
|
|
90
|
+
private ensureInitialized;
|
|
91
|
+
/**
|
|
92
|
+
* 分发事件到对应的处理器
|
|
93
|
+
*/
|
|
94
|
+
private dispatch;
|
|
95
|
+
/**
|
|
96
|
+
* 发送事件
|
|
97
|
+
* @param event 事件实例
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* eventBus.emit(new PaymentSuccessEvent('order-123', 99.99))
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
emit<T extends BaseEvent>(event: T): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* 订阅事件
|
|
107
|
+
* @param EventClass 事件类
|
|
108
|
+
* @param handler 事件处理器
|
|
109
|
+
* @returns 取消订阅函数
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* // 订阅
|
|
114
|
+
* const unsubscribe = eventBus.on(PaymentSuccessEvent, (event) => {
|
|
115
|
+
* console.log(event.orderId)
|
|
116
|
+
* })
|
|
117
|
+
*
|
|
118
|
+
* // 取消订阅
|
|
119
|
+
* unsubscribe()
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
on<T extends BaseEvent>(EventClass: Constructor<T>, handler: Handler<T>): () => void;
|
|
123
|
+
/**
|
|
124
|
+
* 取消订阅事件
|
|
125
|
+
* @param EventClass 事件类
|
|
126
|
+
* @param handler 事件处理器
|
|
127
|
+
*/
|
|
128
|
+
off<T extends BaseEvent>(EventClass: Constructor<T>, handler: Handler<T>): void;
|
|
129
|
+
/**
|
|
130
|
+
* 订阅一次性事件(触发后自动取消订阅)
|
|
131
|
+
* @param EventClass 事件类
|
|
132
|
+
* @param handler 事件处理器
|
|
133
|
+
* @returns 取消订阅函数
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* eventBus.once(PaymentSuccessEvent, (event) => {
|
|
138
|
+
* console.log('只触发一次:', event.orderId)
|
|
139
|
+
* })
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
once<T extends BaseEvent>(EventClass: Constructor<T>, handler: Handler<T>): () => void;
|
|
143
|
+
/**
|
|
144
|
+
* 检查是否有订阅者
|
|
145
|
+
* @param EventClass 事件类
|
|
146
|
+
*/
|
|
147
|
+
hasSubscribers<T extends BaseEvent>(EventClass: Constructor<T>): boolean;
|
|
148
|
+
/**
|
|
149
|
+
* 获取订阅者数量
|
|
150
|
+
* @param EventClass 事件类
|
|
151
|
+
*/
|
|
152
|
+
subscriberCount<T extends BaseEvent>(EventClass: Constructor<T>): number;
|
|
153
|
+
/**
|
|
154
|
+
* 清除指定事件的所有订阅
|
|
155
|
+
* @param EventClass 事件类
|
|
156
|
+
*/
|
|
157
|
+
clear<T extends BaseEvent>(EventClass: Constructor<T>): void;
|
|
158
|
+
/**
|
|
159
|
+
* 清除所有订阅
|
|
160
|
+
*/
|
|
161
|
+
clearAll(): void;
|
|
162
|
+
/**
|
|
163
|
+
* 关闭频道并释放资源
|
|
164
|
+
*/
|
|
165
|
+
destroy(): Promise<void>;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 事件总线单例
|
|
169
|
+
*/
|
|
170
|
+
export declare const eventBus: EventBus;
|
|
171
|
+
export {};
|
|
172
|
+
//# sourceMappingURL=EventBus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventBus.d.ts","sourceRoot":"","sources":["../../src/event-bus/EventBus.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAA;AAEpC;;GAEG;AACH,KAAK,WAAW,CAAC,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;AAErD;;;;;;;;;;;;;GAaG;AACH,8BAAsB,SAAS;IAC3B;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAE5B;;OAEG;IACH,MAAM,CAAC,OAAO,IAAI,MAAM;IAUxB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGxB;AAED;;;;;;;;;;;;;;GAcG;AACH,cAAM,QAAQ;IACV,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAwB;IAE/C,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,aAAa,CAA4C;IACjE,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,WAAW,CAAQ;IAE3B,OAAO;IAIP;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,SAAc,GAAG,QAAQ;IAOhD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAazB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAkBhB;;;;;;;;OAQG;IACH,IAAI,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBlD;;;;;;;;;;;;;;;;OAgBG;IACH,EAAE,CAAC,CAAC,SAAS,SAAS,EAClB,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GACpB,MAAM,IAAI;IAoBb;;;;OAIG;IACH,GAAG,CAAC,CAAC,SAAS,SAAS,EACnB,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GACpB,IAAI;IAYP;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,CAAC,SAAS,SAAS,EACpB,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GACpB,MAAM,IAAI;IAQb;;;OAGG;IACH,cAAc,CAAC,CAAC,SAAS,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO;IAMxE;;;OAGG;IACH,eAAe,CAAC,CAAC,SAAS,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,MAAM;IAKxE;;;OAGG;IACH,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;IAM5D;;OAEG;IACH,QAAQ,IAAI,IAAI;IAKhB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CASjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,UAAyB,CAAA"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { BroadcastChannel } from 'broadcast-channel';
|
|
2
|
+
/**
|
|
3
|
+
* 事件基类
|
|
4
|
+
* 所有事件都需要继承此类
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* export class PaymentSuccessEvent extends BaseEvent {
|
|
9
|
+
* static readonly type = 'PaymentSuccessEvent'
|
|
10
|
+
* constructor(public orderId: string, public amount: number) {
|
|
11
|
+
* super()
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export class BaseEvent {
|
|
17
|
+
/**
|
|
18
|
+
* 获取事件类型标识
|
|
19
|
+
*/
|
|
20
|
+
static getType() {
|
|
21
|
+
if (!this.type) {
|
|
22
|
+
throw new Error(`[EventBus] Event class "${this.name}" must define a static "type" property. ` +
|
|
23
|
+
`Example: static readonly type = '${this.name}'`);
|
|
24
|
+
}
|
|
25
|
+
return this.type;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 发送当前事件
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* // 发送事件
|
|
33
|
+
* new PaymentSuccessEvent('order-123', 99.99).post()
|
|
34
|
+
*
|
|
35
|
+
* // 监听方式1:直接订阅
|
|
36
|
+
* eventBus.on(PaymentSuccessEvent, (event) => {
|
|
37
|
+
* console.log(event.orderId, event.amount)
|
|
38
|
+
* })
|
|
39
|
+
*
|
|
40
|
+
* // 监听方式2:React Hook
|
|
41
|
+
* useEvent(PaymentSuccessEvent, (event) => {
|
|
42
|
+
* console.log(event.orderId, event.amount)
|
|
43
|
+
* })
|
|
44
|
+
*
|
|
45
|
+
* // 监听方式3:一次性监听
|
|
46
|
+
* useEventOnce(PaymentSuccessEvent, (event) => {
|
|
47
|
+
* console.log('只触发一次')
|
|
48
|
+
* })
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
post() {
|
|
52
|
+
return eventBus.emit(this);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 事件总线
|
|
57
|
+
* 基于 BroadcastChannel 实现跨浏览器 Tab 通信
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* // 发送事件
|
|
62
|
+
* eventBus.emit(new PaymentSuccessEvent('order-123', 99.99))
|
|
63
|
+
*
|
|
64
|
+
* // 订阅事件
|
|
65
|
+
* eventBus.on(PaymentSuccessEvent, (event) => {
|
|
66
|
+
* console.log(event.orderId)
|
|
67
|
+
* })
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
class EventBus {
|
|
71
|
+
constructor(name) {
|
|
72
|
+
this.channel = null;
|
|
73
|
+
this.handlers = new Map();
|
|
74
|
+
this.eventRegistry = new Map();
|
|
75
|
+
this.isInitialized = false;
|
|
76
|
+
this.channelName = name;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 获取单例实例
|
|
80
|
+
* @param name 频道名称,默认 'nexus-app'
|
|
81
|
+
*/
|
|
82
|
+
static getInstance(name = 'nexus-app') {
|
|
83
|
+
if (!EventBus.instance) {
|
|
84
|
+
EventBus.instance = new EventBus(name);
|
|
85
|
+
}
|
|
86
|
+
return EventBus.instance;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 初始化频道(延迟初始化,仅在浏览器环境)
|
|
90
|
+
*/
|
|
91
|
+
ensureInitialized() {
|
|
92
|
+
if (this.isInitialized)
|
|
93
|
+
return;
|
|
94
|
+
// 仅在浏览器环境初始化
|
|
95
|
+
if (typeof window === 'undefined')
|
|
96
|
+
return;
|
|
97
|
+
this.channel = new BroadcastChannel(this.channelName);
|
|
98
|
+
this.channel.onmessage = (msg) => {
|
|
99
|
+
this.dispatch(msg.type, msg.data);
|
|
100
|
+
};
|
|
101
|
+
this.isInitialized = true;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 分发事件到对应的处理器
|
|
105
|
+
*/
|
|
106
|
+
dispatch(type, data) {
|
|
107
|
+
const EventClass = this.eventRegistry.get(type);
|
|
108
|
+
if (!EventClass)
|
|
109
|
+
return;
|
|
110
|
+
const handlers = this.handlers.get(type);
|
|
111
|
+
if (!handlers || handlers.size === 0)
|
|
112
|
+
return;
|
|
113
|
+
// 还原事件对象
|
|
114
|
+
const event = Object.assign(Object.create(EventClass.prototype), data);
|
|
115
|
+
handlers.forEach(handler => {
|
|
116
|
+
try {
|
|
117
|
+
handler(event);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
console.error(`[EventBus] Error in handler for ${type}:`, error);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 发送事件
|
|
126
|
+
* @param event 事件实例
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* eventBus.emit(new PaymentSuccessEvent('order-123', 99.99))
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
emit(event) {
|
|
134
|
+
this.ensureInitialized();
|
|
135
|
+
if (!this.channel) {
|
|
136
|
+
console.warn('[EventBus] Channel not available (SSR environment)');
|
|
137
|
+
return Promise.resolve();
|
|
138
|
+
}
|
|
139
|
+
const EventClass = event.constructor;
|
|
140
|
+
const type = EventClass.getType();
|
|
141
|
+
// 序列化事件数据(排除原型方法)
|
|
142
|
+
const data = Object.keys(event).reduce((acc, key) => {
|
|
143
|
+
acc[key] = event[key];
|
|
144
|
+
return acc;
|
|
145
|
+
}, {});
|
|
146
|
+
return this.channel.postMessage({ type, data });
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* 订阅事件
|
|
150
|
+
* @param EventClass 事件类
|
|
151
|
+
* @param handler 事件处理器
|
|
152
|
+
* @returns 取消订阅函数
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* // 订阅
|
|
157
|
+
* const unsubscribe = eventBus.on(PaymentSuccessEvent, (event) => {
|
|
158
|
+
* console.log(event.orderId)
|
|
159
|
+
* })
|
|
160
|
+
*
|
|
161
|
+
* // 取消订阅
|
|
162
|
+
* unsubscribe()
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
on(EventClass, handler) {
|
|
166
|
+
this.ensureInitialized();
|
|
167
|
+
const type = EventClass.getType();
|
|
168
|
+
// 注册事件类
|
|
169
|
+
if (!this.eventRegistry.has(type)) {
|
|
170
|
+
this.eventRegistry.set(type, EventClass);
|
|
171
|
+
}
|
|
172
|
+
// 添加处理器
|
|
173
|
+
if (!this.handlers.has(type)) {
|
|
174
|
+
this.handlers.set(type, new Set());
|
|
175
|
+
}
|
|
176
|
+
this.handlers.get(type).add(handler);
|
|
177
|
+
// 返回取消订阅函数
|
|
178
|
+
return () => this.off(EventClass, handler);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* 取消订阅事件
|
|
182
|
+
* @param EventClass 事件类
|
|
183
|
+
* @param handler 事件处理器
|
|
184
|
+
*/
|
|
185
|
+
off(EventClass, handler) {
|
|
186
|
+
const type = EventClass.getType();
|
|
187
|
+
const handlers = this.handlers.get(type);
|
|
188
|
+
if (handlers) {
|
|
189
|
+
handlers.delete(handler);
|
|
190
|
+
// 清理空 Set 避免内存泄漏
|
|
191
|
+
if (handlers.size === 0) {
|
|
192
|
+
this.handlers.delete(type);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 订阅一次性事件(触发后自动取消订阅)
|
|
198
|
+
* @param EventClass 事件类
|
|
199
|
+
* @param handler 事件处理器
|
|
200
|
+
* @returns 取消订阅函数
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```ts
|
|
204
|
+
* eventBus.once(PaymentSuccessEvent, (event) => {
|
|
205
|
+
* console.log('只触发一次:', event.orderId)
|
|
206
|
+
* })
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
once(EventClass, handler) {
|
|
210
|
+
const wrapper = (event) => {
|
|
211
|
+
this.off(EventClass, wrapper);
|
|
212
|
+
handler(event);
|
|
213
|
+
};
|
|
214
|
+
return this.on(EventClass, wrapper);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* 检查是否有订阅者
|
|
218
|
+
* @param EventClass 事件类
|
|
219
|
+
*/
|
|
220
|
+
hasSubscribers(EventClass) {
|
|
221
|
+
const type = EventClass.getType();
|
|
222
|
+
const handlers = this.handlers.get(type);
|
|
223
|
+
return !!handlers && handlers.size > 0;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* 获取订阅者数量
|
|
227
|
+
* @param EventClass 事件类
|
|
228
|
+
*/
|
|
229
|
+
subscriberCount(EventClass) {
|
|
230
|
+
var _a, _b;
|
|
231
|
+
const type = EventClass.getType();
|
|
232
|
+
return (_b = (_a = this.handlers.get(type)) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 清除指定事件的所有订阅
|
|
236
|
+
* @param EventClass 事件类
|
|
237
|
+
*/
|
|
238
|
+
clear(EventClass) {
|
|
239
|
+
const type = EventClass.getType();
|
|
240
|
+
this.handlers.delete(type);
|
|
241
|
+
this.eventRegistry.delete(type);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 清除所有订阅
|
|
245
|
+
*/
|
|
246
|
+
clearAll() {
|
|
247
|
+
this.handlers.clear();
|
|
248
|
+
this.eventRegistry.clear();
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* 关闭频道并释放资源
|
|
252
|
+
*/
|
|
253
|
+
async destroy() {
|
|
254
|
+
this.clearAll();
|
|
255
|
+
if (this.channel) {
|
|
256
|
+
await this.channel.close();
|
|
257
|
+
this.channel = null;
|
|
258
|
+
}
|
|
259
|
+
this.isInitialized = false;
|
|
260
|
+
EventBus.instance = null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
EventBus.instance = null;
|
|
264
|
+
/**
|
|
265
|
+
* 事件总线单例
|
|
266
|
+
*/
|
|
267
|
+
export const eventBus = EventBus.getInstance();
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { BaseEvent } from './index';
|
|
2
|
+
/**
|
|
3
|
+
* 支付成功事件
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* // 发送
|
|
8
|
+
* new PaymentSuccessEvent('order-123', 99.99).post()
|
|
9
|
+
*
|
|
10
|
+
* // 监听
|
|
11
|
+
* useEvent(PaymentSuccessEvent, (e) => console.log(e.orderId, e.amount))
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare class PaymentSuccessEvent extends BaseEvent {
|
|
15
|
+
orderId: string;
|
|
16
|
+
amount: number;
|
|
17
|
+
static readonly type = "PaymentSuccessEvent";
|
|
18
|
+
constructor(orderId: string, amount: number);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 用户登录事件
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* // 发送
|
|
26
|
+
* new LoginEvent('user-123', 'john@example.com').post()
|
|
27
|
+
*
|
|
28
|
+
* // 监听
|
|
29
|
+
* useEvent(LoginEvent, (e) => console.log(e.userId, e.email))
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare class LoginEvent extends BaseEvent {
|
|
33
|
+
userId: string;
|
|
34
|
+
email?: string | undefined;
|
|
35
|
+
static readonly type = "LoginEvent";
|
|
36
|
+
constructor(userId: string, email?: string | undefined);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 用户登出事件
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* // 发送
|
|
44
|
+
* new LogoutEvent().post()
|
|
45
|
+
*
|
|
46
|
+
* // 监听
|
|
47
|
+
* useEvent(LogoutEvent, () => console.log('用户已登出'))
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare class LogoutEvent extends BaseEvent {
|
|
51
|
+
static readonly type = "LogoutEvent";
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 用户积分变更事件
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* // 发送
|
|
59
|
+
* new CreditsChangedEvent(100, 200).post()
|
|
60
|
+
*
|
|
61
|
+
* // 监听
|
|
62
|
+
* useEvent(CreditsChangedEvent, (e) => console.log(e.previousCredits, e.currentCredits))
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare class CreditsChangedEvent extends BaseEvent {
|
|
66
|
+
previousCredits: number;
|
|
67
|
+
currentCredits: number;
|
|
68
|
+
static readonly type = "CreditsChangedEvent";
|
|
69
|
+
constructor(previousCredits: number, currentCredits: number);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=EventDemo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventDemo.d.ts","sourceRoot":"","sources":["../../src/event-bus/EventDemo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAEnC;;;;;;;;;;;GAWG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;IAIvC,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,MAAM;IAJvB,MAAM,CAAC,QAAQ,CAAC,IAAI,yBAAwB;gBAGnC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;CAIxB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,UAAW,SAAQ,SAAS;IAI9B,MAAM,EAAE,MAAM;IACd,KAAK,CAAC,EAAE,MAAM;IAJvB,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAe;gBAG1B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,YAAA;CAIxB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,WAAY,SAAQ,SAAS;IACxC,MAAM,CAAC,QAAQ,CAAC,IAAI,iBAAgB;CACrC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;IAIvC,eAAe,EAAE,MAAM;IACvB,cAAc,EAAE,MAAM;IAJ/B,MAAM,CAAC,QAAQ,CAAC,IAAI,yBAAwB;gBAGnC,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,MAAM;CAIhC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { BaseEvent } from './index';
|
|
2
|
+
/**
|
|
3
|
+
* 支付成功事件
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* // 发送
|
|
8
|
+
* new PaymentSuccessEvent('order-123', 99.99).post()
|
|
9
|
+
*
|
|
10
|
+
* // 监听
|
|
11
|
+
* useEvent(PaymentSuccessEvent, (e) => console.log(e.orderId, e.amount))
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export class PaymentSuccessEvent extends BaseEvent {
|
|
15
|
+
constructor(orderId, amount) {
|
|
16
|
+
super();
|
|
17
|
+
this.orderId = orderId;
|
|
18
|
+
this.amount = amount;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
PaymentSuccessEvent.type = 'PaymentSuccessEvent';
|
|
22
|
+
/**
|
|
23
|
+
* 用户登录事件
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* // 发送
|
|
28
|
+
* new LoginEvent('user-123', 'john@example.com').post()
|
|
29
|
+
*
|
|
30
|
+
* // 监听
|
|
31
|
+
* useEvent(LoginEvent, (e) => console.log(e.userId, e.email))
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export class LoginEvent extends BaseEvent {
|
|
35
|
+
constructor(userId, email) {
|
|
36
|
+
super();
|
|
37
|
+
this.userId = userId;
|
|
38
|
+
this.email = email;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
LoginEvent.type = 'LoginEvent';
|
|
42
|
+
/**
|
|
43
|
+
* 用户登出事件
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* // 发送
|
|
48
|
+
* new LogoutEvent().post()
|
|
49
|
+
*
|
|
50
|
+
* // 监听
|
|
51
|
+
* useEvent(LogoutEvent, () => console.log('用户已登出'))
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export class LogoutEvent extends BaseEvent {
|
|
55
|
+
}
|
|
56
|
+
LogoutEvent.type = 'LogoutEvent';
|
|
57
|
+
/**
|
|
58
|
+
* 用户积分变更事件
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* // 发送
|
|
63
|
+
* new CreditsChangedEvent(100, 200).post()
|
|
64
|
+
*
|
|
65
|
+
* // 监听
|
|
66
|
+
* useEvent(CreditsChangedEvent, (e) => console.log(e.previousCredits, e.currentCredits))
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export class CreditsChangedEvent extends BaseEvent {
|
|
70
|
+
constructor(previousCredits, currentCredits) {
|
|
71
|
+
super();
|
|
72
|
+
this.previousCredits = previousCredits;
|
|
73
|
+
this.currentCredits = currentCredits;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
CreditsChangedEvent.type = 'CreditsChangedEvent';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BaseEvent } from './index';
|
|
2
|
+
type Constructor<T = any> = new (...args: any[]) => T;
|
|
3
|
+
/**
|
|
4
|
+
* 订阅事件的 React Hook
|
|
5
|
+
* 自动在组件卸载时取消订阅
|
|
6
|
+
*
|
|
7
|
+
* handler 会自动获取最新闭包值,无需手动管理依赖
|
|
8
|
+
*
|
|
9
|
+
* @param EventClass 事件类
|
|
10
|
+
* @param handler 事件处理器
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* function PaymentListener() {
|
|
15
|
+
* const [count, setCount] = useState(0)
|
|
16
|
+
*
|
|
17
|
+
* useEvent(PaymentSuccessEvent, (event) => {
|
|
18
|
+
* // 可以安全访问最新的 count 值
|
|
19
|
+
* console.log('当前计数:', count)
|
|
20
|
+
* console.log('收到支付成功事件:', event.orderId)
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* return <div>Listening...</div>
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function useEvent<T extends BaseEvent>(EventClass: Constructor<T>, handler: (event: T) => void): void;
|
|
28
|
+
/**
|
|
29
|
+
* 订阅一次性事件的 React Hook
|
|
30
|
+
* 事件触发一次后自动取消订阅
|
|
31
|
+
*
|
|
32
|
+
* @param EventClass 事件类
|
|
33
|
+
* @param handler 事件处理器
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* function OneTimeListener() {
|
|
38
|
+
* useEventOnce(PaymentSuccessEvent, (event) => {
|
|
39
|
+
* console.log('只触发一次:', event.orderId)
|
|
40
|
+
* })
|
|
41
|
+
*
|
|
42
|
+
* return <div>Waiting for one event...</div>
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function useEventOnce<T extends BaseEvent>(EventClass: Constructor<T>, handler: (event: T) => void): void;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=EventHooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventHooks.d.ts","sourceRoot":"","sources":["../../src/event-bus/EventHooks.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,SAAS,EAAE,MAAM,SAAS,CAAA;AAE7C,KAAK,WAAW,CAAC,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;AAErD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,SAAS,EAC1C,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAC1B,IAAI,CAaN;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,EAC9C,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAC1B,IAAI,CAoBN"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useEffect, useCallback, useRef } from 'react';
|
|
2
|
+
import { eventBus } from './index';
|
|
3
|
+
/**
|
|
4
|
+
* 订阅事件的 React Hook
|
|
5
|
+
* 自动在组件卸载时取消订阅
|
|
6
|
+
*
|
|
7
|
+
* handler 会自动获取最新闭包值,无需手动管理依赖
|
|
8
|
+
*
|
|
9
|
+
* @param EventClass 事件类
|
|
10
|
+
* @param handler 事件处理器
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* function PaymentListener() {
|
|
15
|
+
* const [count, setCount] = useState(0)
|
|
16
|
+
*
|
|
17
|
+
* useEvent(PaymentSuccessEvent, (event) => {
|
|
18
|
+
* // 可以安全访问最新的 count 值
|
|
19
|
+
* console.log('当前计数:', count)
|
|
20
|
+
* console.log('收到支付成功事件:', event.orderId)
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* return <div>Listening...</div>
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function useEvent(EventClass, handler) {
|
|
28
|
+
// 使用 ref 保存最新的 handler,避免频繁订阅/取消订阅
|
|
29
|
+
const handlerRef = useRef(handler);
|
|
30
|
+
handlerRef.current = handler;
|
|
31
|
+
// 稳定的回调函数,始终调用最新的 handler
|
|
32
|
+
const stableHandler = useCallback((event) => {
|
|
33
|
+
handlerRef.current(event);
|
|
34
|
+
}, []);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
return eventBus.on(EventClass, stableHandler);
|
|
37
|
+
}, [EventClass, stableHandler]);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 订阅一次性事件的 React Hook
|
|
41
|
+
* 事件触发一次后自动取消订阅
|
|
42
|
+
*
|
|
43
|
+
* @param EventClass 事件类
|
|
44
|
+
* @param handler 事件处理器
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* function OneTimeListener() {
|
|
49
|
+
* useEventOnce(PaymentSuccessEvent, (event) => {
|
|
50
|
+
* console.log('只触发一次:', event.orderId)
|
|
51
|
+
* })
|
|
52
|
+
*
|
|
53
|
+
* return <div>Waiting for one event...</div>
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function useEventOnce(EventClass, handler) {
|
|
58
|
+
// 使用 ref 保存最新的 handler
|
|
59
|
+
const handlerRef = useRef(handler);
|
|
60
|
+
handlerRef.current = handler;
|
|
61
|
+
// 追踪是否已触发,避免组件卸载后执行
|
|
62
|
+
const firedRef = useRef(false);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
firedRef.current = false;
|
|
65
|
+
const stableHandler = (event) => {
|
|
66
|
+
if (!firedRef.current) {
|
|
67
|
+
firedRef.current = true;
|
|
68
|
+
handlerRef.current(event);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
return eventBus.once(EventClass, stableHandler);
|
|
72
|
+
}, [EventClass]);
|
|
73
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/event-bus/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAG5B,wBAAgB,OAAO,SAEtB"}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xxf_react",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"./layout": {
|
|
50
50
|
"types": "./dist/layout/index.d.ts",
|
|
51
51
|
"import": "./dist/layout/index.js"
|
|
52
|
+
},
|
|
53
|
+
"./event-bus": {
|
|
54
|
+
"types": "./dist/event-bus/index.d.ts",
|
|
55
|
+
"import": "./dist/event-bus/index.js"
|
|
52
56
|
}
|
|
53
57
|
},
|
|
54
58
|
"files": [
|
|
@@ -64,8 +68,8 @@
|
|
|
64
68
|
"@microsoft/fetch-event-source": "^2.0.1",
|
|
65
69
|
"@use-gesture/react": "^10.3.1",
|
|
66
70
|
"bowser": "^2.14.1",
|
|
71
|
+
"broadcast-channel": "^7.3.0",
|
|
67
72
|
"dayjs": "^1.11.19",
|
|
68
|
-
"mitt": "^3.0.1",
|
|
69
73
|
"react-async-hook": "^4.0.0",
|
|
70
74
|
"react-resize-detector": "^12.3.0",
|
|
71
75
|
"react-responsive": "^10.0.1",
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { ReactNode, CSSProperties, ElementType, ComponentPropsWithoutRef } from 'react';
|
|
2
|
-
import React from "react";
|
|
3
|
-
export interface ContainerSize {
|
|
4
|
-
width: number;
|
|
5
|
-
height: number;
|
|
6
|
-
}
|
|
7
|
-
interface SizedContainerProps<T extends ElementType = 'div'> {
|
|
8
|
-
/** 子元素渲染函数,接收容器尺寸和就绪状态 */
|
|
9
|
-
children: (size: ContainerSize & {
|
|
10
|
-
isReady: boolean;
|
|
11
|
-
}) => ReactNode;
|
|
12
|
-
/** 容器的 className */
|
|
13
|
-
className?: string;
|
|
14
|
-
/** 容器的 style */
|
|
15
|
-
style?: CSSProperties;
|
|
16
|
-
/** 自定义容器元素类型,默认 div */
|
|
17
|
-
as?: T;
|
|
18
|
-
/** 是否只监听宽度变化 */
|
|
19
|
-
widthOnly?: boolean;
|
|
20
|
-
/** 是否只监听高度变化 */
|
|
21
|
-
heightOnly?: boolean;
|
|
22
|
-
/** 防抖延迟(毫秒) */
|
|
23
|
-
debounce?: number;
|
|
24
|
-
/** 是否跳过首次挂载时的计算 */
|
|
25
|
-
skipOnMount?: boolean;
|
|
26
|
-
/** 尺寸未就绪时显示的占位内容 */
|
|
27
|
-
fallback?: ReactNode;
|
|
28
|
-
/** 尺寸变化时的回调 */
|
|
29
|
-
onResize?: (size: ContainerSize) => void;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 自动测量尺寸的容器组件
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* // 基础用法
|
|
36
|
-
* <SizedContainer className="h-full w-full">
|
|
37
|
-
* {({ width, height, isReady }) => (
|
|
38
|
-
* <VirtuosoGrid style={{ width, height }} ... />
|
|
39
|
-
* )}
|
|
40
|
-
* </SizedContainer>
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* // 只监听高度,带防抖和占位符
|
|
44
|
-
* <SizedContainer
|
|
45
|
-
* heightOnly
|
|
46
|
-
* debounce={100}
|
|
47
|
-
* fallback={<Skeleton />}
|
|
48
|
-
* >
|
|
49
|
-
* {({ height }) => <List style={{ height }} />}
|
|
50
|
-
* </SizedContainer>
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* // 自定义元素类型
|
|
54
|
-
* <SizedContainer as="section" className="h-full">
|
|
55
|
-
* {({ width, height }) => <Chart width={width} height={height} />}
|
|
56
|
-
* </SizedContainer>
|
|
57
|
-
*/
|
|
58
|
-
export declare function SizedContainer<T extends ElementType = 'div'>({ children, className, style, as, widthOnly, heightOnly, debounce, skipOnMount, fallback, onResize, }: SizedContainerProps<T> & Omit<ComponentPropsWithoutRef<T>, keyof SizedContainerProps<T>>): React.JSX.Element;
|
|
59
|
-
export {};
|
|
60
|
-
//# sourceMappingURL=SizedContainer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SizedContainer.d.ts","sourceRoot":"","sources":["../../src/utils/SizedContainer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,OAAO,CAAC;AACxF,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,mBAAmB,CAAC,CAAC,SAAS,WAAW,GAAG,KAAK;IACvD,0BAA0B;IAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,KAAK,SAAS,CAAC;IACpE,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB;IAChB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,uBAAuB;IACvB,EAAE,CAAC,EAAE,CAAC,CAAC;IACP,gBAAgB;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,eAAe;IACf,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CAC5C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,WAAW,GAAG,KAAK,EAAE,EACI,QAAQ,EACR,SAAS,EACT,KAAK,EACL,EAAE,EACF,SAAiB,EACjB,UAAkB,EAClB,QAAQ,EACR,WAAmB,EACnB,QAAQ,EACR,QAAQ,GACX,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,MAAM,mBAAmB,CAAC,CAAC,CAAC,CAAC,qBAmCxJ"}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { useResizeDetector } from 'react-resize-detector';
|
|
3
|
-
import React from "react";
|
|
4
|
-
/**
|
|
5
|
-
* 自动测量尺寸的容器组件
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* // 基础用法
|
|
9
|
-
* <SizedContainer className="h-full w-full">
|
|
10
|
-
* {({ width, height, isReady }) => (
|
|
11
|
-
* <VirtuosoGrid style={{ width, height }} ... />
|
|
12
|
-
* )}
|
|
13
|
-
* </SizedContainer>
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* // 只监听高度,带防抖和占位符
|
|
17
|
-
* <SizedContainer
|
|
18
|
-
* heightOnly
|
|
19
|
-
* debounce={100}
|
|
20
|
-
* fallback={<Skeleton />}
|
|
21
|
-
* >
|
|
22
|
-
* {({ height }) => <List style={{ height }} />}
|
|
23
|
-
* </SizedContainer>
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* // 自定义元素类型
|
|
27
|
-
* <SizedContainer as="section" className="h-full">
|
|
28
|
-
* {({ width, height }) => <Chart width={width} height={height} />}
|
|
29
|
-
* </SizedContainer>
|
|
30
|
-
*/
|
|
31
|
-
export function SizedContainer({ children, className, style, as, widthOnly = false, heightOnly = false, debounce, skipOnMount = false, fallback, onResize, }) {
|
|
32
|
-
const { width, height, ref } = useResizeDetector({
|
|
33
|
-
handleWidth: !heightOnly,
|
|
34
|
-
handleHeight: !widthOnly,
|
|
35
|
-
refreshMode: debounce ? 'debounce' : undefined,
|
|
36
|
-
refreshRate: debounce,
|
|
37
|
-
skipOnMount,
|
|
38
|
-
onResize: onResize
|
|
39
|
-
? ({ width: w, height: h }) => {
|
|
40
|
-
if (w !== null && h !== null) {
|
|
41
|
-
onResize({ width: w, height: h });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
: undefined,
|
|
45
|
-
});
|
|
46
|
-
const size = {
|
|
47
|
-
width: width !== null && width !== void 0 ? width : 0,
|
|
48
|
-
height: height !== null && height !== void 0 ? height : 0,
|
|
49
|
-
};
|
|
50
|
-
// 根据监听模式判断是否就绪
|
|
51
|
-
const isReady = (() => {
|
|
52
|
-
if (widthOnly)
|
|
53
|
-
return size.width > 0;
|
|
54
|
-
if (heightOnly)
|
|
55
|
-
return size.height > 0;
|
|
56
|
-
return size.width > 0 && size.height > 0;
|
|
57
|
-
})();
|
|
58
|
-
const Component = as || 'div';
|
|
59
|
-
return (React.createElement(Component, { ref: ref, className: className, style: style }, isReady ? children({ ...size, isReady }) : fallback));
|
|
60
|
-
}
|