@rogieking/figui3 11.4.2 → 11.6.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/SKILL.md +9 -6
- package/.cursor/skills/fig-editor/components.md +142 -0
- package/.cursor/skills/fig-editor/reference.md +62 -0
- package/.cursor/skills/figui3/components.md +7 -1
- package/.cursor/skills/figui3/react.md +3 -0
- package/.cursor/skills/figui3/reference.md +2 -0
- package/CHANGELOG.md +37 -0
- package/README.md +123 -3
- package/components.css +83 -10
- package/dist/components.css +1 -1
- package/dist/fig-editor.css +1 -1
- package/dist/fig-editor.js +3 -3
- package/dist/fig-property.css +1 -0
- package/dist/fig-property.js +1 -0
- package/dist/fig.css +1 -1
- package/dist/fig.js +5 -5
- package/fig-editor.css +45 -185
- package/fig-editor.js +253 -88
- package/fig-gradient-editor.css +76 -0
- package/fig-gradient-editor.js +598 -0
- package/fig-popup-easing.css +8 -0
- package/fig-popup-easing.js +141 -0
- package/fig-popup-gradient.css +11 -0
- package/fig-popup-gradient.js +138 -0
- package/fig-popup-palette.css +7 -0
- package/fig-popup-palette.js +173 -0
- package/fig-property.css +116 -0
- package/fig-property.js +220 -0
- package/fig.js +265 -99
- package/package.json +17 -2
package/fig.js
CHANGED
|
@@ -23,6 +23,7 @@ function createFigIcon(name, options = {}) {
|
|
|
23
23
|
const icon = document.createElement("fig-icon");
|
|
24
24
|
if (name) icon.setAttribute("name", name);
|
|
25
25
|
if (options.size) icon.setAttribute("size", options.size);
|
|
26
|
+
if (options.slot) icon.setAttribute("slot", options.slot);
|
|
26
27
|
if (options.className) icon.className = options.className;
|
|
27
28
|
return icon;
|
|
28
29
|
}
|
|
@@ -8684,7 +8685,11 @@ class FigField extends HTMLElement {
|
|
|
8684
8685
|
this.input = Array.from(this.childNodes).find((node) =>
|
|
8685
8686
|
node.nodeType === Node.ELEMENT_NODE &&
|
|
8686
8687
|
node.nodeName.toLowerCase().startsWith("fig-") &&
|
|
8687
|
-
!(
|
|
8688
|
+
!(
|
|
8689
|
+
node instanceof Element &&
|
|
8690
|
+
(node.classList.contains("fig-field-chevron") ||
|
|
8691
|
+
["leading", "trailing"].includes(node.getAttribute("slot")))
|
|
8692
|
+
),
|
|
8688
8693
|
);
|
|
8689
8694
|
this.#observeInputAttributes();
|
|
8690
8695
|
|
|
@@ -8714,6 +8719,7 @@ class FigField extends HTMLElement {
|
|
|
8714
8719
|
if (!this.#chevron || !this.#chevron.isConnected) {
|
|
8715
8720
|
this.#chevron = createFigIcon("chevron", {
|
|
8716
8721
|
size: "small",
|
|
8722
|
+
slot: "leading",
|
|
8717
8723
|
className: "fig-field-chevron",
|
|
8718
8724
|
});
|
|
8719
8725
|
this.insertBefore(this.#chevron, this.label);
|
|
@@ -10883,7 +10889,6 @@ class FigInputPalette extends HTMLElement {
|
|
|
10883
10889
|
#renderRAF = null;
|
|
10884
10890
|
#pickerDefinitionPromise = null;
|
|
10885
10891
|
#pickerPopup = null;
|
|
10886
|
-
#pickerEditor = null;
|
|
10887
10892
|
#syncingValueAttribute = false;
|
|
10888
10893
|
#boundHandleKeyDown = this.#handleKeyDown.bind(this);
|
|
10889
10894
|
#boundHandleHostFocus = () => this.focus();
|
|
@@ -11162,13 +11167,13 @@ class FigInputPalette extends HTMLElement {
|
|
|
11162
11167
|
#renderPickerWhenAvailable() {
|
|
11163
11168
|
if (
|
|
11164
11169
|
this.#editMode !== "picker" ||
|
|
11165
|
-
customElements.get("fig-palette
|
|
11170
|
+
customElements.get("fig-popup-palette")
|
|
11166
11171
|
) {
|
|
11167
11172
|
this.#syncPickerOpenState();
|
|
11168
11173
|
return;
|
|
11169
11174
|
}
|
|
11170
11175
|
this.#pickerDefinitionPromise ??= customElements
|
|
11171
|
-
.whenDefined("fig-palette
|
|
11176
|
+
.whenDefined("fig-popup-palette")
|
|
11172
11177
|
.then(() => {
|
|
11173
11178
|
if (!this.isConnected || this.#editMode !== "picker") return;
|
|
11174
11179
|
this.#syncPickerOpenState();
|
|
@@ -11177,28 +11182,16 @@ class FigInputPalette extends HTMLElement {
|
|
|
11177
11182
|
|
|
11178
11183
|
#ensurePickerPopup() {
|
|
11179
11184
|
if (this.#pickerPopup?.isConnected) return this.#pickerPopup;
|
|
11180
|
-
if (!customElements.get("fig-palette
|
|
11185
|
+
if (!customElements.get("fig-popup-palette")) return null;
|
|
11181
11186
|
|
|
11182
|
-
const popup = document.createElement("dialog", {
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
popup.setAttribute("
|
|
11186
|
-
popup.setAttribute("offset", "0 8");
|
|
11187
|
-
popup.setAttribute("viewport-margin", "8");
|
|
11188
|
-
popup.setAttribute("popover", "manual");
|
|
11189
|
-
popup.className = "fig-palette-editor-popup";
|
|
11187
|
+
const popup = document.createElement("dialog", {
|
|
11188
|
+
is: "fig-popup-palette",
|
|
11189
|
+
});
|
|
11190
|
+
popup.setAttribute("is", "fig-popup-palette");
|
|
11190
11191
|
popup.id = figUniqueId();
|
|
11191
11192
|
popup.anchor = this;
|
|
11192
11193
|
|
|
11193
|
-
const
|
|
11194
|
-
const content = figCreateElement(
|
|
11195
|
-
"fig-content",
|
|
11196
|
-
{ className: "fig-palette-editor-content" },
|
|
11197
|
-
editor,
|
|
11198
|
-
);
|
|
11199
|
-
popup.append(content);
|
|
11200
|
-
|
|
11201
|
-
const handleEditorEvent = (event) => {
|
|
11194
|
+
const handlePopupEvent = (event) => {
|
|
11202
11195
|
event.stopPropagation();
|
|
11203
11196
|
if (!Array.isArray(event.detail)) return;
|
|
11204
11197
|
this.#colors = event.detail.map((entry) => ({
|
|
@@ -11218,14 +11211,13 @@ class FigInputPalette extends HTMLElement {
|
|
|
11218
11211
|
}),
|
|
11219
11212
|
);
|
|
11220
11213
|
};
|
|
11221
|
-
|
|
11222
|
-
|
|
11214
|
+
popup.addEventListener("input", handlePopupEvent);
|
|
11215
|
+
popup.addEventListener("change", handlePopupEvent);
|
|
11223
11216
|
popup.addEventListener("close", this.#boundPickerClosed);
|
|
11224
11217
|
popup.addEventListener("toggle", this.#boundPickerClosed);
|
|
11225
11218
|
|
|
11226
11219
|
(figGetOverlayRoot() ?? document.body).append(popup);
|
|
11227
11220
|
this.#pickerPopup = popup;
|
|
11228
|
-
this.#pickerEditor = editor;
|
|
11229
11221
|
this.querySelector(".palette-colors-inline")?.setAttribute(
|
|
11230
11222
|
"aria-controls",
|
|
11231
11223
|
popup.id,
|
|
@@ -11235,21 +11227,21 @@ class FigInputPalette extends HTMLElement {
|
|
|
11235
11227
|
}
|
|
11236
11228
|
|
|
11237
11229
|
#syncPickerEditor() {
|
|
11238
|
-
const
|
|
11239
|
-
if (!
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11230
|
+
const popup = this.#pickerPopup;
|
|
11231
|
+
if (!popup) return;
|
|
11232
|
+
popup.setAttribute("value", JSON.stringify(this.#colors));
|
|
11233
|
+
popup.setAttribute("min", String(this.#min));
|
|
11234
|
+
popup.setAttribute("max", String(this.#max));
|
|
11235
|
+
popup.toggleAttribute("fixed", this.#isFixed);
|
|
11244
11236
|
const disabled =
|
|
11245
11237
|
this.hasAttribute("disabled") &&
|
|
11246
11238
|
this.getAttribute("disabled") !== "false";
|
|
11247
|
-
|
|
11239
|
+
popup.toggleAttribute("disabled", disabled);
|
|
11248
11240
|
}
|
|
11249
11241
|
|
|
11250
11242
|
#syncPickerOpenState() {
|
|
11251
11243
|
if (!this.isConnected || this.#editMode !== "picker") return;
|
|
11252
|
-
if (!customElements.get("fig-palette
|
|
11244
|
+
if (!customElements.get("fig-popup-palette")) {
|
|
11253
11245
|
this.#renderPickerWhenAvailable();
|
|
11254
11246
|
return;
|
|
11255
11247
|
}
|
|
@@ -11280,7 +11272,6 @@ class FigInputPalette extends HTMLElement {
|
|
|
11280
11272
|
"aria-controls",
|
|
11281
11273
|
);
|
|
11282
11274
|
this.#pickerPopup = null;
|
|
11283
|
-
this.#pickerEditor = null;
|
|
11284
11275
|
}
|
|
11285
11276
|
|
|
11286
11277
|
#createPicker(entry, index, disabled, { inline = false } = {}) {
|
|
@@ -11539,10 +11530,11 @@ figDefineElement("fig-input-palette", FigInputPalette);
|
|
|
11539
11530
|
|
|
11540
11531
|
/* Input Gradient */
|
|
11541
11532
|
/**
|
|
11542
|
-
* A gradient-only fill input
|
|
11533
|
+
* A gradient-only fill input with inline and reusable popup editing modes.
|
|
11543
11534
|
* @attr {string} value - JSON string with gradient fill data
|
|
11544
11535
|
* @attr {string} size - Passed through to the internal fig-swatch (e.g. "large")
|
|
11545
11536
|
* @attr {boolean} disabled - Whether the input is disabled
|
|
11537
|
+
* @attr {string} edit - `"true"` for inline stops, `"false"` for preview, or `"picker"` for fig-popup-gradient
|
|
11546
11538
|
* @fires input - When the gradient value changes
|
|
11547
11539
|
* @fires change - When the gradient value is committed
|
|
11548
11540
|
*/
|
|
@@ -11555,7 +11547,20 @@ class FigInputGradient extends HTMLElement {
|
|
|
11555
11547
|
#colorObserver = null;
|
|
11556
11548
|
#repositionRAF = null;
|
|
11557
11549
|
#pickerDefinitionPromise = null;
|
|
11550
|
+
#pickerPopup = null;
|
|
11551
|
+
#syncingValueAttribute = false;
|
|
11558
11552
|
anchorElement = null;
|
|
11553
|
+
#boundPickerClosed = () => {
|
|
11554
|
+
if (!this.#pickerPopup) return;
|
|
11555
|
+
if (
|
|
11556
|
+
this.#pickerPopup.hasAttribute("open") ||
|
|
11557
|
+
this.#pickerPopup.matches?.(":open") ||
|
|
11558
|
+
this.#pickerPopup.matches?.(":popover-open")
|
|
11559
|
+
) {
|
|
11560
|
+
return;
|
|
11561
|
+
}
|
|
11562
|
+
this.classList.remove("has-popup-open");
|
|
11563
|
+
};
|
|
11559
11564
|
#gradient = {
|
|
11560
11565
|
type: "linear",
|
|
11561
11566
|
angle: 90,
|
|
@@ -11654,15 +11659,22 @@ class FigInputGradient extends HTMLElement {
|
|
|
11654
11659
|
this.#parseValue();
|
|
11655
11660
|
this.#render();
|
|
11656
11661
|
this.#renderPickerWhenAvailable();
|
|
11662
|
+
this.removeEventListener("click", this.#onPickerClick);
|
|
11663
|
+
this.addEventListener("click", this.#onPickerClick);
|
|
11657
11664
|
this.removeEventListener("keydown", this.#onPickerKeyDown);
|
|
11658
11665
|
this.addEventListener("keydown", this.#onPickerKeyDown);
|
|
11659
11666
|
if (this.#isEditable) document.addEventListener("keydown", this.#onKeyDown);
|
|
11660
11667
|
}
|
|
11661
11668
|
|
|
11662
11669
|
#renderPickerWhenAvailable() {
|
|
11663
|
-
if (
|
|
11670
|
+
if (
|
|
11671
|
+
this.#editMode !== "picker" ||
|
|
11672
|
+
customElements.get("fig-popup-gradient")
|
|
11673
|
+
) {
|
|
11674
|
+
return;
|
|
11675
|
+
}
|
|
11664
11676
|
this.#pickerDefinitionPromise ??= customElements
|
|
11665
|
-
.whenDefined("fig-
|
|
11677
|
+
.whenDefined("fig-popup-gradient")
|
|
11666
11678
|
.then(() => {
|
|
11667
11679
|
if (!this.isConnected || this.#editMode !== "picker") return;
|
|
11668
11680
|
this.#render();
|
|
@@ -11671,7 +11683,9 @@ class FigInputGradient extends HTMLElement {
|
|
|
11671
11683
|
|
|
11672
11684
|
disconnectedCallback() {
|
|
11673
11685
|
document.removeEventListener("keydown", this.#onKeyDown);
|
|
11686
|
+
this.removeEventListener("click", this.#onPickerClick);
|
|
11674
11687
|
this.removeEventListener("keydown", this.#onPickerKeyDown);
|
|
11688
|
+
this.#destroyPickerPopup();
|
|
11675
11689
|
if (this.#colorObserver) {
|
|
11676
11690
|
this.#colorObserver.disconnect();
|
|
11677
11691
|
this.#colorObserver = null;
|
|
@@ -11779,10 +11793,18 @@ class FigInputGradient extends HTMLElement {
|
|
|
11779
11793
|
if (e.key !== "Enter" && e.key !== " ") return;
|
|
11780
11794
|
if (e.altKey || e.ctrlKey || e.metaKey) return;
|
|
11781
11795
|
if (figBooleanAttribute(this, "disabled")) return;
|
|
11782
|
-
const picker = this.querySelector("fig-fill-picker");
|
|
11783
|
-
if (!picker || typeof picker.open !== "function") return;
|
|
11784
11796
|
e.preventDefault();
|
|
11785
|
-
|
|
11797
|
+
this.#openPickerPopup();
|
|
11798
|
+
};
|
|
11799
|
+
|
|
11800
|
+
#onPickerClick = () => {
|
|
11801
|
+
if (
|
|
11802
|
+
this.#editMode !== "picker" ||
|
|
11803
|
+
figBooleanAttribute(this, "disabled")
|
|
11804
|
+
) {
|
|
11805
|
+
return;
|
|
11806
|
+
}
|
|
11807
|
+
this.#openPickerPopup();
|
|
11786
11808
|
};
|
|
11787
11809
|
|
|
11788
11810
|
#parseValue() {
|
|
@@ -11894,25 +11916,16 @@ class FigInputGradient extends HTMLElement {
|
|
|
11894
11916
|
disabled,
|
|
11895
11917
|
});
|
|
11896
11918
|
|
|
11897
|
-
if (mode === "picker"
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
"fig-fill-picker",
|
|
11901
|
-
{
|
|
11902
|
-
mode: "gradient",
|
|
11903
|
-
value: gradientValue,
|
|
11904
|
-
disabled,
|
|
11905
|
-
},
|
|
11906
|
-
swatch,
|
|
11907
|
-
);
|
|
11908
|
-
this.replaceChildren(picker);
|
|
11919
|
+
if (mode === "picker") {
|
|
11920
|
+
this.setAttribute("aria-haspopup", "dialog");
|
|
11921
|
+
this.replaceChildren(swatch);
|
|
11909
11922
|
this.#swatch = swatch;
|
|
11910
11923
|
this.#track = null;
|
|
11911
|
-
this.#setupPickerEvents();
|
|
11912
11924
|
this.#syncFocusTarget();
|
|
11913
11925
|
return;
|
|
11914
11926
|
}
|
|
11915
11927
|
|
|
11928
|
+
this.removeAttribute("aria-haspopup");
|
|
11916
11929
|
const editable = mode === "true" || mode === "picker";
|
|
11917
11930
|
const track = editable
|
|
11918
11931
|
? figCreateElement(
|
|
@@ -11932,36 +11945,83 @@ class FigInputGradient extends HTMLElement {
|
|
|
11932
11945
|
this.#syncFocusTarget();
|
|
11933
11946
|
}
|
|
11934
11947
|
|
|
11935
|
-
#
|
|
11936
|
-
|
|
11937
|
-
if (!
|
|
11938
|
-
picker.anchorElement = this.anchorElement || this;
|
|
11948
|
+
#ensurePickerPopup() {
|
|
11949
|
+
if (this.#pickerPopup?.isConnected) return this.#pickerPopup;
|
|
11950
|
+
if (!customElements.get("fig-popup-gradient")) return null;
|
|
11939
11951
|
|
|
11940
|
-
const
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11952
|
+
const popup = document.createElement("dialog", {
|
|
11953
|
+
is: "fig-popup-gradient",
|
|
11954
|
+
});
|
|
11955
|
+
popup.setAttribute("is", "fig-popup-gradient");
|
|
11956
|
+
popup.id = figUniqueId();
|
|
11957
|
+
popup.anchor = this.anchorElement || this;
|
|
11958
|
+
|
|
11959
|
+
const handlePopupEvent = (event) => {
|
|
11960
|
+
event.stopPropagation();
|
|
11961
|
+
if (!event.detail?.gradient) return;
|
|
11944
11962
|
this.#gradient = this.#normalizeGradient({
|
|
11945
11963
|
...this.#gradient,
|
|
11946
|
-
...detail.gradient,
|
|
11964
|
+
...event.detail.gradient,
|
|
11947
11965
|
});
|
|
11948
|
-
|
|
11949
|
-
|
|
11966
|
+
this.#syncingValueAttribute = true;
|
|
11967
|
+
this.setAttribute("value", JSON.stringify(this.value));
|
|
11968
|
+
this.#syncingValueAttribute = false;
|
|
11969
|
+
if (typeof event.detail.css === "string" && event.detail.css) {
|
|
11970
|
+
this.#swatch?.setAttribute("background", event.detail.css);
|
|
11950
11971
|
this.#syncSwatchSize();
|
|
11951
|
-
|
|
11972
|
+
} else {
|
|
11973
|
+
this.#syncSwatch();
|
|
11952
11974
|
}
|
|
11953
|
-
this
|
|
11975
|
+
this.dispatchEvent(
|
|
11976
|
+
new CustomEvent(event.type, {
|
|
11977
|
+
bubbles: true,
|
|
11978
|
+
composed: true,
|
|
11979
|
+
detail: this.value,
|
|
11980
|
+
}),
|
|
11981
|
+
);
|
|
11954
11982
|
};
|
|
11983
|
+
popup.addEventListener("input", handlePopupEvent);
|
|
11984
|
+
popup.addEventListener("change", handlePopupEvent);
|
|
11985
|
+
popup.addEventListener("close", this.#boundPickerClosed);
|
|
11986
|
+
popup.addEventListener("toggle", this.#boundPickerClosed);
|
|
11955
11987
|
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11988
|
+
(figGetOverlayRoot() ?? document.body).append(popup);
|
|
11989
|
+
this.#pickerPopup = popup;
|
|
11990
|
+
this.setAttribute("aria-controls", popup.id);
|
|
11991
|
+
this.#syncPickerPopup();
|
|
11992
|
+
return popup;
|
|
11993
|
+
}
|
|
11960
11994
|
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
|
|
11995
|
+
#syncPickerPopup() {
|
|
11996
|
+
if (!this.#pickerPopup) return;
|
|
11997
|
+
this.#pickerPopup.setAttribute("value", JSON.stringify(this.#gradient));
|
|
11998
|
+
this.#pickerPopup.toggleAttribute(
|
|
11999
|
+
"disabled",
|
|
12000
|
+
figBooleanAttribute(this, "disabled"),
|
|
12001
|
+
);
|
|
12002
|
+
this.#pickerPopup.anchor = this.anchorElement || this;
|
|
12003
|
+
}
|
|
12004
|
+
|
|
12005
|
+
#openPickerPopup() {
|
|
12006
|
+
const popup = this.#ensurePickerPopup();
|
|
12007
|
+
if (!popup) {
|
|
12008
|
+
this.#renderPickerWhenAvailable();
|
|
12009
|
+
return;
|
|
12010
|
+
}
|
|
12011
|
+
this.#syncPickerPopup();
|
|
12012
|
+
popup.open = true;
|
|
12013
|
+
this.classList.add("has-popup-open");
|
|
12014
|
+
}
|
|
12015
|
+
|
|
12016
|
+
#destroyPickerPopup() {
|
|
12017
|
+
if (!this.#pickerPopup) return;
|
|
12018
|
+
this.#pickerPopup.removeEventListener("close", this.#boundPickerClosed);
|
|
12019
|
+
this.#pickerPopup.removeEventListener("toggle", this.#boundPickerClosed);
|
|
12020
|
+
this.#pickerPopup.open = false;
|
|
12021
|
+
this.#pickerPopup.remove();
|
|
12022
|
+
this.#pickerPopup = null;
|
|
12023
|
+
this.removeAttribute("aria-controls");
|
|
12024
|
+
this.classList.remove("has-popup-open");
|
|
11965
12025
|
}
|
|
11966
12026
|
|
|
11967
12027
|
#sampleGradientColor(position) {
|
|
@@ -12481,17 +12541,20 @@ class FigInputGradient extends HTMLElement {
|
|
|
12481
12541
|
}
|
|
12482
12542
|
|
|
12483
12543
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
12484
|
-
if (oldValue === newValue) return;
|
|
12544
|
+
if (oldValue === newValue || this.#syncingValueAttribute) return;
|
|
12485
12545
|
switch (name) {
|
|
12486
12546
|
case "value":
|
|
12487
12547
|
this.#parseValue();
|
|
12488
12548
|
this.#syncSwatch();
|
|
12489
12549
|
this.#syncHandles();
|
|
12550
|
+
this.#syncPickerPopup();
|
|
12490
12551
|
break;
|
|
12491
12552
|
case "disabled":
|
|
12492
12553
|
this.#syncDisabled();
|
|
12554
|
+
this.#syncPickerPopup();
|
|
12493
12555
|
break;
|
|
12494
12556
|
case "edit":
|
|
12557
|
+
if (this.#editMode !== "picker") this.#destroyPickerPopup();
|
|
12495
12558
|
this.#render();
|
|
12496
12559
|
this.#renderPickerWhenAvailable();
|
|
12497
12560
|
if (this.#isEditable) {
|
|
@@ -15949,7 +16012,7 @@ class FigInputFile extends HTMLElement {
|
|
|
15949
16012
|
),
|
|
15950
16013
|
)
|
|
15951
16014
|
) {
|
|
15952
|
-
return "
|
|
16015
|
+
return "audio";
|
|
15953
16016
|
}
|
|
15954
16017
|
if (
|
|
15955
16018
|
files.every((file) =>
|
|
@@ -15978,7 +16041,7 @@ class FigInputFile extends HTMLElement {
|
|
|
15978
16041
|
FIG_INPUT_FILE_AUDIO_EXTENSIONS,
|
|
15979
16042
|
)
|
|
15980
16043
|
) {
|
|
15981
|
-
return "
|
|
16044
|
+
return "audio";
|
|
15982
16045
|
}
|
|
15983
16046
|
if (
|
|
15984
16047
|
this.#hasKnownExtension(
|
|
@@ -16137,11 +16200,13 @@ class FigInputFile extends HTMLElement {
|
|
|
16137
16200
|
this.#audioIcon = null;
|
|
16138
16201
|
this.#audioWaveform = null;
|
|
16139
16202
|
this.#audioPlaying = false;
|
|
16203
|
+
this.removeAttribute("data-audio-playing");
|
|
16140
16204
|
}
|
|
16141
16205
|
|
|
16142
16206
|
#setAudioPlaybackUi(playing) {
|
|
16143
16207
|
this.#audioPlaying = playing;
|
|
16144
16208
|
this.#audioIcon?.setAttribute("name", playing ? "pause" : "play");
|
|
16209
|
+
this.toggleAttribute("data-audio-playing", playing);
|
|
16145
16210
|
this.#uploadBtn?.toggleAttribute("selected", playing);
|
|
16146
16211
|
this.#uploadBtn?.setAttribute(
|
|
16147
16212
|
"aria-label",
|
|
@@ -16345,26 +16410,27 @@ class FigInputFile extends HTMLElement {
|
|
|
16345
16410
|
? this.#createMultipleFileIcon(this.#files.length)
|
|
16346
16411
|
: showsImagePreview
|
|
16347
16412
|
? this.#createImagePreviewSwatch()
|
|
16348
|
-
: createFigIcon(
|
|
16349
|
-
|
|
16350
|
-
|
|
16413
|
+
: createFigIcon(this.#selectedFileIcon());
|
|
16414
|
+
const truncEl = document.createElement("fig-truncate");
|
|
16415
|
+
truncEl.setAttribute("position", "middle");
|
|
16416
|
+
truncEl.setAttribute("tooltip", "");
|
|
16417
|
+
const buttonLabel = showsMultiplePreview
|
|
16418
|
+
? "Multiple files"
|
|
16419
|
+
: filename;
|
|
16420
|
+
const dotIdx = buttonLabel.lastIndexOf(".");
|
|
16421
|
+
if (!showsMultiplePreview && dotIdx > 0) {
|
|
16422
|
+
truncEl.setAttribute("tail", buttonLabel.slice(dotIdx));
|
|
16423
|
+
}
|
|
16424
|
+
truncEl.textContent = buttonLabel;
|
|
16425
|
+
fileIcon.setAttribute("slot", "prepend");
|
|
16351
16426
|
if (showsAudioPreview) {
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
this.#
|
|
16427
|
+
fileIcon.classList.add("fig-input-file-audio-icon");
|
|
16428
|
+
truncEl.classList.add("fig-input-file-audio-label");
|
|
16429
|
+
this.#audioIcon = createFigIcon("play");
|
|
16430
|
+
this.#audioIcon.classList.add("fig-input-file-audio-control");
|
|
16431
|
+
this.#audioIcon.setAttribute("slot", "prepend");
|
|
16432
|
+
this.#uploadBtn.append(fileIcon, this.#audioIcon, truncEl);
|
|
16355
16433
|
} else {
|
|
16356
|
-
const truncEl = document.createElement("fig-truncate");
|
|
16357
|
-
truncEl.setAttribute("position", "middle");
|
|
16358
|
-
truncEl.setAttribute("tooltip", "");
|
|
16359
|
-
const buttonLabel = showsMultiplePreview
|
|
16360
|
-
? "Multiple files"
|
|
16361
|
-
: filename;
|
|
16362
|
-
const dotIdx = buttonLabel.lastIndexOf(".");
|
|
16363
|
-
if (!showsMultiplePreview && dotIdx > 0) {
|
|
16364
|
-
truncEl.setAttribute("tail", buttonLabel.slice(dotIdx));
|
|
16365
|
-
}
|
|
16366
|
-
truncEl.textContent = buttonLabel;
|
|
16367
|
-
fileIcon.setAttribute("slot", "prepend");
|
|
16368
16434
|
this.#uploadBtn.append(fileIcon, truncEl);
|
|
16369
16435
|
}
|
|
16370
16436
|
|
|
@@ -16483,6 +16549,8 @@ class FigEasingCurve extends HTMLElement {
|
|
|
16483
16549
|
#durationBarWidth = 10;
|
|
16484
16550
|
#durationBarHeight = 10;
|
|
16485
16551
|
#durationBarRadius = 3;
|
|
16552
|
+
#pickerDefinitionPromise = null;
|
|
16553
|
+
#pickerPopup = null;
|
|
16486
16554
|
|
|
16487
16555
|
static PRESETS = [
|
|
16488
16556
|
{ group: null, name: "Linear", type: "bezier", value: [0, 0, 1, 1] },
|
|
@@ -16581,6 +16649,7 @@ class FigEasingCurve extends HTMLElement {
|
|
|
16581
16649
|
this.#resizeObserver.disconnect();
|
|
16582
16650
|
this.#resizeObserver = null;
|
|
16583
16651
|
}
|
|
16652
|
+
this.#destroyPickerPopup();
|
|
16584
16653
|
}
|
|
16585
16654
|
|
|
16586
16655
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
@@ -16596,6 +16665,9 @@ class FigEasingCurve extends HTMLElement {
|
|
|
16596
16665
|
}
|
|
16597
16666
|
|
|
16598
16667
|
if (name === "edit" || name === "presets" || name === "text") {
|
|
16668
|
+
if (name === "edit" && newValue !== "false") {
|
|
16669
|
+
this.#destroyPickerPopup();
|
|
16670
|
+
}
|
|
16599
16671
|
if (this.isConnected) this.#render();
|
|
16600
16672
|
return;
|
|
16601
16673
|
}
|
|
@@ -16607,6 +16679,7 @@ class FigEasingCurve extends HTMLElement {
|
|
|
16607
16679
|
this.#applyModeConstraint();
|
|
16608
16680
|
this.#presetName = this.#matchPreset();
|
|
16609
16681
|
if (this.isConnected) this.#render();
|
|
16682
|
+
this.#syncPickerPopup();
|
|
16610
16683
|
return;
|
|
16611
16684
|
}
|
|
16612
16685
|
|
|
@@ -16625,6 +16698,9 @@ class FigEasingCurve extends HTMLElement {
|
|
|
16625
16698
|
if (name === "precision") {
|
|
16626
16699
|
this.#precision = parseInt(newValue || "2");
|
|
16627
16700
|
}
|
|
16701
|
+
if (name === "value" || name === "mode" || name === "precision") {
|
|
16702
|
+
this.#syncPickerPopup();
|
|
16703
|
+
}
|
|
16628
16704
|
}
|
|
16629
16705
|
|
|
16630
16706
|
get value() {
|
|
@@ -17086,7 +17162,14 @@ class FigEasingCurve extends HTMLElement {
|
|
|
17086
17162
|
let parent = dropdown;
|
|
17087
17163
|
for (const preset of FigEasingCurve.PRESETS) {
|
|
17088
17164
|
if (!this.#allowsPreset(preset)) continue;
|
|
17089
|
-
if (
|
|
17165
|
+
if (
|
|
17166
|
+
!this.#isEditEnabled() &&
|
|
17167
|
+
!customElements.get("fig-popup-easing") &&
|
|
17168
|
+
!preset.value &&
|
|
17169
|
+
!preset.spring
|
|
17170
|
+
) {
|
|
17171
|
+
continue;
|
|
17172
|
+
}
|
|
17090
17173
|
if (preset.group !== currentGroup) {
|
|
17091
17174
|
currentGroup = preset.group;
|
|
17092
17175
|
parent = currentGroup
|
|
@@ -17108,7 +17191,14 @@ class FigEasingCurve extends HTMLElement {
|
|
|
17108
17191
|
let currentGroup = undefined;
|
|
17109
17192
|
for (const p of FigEasingCurve.PRESETS) {
|
|
17110
17193
|
if (!this.#allowsPreset(p)) continue;
|
|
17111
|
-
if (
|
|
17194
|
+
if (
|
|
17195
|
+
!this.#isEditEnabled() &&
|
|
17196
|
+
!customElements.get("fig-popup-easing") &&
|
|
17197
|
+
!p.value &&
|
|
17198
|
+
!p.spring
|
|
17199
|
+
) {
|
|
17200
|
+
continue;
|
|
17201
|
+
}
|
|
17112
17202
|
if (p.group !== currentGroup) {
|
|
17113
17203
|
if (p.group) {
|
|
17114
17204
|
options.appendChild(
|
|
@@ -17138,7 +17228,7 @@ class FigEasingCurve extends HTMLElement {
|
|
|
17138
17228
|
label: p.name,
|
|
17139
17229
|
},
|
|
17140
17230
|
[
|
|
17141
|
-
figCreateElement("
|
|
17231
|
+
figCreateElement("fig-icon", { slot: "prepend" }, icon),
|
|
17142
17232
|
figCreateElement("span", {}, p.name),
|
|
17143
17233
|
],
|
|
17144
17234
|
),
|
|
@@ -17727,7 +17817,12 @@ class FigEasingCurve extends HTMLElement {
|
|
|
17727
17817
|
|
|
17728
17818
|
#refreshCustomPresetIcons() {
|
|
17729
17819
|
if (!this.#select) return;
|
|
17730
|
-
if (
|
|
17820
|
+
if (
|
|
17821
|
+
!this.#isEditEnabled() &&
|
|
17822
|
+
!customElements.get("fig-popup-easing")
|
|
17823
|
+
) {
|
|
17824
|
+
return;
|
|
17825
|
+
}
|
|
17731
17826
|
const bezierIcon = FigEasingCurve.#createCurveIcon(
|
|
17732
17827
|
this.#cp1.x,
|
|
17733
17828
|
this.#cp1.y,
|
|
@@ -17936,6 +18031,22 @@ class FigEasingCurve extends HTMLElement {
|
|
|
17936
18031
|
}
|
|
17937
18032
|
|
|
17938
18033
|
if (this.#select) {
|
|
18034
|
+
if (!this.#isEditEnabled() && this.#select.tagName === "FIG-SELECT") {
|
|
18035
|
+
const openPicker = (event) => {
|
|
18036
|
+
if (!customElements.get("fig-popup-easing")) return;
|
|
18037
|
+
event.preventDefault();
|
|
18038
|
+
event.stopImmediatePropagation();
|
|
18039
|
+
this.#openPickerPopup();
|
|
18040
|
+
};
|
|
18041
|
+
this.#select.addEventListener("click", openPicker, true);
|
|
18042
|
+
this.#select.addEventListener(
|
|
18043
|
+
"keydown",
|
|
18044
|
+
(event) => {
|
|
18045
|
+
if (event.key === "Enter" || event.key === " ") openPicker(event);
|
|
18046
|
+
},
|
|
18047
|
+
true,
|
|
18048
|
+
);
|
|
18049
|
+
}
|
|
17939
18050
|
this.#select.addEventListener("input", (e) => {
|
|
17940
18051
|
e.stopPropagation();
|
|
17941
18052
|
});
|
|
@@ -18003,6 +18114,59 @@ class FigEasingCurve extends HTMLElement {
|
|
|
18003
18114
|
}
|
|
18004
18115
|
}
|
|
18005
18116
|
|
|
18117
|
+
#openPickerPopup() {
|
|
18118
|
+
if (!customElements.get("fig-popup-easing")) {
|
|
18119
|
+
this.#pickerDefinitionPromise ??= customElements
|
|
18120
|
+
.whenDefined("fig-popup-easing")
|
|
18121
|
+
.then(() => {
|
|
18122
|
+
if (!this.isConnected || this.#isEditEnabled()) return;
|
|
18123
|
+
this.#openPickerPopup();
|
|
18124
|
+
});
|
|
18125
|
+
return;
|
|
18126
|
+
}
|
|
18127
|
+
|
|
18128
|
+
let popup = this.#pickerPopup;
|
|
18129
|
+
if (!popup?.isConnected) {
|
|
18130
|
+
popup = document.createElement("dialog", { is: "fig-popup-easing" });
|
|
18131
|
+
popup.setAttribute("is", "fig-popup-easing");
|
|
18132
|
+
popup.id = figUniqueId();
|
|
18133
|
+
popup.anchor = this.#select;
|
|
18134
|
+
const handlePopupEvent = (event) => {
|
|
18135
|
+
event.stopPropagation();
|
|
18136
|
+
this.value = popup.value;
|
|
18137
|
+
this.#emit(event.type);
|
|
18138
|
+
};
|
|
18139
|
+
popup.addEventListener("input", handlePopupEvent);
|
|
18140
|
+
popup.addEventListener("change", handlePopupEvent);
|
|
18141
|
+
(figGetOverlayRoot() ?? document.body).append(popup);
|
|
18142
|
+
this.#pickerPopup = popup;
|
|
18143
|
+
this.#select?.setAttribute("aria-controls", popup.id);
|
|
18144
|
+
}
|
|
18145
|
+
|
|
18146
|
+
this.#syncPickerPopup();
|
|
18147
|
+
popup.open = true;
|
|
18148
|
+
}
|
|
18149
|
+
|
|
18150
|
+
#syncPickerPopup() {
|
|
18151
|
+
const popup = this.#pickerPopup;
|
|
18152
|
+
if (!popup) return;
|
|
18153
|
+
popup.anchor = this.#select;
|
|
18154
|
+
popup.setAttribute("value", this.value);
|
|
18155
|
+
for (const name of ["mode", "precision"]) {
|
|
18156
|
+
const value = this.getAttribute(name);
|
|
18157
|
+
if (value === null) popup.removeAttribute(name);
|
|
18158
|
+
else popup.setAttribute(name, value);
|
|
18159
|
+
}
|
|
18160
|
+
}
|
|
18161
|
+
|
|
18162
|
+
#destroyPickerPopup() {
|
|
18163
|
+
if (!this.#pickerPopup) return;
|
|
18164
|
+
this.#pickerPopup.open = false;
|
|
18165
|
+
this.#pickerPopup.remove();
|
|
18166
|
+
this.#select?.removeAttribute("aria-controls");
|
|
18167
|
+
this.#pickerPopup = null;
|
|
18168
|
+
}
|
|
18169
|
+
|
|
18006
18170
|
#clientToSVG(e) {
|
|
18007
18171
|
const ctm = this.#svg.getScreenCTM();
|
|
18008
18172
|
if (!ctm) return { x: 0, y: 0 };
|
|
@@ -20777,6 +20941,7 @@ const FIG_ICON_TOKENS = {
|
|
|
20777
20941
|
upload: "--icon-24-upload",
|
|
20778
20942
|
image: "--icon-24-image",
|
|
20779
20943
|
video: { medium: "--icon-24-video", small: "--icon-16-video" },
|
|
20944
|
+
audio: "--icon-24-audio",
|
|
20780
20945
|
sound: { medium: "--icon-24-sound", small: "--icon-16-sound" },
|
|
20781
20946
|
"sound-off": {
|
|
20782
20947
|
medium: "--icon-24-sound-off",
|
|
@@ -20793,6 +20958,7 @@ const FIG_ICON_TOKENS = {
|
|
|
20793
20958
|
warning: { medium: "--icon-24-warning", small: "--icon-16-warning" },
|
|
20794
20959
|
copy: { medium: "--icon-24-copy", small: "--icon-16-copy" },
|
|
20795
20960
|
trash: { medium: "--icon-24-trash", small: "--icon-16-trash" },
|
|
20961
|
+
"drag-handle": "--icon-16-drag-handle",
|
|
20796
20962
|
};
|
|
20797
20963
|
|
|
20798
20964
|
function figIconCssVar(name, size = "medium") {
|