@udixio/ui-react 2.3.2 → 2.4.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/CHANGELOG.md +29 -0
- package/dist/index.cjs +2 -2
- package/dist/index.js +619 -598
- package/dist/lib/effects/AnimateOnScroll.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/lib/config/define-config.ts +1 -1
- package/src/lib/effects/AnimateOnScroll.ts +75 -26
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnimateOnScroll.d.ts","sourceRoot":"","sources":["../../../src/lib/effects/AnimateOnScroll.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AnimateOnScroll.d.ts","sourceRoot":"","sources":["../../../src/lib/effects/AnimateOnScroll.ts"],"names":[],"mappings":"AAkLA,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,sBAA2B,GACnC,MAAM,IAAI,CAgIZ;AAGD,eAAO,MAAM,mBAAmB,4BAAsB,CAAC;AACvD,eAAO,MAAM,eAAe,4BAAsB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@udixio/ui-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"react": "^19.1.1",
|
|
38
38
|
"react-dom": "^19.1.1",
|
|
39
|
-
"@udixio/theme": "2.
|
|
40
|
-
"@udixio/tailwind": "2.3.
|
|
39
|
+
"@udixio/theme": "2.1.0",
|
|
40
|
+
"@udixio/tailwind": "2.3.4"
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
|
@@ -9,7 +9,7 @@ import { TailwindPlugin } from '@udixio/tailwind';
|
|
|
9
9
|
|
|
10
10
|
export function defineConfig(configObject: ConfigInterface): ConfigTheme {
|
|
11
11
|
return defineConfigTheme({
|
|
12
|
-
variant: Variants.
|
|
12
|
+
variant: Variants.Udixio,
|
|
13
13
|
...configObject,
|
|
14
14
|
plugins: [new FontPlugin(configObject), new TailwindPlugin(configObject)],
|
|
15
15
|
});
|
|
@@ -42,12 +42,8 @@ function isScrollDrivenCandidate(el: Element): boolean {
|
|
|
42
42
|
function isJsObserverCandidate(el: Element): boolean {
|
|
43
43
|
if (!(el instanceof HTMLElement)) return false;
|
|
44
44
|
const cls = el.classList;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
);
|
|
48
|
-
if (!hasAnimation) return false;
|
|
49
|
-
// Not scroll-driven
|
|
50
|
-
return !isScrollDrivenCandidate(el);
|
|
45
|
+
|
|
46
|
+
return Array.from(cls).some((className) => className.startsWith('anim-'));
|
|
51
47
|
}
|
|
52
48
|
|
|
53
49
|
function hydrateElement(el: HTMLElement, prefix: string): void {
|
|
@@ -101,7 +97,9 @@ function queryScrollDrivenCandidates(
|
|
|
101
97
|
): HTMLElement[] {
|
|
102
98
|
// Select any elements that have an animation class and are marked as scroll-driven
|
|
103
99
|
const animated = Array.from(
|
|
104
|
-
root.querySelectorAll<HTMLElement>(
|
|
100
|
+
root.querySelectorAll<HTMLElement>(
|
|
101
|
+
`[class*="${prefix}-"][class*="-scroll"]`,
|
|
102
|
+
),
|
|
105
103
|
);
|
|
106
104
|
return animated.filter((el) => isScrollDrivenCandidate(el));
|
|
107
105
|
}
|
|
@@ -110,14 +108,74 @@ function queryJsObserverCandidates(
|
|
|
110
108
|
root: ParentNode = document,
|
|
111
109
|
prefix: string,
|
|
112
110
|
): HTMLElement[] {
|
|
113
|
-
//
|
|
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.
|
|
114
115
|
const animated = Array.from(
|
|
115
|
-
root.querySelectorAll<HTMLElement>(`[class*="
|
|
116
|
+
root.querySelectorAll<HTMLElement>(`[class*="${prefix}-"]`),
|
|
116
117
|
);
|
|
117
118
|
|
|
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
|
+
});
|
|
119
152
|
}
|
|
120
153
|
|
|
154
|
+
// Utility: identify presence of in/out classes
|
|
155
|
+
function hasInOutClass(cls: DOMTokenList, prefix: string): boolean {
|
|
156
|
+
return cls.contains(`${prefix}-in`) || cls.contains(`${prefix}-out`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Utility: set run flags for a given direction ("in" or "out"), always ensuring generic run flag exists
|
|
160
|
+
function setRunFlag(el: HTMLElement, prefix: string, dir: 'in' | 'out'): void {
|
|
161
|
+
el.setAttribute(`data-${prefix}-run`, ``);
|
|
162
|
+
el.setAttribute(`data-${prefix}-${dir}-run`, ``);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Utility: reset run flags and restart animation timeline without changing computed styles
|
|
166
|
+
function resetRunFlags(el: HTMLElement, prefix: string): void {
|
|
167
|
+
const currentAnimationName = el.style.animationName;
|
|
168
|
+
el.style.animationName = 'none';
|
|
169
|
+
el.removeAttribute(`data-${prefix}-run`);
|
|
170
|
+
el.removeAttribute(`data-${prefix}-in-run`);
|
|
171
|
+
el.removeAttribute(`data-${prefix}-out-run`);
|
|
172
|
+
void (el as HTMLElement).offsetWidth; // reflow to restart animations
|
|
173
|
+
el.style.animationName = currentAnimationName;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// IO thresholds centralized for clarity
|
|
177
|
+
const IO_THRESHOLD: number[] = [0, 0.2];
|
|
178
|
+
|
|
121
179
|
export type AnimateOnScrollOptions = {
|
|
122
180
|
prefix?: string;
|
|
123
181
|
once?: boolean;
|
|
@@ -144,29 +202,20 @@ export function initAnimateOnScroll(
|
|
|
144
202
|
|
|
145
203
|
if (!isJsObserverCandidate(el)) continue;
|
|
146
204
|
|
|
147
|
-
const
|
|
148
|
-
const isOut = cls.contains(`${prefix}-out`);
|
|
149
|
-
const isIn = !isOut;
|
|
205
|
+
const isOut = el.classList.contains(`${prefix}-out`);
|
|
150
206
|
|
|
151
|
-
if (
|
|
152
|
-
el
|
|
207
|
+
if (!isOut && entry.isIntersecting) {
|
|
208
|
+
setRunFlag(el, prefix, 'in');
|
|
153
209
|
if (once) io.unobserve(el);
|
|
154
210
|
} else if (isOut && !entry.isIntersecting) {
|
|
155
|
-
el
|
|
211
|
+
setRunFlag(el, prefix, 'out');
|
|
156
212
|
if (once) io.unobserve(el);
|
|
157
|
-
} else {
|
|
158
|
-
|
|
159
|
-
const currentAnimationName = el.style.animationName;
|
|
160
|
-
el.style.animationName = 'none';
|
|
161
|
-
el.removeAttribute(`data-${prefix}-in-run`);
|
|
162
|
-
el.removeAttribute(`data-${prefix}-out-run`);
|
|
163
|
-
void el.offsetWidth; // reflow
|
|
164
|
-
el.style.animationName = currentAnimationName;
|
|
165
|
-
}
|
|
213
|
+
} else if (!once) {
|
|
214
|
+
resetRunFlags(el, prefix);
|
|
166
215
|
}
|
|
167
216
|
}
|
|
168
217
|
},
|
|
169
|
-
{ threshold:
|
|
218
|
+
{ threshold: IO_THRESHOLD },
|
|
170
219
|
);
|
|
171
220
|
|
|
172
221
|
const observeJsCandidates = (root?: ParentNode) => {
|