Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 7 additions & 3 deletions packages/imagekit-editor-dev/src/components/RetryableImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
} from "@chakra-ui/react"
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { useVisibility } from "../hooks/useVisibility"
import { useEditorStore } from "../store"

export interface RetryableImageProps extends ImageProps {
maxRetries?: number
Expand Down Expand Up @@ -105,11 +104,12 @@ export default function RetryableImage(props: RetryableImageProps) {
setProbing(true)
}, [currentSrcBase, src])

// biome-ignore lint/correctness/useExhaustiveDependencies: <not needed>
useEffect(() => {
if (!src) return
if (lazy && !visible) return
setAttempt(0)
beginLoad(0)
beginLoad()
}, [src, visible, lazy])

const scheduleRetry = useCallback(() => {
Expand Down Expand Up @@ -156,7 +156,11 @@ export default function RetryableImage(props: RetryableImageProps) {
}

return (
<Box ref={rootRef as any} position="relative" display="inline-block">
<Box
ref={rootRef as React.RefObject<HTMLDivElement>}
position="relative"
display="inline-block"
>
{error ? (
<Center
w={imgProps.width || "full"}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
type As,
Box,
Flex,
HStack,
Expand Down Expand Up @@ -67,6 +68,7 @@ export const CheckboxCardField: React.FC<CheckboxCardFieldProps> = ({
}

return (
// biome-ignore lint/a11y/useSemanticElements: <role used to concur to chakra standard>
<HStack
as="fieldset"
id={id}
Expand All @@ -85,6 +87,7 @@ export const CheckboxCardField: React.FC<CheckboxCardFieldProps> = ({
const isChecked = value.includes(opt.value)
const disabled = opt.isDisabled || (!isChecked && isMaxed)
return (
// biome-ignore lint/a11y/useSemanticElements: <role used to concur to chakra standard>
<Box
key={opt.value}
data-checkbox-card
Expand Down Expand Up @@ -114,7 +117,7 @@ export const CheckboxCardField: React.FC<CheckboxCardFieldProps> = ({
}}
>
<Flex align="center" gap="2">
{opt.icon ? <Icon as={opt.icon as any} boxSize="16px" /> : null}
{opt.icon ? <Icon as={opt.icon as As} boxSize="16px" /> : null}
<Text fontSize="sm" noOfLines={1}>
{opt.label}
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
PopoverTrigger,
} from "@chakra-ui/react"
import { memo, useEffect, useState } from "react"
import ColorPicker, { ColorPickerProps } from "react-best-gradient-color-picker"
import ColorPicker, {
type ColorPickerProps,
} from "react-best-gradient-color-picker"
import { useDebounce } from "../../hooks/useDebounce"

const ColorPickerField = ({
Expand Down
188 changes: 128 additions & 60 deletions packages/imagekit-editor-dev/src/components/common/CornerRadiusInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,22 @@ import {
Flex,
HStack,
Icon,
Text,
IconButton,
Input,
InputGroup,
InputLeftElement,
IconButton,
useColorModeValue,
Text,
Tooltip,
useColorModeValue,
} from "@chakra-ui/react"
import { set } from "lodash"
import type * as React from "react"
import { useState, useEffect, forwardRef } from "react"
import { RxCornerBottomLeft } from "@react-icons/all-files/rx/RxCornerBottomLeft"
import { RxCornerBottomRight } from "@react-icons/all-files/rx/RxCornerBottomRight"
import { RxCornerTopLeft } from "@react-icons/all-files/rx/RxCornerTopLeft"
import { RxCornerTopRight } from "@react-icons/all-files/rx/RxCornerTopRight"
import { RxCornerBottomRight } from "@react-icons/all-files/rx/RxCornerBottomRight"
import { RxCornerBottomLeft } from "@react-icons/all-files/rx/RxCornerBottomLeft"
import { TbBorderCorners } from "@react-icons/all-files/tb/TbBorderCorners"
import { FieldErrors } from "react-hook-form"
import { set } from "lodash"
import type * as React from "react"
import { useEffect, useState } from "react"

type RadiusMode = "uniform" | "individual"

Expand All @@ -28,28 +27,43 @@ export type RadiusState = {
radius: RadiusObject | string
}

type RadiusInputFieldProps = {
id?: string
onChange: (value: RadiusState) => void
errors?: FieldErrors<Record<string, unknown>>
name: string,
value?: Partial<RadiusState>
}

export type RadiusObject = {
topLeft: string | "max"
topRight: string | "max"
bottomRight: string | "max"
bottomLeft: string | "max"
}

type ErrorObject = {
message: string
}

type CornerErrors = {
[key in keyof RadiusObject]?: ErrorObject
} & ErrorObject

export type RadiusErrors = Record<
string,
{
radius?: CornerErrors
}
>

type RadiusInputFieldProps = {
id?: string
onChange: (value: RadiusState) => void
errors?: RadiusErrors
name: string
value?: Partial<RadiusState>
}

type RadiusDirection = "topLeft" | "topRight" | "bottomRight" | "bottomLeft"

function getUpdatedRadiusValue(
current: RadiusObject | string,
corner: RadiusDirection | "all",
value: string,
mode: "uniform" | "individual"
mode: "uniform" | "individual",
): RadiusObject | string {
let inputValue: RadiusObject | number | string
try {
Expand All @@ -60,24 +74,37 @@ function getUpdatedRadiusValue(
if (mode === "uniform") {
if (inputValue === "") {
return ""
} else if (typeof inputValue === "string" || typeof inputValue === "number") {
} else if (
typeof inputValue === "string" ||
typeof inputValue === "number"
) {
return inputValue.toString()
} else {
const { topLeft, topRight, bottomRight, bottomLeft } = inputValue
if (topLeft === topRight && topLeft === bottomRight && topLeft === bottomLeft) {
if (
topLeft === topRight &&
topLeft === bottomRight &&
topLeft === bottomLeft
) {
return topLeft
} else {
return "";
return ""
}
}
} else {
let commonValue: string = ""
if (typeof inputValue === "string" || typeof inputValue === "number") {
commonValue = inputValue.toString()
}
const updatedRadius = current && typeof current === "object"
? { ...current }
: { topLeft: commonValue, topRight: commonValue, bottomRight: commonValue, bottomLeft: commonValue }
const updatedRadius =
current && typeof current === "object"
? { ...current }
: {
topLeft: commonValue,
topRight: commonValue,
bottomRight: commonValue,
bottomLeft: commonValue,
}
if (corner !== "all") {
set(updatedRadius, corner, inputValue.toString())
}
Expand All @@ -90,29 +117,36 @@ export const RadiusInputField: React.FC<RadiusInputFieldProps> = ({
onChange,
errors,
name: propertyName,
value
value,
}) => {
const [radiusMode, setRadiusMode] = useState<RadiusMode>(value?.mode ?? "uniform")
const [radiusValue, setRadiusValue] = useState<RadiusObject | string>(value?.radius ?? "")
const [radiusMode, setRadiusMode] = useState<RadiusMode>(
value?.mode ?? "uniform",
)
const [radiusValue, setRadiusValue] = useState<RadiusObject | string>(
value?.radius ?? "",
)
const errorRed = useColorModeValue("red.500", "red.300")
const activeColor = useColorModeValue("blue.500", "blue.600")
const inactiveColor = useColorModeValue("gray.600", "gray.400")

// biome-ignore lint/correctness/useExhaustiveDependencies: <causes re-render loop if added>
useEffect(() => {
const formatRadiusValue = (value: RadiusObject | string): string | RadiusObject => {
const formatRadiusValue = (
value: RadiusObject | string,
): string | RadiusObject => {
if (value === "") return ""
if (typeof value === "string") {
return value
} else {
return value;
return value
}
}
const formattedValue = formatRadiusValue(radiusValue)
onChange({ mode: radiusMode, radius: formattedValue })
}, [radiusValue, radiusMode])


return (
// biome-ignore lint/a11y/useSemanticElements: <role used to concur to chakra standard>
<HStack
as="fieldset"
id={id}
Expand All @@ -127,27 +161,35 @@ export const RadiusInputField: React.FC<RadiusInputFieldProps> = ({
<Input
onChange={(e) => {
const val = e.target.value
setRadiusValue(getUpdatedRadiusValue(
radiusValue,
"all",
val,
radiusMode
))
setRadiusValue(
getUpdatedRadiusValue(radiusValue, "all", val, radiusMode),
)
}}
value={typeof radiusValue === "string" ? radiusValue : ""}
placeholder="Uniform Radius"
isInvalid={!!errors?.[propertyName]?.radius}
fontSize="sm"
/>
<Text fontSize='xs' color={errorRed}>{errors?.[propertyName]?.radius?.message}</Text>
<Text fontSize="xs" color={errorRed}>
{errors?.[propertyName]?.radius?.message}
</Text>
</Box>
) : (
// biome-ignore lint/complexity/noUselessFragments: <fragment is required otherwise syntax breaks>
<>
{[
{ name: "topLeft", label: "Top Left", icon: RxCornerTopLeft },
{ name: "topRight", label: "Top Right", icon: RxCornerTopRight },
{ name: "bottomLeft", label: "Bottom Left", icon: RxCornerBottomLeft },
{ name: "bottomRight", label: "Bottom Right", icon: RxCornerBottomRight },
{
name: "bottomLeft",
label: "Bottom Left",
icon: RxCornerBottomLeft,
},
{
name: "bottomRight",
label: "Bottom Right",
icon: RxCornerBottomRight,
},
].map(({ name, label, icon }) => (
<Box flex="1 1 calc(50% - 4px)" key={name}>
<InputGroup>
Expand All @@ -157,53 +199,79 @@ export const RadiusInputField: React.FC<RadiusInputFieldProps> = ({
<Input
onChange={(e) => {
const val = e.target.value
setRadiusValue(getUpdatedRadiusValue(
radiusValue,
name as RadiusDirection,
val,
radiusMode
))
setRadiusValue(
getUpdatedRadiusValue(
radiusValue,
name as RadiusDirection,
val,
radiusMode,
),
)
}}
value={typeof radiusValue === "object" ? radiusValue?.[name as RadiusDirection] ?? "" : ""}
value={
typeof radiusValue === "object"
? (radiusValue?.[name as RadiusDirection] ?? "")
: ""
}
placeholder={label}
isInvalid={!!errors?.[propertyName]?.radius?.[name as RadiusDirection]}
isInvalid={
!!errors?.[propertyName]?.radius?.[
name as RadiusDirection
]
}
fontSize="sm"
/>
</InputGroup>
<Text fontSize='xs' color={errorRed}>{errors?.[propertyName]?.radius?.[name as RadiusDirection]?.message}</Text>
<Text fontSize="xs" color={errorRed}>
{
errors?.[propertyName]?.radius?.[name as RadiusDirection]
?.message
}
</Text>
</Box>
))}
</>
)}
</Flex>
<Tooltip
hasArrow
label={radiusMode === "uniform" ? "Enable individual radius" : "Disable individual radius"}
label={
radiusMode === "uniform"
? "Enable individual radius"
: "Disable individual radius"
}
openDelay={200}
modifiers={[
{
name: 'zIndex',
name: "zIndex",
enabled: true,
phase: 'write',
phase: "write",
fn({ state }) {
state.elements.popper.style.zIndex = '2100';
state.elements.popper.style.zIndex = "2100"
},
},
]}
>
<IconButton
aria-label={radiusMode === "uniform" ? "Switch to individual radius" : "Switch to uniform radius"}
aria-label={
radiusMode === "uniform"
? "Switch to individual radius"
: "Switch to uniform radius"
}
aria-pressed={radiusMode === "individual"}
icon={<TbBorderCorners size={20} />}
padding="0.05em"
onClick={() => {
const newRadiusMode = radiusMode === "uniform" ? "individual" : "uniform"
setRadiusValue(getUpdatedRadiusValue(
radiusValue,
"all",
JSON.stringify(radiusValue),
newRadiusMode
))
const newRadiusMode =
radiusMode === "uniform" ? "individual" : "uniform"
setRadiusValue(
getUpdatedRadiusValue(
radiusValue,
"all",
JSON.stringify(radiusValue),
newRadiusMode,
),
)
setRadiusMode(newRadiusMode)
}}
variant="outline"
Expand Down
Loading