Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: images keep size before loading #10750

Merged
merged 2 commits into from
Jan 30, 2025
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ const PhaseItemEditor = (props: Props) => {
>
<div
className={cn(
'ProseMirror flex max-h-28 min-h-4 w-full items-center px-4 pt-3 leading-none',
'ProseMirror flex max-h-28 min-h-4 w-full flex-col items-start justify-center px-4 pt-3 leading-none',
disableAnonymity ? 'pb-0' : 'pb-3'
)}
dangerouslySetInnerHTML={{__html: card.html}}
Expand Down
8 changes: 4 additions & 4 deletions packages/client/hooks/useBlockResizer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ const makeDrag = () => ({
})
export const useBlockResizer = (
width: number,
setWidth: (width: number) => void,
updateAttributes: (attrs: Record<string, any>) => void,
aspectRatioRef: RefObject<number>
aspectRatioRef: RefObject<number>,
maxWidth: number
) => {
const dragRef = useRef(makeDrag())
const onMouseUp = useEventCallback((e: MouseEvent | TouchEvent) => {
Expand Down Expand Up @@ -41,8 +41,8 @@ export const useBlockResizer = (
const sideCoefficient = drag.side === 'left' ? 1 : -1
const delta = (drag.lastX - clientX) * sideCoefficient
drag.lastX = clientX
const nextWidth = Math.max(48, width + delta)
setWidth(nextWidth)
const nextWidth = Math.min(maxWidth, Math.max(48, width + delta))
updateAttributes({width: nextWidth, height: Math.round(nextWidth / aspectRatioRef.current!)})
})

const onMouseDown = useEventCallback(
Expand Down
5 changes: 4 additions & 1 deletion packages/client/hooks/useTipTapReflectionEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ export const useTipTapReflectionEditor = (
'To-do list': false
}),
Focus,
ImageUpload.configure({editorWidth: ElementWidth.REFLECTION_CARD, editorHeight: 88}),
ImageUpload.configure({
editorWidth: ElementWidth.REFLECTION_CARD - 16 * 2,
editorHeight: 88
}),
ImageBlock,
LoomExtension,
Placeholder.configure({
Expand Down
4 changes: 2 additions & 2 deletions packages/client/tiptap/extensions/imageBlock/ImageBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ export const ImageBlock = ImageBlockBase.extend({
})
},
height: {
default: '100%',
default: undefined,
parseHTML: (element) => element.getAttribute('height'),
renderHTML: (attributes) => ({
height: attributes.height
})
},
width: {
default: '100%',
default: undefined,
parseHTML: (element) => element.getAttribute('width'),
renderHTML: (attributes) => ({
width: attributes.width
Expand Down
41 changes: 21 additions & 20 deletions packages/client/tiptap/extensions/imageBlock/ImageBlockView.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
import {NodeViewWrapper, type NodeViewProps} from '@tiptap/react'
import {useCallback, useEffect, useRef, useState} from 'react'
import {useCallback, useRef, useState} from 'react'
import {useBlockResizer} from '../../../hooks/useBlockResizer'
import {cn} from '../../../ui/cn'
import {BlockResizer} from './BlockResizer'
import {ImageBlockBubbleMenu} from './ImageBlockBubbleMenu'
export const ImageBlockView = (props: NodeViewProps) => {
const {editor, getPos, node, updateAttributes} = props
const imageWrapperRef = useRef<HTMLDivElement>(null)
const {src, align} = node.attrs

const {attrs} = node
const {src, align, height, width} = attrs
const alignClass =
align === 'left' ? 'justify-start' : align === 'right' ? 'justify-end' : 'justify-center'

const onClick = useCallback(() => {
editor.commands.setNodeSelection(getPos())
}, [getPos, editor.commands])

const maxHeightRef = useRef<number | undefined>(editor.storage.imageUpload.editorHeight)
const {current: maxHeight} = maxHeightRef
const aspectRatioRef = useRef(0)
const ref = useRef<HTMLImageElement>(null)
const [width, setWidth] = useState<number>(node.attrs.width || 0)
const {onMouseDown} = useBlockResizer(width, setWidth, updateAttributes, aspectRatioRef)
const [maxHeight, setMaxHeight] = useState(
// if no height is provided (first load), make sure the image is no taller than the editor
height ? undefined : editor.storage.imageUpload.editorHeight
)

const aspectRatioRef = useRef(1)
const {onMouseDown} = useBlockResizer(
width,
updateAttributes,
aspectRatioRef,
editor.storage.imageUpload.editorWidth
)
const onMouseDownLeft = onMouseDown('left')
const onMouseDownRight = onMouseDown('right')
useEffect(() => {
if (width === node.attrs.width) return
// the attributes will change if another instance (e.g. a reflection in an expanded stack) edits them
setWidth(node.attrs.width)
}, [node.attrs.width])
return (
<NodeViewWrapper>
<div className={cn('flex', alignClass)}>
Expand All @@ -38,15 +39,15 @@ export const ImageBlockView = (props: NodeViewProps) => {
src={src}
alt=''
onClick={onClick}
style={{maxHeight, width: width === 0 ? undefined : width}}
ref={ref}
style={{maxHeight}}
width={width}
height={height}
onLoad={(e) => {
const img = e.target as HTMLImageElement
console.log('loaded', img.width, img.height, maxHeightRef.current)
maxHeightRef.current = undefined
aspectRatioRef.current = img.width / img.height
if (img.width !== node.attrs.width) {
setWidth(img.width)
if (img.width !== width) {
// on initial load, once we grab the h/w/ar, remove the maxH constraint
setMaxHeight(undefined)
updateAttributes({width: img.width, height: img.height})
}
}}
Expand Down