Summary
When cropping an image through the Inspector, Open Slide writes objectFit, objectPosition, and objectViewBox back to the JSX source location for the selected <img>. If that image is rendered from a reused component, the source location is the shared component implementation, so cropping one rendered instance changes every instance in the deck.
This is easy to trigger with common slide code that wraps screenshots in a reusable component.
Environment
- Package:
@open-slide/core
- Version observed:
1.10.0
Minimal reproduction
const ScreenshotFrame = ({ src, alt }: { src: string; alt: string }) => (
<div style={{ width: 700, height: 500, overflow: "hidden" }}>
<img
src={src}
alt={alt}
style={{ width: "100%", height: "100%", objectFit: "contain" }}
/>
</div>
);
const PageA: Page = () => <ScreenshotFrame src={imageA} alt="A" />;
const PageB: Page = () => <ScreenshotFrame src={imageB} alt="B" />;
Steps:
- Open
PageA in the editor.
- Use Inspector -> Crop on the rendered image.
- Apply and save the crop.
- Open
PageB.
Actual behavior
The crop styles are written to the <img> inside ScreenshotFrame, so both PageA and PageB are cropped. In a larger deck this can silently alter many pages at once.
Expected behavior
Cropping a selected image should not silently change other rendered image instances. Ideally it should affect only the selected rendered instance. If Open Slide cannot safely rewrite only that instance, it should warn or block the operation.
Why this happens
The Inspector style writeback appears to be keyed by source line:column. Reused components render multiple DOM nodes that share the same source location, so a style operation on one instance is applied to the shared JSX implementation.
The editor already has some instance-aware handling for text edits via per-instance ids, but crop/style operations are still source-location based.
Suggested fix
A conservative fix would be:
- Before applying crop style ops, check whether the selected image's
data-slide-loc appears on multiple rendered DOM nodes in the current deck/page scope.
- If multiple rendered nodes share that source location, warn the user that this crop will affect all instances.
- Default to blocking the save unless the user explicitly chooses an "apply to all instances" action.
A fuller fix could support instance-level rewrites, but arbitrary React components may not expose a safe style / imageStyle prop path. Warning/blocking would already prevent accidental deck-wide damage.
Workaround
Inline each crop-target image directly in the page JSX instead of rendering it from a reused component. That gives each image a unique source location, so crop writeback only affects the intended image.
Summary
When cropping an image through the Inspector, Open Slide writes
objectFit,objectPosition, andobjectViewBoxback to the JSX source location for the selected<img>. If that image is rendered from a reused component, the source location is the shared component implementation, so cropping one rendered instance changes every instance in the deck.This is easy to trigger with common slide code that wraps screenshots in a reusable component.
Environment
@open-slide/core1.10.0Minimal reproduction
Steps:
PageAin the editor.PageB.Actual behavior
The crop styles are written to the
<img>insideScreenshotFrame, so bothPageAandPageBare cropped. In a larger deck this can silently alter many pages at once.Expected behavior
Cropping a selected image should not silently change other rendered image instances. Ideally it should affect only the selected rendered instance. If Open Slide cannot safely rewrite only that instance, it should warn or block the operation.
Why this happens
The Inspector style writeback appears to be keyed by source
line:column. Reused components render multiple DOM nodes that share the same source location, so a style operation on one instance is applied to the shared JSX implementation.The editor already has some instance-aware handling for text edits via per-instance ids, but crop/style operations are still source-location based.
Suggested fix
A conservative fix would be:
data-slide-locappears on multiple rendered DOM nodes in the current deck/page scope.A fuller fix could support instance-level rewrites, but arbitrary React components may not expose a safe
style/imageStyleprop path. Warning/blocking would already prevent accidental deck-wide damage.Workaround
Inline each crop-target image directly in the page JSX instead of rendering it from a reused component. That gives each image a unique source location, so crop writeback only affects the intended image.