@taprootio/espalier 2.6.0 → 2.7.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.
@@ -1,51 +1,442 @@
1
- var a=function(h,e,t,i){var o=arguments.length,r=o<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,t):i,s;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(h,e,t,i);else for(var c=h.length-1;c>=0;c--)(s=h[c])&&(r=(o<3?s(r):o>3?s(e,t,r):s(e,t))||r);return o>3&&r&&Object.defineProperty(e,t,r),r},d;import{css as m,html as p,nothing as f}from"lit";import{customElement as y,property as l,state as b}from"lit/decorators.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import{validImageDimensions as u}from"./image-dimensions.js";import"./esp-image-option.js";let n=d=class extends g{constructor(){super(...arguments),this.originalHeight=0,this.originalWidth=0,this.imageUrl="",this.localImage="",this.caption="",this.sizes="100vw",this.loading="eager",this.renderedWidth=0,this.resizeObserver=null,this.handleSlotChange=()=>{this.requestUpdate()}}get isPortrait(){const e=u(this.originalWidth,this.originalHeight);return e!==null&&e.height>e.width}findProjected(){for(const e of this.children)if(e.tagName==="PICTURE"||e.tagName==="IMG")return e;return null}connectedCallback(){super.connectedCallback(),d.ensureProjectionStyles(this.getRootNode()),this.resizeObserver??=new ResizeObserver(e=>{const t=e[0]?.contentBoxSize?.[0],i=Math.round(t?t.inlineSize:e[0]?.contentRect.width??0);i>0&&i!==this.renderedWidth&&(this.renderedWidth=i)}),this.resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this.resizeObserver?.disconnect(),this.resizeObserver=null}effectiveSizes(){return this.renderedWidth>0?`${this.renderedWidth}px`:this.sizes}buildSources(){const e=Array.from(this.querySelectorAll("esp-image-option")),t=new Map;for(const i of e){const o=i.getAttribute("url"),r=Number(i.getAttribute("width"));if(!o||!Number.isFinite(r)||r<=0)continue;const s=i.getAttribute("type")??"",c=t.get(s)??[];c.push({url:o,width:r}),t.set(s,c)}return Array.from(t,([i,o])=>({type:i,srcset:o.sort((r,s)=>r.width-s.width).map(r=>`${r.url} ${r.width}w`).join(", ")})).filter(i=>i.srcset.length>0)}willUpdate(e){if(super.willUpdate(e),!this.hasUpdated||e.has("originalWidth")||e.has("originalHeight")){const t=u(this.originalWidth,this.originalHeight);t?this.style.setProperty("--_esp-image-aspect-ratio",`${t.width} / ${t.height}`):this.style.removeProperty("--_esp-image-aspect-ratio")}}updated(e){if(super.updated(e),this.renderedWidth<=0)return;const t=this.findProjected();if(!t)return;const i=this.effectiveSizes();if(t.tagName==="PICTURE")for(const r of t.querySelectorAll("source"))r.setAttribute("sizes",i);const o=t.tagName==="IMG"?t:t.querySelector("img");o?.hasAttribute("srcset")&&o.setAttribute("sizes",i)}render(){if(this.localImage)return p`<img
1
+ var n=function(p,e,t,r){var i=arguments.length,o=i<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,s;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(p,e,t,r);else for(var c=p.length-1;c>=0;c--)(s=p[c])&&(o=(i<3?s(o):i>3?s(e,t,o):s(e,t))||o);return i>3&&o&&Object.defineProperty(e,t,o),o},m;import{css as T,html as d,nothing as N}from"lit";import{customElement as P,property as l,state as u}from"lit/decorators.js";import{EspalierElementBase as y}from"../shared/esp-element-base.js";import{slotHasContent as f}from"../shared/slot-content.js";import{renderVisualOverlay as R,visualOverlayStyles as I}from"../shared/visual-overlay.js";import{focusConverter as E,normalizeFocus as O}from"./image-focus.js";import{ensureImageTextureFilters as A,imageTextureFilterId as W}from"./image-texture-filters.js";import{getImageTexture as b,isBuiltInImageTexture as x,subscribeToImageTextureRegistry as H}from"../shared/image-texture-registry.js";import{validImageDimensions as _}from"./image-dimensions.js";import"./esp-image-option.js";const k=new Set(["auto","none","flat","top","bottom","left","right","radial"]),S=new Set(["soft","medium","strong"]),w=new Set(["fine","medium","coarse"]),z=new Set(["auto","light","dark"]),j=new Set(["bottom-start","bottom","bottom-end","center","top-start","top","top-end"]);function h(p,e){return{fromAttribute(t){return t&&p.has(t)?t:e},toAttribute(t){return p.has(t)?t:e}}}function C(p){const e=p.trim();if(!e)return null;const t=e.split("/").map(i=>i.trim());if(t.length>2||t.some(i=>i.length===0))return null;const r=t.map(Number);return r.some(i=>!Number.isFinite(i)||i<=0)?null:r.length===1?String(r[0]):`${r[0]} / ${r[1]}`}let a=m=class extends y{constructor(){super(...arguments),this.originalHeight=0,this.originalWidth=0,this.imageUrl="",this.localImage="",this.caption="",this.sizes="100vw",this.loading="eager",this.banner=!1,this.bannerScheme="auto",this.scrim="auto",this.scrimStrength="medium",this.texture="none",this.textureScale="medium",this.contentPosition="bottom-start",this.focusPoint={x:.5,y:.5},this.ratio="",this.compactRatio="",this.renderedWidth=0,this.compact=!1,this.overlayHasContent=!1,this.resizeObserver=null,this.unsubscribeTextures=null,this.handleSlotChange=e=>{if(e.target instanceof HTMLSlotElement){if(e.target.name==="overlay"){const t=f(e.target);t!==this.overlayHasContent&&(this.overlayHasContent=t);return}this.requestUpdate()}}}get isPortrait(){const e=_(this.originalWidth,this.originalHeight);return e!==null&&e.height>e.width}findProjected(){for(const e of this.children)if(e.tagName==="PICTURE"||e.tagName==="IMG")return e;return null}connectedCallback(){super.connectedCallback(),m.ensureProjectionStyles(this.getRootNode()),this.unsubscribeTextures??=H(()=>this.requestUpdate()),this.resizeObserver??=new ResizeObserver(e=>{const t=e[0]?.contentBoxSize?.[0],r=Math.round(t?t.inlineSize:e[0]?.contentRect.width??0);r>0&&r!==this.renderedWidth&&(this.renderedWidth=r)}),this.resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeTextures?.(),this.unsubscribeTextures=null,this.resizeObserver?.disconnect(),this.resizeObserver=null}effectiveSizes(){return this.renderedWidth>0?`${this.renderedWidth}px`:this.sizes}buildSources(){const e=new Map;for(const t of this.querySelectorAll("esp-image-option")){const r=t.getAttribute("url"),i=Number(t.getAttribute("width"));if(!r||!Number.isFinite(i)||i<=0)continue;const o=t.getAttribute("type")??"",s=e.get(o)??[];s.push({url:r,width:i}),e.set(o,s)}return Array.from(e,([t,r])=>({type:t,srcset:r.sort((i,o)=>i.width-o.width).map(i=>`${i.url} ${i.width}w`).join(", ")})).filter(t=>t.srcset.length>0)}resolvedBannerScheme(){return this.bannerScheme!=="auto"?this.bannerScheme:this.scheme==="dark"?"dark":"light"}resolvedTexture(){return x(this.texture)?this.texture:b(this.texture)?this.texture:"none"}resolvedScrim(){return this.scrim!=="auto"?this.scrim:this.overlayHasContent?this.contentPosition.startsWith("top")?"top":this.contentPosition.startsWith("bottom")?"bottom":"radial":"none"}resolvedAspectRatio(){const e=_(this.originalWidth,this.originalHeight);if(!this.banner)return e?`${e.width} / ${e.height}`:null;const t=C(this.ratio);return(this.compact?C(this.compactRatio):null)??t??(e?`${e.width} / ${e.height}`:null)}normalizeEnums(e){e.has("scrim")&&!k.has(this.scrim)&&(this.scrim="auto"),e.has("bannerScheme")&&!z.has(this.bannerScheme)&&(this.bannerScheme="auto"),e.has("scrimStrength")&&!S.has(this.scrimStrength)&&(this.scrimStrength="medium"),e.has("textureScale")&&!w.has(this.textureScale)&&(this.textureScale="medium"),e.has("contentPosition")&&!j.has(this.contentPosition)&&(this.contentPosition="bottom-start")}willUpdate(e){super.willUpdate(e),this.normalizeEnums(e);const t=O(this.focusPoint),r=Number((t.x*100).toFixed(4)),i=Number((t.y*100).toFixed(4));this.style.setProperty("--_esp-image-object-position",`${r}% ${i}%`);const o=this.resolvedAspectRatio();o?this.style.setProperty("--_esp-image-aspect-ratio",o):this.style.removeProperty("--_esp-image-aspect-ratio");const s=this.resolvedTexture();if(["paper","grain","grunge"].includes(s)){const g=s==="grunge"&&this.resolvedBannerScheme()==="light"?"grunge-light":s;this.style.setProperty("--_esp-image-texture-filter",`url(#${W(g,this.textureScale)})`)}else this.style.removeProperty("--_esp-image-texture-filter");const c=x(s)?void 0:b(s),$=[["--_esp-image-registered-image",c?.image],["--_esp-image-registered-size",c?.size],["--_esp-image-registered-repeat",c?.repeat],["--_esp-image-registered-position",c?.position],["--_esp-image-registered-opacity",c?.opacity?.toString()],["--_esp-image-registered-blend-mode",c?.blendMode]];for(const[g,v]of $)v===void 0?this.style.removeProperty(g):this.style.setProperty(g,v)}firstUpdated(e){super.firstUpdated(e);const t=this.shadowRoot?.querySelector('slot[name="overlay"]');t&&(this.overlayHasContent=f(t))}updated(e){if(super.updated(e),["paper","grain","grunge"].includes(this.resolvedTexture())&&this.renderRoot&&A(this.renderRoot),this.renderedWidth>0){const s=this.shadowRoot?.querySelector(".compact-sentinel")?.getBoundingClientRect().width??0,c=s>0&&this.renderedWidth<s;c!==this.compact&&(this.compact=c)}if(this.renderedWidth<=0)return;const t=this.findProjected();if(!t)return;const r=this.effectiveSizes();if(t.tagName==="PICTURE")for(const o of t.querySelectorAll("source"))o.setAttribute("sizes",r);const i=t.tagName==="IMG"?t:t.querySelector("img");i?.hasAttribute("srcset")&&i.setAttribute("sizes",r)}renderMedia(){if(this.localImage)return d`<img
2
2
  src=${this.localImage}
3
3
  alt=${this.caption}
4
4
  decoding="async"
5
5
  loading=${this.loading}
6
- />`;const e=p`<slot @slotchange=${this.handleSlotChange}></slot>`;if(this.findProjected())return e;const t=this.buildSources();return p`<picture>
7
- ${t.map(i=>p`<source
8
- srcset=${i.srcset}
6
+ />`;const e=d`<slot @slotchange=${this.handleSlotChange}></slot>`;if(this.findProjected())return e;const t=this.buildSources();return d`
7
+ <picture>
8
+ ${t.map(r=>d`
9
+ <source
10
+ srcset=${r.srcset}
9
11
  sizes=${this.effectiveSizes()}
10
- type=${i.type||f}
11
- />`)}
12
+ type=${r.type||N}
13
+ />
14
+ `)}
12
15
  <img src=${this.imageUrl} alt=${this.caption} decoding="async" loading=${this.loading} />
13
16
  </picture>
14
- ${e}`}static ensureProjectionStyles(e){const t=e.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&"host"in e?e:e.nodeType===Node.DOCUMENT_NODE?e.head:e.ownerDocument?.head??document.head,i=Array.from(t.querySelectorAll("style[data-esp-image-projection-styles]")),o=i.find(s=>s.textContent===d.projectionStyles);if(o){for(const s of i)s!==o&&s.remove();return}for(const s of i)s.remove();const r=t.ownerDocument.createElement("style");r.dataset.espImageProjectionStyles="",r.textContent=d.projectionStyles,t.appendChild(r)}};n.projectionStyles=`
17
+ ${e}
18
+ `}render(){return d`
19
+ <div
20
+ part="frame"
21
+ class="frame"
22
+ data-banner-scheme=${this.resolvedBannerScheme()}
23
+ data-scrim=${this.resolvedScrim()}
24
+ data-scrim-strength=${this.scrimStrength}
25
+ data-texture=${this.resolvedTexture()}
26
+ data-texture-scale=${this.textureScale}
27
+ data-content-position=${this.contentPosition}
28
+ >
29
+ <div part="image" class="image">${this.renderMedia()}</div>
30
+ ${R({className:"banner-layers",imagePart:"texture",scrimPart:"scrim",texturePart:"texture"})}
31
+ <div part="overlay" class="overlay" ?hidden=${!this.banner||!this.overlayHasContent}>
32
+ <slot name="overlay" @slotchange=${this.handleSlotChange}></slot>
33
+ </div>
34
+ <span class="compact-sentinel" aria-hidden="true"></span>
35
+ </div>
36
+ `}static ensureProjectionStyles(e){const t=e.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&"host"in e?e:e.nodeType===Node.DOCUMENT_NODE?e.head:e.ownerDocument?.head??document.head,r=Array.from(t.querySelectorAll("style[data-esp-image-projection-styles]")),i=r.find(s=>s.textContent===m.projectionStyles);if(i){for(const s of r)s!==i&&s.remove();return}for(const s of r)s.remove();const o=t.ownerDocument.createElement("style");o.dataset.espImageProjectionStyles="",o.textContent=m.projectionStyles,t.append(o)}};a.projectionStyles=`
15
37
  esp-image > picture,
16
38
  esp-image > img {
17
39
  display: block;
18
40
  width: 100%;
19
41
  height: 100%;
20
42
  object-fit: var(--_esp-image-object-fit, cover);
43
+ object-position: var(--esp-image-object-position, var(--_esp-image-object-position, center));
21
44
  }
22
45
  esp-image > picture > img {
23
46
  display: block;
24
47
  width: 100%;
25
48
  height: 100%;
26
49
  object-fit: var(--_esp-image-object-fit, cover);
50
+ object-position: var(--esp-image-object-position, var(--_esp-image-object-position, center));
27
51
  }
28
- `,n.styles=[...g.styles,m`
52
+ `,a.styles=[...y.styles,T`
29
53
  :host {
30
54
  display: block;
31
55
  aspect-ratio: var(--_esp-image-aspect-ratio, auto);
32
- border: var(--esp-image-border, 2px solid var(--esp-color-border));
56
+ border: var(
57
+ --esp-image-border,
58
+ var(--_esp-image-border-default, 2px solid var(--esp-color-border))
59
+ );
33
60
  box-sizing: border-box;
34
- border-radius: var(--esp-size-border-radius);
61
+ border-radius: var(
62
+ --esp-image-border-radius,
63
+ var(--_esp-image-radius-default, var(--esp-size-border-radius))
64
+ );
35
65
  overflow: hidden;
36
66
  position: relative;
37
67
  }
38
68
 
39
- picture {
40
- display: block;
41
- height: 100%;
42
- width: 100%;
69
+ :host([banner]) {
70
+ --_esp-image-border-default: none;
71
+ --_esp-image-radius-default: 0;
72
+ }
73
+
74
+ [hidden] {
75
+ display: none !important;
43
76
  }
44
77
 
78
+ .frame,
79
+ .image,
80
+ picture,
45
81
  img {
46
82
  display: block;
47
- height: 100%;
48
- width: 100%;
83
+ inline-size: 100%;
84
+ block-size: 100%;
85
+ }
86
+
87
+ .frame {
88
+ position: relative;
89
+ overflow: hidden;
90
+
91
+ isolation: isolate;
92
+
93
+ --_esp-image-scrim-resolved: var(
94
+ --esp-image-scrim-color,
95
+ var(--_esp-image-scrim-ink, oklch(0.12 0.015 255))
96
+ );
97
+ --_esp-image-texture-ink-resolved: var(
98
+ --esp-image-texture-color,
99
+ var(--_esp-image-texture-ink, oklch(0.1 0.015 255))
100
+ );
101
+
102
+ --_esp-image-pitch-resolved: var(
103
+ --esp-image-texture-scale,
104
+ var(--_esp-image-texture-pitch, 8px)
105
+ );
106
+ }
107
+ .image {
108
+ position: relative;
109
+ z-index: 0;
110
+ }
111
+
112
+ img {
49
113
  object-fit: var(--_esp-image-object-fit, cover);
114
+ object-position: var(
115
+ --esp-image-object-position,
116
+ var(--_esp-image-object-position, center)
117
+ );
118
+ }
119
+
120
+ .banner-layers {
121
+ display: none;
122
+ }
123
+
124
+ :host([banner]) .banner-layers {
125
+
126
+
127
+ --_esp-overlay-image: var(
128
+ --esp-image-texture-image,
129
+ var(--_esp-image-registered-image, none)
130
+ );
131
+ --_esp-overlay-image-opacity: var(
132
+ --esp-image-texture-image-opacity,
133
+ var(--_esp-image-registered-opacity, 1)
134
+ );
135
+ --_esp-overlay-image-repeat: var(
136
+ --esp-image-texture-repeat,
137
+ var(--_esp-image-registered-repeat, repeat)
138
+ );
139
+ --_esp-overlay-image-position: var(
140
+ --esp-image-texture-position,
141
+ var(--_esp-image-registered-position, 0 0)
142
+ );
143
+ --_esp-overlay-image-size: var(
144
+ --esp-image-texture-size,
145
+ var(--_esp-image-registered-size, auto)
146
+ );
147
+ --_esp-overlay-image-blend-mode: var(
148
+ --esp-image-texture-blend-mode,
149
+ var(--_esp-image-registered-blend-mode, normal)
150
+ );
151
+ --_esp-overlay-scrim-opacity: var(
152
+ --esp-image-scrim-opacity,
153
+ var(--_esp-image-scrim-opacity, 0.56)
154
+ );
155
+
156
+ --_esp-overlay-texture-opacity: var(
157
+ --esp-image-texture-opacity,
158
+ var(--_esp-image-texture-opacity, 1)
159
+ );
160
+ --_esp-overlay-texture-blend-mode: var(
161
+ --esp-image-texture-blend-mode,
162
+ var(--_esp-image-texture-blend-mode, normal)
163
+ );
164
+ --_esp-overlay-texture-filter: var(--_esp-image-texture-filter, none);
165
+ display: block;
166
+ }
167
+
168
+ .frame[data-scrim-strength="soft"] {
169
+ --_esp-image-scrim-opacity: 0.36;
170
+ }
171
+ .frame[data-scrim-strength="medium"] {
172
+ --_esp-image-scrim-opacity: 0.56;
173
+ }
174
+ .frame[data-scrim-strength="strong"] {
175
+ --_esp-image-scrim-opacity: 0.76;
176
+ }
177
+
178
+ .frame[data-scrim="none"] {
179
+ --_esp-overlay-scrim: none;
180
+ }
181
+ .frame[data-scrim="flat"] {
182
+ --_esp-overlay-scrim: var(--_esp-image-scrim-resolved);
183
+ }
184
+ .frame[data-scrim="top"] {
185
+ --_esp-overlay-scrim: linear-gradient(
186
+ to bottom,
187
+ var(--_esp-image-scrim-resolved) 0% 20%,
188
+ color-mix(in oklch, var(--_esp-image-scrim-resolved) 68%, transparent) 48%,
189
+ transparent 78%
190
+ );
191
+ }
192
+ .frame[data-scrim="bottom"] {
193
+ --_esp-overlay-scrim: linear-gradient(
194
+ to top,
195
+ var(--_esp-image-scrim-resolved) 0% 20%,
196
+ color-mix(in oklch, var(--_esp-image-scrim-resolved) 68%, transparent) 48%,
197
+ transparent 78%
198
+ );
199
+ }
200
+ .frame[data-scrim="left"] {
201
+ --_esp-overlay-scrim: linear-gradient(
202
+ to right,
203
+ var(--_esp-image-scrim-resolved) 0% 20%,
204
+ color-mix(in oklch, var(--_esp-image-scrim-resolved) 68%, transparent) 48%,
205
+ transparent 78%
206
+ );
207
+ }
208
+ .frame[data-scrim="right"] {
209
+ --_esp-overlay-scrim: linear-gradient(
210
+ to left,
211
+ var(--_esp-image-scrim-resolved) 0% 20%,
212
+ color-mix(in oklch, var(--_esp-image-scrim-resolved) 68%, transparent) 48%,
213
+ transparent 78%
214
+ );
215
+ }
216
+ .frame[data-scrim="radial"] {
217
+ --_esp-overlay-scrim: radial-gradient(
218
+ circle at center,
219
+ var(--_esp-image-scrim-resolved) 0%,
220
+ color-mix(in oklch, var(--_esp-image-scrim-resolved) 72%, transparent) 34%,
221
+ color-mix(in oklch, var(--_esp-image-scrim-resolved) 28%, transparent) 64%,
222
+ transparent 82%
223
+ );
224
+ }
225
+
226
+
227
+ .frame[data-banner-scheme="dark"] {
228
+ --_esp-image-scrim-ink: oklch(from var(--esp-color-background, oklch(0.98 0 0)) 0.13 c h);
229
+ --_esp-image-texture-ink: oklch(from var(--esp-color-background, oklch(0.98 0 0)) 0.12 c h);
230
+ --_esp-image-overlay-ink: oklch(from var(--esp-color-headings, oklch(0.2 0 0)) 0.97 c h);
231
+ --_esp-image-overlay-text-shadow:
232
+ 0 1px 2px oklch(0.1 0 0 / 0.45), 0 2px 12px oklch(0.1 0 0 / 0.3);
233
+ }
234
+ .frame[data-banner-scheme="light"] {
235
+ --_esp-image-scrim-ink: oklch(from var(--esp-color-background, oklch(0.98 0 0)) 0.97 c h);
236
+ --_esp-image-texture-ink: oklch(from var(--esp-color-background, oklch(0.98 0 0)) 0.98 c h);
237
+ --_esp-image-overlay-ink: oklch(from var(--esp-color-headings, oklch(0.2 0 0)) 0.2 c h);
238
+ --_esp-image-overlay-text-shadow:
239
+ 0 1px 2px oklch(1 0 0 / 0.55), 0 2px 12px oklch(1 0 0 / 0.4);
240
+ }
241
+
242
+ :host([scheme="light"]) .frame[data-banner-scheme="light"],
243
+ :host([scheme="dark"]) .frame[data-banner-scheme="dark"] {
244
+ --_esp-image-scrim-ink: var(--esp-color-background, oklch(0.98 0 0));
245
+ --_esp-image-texture-ink: var(--esp-color-background, oklch(0.98 0 0));
246
+ --_esp-image-overlay-ink: var(--esp-color-headings, oklch(0.2 0 0));
247
+ }
248
+
249
+ .frame[data-banner-scheme="light"][data-texture="halftone"],
250
+ .frame[data-banner-scheme="light"][data-texture="grunge"] {
251
+ --_esp-image-texture-blend-mode: screen;
252
+ }
253
+
254
+ .frame[data-texture-scale="fine"] {
255
+ --_esp-image-texture-pitch: 4px;
256
+ }
257
+ .frame[data-texture-scale="medium"] {
258
+ --_esp-image-texture-pitch: 8px;
259
+ }
260
+ .frame[data-texture-scale="coarse"] {
261
+ --_esp-image-texture-pitch: 14px;
262
+ }
263
+ .frame[data-texture="none"] {
264
+ --_esp-overlay-texture: none;
265
+ }
266
+ .frame[data-texture="dots"] {
267
+ --_esp-overlay-texture: radial-gradient(
268
+ circle,
269
+ var(--_esp-image-texture-ink-resolved) 0 calc(var(--_esp-image-pitch-resolved) * 0.17),
270
+ transparent calc(var(--_esp-image-pitch-resolved) * 0.17 + 0.35px)
271
+ );
272
+ --_esp-overlay-texture-size: var(--_esp-image-pitch-resolved)
273
+ var(--_esp-image-pitch-resolved);
274
+ --_esp-image-texture-opacity: 0.8;
275
+ --_esp-image-texture-blend-mode: normal;
276
+ }
277
+ .frame[data-texture="halftone"] {
278
+ --_esp-overlay-texture: radial-gradient(
279
+ circle,
280
+ var(--_esp-image-texture-ink-resolved) 0 calc(var(--_esp-image-pitch-resolved) * 0.22),
281
+ transparent calc(var(--_esp-image-pitch-resolved) * 0.22 + 0.35px)
282
+ );
283
+ --_esp-overlay-texture-size: var(--_esp-image-pitch-resolved)
284
+ var(--_esp-image-pitch-resolved);
285
+ --_esp-image-texture-opacity: 0.9;
286
+ --_esp-image-texture-blend-mode: multiply;
287
+
288
+ --_esp-overlay-texture-mask: linear-gradient(to top, black, transparent 82%);
289
+ }
290
+ .frame[data-texture="scanlines"] {
291
+ --_esp-overlay-texture: repeating-linear-gradient(
292
+ to bottom,
293
+ var(--_esp-image-texture-ink-resolved) 0 calc(var(--_esp-image-pitch-resolved) * 0.3),
294
+ transparent calc(var(--_esp-image-pitch-resolved) * 0.3) var(--_esp-image-pitch-resolved)
295
+ );
296
+ --_esp-image-texture-opacity: 0.35;
297
+ --_esp-image-texture-blend-mode: normal;
298
+ }
299
+ .frame[data-texture="duotone"] {
300
+ --_esp-overlay-texture: linear-gradient(
301
+ 135deg,
302
+ var(
303
+ --esp-image-duotone-shadow-color,
304
+ oklch(from var(--esp-color-primary, oklch(0.45 0.1 265)) 0.32 c h)
305
+ )
306
+ 0% 42%,
307
+ var(
308
+ --esp-image-duotone-highlight-color,
309
+ oklch(from var(--esp-color-complementary, oklch(0.75 0.1 85)) 0.84 c h)
310
+ )
311
+ 100%
312
+ );
313
+ --_esp-image-texture-opacity: 0.9;
314
+ --_esp-image-texture-blend-mode: color;
315
+ }
316
+
317
+ .frame[data-texture="paper"] {
318
+ --_esp-overlay-texture: linear-gradient(oklch(1 0 0), oklch(1 0 0));
319
+ --_esp-image-texture-opacity: 0.9;
320
+ --_esp-image-texture-blend-mode: overlay;
321
+ }
322
+ .frame[data-texture="grain"] {
323
+ --_esp-overlay-texture: linear-gradient(oklch(1 0 0), oklch(1 0 0));
324
+ --_esp-image-texture-opacity: 0.72;
325
+ --_esp-image-texture-blend-mode: overlay;
326
+ }
327
+ .frame[data-texture="grunge"] {
328
+ --_esp-overlay-texture: linear-gradient(oklch(1 0 0), oklch(1 0 0));
329
+ --_esp-image-texture-opacity: 0.42;
330
+ --_esp-image-texture-blend-mode: multiply;
331
+ }
332
+
333
+ .frame[data-texture="halftone"][data-scrim="top"] {
334
+ --_esp-overlay-texture-mask: linear-gradient(to bottom, black, transparent 82%);
335
+ }
336
+ .frame[data-texture="halftone"][data-scrim="bottom"] {
337
+ --_esp-overlay-texture-mask: linear-gradient(to top, black, transparent 82%);
338
+ }
339
+ .frame[data-texture="halftone"][data-scrim="left"] {
340
+ --_esp-overlay-texture-mask: linear-gradient(to right, black, transparent 82%);
341
+ }
342
+ .frame[data-texture="halftone"][data-scrim="right"] {
343
+ --_esp-overlay-texture-mask: linear-gradient(to left, black, transparent 82%);
344
+ }
345
+ .frame[data-texture="halftone"][data-scrim="radial"] {
346
+ --_esp-overlay-texture-mask: radial-gradient(circle at center, black, transparent 82%);
347
+ }
348
+
349
+ .overlay {
350
+ position: absolute;
351
+ z-index: 2;
352
+ inset: 0;
353
+ display: flex;
354
+ align-items: flex-end;
355
+ justify-content: flex-start;
356
+ padding: var(--esp-image-overlay-padding, var(--esp-size-padding-page));
357
+ color: var(--esp-image-overlay-color, var(--_esp-image-overlay-ink, white));
358
+
359
+ text-shadow: var(
360
+ --esp-image-overlay-text-shadow,
361
+ var(--_esp-image-overlay-text-shadow, none)
362
+ );
363
+ pointer-events: none;
364
+ }
365
+ .overlay slot::slotted(*) {
366
+ color: inherit !important;
367
+ pointer-events: auto;
368
+ }
369
+ .frame[data-content-position="bottom"] .overlay {
370
+ justify-content: center;
371
+ text-align: center;
372
+ }
373
+ .frame[data-content-position="bottom-end"] .overlay {
374
+ justify-content: flex-end;
375
+ text-align: end;
376
+ }
377
+ .frame[data-content-position="center"] .overlay {
378
+ align-items: center;
379
+ justify-content: center;
380
+ text-align: center;
381
+ }
382
+ .frame[data-content-position="top-start"] .overlay {
383
+ align-items: flex-start;
384
+ }
385
+ .frame[data-content-position="top"] .overlay {
386
+ align-items: flex-start;
387
+ justify-content: center;
388
+ text-align: center;
389
+ }
390
+ .frame[data-content-position="top-end"] .overlay {
391
+ align-items: flex-start;
392
+ justify-content: flex-end;
393
+ text-align: end;
394
+ }
395
+
396
+ .compact-sentinel {
397
+ position: absolute;
398
+ inline-size: var(--esp-image-compact-width, 40rem);
399
+ block-size: 0;
400
+ visibility: hidden;
401
+ pointer-events: none;
402
+ }
403
+
404
+ @media (forced-colors: active) {
405
+ :host([banner]) .banner-layers {
406
+ display: none;
407
+ }
408
+ .overlay {
409
+ background: Canvas;
410
+ color: CanvasText;
411
+ }
412
+ }
413
+
414
+ @media (prefers-reduced-transparency: reduce) {
415
+ :host([banner]) .banner-layers {
416
+ --_esp-overlay-scrim-opacity: max(0.82, var(--esp-image-scrim-opacity, 0.82));
417
+ }
418
+ .esp-visual-overlay__texture,
419
+ .esp-visual-overlay__image {
420
+ display: none;
421
+ }
422
+ }
423
+
424
+ @media print {
425
+ :host([banner]) .banner-layers {
426
+ display: none;
427
+ }
428
+
429
+ .overlay {
430
+ background: white;
431
+ color: black;
432
+ }
433
+ }
434
+
435
+ @media (prefers-reduced-motion: reduce) {
436
+ .banner-layers,
437
+ .overlay {
438
+ animation: none !important;
439
+ transition: none !important;
440
+ }
50
441
  }
51
- `],a([l({attribute:"original-height",type:Number})],n.prototype,"originalHeight",void 0),a([l({attribute:"original-width",type:Number})],n.prototype,"originalWidth",void 0),a([l({attribute:"low-res",type:String})],n.prototype,"imageUrl",void 0),a([l({attribute:"local-image",type:String})],n.prototype,"localImage",void 0),a([l({type:String})],n.prototype,"caption",void 0),a([l({attribute:"sizes",type:String})],n.prototype,"sizes",void 0),a([l({attribute:"loading",type:String})],n.prototype,"loading",void 0),a([b()],n.prototype,"renderedWidth",void 0),n=d=a([y("esp-image")],n);export{n as EspalierImage};
442
+ `,I],n([l({attribute:"original-height",type:Number})],a.prototype,"originalHeight",void 0),n([l({attribute:"original-width",type:Number})],a.prototype,"originalWidth",void 0),n([l({attribute:"low-res",type:String})],a.prototype,"imageUrl",void 0),n([l({attribute:"local-image",type:String})],a.prototype,"localImage",void 0),n([l({type:String})],a.prototype,"caption",void 0),n([l({attribute:"sizes",type:String})],a.prototype,"sizes",void 0),n([l({attribute:"loading",type:String})],a.prototype,"loading",void 0),n([l({type:Boolean,reflect:!0})],a.prototype,"banner",void 0),n([l({attribute:"banner-scheme",converter:h(z,"auto"),reflect:!0})],a.prototype,"bannerScheme",void 0),n([l({converter:h(k,"auto"),reflect:!0})],a.prototype,"scrim",void 0),n([l({attribute:"scrim-strength",converter:h(S,"medium"),reflect:!0})],a.prototype,"scrimStrength",void 0),n([l({type:String,reflect:!0})],a.prototype,"texture",void 0),n([l({attribute:"texture-scale",converter:h(w,"medium"),reflect:!0})],a.prototype,"textureScale",void 0),n([l({attribute:"content-position",converter:h(j,"bottom-start"),reflect:!0})],a.prototype,"contentPosition",void 0),n([l({attribute:"focus",converter:E,reflect:!0})],a.prototype,"focusPoint",void 0),n([l({type:String})],a.prototype,"ratio",void 0),n([l({attribute:"compact-ratio",type:String})],a.prototype,"compactRatio",void 0),n([u()],a.prototype,"renderedWidth",void 0),n([u()],a.prototype,"compact",void 0),n([u()],a.prototype,"overlayHasContent",void 0),a=m=n([P("esp-image")],a);export{a as EspalierImage,C as parseImageRatio};
@@ -0,0 +1,16 @@
1
+ import type { ComplexAttributeConverter } from "lit";
2
+ /** A normalized point within an image, from its top-left corner. */
3
+ export interface FocusPoint {
4
+ x: number;
5
+ y: number;
6
+ }
7
+ export declare const CENTER_FOCUS: Readonly<FocusPoint>;
8
+ /** Return a safe copy of a normalized focus value, or center when invalid. */
9
+ export declare function normalizeFocus(value: unknown): FocusPoint;
10
+ /** Parse the public `"x y"` attribute grammar. */
11
+ export declare function parseFocus(value: string | null): FocusPoint;
12
+ /** Serialize a focus value for HTML without losing round-trip precision. */
13
+ export declare function serializeFocus(value: FocusPoint): string;
14
+ export declare const focusConverter: ComplexAttributeConverter<FocusPoint>;
15
+ /** Clamp an authoring value to the normalized focus range. */
16
+ export declare function clampFocus(value: FocusPoint): FocusPoint;
@@ -0,0 +1 @@
1
+ const n=Object.freeze({x:.5,y:.5});function o(t){return typeof t=="number"&&Number.isFinite(t)&&t>=0&&t<=1}function c(t){return typeof t=="object"&&t!==null&&"x"in t&&"y"in t&&o(t.x)&&o(t.y)?{x:t.x,y:t.y}:{...n}}function s(t){if(!t)return{...n};const r=t.trim().split(/\s+/);if(r.length!==2)return{...n};const[i,e]=r.map(Number);return o(i)&&o(e)?{x:i,y:e}:{...n}}function x(t){const r=c(t);return`${r.x} ${r.y}`}const m={fromAttribute:s,toAttribute(t){return x(t)}};function p(t){const r=i=>Math.min(1,Math.max(0,i));return{x:Number.isFinite(t.x)?r(t.x):n.x,y:Number.isFinite(t.y)?r(t.y):n.y}}export{n as CENTER_FOCUS,p as clampFocus,m as focusConverter,c as normalizeFocus,s as parseFocus,x as serializeFocus};
@@ -0,0 +1 @@
1
+ const p="data-esp-image-texture-filters",l=[{id:"paper-fine",baseFrequency:"0.016",octaves:6,post:"paper",contrast:2.6},{id:"paper-medium",baseFrequency:"0.011",octaves:6,post:"paper",contrast:2.6},{id:"paper-coarse",baseFrequency:"0.007",octaves:6,post:"paper",contrast:2.6},{id:"grain-fine",baseFrequency:"0.65",octaves:1,post:"grain",contrast:1.7},{id:"grain-medium",baseFrequency:"0.5",octaves:1,post:"grain",contrast:1.7},{id:"grain-coarse",baseFrequency:"0.38",octaves:1,post:"grain",contrast:1.7},{id:"grunge-fine",baseFrequency:"0.14",octaves:2,post:"grunge",markLightness:0},{id:"grunge-medium",baseFrequency:"0.09",octaves:3,post:"grunge",markLightness:0},{id:"grunge-coarse",baseFrequency:"0.05",octaves:4,post:"grunge",markLightness:0},{id:"grunge-light-fine",baseFrequency:"0.14",octaves:2,post:"grunge",markLightness:1},{id:"grunge-light-medium",baseFrequency:"0.09",octaves:3,post:"grunge",markLightness:1},{id:"grunge-light-coarse",baseFrequency:"0.05",octaves:4,post:"grunge",markLightness:1}];function m(e){return e.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&"host"in e?e:e.nodeType===Node.DOCUMENT_NODE?e.body:e.ownerDocument?.body??document.body}function h(e){const o=m(e);if(o.querySelector(`svg[${p}]`))return;const g="http://www.w3.org/2000/svg",d=o.ownerDocument,t=(n,r)=>{const s=d.createElementNS(g,n);for(const[a,i]of Object.entries(r))s.setAttribute(a,i);return s},c=t("svg",{[p]:"","aria-hidden":"true",width:"0",height:"0"});c.setAttribute("style","position:absolute;inline-size:0;block-size:0;overflow:hidden");const u=t("defs",{});for(const n of l){const r=t("filter",{id:`esp-image-texture-${n.id}`,x:"-10%",y:"-10%",width:"120%",height:"120%"});if(r.append(t("feTurbulence",{type:"fractalNoise",baseFrequency:n.baseFrequency,numOctaves:String(n.octaves),seed:"17",stitchTiles:"stitch",result:"noise"})),n.post==="grunge"){const s=n.markLightness??0;r.append(t("feColorMatrix",{in:"noise",type:"matrix",values:`0 0 0 0 ${s} 0 0 0 0 ${s} 0 0 0 0 ${s} 0 0 0 -1.4 0.95`,result:"thresholded"}));const a=t("feComponentTransfer",{in:"thresholded"});a.append(t("feFuncA",{type:"discrete",tableValues:"0 0 0 1 1"})),r.append(a)}else if(r.append(t("feColorMatrix",{in:"noise",type:"saturate",values:"0",result:"mono"})),n.contrast){const s=n.contrast,a=(1-s)/2,i=t("feComponentTransfer",{in:"mono"});for(const f of["feFuncR","feFuncG","feFuncB"])i.append(t(f,{type:"linear",slope:String(s),intercept:String(a)}));r.append(i)}u.append(r)}c.append(u),o.append(c)}function y(e,o){return`esp-image-texture-${e}-${o}`}export{h as ensureImageTextureFilters,y as imageTextureFilterId};
package/dist/index.d.ts CHANGED
@@ -25,9 +25,11 @@ export * from "./empty-state/esp-empty-state.js";
25
25
  export * from "./image-upload/esp-image-upload.js";
26
26
  export * from "./file-upload/esp-file-upload.js";
27
27
  export * from "./font-picker/esp-font-picker.js";
28
+ export * from "./focus-picker/esp-focus-picker.js";
28
29
  export * from "./footer/index.js";
29
30
  export * from "./grid/esp-grid.js";
30
31
  export * from "./image/esp-image.js";
32
+ export * from "./image/image-focus.js";
31
33
  export * from "./lightbox/esp-lightbox.js";
32
34
  export * from "./info/esp-info.js";
33
35
  export * from "./input/esp-input.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./box/esp-box.js";export*from"./action-menu/esp-action-menu.js";export*from"./action-menu/esp-action-menu-item.js";export*from"./avatar/esp-avatar.js";export*from"./avatar/esp-profile-chip.js";export*from"./badge/esp-badge.js";export*from"./checkbox/esp-checkbox.js";export*from"./checkbox/esp-checkbox-group.js";export*from"./data-cell/esp-data-cell.js";export*from"./radio-button/esp-radio-button.js";export*from"./radio-button/esp-radio-button-group.js";export*from"./repeater/esp-repeater.js";export*from"./breadcrumbs/esp-breadcrumbs.js";export*from"./button/esp-button.js";export*from"./button/esp-button-group.js";export*from"./color-picker/esp-color-picker.js";export*from"./flyout/esp-flyout.js";export*from"./form/esp-form.js";export*from"./form-item/esp-form-item.js";export*from"./header/index.js";export*from"./page/esp-page.js";export*from"./popover/esp-popover.js";export*from"./dialog/esp-dialog.js";export*from"./empty-state/esp-empty-state.js";export*from"./image-upload/esp-image-upload.js";export*from"./file-upload/esp-file-upload.js";export*from"./font-picker/esp-font-picker.js";export*from"./footer/index.js";export*from"./grid/esp-grid.js";export*from"./image/esp-image.js";export*from"./lightbox/esp-lightbox.js";export*from"./info/esp-info.js";export*from"./input/esp-input.js";export*from"./textarea/esp-textarea.js";export*from"./pickers/esp-pick-one.js";export*from"./pickers/esp-pick-some.js";export*from"./pickers/esp-picker-menu.js";export*from"./pickers/esp-picker-item.js";export*from"./root/esp-root.js";export*from"./menu/index.js";export*from"./burger/esp-burger.js";export*from"./date-picker/esp-date-picker.js";export*from"./details/esp-details.js";export*from"./details/esp-details-group.js";export*from"./tabs/esp-tab.js";export*from"./tabs/esp-tab-group.js";export*from"./slider/esp-slider.js";export*from"./switch/esp-switch.js";export*from"./toaster/esp-toaster.js";export*from"./tooltip/esp-tooltip.js";export*from"./progress/esp-progress.js";export*from"./search/esp-search.js";export*from"./status-indicator/esp-status-indicator.js";export*from"./tree/esp-tree.js";export*from"./tree/esp-tree-item.js";import{DEFAULT_ICON_SPRITE_URL as to,DEFAULT_ICON_VIEW_BOX as mo,INTENT_VARIANTS as po,normalizeIntentVariant as fo,getIconHref as xo,getIconHrefForHost as ao,getIconSpriteUrl as lo}from"./shared/intent-values.js";import{EspalierElementBase as To}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as io}from"./shared/validation.js";import{FormFieldController as Io}from"./shared/form-field-controller.js";import{traverseToClosest as ho}from"./shared/utilities.js";import{showToast as Fo}from"./shared/toast-events.js";import{showFlyout as Ao,closeFlyout as Lo}from"./shared/flyout-events.js";import{getEspBus as uo}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as So,releasePreviewUrl as bo}from"./image-upload/image-helpers.js";import{calculatePhotoLayout as Co}from"./shared/justified-layout.js";import{encodeTheme as Vo,parseTheme as Wo,mergePartials as Bo,layerThemes as Po,buildTaprootLightTheme as vo,buildTaprootDarkTheme as wo,NESTED_THEME_KEYS as Go}from"./shared/theme.js";import{WEIGHT_LABELS as Ro,extractWeights as ko,normalizeWeight as zo,bestAvailableWeight as Yo,extractFamily as Ko,getFallbackFont as Mo}from"./shared/font-helpers.js";import{getGoogleFonts as jo}from"./font-picker/esp-font-picker.js";export{to as DEFAULT_ICON_SPRITE_URL,mo as DEFAULT_ICON_VIEW_BOX,To as EspalierElementBase,Io as FormFieldController,po as INTENT_VARIANTS,Go as NESTED_THEME_KEYS,io as VALIDITY_CHANGED_EVENT,Ro as WEIGHT_LABELS,Yo as bestAvailableWeight,wo as buildTaprootDarkTheme,vo as buildTaprootLightTheme,Co as calculatePhotoLayout,Lo as closeFlyout,Vo as encodeTheme,Ko as extractFamily,ko as extractWeights,uo as getEspBus,Mo as getFallbackFont,jo as getGoogleFonts,xo as getIconHref,ao as getIconHrefForHost,lo as getIconSpriteUrl,So as getImageDetails,Po as layerThemes,Bo as mergePartials,fo as normalizeIntentVariant,zo as normalizeWeight,Wo as parseTheme,bo as releasePreviewUrl,Ao as showFlyout,Fo as showToast,ho as traverseToClosest};
1
+ export*from"./box/esp-box.js";export*from"./action-menu/esp-action-menu.js";export*from"./action-menu/esp-action-menu-item.js";export*from"./avatar/esp-avatar.js";export*from"./avatar/esp-profile-chip.js";export*from"./badge/esp-badge.js";export*from"./checkbox/esp-checkbox.js";export*from"./checkbox/esp-checkbox-group.js";export*from"./data-cell/esp-data-cell.js";export*from"./radio-button/esp-radio-button.js";export*from"./radio-button/esp-radio-button-group.js";export*from"./repeater/esp-repeater.js";export*from"./breadcrumbs/esp-breadcrumbs.js";export*from"./button/esp-button.js";export*from"./button/esp-button-group.js";export*from"./color-picker/esp-color-picker.js";export*from"./flyout/esp-flyout.js";export*from"./form/esp-form.js";export*from"./form-item/esp-form-item.js";export*from"./header/index.js";export*from"./page/esp-page.js";export*from"./popover/esp-popover.js";export*from"./dialog/esp-dialog.js";export*from"./empty-state/esp-empty-state.js";export*from"./image-upload/esp-image-upload.js";export*from"./file-upload/esp-file-upload.js";export*from"./font-picker/esp-font-picker.js";export*from"./focus-picker/esp-focus-picker.js";export*from"./footer/index.js";export*from"./grid/esp-grid.js";export*from"./image/esp-image.js";export*from"./image/image-focus.js";export*from"./lightbox/esp-lightbox.js";export*from"./info/esp-info.js";export*from"./input/esp-input.js";export*from"./textarea/esp-textarea.js";export*from"./pickers/esp-pick-one.js";export*from"./pickers/esp-pick-some.js";export*from"./pickers/esp-picker-menu.js";export*from"./pickers/esp-picker-item.js";export*from"./root/esp-root.js";export*from"./menu/index.js";export*from"./burger/esp-burger.js";export*from"./date-picker/esp-date-picker.js";export*from"./details/esp-details.js";export*from"./details/esp-details-group.js";export*from"./tabs/esp-tab.js";export*from"./tabs/esp-tab-group.js";export*from"./slider/esp-slider.js";export*from"./switch/esp-switch.js";export*from"./toaster/esp-toaster.js";export*from"./tooltip/esp-tooltip.js";export*from"./progress/esp-progress.js";export*from"./search/esp-search.js";export*from"./status-indicator/esp-status-indicator.js";export*from"./tree/esp-tree.js";export*from"./tree/esp-tree-item.js";import{DEFAULT_ICON_SPRITE_URL as po,DEFAULT_ICON_VIEW_BOX as fo,INTENT_VARIANTS as xo,normalizeIntentVariant as ao,getIconHref as lo,getIconHrefForHost as so,getIconSpriteUrl as To}from"./shared/intent-values.js";import{EspalierElementBase as io}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as Io}from"./shared/validation.js";import{FormFieldController as ho}from"./shared/form-field-controller.js";import{traverseToClosest as Fo}from"./shared/utilities.js";import{showToast as Ao}from"./shared/toast-events.js";import{showFlyout as No,closeFlyout as uo}from"./shared/flyout-events.js";import{getEspBus as Ho}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as yo,releasePreviewUrl as Co}from"./image-upload/image-helpers.js";import{calculatePhotoLayout as Vo}from"./shared/justified-layout.js";import{encodeTheme as Bo,parseTheme as Po,mergePartials as vo,layerThemes as wo,buildTaprootLightTheme as Go,buildTaprootDarkTheme as Oo,NESTED_THEME_KEYS as Ro}from"./shared/theme.js";import{WEIGHT_LABELS as zo,extractWeights as Yo,normalizeWeight as Ko,bestAvailableWeight as Mo,extractFamily as Xo,getFallbackFont as jo}from"./shared/font-helpers.js";import{getGoogleFonts as Jo}from"./font-picker/esp-font-picker.js";export{po as DEFAULT_ICON_SPRITE_URL,fo as DEFAULT_ICON_VIEW_BOX,io as EspalierElementBase,ho as FormFieldController,xo as INTENT_VARIANTS,Ro as NESTED_THEME_KEYS,Io as VALIDITY_CHANGED_EVENT,zo as WEIGHT_LABELS,Mo as bestAvailableWeight,Oo as buildTaprootDarkTheme,Go as buildTaprootLightTheme,Vo as calculatePhotoLayout,uo as closeFlyout,Bo as encodeTheme,Xo as extractFamily,Yo as extractWeights,Ho as getEspBus,jo as getFallbackFont,Jo as getGoogleFonts,lo as getIconHref,so as getIconHrefForHost,To as getIconSpriteUrl,yo as getImageDetails,wo as layerThemes,vo as mergePartials,ao as normalizeIntentVariant,Ko as normalizeWeight,Po as parseTheme,Co as releasePreviewUrl,No as showFlyout,Ao as showToast,Fo as traverseToClosest};
@@ -1,6 +1,8 @@
1
1
  import { LitElement, type PropertyValues } from "lit";
2
2
  import { type SchemeEvents, type SeedColorRoot } from "../shared/bus-events.js";
3
3
  import { type EspalierTheme } from "../shared/theme.js";
4
+ import { type ImageTextureDefinition } from "../shared/image-texture-registry.js";
5
+ export { registerImageTexture, registeredImageTextures, BUILT_IN_IMAGE_TEXTURES, type ImageTextureDefinition, } from "../shared/image-texture-registry.js";
4
6
  export type GoogleFontLoadingPolicy = "auto" | "none";
5
7
  export type { SchemeEvents } from "../shared/bus-events.js";
6
8
  /**
@@ -52,6 +54,13 @@ export type { SchemeEvents } from "../shared/bus-events.js";
52
54
  * `theme-changed`, and `icon-sprite-url-changed`. Components derived from
53
55
  * `EspalierElementBase` use the same closest-root filter internally.
54
56
  *
57
+ * The root also owns the application's banner-texture vocabulary:
58
+ * `EspalierRoot.registerTexture(name, definition)` registers an
59
+ * image-backed texture preset that any
60
+ * [esp-image](/components/image) banner in the application selects with
61
+ * `texture="<name>"`, and `EspalierRoot.registeredTextures()` enumerates
62
+ * the presets for building texture pickers.
63
+ *
55
64
  * @customElement esp-root
56
65
  * @slot - Place Espalier components and content here.
57
66
  *
@@ -64,6 +73,17 @@ export type { SchemeEvents } from "../shared/bus-events.js";
64
73
  *
65
74
  */
66
75
  export declare class EspalierRoot extends LitElement implements SeedColorRoot {
76
+ /**
77
+ * Register (or replace) a named, image-backed banner-texture preset.
78
+ * Any `esp-image` banner under a root selects it with `texture="<name>"`;
79
+ * banners already pointing at the name re-render, so registration at
80
+ * mount and markup order never race. Static delegate to
81
+ * `registerImageTexture` so script-only contexts (docs demos, published
82
+ * sites) can reach it from the root element without module imports.
83
+ */
84
+ static registerTexture(name: string, definition: ImageTextureDefinition): void;
85
+ /** Snapshot of the registered texture presets, for building pickers. */
86
+ static registeredTextures(): Map<string, Readonly<ImageTextureDefinition>>;
67
87
  /** Unique ID for correlating bus events across multiple roots. */
68
88
  correlationId: `${string}-${string}-${string}-${string}-${string}`;
69
89
  /**