@rogieking/figui3 2.36.0 → 2.37.0
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/README.md +2 -1
- package/components.css +1 -1
- package/fig.js +103 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -319,12 +319,13 @@ A range slider with multiple types and optional text input.
|
|
|
319
319
|
| Attribute | Type | Default | Description |
|
|
320
320
|
|-----------|------|---------|-------------|
|
|
321
321
|
| `type` | string | `"range"` | Type: `"range"`, `"hue"`, `"opacity"`, `"delta"`, `"stepper"` |
|
|
322
|
-
| `value` | number | — | Current value |
|
|
322
|
+
| `value` | number | — | Current value; missing/invalid values fall back to `min` (or `default` for `type="delta"`, then `0`) |
|
|
323
323
|
| `min` | number | `0` | Minimum value |
|
|
324
324
|
| `max` | number | `100` | Maximum value |
|
|
325
325
|
| `step` | number | `1` | Step increment |
|
|
326
326
|
| `default` | number | — | Default/reset value (shown as a marker on the track) |
|
|
327
327
|
| `text` | boolean | `false` | Show text input |
|
|
328
|
+
| `placeholder` | string | `"##"` | Placeholder for text input mode (`text="true"`) |
|
|
328
329
|
| `units` | string | — | Unit label (e.g., `"%"`, `"px"`) |
|
|
329
330
|
| `transform` | number | — | Multiplier for display value |
|
|
330
331
|
| `color` | string | — | Track color (for opacity type) |
|
package/components.css
CHANGED
|
@@ -1959,7 +1959,7 @@ fig-slider {
|
|
|
1959
1959
|
--slider-handle-shadow-focus:
|
|
1960
1960
|
inset 0 0 0 4px var(--handle-color), inset 0 0 0 5px rgba(0, 0, 0, 0.1),
|
|
1961
1961
|
var(--handle-shadow), 0 0 0 1px var(--figma-color-border-selected);
|
|
1962
|
-
--slider-transition:
|
|
1962
|
+
--slider-transition: none;
|
|
1963
1963
|
--handle-transition: var(--slider-transition);
|
|
1964
1964
|
|
|
1965
1965
|
display: inline-flex;
|
package/fig.js
CHANGED
|
@@ -2357,6 +2357,7 @@ customElements.define("fig-segmented-control", FigSegmentedControl);
|
|
|
2357
2357
|
* @attr {number} max - The maximum value
|
|
2358
2358
|
* @attr {number} step - The step increment
|
|
2359
2359
|
* @attr {boolean} text - Whether to show a text input alongside the slider
|
|
2360
|
+
* @attr {string} placeholder - Placeholder for the number input when text is enabled
|
|
2360
2361
|
* @attr {string} units - The units to display after the value
|
|
2361
2362
|
* @attr {number} transform - A multiplier for the displayed value
|
|
2362
2363
|
* @attr {boolean} disabled - Whether the slider is disabled
|
|
@@ -2364,6 +2365,7 @@ customElements.define("fig-segmented-control", FigSegmentedControl);
|
|
|
2364
2365
|
*/
|
|
2365
2366
|
class FigSlider extends HTMLElement {
|
|
2366
2367
|
#isInteracting = false;
|
|
2368
|
+
#showEmptyTextValue = false;
|
|
2367
2369
|
// Private fields declarations
|
|
2368
2370
|
#typeDefaults = {
|
|
2369
2371
|
range: { min: 0, max: 100, step: 1 },
|
|
@@ -2405,7 +2407,7 @@ class FigSlider extends HTMLElement {
|
|
|
2405
2407
|
}
|
|
2406
2408
|
|
|
2407
2409
|
#regenerateInnerHTML() {
|
|
2408
|
-
|
|
2410
|
+
const rawValue = this.getAttribute("value");
|
|
2409
2411
|
this.type = this.getAttribute("type") || "range";
|
|
2410
2412
|
this.variant = this.getAttribute("variant") || "default";
|
|
2411
2413
|
this.text =
|
|
@@ -2416,13 +2418,25 @@ class FigSlider extends HTMLElement {
|
|
|
2416
2418
|
this.precision = this.hasAttribute("precision")
|
|
2417
2419
|
? Number(this.getAttribute("precision"))
|
|
2418
2420
|
: null;
|
|
2421
|
+
this.placeholder =
|
|
2422
|
+
this.getAttribute("placeholder") !== null
|
|
2423
|
+
? this.getAttribute("placeholder")
|
|
2424
|
+
: "##";
|
|
2419
2425
|
|
|
2420
2426
|
const defaults = this.#typeDefaults[this.type];
|
|
2421
2427
|
this.min = Number(this.getAttribute("min") || defaults.min);
|
|
2422
2428
|
this.max = Number(this.getAttribute("max") || defaults.max);
|
|
2423
2429
|
this.step = Number(this.getAttribute("step") || defaults.step);
|
|
2424
2430
|
this.color = this.getAttribute("color") || defaults?.color;
|
|
2425
|
-
this.default = this.
|
|
2431
|
+
this.default = this.hasAttribute("default")
|
|
2432
|
+
? this.getAttribute("default")
|
|
2433
|
+
: this.type === "delta"
|
|
2434
|
+
? 0
|
|
2435
|
+
: this.min;
|
|
2436
|
+
this.#showEmptyTextValue =
|
|
2437
|
+
rawValue === null ||
|
|
2438
|
+
(typeof rawValue === "string" && rawValue.trim() === "");
|
|
2439
|
+
this.value = this.#normalizeSliderValue(rawValue);
|
|
2426
2440
|
|
|
2427
2441
|
if (this.color) {
|
|
2428
2442
|
this.style.setProperty("--color", this.color);
|
|
@@ -2447,12 +2461,12 @@ class FigSlider extends HTMLElement {
|
|
|
2447
2461
|
if (this.text) {
|
|
2448
2462
|
html = `${slider}
|
|
2449
2463
|
<fig-input-number
|
|
2450
|
-
placeholder="
|
|
2464
|
+
placeholder="${this.placeholder}"
|
|
2451
2465
|
min="${this.min}"
|
|
2452
2466
|
max="${this.max}"
|
|
2453
2467
|
transform="${this.transform}"
|
|
2454
2468
|
step="${this.step}"
|
|
2455
|
-
value="${this.value}"
|
|
2469
|
+
value="${this.#showEmptyTextValue ? "" : this.value}"
|
|
2456
2470
|
${this.units ? `units="${this.units}"` : ""}
|
|
2457
2471
|
${this.precision !== null ? `precision="${this.precision}"` : ""}>
|
|
2458
2472
|
</fig-input-number>`;
|
|
@@ -2566,17 +2580,59 @@ class FigSlider extends HTMLElement {
|
|
|
2566
2580
|
|
|
2567
2581
|
#handleTextInput() {
|
|
2568
2582
|
if (this.figInputNumber) {
|
|
2569
|
-
|
|
2570
|
-
this.#
|
|
2583
|
+
const rawTextValue = this.figInputNumber.value;
|
|
2584
|
+
this.#showEmptyTextValue =
|
|
2585
|
+
rawTextValue === null ||
|
|
2586
|
+
rawTextValue === undefined ||
|
|
2587
|
+
(typeof rawTextValue === "string" && rawTextValue.trim() === "");
|
|
2588
|
+
const normalized = this.#normalizeSliderValue(rawTextValue);
|
|
2589
|
+
this.value = normalized;
|
|
2590
|
+
this.input.value = String(normalized);
|
|
2591
|
+
this.#syncValue();
|
|
2571
2592
|
this.dispatchEvent(
|
|
2572
2593
|
new CustomEvent("input", { detail: this.value, bubbles: true }),
|
|
2573
2594
|
);
|
|
2574
2595
|
}
|
|
2575
2596
|
}
|
|
2576
2597
|
#calculateNormal(value) {
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2598
|
+
const { min, max } = this.#getBounds();
|
|
2599
|
+
const range = max - min;
|
|
2600
|
+
if (range === 0) return 0;
|
|
2601
|
+
return (Number(value) - min) / range;
|
|
2602
|
+
}
|
|
2603
|
+
#toFiniteNumber(value) {
|
|
2604
|
+
if (value === null || value === undefined) return null;
|
|
2605
|
+
if (typeof value === "string" && value.trim() === "") return null;
|
|
2606
|
+
const parsed = Number(value);
|
|
2607
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
2608
|
+
}
|
|
2609
|
+
#getBounds() {
|
|
2610
|
+
let min = this.#toFiniteNumber(this.min);
|
|
2611
|
+
let max = this.#toFiniteNumber(this.max);
|
|
2612
|
+
if (min === null) min = 0;
|
|
2613
|
+
if (max === null) max = min;
|
|
2614
|
+
if (min > max) {
|
|
2615
|
+
[min, max] = [max, min];
|
|
2616
|
+
}
|
|
2617
|
+
return { min, max };
|
|
2618
|
+
}
|
|
2619
|
+
#clampToBounds(value) {
|
|
2620
|
+
const { min, max } = this.#getBounds();
|
|
2621
|
+
return Math.min(max, Math.max(min, value));
|
|
2622
|
+
}
|
|
2623
|
+
#getFallbackValue() {
|
|
2624
|
+
if (this.type === "delta") {
|
|
2625
|
+
const deltaDefault = this.#toFiniteNumber(this.default);
|
|
2626
|
+
if (deltaDefault !== null) return this.#clampToBounds(deltaDefault);
|
|
2627
|
+
return this.#clampToBounds(0);
|
|
2628
|
+
}
|
|
2629
|
+
const { min } = this.#getBounds();
|
|
2630
|
+
return min;
|
|
2631
|
+
}
|
|
2632
|
+
#normalizeSliderValue(rawValue) {
|
|
2633
|
+
const parsed = this.#toFiniteNumber(rawValue);
|
|
2634
|
+
if (parsed === null) return this.#getFallbackValue();
|
|
2635
|
+
return this.#clampToBounds(parsed);
|
|
2580
2636
|
}
|
|
2581
2637
|
#syncProperties() {
|
|
2582
2638
|
let complete = this.#calculateNormal(this.value);
|
|
@@ -2592,11 +2648,15 @@ class FigSlider extends HTMLElement {
|
|
|
2592
2648
|
// Update ARIA value
|
|
2593
2649
|
this.input.setAttribute("aria-valuenow", val);
|
|
2594
2650
|
if (this.figInputNumber) {
|
|
2595
|
-
this.figInputNumber.setAttribute(
|
|
2651
|
+
this.figInputNumber.setAttribute(
|
|
2652
|
+
"value",
|
|
2653
|
+
this.#showEmptyTextValue ? "" : val,
|
|
2654
|
+
);
|
|
2596
2655
|
}
|
|
2597
2656
|
}
|
|
2598
2657
|
|
|
2599
2658
|
#handleInput() {
|
|
2659
|
+
this.#showEmptyTextValue = false;
|
|
2600
2660
|
this.#syncValue();
|
|
2601
2661
|
this.dispatchEvent(
|
|
2602
2662
|
new CustomEvent("input", { detail: this.value, bubbles: true }),
|
|
@@ -2605,6 +2665,7 @@ class FigSlider extends HTMLElement {
|
|
|
2605
2665
|
|
|
2606
2666
|
#handleChange() {
|
|
2607
2667
|
this.#isInteracting = false;
|
|
2668
|
+
this.#showEmptyTextValue = false;
|
|
2608
2669
|
this.#syncValue();
|
|
2609
2670
|
this.dispatchEvent(
|
|
2610
2671
|
new CustomEvent("change", { detail: this.value, bubbles: true }),
|
|
@@ -2613,8 +2674,15 @@ class FigSlider extends HTMLElement {
|
|
|
2613
2674
|
|
|
2614
2675
|
#handleTextChange() {
|
|
2615
2676
|
if (this.figInputNumber) {
|
|
2616
|
-
|
|
2617
|
-
this.#
|
|
2677
|
+
const rawTextValue = this.figInputNumber.value;
|
|
2678
|
+
this.#showEmptyTextValue =
|
|
2679
|
+
rawTextValue === null ||
|
|
2680
|
+
rawTextValue === undefined ||
|
|
2681
|
+
(typeof rawTextValue === "string" && rawTextValue.trim() === "");
|
|
2682
|
+
const normalized = this.#normalizeSliderValue(rawTextValue);
|
|
2683
|
+
this.value = normalized;
|
|
2684
|
+
this.input.value = String(normalized);
|
|
2685
|
+
this.#syncValue();
|
|
2618
2686
|
this.dispatchEvent(
|
|
2619
2687
|
new CustomEvent("change", { detail: this.value, bubbles: true }),
|
|
2620
2688
|
);
|
|
@@ -2634,6 +2702,7 @@ class FigSlider extends HTMLElement {
|
|
|
2634
2702
|
"units",
|
|
2635
2703
|
"transform",
|
|
2636
2704
|
"text",
|
|
2705
|
+
"placeholder",
|
|
2637
2706
|
"default",
|
|
2638
2707
|
"precision",
|
|
2639
2708
|
];
|
|
@@ -2660,11 +2729,17 @@ class FigSlider extends HTMLElement {
|
|
|
2660
2729
|
break;
|
|
2661
2730
|
case "value":
|
|
2662
2731
|
if (this.#isInteracting) break;
|
|
2663
|
-
this
|
|
2664
|
-
|
|
2665
|
-
|
|
2732
|
+
this.#showEmptyTextValue =
|
|
2733
|
+
newValue === null ||
|
|
2734
|
+
(typeof newValue === "string" && newValue.trim() === "");
|
|
2735
|
+
this.value = this.#normalizeSliderValue(newValue);
|
|
2736
|
+
this.input.value = String(this.value);
|
|
2737
|
+
this.#syncValue();
|
|
2666
2738
|
if (this.figInputNumber) {
|
|
2667
|
-
this.figInputNumber.setAttribute(
|
|
2739
|
+
this.figInputNumber.setAttribute(
|
|
2740
|
+
"value",
|
|
2741
|
+
this.#showEmptyTextValue ? "" : this.value,
|
|
2742
|
+
);
|
|
2668
2743
|
}
|
|
2669
2744
|
break;
|
|
2670
2745
|
case "transform":
|
|
@@ -2683,8 +2758,19 @@ class FigSlider extends HTMLElement {
|
|
|
2683
2758
|
}
|
|
2684
2759
|
}
|
|
2685
2760
|
break;
|
|
2761
|
+
case "placeholder":
|
|
2762
|
+
this.placeholder = newValue !== null ? newValue : "##";
|
|
2763
|
+
if (this.figInputNumber) {
|
|
2764
|
+
this.figInputNumber.setAttribute("placeholder", this.placeholder);
|
|
2765
|
+
}
|
|
2766
|
+
break;
|
|
2686
2767
|
case "default":
|
|
2687
|
-
this.default =
|
|
2768
|
+
this.default =
|
|
2769
|
+
newValue !== null
|
|
2770
|
+
? newValue
|
|
2771
|
+
: this.type === "delta"
|
|
2772
|
+
? 0
|
|
2773
|
+
: this.min;
|
|
2688
2774
|
this.#syncProperties();
|
|
2689
2775
|
break;
|
|
2690
2776
|
case "min":
|
package/package.json
CHANGED