@ilokesto/utilinent 0.0.23 → 0.0.24
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/components/For.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
import { createElement, forwardRef } from "react";
|
|
2
3
|
import { htmlTags } from "../constants/htmlTags";
|
|
3
4
|
function BaseFor({ each, children, fallback = null, }) {
|
|
4
|
-
return each && each.length > 0 ? each.map(children) : fallback;
|
|
5
|
+
return _jsx(_Fragment, { children: each && each.length > 0 ? each.map(children) : fallback });
|
|
5
6
|
}
|
|
6
7
|
const renderForTag = (tag) =>
|
|
7
8
|
// forward ref so consumers can attach a ref to the underlying DOM element
|
|
8
9
|
forwardRef(({ each, children, fallback = null, ...props }, ref) => {
|
|
9
|
-
|
|
10
|
-
return fallback;
|
|
11
|
-
const content = each.map(children);
|
|
10
|
+
const content = each && each.length > 0 ? each.map(children) : fallback;
|
|
12
11
|
return createElement(tag, { ...props, ref }, content);
|
|
13
12
|
});
|
|
14
13
|
const tagEntries = htmlTags.reduce((acc, tag) => {
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import type { ObserverProps } from "../types";
|
|
2
|
-
export declare
|
|
2
|
+
export declare const Observer: import("react").ForwardRefExoticComponent<ObserverProps & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
3
|
+
ref?: ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLDivElement> | null | undefined;
|
|
4
|
+
}, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useCallback } from "react";
|
|
2
3
|
import { useIntersectionObserver } from "../hooks/useIntersectionObserver";
|
|
3
4
|
import { Show } from "./Show";
|
|
4
|
-
export function Observer({ children, fallback = null, threshold = 0, rootMargin = "0px", triggerOnce: freezeOnceVisible = false, onIntersect: onChange, }) {
|
|
5
|
-
const { ref, isIntersecting } = useIntersectionObserver({
|
|
5
|
+
export const Observer = forwardRef(function Observer({ children, fallback = null, threshold = 0, rootMargin = "0px", triggerOnce: freezeOnceVisible = false, onIntersect: onChange, style, ...props }, forwardedRef) {
|
|
6
|
+
const { ref: observerRef, isIntersecting } = useIntersectionObserver({
|
|
6
7
|
threshold,
|
|
7
8
|
rootMargin,
|
|
8
9
|
freezeOnceVisible,
|
|
9
10
|
onChange,
|
|
10
11
|
});
|
|
11
|
-
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
12
|
+
const mergedRef = useCallback((node) => {
|
|
13
|
+
// Set observer ref
|
|
14
|
+
observerRef(node);
|
|
15
|
+
// Handle forwarded ref
|
|
16
|
+
if (typeof forwardedRef === "function") {
|
|
17
|
+
forwardedRef(node);
|
|
18
|
+
}
|
|
19
|
+
else if (forwardedRef) {
|
|
20
|
+
forwardedRef.current = node;
|
|
21
|
+
}
|
|
22
|
+
}, [observerRef, forwardedRef]);
|
|
23
|
+
return (_jsx(Show.div, { ref: mergedRef, when: isIntersecting, fallback: fallback, style: {
|
|
24
|
+
...style,
|
|
25
|
+
minHeight: style?.minHeight ?? "1px",
|
|
26
|
+
minWidth: style?.minWidth ?? "1px",
|
|
27
|
+
display: style?.display ?? "block",
|
|
28
|
+
}, ...props, children: typeof children === "function" ? children(isIntersecting) : children }));
|
|
29
|
+
});
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createElement, forwardRef } from "react";
|
|
3
3
|
import { htmlTags } from "../constants/htmlTags";
|
|
4
|
+
import { For } from "./For";
|
|
4
5
|
function BaseRepeat({ times, children, fallback = null }) {
|
|
5
6
|
if (!times || times <= 0 || !Number.isInteger(times)) {
|
|
6
7
|
return fallback ?? null;
|
|
7
8
|
}
|
|
8
|
-
return _jsx(
|
|
9
|
+
return _jsx(For, { each: Array.from({ length: times }, (_, i) => i), children: children });
|
|
9
10
|
}
|
|
10
11
|
const renderForTag = (tag) =>
|
|
11
12
|
// forward ref so consumers can attach a ref to the underlying DOM element
|
|
12
13
|
forwardRef(({ times, children, fallback = null, ...props }, ref) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const content = Array.from({ length: times }, (_, i) => children(i));
|
|
14
|
+
const content = times && times > 0 && Number.isInteger(times)
|
|
15
|
+
? Array.from({ length: times }, (_, i) => children(i))
|
|
16
|
+
: fallback ?? null;
|
|
17
17
|
return createElement(tag, { ...props, ref }, content);
|
|
18
18
|
});
|
|
19
19
|
const tagEntries = htmlTags.reduce((acc, tag) => {
|
package/dist/components/Show.js
CHANGED
|
@@ -12,9 +12,11 @@ const renderForTag = (tag) =>
|
|
|
12
12
|
// forward ref so consumers like Observer can pass a ref to the real DOM element
|
|
13
13
|
forwardRef(function Render({ when, children, fallback = null, ...props }, ref) {
|
|
14
14
|
const shouldRender = Array.isArray(when) ? when.every(Boolean) : !!when;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const content = shouldRender
|
|
16
|
+
? typeof children === "function"
|
|
17
|
+
? children(when)
|
|
18
|
+
: children
|
|
19
|
+
: fallback;
|
|
18
20
|
return createElement(tag, { ...props, ref }, content);
|
|
19
21
|
});
|
|
20
22
|
const tagEntries = htmlTags.reduce((acc, tag) => {
|
|
@@ -3,26 +3,26 @@ export function useIntersectionObserver({ threshold = 0, root = null, rootMargin
|
|
|
3
3
|
const [element, setElement] = useState(null);
|
|
4
4
|
const [isIntersecting, setIsIntersecting] = useState(initialIsIntersecting);
|
|
5
5
|
const [entry, setEntry] = useState();
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const observerOptions = useMemo(() => ({
|
|
10
|
-
threshold,
|
|
11
|
-
root,
|
|
12
|
-
rootMargin,
|
|
13
|
-
}), [threshold, root, rootMargin]);
|
|
14
|
-
const isFrozen = freezeOnceVisible && isIntersecting;
|
|
6
|
+
const onChangeRef = useRef(onChange);
|
|
7
|
+
const isFirstCallbackRef = useRef(true);
|
|
8
|
+
const isFrozen = useRef(false);
|
|
15
9
|
// Keep callback ref updated
|
|
16
10
|
useEffect(() => {
|
|
17
|
-
|
|
11
|
+
onChangeRef.current = onChange;
|
|
18
12
|
}, [onChange]);
|
|
13
|
+
// Memoize options
|
|
14
|
+
const observerOptions = useMemo(() => ({ threshold, root, rootMargin }), [threshold, root, rootMargin]);
|
|
19
15
|
// Ref callback to set the element
|
|
20
16
|
const ref = useCallback((node) => {
|
|
21
17
|
setElement(node);
|
|
22
18
|
}, []);
|
|
23
19
|
// Main intersection observer effect
|
|
24
20
|
useEffect(() => {
|
|
25
|
-
if (!element || !("IntersectionObserver" in window)
|
|
21
|
+
if (!element || !("IntersectionObserver" in window)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// If frozen (triggerOnce + already intersected), skip observation
|
|
25
|
+
if (isFrozen.current) {
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -34,28 +34,38 @@ export function useIntersectionObserver({ threshold = 0, root = null, rootMargin
|
|
|
34
34
|
: [observer.thresholds];
|
|
35
35
|
const isCurrentlyIntersecting = intersectionEntry.isIntersecting &&
|
|
36
36
|
thresholds.some((t) => intersectionEntry.intersectionRatio >= t);
|
|
37
|
+
// Update state
|
|
37
38
|
setIsIntersecting(isCurrentlyIntersecting);
|
|
38
39
|
setEntry(intersectionEntry);
|
|
39
|
-
//
|
|
40
|
-
|
|
40
|
+
// Skip the first callback (initial observation)
|
|
41
|
+
if (isFirstCallbackRef.current) {
|
|
42
|
+
isFirstCallbackRef.current = false;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Call onChange callback
|
|
46
|
+
onChangeRef.current?.(isCurrentlyIntersecting, intersectionEntry);
|
|
47
|
+
// Freeze if triggerOnce and now intersecting
|
|
48
|
+
if (freezeOnceVisible && isCurrentlyIntersecting) {
|
|
49
|
+
isFrozen.current = true;
|
|
50
|
+
// Immediately disconnect to stop further observations
|
|
51
|
+
observer.disconnect();
|
|
52
|
+
}
|
|
41
53
|
}, observerOptions);
|
|
42
54
|
observer.observe(element);
|
|
43
|
-
observerRef.current = observer;
|
|
44
55
|
return () => {
|
|
45
56
|
observer.disconnect();
|
|
46
|
-
observerRef.current = null;
|
|
47
57
|
};
|
|
48
|
-
}, [element, observerOptions,
|
|
49
|
-
// Reset
|
|
58
|
+
}, [element, observerOptions, freezeOnceVisible]);
|
|
59
|
+
// Reset when element is removed
|
|
50
60
|
useEffect(() => {
|
|
51
|
-
if (!element
|
|
61
|
+
if (!element) {
|
|
52
62
|
setIsIntersecting(initialIsIntersecting);
|
|
53
63
|
setEntry(undefined);
|
|
64
|
+
isFirstCallbackRef.current = true;
|
|
65
|
+
if (!freezeOnceVisible) {
|
|
66
|
+
isFrozen.current = false;
|
|
67
|
+
}
|
|
54
68
|
}
|
|
55
|
-
}, [element, freezeOnceVisible,
|
|
56
|
-
return useMemo(() => ({
|
|
57
|
-
ref,
|
|
58
|
-
isIntersecting,
|
|
59
|
-
entry,
|
|
60
|
-
}), [ref, isIntersecting, entry]);
|
|
69
|
+
}, [element, freezeOnceVisible, initialIsIntersecting]);
|
|
70
|
+
return useMemo(() => ({ ref, isIntersecting, entry }), [ref, isIntersecting, entry]);
|
|
61
71
|
}
|