Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1dc7e50
fix: resumable last session from localStorage
hrhv May 5, 2026
f513690
fix: noise on blank state; now new templates will never be created by…
hrhv May 5, 2026
a8a6128
fix: skeleton loaders in templates dropdown and library modal + fixed…
hrhv May 5, 2026
84ffdc6
fix: fixed gradient color picker crashing when clearing from color or…
hrhv May 5, 2026
f77060d
fix: layout shift in transformation name component due to overflowing…
hrhv May 5, 2026
6637c3a
fix: height of new button in template dropdown
hrhv May 5, 2026
8f4a4dc
chore: update example project to make sure it runs with the latest pa…
hrhv May 6, 2026
25363e2
chore: add yalc for local package linking and development workflow
ahnv May 6, 2026
274dbe8
chore: update example project to make sure it runs with the latest pa…
hrhv May 6, 2026
d90d93a
chore: add yalc for local package linking and development workflow
ahnv May 6, 2026
2f9de99
fix: resume modal behavior conditions to respect the current change n…
hrhv May 12, 2026
2926374
ci: disabled yalc publish in test environments
hrhv May 12, 2026
2200f2e
chore: improved test coverage
hrhv May 12, 2026
d83d546
refactor: store split into slices and test cases to ensure nothing br…
hrhv May 12, 2026
c8e7687
Merge remote-tracking branch 'origin/main' into ux-improvements
hrhv May 12, 2026
1d91839
fix: issues with race conditions in drafts and provider syncs
hrhv May 12, 2026
02e7e21
fix: renaming a transformation now occupies entire space and does not…
hrhv May 12, 2026
704d9ae
fix: disabled save button in the template status dropdown when there …
hrhv May 12, 2026
266aee5
fix: initial visibility prop mapping to id instead of name - unused i…
hrhv May 12, 2026
a781158
feat: updated example project to match the consuming project's dom st…
hrhv May 12, 2026
18ede78
fix: added validations for gradient from and to colors
hrhv May 12, 2026
0d80a8f
fix: increase number of items displayed in templates dropdown
hrhv May 12, 2026
1ffa82a
chore: bump version for testing
hrhv May 12, 2026
e678cbb
chore: bump version to 3.0.1 for release
hrhv May 13, 2026
3d641f6
Merge pull request #12 from imagekit-developer/ux-improvements
hrhv May 13, 2026
5321587
Merge with main
manu4543 May 15, 2026
0c7ffde
Fix lint
manu4543 May 15, 2026
1978412
fix: update coverage include paths and lower branch threshold to acco…
manu4543 May 15, 2026
c69b548
feat: add colorize transformation with adjustable tint and intensity
manu4543 May 15, 2026
6ea22d3
feat: add new crop/resize modes and update visibility logic for no en…
manu4543 May 15, 2026
1e20135
fix: update transformation initialization to use transformation ID in…
manu4543 May 15, 2026
b018acc
fix: update resume session modal to remove close editor functionality…
manu4543 May 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion examples/react-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@chakra-ui/hooks": "^1.7.1",
"@chakra-ui/icons": "1.1.1",
"@chakra-ui/react": "^1.6.7",
"@emotion/react": "^11",
"@emotion/styled": "^11",
"@imagekit/editor": "workspace:*",
"@types/node": "^20.11.24",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"framer-motion": "6.5.1",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react-dom": "^17.0.2",
"react-select": "^5.2.1"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.5.2",
Expand Down
130 changes: 122 additions & 8 deletions examples/react-example/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,118 @@
import { Icon } from "@chakra-ui/react"
import { Box, ChakraProvider, Portal } from "@chakra-ui/react"
import {
createLocalStorageProvider,
ImageKitEditor,
type ImageKitEditorProps,
type ImageKitEditorRef,
type TemplateStorageProvider,
TRANSFORMATION_STATE_VERSION,
type Transformation,
} from "@imagekit/editor"
import { PiDownload } from "@react-icons/all-files/pi/PiDownload"
import React, { useCallback, useEffect } from "react"
import ReactDOM from "react-dom"
import { hostTheme } from "./theme/hostTheme"

const TEMPLATE_STORAGE_KEY = "ik-editor:templates:v1"

type StoredTemplateRecord = {
id: string
clientNumber: string
isPrivate: boolean
isPinned: boolean
name: string
transformations: Omit<Transformation, "id">[]
createdBy: { userId: string; name: string; email: string }
updatedBy: { userId: string; name: string; email: string }
createdAt: number
updatedAt: number
lastUsedAt?: number
}

function readAllTemplates(): StoredTemplateRecord[] {
const raw = localStorage.getItem(TEMPLATE_STORAGE_KEY)
if (!raw) return []
try {
const parsed = JSON.parse(raw)
return Array.isArray(parsed) ? (parsed as StoredTemplateRecord[]) : []
} catch {
return []
}
}

function writeAllTemplates(records: StoredTemplateRecord[]) {
localStorage.setItem(TEMPLATE_STORAGE_KEY, JSON.stringify(records))
}

function createLocalTemplateStorage(): TemplateStorageProvider {
const session = {
userId: "demo-user",
name: "Demo User",
email: "demo@example.com",
clientNumber: "demo-client",
}

return {
async listTemplates() {
return readAllTemplates().sort((a, b) => b.updatedAt - a.updatedAt)
},
async getTemplate(id: string) {
return readAllTemplates().find((t) => t.id === id) ?? null
},
async saveTemplate(input) {
const now = Date.now()
const all = readAllTemplates()
const existing = input.id
? (all.find((t) => t.id === input.id) ?? null)
: null

const id = existing?.id ?? crypto.randomUUID?.() ?? String(now)
const record: StoredTemplateRecord = {
id,
clientNumber: input.clientNumber ?? existing?.clientNumber ?? "demo",
isPrivate: input.isPrivate ?? existing?.isPrivate ?? false,
isPinned: input.isPinned ?? existing?.isPinned ?? false,
name: input.name,
transformations: input.transformations,
createdBy: input.createdBy ??
existing?.createdBy ?? {
userId: session.userId,
name: session.name,
email: session.email,
},
updatedBy: input.updatedBy ?? {
userId: session.userId,
name: session.name,
email: session.email,
},
createdAt: input.createdAt ?? existing?.createdAt ?? now,
updatedAt: input.updatedAt ?? now,
lastUsedAt: existing?.lastUsedAt,
}

const next = [record, ...all.filter((t) => t.id !== id)]
writeAllTemplates(next)
return record
},
async deleteTemplate(id: string) {
writeAllTemplates(readAllTemplates().filter((t) => t.id !== id))
},
async setTemplatePinned(id: string, isPinned: boolean) {
const all = readAllTemplates()
const existing = all.find((t) => t.id === id)
if (!existing) {
throw new Error("Template not found")
}
const updated = { ...existing, isPinned, updatedAt: Date.now() }
writeAllTemplates([updated, ...all.filter((t) => t.id !== id)])
return updated
},
getProviderName() {
return "localStorage"
},
getCurrentUserSession() {
return session
},
}
}

function App() {
const [open, setOpen] = React.useState(true)
Expand Down Expand Up @@ -115,12 +219,14 @@ function App() {
// })),
],
onAddImage: handleAddImage,
onClose: () => setOpen(false),
onClose: ({ destroy }) => {
destroy()
setOpen(false)
},
exportOptions: [
{
type: "button",
label: "Export",
icon: <Icon boxSize={"5"} as={PiDownload} />,
isVisible: true,
onClick: (images, currentImage) => {
console.log("Export images:", images, currentImage)
Expand Down Expand Up @@ -149,7 +255,7 @@ function App() {
console.log("Signed URL", request.url)
return Promise.resolve(request.url)
},
templateStorage: createLocalStorageProvider(),
templateStorage: createLocalTemplateStorage(),
})
}, [handleAddImage])

Expand Down Expand Up @@ -318,15 +424,23 @@ function App() {
</div>
</div>

{open && editorProps && <ImageKitEditor {...editorProps} ref={ref} />}
{open && editorProps && (
<Portal>
<Box zIndex="modal" position="relative">
<ImageKitEditor {...editorProps} ref={ref} />
</Box>
</Portal>
)}
</>
)
}

const root = document.getElementById("root")
ReactDOM.render(
<React.StrictMode>
<App />
<ChakraProvider theme={hostTheme}>
<App />
</ChakraProvider>
</React.StrictMode>,
root,
)
57 changes: 57 additions & 0 deletions examples/react-example/src/theme/hostTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { extendTheme } from "@chakra-ui/react"

/**
* Mirrors consuming project's theme's z-index.ts
* and the component overrides that reference those tokens (tooltip, modal, popover).
*/
const zIndices = {
hide: -1,
auto: "auto" as const,
base: 0,
docked: 10,
dropdown: 1000,
sticky: 1100,
banner: 1200,
overlay: 1300,
modal: 2100,
popover: 2000,
skipLink: 1600,
toast: 1700,
tooltip: 2200,
}

export const hostTheme = extendTheme({
zIndices,
styles: {
global: {
html: { overflow: "hidden" },
},
},
components: {
Tooltip: {
baseStyle: {
zIndex: "tooltip",
},
},
Popover: {
baseStyle: {
popper: {
zIndex: "popover",
},
},
},
Modal: {
baseStyle: {
overlay: {
zIndex: "modal",
},
dialogContainer: {
zIndex: "modal",
},
dialog: {
zIndex: "modal",
},
},
},
},
})
4 changes: 2 additions & 2 deletions packages/imagekit-editor-dev/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "imagekit-editor-dev",
"version": "3.0.0",
"version": "3.0.1",
"description": "AI Image Editor powered by ImageKit",
"scripts": {
"prepack": "yarn build",
Expand Down Expand Up @@ -50,7 +50,7 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@hookform/resolvers": "^5.1.1",
"@imagekit/javascript": "^5.3.0",
"@imagekit/javascript": "^5.4.0",
"@react-icons/all-files": "https://github.com/react-icons/react-icons/releases/download/v5.4.0/react-icons-all-files-5.4.0.tgz",
"@tanstack/react-virtual": "^3.13.12",
"framer-motion": "6.5.1",
Expand Down
Loading
Loading