@grapu-design/react-image 0.1.1 → 0.1.2
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/lib/Image-12s-EMlItKgm.cjs +160 -0
- package/lib/Image-12s-fNttHZ8N.js +156 -0
- package/lib/index.cjs +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.js +2 -2
- package/package.json +4 -4
- package/src/Image.tsx +2 -2
- package/src/useImage.ts +1 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
3
|
+
var reactComposeRefs = require('@radix-ui/react-compose-refs');
|
|
4
|
+
var reactUseLayoutEffect = require('@radix-ui/react-use-layout-effect');
|
|
5
|
+
var domUtils = require('@grape-design/dom-utils');
|
|
6
|
+
var reactPrimitive = require('@grape-design/react-primitive');
|
|
7
|
+
var react = require('react');
|
|
8
|
+
var reactUseCallbackRef = require('@radix-ui/react-use-callback-ref');
|
|
9
|
+
|
|
10
|
+
function useImage(props) {
|
|
11
|
+
const onLoadingStatusChange = reactUseCallbackRef.useCallbackRef(props.onLoadingStatusChange);
|
|
12
|
+
const [loadingStatus, setLoadingStatus] = react.useState("loading");
|
|
13
|
+
const imageRef = react.useRef(null);
|
|
14
|
+
reactUseLayoutEffect.useLayoutEffect(()=>{
|
|
15
|
+
if (imageRef.current) {
|
|
16
|
+
if (imageRef.current.complete) {
|
|
17
|
+
if (imageRef.current.naturalWidth === 0 || imageRef.current.naturalHeight === 0) {
|
|
18
|
+
setLoadingStatus("error");
|
|
19
|
+
onLoadingStatusChange?.("error");
|
|
20
|
+
} else {
|
|
21
|
+
setLoadingStatus("loaded");
|
|
22
|
+
onLoadingStatusChange?.("loaded");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}, [
|
|
27
|
+
onLoadingStatusChange
|
|
28
|
+
]);
|
|
29
|
+
const isLoaded = loadingStatus === "loaded";
|
|
30
|
+
const stateProps = react.useMemo(()=>domUtils.elementProps({
|
|
31
|
+
"data-loading-state": loadingStatus
|
|
32
|
+
}), [
|
|
33
|
+
loadingStatus
|
|
34
|
+
]);
|
|
35
|
+
const setSrc = react.useCallback((src)=>{
|
|
36
|
+
if (src === undefined || src === null) {
|
|
37
|
+
setLoadingStatus("error");
|
|
38
|
+
onLoadingStatusChange?.("error");
|
|
39
|
+
} else {
|
|
40
|
+
setLoadingStatus("loading");
|
|
41
|
+
onLoadingStatusChange?.("loading");
|
|
42
|
+
}
|
|
43
|
+
}, [
|
|
44
|
+
onLoadingStatusChange
|
|
45
|
+
]);
|
|
46
|
+
const getContentProps = react.useCallback(({ src })=>{
|
|
47
|
+
return domUtils.imgProps({
|
|
48
|
+
hidden: !isLoaded,
|
|
49
|
+
"data-visible": domUtils.dataAttr(isLoaded),
|
|
50
|
+
src,
|
|
51
|
+
...stateProps
|
|
52
|
+
});
|
|
53
|
+
}, [
|
|
54
|
+
isLoaded,
|
|
55
|
+
stateProps
|
|
56
|
+
]);
|
|
57
|
+
const handleLoad = react.useCallback(()=>{
|
|
58
|
+
setLoadingStatus("loaded");
|
|
59
|
+
onLoadingStatusChange?.("loaded");
|
|
60
|
+
}, [
|
|
61
|
+
onLoadingStatusChange
|
|
62
|
+
]);
|
|
63
|
+
const handleError = react.useCallback(()=>{
|
|
64
|
+
setLoadingStatus("error");
|
|
65
|
+
onLoadingStatusChange?.("error");
|
|
66
|
+
}, [
|
|
67
|
+
onLoadingStatusChange
|
|
68
|
+
]);
|
|
69
|
+
const fallbackProps = react.useMemo(()=>domUtils.elementProps({
|
|
70
|
+
hidden: isLoaded,
|
|
71
|
+
"data-visible": domUtils.dataAttr(!isLoaded),
|
|
72
|
+
...stateProps
|
|
73
|
+
}), [
|
|
74
|
+
isLoaded,
|
|
75
|
+
stateProps
|
|
76
|
+
]);
|
|
77
|
+
return {
|
|
78
|
+
refs: {
|
|
79
|
+
image: imageRef
|
|
80
|
+
},
|
|
81
|
+
loadingStatus,
|
|
82
|
+
stateProps,
|
|
83
|
+
rootProps: stateProps,
|
|
84
|
+
setSrc,
|
|
85
|
+
getContentProps,
|
|
86
|
+
handleLoad,
|
|
87
|
+
handleError,
|
|
88
|
+
fallbackProps
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const ImageContext = /*#__PURE__*/ react.createContext(null);
|
|
93
|
+
const ImageProvider = ImageContext.Provider;
|
|
94
|
+
function useImageContext({ strict = true } = {}) {
|
|
95
|
+
const context = react.useContext(ImageContext);
|
|
96
|
+
if (!context && strict) {
|
|
97
|
+
throw new Error("useImageContext must be used within an Image");
|
|
98
|
+
}
|
|
99
|
+
return context;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const ImageRoot = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
103
|
+
const { onLoadingStatusChange, ...otherProps } = props;
|
|
104
|
+
const api = useImage({
|
|
105
|
+
onLoadingStatusChange
|
|
106
|
+
});
|
|
107
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ImageProvider, {
|
|
108
|
+
value: api,
|
|
109
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
|
|
110
|
+
ref: ref,
|
|
111
|
+
...domUtils.mergeProps(api.rootProps, otherProps)
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
ImageRoot.displayName = "ImageRoot";
|
|
116
|
+
const ImageContent = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
117
|
+
const { src, onLoad, onError, ...otherProps } = props;
|
|
118
|
+
const { refs, setSrc, getContentProps, handleLoad, handleError } = useImageContext();
|
|
119
|
+
reactUseLayoutEffect.useLayoutEffect(()=>{
|
|
120
|
+
setSrc(src);
|
|
121
|
+
}, [
|
|
122
|
+
src,
|
|
123
|
+
setSrc
|
|
124
|
+
]);
|
|
125
|
+
const contentProps = getContentProps({
|
|
126
|
+
src
|
|
127
|
+
});
|
|
128
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.img, {
|
|
129
|
+
ref: reactComposeRefs.composeRefs(refs.image, ref),
|
|
130
|
+
...domUtils.mergeProps(contentProps, otherProps, {
|
|
131
|
+
// if loading is lazy, we should not hide the image even if it's not loaded yet,
|
|
132
|
+
// because the browser should be able to check if it's in the viewport.
|
|
133
|
+
// TODO: it should be better than this; why doesn't useImage properly handle this case?
|
|
134
|
+
hidden: otherProps.loading === "lazy" ? false : contentProps.hidden
|
|
135
|
+
}),
|
|
136
|
+
onLoad: (e)=>{
|
|
137
|
+
handleLoad();
|
|
138
|
+
onLoad?.(e);
|
|
139
|
+
},
|
|
140
|
+
onError: (e)=>{
|
|
141
|
+
handleError();
|
|
142
|
+
onError?.(e);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
ImageContent.displayName = "ImageContent";
|
|
147
|
+
const ImageFallback = /*#__PURE__*/ react.forwardRef((props, ref)=>{
|
|
148
|
+
const { fallbackProps } = useImageContext();
|
|
149
|
+
return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
|
|
150
|
+
ref: ref,
|
|
151
|
+
...domUtils.mergeProps(fallbackProps, props)
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
ImageFallback.displayName = "ImageFallback";
|
|
155
|
+
|
|
156
|
+
exports.ImageContent = ImageContent;
|
|
157
|
+
exports.ImageFallback = ImageFallback;
|
|
158
|
+
exports.ImageRoot = ImageRoot;
|
|
159
|
+
exports.useImage = useImage;
|
|
160
|
+
exports.useImageContext = useImageContext;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { composeRefs } from '@radix-ui/react-compose-refs';
|
|
4
|
+
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
|
|
5
|
+
import { elementProps, imgProps, dataAttr, mergeProps } from '@grape-design/dom-utils';
|
|
6
|
+
import { Primitive } from '@grape-design/react-primitive';
|
|
7
|
+
import { useState, useRef, useMemo, useCallback, createContext, useContext, forwardRef } from 'react';
|
|
8
|
+
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
|
|
9
|
+
|
|
10
|
+
function useImage(props) {
|
|
11
|
+
const onLoadingStatusChange = useCallbackRef(props.onLoadingStatusChange);
|
|
12
|
+
const [loadingStatus, setLoadingStatus] = useState("loading");
|
|
13
|
+
const imageRef = useRef(null);
|
|
14
|
+
useLayoutEffect(()=>{
|
|
15
|
+
if (imageRef.current) {
|
|
16
|
+
if (imageRef.current.complete) {
|
|
17
|
+
if (imageRef.current.naturalWidth === 0 || imageRef.current.naturalHeight === 0) {
|
|
18
|
+
setLoadingStatus("error");
|
|
19
|
+
onLoadingStatusChange?.("error");
|
|
20
|
+
} else {
|
|
21
|
+
setLoadingStatus("loaded");
|
|
22
|
+
onLoadingStatusChange?.("loaded");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}, [
|
|
27
|
+
onLoadingStatusChange
|
|
28
|
+
]);
|
|
29
|
+
const isLoaded = loadingStatus === "loaded";
|
|
30
|
+
const stateProps = useMemo(()=>elementProps({
|
|
31
|
+
"data-loading-state": loadingStatus
|
|
32
|
+
}), [
|
|
33
|
+
loadingStatus
|
|
34
|
+
]);
|
|
35
|
+
const setSrc = useCallback((src)=>{
|
|
36
|
+
if (src === undefined || src === null) {
|
|
37
|
+
setLoadingStatus("error");
|
|
38
|
+
onLoadingStatusChange?.("error");
|
|
39
|
+
} else {
|
|
40
|
+
setLoadingStatus("loading");
|
|
41
|
+
onLoadingStatusChange?.("loading");
|
|
42
|
+
}
|
|
43
|
+
}, [
|
|
44
|
+
onLoadingStatusChange
|
|
45
|
+
]);
|
|
46
|
+
const getContentProps = useCallback(({ src })=>{
|
|
47
|
+
return imgProps({
|
|
48
|
+
hidden: !isLoaded,
|
|
49
|
+
"data-visible": dataAttr(isLoaded),
|
|
50
|
+
src,
|
|
51
|
+
...stateProps
|
|
52
|
+
});
|
|
53
|
+
}, [
|
|
54
|
+
isLoaded,
|
|
55
|
+
stateProps
|
|
56
|
+
]);
|
|
57
|
+
const handleLoad = useCallback(()=>{
|
|
58
|
+
setLoadingStatus("loaded");
|
|
59
|
+
onLoadingStatusChange?.("loaded");
|
|
60
|
+
}, [
|
|
61
|
+
onLoadingStatusChange
|
|
62
|
+
]);
|
|
63
|
+
const handleError = useCallback(()=>{
|
|
64
|
+
setLoadingStatus("error");
|
|
65
|
+
onLoadingStatusChange?.("error");
|
|
66
|
+
}, [
|
|
67
|
+
onLoadingStatusChange
|
|
68
|
+
]);
|
|
69
|
+
const fallbackProps = useMemo(()=>elementProps({
|
|
70
|
+
hidden: isLoaded,
|
|
71
|
+
"data-visible": dataAttr(!isLoaded),
|
|
72
|
+
...stateProps
|
|
73
|
+
}), [
|
|
74
|
+
isLoaded,
|
|
75
|
+
stateProps
|
|
76
|
+
]);
|
|
77
|
+
return {
|
|
78
|
+
refs: {
|
|
79
|
+
image: imageRef
|
|
80
|
+
},
|
|
81
|
+
loadingStatus,
|
|
82
|
+
stateProps,
|
|
83
|
+
rootProps: stateProps,
|
|
84
|
+
setSrc,
|
|
85
|
+
getContentProps,
|
|
86
|
+
handleLoad,
|
|
87
|
+
handleError,
|
|
88
|
+
fallbackProps
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const ImageContext = /*#__PURE__*/ createContext(null);
|
|
93
|
+
const ImageProvider = ImageContext.Provider;
|
|
94
|
+
function useImageContext({ strict = true } = {}) {
|
|
95
|
+
const context = useContext(ImageContext);
|
|
96
|
+
if (!context && strict) {
|
|
97
|
+
throw new Error("useImageContext must be used within an Image");
|
|
98
|
+
}
|
|
99
|
+
return context;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const ImageRoot = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
103
|
+
const { onLoadingStatusChange, ...otherProps } = props;
|
|
104
|
+
const api = useImage({
|
|
105
|
+
onLoadingStatusChange
|
|
106
|
+
});
|
|
107
|
+
return /*#__PURE__*/ jsx(ImageProvider, {
|
|
108
|
+
value: api,
|
|
109
|
+
children: /*#__PURE__*/ jsx(Primitive.div, {
|
|
110
|
+
ref: ref,
|
|
111
|
+
...mergeProps(api.rootProps, otherProps)
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
ImageRoot.displayName = "ImageRoot";
|
|
116
|
+
const ImageContent = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
117
|
+
const { src, onLoad, onError, ...otherProps } = props;
|
|
118
|
+
const { refs, setSrc, getContentProps, handleLoad, handleError } = useImageContext();
|
|
119
|
+
useLayoutEffect(()=>{
|
|
120
|
+
setSrc(src);
|
|
121
|
+
}, [
|
|
122
|
+
src,
|
|
123
|
+
setSrc
|
|
124
|
+
]);
|
|
125
|
+
const contentProps = getContentProps({
|
|
126
|
+
src
|
|
127
|
+
});
|
|
128
|
+
return /*#__PURE__*/ jsx(Primitive.img, {
|
|
129
|
+
ref: composeRefs(refs.image, ref),
|
|
130
|
+
...mergeProps(contentProps, otherProps, {
|
|
131
|
+
// if loading is lazy, we should not hide the image even if it's not loaded yet,
|
|
132
|
+
// because the browser should be able to check if it's in the viewport.
|
|
133
|
+
// TODO: it should be better than this; why doesn't useImage properly handle this case?
|
|
134
|
+
hidden: otherProps.loading === "lazy" ? false : contentProps.hidden
|
|
135
|
+
}),
|
|
136
|
+
onLoad: (e)=>{
|
|
137
|
+
handleLoad();
|
|
138
|
+
onLoad?.(e);
|
|
139
|
+
},
|
|
140
|
+
onError: (e)=>{
|
|
141
|
+
handleError();
|
|
142
|
+
onError?.(e);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
ImageContent.displayName = "ImageContent";
|
|
147
|
+
const ImageFallback = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
148
|
+
const { fallbackProps } = useImageContext();
|
|
149
|
+
return /*#__PURE__*/ jsx(Primitive.div, {
|
|
150
|
+
ref: ref,
|
|
151
|
+
...mergeProps(fallbackProps, props)
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
ImageFallback.displayName = "ImageFallback";
|
|
155
|
+
|
|
156
|
+
export { ImageContent as I, ImageFallback as a, ImageRoot as b, useImageContext as c, useImage as u };
|
package/lib/index.cjs
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PrimitiveProps } from '@
|
|
1
|
+
import { PrimitiveProps } from '@grape-design/react-primitive';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
|
|
4
4
|
type ImageLoadingStatus = "loading" | "loaded" | "error";
|
|
@@ -551,7 +551,6 @@ declare function useImage(props: UseImageProps): {
|
|
|
551
551
|
getContentProps: ({ src }: {
|
|
552
552
|
src?: string;
|
|
553
553
|
}) => {
|
|
554
|
-
loading?: "eager" | "lazy" | undefined;
|
|
555
554
|
defaultChecked?: boolean | undefined;
|
|
556
555
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
557
556
|
suppressContentEditableWarning?: boolean | undefined;
|
|
@@ -818,14 +817,15 @@ declare function useImage(props: UseImageProps): {
|
|
|
818
817
|
onAnimationIterationCapture?: react.AnimationEventHandler<HTMLImageElement>;
|
|
819
818
|
onTransitionEnd?: react.TransitionEventHandler<HTMLImageElement>;
|
|
820
819
|
onTransitionEndCapture?: react.TransitionEventHandler<HTMLImageElement>;
|
|
821
|
-
src?: string | undefined;
|
|
822
820
|
alt?: string | undefined;
|
|
823
821
|
crossOrigin?: "" | "anonymous" | "use-credentials";
|
|
824
822
|
decoding?: "async" | "auto" | "sync" | undefined;
|
|
825
823
|
fetchPriority?: "high" | "low" | "auto";
|
|
826
824
|
height?: number | string | undefined;
|
|
825
|
+
loading?: "eager" | "lazy" | undefined;
|
|
827
826
|
referrerPolicy?: react.HTMLAttributeReferrerPolicy | undefined;
|
|
828
827
|
sizes?: string | undefined;
|
|
828
|
+
src?: string | undefined;
|
|
829
829
|
srcSet?: string | undefined;
|
|
830
830
|
useMap?: string | undefined;
|
|
831
831
|
width?: number | string | undefined;
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as ImageContent, a as ImageFallback, b as ImageRoot } from './Image-12s-
|
|
2
|
-
export { u as useImage, c as useImageContext } from './Image-12s-
|
|
1
|
+
import { I as ImageContent, a as ImageFallback, b as ImageRoot } from './Image-12s-fNttHZ8N.js';
|
|
2
|
+
export { u as useImage, c as useImageContext } from './Image-12s-fNttHZ8N.js';
|
|
3
3
|
|
|
4
4
|
var Image_namespace = {
|
|
5
5
|
__proto__: null,
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grapu-design/react-image",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
|
-
"url": "git+https://github.com/
|
|
6
|
+
"url": "git+https://github.com/grape-design/designsystem.git",
|
|
7
7
|
"directory": "packages/react-headless/image"
|
|
8
8
|
},
|
|
9
9
|
"sideEffects": false,
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"@radix-ui/react-compose-refs": "^1.1.2",
|
|
31
31
|
"@radix-ui/react-use-callback-ref": "^1.1.1",
|
|
32
32
|
"@radix-ui/react-use-layout-effect": "^1.1.1",
|
|
33
|
-
"@grapu-design/dom-utils": "^0.1.
|
|
34
|
-
"@grapu-design/react-primitive": "^0.1.
|
|
33
|
+
"@grapu-design/dom-utils": "^0.1.2",
|
|
34
|
+
"@grapu-design/react-primitive": "^0.1.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/react": "^19.1.6",
|
package/src/Image.tsx
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { composeRefs } from "@radix-ui/react-compose-refs";
|
|
4
4
|
import { useLayoutEffect } from "@radix-ui/react-use-layout-effect";
|
|
5
|
-
import { mergeProps } from "@
|
|
6
|
-
import { Primitive, type PrimitiveProps } from "@
|
|
5
|
+
import { mergeProps } from "@grape-design/dom-utils";
|
|
6
|
+
import { Primitive, type PrimitiveProps } from "@grape-design/react-primitive";
|
|
7
7
|
import type * as React from "react";
|
|
8
8
|
import { forwardRef } from "react";
|
|
9
9
|
import { useImage, type UseImageProps } from "./useImage";
|
package/src/useImage.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
|
|
2
2
|
import { useLayoutEffect } from "@radix-ui/react-use-layout-effect";
|
|
3
|
-
import { dataAttr, elementProps, imgProps } from "@
|
|
3
|
+
import { dataAttr, elementProps, imgProps } from "@grape-design/dom-utils";
|
|
4
4
|
import { useCallback, useMemo, useRef, useState } from "react";
|
|
5
5
|
|
|
6
6
|
export type ImageLoadingStatus = "loading" | "loaded" | "error";
|