@rogieking/figui3 11.0.2 → 11.1.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/.cursor/skills/fig-editor/components.md +1 -1
- package/.cursor/skills/fig-editor/reference.md +1 -0
- package/.cursor/skills/figui3/components.md +7 -4
- package/.cursor/skills/figui3/react.md +1 -0
- package/CHANGELOG.md +23 -0
- package/README.md +13 -5
- package/components.css +18 -6
- package/dist/components.css +1 -1
- package/dist/fig-editor.css +1 -1
- package/dist/fig.css +1 -1
- package/dist/fig.js +6 -6
- package/fig-editor.css +25 -1
- package/fig-editor.js +1 -1
- package/fig.js +170 -85
- package/package.json +1 -1
package/fig-editor.css
CHANGED
|
@@ -735,7 +735,31 @@ fig-select {
|
|
|
735
735
|
box-shadow: none;
|
|
736
736
|
background-color: transparent;
|
|
737
737
|
|
|
738
|
-
&:hover:not([disabled]):not([disabled="false"])
|
|
738
|
+
&:hover:not([disabled]):not([disabled="false"]):not(
|
|
739
|
+
[open]:not([open="false"])
|
|
740
|
+
) {
|
|
741
|
+
background-color: var(--figma-color-bg-secondary);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
&[variant="input"] {
|
|
746
|
+
box-shadow: none;
|
|
747
|
+
background-color: var(--figma-color-bg-secondary);
|
|
748
|
+
color: var(--figma-color-text);
|
|
749
|
+
|
|
750
|
+
&:hover:not([disabled]):not([disabled="false"]):not(
|
|
751
|
+
[open]:not([open="false"])
|
|
752
|
+
) {
|
|
753
|
+
box-shadow: inset 0 0 0 1px var(--figma-color-bordertranslucent);
|
|
754
|
+
background-color: var(--figma-color-bg-transparent);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
&:active:not([disabled]):not([disabled="false"]) {
|
|
758
|
+
background-color: var(--figma-color-bg-transparent-pressed);
|
|
759
|
+
color: var(--figma-color-text);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
&:focus-within {
|
|
739
763
|
background-color: var(--figma-color-bg-secondary);
|
|
740
764
|
}
|
|
741
765
|
}
|
package/fig-editor.js
CHANGED
|
@@ -499,7 +499,7 @@ figEditorDefineElement("fig-select-options", FigSelectOptions);
|
|
|
499
499
|
|
|
500
500
|
/**
|
|
501
501
|
* A dropdown-styled select.
|
|
502
|
-
* @attr {string} variant - Visual style
|
|
502
|
+
* @attr {string} variant - Visual style: `ghost` or input-like `input`.
|
|
503
503
|
* @attr {string} size - Control size. Use `large` for a 32px-tall control.
|
|
504
504
|
* @attr {boolean} icon - Shows a square chevron-only trigger.
|
|
505
505
|
* @attr {string} menu-anchor - CSS selector for an alternate menu anchor.
|
package/fig.js
CHANGED
|
@@ -12469,16 +12469,19 @@ class FigSwitch extends FigCheckbox {
|
|
|
12469
12469
|
}
|
|
12470
12470
|
figDefineElement("fig-switch", FigSwitch);
|
|
12471
12471
|
|
|
12472
|
-
/*
|
|
12472
|
+
/* Split Input */
|
|
12473
12473
|
/**
|
|
12474
|
-
* A
|
|
12474
|
+
* A split input with text and dropdown controls.
|
|
12475
|
+
* @attr {string} type - Main input type: "text" (default) or "number"
|
|
12475
12476
|
* @attr {string} options - Comma-separated list of dropdown options
|
|
12476
12477
|
* @attr {string} placeholder - Placeholder text for the input
|
|
12477
12478
|
* @attr {string} value - The current input value
|
|
12478
12479
|
* @attr {boolean} disabled - Disables the input and dropdown button
|
|
12480
|
+
* @attr {boolean} full - Expands the split input to the available width
|
|
12479
12481
|
*/
|
|
12480
|
-
class
|
|
12482
|
+
class FigSplitInput extends HTMLElement {
|
|
12481
12483
|
static observedAttributes = [
|
|
12484
|
+
"type",
|
|
12482
12485
|
"options",
|
|
12483
12486
|
"placeholder",
|
|
12484
12487
|
"value",
|
|
@@ -12490,11 +12493,11 @@ class FigComboInput extends HTMLElement {
|
|
|
12490
12493
|
"aria-required",
|
|
12491
12494
|
];
|
|
12492
12495
|
|
|
12493
|
-
#
|
|
12496
|
+
#usesCustomSelector = false;
|
|
12494
12497
|
#input = null;
|
|
12495
|
-
#
|
|
12498
|
+
#selector = null;
|
|
12496
12499
|
#button = null;
|
|
12497
|
-
#
|
|
12500
|
+
#customSelector = null;
|
|
12498
12501
|
#internalUpdate = false;
|
|
12499
12502
|
#a11yAttributes = [
|
|
12500
12503
|
"aria-label",
|
|
@@ -12504,10 +12507,10 @@ class FigComboInput extends HTMLElement {
|
|
|
12504
12507
|
"aria-required",
|
|
12505
12508
|
];
|
|
12506
12509
|
|
|
12507
|
-
#
|
|
12508
|
-
#
|
|
12509
|
-
#
|
|
12510
|
-
#
|
|
12510
|
+
#boundHandleSelectorInput = this.#handleSelectorInput.bind(this);
|
|
12511
|
+
#boundHandleSelectorChange = this.#handleSelectorChange.bind(this);
|
|
12512
|
+
#boundHandleMainInput = this.#handleMainInput.bind(this);
|
|
12513
|
+
#boundHandleMainChange = this.#handleMainChange.bind(this);
|
|
12511
12514
|
|
|
12512
12515
|
get value() {
|
|
12513
12516
|
return this.getAttribute("value") || "";
|
|
@@ -12517,14 +12520,38 @@ class FigComboInput extends HTMLElement {
|
|
|
12517
12520
|
this.setAttribute("value", val ?? "");
|
|
12518
12521
|
}
|
|
12519
12522
|
|
|
12523
|
+
#inputTagName() {
|
|
12524
|
+
return this.getAttribute("type") === "number"
|
|
12525
|
+
? "fig-input-number"
|
|
12526
|
+
: "fig-input-text";
|
|
12527
|
+
}
|
|
12528
|
+
|
|
12529
|
+
#createInput() {
|
|
12530
|
+
return figCreateElement(this.#inputTagName(), {
|
|
12531
|
+
placeholder: this.getAttribute("placeholder") || "",
|
|
12532
|
+
value: this.value,
|
|
12533
|
+
});
|
|
12534
|
+
}
|
|
12535
|
+
|
|
12520
12536
|
#canReuseMarkup() {
|
|
12521
|
-
|
|
12537
|
+
const input = this.querySelector(
|
|
12538
|
+
":scope > .input-combo > :is(fig-input-text, fig-input-number)",
|
|
12539
|
+
);
|
|
12540
|
+
return input?.localName === this.#inputTagName();
|
|
12522
12541
|
}
|
|
12523
12542
|
|
|
12524
12543
|
#refreshMarkup() {
|
|
12525
|
-
this.#input = this.querySelector(
|
|
12544
|
+
this.#input = this.querySelector(
|
|
12545
|
+
":scope > .input-combo > :is(fig-input-text, fig-input-number)",
|
|
12546
|
+
);
|
|
12526
12547
|
this.#button = this.querySelector("fig-button");
|
|
12527
|
-
this.#
|
|
12548
|
+
this.#selector = this.querySelector("fig-select, fig-dropdown");
|
|
12549
|
+
if (
|
|
12550
|
+
this.#selector?.localName === "fig-select" &&
|
|
12551
|
+
customElements.get("fig-select")
|
|
12552
|
+
) {
|
|
12553
|
+
this.#selector.menuAnchor = this;
|
|
12554
|
+
}
|
|
12528
12555
|
if (this.#input) {
|
|
12529
12556
|
this.#input.setAttribute("value", this.value);
|
|
12530
12557
|
this.#input.setAttribute(
|
|
@@ -12536,17 +12563,24 @@ class FigComboInput extends HTMLElement {
|
|
|
12536
12563
|
}
|
|
12537
12564
|
|
|
12538
12565
|
connectedCallback() {
|
|
12539
|
-
this.#
|
|
12566
|
+
this.#customSelector =
|
|
12540
12567
|
Array.from(this.children).find(
|
|
12541
|
-
(child) =>
|
|
12568
|
+
(child) =>
|
|
12569
|
+
child.tagName === "FIG-SELECT" || child.tagName === "FIG-DROPDOWN",
|
|
12542
12570
|
) || null;
|
|
12543
|
-
this.#
|
|
12544
|
-
if (this.#
|
|
12545
|
-
this.#
|
|
12571
|
+
this.#usesCustomSelector = this.#customSelector !== null;
|
|
12572
|
+
if (this.#customSelector) {
|
|
12573
|
+
this.#customSelector.remove();
|
|
12546
12574
|
}
|
|
12547
12575
|
|
|
12548
12576
|
if (this.#canReuseMarkup()) {
|
|
12549
12577
|
this.#refreshMarkup();
|
|
12578
|
+
if (!this.#customSelector) {
|
|
12579
|
+
this.#usesCustomSelector =
|
|
12580
|
+
!!this.#selector &&
|
|
12581
|
+
!this.#selector.hasAttribute("data-fig-split-generated");
|
|
12582
|
+
this.#customSelector = this.#usesCustomSelector ? this.#selector : null;
|
|
12583
|
+
}
|
|
12550
12584
|
this.#setupListeners();
|
|
12551
12585
|
} else {
|
|
12552
12586
|
this.#render();
|
|
@@ -12562,93 +12596,112 @@ class FigComboInput extends HTMLElement {
|
|
|
12562
12596
|
|
|
12563
12597
|
#render() {
|
|
12564
12598
|
const options = this.#getOptions();
|
|
12565
|
-
const placeholder = this.getAttribute("placeholder") || "";
|
|
12566
|
-
const currentValue = this.value;
|
|
12567
12599
|
const dropdownLabel = this.#dropdownLabel();
|
|
12568
12600
|
|
|
12569
|
-
const input =
|
|
12570
|
-
|
|
12571
|
-
|
|
12572
|
-
|
|
12573
|
-
const button = figCreateElement(
|
|
12574
|
-
"fig-button",
|
|
12575
|
-
{
|
|
12576
|
-
type: "select",
|
|
12577
|
-
variant: "input",
|
|
12601
|
+
const input = this.#createInput();
|
|
12602
|
+
let selector = this.#customSelector;
|
|
12603
|
+
if (!selector && customElements.get("fig-select")) {
|
|
12604
|
+
selector = figCreateElement("fig-select", {
|
|
12578
12605
|
icon: true,
|
|
12579
|
-
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12606
|
+
variant: "input",
|
|
12607
|
+
options: options.join(","),
|
|
12608
|
+
label: dropdownLabel,
|
|
12609
|
+
"aria-label": dropdownLabel,
|
|
12610
|
+
"data-fig-split-generated": true,
|
|
12611
|
+
});
|
|
12612
|
+
}
|
|
12613
|
+
if (!selector) {
|
|
12614
|
+
selector = figCreateElement(
|
|
12615
|
+
"fig-dropdown",
|
|
12616
|
+
{
|
|
12617
|
+
type: "dropdown",
|
|
12618
|
+
label: dropdownLabel,
|
|
12619
|
+
"data-fig-split-generated": true,
|
|
12620
|
+
},
|
|
12621
|
+
options.map((option) =>
|
|
12622
|
+
figCreateElement("option", {}, option.trim()),
|
|
12592
12623
|
),
|
|
12593
12624
|
);
|
|
12594
12625
|
}
|
|
12626
|
+
|
|
12627
|
+
let action = selector;
|
|
12628
|
+
let button = null;
|
|
12629
|
+
if (selector.localName === "fig-dropdown") {
|
|
12630
|
+
if (!selector.hasAttribute("type")) {
|
|
12631
|
+
selector.setAttribute("type", "dropdown");
|
|
12632
|
+
}
|
|
12633
|
+
button = figCreateElement(
|
|
12634
|
+
"fig-button",
|
|
12635
|
+
{
|
|
12636
|
+
type: "select",
|
|
12637
|
+
variant: "input",
|
|
12638
|
+
icon: true,
|
|
12639
|
+
},
|
|
12640
|
+
figCreateElement("fig-icon", {
|
|
12641
|
+
name: "chevron",
|
|
12642
|
+
size: "small",
|
|
12643
|
+
slot: "append",
|
|
12644
|
+
}),
|
|
12645
|
+
);
|
|
12646
|
+
button.append(selector);
|
|
12647
|
+
action = button;
|
|
12648
|
+
}
|
|
12649
|
+
if (!selector.hasAttribute("label")) {
|
|
12650
|
+
selector.setAttribute("label", dropdownLabel);
|
|
12651
|
+
}
|
|
12652
|
+
|
|
12595
12653
|
this.replaceChildren(
|
|
12596
|
-
figCreateElement("div", { className: "input-combo" }, [input,
|
|
12654
|
+
figCreateElement("div", { className: "input-combo" }, [input, action]),
|
|
12597
12655
|
);
|
|
12598
12656
|
|
|
12599
12657
|
this.#input = input;
|
|
12600
12658
|
this.#button = button;
|
|
12601
|
-
|
|
12602
|
-
if (
|
|
12603
|
-
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
|
|
12607
|
-
this.#customDropdown.setAttribute("label", dropdownLabel);
|
|
12608
|
-
}
|
|
12609
|
-
this.#button.append(this.#customDropdown);
|
|
12659
|
+
this.#selector = selector;
|
|
12660
|
+
if (
|
|
12661
|
+
selector.localName === "fig-select" &&
|
|
12662
|
+
customElements.get("fig-select")
|
|
12663
|
+
) {
|
|
12664
|
+
selector.menuAnchor = this;
|
|
12610
12665
|
}
|
|
12611
|
-
|
|
12612
|
-
this.#dropdown = this.querySelector("fig-dropdown");
|
|
12613
12666
|
this.#syncA11yAttributes();
|
|
12614
12667
|
}
|
|
12615
12668
|
|
|
12616
12669
|
#setupListeners() {
|
|
12617
12670
|
this.#teardownListeners();
|
|
12618
|
-
this.#
|
|
12619
|
-
this.#
|
|
12620
|
-
this.#input?.addEventListener("input", this.#
|
|
12621
|
-
this.#input?.addEventListener("change", this.#
|
|
12671
|
+
this.#selector?.addEventListener("input", this.#boundHandleSelectorInput);
|
|
12672
|
+
this.#selector?.addEventListener("change", this.#boundHandleSelectorChange);
|
|
12673
|
+
this.#input?.addEventListener("input", this.#boundHandleMainInput);
|
|
12674
|
+
this.#input?.addEventListener("change", this.#boundHandleMainChange);
|
|
12622
12675
|
}
|
|
12623
12676
|
|
|
12624
12677
|
#teardownListeners() {
|
|
12625
|
-
this.#
|
|
12626
|
-
this.#
|
|
12627
|
-
this.#input?.removeEventListener("input", this.#
|
|
12628
|
-
this.#input?.removeEventListener("change", this.#
|
|
12678
|
+
this.#selector?.removeEventListener("input", this.#boundHandleSelectorInput);
|
|
12679
|
+
this.#selector?.removeEventListener("change", this.#boundHandleSelectorChange);
|
|
12680
|
+
this.#input?.removeEventListener("input", this.#boundHandleMainInput);
|
|
12681
|
+
this.#input?.removeEventListener("change", this.#boundHandleMainChange);
|
|
12629
12682
|
}
|
|
12630
12683
|
|
|
12631
|
-
#
|
|
12684
|
+
#handleSelectorInput(e) {
|
|
12632
12685
|
e.stopPropagation();
|
|
12633
|
-
this.#
|
|
12686
|
+
this.#syncSelectorValue(e);
|
|
12634
12687
|
this.#emitInput();
|
|
12635
12688
|
}
|
|
12636
12689
|
|
|
12637
|
-
#
|
|
12690
|
+
#handleSelectorChange(e) {
|
|
12638
12691
|
e.stopPropagation();
|
|
12639
|
-
this.#
|
|
12692
|
+
this.#syncSelectorValue(e);
|
|
12640
12693
|
this.#emitChange();
|
|
12641
12694
|
}
|
|
12642
12695
|
|
|
12643
|
-
#
|
|
12644
|
-
const val = e.target.closest("fig-dropdown")?.value ?? "";
|
|
12696
|
+
#syncSelectorValue(e) {
|
|
12697
|
+
const val = e.target.closest("fig-select, fig-dropdown")?.value ?? "";
|
|
12645
12698
|
this.#internalUpdate = true;
|
|
12646
12699
|
this.setAttribute("value", val);
|
|
12647
12700
|
this.#internalUpdate = false;
|
|
12648
12701
|
if (this.#input) this.#input.setAttribute("value", val);
|
|
12649
12702
|
}
|
|
12650
12703
|
|
|
12651
|
-
#
|
|
12704
|
+
#handleMainInput(e) {
|
|
12652
12705
|
e.stopPropagation();
|
|
12653
12706
|
const val = e.target.value ?? "";
|
|
12654
12707
|
this.#internalUpdate = true;
|
|
@@ -12657,7 +12710,7 @@ class FigComboInput extends HTMLElement {
|
|
|
12657
12710
|
this.#emitInput();
|
|
12658
12711
|
}
|
|
12659
12712
|
|
|
12660
|
-
#
|
|
12713
|
+
#handleMainChange(e) {
|
|
12661
12714
|
e.stopPropagation();
|
|
12662
12715
|
const val = e.target.value ?? "";
|
|
12663
12716
|
this.#internalUpdate = true;
|
|
@@ -12697,7 +12750,7 @@ class FigComboInput extends HTMLElement {
|
|
|
12697
12750
|
return (
|
|
12698
12751
|
this.getAttribute("aria-label") ||
|
|
12699
12752
|
this.getAttribute("placeholder") ||
|
|
12700
|
-
"
|
|
12753
|
+
"Split input"
|
|
12701
12754
|
).trim();
|
|
12702
12755
|
}
|
|
12703
12756
|
|
|
@@ -12713,8 +12766,19 @@ class FigComboInput extends HTMLElement {
|
|
|
12713
12766
|
else this.#input.setAttribute(name, value);
|
|
12714
12767
|
});
|
|
12715
12768
|
}
|
|
12716
|
-
if (this.#
|
|
12717
|
-
|
|
12769
|
+
if (this.#selector) {
|
|
12770
|
+
const label = this.#dropdownLabel();
|
|
12771
|
+
if (!this.#usesCustomSelector) {
|
|
12772
|
+
this.#selector.setAttribute("label", label);
|
|
12773
|
+
if (this.#selector.localName === "fig-select") {
|
|
12774
|
+
this.#selector.setAttribute("aria-label", label);
|
|
12775
|
+
}
|
|
12776
|
+
} else if (
|
|
12777
|
+
!this.#selector.hasAttribute("aria-label") &&
|
|
12778
|
+
!this.#selector.hasAttribute("label")
|
|
12779
|
+
) {
|
|
12780
|
+
this.#selector.setAttribute("label", label);
|
|
12781
|
+
}
|
|
12718
12782
|
}
|
|
12719
12783
|
}
|
|
12720
12784
|
|
|
@@ -12727,9 +12791,9 @@ class FigComboInput extends HTMLElement {
|
|
|
12727
12791
|
if (disabled) this.#button.setAttribute("disabled", "");
|
|
12728
12792
|
else this.#button.removeAttribute("disabled");
|
|
12729
12793
|
}
|
|
12730
|
-
if (this.#
|
|
12731
|
-
if (disabled) this.#
|
|
12732
|
-
else this.#
|
|
12794
|
+
if (this.#selector) {
|
|
12795
|
+
if (disabled) this.#selector.setAttribute("disabled", "");
|
|
12796
|
+
else this.#selector.removeAttribute("disabled");
|
|
12733
12797
|
}
|
|
12734
12798
|
}
|
|
12735
12799
|
|
|
@@ -12740,16 +12804,33 @@ class FigComboInput extends HTMLElement {
|
|
|
12740
12804
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
12741
12805
|
if (oldValue === newValue) return;
|
|
12742
12806
|
switch (name) {
|
|
12807
|
+
case "type": {
|
|
12808
|
+
if (!this.#input || this.#input.localName === this.#inputTagName()) break;
|
|
12809
|
+
const restoreFocus = this.#input.matches(":focus-within");
|
|
12810
|
+
this.#teardownListeners();
|
|
12811
|
+
const input = this.#createInput();
|
|
12812
|
+
this.#input.replaceWith(input);
|
|
12813
|
+
this.#input = input;
|
|
12814
|
+
this.#syncA11yAttributes();
|
|
12815
|
+
this.#applyDisabled(figBooleanAttribute(this, "disabled"));
|
|
12816
|
+
this.#setupListeners();
|
|
12817
|
+
if (restoreFocus) this.focus();
|
|
12818
|
+
break;
|
|
12819
|
+
}
|
|
12743
12820
|
case "options":
|
|
12744
|
-
if (this.#
|
|
12745
|
-
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12821
|
+
if (this.#selector && !this.#usesCustomSelector) {
|
|
12822
|
+
if (this.#selector.localName === "fig-select") {
|
|
12823
|
+
this.#selector.setAttribute("options", newValue || "");
|
|
12824
|
+
} else {
|
|
12825
|
+
const options = this.#getOptions();
|
|
12826
|
+
this.#selector.replaceChildren(
|
|
12827
|
+
...options.map((value) => {
|
|
12828
|
+
const option = document.createElement("option");
|
|
12829
|
+
option.textContent = value;
|
|
12830
|
+
return option;
|
|
12831
|
+
}),
|
|
12832
|
+
);
|
|
12833
|
+
}
|
|
12753
12834
|
}
|
|
12754
12835
|
break;
|
|
12755
12836
|
case "placeholder":
|
|
@@ -12774,6 +12855,10 @@ class FigComboInput extends HTMLElement {
|
|
|
12774
12855
|
}
|
|
12775
12856
|
}
|
|
12776
12857
|
}
|
|
12858
|
+
figDefineElement("fig-split-input", FigSplitInput);
|
|
12859
|
+
|
|
12860
|
+
/** @deprecated Use fig-split-input. */
|
|
12861
|
+
class FigComboInput extends FigSplitInput {}
|
|
12777
12862
|
figDefineElement("fig-combo-input", FigComboInput);
|
|
12778
12863
|
|
|
12779
12864
|
/* Swatch */
|
package/package.json
CHANGED