@rogieking/figui3 6.6.1 → 6.6.2
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/fig.js +26 -26
- package/fig.js +559 -209
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -27,6 +27,14 @@ function createFigIcon(name, options = {}) {
|
|
|
27
27
|
return icon;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/** Run callback on the next frame; skip if the host disconnected first. */
|
|
31
|
+
function figNextFrame(host, callback) {
|
|
32
|
+
requestAnimationFrame(() => {
|
|
33
|
+
if (host && !host.isConnected) return;
|
|
34
|
+
callback();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
function createFigOverflowButtons({
|
|
31
39
|
owner,
|
|
32
40
|
onStart,
|
|
@@ -202,16 +210,26 @@ class FigButton extends HTMLElement {
|
|
|
202
210
|
#selected;
|
|
203
211
|
#a11yAttributes = ["aria-label", "aria-labelledby", "aria-describedby", "title"];
|
|
204
212
|
#boundHandleControlKeydown = this.#handleControlKeydown.bind(this);
|
|
213
|
+
#boundHandleClick = this.#handleClick.bind(this);
|
|
214
|
+
#boundHandleFocus = () => {
|
|
215
|
+
if (this.button?.matches(":focus-visible")) {
|
|
216
|
+
this.setAttribute("data-focus-visible", "");
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
#boundHandleBlur = () => {
|
|
220
|
+
this.removeAttribute("data-focus-visible");
|
|
221
|
+
};
|
|
205
222
|
constructor() {
|
|
206
223
|
super();
|
|
207
224
|
this.attachShadow({ mode: "open", delegatesFocus: true });
|
|
208
225
|
}
|
|
209
226
|
connectedCallback() {
|
|
210
227
|
this.type = this.getAttribute("type") || "button";
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
228
|
+
if (!this.button) {
|
|
229
|
+
const isControlWrapper = this.type === "select" || this.type === "upload";
|
|
230
|
+
const controlTag = isControlWrapper ? "span" : "button";
|
|
231
|
+
const typeAttr = isControlWrapper ? "" : ` type="${this.type}"`;
|
|
232
|
+
this.shadowRoot.innerHTML = `
|
|
215
233
|
<style>
|
|
216
234
|
button, button:hover, button:active, .fig-button-control {
|
|
217
235
|
padding: 0 var(--spacer-2);
|
|
@@ -249,24 +267,18 @@ class FigButton extends HTMLElement {
|
|
|
249
267
|
</${controlTag}>
|
|
250
268
|
`;
|
|
251
269
|
|
|
270
|
+
this.button = this.shadowRoot.querySelector("button, .fig-button-control");
|
|
271
|
+
this.button.addEventListener("click", this.#boundHandleClick);
|
|
272
|
+
this.button.addEventListener("focus", this.#boundHandleFocus);
|
|
273
|
+
this.button.addEventListener("blur", this.#boundHandleBlur);
|
|
274
|
+
this.addEventListener("keydown", this.#boundHandleControlKeydown);
|
|
275
|
+
}
|
|
276
|
+
|
|
252
277
|
this.#selected =
|
|
253
278
|
this.hasAttribute("selected") &&
|
|
254
279
|
this.getAttribute("selected") !== "false";
|
|
255
280
|
|
|
256
|
-
this.button = this.shadowRoot.querySelector("button, .fig-button-control");
|
|
257
281
|
this.#syncButtonAttributes();
|
|
258
|
-
this.button.addEventListener("click", this.#handleClick.bind(this));
|
|
259
|
-
|
|
260
|
-
// Forward focus-visible state to host element
|
|
261
|
-
this.button.addEventListener("focus", () => {
|
|
262
|
-
if (this.button.matches(":focus-visible")) {
|
|
263
|
-
this.setAttribute("data-focus-visible", "");
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
this.button.addEventListener("blur", () => {
|
|
267
|
-
this.removeAttribute("data-focus-visible");
|
|
268
|
-
});
|
|
269
|
-
this.addEventListener("keydown", this.#boundHandleControlKeydown);
|
|
270
282
|
}
|
|
271
283
|
|
|
272
284
|
get type() {
|
|
@@ -390,8 +402,17 @@ class FigButton extends HTMLElement {
|
|
|
390
402
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
391
403
|
if (oldValue === newValue) return;
|
|
392
404
|
switch (name) {
|
|
405
|
+
case "type": {
|
|
406
|
+
const isWrapper = (type) => type === "select" || type === "upload";
|
|
407
|
+
if (isWrapper(oldValue || "button") !== isWrapper(newValue || "button")) {
|
|
408
|
+
this.button = null;
|
|
409
|
+
this.connectedCallback();
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
this.#syncButtonAttributes();
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
393
415
|
case "disabled":
|
|
394
|
-
case "type":
|
|
395
416
|
this.#syncButtonAttributes();
|
|
396
417
|
break;
|
|
397
418
|
case "selected":
|
|
@@ -520,11 +541,19 @@ class FigDropdown extends HTMLElement {
|
|
|
520
541
|
this.select.setAttribute("aria-label", this.#label);
|
|
521
542
|
this.#syncDisabled();
|
|
522
543
|
|
|
523
|
-
|
|
524
|
-
|
|
544
|
+
if (!this.select.isConnected) {
|
|
545
|
+
this.appendChild(this.select);
|
|
546
|
+
}
|
|
547
|
+
if (!this.optionsSlot.isConnected) {
|
|
548
|
+
this.shadowRoot.appendChild(this.optionsSlot);
|
|
549
|
+
}
|
|
525
550
|
|
|
551
|
+
this.optionsSlot.removeEventListener("slotchange", this.#boundSlotChange);
|
|
526
552
|
this.optionsSlot.addEventListener("slotchange", this.#boundSlotChange);
|
|
527
553
|
|
|
554
|
+
this.select.removeEventListener("input", this.#boundHandleSelectInput);
|
|
555
|
+
this.select.removeEventListener("change", this.#boundHandleSelectChange);
|
|
556
|
+
this.select.removeEventListener("keydown", this.#boundHandleSelectKeydown);
|
|
528
557
|
this.#addEventListeners();
|
|
529
558
|
}
|
|
530
559
|
|
|
@@ -1152,7 +1181,7 @@ class FigTruncate extends HTMLElement {
|
|
|
1152
1181
|
|
|
1153
1182
|
connectedCallback() {
|
|
1154
1183
|
this.#originalText = this.textContent;
|
|
1155
|
-
|
|
1184
|
+
figNextFrame(this, () => {
|
|
1156
1185
|
this.#render();
|
|
1157
1186
|
this.#setupTooltip();
|
|
1158
1187
|
});
|
|
@@ -1284,7 +1313,7 @@ class FigDialog extends HTMLDialogElement {
|
|
|
1284
1313
|
|
|
1285
1314
|
this._ensureHeader();
|
|
1286
1315
|
|
|
1287
|
-
|
|
1316
|
+
figNextFrame(this, () => {
|
|
1288
1317
|
this._addCloseListeners();
|
|
1289
1318
|
this._setupDragListeners();
|
|
1290
1319
|
this._applyPosition();
|
|
@@ -3111,7 +3140,7 @@ class FigTab extends HTMLElement {
|
|
|
3111
3140
|
if (!this.hasAttribute("tabindex")) this.setAttribute("tabindex", "-1");
|
|
3112
3141
|
this.addEventListener("click", this.#boundHandleClick);
|
|
3113
3142
|
|
|
3114
|
-
|
|
3143
|
+
figNextFrame(this, () => {
|
|
3115
3144
|
if (typeof this.getAttribute("content") === "string") {
|
|
3116
3145
|
this.content = document.querySelector(this.getAttribute("content"));
|
|
3117
3146
|
if (this.content) {
|
|
@@ -3211,7 +3240,7 @@ class FigTabs extends HTMLElement {
|
|
|
3211
3240
|
this.#createNavButtons();
|
|
3212
3241
|
this.#startObserver();
|
|
3213
3242
|
this.#startResizeObserver();
|
|
3214
|
-
|
|
3243
|
+
figNextFrame(this, () => {
|
|
3215
3244
|
const value = this.getAttribute("value");
|
|
3216
3245
|
if (value) {
|
|
3217
3246
|
this.#selectByValue(value);
|
|
@@ -3662,7 +3691,7 @@ class FigSegmentedControl extends HTMLElement {
|
|
|
3662
3691
|
this.#startResizeObserver();
|
|
3663
3692
|
|
|
3664
3693
|
// Defer initial selection so child segments are available.
|
|
3665
|
-
|
|
3694
|
+
figNextFrame(this, () => {
|
|
3666
3695
|
this.#syncSelectionFromAttributes({ enforceFallback: true });
|
|
3667
3696
|
this.#refreshResizeObserverTargets();
|
|
3668
3697
|
this.#queueIndicatorSync({ forceInstant: true });
|
|
@@ -4118,13 +4147,52 @@ class FigOptions extends HTMLElement {
|
|
|
4118
4147
|
return String(fallbackValue);
|
|
4119
4148
|
}
|
|
4120
4149
|
|
|
4150
|
+
#canReuseControl() {
|
|
4151
|
+
if (this.#parsedOptions.length === 0) return false;
|
|
4152
|
+
const segments = this.querySelector(":scope > fig-segmented-control");
|
|
4153
|
+
if (segments) {
|
|
4154
|
+
const opts = segments.querySelectorAll("fig-segment");
|
|
4155
|
+
if (opts.length !== this.#parsedOptions.length) return false;
|
|
4156
|
+
return Array.from(opts).every(
|
|
4157
|
+
(seg, i) => seg.getAttribute("value") === this.#parsedOptions[i],
|
|
4158
|
+
);
|
|
4159
|
+
}
|
|
4160
|
+
const dropdown = this.querySelector(":scope > fig-dropdown");
|
|
4161
|
+
if (dropdown) {
|
|
4162
|
+
const opts = dropdown.querySelectorAll("option");
|
|
4163
|
+
return (
|
|
4164
|
+
opts.length === this.#parsedOptions.length &&
|
|
4165
|
+
Array.from(opts).every(
|
|
4166
|
+
(opt, i) => opt.textContent?.trim() === this.#parsedOptions[i],
|
|
4167
|
+
)
|
|
4168
|
+
);
|
|
4169
|
+
}
|
|
4170
|
+
return false;
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
#reuseControl() {
|
|
4174
|
+
const segments = this.querySelector(":scope > fig-segmented-control");
|
|
4175
|
+
if (segments) {
|
|
4176
|
+
this.#childControl = segments;
|
|
4177
|
+
this.#currentMode = "segments";
|
|
4178
|
+
} else {
|
|
4179
|
+
this.#childControl = this.querySelector(":scope > fig-dropdown");
|
|
4180
|
+
this.#currentMode = "dropdown";
|
|
4181
|
+
}
|
|
4182
|
+
this.#syncValueToChild();
|
|
4183
|
+
}
|
|
4184
|
+
|
|
4121
4185
|
connectedCallback() {
|
|
4122
4186
|
this.#parseOptions();
|
|
4187
|
+
if (this.#canReuseControl()) {
|
|
4188
|
+
this.#reuseControl();
|
|
4189
|
+
this.#startResizeObserver();
|
|
4190
|
+
figNextFrame(this, () => figNextFrame(this, () => this.#checkOverflow()));
|
|
4191
|
+
return;
|
|
4192
|
+
}
|
|
4123
4193
|
this.#renderSegments();
|
|
4124
4194
|
this.#startResizeObserver();
|
|
4125
|
-
|
|
4126
|
-
requestAnimationFrame(() => this.#checkOverflow());
|
|
4127
|
-
});
|
|
4195
|
+
figNextFrame(this, () => figNextFrame(this, () => this.#checkOverflow()));
|
|
4128
4196
|
}
|
|
4129
4197
|
|
|
4130
4198
|
disconnectedCallback() {
|
|
@@ -4476,7 +4544,7 @@ class FigSlider extends HTMLElement {
|
|
|
4476
4544
|
};
|
|
4477
4545
|
}
|
|
4478
4546
|
|
|
4479
|
-
#
|
|
4547
|
+
#readAttributesFromMarkup() {
|
|
4480
4548
|
const rawValue = this.getAttribute("value");
|
|
4481
4549
|
this.type = this.getAttribute("type") || "range";
|
|
4482
4550
|
this.variant = this.getAttribute("variant") || "default";
|
|
@@ -4507,6 +4575,103 @@ class FigSlider extends HTMLElement {
|
|
|
4507
4575
|
(rawValue === null ||
|
|
4508
4576
|
(typeof rawValue === "string" && rawValue.trim() === ""));
|
|
4509
4577
|
this.value = this.#normalizeSliderValue(rawValue);
|
|
4578
|
+
}
|
|
4579
|
+
|
|
4580
|
+
#canReuseRenderedMarkup() {
|
|
4581
|
+
const range = this.querySelector("[type=range]");
|
|
4582
|
+
if (!range) return false;
|
|
4583
|
+
const wantsText = this.getAttribute("text") !== "false";
|
|
4584
|
+
return wantsText === !!this.querySelector("fig-input-number");
|
|
4585
|
+
}
|
|
4586
|
+
|
|
4587
|
+
#updateRenderedMarkup() {
|
|
4588
|
+
this.#readAttributesFromMarkup();
|
|
4589
|
+
if (this.color) {
|
|
4590
|
+
this.style.setProperty("--color", this.color);
|
|
4591
|
+
} else {
|
|
4592
|
+
this.style.removeProperty("--color");
|
|
4593
|
+
}
|
|
4594
|
+
|
|
4595
|
+
this.input = this.querySelector("[type=range]");
|
|
4596
|
+
this.inputContainer = this.querySelector(".fig-slider-input-container");
|
|
4597
|
+
this.input.className = this.type;
|
|
4598
|
+
this.input.min = String(this.min);
|
|
4599
|
+
this.input.max = String(this.max);
|
|
4600
|
+
this.input.step = String(this.step);
|
|
4601
|
+
this.input.value = String(this.value);
|
|
4602
|
+
this.input.disabled = this.disabled;
|
|
4603
|
+
if (this.text) this.input.setAttribute("tabindex", "-1");
|
|
4604
|
+
else this.input.removeAttribute("tabindex");
|
|
4605
|
+
this.input.setAttribute("aria-valuemin", String(this.min));
|
|
4606
|
+
this.input.setAttribute("aria-valuemax", String(this.max));
|
|
4607
|
+
this.input.setAttribute("aria-valuenow", String(this.value));
|
|
4608
|
+
|
|
4609
|
+
this.figInputNumber = this.querySelector("fig-input-number");
|
|
4610
|
+
if (this.figInputNumber) {
|
|
4611
|
+
this.figInputNumber.setAttribute("placeholder", this.placeholder);
|
|
4612
|
+
this.figInputNumber.setAttribute("min", String(this.min));
|
|
4613
|
+
this.figInputNumber.setAttribute("max", String(this.max));
|
|
4614
|
+
this.figInputNumber.setAttribute("transform", String(this.transform));
|
|
4615
|
+
this.figInputNumber.setAttribute("step", String(this.step));
|
|
4616
|
+
this.figInputNumber.setAttribute(
|
|
4617
|
+
"value",
|
|
4618
|
+
this.#showEmptyTextValue ? "" : String(this.value),
|
|
4619
|
+
);
|
|
4620
|
+
if (this.units) this.figInputNumber.setAttribute("units", this.units);
|
|
4621
|
+
else this.figInputNumber.removeAttribute("units");
|
|
4622
|
+
if (this.precision !== null) {
|
|
4623
|
+
this.figInputNumber.setAttribute("precision", String(this.precision));
|
|
4624
|
+
} else {
|
|
4625
|
+
this.figInputNumber.removeAttribute("precision");
|
|
4626
|
+
}
|
|
4627
|
+
this.figInputNumber.disabled = this.disabled;
|
|
4628
|
+
this.figInputNumber.toggleAttribute("disabled", this.disabled);
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
|
|
4632
|
+
#bindControlListeners() {
|
|
4633
|
+
this.#syncInputA11yAttributes();
|
|
4634
|
+
this.input.removeEventListener("input", this.#boundHandleInput);
|
|
4635
|
+
this.input.addEventListener("input", this.#boundHandleInput);
|
|
4636
|
+
this.input.removeEventListener("change", this.#boundHandleChange);
|
|
4637
|
+
this.input.addEventListener("change", this.#boundHandleChange);
|
|
4638
|
+
this.input.removeEventListener("keydown", this.#boundHandleKeyDown);
|
|
4639
|
+
this.input.addEventListener("keydown", this.#boundHandleKeyDown);
|
|
4640
|
+
this.input.removeEventListener("pointerdown", this.#boundRangePointerDown);
|
|
4641
|
+
this.input.addEventListener("pointerdown", this.#boundRangePointerDown);
|
|
4642
|
+
this.input.removeEventListener("pointerup", this.#boundRangePointerUp);
|
|
4643
|
+
this.input.addEventListener("pointerup", this.#boundRangePointerUp);
|
|
4644
|
+
|
|
4645
|
+
if (this.default) {
|
|
4646
|
+
this.style.setProperty(
|
|
4647
|
+
"--default",
|
|
4648
|
+
this.#calculateNormal(this.default),
|
|
4649
|
+
);
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
if (this.figInputNumber) {
|
|
4653
|
+
this.#syncTextInputA11yAttributes();
|
|
4654
|
+
this.figInputNumber.removeEventListener(
|
|
4655
|
+
"input",
|
|
4656
|
+
this.#boundHandleTextInput,
|
|
4657
|
+
);
|
|
4658
|
+
this.figInputNumber.addEventListener(
|
|
4659
|
+
"input",
|
|
4660
|
+
this.#boundHandleTextInput,
|
|
4661
|
+
);
|
|
4662
|
+
this.figInputNumber.removeEventListener(
|
|
4663
|
+
"change",
|
|
4664
|
+
this.#boundHandleTextChange,
|
|
4665
|
+
);
|
|
4666
|
+
this.figInputNumber.addEventListener(
|
|
4667
|
+
"change",
|
|
4668
|
+
this.#boundHandleTextChange,
|
|
4669
|
+
);
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
|
|
4673
|
+
#regenerateInnerHTML() {
|
|
4674
|
+
this.#readAttributesFromMarkup();
|
|
4510
4675
|
|
|
4511
4676
|
if (this.color) {
|
|
4512
4677
|
this.style.setProperty("--color", this.color);
|
|
@@ -4547,24 +4712,7 @@ class FigSlider extends HTMLElement {
|
|
|
4547
4712
|
|
|
4548
4713
|
this.input = this.querySelector("[type=range]");
|
|
4549
4714
|
this.inputContainer = this.querySelector(".fig-slider-input-container");
|
|
4550
|
-
this.#
|
|
4551
|
-
this.input.removeEventListener("input", this.#boundHandleInput);
|
|
4552
|
-
this.input.addEventListener("input", this.#boundHandleInput);
|
|
4553
|
-
this.input.removeEventListener("change", this.#boundHandleChange);
|
|
4554
|
-
this.input.addEventListener("change", this.#boundHandleChange);
|
|
4555
|
-
this.input.removeEventListener("keydown", this.#boundHandleKeyDown);
|
|
4556
|
-
this.input.addEventListener("keydown", this.#boundHandleKeyDown);
|
|
4557
|
-
this.input.removeEventListener("pointerdown", this.#boundRangePointerDown);
|
|
4558
|
-
this.input.addEventListener("pointerdown", this.#boundRangePointerDown);
|
|
4559
|
-
this.input.removeEventListener("pointerup", this.#boundRangePointerUp);
|
|
4560
|
-
this.input.addEventListener("pointerup", this.#boundRangePointerUp);
|
|
4561
|
-
|
|
4562
|
-
if (this.default) {
|
|
4563
|
-
this.style.setProperty(
|
|
4564
|
-
"--default",
|
|
4565
|
-
this.#calculateNormal(this.default),
|
|
4566
|
-
);
|
|
4567
|
-
}
|
|
4715
|
+
this.#bindControlListeners();
|
|
4568
4716
|
|
|
4569
4717
|
this.datalist = this.querySelector("datalist");
|
|
4570
4718
|
this.figInputNumber = this.querySelector("fig-input-number");
|
|
@@ -4603,30 +4751,16 @@ class FigSlider extends HTMLElement {
|
|
|
4603
4751
|
defaultOption.setAttribute("default", "true");
|
|
4604
4752
|
}
|
|
4605
4753
|
}
|
|
4606
|
-
if (this.figInputNumber) {
|
|
4607
|
-
this.#syncTextInputA11yAttributes();
|
|
4608
|
-
this.figInputNumber.removeEventListener(
|
|
4609
|
-
"input",
|
|
4610
|
-
this.#boundHandleTextInput,
|
|
4611
|
-
);
|
|
4612
|
-
this.figInputNumber.addEventListener(
|
|
4613
|
-
"input",
|
|
4614
|
-
this.#boundHandleTextInput,
|
|
4615
|
-
);
|
|
4616
|
-
this.figInputNumber.removeEventListener(
|
|
4617
|
-
"change",
|
|
4618
|
-
this.#boundHandleTextChange,
|
|
4619
|
-
);
|
|
4620
|
-
this.figInputNumber.addEventListener(
|
|
4621
|
-
"change",
|
|
4622
|
-
this.#boundHandleTextChange,
|
|
4623
|
-
);
|
|
4624
|
-
}
|
|
4625
|
-
|
|
4626
4754
|
this.#syncValue();
|
|
4627
4755
|
}
|
|
4628
4756
|
|
|
4629
4757
|
connectedCallback() {
|
|
4758
|
+
if (this.#canReuseRenderedMarkup()) {
|
|
4759
|
+
this.#updateRenderedMarkup();
|
|
4760
|
+
this.#bindControlListeners();
|
|
4761
|
+
this.#syncValue();
|
|
4762
|
+
return;
|
|
4763
|
+
}
|
|
4630
4764
|
this.#regenerateInnerHTML();
|
|
4631
4765
|
}
|
|
4632
4766
|
|
|
@@ -5064,35 +5198,7 @@ class FigInputText extends HTMLElement {
|
|
|
5064
5198
|
}
|
|
5065
5199
|
}
|
|
5066
5200
|
|
|
5067
|
-
|
|
5068
|
-
type="${this.type}"
|
|
5069
|
-
${this.name ? `name="${this.name}"` : ""}
|
|
5070
|
-
placeholder="${this.placeholder}"
|
|
5071
|
-
value="${
|
|
5072
|
-
this.type === "number" ? this.#transformNumber(this.value) : this.value
|
|
5073
|
-
}" />`;
|
|
5074
|
-
if (this.multiline) {
|
|
5075
|
-
html = `<textarea
|
|
5076
|
-
placeholder="${this.placeholder}">${this.value}</textarea>`;
|
|
5077
|
-
}
|
|
5078
|
-
|
|
5079
|
-
let append = this.querySelector("[slot=append]");
|
|
5080
|
-
let prepend = this.querySelector("[slot=prepend]");
|
|
5081
|
-
|
|
5082
|
-
this.innerHTML = html;
|
|
5083
|
-
|
|
5084
|
-
if (prepend) {
|
|
5085
|
-
prepend.removeEventListener("click", this.#boundFocusControl);
|
|
5086
|
-
prepend.addEventListener("click", this.#boundFocusControl);
|
|
5087
|
-
this.prepend(prepend);
|
|
5088
|
-
}
|
|
5089
|
-
if (append) {
|
|
5090
|
-
append.removeEventListener("click", this.#boundFocusControl);
|
|
5091
|
-
append.addEventListener("click", this.#boundFocusControl);
|
|
5092
|
-
this.append(append);
|
|
5093
|
-
}
|
|
5094
|
-
|
|
5095
|
-
this.input = this.querySelector("input,textarea");
|
|
5201
|
+
this.input = this.#ensureInputControl();
|
|
5096
5202
|
this.input.readOnly = this.readonly;
|
|
5097
5203
|
this.#syncInputA11yAttributes();
|
|
5098
5204
|
this.#syncSearchPrefix();
|
|
@@ -5132,6 +5238,46 @@ class FigInputText extends HTMLElement {
|
|
|
5132
5238
|
focus() {
|
|
5133
5239
|
this.input.focus();
|
|
5134
5240
|
}
|
|
5241
|
+
#ensureInputControl() {
|
|
5242
|
+
const wantsTextarea = this.multiline;
|
|
5243
|
+
const existing = this.querySelector("input,textarea");
|
|
5244
|
+
if (existing) {
|
|
5245
|
+
const matches = wantsTextarea
|
|
5246
|
+
? existing.tagName === "TEXTAREA"
|
|
5247
|
+
: existing.tagName === "INPUT";
|
|
5248
|
+
if (matches) return existing;
|
|
5249
|
+
}
|
|
5250
|
+
|
|
5251
|
+
let html = `<input
|
|
5252
|
+
type="${this.type}"
|
|
5253
|
+
${this.name ? `name="${this.name}"` : ""}
|
|
5254
|
+
placeholder="${this.placeholder}"
|
|
5255
|
+
value="${
|
|
5256
|
+
this.type === "number" ? this.#transformNumber(this.value) : this.value
|
|
5257
|
+
}" />`;
|
|
5258
|
+
if (wantsTextarea) {
|
|
5259
|
+
html = `<textarea
|
|
5260
|
+
placeholder="${this.placeholder}">${this.value}</textarea>`;
|
|
5261
|
+
}
|
|
5262
|
+
|
|
5263
|
+
const append = this.querySelector("[slot=append]");
|
|
5264
|
+
const prepend = this.querySelector("[slot=prepend]");
|
|
5265
|
+
|
|
5266
|
+
this.innerHTML = html;
|
|
5267
|
+
|
|
5268
|
+
if (prepend) {
|
|
5269
|
+
prepend.removeEventListener("click", this.#boundFocusControl);
|
|
5270
|
+
prepend.addEventListener("click", this.#boundFocusControl);
|
|
5271
|
+
this.prepend(prepend);
|
|
5272
|
+
}
|
|
5273
|
+
if (append) {
|
|
5274
|
+
append.removeEventListener("click", this.#boundFocusControl);
|
|
5275
|
+
append.addEventListener("click", this.#boundFocusControl);
|
|
5276
|
+
this.append(append);
|
|
5277
|
+
}
|
|
5278
|
+
|
|
5279
|
+
return this.querySelector("input,textarea");
|
|
5280
|
+
}
|
|
5135
5281
|
#syncInputA11yAttributes() {
|
|
5136
5282
|
if (!this.input) return;
|
|
5137
5283
|
this.#a11yAttributes.forEach((name) => {
|
|
@@ -5153,13 +5299,19 @@ class FigInputText extends HTMLElement {
|
|
|
5153
5299
|
}
|
|
5154
5300
|
const prepend = this.querySelector('[slot="prepend"]');
|
|
5155
5301
|
if (prepend && prepend !== generated) return;
|
|
5156
|
-
if (generated)
|
|
5302
|
+
if (generated) {
|
|
5303
|
+
const icon = generated.querySelector("fig-icon");
|
|
5304
|
+
if (icon && icon.getAttribute("name") !== "search") {
|
|
5305
|
+
icon.setAttribute("name", "search");
|
|
5306
|
+
}
|
|
5307
|
+
return;
|
|
5308
|
+
}
|
|
5157
5309
|
|
|
5158
5310
|
const icon = createFigIcon("search");
|
|
5159
5311
|
icon.setAttribute("slot", "prepend");
|
|
5160
5312
|
icon.setAttribute("data-generated", "search-prefix");
|
|
5161
5313
|
icon.setAttribute("color", "var(--figma-color-icon)");
|
|
5162
|
-
icon.addEventListener("click", this
|
|
5314
|
+
icon.addEventListener("click", this.#boundFocusControl);
|
|
5163
5315
|
this.prepend(icon);
|
|
5164
5316
|
}
|
|
5165
5317
|
#syncSearchClear() {
|
|
@@ -5172,7 +5324,13 @@ class FigInputText extends HTMLElement {
|
|
|
5172
5324
|
}
|
|
5173
5325
|
const append = this.querySelector('[slot="append"]');
|
|
5174
5326
|
if (append && append !== generated) return;
|
|
5175
|
-
if (generated)
|
|
5327
|
+
if (generated) {
|
|
5328
|
+
const icon = generated.querySelector("fig-icon");
|
|
5329
|
+
if (icon && icon.getAttribute("name") !== "close") {
|
|
5330
|
+
icon.setAttribute("name", "close");
|
|
5331
|
+
}
|
|
5332
|
+
return;
|
|
5333
|
+
}
|
|
5176
5334
|
|
|
5177
5335
|
const wrapper = document.createElement("span");
|
|
5178
5336
|
wrapper.setAttribute("slot", "append");
|
|
@@ -5186,13 +5344,12 @@ class FigInputText extends HTMLElement {
|
|
|
5186
5344
|
button.setAttribute("icon", "");
|
|
5187
5345
|
button.setAttribute("aria-label", "Clear search");
|
|
5188
5346
|
|
|
5189
|
-
const icon = createFigIcon("", { size: "small" });
|
|
5347
|
+
const icon = createFigIcon("close", { size: "small" });
|
|
5190
5348
|
icon.setAttribute("color", "var(--figma-color-icon-secondary)");
|
|
5191
5349
|
button.append(icon);
|
|
5192
5350
|
tooltip.append(button);
|
|
5193
5351
|
wrapper.append(tooltip);
|
|
5194
5352
|
this.append(wrapper);
|
|
5195
|
-
icon.style.setProperty("--icon", "var(--icon-16-close)");
|
|
5196
5353
|
|
|
5197
5354
|
button.addEventListener("click", (e) => {
|
|
5198
5355
|
e.preventDefault();
|
|
@@ -5658,30 +5815,7 @@ class FigInputNumber extends HTMLElement {
|
|
|
5658
5815
|
this.hasAttribute("steppers") &&
|
|
5659
5816
|
this.getAttribute("steppers") !== "false";
|
|
5660
5817
|
|
|
5661
|
-
|
|
5662
|
-
type="text"
|
|
5663
|
-
inputmode="decimal"
|
|
5664
|
-
${this.name ? `name="${this.name}"` : ""}
|
|
5665
|
-
placeholder="${this.placeholder}"
|
|
5666
|
-
value="${this.#formatWithUnit(this.value)}" />`;
|
|
5667
|
-
|
|
5668
|
-
let append = this.querySelector("[slot=append]");
|
|
5669
|
-
let prepend = this.querySelector("[slot=prepend]");
|
|
5670
|
-
|
|
5671
|
-
this.innerHTML = html;
|
|
5672
|
-
|
|
5673
|
-
if (prepend) {
|
|
5674
|
-
prepend.removeEventListener("click", this.#boundFocusControl);
|
|
5675
|
-
prepend.addEventListener("click", this.#boundFocusControl);
|
|
5676
|
-
this.prepend(prepend);
|
|
5677
|
-
}
|
|
5678
|
-
if (append) {
|
|
5679
|
-
append.removeEventListener("click", this.#boundFocusControl);
|
|
5680
|
-
append.addEventListener("click", this.#boundFocusControl);
|
|
5681
|
-
this.append(append);
|
|
5682
|
-
}
|
|
5683
|
-
|
|
5684
|
-
this.input = this.querySelector("input");
|
|
5818
|
+
this.input = this.#ensureInputControl();
|
|
5685
5819
|
this.#syncInputA11yAttributes();
|
|
5686
5820
|
|
|
5687
5821
|
if (this.getAttribute("min")) {
|
|
@@ -5735,6 +5869,36 @@ class FigInputNumber extends HTMLElement {
|
|
|
5735
5869
|
this.input.focus();
|
|
5736
5870
|
}
|
|
5737
5871
|
|
|
5872
|
+
#ensureInputControl() {
|
|
5873
|
+
const existing = this.querySelector("input");
|
|
5874
|
+
if (existing) return existing;
|
|
5875
|
+
|
|
5876
|
+
const html = `<input
|
|
5877
|
+
type="text"
|
|
5878
|
+
inputmode="decimal"
|
|
5879
|
+
${this.name ? `name="${this.name}"` : ""}
|
|
5880
|
+
placeholder="${this.placeholder}"
|
|
5881
|
+
value="${this.#formatWithUnit(this.value)}" />`;
|
|
5882
|
+
|
|
5883
|
+
const append = this.querySelector("[slot=append]");
|
|
5884
|
+
const prepend = this.querySelector("[slot=prepend]");
|
|
5885
|
+
|
|
5886
|
+
this.innerHTML = html;
|
|
5887
|
+
|
|
5888
|
+
if (prepend) {
|
|
5889
|
+
prepend.removeEventListener("click", this.#boundFocusControl);
|
|
5890
|
+
prepend.addEventListener("click", this.#boundFocusControl);
|
|
5891
|
+
this.prepend(prepend);
|
|
5892
|
+
}
|
|
5893
|
+
if (append) {
|
|
5894
|
+
append.removeEventListener("click", this.#boundFocusControl);
|
|
5895
|
+
append.addEventListener("click", this.#boundFocusControl);
|
|
5896
|
+
this.append(append);
|
|
5897
|
+
}
|
|
5898
|
+
|
|
5899
|
+
return this.querySelector("input");
|
|
5900
|
+
}
|
|
5901
|
+
|
|
5738
5902
|
#syncInputA11yAttributes() {
|
|
5739
5903
|
if (!this.input) return;
|
|
5740
5904
|
this.#a11yAttributes.forEach((name) => {
|
|
@@ -6318,6 +6482,14 @@ class FigInputColor extends HTMLElement {
|
|
|
6318
6482
|
#suppressNativeColorClick = false;
|
|
6319
6483
|
#pendingFillPickerPointerOpen = false;
|
|
6320
6484
|
#nativeColorClickTimer = null;
|
|
6485
|
+
#boundSwatchPointerDown = this.#handleSwatchPointerDown.bind(this);
|
|
6486
|
+
#boundSwatchClick = this.#handleSwatchClick.bind(this);
|
|
6487
|
+
#boundSwatchKeyDown = this.#handleSwatchKeyDown.bind(this);
|
|
6488
|
+
#boundHandleInput = this.#handleInput.bind(this);
|
|
6489
|
+
#boundTextInput = this.#handleTextInput.bind(this);
|
|
6490
|
+
#boundChange = this.#handleChange.bind(this);
|
|
6491
|
+
#boundAlphaInput = this.#handleAlphaInput.bind(this);
|
|
6492
|
+
#boundFillPickerInput = this.#handleFillPickerInput.bind(this);
|
|
6321
6493
|
constructor() {
|
|
6322
6494
|
super();
|
|
6323
6495
|
}
|
|
@@ -6354,9 +6526,105 @@ class FigInputColor extends HTMLElement {
|
|
|
6354
6526
|
}
|
|
6355
6527
|
|
|
6356
6528
|
connectedCallback() {
|
|
6529
|
+
if (this.#canReuseUI()) {
|
|
6530
|
+
this.#refreshUI();
|
|
6531
|
+
return;
|
|
6532
|
+
}
|
|
6357
6533
|
this.#buildUI();
|
|
6358
6534
|
}
|
|
6359
6535
|
|
|
6536
|
+
disconnectedCallback() {
|
|
6537
|
+
this.#teardownControlListeners();
|
|
6538
|
+
}
|
|
6539
|
+
|
|
6540
|
+
#canReuseUI() {
|
|
6541
|
+
const showText = this.getAttribute("text") !== "false";
|
|
6542
|
+
return showText
|
|
6543
|
+
? !!this.querySelector(":scope > .input-combo")
|
|
6544
|
+
: !!this.querySelector(":scope > fig-chit");
|
|
6545
|
+
}
|
|
6546
|
+
|
|
6547
|
+
#refreshUI() {
|
|
6548
|
+
this.#setValues(this.getAttribute("value"));
|
|
6549
|
+
this.#swatch = this.querySelector("fig-chit");
|
|
6550
|
+
this.#fillPicker = this.querySelector("fig-fill-picker");
|
|
6551
|
+
this.#textInput = this.querySelector("fig-input-text:not([type=number])");
|
|
6552
|
+
this.#alphaInput = this.querySelector("fig-input-number");
|
|
6553
|
+
if (this.#textInput) {
|
|
6554
|
+
this.#textInput.setAttribute(
|
|
6555
|
+
"value",
|
|
6556
|
+
this.hexOpaque.slice(1).toUpperCase(),
|
|
6557
|
+
);
|
|
6558
|
+
}
|
|
6559
|
+
if (this.#alphaInput) {
|
|
6560
|
+
this.#alphaInput.setAttribute("value", String(this.#alphaPercent));
|
|
6561
|
+
}
|
|
6562
|
+
if (this.#swatch) {
|
|
6563
|
+
this.#swatch.setAttribute("background", this.hexOpaque);
|
|
6564
|
+
this.#swatch.setAttribute("alpha", String(this.rgba.a));
|
|
6565
|
+
}
|
|
6566
|
+
this.#syncA11yAttributes();
|
|
6567
|
+
this.#bindControlListeners();
|
|
6568
|
+
}
|
|
6569
|
+
|
|
6570
|
+
#teardownControlListeners() {
|
|
6571
|
+
if (this.#swatch) {
|
|
6572
|
+
this.#swatch.removeEventListener(
|
|
6573
|
+
"pointerdown",
|
|
6574
|
+
this.#boundSwatchPointerDown,
|
|
6575
|
+
{ capture: true },
|
|
6576
|
+
);
|
|
6577
|
+
this.#swatch.removeEventListener("click", this.#boundSwatchClick, {
|
|
6578
|
+
capture: true,
|
|
6579
|
+
});
|
|
6580
|
+
const swatchInput = this.#swatch.querySelector('input[type="color"]');
|
|
6581
|
+
swatchInput?.removeEventListener("keydown", this.#boundSwatchKeyDown);
|
|
6582
|
+
this.#swatch.removeEventListener("input", this.#boundHandleInput);
|
|
6583
|
+
}
|
|
6584
|
+
this.#textInput?.removeEventListener("input", this.#boundTextInput);
|
|
6585
|
+
this.#textInput?.removeEventListener("change", this.#boundChange);
|
|
6586
|
+
this.#alphaInput?.removeEventListener("input", this.#boundAlphaInput);
|
|
6587
|
+
this.#alphaInput?.removeEventListener("change", this.#boundChange);
|
|
6588
|
+
this.#fillPicker?.removeEventListener("input", this.#boundFillPickerInput);
|
|
6589
|
+
this.#fillPicker?.removeEventListener("change", this.#boundChange);
|
|
6590
|
+
}
|
|
6591
|
+
|
|
6592
|
+
#bindControlListeners() {
|
|
6593
|
+
if (this.#swatch) {
|
|
6594
|
+
this.#swatch.disabled = this.hasAttribute("disabled");
|
|
6595
|
+
const swatchInput = this.#swatch.querySelector('input[type="color"]');
|
|
6596
|
+
if (this.#textInput || this.hasAttribute("swatch-disabled")) {
|
|
6597
|
+
swatchInput?.setAttribute("tabindex", "-1");
|
|
6598
|
+
}
|
|
6599
|
+
if (this.hasAttribute("swatch-disabled")) {
|
|
6600
|
+
swatchInput?.setAttribute("disabled", "");
|
|
6601
|
+
if (swatchInput) swatchInput.style.pointerEvents = "none";
|
|
6602
|
+
}
|
|
6603
|
+
this.#swatch.addEventListener(
|
|
6604
|
+
"pointerdown",
|
|
6605
|
+
this.#boundSwatchPointerDown,
|
|
6606
|
+
{ capture: true },
|
|
6607
|
+
);
|
|
6608
|
+
this.#swatch.addEventListener("click", this.#boundSwatchClick, {
|
|
6609
|
+
capture: true,
|
|
6610
|
+
});
|
|
6611
|
+
swatchInput?.addEventListener("keydown", this.#boundSwatchKeyDown);
|
|
6612
|
+
this.#swatch.addEventListener("input", this.#boundHandleInput);
|
|
6613
|
+
}
|
|
6614
|
+
if (this.#textInput) {
|
|
6615
|
+
this.#textInput.addEventListener("input", this.#boundTextInput);
|
|
6616
|
+
this.#textInput.addEventListener("change", this.#boundChange);
|
|
6617
|
+
}
|
|
6618
|
+
if (this.#alphaInput) {
|
|
6619
|
+
this.#alphaInput.addEventListener("input", this.#boundAlphaInput);
|
|
6620
|
+
this.#alphaInput.addEventListener("change", this.#boundChange);
|
|
6621
|
+
}
|
|
6622
|
+
if (this.#fillPicker) {
|
|
6623
|
+
this.#fillPicker.addEventListener("input", this.#boundFillPickerInput);
|
|
6624
|
+
this.#fillPicker.addEventListener("change", this.#boundChange);
|
|
6625
|
+
}
|
|
6626
|
+
}
|
|
6627
|
+
|
|
6360
6628
|
#buildUI() {
|
|
6361
6629
|
this.#setValues(this.getAttribute("value"));
|
|
6362
6630
|
|
|
@@ -6402,54 +6670,15 @@ class FigInputColor extends HTMLElement {
|
|
|
6402
6670
|
this.#alphaInput = this.querySelector("fig-input-number");
|
|
6403
6671
|
this.#syncA11yAttributes();
|
|
6404
6672
|
|
|
6405
|
-
// Setup swatch (native picker)
|
|
6406
|
-
if (this.#swatch) {
|
|
6407
|
-
this.#swatch.disabled = this.hasAttribute("disabled");
|
|
6408
|
-
const swatchInput = this.#swatch.querySelector('input[type="color"]');
|
|
6409
|
-
if (this.#textInput || this.hasAttribute("swatch-disabled")) {
|
|
6410
|
-
swatchInput?.setAttribute("tabindex", "-1");
|
|
6411
|
-
}
|
|
6412
|
-
if (this.hasAttribute("swatch-disabled")) {
|
|
6413
|
-
swatchInput?.setAttribute("disabled", "");
|
|
6414
|
-
if (swatchInput) swatchInput.style.pointerEvents = "none";
|
|
6415
|
-
}
|
|
6416
|
-
this.#swatch.addEventListener("pointerdown", this.#handleSwatchPointerDown.bind(this), {
|
|
6417
|
-
capture: true,
|
|
6418
|
-
});
|
|
6419
|
-
this.#swatch.addEventListener("click", this.#handleSwatchClick.bind(this), {
|
|
6420
|
-
capture: true,
|
|
6421
|
-
});
|
|
6422
|
-
swatchInput?.addEventListener("keydown", this.#handleSwatchKeyDown.bind(this));
|
|
6423
|
-
this.#swatch.addEventListener("input", this.#handleInput.bind(this));
|
|
6424
|
-
}
|
|
6425
|
-
|
|
6426
6673
|
if (this.#textInput) {
|
|
6427
6674
|
const hex = this.rgbAlphaToHex(this.rgba, 1);
|
|
6428
|
-
// Display without # prefix
|
|
6429
6675
|
this.#textInput.value = hex.slice(1).toUpperCase();
|
|
6430
6676
|
if (this.#swatch) {
|
|
6431
6677
|
this.#swatch.background = hex;
|
|
6432
6678
|
}
|
|
6433
|
-
this.#textInput.addEventListener(
|
|
6434
|
-
"input",
|
|
6435
|
-
this.#handleTextInput.bind(this),
|
|
6436
|
-
);
|
|
6437
|
-
this.#textInput.addEventListener(
|
|
6438
|
-
"change",
|
|
6439
|
-
this.#handleChange.bind(this),
|
|
6440
|
-
);
|
|
6441
6679
|
}
|
|
6442
6680
|
|
|
6443
|
-
|
|
6444
|
-
this.#alphaInput.addEventListener(
|
|
6445
|
-
"input",
|
|
6446
|
-
this.#handleAlphaInput.bind(this),
|
|
6447
|
-
);
|
|
6448
|
-
this.#alphaInput.addEventListener(
|
|
6449
|
-
"change",
|
|
6450
|
-
this.#handleChange.bind(this),
|
|
6451
|
-
);
|
|
6452
|
-
}
|
|
6681
|
+
this.#bindControlListeners();
|
|
6453
6682
|
}
|
|
6454
6683
|
|
|
6455
6684
|
#syncFillPicker() {
|
|
@@ -8001,6 +8230,7 @@ class FigInputPalette extends HTMLElement {
|
|
|
8001
8230
|
if (this.#renderRAF) cancelAnimationFrame(this.#renderRAF);
|
|
8002
8231
|
this.#renderRAF = requestAnimationFrame(() => {
|
|
8003
8232
|
this.#renderRAF = null;
|
|
8233
|
+
if (!this.isConnected) return;
|
|
8004
8234
|
this.#parseValue();
|
|
8005
8235
|
this.#render();
|
|
8006
8236
|
});
|
|
@@ -9536,6 +9766,24 @@ class FigComboInput extends HTMLElement {
|
|
|
9536
9766
|
this.setAttribute("value", val ?? "");
|
|
9537
9767
|
}
|
|
9538
9768
|
|
|
9769
|
+
#canReuseMarkup() {
|
|
9770
|
+
return !!this.querySelector(":scope > .input-combo");
|
|
9771
|
+
}
|
|
9772
|
+
|
|
9773
|
+
#refreshMarkup() {
|
|
9774
|
+
this.#input = this.querySelector("fig-input-text");
|
|
9775
|
+
this.#button = this.querySelector("fig-button");
|
|
9776
|
+
this.#dropdown = this.querySelector("fig-dropdown");
|
|
9777
|
+
if (this.#input) {
|
|
9778
|
+
this.#input.setAttribute("value", this.value);
|
|
9779
|
+
this.#input.setAttribute(
|
|
9780
|
+
"placeholder",
|
|
9781
|
+
this.getAttribute("placeholder") || "",
|
|
9782
|
+
);
|
|
9783
|
+
}
|
|
9784
|
+
this.#syncA11yAttributes();
|
|
9785
|
+
}
|
|
9786
|
+
|
|
9539
9787
|
connectedCallback() {
|
|
9540
9788
|
this.#customDropdown =
|
|
9541
9789
|
Array.from(this.children).find(
|
|
@@ -9546,8 +9794,13 @@ class FigComboInput extends HTMLElement {
|
|
|
9546
9794
|
this.#customDropdown.remove();
|
|
9547
9795
|
}
|
|
9548
9796
|
|
|
9549
|
-
this.#
|
|
9550
|
-
|
|
9797
|
+
if (this.#canReuseMarkup()) {
|
|
9798
|
+
this.#refreshMarkup();
|
|
9799
|
+
this.#setupListeners();
|
|
9800
|
+
} else {
|
|
9801
|
+
this.#render();
|
|
9802
|
+
this.#setupListeners();
|
|
9803
|
+
}
|
|
9551
9804
|
|
|
9552
9805
|
if (this.hasAttribute("disabled")) {
|
|
9553
9806
|
this.#applyDisabled(true);
|
|
@@ -9601,6 +9854,7 @@ class FigComboInput extends HTMLElement {
|
|
|
9601
9854
|
}
|
|
9602
9855
|
|
|
9603
9856
|
#setupListeners() {
|
|
9857
|
+
this.#teardownListeners();
|
|
9604
9858
|
this.#dropdown?.addEventListener("input", this.#boundHandleDropdownInput);
|
|
9605
9859
|
this.#input?.addEventListener("input", this.#boundHandleTextInput);
|
|
9606
9860
|
this.#input?.addEventListener("change", this.#boundHandleTextChange);
|
|
@@ -12251,8 +12505,11 @@ class Fig3DRotate extends HTMLElement {
|
|
|
12251
12505
|
#container = null;
|
|
12252
12506
|
#boundKeyDown = null;
|
|
12253
12507
|
#boundKeyUp = null;
|
|
12508
|
+
#boundContainerPointerDown = (e) => this.#startDrag(e);
|
|
12509
|
+
#eventAbort = null;
|
|
12254
12510
|
#fields = [];
|
|
12255
12511
|
#fieldInputs = {};
|
|
12512
|
+
#fieldInputHandlers = {};
|
|
12256
12513
|
|
|
12257
12514
|
static get observedAttributes() {
|
|
12258
12515
|
return [
|
|
@@ -12281,16 +12538,36 @@ class Fig3DRotate extends HTMLElement {
|
|
|
12281
12538
|
this.#parseFields(this.getAttribute("fields"));
|
|
12282
12539
|
const val = this.getAttribute("value");
|
|
12283
12540
|
if (val) this.#parseValue(val);
|
|
12284
|
-
this
|
|
12541
|
+
if (this.querySelector(".fig-3d-rotate-container")) {
|
|
12542
|
+
this.#reuseRenderedMarkup();
|
|
12543
|
+
} else {
|
|
12544
|
+
this.#render();
|
|
12545
|
+
}
|
|
12285
12546
|
this.#syncSelected(this.getAttribute("selected"));
|
|
12286
12547
|
this.#syncDragState();
|
|
12287
12548
|
}
|
|
12288
12549
|
|
|
12289
12550
|
disconnectedCallback() {
|
|
12290
12551
|
this.#isDragging = false;
|
|
12552
|
+
this.#teardownEvents();
|
|
12553
|
+
}
|
|
12554
|
+
|
|
12555
|
+
#reuseRenderedMarkup() {
|
|
12556
|
+
this.#container = this.querySelector(".fig-3d-rotate-container");
|
|
12557
|
+
this.#cube = this.querySelector(".fig-3d-rotate-cube");
|
|
12558
|
+
this.#wireFieldInputs();
|
|
12559
|
+
this.#updateCube();
|
|
12560
|
+
this.#setupEvents();
|
|
12561
|
+
}
|
|
12562
|
+
|
|
12563
|
+
#teardownEvents() {
|
|
12564
|
+
this.#eventAbort?.abort();
|
|
12565
|
+
this.#eventAbort = null;
|
|
12291
12566
|
if (this.#boundKeyDown) {
|
|
12292
12567
|
window.removeEventListener("keydown", this.#boundKeyDown);
|
|
12293
12568
|
window.removeEventListener("keyup", this.#boundKeyUp);
|
|
12569
|
+
this.#boundKeyDown = null;
|
|
12570
|
+
this.#boundKeyUp = null;
|
|
12294
12571
|
}
|
|
12295
12572
|
}
|
|
12296
12573
|
|
|
@@ -12444,12 +12721,19 @@ class Fig3DRotate extends HTMLElement {
|
|
|
12444
12721
|
</div>${fieldsHTML}`;
|
|
12445
12722
|
this.#container = this.querySelector(".fig-3d-rotate-container");
|
|
12446
12723
|
this.#cube = this.querySelector(".fig-3d-rotate-cube");
|
|
12724
|
+
this.#wireFieldInputs();
|
|
12725
|
+
this.#updateCube();
|
|
12726
|
+
this.#setupEvents();
|
|
12727
|
+
}
|
|
12728
|
+
|
|
12729
|
+
#wireFieldInputs() {
|
|
12447
12730
|
this.#fieldInputs = {};
|
|
12448
12731
|
for (const axis of this.#fields) {
|
|
12449
12732
|
const input = this.querySelector(`fig-input-number[name="${axis}"]`);
|
|
12450
|
-
if (input)
|
|
12451
|
-
|
|
12452
|
-
|
|
12733
|
+
if (!input) continue;
|
|
12734
|
+
this.#fieldInputs[axis] = input;
|
|
12735
|
+
if (!this.#fieldInputHandlers[axis]) {
|
|
12736
|
+
this.#fieldInputHandlers[axis] = (e) => {
|
|
12453
12737
|
e.stopPropagation();
|
|
12454
12738
|
const val = parseFloat(e.target.value);
|
|
12455
12739
|
if (isNaN(val)) return;
|
|
@@ -12459,12 +12743,13 @@ class Fig3DRotate extends HTMLElement {
|
|
|
12459
12743
|
this.#updateCube();
|
|
12460
12744
|
this.#emit(e.type);
|
|
12461
12745
|
};
|
|
12462
|
-
input.addEventListener("input", handleFieldValue);
|
|
12463
|
-
input.addEventListener("change", handleFieldValue);
|
|
12464
12746
|
}
|
|
12747
|
+
const handler = this.#fieldInputHandlers[axis];
|
|
12748
|
+
input.removeEventListener("input", handler);
|
|
12749
|
+
input.removeEventListener("change", handler);
|
|
12750
|
+
input.addEventListener("input", handler);
|
|
12751
|
+
input.addEventListener("change", handler);
|
|
12465
12752
|
}
|
|
12466
|
-
this.#updateCube();
|
|
12467
|
-
this.#setupEvents();
|
|
12468
12753
|
}
|
|
12469
12754
|
|
|
12470
12755
|
#syncFieldInputs() {
|
|
@@ -12505,7 +12790,12 @@ class Fig3DRotate extends HTMLElement {
|
|
|
12505
12790
|
}
|
|
12506
12791
|
|
|
12507
12792
|
#setupEvents() {
|
|
12508
|
-
this.#
|
|
12793
|
+
this.#teardownEvents();
|
|
12794
|
+
if (!this.#container) return;
|
|
12795
|
+
this.#eventAbort = new AbortController();
|
|
12796
|
+
this.#container.addEventListener("pointerdown", this.#boundContainerPointerDown, {
|
|
12797
|
+
signal: this.#eventAbort.signal,
|
|
12798
|
+
});
|
|
12509
12799
|
this.#boundKeyDown = (e) => {
|
|
12510
12800
|
if (e.key === "Shift") this.#isShiftHeld = true;
|
|
12511
12801
|
};
|
|
@@ -12597,12 +12887,28 @@ class FigOriginGrid extends HTMLElement {
|
|
|
12597
12887
|
return ["value", "precision", "aspect-ratio", "drag", "fields"];
|
|
12598
12888
|
}
|
|
12599
12889
|
|
|
12890
|
+
#reuseRenderedMarkup() {
|
|
12891
|
+
this.#grid = this.querySelector(".origin-grid");
|
|
12892
|
+
this.#cells = Array.from(this.querySelectorAll(".origin-grid-cell"));
|
|
12893
|
+
this.#handle = this.querySelector("fig-handle");
|
|
12894
|
+
this.#xInput = this.querySelector('fig-input-number[name="x"]');
|
|
12895
|
+
this.#yInput = this.querySelector('fig-input-number[name="y"]');
|
|
12896
|
+
this.#syncHandlePosition();
|
|
12897
|
+
this.#syncOverflowState();
|
|
12898
|
+
this.#syncValueInputs();
|
|
12899
|
+
this.#setupEvents();
|
|
12900
|
+
}
|
|
12901
|
+
|
|
12600
12902
|
connectedCallback() {
|
|
12601
12903
|
this.#precision = parseInt(this.getAttribute("precision") || "0");
|
|
12602
12904
|
figSyncCssVar(this, "--aspect-ratio", this.getAttribute("aspect-ratio"));
|
|
12603
12905
|
this.#applyIncomingValue(this.getAttribute("value"));
|
|
12604
12906
|
|
|
12605
|
-
this
|
|
12907
|
+
if (this.querySelector(".fig-origin-grid-surface")) {
|
|
12908
|
+
this.#reuseRenderedMarkup();
|
|
12909
|
+
} else {
|
|
12910
|
+
this.#render();
|
|
12911
|
+
}
|
|
12606
12912
|
this.#syncDragState();
|
|
12607
12913
|
this.#syncValueAttribute();
|
|
12608
12914
|
}
|
|
@@ -12610,6 +12916,7 @@ class FigOriginGrid extends HTMLElement {
|
|
|
12610
12916
|
disconnectedCallback() {
|
|
12611
12917
|
this.#isDragging = false;
|
|
12612
12918
|
this.#detachHandleDragListeners();
|
|
12919
|
+
this.#teardownEvents();
|
|
12613
12920
|
}
|
|
12614
12921
|
|
|
12615
12922
|
get value() {
|
|
@@ -13014,38 +13321,65 @@ class FigOriginGrid extends HTMLElement {
|
|
|
13014
13321
|
);
|
|
13015
13322
|
}
|
|
13016
13323
|
|
|
13324
|
+
#eventAbort = null;
|
|
13325
|
+
|
|
13326
|
+
#teardownEvents() {
|
|
13327
|
+
this.#eventAbort?.abort();
|
|
13328
|
+
this.#eventAbort = null;
|
|
13329
|
+
}
|
|
13330
|
+
|
|
13017
13331
|
#setupEvents() {
|
|
13332
|
+
this.#teardownEvents();
|
|
13018
13333
|
if (!this.#grid || !this.#handle) return;
|
|
13019
13334
|
|
|
13020
|
-
this.#
|
|
13021
|
-
|
|
13022
|
-
this.#setHoveredCell(hovered);
|
|
13335
|
+
this.#eventAbort = new AbortController();
|
|
13336
|
+
const { signal } = this.#eventAbort;
|
|
13023
13337
|
|
|
13024
|
-
|
|
13025
|
-
|
|
13026
|
-
|
|
13027
|
-
|
|
13338
|
+
this.#grid.addEventListener(
|
|
13339
|
+
"pointerdown",
|
|
13340
|
+
(e) => {
|
|
13341
|
+
const hovered = this.#gridCellFromClient(e.clientX, e.clientY);
|
|
13342
|
+
this.#setHoveredCell(hovered);
|
|
13028
13343
|
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
|
|
13344
|
+
if (this.#dragEnabled) {
|
|
13345
|
+
this.#startGridDrag(e);
|
|
13346
|
+
return;
|
|
13347
|
+
}
|
|
13033
13348
|
|
|
13034
|
-
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13349
|
+
const center = this.#cellCenterFromClient(e.clientX, e.clientY);
|
|
13350
|
+
this.#setFromPercent(center.x, center.y, "input");
|
|
13351
|
+
this.#emit("change");
|
|
13352
|
+
},
|
|
13353
|
+
{ signal },
|
|
13354
|
+
);
|
|
13039
13355
|
|
|
13040
|
-
this.#grid.addEventListener(
|
|
13041
|
-
|
|
13042
|
-
|
|
13356
|
+
this.#grid.addEventListener(
|
|
13357
|
+
"pointermove",
|
|
13358
|
+
(e) => {
|
|
13359
|
+
if (this.#isDragging) return;
|
|
13360
|
+
const hovered = this.#gridCellFromClient(e.clientX, e.clientY);
|
|
13361
|
+
this.#setHoveredCell(hovered);
|
|
13362
|
+
},
|
|
13363
|
+
{ signal },
|
|
13364
|
+
);
|
|
13043
13365
|
|
|
13044
|
-
this.#
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13366
|
+
this.#grid.addEventListener(
|
|
13367
|
+
"pointerleave",
|
|
13368
|
+
() => {
|
|
13369
|
+
this.#clearHoveredCells();
|
|
13370
|
+
},
|
|
13371
|
+
{ signal },
|
|
13372
|
+
);
|
|
13373
|
+
|
|
13374
|
+
this.#handle.addEventListener(
|
|
13375
|
+
"keydown",
|
|
13376
|
+
(e) => {
|
|
13377
|
+
if (!this.#moveHandleByKeyboard(e)) return;
|
|
13378
|
+
e.preventDefault();
|
|
13379
|
+
e.stopPropagation();
|
|
13380
|
+
},
|
|
13381
|
+
{ signal },
|
|
13382
|
+
);
|
|
13049
13383
|
|
|
13050
13384
|
const bindValueInput = (inputEl, axis) => {
|
|
13051
13385
|
if (!inputEl) return;
|
|
@@ -13058,11 +13392,15 @@ class FigOriginGrid extends HTMLElement {
|
|
|
13058
13392
|
this.#setFromPercent(this.#x, next, "input");
|
|
13059
13393
|
}
|
|
13060
13394
|
};
|
|
13061
|
-
inputEl.addEventListener("input", handle);
|
|
13062
|
-
inputEl.addEventListener("change", handle);
|
|
13063
|
-
inputEl.addEventListener(
|
|
13064
|
-
|
|
13065
|
-
|
|
13395
|
+
inputEl.addEventListener("input", handle, { signal });
|
|
13396
|
+
inputEl.addEventListener("change", handle, { signal });
|
|
13397
|
+
inputEl.addEventListener(
|
|
13398
|
+
"focusout",
|
|
13399
|
+
() => {
|
|
13400
|
+
this.#emit("change");
|
|
13401
|
+
},
|
|
13402
|
+
{ signal },
|
|
13403
|
+
);
|
|
13066
13404
|
};
|
|
13067
13405
|
|
|
13068
13406
|
bindValueInput(this.#xInput, "x");
|
|
@@ -13116,9 +13454,16 @@ class FigInputJoystick extends HTMLElement {
|
|
|
13116
13454
|
this.#boundYFocusOut = () => this.#handleFieldFocusOut();
|
|
13117
13455
|
}
|
|
13118
13456
|
|
|
13457
|
+
#reuseRenderedMarkup() {
|
|
13458
|
+
this.#setupListeners();
|
|
13459
|
+
this.#syncHandlePosition();
|
|
13460
|
+
this.#syncValueAttribute();
|
|
13461
|
+
this.#syncResetButton();
|
|
13462
|
+
this.#initialized = true;
|
|
13463
|
+
}
|
|
13464
|
+
|
|
13119
13465
|
connectedCallback() {
|
|
13120
|
-
|
|
13121
|
-
requestAnimationFrame(() => {
|
|
13466
|
+
figNextFrame(this, () => {
|
|
13122
13467
|
this.precision = this.getAttribute("precision") || 3;
|
|
13123
13468
|
this.precision = parseInt(this.precision);
|
|
13124
13469
|
this.transform = this.getAttribute("transform") || 1;
|
|
@@ -13129,6 +13474,11 @@ class FigInputJoystick extends HTMLElement {
|
|
|
13129
13474
|
this.setAttribute("value", "50% 50%");
|
|
13130
13475
|
}
|
|
13131
13476
|
|
|
13477
|
+
if (this.querySelector(".fig-input-joystick-plane")) {
|
|
13478
|
+
this.#reuseRenderedMarkup();
|
|
13479
|
+
return;
|
|
13480
|
+
}
|
|
13481
|
+
|
|
13132
13482
|
this.#render();
|
|
13133
13483
|
this.#setupListeners();
|
|
13134
13484
|
this.#syncHandlePosition();
|
|
@@ -14417,7 +14767,7 @@ class FigChooser extends HTMLElement {
|
|
|
14417
14767
|
this.#startObserver();
|
|
14418
14768
|
this.#startResizeObserver();
|
|
14419
14769
|
|
|
14420
|
-
|
|
14770
|
+
figNextFrame(this, () => {
|
|
14421
14771
|
this.#syncSelection();
|
|
14422
14772
|
this.#syncOverflow();
|
|
14423
14773
|
this.#scheduleInitialScrollSettle();
|