Skip to content

fix: handle CLS issues in chart modal#2032

Merged
graphieros merged 10 commits intomainfrom
chart-improvements
Mar 18, 2026
Merged

fix: handle CLS issues in chart modal#2032
graphieros merged 10 commits intomainfrom
chart-improvements

Conversation

@graphieros
Copy link
Contributor

The introduction of the data correction section in the chart modal leads to CLS when toggling the menu.
The fix consists in:

  • adapting the height of the chart depending on the open state of the data correction menu
  • pausing chart element transitions to avoid triggering them when the chart is resized.

BEFORE:

Enregistrement.de.l.ecran.2026-03-11.a.07.34.48.mov

AFTER:

Enregistrement.de.l.ecran.2026-03-11.a.07.31.29.mov

@vercel
Copy link

vercel bot commented Mar 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs.npmx.dev Ready Ready Preview, Comment Mar 18, 2026 11:44am
npmx.dev Ready Ready Preview, Comment Mar 18, 2026 11:44am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
npmx-lunaria Ignored Ignored Mar 18, 2026 11:44am

Request Review

@codecov
Copy link

codecov bot commented Mar 11, 2026

Codecov Report

❌ Patch coverage is 91.17647% with 3 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/components/Package/TrendsChart.vue 91.17% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This change makes TrendsChart dynamically compute chartHeight based on mobile vs non-mobile and whether correction controls or modal are shown, replacing static heights in the chart config. It adds a resize guard (isResizing) with debounce to pause SVG/chart transitions during resize and applies a no-transition class to chart primitives while resizing. The data-correction UI is refactored into a togglable, height-controlled container (showCorrectionControls) with accessible attributes, and minimap/legend/export rendering now respect the no-transition and responsive height state. Data rendering logic remains unchanged.

Possibly related PRs

Suggested reviewers

  • danielroe
  • ghostdevv
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description clearly relates to the changeset, explaining that it fixes cumulative layout shift (CLS) issues in the chart modal by adapting chart height and pausing transitions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chart-improvements
📝 Coding Plan
  • Generate coding plan for human review comments

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can scan for known vulnerabilities in your dependencies using OSV Scanner.

OSV Scanner will automatically detect and report security vulnerabilities in your project's dependencies. No additional configuration is required.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/components/Package/TrendsChart.vue (1)

1719-1726: Consider adding height to the transition for smoother expansion.

Currently, only opacity is transitioned (transition-[opacity]), so the container height snaps instantly from max-h-0 to max-h-[220px]. If you want a smoother expand/collapse animation, you could transition both properties:

-          class="overflow-hidden transition-[opacity] duration-200 ease-out"
+          class="overflow-hidden transition-[max-height,opacity] duration-200 ease-out"

If the instant height change is intentional to minimise perceived CLS, this is fine as-is.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 906e8b30-3531-4b15-abc5-49dfb0829107

📥 Commits

Reviewing files that changed from the base of the PR and between 3712560 and 6e5af51.

📒 Files selected for processing (1)
  • app/components/Package/TrendsChart.vue

@graphieros graphieros enabled auto-merge March 11, 2026 06:42
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/components/Package/TrendsChart.vue (1)

1698-1844: ⚠️ Potential issue | 🟠 Major

Make the correction panel a proper disclosure.

Line 1711 only hides the panel visually, so the sliders on Lines 1726, 1741 and 1756 plus the checkbox on Line 1828 stay tabbable when the section is “closed”. The toggle on Line 1698 also does not expose its expanded state.

♿ Suggested fix
         <button
           type="button"
+          :aria-expanded="showCorrectionControls"
+          aria-controls="trend-correction-controls"
           class="self-start flex items-center gap-1 text-2xs font-mono text-fg-subtle hover:text-fg transition-colors"
           `@click`="showCorrectionControls = !showCorrectionControls"
         >
@@
         <div
+          id="trend-correction-controls"
+          :aria-hidden="!showCorrectionControls"
+          :inert="!showCorrectionControls || undefined"
           class="overflow-hidden transition-[opacity] duration-200 ease-out"
           :class="
             showCorrectionControls
               ? 'max-h-[220px] opacity-100'
               : 'max-h-0 opacity-0 pointer-events-none'
           "
         >
🧹 Nitpick comments (1)
app/components/Package/TrendsChart.vue (1)

1351-1356: Unify the chart-height maths in one place.

chartHeight now uses 950 / 600 / 494, while the wrapper on Lines 1861-1867 uses a separate 567 / 491 branch. Those values will drift over time and make this CLS fix brittle, because the outer container and VueUiXy sizing can diverge silently.

Also applies to: 1861-1867


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 63f7d82a-30ad-4bb3-a3ba-65fb3d163667

📥 Commits

Reviewing files that changed from the base of the PR and between 6e5af51 and aaa02a0.

📒 Files selected for processing (1)
  • app/components/Package/TrendsChart.vue

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/components/Package/TrendsChart.vue (1)

2170-2173: Scope .no-transition styles to this component root

The selector is currently global and generic. Scoping it to #trends-chart keeps the transition guard local and avoids unintended styling collisions with other components using the same class name.

Proposed refactor
-.no-transition line,
-.no-transition circle {
+#trends-chart .no-transition line,
+#trends-chart .no-transition circle {
   transition: none !important;
 }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3f9108c3-aaba-4626-adf5-6ca247467e32

📥 Commits

Reviewing files that changed from the base of the PR and between aaa02a0 and 31ce284.

📒 Files selected for processing (1)
  • app/components/Package/TrendsChart.vue

@graphieros graphieros added the front Frontend, Design label Mar 14, 2026
@serhalp serhalp added the needs review This PR is waiting for a review from a maintainer label Mar 15, 2026
@graphieros graphieros requested review from MatteoGabriele, serhalp and shuuji3 and removed request for serhalp March 16, 2026 12:05
Copy link
Member

@shuuji3 shuuji3 left a comment

Choose a reason for hiding this comment

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

@graphieros Nice refinement ✨

I put two suggestions: simplifying with useTimeoutFn() and adding disabled prop.

Comment on lines +1354 to +1382
const isResizing = shallowRef(false)

const chartHeight = computed(() => {
if (isMobile.value) {
return 950
}
return showCorrectionControls.value && props.inModal ? 494 : 600
})

const timeoutId = shallowRef<ReturnType<typeof setTimeout> | null>(null)

function pauseChartTransitions() {
if (timeoutId.value) {
clearTimeout(timeoutId.value)
}

isResizing.value = true

timeoutId.value = setTimeout(() => {
isResizing.value = false
timeoutId.value = null
}, 200)
}

onBeforeUnmount(() => {
if (timeoutId.value) {
clearTimeout(timeoutId.value)
}
})
Copy link
Member

Choose a reason for hiding this comment

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

You can probably simplify timeout logic with useTimeoutFn() (ref. https://vueuse.org/shared/useTimeoutFn/). Calling start() resets the timer countdown from the beginning (playground), so this should provide the same behavior (not tested yet).

Suggested change
const isResizing = shallowRef(false)
const chartHeight = computed(() => {
if (isMobile.value) {
return 950
}
return showCorrectionControls.value && props.inModal ? 494 : 600
})
const timeoutId = shallowRef<ReturnType<typeof setTimeout> | null>(null)
function pauseChartTransitions() {
if (timeoutId.value) {
clearTimeout(timeoutId.value)
}
isResizing.value = true
timeoutId.value = setTimeout(() => {
isResizing.value = false
timeoutId.value = null
}, 200)
}
onBeforeUnmount(() => {
if (timeoutId.value) {
clearTimeout(timeoutId.value)
}
})
const isResizing = shallowRef(false)
const chartHeight = computed(() => {
if (isMobile.value) {
return 950
}
return showCorrectionControls.value && props.inModal ? 494 : 600
})
const { start } = useTimeoutFn(() => {
isResizing.value = false
}, 200, { immediate: false })
function pauseChartTransitions() {
isResizing.value = true
start()
}

Comment on lines +1718 to +1720
showCorrectionControls
? 'max-h-[220px] opacity-100'
: 'max-h-0 opacity-0 pointer-events-none'
Copy link
Member

Choose a reason for hiding this comment

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

Since v-if="showCorrectionControls" was removed, input elements seems to be still focusable by keyboard when collapsed. This adds three invisible focuses and pops up tooltips when you navigates by typing Tab 😅

screenshot of collapsed controls but tooptip is shown for hidden element

If we need h-0, I think we could add disabled to avoid focusing on them.

max="20"
step="1"
class="accent-[var(--accent-color,var(--fg-subtle))]"
/>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/>
:disabled="!showCorrectionControls"
/>

max="20"
step="1"
class="accent-[var(--accent-color,var(--fg-subtle))]"
/>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/>
:disabled="!showCorrectionControls"
/>

max="30"
step="1"
class="accent-[var(--accent-color,var(--fg-subtle))]"
/>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/>
:disabled="!showCorrectionControls"
/>

"
type="checkbox"
class="accent-[var(--accent-color,var(--fg-subtle))]"
/>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/>
:disabled="!showCorrectionControls"
/>

@graphieros
Copy link
Contributor Author

@shuuji3 thank you so much for your thorough review ❤️
Will rework the whole thing accordingly.

@graphieros graphieros removed the request for review from MatteoGabriele March 18, 2026 10:36
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
app/components/Package/TrendsChart.vue (1)

1695-1715: Expose the expand/collapse state to assistive technologies.

The toggle currently changes visibility visually, but it does not communicate expanded state or controlled region semantics. Adding aria-expanded / aria-controls on the button and id / aria-hidden (or inert) on the panel would improve screen-reader clarity.

♿ Suggested accessibility refinement
         <button
           type="button"
+          :aria-expanded="showCorrectionControls"
+          aria-controls="trends-correction-controls"
           class="self-start flex items-center gap-1 text-2xs font-mono text-fg-subtle hover:text-fg transition-colors"
           `@click`="showCorrectionControls = !showCorrectionControls"
         >
@@
-        <div
+        <div
+          id="trends-correction-controls"
+          :aria-hidden="!showCorrectionControls"
+          :inert="!showCorrectionControls"
           class="overflow-hidden transition-[opacity] duration-200 ease-out"
           :class="
             showCorrectionControls
               ? 'max-h-[220px] opacity-100'
               : 'max-h-0 opacity-0 pointer-events-none'
           "
         >

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0c93bdb3-7c5e-42be-8ea0-abc1ea0bcd43

📥 Commits

Reviewing files that changed from the base of the PR and between 31ce284 and 36136da.

📒 Files selected for processing (1)
  • app/components/Package/TrendsChart.vue

@graphieros graphieros requested a review from shuuji3 March 18, 2026 11:33
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/components/Package/TrendsChart.vue (1)

1682-1708: ⚠️ Potential issue | 🟠 Major

Misplaced ARIA attributes — move to the correct toggle button.

The aria-expanded and aria-controls attributes are on the reset date range button, but these attributes should be on the correction controls toggle button (lines 1697-1708). The reset button resets the date range and has no relationship to the correction controls panel.

🔧 Proposed fix

Remove ARIA attributes from the reset button:

       <button
         v-if="showResetButton"
-        :aria-expanded="showCorrectionControls"
-        aria-controls="trends-correction-controls"
         type="button"
         aria-label="Reset date range"

Add ARIA attributes to the correction controls toggle button:

       <button
         type="button"
+        :aria-expanded="showCorrectionControls"
+        aria-controls="trends-correction-controls"
         class="self-start flex items-center gap-1 text-2xs font-mono text-fg-subtle hover:text-fg transition-colors"
         `@click`="showCorrectionControls = !showCorrectionControls"
       >
🧹 Nitpick comments (1)
app/components/Package/TrendsChart.vue (1)

2175-2178: Consider including path elements if main chart line transitions cause CLS.

The current selector targets line and circle elements (used in estimation overlays), but if VueUiXy internally transitions path elements for the main chart lines, those may also need suppression during resize.

If you've tested this and confirmed no CLS from path transitions, this is fine as-is. Otherwise, consider:

 .no-transition line,
-.no-transition circle {
+.no-transition circle,
+.no-transition path {
   transition: none !important;
 }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 30be1dfe-55be-4201-8cb7-616fc1a93a9d

📥 Commits

Reviewing files that changed from the base of the PR and between 36136da and a8afbe1.

📒 Files selected for processing (1)
  • app/components/Package/TrendsChart.vue

Copy link
Member

@shuuji3 shuuji3 left a comment

Choose a reason for hiding this comment

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

Thanks, confirmed the fix! ✅

@graphieros graphieros added this pull request to the merge queue Mar 18, 2026
Merged via the queue into main with commit da2cf3e Mar 18, 2026
23 checks passed
@graphieros graphieros deleted the chart-improvements branch March 18, 2026 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

front Frontend, Design needs review This PR is waiting for a review from a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants