Skip to content

feat: add Corex.Slider for single-thumb and range - #106

Merged
karim-semmoud merged 19 commits into
mainfrom
cursor/slider-component-3e37
Aug 26, 2026
Merged

feat: add Corex.Slider for single-thumb and range#106
karim-semmoud merged 19 commits into
mainfrom
cursor/slider-component-3e37

Conversation

@karim-semmoud

@karim-semmoud karim-semmoud commented Aug 24, 2026

Copy link
Copy Markdown
Member

Summary

Adds Corex.Slider, a linear Zag.js slider for Phoenix LiveView. It follows the same anatomy and API as Corex.AngleSlider: a root + track + range + one or more thumbs, with optional markers, form wiring, and server-driven value updates.

A single thumb is the default. Passing a value list (for example [20, 80]) renders a range slider with N thumbs.

Component

  • Corex.Slider with root, label, control, track, range, thumb, hidden_input, marker_group, marker, and value_text
  • Single-thumb and multi-thumb (range) from the same API
  • Markers via get_marker_points/2 (count or explicit values)
  • Form support: hidden inputs, name, form, and changeset/validate error display
  • Phoenix.Component and LiveComponent (Corex.Slider.Live)
  • Keyboard, pointer, and focus-visible behavior from Zag.js

Client / JS

  • @zag-js/slider hook in assets/js/hooks/slider.ts
  • Generated priv/static/slider.mjs and CSS (design/priv/css/components/slider.css)
  • Client events: value.change, value.change.start, value.change.end, focus.change, dragging.change

Server API

  • push_value_change/3, push_focus/2, push_blur/2 for programmatic updates from LiveView
  • on_value_change, on_value_change_end, on_focus_change callbacks
  • Shared value conversion through Corex.Slider.Value

Docs and e2e

  • Hex docs and Cheatsheet entries
  • e2e playground, events, markers, and form pages (/en/slider/...)
  • Wallaby coverage for pointer/keyboard interaction, range thumbs, markers, client/server events, and static + LiveView form submit

Test plan

  • mix test test/components/slider_test.exs — anatomy, value conversion, markers, server API
  • pnpm test — slider hook unit tests
  • e2e Wallaby: playground, events (single + range), markers, form (changeset + validate, static + live)
  • Conn tests for static form flash (Submitted: volume=95.0)
  • CI green after merging latest main (Zag.js 1.43.3, Phoenix 1.8.13, LiveView 1.2.10)
Open in Web Open in Cursor 

cursoragent and others added 3 commits August 24, 2026 12:32
Uncontrolled Zag slider covering one thumb or N thumbs from the value
list, with form gating, JS/server API, design CSS, and demo/e2e coverage
following AngleSlider.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Simplify hidden-input attrs, use ~S in assertions, format e2e HEEx/JS
helpers, and order aliases so mix lint and prettier pass.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Match other components: Phoenix.LiveView.JS.dispatch success typing
trips contract_with_opaque on Slider API helpers.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
@karim-semmoud karim-semmoud self-assigned this Aug 24, 2026
karim-semmoud and others added 13 commits August 24, 2026 21:03
SSR thumbs now expose role=slider so Zag can measure size before the
first spread (contain alignment was leaving them visibility:hidden and
unfocusable). Wire the fill-host Max width section on the style page.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Open Combobox/DatePicker floating layers were intercepting Wallaby clicks
on the next trigger (playground Select, range anatomy). Close the open
layer first, and stop mapping slider track control to checkbox chrome.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Zag's default contain alignment hides thumbs and markers until thumbSize
is measured. Seed thumbSize from SSR layout before the machine starts so
hydration does not flash content away.

Also align SSR thumb and marker offsets with Zag's contain positioning
using calc() and --thumb-size, and add regression tests.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
- Move marker-group inside control so ticks overlay the track (Zag pattern)
- Add markers boolean (default false) on Slider and AngleSlider; marker_values
  only applies when markers is true
- Position track marks with absolute inset matching thumb padding
- Simplify API LiveView handlers: set_value/3 already coerces numeric strings
- Update demos, captures, tests, and design CSS snapshot

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Elixir inspect/1 prints one-element integer lists like [75] as ~c"K",
which made the events demo look like keyboard input. Use numeric formatting
for the event log and pass only id/value in the client pushEvent payload.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Remove the unreachable default_angle_marker_values(0, 360) clause that
Dialyzer flagged as dead code; the general min/max helper already covers
0–360 and matches Slider's default marker behavior.

Run mix format on e2e files where markers and marker_values attributes
were on a single line.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Run prettier on assets/components/slider.ts and
assets/test/helpers/component-smoke.ts to satisfy format:check in CI.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Place marker-group as a control sibling, style range markers by in-between vs out contrast, add parallel range sections on API/events/form pages, and fix Ecto volume validation so controller submits surface errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve priv/static build conflicts by regenerating assets from the merged sources.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@karim-semmoud
karim-semmoud marked this pull request as ready for review August 25, 2026 22:36
cursoragent and others added 3 commits August 26, 2026 01:16
Range client dispatch now accepts a value list. Controller ecto
submit toasts the cast volume so Wallaby matches volume=95.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Bring in Zag.js 1.43.3, Phoenix 1.8.13, LiveView 1.2.10, and Credo
updates. Keep Slider at the lockstep Zag version and regenerate assets.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
Keep script-based overlay dismiss from Slider e2e and wait until the
content is closed, matching DatePicker.

Co-authored-by: Karim Semmoud <karim-semmoud@users.noreply.github.com>
@karim-semmoud
karim-semmoud merged commit 694796e into main Aug 26, 2026
16 checks passed
@karim-semmoud
karim-semmoud deleted the cursor/slider-component-3e37 branch August 26, 2026 07:09
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.

2 participants