@rogieking/figui3 6.32.2 → 6.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/components.css +9 -2
- package/dist/components.css +1 -1
- package/dist/fig.css +1 -1
- package/dist/fig.js +80 -80
- package/fig.js +164 -2
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -12668,11 +12668,42 @@ class FigSwatch extends HTMLElement {
|
|
|
12668
12668
|
figDefineElement("fig-swatch", FigSwatch);
|
|
12669
12669
|
|
|
12670
12670
|
/* Media */
|
|
12671
|
+
const FIG_IMAGE_FORWARDED_EVENTS = ["load", "error"];
|
|
12672
|
+
const FIG_VIDEO_FORWARDED_EVENTS = [
|
|
12673
|
+
"loadstart",
|
|
12674
|
+
"progress",
|
|
12675
|
+
"suspend",
|
|
12676
|
+
"abort",
|
|
12677
|
+
"error",
|
|
12678
|
+
"emptied",
|
|
12679
|
+
"stalled",
|
|
12680
|
+
"loadedmetadata",
|
|
12681
|
+
"loadeddata",
|
|
12682
|
+
"canplay",
|
|
12683
|
+
"canplaythrough",
|
|
12684
|
+
"playing",
|
|
12685
|
+
"waiting",
|
|
12686
|
+
"seeking",
|
|
12687
|
+
"seeked",
|
|
12688
|
+
"durationchange",
|
|
12689
|
+
"timeupdate",
|
|
12690
|
+
"ratechange",
|
|
12691
|
+
"resize",
|
|
12692
|
+
"volumechange",
|
|
12693
|
+
];
|
|
12694
|
+
const FIG_MEDIA_FORWARDED_EVENTS = [
|
|
12695
|
+
...new Set([
|
|
12696
|
+
...FIG_IMAGE_FORWARDED_EVENTS,
|
|
12697
|
+
...FIG_VIDEO_FORWARDED_EVENTS,
|
|
12698
|
+
]),
|
|
12699
|
+
];
|
|
12700
|
+
|
|
12671
12701
|
/**
|
|
12672
12702
|
* @attr {string} src - Media source URL
|
|
12673
12703
|
* @attr {string} type - "image" (default) or "video" (for fig-media)
|
|
12674
12704
|
* @attr {string} alt - Alt text for the generated image (default "")
|
|
12675
12705
|
* @attr {boolean} upload - Show upload overlay (generates fig-input-file)
|
|
12706
|
+
* @attr {boolean} loading-indicator - Set to `false` to disable the generated image loading spinner
|
|
12676
12707
|
* @attr {string} label - Upload button label (default "Upload")
|
|
12677
12708
|
* @attr {string} size - small | medium | large | auto (token-sized square)
|
|
12678
12709
|
* @attr {string} aspect-ratio - CSS aspect-ratio value (default `4/3`)
|
|
@@ -12686,6 +12717,14 @@ figDefineElement("fig-swatch", FigSwatch);
|
|
|
12686
12717
|
* @attr {string} poster - Video poster image URL
|
|
12687
12718
|
* @attr {string} aria-label - Accessible label forwarded to generated video
|
|
12688
12719
|
* @attr {string} aria-labelledby - Accessible label reference forwarded to generated video
|
|
12720
|
+
* @fires load - Image loaded
|
|
12721
|
+
* @fires error - Image or video failed to load
|
|
12722
|
+
* @fires loadstart - Video loading started
|
|
12723
|
+
* @fires loadedmetadata - Video metadata loaded
|
|
12724
|
+
* @fires loadeddata - Video frame data loaded
|
|
12725
|
+
* @fires canplay - Video can begin playback
|
|
12726
|
+
* @fires canplaythrough - Video can likely play through
|
|
12727
|
+
* @fires waiting - Video playback is waiting for data
|
|
12689
12728
|
*
|
|
12690
12729
|
* When `controls` are shown and no video `src` is loaded, fig-media sets
|
|
12691
12730
|
* `disabled` on the associated `fig-media-controls` until media is available.
|
|
@@ -12707,6 +12746,11 @@ class FigMedia extends HTMLElement {
|
|
|
12707
12746
|
#boundHandleMediaPlay = this.#handleMediaPlay.bind(this);
|
|
12708
12747
|
#boundHandleMediaPause = this.#handleMediaPause.bind(this);
|
|
12709
12748
|
#boundHandleMediaEnded = this.#handleMediaEnded.bind(this);
|
|
12749
|
+
#boundForwardMediaEvent = this.#forwardMediaEvent.bind(this);
|
|
12750
|
+
#loadingSpinner = null;
|
|
12751
|
+
#loadingTimer = null;
|
|
12752
|
+
#loadingSource = null;
|
|
12753
|
+
#ariaBusyBeforeLoading = undefined;
|
|
12710
12754
|
#controlsEl = null;
|
|
12711
12755
|
#controlsWiredFor = null;
|
|
12712
12756
|
#controlsWiredControls = null;
|
|
@@ -12721,6 +12765,7 @@ class FigMedia extends HTMLElement {
|
|
|
12721
12765
|
"type",
|
|
12722
12766
|
"alt",
|
|
12723
12767
|
"upload",
|
|
12768
|
+
"loading-indicator",
|
|
12724
12769
|
"label",
|
|
12725
12770
|
"aspect-ratio",
|
|
12726
12771
|
"fit",
|
|
@@ -12812,6 +12857,7 @@ class FigMedia extends HTMLElement {
|
|
|
12812
12857
|
this.#ensureMediaElement();
|
|
12813
12858
|
this.#addMediaElementListeners();
|
|
12814
12859
|
this.#syncGeneratedMediaElement();
|
|
12860
|
+
this.#syncImageLoadingState();
|
|
12815
12861
|
this.#syncMediaAccessibility();
|
|
12816
12862
|
this.#syncCaption();
|
|
12817
12863
|
|
|
@@ -12826,6 +12872,7 @@ class FigMedia extends HTMLElement {
|
|
|
12826
12872
|
|
|
12827
12873
|
disconnectedCallback() {
|
|
12828
12874
|
this.#fileInput?.removeEventListener("change", this.#boundHandleFileInput);
|
|
12875
|
+
this.#finishImageLoading();
|
|
12829
12876
|
this.#removeMediaElementListeners();
|
|
12830
12877
|
this.#removeControls();
|
|
12831
12878
|
if (this.#blobUrl) {
|
|
@@ -12837,6 +12884,9 @@ class FigMedia extends HTMLElement {
|
|
|
12837
12884
|
|
|
12838
12885
|
#removeMediaElementListeners() {
|
|
12839
12886
|
if (!this.#mediaEl) return;
|
|
12887
|
+
FIG_MEDIA_FORWARDED_EVENTS.forEach((type) => {
|
|
12888
|
+
this.#mediaEl.removeEventListener(type, this.#boundForwardMediaEvent);
|
|
12889
|
+
});
|
|
12840
12890
|
if (this.#mediaEl.tagName === "VIDEO") {
|
|
12841
12891
|
this.#mediaEl.removeEventListener("play", this.#boundHandleMediaPlay);
|
|
12842
12892
|
this.#mediaEl.removeEventListener("pause", this.#boundHandleMediaPause);
|
|
@@ -12846,12 +12896,86 @@ class FigMedia extends HTMLElement {
|
|
|
12846
12896
|
|
|
12847
12897
|
#addMediaElementListeners() {
|
|
12848
12898
|
this.#removeMediaElementListeners();
|
|
12849
|
-
if (this.#mediaEl
|
|
12899
|
+
if (!this.#mediaEl) return;
|
|
12900
|
+
const forwardedEvents =
|
|
12901
|
+
this.#mediaEl.tagName === "VIDEO"
|
|
12902
|
+
? FIG_VIDEO_FORWARDED_EVENTS
|
|
12903
|
+
: FIG_IMAGE_FORWARDED_EVENTS;
|
|
12904
|
+
forwardedEvents.forEach((type) => {
|
|
12905
|
+
this.#mediaEl.addEventListener(type, this.#boundForwardMediaEvent);
|
|
12906
|
+
});
|
|
12907
|
+
if (this.#mediaEl.tagName !== "VIDEO") return;
|
|
12850
12908
|
this.#mediaEl.addEventListener("play", this.#boundHandleMediaPlay);
|
|
12851
12909
|
this.#mediaEl.addEventListener("pause", this.#boundHandleMediaPause);
|
|
12852
12910
|
this.#mediaEl.addEventListener("ended", this.#boundHandleMediaEnded);
|
|
12853
12911
|
}
|
|
12854
12912
|
|
|
12913
|
+
#usesDefaultImageLoadingIndicator() {
|
|
12914
|
+
return (
|
|
12915
|
+
this.mediaKind === "image" &&
|
|
12916
|
+
this.getAttribute("loading-indicator") !== "false" &&
|
|
12917
|
+
this.#previewEl?.hasAttribute("data-generated") &&
|
|
12918
|
+
this.#mediaEl?.hasAttribute("data-generated")
|
|
12919
|
+
);
|
|
12920
|
+
}
|
|
12921
|
+
|
|
12922
|
+
#syncImageLoadingState() {
|
|
12923
|
+
const src = this.#currentMediaSrc();
|
|
12924
|
+
if (!src || !this.#usesDefaultImageLoadingIndicator()) {
|
|
12925
|
+
this.#finishImageLoading();
|
|
12926
|
+
return;
|
|
12927
|
+
}
|
|
12928
|
+
if (
|
|
12929
|
+
this.#mediaEl?.tagName === "IMG" &&
|
|
12930
|
+
this.#mediaEl.complete &&
|
|
12931
|
+
this.#mediaEl.currentSrc
|
|
12932
|
+
) {
|
|
12933
|
+
this.#finishImageLoading();
|
|
12934
|
+
return;
|
|
12935
|
+
}
|
|
12936
|
+
if (this.#loadingSource === src) return;
|
|
12937
|
+
|
|
12938
|
+
this.#finishImageLoading();
|
|
12939
|
+
this.#loadingSource = src;
|
|
12940
|
+
this.#ariaBusyBeforeLoading = this.getAttribute("aria-busy");
|
|
12941
|
+
this.setAttribute("aria-busy", "true");
|
|
12942
|
+
this.#loadingTimer = setTimeout(() => {
|
|
12943
|
+
this.#loadingTimer = null;
|
|
12944
|
+
if (
|
|
12945
|
+
this.#loadingSource !== src ||
|
|
12946
|
+
!this.isConnected ||
|
|
12947
|
+
!this.#usesDefaultImageLoadingIndicator()
|
|
12948
|
+
) {
|
|
12949
|
+
return;
|
|
12950
|
+
}
|
|
12951
|
+
const spinner = document.createElement("fig-spinner");
|
|
12952
|
+
spinner.setAttribute("data-generated", "");
|
|
12953
|
+
spinner.setAttribute("data-loading-indicator", "");
|
|
12954
|
+
spinner.setAttribute("slot", "overlay");
|
|
12955
|
+
spinner.setAttribute("aria-hidden", "true");
|
|
12956
|
+
this.append(spinner);
|
|
12957
|
+
this.#loadingSpinner = spinner;
|
|
12958
|
+
}, 150);
|
|
12959
|
+
}
|
|
12960
|
+
|
|
12961
|
+
#finishImageLoading() {
|
|
12962
|
+
if (this.#loadingTimer !== null) {
|
|
12963
|
+
clearTimeout(this.#loadingTimer);
|
|
12964
|
+
this.#loadingTimer = null;
|
|
12965
|
+
}
|
|
12966
|
+
this.#loadingSpinner?.remove();
|
|
12967
|
+
this.#loadingSpinner = null;
|
|
12968
|
+
this.#loadingSource = null;
|
|
12969
|
+
if (this.#ariaBusyBeforeLoading !== undefined) {
|
|
12970
|
+
if (this.#ariaBusyBeforeLoading === null) {
|
|
12971
|
+
this.removeAttribute("aria-busy");
|
|
12972
|
+
} else {
|
|
12973
|
+
this.setAttribute("aria-busy", this.#ariaBusyBeforeLoading);
|
|
12974
|
+
}
|
|
12975
|
+
this.#ariaBusyBeforeLoading = undefined;
|
|
12976
|
+
}
|
|
12977
|
+
}
|
|
12978
|
+
|
|
12855
12979
|
#ensurePreviewElement() {
|
|
12856
12980
|
if (this.#previewEl?.isConnected) return;
|
|
12857
12981
|
const existing = this.querySelector(":scope > fig-preview");
|
|
@@ -12884,6 +13008,7 @@ class FigMedia extends HTMLElement {
|
|
|
12884
13008
|
if (this.#previewEl && userEl.parentElement !== this.#previewEl) {
|
|
12885
13009
|
this.#previewEl.append(userEl);
|
|
12886
13010
|
}
|
|
13011
|
+
this.#addMediaElementListeners();
|
|
12887
13012
|
this.#syncMediaAccessibility();
|
|
12888
13013
|
return;
|
|
12889
13014
|
}
|
|
@@ -12907,7 +13032,6 @@ class FigMedia extends HTMLElement {
|
|
|
12907
13032
|
video.preload = "auto";
|
|
12908
13033
|
this.#previewEl.append(video);
|
|
12909
13034
|
this.#mediaEl = video;
|
|
12910
|
-
this.#addMediaElementListeners();
|
|
12911
13035
|
const seekToFirstFrame = () => {
|
|
12912
13036
|
if (this.#mediaEl?.autoplay) return;
|
|
12913
13037
|
try {
|
|
@@ -12925,6 +13049,7 @@ class FigMedia extends HTMLElement {
|
|
|
12925
13049
|
this.#previewEl.append(img);
|
|
12926
13050
|
this.#mediaEl = img;
|
|
12927
13051
|
}
|
|
13052
|
+
this.#addMediaElementListeners();
|
|
12928
13053
|
}
|
|
12929
13054
|
|
|
12930
13055
|
#syncMediaAccessibility() {
|
|
@@ -13012,6 +13137,7 @@ class FigMedia extends HTMLElement {
|
|
|
13012
13137
|
}
|
|
13013
13138
|
if (this.#mediaEl.tagName === "IMG") {
|
|
13014
13139
|
this.#syncMediaAccessibility();
|
|
13140
|
+
this.#syncImageLoadingState();
|
|
13015
13141
|
return;
|
|
13016
13142
|
}
|
|
13017
13143
|
const poster = this.getAttribute("poster");
|
|
@@ -13029,6 +13155,7 @@ class FigMedia extends HTMLElement {
|
|
|
13029
13155
|
this.#syncMediaAccessibility();
|
|
13030
13156
|
this.#syncControlsVisibility();
|
|
13031
13157
|
this.#syncControlsDisabled();
|
|
13158
|
+
this.#syncImageLoadingState();
|
|
13032
13159
|
}
|
|
13033
13160
|
|
|
13034
13161
|
get mediaEl() {
|
|
@@ -13321,6 +13448,37 @@ class FigMedia extends HTMLElement {
|
|
|
13321
13448
|
);
|
|
13322
13449
|
}
|
|
13323
13450
|
|
|
13451
|
+
#forwardMediaEvent(event) {
|
|
13452
|
+
const media = this.#mediaEl;
|
|
13453
|
+
if (!media || event.currentTarget !== media) return;
|
|
13454
|
+
if (
|
|
13455
|
+
media.tagName === "IMG" &&
|
|
13456
|
+
(event.type === "load" || event.type === "error")
|
|
13457
|
+
) {
|
|
13458
|
+
this.#finishImageLoading();
|
|
13459
|
+
}
|
|
13460
|
+
const detail = {
|
|
13461
|
+
src: this.#currentMediaSrc(),
|
|
13462
|
+
media,
|
|
13463
|
+
originalEvent: event,
|
|
13464
|
+
};
|
|
13465
|
+
if (media.tagName === "VIDEO") {
|
|
13466
|
+
detail.currentTime = media.currentTime;
|
|
13467
|
+
detail.duration = media.duration;
|
|
13468
|
+
detail.readyState = media.readyState;
|
|
13469
|
+
detail.networkState = media.networkState;
|
|
13470
|
+
detail.error = media.error;
|
|
13471
|
+
}
|
|
13472
|
+
this.dispatchEvent(
|
|
13473
|
+
new CustomEvent(event.type, {
|
|
13474
|
+
bubbles: true,
|
|
13475
|
+
cancelable: false,
|
|
13476
|
+
composed: true,
|
|
13477
|
+
detail,
|
|
13478
|
+
}),
|
|
13479
|
+
);
|
|
13480
|
+
}
|
|
13481
|
+
|
|
13324
13482
|
#handleMediaPlay() {
|
|
13325
13483
|
this.#emitPlaybackEvent("play");
|
|
13326
13484
|
}
|
|
@@ -13390,6 +13548,10 @@ class FigMedia extends HTMLElement {
|
|
|
13390
13548
|
}
|
|
13391
13549
|
}
|
|
13392
13550
|
|
|
13551
|
+
if (name === "loading-indicator") {
|
|
13552
|
+
this.#syncImageLoadingState();
|
|
13553
|
+
}
|
|
13554
|
+
|
|
13393
13555
|
if (name === "aspect-ratio") {
|
|
13394
13556
|
if (newValue) {
|
|
13395
13557
|
this.style.setProperty("--fig-media-aspect-ratio", newValue);
|
package/package.json
CHANGED