@taprootio/espalier 2.5.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.
- package/CHANGELOG.md +25 -0
- package/css/textures/banner-textures.css +26 -0
- package/css/textures/espalier-grain.png +0 -0
- package/css/textures/espalier-grunge.png +0 -0
- package/css/textures/espalier-paper.png +0 -0
- package/custom-elements.json +5583 -1218
- package/dist/focus-picker/esp-focus-picker.d.ts +77 -0
- package/dist/focus-picker/esp-focus-picker.js +129 -0
- package/dist/footer/esp-footer-column.d.ts +47 -0
- package/dist/footer/esp-footer-column.js +8 -0
- package/dist/footer/esp-footer.d.ts +37 -5
- package/dist/footer/esp-footer.js +19 -20
- package/dist/footer/index.d.ts +1 -0
- package/dist/footer/index.js +1 -1
- package/dist/image/esp-image.d.ts +225 -70
- package/dist/image/esp-image.js +408 -17
- package/dist/image/image-focus.d.ts +16 -0
- package/dist/image/image-focus.js +1 -0
- package/dist/image/image-texture-filters.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/root/esp-root.d.ts +59 -1
- package/dist/root/esp-root.js +2 -2
- package/dist/shared/bus-events.d.ts +12 -5
- package/dist/shared/esp-element-base.js +2 -2
- package/dist/shared/image-texture-registry.d.ts +45 -0
- package/dist/shared/image-texture-registry.js +1 -0
- package/dist/shared/root-event-subscription.js +1 -0
- package/dist/shared/visual-overlay.js +51 -0
- package/espalier.token-manifest.json +158 -2
- package/licenses/ASSET_PROVENANCE.md +3 -0
- package/licenses/asset-provenance.json +68 -1
- package/package.json +15 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type PropertyValues } from "lit";
|
|
2
|
+
import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
3
|
+
import { type FocusPoint } from "../image/image-focus.js";
|
|
4
|
+
import "../image/esp-image.js";
|
|
5
|
+
export declare const FOCUS_CHANGED_EVENT = "focus-changed";
|
|
6
|
+
export type FocusChangedDetail = FocusPoint;
|
|
7
|
+
/**
|
|
8
|
+
* A keyboard- and pointer-operable focal-point authoring control with live
|
|
9
|
+
* banner-cover previews.
|
|
10
|
+
*
|
|
11
|
+
* The HTML value is `focus="x y"`. In JavaScript use `.focusPoint`; the name
|
|
12
|
+
* avoids replacing the platform's required `HTMLElement.focus()` method.
|
|
13
|
+
*
|
|
14
|
+
* ```html
|
|
15
|
+
* <esp-focus-picker
|
|
16
|
+
* src="/assets/focus-picker-unsplash.jpg"
|
|
17
|
+
* alt="A woman standing in a sunlit field with her back to the camera"
|
|
18
|
+
* focus="0.65 0.55"
|
|
19
|
+
* ratio="3/1"
|
|
20
|
+
* compact-ratio="3/2"
|
|
21
|
+
* ></esp-focus-picker>
|
|
22
|
+
* <p>
|
|
23
|
+
* Photo by <a href="https://unsplash.com/@sashafreemind?utm_source=espalier&utm_medium=referral">Sasha Freemind</a>
|
|
24
|
+
* on <a href="https://unsplash.com/?utm_source=espalier&utm_medium=referral">Unsplash</a>.
|
|
25
|
+
* </p>
|
|
26
|
+
* <script>
|
|
27
|
+
* const picker = findByTagName("esp-focus-picker")[0];
|
|
28
|
+
* picker.addEventListener("focus-changed", (event) => {
|
|
29
|
+
* localStorage.setItem("banner-focus", JSON.stringify(event.detail));
|
|
30
|
+
* });
|
|
31
|
+
* </script>
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @event {CustomEvent<{x: number, y: number}>} focus-changed - Bubbles across
|
|
35
|
+
* shadow boundaries after every pointer or keyboard adjustment.
|
|
36
|
+
* @csspart picker - The complete control layout.
|
|
37
|
+
* @csspart stage - The source-image authoring surface.
|
|
38
|
+
* @csspart image - The source image.
|
|
39
|
+
* @csspart marker - The focusable focal-point marker.
|
|
40
|
+
* @csspart previews - The live preview group.
|
|
41
|
+
* @csspart preview - A live `esp-image` preview cell.
|
|
42
|
+
* @cssprop --esp-focus-picker-gap - Gap between the stage and previews.
|
|
43
|
+
* @cssprop --esp-focus-picker-stage-background - Empty/loading stage color.
|
|
44
|
+
* @cssprop --esp-focus-picker-marker-size - Focal marker diameter.
|
|
45
|
+
* @cssprop --esp-focus-picker-marker-color - Focal marker fill.
|
|
46
|
+
* @cssprop --esp-focus-picker-marker-border - Focal marker border.
|
|
47
|
+
* @cssprop --esp-focus-picker-marker-shadow - Focal marker shadow.
|
|
48
|
+
* @cssprop --esp-focus-picker-focus-outline - Marker focus-visible outline.
|
|
49
|
+
* @docPageTitle Focus Picker
|
|
50
|
+
* @docUrl /components/focus-picker
|
|
51
|
+
* @menuGroup Media
|
|
52
|
+
* @menuLabel Focus Picker
|
|
53
|
+
* @menuIcon target
|
|
54
|
+
*/
|
|
55
|
+
export declare class EspalierFocusPicker extends EspalierElementBase {
|
|
56
|
+
/** Image URL shown in the authoring surface and live previews. */
|
|
57
|
+
src: string;
|
|
58
|
+
/** Alternative text for the source-image authoring surface. */
|
|
59
|
+
alt: string;
|
|
60
|
+
/** Normalized current value. Its HTML attribute is named `focus`. */
|
|
61
|
+
focusPoint: FocusPoint;
|
|
62
|
+
/** Aspect ratio for the wide live preview. */
|
|
63
|
+
ratio: string;
|
|
64
|
+
/** Aspect ratio for the compact live preview. */
|
|
65
|
+
compactRatio: string;
|
|
66
|
+
protected willUpdate(changedProperties: PropertyValues): void;
|
|
67
|
+
protected render(): import("lit-html").TemplateResult<1>;
|
|
68
|
+
static styles: import("lit").CSSResult[];
|
|
69
|
+
}
|
|
70
|
+
declare global {
|
|
71
|
+
interface HTMLElementTagNameMap {
|
|
72
|
+
"esp-focus-picker": EspalierFocusPicker;
|
|
73
|
+
}
|
|
74
|
+
interface HTMLElementEventMap {
|
|
75
|
+
"focus-changed": CustomEvent<FocusChangedDetail>;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
var s=function(n,e,r,i){var c=arguments.length,o=c<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,r):i,p;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(n,e,r,i);else for(var l=n.length-1;l>=0;l--)(p=n[l])&&(o=(c<3?p(o):c>3?p(e,r,o):p(e,r))||o);return c>3&&o&&Object.defineProperty(e,r,o),o};import{css as d,html as f}from"lit";import{customElement as m,property as a}from"lit/decorators.js";import{styleMap as h}from"lit/directives/style-map.js";import{EspalierElementBase as u}from"../shared/esp-element-base.js";import{clampFocus as g,focusConverter as v,normalizeFocus as b}from"../image/image-focus.js";import"../image/esp-image.js";const $="focus-changed";let t=class extends u{constructor(){super(...arguments),this.src="",this.alt="",this.focusPoint={x:.5,y:.5},this.ratio="3/1",this.compactRatio="3/2",this.activePointer=null,this.handlePointerDown=e=>{e.button===0&&(e.preventDefault(),this.activePointer=e.pointerId,e.currentTarget.setPointerCapture?.(e.pointerId),this.updateFromPointer(e))},this.handlePointerMove=e=>{e.pointerId===this.activePointer&&this.updateFromPointer(e)},this.handlePointerEnd=e=>{e.pointerId===this.activePointer&&(e.currentTarget.releasePointerCapture?.(e.pointerId),this.activePointer=null)},this.handleKeyDown=e=>{const r=e.shiftKey?.01:.05,i={};if(e.key==="ArrowLeft")i.x=-r;else if(e.key==="ArrowRight")i.x=r;else if(e.key==="ArrowUp")i.y=-r;else if(e.key==="ArrowDown")i.y=r;else return;e.preventDefault(),this.updateFocus({x:this.focusPoint.x+(i.x??0),y:this.focusPoint.y+(i.y??0)})}}willUpdate(e){if(super.willUpdate(e),e.has("focusPoint")){const r=this.focusPoint,i=b(r);(i.x!==r?.x||i.y!==r?.y)&&(this.focusPoint=i)}}updateFocus(e){const r=g(e),i={x:Number(r.x.toFixed(4)),y:Number(r.y.toFixed(4))};i.x===this.focusPoint.x&&i.y===this.focusPoint.y||(this.focusPoint=i,this.dispatchEvent(new CustomEvent("focus-changed",{detail:{...i},bubbles:!0,composed:!0})))}updateFromPointer(e){const i=e.currentTarget.getBoundingClientRect();i.width<=0||i.height<=0||this.updateFocus({x:(e.clientX-i.left)/i.width,y:(e.clientY-i.top)/i.height})}render(){const e=Math.round(this.focusPoint.x*100),r=Math.round(this.focusPoint.y*100),i={"--_esp-focus-picker-x":`${this.focusPoint.x*100}%`,"--_esp-focus-picker-y":`${this.focusPoint.y*100}%`};return f`
|
|
2
|
+
<div part="picker" class="picker">
|
|
3
|
+
<div
|
|
4
|
+
part="stage"
|
|
5
|
+
class="stage"
|
|
6
|
+
@pointerdown=${this.handlePointerDown}
|
|
7
|
+
@pointermove=${this.handlePointerMove}
|
|
8
|
+
@pointerup=${this.handlePointerEnd}
|
|
9
|
+
@pointercancel=${this.handlePointerEnd}
|
|
10
|
+
>
|
|
11
|
+
<img part="image" src=${this.src} alt=${this.alt} draggable="false" />
|
|
12
|
+
|
|
13
|
+
<div
|
|
14
|
+
part="marker"
|
|
15
|
+
class="marker"
|
|
16
|
+
style=${h(i)}
|
|
17
|
+
role="slider"
|
|
18
|
+
tabindex="0"
|
|
19
|
+
aria-label="Image focal point"
|
|
20
|
+
aria-valuemin="0"
|
|
21
|
+
aria-valuemax="100"
|
|
22
|
+
aria-valuenow=${e}
|
|
23
|
+
aria-valuetext=${`Horizontal ${e}%, vertical ${r}%`}
|
|
24
|
+
@keydown=${this.handleKeyDown}
|
|
25
|
+
></div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div part="previews" class="previews" aria-label="Banner framing previews">
|
|
29
|
+
<figure part="preview" class="preview wide">
|
|
30
|
+
<figcaption>Wide (${this.ratio})</figcaption>
|
|
31
|
+
<esp-image
|
|
32
|
+
banner
|
|
33
|
+
scrim="none"
|
|
34
|
+
.localImage=${this.src}
|
|
35
|
+
.caption=${""}
|
|
36
|
+
.focusPoint=${this.focusPoint}
|
|
37
|
+
.ratio=${this.ratio}
|
|
38
|
+
></esp-image>
|
|
39
|
+
</figure>
|
|
40
|
+
<figure part="preview" class="preview compact">
|
|
41
|
+
<figcaption>Compact (${this.compactRatio})</figcaption>
|
|
42
|
+
<esp-image
|
|
43
|
+
banner
|
|
44
|
+
scrim="none"
|
|
45
|
+
.localImage=${this.src}
|
|
46
|
+
.caption=${""}
|
|
47
|
+
.focusPoint=${this.focusPoint}
|
|
48
|
+
.ratio=${this.compactRatio}
|
|
49
|
+
></esp-image>
|
|
50
|
+
</figure>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
`}};t.styles=[...u.styles,d`
|
|
54
|
+
:host {
|
|
55
|
+
display: block;
|
|
56
|
+
min-inline-size: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.picker {
|
|
60
|
+
display: grid;
|
|
61
|
+
gap: var(--esp-focus-picker-gap, var(--esp-size-big));
|
|
62
|
+
min-inline-size: 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.stage {
|
|
66
|
+
position: relative;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
min-block-size: var(--esp-size-big);
|
|
69
|
+
border: 1px solid var(--esp-color-border);
|
|
70
|
+
border-radius: var(--esp-size-border-radius);
|
|
71
|
+
background: var(--esp-focus-picker-stage-background, var(--esp-color-layer-2));
|
|
72
|
+
cursor: crosshair;
|
|
73
|
+
touch-action: none;
|
|
74
|
+
user-select: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.stage img {
|
|
78
|
+
display: block;
|
|
79
|
+
inline-size: 100%;
|
|
80
|
+
block-size: auto;
|
|
81
|
+
pointer-events: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.marker {
|
|
85
|
+
position: absolute;
|
|
86
|
+
inset-inline-start: var(--_esp-focus-picker-x);
|
|
87
|
+
inset-block-start: var(--_esp-focus-picker-y);
|
|
88
|
+
inline-size: var(--esp-focus-picker-marker-size, var(--esp-size-medium));
|
|
89
|
+
block-size: var(--esp-focus-picker-marker-size, var(--esp-size-medium));
|
|
90
|
+
translate: -50% -50%;
|
|
91
|
+
box-sizing: border-box;
|
|
92
|
+
border: var(--esp-focus-picker-marker-border, 2px solid white);
|
|
93
|
+
border-radius: 50%;
|
|
94
|
+
background: var(--esp-focus-picker-marker-color, var(--esp-color-action-background));
|
|
95
|
+
box-shadow: var(--esp-focus-picker-marker-shadow, 0 1px 5px oklch(0 0 0 / 0.65));
|
|
96
|
+
cursor: grab;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.marker:active {
|
|
100
|
+
cursor: grabbing;
|
|
101
|
+
}
|
|
102
|
+
.marker:focus-visible {
|
|
103
|
+
outline: var(--esp-focus-picker-focus-outline, 3px solid var(--esp-color-link));
|
|
104
|
+
outline-offset: 3px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.previews {
|
|
108
|
+
display: grid;
|
|
109
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
|
|
110
|
+
gap: var(--esp-focus-picker-gap, var(--esp-size-big));
|
|
111
|
+
min-inline-size: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
figure {
|
|
115
|
+
min-inline-size: 0;
|
|
116
|
+
margin: 0;
|
|
117
|
+
}
|
|
118
|
+
figcaption {
|
|
119
|
+
margin-block-end: var(--esp-size-tiny);
|
|
120
|
+
color: var(--esp-color-text);
|
|
121
|
+
font-size: var(--esp-type-small);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@media (prefers-reduced-motion: reduce) {
|
|
125
|
+
.marker {
|
|
126
|
+
transition: none;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
`],s([a({type:String})],t.prototype,"src",void 0),s([a({type:String})],t.prototype,"alt",void 0),s([a({attribute:"focus",converter:v,reflect:!0})],t.prototype,"focusPoint",void 0),s([a({type:String})],t.prototype,"ratio",void 0),s([a({attribute:"compact-ratio",type:String})],t.prototype,"compactRatio",void 0),t=s([m("esp-focus-picker")],t);export{t as EspalierFocusPicker,$ as FOCUS_CHANGED_EVENT};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
2
|
+
/**
|
|
3
|
+
* A layout-only column for creator-controlled link-group stacking inside
|
|
4
|
+
* [`<esp-footer>`](/components/footer/).
|
|
5
|
+
*
|
|
6
|
+
* Use bare `esp-footer-link-group` children when groups should auto-flow
|
|
7
|
+
* independently through the footer grid. Wrap ordered groups in
|
|
8
|
+
* `esp-footer-column` when they must remain together as one grid item:
|
|
9
|
+
*
|
|
10
|
+
* ```html
|
|
11
|
+
* <esp-footer columns="3">
|
|
12
|
+
* <esp-footer-column>
|
|
13
|
+
* <esp-footer-link-group heading="Product">
|
|
14
|
+
* <a href="/features">Features</a>
|
|
15
|
+
* <a href="/pricing">Pricing</a>
|
|
16
|
+
* </esp-footer-link-group>
|
|
17
|
+
* <esp-footer-link-group heading="Company">
|
|
18
|
+
* <a href="/about">About</a>
|
|
19
|
+
* <a href="/careers">Careers</a>
|
|
20
|
+
* </esp-footer-link-group>
|
|
21
|
+
* </esp-footer-column>
|
|
22
|
+
* </esp-footer>
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* The component adds no heading, landmark, or chrome. It preserves the
|
|
26
|
+
* slotted order of its child groups and uses `--esp-footer-row-gap`, defaulting
|
|
27
|
+
* to `var(--esp-size-big)`, for its vertical rhythm.
|
|
28
|
+
*
|
|
29
|
+
* @customElement esp-footer-column
|
|
30
|
+
* @slot - Ordered `esp-footer-link-group` children belonging to this column.
|
|
31
|
+
* @cssprop --esp-footer-row-gap - Vertical gap between footer grid rows and
|
|
32
|
+
* link groups stacked in `esp-footer-column`. Defaults to `var(--esp-size-big)`.
|
|
33
|
+
* @docPageTitle Footer Column
|
|
34
|
+
* @docUrl /components/footer/column
|
|
35
|
+
* @menuGroup Structure
|
|
36
|
+
* @menuLabel Footer Column
|
|
37
|
+
* @menuIcon columns
|
|
38
|
+
*/
|
|
39
|
+
export declare class EspalierFooterColumn extends EspalierElementBase {
|
|
40
|
+
protected render(): import("lit-html").TemplateResult<1>;
|
|
41
|
+
static styles: import("lit").CSSResult[];
|
|
42
|
+
}
|
|
43
|
+
declare global {
|
|
44
|
+
interface HTMLElementTagNameMap {
|
|
45
|
+
"esp-footer-column": EspalierFooterColumn;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var m=function(r,o,t,l){var n=arguments.length,e=n<3?o:l===null?l=Object.getOwnPropertyDescriptor(o,t):l,s;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")e=Reflect.decorate(r,o,t,l);else for(var f=r.length-1;f>=0;f--)(s=r[f])&&(e=(n<3?s(e):n>3?s(o,t,e):s(o,t))||e);return n>3&&e&&Object.defineProperty(o,t,e),e};import{css as c,html as a}from"lit";import{customElement as u}from"lit/decorators.js";import{EspalierElementBase as p}from"../shared/esp-element-base.js";let i=class extends p{render(){return a`<slot></slot>`}};i.styles=[...p.styles,c`
|
|
2
|
+
:host {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: var(--esp-footer-row-gap, var(--esp-size-big));
|
|
6
|
+
min-inline-size: 0;
|
|
7
|
+
}
|
|
8
|
+
`],i=m([u("esp-footer-column")],i);export{i as EspalierFooterColumn};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type PropertyValues } from "lit";
|
|
2
2
|
import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
3
|
+
import "./esp-footer-column.js";
|
|
3
4
|
import "./esp-footer-link-group.js";
|
|
4
5
|
export type FooterColumns = "auto" | "1" | "2" | "3" | "4" | "5" | "6";
|
|
5
6
|
/**
|
|
@@ -7,10 +8,12 @@ export type FooterColumns = "auto" | "1" | "2" | "3" | "4" | "5" | "6";
|
|
|
7
8
|
* artwork, link groups, supporting actions, and legal or utility content.
|
|
8
9
|
* Its background remains full-bleed while its content automatically aligns
|
|
9
10
|
* to the surface of a containing [`<esp-page>`](/components/page/).
|
|
11
|
+
* The decorative background uses the same internal visual-layer primitive as
|
|
12
|
+
* `esp-image` banners; the footer's public background tokens are unchanged.
|
|
10
13
|
*
|
|
11
|
-
* Use [`<esp-footer-link-group>`](/components/footer/link-group/) children
|
|
12
|
-
*
|
|
13
|
-
* columns when they no longer fit.
|
|
14
|
+
* Use bare [`<esp-footer-link-group>`](/components/footer/link-group/) children
|
|
15
|
+
* when navigation groups should auto-flow independently through the grid.
|
|
16
|
+
* `columns` is a maximum: the grid always drops columns when they no longer fit.
|
|
14
17
|
*
|
|
15
18
|
* ```html
|
|
16
19
|
* <esp-footer
|
|
@@ -35,6 +38,33 @@ export type FooterColumns = "auto" | "1" | "2" | "3" | "4" | "5" | "6";
|
|
|
35
38
|
* </esp-footer>
|
|
36
39
|
* ```
|
|
37
40
|
*
|
|
41
|
+
* For creator-controlled columns, wrap each ordered stack of groups in
|
|
42
|
+
* [`<esp-footer-column>`](/components/footer/column/). Each wrapper is one grid
|
|
43
|
+
* item at wide sizes; below the footer's compact container breakpoint, the
|
|
44
|
+
* columns become full-width rows in their slotted order. `columns` remains the
|
|
45
|
+
* maximum number of grid items per row:
|
|
46
|
+
*
|
|
47
|
+
* ```html
|
|
48
|
+
* <esp-footer columns="3">
|
|
49
|
+
* <esp-footer-column>
|
|
50
|
+
* <esp-footer-link-group heading="Product">
|
|
51
|
+
* <a href="/features">Features</a>
|
|
52
|
+
* <a href="/pricing">Pricing</a>
|
|
53
|
+
* </esp-footer-link-group>
|
|
54
|
+
* <esp-footer-link-group heading="Company">
|
|
55
|
+
* <a href="/about">About</a>
|
|
56
|
+
* <a href="/careers">Careers</a>
|
|
57
|
+
* </esp-footer-link-group>
|
|
58
|
+
* </esp-footer-column>
|
|
59
|
+
* <esp-footer-column>
|
|
60
|
+
* <esp-footer-link-group heading="Resources">
|
|
61
|
+
* <a href="/docs">Documentation</a>
|
|
62
|
+
* <a href="/support">Support</a>
|
|
63
|
+
* </esp-footer-link-group>
|
|
64
|
+
* </esp-footer-column>
|
|
65
|
+
* </esp-footer>
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
38
68
|
* A slotted brand replaces configured branding, while the media slot accepts
|
|
39
69
|
* a responsive `picture`, native image, or `esp-image`. Media spans the
|
|
40
70
|
* surface-aligned content well; use the decorative background layer for
|
|
@@ -112,7 +142,8 @@ export type FooterColumns = "auto" | "1" | "2" | "3" | "4" | "5" | "6";
|
|
|
112
142
|
* preferably responsive `<picture>` markup or an `esp-image` with appropriate
|
|
113
143
|
* alternative text.
|
|
114
144
|
* @slot brand - Custom brand identity. Overrides configured brand properties.
|
|
115
|
-
* @slot - `esp-footer-link-group`
|
|
145
|
+
* @slot - Bare `esp-footer-link-group` children for automatic flow, or
|
|
146
|
+
* `esp-footer-column` children for creator-controlled group stacks.
|
|
116
147
|
* @slot aside - Supporting content such as a newsletter, call to action,
|
|
117
148
|
* contact details, social links, or locale controls.
|
|
118
149
|
* @slot bottom - Copyright, legal/utility links, attribution, accessibility
|
|
@@ -137,7 +168,8 @@ export type FooterColumns = "auto" | "1" | "2" | "3" | "4" | "5" | "6";
|
|
|
137
168
|
* @cssprop --esp-footer-padding-inline - Content inline padding. Defaults to `var(--esp-size-padding-page)`.
|
|
138
169
|
* @cssprop --esp-footer-section-gap - Gap between media, primary, and bottom regions. Defaults to `var(--esp-size-big)`.
|
|
139
170
|
* @cssprop --esp-footer-column-gap - Gap between link-group columns and major primary regions. Defaults to `var(--esp-size-padding-page)`.
|
|
140
|
-
* @cssprop --esp-footer-row-gap -
|
|
171
|
+
* @cssprop --esp-footer-row-gap - Vertical gap between footer grid rows and
|
|
172
|
+
* link groups stacked in `esp-footer-column`. Defaults to `var(--esp-size-big)`.
|
|
141
173
|
* @cssprop --esp-footer-link-group-min-width - Intrinsic minimum link-group column width. Defaults to `10rem`.
|
|
142
174
|
* @cssprop --esp-footer-link-group-gap - Space between a link-group heading and its links. Defaults to `var(--esp-size-small)`.
|
|
143
175
|
* @cssprop --esp-footer-brand-logo-size - Configured logo block size. Defaults to `3rem`.
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
var t=function(i,o,e
|
|
1
|
+
var t=function(i,o,a,e){var s=arguments.length,d=s<3?o:e===null?e=Object.getOwnPropertyDescriptor(o,a):e,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")d=Reflect.decorate(i,o,a,e);else for(var p=i.length-1;p>=0;p--)(l=i[p])&&(d=(s<3?l(d):s>3?l(o,a,d):l(o,a))||d);return s>3&&d&&Object.defineProperty(o,a,d),d};import{css as f,html as v,nothing as y}from"lit";import{customElement as x,property as n,state as _}from"lit/decorators.js";import{classMap as C}from"lit/directives/class-map.js";import{styleMap as k}from"lit/directives/style-map.js";import{renderConfiguredBrand as z,resolveConfiguredBrand as B}from"../shared/configured-brand.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import{slotHasContent as h}from"../shared/slot-content.js";import{renderVisualOverlay as S,visualOverlayStyles as L}from"../shared/visual-overlay.js";import"./esp-footer-column.js";import"./esp-footer-link-group.js";const m=new Set(["auto","1","2","3","4","5","6"]),c={media:!1,brand:!1,groups:!1,aside:!1,bottom:!1},w={fromAttribute(i){return i&&m.has(i)?i:"auto"},toAttribute(i){return m.has(i)?i:"auto"}};let r=class extends g{constructor(){super(...arguments),this.slotContent={...c},this.brandText="",this.brandLogo="",this.lightBrandLogo="",this.darkBrandLogo="",this.brandHref="",this.brandAlt="",this.brandColor="",this.lightBrandColor="",this.darkBrandColor="",this.columns="auto",this.fullBleedContent=!1,this.landmarkLabel="",this.handleSlotChange=o=>{if(!(o.target instanceof HTMLSlotElement))return;const a=this.slotRegion(o.target);if(!a)return;const e=h(o.target);this.slotContent[a]!==e&&(this.slotContent={...this.slotContent,[a]:e})}}willUpdate(o){super.willUpdate(o),o.has("columns")&&!m.has(this.columns)&&(this.columns="auto")}slotRegion(o){return o.name?["media","brand","aside","bottom"].includes(o.name)?o.name:null:"groups"}firstUpdated(o){super.firstUpdated(o);const a={...c};for(const e of this.shadowRoot?.querySelectorAll("slot")??[]){const s=this.slotRegion(e);s&&(a[s]=h(e))}Object.entries(a).some(([e,s])=>this.slotContent[e]!==s)&&(this.slotContent=a)}render(){const{media:o,brand:a,groups:e,aside:s,bottom:d}=this.slotContent,l=B({scheme:this.scheme,brandLogo:this.brandLogo,brandColor:this.brandColor,lightBrandLogo:this.lightBrandLogo,darkBrandLogo:this.darkBrandLogo,lightBrandColor:this.lightBrandColor,darkBrandColor:this.darkBrandColor}),p=a||!!(l.brandLogo||this.brandText),u=p||e||s,b={primary:!0,"has-brand":p,"has-groups":e,"has-aside":s};return v`
|
|
2
2
|
<footer
|
|
3
3
|
part="footer"
|
|
4
4
|
aria-label=${this.landmarkLabel||y}
|
|
5
|
-
style=${
|
|
5
|
+
style=${k({"--_esp-footer-brand-color":l.brandColor||null})}
|
|
6
6
|
>
|
|
7
|
-
|
|
7
|
+
${S({className:"background",rootPart:"background"})}
|
|
8
8
|
<div part="content" class="content-frame">
|
|
9
9
|
<div class="content">
|
|
10
10
|
<div part="media" class="media" ?hidden=${!o}>
|
|
11
11
|
<slot name="media" @slotchange=${this.handleSlotChange}></slot>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
|
-
<div part="primary" class=${
|
|
14
|
+
<div part="primary" class=${C(b)} ?hidden=${!u}>
|
|
15
15
|
<div part="brand" class="brand" ?hidden=${!p}>
|
|
16
16
|
<slot name="brand" @slotchange=${this.handleSlotChange}
|
|
17
17
|
>${z({brandLogo:l.brandLogo,brandText:this.brandText,brandHref:this.brandHref,brandAlt:this.brandAlt})}</slot
|
|
18
18
|
>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
|
-
<div part="groups" class="groups" ?hidden=${!
|
|
21
|
+
<div part="groups" class="groups" ?hidden=${!e}>
|
|
22
22
|
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
@@ -44,28 +44,23 @@ var t=function(i,o,e,a){var s=arguments.length,d=s<3?o:a===null?a=Object.getOwnP
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
footer {
|
|
47
|
+
--_esp-overlay-base-color: var(--esp-footer-background, var(--esp-color-layer-2));
|
|
48
|
+
--_esp-overlay-image: var(--esp-footer-background-image, none);
|
|
49
|
+
--_esp-overlay-image-opacity: var(--esp-footer-background-image-opacity, 1);
|
|
50
|
+
--_esp-overlay-image-repeat: var(--esp-footer-background-repeat, repeat);
|
|
51
|
+
--_esp-overlay-image-position: var(--esp-footer-background-position, 0 0);
|
|
52
|
+
--_esp-overlay-image-size: var(--esp-footer-background-size, auto);
|
|
53
|
+
--_esp-overlay-image-blend-mode: var(--esp-footer-background-blend-mode, normal);
|
|
54
|
+
--_esp-overlay-z-index: -1;
|
|
55
|
+
|
|
47
56
|
position: relative;
|
|
48
57
|
isolation: isolate;
|
|
49
58
|
min-inline-size: 0;
|
|
50
59
|
overflow: hidden;
|
|
51
60
|
color: var(--esp-footer-color, var(--esp-color-text));
|
|
52
|
-
background: var(--esp-footer-background, var(--esp-color-layer-2));
|
|
53
61
|
border-block-start: var(--esp-footer-border, 1px solid var(--esp-color-border));
|
|
54
62
|
}
|
|
55
63
|
|
|
56
|
-
.background {
|
|
57
|
-
position: absolute;
|
|
58
|
-
z-index: -1;
|
|
59
|
-
inset: 0;
|
|
60
|
-
pointer-events: none;
|
|
61
|
-
background-image: var(--esp-footer-background-image, none);
|
|
62
|
-
background-repeat: var(--esp-footer-background-repeat, repeat);
|
|
63
|
-
background-position: var(--esp-footer-background-position, 0 0);
|
|
64
|
-
background-size: var(--esp-footer-background-size, auto);
|
|
65
|
-
opacity: var(--esp-footer-background-image-opacity, 1);
|
|
66
|
-
mix-blend-mode: var(--esp-footer-background-blend-mode, normal);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
64
|
.content-frame {
|
|
70
65
|
--_esp-footer-content-surplus: max(
|
|
71
66
|
0px,
|
|
@@ -257,6 +252,10 @@ var t=function(i,o,e,a){var s=arguments.length,d=s<3?o:a===null?a=Object.getOwnP
|
|
|
257
252
|
}
|
|
258
253
|
|
|
259
254
|
@container esp-footer (max-width: 48rem) {
|
|
255
|
+
.groups ::slotted(esp-footer-column) {
|
|
256
|
+
grid-column: 1 / -1;
|
|
257
|
+
}
|
|
258
|
+
|
|
260
259
|
.primary,
|
|
261
260
|
.primary.has-brand.has-groups:not(.has-aside),
|
|
262
261
|
.primary.has-groups.has-aside:not(.has-brand),
|
|
@@ -304,4 +303,4 @@ var t=function(i,o,e,a){var s=arguments.length,d=s<3?o:a===null?a=Object.getOwnP
|
|
|
304
303
|
grid-template-areas: "aside";
|
|
305
304
|
}
|
|
306
305
|
}
|
|
307
|
-
|
|
306
|
+
`,L],t([_()],r.prototype,"slotContent",void 0),t([n({attribute:"brand-text",type:String})],r.prototype,"brandText",void 0),t([n({attribute:"brand-logo",type:String})],r.prototype,"brandLogo",void 0),t([n({attribute:"light-brand-logo",type:String})],r.prototype,"lightBrandLogo",void 0),t([n({attribute:"dark-brand-logo",type:String})],r.prototype,"darkBrandLogo",void 0),t([n({attribute:"brand-href",type:String})],r.prototype,"brandHref",void 0),t([n({attribute:"brand-alt",type:String})],r.prototype,"brandAlt",void 0),t([n({attribute:"brand-color",type:String})],r.prototype,"brandColor",void 0),t([n({attribute:"light-brand-color",type:String})],r.prototype,"lightBrandColor",void 0),t([n({attribute:"dark-brand-color",type:String})],r.prototype,"darkBrandColor",void 0),t([n({converter:w,reflect:!0})],r.prototype,"columns",void 0),t([n({attribute:"full-bleed-content",type:Boolean,reflect:!0})],r.prototype,"fullBleedContent",void 0),t([n({attribute:"landmark-label",type:String})],r.prototype,"landmarkLabel",void 0),r=t([x("esp-footer")],r);export{r as EspalierFooter};
|
package/dist/footer/index.d.ts
CHANGED
package/dist/footer/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./esp-footer-link-group.js";export*from"./esp-footer.js";
|
|
1
|
+
export*from"./esp-footer-column.js";export*from"./esp-footer-link-group.js";export*from"./esp-footer.js";
|