Skip to content

fix(Label): align celebration animation stroke radius with small size#3353

Open
yousefkadah wants to merge 4 commits into
mondaycom:masterfrom
yousefkadah:fix/label-celebration-animation-small-size
Open

fix(Label): align celebration animation stroke radius with small size#3353
yousefkadah wants to merge 4 commits into
mondaycom:masterfrom
yousefkadah:fix/label-celebration-animation-small-size

Conversation

@yousefkadah

@yousefkadah yousefkadah commented Apr 27, 2026

Copy link
Copy Markdown

User description

Fixes the celebration animation overflowing on small labels — it was drawing 4px corners around a 2px-radius box. Now passes the label's actual border-radius through to the animation.

Closes #3128


PR Type

Bug fix


Description

  • Dynamically read corner radii from rendered element instead of hardcoding

  • Support non-uniform border-radius on labels with legs or CSS overrides

  • Fix celebration stroke path to match label's actual shape and size

  • Align stroke-dasharray with drawn path length to prevent animation jumps


Diagram Walkthrough

flowchart LR
  A["Hardcoded 4px radius"] -->|Remove| B["Read from computed style"]
  B -->|Query inner element| C["Get actual corner radii"]
  C -->|Pass to path generator| D["Generate matching SVG path"]
  D -->|Calculate perimeter| E["Align stroke-dasharray"]
  E -->|Result| F["Smooth looping animation"]
Loading

File Walkthrough

Relevant files
Bug fix
LabelCelebrationAnimation.tsx
Dynamic corner radii and path alignment fixes                       

packages/core/src/components/Label/LabelCelebrationAnimation.tsx

  • Removed hardcoded DEFAULT_BORDER_RADIUS constant
  • Added CornerRadii interface to track individual corner radii (tl, tr,
    br, bl)
  • Implemented readCornerRadii() function to dynamically read computed
    border-radius values from the styled inner element via
    getComputedStyle()
  • Updated getPath() to accept individual corner radii and generate SVG
    path with proper insets for stroke width, ensuring smooth animation
  • Updated getPerimeter() to calculate perimeter based on actual corner
    radii and stroke width, fixing animation loop alignment
  • Modified resize observer callback to query the inner
    [data-celebration-text] element for accurate border-radius values
+53/-24 

The celebration animation hardcoded a 4px corner radius, which overflowed
the 2px-radius corners of small labels. Thread the actual border-radius
into the SVG path generator so the animated stroke matches the label's
rendered shape.

Closes mondaycom#3128

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@yousefkadah yousefkadah requested a review from a team as a code owner April 27, 2026 06:56
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2) 📎 Requirement gaps (0)

Context used

Grey Divider


Action required

1. Radii read from wrapper ✓ Resolved 🐞 Bug ≡ Correctness
Description
LabelCelebrationAnimation reads computed border radii from childRef (the outer Label wrapper
<span>), but Label’s border-radius is applied to a nested Text <span> (.label), so the computed
radii will be 0 and the SVG stroke path/perimeter won’t match the label’s rounded corners (including
the leg’s squared corner).
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R52-55]

Evidence
The animation measures radii from childRef.current, but the Label component applies border-radius
on the inner Text element (className={classNames} includes styles.label) rather than the outer
wrapper span, so getComputedStyle() on the outer span will return 0 radii and produce a square
path.

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[43-56]
packages/core/src/components/Label/Label.tsx[127-155]
packages/core/src/components/Label/Label.module.scss[14-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`readCornerRadii(childRef.current)` is reading computed border radii from the *outer* Label wrapper `<span>`, but the actual `border-radius` is applied to the nested Text `<span>` with `styles.label`. This makes the computed radii effectively 0, so the celebration SVG path doesn’t match the visual label corners.
### Issue Context
In `Label.tsx`, the element wrapped by `LabelCelebrationAnimation` is an outer `<span>`, while the rounded box styling is on the nested `<Text element="span" className={classNames} ...>`.
### Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[43-56]
### Suggested change
In the resize observer callback, resolve the actual element that has the label shape and border radius, and pass *that* into `readCornerRadii`.
For example (one option):
- Find the inner element via a stable selector like `[data-celebration-text]` (already present on the Text element), or by using `childRef.current.firstElementChild` if that structure is guaranteed.
- Then:
- `const shapeEl = childRef.current?.querySelector('[data-celebration-text]') as HTMLElement | null;`
- `const radii = readCornerRadii(shapeEl);`
Optionally, for maximum consistency, also measure width/height from the same `shapeEl` (or ensure the observed element is the same one you read radii from).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. LabelCelebrationAnimationProps defined inline 📘 Rule violation ⚙ Maintainability
Description
borderRadius was added to an inline props interface inside LabelCelebrationAnimation.tsx instead
of using a dedicated *.types.ts file extending VibeComponentProps. This breaks the required
types-first component structure and increases long-term API inconsistency risk.
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R18-23]

Evidence
PR Compliance ID 2 requires component props/interfaces to be defined in a dedicated *.types.ts
file extending VibeComponentProps; the PR adds the new borderRadius?: number prop directly
inside the component file’s LabelCelebrationAnimationProps interface.

CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md
packages/core/src/components/Label/LabelCelebrationAnimation.tsx[18-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`LabelCelebrationAnimationProps` is defined/extended inline in `LabelCelebrationAnimation.tsx` (updated in this PR), but compliance requires component props to live in a dedicated `*.types.ts` file and extend `VibeComponentProps`.
## Issue Context
This PR added `borderRadius?: number` to `LabelCelebrationAnimationProps`, so this is a good time to align the component with the required types-first structure.
## Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[18-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. LabelCelebrationAnimation not forwardRef 📘 Rule violation ⚙ Maintainability
Description
LabelCelebrationAnimation is still declared as a plain function component rather than being
implemented via React forwardRef. This violates the required component implementation pattern and
makes ref usage inconsistent across the system.
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R25-29]

Evidence
PR Compliance ID 3 requires React components to be implemented using forwardRef; the updated
component signature remains a plain function LabelCelebrationAnimation(...) rather than
forwardRef(...).

CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md
packages/core/src/components/Label/LabelCelebrationAnimation.tsx[25-29]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`LabelCelebrationAnimation` is implemented as a plain function component, but compliance requires using `React.forwardRef` for components.
## Issue Context
This PR changed the component signature to add `borderRadius`, so the component is already being modified and can be refactored to the required `forwardRef` pattern.
## Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[25-29]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Radii stale without resize 🐞 Bug ≡ Correctness ⭐ New
Description
LabelCelebrationAnimation recalculates the SVG path/perimeter only inside the ResizeObserver
callback, so border-radius changes that don’t affect width/height won’t update the stroke. This can
leave the celebration animation mismatched when isLegIncluded toggles (corner radii change only)
or when radii are changed via CSS overrides without resizing.
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R49-57]

Evidence
The animation’s radii are computed only in the ResizeObserver callback, but the Label can change
corner radii via a class toggle (withLeg) that does not necessarily change element dimensions;
therefore the callback may not run and the SVG path/perimeter can remain outdated.

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[43-58]
packages/core/src/components/Label/Label.module.scss[14-34]
packages/core/src/components/Label/Label.tsx[77-88]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`LabelCelebrationAnimation` reads corner radii and generates the SVG path/perimeter only when `ResizeObserver` fires. If the label’s border-radius changes without a size change (common when toggling classes like `withLeg`), the existing `path` and `--container-perimeter` stay stale and the animation no longer matches the rendered label shape.

### Issue Context
- `withLeg` changes only border radii (including forcing one corner to `0`) and can be toggled via `isLegIncluded`, but this does not inherently change layout size, so `ResizeObserver` may not fire.
- The PR’s stated goal includes supporting non-uniform radii / overrides; those can change independently of dimensions.

### Fix Focus Areas
- Add a non-resize recomputation trigger (e.g., a `useLayoutEffect/useEffect`) that recalculates `width/height` (via `getBoundingClientRect()`), re-reads computed radii, and updates `path` + `--container-perimeter` whenever the wrapped `children` changes (and/or when the underlying element’s class/style changes).
- Keep the existing ResizeObserver path for actual size changes, but share the same “recompute” function.

- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[43-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Hardcoded radius ignores token ✓ Resolved 🐞 Bug ≡ Correctness
Description
Label hardcodes labelBorderRadius to 4 for non-small labels even though the actual rendered
radius comes from var(--border-radius-small). If that CSS variable (or consumer overrides via
className/theme) changes, the celebration stroke will no longer match the label corners.
Code

packages/core/src/components/Label/Label.tsx[R174-182]

Evidence
The PR adds a TS-side mapping of size->radius (2/4) and passes it to the animation. But the actual
non-small label border-radius is defined via a CSS variable, so TS can drift from what is rendered
if the variable is overridden.

packages/core/src/components/Label/Label.tsx[172-185]
packages/core/src/components/Label/Label.module.scss[14-27]
packages/style/src/border-radius.scss[1-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Label` hardcodes `borderRadius` (2/4) when wrapping with `LabelCelebrationAnimation`, but the rendered radius for non-small labels is controlled by CSS (`var(--border-radius-small)`). This can cause animation/shape mismatch when design tokens are overridden.
### Issue Context
- Non-small labels use `border-radius: var(--border-radius-small)`.
- The animation needs the *actual* rendered radius to draw a matching SVG path.
### Fix Focus Areas
- packages/core/src/components/Label/Label.tsx[172-185]
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[25-48]
### Suggested fix
- Avoid hardcoding `4` in `Label.tsx` for the non-small case.
- Prefer deriving the radius from the rendered element:
- Option A (best): In `LabelCelebrationAnimation`, when `borderRadius` is not provided, read `getComputedStyle(childElement).borderTopLeftRadius` (parseFloat) and use that value.
- Option B: Read `--border-radius-small` via `getComputedStyle` and parseFloat (guard for SSR) and pass that into `LabelCelebrationAnimation`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

6. Unclamped borderRadius breaks path ✓ Resolved 🐞 Bug ☼ Reliability
Description
LabelCelebrationAnimation forwards the new borderRadius prop directly into
getPath/getPerimeter without guarding for negative or too-large values. If a caller passes an
invalid radius (e.g., larger than half the element size), the SVG path/perimeter math can become
invalid and break the stroke animation.
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R25-32]

Evidence
The new borderRadius prop is public to this component and is used in the geometry computations.
getPerimeter subtracts 2*borderRadius from width/height and getPath uses borderRadius in arc
commands, so invalid inputs can yield negative/NaN values or nonsensical SVG commands.

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[9-48]
packages/core/src/components/Label/LabelCelebrationAnimation.tsx[77-114]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `borderRadius` prop is used directly in SVG path and perimeter calculations. Invalid values (negative, NaN, or greater than `min(width,height)/2`) can produce broken paths and negative perimeters.
### Issue Context
Even if current internal callers pass safe values, this component now exposes an additional parameter that can be misused by future internal usage.
### Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[35-48]
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[77-114]
### Suggested fix
- In the resize callback, before calling `getPath/getPerimeter`:
- Guard `width`/`height` (return early if not finite numbers or <= 0).
- Clamp radius:
- `const maxR = Math.min(width, height) / 2;`
- `const r = Math.max(0, Math.min(borderRadius, maxR));`
- Use `r` for both `getPath` and `getPerimeter`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Ref mismatch with leg shape 🐞 Bug ≡ Correctness
Description
The celebration animation still assumes a uniform corner radius, but Label can render non-uniform
radii when isLegIncluded is true (one corner becomes square). This makes the PR’s “match the
rendered shape” guarantee incomplete for the reachable combination `kind="line" &&
celebrationAnimation && isLegIncluded`.
Code

packages/core/src/components/Label/Label.tsx[R172-185]

Evidence
Label applies styles.withLeg based solely on isLegIncluded and can still enter the celebration
wrapper when kind === "line". The leg styling sets one corner radius to 0, while the animation
path generator only supports a single borderRadius value for all corners.

packages/core/src/components/Label/Label.tsx[77-90]
packages/core/src/components/Label/Label.tsx[172-186]
packages/core/src/components/Label/Label.module.scss[29-34]
packages/core/src/components/Label/LabelCelebrationAnimation.tsx[77-99]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
With `isLegIncluded`, the label’s corner radii are not uniform (one corner is 0), but the celebration SVG path is generated using a single radius. This can cause visible mismatch for `kind="line"` labels that include a leg.
### Issue Context
`Label.tsx` wraps the already-styled `label` element with `LabelCelebrationAnimation` when `kind === "line"` and celebration is active; it does not check `isLegIncluded`.
### Fix Focus Areas
- packages/core/src/components/Label/Label.tsx[172-186]
- packages/core/src/components/Label/Label.module.scss[29-34]
### Suggested fix
- Easiest/least risky: prevent wrapping with `LabelCelebrationAnimation` when `isLegIncluded` is true.
- Alternatively (bigger change): extend the path generator to support per-corner radii and pass the correct corner set when the leg is included.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit 79d06e6

Results up to commit N/A


🐞 Bugs (1) 📘 Rule violations (2) 📎 Requirement gaps (0)


Action required
1. Radii read from wrapper ✓ Resolved 🐞 Bug ≡ Correctness
Description
LabelCelebrationAnimation reads computed border radii from childRef (the outer Label wrapper
<span>), but Label’s border-radius is applied to a nested Text <span> (.label), so the computed
radii will be 0 and the SVG stroke path/perimeter won’t match the label’s rounded corners (including
the leg’s squared corner).
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R52-55]

Evidence
The animation measures radii from childRef.current, but the Label component applies border-radius
on the inner Text element (className={classNames} includes styles.label) rather than the outer
wrapper span, so getComputedStyle() on the outer span will return 0 radii and produce a square
path.

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[43-56]
packages/core/src/components/Label/Label.tsx[127-155]
packages/core/src/components/Label/Label.module.scss[14-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`readCornerRadii(childRef.current)` is reading computed border radii from the *outer* Label wrapper `<span>`, but the actual `border-radius` is applied to the nested Text `<span>` with `styles.label`. This makes the computed radii effectively 0, so the celebration SVG path doesn’t match the visual label corners.
### Issue Context
In `Label.tsx`, the element wrapped by `LabelCelebrationAnimation` is an outer `<span>`, while the rounded box styling is on the nested `<Text element="span" className={classNames} ...>`.
### Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[43-56]
### Suggested change
In the resize observer callback, resolve the actual element that has the label shape and border radius, and pass *that* into `readCornerRadii`.
For example (one option):
- Find the inner element via a stable selector like `[data-celebration-text]` (already present on the Text element), or by using `childRef.current.firstElementChild` if that structure is guaranteed.
- Then:
- `const shapeEl = childRef.current?.querySelector('[data-celebration-text]') as HTMLElement | null;`
- `const radii = readCornerRadii(shapeEl);`
Optionally, for maximum consistency, also measure width/height from the same `shapeEl` (or ensure the observed element is the same one you read radii from).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. LabelCelebrationAnimationProps defined inline 📘 Rule violation ⚙ Maintainability
Description
borderRadius was added to an inline props interface inside LabelCelebrationAnimation.tsx instead
of using a dedicated *.types.ts file extending VibeComponentProps. This breaks the required
types-first component structure and increases long-term API inconsistency risk.
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R18-23]

Evidence
PR Compliance ID 2 requires component props/interfaces to be defined in a dedicated *.types.ts
file extending VibeComponentProps; the PR adds the new borderRadius?: number prop directly
inside the component file’s LabelCelebrationAnimationProps interface.

CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md
packages/core/src/components/Label/LabelCelebrationAnimation.tsx[18-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`LabelCelebrationAnimationProps` is defined/extended inline in `LabelCelebrationAnimation.tsx` (updated in this PR), but compliance requires component props to live in a dedicated `*.types.ts` file and extend `VibeComponentProps`.
## Issue Context
This PR added `borderRadius?: number` to `LabelCelebrationAnimationProps`, so this is a good time to align the component with the required types-first structure.
## Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[18-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. LabelCelebrationAnimation not forwardRef 📘 Rule violation ⚙ Maintainability
Description
LabelCelebrationAnimation is still declared as a plain function component rather than being
implemented via React forwardRef. This violates the required component implementation pattern and
makes ref usage inconsistent across the system.
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R25-29]

Evidence
PR Compliance ID 3 requires React components to be implemented using forwardRef; the updated
component signature remains a plain function LabelCelebrationAnimation(...) rather than
forwardRef(...).

CLAUDE.md: CLAUDE.md: CLAUDE.md: CLAUDE.md
packages/core/src/components/Label/LabelCelebrationAnimation.tsx[25-29]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`LabelCelebrationAnimation` is implemented as a plain function component, but compliance requires using `React.forwardRef` for components.
## Issue Context
This PR changed the component signature to add `borderRadius`, so the component is already being modified and can be refactored to the required `forwardRef` pattern.
## Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[25-29]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
4. Hardcoded radius ignores token ✓ Resolved 🐞 Bug ≡ Correctness
Description
Label hardcodes labelBorderRadius to 4 for non-small labels even though the actual rendered
radius comes from var(--border-radius-small). If that CSS variable (or consumer overrides via
className/theme) changes, the celebration stroke will no longer match the label corners.
Code

packages/core/src/components/Label/Label.tsx[R174-182]

Evidence
The PR adds a TS-side mapping of size->radius (2/4) and passes it to the animation. But the actual
non-small label border-radius is defined via a CSS variable, so TS can drift from what is rendered
if the variable is overridden.

packages/core/src/components/Label/Label.tsx[172-185]
packages/core/src/components/Label/Label.module.scss[14-27]
packages/style/src/border-radius.scss[1-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Label` hardcodes `borderRadius` (2/4) when wrapping with `LabelCelebrationAnimation`, but the rendered radius for non-small labels is controlled by CSS (`var(--border-radius-small)`). This can cause animation/shape mismatch when design tokens are overridden.
### Issue Context
- Non-small labels use `border-radius: var(--border-radius-small)`.
- The animation needs the *actual* rendered radius to draw a matching SVG path.
### Fix Focus Areas
- packages/core/src/components/Label/Label.tsx[172-185]
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[25-48]
### Suggested fix
- Avoid hardcoding `4` in `Label.tsx` for the non-small case.
- Prefer deriving the radius from the rendered element:
- Option A (best): In `LabelCelebrationAnimation`, when `borderRadius` is not provided, read `getComputedStyle(childElement).borderTopLeftRadius` (parseFloat) and use that value.
- Option B: Read `--border-radius-small` via `getComputedStyle` and parseFloat (guard for SSR) and pass that into `LabelCelebrationAnimation`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments
5. Unclamped borderRadius breaks path ✓ Resolved 🐞 Bug ☼ Reliability
Description
LabelCelebrationAnimation forwards the new borderRadius prop directly into
getPath/getPerimeter without guarding for negative or too-large values. If a caller passes an
invalid radius (e.g., larger than half the element size), the SVG path/perimeter math can become
invalid and break the stroke animation.
Code

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[R25-32]

Evidence
The new borderRadius prop is public to this component and is used in the geometry computations.
getPerimeter subtracts 2*borderRadius from width/height and getPath uses borderRadius in arc
commands, so invalid inputs can yield negative/NaN values or nonsensical SVG commands.

packages/core/src/components/Label/LabelCelebrationAnimation.tsx[9-48]
packages/core/src/components/Label/LabelCelebrationAnimation.tsx[77-114]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `borderRadius` prop is used directly in SVG path and perimeter calculations. Invalid values (negative, NaN, or greater than `min(width,height)/2`) can produce broken paths and negative perimeters.
### Issue Context
Even if current internal callers pass safe values, this component now exposes an additional parameter that can be misused by future internal usage.
### Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[35-48]
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[77-114]
### Suggested fix
- In the resize callback, before calling `getPath/getPerimeter`:
- Guard `width`/`height` (return early if not finite numbers or <= 0).
- Clamp radius:
- `const maxR = Math.min(width, height) / 2;`
- `const r = Math.max(0, Math.min(borderRadius, maxR));`
- Use `r` for both `getPath` and `getPerimeter`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Ref mismatch with leg shape 🐞 Bug ≡ Correctness
Description
The celebration animation still assumes a uniform corner radius, but Label can render non-uniform
radii when isLegIncluded is true (one corner becomes square). This makes the PR’s “match the
rendered shape” guarantee incomplete for the reachable combination `kind="line" &&
celebrationAnimation && isLegIncluded`.
Code

packages/core/src/components/Label/Label.tsx[R172-185]

Evidence
Label applies styles.withLeg based solely on isLegIncluded and can still enter the celebration
wrapper when kind === "line". The leg styling sets one corner radius to 0, while the animation
path generator only supports a single borderRadius value for all corners.

packages/core/src/components/Label/Label.tsx[77-90]
packages/core/src/components/Label/Label.tsx[172-186]
packages/core/src/components/Label/Label.module.scss[29-34]
packages/core/src/components/Label/LabelCelebrationAnimation.tsx[77-99]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
With `isLegIncluded`, the label’s corner radii are not uniform (one corner is 0), but the celebration SVG path is generated using a single radius. This can cause visible mismatch for `kind="line"` labels that include a leg.
### Issue Context
`Label.tsx` wraps the already-styled `label` element with `LabelCelebrationAnimation` when `kind === "line"` and celebration is active; it does not check `isLegIncluded`.
### Fix Focus Areas
- packages/core/src/components/Label/Label.tsx[172-186]
- packages/core/src/components/Label/Label.module.scss[29-34]
### Suggested fix
- Easiest/least risky: prevent wrapping with `LabelCelebrationAnimation` when `isLegIncluded` is true.
- Alternatively (bigger change): extend the path generator to support per-corner radii and pass the correct corner set when the leg is included.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment on lines 18 to 23
/**
* Border radius of the wrapped label, in pixels. Used to draw the animated stroke so it follows
* the label's actual rounded corners (e.g. small labels use a 2px radius, medium labels 4px).
*/
borderRadius?: number;
}

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.

Action required

1. labelcelebrationanimationprops defined inline 📘 Rule violation ⚙ Maintainability

borderRadius was added to an inline props interface inside LabelCelebrationAnimation.tsx instead
of using a dedicated *.types.ts file extending VibeComponentProps. This breaks the required
types-first component structure and increases long-term API inconsistency risk.
Agent Prompt
## Issue description
`LabelCelebrationAnimationProps` is defined/extended inline in `LabelCelebrationAnimation.tsx` (updated in this PR), but compliance requires component props to live in a dedicated `*.types.ts` file and extend `VibeComponentProps`.

## Issue Context
This PR added `borderRadius?: number` to `LabelCelebrationAnimationProps`, so this is a good time to align the component with the required types-first structure.

## Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[18-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +25 to +29
function LabelCelebrationAnimation({
children,
onAnimationEnd,
borderRadius = DEFAULT_BORDER_RADIUS
}: LabelCelebrationAnimationProps) {

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.

Action required

2. labelcelebrationanimation not forwardref 📘 Rule violation ⚙ Maintainability

LabelCelebrationAnimation is still declared as a plain function component rather than being
implemented via React forwardRef. This violates the required component implementation pattern and
makes ref usage inconsistent across the system.
Agent Prompt
## Issue description
`LabelCelebrationAnimation` is implemented as a plain function component, but compliance requires using `React.forwardRef` for components.

## Issue Context
This PR changed the component signature to add `borderRadius`, so the component is already being modified and can be refactored to the required `forwardRef` pattern.

## Fix Focus Areas
- packages/core/src/components/Label/LabelCelebrationAnimation.tsx[25-29]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Read the four corner radii from the child via getComputedStyle instead of
hardcoding values in TS. This keeps the stroke aligned with the label's
shape when CSS tokens are overridden, and correctly handles labels with a
leg, where one corner is squared off.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit ae9c031

Comment thread packages/core/src/components/Label/LabelCelebrationAnimation.tsx Outdated
childRef points to the outer wrapper span, but border-radius is applied to
the nested Text element marked with data-celebration-text. Resolve that
inner element via querySelector before reading computed radii so the SVG
stroke matches the rendered shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit d340035

@talkor

talkor commented May 25, 2026

Copy link
Copy Markdown
Member

@yousefkadah thank you so much for this PR!
The borders now look good! One thing I noticed, the line on the top is a bit off which makes the animation a bit jumpy. Do you have any solution for that as well?

Screen.Recording.2026-05-25.at.16.34.49.mov

@yousefkadah

Copy link
Copy Markdown
Author

Hey @talkor, thanks! 🙏

The jumpy top line came from two small things in the stroke path: the top edge wasn't lined up evenly with the corners, and the length I used for the dash animation was a few pixels longer than the actual path, so the line overshot at the top and jumped.

I fixed both — now the edges line up and the dash length matches the real path, so the loop should be smooth. Could you take another look when you get a chance?

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

Qodo Logo

Inset every edge of the celebration path by half the stroke width consistently, and subtract that inset from the perimeter so stroke-dasharray equals the actual path length. Fixes the slightly-off top edge and the jumpy looping stroke.
@yousefkadah yousefkadah force-pushed the fix/label-celebration-animation-small-size branch from a4b4ae6 to 79d06e6 Compare May 31, 2026 00:40
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 79d06e6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Label - celebration animation is broken is small size

3 participants