@udixio/ui-react 2.10.12 → 2.10.14
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/index.cjs +3 -3
- package/dist/index.js +2696 -2710
- package/dist/lib/effects/ThemeProvider.d.ts.map +1 -1
- package/dist/theme.worker.js +6633 -0
- package/package.json +4 -1
- package/.eslintrc.mjs +0 -22
- package/.storybook/main.ts +0 -20
- package/.storybook/preview.ts +0 -1
- package/CHANGELOG.md +0 -1130
- package/dist/scrollDriven-AP2yWhzi.js +0 -121
- package/postcss.config.mjs +0 -5
- package/src/index.css +0 -4
- package/src/index.ts +0 -1
- package/src/lib/components/AnchorPositioner.tsx +0 -185
- package/src/lib/components/Button.tsx +0 -208
- package/src/lib/components/Card.tsx +0 -47
- package/src/lib/components/Carousel.tsx +0 -437
- package/src/lib/components/CarouselItem.tsx +0 -61
- package/src/lib/components/Checkbox.tsx +0 -120
- package/src/lib/components/Chip.tsx +0 -341
- package/src/lib/components/Chips.tsx +0 -331
- package/src/lib/components/ContextMenu.tsx +0 -109
- package/src/lib/components/DatePicker.tsx +0 -432
- package/src/lib/components/Divider.tsx +0 -20
- package/src/lib/components/Fab.tsx +0 -127
- package/src/lib/components/FabMenu.tsx +0 -239
- package/src/lib/components/IconButton.tsx +0 -146
- package/src/lib/components/Menu.tsx +0 -88
- package/src/lib/components/MenuGroup.tsx +0 -34
- package/src/lib/components/MenuHeadline.tsx +0 -9
- package/src/lib/components/MenuItem.tsx +0 -215
- package/src/lib/components/NavigationRail.tsx +0 -186
- package/src/lib/components/NavigationRailItem.tsx +0 -227
- package/src/lib/components/ProgressIndicator.tsx +0 -214
- package/src/lib/components/SideSheet.tsx +0 -135
- package/src/lib/components/Slider.tsx +0 -374
- package/src/lib/components/Snackbar.tsx +0 -77
- package/src/lib/components/Switch.tsx +0 -107
- package/src/lib/components/Tab.tsx +0 -123
- package/src/lib/components/TabGroup.tsx +0 -66
- package/src/lib/components/TabGroupContext.tsx +0 -16
- package/src/lib/components/TabPanel.tsx +0 -27
- package/src/lib/components/TabPanels.tsx +0 -76
- package/src/lib/components/Tabs.tsx +0 -105
- package/src/lib/components/TextField.tsx +0 -586
- package/src/lib/components/Tooltip.tsx +0 -217
- package/src/lib/components/index.ts +0 -34
- package/src/lib/config/config.interface.ts +0 -9
- package/src/lib/config/define-config.ts +0 -16
- package/src/lib/config/index.ts +0 -2
- package/src/lib/effects/AnimateOnScroll.ts +0 -391
- package/src/lib/effects/State.tsx +0 -90
- package/src/lib/effects/SyncedFixedWrapper.tsx +0 -62
- package/src/lib/effects/ThemeProvider.tsx +0 -172
- package/src/lib/effects/block-scroll.effect.tsx +0 -313
- package/src/lib/effects/custom-scroll/custom-scroll.effect.tsx +0 -407
- package/src/lib/effects/custom-scroll/custom-scroll.interface.ts +0 -29
- package/src/lib/effects/custom-scroll/custom-scroll.style.ts +0 -32
- package/src/lib/effects/custom-scroll/index.ts +0 -3
- package/src/lib/effects/index.ts +0 -7
- package/src/lib/effects/ripple/RippleEffect.tsx +0 -116
- package/src/lib/effects/ripple/index.tsx +0 -1
- package/src/lib/effects/scrollDriven.ts +0 -239
- package/src/lib/effects/smooth-scroll.effect.tsx +0 -112
- package/src/lib/effects/theme.worker.ts +0 -97
- package/src/lib/hooks/index.ts +0 -10
- package/src/lib/hooks/useTooltipTrigger.ts +0 -270
- package/src/lib/icon/icon.tsx +0 -125
- package/src/lib/icon/index.ts +0 -1
- package/src/lib/index.ts +0 -8
- package/src/lib/interfaces/button.interface.ts +0 -65
- package/src/lib/interfaces/card.interface.ts +0 -11
- package/src/lib/interfaces/carousel-item.interface.ts +0 -12
- package/src/lib/interfaces/carousel.interface.ts +0 -41
- package/src/lib/interfaces/checkbox.interface.ts +0 -39
- package/src/lib/interfaces/chip.interface.ts +0 -97
- package/src/lib/interfaces/chips.interface.ts +0 -37
- package/src/lib/interfaces/date-picker.interface.ts +0 -79
- package/src/lib/interfaces/divider.interface.ts +0 -7
- package/src/lib/interfaces/fab-menu.interface.ts +0 -12
- package/src/lib/interfaces/fab.interface.ts +0 -27
- package/src/lib/interfaces/icon-button.interface.ts +0 -38
- package/src/lib/interfaces/index.ts +0 -26
- package/src/lib/interfaces/menu-group.interface.ts +0 -13
- package/src/lib/interfaces/menu-item.interface.ts +0 -29
- package/src/lib/interfaces/menu.interface.ts +0 -19
- package/src/lib/interfaces/navigation-rail-item.interface.ts +0 -39
- package/src/lib/interfaces/navigation-rail.interface.ts +0 -39
- package/src/lib/interfaces/progress-indicator.interface.ts +0 -41
- package/src/lib/interfaces/side-sheet.interface.tsx +0 -28
- package/src/lib/interfaces/slider.interface.ts +0 -27
- package/src/lib/interfaces/snackbar.interface.ts +0 -13
- package/src/lib/interfaces/switch.interface.ts +0 -14
- package/src/lib/interfaces/tab-group.interface.ts +0 -13
- package/src/lib/interfaces/tab-panels.interface.ts +0 -21
- package/src/lib/interfaces/tab.interface.ts +0 -31
- package/src/lib/interfaces/tabs.interface.ts +0 -22
- package/src/lib/interfaces/text-field.interface.ts +0 -61
- package/src/lib/interfaces/tooltip.interface.ts +0 -61
- package/src/lib/styles/button.style.ts +0 -136
- package/src/lib/styles/card.style.ts +0 -29
- package/src/lib/styles/carousel-item.style.ts +0 -24
- package/src/lib/styles/carousel.style.ts +0 -22
- package/src/lib/styles/checkbox.style.ts +0 -64
- package/src/lib/styles/chip.style.ts +0 -62
- package/src/lib/styles/chips.style.ts +0 -20
- package/src/lib/styles/date-picker.style.ts +0 -43
- package/src/lib/styles/divider.style.ts +0 -31
- package/src/lib/styles/fab-menu.style.ts +0 -29
- package/src/lib/styles/fab.style.ts +0 -49
- package/src/lib/styles/icon-button.style.ts +0 -168
- package/src/lib/styles/index.ts +0 -25
- package/src/lib/styles/menu-group.style.ts +0 -34
- package/src/lib/styles/menu-headline.style.ts +0 -20
- package/src/lib/styles/menu-item.style.ts +0 -45
- package/src/lib/styles/menu.style.ts +0 -32
- package/src/lib/styles/navigation-rail-item.style.ts +0 -56
- package/src/lib/styles/navigation-rail.style.ts +0 -36
- package/src/lib/styles/progress-indicator.style.ts +0 -72
- package/src/lib/styles/side-sheet.style.ts +0 -45
- package/src/lib/styles/slider.style.ts +0 -41
- package/src/lib/styles/snackbar.style.ts +0 -26
- package/src/lib/styles/switch.style.ts +0 -67
- package/src/lib/styles/tab-panels.style.ts +0 -35
- package/src/lib/styles/tab.style.ts +0 -78
- package/src/lib/styles/tabs.style.ts +0 -22
- package/src/lib/styles/text-field.style.ts +0 -115
- package/src/lib/styles/tooltip.style.ts +0 -48
- package/src/lib/utils/component-helper.ts +0 -134
- package/src/lib/utils/component.ts +0 -34
- package/src/lib/utils/index.ts +0 -7
- package/src/lib/utils/string.ts +0 -9
- package/src/lib/utils/styles/classnames.ts +0 -49
- package/src/lib/utils/styles/get-classname.ts +0 -96
- package/src/lib/utils/styles/index.ts +0 -4
- package/src/lib/utils/styles/use-classnames.ts +0 -25
- package/src/stories/action/button.stories.tsx +0 -86
- package/src/stories/action/fab.stories.tsx +0 -54
- package/src/stories/action/icon-button.stories.tsx +0 -134
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +0 -5
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +0 -15
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +0 -3
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +0 -12
- package/src/stories/assets/youtube.svg +0 -4
- package/src/stories/communication/ProgressIndicator.stories.tsx +0 -57
- package/src/stories/communication/SnackBar.stories.tsx +0 -32
- package/src/stories/communication/tool-tip.stories.tsx +0 -133
- package/src/stories/containment/card.stories.tsx +0 -42
- package/src/stories/containment/carousel.stories.tsx +0 -65
- package/src/stories/containment/divider.stories.tsx +0 -35
- package/src/stories/containment/slide-sheet.stories.tsx +0 -45
- package/src/stories/effect/smooth-scroll.stories.tsx +0 -54
- package/src/stories/navigation/navigation-rail/navigation-rail-item.stories.tsx +0 -65
- package/src/stories/navigation/navigation-rail/navigation-rail.stories.tsx +0 -122
- package/src/stories/navigation/tabs/tab.stories.tsx +0 -57
- package/src/stories/navigation/tabs/tabs.stories.tsx +0 -102
- package/src/stories/selection/slider.stories.tsx +0 -85
- package/src/stories/selection/switch.stories.tsx +0 -46
- package/src/stories/text-inputs/text-field.stories.tsx +0 -135
- package/src/tests/Button.spec.tsx +0 -67
- package/src/tests/useClassNames.spec.tsx +0 -82
- package/src/udixio.css +0 -120
- package/theme.config.ts +0 -7
- package/tsconfig.json +0 -16
- package/tsconfig.lib.json +0 -51
- package/tsconfig.spec.json +0 -37
- package/tsconfig.storybook.json +0 -38
- package/vite.config.ts +0 -82
- /package/dist/{scrollDriven-DWAu7CR0.cjs → scrollDriven.js} +0 -0
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import { cloneElement, isValidElement, useEffect, useRef } from 'react';
|
|
2
|
-
import { MotionProps } from '../utils';
|
|
3
|
-
import { Button } from './Button';
|
|
4
|
-
import { AnchorPositioner } from './AnchorPositioner';
|
|
5
|
-
import { ToolTipInterface } from '../interfaces';
|
|
6
|
-
import { useToolTipStyle } from '../styles';
|
|
7
|
-
import { AnimatePresence, motion } from 'motion/react';
|
|
8
|
-
import { useTooltipTrigger } from '../hooks';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Tooltips display brief labels or messages
|
|
12
|
-
* @status beta
|
|
13
|
-
* @category Communication
|
|
14
|
-
* @devx
|
|
15
|
-
* - `content` overrides `title`/`text`/`buttons` for fully custom content.
|
|
16
|
-
* - Supports controlled `isOpen` plus `openDelay`/`closeDelay`.
|
|
17
|
-
* @a11y
|
|
18
|
-
* - Provides `role="tooltip"` and `aria-describedby` when open.
|
|
19
|
-
*/
|
|
20
|
-
export const Tooltip = ({
|
|
21
|
-
variant = 'plain',
|
|
22
|
-
buttons,
|
|
23
|
-
className,
|
|
24
|
-
children,
|
|
25
|
-
title,
|
|
26
|
-
text,
|
|
27
|
-
content,
|
|
28
|
-
position: positionProp,
|
|
29
|
-
targetRef,
|
|
30
|
-
ref,
|
|
31
|
-
trigger = ['hover', 'focus'],
|
|
32
|
-
transition,
|
|
33
|
-
openDelay = 400,
|
|
34
|
-
closeDelay = 150,
|
|
35
|
-
isOpen: isOpenProp,
|
|
36
|
-
defaultOpen = false,
|
|
37
|
-
onOpenChange,
|
|
38
|
-
id,
|
|
39
|
-
anchorRef,
|
|
40
|
-
...props
|
|
41
|
-
}: MotionProps<ToolTipInterface>) => {
|
|
42
|
-
const defaultPosition = variant === 'rich' ? 'bottom-right' : 'bottom';
|
|
43
|
-
const effectivePosition = positionProp || defaultPosition;
|
|
44
|
-
|
|
45
|
-
transition = { duration: 0.3, ...transition };
|
|
46
|
-
|
|
47
|
-
if (!children && !targetRef) {
|
|
48
|
-
throw new Error('Tooltip must have a child or a targetRef');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (buttons && !Array.isArray(buttons)) {
|
|
52
|
-
buttons = [buttons];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const internalRef = useRef<HTMLElement | null>(null);
|
|
56
|
-
const resolvedRef = targetRef || internalRef;
|
|
57
|
-
const positioningRef = anchorRef || resolvedRef;
|
|
58
|
-
|
|
59
|
-
// Use the trigger hook for state management and accessibility
|
|
60
|
-
const { triggerProps, tooltipProps, isOpen } = useTooltipTrigger({
|
|
61
|
-
trigger,
|
|
62
|
-
isOpen: isOpenProp,
|
|
63
|
-
defaultOpen,
|
|
64
|
-
onOpenChange,
|
|
65
|
-
openDelay,
|
|
66
|
-
closeDelay,
|
|
67
|
-
id,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Apply trigger props to the target element
|
|
71
|
-
const enhancedChildren =
|
|
72
|
-
!targetRef && isValidElement(children)
|
|
73
|
-
? cloneElement(children, {
|
|
74
|
-
ref: internalRef,
|
|
75
|
-
...triggerProps,
|
|
76
|
-
// Merge event handlers if the child already has them
|
|
77
|
-
onMouseEnter: (e: React.MouseEvent) => {
|
|
78
|
-
triggerProps.onMouseEnter();
|
|
79
|
-
(children.props as any)?.onMouseEnter?.(e);
|
|
80
|
-
},
|
|
81
|
-
onMouseLeave: (e: React.MouseEvent) => {
|
|
82
|
-
triggerProps.onMouseLeave();
|
|
83
|
-
(children.props as any)?.onMouseLeave?.(e);
|
|
84
|
-
},
|
|
85
|
-
onFocus: (e: React.FocusEvent) => {
|
|
86
|
-
triggerProps.onFocus();
|
|
87
|
-
(children.props as any)?.onFocus?.(e);
|
|
88
|
-
},
|
|
89
|
-
onBlur: (e: React.FocusEvent) => {
|
|
90
|
-
triggerProps.onBlur();
|
|
91
|
-
(children.props as any)?.onBlur?.(e);
|
|
92
|
-
},
|
|
93
|
-
onClick: (e: React.MouseEvent) => {
|
|
94
|
-
triggerProps.onClick();
|
|
95
|
-
(children.props as any)?.onClick?.(e);
|
|
96
|
-
},
|
|
97
|
-
onKeyDown: (e: React.KeyboardEvent) => {
|
|
98
|
-
triggerProps.onKeyDown(e);
|
|
99
|
-
(children.props as any)?.onKeyDown?.(e);
|
|
100
|
-
},
|
|
101
|
-
} as any)
|
|
102
|
-
: children;
|
|
103
|
-
|
|
104
|
-
// Attach trigger handlers when using targetRef (no direct child to clone)
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
if (!targetRef) return;
|
|
107
|
-
const element = targetRef.current;
|
|
108
|
-
if (!element) return;
|
|
109
|
-
|
|
110
|
-
const handleMouseEnter = () => triggerProps.onMouseEnter();
|
|
111
|
-
const handleMouseLeave = () => triggerProps.onMouseLeave();
|
|
112
|
-
const handleFocus = () => triggerProps.onFocus();
|
|
113
|
-
const handleBlur = () => triggerProps.onBlur();
|
|
114
|
-
const handleClick = () => triggerProps.onClick();
|
|
115
|
-
const handleKeyDown = (event: KeyboardEvent) =>
|
|
116
|
-
triggerProps.onKeyDown(event as unknown as React.KeyboardEvent);
|
|
117
|
-
|
|
118
|
-
element.addEventListener('mouseenter', handleMouseEnter);
|
|
119
|
-
element.addEventListener('mouseleave', handleMouseLeave);
|
|
120
|
-
element.addEventListener('focus', handleFocus, true);
|
|
121
|
-
element.addEventListener('blur', handleBlur, true);
|
|
122
|
-
element.addEventListener('click', handleClick);
|
|
123
|
-
element.addEventListener('keydown', handleKeyDown);
|
|
124
|
-
|
|
125
|
-
if (triggerProps['aria-describedby']) {
|
|
126
|
-
element.setAttribute(
|
|
127
|
-
'aria-describedby',
|
|
128
|
-
triggerProps['aria-describedby'],
|
|
129
|
-
);
|
|
130
|
-
} else {
|
|
131
|
-
element.removeAttribute('aria-describedby');
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return () => {
|
|
135
|
-
element.removeEventListener('mouseenter', handleMouseEnter);
|
|
136
|
-
element.removeEventListener('mouseleave', handleMouseLeave);
|
|
137
|
-
element.removeEventListener('focus', handleFocus, true);
|
|
138
|
-
element.removeEventListener('blur', handleBlur, true);
|
|
139
|
-
element.removeEventListener('click', handleClick);
|
|
140
|
-
element.removeEventListener('keydown', handleKeyDown);
|
|
141
|
-
};
|
|
142
|
-
}, [targetRef, triggerProps]);
|
|
143
|
-
|
|
144
|
-
const styles = useToolTipStyle({
|
|
145
|
-
variant,
|
|
146
|
-
buttons,
|
|
147
|
-
className,
|
|
148
|
-
title,
|
|
149
|
-
text,
|
|
150
|
-
position: effectivePosition,
|
|
151
|
-
trigger,
|
|
152
|
-
targetRef: targetRef as any,
|
|
153
|
-
children: children as any,
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
const variants = {
|
|
157
|
-
open: {
|
|
158
|
-
opacity: 1,
|
|
159
|
-
height: 'auto',
|
|
160
|
-
},
|
|
161
|
-
close: {
|
|
162
|
-
opacity: 0,
|
|
163
|
-
height: 16,
|
|
164
|
-
},
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
return (
|
|
168
|
-
<>
|
|
169
|
-
{enhancedChildren}
|
|
170
|
-
<AnimatePresence>
|
|
171
|
-
{isOpen && (
|
|
172
|
-
<AnchorPositioner
|
|
173
|
-
anchorRef={positioningRef}
|
|
174
|
-
position={effectivePosition}
|
|
175
|
-
>
|
|
176
|
-
<motion.div
|
|
177
|
-
initial={'close'}
|
|
178
|
-
variants={variants}
|
|
179
|
-
animate={'open'}
|
|
180
|
-
transition={{ duration: transition.duration }}
|
|
181
|
-
exit={'close'}
|
|
182
|
-
className={styles.toolTip}
|
|
183
|
-
{...props}
|
|
184
|
-
{...tooltipProps}
|
|
185
|
-
>
|
|
186
|
-
<div className={styles.container}>
|
|
187
|
-
{content ? (
|
|
188
|
-
<div className={styles.content}>{content}</div>
|
|
189
|
-
) : (
|
|
190
|
-
<>
|
|
191
|
-
{title && <div className={styles.subHead}>{title}</div>}
|
|
192
|
-
{text && (
|
|
193
|
-
<div className={styles.supportingText}>{text}</div>
|
|
194
|
-
)}
|
|
195
|
-
{buttons && (
|
|
196
|
-
<div className={styles.actions}>
|
|
197
|
-
{Array.isArray(buttons) &&
|
|
198
|
-
buttons.map((buttonArgs, index) => (
|
|
199
|
-
<Button
|
|
200
|
-
key={index}
|
|
201
|
-
size={'small'}
|
|
202
|
-
variant={'text'}
|
|
203
|
-
{...buttonArgs}
|
|
204
|
-
/>
|
|
205
|
-
))}
|
|
206
|
-
</div>
|
|
207
|
-
)}
|
|
208
|
-
</>
|
|
209
|
-
)}
|
|
210
|
-
</div>
|
|
211
|
-
</motion.div>
|
|
212
|
-
</AnchorPositioner>
|
|
213
|
-
)}
|
|
214
|
-
</AnimatePresence>
|
|
215
|
-
</>
|
|
216
|
-
);
|
|
217
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export * from './AnchorPositioner';
|
|
3
|
-
export * from './Button';
|
|
4
|
-
export * from './Card';
|
|
5
|
-
export * from './Card';
|
|
6
|
-
export * from './Carousel';
|
|
7
|
-
export * from './CarouselItem';
|
|
8
|
-
export * from './Checkbox';
|
|
9
|
-
export * from './Chip';
|
|
10
|
-
export * from './ContextMenu';
|
|
11
|
-
export * from './Chips';
|
|
12
|
-
export * from './Divider';
|
|
13
|
-
export * from './Fab';
|
|
14
|
-
export * from './FabMenu';
|
|
15
|
-
export * from './IconButton';
|
|
16
|
-
export * from './Menu';
|
|
17
|
-
export * from './MenuItem';
|
|
18
|
-
export * from './MenuGroup';
|
|
19
|
-
export * from './MenuHeadline';
|
|
20
|
-
export * from './ProgressIndicator';
|
|
21
|
-
export * from './Slider';
|
|
22
|
-
export * from './SideSheet';
|
|
23
|
-
export * from './Snackbar';
|
|
24
|
-
export * from './Switch';
|
|
25
|
-
export * from './Tab';
|
|
26
|
-
export * from './Tabs';
|
|
27
|
-
export * from './TabGroup';
|
|
28
|
-
export * from './TabPanels';
|
|
29
|
-
export * from './TabPanel';
|
|
30
|
-
export * from './TextField';
|
|
31
|
-
export * from './NavigationRailItem';
|
|
32
|
-
export * from './NavigationRail';
|
|
33
|
-
export * from './Tooltip';
|
|
34
|
-
export * from './DatePicker';
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ConfigInterface as ConfigTheme,
|
|
3
|
-
FontPluginOptions,
|
|
4
|
-
} from '@udixio/theme';
|
|
5
|
-
import { TailwindPluginOptions } from '@udixio/tailwind';
|
|
6
|
-
|
|
7
|
-
export type ConfigInterface = Omit<ConfigTheme, 'plugins' | 'isDark'> &
|
|
8
|
-
TailwindPluginOptions &
|
|
9
|
-
FontPluginOptions;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { ConfigInterface } from './config.interface';
|
|
2
|
-
import {
|
|
3
|
-
ConfigInterface as ConfigTheme,
|
|
4
|
-
defineConfig as defineConfigTheme,
|
|
5
|
-
FontPlugin,
|
|
6
|
-
Variants,
|
|
7
|
-
} from '@udixio/theme';
|
|
8
|
-
import { TailwindPlugin } from '@udixio/tailwind';
|
|
9
|
-
|
|
10
|
-
export function defineConfig(configObject: ConfigInterface): ConfigTheme {
|
|
11
|
-
return defineConfigTheme({
|
|
12
|
-
variant: Variants.Udixio,
|
|
13
|
-
...configObject,
|
|
14
|
-
plugins: [new FontPlugin(configObject), new TailwindPlugin(configObject)],
|
|
15
|
-
});
|
|
16
|
-
}
|
package/src/lib/config/index.ts
DELETED
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
// Simple script initializer (no React component)
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* AnimateOnScroll
|
|
5
|
-
*
|
|
6
|
-
* Manages triggers for animations:
|
|
7
|
-
* - ScrollDriven animations: use native CSS if supported; otherwise import JS fallback per element set.
|
|
8
|
-
* - Other entry/exit animations: handled via IntersectionObserver in JS.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
function supportsScrollTimeline(): boolean {
|
|
12
|
-
if (typeof window === `undefined`) return false;
|
|
13
|
-
try {
|
|
14
|
-
// @ts-ignore - CSS may not exist in TS lib
|
|
15
|
-
if (window.CSS && typeof window.CSS.supports === `function`) {
|
|
16
|
-
// @ts-ignore
|
|
17
|
-
return (
|
|
18
|
-
CSS.supports(`animation-timeline: view()`) ||
|
|
19
|
-
CSS.supports(`animation-timeline: scroll()`) ||
|
|
20
|
-
// some older implementations used view-timeline-name
|
|
21
|
-
CSS.supports(`view-timeline-name: --a`)
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
} catch {}
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function prefersReducedMotion(): boolean {
|
|
29
|
-
if (typeof window === `undefined` || !(`matchMedia` in window)) return false;
|
|
30
|
-
return window.matchMedia(`(prefers-reduced-motion: reduce)`).matches;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function isScrollDrivenCandidate(el: Element): boolean {
|
|
34
|
-
if (!(el instanceof HTMLElement)) return false;
|
|
35
|
-
const cls = el.classList;
|
|
36
|
-
|
|
37
|
-
return Array.from(cls).some(
|
|
38
|
-
(className) =>
|
|
39
|
-
className.startsWith('anim-') && className.includes('scroll'),
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
function isJsObserverCandidate(el: Element): boolean {
|
|
43
|
-
if (!(el instanceof HTMLElement)) return false;
|
|
44
|
-
const cls = el.classList;
|
|
45
|
-
|
|
46
|
-
return Array.from(cls).some((className) => className.startsWith('anim-'));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function hydrateElement(el: HTMLElement, prefix: string): void {
|
|
50
|
-
if (!isScrollDrivenCandidate(el)) return;
|
|
51
|
-
|
|
52
|
-
// Map data-anim-scroll to correct axis class if provided
|
|
53
|
-
if (el.hasAttribute(`data-${prefix}-scroll`)) {
|
|
54
|
-
const raw = (el.getAttribute(`data-${prefix}-scroll`) || ``)
|
|
55
|
-
.trim()
|
|
56
|
-
.toLowerCase();
|
|
57
|
-
const axis =
|
|
58
|
-
raw === `x` || raw === `inline`
|
|
59
|
-
? `inline`
|
|
60
|
-
: raw === `y` || raw === `block`
|
|
61
|
-
? `block`
|
|
62
|
-
: `auto`;
|
|
63
|
-
const hasAny =
|
|
64
|
-
el.classList.contains(`${prefix}-timeline`) ||
|
|
65
|
-
el.classList.contains(`${prefix}-timeline-inline`) ||
|
|
66
|
-
el.classList.contains(`${prefix}-timeline-block`) ||
|
|
67
|
-
el.classList.contains(`${prefix}-timeline-x`) ||
|
|
68
|
-
el.classList.contains(`${prefix}-timeline-y`);
|
|
69
|
-
if (!hasAny) {
|
|
70
|
-
if (axis === `inline`) el.classList.add(`${prefix}-timeline-inline`);
|
|
71
|
-
else if (axis === `block`) el.classList.add(`${prefix}-timeline-block`);
|
|
72
|
-
else el.classList.add(`${prefix}-scroll`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Offsets via data-anim-start / data-anim-end (accepts tokens like "entry 20%", "cover 50%", etc.)
|
|
77
|
-
const start = el.getAttribute(`data-${prefix}-start`);
|
|
78
|
-
if (start) el.style.setProperty(`--${prefix}-range-start`, start);
|
|
79
|
-
const end = el.getAttribute(`data-${prefix}-end`);
|
|
80
|
-
if (end) el.style.setProperty(`--${prefix}-range-end`, end);
|
|
81
|
-
|
|
82
|
-
// Ensure play state is running unless explicitly paused
|
|
83
|
-
const explicitlyPaused =
|
|
84
|
-
el.hasAttribute(`data-${prefix}-paused`) ||
|
|
85
|
-
el.classList.contains(`${prefix}-paused`);
|
|
86
|
-
const alreadyRunning =
|
|
87
|
-
el.hasAttribute(`data-${prefix}-run`) ||
|
|
88
|
-
el.classList.contains(`${prefix}-run`);
|
|
89
|
-
if (!explicitlyPaused && !alreadyRunning) {
|
|
90
|
-
el.setAttribute(`data-${prefix}-run`, ``);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function queryScrollDrivenCandidates(
|
|
95
|
-
root: ParentNode = document,
|
|
96
|
-
prefix: string,
|
|
97
|
-
): HTMLElement[] {
|
|
98
|
-
// Select any elements that have an animation class and are marked as scroll-driven
|
|
99
|
-
const animated = Array.from(
|
|
100
|
-
root.querySelectorAll<HTMLElement>(
|
|
101
|
-
`[class*="${prefix}-"][class*="-scroll"]`,
|
|
102
|
-
),
|
|
103
|
-
);
|
|
104
|
-
return animated.filter((el) => isScrollDrivenCandidate(el));
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function queryJsObserverCandidates(
|
|
108
|
-
root: ParentNode = document,
|
|
109
|
-
prefix: string,
|
|
110
|
-
): HTMLElement[] {
|
|
111
|
-
// Observe any element that has `${prefix}-in` or `${prefix}-out` even if it's scroll-driven.
|
|
112
|
-
// Additionally, observe elements that have at least one non-scroll `${prefix}-*` class
|
|
113
|
-
// (e.g., `anim-fade`, `anim-scale-150`) even if they also include scroll-driven classes.
|
|
114
|
-
// This ensures default IN animations are triggered.
|
|
115
|
-
const animated = Array.from(
|
|
116
|
-
root.querySelectorAll<HTMLElement>(`[class*="${prefix}-"]`),
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
const reserved = new Set([
|
|
120
|
-
`${prefix}-run`,
|
|
121
|
-
`${prefix}-in`,
|
|
122
|
-
`${prefix}-out`,
|
|
123
|
-
`${prefix}-in-run`,
|
|
124
|
-
`${prefix}-out-run`,
|
|
125
|
-
`${prefix}-paused`,
|
|
126
|
-
`${prefix}-timeline`,
|
|
127
|
-
`${prefix}-timeline-inline`,
|
|
128
|
-
`${prefix}-timeline-block`,
|
|
129
|
-
`${prefix}-timeline-x`,
|
|
130
|
-
`${prefix}-timeline-y`,
|
|
131
|
-
`${prefix}-scroll`,
|
|
132
|
-
]);
|
|
133
|
-
|
|
134
|
-
return animated.filter((el) => {
|
|
135
|
-
if (!(el instanceof HTMLElement)) return false;
|
|
136
|
-
const cls = el.classList;
|
|
137
|
-
const hasInOut =
|
|
138
|
-
cls.contains(`${prefix}-in`) || cls.contains(`${prefix}-out`);
|
|
139
|
-
if (hasInOut) return true;
|
|
140
|
-
|
|
141
|
-
// Check if element has any non-scroll animation class (not in reserved set and not containing "scroll")
|
|
142
|
-
const hasNonScrollAnim = Array.from(cls).some(
|
|
143
|
-
(c) =>
|
|
144
|
-
c.startsWith(`${prefix}-`) && !c.includes('scroll') && !reserved.has(c),
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
if (hasNonScrollAnim) return true;
|
|
148
|
-
|
|
149
|
-
// Otherwise only observe if it's not scroll-driven at all
|
|
150
|
-
return !isScrollDrivenCandidate(el);
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Utility: identify presence of in/out classes
|
|
155
|
-
function hasOutClass(cls: DOMTokenList, prefix: string): boolean {
|
|
156
|
-
return Array.from(cls).some(
|
|
157
|
-
(className) => className.startsWith(prefix) && className.includes('-out'),
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
// Utility: set run flags for a given direction ("in" or "out"), always ensuring generic run flag exists
|
|
161
|
-
function setRunFlag(el: HTMLElement, prefix: string, dir: 'in' | 'out'): void {
|
|
162
|
-
el.setAttribute(`data-${prefix}-run`, ``);
|
|
163
|
-
el.setAttribute(`data-${prefix}-${dir}-run`, ``);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Utility: reset run flags and restart animation timeline without changing computed styles
|
|
167
|
-
function resetRunFlags(
|
|
168
|
-
el: HTMLElement,
|
|
169
|
-
prefix: string,
|
|
170
|
-
direction?: 'in' | 'out',
|
|
171
|
-
): void {
|
|
172
|
-
const currentAnimationName = el.style.animationName;
|
|
173
|
-
el.style.animationName = 'none';
|
|
174
|
-
el.removeAttribute(`data-${prefix}-run`);
|
|
175
|
-
if (!direction) {
|
|
176
|
-
el.removeAttribute(`data-${prefix}-in-run`);
|
|
177
|
-
el.removeAttribute(`data-${prefix}-out-run`);
|
|
178
|
-
} else {
|
|
179
|
-
el.removeAttribute(`data-${prefix}-${direction}-run`);
|
|
180
|
-
}
|
|
181
|
-
void (el as HTMLElement).offsetWidth; // reflow to restart animations
|
|
182
|
-
el.style.animationName = currentAnimationName;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// IO thresholds centralized for clarity
|
|
186
|
-
const IO_THRESHOLD: number[] = [0, 0.2];
|
|
187
|
-
|
|
188
|
-
// Track which elements have animation lifecycle listeners attached
|
|
189
|
-
const listenersAttached = new WeakSet<Element>();
|
|
190
|
-
|
|
191
|
-
function addAnimationLifecycle(el: HTMLElement, prefix: string): void {
|
|
192
|
-
if (listenersAttached.has(el)) return;
|
|
193
|
-
listenersAttached.add(el);
|
|
194
|
-
|
|
195
|
-
const onStart = (e: AnimationEvent) => {
|
|
196
|
-
if (e.target !== el) return;
|
|
197
|
-
// Only mark as animating if this animation was initiated by our run flags.
|
|
198
|
-
// This avoids setting data-{prefix}-animating during hydration or passive CSS animations
|
|
199
|
-
// which would block the initial in/out trigger from IntersectionObserver.
|
|
200
|
-
if (
|
|
201
|
-
el.hasAttribute(`data-${prefix}-in-run`) ||
|
|
202
|
-
el.hasAttribute(`data-${prefix}-out-run`)
|
|
203
|
-
) {
|
|
204
|
-
el.setAttribute(`data-${prefix}-animating`, ``);
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
const onEndOrCancel = (e: AnimationEvent) => {
|
|
209
|
-
if (e.target !== el) return;
|
|
210
|
-
// If an IN animation just finished, persist a completion flag so it won't replay on upward scroll
|
|
211
|
-
|
|
212
|
-
el.removeAttribute(`data-${prefix}-animating`);
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
el.addEventListener('animationstart', onStart as EventListener);
|
|
216
|
-
el.addEventListener('animationend', onEndOrCancel as EventListener);
|
|
217
|
-
el.addEventListener('animationcancel', onEndOrCancel as EventListener);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export type AnimateOnScrollOptions = {
|
|
221
|
-
prefix?: string;
|
|
222
|
-
once?: boolean;
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
export function initAnimateOnScroll(
|
|
226
|
-
options: AnimateOnScrollOptions = {},
|
|
227
|
-
): () => void {
|
|
228
|
-
const { prefix = 'anim', once = true } = options;
|
|
229
|
-
|
|
230
|
-
if (prefersReducedMotion()) {
|
|
231
|
-
return () => {};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const cssSupported = supportsScrollTimeline();
|
|
235
|
-
|
|
236
|
-
// Setup JS observers for non-scroll-driven animations
|
|
237
|
-
const observed = new WeakSet<Element>();
|
|
238
|
-
|
|
239
|
-
// Track scroll direction to prevent triggering IN when scrolling up
|
|
240
|
-
let lastScrollY =
|
|
241
|
-
typeof window !== 'undefined'
|
|
242
|
-
? window.pageYOffset || window.scrollY || 0
|
|
243
|
-
: 0;
|
|
244
|
-
let scrollingDown = true; // default allow initial IN
|
|
245
|
-
const onScrollDir = () => {
|
|
246
|
-
const y = window.pageYOffset || window.scrollY || 0;
|
|
247
|
-
scrollingDown = y >= lastScrollY;
|
|
248
|
-
lastScrollY = y;
|
|
249
|
-
};
|
|
250
|
-
if (typeof window !== 'undefined') {
|
|
251
|
-
window.addEventListener('scroll', onScrollDir, { passive: true });
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const io = new IntersectionObserver(
|
|
255
|
-
(entries) => {
|
|
256
|
-
for (const entry of entries) {
|
|
257
|
-
const el = entry.target as HTMLElement;
|
|
258
|
-
|
|
259
|
-
if (!isJsObserverCandidate(el)) continue;
|
|
260
|
-
|
|
261
|
-
// If an animation is in progress, avoid re-triggering or flipping direction
|
|
262
|
-
if (el.hasAttribute(`data-${prefix}-animating`)) continue;
|
|
263
|
-
|
|
264
|
-
const isOut = hasOutClass(el.classList, prefix);
|
|
265
|
-
|
|
266
|
-
if (entry.isIntersecting) {
|
|
267
|
-
if (isOut) {
|
|
268
|
-
resetRunFlags(el, prefix, 'out');
|
|
269
|
-
}
|
|
270
|
-
setRunFlag(el, prefix, 'in');
|
|
271
|
-
|
|
272
|
-
if (once) io.unobserve(el);
|
|
273
|
-
} else {
|
|
274
|
-
if (!once) {
|
|
275
|
-
if (!scrollingDown) {
|
|
276
|
-
resetRunFlags(el, prefix, 'in');
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (isOut) {
|
|
280
|
-
setRunFlag(el, prefix, 'out');
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
{ threshold: IO_THRESHOLD },
|
|
287
|
-
);
|
|
288
|
-
|
|
289
|
-
const observeJsCandidates = (root?: ParentNode) => {
|
|
290
|
-
const candidates = queryJsObserverCandidates(root || document, prefix);
|
|
291
|
-
for (const el of candidates) {
|
|
292
|
-
if (observed.has(el)) continue;
|
|
293
|
-
observed.add(el);
|
|
294
|
-
io.observe(el);
|
|
295
|
-
addAnimationLifecycle(el, prefix);
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
// Initial observe
|
|
300
|
-
observeJsCandidates();
|
|
301
|
-
|
|
302
|
-
// Scroll-driven branch per support state
|
|
303
|
-
let cleanupScrollDriven: void | (() => void);
|
|
304
|
-
let mo: MutationObserver | null = null;
|
|
305
|
-
let rafId: number | null = null;
|
|
306
|
-
|
|
307
|
-
if (cssSupported) {
|
|
308
|
-
const schedule = () => {
|
|
309
|
-
if (rafId != null) return;
|
|
310
|
-
rafId = requestAnimationFrame(() => {
|
|
311
|
-
rafId = null;
|
|
312
|
-
const els = queryScrollDrivenCandidates(undefined, prefix);
|
|
313
|
-
for (const el of els) hydrateElement(el, prefix);
|
|
314
|
-
});
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
// Initial hydration
|
|
318
|
-
schedule();
|
|
319
|
-
|
|
320
|
-
mo = new MutationObserver((muts) => {
|
|
321
|
-
for (const m of muts) {
|
|
322
|
-
if (m.type === `attributes`) {
|
|
323
|
-
const t = m.target;
|
|
324
|
-
if (t instanceof HTMLElement) {
|
|
325
|
-
hydrateElement(t as HTMLElement, prefix);
|
|
326
|
-
if (isJsObserverCandidate(t)) {
|
|
327
|
-
if (!observed.has(t)) {
|
|
328
|
-
observed.add(t);
|
|
329
|
-
io.observe(t);
|
|
330
|
-
addAnimationLifecycle(t as HTMLElement, prefix);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
} else if (m.type === `childList`) {
|
|
335
|
-
if (m.addedNodes && m.addedNodes.length) {
|
|
336
|
-
for (const node of Array.from(m.addedNodes)) {
|
|
337
|
-
if (node instanceof HTMLElement) {
|
|
338
|
-
const sds = queryScrollDrivenCandidates(node, prefix);
|
|
339
|
-
for (const el of sds) hydrateElement(el, prefix);
|
|
340
|
-
observeJsCandidates(node);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
mo.observe(document.documentElement, {
|
|
349
|
-
subtree: true,
|
|
350
|
-
childList: true,
|
|
351
|
-
attributes: true,
|
|
352
|
-
attributeFilter: [
|
|
353
|
-
`class`,
|
|
354
|
-
`data-${prefix}-scroll`,
|
|
355
|
-
`data-${prefix}-start`,
|
|
356
|
-
`data-${prefix}-end`,
|
|
357
|
-
`data-${prefix}-paused`,
|
|
358
|
-
`data-${prefix}-run`,
|
|
359
|
-
],
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
cleanupScrollDriven = () => {
|
|
363
|
-
if (rafId != null) cancelAnimationFrame(rafId);
|
|
364
|
-
if (mo) mo.disconnect();
|
|
365
|
-
};
|
|
366
|
-
} else {
|
|
367
|
-
let stop: void | (() => void);
|
|
368
|
-
const existing = queryScrollDrivenCandidates(undefined, prefix);
|
|
369
|
-
if (existing.length > 0) {
|
|
370
|
-
import(`./scrollDriven`).then((m) => {
|
|
371
|
-
stop = m.initScrollViewFallback({ once });
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
cleanupScrollDriven = () => {
|
|
375
|
-
if (typeof stop === `function`) (stop as () => void)();
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Public cleanup
|
|
380
|
-
return () => {
|
|
381
|
-
if (cleanupScrollDriven) cleanupScrollDriven();
|
|
382
|
-
if (typeof window !== 'undefined') {
|
|
383
|
-
window.removeEventListener('scroll', onScrollDir as EventListener);
|
|
384
|
-
}
|
|
385
|
-
io.disconnect();
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Backward-compatible alias name (non-React):
|
|
390
|
-
export const AnimateOnScrollInit = initAnimateOnScroll;
|
|
391
|
-
export const animateOnScroll = initAnimateOnScroll;
|