@zywave/zui-slider 4.4.0-pre.3 → 4.4.0-pre.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom-elements.json +188 -7
- package/dist/zui-slider-css.js +1 -1
- package/dist/zui-slider-css.js.map +1 -1
- package/dist/zui-slider.d.ts +16 -21
- package/dist/zui-slider.js +372 -91
- package/dist/zui-slider.js.map +1 -1
- package/docs/demo.html +99 -78
- package/lab.html +415 -15
- package/package.json +2 -2
- package/src/zui-slider-css.js +1 -1
- package/src/zui-slider.scss +32 -7
- package/src/zui-slider.ts +380 -89
- package/test/zui-slider.test.ts +561 -131
package/lab.html
CHANGED
|
@@ -21,10 +21,6 @@
|
|
|
21
21
|
margin-bottom: 20px;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
zui-slider#decimals {
|
|
25
|
-
--zui-slider-thumb-size: 3rem;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
24
|
</style>
|
|
29
25
|
</head>
|
|
30
26
|
|
|
@@ -43,17 +39,29 @@
|
|
|
43
39
|
<h3>disabled zui slider</h3>
|
|
44
40
|
<zui-slider id="disabled" disabled></zui-slider>
|
|
45
41
|
|
|
46
|
-
<h3>
|
|
42
|
+
<h3>bounded slider with negative values (min=-50, max=50)</h3>
|
|
47
43
|
<zui-slider id="negative" value="0" min="-50" max="50"></zui-slider>
|
|
48
44
|
|
|
49
45
|
<h3>zui slider no text</h3>
|
|
50
46
|
<zui-slider id="text" no-text></zui-slider>
|
|
51
47
|
|
|
52
|
-
<
|
|
53
|
-
|
|
48
|
+
<h2>Decimal sliders</h2>
|
|
49
|
+
|
|
50
|
+
<h3>decimal — step=0.5</h3>
|
|
51
|
+
<p>Drag snaps to 0.5 increments. Typing <code>47.01</code> rounds to <code>47.0</code>; typing <code>47.9</code> rounds to <code>48.0</code>.</p>
|
|
52
|
+
<zui-slider id="decimals" step="0.5" value="50"></zui-slider>
|
|
53
|
+
|
|
54
|
+
<h3>decimal — step=0.1, min=0, max=10</h3>
|
|
55
|
+
<zui-slider id="decimals-tenth" step="0.1" value="5" min="0" max="10"></zui-slider>
|
|
56
|
+
|
|
57
|
+
<h3>decimal — step=0.25, min=0, max=5</h3>
|
|
58
|
+
<zui-slider id="decimals-quarter" step="0.25" value="2.5" min="0" max="5"></zui-slider>
|
|
59
|
+
|
|
60
|
+
<h3>decimal — range, step=0.5</h3>
|
|
61
|
+
<zui-slider id="decimals-range" range step="0.5" value-start="25" value-end="75"></zui-slider>
|
|
54
62
|
|
|
55
|
-
<h3>
|
|
56
|
-
<zui-slider id="
|
|
63
|
+
<h3>decimal — range, step=0.1, min=0, max=10</h3>
|
|
64
|
+
<zui-slider id="decimals-range-tenth" range step="0.1" value-start="2" value-end="8" min="0" max="10"></zui-slider>
|
|
57
65
|
|
|
58
66
|
<h3>set zui slider programmatically</h3>
|
|
59
67
|
<button id="clickme">Click me</button>
|
|
@@ -77,12 +85,6 @@
|
|
|
77
85
|
<h3>range slider disabled</h3>
|
|
78
86
|
<zui-slider id="range-disabled" range disabled value-start="30" value-end="70"></zui-slider>
|
|
79
87
|
|
|
80
|
-
<h3>range slider show min/max</h3>
|
|
81
|
-
<zui-slider id="range-show-min-max" range show-min-max></zui-slider>
|
|
82
|
-
|
|
83
|
-
<h3>range slider stepped + show min/max</h3>
|
|
84
|
-
<zui-slider id="range-stepped-min-max" range step="10" value-start="20" value-end="60" show-min-max></zui-slider>
|
|
85
|
-
|
|
86
88
|
<h3>set range slider programmatically</h3>
|
|
87
89
|
<button id="clickme-range">Reset range</button>
|
|
88
90
|
<zui-slider id="range-programmatic" range value-start="10" value-end="90"></zui-slider>
|
|
@@ -113,6 +115,404 @@
|
|
|
113
115
|
});
|
|
114
116
|
|
|
115
117
|
</script>
|
|
118
|
+
|
|
119
|
+
<!-- ─── Custom steps — single mode ─────────────────────────────────── -->
|
|
120
|
+
|
|
121
|
+
<h2>Custom steps</h2>
|
|
122
|
+
|
|
123
|
+
<h3>steps — numeric steps (single)</h3>
|
|
124
|
+
<zui-slider id="steps-basic"></zui-slider>
|
|
125
|
+
|
|
126
|
+
<h3>steps — initial value</h3>
|
|
127
|
+
<zui-slider id="steps-initial"></zui-slider>
|
|
128
|
+
|
|
129
|
+
<h3>steps — string labels</h3>
|
|
130
|
+
<zui-slider id="steps-sizes"></zui-slider>
|
|
131
|
+
|
|
132
|
+
<h3>steps - overflow step</h3>
|
|
133
|
+
<zui-slider id="steps-overflow"></zui-slider>
|
|
134
|
+
|
|
135
|
+
<h3>steps — object form <code>{ value, label }</code></h3>
|
|
136
|
+
<zui-slider id="steps-obj-basic"></zui-slider>
|
|
137
|
+
|
|
138
|
+
<h3>steps — object form: financial labels without stepParser</h3>
|
|
139
|
+
<p>Explicit numeric <code>value</code> fields let the slider snap correctly without a <code>stepParser</code>.</p>
|
|
140
|
+
<zui-slider id="steps-obj-financial"></zui-slider>
|
|
141
|
+
|
|
142
|
+
<h3>steps — object form: label omitted (defaults to String(value))</h3>
|
|
143
|
+
<zui-slider id="steps-obj-no-label"></zui-slider>
|
|
144
|
+
|
|
145
|
+
<h3>steps — mixed shorthand and object form</h3>
|
|
146
|
+
<zui-slider id="steps-mixed"></zui-slider>
|
|
147
|
+
|
|
148
|
+
<h3>steps — show-step-labels (numeric steps)</h3>
|
|
149
|
+
<zui-slider steps="0,1,10,50,100,200,1000" show-step-labels></zui-slider>
|
|
150
|
+
|
|
151
|
+
<h3>steps — show-step-labels (object form with labels)</h3>
|
|
152
|
+
<zui-slider id="steps-show-labels-obj" show-step-labels></zui-slider>
|
|
153
|
+
|
|
154
|
+
<h3>steps — show-step-labels (range mode)</h3>
|
|
155
|
+
<zui-slider steps="0,1,10,50,100,200,1000" range show-step-labels></zui-slider>
|
|
156
|
+
|
|
157
|
+
<h3>steps — show-step-labels (JS setup)</h3>
|
|
158
|
+
<zui-slider id="steps-show-labels-js"></zui-slider>
|
|
159
|
+
|
|
160
|
+
<h3>steps — disabled</h3>
|
|
161
|
+
<zui-slider id="steps-disabled" disabled></zui-slider>
|
|
162
|
+
|
|
163
|
+
<h3>steps — read-only</h3>
|
|
164
|
+
<zui-slider id="steps-readonly" readonly></zui-slider>
|
|
165
|
+
|
|
166
|
+
<h3>steps — programmatic value update</h3>
|
|
167
|
+
<button id="steps-programmatic-btn">Pick random step</button>
|
|
168
|
+
<zui-slider id="steps-programmatic"></zui-slider>
|
|
169
|
+
|
|
170
|
+
<!-- ─── stepParser — single mode ──────────────────────────────────── -->
|
|
171
|
+
|
|
172
|
+
<h2>stepParser</h2>
|
|
173
|
+
|
|
174
|
+
<h3>stepParser — multiple aliases for one step</h3>
|
|
175
|
+
<p>Type <code>1k</code>, <code>1,000</code>, or <code>1000</code> — all resolve to the step labeled <code>1K</code>. The displayed value is always the canonical step label, not the typed alias.</p>
|
|
176
|
+
<zui-slider id="steps-parser-numeric"></zui-slider>
|
|
177
|
+
|
|
178
|
+
<h3>stepParser — financial labels ('1M', '1MM', '1,000,000')</h3>
|
|
179
|
+
<p>Type <code>1M</code>, <code>1MM</code>, <code>1,000,000</code>, or <code>1000000</code> in the floating input.</p>
|
|
180
|
+
<zui-slider id="steps-parser-financial"></zui-slider>
|
|
181
|
+
|
|
182
|
+
<h3>stepParser — exact string label match (case-insensitive)</h3>
|
|
183
|
+
<p>Type <code>low</code>, <code>Medium</code>, or <code>HIGH</code>. Unrecognised input is rejected.</p>
|
|
184
|
+
<zui-slider id="steps-parser-exact"></zui-slider>
|
|
185
|
+
|
|
186
|
+
<h3>stepParser — exact label match takes priority over stepParser</h3>
|
|
187
|
+
<p>
|
|
188
|
+
Steps have labels <code>0</code>, <code>1K</code>, <code>1M</code>, <code>1B</code>.
|
|
189
|
+
Typing an exact label (e.g. <code>1M</code>) is accepted directly — <code>stepParser</code>
|
|
190
|
+
is never called. Typing an alias like <code>1mm</code> or <code>500k</code> goes through
|
|
191
|
+
<code>stepParser</code>.
|
|
192
|
+
</p>
|
|
193
|
+
<zui-slider id="steps-parser-priority"></zui-slider>
|
|
194
|
+
|
|
195
|
+
<!-- ─── Custom steps — range mode ─────────────────────────────────── -->
|
|
196
|
+
|
|
197
|
+
<h2>Custom steps — range mode</h2>
|
|
198
|
+
|
|
199
|
+
<h3>steps — range slider</h3>
|
|
200
|
+
<zui-slider id="steps-range" range></zui-slider>
|
|
201
|
+
|
|
202
|
+
<h3>steps — range slider with initial values</h3>
|
|
203
|
+
<zui-slider id="steps-range-initial" range></zui-slider>
|
|
204
|
+
|
|
205
|
+
<h3>steps — range slider with overflow step</h3>
|
|
206
|
+
<zui-slider id="steps-range-overflow" range></zui-slider>
|
|
207
|
+
|
|
208
|
+
<h3>steps — range slider disabled</h3>
|
|
209
|
+
<zui-slider id="steps-range-disabled" range disabled></zui-slider>
|
|
210
|
+
|
|
211
|
+
<h3>steps — range slider read-only</h3>
|
|
212
|
+
<zui-slider id="steps-range-readonly" range readonly></zui-slider>
|
|
213
|
+
|
|
214
|
+
<h3>steps — range slider programmatic update</h3>
|
|
215
|
+
<button id="steps-range-programmatic-btn">Pick random range</button>
|
|
216
|
+
<zui-slider id="steps-range-programmatic" range></zui-slider>
|
|
217
|
+
|
|
218
|
+
<!-- ─── stepParser — range mode ───────────────────────────────────── -->
|
|
219
|
+
|
|
220
|
+
<h3>stepParser — financial range slider ('1M'–'1B+')</h3>
|
|
221
|
+
<p>Type <code>1M</code>, <code>1MM</code>, <code>1,000,000</code>, or <code>10000000000</code> in either floating input.</p>
|
|
222
|
+
<zui-slider id="steps-range-parser" range></zui-slider>
|
|
223
|
+
<p>Last change: <strong id="steps-range-parser-output">—</strong></p>
|
|
224
|
+
|
|
225
|
+
<!-- ─── Dynamic steps update ──────────────────────────────────────── -->
|
|
226
|
+
|
|
227
|
+
<h2>Dynamic steps</h2>
|
|
228
|
+
|
|
229
|
+
<h3>steps — dynamic update at runtime</h3>
|
|
230
|
+
<button id="steps-dynamic-few">3 steps</button>
|
|
231
|
+
<button id="steps-dynamic-many">8 steps</button>
|
|
232
|
+
<button id="steps-dynamic-clear">Clear (fallback to min/max)</button>
|
|
233
|
+
<zui-slider id="steps-dynamic"></zui-slider>
|
|
234
|
+
|
|
235
|
+
<!-- ─── Form integration ───────────────────────────────────────────── -->
|
|
236
|
+
|
|
237
|
+
<h2>Custom steps — form integration</h2>
|
|
238
|
+
|
|
239
|
+
<h3>steps — form integration (single mode)</h3>
|
|
240
|
+
<form id="steps-form">
|
|
241
|
+
<zui-slider id="steps-form-slider" name="tier"></zui-slider>
|
|
242
|
+
<br />
|
|
243
|
+
<button type="submit">Submit</button>
|
|
244
|
+
<button type="reset">Reset</button>
|
|
245
|
+
</form>
|
|
246
|
+
<p>Submitted value: <strong id="steps-form-output">—</strong></p>
|
|
247
|
+
|
|
248
|
+
<h3>steps — form integration (range mode)</h3>
|
|
249
|
+
<form id="steps-range-form">
|
|
250
|
+
<zui-slider id="steps-range-form-slider" range name="budget"></zui-slider>
|
|
251
|
+
<br />
|
|
252
|
+
<button type="submit">Submit</button>
|
|
253
|
+
<button type="reset">Reset</button>
|
|
254
|
+
</form>
|
|
255
|
+
<p>Submitted value: <strong id="steps-range-form-output">—</strong></p>
|
|
256
|
+
|
|
257
|
+
<script>
|
|
258
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
259
|
+
const numericSteps = [1, 10, 50, 100, 200, 1000];
|
|
260
|
+
|
|
261
|
+
function financialParser(input) {
|
|
262
|
+
const cleaned = input.replace(/,/g, "").trim().toUpperCase();
|
|
263
|
+
if (cleaned === "0") return 0;
|
|
264
|
+
const multipliers = { K: 1e3, MM: 1e6, M: 1e6, B: 1e9, T: 1e12 };
|
|
265
|
+
for (const [suffix, factor] of Object.entries(multipliers)) {
|
|
266
|
+
if (cleaned.endsWith(suffix)) {
|
|
267
|
+
const n = parseFloat(cleaned);
|
|
268
|
+
if (!isNaN(n)) return n * factor;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const n = parseFloat(cleaned);
|
|
272
|
+
return isNaN(n) ? null : n;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ── Single — numeric steps ────────────────────────────────────────────
|
|
276
|
+
document.getElementById("steps-basic").steps = numericSteps;
|
|
277
|
+
|
|
278
|
+
const stepsInitial = document.getElementById("steps-initial");
|
|
279
|
+
stepsInitial.steps = numericSteps;
|
|
280
|
+
stepsInitial.value = "100";
|
|
281
|
+
|
|
282
|
+
document.getElementById("steps-sizes").steps = ["0", "1M", "10M", "50M", "100M", "200M", "1B", "1B+"];
|
|
283
|
+
|
|
284
|
+
document.getElementById("steps-overflow").steps = [0, 100, 250, 500, { value: Infinity, label: "1000+" }];
|
|
285
|
+
|
|
286
|
+
// Object form: { value, label } — label is displayed, value is used for numeric snapping
|
|
287
|
+
document.getElementById("steps-obj-basic").steps = [
|
|
288
|
+
{ value: 0, label: "0" },
|
|
289
|
+
{ value: 100, label: "100" },
|
|
290
|
+
{ value: 250, label: "250" },
|
|
291
|
+
{ value: 500, label: "500" },
|
|
292
|
+
{ value: 1000, label: "1000+" },
|
|
293
|
+
];
|
|
294
|
+
|
|
295
|
+
// Object form with explicit numeric values for financial labels — no stepParser required
|
|
296
|
+
document.getElementById("steps-obj-financial").steps = [
|
|
297
|
+
{ value: 0, label: "0" },
|
|
298
|
+
{ value: 1_000_000, label: "1M" },
|
|
299
|
+
{ value: 10_000_000, label: "10M" },
|
|
300
|
+
{ value: 50_000_000, label: "50M" },
|
|
301
|
+
{ value: 100_000_000, label: "100M"},
|
|
302
|
+
{ value: 200_000_000, label: "200M"},
|
|
303
|
+
{ value: 1_000_000_000, label: "1B"},
|
|
304
|
+
{ value: Infinity, label: "1B+" },
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
// Object form with label omitted — label defaults to String(value)
|
|
308
|
+
document.getElementById("steps-obj-no-label").steps = [
|
|
309
|
+
{ value: 0 },
|
|
310
|
+
{ value: 25 },
|
|
311
|
+
{ value: 50 },
|
|
312
|
+
{ value: 75 },
|
|
313
|
+
{ value: 100 },
|
|
314
|
+
];
|
|
315
|
+
|
|
316
|
+
// Mix of shorthand numbers, shorthand strings, and object form
|
|
317
|
+
document.getElementById("steps-mixed").steps = [
|
|
318
|
+
0,
|
|
319
|
+
{ value: 500_000, label: "500K" },
|
|
320
|
+
{ value: 1_000_000, label: "1M" },
|
|
321
|
+
{ value: 5_000_000, label: "5M" },
|
|
322
|
+
"custom",
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
const stepsShowLabelsJs = document.getElementById("steps-show-labels-js");
|
|
326
|
+
stepsShowLabelsJs.steps = [0, 1, 10, 50, 100, 200, 1000];
|
|
327
|
+
stepsShowLabelsJs.showStepLabels = true;
|
|
328
|
+
|
|
329
|
+
document.getElementById("steps-show-labels-obj").steps = [
|
|
330
|
+
{ value: 0, label: "0" },
|
|
331
|
+
{ value: 1, label: "1M" },
|
|
332
|
+
{ value: 10, label: "10M" },
|
|
333
|
+
{ value: 50, label: "50M" },
|
|
334
|
+
{ value: 100, label: "100M" },
|
|
335
|
+
{ value: 200, label: "200M" },
|
|
336
|
+
{ value: 1000, label: "1B" },
|
|
337
|
+
{ value: 1001, label: "1B+" },
|
|
338
|
+
];
|
|
339
|
+
|
|
340
|
+
const stepsDisabled = document.getElementById("steps-disabled");
|
|
341
|
+
stepsDisabled.steps = numericSteps;
|
|
342
|
+
stepsDisabled.value = "50";
|
|
343
|
+
|
|
344
|
+
const stepsReadonly = document.getElementById("steps-readonly");
|
|
345
|
+
stepsReadonly.steps = numericSteps;
|
|
346
|
+
stepsReadonly.value = "50";
|
|
347
|
+
|
|
348
|
+
const stepsProgrammatic = document.getElementById("steps-programmatic");
|
|
349
|
+
stepsProgrammatic.steps = numericSteps;
|
|
350
|
+
document.getElementById("steps-programmatic-btn").addEventListener("click", () => {
|
|
351
|
+
stepsProgrammatic.value = String(numericSteps[Math.floor(Math.random() * numericSteps.length)]);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
// ── Single — stepParser ───────────────────────────────────────────────
|
|
355
|
+
const stepsParserNumeric = document.getElementById("steps-parser-numeric");
|
|
356
|
+
stepsParserNumeric.steps = [
|
|
357
|
+
{ value: 0, label: "0" },
|
|
358
|
+
{ value: 1_000, label: "1K" },
|
|
359
|
+
{ value: 10_000, label: "10K" },
|
|
360
|
+
{ value: 100_000, label: "100K" },
|
|
361
|
+
{ value: 1_000_000, label: "1M" },
|
|
362
|
+
];
|
|
363
|
+
stepsParserNumeric.stepParser = (input) => {
|
|
364
|
+
const cleaned = input.replace(/,/g, "").trim().toLowerCase();
|
|
365
|
+
if (cleaned.endsWith("k")) {
|
|
366
|
+
const n = parseFloat(cleaned);
|
|
367
|
+
return isNaN(n) ? null : n * 1e3;
|
|
368
|
+
}
|
|
369
|
+
if (cleaned.endsWith("m")) {
|
|
370
|
+
const n = parseFloat(cleaned);
|
|
371
|
+
return isNaN(n) ? null : n * 1e6;
|
|
372
|
+
}
|
|
373
|
+
const n = parseFloat(cleaned);
|
|
374
|
+
return isNaN(n) ? null : n;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
const stepsParserFinancial = document.getElementById("steps-parser-financial");
|
|
378
|
+
stepsParserFinancial.steps = [
|
|
379
|
+
{ value: 0, label: "0" },
|
|
380
|
+
{ value: 1_000_000, label: "1M" },
|
|
381
|
+
{ value: 10_000_000, label: "10M" },
|
|
382
|
+
{ value: 50_000_000, label: "50M" },
|
|
383
|
+
{ value: 100_000_000, label: "100M" },
|
|
384
|
+
{ value: 200_000_000, label: "200M" },
|
|
385
|
+
{ value: 1_000_000_000, label: "1B" },
|
|
386
|
+
{ value: Infinity, label: "1B+" },
|
|
387
|
+
];
|
|
388
|
+
stepsParserFinancial.stepParser = financialParser;
|
|
389
|
+
|
|
390
|
+
const stepsParserExact = document.getElementById("steps-parser-exact");
|
|
391
|
+
stepsParserExact.steps = ["Low", "Medium", "High"];
|
|
392
|
+
stepsParserExact.stepParser = (input) => {
|
|
393
|
+
const map = { low: "Low", medium: "Medium", high: "High" };
|
|
394
|
+
return map[input.trim().toLowerCase()] ?? null;
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const stepsParserPriority = document.getElementById("steps-parser-priority");
|
|
398
|
+
stepsParserPriority.steps = [
|
|
399
|
+
{ value: 0, label: "0" },
|
|
400
|
+
{ value: 1_000, label: "1K" },
|
|
401
|
+
{ value: 1_000_000, label: "1M" },
|
|
402
|
+
{ value: 1_000_000_000, label: "1B" },
|
|
403
|
+
];
|
|
404
|
+
// Handles aliases like '1k', '1mm', '500k' but NOT '1K', '1M', '1B' themselves —
|
|
405
|
+
// those match step labels exactly and are accepted before stepParser is ever called.
|
|
406
|
+
stepsParserPriority.stepParser = (input) => {
|
|
407
|
+
const cleaned = input.replace(/,/g, "").trim().toLowerCase();
|
|
408
|
+
const suffixes = { k: 1e3, mm: 1e6, m: 1e6, b: 1e9 };
|
|
409
|
+
for (const [suffix, factor] of Object.entries(suffixes)) {
|
|
410
|
+
if (cleaned.endsWith(suffix)) {
|
|
411
|
+
const n = parseFloat(cleaned);
|
|
412
|
+
if (!isNaN(n)) { return n * factor; }
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const n = parseFloat(cleaned);
|
|
416
|
+
return isNaN(n) ? null : n;
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
// ── Range — numeric steps ─────────────────────────────────────────────
|
|
420
|
+
document.getElementById("steps-range").steps = numericSteps;
|
|
421
|
+
|
|
422
|
+
const stepsRangeInitial = document.getElementById("steps-range-initial");
|
|
423
|
+
stepsRangeInitial.steps = numericSteps;
|
|
424
|
+
stepsRangeInitial.valueStart = "10";
|
|
425
|
+
stepsRangeInitial.valueEnd = "200";
|
|
426
|
+
|
|
427
|
+
document.getElementById("steps-range-overflow").steps = [
|
|
428
|
+
{ value: 0, label: "0" },
|
|
429
|
+
{ value: 1_000_000, label: "1M" },
|
|
430
|
+
{ value: 10_000_000, label: "10M" },
|
|
431
|
+
{ value: 50_000_000, label: "50M" },
|
|
432
|
+
{ value: 100_000_000, label: "100M" },
|
|
433
|
+
{ value: 200_000_000, label: "200M" },
|
|
434
|
+
{ value: 1_000_000_000, label: "1B" },
|
|
435
|
+
{ value: Infinity, label: "1B+" },
|
|
436
|
+
];
|
|
437
|
+
|
|
438
|
+
const stepsRangeDisabled = document.getElementById("steps-range-disabled");
|
|
439
|
+
stepsRangeDisabled.steps = numericSteps;
|
|
440
|
+
stepsRangeDisabled.valueStart = "10";
|
|
441
|
+
stepsRangeDisabled.valueEnd = "200";
|
|
442
|
+
|
|
443
|
+
const stepsRangeReadonly = document.getElementById("steps-range-readonly");
|
|
444
|
+
stepsRangeReadonly.steps = numericSteps;
|
|
445
|
+
stepsRangeReadonly.valueStart = "10";
|
|
446
|
+
stepsRangeReadonly.valueEnd = "200";
|
|
447
|
+
|
|
448
|
+
const stepsRangeProgrammatic = document.getElementById("steps-range-programmatic");
|
|
449
|
+
stepsRangeProgrammatic.steps = numericSteps;
|
|
450
|
+
document.getElementById("steps-range-programmatic-btn").addEventListener("click", () => {
|
|
451
|
+
const a = Math.floor(Math.random() * (numericSteps.length - 1));
|
|
452
|
+
const b = Math.floor(Math.random() * (numericSteps.length - 1 - a)) + a + 1;
|
|
453
|
+
stepsRangeProgrammatic.valueStart = String(numericSteps[a]);
|
|
454
|
+
stepsRangeProgrammatic.valueEnd = String(numericSteps[b]);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// ── Range — stepParser ────────────────────────────────────────────────
|
|
458
|
+
const stepsRangeParser = document.getElementById("steps-range-parser");
|
|
459
|
+
stepsRangeParser.steps = [
|
|
460
|
+
{ value: 0, label: "0" },
|
|
461
|
+
{ value: 1_000_000, label: "1M" },
|
|
462
|
+
{ value: 10_000_000, label: "10M" },
|
|
463
|
+
{ value: 50_000_000, label: "50M" },
|
|
464
|
+
{ value: 100_000_000, label: "100M" },
|
|
465
|
+
{ value: 200_000_000, label: "200M" },
|
|
466
|
+
{ value: 1_000_000_000, label: "1B" },
|
|
467
|
+
{ value: Infinity, label: "1B+" },
|
|
468
|
+
];
|
|
469
|
+
stepsRangeParser.valueStart = "1M";
|
|
470
|
+
stepsRangeParser.valueEnd = "100M";
|
|
471
|
+
stepsRangeParser.stepParser = financialParser;
|
|
472
|
+
stepsRangeParser.addEventListener("change", (e) => {
|
|
473
|
+
const { valueStart, valueEnd } = e.detail;
|
|
474
|
+
document.getElementById("steps-range-parser-output").textContent =
|
|
475
|
+
`valueStart=${valueStart}, valueEnd=${valueEnd}`;
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// ── Dynamic steps ─────────────────────────────────────────────────────
|
|
479
|
+
const stepsDynamic = document.getElementById("steps-dynamic");
|
|
480
|
+
stepsDynamic.steps = [10, 50, 100];
|
|
481
|
+
document.getElementById("steps-dynamic-few").addEventListener("click", () => {
|
|
482
|
+
stepsDynamic.steps = [10, 50, 100];
|
|
483
|
+
});
|
|
484
|
+
document.getElementById("steps-dynamic-many").addEventListener("click", () => {
|
|
485
|
+
stepsDynamic.steps = [0, 10, 25, 50, 75, 100, 200, 500];
|
|
486
|
+
});
|
|
487
|
+
document.getElementById("steps-dynamic-clear").addEventListener("click", () => {
|
|
488
|
+
stepsDynamic.steps = [];
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
// ── Form integration ──────────────────────────────────────────────────
|
|
492
|
+
document.getElementById("steps-form-slider").steps = numericSteps;
|
|
493
|
+
document.getElementById("steps-form").addEventListener("submit", (e) => {
|
|
494
|
+
e.preventDefault();
|
|
495
|
+
document.getElementById("steps-form-output").textContent = new FormData(e.target).get("tier");
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
const stepsRangeFormSlider = document.getElementById("steps-range-form-slider");
|
|
499
|
+
stepsRangeFormSlider.steps = [
|
|
500
|
+
{ value: 0, label: "0" },
|
|
501
|
+
{ value: 1_000_000, label: "1M" },
|
|
502
|
+
{ value: 10_000_000, label: "10M" },
|
|
503
|
+
{ value: 50_000_000, label: "50M" },
|
|
504
|
+
{ value: 100_000_000, label: "100M" },
|
|
505
|
+
{ value: 200_000_000, label: "200M" },
|
|
506
|
+
{ value: 1_000_000_000, label: "1B" },
|
|
507
|
+
{ value: Infinity, label: "1B+" },
|
|
508
|
+
];
|
|
509
|
+
stepsRangeFormSlider.valueStart = "1M";
|
|
510
|
+
stepsRangeFormSlider.valueEnd = "100M";
|
|
511
|
+
document.getElementById("steps-range-form").addEventListener("submit", (e) => {
|
|
512
|
+
e.preventDefault();
|
|
513
|
+
document.getElementById("steps-range-form-output").textContent = new FormData(e.target).get("budget");
|
|
514
|
+
});
|
|
515
|
+
</script>
|
|
116
516
|
</body>
|
|
117
517
|
|
|
118
518
|
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zywave/zui-slider",
|
|
3
|
-
"version": "4.4.0-pre.
|
|
3
|
+
"version": "4.4.0-pre.4",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@zywave/zui-input": "^4.2.3"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "951dae4a386aa23d0148f7fefc096a3f97a697b0"
|
|
31
31
|
}
|
package/src/zui-slider-css.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
2
|
|
|
3
|
-
export const style = css`:host .thumb-input input
|
|
3
|
+
export const style = css`:host .thumb-input input{display:inline-block;width:100%;min-height:2.625rem;vertical-align:middle;padding:0 .625rem;background-color:#fff;border:.0625rem solid var(--zui-gray-200);border-radius:.25rem;font:inherit;color:inherit;transition:border 100ms ease-in-out,box-shadow 100ms ease-in-out;box-sizing:border-box;appearance:textfield}:host .thumb-input input::-webkit-input-placeholder{color:var(--zui-gray-200)}:host .thumb-input input::-moz-placeholder{opacity:1;color:var(--zui-gray-200)}:host .thumb-input input:-moz-placeholder{opacity:1;color:var(--zui-gray-200)}:host .thumb-input input:-ms-input-placeholder{color:var(--zui-gray-200)}:host .thumb-input input:not(output):-moz-ui-invalid{box-shadow:none}:host .thumb-input input:hover{border-color:var(--zui-gray-400)}:host .thumb-input input:focus{border-color:var(--zui-blue-400);box-shadow:0 0 0 .0625rem var(--zui-blue-400);outline:none}:host .thumb-input input[disabled]{background-color:var(--zui-gray-100);cursor:not-allowed;color:var(--zui-gray-300)}:host .thumb-input input[disabled]:hover{border:.0625rem solid var(--zui-gray-200)}:host .thumb-input input[readonly]{outline:none}:host{--zui-slider-thumb-size: 0.875rem;--zui-slider-input-width: 8ch;position:relative;display:block}:host .single-wrapper,:host .range-wrapper{position:relative;display:flex;height:var(--zui-slider-thumb-size);align-items:center;margin:0 calc(var(--zui-slider-thumb-size)*-1)}:host input[type=range]{width:100%;height:var(--zui-slider-thumb-size);margin:0;background:rgba(0,0,0,0);outline:none;cursor:grab;-webkit-appearance:none;appearance:none}:host input[type=range]::-webkit-slider-runnable-track{height:.25rem;background:var(--zui-slider-track-bg)}:host input[type=range]::-moz-range-track{height:.25rem;background:var(--zui-slider-track-bg)}:host input[type=range]::-webkit-slider-thumb{width:calc(var(--zui-slider-thumb-size)*3);height:calc(var(--zui-slider-thumb-size)*3);background:radial-gradient(circle, var(--zui-blue) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2));border-radius:50%;box-shadow:none;cursor:grab;transition:background 100ms ease-out,box-shadow 100ms ease-out}:host input[type=range]::-webkit-slider-thumb:hover{box-shadow:inset 0 0 0 var(--zui-slider-thumb-size) rgba(120,120,140,.16)}:host input[type=range]::-moz-range-thumb{width:calc(var(--zui-slider-thumb-size)*3);height:calc(var(--zui-slider-thumb-size)*3);background:radial-gradient(circle, var(--zui-blue) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2));border-radius:50%;box-shadow:none;cursor:grab;transition:background 100ms ease-out,box-shadow 100ms ease-out}:host input[type=range]::-moz-range-thumb:hover{box-shadow:inset 0 0 0 var(--zui-slider-thumb-size) rgba(120,120,140,.16)}:host input[type=range]::-webkit-slider-thumb{transform:translateY(calc(-50% + 0.125rem));-webkit-appearance:none;appearance:none}:host input[type=range]::-moz-range-thumb{border:0}:host input[type=range]:hover::-webkit-slider-thumb{background:radial-gradient(circle, var(--zui-blue-400) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2))}:host input[type=range]:hover::-moz-range-thumb{background:radial-gradient(circle, var(--zui-blue-400) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2))}:host input[type=range]:focus::-webkit-slider-thumb{box-shadow:inset 0 0 0 var(--zui-slider-thumb-size) rgba(120,120,140,.16)}:host input[type=range]:focus::-moz-range-thumb{box-shadow:inset 0 0 0 var(--zui-slider-thumb-size) rgba(120,120,140,.16)}:host input[type=range]:active::-webkit-slider-thumb{background:radial-gradient(circle, var(--zui-blue-600) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2));box-shadow:inset 0 0 0 var(--zui-slider-thumb-size) rgba(120,120,140,.16);cursor:grabbing}:host input[type=range]:active::-moz-range-thumb{background:radial-gradient(circle, var(--zui-blue-600) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2));box-shadow:inset 0 0 0 var(--zui-slider-thumb-size) rgba(120,120,140,.16);cursor:grabbing}:host .thumb-input{position:absolute;bottom:calc(var(--zui-slider-thumb-size)*2 + 0.25rem);opacity:0;z-index:10;transform:translateX(-50%);transition:opacity 100ms ease-out;pointer-events:none}:host .thumb-input--visible,:host .thumb-input:focus-within{opacity:1;pointer-events:auto}:host .thumb-input input{width:var(--zui-slider-input-width);text-align:center}:host .thumb-input input::-webkit-inner-spin-button,:host .thumb-input input::-webkit-outer-spin-button{appearance:none}:host .step-dots{position:absolute;top:50%;left:0;width:100%;height:0;pointer-events:none}:host .step-dots .step-dot{position:absolute;width:.375rem;height:.375rem;background-color:var(--zui-blue);border-radius:50%;transform:translate(-50%, -50%)}:host .step-dots .step-dot:first-child,:host .step-dots .step-dot:last-child,:host .step-dots .step-dot--last{width:.125rem;height:1rem;border-radius:.125rem}:host .step-dots .step-dot-label{position:absolute;top:.375rem;font-weight:600;white-space:nowrap;color:var(--zui-gray-600);transform:translateX(-50%);user-select:none}:host .step-dots .step-dot-label:nth-child(2){transform:none}:host .step-dots .step-dot-label:last-child{transform:translateX(-100%)}:host .range-wrapper{cursor:grab}:host .range-wrapper:active{cursor:grabbing}:host .range-wrapper input[type=range]{position:absolute;pointer-events:none}:host .range-wrapper input[type=range]::-webkit-slider-thumb{pointer-events:all}:host .range-wrapper input[type=range]::-moz-range-thumb{pointer-events:all}:host .range-wrapper input[type=range]::-moz-range-progress{background:rgba(0,0,0,0)}:host .min-max-labels{display:flex;justify-content:space-between;user-select:none}:host .min-max-labels .min-max-label{font-weight:600;color:var(--zui-gray-600)}:host([range]) .min-max-labels{margin-top:.3125rem}:host([readonly]) input[type=range]:disabled{cursor:default}:host([readonly]) input[type=range]:disabled::-webkit-slider-thumb{background:radial-gradient(circle, var(--zui-blue) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2));cursor:default}:host([readonly]) input[type=range]:disabled::-moz-range-thumb{background:radial-gradient(circle, var(--zui-blue) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2));cursor:default}:host([disabled]){cursor:not-allowed}:host([disabled]) input[type=range]:disabled{cursor:not-allowed}:host([disabled]) input[type=range]:disabled::-webkit-slider-thumb{background:radial-gradient(circle, var(--zui-gray) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2));cursor:not-allowed}:host([disabled]) input[type=range]:disabled::-webkit-slider-thumb:hover{box-shadow:none}:host([disabled]) input[type=range]:disabled::-moz-range-thumb{background:radial-gradient(circle, var(--zui-gray) calc(var(--zui-slider-thumb-size) / 2 - 0.0625rem), transparent calc(var(--zui-slider-thumb-size) / 2));cursor:not-allowed}:host([disabled]) input[type=range]:disabled::-moz-range-thumb:hover{box-shadow:none}:host([disabled]) .step-dot{background-color:var(--zui-gray)}:host([disabled]) .range-wrapper{cursor:not-allowed}`;
|
package/src/zui-slider.scss
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
position: relative;
|
|
37
37
|
display: block;
|
|
38
38
|
|
|
39
|
-
//
|
|
39
|
+
// Shared: wrapper layout
|
|
40
40
|
|
|
41
41
|
.single-wrapper,
|
|
42
42
|
.range-wrapper {
|
|
@@ -57,7 +57,6 @@
|
|
|
57
57
|
outline: none;
|
|
58
58
|
cursor: grab;
|
|
59
59
|
-webkit-appearance: none;
|
|
60
|
-
-moz-appearance: none;
|
|
61
60
|
appearance: none;
|
|
62
61
|
|
|
63
62
|
@include on-track {
|
|
@@ -65,9 +64,11 @@
|
|
|
65
64
|
background: var(--zui-slider-track-bg);
|
|
66
65
|
}
|
|
67
66
|
|
|
67
|
+
$thumb-hit-size: calc(var(--zui-slider-thumb-size) * 3);
|
|
68
|
+
|
|
68
69
|
@include on-thumb {
|
|
69
|
-
width:
|
|
70
|
-
height:
|
|
70
|
+
width: $thumb-hit-size;
|
|
71
|
+
height: $thumb-hit-size;
|
|
71
72
|
@include thumb-bg(var(--zui-blue));
|
|
72
73
|
border-radius: 50%;
|
|
73
74
|
box-shadow: none;
|
|
@@ -124,10 +125,10 @@
|
|
|
124
125
|
&--visible,
|
|
125
126
|
&:focus-within {
|
|
126
127
|
opacity: 1;
|
|
127
|
-
pointer-events:
|
|
128
|
+
pointer-events: auto;
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
input
|
|
131
|
+
input {
|
|
131
132
|
@extend %input-base;
|
|
132
133
|
width: var(--zui-slider-input-width);
|
|
133
134
|
text-align: center;
|
|
@@ -157,13 +158,36 @@
|
|
|
157
158
|
border-radius: 50%;
|
|
158
159
|
transform: translate(-50%, -50%);
|
|
159
160
|
|
|
161
|
+
// &--last covers the case where showStepLabels is true: a label becomes the last
|
|
162
|
+
// child, so :last-child alone no longer targets the final dot.
|
|
160
163
|
&:first-child,
|
|
161
|
-
&:last-child
|
|
164
|
+
&:last-child,
|
|
165
|
+
&--last {
|
|
162
166
|
width: rem(2);
|
|
163
167
|
height: rem(16);
|
|
164
168
|
border-radius: rem(2);
|
|
165
169
|
}
|
|
166
170
|
}
|
|
171
|
+
|
|
172
|
+
.step-dot-label {
|
|
173
|
+
position: absolute;
|
|
174
|
+
top: rem(6);
|
|
175
|
+
font-weight: 600;
|
|
176
|
+
white-space: nowrap;
|
|
177
|
+
color: var(--zui-gray-600);
|
|
178
|
+
transform: translateX(-50%);
|
|
179
|
+
user-select: none;
|
|
180
|
+
|
|
181
|
+
// When labels are rendered, the first label is the 2nd child (after the first dot)
|
|
182
|
+
// and the last label is always the last child — align them to the track edges.
|
|
183
|
+
&:nth-child(2) {
|
|
184
|
+
transform: none;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
&:last-child {
|
|
188
|
+
transform: translateX(-100%);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
167
191
|
}
|
|
168
192
|
|
|
169
193
|
// Range mode
|
|
@@ -194,6 +218,7 @@
|
|
|
194
218
|
.min-max-labels {
|
|
195
219
|
display: flex;
|
|
196
220
|
justify-content: space-between;
|
|
221
|
+
user-select: none;
|
|
197
222
|
|
|
198
223
|
.min-max-label {
|
|
199
224
|
font-weight: 600;
|