@taprootio/espalier 6.0.0 → 6.1.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 +13 -0
- package/css/image/banner-static.css +237 -0
- package/custom-elements.json +6835 -6590
- package/dist/image/esp-image.d.ts +70 -3
- package/dist/image/esp-image.js +171 -12
- package/dist/pickers/esp-pick-one.js +12 -14
- package/dist/pickers/esp-picker-menu.js +4 -3
- package/dist/shared/virtualizer/internal/virtualize.js +1 -1
- package/espalier.css-data.json +16 -0
- package/espalier.token-manifest.json +24 -0
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
# 6.1.0
|
|
2
|
+
|
|
3
|
+
Banner overlays gain a copy-stack layout contract (supporting copy, one action, middle positions, a compact band, and a static first-paint layout), and pickers no longer pick the option a finger lands on when it starts scrolling.
|
|
4
|
+
|
|
5
|
+
- **New: middle content positions.** `esp-image`'s `content-position` takes `middle-start` and `middle-end`, centering the copy against the inline start or end edge and mirroring in right-to-left text. An `auto` scrim follows the copy to that edge.
|
|
6
|
+
- **New: a banner copy stack.** Beside `slot="overlay"` (the headline), banners take `slot="overlay-supporting"` for one supporting sentence and `slot="overlay-action"` for one native link or button. Together they lay out as one stack: grouped spacing (`--esp-image-overlay-gap`), the supporting sentence on the lead type role, a line length bounded by `--esp-image-overlay-measure` (`36rem` by default), and an action with a comfortable target and a two-tone focus ring that reads over any photograph. The scrim now covers every piece of overlay copy, not just the headline. A headline on its own lays out exactly as before.
|
|
7
|
+
- **New: `compact-placement="below"`.** Below the compact width the copy moves into a band under the image, on the banner scheme's own surface and ink, for crops that lose their quiet region at narrow widths. The default, `overlay`, keeps today's behavior.
|
|
8
|
+
- **New: `@taprootio/espalier/image/banner-static.css`.** A stylesheet that lays server-rendered banners out before `esp-image` upgrades, from the same attributes plus `--esp-image-static-ratio` and `--esp-image-static-compact-ratio`, so nothing shifts at hydration. The Image banners guide lists its inputs and limits.
|
|
9
|
+
- **Fixed: banner copy could be clipped.** Copy taller than the ratio's frame (text enlarged to 200%, long localized labels, a narrow column) was cut off; the banner now grows to fit it, the image covers the grown frame, and words too long for a line wrap. A banner whose copy fits keeps exactly its current geometry, and an explicit, capped, or stretched block size still wins.
|
|
10
|
+
- **Banner copy never moves with the image.** A transform or animation on a banner's projected image or `::part(image)` stays inside the image box, and under `prefers-reduced-motion` those animations and transitions stop.
|
|
11
|
+
- **Fixed: swiping a picker's option list picked the first option touched.** Pickers picked on the press, before the browser could tell a tap from a scroll, so on a phone every swipe chose an option and closed the menu; `esp-pick-one` also picked a hidden option behind its input when the input was tapped after scrolling. Options are now picked by the tap that ends on them, a press keeps focus (and a typeahead query) in the input, and a tap on the input only focuses it. This applies to `esp-pick-one`, `esp-pick-some`, and `esp-font-picker`, with or without typeahead.
|
|
12
|
+
- **Fixed: typing a typeahead filter after scrolling a long picker list could throw** while the list shrank.
|
|
13
|
+
|
|
1
14
|
# 6.0.0
|
|
2
15
|
|
|
3
16
|
Espalier 6 removes `esp-video`'s unused streaming adapter, and pickers now show an item's new label when its text changes after it was selected.
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Espalier esp-image banner: static layout before the component upgrades.
|
|
3
|
+
*
|
|
4
|
+
* Server-rendered `<esp-image banner>` markup paints with page styles alone
|
|
5
|
+
* until Espalier's module defines the element. This sheet lays the same
|
|
6
|
+
* markup out from its attributes in that window, matching the upgraded
|
|
7
|
+
* banner's geometry so nothing shifts at hydration: the frame ratio, focal
|
|
8
|
+
* cropping, every `content-position`, the copy stack and its measure, growth
|
|
9
|
+
* for long or enlarged copy, and `compact-placement="below"`.
|
|
10
|
+
*
|
|
11
|
+
* Every rule is scoped to `esp-image[banner]:not(:defined)`, so it stops
|
|
12
|
+
* applying the moment the element upgrades.
|
|
13
|
+
*
|
|
14
|
+
* Inputs the server sets inline (CSS cannot read a ratio from an attribute):
|
|
15
|
+
* --esp-image-static-ratio the `ratio` value, e.g. `3 / 1`
|
|
16
|
+
* --esp-image-static-compact-ratio the `compact-ratio` value, if any
|
|
17
|
+
* --esp-image-object-position the focal point, e.g. `65% 40%`
|
|
18
|
+
*
|
|
19
|
+
* Limits, all documented in the image banners guide: the compact switch uses
|
|
20
|
+
* the default 40rem width (a custom `--esp-image-compact-width` cannot apply
|
|
21
|
+
* before upgrade); no scrim or texture paints until upgrade; copy must be
|
|
22
|
+
* emitted in stack order (headline, supporting, action); and a custom
|
|
23
|
+
* `--esp-image-overlay-padding` must be a single length for the compact band.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
esp-image[banner]:not(:defined) {
|
|
27
|
+
--_esp-image-static-pad: var(--esp-image-overlay-padding, var(--esp-size-padding-page, 1rem));
|
|
28
|
+
--_esp-image-static-gap: var(--esp-image-overlay-gap, var(--esp-size-small, 0.75rem));
|
|
29
|
+
--_esp-image-static-before: 1fr;
|
|
30
|
+
--_esp-image-static-after: 0fr;
|
|
31
|
+
display: grid;
|
|
32
|
+
grid-template-columns: minmax(0, 1fr);
|
|
33
|
+
/* media | space before | headline | supporting | action | space after */
|
|
34
|
+
grid-template-rows:
|
|
35
|
+
auto minmax(0, var(--_esp-image-static-before)) auto auto auto
|
|
36
|
+
minmax(0, var(--_esp-image-static-after));
|
|
37
|
+
justify-items: start;
|
|
38
|
+
text-align: start;
|
|
39
|
+
overflow: clip;
|
|
40
|
+
overflow-wrap: anywhere;
|
|
41
|
+
container-type: inline-size;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* The image spans every row at the banner ratio, so the banner is as tall as
|
|
45
|
+
the ratio or the copy, whichever is taller, and the image covers it all. */
|
|
46
|
+
esp-image[banner]:not(:defined) > picture,
|
|
47
|
+
esp-image[banner]:not(:defined) > img {
|
|
48
|
+
display: block;
|
|
49
|
+
grid-row: 1 / -1;
|
|
50
|
+
grid-column: 1;
|
|
51
|
+
align-self: stretch;
|
|
52
|
+
justify-self: stretch;
|
|
53
|
+
inline-size: 100%;
|
|
54
|
+
block-size: auto;
|
|
55
|
+
aspect-ratio: var(--esp-image-static-ratio, auto);
|
|
56
|
+
object-fit: cover;
|
|
57
|
+
object-position: var(--esp-image-object-position, center);
|
|
58
|
+
}
|
|
59
|
+
esp-image[banner]:not(:defined) > picture > img {
|
|
60
|
+
display: block;
|
|
61
|
+
inline-size: 100%;
|
|
62
|
+
block-size: 100%;
|
|
63
|
+
object-fit: cover;
|
|
64
|
+
object-position: var(--esp-image-object-position, center);
|
|
65
|
+
}
|
|
66
|
+
esp-image[banner]:not(:defined) > esp-image-option {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Vertical placement: which side of the copy takes the free space. */
|
|
71
|
+
esp-image[banner]:not(:defined):is(
|
|
72
|
+
[content-position="top-start"],
|
|
73
|
+
[content-position="top"],
|
|
74
|
+
[content-position="top-end"]
|
|
75
|
+
) {
|
|
76
|
+
--_esp-image-static-before: 0fr;
|
|
77
|
+
--_esp-image-static-after: 1fr;
|
|
78
|
+
}
|
|
79
|
+
esp-image[banner]:not(:defined):is(
|
|
80
|
+
[content-position="middle-start"],
|
|
81
|
+
[content-position="center"],
|
|
82
|
+
[content-position="middle-end"]
|
|
83
|
+
) {
|
|
84
|
+
--_esp-image-static-before: 1fr;
|
|
85
|
+
--_esp-image-static-after: 1fr;
|
|
86
|
+
}
|
|
87
|
+
/* Inline placement, logical so right-to-left mirrors. */
|
|
88
|
+
esp-image[banner]:not(:defined):is(
|
|
89
|
+
[content-position="top"],
|
|
90
|
+
[content-position="center"],
|
|
91
|
+
[content-position="bottom"]
|
|
92
|
+
) {
|
|
93
|
+
justify-items: center;
|
|
94
|
+
text-align: center;
|
|
95
|
+
}
|
|
96
|
+
esp-image[banner]:not(:defined):is(
|
|
97
|
+
[content-position="top-end"],
|
|
98
|
+
[content-position="middle-end"],
|
|
99
|
+
[content-position="bottom-end"]
|
|
100
|
+
) {
|
|
101
|
+
justify-items: end;
|
|
102
|
+
text-align: end;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* The copy. The upgraded overlay pads the copy as a block; here each piece of
|
|
106
|
+
copy carries that padding itself, as a margin, so the image stays
|
|
107
|
+
full-bleed. A headline on its own keeps its own margins, as it does once
|
|
108
|
+
upgraded, by taking the padding as padding instead. */
|
|
109
|
+
esp-image[banner]:not(:defined) > :is([slot="overlay"], [slot="overlay-supporting"], [slot="overlay-action"]) {
|
|
110
|
+
grid-column: 1;
|
|
111
|
+
min-inline-size: 0;
|
|
112
|
+
}
|
|
113
|
+
esp-image[banner]:not(:defined) > [slot="overlay"] {
|
|
114
|
+
grid-row: 3;
|
|
115
|
+
max-inline-size: var(--esp-image-overlay-measure, none);
|
|
116
|
+
padding: var(--_esp-image-static-pad);
|
|
117
|
+
}
|
|
118
|
+
/* A lone headline carries the overlay padding here; content-box keeps a
|
|
119
|
+
measure bounding its text, as after upgrade, where that padding belongs to
|
|
120
|
+
the overlay rather than the headline. */
|
|
121
|
+
esp-image[banner]:not(:defined):not(:has(> [slot="overlay-supporting"], > [slot="overlay-action"]))
|
|
122
|
+
> [slot="overlay"] {
|
|
123
|
+
box-sizing: content-box;
|
|
124
|
+
}
|
|
125
|
+
esp-image[banner]:not(:defined) > [slot="overlay-supporting"] {
|
|
126
|
+
grid-row: 4;
|
|
127
|
+
}
|
|
128
|
+
esp-image[banner]:not(:defined) > [slot="overlay-action"] {
|
|
129
|
+
grid-row: 5;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* A copy stack: supporting copy or an action is present. */
|
|
133
|
+
esp-image[banner]:not(:defined):has(> [slot="overlay-supporting"], > [slot="overlay-action"])
|
|
134
|
+
> :is([slot="overlay"], [slot="overlay-supporting"], [slot="overlay-action"]) {
|
|
135
|
+
max-inline-size: var(--esp-image-overlay-measure, 36rem);
|
|
136
|
+
margin: var(--_esp-image-static-pad) !important;
|
|
137
|
+
}
|
|
138
|
+
esp-image[banner]:not(:defined):has(> [slot="overlay-supporting"], > [slot="overlay-action"])
|
|
139
|
+
> [slot="overlay"] {
|
|
140
|
+
padding: 0;
|
|
141
|
+
}
|
|
142
|
+
esp-image[banner]:not(:defined):has(> [slot="overlay-supporting"], > [slot="overlay-action"])
|
|
143
|
+
> [slot="overlay"]:has(~ [slot="overlay-supporting"], ~ [slot="overlay-action"]) {
|
|
144
|
+
margin-block-end: 0 !important;
|
|
145
|
+
}
|
|
146
|
+
esp-image[banner]:not(:defined) > [slot="overlay"] ~ [slot="overlay-supporting"] {
|
|
147
|
+
margin-block-start: var(--_esp-image-static-gap) !important;
|
|
148
|
+
}
|
|
149
|
+
esp-image[banner]:not(:defined) > [slot="overlay-supporting"]:has(~ [slot="overlay-action"]) {
|
|
150
|
+
margin-block-end: 0 !important;
|
|
151
|
+
}
|
|
152
|
+
esp-image[banner]:not(:defined)
|
|
153
|
+
> :is([slot="overlay"], [slot="overlay-supporting"])
|
|
154
|
+
~ [slot="overlay-action"] {
|
|
155
|
+
margin-block-start: calc(2 * var(--_esp-image-static-gap)) !important;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* Defaults the upgraded overlay gives its supporting copy and action. They
|
|
159
|
+
carry no specificity, so page styles win here exactly as they do after
|
|
160
|
+
upgrade. */
|
|
161
|
+
:where(esp-image[banner]:not(:defined)) > :where([slot="overlay-supporting"]) {
|
|
162
|
+
font-family: var(--esp-font-body, inherit);
|
|
163
|
+
font-weight: var(--esp-type-lead-font-weight, var(--esp-font-weight-body, 400));
|
|
164
|
+
font-size: var(--esp-type-lead-font-size, 1.25rem);
|
|
165
|
+
line-height: 1.4;
|
|
166
|
+
}
|
|
167
|
+
:where(esp-image[banner]:not(:defined)) > :where(a[slot="overlay-action"], button[slot="overlay-action"]) {
|
|
168
|
+
display: inline-flex;
|
|
169
|
+
align-items: center;
|
|
170
|
+
justify-content: center;
|
|
171
|
+
box-sizing: border-box;
|
|
172
|
+
min-block-size: 2.75rem;
|
|
173
|
+
padding: 0.5em 1.25em;
|
|
174
|
+
border: 2px solid currentColor;
|
|
175
|
+
border-radius: var(--esp-size-border-radius, 0.375rem);
|
|
176
|
+
background: transparent;
|
|
177
|
+
font-family: var(--esp-font-body, inherit);
|
|
178
|
+
font-size: var(--esp-type-normal, 1rem);
|
|
179
|
+
font-weight: 600;
|
|
180
|
+
line-height: 1.2;
|
|
181
|
+
text-align: center;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Compact band: below the default compact width the image keeps the compact
|
|
185
|
+
ratio in its own row and the copy follows on the banner scheme's surface. */
|
|
186
|
+
esp-image[banner][compact-placement="below"]:not(:defined) {
|
|
187
|
+
background-color: var(--esp-image-scrim-color, var(--esp-color-background, oklch(0.98 0 0)));
|
|
188
|
+
}
|
|
189
|
+
esp-image[banner][compact-placement="below"][banner-scheme="light"]:not(:defined) {
|
|
190
|
+
background-color: var(
|
|
191
|
+
--esp-image-scrim-color,
|
|
192
|
+
oklch(from var(--esp-color-background, oklch(0.98 0 0)) 0.97 c h)
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
esp-image[banner][compact-placement="below"][banner-scheme="dark"]:not(:defined) {
|
|
196
|
+
background-color: var(
|
|
197
|
+
--esp-image-scrim-color,
|
|
198
|
+
oklch(from var(--esp-color-background, oklch(0.98 0 0)) 0.13 c h)
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
@container (width < 40rem) {
|
|
202
|
+
esp-image[banner]:not(:defined) > :is(picture, img) {
|
|
203
|
+
aspect-ratio: var(--esp-image-static-compact-ratio, var(--esp-image-static-ratio, auto));
|
|
204
|
+
}
|
|
205
|
+
esp-image[banner][compact-placement="below"]:not(:defined) > :is(picture, img) {
|
|
206
|
+
grid-row: 1;
|
|
207
|
+
}
|
|
208
|
+
esp-image[banner][compact-placement="below"]:not(:defined)
|
|
209
|
+
> :is([slot="overlay"], [slot="overlay-supporting"], [slot="overlay-action"]) {
|
|
210
|
+
color: var(--esp-image-overlay-color, var(--esp-color-headings, oklch(0.2 0 0)));
|
|
211
|
+
text-shadow: none;
|
|
212
|
+
}
|
|
213
|
+
esp-image[banner][compact-placement="below"][banner-scheme="light"]:not(:defined)
|
|
214
|
+
> :is([slot="overlay"], [slot="overlay-supporting"], [slot="overlay-action"]) {
|
|
215
|
+
color: var(
|
|
216
|
+
--esp-image-overlay-color,
|
|
217
|
+
oklch(from var(--esp-color-headings, oklch(0.2 0 0)) 0.2 c h)
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
esp-image[banner][compact-placement="below"][banner-scheme="dark"]:not(:defined)
|
|
221
|
+
> :is([slot="overlay"], [slot="overlay-supporting"], [slot="overlay-action"]) {
|
|
222
|
+
color: var(
|
|
223
|
+
--esp-image-overlay-color,
|
|
224
|
+
oklch(from var(--esp-color-headings, oklch(0.2 0 0)) 0.97 c h)
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* The image never moves under reduced motion, before upgrade as after. */
|
|
230
|
+
@media (prefers-reduced-motion: reduce) {
|
|
231
|
+
esp-image[banner]:not(:defined) > picture,
|
|
232
|
+
esp-image[banner]:not(:defined) > picture > img,
|
|
233
|
+
esp-image[banner]:not(:defined) > img {
|
|
234
|
+
animation: none !important;
|
|
235
|
+
transition: none !important;
|
|
236
|
+
}
|
|
237
|
+
}
|