coverflow-carousel 0.2.0-dev.2 → 0.2.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 CHANGED
@@ -77,6 +77,12 @@ initCoverflowCarousels({
77
77
  // - CSSStyleSheet (constructable stylesheet)
78
78
  // - string (e.g. imported via ?raw)
79
79
  // stylesheet: coverflowCarouselCssText,
80
+ //
81
+ // Optional overrides (applied on top of the base stylesheet):
82
+ // styleOverrides: `
83
+ // .cfc { --cfc-card-ar-num: 1.6; }
84
+ // .cfc__arrow { background: Black; }
85
+ // `,
80
86
  });
81
87
  ```
82
88
 
@@ -84,11 +90,13 @@ initCoverflowCarousels({
84
90
  ```javascript
85
91
  import { registerCoverflowCarouselElement, initCoverflowCarousels } from 'coverflow-carousel';
86
92
  import MyCfcCss from './assets/cfc.custom.css?raw';
93
+ import MyCfcOverrides from './assets/cfc.overrides.css?raw';
87
94
 
88
95
  registerCoverflowCarouselElement();
89
96
 
90
97
  initCoverflowCarousels({
91
98
  stylesheet: MyCfcCss,
99
+ styleOverrides: MyCfcOverrides,
92
100
  });
93
101
  ```
94
102
 
@@ -107,6 +115,13 @@ initCoverflowCarousels({
107
115
  });
108
116
  ```
109
117
 
118
+ <sub>CSS: override CSS variables (recommended for simple tweaks)</sub>
119
+ ```css
120
+ coverflow-carousel {
121
+ --cfc-card-ar-num: 1.6;
122
+ }
123
+ ```
124
+
110
125
  <sub>JS: manual control (prev/next/goTo/refresh)</sub>
111
126
  ```javascript
112
127
  import { registerCoverflowCarouselElement } from 'coverflow-carousel';
@@ -126,36 +141,37 @@ el?.refresh();
126
141
  <br>
127
142
 
128
143
  # Options
129
- | Option (attribute) | Type | Default | Description |
130
- |:--------------------:|:-----------------------:|:------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------|
131
- | `start-index` | `number` | `0` | Start index if `index` is not set. |
132
- | `index` | `number` | | Current index. If you update it externally, the carousel will animate to it. The component also reflects the current value back into `index`. |
133
- | `show-dots` | `boolean` | `false` | Shows pagination dots (decorative, non-interactive). |
134
- | `show-arrows` | `boolean` | `false` | Shows Prev/Next arrows. |
135
- | `announce-changes` | `boolean` | `true` | Enables slide-change announcements via live-region (a11y). |
144
+ | Option (attribute) | Type | Default | Description |
145
+ |:------------------:|:---------:|:-------:|:-----------------------------------------------------------------------------------------------------------------------------------------------|
146
+ | `start-index` | `number` | `0` | Start index if `index` is not set. |
147
+ | `index` | `number` | | Current index. If you update it externally, the carousel will animate to it. The component also reflects the current value back into `index`. |
148
+ | `show-dots` | `boolean` | `false` | Shows pagination dots (decorative, non-interactive). |
149
+ | `show-arrows` | `boolean` | `false` | Shows Prev/Next arrows. |
150
+ | `announce-changes` | `boolean` | `true` | Enables slide-change announcements via live-region (a11y). |
136
151
 
137
152
  <br>
138
153
 
139
154
  # Events
140
- | Event | Detail | Description |
141
- |-------------------|------------------------------|--------------------------------------------------------------------------------------------------|
142
- | `coverflow-carousel:ready` | `{ index: number, length: number }` | Fired after the first `refresh()` (when slides are built and layout/a11y is applied). |
143
- | `coverflow-carousel:change` | `{ index: number, length: number }` | Fired on active slide change via `prev/next/goTo` (and when `index` is updated externally). |
144
- | `coverflow-carousel:scratch-complete` | `{ index: number, length: number, percent: number }` | Fired when a descendant `<scratch-reveal>` dispatches `complete` for a slide. |
155
+ | Event | Detail | Description |
156
+ |---------------------------------------|------------------------------------------------------|---------------------------------------------------------------------------------------------|
157
+ | `coverflow-carousel:ready` | `{ index: number, length: number }` | Fired after the first `refresh()` (when slides are built and layout/a11y is applied). |
158
+ | `coverflow-carousel:change` | `{ index: number, length: number }` | Fired on active slide change via `prev/next/goTo` (and when `index` is updated externally). |
159
+ | `coverflow-carousel:scratch-complete` | `{ index: number, length: number, percent: number }` | Fired when a descendant `<scratch-reveal>` dispatches `complete` for a slide. |
145
160
 
146
161
  <br>
147
162
 
148
163
  # API Methods
149
- | Method | Description |
150
- |-------------------|--------------------------------------------------------------------------------------------------|
151
- | `initCoverflowCarousels({ selector?, onReady?, onChange?, onScratchComplete?, stylesheet? }): HTMLElement[]` | Finds elements by `selector` (default: `coverflow-carousel`), optionally subscribes to `ready/change/scratch-complete` events, and optionally applies styles to each element (`stylesheet?: CSSStyleSheet \| string \| null`). |
152
- | `prev(): void` | Go to the previous slide (circular). |
153
- | `next(): void` | Go to the next slide (circular). |
154
- | `goTo(index: number): void` | Go to the given index (circular normalization). While animating, repeated transitions are ignored. |
155
- | `refresh(): void` | Rebuilds cards from current `children` (useful after dynamic changes) and dispatches `coverflow-carousel:ready`. |
156
- | `destroy(): void` | Removes event handlers and cancels animation-related timers. |
157
- | `adoptStylesheet(sheet: CSSStyleSheet): void` | Applies a stylesheet via `adoptedStyleSheets` (when supported). |
158
- | `adoptStyles(styles: CSSStyleSheet \| string \| null): void` | Applies styles: string via `adoptedStyleSheets` (when possible) or `<style>` fallback in the shadow root; `null` restores the package default styles. |
164
+ | Method | Description |
165
+ |-------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
166
+ | `initCoverflowCarousels({ selector?, onReady?, onChange?, onScratchComplete?, stylesheet?, styleOverrides? }): HTMLElement[]` | Finds elements by `selector` (default: `coverflow-carousel`), optionally subscribes to `ready/change/scratch-complete` events, and optionally applies styles to each element (`stylesheet?: CSSStyleSheet \| string \| null`, `styleOverrides?: CSSStyleSheet \| string \| null`). |
167
+ | `prev(): void` | Go to the previous slide (circular). |
168
+ | `next(): void` | Go to the next slide (circular). |
169
+ | `goTo(index: number): void` | Go to the given index (circular normalization). While animating, repeated transitions are ignored. |
170
+ | `refresh(): void` | Rebuilds cards from current `children` (useful after dynamic changes) and dispatches `coverflow-carousel:ready`. |
171
+ | `destroy(): void` | Removes event handlers and cancels animation-related timers. |
172
+ | `adoptStylesheet(sheet: CSSStyleSheet): void` | Applies a stylesheet via `adoptedStyleSheets` (when supported). |
173
+ | `adoptStyles(styles: CSSStyleSheet \| string \| null): void` | Applies styles: string via `adoptedStyleSheets` (when possible) or `<style>` fallback in the shadow root; `null` restores the package default styles. |
174
+ | `adoptStyleOverrides(styles: CSSStyleSheet \| string \| null): void` | Applies an additional "overlay" stylesheet on top of the current base styles (useful for small tweaks like CSS variables). |
159
175
 
160
176
  <br>
161
177
 
@@ -1 +1 @@
1
- :host{width:100%;height:100%;display:block;overflow:hidden;container-type:inline-size}.cfc{--cfc-card-ar-num:1.25;--cfc-card-w:clamp(160px,100vw - 120px,380px);--cfc-card-ar:1/var(--cfc-card-ar-num);--cfc-step-x:min(22vw,250px);--cfc-step-z:calc(var(--cfc-card-w)*.5);--cfc-scale-step:.1;--cfc-transition-ms:.55s;--cfc-easing:cubic-bezier(.785,.135,.15,.86);--cfc-arrow-size:50px;--cfc-park-x:0px;--cfc-park-z:calc(var(--cfc-step-z)*-6);--cfc-park-scale:.1;perspective:1000px;width:min(900px,100%);height:100%;margin:auto;position:relative}.cfc__track{width:100%;height:calc(var(--cfc-card-w)*var(--cfc-card-ar-num));transform-style:preserve-3d;position:relative}.cfc__card{--cfc-delta:0;--cfc-abs:0;--cfc-scale:clamp(.1,calc(1 - (var(--cfc-abs)*var(--cfc-scale-step))),1);--cfc-x:calc(var(--cfc-step-x)*var(--cfc-delta));--cfc-z:calc(var(--cfc-step-z)*-1*var(--cfc-abs));--cfc-zIndex:calc(100 - var(--cfc-abs));--cfc-scale-effective:var(--cfc-scale);--cfc-x-effective:var(--cfc-x);--cfc-z-effective:var(--cfc-z);pointer-events:auto;width:var(--cfc-card-w);aspect-ratio:var(--cfc-card-ar);z-index:var(--cfc-zIndex);transform-style:preserve-3d;transform:translate(-50%,-50%)translate3d(var(--cfc-x-effective),0px,var(--cfc-z-effective))scale(var(--cfc-scale-effective));transition:transform var(--cfc-transition-ms)var(--cfc-easing);position:absolute;inset:50% 0 0 50%;overflow:hidden}.cfc__card[aria-hidden=false]{will-change:transform}.cfc__card[aria-hidden=true]{--cfc-x-effective:var(--cfc-park-x);--cfc-z-effective:var(--cfc-park-z);--cfc-scale-effective:var(--cfc-park-scale);pointer-events:none}.cfc__card[data-active=true]{--cfc-scale-effective:1}.cfc__card ::slotted(img),.cfc__card img{object-fit:cover;object-position:center;width:100%;height:100%;display:block}.cfc__arrow{top:calc(50% - var(--cfc-arrow-size));width:var(--cfc-arrow-size);height:var(--cfc-arrow-size);cursor:pointer;z-index:50;background:#dc143c;border:none;transition:background .25s;position:absolute}.cfc__arrow:hover{background:#d3d3d3}.cfc__arrow--left{left:20px}.cfc__arrow--right{right:20px}.cfc__dots{justify-content:center;align-items:center;gap:10px;height:50px;display:flex}.cfc__dot{cursor:default;background:#d3d3d3;border-radius:50%;width:10px;height:10px;transition:transform .25s,background .25s}.cfc__dot[data-active=true]{background:#dc143c;transform:scale(1.2)}.cfc__sr{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}
1
+ :host{--cfc-card-ar-num:1.25;--cfc-card-w:clamp(160px,100vw - 120px,380px);--cfc-card-ar:1/var(--cfc-card-ar-num);--cfc-step-x:min(22vw,250px);--cfc-step-z:calc(var(--cfc-card-w)*.5);--cfc-scale-step:.1;--cfc-transition-ms:.55s;--cfc-easing:cubic-bezier(.785,.135,.15,.86);--cfc-arrow-size:50px;--cfc-park-x:0px;--cfc-park-z:calc(var(--cfc-step-z)*-6);--cfc-park-scale:.1;width:100%;height:100%;display:block;overflow:hidden;container-type:inline-size}.cfc{perspective:1000px;width:min(900px,100%);height:100%;margin:auto;position:relative}.cfc__track{width:100%;height:calc(var(--cfc-card-w)*var(--cfc-card-ar-num));transform-style:preserve-3d;position:relative}.cfc__card{--cfc-delta:0;--cfc-abs:0;--cfc-scale:clamp(.1,calc(1 - (var(--cfc-abs)*var(--cfc-scale-step))),1);--cfc-x:calc(var(--cfc-step-x)*var(--cfc-delta));--cfc-z:calc(var(--cfc-step-z)*-1*var(--cfc-abs));--cfc-zIndex:calc(100 - var(--cfc-abs));--cfc-scale-effective:var(--cfc-scale);--cfc-x-effective:var(--cfc-x);--cfc-z-effective:var(--cfc-z);pointer-events:auto;width:var(--cfc-card-w);aspect-ratio:var(--cfc-card-ar);z-index:var(--cfc-zIndex);transform-style:preserve-3d;transform:translate(-50%,-50%)translate3d(var(--cfc-x-effective),0px,var(--cfc-z-effective))scale(var(--cfc-scale-effective));transition:transform var(--cfc-transition-ms)var(--cfc-easing);position:absolute;inset:50% 0 0 50%;overflow:hidden}.cfc__card[aria-hidden=false]{will-change:transform}.cfc__card[aria-hidden=true]{--cfc-x-effective:var(--cfc-park-x);--cfc-z-effective:var(--cfc-park-z);--cfc-scale-effective:var(--cfc-park-scale);pointer-events:none}.cfc__card[data-active=true]{--cfc-scale-effective:1}.cfc__card ::slotted(img),.cfc__card img{object-fit:cover;object-position:center;width:100%;height:100%;display:block}.cfc__arrow{top:calc(50% - var(--cfc-arrow-size));width:var(--cfc-arrow-size);height:var(--cfc-arrow-size);cursor:pointer;z-index:50;background:#dc143c;border:none;transition:background .25s;position:absolute}.cfc__arrow:hover{background:#d3d3d3}.cfc__arrow--left{left:20px}.cfc__arrow--right{right:20px}.cfc__dots{justify-content:center;align-items:center;gap:10px;height:50px;display:flex}.cfc__dot{cursor:default;background:#d3d3d3;border-radius:50%;width:10px;height:10px;transition:transform .25s,background .25s}.cfc__dot[data-active=true]{background:#dc143c;transform:scale(1.2)}.cfc__sr{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}
@@ -10,7 +10,10 @@ export declare class CoverflowCarouselElement extends HTMLElement {
10
10
  private prevBtn;
11
11
  private nextBtn;
12
12
  private liveRegion;
13
- private styleEl;
13
+ private baseStyles;
14
+ private overrideStyles;
15
+ private baseStyleEl;
16
+ private overrideStyleEl;
14
17
  private cards;
15
18
  private dots;
16
19
  private currentIndex;
@@ -36,6 +39,7 @@ export declare class CoverflowCarouselElement extends HTMLElement {
36
39
  destroy(): void;
37
40
  adoptStylesheet(sheet: CSSStyleSheet): void;
38
41
  adoptStyles(styles: StylesInput): void;
42
+ adoptStyleOverrides(styles: StylesInput): void;
39
43
  private readAttributes;
40
44
  private render;
41
45
  private bindEvents;
@@ -54,5 +58,8 @@ export declare class CoverflowCarouselElement extends HTMLElement {
54
58
  private dispatchReady;
55
59
  private announce;
56
60
  private reflectIndexAttr;
57
- private applyStyles;
61
+ private setBaseStyles;
62
+ private setOverrideStyles;
63
+ private applyAllStyles;
64
+ private applyAllStylesFallback;
58
65
  }
package/dist/index.cjs.js CHANGED
@@ -4,9 +4,7 @@
4
4
  height: 100%;
5
5
  container-type: inline-size;
6
6
  overflow: hidden;
7
- }
8
7
 
9
- .cfc {
10
8
  /* Layout */
11
9
  --cfc-card-ar-num: 1.25;
12
10
  --cfc-card-w: clamp(160px, 100vw - 120px, 380px);
@@ -30,7 +28,9 @@
30
28
  --cfc-park-x: 0px;
31
29
  --cfc-park-z: calc(var(--cfc-step-z) * -6);
32
30
  --cfc-park-scale: 0.1;
31
+ }
33
32
 
33
+ .cfc {
34
34
  margin: auto;
35
35
  width: min(900px, 100%);
36
36
  height: 100%;
@@ -164,4 +164,4 @@
164
164
  white-space: nowrap;
165
165
  border: 0;
166
166
  }
167
- `,A=x;function v(a){return"adoptedStyleSheets"in a}function S(a){try{const t=new CSSStyleSheet;return t.replaceSync(a),t}catch{return null}}const I=S(x),_=x;function b(a){return a.split(",").map(t=>t.trim()).filter(Boolean)}function g(a,t){const n=a.trim();if(!n)return t;if(n.endsWith("ms")){const e=Number(n.slice(0,-2).trim());return Number.isFinite(e)?e:t}if(n.endsWith("s")){const e=Number(n.slice(0,-1).trim());return Number.isFinite(e)?e*1e3:t}const s=Number(n);return Number.isFinite(s)?s:t}function C(a,t){const n=b(a.transitionProperty),s=b(a.transitionDuration),e=b(a.transitionDelay);if(!n.length)return 0;const r=(m=>{const h=n.indexOf(m);if(h>=0)return h;const E=n.indexOf("all");return E>=0?E:-1})(t);if(r<0)return 0;const c=s[Math.min(r,s.length-1)]??"0s",o=e[Math.min(r,e.length-1)]??"0s",l=g(c,0),y=g(o,0);return Math.max(0,l+y)}function k(){return window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches??!1}function u(a,t,n){if(!a.hasAttribute(t))return n;const s=a.getAttribute(t);return s==null||s===""?!0:s!=="false"}function L(a,t,n){const s=a.getAttribute(t);if(s==null)return n;const e=Number(s.trim());return Number.isFinite(e)?Math.trunc(e):n}function w(a,t){const n=a.getAttribute(t);if(n==null)return null;const s=n.trim();return s||null}function f(a,t){return t<=0?0:(a%t+t)%t}function T(a,t,n){const s=t-a,e=n/2;return s>e?s-n:s<-e?s+n:s}const p=1;let D=0;class d extends HTMLElement{static defaultStylesheet=I;static observedAttributes=["start-index","index","show-dots","show-arrows","announce-changes"];shadow=this.attachShadow({mode:"open"});instanceId=`cfc-${++D}`;rootEl;trackEl;dotsEl;prevBtn;nextBtn;liveRegion;styleEl=null;cards=[];dots=[];currentIndex=0;isAnimating=!1;hasAppliedInitialLayout=!1;lastLayoutIndex=null;lastVisibleSet=new Set;pendingAnimToken=0;animFallbackTimerId=null;cleanup=[];lightDomObserverOptions={childList:!0,attributes:!0,subtree:!0};lightDomObserver=null;refreshScheduled=!1;suppressMutations=!1;reflectGuard=!1;connectedCallback(){this.render(),this.readAttributes({isInit:!0}),this.refresh(),this.setupLightDomObserver()}disconnectedCallback(){this.destroy()}attributeChangedCallback(t,n,s){if(!this.isConnected||this.reflectGuard)return;this.readAttributes({isInit:!1});const e=w(this,"index");if(e!=null){const i=f(Number(e),this.cards.length);if(Number.isFinite(i)&&i!==this.currentIndex){this.goTo(i);return}}this.applyLayoutAndA11y({announce:!0,emitChange:!1})}next(){this.goTo(this.currentIndex+1)}prev(){this.goTo(this.currentIndex-1)}goTo(t){if(this.isAnimating)return;const n=f(t,this.cards.length);n!==this.currentIndex&&(this.isAnimating=!0,this.currentIndex=n,this.reflectIndexAttr(),this.applyLayoutAndA11y({announce:!0,emitChange:!0}),this.lockUntilTransitionEnd())}refresh(){const t=this.lightDomObserver;t&&(this.suppressMutations=!0,t.disconnect(),t.takeRecords()),this.rebuildCardsFromLightDom();const n=L(this,"start-index",0),s=w(this,"index"),e=s!=null?Number(s):n,i=Number.isFinite(e)?e:0;this.currentIndex=f(i,this.cards.length),this.reflectIndexAttr(),this.buildDots(),this.hasAppliedInitialLayout=!1,this.lastLayoutIndex=null,this.lastVisibleSet=new Set,this.applyLayoutAndA11y({announce:!0,emitChange:!1}),this.dispatchReady(),t&&(t.observe(this,this.lightDomObserverOptions),t.takeRecords(),this.suppressMutations=!1)}destroy(){this.animFallbackTimerId!==null&&(window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=null),this.cleanup.forEach(t=>{t()}),this.cleanup=[],this.isAnimating=!1}adoptStylesheet(t){this.applyStyles(t)}adoptStyles(t){this.applyStyles(t)}readAttributes(t){this.rootEl||this.render();const n=u(this,"show-arrows",!1),s=u(this,"show-dots",!1);this.prevBtn.style.display=n?"":"none",this.nextBtn.style.display=n?"":"none",this.dotsEl.style.display=s?"":"none";const e=this.getAttribute("aria-label");e&&this.rootEl.setAttribute("aria-label",e),t.isInit&&this.setAttribute("aria-roledescription","carousel")}render(){this.applyStyles(null),this.rootEl=document.createElement("div"),this.rootEl.className="cfc",this.trackEl=document.createElement("div"),this.trackEl.className="cfc__track",this.prevBtn=document.createElement("button"),this.prevBtn.type="button",this.prevBtn.className="cfc__arrow cfc__arrow--left",this.prevBtn.setAttribute("aria-label","Previous"),this.prevBtn.textContent="‹",this.nextBtn=document.createElement("button"),this.nextBtn.type="button",this.nextBtn.className="cfc__arrow cfc__arrow--right",this.nextBtn.setAttribute("aria-label","Next"),this.nextBtn.textContent="›",this.dotsEl=document.createElement("div"),this.dotsEl.className="cfc__dots",this.liveRegion=document.createElement("div"),this.liveRegion.className="cfc__sr",this.liveRegion.setAttribute("aria-live","polite"),this.liveRegion.setAttribute("aria-atomic","true"),this.rootEl.append(this.trackEl,this.prevBtn,this.nextBtn,this.dotsEl,this.liveRegion),this.shadow.innerHTML="",this.styleEl&&this.shadow.append(this.styleEl),this.shadow.append(this.rootEl),this.bindEvents()}bindEvents(){this.cleanup.forEach(i=>{i()}),this.cleanup=[];const t=()=>this.prev(),n=()=>this.next();this.prevBtn.addEventListener("click",t),this.nextBtn.addEventListener("click",n),this.cleanup.push(()=>this.prevBtn.removeEventListener("click",t)),this.cleanup.push(()=>this.nextBtn.removeEventListener("click",n));const s=i=>{if(!this.isAnimating||i.propertyName!=="transform"||!(i.target instanceof HTMLElement))return;const r=this.cards[this.currentIndex];r&&i.target===r&&this.unlockAnimation()};this.rootEl.addEventListener("transitionend",s),this.cleanup.push(()=>this.rootEl.removeEventListener("transitionend",s));const e=i=>{const r=i.target;if(!(r instanceof HTMLElement)||r.tagName!=="SCRATCH-REVEAL")return;const c=i.composedPath?.();if(!c?.length)return;const o=c.find(h=>h instanceof HTMLElement&&h.classList.contains("cfc__card")&&h.dataset.cfcIndex!=null);if(!o)return;const l=Number(o.dataset.cfcIndex);if(!Number.isFinite(l))return;const m=i.detail?.percent??100;this.dispatchEvent(new CustomEvent("coverflow-carousel:scratch-complete",{detail:{index:l,length:this.cards.length,percent:m},bubbles:!0,composed:!0}))};this.rootEl.addEventListener("complete",e),this.cleanup.push(()=>this.rootEl.removeEventListener("complete",e))}setupLightDomObserver(){this.lightDomObserver||(this.lightDomObserver=new MutationObserver(t=>{this.suppressMutations||!t.some(s=>!(s.type==="attributes"&&s.attributeName==="slot"))||this.scheduleRefreshFromMutations()}),this.lightDomObserver.observe(this,{...this.lightDomObserverOptions}),this.cleanup.push(()=>{this.lightDomObserver?.disconnect(),this.lightDomObserver=null}))}scheduleRefreshFromMutations(){this.refreshScheduled||(this.refreshScheduled=!0,queueMicrotask(()=>{this.refreshScheduled=!1,this.isConnected&&this.refresh()}))}rebuildCardsFromLightDom(){const t=Array.from(this.trackEl.children).filter(e=>e instanceof HTMLElement&&e.classList.contains("cfc__card")),n=[],s=Array.from(this.children).filter(e=>e instanceof HTMLElement);for(let e=0;e<s.length;e++){const i=s[e],r=t[e]??document.createElement("div"),c=`${this.instanceId}-slot-${e}`;t[e]||(r.className="cfc__card",this.trackEl.append(r)),i.getAttribute("slot")!==c&&i.setAttribute("slot",c);const o=r.querySelector("slot");let l;o instanceof HTMLSlotElement?l=o:(l=document.createElement("slot"),r.replaceChildren(l)),l.name!==c&&(l.name=c),n.push(r)}for(let e=s.length;e<t.length;e++)t[e]?.remove();this.cards=n,this.hasAppliedInitialLayout=!1,this.lastLayoutIndex=null,this.lastVisibleSet=new Set}getVisibleSet(){const t=this.cards.length,n=new Set;if(t<=0)return n;const s=Math.floor(t/2);if(p>=s){for(let e=0;e<t;e++)n.add(e);return n}for(let e=-p;e<=p;e++)n.add(f(this.currentIndex+e,t));return n}buildDots(){const t=Array.from(this.dotsEl.children).filter(i=>i instanceof HTMLElement&&i.classList.contains("cfc__dot"));if(!u(this,"show-dots",!1)){t.forEach(i=>{i.remove()}),this.dots=[];return}const s=[],e=this.cards.length;for(let i=0;i<e;i++){const r=t[i]??document.createElement("span");t[i]||this.dotsEl.append(r),r.className="cfc__dot",r.setAttribute("aria-hidden","true"),s.push(r)}for(let i=e;i<t.length;i++)t[i]?.remove();this.dots=s,this.updateDotsVisualState()}computeCardState(t){const n=this.cards.length,s=T(this.currentIndex,t,n),e=Math.abs(s);return{index:t,delta:s,abs:e,isVisible:e<=p,isActive:t===this.currentIndex}}applyCardState(t,n){t.setAttribute("aria-hidden",n.isVisible?"false":"true"),t.dataset.active=n.isActive?"true":"false",t.dataset.cfcIndex=String(n.index),t.setAttribute("role","group"),t.setAttribute("aria-roledescription","slide"),t.setAttribute("aria-setsize",String(this.cards.length)),t.setAttribute("aria-posinset",String(n.index+1));const s=`${this.instanceId}-slide-${n.index}`;t.id=s;const e=String(n.delta),i=String(n.abs),r=t.dataset.cfcDelta,c=t.dataset.cfcAbs;r!==e&&(t.style.setProperty("--cfc-delta",e),t.dataset.cfcDelta=e),c!==i&&(t.style.setProperty("--cfc-abs",i),t.dataset.cfcAbs=i)}applyLayoutAndA11y(t){if(this.cards.length){if(this.hasAppliedInitialLayout){const n=this.getVisibleSet(),s=new Set;this.lastVisibleSet.forEach(e=>{s.add(e)}),n.forEach(e=>{s.add(e)}),this.lastLayoutIndex!=null&&s.add(this.lastLayoutIndex),s.add(this.currentIndex),s.forEach(e=>{const i=this.cards[e];if(!i)return;const r=this.computeCardState(e);this.applyCardState(i,r)}),this.lastLayoutIndex=this.currentIndex,this.lastVisibleSet=n}else{for(let n=0;n<this.cards.length;n++){const s=this.cards[n];if(!s)continue;const e=this.computeCardState(n);this.applyCardState(s,e)}this.hasAppliedInitialLayout=!0,this.lastLayoutIndex=this.currentIndex,this.lastVisibleSet=this.getVisibleSet()}this.updateDotsVisualState(),t.announce&&u(this,"announce-changes",!0)&&this.announce(`Slide ${this.currentIndex+1} of ${this.cards.length}`),t.emitChange&&this.emitChange()}}updateDotsVisualState(){if(this.dots.length)for(let t=0;t<this.dots.length;t++){const n=this.dots[t],s=t===this.currentIndex;n.dataset.active=s?"true":"false"}}lockUntilTransitionEnd(){this.pendingAnimToken++;const t=this.pendingAnimToken;if(k()){this.unlockAnimation();return}const n=this.cards[this.currentIndex];if(!n){this.unlockAnimation();return}const s=getComputedStyle(n),e=C(s,"transform");if(e<=0){this.unlockAnimation();return}const i=g(s.getPropertyValue("--cfc-transition-ms").trim(),400),c=Math.max(e,i)+60;this.animFallbackTimerId!==null&&window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=window.setTimeout(()=>{this.pendingAnimToken===t&&this.unlockAnimation()},c)}unlockAnimation(){this.isAnimating=!1,this.animFallbackTimerId!==null&&(window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=null)}emitChange(){this.dispatchEvent(new CustomEvent("coverflow-carousel:change",{detail:{index:this.currentIndex,length:this.cards.length}}))}dispatchReady(){this.dispatchEvent(new CustomEvent("coverflow-carousel:ready",{detail:{index:this.currentIndex,length:this.cards.length}}))}announce(t){this.liveRegion.textContent="",queueMicrotask(()=>{this.liveRegion.textContent=t})}reflectIndexAttr(){this.reflectGuard=!0;try{this.setAttribute("index",String(this.currentIndex))}finally{this.reflectGuard=!1}}applyStyles(t){if(typeof t=="string"){if(v(this.shadow)){const n=S(t);if(n){this.shadow.adoptedStyleSheets=[n],this.styleEl=null;return}}this.styleEl||(this.styleEl=document.createElement("style")),this.styleEl.textContent=t;return}if(t&&v(this.shadow)){this.shadow.adoptedStyleSheets=[t],this.styleEl=null;return}if(d.defaultStylesheet&&v(this.shadow)){this.shadow.adoptedStyleSheets=[d.defaultStylesheet],this.styleEl=null;return}this.styleEl||(this.styleEl=document.createElement("style")),this.styleEl.textContent=_}}function M(a={}){const{selector:t="coverflow-carousel",onReady:n,onChange:s,onScratchComplete:e,stylesheet:i}=a,r=Array.from(document.querySelectorAll(t));return(n||s||e)&&r.forEach(c=>{n&&c.addEventListener("coverflow-carousel:ready",o=>{n(c,o.detail)}),s&&c.addEventListener("coverflow-carousel:change",o=>{s(c,o.detail)}),e&&c.addEventListener("coverflow-carousel:scratch-complete",o=>{e(c,o.detail)})}),i&&r.forEach(c=>{const o=c;typeof i=="string"?o.adoptStyles(i):o.adoptStylesheet(i)}),r}function N(a="coverflow-carousel"){typeof window>"u"||!("customElements"in window)||customElements.get(a)||customElements.define(a,d)}exports.CoverflowCarouselElement=d;exports.coverflowCarouselCssText=A;exports.initCoverflowCarousels=M;exports.registerCoverflowCarouselElement=N;
167
+ `,A=x;function E(a){return"adoptedStyleSheets"in a}function y(a){try{const t=new CSSStyleSheet;return t.replaceSync(a),t}catch{return null}}const I=y(x),k=x;function b(a){return a.split(",").map(t=>t.trim()).filter(Boolean)}function g(a,t){const n=a.trim();if(!n)return t;if(n.endsWith("ms")){const e=Number(n.slice(0,-2).trim());return Number.isFinite(e)?e:t}if(n.endsWith("s")){const e=Number(n.slice(0,-1).trim());return Number.isFinite(e)?e*1e3:t}const s=Number(n);return Number.isFinite(s)?s:t}function C(a,t){const n=b(a.transitionProperty),s=b(a.transitionDuration),e=b(a.transitionDelay);if(!n.length)return 0;const r=(v=>{const h=n.indexOf(v);if(h>=0)return h;const S=n.indexOf("all");return S>=0?S:-1})(t);if(r<0)return 0;const o=s[Math.min(r,s.length-1)]??"0s",l=e[Math.min(r,e.length-1)]??"0s",c=g(o,0),d=g(l,0);return Math.max(0,c+d)}function _(){return window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches??!1}function f(a,t,n){if(!a.hasAttribute(t))return n;const s=a.getAttribute(t);return s==null||s===""?!0:s!=="false"}function L(a,t,n){const s=a.getAttribute(t);if(s==null)return n;const e=Number(s.trim());return Number.isFinite(e)?Math.trunc(e):n}function w(a,t){const n=a.getAttribute(t);if(n==null)return null;const s=n.trim();return s||null}function p(a,t){return t<=0?0:(a%t+t)%t}function T(a,t,n){const s=t-a,e=n/2;return s>e?s-n:s<-e?s+n:s}const m=1;let D=0;class u extends HTMLElement{static defaultStylesheet=I;static observedAttributes=["start-index","index","show-dots","show-arrows","announce-changes"];shadow=this.attachShadow({mode:"open"});instanceId=`cfc-${++D}`;rootEl;trackEl;dotsEl;prevBtn;nextBtn;liveRegion;baseStyles=null;overrideStyles=null;baseStyleEl=null;overrideStyleEl=null;cards=[];dots=[];currentIndex=0;isAnimating=!1;hasAppliedInitialLayout=!1;lastLayoutIndex=null;lastVisibleSet=new Set;pendingAnimToken=0;animFallbackTimerId=null;cleanup=[];lightDomObserverOptions={childList:!0,attributes:!0,subtree:!0};lightDomObserver=null;refreshScheduled=!1;suppressMutations=!1;reflectGuard=!1;connectedCallback(){this.render(),this.readAttributes({isInit:!0}),this.refresh(),this.setupLightDomObserver()}disconnectedCallback(){this.destroy()}attributeChangedCallback(t,n,s){if(!this.isConnected||this.reflectGuard)return;this.readAttributes({isInit:!1});const e=w(this,"index");if(e!=null){const i=p(Number(e),this.cards.length);if(Number.isFinite(i)&&i!==this.currentIndex){this.goTo(i);return}}this.applyLayoutAndA11y({announce:!0,emitChange:!1})}next(){this.goTo(this.currentIndex+1)}prev(){this.goTo(this.currentIndex-1)}goTo(t){if(this.isAnimating)return;const n=p(t,this.cards.length);n!==this.currentIndex&&(this.isAnimating=!0,this.currentIndex=n,this.reflectIndexAttr(),this.applyLayoutAndA11y({announce:!0,emitChange:!0}),this.lockUntilTransitionEnd())}refresh(){const t=this.lightDomObserver;t&&(this.suppressMutations=!0,t.disconnect(),t.takeRecords()),this.rebuildCardsFromLightDom();const n=L(this,"start-index",0),s=w(this,"index"),e=s!=null?Number(s):n,i=Number.isFinite(e)?e:0;this.currentIndex=p(i,this.cards.length),this.reflectIndexAttr(),this.buildDots(),this.hasAppliedInitialLayout=!1,this.lastLayoutIndex=null,this.lastVisibleSet=new Set,this.applyLayoutAndA11y({announce:!0,emitChange:!1}),this.dispatchReady(),t&&(t.observe(this,this.lightDomObserverOptions),t.takeRecords(),this.suppressMutations=!1)}destroy(){this.animFallbackTimerId!==null&&(window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=null),this.cleanup.forEach(t=>{t()}),this.cleanup=[],this.isAnimating=!1}adoptStylesheet(t){this.setBaseStyles(t)}adoptStyles(t){this.setBaseStyles(t)}adoptStyleOverrides(t){this.setOverrideStyles(t)}readAttributes(t){this.rootEl||this.render();const n=f(this,"show-arrows",!1),s=f(this,"show-dots",!1);this.prevBtn.style.display=n?"":"none",this.nextBtn.style.display=n?"":"none",this.dotsEl.style.display=s?"":"none";const e=this.getAttribute("aria-label");e&&this.rootEl.setAttribute("aria-label",e),t.isInit&&this.setAttribute("aria-roledescription","carousel")}render(){this.applyAllStyles(),this.rootEl=document.createElement("div"),this.rootEl.className="cfc",this.trackEl=document.createElement("div"),this.trackEl.className="cfc__track",this.prevBtn=document.createElement("button"),this.prevBtn.type="button",this.prevBtn.className="cfc__arrow cfc__arrow--left",this.prevBtn.setAttribute("aria-label","Previous"),this.prevBtn.textContent="‹",this.nextBtn=document.createElement("button"),this.nextBtn.type="button",this.nextBtn.className="cfc__arrow cfc__arrow--right",this.nextBtn.setAttribute("aria-label","Next"),this.nextBtn.textContent="›",this.dotsEl=document.createElement("div"),this.dotsEl.className="cfc__dots",this.liveRegion=document.createElement("div"),this.liveRegion.className="cfc__sr",this.liveRegion.setAttribute("aria-live","polite"),this.liveRegion.setAttribute("aria-atomic","true"),this.rootEl.append(this.trackEl,this.prevBtn,this.nextBtn,this.dotsEl,this.liveRegion),this.shadow.innerHTML="",this.baseStyleEl&&this.shadow.append(this.baseStyleEl),this.overrideStyleEl&&this.shadow.append(this.overrideStyleEl),this.shadow.append(this.rootEl),this.bindEvents()}bindEvents(){this.cleanup.forEach(i=>{i()}),this.cleanup=[];const t=()=>this.prev(),n=()=>this.next();this.prevBtn.addEventListener("click",t),this.nextBtn.addEventListener("click",n),this.cleanup.push(()=>this.prevBtn.removeEventListener("click",t)),this.cleanup.push(()=>this.nextBtn.removeEventListener("click",n));const s=i=>{if(!this.isAnimating||i.propertyName!=="transform"||!(i.target instanceof HTMLElement))return;const r=this.cards[this.currentIndex];r&&i.target===r&&this.unlockAnimation()};this.rootEl.addEventListener("transitionend",s),this.cleanup.push(()=>this.rootEl.removeEventListener("transitionend",s));const e=i=>{const r=i.target;if(!(r instanceof HTMLElement)||r.tagName!=="SCRATCH-REVEAL")return;const o=i.composedPath?.();if(!o?.length)return;const l=o.find(h=>h instanceof HTMLElement&&h.classList.contains("cfc__card")&&h.dataset.cfcIndex!=null);if(!l)return;const c=Number(l.dataset.cfcIndex);if(!Number.isFinite(c))return;const v=i.detail?.percent??100;this.dispatchEvent(new CustomEvent("coverflow-carousel:scratch-complete",{detail:{index:c,length:this.cards.length,percent:v},bubbles:!0,composed:!0}))};this.rootEl.addEventListener("complete",e),this.cleanup.push(()=>this.rootEl.removeEventListener("complete",e))}setupLightDomObserver(){this.lightDomObserver||(this.lightDomObserver=new MutationObserver(t=>{this.suppressMutations||!t.some(s=>!(s.type==="attributes"&&s.attributeName==="slot"))||this.scheduleRefreshFromMutations()}),this.lightDomObserver.observe(this,{...this.lightDomObserverOptions}),this.cleanup.push(()=>{this.lightDomObserver?.disconnect(),this.lightDomObserver=null}))}scheduleRefreshFromMutations(){this.refreshScheduled||(this.refreshScheduled=!0,queueMicrotask(()=>{this.refreshScheduled=!1,this.isConnected&&this.refresh()}))}rebuildCardsFromLightDom(){const t=Array.from(this.trackEl.children).filter(e=>e instanceof HTMLElement&&e.classList.contains("cfc__card")),n=[],s=Array.from(this.children).filter(e=>e instanceof HTMLElement);for(let e=0;e<s.length;e++){const i=s[e],r=t[e]??document.createElement("div"),o=`${this.instanceId}-slot-${e}`;t[e]||(r.className="cfc__card",this.trackEl.append(r)),i.getAttribute("slot")!==o&&i.setAttribute("slot",o);const l=r.querySelector("slot");let c;l instanceof HTMLSlotElement?c=l:(c=document.createElement("slot"),r.replaceChildren(c)),c.name!==o&&(c.name=o),n.push(r)}for(let e=s.length;e<t.length;e++)t[e]?.remove();this.cards=n,this.hasAppliedInitialLayout=!1,this.lastLayoutIndex=null,this.lastVisibleSet=new Set}getVisibleSet(){const t=this.cards.length,n=new Set;if(t<=0)return n;const s=Math.floor(t/2);if(m>=s){for(let e=0;e<t;e++)n.add(e);return n}for(let e=-m;e<=m;e++)n.add(p(this.currentIndex+e,t));return n}buildDots(){const t=Array.from(this.dotsEl.children).filter(i=>i instanceof HTMLElement&&i.classList.contains("cfc__dot"));if(!f(this,"show-dots",!1)){t.forEach(i=>{i.remove()}),this.dots=[];return}const s=[],e=this.cards.length;for(let i=0;i<e;i++){const r=t[i]??document.createElement("span");t[i]||this.dotsEl.append(r),r.className="cfc__dot",r.setAttribute("aria-hidden","true"),s.push(r)}for(let i=e;i<t.length;i++)t[i]?.remove();this.dots=s,this.updateDotsVisualState()}computeCardState(t){const n=this.cards.length,s=T(this.currentIndex,t,n),e=Math.abs(s);return{index:t,delta:s,abs:e,isVisible:e<=m,isActive:t===this.currentIndex}}applyCardState(t,n){t.setAttribute("aria-hidden",n.isVisible?"false":"true"),t.dataset.active=n.isActive?"true":"false",t.dataset.cfcIndex=String(n.index),t.setAttribute("role","group"),t.setAttribute("aria-roledescription","slide"),t.setAttribute("aria-setsize",String(this.cards.length)),t.setAttribute("aria-posinset",String(n.index+1));const s=`${this.instanceId}-slide-${n.index}`;t.id=s;const e=String(n.delta),i=String(n.abs),r=t.dataset.cfcDelta,o=t.dataset.cfcAbs;r!==e&&(t.style.setProperty("--cfc-delta",e),t.dataset.cfcDelta=e),o!==i&&(t.style.setProperty("--cfc-abs",i),t.dataset.cfcAbs=i)}applyLayoutAndA11y(t){if(this.cards.length){if(this.hasAppliedInitialLayout){const n=this.getVisibleSet(),s=new Set;this.lastVisibleSet.forEach(e=>{s.add(e)}),n.forEach(e=>{s.add(e)}),this.lastLayoutIndex!=null&&s.add(this.lastLayoutIndex),s.add(this.currentIndex),s.forEach(e=>{const i=this.cards[e];if(!i)return;const r=this.computeCardState(e);this.applyCardState(i,r)}),this.lastLayoutIndex=this.currentIndex,this.lastVisibleSet=n}else{for(let n=0;n<this.cards.length;n++){const s=this.cards[n];if(!s)continue;const e=this.computeCardState(n);this.applyCardState(s,e)}this.hasAppliedInitialLayout=!0,this.lastLayoutIndex=this.currentIndex,this.lastVisibleSet=this.getVisibleSet()}this.updateDotsVisualState(),t.announce&&f(this,"announce-changes",!0)&&this.announce(`Slide ${this.currentIndex+1} of ${this.cards.length}`),t.emitChange&&this.emitChange()}}updateDotsVisualState(){if(this.dots.length)for(let t=0;t<this.dots.length;t++){const n=this.dots[t],s=t===this.currentIndex;n.dataset.active=s?"true":"false"}}lockUntilTransitionEnd(){this.pendingAnimToken++;const t=this.pendingAnimToken;if(_()){this.unlockAnimation();return}const n=this.cards[this.currentIndex];if(!n){this.unlockAnimation();return}const s=getComputedStyle(n),e=C(s,"transform");if(e<=0){this.unlockAnimation();return}const i=g(s.getPropertyValue("--cfc-transition-ms").trim(),400),o=Math.max(e,i)+60;this.animFallbackTimerId!==null&&window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=window.setTimeout(()=>{this.pendingAnimToken===t&&this.unlockAnimation()},o)}unlockAnimation(){this.isAnimating=!1,this.animFallbackTimerId!==null&&(window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=null)}emitChange(){this.dispatchEvent(new CustomEvent("coverflow-carousel:change",{detail:{index:this.currentIndex,length:this.cards.length}}))}dispatchReady(){this.dispatchEvent(new CustomEvent("coverflow-carousel:ready",{detail:{index:this.currentIndex,length:this.cards.length}}))}announce(t){this.liveRegion.textContent="",queueMicrotask(()=>{this.liveRegion.textContent=t})}reflectIndexAttr(){this.reflectGuard=!0;try{this.setAttribute("index",String(this.currentIndex))}finally{this.reflectGuard=!1}}setBaseStyles(t){this.baseStyles=t??null,this.applyAllStyles()}setOverrideStyles(t){this.overrideStyles=t??null,this.applyAllStyles()}applyAllStyles(){const t=this.baseStyles,n=this.overrideStyles;if(E(this.shadow)){const e=[];if(typeof t=="string"){const i=y(t);if(!i){this.applyAllStylesFallback();return}e.push(i)}else if(t)e.push(t);else if(u.defaultStylesheet)e.push(u.defaultStylesheet);else{this.applyAllStylesFallback();return}if(typeof n=="string"){const i=y(n);if(!i){this.applyAllStylesFallback();return}e.push(i)}else n&&e.push(n);this.shadow.adoptedStyleSheets=e,this.baseStyleEl?.remove(),this.overrideStyleEl?.remove(),this.baseStyleEl=null,this.overrideStyleEl=null;return}this.applyAllStylesFallback()}applyAllStylesFallback(){const t=this.baseStyles,n=this.overrideStyles;E(this.shadow)&&(this.shadow.adoptedStyleSheets=[]);const s=typeof t=="string"?t:k,e=typeof n=="string"?n:"";this.baseStyleEl||(this.baseStyleEl=document.createElement("style")),this.baseStyleEl.textContent=s,e?(this.overrideStyleEl||(this.overrideStyleEl=document.createElement("style")),this.overrideStyleEl.textContent=e):(this.overrideStyleEl?.remove(),this.overrideStyleEl=null)}}function F(a={}){const{selector:t="coverflow-carousel",onReady:n,onChange:s,onScratchComplete:e,stylesheet:i,styleOverrides:r}=a,o=Array.from(document.querySelectorAll(t));return(n||s||e)&&o.forEach(l=>{n&&l.addEventListener("coverflow-carousel:ready",c=>{n(l,c.detail)}),s&&l.addEventListener("coverflow-carousel:change",c=>{s(l,c.detail)}),e&&l.addEventListener("coverflow-carousel:scratch-complete",c=>{e(l,c.detail)})}),i&&o.forEach(l=>{const c=l;typeof i=="string"?c.adoptStyles(i):c.adoptStylesheet(i)}),r&&o.forEach(l=>{l.adoptStyleOverrides(r)}),o}function M(a="coverflow-carousel"){typeof window>"u"||!("customElements"in window)||customElements.get(a)||customElements.define(a,u)}exports.CoverflowCarouselElement=u;exports.coverflowCarouselCssText=A;exports.initCoverflowCarousels=F;exports.registerCoverflowCarouselElement=M;
package/dist/index.es.js CHANGED
@@ -4,9 +4,7 @@ const x = `:host {
4
4
  height: 100%;
5
5
  container-type: inline-size;
6
6
  overflow: hidden;
7
- }
8
7
 
9
- .cfc {
10
8
  /* Layout */
11
9
  --cfc-card-ar-num: 1.25;
12
10
  --cfc-card-w: clamp(160px, 100vw - 120px, 380px);
@@ -30,7 +28,9 @@ const x = `:host {
30
28
  --cfc-park-x: 0px;
31
29
  --cfc-park-z: calc(var(--cfc-step-z) * -6);
32
30
  --cfc-park-scale: 0.1;
31
+ }
33
32
 
33
+ .cfc {
34
34
  margin: auto;
35
35
  width: min(900px, 100%);
36
36
  height: 100%;
@@ -165,10 +165,10 @@ const x = `:host {
165
165
  border: 0;
166
166
  }
167
167
  `, D = x;
168
- function v(a) {
168
+ function E(a) {
169
169
  return "adoptedStyleSheets" in a;
170
170
  }
171
- function S(a) {
171
+ function y(a) {
172
172
  try {
173
173
  const t = new CSSStyleSheet();
174
174
  return t.replaceSync(a), t;
@@ -176,7 +176,7 @@ function S(a) {
176
176
  return null;
177
177
  }
178
178
  }
179
- const A = S(x), I = x;
179
+ const A = y(x), I = x;
180
180
  function b(a) {
181
181
  return a.split(",").map((t) => t.trim()).filter(Boolean);
182
182
  }
@@ -194,23 +194,23 @@ function g(a, t) {
194
194
  const s = Number(n);
195
195
  return Number.isFinite(s) ? s : t;
196
196
  }
197
- function _(a, t) {
197
+ function k(a, t) {
198
198
  const n = b(a.transitionProperty), s = b(a.transitionDuration), e = b(a.transitionDelay);
199
199
  if (!n.length) return 0;
200
- const r = ((m) => {
201
- const h = n.indexOf(m);
200
+ const r = ((v) => {
201
+ const h = n.indexOf(v);
202
202
  if (h >= 0) return h;
203
- const E = n.indexOf("all");
204
- return E >= 0 ? E : -1;
203
+ const S = n.indexOf("all");
204
+ return S >= 0 ? S : -1;
205
205
  })(t);
206
206
  if (r < 0) return 0;
207
- const c = s[Math.min(r, s.length - 1)] ?? "0s", o = e[Math.min(r, e.length - 1)] ?? "0s", l = g(c, 0), y = g(o, 0);
208
- return Math.max(0, l + y);
207
+ const o = s[Math.min(r, s.length - 1)] ?? "0s", l = e[Math.min(r, e.length - 1)] ?? "0s", c = g(o, 0), d = g(l, 0);
208
+ return Math.max(0, c + d);
209
209
  }
210
- function k() {
210
+ function _() {
211
211
  return window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches ?? !1;
212
212
  }
213
- function d(a, t, n) {
213
+ function u(a, t, n) {
214
214
  if (!a.hasAttribute(t)) return n;
215
215
  const s = a.getAttribute(t);
216
216
  return s == null || s === "" ? !0 : s !== "false";
@@ -227,16 +227,16 @@ function w(a, t) {
227
227
  const s = n.trim();
228
228
  return s || null;
229
229
  }
230
- function u(a, t) {
230
+ function f(a, t) {
231
231
  return t <= 0 ? 0 : (a % t + t) % t;
232
232
  }
233
233
  function L(a, t, n) {
234
234
  const s = t - a, e = n / 2;
235
235
  return s > e ? s - n : s < -e ? s + n : s;
236
236
  }
237
- const f = 1;
237
+ const p = 1;
238
238
  let T = 0;
239
- class p extends HTMLElement {
239
+ class m extends HTMLElement {
240
240
  static defaultStylesheet = A;
241
241
  static observedAttributes = [
242
242
  "start-index",
@@ -253,7 +253,10 @@ class p extends HTMLElement {
253
253
  prevBtn;
254
254
  nextBtn;
255
255
  liveRegion;
256
- styleEl = null;
256
+ baseStyles = null;
257
+ overrideStyles = null;
258
+ baseStyleEl = null;
259
+ overrideStyleEl = null;
257
260
  cards = [];
258
261
  dots = [];
259
262
  currentIndex = 0;
@@ -284,7 +287,7 @@ class p extends HTMLElement {
284
287
  this.readAttributes({ isInit: !1 });
285
288
  const e = w(this, "index");
286
289
  if (e != null) {
287
- const i = u(Number(e), this.cards.length);
290
+ const i = f(Number(e), this.cards.length);
288
291
  if (Number.isFinite(i) && i !== this.currentIndex) {
289
292
  this.goTo(i);
290
293
  return;
@@ -300,14 +303,14 @@ class p extends HTMLElement {
300
303
  }
301
304
  goTo(t) {
302
305
  if (this.isAnimating) return;
303
- const n = u(t, this.cards.length);
306
+ const n = f(t, this.cards.length);
304
307
  n !== this.currentIndex && (this.isAnimating = !0, this.currentIndex = n, this.reflectIndexAttr(), this.applyLayoutAndA11y({ announce: !0, emitChange: !0 }), this.lockUntilTransitionEnd());
305
308
  }
306
309
  refresh() {
307
310
  const t = this.lightDomObserver;
308
311
  t && (this.suppressMutations = !0, t.disconnect(), t.takeRecords()), this.rebuildCardsFromLightDom();
309
312
  const n = C(this, "start-index", 0), s = w(this, "index"), e = s != null ? Number(s) : n, i = Number.isFinite(e) ? e : 0;
310
- this.currentIndex = u(i, this.cards.length), this.reflectIndexAttr(), this.buildDots(), this.hasAppliedInitialLayout = !1, this.lastLayoutIndex = null, this.lastVisibleSet = /* @__PURE__ */ new Set(), this.applyLayoutAndA11y({ announce: !0, emitChange: !1 }), this.dispatchReady(), t && (t.observe(this, this.lightDomObserverOptions), t.takeRecords(), this.suppressMutations = !1);
313
+ this.currentIndex = f(i, this.cards.length), this.reflectIndexAttr(), this.buildDots(), this.hasAppliedInitialLayout = !1, this.lastLayoutIndex = null, this.lastVisibleSet = /* @__PURE__ */ new Set(), this.applyLayoutAndA11y({ announce: !0, emitChange: !1 }), this.dispatchReady(), t && (t.observe(this, this.lightDomObserverOptions), t.takeRecords(), this.suppressMutations = !1);
311
314
  }
312
315
  destroy() {
313
316
  this.animFallbackTimerId !== null && (window.clearTimeout(this.animFallbackTimerId), this.animFallbackTimerId = null), this.cleanup.forEach((t) => {
@@ -315,20 +318,23 @@ class p extends HTMLElement {
315
318
  }), this.cleanup = [], this.isAnimating = !1;
316
319
  }
317
320
  adoptStylesheet(t) {
318
- this.applyStyles(t);
321
+ this.setBaseStyles(t);
319
322
  }
320
323
  adoptStyles(t) {
321
- this.applyStyles(t);
324
+ this.setBaseStyles(t);
325
+ }
326
+ adoptStyleOverrides(t) {
327
+ this.setOverrideStyles(t);
322
328
  }
323
329
  readAttributes(t) {
324
330
  this.rootEl || this.render();
325
- const n = d(this, "show-arrows", !1), s = d(this, "show-dots", !1);
331
+ const n = u(this, "show-arrows", !1), s = u(this, "show-dots", !1);
326
332
  this.prevBtn.style.display = n ? "" : "none", this.nextBtn.style.display = n ? "" : "none", this.dotsEl.style.display = s ? "" : "none";
327
333
  const e = this.getAttribute("aria-label");
328
334
  e && this.rootEl.setAttribute("aria-label", e), t.isInit && this.setAttribute("aria-roledescription", "carousel");
329
335
  }
330
336
  render() {
331
- this.applyStyles(null), this.rootEl = document.createElement("div"), this.rootEl.className = "cfc", this.trackEl = document.createElement("div"), this.trackEl.className = "cfc__track", this.prevBtn = document.createElement("button"), this.prevBtn.type = "button", this.prevBtn.className = "cfc__arrow cfc__arrow--left", this.prevBtn.setAttribute("aria-label", "Previous"), this.prevBtn.textContent = "‹", this.nextBtn = document.createElement("button"), this.nextBtn.type = "button", this.nextBtn.className = "cfc__arrow cfc__arrow--right", this.nextBtn.setAttribute("aria-label", "Next"), this.nextBtn.textContent = "›", this.dotsEl = document.createElement("div"), this.dotsEl.className = "cfc__dots", this.liveRegion = document.createElement("div"), this.liveRegion.className = "cfc__sr", this.liveRegion.setAttribute("aria-live", "polite"), this.liveRegion.setAttribute("aria-atomic", "true"), this.rootEl.append(this.trackEl, this.prevBtn, this.nextBtn, this.dotsEl, this.liveRegion), this.shadow.innerHTML = "", this.styleEl && this.shadow.append(this.styleEl), this.shadow.append(this.rootEl), this.bindEvents();
337
+ this.applyAllStyles(), this.rootEl = document.createElement("div"), this.rootEl.className = "cfc", this.trackEl = document.createElement("div"), this.trackEl.className = "cfc__track", this.prevBtn = document.createElement("button"), this.prevBtn.type = "button", this.prevBtn.className = "cfc__arrow cfc__arrow--left", this.prevBtn.setAttribute("aria-label", "Previous"), this.prevBtn.textContent = "‹", this.nextBtn = document.createElement("button"), this.nextBtn.type = "button", this.nextBtn.className = "cfc__arrow cfc__arrow--right", this.nextBtn.setAttribute("aria-label", "Next"), this.nextBtn.textContent = "›", this.dotsEl = document.createElement("div"), this.dotsEl.className = "cfc__dots", this.liveRegion = document.createElement("div"), this.liveRegion.className = "cfc__sr", this.liveRegion.setAttribute("aria-live", "polite"), this.liveRegion.setAttribute("aria-atomic", "true"), this.rootEl.append(this.trackEl, this.prevBtn, this.nextBtn, this.dotsEl, this.liveRegion), this.shadow.innerHTML = "", this.baseStyleEl && this.shadow.append(this.baseStyleEl), this.overrideStyleEl && this.shadow.append(this.overrideStyleEl), this.shadow.append(this.rootEl), this.bindEvents();
332
338
  }
333
339
  bindEvents() {
334
340
  this.cleanup.forEach((i) => {
@@ -345,18 +351,18 @@ class p extends HTMLElement {
345
351
  const e = (i) => {
346
352
  const r = i.target;
347
353
  if (!(r instanceof HTMLElement) || r.tagName !== "SCRATCH-REVEAL") return;
348
- const c = i.composedPath?.();
349
- if (!c?.length) return;
350
- const o = c.find(
354
+ const o = i.composedPath?.();
355
+ if (!o?.length) return;
356
+ const l = o.find(
351
357
  (h) => h instanceof HTMLElement && h.classList.contains("cfc__card") && h.dataset.cfcIndex != null
352
358
  );
353
- if (!o) return;
354
- const l = Number(o.dataset.cfcIndex);
355
- if (!Number.isFinite(l)) return;
356
- const m = i.detail?.percent ?? 100;
359
+ if (!l) return;
360
+ const c = Number(l.dataset.cfcIndex);
361
+ if (!Number.isFinite(c)) return;
362
+ const v = i.detail?.percent ?? 100;
357
363
  this.dispatchEvent(
358
364
  new CustomEvent("coverflow-carousel:scratch-complete", {
359
- detail: { index: l, length: this.cards.length, percent: m },
365
+ detail: { index: c, length: this.cards.length, percent: v },
360
366
  bubbles: !0,
361
367
  composed: !0
362
368
  })
@@ -387,11 +393,11 @@ class p extends HTMLElement {
387
393
  (e) => e instanceof HTMLElement
388
394
  );
389
395
  for (let e = 0; e < s.length; e++) {
390
- const i = s[e], r = t[e] ?? document.createElement("div"), c = `${this.instanceId}-slot-${e}`;
391
- t[e] || (r.className = "cfc__card", this.trackEl.append(r)), i.getAttribute("slot") !== c && i.setAttribute("slot", c);
392
- const o = r.querySelector("slot");
393
- let l;
394
- o instanceof HTMLSlotElement ? l = o : (l = document.createElement("slot"), r.replaceChildren(l)), l.name !== c && (l.name = c), n.push(r);
396
+ const i = s[e], r = t[e] ?? document.createElement("div"), o = `${this.instanceId}-slot-${e}`;
397
+ t[e] || (r.className = "cfc__card", this.trackEl.append(r)), i.getAttribute("slot") !== o && i.setAttribute("slot", o);
398
+ const l = r.querySelector("slot");
399
+ let c;
400
+ l instanceof HTMLSlotElement ? c = l : (c = document.createElement("slot"), r.replaceChildren(c)), c.name !== o && (c.name = o), n.push(r);
395
401
  }
396
402
  for (let e = s.length; e < t.length; e++)
397
403
  t[e]?.remove();
@@ -401,19 +407,19 @@ class p extends HTMLElement {
401
407
  const t = this.cards.length, n = /* @__PURE__ */ new Set();
402
408
  if (t <= 0) return n;
403
409
  const s = Math.floor(t / 2);
404
- if (f >= s) {
410
+ if (p >= s) {
405
411
  for (let e = 0; e < t; e++) n.add(e);
406
412
  return n;
407
413
  }
408
- for (let e = -f; e <= f; e++)
409
- n.add(u(this.currentIndex + e, t));
414
+ for (let e = -p; e <= p; e++)
415
+ n.add(f(this.currentIndex + e, t));
410
416
  return n;
411
417
  }
412
418
  buildDots() {
413
419
  const t = Array.from(this.dotsEl.children).filter(
414
420
  (i) => i instanceof HTMLElement && i.classList.contains("cfc__dot")
415
421
  );
416
- if (!d(this, "show-dots", !1)) {
422
+ if (!u(this, "show-dots", !1)) {
417
423
  t.forEach((i) => {
418
424
  i.remove();
419
425
  }), this.dots = [];
@@ -434,7 +440,7 @@ class p extends HTMLElement {
434
440
  index: t,
435
441
  delta: s,
436
442
  abs: e,
437
- isVisible: e <= f,
443
+ isVisible: e <= p,
438
444
  isActive: t === this.currentIndex
439
445
  };
440
446
  }
@@ -442,8 +448,8 @@ class p extends HTMLElement {
442
448
  t.setAttribute("aria-hidden", n.isVisible ? "false" : "true"), t.dataset.active = n.isActive ? "true" : "false", t.dataset.cfcIndex = String(n.index), t.setAttribute("role", "group"), t.setAttribute("aria-roledescription", "slide"), t.setAttribute("aria-setsize", String(this.cards.length)), t.setAttribute("aria-posinset", String(n.index + 1));
443
449
  const s = `${this.instanceId}-slide-${n.index}`;
444
450
  t.id = s;
445
- const e = String(n.delta), i = String(n.abs), r = t.dataset.cfcDelta, c = t.dataset.cfcAbs;
446
- r !== e && (t.style.setProperty("--cfc-delta", e), t.dataset.cfcDelta = e), c !== i && (t.style.setProperty("--cfc-abs", i), t.dataset.cfcAbs = i);
451
+ const e = String(n.delta), i = String(n.abs), r = t.dataset.cfcDelta, o = t.dataset.cfcAbs;
452
+ r !== e && (t.style.setProperty("--cfc-delta", e), t.dataset.cfcDelta = e), o !== i && (t.style.setProperty("--cfc-abs", i), t.dataset.cfcAbs = i);
447
453
  }
448
454
  applyLayoutAndA11y(t) {
449
455
  if (this.cards.length) {
@@ -468,7 +474,7 @@ class p extends HTMLElement {
468
474
  }
469
475
  this.hasAppliedInitialLayout = !0, this.lastLayoutIndex = this.currentIndex, this.lastVisibleSet = this.getVisibleSet();
470
476
  }
471
- this.updateDotsVisualState(), t.announce && d(this, "announce-changes", !0) && this.announce(`Slide ${this.currentIndex + 1} of ${this.cards.length}`), t.emitChange && this.emitChange();
477
+ this.updateDotsVisualState(), t.announce && u(this, "announce-changes", !0) && this.announce(`Slide ${this.currentIndex + 1} of ${this.cards.length}`), t.emitChange && this.emitChange();
472
478
  }
473
479
  }
474
480
  updateDotsVisualState() {
@@ -481,7 +487,7 @@ class p extends HTMLElement {
481
487
  lockUntilTransitionEnd() {
482
488
  this.pendingAnimToken++;
483
489
  const t = this.pendingAnimToken;
484
- if (k()) {
490
+ if (_()) {
485
491
  this.unlockAnimation();
486
492
  return;
487
493
  }
@@ -490,15 +496,15 @@ class p extends HTMLElement {
490
496
  this.unlockAnimation();
491
497
  return;
492
498
  }
493
- const s = getComputedStyle(n), e = _(s, "transform");
499
+ const s = getComputedStyle(n), e = k(s, "transform");
494
500
  if (e <= 0) {
495
501
  this.unlockAnimation();
496
502
  return;
497
503
  }
498
- const i = g(s.getPropertyValue("--cfc-transition-ms").trim(), 400), c = Math.max(e, i) + 60;
504
+ const i = g(s.getPropertyValue("--cfc-transition-ms").trim(), 400), o = Math.max(e, i) + 60;
499
505
  this.animFallbackTimerId !== null && window.clearTimeout(this.animFallbackTimerId), this.animFallbackTimerId = window.setTimeout(() => {
500
506
  this.pendingAnimToken === t && this.unlockAnimation();
501
- }, c);
507
+ }, o);
502
508
  }
503
509
  unlockAnimation() {
504
510
  this.isAnimating = !1, this.animFallbackTimerId !== null && (window.clearTimeout(this.animFallbackTimerId), this.animFallbackTimerId = null);
@@ -530,56 +536,81 @@ class p extends HTMLElement {
530
536
  this.reflectGuard = !1;
531
537
  }
532
538
  }
533
- applyStyles(t) {
534
- if (typeof t == "string") {
535
- if (v(this.shadow)) {
536
- const n = S(t);
537
- if (n) {
538
- this.shadow.adoptedStyleSheets = [n], this.styleEl = null;
539
+ setBaseStyles(t) {
540
+ this.baseStyles = t ?? null, this.applyAllStyles();
541
+ }
542
+ setOverrideStyles(t) {
543
+ this.overrideStyles = t ?? null, this.applyAllStyles();
544
+ }
545
+ applyAllStyles() {
546
+ const t = this.baseStyles, n = this.overrideStyles;
547
+ if (E(this.shadow)) {
548
+ const e = [];
549
+ if (typeof t == "string") {
550
+ const i = y(t);
551
+ if (!i) {
552
+ this.applyAllStylesFallback();
539
553
  return;
540
554
  }
555
+ e.push(i);
556
+ } else if (t)
557
+ e.push(t);
558
+ else if (m.defaultStylesheet)
559
+ e.push(m.defaultStylesheet);
560
+ else {
561
+ this.applyAllStylesFallback();
562
+ return;
541
563
  }
542
- this.styleEl || (this.styleEl = document.createElement("style")), this.styleEl.textContent = t;
543
- return;
544
- }
545
- if (t && v(this.shadow)) {
546
- this.shadow.adoptedStyleSheets = [t], this.styleEl = null;
547
- return;
548
- }
549
- if (p.defaultStylesheet && v(this.shadow)) {
550
- this.shadow.adoptedStyleSheets = [p.defaultStylesheet], this.styleEl = null;
564
+ if (typeof n == "string") {
565
+ const i = y(n);
566
+ if (!i) {
567
+ this.applyAllStylesFallback();
568
+ return;
569
+ }
570
+ e.push(i);
571
+ } else n && e.push(n);
572
+ this.shadow.adoptedStyleSheets = e, this.baseStyleEl?.remove(), this.overrideStyleEl?.remove(), this.baseStyleEl = null, this.overrideStyleEl = null;
551
573
  return;
552
574
  }
553
- this.styleEl || (this.styleEl = document.createElement("style")), this.styleEl.textContent = I;
575
+ this.applyAllStylesFallback();
576
+ }
577
+ applyAllStylesFallback() {
578
+ const t = this.baseStyles, n = this.overrideStyles;
579
+ E(this.shadow) && (this.shadow.adoptedStyleSheets = []);
580
+ const s = typeof t == "string" ? t : I, e = typeof n == "string" ? n : "";
581
+ this.baseStyleEl || (this.baseStyleEl = document.createElement("style")), this.baseStyleEl.textContent = s, e ? (this.overrideStyleEl || (this.overrideStyleEl = document.createElement("style")), this.overrideStyleEl.textContent = e) : (this.overrideStyleEl?.remove(), this.overrideStyleEl = null);
554
582
  }
555
583
  }
556
- function M(a = {}) {
584
+ function F(a = {}) {
557
585
  const {
558
586
  selector: t = "coverflow-carousel",
559
587
  onReady: n,
560
588
  onChange: s,
561
589
  onScratchComplete: e,
562
- stylesheet: i
563
- } = a, r = Array.from(document.querySelectorAll(t));
564
- return (n || s || e) && r.forEach((c) => {
565
- n && c.addEventListener("coverflow-carousel:ready", (o) => {
566
- n(c, o.detail);
567
- }), s && c.addEventListener("coverflow-carousel:change", (o) => {
568
- s(c, o.detail);
569
- }), e && c.addEventListener("coverflow-carousel:scratch-complete", (o) => {
570
- e(c, o.detail);
590
+ stylesheet: i,
591
+ styleOverrides: r
592
+ } = a, o = Array.from(document.querySelectorAll(t));
593
+ return (n || s || e) && o.forEach((l) => {
594
+ n && l.addEventListener("coverflow-carousel:ready", (c) => {
595
+ n(l, c.detail);
596
+ }), s && l.addEventListener("coverflow-carousel:change", (c) => {
597
+ s(l, c.detail);
598
+ }), e && l.addEventListener("coverflow-carousel:scratch-complete", (c) => {
599
+ e(l, c.detail);
571
600
  });
572
- }), i && r.forEach((c) => {
573
- const o = c;
574
- typeof i == "string" ? o.adoptStyles(i) : o.adoptStylesheet(i);
575
- }), r;
601
+ }), i && o.forEach((l) => {
602
+ const c = l;
603
+ typeof i == "string" ? c.adoptStyles(i) : c.adoptStylesheet(i);
604
+ }), r && o.forEach((l) => {
605
+ l.adoptStyleOverrides(r);
606
+ }), o;
576
607
  }
577
- function N(a = "coverflow-carousel") {
578
- typeof window > "u" || !("customElements" in window) || customElements.get(a) || customElements.define(a, p);
608
+ function M(a = "coverflow-carousel") {
609
+ typeof window > "u" || !("customElements" in window) || customElements.get(a) || customElements.define(a, m);
579
610
  }
580
611
  export {
581
- p as CoverflowCarouselElement,
612
+ m as CoverflowCarouselElement,
582
613
  D as coverflowCarouselCssText,
583
- M as initCoverflowCarousels,
584
- N as registerCoverflowCarouselElement
614
+ F as initCoverflowCarousels,
615
+ M as registerCoverflowCarouselElement
585
616
  };
package/dist/index.umd.js CHANGED
@@ -4,9 +4,7 @@
4
4
  height: 100%;
5
5
  container-type: inline-size;
6
6
  overflow: hidden;
7
- }
8
7
 
9
- .cfc {
10
8
  /* Layout */
11
9
  --cfc-card-ar-num: 1.25;
12
10
  --cfc-card-w: clamp(160px, 100vw - 120px, 380px);
@@ -30,7 +28,9 @@
30
28
  --cfc-park-x: 0px;
31
29
  --cfc-park-z: calc(var(--cfc-step-z) * -6);
32
30
  --cfc-park-scale: 0.1;
31
+ }
33
32
 
33
+ .cfc {
34
34
  margin: auto;
35
35
  width: min(900px, 100%);
36
36
  height: 100%;
@@ -164,4 +164,4 @@
164
164
  white-space: nowrap;
165
165
  border: 0;
166
166
  }
167
- `,I=d;function b(a){return"adoptedStyleSheets"in a}function E(a){try{const t=new CSSStyleSheet;return t.replaceSync(a),t}catch{return null}}const C=E(d),_=d;function g(a){return a.split(",").map(t=>t.trim()).filter(Boolean)}function x(a,t){const n=a.trim();if(!n)return t;if(n.endsWith("ms")){const e=Number(n.slice(0,-2).trim());return Number.isFinite(e)?e:t}if(n.endsWith("s")){const e=Number(n.slice(0,-1).trim());return Number.isFinite(e)?e*1e3:t}const s=Number(n);return Number.isFinite(s)?s:t}function k(a,t){const n=g(a.transitionProperty),s=g(a.transitionDuration),e=g(a.transitionDelay);if(!n.length)return 0;const r=(y=>{const u=n.indexOf(y);if(u>=0)return u;const A=n.indexOf("all");return A>=0?A:-1})(t);if(r<0)return 0;const c=s[Math.min(r,s.length-1)]??"0s",o=e[Math.min(r,e.length-1)]??"0s",l=x(c,0),S=x(o,0);return Math.max(0,l+S)}function L(){return window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches??!1}function p(a,t,n){if(!a.hasAttribute(t))return n;const s=a.getAttribute(t);return s==null||s===""?!0:s!=="false"}function T(a,t,n){const s=a.getAttribute(t);if(s==null)return n;const e=Number(s.trim());return Number.isFinite(e)?Math.trunc(e):n}function w(a,t){const n=a.getAttribute(t);if(n==null)return null;const s=n.trim();return s||null}function m(a,t){return t<=0?0:(a%t+t)%t}function D(a,t,n){const s=t-a,e=n/2;return s>e?s-n:s<-e?s+n:s}const v=1;let M=0;class f extends HTMLElement{static defaultStylesheet=C;static observedAttributes=["start-index","index","show-dots","show-arrows","announce-changes"];shadow=this.attachShadow({mode:"open"});instanceId=`cfc-${++M}`;rootEl;trackEl;dotsEl;prevBtn;nextBtn;liveRegion;styleEl=null;cards=[];dots=[];currentIndex=0;isAnimating=!1;hasAppliedInitialLayout=!1;lastLayoutIndex=null;lastVisibleSet=new Set;pendingAnimToken=0;animFallbackTimerId=null;cleanup=[];lightDomObserverOptions={childList:!0,attributes:!0,subtree:!0};lightDomObserver=null;refreshScheduled=!1;suppressMutations=!1;reflectGuard=!1;connectedCallback(){this.render(),this.readAttributes({isInit:!0}),this.refresh(),this.setupLightDomObserver()}disconnectedCallback(){this.destroy()}attributeChangedCallback(t,n,s){if(!this.isConnected||this.reflectGuard)return;this.readAttributes({isInit:!1});const e=w(this,"index");if(e!=null){const i=m(Number(e),this.cards.length);if(Number.isFinite(i)&&i!==this.currentIndex){this.goTo(i);return}}this.applyLayoutAndA11y({announce:!0,emitChange:!1})}next(){this.goTo(this.currentIndex+1)}prev(){this.goTo(this.currentIndex-1)}goTo(t){if(this.isAnimating)return;const n=m(t,this.cards.length);n!==this.currentIndex&&(this.isAnimating=!0,this.currentIndex=n,this.reflectIndexAttr(),this.applyLayoutAndA11y({announce:!0,emitChange:!0}),this.lockUntilTransitionEnd())}refresh(){const t=this.lightDomObserver;t&&(this.suppressMutations=!0,t.disconnect(),t.takeRecords()),this.rebuildCardsFromLightDom();const n=T(this,"start-index",0),s=w(this,"index"),e=s!=null?Number(s):n,i=Number.isFinite(e)?e:0;this.currentIndex=m(i,this.cards.length),this.reflectIndexAttr(),this.buildDots(),this.hasAppliedInitialLayout=!1,this.lastLayoutIndex=null,this.lastVisibleSet=new Set,this.applyLayoutAndA11y({announce:!0,emitChange:!1}),this.dispatchReady(),t&&(t.observe(this,this.lightDomObserverOptions),t.takeRecords(),this.suppressMutations=!1)}destroy(){this.animFallbackTimerId!==null&&(window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=null),this.cleanup.forEach(t=>{t()}),this.cleanup=[],this.isAnimating=!1}adoptStylesheet(t){this.applyStyles(t)}adoptStyles(t){this.applyStyles(t)}readAttributes(t){this.rootEl||this.render();const n=p(this,"show-arrows",!1),s=p(this,"show-dots",!1);this.prevBtn.style.display=n?"":"none",this.nextBtn.style.display=n?"":"none",this.dotsEl.style.display=s?"":"none";const e=this.getAttribute("aria-label");e&&this.rootEl.setAttribute("aria-label",e),t.isInit&&this.setAttribute("aria-roledescription","carousel")}render(){this.applyStyles(null),this.rootEl=document.createElement("div"),this.rootEl.className="cfc",this.trackEl=document.createElement("div"),this.trackEl.className="cfc__track",this.prevBtn=document.createElement("button"),this.prevBtn.type="button",this.prevBtn.className="cfc__arrow cfc__arrow--left",this.prevBtn.setAttribute("aria-label","Previous"),this.prevBtn.textContent="‹",this.nextBtn=document.createElement("button"),this.nextBtn.type="button",this.nextBtn.className="cfc__arrow cfc__arrow--right",this.nextBtn.setAttribute("aria-label","Next"),this.nextBtn.textContent="›",this.dotsEl=document.createElement("div"),this.dotsEl.className="cfc__dots",this.liveRegion=document.createElement("div"),this.liveRegion.className="cfc__sr",this.liveRegion.setAttribute("aria-live","polite"),this.liveRegion.setAttribute("aria-atomic","true"),this.rootEl.append(this.trackEl,this.prevBtn,this.nextBtn,this.dotsEl,this.liveRegion),this.shadow.innerHTML="",this.styleEl&&this.shadow.append(this.styleEl),this.shadow.append(this.rootEl),this.bindEvents()}bindEvents(){this.cleanup.forEach(i=>{i()}),this.cleanup=[];const t=()=>this.prev(),n=()=>this.next();this.prevBtn.addEventListener("click",t),this.nextBtn.addEventListener("click",n),this.cleanup.push(()=>this.prevBtn.removeEventListener("click",t)),this.cleanup.push(()=>this.nextBtn.removeEventListener("click",n));const s=i=>{if(!this.isAnimating||i.propertyName!=="transform"||!(i.target instanceof HTMLElement))return;const r=this.cards[this.currentIndex];r&&i.target===r&&this.unlockAnimation()};this.rootEl.addEventListener("transitionend",s),this.cleanup.push(()=>this.rootEl.removeEventListener("transitionend",s));const e=i=>{const r=i.target;if(!(r instanceof HTMLElement)||r.tagName!=="SCRATCH-REVEAL")return;const c=i.composedPath?.();if(!c?.length)return;const o=c.find(u=>u instanceof HTMLElement&&u.classList.contains("cfc__card")&&u.dataset.cfcIndex!=null);if(!o)return;const l=Number(o.dataset.cfcIndex);if(!Number.isFinite(l))return;const y=i.detail?.percent??100;this.dispatchEvent(new CustomEvent("coverflow-carousel:scratch-complete",{detail:{index:l,length:this.cards.length,percent:y},bubbles:!0,composed:!0}))};this.rootEl.addEventListener("complete",e),this.cleanup.push(()=>this.rootEl.removeEventListener("complete",e))}setupLightDomObserver(){this.lightDomObserver||(this.lightDomObserver=new MutationObserver(t=>{this.suppressMutations||!t.some(s=>!(s.type==="attributes"&&s.attributeName==="slot"))||this.scheduleRefreshFromMutations()}),this.lightDomObserver.observe(this,{...this.lightDomObserverOptions}),this.cleanup.push(()=>{this.lightDomObserver?.disconnect(),this.lightDomObserver=null}))}scheduleRefreshFromMutations(){this.refreshScheduled||(this.refreshScheduled=!0,queueMicrotask(()=>{this.refreshScheduled=!1,this.isConnected&&this.refresh()}))}rebuildCardsFromLightDom(){const t=Array.from(this.trackEl.children).filter(e=>e instanceof HTMLElement&&e.classList.contains("cfc__card")),n=[],s=Array.from(this.children).filter(e=>e instanceof HTMLElement);for(let e=0;e<s.length;e++){const i=s[e],r=t[e]??document.createElement("div"),c=`${this.instanceId}-slot-${e}`;t[e]||(r.className="cfc__card",this.trackEl.append(r)),i.getAttribute("slot")!==c&&i.setAttribute("slot",c);const o=r.querySelector("slot");let l;o instanceof HTMLSlotElement?l=o:(l=document.createElement("slot"),r.replaceChildren(l)),l.name!==c&&(l.name=c),n.push(r)}for(let e=s.length;e<t.length;e++)t[e]?.remove();this.cards=n,this.hasAppliedInitialLayout=!1,this.lastLayoutIndex=null,this.lastVisibleSet=new Set}getVisibleSet(){const t=this.cards.length,n=new Set;if(t<=0)return n;const s=Math.floor(t/2);if(v>=s){for(let e=0;e<t;e++)n.add(e);return n}for(let e=-v;e<=v;e++)n.add(m(this.currentIndex+e,t));return n}buildDots(){const t=Array.from(this.dotsEl.children).filter(i=>i instanceof HTMLElement&&i.classList.contains("cfc__dot"));if(!p(this,"show-dots",!1)){t.forEach(i=>{i.remove()}),this.dots=[];return}const s=[],e=this.cards.length;for(let i=0;i<e;i++){const r=t[i]??document.createElement("span");t[i]||this.dotsEl.append(r),r.className="cfc__dot",r.setAttribute("aria-hidden","true"),s.push(r)}for(let i=e;i<t.length;i++)t[i]?.remove();this.dots=s,this.updateDotsVisualState()}computeCardState(t){const n=this.cards.length,s=D(this.currentIndex,t,n),e=Math.abs(s);return{index:t,delta:s,abs:e,isVisible:e<=v,isActive:t===this.currentIndex}}applyCardState(t,n){t.setAttribute("aria-hidden",n.isVisible?"false":"true"),t.dataset.active=n.isActive?"true":"false",t.dataset.cfcIndex=String(n.index),t.setAttribute("role","group"),t.setAttribute("aria-roledescription","slide"),t.setAttribute("aria-setsize",String(this.cards.length)),t.setAttribute("aria-posinset",String(n.index+1));const s=`${this.instanceId}-slide-${n.index}`;t.id=s;const e=String(n.delta),i=String(n.abs),r=t.dataset.cfcDelta,c=t.dataset.cfcAbs;r!==e&&(t.style.setProperty("--cfc-delta",e),t.dataset.cfcDelta=e),c!==i&&(t.style.setProperty("--cfc-abs",i),t.dataset.cfcAbs=i)}applyLayoutAndA11y(t){if(this.cards.length){if(this.hasAppliedInitialLayout){const n=this.getVisibleSet(),s=new Set;this.lastVisibleSet.forEach(e=>{s.add(e)}),n.forEach(e=>{s.add(e)}),this.lastLayoutIndex!=null&&s.add(this.lastLayoutIndex),s.add(this.currentIndex),s.forEach(e=>{const i=this.cards[e];if(!i)return;const r=this.computeCardState(e);this.applyCardState(i,r)}),this.lastLayoutIndex=this.currentIndex,this.lastVisibleSet=n}else{for(let n=0;n<this.cards.length;n++){const s=this.cards[n];if(!s)continue;const e=this.computeCardState(n);this.applyCardState(s,e)}this.hasAppliedInitialLayout=!0,this.lastLayoutIndex=this.currentIndex,this.lastVisibleSet=this.getVisibleSet()}this.updateDotsVisualState(),t.announce&&p(this,"announce-changes",!0)&&this.announce(`Slide ${this.currentIndex+1} of ${this.cards.length}`),t.emitChange&&this.emitChange()}}updateDotsVisualState(){if(this.dots.length)for(let t=0;t<this.dots.length;t++){const n=this.dots[t],s=t===this.currentIndex;n.dataset.active=s?"true":"false"}}lockUntilTransitionEnd(){this.pendingAnimToken++;const t=this.pendingAnimToken;if(L()){this.unlockAnimation();return}const n=this.cards[this.currentIndex];if(!n){this.unlockAnimation();return}const s=getComputedStyle(n),e=k(s,"transform");if(e<=0){this.unlockAnimation();return}const i=x(s.getPropertyValue("--cfc-transition-ms").trim(),400),c=Math.max(e,i)+60;this.animFallbackTimerId!==null&&window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=window.setTimeout(()=>{this.pendingAnimToken===t&&this.unlockAnimation()},c)}unlockAnimation(){this.isAnimating=!1,this.animFallbackTimerId!==null&&(window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=null)}emitChange(){this.dispatchEvent(new CustomEvent("coverflow-carousel:change",{detail:{index:this.currentIndex,length:this.cards.length}}))}dispatchReady(){this.dispatchEvent(new CustomEvent("coverflow-carousel:ready",{detail:{index:this.currentIndex,length:this.cards.length}}))}announce(t){this.liveRegion.textContent="",queueMicrotask(()=>{this.liveRegion.textContent=t})}reflectIndexAttr(){this.reflectGuard=!0;try{this.setAttribute("index",String(this.currentIndex))}finally{this.reflectGuard=!1}}applyStyles(t){if(typeof t=="string"){if(b(this.shadow)){const n=E(t);if(n){this.shadow.adoptedStyleSheets=[n],this.styleEl=null;return}}this.styleEl||(this.styleEl=document.createElement("style")),this.styleEl.textContent=t;return}if(t&&b(this.shadow)){this.shadow.adoptedStyleSheets=[t],this.styleEl=null;return}if(f.defaultStylesheet&&b(this.shadow)){this.shadow.adoptedStyleSheets=[f.defaultStylesheet],this.styleEl=null;return}this.styleEl||(this.styleEl=document.createElement("style")),this.styleEl.textContent=_}}function N(a={}){const{selector:t="coverflow-carousel",onReady:n,onChange:s,onScratchComplete:e,stylesheet:i}=a,r=Array.from(document.querySelectorAll(t));return(n||s||e)&&r.forEach(c=>{n&&c.addEventListener("coverflow-carousel:ready",o=>{n(c,o.detail)}),s&&c.addEventListener("coverflow-carousel:change",o=>{s(c,o.detail)}),e&&c.addEventListener("coverflow-carousel:scratch-complete",o=>{e(c,o.detail)})}),i&&r.forEach(c=>{const o=c;typeof i=="string"?o.adoptStyles(i):o.adoptStylesheet(i)}),r}function F(a="coverflow-carousel"){typeof window>"u"||!("customElements"in window)||customElements.get(a)||customElements.define(a,f)}h.CoverflowCarouselElement=f,h.coverflowCarouselCssText=I,h.initCoverflowCarousels=N,h.registerCoverflowCarouselElement=F,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
167
+ `,I=d;function E(a){return"adoptedStyleSheets"in a}function y(a){try{const t=new CSSStyleSheet;return t.replaceSync(a),t}catch{return null}}const C=y(d),k=d;function g(a){return a.split(",").map(t=>t.trim()).filter(Boolean)}function x(a,t){const n=a.trim();if(!n)return t;if(n.endsWith("ms")){const e=Number(n.slice(0,-2).trim());return Number.isFinite(e)?e:t}if(n.endsWith("s")){const e=Number(n.slice(0,-1).trim());return Number.isFinite(e)?e*1e3:t}const s=Number(n);return Number.isFinite(s)?s:t}function _(a,t){const n=g(a.transitionProperty),s=g(a.transitionDuration),e=g(a.transitionDelay);if(!n.length)return 0;const r=(S=>{const u=n.indexOf(S);if(u>=0)return u;const A=n.indexOf("all");return A>=0?A:-1})(t);if(r<0)return 0;const o=s[Math.min(r,s.length-1)]??"0s",l=e[Math.min(r,e.length-1)]??"0s",c=x(o,0),p=x(l,0);return Math.max(0,c+p)}function T(){return window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches??!1}function m(a,t,n){if(!a.hasAttribute(t))return n;const s=a.getAttribute(t);return s==null||s===""?!0:s!=="false"}function L(a,t,n){const s=a.getAttribute(t);if(s==null)return n;const e=Number(s.trim());return Number.isFinite(e)?Math.trunc(e):n}function w(a,t){const n=a.getAttribute(t);if(n==null)return null;const s=n.trim();return s||null}function v(a,t){return t<=0?0:(a%t+t)%t}function D(a,t,n){const s=t-a,e=n/2;return s>e?s-n:s<-e?s+n:s}const b=1;let F=0;class f extends HTMLElement{static defaultStylesheet=C;static observedAttributes=["start-index","index","show-dots","show-arrows","announce-changes"];shadow=this.attachShadow({mode:"open"});instanceId=`cfc-${++F}`;rootEl;trackEl;dotsEl;prevBtn;nextBtn;liveRegion;baseStyles=null;overrideStyles=null;baseStyleEl=null;overrideStyleEl=null;cards=[];dots=[];currentIndex=0;isAnimating=!1;hasAppliedInitialLayout=!1;lastLayoutIndex=null;lastVisibleSet=new Set;pendingAnimToken=0;animFallbackTimerId=null;cleanup=[];lightDomObserverOptions={childList:!0,attributes:!0,subtree:!0};lightDomObserver=null;refreshScheduled=!1;suppressMutations=!1;reflectGuard=!1;connectedCallback(){this.render(),this.readAttributes({isInit:!0}),this.refresh(),this.setupLightDomObserver()}disconnectedCallback(){this.destroy()}attributeChangedCallback(t,n,s){if(!this.isConnected||this.reflectGuard)return;this.readAttributes({isInit:!1});const e=w(this,"index");if(e!=null){const i=v(Number(e),this.cards.length);if(Number.isFinite(i)&&i!==this.currentIndex){this.goTo(i);return}}this.applyLayoutAndA11y({announce:!0,emitChange:!1})}next(){this.goTo(this.currentIndex+1)}prev(){this.goTo(this.currentIndex-1)}goTo(t){if(this.isAnimating)return;const n=v(t,this.cards.length);n!==this.currentIndex&&(this.isAnimating=!0,this.currentIndex=n,this.reflectIndexAttr(),this.applyLayoutAndA11y({announce:!0,emitChange:!0}),this.lockUntilTransitionEnd())}refresh(){const t=this.lightDomObserver;t&&(this.suppressMutations=!0,t.disconnect(),t.takeRecords()),this.rebuildCardsFromLightDom();const n=L(this,"start-index",0),s=w(this,"index"),e=s!=null?Number(s):n,i=Number.isFinite(e)?e:0;this.currentIndex=v(i,this.cards.length),this.reflectIndexAttr(),this.buildDots(),this.hasAppliedInitialLayout=!1,this.lastLayoutIndex=null,this.lastVisibleSet=new Set,this.applyLayoutAndA11y({announce:!0,emitChange:!1}),this.dispatchReady(),t&&(t.observe(this,this.lightDomObserverOptions),t.takeRecords(),this.suppressMutations=!1)}destroy(){this.animFallbackTimerId!==null&&(window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=null),this.cleanup.forEach(t=>{t()}),this.cleanup=[],this.isAnimating=!1}adoptStylesheet(t){this.setBaseStyles(t)}adoptStyles(t){this.setBaseStyles(t)}adoptStyleOverrides(t){this.setOverrideStyles(t)}readAttributes(t){this.rootEl||this.render();const n=m(this,"show-arrows",!1),s=m(this,"show-dots",!1);this.prevBtn.style.display=n?"":"none",this.nextBtn.style.display=n?"":"none",this.dotsEl.style.display=s?"":"none";const e=this.getAttribute("aria-label");e&&this.rootEl.setAttribute("aria-label",e),t.isInit&&this.setAttribute("aria-roledescription","carousel")}render(){this.applyAllStyles(),this.rootEl=document.createElement("div"),this.rootEl.className="cfc",this.trackEl=document.createElement("div"),this.trackEl.className="cfc__track",this.prevBtn=document.createElement("button"),this.prevBtn.type="button",this.prevBtn.className="cfc__arrow cfc__arrow--left",this.prevBtn.setAttribute("aria-label","Previous"),this.prevBtn.textContent="‹",this.nextBtn=document.createElement("button"),this.nextBtn.type="button",this.nextBtn.className="cfc__arrow cfc__arrow--right",this.nextBtn.setAttribute("aria-label","Next"),this.nextBtn.textContent="›",this.dotsEl=document.createElement("div"),this.dotsEl.className="cfc__dots",this.liveRegion=document.createElement("div"),this.liveRegion.className="cfc__sr",this.liveRegion.setAttribute("aria-live","polite"),this.liveRegion.setAttribute("aria-atomic","true"),this.rootEl.append(this.trackEl,this.prevBtn,this.nextBtn,this.dotsEl,this.liveRegion),this.shadow.innerHTML="",this.baseStyleEl&&this.shadow.append(this.baseStyleEl),this.overrideStyleEl&&this.shadow.append(this.overrideStyleEl),this.shadow.append(this.rootEl),this.bindEvents()}bindEvents(){this.cleanup.forEach(i=>{i()}),this.cleanup=[];const t=()=>this.prev(),n=()=>this.next();this.prevBtn.addEventListener("click",t),this.nextBtn.addEventListener("click",n),this.cleanup.push(()=>this.prevBtn.removeEventListener("click",t)),this.cleanup.push(()=>this.nextBtn.removeEventListener("click",n));const s=i=>{if(!this.isAnimating||i.propertyName!=="transform"||!(i.target instanceof HTMLElement))return;const r=this.cards[this.currentIndex];r&&i.target===r&&this.unlockAnimation()};this.rootEl.addEventListener("transitionend",s),this.cleanup.push(()=>this.rootEl.removeEventListener("transitionend",s));const e=i=>{const r=i.target;if(!(r instanceof HTMLElement)||r.tagName!=="SCRATCH-REVEAL")return;const o=i.composedPath?.();if(!o?.length)return;const l=o.find(u=>u instanceof HTMLElement&&u.classList.contains("cfc__card")&&u.dataset.cfcIndex!=null);if(!l)return;const c=Number(l.dataset.cfcIndex);if(!Number.isFinite(c))return;const S=i.detail?.percent??100;this.dispatchEvent(new CustomEvent("coverflow-carousel:scratch-complete",{detail:{index:c,length:this.cards.length,percent:S},bubbles:!0,composed:!0}))};this.rootEl.addEventListener("complete",e),this.cleanup.push(()=>this.rootEl.removeEventListener("complete",e))}setupLightDomObserver(){this.lightDomObserver||(this.lightDomObserver=new MutationObserver(t=>{this.suppressMutations||!t.some(s=>!(s.type==="attributes"&&s.attributeName==="slot"))||this.scheduleRefreshFromMutations()}),this.lightDomObserver.observe(this,{...this.lightDomObserverOptions}),this.cleanup.push(()=>{this.lightDomObserver?.disconnect(),this.lightDomObserver=null}))}scheduleRefreshFromMutations(){this.refreshScheduled||(this.refreshScheduled=!0,queueMicrotask(()=>{this.refreshScheduled=!1,this.isConnected&&this.refresh()}))}rebuildCardsFromLightDom(){const t=Array.from(this.trackEl.children).filter(e=>e instanceof HTMLElement&&e.classList.contains("cfc__card")),n=[],s=Array.from(this.children).filter(e=>e instanceof HTMLElement);for(let e=0;e<s.length;e++){const i=s[e],r=t[e]??document.createElement("div"),o=`${this.instanceId}-slot-${e}`;t[e]||(r.className="cfc__card",this.trackEl.append(r)),i.getAttribute("slot")!==o&&i.setAttribute("slot",o);const l=r.querySelector("slot");let c;l instanceof HTMLSlotElement?c=l:(c=document.createElement("slot"),r.replaceChildren(c)),c.name!==o&&(c.name=o),n.push(r)}for(let e=s.length;e<t.length;e++)t[e]?.remove();this.cards=n,this.hasAppliedInitialLayout=!1,this.lastLayoutIndex=null,this.lastVisibleSet=new Set}getVisibleSet(){const t=this.cards.length,n=new Set;if(t<=0)return n;const s=Math.floor(t/2);if(b>=s){for(let e=0;e<t;e++)n.add(e);return n}for(let e=-b;e<=b;e++)n.add(v(this.currentIndex+e,t));return n}buildDots(){const t=Array.from(this.dotsEl.children).filter(i=>i instanceof HTMLElement&&i.classList.contains("cfc__dot"));if(!m(this,"show-dots",!1)){t.forEach(i=>{i.remove()}),this.dots=[];return}const s=[],e=this.cards.length;for(let i=0;i<e;i++){const r=t[i]??document.createElement("span");t[i]||this.dotsEl.append(r),r.className="cfc__dot",r.setAttribute("aria-hidden","true"),s.push(r)}for(let i=e;i<t.length;i++)t[i]?.remove();this.dots=s,this.updateDotsVisualState()}computeCardState(t){const n=this.cards.length,s=D(this.currentIndex,t,n),e=Math.abs(s);return{index:t,delta:s,abs:e,isVisible:e<=b,isActive:t===this.currentIndex}}applyCardState(t,n){t.setAttribute("aria-hidden",n.isVisible?"false":"true"),t.dataset.active=n.isActive?"true":"false",t.dataset.cfcIndex=String(n.index),t.setAttribute("role","group"),t.setAttribute("aria-roledescription","slide"),t.setAttribute("aria-setsize",String(this.cards.length)),t.setAttribute("aria-posinset",String(n.index+1));const s=`${this.instanceId}-slide-${n.index}`;t.id=s;const e=String(n.delta),i=String(n.abs),r=t.dataset.cfcDelta,o=t.dataset.cfcAbs;r!==e&&(t.style.setProperty("--cfc-delta",e),t.dataset.cfcDelta=e),o!==i&&(t.style.setProperty("--cfc-abs",i),t.dataset.cfcAbs=i)}applyLayoutAndA11y(t){if(this.cards.length){if(this.hasAppliedInitialLayout){const n=this.getVisibleSet(),s=new Set;this.lastVisibleSet.forEach(e=>{s.add(e)}),n.forEach(e=>{s.add(e)}),this.lastLayoutIndex!=null&&s.add(this.lastLayoutIndex),s.add(this.currentIndex),s.forEach(e=>{const i=this.cards[e];if(!i)return;const r=this.computeCardState(e);this.applyCardState(i,r)}),this.lastLayoutIndex=this.currentIndex,this.lastVisibleSet=n}else{for(let n=0;n<this.cards.length;n++){const s=this.cards[n];if(!s)continue;const e=this.computeCardState(n);this.applyCardState(s,e)}this.hasAppliedInitialLayout=!0,this.lastLayoutIndex=this.currentIndex,this.lastVisibleSet=this.getVisibleSet()}this.updateDotsVisualState(),t.announce&&m(this,"announce-changes",!0)&&this.announce(`Slide ${this.currentIndex+1} of ${this.cards.length}`),t.emitChange&&this.emitChange()}}updateDotsVisualState(){if(this.dots.length)for(let t=0;t<this.dots.length;t++){const n=this.dots[t],s=t===this.currentIndex;n.dataset.active=s?"true":"false"}}lockUntilTransitionEnd(){this.pendingAnimToken++;const t=this.pendingAnimToken;if(T()){this.unlockAnimation();return}const n=this.cards[this.currentIndex];if(!n){this.unlockAnimation();return}const s=getComputedStyle(n),e=_(s,"transform");if(e<=0){this.unlockAnimation();return}const i=x(s.getPropertyValue("--cfc-transition-ms").trim(),400),o=Math.max(e,i)+60;this.animFallbackTimerId!==null&&window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=window.setTimeout(()=>{this.pendingAnimToken===t&&this.unlockAnimation()},o)}unlockAnimation(){this.isAnimating=!1,this.animFallbackTimerId!==null&&(window.clearTimeout(this.animFallbackTimerId),this.animFallbackTimerId=null)}emitChange(){this.dispatchEvent(new CustomEvent("coverflow-carousel:change",{detail:{index:this.currentIndex,length:this.cards.length}}))}dispatchReady(){this.dispatchEvent(new CustomEvent("coverflow-carousel:ready",{detail:{index:this.currentIndex,length:this.cards.length}}))}announce(t){this.liveRegion.textContent="",queueMicrotask(()=>{this.liveRegion.textContent=t})}reflectIndexAttr(){this.reflectGuard=!0;try{this.setAttribute("index",String(this.currentIndex))}finally{this.reflectGuard=!1}}setBaseStyles(t){this.baseStyles=t??null,this.applyAllStyles()}setOverrideStyles(t){this.overrideStyles=t??null,this.applyAllStyles()}applyAllStyles(){const t=this.baseStyles,n=this.overrideStyles;if(E(this.shadow)){const e=[];if(typeof t=="string"){const i=y(t);if(!i){this.applyAllStylesFallback();return}e.push(i)}else if(t)e.push(t);else if(f.defaultStylesheet)e.push(f.defaultStylesheet);else{this.applyAllStylesFallback();return}if(typeof n=="string"){const i=y(n);if(!i){this.applyAllStylesFallback();return}e.push(i)}else n&&e.push(n);this.shadow.adoptedStyleSheets=e,this.baseStyleEl?.remove(),this.overrideStyleEl?.remove(),this.baseStyleEl=null,this.overrideStyleEl=null;return}this.applyAllStylesFallback()}applyAllStylesFallback(){const t=this.baseStyles,n=this.overrideStyles;E(this.shadow)&&(this.shadow.adoptedStyleSheets=[]);const s=typeof t=="string"?t:k,e=typeof n=="string"?n:"";this.baseStyleEl||(this.baseStyleEl=document.createElement("style")),this.baseStyleEl.textContent=s,e?(this.overrideStyleEl||(this.overrideStyleEl=document.createElement("style")),this.overrideStyleEl.textContent=e):(this.overrideStyleEl?.remove(),this.overrideStyleEl=null)}}function M(a={}){const{selector:t="coverflow-carousel",onReady:n,onChange:s,onScratchComplete:e,stylesheet:i,styleOverrides:r}=a,o=Array.from(document.querySelectorAll(t));return(n||s||e)&&o.forEach(l=>{n&&l.addEventListener("coverflow-carousel:ready",c=>{n(l,c.detail)}),s&&l.addEventListener("coverflow-carousel:change",c=>{s(l,c.detail)}),e&&l.addEventListener("coverflow-carousel:scratch-complete",c=>{e(l,c.detail)})}),i&&o.forEach(l=>{const c=l;typeof i=="string"?c.adoptStyles(i):c.adoptStylesheet(i)}),r&&o.forEach(l=>{l.adoptStyleOverrides(r)}),o}function N(a="coverflow-carousel"){typeof window>"u"||!("customElements"in window)||customElements.get(a)||customElements.define(a,f)}h.CoverflowCarouselElement=f,h.coverflowCarouselCssText=I,h.initCoverflowCarousels=M,h.registerCoverflowCarouselElement=N,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
package/dist/init.d.ts CHANGED
@@ -14,5 +14,6 @@ export type InitCoverflowCarouselsOptions = {
14
14
  percent: number;
15
15
  }) => void;
16
16
  stylesheet?: CSSStyleSheet | string | null;
17
+ styleOverrides?: CSSStyleSheet | string | null;
17
18
  };
18
19
  export declare function initCoverflowCarousels(options?: InitCoverflowCarouselsOptions): HTMLElement[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coverflow-carousel",
3
- "version": "0.2.0-dev.2",
3
+ "version": "0.2.0",
4
4
  "description": "Tiny coverflow carousel Web Component. Exposes API via attributes + events (explicit element registration).",
5
5
  "author": "ux-ui.pro",
6
6
  "license": "MIT",