Skip to content

feat!: constrain the image to the component's max height - #42

Merged
paodb merged 1 commit into
masterfrom
feat/image-max-height
Nov 4, 2026
Merged

paodb merged 1 commit into
masterfrom
feat/image-max-height

Conversation

@paodb

@paodb paodb commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

As discussed in #12, this breaking change was deferred to the next major version, so it is included in 2.0.

The image now scales down to fit the component's max height (and the available width), keeping its aspect ratio and without upscaling small images. For instance, getStyle().set("max-height", "70vh") keeps large images within a dialog.

  • Propagate the component's max-height to the image via CSS (only absolute and viewport units, such as px or vh, are supported)
  • Remove setImageFullHeight (breaking): use getStyle().set("max-height", "100vh") instead
  • Update the upload demo and README

Close #12
Close #8

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6c84812d-a0d9-4fde-8de6-19a04062da7d

No actionable comments were generated in the recent review.

Walkthrough

ImageCrop now implements Vaadin’s HasSize interface. Its styles constrain the crop element’s width and apply maximum-height inheritance to the crop wrapper. The README and upload demo show setting a maximum height of 70vh. The setImageFullHeight(Boolean) method and its viewport-height style were removed.

Changes

ImageCrop sizing

Layer / File(s) Summary
Component sizing API
src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java
ImageCrop implements HasSize and documents how the image scales to the available width and maximum height. The setImageFullHeight(Boolean) method was removed.
Sizing styles and usage examples
src/main/resources/META-INF/frontend/styles/image-crop-styles.css, README.md, src/test/java/com/flowingcode/vaadin/addons/imagecrop/UploadImageCropDemo.java
The crop element displays as inline-block with a maximum width of 100%, and the .ReactCrop wrapper inherits max-height. The README and demo set the component’s maximum height to 70vh.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Feature · Severity of issue fixed: Medium

Merge Risk: Minimal · previous review ea843

The crop image is constrained by the configured maximum height, so the documented sizing behavior is supported. No actionable issue remains before merge.

Pre-merge checks: Passed 4
Check name Status Explanation
Linked Issues check Passed The active linked issues have no conflicting coding acceptance criteria. For #12, the PR removes the obsolete setImageFullHeight(Boolean) API and documents setMaxHeight(...) as the replacement. Fo…
Out of Scope Changes check Passed The reviewed changes stay within #8 and #12. The Java API change, CSS rules, README example, and upload-demo change all support image sizing or the removal and replacement of setImageFullHeight. No …
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title "feat!: constrain the image to the component's max height" matches the main change in the changeset. The PR makes ImageCrop implement HasSize, scales large images to fit the maximum height a…
Full details: Linked Issues check

Explanation

The active linked issues have no conflicting coding acceptance criteria. For #12, the PR removes the obsolete setImageFullHeight(Boolean) API and documents setMaxHeight(...) as the replacement. For #8, ImageCrop now implements HasSize, the component has max-width: 100%, and the CSS propagates max-height through .ReactCrop to the image. The class documentation states that large images scale down with aspect ratio and small images are not upscaled. The README and upload demo document and use setMaxHeight("70vh"). Neither issue specifies an automated-test requirement.

Full details: Out of Scope Changes check

Explanation

The reviewed changes stay within #8 and #12. The Java API change, CSS rules, README example, and upload-demo change all support image sizing or the removal and replacement of setImageFullHeight. No unrelated behavior or files are identified in the supplied PR evidence.

Full details: Title check

Explanation

The title "feat!: constrain the image to the component's max height" matches the main change in the changeset. The PR makes ImageCrop implement HasSize, scales large images to fit the maximum height and available width, and removes setImageFullHeight. The "!" marker correctly flags the breaking change. The title names one aspect of the change, the height constraint, and omits the width scaling and the removal of setImageFullHeight. That omission is acceptable because the title does not need to cover every detail.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share
ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2949e623-cc99-4309-b9db-1742d64295e1
📥 Commits

Reviewing files that changed from the base of the PR and between 2892700 and ea84365.

📒 Files selected for processing: 4
  • README.md
  • src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java
  • src/main/resources/META-INF/frontend/styles/image-crop-styles.css
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/UploadImageCropDemo.java

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

@paodb
paodb marked this pull request as ready for review October 16, 2026 18:53
@javier-godoy
javier-godoy self-requested a review October 16, 2026 18:56

@javier-godoy javier-godoy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementing HasSize is an unrelated change

@paodb
paodb force-pushed the feat/image-max-height branch from ea84365 to ef5be8b Compare October 16, 2026 19:11
@paodb

paodb commented Oct 16, 2026 •

Copy link
Copy Markdown
Member Author

@javier-godoy Removed the HasSize implementation as it was unrelated; the examples now use getStyle().set("max-height", ...).

/* Propagate the component's max-height to the image (react-image-crop
applies max-height: inherit to its wrapper and to the image). */
image-crop .ReactCrop {
max-height: inherit;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inherit copies the max-height value as written, not as computed, so a percentage doesn't work. With max-height: 100% on an image-crop inside a 300px-tall container, the host resolves it to 300px. .ReactCrop also gets 100%, but resolves it against the host, whose height is auto, so it acts as none. The wrapper and the img inherit that, and a 4000×3000 image renders at 1280×960, overflowing the host. The same layout with max-height: 300px works (the image renders at 400×300). The same happens with calc() values that contain a percentage, and with a Dialog sized setMaxHeight("100%") like the one in the upload demo.

If only absolute and viewport lengths are meant to be supported, the Javadoc and README should say so; right now they promise the image fits "the component's max-height".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed: the image is now fitted in the .tsx to the component's measured height, so percentages, calc(), fixed heights and layout sizes all work. Javadoc and README updated accordingly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed: in a 300px container, max-height: 100% and calc(100% - 20px) now render a 4000×3000 image at 400×300 and 373×280, and the image also fits in a Dialog with setMaxHeight("100%"). The docs now claim a bit more than the code does, though; see my comment on the README.

@paodb
paodb requested a review from javier-godoy October 20, 2026 19:31
@paodb
paodb force-pushed the feat/image-max-height branch from 7e52563 to 8895cf0 Compare October 21, 2026 20:47
Comment on lines +165 to +166
const available = this.clientHeight - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom);
if (img.getBoundingClientRect().height > available + 0.5) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getBoundingClientRect() includes CSS transforms, but clientHeight doesn't, and a transform change doesn't trigger the ResizeObserver. In a Dialog, the image is measured during the opening animation, while the overlay is scaled to 0.95. With max-height: 70vh at a 905px viewport (633.5px) and a 1000×650 image, the image measures 618px, so it isn't clamped. When the animation ends, it renders at 650px in a 634px component, overflowing by 17px, and nothing refits it. The same happens inside any container with a scale below 1. Comparing img.offsetHeight, which isn't affected by transforms, avoids this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not applicable anymore: as discussed in the PR comments, the scope was narrowed to CSS only in ebe2ae4, so the image is no longer measured.

Comment on lines +163 to +167
cropElement.style.maxHeight = "";
const style = getComputedStyle(this);
const available = this.clientHeight - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom);
if (img.getBoundingClientRect().height > available + 0.5) {
cropElement.style.maxHeight = `${available}px`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Measuring with the clamp cleared assumes the clamp doesn't change the space the layout gives the component. In a flex container where a sibling can also shrink, it does: the space each item loses is weighted by its flex basis, and the clamp lowers the component's basis. In a 500px-tall flex column with an image-crop (1000×3000 image) and a sibling with flex: 0 1 200px, the unclamped component gets 469px, so the image is clamped to 469px. With that smaller basis the component then gets 351px, and the image overflows it by 118px. It stays that way: at 250px the overflow is 98px, at 700px it is 119px.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not applicable anymore: the JS measuring was removed in ebe2ae4; flex sizing is documented as not supported.

Comment thread README.md Outdated

* Constrain the size of large images

The image is scaled down to fit the component's size, whether it is set with `height` or `max-height` (in any unit) or given by the layout.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only holds when something limits the component's height. In a container that doesn't size its children, the component grows to the image's height, so nothing is clamped: with new Div(imageCrop) and div.setHeight("400px"), a 1000×4000 image renders at 4000px and overflows the Div. Percentages also need a parent with a defined height. Since HasSize was removed, setSizeFull() isn't available either.

Suggested change
The image is scaled down to fit the component's size, whether it is set with `height` or `max-height` (in any unit) or given by the layout.
The image is scaled down, keeping its aspect ratio, to fit the component's height when that height is limited: by a `height` or `max-height` set on the component, or by a flex layout such as `VerticalLayout` that sizes it. Percentages are resolved against the parent's height, so the parent needs a defined height. In a container that doesn't size its children, such as a `Div`, the component grows to the image's height; set a height on it, for instance `getStyle().set("height", "100%")`, to constrain the image.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in ebe2ae4: the README now says that only absolute and viewport units for max-height are supported.

Comment on lines +44 to +48
* The image is scaled down, keeping its aspect ratio, to fit the component's width
* and height, whether they are set on the component (a {@code height} or a
* {@code max-height} in any unit) or given by the layout it is in. For instance,
* {@code getStyle().set("max-height", "100vh")} keeps a large image within the
* viewport. Images smaller than these limits are shown at their natural size.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the README:

Suggested change
* The image is scaled down, keeping its aspect ratio, to fit the component's width
* and height, whether they are set on the component (a {@code height} or a
* {@code max-height} in any unit) or given by the layout it is in. For instance,
* {@code getStyle().set("max-height", "100vh")} keeps a large image within the
* viewport. Images smaller than these limits are shown at their natural size.
* The image is scaled down, keeping its aspect ratio, to fit the component's width
* and height. The height is limited by a {@code height} or {@code max-height} set on
* the component, or by a flex layout that sizes it, such as a {@code VerticalLayout}.
* Percentages are resolved against the parent's height, so they only take effect when
* the parent has a defined height. In a container that does not size its children,
* such as a {@code Div}, the component grows to the image's height unless a height is
* set on it. For instance, {@code getStyle().set("max-height", "100vh")} keeps a large
* image within the viewport. Images smaller than these limits are shown at their
* natural size.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in ebe2ae4: the Javadoc now says that only absolute and viewport units for max-height are supported.

@paodb

paodb commented Oct 23, 2026

Copy link
Copy Markdown
Member Author

@javier-godoy Each round of measuring in JS fixes one layout case and exposes another (transforms during the Dialog animation, flex-shrink feedback), and the general case of fitting the image to whatever height the layout gives the component seems hard to get right. #8 and #12 only ask to keep large images within the viewport or a dialog.

I'd suggest narrowing the scope: go back to the CSS-only approach from the first commit, drop fitImageHeight() and the ResizeObserver, and document that only absolute and viewport lengths for max-height are supported (px, vh, …), as you mentioned in your first review. Percentages, fixed heights and flex sizing could go to a separate issue if needed. What do you think?

@scardanzan

Copy link
Copy Markdown
Member

@javier-godoy Each round of measuring in JS fixes one layout case and exposes another (transforms during the Dialog animation, flex-shrink feedback), and the general case of fitting the image to whatever height the layout gives the component seems hard to get right. #8 and #12 only ask to keep large images within the viewport or a dialog.

I'd suggest narrowing the scope: go back to the CSS-only approach from the first commit, drop fitImageHeight() and the ResizeObserver, and document that only absolute and viewport lengths for max-height are supported (px, vh, …), as you mentioned in your first review. Percentages, fixed heights and flex sizing could go to a separate issue if needed. What do you think?

I agree, its better to have a simple solution that works.

@paodb
paodb force-pushed the feat/image-max-height branch from 8895cf0 to ebe2ae4 Compare November 4, 2026 17:48
@paodb

paodb commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

@scardanzan Thanks! Done in ebe2ae4: the JS measuring was removed and the image is fitted to max-height in CSS only. The README and Javadoc now say that only absolute and viewport units (such as px or vh) are supported.

@scardanzan scardanzan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

BREAKING CHANGE: setImageFullHeight was removed; use
getStyle().set("max-height", "100vh") instead.

Close #12
Close #8
@paodb
paodb force-pushed the feat/image-max-height branch from ebe2ae4 to c095293 Compare November 4, 2026 18:49
@sonarqubecloud

sonarqubecloud Bot commented Nov 4, 2026

Copy link
Copy Markdown

@paodb
paodb merged commit 73551f5 into master Nov 4, 2026
7 checks passed
@paodb
paodb deleted the feat/image-max-height branch November 4, 2026 19:01
@github-project-automation github-project-automation Bot moved this from In Progress to Pending release in Flowing Code Addons Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Pending release

Development

Successfully merging this pull request may close these issues.

Should imageFullHeight default to true? Constrain the size of the ImageCrop for large images.

3 participants