Skip to content

[WC-3322]: Fix slider decimal places formatting#2220

Open
samuelreichert wants to merge 5 commits into
mainfrom
worktree-fix+slider-decimal-places-formatting
Open

[WC-3322]: Fix slider decimal places formatting#2220
samuelreichert wants to merge 5 commits into
mainfrom
worktree-fix+slider-decimal-places-formatting

Conversation

@samuelreichert
Copy link
Copy Markdown
Contributor

Pull request type

Bug fix (non-breaking change which fixes an issue)


Description

When decimalPlaces is configured on the Slider widget, displayed values were silently stripping trailing zeros:

  • Mark labels: 10.00 rendered as 10, 9.20 rendered as 9.2
  • Tooltip: same raw number passed through with no formatting applied

Root causes:

  1. marks.tsparseFloat(value.toFixed(n)).toString() round-tripped through a number, discarding trailing zeros. Fixed by keeping the toFixed string directly as the label and using parseFloat only for the numeric key.

  2. createHandleRender.tsx — tooltip overlay received restProps.value (raw RC Slider number). Fixed by adding a decimalPlaces parameter and applying .toFixed(decimalPlaces) before passing to the overlay.

Files changed:

  • src/utils/marks.ts — fix label generation
  • src/utils/createHandleRender.tsx — accept and apply decimalPlaces
  • src/components/Container.tsx — pass decimalPlaces to createHandleRender
  • src/utils/__tests__/marks.spec.ts — new unit tests
  • src/utils/__tests__/createHandleRender.spec.tsx — new unit tests

What should be covered while testing?

  1. Configure a Slider widget with decimalPlaces = 2 and Number of markers > 0.
  2. Set min/max so some markers land on whole numbers (e.g. min=0, max=10, markers=2).
  3. Mark labels should show 0.00, 5.00, 10.00 — not 0, 5, 10.
  4. Drag the handle to a whole number value — tooltip should show 10.00, not 10.
  5. Drag to a value with one decimal (e.g. 9.5) — tooltip should show 9.50.
  6. Set decimalPlaces = 0 and verify no change in existing behavior (labels and tooltip show integers without decimal point).

@samuelreichert samuelreichert requested a review from a team as a code owner May 19, 2026 11:35
@github-actions

This comment was marked as outdated.

@samuelreichert samuelreichert changed the title Worktree fix+slider decimal places formatting [WC-3322]: Fix slider decimal places formatting May 19, 2026
@github-actions

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@samuelreichert samuelreichert force-pushed the worktree-fix+slider-decimal-places-formatting branch from 4e14487 to 945997f Compare May 22, 2026 12:23
@github-actions

This comment was marked as outdated.

@samuelreichert samuelreichert force-pushed the worktree-fix+slider-decimal-places-formatting branch from 945997f to 98f491a Compare May 26, 2026 07:37
@github-actions
Copy link
Copy Markdown

AI Code Review

⚠️ Approved with suggestions — low-severity items only, safe to merge


What was reviewed

File Change
packages/pluggableWidgets/slider-web/CHANGELOG.md Added [Unreleased] Fixed entry for trailing-zero formatting
packages/pluggableWidgets/slider-web/src/components/Container.tsx Wrapped createHandleRender call in useMemo; passes decimalPlaces
packages/pluggableWidgets/slider-web/src/utils/createHandleRender.tsx Added decimalPlaces param; applies .toFixed() to tooltip overlay value
packages/pluggableWidgets/slider-web/src/utils/marks.ts Keeps toFixed string as label, uses parseFloat only for numeric key
packages/pluggableWidgets/slider-web/src/utils/__tests__/createHandleRender.spec.tsx New unit tests for tooltip value formatting
packages/pluggableWidgets/slider-web/src/utils/__tests__/marks.spec.ts New unit tests for mark label generation

Skipped (out of scope): dist/, pnpm-lock.yaml

CI checks could not be fetched — verify green before merge.


Findings

⚠️ Low — sliderRef omitted from useMemo dependency array

File: packages/pluggableWidgets/slider-web/src/components/Container.tsx line 44
Note: sliderRef is captured inside the createHandleRender closure (getTooltipContainer uses it) but is not listed in the useMemo deps array. In practice useRef returns a stable object so this never causes a stale-closure bug — but it is technically an omission that eslint-plugin-react-hooks will flag. Either add sliderRef to the deps array or suppress the rule with a comment explaining the stable-ref guarantee.

// Option A: add to deps (harmless — useRef is stable)
[props.showTooltip, props.tooltip, props.tooltipType, props.tooltipAlwaysVisible, props.decimalPlaces, sliderRef]

// Option B: suppress and explain
// eslint-disable-next-line react-hooks/exhaustive-deps -- sliderRef is a stable useRef object
[props.showTooltip, props.tooltip, props.tooltipType, props.tooltipAlwaysVisible, props.decimalPlaces]

⚠️ Low — createHandleRender always returns a value but its return type advertises | undefined

File: packages/pluggableWidgets/slider-web/src/utils/createHandleRender.tsx line 22
Note: The function signature says it can return undefined, but the function body always returns handleRender. The | undefined in the return type is now misleading and causes the test file to non-null-assert the result (!). Consider narrowing the return type to RcSliderProps["handleRender"] (non-optional). The undefined path belongs at the call site in Container.tsx where showTooltip gates it.

// Before
): RcSliderProps["handleRender"] | undefined {

// After
): RcSliderProps["handleRender"] {

Positives

  • The root-cause analysis in the PR description is precise — it correctly identifies both the marks.ts round-trip through Number and the missing toFixed in createHandleRender, with separate fixes for each.
  • Wrapping createHandleRender in useMemo is a good opportunistic improvement: it prevents a new function reference on every render, which would have caused RC Slider to unnecessarily re-create the handle.
  • Test cases cover all key branches: decimalPlaces=2 with a whole number, decimalPlaces=2 with a partial decimal, decimalPlaces=0, custom text tooltip, numberOfMarks=0, and min === max guard. Good edge-case coverage.
  • CHANGELOG entry is present and follows Keep a Changelog format with a user-facing description.

@samuelreichert samuelreichert force-pushed the worktree-fix+slider-decimal-places-formatting branch 2 times, most recently from 5092cb6 to 07fc177 Compare May 26, 2026 12:41
@samuelreichert samuelreichert force-pushed the worktree-fix+slider-decimal-places-formatting branch from 07fc177 to 691462a Compare May 26, 2026 13:20
@github-actions
Copy link
Copy Markdown

AI Code Review

⚠️ Approved with suggestions — low-severity items only, safe to merge


What was reviewed

File Change
packages/pluggableWidgets/slider-web/CHANGELOG.md Added ### Fixed entry under [Unreleased]
packages/pluggableWidgets/slider-web/src/utils/marks.ts Keep toFixed string as mark label; use parseFloat only for numeric key
packages/pluggableWidgets/slider-web/src/utils/createHandleRender.tsx Added decimalPlaces param; apply .toFixed(decimalPlaces) to tooltip overlay
packages/pluggableWidgets/slider-web/src/components/Container.tsx Wrapped createHandleRender in useMemo; pass decimalPlaces
packages/pluggableWidgets/slider-web/src/utils/__tests__/marks.spec.ts New unit tests for createMarks label formatting
packages/pluggableWidgets/slider-web/src/utils/__tests__/createHandleRender.spec.tsx New unit tests for tooltip overlay formatting

Skipped (out of scope): dist/, pnpm-lock.yaml

⚠️ CI status could not be verifiedgh pr checks required additional approval. Please confirm checks are green before merging.


Findings

⚠️ Low — Module-level jest.fn() mocks not reset between tests

File: src/utils/__tests__/createHandleRender.spec.tsx lines 8–10
Note: onFocus and onBlur are jest.fn() created once at module scope and shared across all test cases. Call counts accumulate across tests. The current tests don't assert on these mocks so this causes no failures today, but it's a pollution risk if assertions are added later.
Fix: Move them inside defaultRenderProps as a factory, or add afterEach:

afterEach(() => {
    jest.clearAllMocks();
});

⚠️ Low — tooltip is a DynamicValue object reference in useMemo deps

File: src/components/Container.tsx line 44
Note: props.tooltip is a DynamicValue<string>. If the Mendix runtime mutates .value in-place on the same object (stable reference), the memoized handleRender would not be recreated, but the closure reads tooltip?.value lazily at render time — so the displayed value would still be current. This is safe as written. Worth a comment so future readers don't incorrectly add a deep-equality dep.


Positives

  • The root-cause diagnosis is precise: two separate code paths (marks label generation and tooltip overlay) each had the same class of bug, and both are fixed independently and correctly.
  • parseFloat(label) used as the numeric key is exactly right — it normalises floating-point noise while keeping the display label from toFixed unchanged.
  • Wrapping createHandleRender in useMemo is a nice bonus improvement; sliderRef is correctly omitted from deps since useRef returns a stable object.
  • Test coverage is solid: both new spec files cover the happy paths, edge cases (decimalPlaces=0, min===max, numberOfMarks=0), and the custom-text tooltip branch.
  • CHANGELOG entry is in the right section and written in user-facing language consistent with the rest of the file.

Copy link
Copy Markdown
Collaborator

@iobuhov iobuhov left a comment

Choose a reason for hiding this comment

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

LGTM

defaultVisible
prefixCls="rc-slider-tooltip"
overlay={isCustomText ? overlay : restProps.value}
overlay={isCustomText ? overlay : restProps.value.toFixed(decimalPlaces)}
Copy link
Copy Markdown
Collaborator

@r0b1n r0b1n May 26, 2026

Choose a reason for hiding this comment

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

I am thinking, default toFixed doesn't respect the user settings, like if current Mendix locale is using , as decimal separator, toFixed will still be . , right? Same with thousands separator.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants