Skip to content

Commit aa98ae5

Browse files
author
matthewcsimpson
committed
simplify
1 parent 302d497 commit aa98ae5

3 files changed

Lines changed: 139 additions & 11 deletions

File tree

Dist/Functional/RangeSliderSimple.js

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*!
22
* WebTricks — RangeSliderSimple
3-
* @version 0.0.2 — pre-release; bump patch (and docs/Functional/RangeSliderSimple.md) on every change to this file.
3+
* @version 0.0.5 — pre-release; bump patch (and docs/Functional/RangeSliderSimple.md) on every change to this file.
44
* Dual native range inputs (no custom thumb DOM). Self-contained (single script tag).
55
* MIT License
66
*/
@@ -174,36 +174,125 @@ class RangeSliderSimple {
174174

175175
const style = document.createElement('style');
176176
style.id = 'wt-rangeslidersimple-styles';
177-
/* Layout only: no appearance:none or ::-webkit-slider-* / ::-moz-range-* so thumbs/tracks stay browser-default. */
177+
/* MDN-like range UI (Chrome docs): blue filled track, grey remainder, white pill thumb.
178+
--wt-rs-track-fill defaults to #3b82f6 (typical RangeSlider [range] bar in docs). */
178179
style.textContent = `
179180
[${ATTR_PREFIX}-element="slider"] {
181+
--wt-rs-track-fill: #3b82f6;
182+
--wt-rs-track-bg: #e5e7eb;
183+
--wt-rs-thumb-bg: #ffffff;
184+
--wt-rs-thumb-border: #cbd5e1;
185+
--wt-rs-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
180186
position: relative;
187+
display: grid;
188+
grid-template-columns: 1fr;
189+
grid-template-rows: 1fr;
190+
align-items: center;
191+
justify-items: stretch;
181192
min-height: 2.75rem;
182193
box-sizing: border-box;
183194
}
184195
185-
[${ATTR_PREFIX}-element="input-left"],
186-
[${ATTR_PREFIX}-element="input-right"] {
187-
position: absolute;
188-
left: 0;
196+
input[type="range"][${ATTR_PREFIX}-element="input-left"],
197+
input[type="range"][${ATTR_PREFIX}-element="input-right"] {
198+
grid-column: 1;
199+
grid-row: 1;
189200
width: 100%;
190201
max-width: 100%;
191-
top: 50%;
192-
transform: translateY(-50%);
193202
margin: 0;
194203
padding: 0;
195204
box-sizing: border-box;
196205
pointer-events: auto;
197206
z-index: 2;
207+
height: 1.5rem;
208+
min-height: 1.5rem;
209+
background: transparent;
210+
-webkit-appearance: none !important;
211+
appearance: none !important;
212+
-moz-appearance: none !important;
198213
}
199214
200-
[${ATTR_PREFIX}-element="input-right"] {
215+
input[type="range"][${ATTR_PREFIX}-element="input-right"] {
201216
z-index: 1;
202217
}
218+
219+
input[type="range"][${ATTR_PREFIX}-element="input-left"]::-webkit-slider-runnable-track,
220+
input[type="range"][${ATTR_PREFIX}-element="input-right"]::-webkit-slider-runnable-track {
221+
height: 6px;
222+
border-radius: 3px;
223+
background: linear-gradient(
224+
to right,
225+
var(--wt-rs-track-fill) 0%,
226+
var(--wt-rs-track-fill) var(--wt-rs-pct, 0%),
227+
var(--wt-rs-track-bg) var(--wt-rs-pct, 0%),
228+
var(--wt-rs-track-bg) 100%
229+
);
230+
}
231+
232+
input[type="range"][${ATTR_PREFIX}-element="input-left"]::-webkit-slider-thumb,
233+
input[type="range"][${ATTR_PREFIX}-element="input-right"]::-webkit-slider-thumb {
234+
-webkit-appearance: none !important;
235+
width: 12px;
236+
height: 16px;
237+
margin-top: -5px;
238+
border-radius: 8px;
239+
background: var(--wt-rs-thumb-bg);
240+
border: 1px solid var(--wt-rs-thumb-border);
241+
box-shadow: var(--wt-rs-thumb-shadow);
242+
cursor: pointer;
243+
}
244+
245+
input[type="range"][${ATTR_PREFIX}-element="input-left"]::-moz-range-track,
246+
input[type="range"][${ATTR_PREFIX}-element="input-right"]::-moz-range-track {
247+
height: 6px;
248+
border-radius: 3px;
249+
background: var(--wt-rs-track-bg);
250+
border: none;
251+
}
252+
253+
input[type="range"][${ATTR_PREFIX}-element="input-left"]::-moz-range-progress,
254+
input[type="range"][${ATTR_PREFIX}-element="input-right"]::-moz-range-progress {
255+
height: 6px;
256+
border-radius: 3px;
257+
background: var(--wt-rs-track-fill);
258+
border: none;
259+
}
260+
261+
input[type="range"][${ATTR_PREFIX}-element="input-left"]::-moz-range-thumb,
262+
input[type="range"][${ATTR_PREFIX}-element="input-right"]::-moz-range-thumb {
263+
width: 12px;
264+
height: 16px;
265+
border-radius: 8px;
266+
background: var(--wt-rs-thumb-bg);
267+
border: 1px solid var(--wt-rs-thumb-border);
268+
box-shadow: var(--wt-rs-thumb-shadow);
269+
cursor: pointer;
270+
}
271+
272+
input[type="range"][${ATTR_PREFIX}-element="input-left"]:focus-visible,
273+
input[type="range"][${ATTR_PREFIX}-element="input-right"]:focus-visible {
274+
outline: 2px solid var(--wt-rs-track-fill);
275+
outline-offset: 2px;
276+
}
203277
`;
204278
document.head.appendChild(style);
205279
}
206280

281+
syncTrackFillPercents() {
282+
if (!this.inputLeft || !this.inputRight) return;
283+
[this.inputLeft, this.inputRight].forEach((input) => {
284+
const min = parseInt(input.min, 10);
285+
const max = parseInt(input.max, 10);
286+
const val = parseInt(input.value, 10);
287+
const safeMin = Number.isFinite(min) ? min : 0;
288+
const safeMax = Number.isFinite(max) ? max : 100;
289+
const safeVal = Number.isFinite(val) ? val : safeMin;
290+
const pct =
291+
safeMax <= safeMin ? 0 : ((safeVal - safeMin) / (safeMax - safeMin)) * 100;
292+
input.style.setProperty('--wt-rs-pct', `${pct}%`);
293+
});
294+
}
295+
207296
initConfig() {
208297
const cfg = this.rs.readSliderConfig(this.slider, ATTR_PREFIX);
209298
this.sliderMin = cfg.sliderMin;
@@ -213,6 +302,15 @@ class RangeSliderSimple {
213302
this.rightSuffix = cfg.rightSuffix;
214303
this.defaultSuffix = cfg.defaultSuffix;
215304
this.shouldFormatNumber = cfg.shouldFormatNumber;
305+
306+
const trackFill = this.slider.getAttribute(`${ATTR_PREFIX}-trackfill`);
307+
if (trackFill) {
308+
this.slider.style.setProperty('--wt-rs-track-fill', trackFill);
309+
}
310+
const trackBg = this.slider.getAttribute(`${ATTR_PREFIX}-trackbg`);
311+
if (trackBg) {
312+
this.slider.style.setProperty('--wt-rs-track-bg', trackBg);
313+
}
216314
}
217315

218316
initElements() {
@@ -298,6 +396,8 @@ class RangeSliderSimple {
298396
this.shouldFormatNumber,
299397
);
300398
}
399+
400+
this.syncTrackFillPercents();
301401
}
302402

303403
updateRightValues(value) {
@@ -332,6 +432,8 @@ class RangeSliderSimple {
332432
this.defaultSuffix,
333433
);
334434
}
435+
436+
this.syncTrackFillPercents();
335437
}
336438

337439
setupEventListeners() {
@@ -432,6 +534,15 @@ const initializeRangeSliderSimple = () => {
432534
const instance = new RangeSliderSimple(wrapper);
433535
window.webtricks.push({ RangeSliderSimple: instance });
434536
});
537+
538+
const bumpStyleOrder = () => {
539+
const injectedStyle = document.getElementById('wt-rangeslidersimple-styles');
540+
if (injectedStyle && document.head) {
541+
document.head.appendChild(injectedStyle);
542+
}
543+
};
544+
bumpStyleOrder();
545+
setTimeout(bumpStyleOrder, 0);
435546
} catch (err) {
436547
console.error(`RangeSliderSimple initialization error: ${err.message}`);
437548
}

docs/Functional/RangeSlider.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ Self-contained: **one** script tag. Use [jsDelivr](https://www.jsdelivr.com/) (n
5050
- `wt-rangeslider-max="100"` - Maximum value (default: 100)
5151
- `wt-rangeslider-steps="1"` - Step size (default: 1)
5252

53+
Style the `[wt-rangeslider-element="range"]` bar in your CSS; examples often use **#3b82f6** for the fill. [RangeSliderSimple](./RangeSliderSimple.md) defaults its track fill to the same for visual parity.
54+
5355
### Optional Elements
5456

5557
- `wt-rangeslider-range="from"` - Form input for start value

docs/Functional/RangeSliderSimple.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
## Version
44

5-
Current version: **0.0.2** (pre-release — see banner in `Dist/Functional/RangeSliderSimple.js`; bump patch and this line when the script changes).
5+
Current version: **0.0.5** (pre-release — see banner in `Dist/Functional/RangeSliderSimple.js`; bump patch and this line when the script changes).
66

77
## Description
88

9-
`RangeSliderSimple` is a dual-handle range control built from two native `<input type="range">` elements. The draggable thumbs you see are the browser’s own controls, so hit targets stay aligned with the visuals. The file is **self-contained** (same core behavior as `RangeSlider`, inlined—keep edits in sync manually if you change constraint/display logic).
9+
`RangeSliderSimple` is a dual-handle range control built from two `<input type="range">` elements. Styling follows the **default MDN / Chrome** pattern (blue filled track, grey remainder, white pill thumb); default fill **#3b82f6** matches typical `RangeSlider` `[range]` bar examples. Hit targets match the painted thumbs. The file is **self-contained** (same core behavior as `RangeSlider`, inlined—keep edits in sync manually if you change constraint/display logic).
1010

1111
Use **`RangeSlider`** when you need custom thumb graphics or a separate range bar element. Use **`RangeSliderSimple`** when native appearance (plus your own CSS overrides) is enough.
1212

@@ -40,6 +40,17 @@ Same semantics as `RangeSlider`, with the `wt-rangeslidersimple-` prefix:
4040
- `wt-rangeslidersimple-min`, `wt-rangeslidersimple-max`, `wt-rangeslidersimple-steps`
4141
- `wt-rangeslidersimple-mindifference`
4242
- `wt-rangeslidersimple-formatnumber`, `wt-rangeslidersimple-rightsuffix`, `wt-rangeslidersimple-defaultsuffix`
43+
- `wt-rangeslidersimple-trackfill` — optional CSS color for the filled portion of the track (default **#3b82f6**, aligned with common `RangeSlider` `[range]` bar examples)
44+
- `wt-rangeslidersimple-trackbg` — optional unfilled track color (default **#e5e7eb**)
45+
46+
## Theming (CSS variables)
47+
48+
On `[wt-rangeslidersimple-element="slider"]` you can override:
49+
50+
- `--wt-rs-track-fill`, `--wt-rs-track-bg`
51+
- `--wt-rs-thumb-bg`, `--wt-rs-thumb-border`, `--wt-rs-thumb-shadow`
52+
53+
Injected styling approximates the default **MDN / Chrome** range look (white vertical pill thumb, blue progress, grey track).
4354

4455
## Optional elements (inside wrapper)
4556

@@ -79,3 +90,7 @@ Filter-driven min/max for collection ranges applies to **`wt-rangeslider-*`** on
7990
After init, instances are available on `window.webtricks` as `{ RangeSliderSimple: instance }`.
8091

8192
- `setFrom(value)`, `setTo(value)`, `setRange(from, to)`, `reset()`
93+
94+
## CodePen / global CSS
95+
96+
The script injects complete **WebKit / Firefox** range pseudo-element styling so host resets (e.g. CodePen `input { appearance: none }`) do not leave unstyled thumbs. It also moves the injected `<style>` to the end of `<head>` (and on `setTimeout(0)`). Avoid duplicating conflicting `input[type=range]` rules in the Pen’s CSS panel; purge jsDelivr or pin a commit after updates.

0 commit comments

Comments
 (0)