@wwog/react 1.2.3 → 1.2.5
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.md +81 -3
- package/dist/index.d.mts +138 -86
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/{ProcessControl → components/ProcessControl}/Switch.tsx +1 -1
- package/src/{ProcessControl → components/ProcessControl}/index.ts +0 -1
- package/src/{Common → components/Struct}/index.ts +0 -2
- package/src/components/Sundry/ClassName.tsx +86 -0
- package/src/components/Sundry/index.ts +4 -0
- package/src/index.ts +3 -2
- package/src/utils/index.ts +44 -0
- /package/src/{ProcessControl → components/ProcessControl}/If.tsx +0 -0
- /package/src/{ProcessControl → components/ProcessControl}/Pipe.tsx +0 -0
- /package/src/{ProcessControl → components/ProcessControl}/When.tsx +0 -0
- /package/src/{Common → components/Struct}/ArrayRender.tsx +0 -0
- /package/src/{Common → components/Struct}/DateRender.tsx +0 -0
- /package/src/{Common → components/Sundry}/Scope.tsx +0 -0
- /package/src/{Common → components/Sundry}/SizeBox.tsx +0 -0
- /package/src/{ProcessControl → components/Sundry}/Toggle.tsx +0 -0
package/README.md
CHANGED
|
@@ -312,6 +312,47 @@ function Layout() {
|
|
|
312
312
|
}
|
|
313
313
|
```
|
|
314
314
|
|
|
315
|
+
#### `<ClassName>` (v1.2.5+)
|
|
316
|
+
|
|
317
|
+
用于将 CSS 类名分类编写的组件,内置类似`clsx`的功能,并且可以去除重复的 className。支持基础类、悬停态、激活态等多种状态的类名管理。
|
|
318
|
+
|
|
319
|
+
```tsx
|
|
320
|
+
import { ClassName } from "@wwog/react";
|
|
321
|
+
|
|
322
|
+
function Example() {
|
|
323
|
+
return (
|
|
324
|
+
<ClassName
|
|
325
|
+
className={{
|
|
326
|
+
base: "p-2 bg-white",
|
|
327
|
+
hover: "hover:bg-gray-100",
|
|
328
|
+
active: "active:bg-gray-200",
|
|
329
|
+
focus: "focus:ring-2",
|
|
330
|
+
}}
|
|
331
|
+
>
|
|
332
|
+
<button>点击我</button>
|
|
333
|
+
</ClassName>
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
还可以使用容器包装元素:
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
<ClassName
|
|
342
|
+
className={{
|
|
343
|
+
base: ["p-2", { "bg-red-500": isError }],
|
|
344
|
+
hover: { "hover:bg-blue-500": true },
|
|
345
|
+
}}
|
|
346
|
+
asWrapper="span"
|
|
347
|
+
>
|
|
348
|
+
内容
|
|
349
|
+
</ClassName>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
- `className`:分类的类名对象,支持各种状态的类名(base, hover, active, focus, disabled 等)
|
|
353
|
+
- `asWrapper`:是否生成包含所有 className 的 wrapper,默认 false,传递标签名如'div'或'span'
|
|
354
|
+
- `children`:子元素,通常是一个 React 元素
|
|
355
|
+
|
|
315
356
|
### hooks
|
|
316
357
|
|
|
317
358
|
- 一些常用的 hooks 的封装
|
|
@@ -320,12 +361,49 @@ function Layout() {
|
|
|
320
361
|
|
|
321
362
|
- 受控组件和非受控组件的切换,方便组件开发
|
|
322
363
|
|
|
323
|
-
###
|
|
364
|
+
### utils
|
|
324
365
|
|
|
325
366
|
- 用于部分组件的内部函数,如需要也可使用
|
|
326
367
|
|
|
327
|
-
formatDate
|
|
328
|
-
|
|
368
|
+
#### `formatDate`
|
|
369
|
+
|
|
370
|
+
比较标准的格式化时间函数
|
|
371
|
+
|
|
372
|
+
#### `childrenLoop`
|
|
373
|
+
|
|
374
|
+
可以中断的子节点遍历,让一些分支流程拥有极致性能
|
|
375
|
+
|
|
376
|
+
#### `Counter`
|
|
377
|
+
|
|
378
|
+
计数器
|
|
379
|
+
|
|
380
|
+
#### `cn` (v1.2.5+)
|
|
381
|
+
|
|
382
|
+
一个高效的 CSS 类名合并工具函数,类似于`clsx`或`classnames`,但能自动去除重复的类名。
|
|
383
|
+
|
|
384
|
+
```tsx
|
|
385
|
+
import { cn } from "@wwog/react";
|
|
386
|
+
|
|
387
|
+
function Example({ isActive, isDisabled }) {
|
|
388
|
+
return (
|
|
389
|
+
<div
|
|
390
|
+
className={cn("base-class", ["array-class-1", "array-class-2"], {
|
|
391
|
+
"active-class": isActive,
|
|
392
|
+
"disabled-class": isDisabled,
|
|
393
|
+
})}
|
|
394
|
+
>
|
|
395
|
+
内容
|
|
396
|
+
</div>
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
支持多种参数类型:
|
|
402
|
+
|
|
403
|
+
- 字符串: `"class1 class2"`
|
|
404
|
+
- 字符串数组: `["class1", "class2"]`
|
|
405
|
+
- 对象: `{ "class1": true, "class2": false }`
|
|
406
|
+
- 以上类型的任意组合
|
|
329
407
|
|
|
330
408
|
## License
|
|
331
409
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React$1, { ReactNode, FC, Dispatch } from 'react';
|
|
1
|
+
import React$1, { ReactNode, FC, HTMLElementType, Dispatch } from 'react';
|
|
2
2
|
|
|
3
3
|
interface SwitchProps<T> {
|
|
4
4
|
value: T;
|
|
@@ -190,46 +190,6 @@ interface PipeProps {
|
|
|
190
190
|
*/
|
|
191
191
|
declare const Pipe: FC<PipeProps>;
|
|
192
192
|
|
|
193
|
-
interface ToggleProps<T = boolean> {
|
|
194
|
-
/**
|
|
195
|
-
* @description_en The initial value to toggle.
|
|
196
|
-
* @description_zh 初始切换值。
|
|
197
|
-
* @default 0
|
|
198
|
-
*/
|
|
199
|
-
index?: number;
|
|
200
|
-
/**
|
|
201
|
-
* @description_en Array of values to toggle between.
|
|
202
|
-
* @description_zh 可切换的值数组。
|
|
203
|
-
*/
|
|
204
|
-
options: T[];
|
|
205
|
-
/**
|
|
206
|
-
* @description_en Function to determine the next value index in the toggle sequence.
|
|
207
|
-
* @description_zh 确定切换序列中下一个值索引的函数。
|
|
208
|
-
* @optional
|
|
209
|
-
*/
|
|
210
|
-
next?: (curIndex: number, options: T[]) => number;
|
|
211
|
-
/**
|
|
212
|
-
* @description_en Render function, receiving the toggled value and toggle function.
|
|
213
|
-
* @description_zh 渲染函数,接收切换后的值和切换函数。
|
|
214
|
-
*/
|
|
215
|
-
render: (value: T, toggle: () => void) => ReactNode;
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* @description_zh 一个声明式组件,用于在预定义选项中切换值并通过 render 函数传递给子组件,支持自定义切换逻辑。
|
|
219
|
-
* @description_en A declarative component for toggling between predefined values and passing them to children via a render function, supporting custom toggle logic.
|
|
220
|
-
* @component
|
|
221
|
-
* @example
|
|
222
|
-
* ```tsx
|
|
223
|
-
* <Toggle
|
|
224
|
-
* options={["light", "dark"]}
|
|
225
|
-
* render={(theme, toggleTheme) => (
|
|
226
|
-
* <div onClick={toggleTheme}>当前主题: {theme}</div>
|
|
227
|
-
* )}
|
|
228
|
-
* />
|
|
229
|
-
* ```
|
|
230
|
-
*/
|
|
231
|
-
declare const Toggle: <T>(props: ToggleProps<T>) => React$1.ReactNode;
|
|
232
|
-
|
|
233
193
|
interface SizeBoxProps {
|
|
234
194
|
size?: number | string;
|
|
235
195
|
height?: number | string;
|
|
@@ -244,13 +204,6 @@ interface SizeBoxProps {
|
|
|
244
204
|
*/
|
|
245
205
|
declare const SizeBox: FC<SizeBoxProps>;
|
|
246
206
|
|
|
247
|
-
interface ArrayRenderProps<T> {
|
|
248
|
-
items: T[];
|
|
249
|
-
renderItem: (item: T, index: number) => React$1.ReactNode;
|
|
250
|
-
filter?: (item: T) => boolean;
|
|
251
|
-
}
|
|
252
|
-
declare function ArrayRender<T>(props: ArrayRenderProps<T>): ReactNode;
|
|
253
|
-
|
|
254
207
|
/**
|
|
255
208
|
* Props for the `Scope` component.
|
|
256
209
|
*
|
|
@@ -306,6 +259,141 @@ interface ScopeProps {
|
|
|
306
259
|
*/
|
|
307
260
|
declare const Scope: FC<ScopeProps>;
|
|
308
261
|
|
|
262
|
+
/**
|
|
263
|
+
* @description 性能优化,替代 React.Children.forEach, 回调可以返回 false 来中断循环
|
|
264
|
+
* @description_en Replace React.Children.forEach, the callback can return false to interrupt the loop
|
|
265
|
+
*/
|
|
266
|
+
declare function childrenLoop(children: React$1.ReactNode | undefined, callback: (child: React$1.ReactNode, index: number) => boolean | void): void;
|
|
267
|
+
/**
|
|
268
|
+
* @param schema
|
|
269
|
+
* @example
|
|
270
|
+
* YY | 18 | Two-digit year
|
|
271
|
+
* YYYY | 2018 | Four-digit year
|
|
272
|
+
* M | 1-12 | The month, beginning at 1
|
|
273
|
+
* MM | 01-12 | The month, 2-digits
|
|
274
|
+
* MMM | Jan-Dec | The abbreviated month name
|
|
275
|
+
* MMMM | January-December | The full month name
|
|
276
|
+
* D | 1-31 | The day of the month
|
|
277
|
+
* DD | 01-31 | The day of the month, 2-digits
|
|
278
|
+
* d | 0-6 | The day of the week, with Sunday as 0
|
|
279
|
+
* dd | Su-Sa | The min name of the day of the week
|
|
280
|
+
* ddd | Sun-Sat | The short name of the day of the week
|
|
281
|
+
* dddd | Sunday-Saturday | The name of the day of the week
|
|
282
|
+
* H | 0-23 | The hour
|
|
283
|
+
* HH | 00-23 | The hour, 2-digits
|
|
284
|
+
* h | 1-12 | The hour, 12-hour clock
|
|
285
|
+
* hh | 01-12 | The hour, 12-hour clock, 2-digits
|
|
286
|
+
* m | 0-59 | The minute
|
|
287
|
+
* mm | 00-59 | The minute, 2-digits
|
|
288
|
+
* s | 0-59 | The second
|
|
289
|
+
* ss | 00-59 | The second, 2-digits
|
|
290
|
+
* SSS | 000-999 | The millisecond, 3-digits
|
|
291
|
+
* Z | +05:00 | The offset from UTC, ±HH:mm
|
|
292
|
+
* ZZ | +0500 | The offset from UTC, ±HHmm
|
|
293
|
+
* A | AM | PM
|
|
294
|
+
* a | am | pm
|
|
295
|
+
*/
|
|
296
|
+
declare function formatDate(schema: string, date?: Date): string;
|
|
297
|
+
declare class Counter {
|
|
298
|
+
count: number;
|
|
299
|
+
/**
|
|
300
|
+
* @description 获取下一个计数值,不考虑越界。
|
|
301
|
+
* @description_en Get the next count value, without considering overflow.
|
|
302
|
+
*/
|
|
303
|
+
next(): number;
|
|
304
|
+
}
|
|
305
|
+
type CxInput = string | string[] | Record<string, boolean> | undefined | null | false;
|
|
306
|
+
declare function cx(...args: CxInput[]): string;
|
|
307
|
+
|
|
308
|
+
interface ClassNameProps {
|
|
309
|
+
className?: {
|
|
310
|
+
base?: CxInput;
|
|
311
|
+
hover?: CxInput;
|
|
312
|
+
active?: CxInput;
|
|
313
|
+
focus?: CxInput;
|
|
314
|
+
disabled?: CxInput;
|
|
315
|
+
[key: string]: CxInput;
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* @description 传入容器标签名.是否生成包含所有 `className` 的 `wrapper`, 默认 false, 传递 `true` 为 `div。`
|
|
319
|
+
* @description_en Whether to generate a `wrapper` containing all `className`, default is false, and pass the container tag name, if `true` will be `div`.
|
|
320
|
+
*/
|
|
321
|
+
asWrapper?: boolean | HTMLElementType;
|
|
322
|
+
children?: React$1.ReactNode;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* @description 用于将 `className` 分类编写的组件,内置了类似`clsx`的功能,并且去除重复的 className。
|
|
326
|
+
* @description_en A component for `className` classification, built-in similar to `clsx` functionality, and removes duplicate className.
|
|
327
|
+
* @component
|
|
328
|
+
* @example
|
|
329
|
+
* ```tsx
|
|
330
|
+
* <ClassName className={{ base: "p-2 bg-red", hover: ["hover:bg-blue", { "hover:text-white": true }] }}>
|
|
331
|
+
* <button>Click me</button>
|
|
332
|
+
* </ClassName>
|
|
333
|
+
* ```
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```tsx
|
|
337
|
+
* <ClassName
|
|
338
|
+
* className={{
|
|
339
|
+
* base: ["p-2", { "bg-red": condition }],
|
|
340
|
+
* hover: { "hover:bg-blue": true },
|
|
341
|
+
* }}
|
|
342
|
+
* asWrapper="span"
|
|
343
|
+
* >
|
|
344
|
+
* <button>Click me</button>
|
|
345
|
+
* </ClassName>
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
declare const ClassName: FC<ClassNameProps>;
|
|
349
|
+
|
|
350
|
+
interface ToggleProps<T = boolean> {
|
|
351
|
+
/**
|
|
352
|
+
* @description_en The initial value to toggle.
|
|
353
|
+
* @description_zh 初始切换值。
|
|
354
|
+
* @default 0
|
|
355
|
+
*/
|
|
356
|
+
index?: number;
|
|
357
|
+
/**
|
|
358
|
+
* @description_en Array of values to toggle between.
|
|
359
|
+
* @description_zh 可切换的值数组。
|
|
360
|
+
*/
|
|
361
|
+
options: T[];
|
|
362
|
+
/**
|
|
363
|
+
* @description_en Function to determine the next value index in the toggle sequence.
|
|
364
|
+
* @description_zh 确定切换序列中下一个值索引的函数。
|
|
365
|
+
* @optional
|
|
366
|
+
*/
|
|
367
|
+
next?: (curIndex: number, options: T[]) => number;
|
|
368
|
+
/**
|
|
369
|
+
* @description_en Render function, receiving the toggled value and toggle function.
|
|
370
|
+
* @description_zh 渲染函数,接收切换后的值和切换函数。
|
|
371
|
+
*/
|
|
372
|
+
render: (value: T, toggle: () => void) => ReactNode;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* @description_zh 一个声明式组件,用于在预定义选项中切换值并通过 render 函数传递给子组件,支持自定义切换逻辑。
|
|
376
|
+
* @description_en A declarative component for toggling between predefined values and passing them to children via a render function, supporting custom toggle logic.
|
|
377
|
+
* @component
|
|
378
|
+
* @example
|
|
379
|
+
* ```tsx
|
|
380
|
+
* <Toggle
|
|
381
|
+
* options={["light", "dark"]}
|
|
382
|
+
* render={(theme, toggleTheme) => (
|
|
383
|
+
* <div onClick={toggleTheme}>当前主题: {theme}</div>
|
|
384
|
+
* )}
|
|
385
|
+
* />
|
|
386
|
+
* ```
|
|
387
|
+
*/
|
|
388
|
+
declare const Toggle: <T>(props: ToggleProps<T>) => React$1.ReactNode;
|
|
389
|
+
|
|
390
|
+
interface ArrayRenderProps<T> {
|
|
391
|
+
items: T[];
|
|
392
|
+
renderItem: (item: T, index: number) => React$1.ReactNode;
|
|
393
|
+
filter?: (item: T) => boolean;
|
|
394
|
+
}
|
|
395
|
+
declare function ArrayRender<T>(props: ArrayRenderProps<T>): ReactNode;
|
|
396
|
+
|
|
309
397
|
interface DateRenderProps<T = string> {
|
|
310
398
|
/**
|
|
311
399
|
* @description_en The input date to render (Date object, ISO string, or timestamp).
|
|
@@ -349,42 +437,6 @@ interface DateRenderProps<T = string> {
|
|
|
349
437
|
*/
|
|
350
438
|
declare function DateRender<T = string>({ source, format, children, }: DateRenderProps<T>): React$1.JSX.Element | null;
|
|
351
439
|
|
|
352
|
-
/**
|
|
353
|
-
* @description 性能优化,替代 React.Children.forEach, 回调可以返回 false 来中断循环
|
|
354
|
-
* @description_en Replace React.Children.forEach, the callback can return false to interrupt the loop
|
|
355
|
-
*/
|
|
356
|
-
declare function childrenLoop(children: React$1.ReactNode | undefined, callback: (child: React$1.ReactNode, index: number) => boolean | void): void;
|
|
357
|
-
/**
|
|
358
|
-
* @param schema
|
|
359
|
-
* @example
|
|
360
|
-
* YY | 18 | Two-digit year
|
|
361
|
-
* YYYY | 2018 | Four-digit year
|
|
362
|
-
* M | 1-12 | The month, beginning at 1
|
|
363
|
-
* MM | 01-12 | The month, 2-digits
|
|
364
|
-
* MMM | Jan-Dec | The abbreviated month name
|
|
365
|
-
* MMMM | January-December | The full month name
|
|
366
|
-
* D | 1-31 | The day of the month
|
|
367
|
-
* DD | 01-31 | The day of the month, 2-digits
|
|
368
|
-
* d | 0-6 | The day of the week, with Sunday as 0
|
|
369
|
-
* dd | Su-Sa | The min name of the day of the week
|
|
370
|
-
* ddd | Sun-Sat | The short name of the day of the week
|
|
371
|
-
* dddd | Sunday-Saturday | The name of the day of the week
|
|
372
|
-
* H | 0-23 | The hour
|
|
373
|
-
* HH | 00-23 | The hour, 2-digits
|
|
374
|
-
* h | 1-12 | The hour, 12-hour clock
|
|
375
|
-
* hh | 01-12 | The hour, 12-hour clock, 2-digits
|
|
376
|
-
* m | 0-59 | The minute
|
|
377
|
-
* mm | 00-59 | The minute, 2-digits
|
|
378
|
-
* s | 0-59 | The second
|
|
379
|
-
* ss | 00-59 | The second, 2-digits
|
|
380
|
-
* SSS | 000-999 | The millisecond, 3-digits
|
|
381
|
-
* Z | +05:00 | The offset from UTC, ±HH:mm
|
|
382
|
-
* ZZ | +0500 | The offset from UTC, ±HHmm
|
|
383
|
-
* A | AM | PM
|
|
384
|
-
* a | am | pm
|
|
385
|
-
*/
|
|
386
|
-
declare function formatDate(schema: string, date?: Date): string;
|
|
387
|
-
|
|
388
440
|
interface UseControlledOptions<T> {
|
|
389
441
|
/**
|
|
390
442
|
* @description - 非受控模式下的默认值,会被受控模式下的值覆盖
|
|
@@ -412,5 +464,5 @@ interface UseControlledOptions<T> {
|
|
|
412
464
|
}
|
|
413
465
|
declare function useControlled<T>(options: UseControlledOptions<T>): [T, Dispatch<React.SetStateAction<T>>];
|
|
414
466
|
|
|
415
|
-
export { ArrayRender, DateRender, False, If, Pipe, Scope, SizeBox, Switch, Toggle, True, When, childrenLoop, formatDate, useControlled };
|
|
416
|
-
export type { ArrayRenderProps, DateRenderProps, ElseIfProps, ElseProps, FalseProps, IfProps, PipeProps, ScopeProps, SwitchCaseProps, SwitchDefaultProps, SwitchProps, ThenProps, ToggleProps, TrueProps, UseControlledOptions, WhenProps };
|
|
467
|
+
export { ArrayRender, ClassName, Counter, DateRender, False, If, Pipe, Scope, SizeBox, Switch, Toggle, True, When, childrenLoop, cx, formatDate, useControlled };
|
|
468
|
+
export type { ArrayRenderProps, ClassNameProps, CxInput, DateRenderProps, ElseIfProps, ElseProps, FalseProps, IfProps, PipeProps, ScopeProps, SwitchCaseProps, SwitchDefaultProps, SwitchProps, ThenProps, ToggleProps, TrueProps, UseControlledOptions, WhenProps };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import r,{useMemo as h,useEffect as
|
|
1
|
+
import r,{useMemo as h,useEffect as I,isValidElement as T,Fragment as M,cloneElement as H,useState as A,useCallback as P}from"react";function Y(t,n){if(t===void 0)return;let e=0;if(Array.isArray(t)){for(const l of t)if(n(l,e++)===!1)break}else n(t,e)}function W(t,n){const e=n||new Date,l=e.getFullYear(),a=e.getMonth()+1,o=e.getDate(),s=e.getHours(),c=e.getMinutes(),u=e.getSeconds(),d=e.getMilliseconds(),i=e.getDay(),f=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],m=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],y=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],x=["January","February","March","April","May","June","July","August","September","October","November","December"],D=i===0?6:i-1,k=m[D],b=f[D],C=a-1,O=x[C],J=y[C],j={YY:l.toString().slice(2),YYYY:l.toString(),M:a.toString(),MM:a.toString().padStart(2,"0"),MMM:J,MMMM:O,D:o.toString(),DD:o.toString().padStart(2,"0"),d:i.toString(),dd:b,ddd:b,dddd:k,H:s.toString(),HH:s.toString().padStart(2,"0"),h:(s%12).toString(),hh:(s%12).toString().padStart(2,"0"),m:c.toString(),mm:c.toString().padStart(2,"0"),s:u.toString(),ss:u.toString().padStart(2,"0"),SSS:d.toString().padStart(3,"0"),Z:"+08:00",ZZ:"+0800",A:s<12?"AM":"PM",a:s<12?"am":"pm"};return t.replace(/YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|SSS|Z{1,2}|A|a/g,R=>j[R])}class _{count=0;next(){return this.count++}}function v(...t){const n=new Set;for(const e of t)if(e){if(typeof e=="string")n.add(e);else if(Array.isArray(e))e.forEach(l=>n.add(l));else if(typeof e=="object")for(const[l,a]of Object.entries(e))a&&n.add(l)}return Array.from(n).join(" ")}const B=(t,n)=>t===n,S=t=>r.createElement(r.Fragment,null,t.children);S.displayName="Switch_Case";const E=t=>r.createElement(r.Fragment,null,t.children);E.displayName="Switch_Default";const g=t=>{const{value:n,compare:e=B,children:l,strict:a=!1}=t,o=new Set;let s=null,c=null,u=!1;return Y(l,(d,i)=>{if(!r.isValidElement(d))throw new Error(`Switch Children only accepts valid React elements at index ${i}`);const f=d.type;if(f.displayName===S.displayName){const m=d.props;if(o.has(m.value))throw new Error(`Switch found duplicate Case value at index ${i}: ${JSON.stringify(m.value)}${a?" (detected in strict mode)":""}`);if(o.add(m.value),!s&&e(n,m.value)&&(s=m.children,a===!1))return!1}else if(f.displayName===E.displayName){if(u)throw new Error(`Switch can only have one Default child at index ${i}`);if(u=!0,c=d.props.children,!a&&s)return!1}else throw new Error(`Switch Children only accepts 'Case' or 'Default' elements, found: ${String(f.displayName||f.name||f)} at index ${i}`)}),r.createElement(r.Fragment,null,s??c)};g.displayName="Switch",g.Case=S,g.Default=E,g.createTyped=function(){return{Switch:g,Case:S,Default:E}};const w=t=>r.createElement(r.Fragment,null,t.children),N=({children:t})=>r.createElement(r.Fragment,null,t),F=t=>r.createElement(r.Fragment,null,t.children);w.displayName="If_Then",N.displayName="If_Else",F.displayName="If_ElseIf";const p=({condition:t,children:n})=>{let e=null,l=null;const a=[];if(r.Children.forEach(n,o=>{if(!r.isValidElement(o))throw new Error("If component only accepts valid React elements");const s=o.type;if(s.displayName===w.displayName){if(e)throw new Error("If component can only have one Then child");e=o}else if(s.displayName===F.displayName)a.push(o);else if(s.displayName===N.displayName){if(l)throw new Error("If component can only have one Else child");l=o}else throw new Error(`If component only accepts 'Then', 'ElseIf', or 'Else' elements as children, found: ${String(s.displayName||s.name||s)}`)}),t)return e?r.createElement(r.Fragment,null,e.props.children):null;for(const o of a)if(o.props.condition)return r.createElement(r.Fragment,null,o.props.children);return l?r.createElement(r.Fragment,null,l.props.children):null};p.displayName="If",p.Then=w,p.ElseIf=F,p.Else=N,p.createTyped=function(){return{If:p,Then:w,ElseIf:F,Else:N}};const V=({condition:t,children:n})=>t?r.createElement(r.Fragment,null,n):null,Z=({condition:t,children:n})=>t===!1?r.createElement(r.Fragment,null,n):null,$=({all:t,any:n,none:e,children:l,fallback:a})=>h(()=>(t&&(n||e)&&console.warn('When: Multiple condition types (all, any, none) provided; "all" takes precedence.'),!!(t&&t.length>0&&t.every(Boolean)||n&&n.length>0&&n.some(Boolean)||e&&e.length>0&&e.every(o=>!o))),[t,n,e])?r.createElement(r.Fragment,null,l):r.createElement(r.Fragment,null,a||null),z=({data:t,transform:n,render:e,fallback:l})=>{const a=h(()=>n.reduce((o,s)=>s(o),t),[t,n]);return a==null?r.createElement(r.Fragment,null,l||null):r.createElement(r.Fragment,null,e(a))},L=t=>{const{children:n,h:e,w:l,size:a,height:o,width:s,className:c}=t;return r.createElement("div",{style:{width:a||l||s,height:a||e||o,flexShrink:0},className:c},n)},q=({let:t,props:n,children:e,fallback:l})=>{const a=h(()=>typeof t=="function"?t(n):t,[t,n]);return!e||!Object.keys(a).length?r.createElement(r.Fragment,null,l||null):r.createElement(r.Fragment,null,e(a))},G=t=>{const{className:n,children:e,asWrapper:l}=t;if(I(()=>{T(e)===!1&&console.warn("<ClassName>: children is not a valid React element. Please check your code.")},[e]),!e)return null;if(!n)return r.createElement(M,null,e);const a=v(...Object.values(n));return l?r.createElement(typeof l=="string"?l:"div",{className:a},e):T(e)?H(e,{className:v(e.props.className,a)}):r.createElement(M,null,e)},K=t=>{const{index:n=0,options:e,next:l,render:a}=t;I(()=>{if(e.length<n+1)throw new Error(`Index ${n} is out of bounds for options array of length ${e.length}. Defaulting to first option.`)},[n,e]);const[o,s]=A(n),c=()=>{s(u=>e.length?l?l(u,e):(u+1)%e.length:u)};return a(e[o],c)};function Q(t){const{items:n,renderItem:e,filter:l}=t;return n?r.createElement(M,null,n.map((a,o)=>l&&!l(a)?null:e(a,o))):(console.error("ArrayRender: items is null"),null)}function U({source:t,format:n,children:e}){const l=h(()=>{if(t instanceof Date)return t;if(typeof t=="string"||typeof t=="number"){const o=new Date(t);return isNaN(o.getTime())?null:o}return null},[t]),a=h(()=>l?n?n(l):l.toLocaleString():null,[l,n]);return!a||!e?null:r.createElement(r.Fragment,null,e(a))}const X="onChange",ee="value";function te(t){const{defaultValue:n,onBeforeChange:e,trigger:l=X,valuePropName:a=ee,props:o}=t,s=Object.prototype.hasOwnProperty.call(o,a),[c,u]=A(n),d=s?o[a]:c,i=h(()=>o[l],[o,l]),f=P(m=>{const y=typeof m=="function"?m(d):m;e&&e(y,d)===!1||(s||u(y),i&&i(y))},[s,e,l,d,i]);return[d,f]}export{Q as ArrayRender,G as ClassName,_ as Counter,U as DateRender,Z as False,p as If,z as Pipe,q as Scope,L as SizeBox,g as Switch,K as Toggle,V as True,$ as When,Y as childrenLoop,v as cx,W as formatDate,te as useControlled};
|
package/package.json
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
cloneElement,
|
|
3
|
+
FC,
|
|
4
|
+
Fragment,
|
|
5
|
+
isValidElement,
|
|
6
|
+
useEffect,
|
|
7
|
+
type HTMLElementType,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { cx, type CxInput } from "../../utils";
|
|
10
|
+
|
|
11
|
+
export interface ClassNameProps {
|
|
12
|
+
className?: {
|
|
13
|
+
base?: CxInput;
|
|
14
|
+
hover?: CxInput;
|
|
15
|
+
active?: CxInput;
|
|
16
|
+
focus?: CxInput;
|
|
17
|
+
disabled?: CxInput;
|
|
18
|
+
[key: string]: CxInput;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* @description 传入容器标签名.是否生成包含所有 `className` 的 `wrapper`, 默认 false, 传递 `true` 为 `div。`
|
|
22
|
+
* @description_en Whether to generate a `wrapper` containing all `className`, default is false, and pass the container tag name, if `true` will be `div`.
|
|
23
|
+
*/
|
|
24
|
+
asWrapper?: boolean | HTMLElementType;
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @description 用于将 `className` 分类编写的组件,内置了类似`clsx`的功能,并且去除重复的 className。
|
|
30
|
+
* @description_en A component for `className` classification, built-in similar to `clsx` functionality, and removes duplicate className.
|
|
31
|
+
* @component
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* <ClassName className={{ base: "p-2 bg-red", hover: ["hover:bg-blue", { "hover:text-white": true }] }}>
|
|
35
|
+
* <button>Click me</button>
|
|
36
|
+
* </ClassName>
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* <ClassName
|
|
42
|
+
* className={{
|
|
43
|
+
* base: ["p-2", { "bg-red": condition }],
|
|
44
|
+
* hover: { "hover:bg-blue": true },
|
|
45
|
+
* }}
|
|
46
|
+
* asWrapper="span"
|
|
47
|
+
* >
|
|
48
|
+
* <button>Click me</button>
|
|
49
|
+
* </ClassName>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export const ClassName: FC<ClassNameProps> = (props) => {
|
|
53
|
+
const { className, children, asWrapper } = props;
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (isValidElement(children) === false) {
|
|
57
|
+
console.warn(
|
|
58
|
+
"<ClassName>: children is not a valid React element. Please check your code."
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}, [children]);
|
|
62
|
+
|
|
63
|
+
if (!children) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!className) {
|
|
68
|
+
return <Fragment>{children}</Fragment>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const generatedCls = cx(...Object.values(className));
|
|
72
|
+
|
|
73
|
+
if (asWrapper) {
|
|
74
|
+
const Wrapper = typeof asWrapper === "string" ? asWrapper : "div";
|
|
75
|
+
return <Wrapper className={generatedCls}>{children}</Wrapper>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (isValidElement(children)) {
|
|
79
|
+
return cloneElement(children, {
|
|
80
|
+
//@ts-expect-error type error
|
|
81
|
+
className: cx(children.props.className, generatedCls),
|
|
82
|
+
} as any);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return <Fragment>{children}</Fragment>;
|
|
86
|
+
};
|
package/src/index.ts
CHANGED
package/src/utils/index.ts
CHANGED
|
@@ -139,3 +139,47 @@ export function formatDate(schema: string, date?: Date): string {
|
|
|
139
139
|
}
|
|
140
140
|
);
|
|
141
141
|
}
|
|
142
|
+
|
|
143
|
+
export class Counter {
|
|
144
|
+
count = 0;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @description 获取下一个计数值,不考虑越界。
|
|
148
|
+
* @description_en Get the next count value, without considering overflow.
|
|
149
|
+
*/
|
|
150
|
+
next() {
|
|
151
|
+
return this.count++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export type CxInput =
|
|
156
|
+
| string
|
|
157
|
+
| string[]
|
|
158
|
+
| Record<string, boolean>
|
|
159
|
+
| undefined
|
|
160
|
+
| null
|
|
161
|
+
| false;
|
|
162
|
+
|
|
163
|
+
export function cx(...args: CxInput[]): string {
|
|
164
|
+
const classes = new Set<string>();
|
|
165
|
+
|
|
166
|
+
for (const arg of args) {
|
|
167
|
+
if (!arg) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (typeof arg === "string") {
|
|
172
|
+
classes.add(arg);
|
|
173
|
+
} else if (Array.isArray(arg)) {
|
|
174
|
+
arg.forEach((item) => classes.add(item));
|
|
175
|
+
} else if (typeof arg === "object") {
|
|
176
|
+
for (const [key, value] of Object.entries(arg)) {
|
|
177
|
+
if (value) {
|
|
178
|
+
classes.add(key);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return Array.from(classes).join(" ");
|
|
185
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|