@rogieking/figui3 8.9.30 → 8.9.32
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-lab/SKILL.md +5 -1
- package/.cursor/skills/fig-lab/reference.md +20 -0
- package/README.md +51 -7
- package/components.css +15 -0
- package/dist/components.css +1 -1
- package/dist/fig-lab.css +1 -1
- package/dist/fig-lab.js +2 -2
- package/dist/fig.css +1 -1
- package/dist/fig.js +5 -5
- package/fig-lab.css +537 -78
- package/fig-lab.js +1149 -12
- package/fig.js +104 -16
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -407,14 +407,19 @@ function figSyncOverflowState(host, scrollEl, axis = "x", threshold = 2) {
|
|
|
407
407
|
return scrollable;
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
-
function figScrollOverflowPage(
|
|
410
|
+
function figScrollOverflowPage(
|
|
411
|
+
scrollEl,
|
|
412
|
+
axis = "x",
|
|
413
|
+
direction = 1,
|
|
414
|
+
behavior = "smooth",
|
|
415
|
+
) {
|
|
411
416
|
if (!scrollEl) return;
|
|
412
417
|
const isHorizontal = axis === "x";
|
|
413
418
|
const pageSize = isHorizontal ? scrollEl.clientWidth : scrollEl.clientHeight;
|
|
414
419
|
const scrollAmount = pageSize * 0.8 * direction;
|
|
415
420
|
scrollEl.scrollBy({
|
|
416
421
|
[isHorizontal ? "left" : "top"]: scrollAmount,
|
|
417
|
-
behavior
|
|
422
|
+
behavior,
|
|
418
423
|
});
|
|
419
424
|
}
|
|
420
425
|
|
|
@@ -17687,6 +17692,8 @@ figDefineElement("fig-choice", FigChoice);
|
|
|
17687
17692
|
* @attr {number} columns - Number of columns when layout="grid" (default: 2)
|
|
17688
17693
|
* @attr {string} value - Selected choice value. Omit to select the first choice; `value=""` means none.
|
|
17689
17694
|
* @attr {boolean} disabled - Whether the chooser is disabled
|
|
17695
|
+
* @attr {boolean} auto-scroll - Whether selection changes automatically scroll into view (default: true)
|
|
17696
|
+
* @attr {"auto"|"smooth"} scroll-behavior - Scrolling animation behavior (default: "smooth")
|
|
17690
17697
|
*/
|
|
17691
17698
|
class FigChooser extends HTMLElement {
|
|
17692
17699
|
#selectedChoice = null;
|
|
@@ -17714,6 +17721,7 @@ class FigChooser extends HTMLElement {
|
|
|
17714
17721
|
"layout",
|
|
17715
17722
|
"overflow",
|
|
17716
17723
|
"loop",
|
|
17724
|
+
"auto-scroll",
|
|
17717
17725
|
];
|
|
17718
17726
|
}
|
|
17719
17727
|
|
|
@@ -17728,6 +17736,31 @@ class FigChooser extends HTMLElement {
|
|
|
17728
17736
|
return attr === null || attr !== "false";
|
|
17729
17737
|
}
|
|
17730
17738
|
|
|
17739
|
+
get autoScroll() {
|
|
17740
|
+
const attr = this.getAttribute("auto-scroll");
|
|
17741
|
+
return attr === null || attr !== "false";
|
|
17742
|
+
}
|
|
17743
|
+
|
|
17744
|
+
set autoScroll(value) {
|
|
17745
|
+
if (value === false || value === "false" || value === null) {
|
|
17746
|
+
this.setAttribute("auto-scroll", "false");
|
|
17747
|
+
} else {
|
|
17748
|
+
this.removeAttribute("auto-scroll");
|
|
17749
|
+
}
|
|
17750
|
+
}
|
|
17751
|
+
|
|
17752
|
+
get scrollBehavior() {
|
|
17753
|
+
return this.getAttribute("scroll-behavior") === "auto" ? "auto" : "smooth";
|
|
17754
|
+
}
|
|
17755
|
+
|
|
17756
|
+
set scrollBehavior(value) {
|
|
17757
|
+
if (value === "auto" || value === "smooth") {
|
|
17758
|
+
this.setAttribute("scroll-behavior", value);
|
|
17759
|
+
} else {
|
|
17760
|
+
this.removeAttribute("scroll-behavior");
|
|
17761
|
+
}
|
|
17762
|
+
}
|
|
17763
|
+
|
|
17731
17764
|
get #choiceSelector() {
|
|
17732
17765
|
return this.getAttribute("choice-element") || "fig-choice";
|
|
17733
17766
|
}
|
|
@@ -17767,7 +17800,7 @@ class FigChooser extends HTMLElement {
|
|
|
17767
17800
|
if (this.getAttribute("value") !== val) {
|
|
17768
17801
|
this.setAttribute("value", val);
|
|
17769
17802
|
}
|
|
17770
|
-
this.#scrollToChoice(element);
|
|
17803
|
+
if (this.autoScroll) this.#scrollToChoice(element);
|
|
17771
17804
|
}
|
|
17772
17805
|
|
|
17773
17806
|
get value() {
|
|
@@ -17782,6 +17815,11 @@ class FigChooser extends HTMLElement {
|
|
|
17782
17815
|
this.setAttribute("value", String(val));
|
|
17783
17816
|
}
|
|
17784
17817
|
|
|
17818
|
+
scrollSelectionIntoView(options = {}) {
|
|
17819
|
+
if (!this.#selectedChoice) return;
|
|
17820
|
+
this.#scrollToChoice(this.#selectedChoice, options);
|
|
17821
|
+
}
|
|
17822
|
+
|
|
17785
17823
|
connectedCallback() {
|
|
17786
17824
|
this.setAttribute("role", "listbox");
|
|
17787
17825
|
if (this.shadowRoot) this.shadowRoot.replaceChildren();
|
|
@@ -17805,9 +17843,9 @@ class FigChooser extends HTMLElement {
|
|
|
17805
17843
|
|
|
17806
17844
|
#scheduleInitialScrollSettle() {
|
|
17807
17845
|
const resettle = () => {
|
|
17808
|
-
if (!this.isConnected) return;
|
|
17846
|
+
if (!this.isConnected || !this.autoScroll) return;
|
|
17809
17847
|
if (this.#selectedChoice) {
|
|
17810
|
-
this.#scrollToChoice(this.#selectedChoice
|
|
17848
|
+
this.#scrollToChoice(this.#selectedChoice);
|
|
17811
17849
|
}
|
|
17812
17850
|
};
|
|
17813
17851
|
const wireImages = () => {
|
|
@@ -17883,6 +17921,9 @@ class FigChooser extends HTMLElement {
|
|
|
17883
17921
|
}
|
|
17884
17922
|
this.#resettleSelectedChoice();
|
|
17885
17923
|
}
|
|
17924
|
+
if (name === "auto-scroll" && this.autoScroll) {
|
|
17925
|
+
this.#resettleSelectedChoice();
|
|
17926
|
+
}
|
|
17886
17927
|
}
|
|
17887
17928
|
|
|
17888
17929
|
#syncSelection() {
|
|
@@ -18026,7 +18067,7 @@ class FigChooser extends HTMLElement {
|
|
|
18026
18067
|
|
|
18027
18068
|
if (nextIndex !== currentIndex && choices[nextIndex]) {
|
|
18028
18069
|
this.selectedChoice = choices[nextIndex];
|
|
18029
|
-
choices[nextIndex].focus();
|
|
18070
|
+
choices[nextIndex].focus({ preventScroll: !this.autoScroll });
|
|
18030
18071
|
this.#emitEvents();
|
|
18031
18072
|
}
|
|
18032
18073
|
}
|
|
@@ -18236,16 +18277,25 @@ class FigChooser extends HTMLElement {
|
|
|
18236
18277
|
|
|
18237
18278
|
#scrollByPage(direction) {
|
|
18238
18279
|
const isHorizontal = this.getAttribute("layout") === "horizontal";
|
|
18239
|
-
figScrollOverflowPage(this, isHorizontal ? "x" : "y", direction);
|
|
18280
|
+
figScrollOverflowPage(this, isHorizontal ? "x" : "y", direction, "auto");
|
|
18240
18281
|
}
|
|
18241
18282
|
|
|
18242
18283
|
#resettleSelectedChoice() {
|
|
18243
|
-
if (!this.#selectedChoice) return;
|
|
18244
|
-
this.#scrollToChoice(this.#selectedChoice
|
|
18284
|
+
if (!this.autoScroll || !this.#selectedChoice) return;
|
|
18285
|
+
this.#scrollToChoice(this.#selectedChoice);
|
|
18245
18286
|
}
|
|
18246
18287
|
|
|
18247
|
-
#scrollToChoice(el,
|
|
18288
|
+
#scrollToChoice(el, options = {}) {
|
|
18248
18289
|
if (!el) return;
|
|
18290
|
+
const scrollOptions =
|
|
18291
|
+
typeof options === "object" && options !== null ? options : {};
|
|
18292
|
+
const behavior =
|
|
18293
|
+
scrollOptions.behavior === "smooth" ||
|
|
18294
|
+
scrollOptions.behavior === "instant"
|
|
18295
|
+
? scrollOptions.behavior
|
|
18296
|
+
: "auto";
|
|
18297
|
+
const block = scrollOptions.block || "center";
|
|
18298
|
+
const inline = scrollOptions.inline || "center";
|
|
18249
18299
|
requestAnimationFrame(() => {
|
|
18250
18300
|
if (!el.isConnected) return;
|
|
18251
18301
|
const overflowY = this.scrollHeight > this.clientHeight;
|
|
@@ -18260,9 +18310,13 @@ class FigChooser extends HTMLElement {
|
|
|
18260
18310
|
if (overflowY) {
|
|
18261
18311
|
const choiceTop = choiceRect.top - hostRect.top + this.scrollTop;
|
|
18262
18312
|
const maxScroll = this.scrollHeight - this.clientHeight;
|
|
18263
|
-
options.top =
|
|
18264
|
-
|
|
18265
|
-
|
|
18313
|
+
options.top = this.#alignedScrollPosition(
|
|
18314
|
+
choiceTop,
|
|
18315
|
+
choiceRect.height,
|
|
18316
|
+
this.clientHeight,
|
|
18317
|
+
this.scrollTop,
|
|
18318
|
+
maxScroll,
|
|
18319
|
+
block,
|
|
18266
18320
|
);
|
|
18267
18321
|
shouldScroll = true;
|
|
18268
18322
|
}
|
|
@@ -18270,9 +18324,13 @@ class FigChooser extends HTMLElement {
|
|
|
18270
18324
|
if (overflowX) {
|
|
18271
18325
|
const choiceLeft = choiceRect.left - hostRect.left + this.scrollLeft;
|
|
18272
18326
|
const maxScroll = this.scrollWidth - this.clientWidth;
|
|
18273
|
-
options.left =
|
|
18274
|
-
|
|
18275
|
-
|
|
18327
|
+
options.left = this.#alignedScrollPosition(
|
|
18328
|
+
choiceLeft,
|
|
18329
|
+
choiceRect.width,
|
|
18330
|
+
this.clientWidth,
|
|
18331
|
+
this.scrollLeft,
|
|
18332
|
+
maxScroll,
|
|
18333
|
+
inline,
|
|
18276
18334
|
);
|
|
18277
18335
|
shouldScroll = true;
|
|
18278
18336
|
}
|
|
@@ -18284,6 +18342,36 @@ class FigChooser extends HTMLElement {
|
|
|
18284
18342
|
});
|
|
18285
18343
|
}
|
|
18286
18344
|
|
|
18345
|
+
#alignedScrollPosition(
|
|
18346
|
+
elementStart,
|
|
18347
|
+
elementSize,
|
|
18348
|
+
viewportSize,
|
|
18349
|
+
currentScroll,
|
|
18350
|
+
maxScroll,
|
|
18351
|
+
alignment,
|
|
18352
|
+
) {
|
|
18353
|
+
let nextScroll;
|
|
18354
|
+
if (alignment === "start") {
|
|
18355
|
+
nextScroll = elementStart;
|
|
18356
|
+
} else if (alignment === "end") {
|
|
18357
|
+
nextScroll = elementStart + elementSize - viewportSize;
|
|
18358
|
+
} else if (alignment === "nearest") {
|
|
18359
|
+
const viewportStart = currentScroll;
|
|
18360
|
+
const viewportEnd = currentScroll + viewportSize;
|
|
18361
|
+
const elementEnd = elementStart + elementSize;
|
|
18362
|
+
if (elementStart >= viewportStart && elementEnd <= viewportEnd) {
|
|
18363
|
+
nextScroll = currentScroll;
|
|
18364
|
+
} else if (elementStart < viewportStart) {
|
|
18365
|
+
nextScroll = elementStart;
|
|
18366
|
+
} else {
|
|
18367
|
+
nextScroll = elementEnd - viewportSize;
|
|
18368
|
+
}
|
|
18369
|
+
} else {
|
|
18370
|
+
nextScroll = elementStart + elementSize / 2 - viewportSize / 2;
|
|
18371
|
+
}
|
|
18372
|
+
return Math.max(0, Math.min(nextScroll, maxScroll));
|
|
18373
|
+
}
|
|
18374
|
+
|
|
18287
18375
|
#startObserver() {
|
|
18288
18376
|
this.#mutationObserver?.disconnect();
|
|
18289
18377
|
this.#mutationObserver = new MutationObserver(() => {
|
package/package.json
CHANGED