@rogieking/figui3 3.0.3 → 3.2.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 +19 -1
- package/dist/fig.js +30 -30
- package/fig.js +187 -26
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -2436,49 +2436,195 @@ customElements.define("fig-segment", FigSegment);
|
|
|
2436
2436
|
*/
|
|
2437
2437
|
class FigSegmentedControl extends HTMLElement {
|
|
2438
2438
|
#selectedSegment = null;
|
|
2439
|
+
#boundHandleClick = this.handleClick.bind(this);
|
|
2440
|
+
#mutationObserver = null;
|
|
2439
2441
|
|
|
2440
2442
|
constructor() {
|
|
2441
2443
|
super();
|
|
2442
2444
|
}
|
|
2443
2445
|
|
|
2444
2446
|
static get observedAttributes() {
|
|
2445
|
-
return ["disabled"];
|
|
2447
|
+
return ["disabled", "value"];
|
|
2446
2448
|
}
|
|
2447
2449
|
|
|
2448
2450
|
connectedCallback() {
|
|
2449
2451
|
this.name = this.getAttribute("name") || "segmented-control";
|
|
2450
|
-
this.addEventListener("click", this
|
|
2452
|
+
this.addEventListener("click", this.#boundHandleClick);
|
|
2451
2453
|
this.#applyDisabled(
|
|
2452
2454
|
this.hasAttribute("disabled") &&
|
|
2453
2455
|
this.getAttribute("disabled") !== "false",
|
|
2454
2456
|
);
|
|
2457
|
+
this.#startSegmentObserver();
|
|
2455
2458
|
|
|
2456
|
-
//
|
|
2459
|
+
// Defer initial selection so child segments are available.
|
|
2457
2460
|
requestAnimationFrame(() => {
|
|
2458
|
-
|
|
2459
|
-
const hasSelected = Array.from(segments).some((s) =>
|
|
2460
|
-
s.hasAttribute("selected"),
|
|
2461
|
-
);
|
|
2462
|
-
if (!hasSelected && segments.length > 0) {
|
|
2463
|
-
this.selectedSegment = segments[0];
|
|
2464
|
-
}
|
|
2461
|
+
this.#syncSelectionFromAttributes({ enforceFallback: true });
|
|
2465
2462
|
});
|
|
2466
2463
|
}
|
|
2467
2464
|
|
|
2465
|
+
disconnectedCallback() {
|
|
2466
|
+
this.removeEventListener("click", this.#boundHandleClick);
|
|
2467
|
+
this.#mutationObserver?.disconnect();
|
|
2468
|
+
this.#mutationObserver = null;
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2468
2471
|
get selectedSegment() {
|
|
2469
2472
|
return this.#selectedSegment;
|
|
2470
2473
|
}
|
|
2471
2474
|
|
|
2472
2475
|
set selectedSegment(segment) {
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
+
const segments = this.querySelectorAll("fig-segment");
|
|
2477
|
+
for (const seg of segments) {
|
|
2478
|
+
const shouldBeSelected = seg === segment;
|
|
2479
|
+
const isSelected = seg.hasAttribute("selected");
|
|
2480
|
+
if (shouldBeSelected && !isSelected) {
|
|
2481
|
+
seg.setAttribute("selected", "true");
|
|
2482
|
+
} else if (!shouldBeSelected && isSelected) {
|
|
2483
|
+
seg.removeAttribute("selected");
|
|
2484
|
+
}
|
|
2476
2485
|
}
|
|
2477
|
-
// Select new
|
|
2478
2486
|
this.#selectedSegment = segment;
|
|
2479
|
-
|
|
2480
|
-
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
get value() {
|
|
2490
|
+
return this.getAttribute("value") || "";
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
set value(val) {
|
|
2494
|
+
if (val === null || val === undefined) {
|
|
2495
|
+
this.removeAttribute("value");
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2498
|
+
this.setAttribute("value", String(val));
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
#emitSelectionEvents(value) {
|
|
2502
|
+
this.dispatchEvent(
|
|
2503
|
+
new CustomEvent("input", {
|
|
2504
|
+
detail: value,
|
|
2505
|
+
bubbles: true,
|
|
2506
|
+
}),
|
|
2507
|
+
);
|
|
2508
|
+
this.dispatchEvent(
|
|
2509
|
+
new CustomEvent("change", {
|
|
2510
|
+
detail: value,
|
|
2511
|
+
bubbles: true,
|
|
2512
|
+
}),
|
|
2513
|
+
);
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
#resolveSegmentValue(segment) {
|
|
2517
|
+
const explicitValue = segment.getAttribute("value");
|
|
2518
|
+
if (explicitValue !== null) {
|
|
2519
|
+
const trimmedExplicitValue = explicitValue.trim();
|
|
2520
|
+
if (trimmedExplicitValue.length > 0) {
|
|
2521
|
+
return trimmedExplicitValue;
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
return segment.textContent?.trim() || "";
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
#getFirstSelectedSegment() {
|
|
2529
|
+
const segments = this.querySelectorAll("fig-segment");
|
|
2530
|
+
for (const segment of segments) {
|
|
2531
|
+
if (segment.hasAttribute("selected")) return segment;
|
|
2532
|
+
}
|
|
2533
|
+
return null;
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
#selectByValue(value) {
|
|
2537
|
+
const normalizedValue = String(value ?? "").trim();
|
|
2538
|
+
if (!normalizedValue) return false;
|
|
2539
|
+
|
|
2540
|
+
const segments = this.querySelectorAll("fig-segment");
|
|
2541
|
+
for (const segment of segments) {
|
|
2542
|
+
const segmentValue = this.#resolveSegmentValue(segment);
|
|
2543
|
+
if (!segmentValue) continue;
|
|
2544
|
+
if (segmentValue === normalizedValue) {
|
|
2545
|
+
this.selectedSegment = segment;
|
|
2546
|
+
return true;
|
|
2547
|
+
}
|
|
2481
2548
|
}
|
|
2549
|
+
|
|
2550
|
+
return false;
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
#syncSelectionFromAttributes({ enforceFallback = false } = {}) {
|
|
2554
|
+
const segments = this.querySelectorAll("fig-segment");
|
|
2555
|
+
if (segments.length === 0) {
|
|
2556
|
+
this.#selectedSegment = null;
|
|
2557
|
+
return;
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
const rawValue = this.getAttribute("value");
|
|
2561
|
+
const normalizedValue = rawValue?.trim() ?? "";
|
|
2562
|
+
if (rawValue !== null) {
|
|
2563
|
+
if (normalizedValue !== rawValue) {
|
|
2564
|
+
this.setAttribute("value", normalizedValue);
|
|
2565
|
+
return;
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
if (normalizedValue && this.#selectByValue(normalizedValue)) {
|
|
2569
|
+
return;
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
const selected = this.#getFirstSelectedSegment();
|
|
2574
|
+
if (selected) {
|
|
2575
|
+
this.selectedSegment = selected;
|
|
2576
|
+
return;
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
if (enforceFallback) {
|
|
2580
|
+
this.selectedSegment = segments[0];
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
#startSegmentObserver() {
|
|
2585
|
+
this.#mutationObserver?.disconnect();
|
|
2586
|
+
this.#mutationObserver = new MutationObserver((mutations) => {
|
|
2587
|
+
let shouldResync = false;
|
|
2588
|
+
|
|
2589
|
+
for (const mutation of mutations) {
|
|
2590
|
+
if (mutation.type === "childList") {
|
|
2591
|
+
shouldResync = true;
|
|
2592
|
+
break;
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
if (
|
|
2596
|
+
mutation.type === "attributes" &&
|
|
2597
|
+
mutation.target instanceof HTMLElement &&
|
|
2598
|
+
mutation.target.tagName.toLowerCase() === "fig-segment" &&
|
|
2599
|
+
(mutation.attributeName === "value" ||
|
|
2600
|
+
mutation.attributeName === "selected")
|
|
2601
|
+
) {
|
|
2602
|
+
shouldResync = true;
|
|
2603
|
+
break;
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
if (mutation.type === "characterData") {
|
|
2607
|
+
shouldResync = true;
|
|
2608
|
+
break;
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
if (shouldResync) {
|
|
2613
|
+
this.#applyDisabled(
|
|
2614
|
+
this.hasAttribute("disabled") &&
|
|
2615
|
+
this.getAttribute("disabled") !== "false",
|
|
2616
|
+
);
|
|
2617
|
+
this.#syncSelectionFromAttributes({ enforceFallback: true });
|
|
2618
|
+
}
|
|
2619
|
+
});
|
|
2620
|
+
|
|
2621
|
+
this.#mutationObserver.observe(this, {
|
|
2622
|
+
childList: true,
|
|
2623
|
+
subtree: true,
|
|
2624
|
+
characterData: true,
|
|
2625
|
+
attributes: true,
|
|
2626
|
+
attributeFilter: ["value", "selected"],
|
|
2627
|
+
});
|
|
2482
2628
|
}
|
|
2483
2629
|
|
|
2484
2630
|
handleClick(event) {
|
|
@@ -2489,15 +2635,23 @@ class FigSegmentedControl extends HTMLElement {
|
|
|
2489
2635
|
return;
|
|
2490
2636
|
}
|
|
2491
2637
|
const segment = event.target.closest("fig-segment");
|
|
2492
|
-
if (segment)
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2638
|
+
if (!segment || !this.contains(segment)) return;
|
|
2639
|
+
|
|
2640
|
+
const previousSegment = this.selectedSegment;
|
|
2641
|
+
const previousValue = this.value;
|
|
2642
|
+
|
|
2643
|
+
this.selectedSegment = segment;
|
|
2644
|
+
const resolvedValue = this.#resolveSegmentValue(segment);
|
|
2645
|
+
|
|
2646
|
+
if (resolvedValue) {
|
|
2647
|
+
this.setAttribute("value", resolvedValue);
|
|
2648
|
+
} else {
|
|
2649
|
+
this.removeAttribute("value");
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2652
|
+
const nextValue = this.value;
|
|
2653
|
+
if (previousSegment !== segment || previousValue !== nextValue) {
|
|
2654
|
+
this.#emitSelectionEvents(nextValue);
|
|
2501
2655
|
}
|
|
2502
2656
|
}
|
|
2503
2657
|
|
|
@@ -2515,8 +2669,15 @@ class FigSegmentedControl extends HTMLElement {
|
|
|
2515
2669
|
}
|
|
2516
2670
|
|
|
2517
2671
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
2518
|
-
if (
|
|
2672
|
+
if (oldValue === newValue) return;
|
|
2673
|
+
|
|
2674
|
+
if (name === "disabled") {
|
|
2519
2675
|
this.#applyDisabled(newValue !== null && newValue !== "false");
|
|
2676
|
+
return;
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
if (name === "value") {
|
|
2680
|
+
this.#syncSelectionFromAttributes({ enforceFallback: false });
|
|
2520
2681
|
}
|
|
2521
2682
|
}
|
|
2522
2683
|
}
|
package/package.json
CHANGED