Skip to content

feat(ProgressBar): introduce a new ProgressBar - #935

Open
aammami-ledger wants to merge 6 commits into
mainfrom
feat/progress-bar
Open

aammami-ledger wants to merge 6 commits into
mainfrom
feat/progress-bar

Conversation

@aammami-ledger

@aammami-ledger aammami-ledger commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Context

Adds a determinate ProgressBar to ui-react and ui-rnative, with semantic and decorative appearances, an optional label and a 200ms ease-out fill animation.

Closes DLS-1074

Screenshot 2026-10-23 at 11 28 15 Screenshot 2026-10-23 at 11 28 31

Technical details

  • value (0 to 100), appearance (5 semantic + 8 decorative-*), label and labelPosition (start-top, start-bottom, end-top, end-bottom).
  • Web requires label or aria-label; React Native requires accessibilityLabel.
  • Label placement is shared in internal/ProgressBase.

How to test

  1. Storybook: Core/ProgressBar.
  2. React Native sandbox: ProgressBar screen.

Copilot AI balanced review requested due to automatic review settings October 23, 2026 09:39
@aammami-ledger
aammami-ledger requested a review from a team as a code owner October 23, 2026 09:39
@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
ldls Ready Ready Preview Oct 29, 2026 1:42pm UTC
ldls-react-native Ready Ready Preview Oct 29, 2026 1:42pm UTC

Request Review

Copilot AI 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.

🟡 Changes recommended

Labeled bars mishandle layout and visibility overrides on both platforms, and boolean labels bypass the web accessible-name requirement.

3 open issues
What changed in this PR

Introduces a determinate ProgressBar in Lumen’s React and React Native libraries, with matching appearances and label placement options.

Changes:

  • Adds animated progress fills, value clamping, accessible naming, and optional labels.
  • Adds tests, Storybook examples, documentation, Figma connections, and a native sandbox demo.
  • Exports both components and includes patch version plans.
File Description
libs/​ui-rnative/​src/​lib/​Components/​internal/​ProgressBase/​useAnimatedProgressWidth.ts Animates native fill width.
libs/​ui-rnative/​src/​lib/​Components/​internal/​ProgressBase/​types.ts Defines native label layout props.
libs/​ui-rnative/​src/​lib/​Components/​internal/​ProgressBase/​ProgressLabelLayout.tsx Positions optional native labels.
libs/​ui-rnative/​src/​lib/​Components/​internal/​ProgressBase/​index.ts Exports native internal helpers.
libs/​ui-rnative/​src/​lib/​Components/​core/​ProgressBar/​types.ts Defines the native public API.
libs/​ui-rnative/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.tsx Implements the native progress bar.
libs/​ui-rnative/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.test.tsx Tests native values, appearance, and labels.
libs/​ui-rnative/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.stories.tsx Demonstrates native variants.
libs/​ui-rnative/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.mdx Documents native usage and accessibility.
libs/​ui-rnative/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.figma.tsx Connects the native component to Figma.
libs/​ui-rnative/​src/​lib/​Components/​core/​ProgressBar/​index.ts Exports the native component and types.
libs/​ui-rnative/​src/​lib/​Components/​core/​index.ts Adds the native public export.
libs/​ui-react/​src/​lib/​Components/​internal/​ProgressBase/​types.ts Defines web label layout props.
libs/​ui-react/​src/​lib/​Components/​internal/​ProgressBase/​ProgressLabelLayout.tsx Positions and identifies web labels.
libs/​ui-react/​src/​lib/​Components/​internal/​ProgressBase/​ProgressLabelLayout.test.tsx Tests web label layout and IDs.
libs/​ui-react/​src/​lib/​Components/​internal/​ProgressBase/​index.ts Exports web internal helpers.
libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​types.ts Defines the web public API and naming constraint.
libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.tsx Implements the web progress bar.
libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.test.tsx Tests web rendering and accessibility.
libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.stories.tsx Demonstrates web variants and naming.
libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.mdx Documents web usage and accessibility.
libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.figma.tsx Connects the web component to Figma.
libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​index.ts Exports the web component and types.
libs/​ui-react/​src/​lib/​Components/​core/​index.ts Adds the web public export.
apps/​app-sandbox-rnative/​src/​blocks.ts Registers the native demo.
apps/​app-sandbox-rnative/​src/​app/​(blocks)/​ProgressBars.tsx Adds interactive and animated native examples.
.nx/​version-plans/​version-plan-1792684934000-ui-rnative.md Schedules the native package patch release.
.nx/​version-plans/​version-plan-1792684934000-ui-react.md Schedules the web package patch release.

Review effort: Balanced

Comment thread libs/ui-react/src/lib/Components/core/ProgressBar/ProgressBar.tsx Outdated
Comment thread libs/ui-react/src/lib/Components/core/ProgressBar/types.ts Outdated
Comment thread libs/ui-rnative/src/lib/Components/core/ProgressBar/ProgressBar.tsx Outdated

Copilot AI 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.

🔵 Needs a closer look

The web component needs correct presentation-prop forwarding for labeled bars and support for reduced-motion preferences.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

Medium severity Disable progress fill transitions for reduced-motion users

libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.tsx:16

6/10 — The web fill's width transition still runs when the user enables prefers-reduced-motion: reduce. Unlike the native hook's ReduceMotion.System behavior, this component has no reduced-motion override. Add motion-reduce:transition-none so progress updates are immediate for users who request reduced motion.

Medium severity Forward presentation and direction props to labeled progress wrapper

libs/​ui-react/​src/​lib/​Components/​core/​ProgressBar/​ProgressBar.tsx:75

7/10 — With a visible label, className targets the wrapper, but style, hidden, and dir are spread onto the inner track only. Consequently, style={{ display: 'none' }} or hidden leaves the label visible, a styled width does not constrain the label wrapper, and dir='rtl' does not change the wrapper's start/end alignment on an LTR page. Forward these presentation and direction props to the wrapper when labeled and to the track when unlabeled, while keeping progress-specific ARIA attributes on the track. Add regression tests for these labeled cases.

3 resolved since last review

Review effort: Balanced

Comment thread libs/ui-react/src/lib/Components/core/ProgressBar/ProgressBar.stories.tsx Outdated
Comment thread libs/ui-rnative/src/lib/Components/internal/ProgressBase/types.ts Outdated
Comment on lines +67 to +69
<Text typography='body4' style={styles.label}>
{label}
</Text>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[low]: on RN the label Text is still its own a11y element, so VoiceOver/TalkBack will stop on "Syncing accounts" and then again on the bar ("Sync progress, 72%"). Since the docs say the label is visual only and accessibilityLabel names the bar, I think we can just hide it from the tree, like we do in AmountDisplay / MenuList:

Suggested change
<Text typography='body4' style={styles.label}>
{label}
</Text>
<Text
typography='body4'
style={styles.label}
accessibilityElementsHidden
importantForAccessibility='no-hide-descendants'
>
{label}
</Text>

Not blocking, but we could also make accessibilityLabel optional when label is a plain string and fall back to it, closer to how web behaves.

Comment on lines +75 to +83
{...props}
ref={ref}
role='progressbar'
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={clampedValue}
aria-label={ariaLabel}
aria-labelledby={labelledBy}
className={cn(progressTrackVariants(), !hasLabel && className)}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[low]: small inconsistency here: with a label, className goes to the wrapper but style (and id, data-*, handlers…) stay on the bar through {...props}. So className='mt-8' and style={{ marginTop: 8 }} don't move the same element. RN gets this right since both lx and style go to the wrapper.

Could we route style the same way as className? Or at least mention it next to the className note in the JSDoc and the MDX.

args: {
value: 40,
appearance: 'base',
'aria-label': 'Upload progress',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[low]: Base sets both aria-label and label with the same text, but the MDX introduces it with "a bar without a visible label needs an aria-label", and says a bit further down that with a label no aria-label is needed. Since people will copy this one, I'd drop aria-label here (keeps label in Controls) and reword the Basic Usage sentence in the MDX.

Suggested change
'aria-label': 'Upload progress',

Comment on lines +9 to +11
example: () => (
<ProgressBar value={25} label='Label' labelPosition='start-bottom' />
),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[low]: the example only has fixed values, so whatever variant you pick in Figma, Dev Mode will always show value={25} label='Label' labelPosition='start-bottom'. Most of our other .figma.tsx map a props block (e.g. Pagination). Could we map appearance and label position with figma.enum and the label text with figma.string? Same thing for the RN file.

@@ -0,0 +1,61 @@
import { cn } from '@ledgerhq/lumen-design-core/cn';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[mid]: Maybe don't overengineer it yet, we might move it to internal components when we start work on the stepper, so we better understand what needs to be abstracted

Comment on lines +22 to +39
type ProgressBarName =
| {
/**
* A visible label that also names the bar for assistive technology.
*/
label: Exclude<NonNullable<ReactNode>, boolean>;
/**
* Names the bar. Takes precedence over the rendered label.
*/
'aria-label'?: string;
}
| {
label?: ReactNode;
/**
* Names the bar. Required when there is no rendered label.
*/
'aria-label': string;
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[low]: I would remove that, as react-node anyway won't be a label if they pass div or view

- Inline the label layout and drop the shared ProgressBase until the
  stepper clarifies what to abstract
- Web: aria-label is required and the visible label is visual only, like RN
- Web: route style to the label wrapper alongside className
- RN: hide the label from the accessibility tree
- Map appearance, label and label position in Code Connect
- Align the Base story and MDX with the aria-label requirement

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
1 New Code Smells (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

This branch was successfully deployed

2 active deployments
Preview – ldls — 0406539a Deployed Oct 29, 2026 by vercel[bot]
Preview – ldls-react-native — 0406539a Deployed Oct 29, 2026 by vercel[bot]
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.

3 participants