@mks2508/mks-ui 0.2.1 → 0.3.1
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/react-ui/hooks/Animation/UseAutoHeight.js +7 -7
- package/dist/react-ui/hooks/DOM/UseIsInView.js +3 -3
- package/dist/react-ui/hooks/Formatting/UseListFormat.d.ts +49 -0
- package/dist/react-ui/hooks/Formatting/UseListFormat.d.ts.map +1 -0
- package/dist/react-ui/hooks/Formatting/UseListFormat.js +105 -0
- package/dist/react-ui/hooks/State/UseControlledState.js +4 -4
- package/dist/react-ui/hooks/State/UseDataState.js +5 -5
- package/dist/react-ui/hooks/index.d.ts +2 -0
- package/dist/react-ui/hooks/index.d.ts.map +1 -1
- package/dist/react-ui/hooks/index.js +1 -0
- package/dist/react-ui/index.js +22 -2
- package/dist/react-ui/lib/get-strict-context.js +3 -3
- package/dist/react-ui/primitives/CountingNumber/index.js +3 -3
- package/dist/react-ui/primitives/Highlight/index.js +26 -26
- package/dist/react-ui/primitives/Slot/index.js +3 -3
- package/dist/react-ui/primitives/index.d.ts +1 -0
- package/dist/react-ui/primitives/index.d.ts.map +1 -1
- package/dist/react-ui/primitives/index.js +18 -0
- package/dist/react-ui/primitives/waapi/Morph/Morph.types.d.ts +76 -0
- package/dist/react-ui/primitives/waapi/Morph/Morph.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/MorphContext.d.ts +11 -0
- package/dist/react-ui/primitives/waapi/Morph/MorphContext.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/MorphContext.js +19 -0
- package/dist/react-ui/primitives/waapi/Morph/index.d.ts +23 -0
- package/dist/react-ui/primitives/waapi/Morph/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/index.js +45 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/index.d.ts +12 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.d.ts +38 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.js +78 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.d.ts +23 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.js +140 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.d.ts +28 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.js +77 -0
- package/dist/react-ui/primitives/waapi/Morph/useMorph.d.ts +27 -0
- package/dist/react-ui/primitives/waapi/Morph/useMorph.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/useMorph.js +86 -0
- package/dist/react-ui/primitives/waapi/Reorder/Reorder.types.d.ts +168 -0
- package/dist/react-ui/primitives/waapi/Reorder/Reorder.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/index.d.ts +25 -0
- package/dist/react-ui/primitives/waapi/Reorder/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/index.js +186 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorder.d.ts +26 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorder.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorder.js +48 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorderPresence.d.ts +33 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorderPresence.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorderPresence.js +137 -0
- package/dist/react-ui/primitives/waapi/Reorder/utils/separatorCoordination.d.ts +47 -0
- package/dist/react-ui/primitives/waapi/Reorder/utils/separatorCoordination.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/utils/separatorCoordination.js +72 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.styles.d.ts +10 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.styles.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.types.d.ts +74 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/index.d.ts +33 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/index.js +354 -0
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.styles.d.ts +25 -0
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.styles.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.types.d.ts +57 -0
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingText/index.d.ts +26 -0
- package/dist/react-ui/primitives/waapi/SlidingText/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingText/index.js +105 -0
- package/dist/react-ui/primitives/waapi/core/animationConstants.d.ts +156 -0
- package/dist/react-ui/primitives/waapi/core/animationConstants.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/animationConstants.js +180 -0
- package/dist/react-ui/primitives/waapi/core/index.d.ts +16 -0
- package/dist/react-ui/primitives/waapi/core/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/index.js +5 -0
- package/dist/react-ui/primitives/waapi/core/types.d.ts +143 -0
- package/dist/react-ui/primitives/waapi/core/types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/useAnimationOrchestrator.d.ts +32 -0
- package/dist/react-ui/primitives/waapi/core/useAnimationOrchestrator.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/useAnimationOrchestrator.js +322 -0
- package/dist/react-ui/primitives/waapi/core/useElementRegistry.d.ts +21 -0
- package/dist/react-ui/primitives/waapi/core/useElementRegistry.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/useElementRegistry.js +65 -0
- package/dist/react-ui/primitives/waapi/core/useFLIPAnimation.d.ts +20 -0
- package/dist/react-ui/primitives/waapi/core/useFLIPAnimation.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/useFLIPAnimation.js +99 -0
- package/dist/react-ui/primitives/waapi/core/usePositionCapture.d.ts +24 -0
- package/dist/react-ui/primitives/waapi/core/usePositionCapture.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/usePositionCapture.js +75 -0
- package/dist/react-ui/primitives/waapi/index.d.ts +33 -0
- package/dist/react-ui/primitives/waapi/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/index.js +18 -0
- package/dist/react-ui/ui/Accordion/index.js +3 -3
- package/dist/react-ui/ui/Button/index.js +8 -8
- package/dist/react-ui/ui/Combobox/index.js +2 -2
- package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts +35 -0
- package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/DataCard/DataCard.styles.js +114 -0
- package/dist/react-ui/ui/DataCard/DataCard.types.d.ts +135 -0
- package/dist/react-ui/ui/DataCard/DataCard.types.d.ts.map +1 -0
- package/dist/react-ui/ui/DataCard/index.d.ts +129 -0
- package/dist/react-ui/ui/DataCard/index.d.ts.map +1 -0
- package/dist/react-ui/ui/DataCard/index.js +276 -0
- package/dist/react-ui/ui/Menu/index.js +2 -2
- package/dist/react-ui/ui/Switch/index.js +3 -3
- package/dist/react-ui/ui/Tabs/index.js +3 -3
- package/dist/react-ui/ui/TextFlow/TextFlow.styles.d.ts +16 -0
- package/dist/react-ui/ui/TextFlow/TextFlow.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/TextFlow/TextFlow.types.d.ts +101 -0
- package/dist/react-ui/ui/TextFlow/TextFlow.types.d.ts.map +1 -0
- package/dist/react-ui/ui/TextFlow/index.d.ts +26 -0
- package/dist/react-ui/ui/TextFlow/index.d.ts.map +1 -0
- package/dist/react-ui/ui/TextFlow/index.js +187 -0
- package/dist/react-ui/ui/index.d.ts +2 -1
- package/dist/react-ui/ui/index.d.ts.map +1 -1
- package/dist/react-ui/ui/index.js +3 -1
- package/package.json +6 -2
- package/src/react-ui/hooks/Formatting/UseListFormat.ts +134 -0
- package/src/react-ui/hooks/index.ts +3 -0
- package/src/react-ui/primitives/index.ts +3 -0
- package/src/react-ui/primitives/waapi/Morph/Morph.types.ts +106 -0
- package/src/react-ui/primitives/waapi/Morph/MorphContext.tsx +21 -0
- package/src/react-ui/primitives/waapi/Morph/index.tsx +56 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/index.ts +12 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.ts +88 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.ts +175 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.ts +86 -0
- package/src/react-ui/primitives/waapi/Morph/useMorph.ts +100 -0
- package/src/react-ui/primitives/waapi/Reorder/Reorder.types.ts +177 -0
- package/src/react-ui/primitives/waapi/Reorder/index.tsx +260 -0
- package/src/react-ui/primitives/waapi/Reorder/useReorder.ts +46 -0
- package/src/react-ui/primitives/waapi/Reorder/useReorderPresence.ts +208 -0
- package/src/react-ui/primitives/waapi/Reorder/utils/separatorCoordination.ts +104 -0
- package/src/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.styles.ts +14 -0
- package/src/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.types.ts +84 -0
- package/src/react-ui/primitives/waapi/SlidingNumber/index.tsx +474 -0
- package/src/react-ui/primitives/waapi/SlidingText/SlidingText.styles.ts +32 -0
- package/src/react-ui/primitives/waapi/SlidingText/SlidingText.types.ts +69 -0
- package/src/react-ui/primitives/waapi/SlidingText/index.tsx +140 -0
- package/src/react-ui/primitives/waapi/core/animationConstants.ts +215 -0
- package/src/react-ui/primitives/waapi/core/index.ts +53 -0
- package/src/react-ui/primitives/waapi/core/types.ts +200 -0
- package/src/react-ui/primitives/waapi/core/useAnimationOrchestrator.ts +429 -0
- package/src/react-ui/primitives/waapi/core/useElementRegistry.ts +80 -0
- package/src/react-ui/primitives/waapi/core/useFLIPAnimation.ts +137 -0
- package/src/react-ui/primitives/waapi/core/usePositionCapture.ts +105 -0
- package/src/react-ui/primitives/waapi/index.ts +116 -0
- package/src/react-ui/styles/animations.css +369 -0
- package/src/react-ui/ui/DataCard/DataCard.styles.ts +150 -0
- package/src/react-ui/ui/DataCard/DataCard.types.ts +146 -0
- package/src/react-ui/ui/DataCard/index.tsx +406 -0
- package/src/react-ui/ui/TextFlow/TextFlow.styles.ts +36 -0
- package/src/react-ui/ui/TextFlow/TextFlow.types.ts +118 -0
- package/src/react-ui/ui/TextFlow/index.tsx +276 -0
- package/src/react-ui/ui/index.ts +4 -1
- /package/dist/react-ui/components/MorphingPopover/{morphing-popover.module-CgbYV_HS.css → morphing-popover.module-BycNI8nU.css} +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import type { StyleSlots } from '@/core/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Style slots for TextFlow component
|
|
6
|
+
*/
|
|
7
|
+
export type TextFlowSlot = 'root' | 'token' | 'separator' | 'overflow' | 'placeholder';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Base styles for TextFlow component
|
|
11
|
+
*/
|
|
12
|
+
export const textFlowBaseStyles: StyleSlots<TextFlowSlot> = {
|
|
13
|
+
root: 'waapi-animated-tokens-container',
|
|
14
|
+
token: 'waapi-token-wrapper',
|
|
15
|
+
separator: 'waapi-token-separator',
|
|
16
|
+
overflow: 'waapi-token-overflow',
|
|
17
|
+
placeholder: 'waapi-token-placeholder',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* CVA variants for TextFlow root container
|
|
22
|
+
*/
|
|
23
|
+
export const textFlowVariants = cva({
|
|
24
|
+
base: 'waapi-animated-tokens-container',
|
|
25
|
+
variants: {
|
|
26
|
+
inline: {
|
|
27
|
+
true: 'waapi-animated-tokens-container--inline',
|
|
28
|
+
false: '',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
inline: false,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export type TextFlowVariants = VariantProps<typeof textFlowVariants>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Token individual para TextFlow
|
|
5
|
+
*/
|
|
6
|
+
export interface IToken {
|
|
7
|
+
/** Identificador único del token */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Texto a mostrar */
|
|
10
|
+
text: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Modo de transición para cambios de texto en separadores
|
|
15
|
+
*/
|
|
16
|
+
export type SeparatorTransitionMode = 'none' | 'fade' | 'slide';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Tipos de lista para Intl.ListFormat
|
|
20
|
+
*/
|
|
21
|
+
export type ListFormatType = 'conjunction' | 'disjunction' | 'unit';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Estilos de lista para Intl.ListFormat
|
|
25
|
+
*/
|
|
26
|
+
export type ListFormatStyle = 'long' | 'short' | 'narrow';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Configuración de separadores entre tokens
|
|
30
|
+
*/
|
|
31
|
+
export interface ISeparatorConfig {
|
|
32
|
+
/** Texto del separador. Si se omite, usa Intl.ListFormat */
|
|
33
|
+
value?: string;
|
|
34
|
+
/** Locale para Intl.ListFormat */
|
|
35
|
+
locale?: string;
|
|
36
|
+
/** Tipo de lista para Intl.ListFormat */
|
|
37
|
+
listType?: ListFormatType;
|
|
38
|
+
/** Estilo de lista para Intl.ListFormat */
|
|
39
|
+
listStyle?: ListFormatStyle;
|
|
40
|
+
/** Modo de transición cuando el texto del separador cambia */
|
|
41
|
+
transition?: SeparatorTransitionMode;
|
|
42
|
+
/** Duración de la transición en ms */
|
|
43
|
+
duration?: number;
|
|
44
|
+
/** Clase CSS adicional para separadores */
|
|
45
|
+
className?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Configuración del indicador de overflow (+N more)
|
|
50
|
+
*/
|
|
51
|
+
export interface IOverflowConfig {
|
|
52
|
+
/** Prefijo antes del número */
|
|
53
|
+
prefix?: string;
|
|
54
|
+
/** Texto después del número */
|
|
55
|
+
label?: string;
|
|
56
|
+
/** Separador mostrado antes del overflow */
|
|
57
|
+
separator?: string;
|
|
58
|
+
/** Mostrar separador antes del overflow */
|
|
59
|
+
showSeparator?: boolean;
|
|
60
|
+
/** Clase CSS adicional para el overflow */
|
|
61
|
+
className?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Configuración de animación de texto
|
|
66
|
+
*/
|
|
67
|
+
export interface ITextAnimationConfig {
|
|
68
|
+
/** Modo de animación del texto */
|
|
69
|
+
mode?: 'character' | 'word';
|
|
70
|
+
/** Dirección de entrada del texto */
|
|
71
|
+
direction?: 'vertical' | 'horizontal';
|
|
72
|
+
/** Delay entre caracteres/palabras en ms */
|
|
73
|
+
stagger?: number;
|
|
74
|
+
/** Duración de animación en ms */
|
|
75
|
+
duration?: number;
|
|
76
|
+
/** Habilitar efecto blur durante animación */
|
|
77
|
+
blur?: boolean;
|
|
78
|
+
/** Animar cambios de ancho del contenedor */
|
|
79
|
+
widthAnimation?: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Props for TextFlow component
|
|
84
|
+
*
|
|
85
|
+
* TextFlow renders an animated list of tokens with locale-aware separators,
|
|
86
|
+
* smooth FLIP animations, and overflow handling.
|
|
87
|
+
*/
|
|
88
|
+
export interface ITextFlowProps {
|
|
89
|
+
/** Array de tokens a mostrar */
|
|
90
|
+
tokens: IToken[];
|
|
91
|
+
|
|
92
|
+
/** Texto placeholder cuando no hay tokens */
|
|
93
|
+
placeholder?: string;
|
|
94
|
+
|
|
95
|
+
/** Máximo de tokens visibles. El resto se muestra como "+N" */
|
|
96
|
+
maxVisible?: number;
|
|
97
|
+
|
|
98
|
+
/** Configuración de separadores */
|
|
99
|
+
separator?: ISeparatorConfig;
|
|
100
|
+
|
|
101
|
+
/** Configuración del indicador de overflow */
|
|
102
|
+
overflow?: IOverflowConfig;
|
|
103
|
+
|
|
104
|
+
/** Configuración de animación de texto */
|
|
105
|
+
animation?: ITextAnimationConfig;
|
|
106
|
+
|
|
107
|
+
/** Modo inline para uso en botones/selects */
|
|
108
|
+
inline?: boolean;
|
|
109
|
+
|
|
110
|
+
/** Clase CSS para el contenedor principal */
|
|
111
|
+
className?: string;
|
|
112
|
+
|
|
113
|
+
/** Clase CSS para cada token */
|
|
114
|
+
tokenClassName?: string;
|
|
115
|
+
|
|
116
|
+
/** Clase CSS para el placeholder */
|
|
117
|
+
placeholderClassName?: string;
|
|
118
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { useMemo, useCallback } from 'react';
|
|
4
|
+
import { SlidingText } from '@/react-ui/primitives/waapi/SlidingText';
|
|
5
|
+
import { Reorder } from '@/react-ui/primitives/waapi/Reorder';
|
|
6
|
+
import { useListFormat } from '@/react-ui/hooks/Formatting/UseListFormat';
|
|
7
|
+
import type {
|
|
8
|
+
ITextFlowProps,
|
|
9
|
+
IToken,
|
|
10
|
+
ISeparatorConfig,
|
|
11
|
+
IOverflowConfig,
|
|
12
|
+
ITextAnimationConfig,
|
|
13
|
+
SeparatorTransitionMode,
|
|
14
|
+
ListFormatType,
|
|
15
|
+
ListFormatStyle,
|
|
16
|
+
} from './TextFlow.types';
|
|
17
|
+
import { cn } from '@/react-ui/lib/utils';
|
|
18
|
+
|
|
19
|
+
// Default configurations
|
|
20
|
+
const DEFAULT_SEPARATOR: Required<Omit<ISeparatorConfig, 'value' | 'locale' | 'className'>> = {
|
|
21
|
+
listType: 'conjunction',
|
|
22
|
+
listStyle: 'long',
|
|
23
|
+
transition: 'none',
|
|
24
|
+
duration: 200,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const DEFAULT_OVERFLOW: Required<Omit<IOverflowConfig, 'separator' | 'className'>> = {
|
|
28
|
+
prefix: '+',
|
|
29
|
+
label: ' more',
|
|
30
|
+
showSeparator: true,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const DEFAULT_ANIMATION: Required<ITextAnimationConfig> = {
|
|
34
|
+
mode: 'character',
|
|
35
|
+
direction: 'vertical',
|
|
36
|
+
stagger: 15,
|
|
37
|
+
duration: 200,
|
|
38
|
+
blur: true,
|
|
39
|
+
widthAnimation: false,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* TextFlow - Locale-aware animated token list component
|
|
44
|
+
*
|
|
45
|
+
* Built on the Reorder primitive, provides smooth FLIP animations for token lists
|
|
46
|
+
* with proper locale-aware separators using Intl.ListFormat.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* // Basic usage
|
|
51
|
+
* <TextFlow tokens={tokens} />
|
|
52
|
+
*
|
|
53
|
+
* // Spanish multiselect with transition
|
|
54
|
+
* <TextFlow
|
|
55
|
+
* tokens={tokens}
|
|
56
|
+
* maxVisible={2}
|
|
57
|
+
* inline
|
|
58
|
+
* separator={{ locale: 'es', transition: 'fade' }}
|
|
59
|
+
* overflow={{ prefix: '+', label: ' más' }}
|
|
60
|
+
* />
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export const TextFlow: React.FC<ITextFlowProps> = ({
|
|
64
|
+
tokens,
|
|
65
|
+
placeholder = 'No tokens',
|
|
66
|
+
maxVisible,
|
|
67
|
+
separator: separatorConfig,
|
|
68
|
+
overflow: overflowConfig,
|
|
69
|
+
animation: animationConfig,
|
|
70
|
+
inline = false,
|
|
71
|
+
className = '',
|
|
72
|
+
tokenClassName = '',
|
|
73
|
+
placeholderClassName = '',
|
|
74
|
+
}) => {
|
|
75
|
+
// Merge configs with defaults
|
|
76
|
+
const separator: Required<Omit<ISeparatorConfig, 'value' | 'locale' | 'className'>> & Pick<ISeparatorConfig, 'value' | 'locale' | 'className'> = {
|
|
77
|
+
...DEFAULT_SEPARATOR,
|
|
78
|
+
...separatorConfig,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const overflow: Required<Omit<IOverflowConfig, 'separator' | 'className'>> & Pick<IOverflowConfig, 'separator' | 'className'> = {
|
|
82
|
+
...DEFAULT_OVERFLOW,
|
|
83
|
+
...overflowConfig,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const animation: Required<ITextAnimationConfig> = {
|
|
87
|
+
...DEFAULT_ANIMATION,
|
|
88
|
+
...animationConfig,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Track exiting token IDs with REF
|
|
92
|
+
const exitingIdsRef = React.useRef<Set<string>>(new Set());
|
|
93
|
+
|
|
94
|
+
// Visible tokens
|
|
95
|
+
const visibleTokens = useMemo(
|
|
96
|
+
() => (maxVisible ? tokens.slice(0, maxVisible) : tokens),
|
|
97
|
+
[tokens, maxVisible]
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const overflowCount = useMemo(
|
|
101
|
+
() => (maxVisible ? Math.max(0, tokens.length - maxVisible) : 0),
|
|
102
|
+
[tokens.length, maxVisible]
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Locale-aware list formatting via useListFormat hook
|
|
106
|
+
const listParts = useListFormat(
|
|
107
|
+
visibleTokens.map(t => t.text),
|
|
108
|
+
{
|
|
109
|
+
locale: separator.locale,
|
|
110
|
+
type: separator.listType,
|
|
111
|
+
style: separator.listStyle,
|
|
112
|
+
separator: separator.value,
|
|
113
|
+
hasOverflow: overflowCount > 0,
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Separator visibility logic
|
|
118
|
+
const shouldShowSeparator = useCallback((tokenIndex: number): boolean => {
|
|
119
|
+
const isLastToken = tokenIndex >= visibleTokens.length - 1;
|
|
120
|
+
return !isLastToken;
|
|
121
|
+
}, [visibleTokens.length]);
|
|
122
|
+
|
|
123
|
+
const handleItemExit = useCallback((id: string) => {
|
|
124
|
+
exitingIdsRef.current.add(id);
|
|
125
|
+
}, []);
|
|
126
|
+
|
|
127
|
+
const handleItemEnter = useCallback((id: string) => {
|
|
128
|
+
// Animation triggered automatically
|
|
129
|
+
}, []);
|
|
130
|
+
|
|
131
|
+
const showPlaceholder = tokens.length === 0 && !!placeholder;
|
|
132
|
+
|
|
133
|
+
// Build children from list parts
|
|
134
|
+
const tokenElements = useMemo(() => {
|
|
135
|
+
let elementIndex = 0;
|
|
136
|
+
|
|
137
|
+
return listParts.map((part, partIndex) => {
|
|
138
|
+
if (part.type === 'element') {
|
|
139
|
+
const token = visibleTokens[part.index];
|
|
140
|
+
if (!token) return null;
|
|
141
|
+
|
|
142
|
+
const isExiting = exitingIdsRef.current.has(token.id);
|
|
143
|
+
elementIndex++;
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<span
|
|
147
|
+
key={token.id}
|
|
148
|
+
className={cn('waapi-token-wrapper', tokenClassName)}
|
|
149
|
+
data-reorder-id={token.id}
|
|
150
|
+
>
|
|
151
|
+
<SlidingText
|
|
152
|
+
text={token.text}
|
|
153
|
+
mode={isExiting ? 'none' : animation.mode}
|
|
154
|
+
direction={animation.direction}
|
|
155
|
+
staggerDelay={animation.stagger}
|
|
156
|
+
duration={animation.duration}
|
|
157
|
+
blur={animation.blur}
|
|
158
|
+
widthAnimation={!isExiting && animation.widthAnimation}
|
|
159
|
+
initial={isExiting ? false : 'initial'}
|
|
160
|
+
animate="animate"
|
|
161
|
+
/>
|
|
162
|
+
</span>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Separator (literal)
|
|
167
|
+
const prevToken = visibleTokens[part.index];
|
|
168
|
+
if (!prevToken) return null;
|
|
169
|
+
|
|
170
|
+
const tokenIndex = part.index;
|
|
171
|
+
const showSep = shouldShowSeparator(tokenIndex);
|
|
172
|
+
|
|
173
|
+
if (!showSep) return null;
|
|
174
|
+
|
|
175
|
+
const separatorKey = `sep-${prevToken.id}`;
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<span
|
|
179
|
+
key={separatorKey}
|
|
180
|
+
className={cn('waapi-token-separator', separator.className ?? '')}
|
|
181
|
+
>
|
|
182
|
+
{part.value}
|
|
183
|
+
</span>
|
|
184
|
+
);
|
|
185
|
+
}).filter(Boolean);
|
|
186
|
+
}, [listParts, visibleTokens, tokenClassName, animation, separator, shouldShowSeparator]);
|
|
187
|
+
|
|
188
|
+
// Overflow element
|
|
189
|
+
const overflowElement = useMemo(() => {
|
|
190
|
+
if (overflowCount === 0) return null;
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<div
|
|
194
|
+
key="overflow-counter"
|
|
195
|
+
data-reorder-id="overflow-counter"
|
|
196
|
+
className={cn('waapi-token-overflow', overflow.className ?? '')}
|
|
197
|
+
>
|
|
198
|
+
{overflow.showSeparator && overflow.separator && (
|
|
199
|
+
<span className={cn('waapi-token-separator', separator.className ?? '')}>
|
|
200
|
+
{overflow.separator}
|
|
201
|
+
</span>
|
|
202
|
+
)}
|
|
203
|
+
{overflow.prefix !== '' && (
|
|
204
|
+
<span className={cn('waapi-token-separator', separator.className ?? '')}>
|
|
205
|
+
{overflow.prefix}
|
|
206
|
+
</span>
|
|
207
|
+
)}
|
|
208
|
+
<SlidingText
|
|
209
|
+
text={String(overflowCount)}
|
|
210
|
+
mode="character"
|
|
211
|
+
duration={animation.duration}
|
|
212
|
+
blur={animation.blur}
|
|
213
|
+
initial="initial"
|
|
214
|
+
animate="animate"
|
|
215
|
+
/>
|
|
216
|
+
{overflow.label && overflow.label !== '' && (
|
|
217
|
+
<SlidingText
|
|
218
|
+
text={overflow.label}
|
|
219
|
+
mode={animation.mode}
|
|
220
|
+
direction={animation.direction}
|
|
221
|
+
staggerDelay={animation.stagger}
|
|
222
|
+
duration={animation.duration}
|
|
223
|
+
blur={animation.blur}
|
|
224
|
+
initial="initial"
|
|
225
|
+
animate="animate"
|
|
226
|
+
/>
|
|
227
|
+
)}
|
|
228
|
+
</div>
|
|
229
|
+
);
|
|
230
|
+
}, [overflowCount, overflow, separator, animation]);
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<div
|
|
234
|
+
role="text"
|
|
235
|
+
className={cn(
|
|
236
|
+
'waapi-animated-tokens-container',
|
|
237
|
+
inline && 'waapi-animated-tokens-container--inline',
|
|
238
|
+
className
|
|
239
|
+
)}
|
|
240
|
+
>
|
|
241
|
+
{showPlaceholder && (
|
|
242
|
+
<SlidingText
|
|
243
|
+
key="placeholder"
|
|
244
|
+
text={placeholder}
|
|
245
|
+
mode="word"
|
|
246
|
+
direction="vertical"
|
|
247
|
+
blur={true}
|
|
248
|
+
duration={150}
|
|
249
|
+
initial="initial"
|
|
250
|
+
animate="animate"
|
|
251
|
+
className={cn('waapi-token-placeholder', placeholderClassName)}
|
|
252
|
+
/>
|
|
253
|
+
)}
|
|
254
|
+
|
|
255
|
+
<Reorder
|
|
256
|
+
layout={inline ? 'inline-horizontal' : 'horizontal'}
|
|
257
|
+
onItemExit={handleItemExit}
|
|
258
|
+
onItemEnter={handleItemEnter}
|
|
259
|
+
>
|
|
260
|
+
{tokenElements}
|
|
261
|
+
{overflowElement}
|
|
262
|
+
</Reorder>
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
TextFlow.displayName = 'TextFlow';
|
|
268
|
+
|
|
269
|
+
export type {
|
|
270
|
+
ITextFlowProps,
|
|
271
|
+
IToken,
|
|
272
|
+
ISeparatorConfig,
|
|
273
|
+
IOverflowConfig,
|
|
274
|
+
ITextAnimationConfig,
|
|
275
|
+
SeparatorTransitionMode,
|
|
276
|
+
};
|
package/src/react-ui/ui/index.ts
CHANGED