react-solidlike 2.3.0 → 2.5.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.
package/README.zh.md ADDED
@@ -0,0 +1,456 @@
1
+ # react-solidlike
2
+
3
+ [English](./README.md) | 中文
4
+
5
+ 声明式 React 控制流组件库,灵感来源于 Solid.js。用于替代 JSX 中的三元表达式和 `array.map()`,让你的组件代码更加清晰易读。支持 React 和 React Native。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm install react-solidlike
11
+ # 或
12
+ bun add react-solidlike
13
+ ```
14
+
15
+ ## 组件
16
+
17
+ ### `<Show>` - 条件渲染
18
+
19
+ 替代三元表达式进行条件渲染。
20
+
21
+ ```tsx
22
+ import { Show } from "react-solidlike";
23
+
24
+ // 基础用法
25
+ <Show when={isLoggedIn}>
26
+ <UserProfile />
27
+ </Show>
28
+
29
+ // 带 fallback
30
+ <Show when={isLoggedIn} fallback={<LoginButton />}>
31
+ <UserProfile />
32
+ </Show>
33
+
34
+ // 使用 render props 获取类型安全的值
35
+ <Show when={user}>
36
+ {(user) => <UserProfile name={user.name} />}
37
+ </Show>
38
+
39
+ // 带 onFallback 回调(用于重定向等副作用)
40
+ <Show when={isAuthenticated} fallback={<Loading />} onFallback={() => navigate('/login')}>
41
+ <Dashboard />
42
+ </Show>
43
+ ```
44
+
45
+ ### `<For>` - 列表渲染
46
+
47
+ 替代 `array.map()` 进行列表渲染。
48
+
49
+ ```tsx
50
+ import { For } from "react-solidlike";
51
+
52
+ // 基础用法
53
+ <For each={items}>
54
+ {(item) => <ListItem {...item} />}
55
+ </For>
56
+
57
+ // 带 keyExtractor
58
+ <For each={users} keyExtractor={(user) => user.id}>
59
+ {(user) => <UserCard user={user} />}
60
+ </For>
61
+
62
+ // 带 fallback 处理空数组
63
+ <For each={items} fallback={<EmptyState />}>
64
+ {(item, index) => <ListItem item={item} index={index} />}
65
+ </For>
66
+
67
+ // 使用 wrapper 包装元素
68
+ <For each={items} wrapper={<ul className="list" />}>
69
+ {(item) => <li>{item.name}</li>}
70
+ </For>
71
+
72
+ // 倒序渲染
73
+ <For each={messages} reverse>
74
+ {(msg) => <Message {...msg} />}
75
+ </For>
76
+
77
+ // 使用 array 参数获取上下文信息
78
+ <For each={steps}>
79
+ {(step, index, array) => (
80
+ <Step
81
+ data={step}
82
+ isFirst={index === 0}
83
+ isLast={index === array.length - 1}
84
+ />
85
+ )}
86
+ </For>
87
+ ```
88
+
89
+ ### `<Switch>` / `<Match>` / `<Default>` - 多分支渲染
90
+
91
+ 替代多个 `if-else` 或 `switch` 语句。
92
+
93
+ ```tsx
94
+ import { Switch, Match, Default } from "react-solidlike";
95
+
96
+ <Switch>
97
+ <Match when={status === "loading"}>
98
+ <LoadingSpinner />
99
+ </Match>
100
+ <Match when={status === "error"}>
101
+ <ErrorMessage />
102
+ </Match>
103
+ <Match when={status === "success"}>
104
+ <SuccessContent />
105
+ </Match>
106
+ <Default>
107
+ <IdleState />
108
+ </Default>
109
+ </Switch>
110
+ ```
111
+
112
+ ### `<Await>` - 异步等待
113
+
114
+ 等待 Promise resolve 后渲染内容。
115
+
116
+ ```tsx
117
+ import { Await } from "react-solidlike";
118
+
119
+ // 基础用法
120
+ <Await promise={fetchUser()} loading={<Spinner />}>
121
+ {(user) => <UserProfile user={user} />}
122
+ </Await>
123
+
124
+ // 带错误处理
125
+ <Await
126
+ promise={fetchData()}
127
+ loading={<Loading />}
128
+ error={(err) => <ErrorMessage message={err.message} />}
129
+ >
130
+ {(data) => <DataView data={data} />}
131
+ </Await>
132
+
133
+ // 支持非 Promise 值(用于缓存场景)
134
+ <Await promise={cache ?? fetchData()} loading={<Spinner />}>
135
+ {(data) => <DataView data={data} />}
136
+ </Await>
137
+ ```
138
+
139
+ ### `<Repeat>` - 重复渲染
140
+
141
+ 替代 `Array.from({ length: n }).map()`。
142
+
143
+ ```tsx
144
+ import { Repeat } from "react-solidlike";
145
+
146
+ // 渲染星级评分
147
+ <Repeat times={5}>
148
+ {(i) => <Star key={i} filled={i < rating} />}
149
+ </Repeat>
150
+
151
+ // 生成骨架屏占位
152
+ <Repeat times={3}>
153
+ {(i) => <SkeletonCard key={i} />}
154
+ </Repeat>
155
+
156
+ // 使用 wrapper 包装元素
157
+ <Repeat times={5} wrapper={<div className="stars" />}>
158
+ {(i) => <Star key={i} />}
159
+ </Repeat>
160
+
161
+ // 倒序渲染
162
+ <Repeat times={5} reverse>
163
+ {(i) => <div key={i}>倒序 {i}</div>}
164
+ </Repeat>
165
+
166
+ // 使用 length 参数显示进度
167
+ <Repeat times={totalSteps}>
168
+ {(i, length) => (
169
+ <Step key={i} current={i + 1} total={length} />
170
+ )}
171
+ </Repeat>
172
+ ```
173
+
174
+ ### `<Split>` - 字符串切割渲染
175
+
176
+ 按分隔符切割字符串并渲染每个部分。
177
+
178
+ ```tsx
179
+ import { Split } from "react-solidlike";
180
+
181
+ // 基础用法 - 切割后不保留分隔符
182
+ <Split string="a,b,c" separator=",">
183
+ {(part) => <span>{part}</span>}
184
+ </Split>
185
+ // 渲染: ["a", "b", "c"]
186
+
187
+ // 保留分隔符
188
+ <Split string="9+5=(9+1)+4" separator="=" keepSeparator>
189
+ {(part) => <span>{part}</span>}
190
+ </Split>
191
+ // 渲染: ["9+5", "=", "(9+1)+4"]
192
+
193
+ // 使用正则表达式分隔符
194
+ <Split string="a1b2c3" separator={/\d/} keepSeparator>
195
+ {(part) => <span>{part}</span>}
196
+ </Split>
197
+ // 渲染: ["a", "1", "b", "2", "c", "3"]
198
+
199
+ // 带 wrapper 包装元素
200
+ <Split string="hello world" separator=" " wrapper={<div className="words" />}>
201
+ {(word) => <span>{word}</span>}
202
+ </Split>
203
+
204
+ // 带 fallback 处理空字符串
205
+ <Split string={text} separator="," fallback={<EmptyState />}>
206
+ {(part) => <Tag>{part}</Tag>}
207
+ </Split>
208
+
209
+ // 倒序渲染
210
+ <Split string="a,b,c" separator="," reverse>
211
+ {(part) => <span>{part}</span>}
212
+ </Split>
213
+ // 渲染顺序: ["c", "b", "a"]
214
+ ```
215
+
216
+ ### `<Dynamic>` - 动态组件
217
+
218
+ 根据条件动态选择要渲染的组件类型。
219
+
220
+ ```tsx
221
+ import { Dynamic } from "react-solidlike";
222
+
223
+ // 动态选择按钮或链接
224
+ <Dynamic
225
+ component={href ? 'a' : 'button'}
226
+ href={href}
227
+ onClick={onClick}
228
+ >
229
+ {label}
230
+ </Dynamic>
231
+
232
+ // 配合自定义组件
233
+ <Dynamic
234
+ component={isAdmin ? AdminPanel : UserPanel}
235
+ user={currentUser}
236
+ />
237
+
238
+ // React Native 中使用
239
+ <Dynamic
240
+ component={isPressable ? Pressable : View}
241
+ onPress={handlePress}
242
+ >
243
+ <Text>Content</Text>
244
+ </Dynamic>
245
+ ```
246
+
247
+ ### `<ErrorBoundary>` - 错误边界
248
+
249
+ 捕获子组件树中的 JavaScript 错误,防止整个应用崩溃。
250
+
251
+ ```tsx
252
+ import { ErrorBoundary } from "react-solidlike";
253
+
254
+ // 基础用法
255
+ <ErrorBoundary fallback={<ErrorPage />}>
256
+ <App />
257
+ </ErrorBoundary>
258
+
259
+ // 使用 render props 获取错误信息和重置函数
260
+ <ErrorBoundary
261
+ fallback={(error, reset) => (
262
+ <div>
263
+ <p>Error: {error.message}</p>
264
+ <button onClick={reset}>Retry</button>
265
+ </div>
266
+ )}
267
+ >
268
+ <App />
269
+ </ErrorBoundary>
270
+
271
+ // resetKey 变化时自动重置
272
+ <ErrorBoundary fallback={<Error />} resetKey={userId}>
273
+ <UserProfile />
274
+ </ErrorBoundary>
275
+ ```
276
+
277
+ ### `<QueryBoundary>` - 查询边界
278
+
279
+ 处理异步查询的各种状态(加载中、错误、空数据、成功)。可与 `@tanstack/react-query`、SWR、RTK Query 等配合使用。
280
+
281
+ ```tsx
282
+ import { QueryBoundary } from "react-solidlike";
283
+ import { useQuery } from "@tanstack/react-query";
284
+
285
+ function UserList() {
286
+ const query = useQuery({ queryKey: ["users"], queryFn: fetchUsers });
287
+
288
+ return (
289
+ <QueryBoundary
290
+ query={query}
291
+ loading={<Spinner />}
292
+ error={<ErrorMessage />}
293
+ empty={<NoData />}
294
+ >
295
+ {(users) => (
296
+ <ul>
297
+ {users.map((user) => (
298
+ <li key={user.id}>{user.name}</li>
299
+ ))}
300
+ </ul>
301
+ )}
302
+ </QueryBoundary>
303
+ );
304
+ }
305
+ ```
306
+
307
+ #### Props
308
+
309
+ | 属性 | 类型 | 描述 |
310
+ | ----------- | ------------------------------------- | ------------ |
311
+ | `query` | `QueryResult<T>` | 查询结果对象 |
312
+ | `loading` | `ReactNode` | 加载中显示 |
313
+ | `error` | `ReactNode` | 错误时显示 |
314
+ | `empty` | `ReactNode` | 空数据显示 |
315
+ | `children` | `ReactNode \| (data: T) => ReactNode` | 成功时渲染 |
316
+ | `isEmptyFn` | `(data: T) => boolean` | 自定义空判断 |
317
+
318
+ ### `<Once>` - 单次渲染
319
+
320
+ 只渲染一次子元素,忽略后续更新。适用于昂贵的计算或不应重新渲染的内容。
321
+
322
+ ```tsx
323
+ import { Once } from "react-solidlike";
324
+
325
+ // 渲染昂贵的组件
326
+ <Once>
327
+ <ExpensiveChart data={data} />
328
+ </Once>
329
+
330
+ // 防止父组件更新导致的重新渲染
331
+ function Parent() {
332
+ const [count, setCount] = useState(0);
333
+ return (
334
+ <div>
335
+ <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
336
+ <Once>
337
+ <Child initialCount={count} />
338
+ </Once>
339
+ </div>
340
+ );
341
+ }
342
+ ```
343
+
344
+ ### `<ClientOnly>` - 仅客户端渲染
345
+
346
+ 仅在客户端(hydration 之后)渲染子元素。适用于依赖浏览器 API 或需要避免 SSR hydration 不匹配的场景。
347
+
348
+ ```tsx
349
+ import { ClientOnly } from "react-solidlike";
350
+
351
+ // 基础用法
352
+ <ClientOnly>
353
+ <BrowserOnlyComponent />
354
+ </ClientOnly>
355
+
356
+ // 带 SSR 备选内容
357
+ <ClientOnly fallback={<Skeleton />}>
358
+ <DynamicChart />
359
+ </ClientOnly>
360
+
361
+ // 使用渲染函数延迟求值(避免访问 window)
362
+ <ClientOnly fallback={<Loading />}>
363
+ {() => <ComponentUsingWindow width={window.innerWidth} />}
364
+ </ClientOnly>
365
+
366
+ // 避免 hydration 不匹配
367
+ <ClientOnly fallback={<span>--:--</span>}>
368
+ <CurrentTime />
369
+ </ClientOnly>
370
+ ```
371
+
372
+ ### `<Timeout>` - 超时渲染
373
+
374
+ 在指定延迟后显示或隐藏内容。适用于自动消失的通知、延迟加载的场景。
375
+
376
+ ```tsx
377
+ import { Timeout } from "react-solidlike";
378
+
379
+ // 延迟后显示(mode="after",默认)
380
+ <Timeout ms={1000} mode="after" fallback={<Spinner />}>
381
+ <DelayedContent />
382
+ </Timeout>
383
+
384
+ // 延迟后隐藏(mode="before")
385
+ <Timeout ms={3000} mode="before">
386
+ <Toast message="操作成功!" />
387
+ </Timeout>
388
+
389
+ // 自动消失的提示
390
+ <Timeout ms={5000} mode="before" onTimeout={() => console.log("已消失")}>
391
+ <Notification type="success">保存成功</Notification>
392
+ </Timeout>
393
+
394
+ // 带加载状态的延迟渲染
395
+ <Timeout ms={2000} mode="after" fallback={<Skeleton />}>
396
+ <ExpensiveComponent />
397
+ </Timeout>
398
+ ```
399
+
400
+ #### Props
401
+
402
+ | 属性 | 类型 | 描述 |
403
+ | ----------- | --------------------- | --------------------------------------------------------------- |
404
+ | `ms` | `number` | 延迟时间(毫秒) |
405
+ | `mode` | `'after' \| 'before'` | `'after'` = 延迟后显示,`'before'` = 延迟后隐藏,默认 `'after'` |
406
+ | `children` | `ReactNode` | 要渲染的内容 |
407
+ | `fallback` | `ReactNode` | 等待时显示的内容(仅 `after` 模式) |
408
+ | `onTimeout` | `() => void` | 超时发生时的回调 |
409
+
410
+ ### `<Visible>` - 可见性渲染(仅 Web)
411
+
412
+ 基于 IntersectionObserver 的可见性渲染,进入视口才渲���。在 React Native 或不支持的环境中会直接渲染 children(优雅降级)。
413
+
414
+ ```tsx
415
+ import { Visible } from "react-solidlike";
416
+
417
+ // 基础用法 - 进入视口时渲染
418
+ <Visible>
419
+ <HeavyComponent />
420
+ </Visible>
421
+
422
+ // 带占位符
423
+ <Visible fallback={<Skeleton />}>
424
+ <Image src={url} />
425
+ </Visible>
426
+
427
+ // 提前预加载(rootMargin)
428
+ <Visible rootMargin="200px" fallback={<Placeholder />}>
429
+ <LazyImage />
430
+ </Visible>
431
+
432
+ // 切换可见性(once=false 时离开视口会卸载)
433
+ <Visible once={false} onVisibilityChange={(v) => console.log(v)}>
434
+ <VideoPlayer />
435
+ </Visible>
436
+ ```
437
+
438
+ ## 开发
439
+
440
+ ```bash
441
+ # 安装依赖
442
+ bun install
443
+
444
+ # 运行测试
445
+ bun test
446
+
447
+ # 代码检查
448
+ bun run lint
449
+
450
+ # 构建
451
+ bun run build
452
+ ```
453
+
454
+ ## License
455
+
456
+ MIT
@@ -0,0 +1,43 @@
1
+ import { type ReactNode } from "react";
2
+ export interface ClientOnlyProps {
3
+ /** Content to render only on client side | 仅在客户端渲染的内容 */
4
+ children: ReactNode | (() => ReactNode);
5
+ /** Fallback content during SSR | SSR 期间渲染的备选内容 */
6
+ fallback?: ReactNode;
7
+ }
8
+ /**
9
+ * Component that renders children only on the client side (after hydration)
10
+ *
11
+ * 仅在客户端(hydration 之后)渲染子元素的组件
12
+ *
13
+ * Useful for components that rely on browser APIs, window object,
14
+ * or need to avoid SSR hydration mismatches.
15
+ *
16
+ * 适用于依赖浏览器 API、window 对象的组件,
17
+ * 或需要避免 SSR hydration 不匹配的场景。
18
+ *
19
+ * @example
20
+ * // Basic usage | 基础用法
21
+ * <ClientOnly>
22
+ * <BrowserOnlyComponent />
23
+ * </ClientOnly>
24
+ *
25
+ * @example
26
+ * // With fallback for SSR | 带 SSR 备选内容
27
+ * <ClientOnly fallback={<Skeleton />}>
28
+ * <DynamicChart />
29
+ * </ClientOnly>
30
+ *
31
+ * @example
32
+ * // Using render function for lazy evaluation | 使用渲染函数延迟求值
33
+ * <ClientOnly fallback={<Loading />}>
34
+ * {() => <ComponentUsingWindow width={window.innerWidth} />}
35
+ * </ClientOnly>
36
+ *
37
+ * @example
38
+ * // Avoid hydration mismatch | 避免 hydration 不匹配
39
+ * <ClientOnly fallback={<span>--:--</span>}>
40
+ * <CurrentTime />
41
+ * </ClientOnly>
42
+ */
43
+ export declare function ClientOnly({ children, fallback }: ClientOnlyProps): ReactNode;
package/dist/Once.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { type ReactNode } from "react";
2
+ export interface OnceProps {
3
+ /** Content to render only once | 只渲染一次的内容 */
4
+ children: ReactNode;
5
+ }
6
+ /**
7
+ * Component that renders children only once and ignores subsequent updates
8
+ *
9
+ * 只渲染一次子元素并忽略后续更新的组件
10
+ *
11
+ * Useful for expensive computations or content that should not re-render.
12
+ * The initial render result is cached and returned on subsequent renders.
13
+ *
14
+ * 适用于昂贵的计算或不应重新渲染的内容。
15
+ * 初始渲染结果会被缓存并在后续渲染时返回。
16
+ *
17
+ * @example
18
+ * // Render expensive component only once | 只渲染一次昂贵的组件
19
+ * <Once>
20
+ * <ExpensiveChart data={data} />
21
+ * </Once>
22
+ *
23
+ * @example
24
+ * // Static content that shouldn't update | 不应更新的静态内容
25
+ * <Once>
26
+ * <Header title={initialTitle} />
27
+ * </Once>
28
+ *
29
+ * @example
30
+ * // Prevent re-renders from parent updates | 防止父组件更新导致的重新渲染
31
+ * function Parent() {
32
+ * const [count, setCount] = useState(0);
33
+ * return (
34
+ * <div>
35
+ * <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
36
+ * <Once>
37
+ * <Child initialCount={count} />
38
+ * </Once>
39
+ * </div>
40
+ * );
41
+ * }
42
+ */
43
+ export declare function Once({ children }: OnceProps): ReactNode;
package/dist/Repeat.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { ReactNode } from 'react';
2
- import { type ForProps } from './For';
3
- export interface RepeatProps extends Omit<ForProps<number>, 'each'> {
1
+ import type { ReactNode } from "react";
2
+ import { type ForProps } from "./For";
3
+ export interface RepeatProps extends Omit<ForProps<number>, "each"> {
4
4
  /** Number of times to repeat | 重复次数 */
5
5
  times: number;
6
6
  }
package/dist/Show.d.ts CHANGED
@@ -6,6 +6,8 @@ export interface ShowProps<T> {
6
6
  children: ReactNode | ((value: NonNullable<T>) => ReactNode);
7
7
  /** Fallback content when condition is falsy | 条件为假时渲染的备选内容 */
8
8
  fallback?: ReactNode;
9
+ /** Callback when condition is falsy (called before rendering fallback) | 条件为假时的回调(在渲染 fallback 之前调用) */
10
+ onFallback?: () => void;
9
11
  }
10
12
  /**
11
13
  * Conditional rendering component, replaces ternary expressions in JSX
@@ -29,5 +31,11 @@ export interface ShowProps<T> {
29
31
  * <Show when={user}>
30
32
  * {(user) => <UserProfile name={user.name} />}
31
33
  * </Show>
34
+ *
35
+ * @example
36
+ * // With onFallback callback for side effects | 带 onFallback 回调用于副作用
37
+ * <Show when={isAuthenticated} fallback={<Loading />} onFallback={() => navigate('/login')}>
38
+ * <Dashboard />
39
+ * </Show>
32
40
  */
33
- export declare function Show<T>({ when, children, fallback }: ShowProps<T>): ReactNode;
41
+ export declare function Show<T>({ when, children, fallback, onFallback }: ShowProps<T>): ReactNode;
package/dist/Split.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { ReactNode } from 'react';
2
- import { type ForProps } from './For';
3
- export interface SplitProps extends Omit<ForProps<string>, 'each'> {
1
+ import type { ReactNode } from "react";
2
+ import { type ForProps } from "./For";
3
+ export interface SplitProps extends Omit<ForProps<string>, "each"> {
4
4
  /** String to split | 要切割的字符串 */
5
5
  string: string | null | undefined;
6
6
  /** Separator to split by, can be string or RegExp | 分隔符,可以是字符串或正则表达式 */
@@ -0,0 +1,45 @@
1
+ import { type ReactNode } from "react";
2
+ /** Timeout mode | 超时模式 */
3
+ export type TimeoutMode = "after" | "before";
4
+ export interface TimeoutProps {
5
+ /** Delay time in milliseconds | 延迟时间(毫秒) */
6
+ ms: number;
7
+ /** Content to render | 要渲染的内容 */
8
+ children: ReactNode;
9
+ /** Display mode: 'after' = show after delay, 'before' = hide after delay | 显示模式:'after' = 延迟后显示,'before' = 延迟后隐藏 */
10
+ mode?: TimeoutMode;
11
+ /** Content to show when hidden (only for 'after' mode) | 隐藏时显示的内容(仅 'after' 模式) */
12
+ fallback?: ReactNode;
13
+ /** Callback when timeout occurs | 超时发生时的回调 */
14
+ onTimeout?: () => void;
15
+ }
16
+ /**
17
+ * Timeout component, shows or hides content after a specified delay
18
+ *
19
+ * 超时组件,在指定延迟后显示或隐藏内容
20
+ *
21
+ * @example
22
+ * // Show content after delay (fade-in effect) | 延迟后显示内容(淡入效果)
23
+ * <Timeout ms={1000} mode="after">
24
+ * <DelayedMessage />
25
+ * </Timeout>
26
+ *
27
+ * @example
28
+ * // Hide content after delay (auto-dismiss) | 延迟后隐藏内容(自动消失)
29
+ * <Timeout ms={3000} mode="before">
30
+ * <Toast message="Saved successfully!" />
31
+ * </Timeout>
32
+ *
33
+ * @example
34
+ * // With fallback while waiting | 等待时显示 fallback
35
+ * <Timeout ms={2000} mode="after" fallback={<Spinner />}>
36
+ * <SlowComponent />
37
+ * </Timeout>
38
+ *
39
+ * @example
40
+ * // With onTimeout callback | 带超时回调
41
+ * <Timeout ms={5000} mode="before" onTimeout={() => console.log("Dismissed")}>
42
+ * <Notification />
43
+ * </Timeout>
44
+ */
45
+ export declare function Timeout({ ms, children, mode, fallback, onTimeout }: TimeoutProps): ReactNode;
@@ -0,0 +1,51 @@
1
+ import { type ReactNode } from "react";
2
+ export interface VisibleProps {
3
+ /** Content to render when visible | 可见时渲染的内容 */
4
+ children: ReactNode;
5
+ /** Fallback content before entering viewport | 进入视口前渲染的备选内容 */
6
+ fallback?: ReactNode;
7
+ /** Root margin for intersection observer (e.g., "100px") | 交叉观察器的根边距 */
8
+ rootMargin?: string;
9
+ /** Visibility threshold (0-1) | 可见性阈值 */
10
+ threshold?: number | number[];
11
+ /** Keep rendered after first visible (default: true) | 首次可见后保持渲染 */
12
+ once?: boolean;
13
+ /** Callback when visibility changes | 可见性变化时的回调 */
14
+ onVisibilityChange?: (isVisible: boolean) => void;
15
+ }
16
+ /**
17
+ * Visibility-based rendering component using IntersectionObserver (Web only)
18
+ *
19
+ * 基于可见性的渲染组件,使用 IntersectionObserver(仅 Web)
20
+ *
21
+ * In React Native or environments without IntersectionObserver,
22
+ * children will be rendered directly (graceful degradation).
23
+ *
24
+ * 在 React Native 或不支持 IntersectionObserver 的环境中,
25
+ * 会直接渲染 children(优雅降级)。
26
+ *
27
+ * @example
28
+ * // Basic usage - render when entering viewport | 基础用法 - 进入视口时渲染
29
+ * <Visible>
30
+ * <HeavyComponent />
31
+ * </Visible>
32
+ *
33
+ * @example
34
+ * // With fallback placeholder | 带占位符
35
+ * <Visible fallback={<Skeleton />}>
36
+ * <Image src={url} />
37
+ * </Visible>
38
+ *
39
+ * @example
40
+ * // Preload before entering viewport | 提前预加载
41
+ * <Visible rootMargin="200px" fallback={<Placeholder />}>
42
+ * <LazyImage />
43
+ * </Visible>
44
+ *
45
+ * @example
46
+ * // Toggle visibility (once=false) | 切换可见性
47
+ * <Visible once={false} onVisibilityChange={(v) => console.log(v)}>
48
+ * <VideoPlayer />
49
+ * </Visible>
50
+ */
51
+ export declare function Visible({ children, fallback, rootMargin, threshold, once, onVisibilityChange, }: VisibleProps): ReactNode;
package/dist/index.d.ts CHANGED
@@ -6,4 +6,6 @@ export { QueryBoundary, type QueryBoundaryProps, type QueryResult } from "./Quer
6
6
  export { Repeat, type RepeatProps } from "./Repeat";
7
7
  export { Show, type ShowProps } from "./Show";
8
8
  export { Split, type SplitProps } from "./Split";
9
- export { Default, type DefaultProps, Match, type MatchProps, Switch, type SwitchProps } from "./Switch";
9
+ export { Default, type DefaultProps, Match, type MatchProps, Switch, type SwitchProps, } from "./Switch";
10
+ export { Timeout, type TimeoutProps } from "./Timeout";
11
+ export { Visible, type VisibleProps } from "./Visible";