Skip to content

Commit aa41bad

Browse files
authored
IK-2406 Expose full FileElement as part of export and compute imageDimensions using the image element (#4)
1 parent 65a6f3e commit aa41bad

File tree

14 files changed

+495
-67
lines changed

14 files changed

+495
-67
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ packages/imagekit-editor/dist/*
1717
packages/imagekit-editor/*.tgz
1818
.turbo
1919
.yarn
20-
builds
20+
builds
21+
packages/imagekit-editor/README.md

examples/react-example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6-
"@imagekit/editor": "1.2.0",
6+
"@imagekit/editor": "2.0.0",
77
"@types/node": "^20.11.24",
88
"@types/react": "^17.0.2",
99
"@types/react-dom": "^17.0.2",

examples/react-example/src/index.tsx

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import ReactDOM from "react-dom"
88
function App() {
99
const [open, setOpen] = React.useState(true)
1010
const [editorProps, setEditorProps] =
11-
React.useState<ImageKitEditorProps<{ requireSignedUrl: boolean }>>()
11+
React.useState<
12+
ImageKitEditorProps<{ requireSignedUrl: boolean; fileName: string }>
13+
>()
1214
const ref = React.useRef<ImageKitEditorRef>(null)
1315

1416
/**
@@ -28,18 +30,21 @@ function App() {
2830
url: "https://ik.imagekit.io/v3sxk1svj/white%20BMW%20car%20on%20street.jpg",
2931
metadata: {
3032
requireSignedUrl: false,
33+
fileName: "white BMW car on street.jpg",
3134
},
3235
},
3336
{
3437
url: "https://ik.imagekit.io/v3sxk1svj/Young%20Living%20Patchouili%20bot....jpg",
3538
metadata: {
3639
requireSignedUrl: false,
40+
fileName: "Young Living Patchouili bot.jpg",
3741
},
3842
},
3943
{
4044
url: "https://ik.imagekit.io/v3sxk1svj/brown%20bear%20plush%20toy%20on%20whi....jpg?updatedAt=1760432666859",
4145
metadata: {
4246
requireSignedUrl: false,
47+
fileName: "brown bear plush toy on white.jpg",
4348
},
4449
},
4550
// ...Array.from({ length: 10000 }).map((_, i) => ({
@@ -57,26 +62,26 @@ function App() {
5762
label: "Export",
5863
icon: <Icon boxSize={"5"} as={PiDownload} />,
5964
isVisible: true,
60-
onClick: (images) => {
61-
console.log(images)
65+
onClick: (images, currentImage) => {
66+
console.log(images, currentImage)
6267
},
6368
},
64-
{
65-
type: "menu",
66-
label: "Export",
67-
icon: <Icon boxSize={"5"} as={PiDownload} />,
68-
isVisible: true,
69-
options: [
70-
{
71-
label: "Export",
72-
icon: <Icon boxSize={"5"} as={PiDownload} />,
73-
isVisible: true,
74-
onClick: (images) => {
75-
console.log(images)
76-
},
77-
},
78-
],
79-
},
69+
// {
70+
// type: "menu",
71+
// label: "Export",
72+
// icon: <Icon boxSize={"5"} as={PiDownload} />,
73+
// isVisible: true,
74+
// options: [
75+
// {
76+
// label: "Export",
77+
// icon: <Icon boxSize={"5"} as={PiDownload} />,
78+
// isVisible: true,
79+
// onClick: (images) => {
80+
// console.log(images)
81+
// },
82+
// },
83+
// ],
84+
// },
8085
],
8186
signer: async (request) => {
8287
console.log(request)

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@
1717
"start": "turbo run start",
1818
"build": "turbo run build",
1919
"version": "yarn workspace @imagekit/editor version",
20-
"package": "yarn build && yarn workspace @imagekit/editor pack --out ../../builds/imagekit-editor-%v.tgz",
21-
"release": "yarn build && yarn workspace @imagekit/editor pack --out ../../builds/imagekit-editor-%v.tgz && yarn workspace @imagekit/editor publish",
20+
"package": "yarn build && shx cp README.md ./packages/imagekit-editor/ && yarn workspace @imagekit/editor pack --out ../../builds/imagekit-editor-%v.tgz",
21+
"release": "yarn build && shx cp README.md ./packages/imagekit-editor/ && yarn workspace @imagekit/editor pack --out ../../builds/imagekit-editor-%v.tgz && yarn workspace @imagekit/editor publish",
2222
"prepare": "husky",
2323
"lint": "biome ci"
2424
},
2525
"devDependencies": {
2626
"@biomejs/biome": "2.1.1",
2727
"husky": "^9.1.7",
2828
"lint-staged": "^16.1.2",
29+
"shx": "^0.4.0",
2930
"turbo": "^2.0.1"
3031
},
3132
"packageManager": "[email protected]",

packages/imagekit-editor-dev/src/ImageKitEditor.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,27 @@ import merge from "lodash/merge"
44
import React, { forwardRef, useImperativeHandle } from "react"
55
import { EditorLayout, EditorWrapper } from "./components/editor"
66
import type { HeaderProps } from "./components/header"
7-
import type { DEFAULT_FOCUS_OBJECTS } from "./schema"
87
import {
9-
type FileElement,
108
type FocusObjects,
9+
type InputFileElement,
1110
type RequiredMetadata,
1211
type Signer,
1312
useEditorStore,
1413
} from "./store"
1514
import { themeOverrides } from "./theme"
1615

1716
export interface ImageKitEditorRef {
18-
loadImage: (image: string | FileElement) => void
19-
loadImages: (images: Array<string | FileElement>) => void
17+
loadImage: (image: string | InputFileElement) => void
18+
loadImages: (images: Array<string | InputFileElement>) => void
2019
setCurrentImage: (imageSrc: string) => void
2120
}
2221

2322
interface EditorProps<Metadata extends RequiredMetadata = RequiredMetadata> {
2423
theme?: Dict
25-
initialImages?: Array<string | FileElement<Metadata>>
24+
initialImages?: Array<string | InputFileElement<Metadata>>
2625
signer?: Signer<Metadata>
2726
onAddImage?: () => void
28-
exportOptions?: HeaderProps["exportOptions"]
27+
exportOptions?: HeaderProps<Metadata>["exportOptions"]
2928
focusObjects?: ReadonlyArray<FocusObjects>
3029
onClose: (args: { dirty: boolean; destroy: () => void }) => void
3130
}

packages/imagekit-editor-dev/src/components/RetryableImage.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from "@chakra-ui/react"
1212
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
1313
import { useVisibility } from "../hooks/useVisibility"
14+
import { useEditorStore } from "../store"
1415

1516
export interface RetryableImageProps extends ImageProps {
1617
maxRetries?: number
@@ -144,7 +145,8 @@ export default function RetryableImage(props: RetryableImageProps) {
144145

145146
const overlayActive = !!externalLoading || loading
146147

147-
const handleVisibleLoad = () => {
148+
const handleVisibleLoad = (event: React.SyntheticEvent<HTMLImageElement>) => {
149+
imgProps?.onLoad?.(event)
148150
setLoading(false)
149151
setError(null)
150152
lastSuccessBaseRef.current = currentSrcBase

packages/imagekit-editor-dev/src/components/editor/ActionBar.tsx

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
import { PiGridFour } from "@react-icons/all-files/pi/PiGridFour"
1818
import { PiImageSquare } from "@react-icons/all-files/pi/PiImageSquare"
1919
import { PiListBullets } from "@react-icons/all-files/pi/PiListBullets"
20-
import { type FC, useEffect, useState } from "react"
20+
import { type FC, useMemo } from "react"
2121
import { useEditorStore } from "../../store"
2222

2323
interface ActionBarProps {
@@ -33,25 +33,19 @@ export const ActionBar: FC<ActionBarProps> = ({
3333
gridImageSize,
3434
setGridImageSize,
3535
}) => {
36-
const { currentImage, showOriginal, setShowOriginal } = useEditorStore()
36+
const {
37+
currentImage,
38+
imageList,
39+
originalImageList,
40+
showOriginal,
41+
setShowOriginal,
42+
} = useEditorStore()
3743

38-
const [imageDimensions, setImageDimensions] = useState<{
39-
width: number
40-
height: number
41-
} | null>(null)
42-
43-
useEffect(() => {
44-
if (currentImage) {
45-
const img = new Image()
46-
img.onload = () => {
47-
setImageDimensions({
48-
width: img.naturalWidth,
49-
height: img.naturalHeight,
50-
})
51-
}
52-
img.src = currentImage
53-
}
54-
}, [currentImage])
44+
const imageDimensions = useMemo(() => {
45+
const idx = imageList.findIndex((img) => img === currentImage)
46+
if (idx === -1) return null
47+
return originalImageList[idx].imageDimensions
48+
}, [currentImage, imageList, originalImageList])
5549

5650
return (
5751
<Box

packages/imagekit-editor-dev/src/components/editor/GridView.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const GridView: FC<GridViewProps> = ({ imageSize, onAddImage }) => {
2727
originalImageList,
2828
signingImages,
2929
removeImage,
30+
setImageDimensions,
3031
} = useEditorStore()
3132
return (
3233
<Flex
@@ -157,6 +158,12 @@ export const GridView: FC<GridViewProps> = ({ imageSize, onAddImage }) => {
157158
</Center>
158159
}
159160
isLoading={isSigning}
161+
onLoad={(event) => {
162+
setImageDimensions(originalImageList[index]!.url, {
163+
width: event.currentTarget.naturalWidth,
164+
height: event.currentTarget.naturalHeight,
165+
})
166+
}}
160167
/>
161168
</Box>
162169
)}

packages/imagekit-editor-dev/src/components/editor/ListView.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const ListView: FC<ListViewProps> = ({ onAddImage }) => {
1515
imageList,
1616
originalImageList,
1717
signingImages,
18+
setImageDimensions,
1819
_internalState,
1920
} = useEditorStore()
2021

@@ -53,6 +54,16 @@ export const ListView: FC<ListViewProps> = ({ onAddImage }) => {
5354
const originalUrl = originalImageList[idx]?.url
5455
return originalUrl ? signingImages[originalUrl] : false
5556
})()}
57+
onLoad={(event) => {
58+
console.log(event)
59+
if (!currentImage) return
60+
const idx = imageList.findIndex((img) => img === currentImage)
61+
if (idx === -1) return
62+
setImageDimensions(originalImageList[idx]!.url, {
63+
width: event.currentTarget.naturalWidth,
64+
height: event.currentTarget.naturalHeight,
65+
})
66+
}}
5667
/>
5768
</Flex>
5869
</Flex>

packages/imagekit-editor-dev/src/components/header/index.tsx

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,46 @@ import { PiImageSquare } from "@react-icons/all-files/pi/PiImageSquare"
1414
import { PiImagesSquare } from "@react-icons/all-files/pi/PiImagesSquare"
1515
import { PiX } from "@react-icons/all-files/pi/PiX"
1616
import React, { useMemo } from "react"
17-
import { useEditorStore } from "../../store"
17+
import {
18+
type FileElement,
19+
type RequiredMetadata,
20+
useEditorStore,
21+
} from "../../store"
1822

19-
interface ExportOptionButton {
23+
interface ExportOptionButton<
24+
Metadata extends RequiredMetadata = RequiredMetadata,
25+
> {
2026
type: "button"
2127
label: string
2228
icon?: React.ReactElement
2329
isVisible: boolean | ((images: string[], currentImage?: string) => boolean)
24-
onClick: (images: string[], currentImage?: string) => void
30+
onClick: (
31+
images: { url: string; file: FileElement<Metadata> }[],
32+
currentImage?: { url: string; file: FileElement<Metadata> },
33+
) => void
2534
}
2635

27-
interface ExportOptionMenu {
36+
interface ExportOptionMenu<
37+
Metadata extends RequiredMetadata = RequiredMetadata,
38+
> {
2839
type: "menu"
2940
label: string
3041
icon?: React.ReactElement
3142
isVisible: boolean | ((images: string[], currentImage?: string) => boolean)
32-
options: Array<Omit<ExportOptionButton, "type">>
43+
options: Array<Omit<ExportOptionButton<Metadata>, "type">>
3344
}
3445

35-
export interface HeaderProps {
46+
export interface HeaderProps<
47+
Metadata extends RequiredMetadata = RequiredMetadata,
48+
> {
3649
onClose: () => void
37-
exportOptions?: Array<ExportOptionButton | ExportOptionMenu>
50+
exportOptions?: Array<
51+
ExportOptionButton<Metadata> | ExportOptionMenu<Metadata>
52+
>
3853
}
3954

4055
export const Header = ({ onClose, exportOptions }: HeaderProps) => {
41-
const { imageList, currentImage } = useEditorStore()
56+
const { imageList, originalImageList, currentImage } = useEditorStore()
4257

4358
const headerText = useMemo(() => {
4459
if (imageList.length === 1) {
@@ -92,7 +107,19 @@ export const Header = ({ onClose, exportOptions }: HeaderProps) => {
92107
borderRadius="0"
93108
px="8"
94109
size="sm"
95-
onClick={() => exportOption.onClick(imageList, currentImage)}
110+
onClick={() => {
111+
const images = imageList.map((image, index) => ({
112+
url: image,
113+
file: originalImageList[index],
114+
}))
115+
const cImage = images.find(
116+
(image) => image.url === currentImage,
117+
)
118+
exportOption.onClick(images, {
119+
url: cImage!.url,
120+
file: cImage!.file,
121+
})
122+
}}
96123
>
97124
{exportOption.label}
98125
</Button>
@@ -121,7 +148,19 @@ export const Header = ({ onClose, exportOptions }: HeaderProps) => {
121148
.map((option) => (
122149
<MenuItem
123150
key={`export-menu-option-${option.label}`}
124-
onClick={() => option.onClick(imageList, currentImage)}
151+
onClick={() => {
152+
const images = imageList.map((image, index) => ({
153+
url: image,
154+
file: originalImageList[index],
155+
}))
156+
const cImage = images.find(
157+
(image) => image.url === currentImage,
158+
)
159+
option.onClick(images, {
160+
url: cImage!.url,
161+
file: cImage!.file,
162+
})
163+
}}
125164
>
126165
{option.label}
127166
</MenuItem>

0 commit comments

Comments
 (0)