@taprootio/espalier 2.1.3 → 2.3.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/custom-elements.json +2019 -94
- package/dist/checkbox/esp-checkbox-group.js +4 -4
- package/dist/checkbox/esp-checkbox.js +3 -3
- package/dist/date-picker/esp-date-picker.js +17 -17
- package/dist/flyout/esp-flyout.d.ts +393 -0
- package/dist/flyout/esp-flyout.js +153 -0
- package/dist/font-picker/esp-font-picker.js +3 -3
- package/dist/form-item/esp-form-item.d.ts +52 -0
- package/dist/form-item/esp-form-item.js +27 -7
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -1
- package/dist/input/esp-input.js +4 -4
- package/dist/page/esp-page.d.ts +20 -1
- package/dist/page/esp-page.js +90 -17
- package/dist/pickers/esp-picker-base.js +1 -1
- package/dist/radio-button/esp-radio-button-group.js +3 -3
- package/dist/radio-button/esp-radio-button.js +4 -4
- package/dist/shared/bus-events.d.ts +18 -1
- package/dist/shared/events.d.ts +13 -0
- package/dist/shared/events.js +1 -1
- package/dist/shared/flyout-events.d.ts +87 -0
- package/dist/shared/flyout-events.js +1 -0
- package/dist/shared/form-field-description-controller.js +1 -0
- package/dist/shared/overlay-controller.js +1 -1
- package/dist/slider/esp-slider.js +2 -2
- package/dist/switch/esp-switch.js +3 -3
- package/dist/textarea/esp-textarea.js +1 -1
- package/dist/toaster/esp-toaster.d.ts +21 -0
- package/dist/toaster/esp-toaster.js +9 -9
- package/espalier.token-manifest.json +61 -1
- package/package.json +2 -1
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { type PropertyValues } from "lit";
|
|
2
|
+
import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
3
|
+
import type { FlyoutCloseReason } from "../shared/flyout-events.js";
|
|
4
|
+
/**
|
|
5
|
+
* A transient panel for help, more-info, and preview content that
|
|
6
|
+
* claims designed spare width before ever covering the page.
|
|
7
|
+
*
|
|
8
|
+
* Place one `esp-flyout` in an `esp-page`'s `flyout` slot. The panel
|
|
9
|
+
* lives on the canvas, outside the content surface. The page decides
|
|
10
|
+
* where it goes, from widest viewport to narrowest:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Gutter** — the panel occupies the right canvas gutter. When the
|
|
13
|
+
* gutter already has room, it claims existing spare canvas and the
|
|
14
|
+
* main content does not move at all, on any alignment.
|
|
15
|
+
* 2. **Shift** — when the gutter is not quite wide enough, the surface
|
|
16
|
+
* slides toward `start` by exactly the shortfall (no more) to free
|
|
17
|
+
* the difference.
|
|
18
|
+
* 3. **Docked sidebar** — once the gutter is gone, the panel competes
|
|
19
|
+
* for width with the main well; content narrows but is never
|
|
20
|
+
* covered.
|
|
21
|
+
* 4. **Overlay drawer** — below the mobile threshold (`50em`, the
|
|
22
|
+
* same one the `esp-menu` drawer uses) the panel becomes a fixed
|
|
23
|
+
* drawer over a vellum backdrop. Set `mode="overlay"` to get this
|
|
24
|
+
* presentation at every width.
|
|
25
|
+
*
|
|
26
|
+
* The panel is styled as a tear-off piece: a dotted perforation on
|
|
27
|
+
* its leading edge, rounded trailing corners, and no shadow — all
|
|
28
|
+
* overridable through the `--esp-flyout-*` tokens below.
|
|
29
|
+
*
|
|
30
|
+
* A11y follows the presentation. In the in-grid modes (1–3) the
|
|
31
|
+
* flyout is a non-modal `complementary` landmark named by its
|
|
32
|
+
* `heading`, and opening it never steals focus. In the overlay-drawer
|
|
33
|
+
* mode (4) it is a true modal: `role="dialog"` + `aria-modal`, the
|
|
34
|
+
* background goes inert, scroll is locked, focus moves into the drawer
|
|
35
|
+
* and is trapped, and focus is restored on close. `Escape` closes it
|
|
36
|
+
* in every mode.
|
|
37
|
+
*
|
|
38
|
+
* ```html
|
|
39
|
+
* <style>
|
|
40
|
+
* esp-page.flyout-demo {
|
|
41
|
+
* --esp-page-max-width: 420px;
|
|
42
|
+
* --esp-page-canvas-background: var(--esp-color-layer-1);
|
|
43
|
+
* &::part(wrapper) {
|
|
44
|
+
* min-height: 320px;
|
|
45
|
+
* height: 320px;
|
|
46
|
+
* }
|
|
47
|
+
* > div {
|
|
48
|
+
* padding: var(--esp-size-padding);
|
|
49
|
+
* }
|
|
50
|
+
* }
|
|
51
|
+
* </style>
|
|
52
|
+
* <esp-page class="flyout-demo" align="center">
|
|
53
|
+
* <esp-flyout slot="flyout" heading="More info" id="demo-flyout" standalone>
|
|
54
|
+
* <p>Spare width claimed; the well shifted only enough to make room.</p>
|
|
55
|
+
* </esp-flyout>
|
|
56
|
+
* <div>
|
|
57
|
+
* <esp-button id="toggle-flyout" label="Toggle flyout" collapsed></esp-button>
|
|
58
|
+
* </div>
|
|
59
|
+
* </esp-page>
|
|
60
|
+
* <script>
|
|
61
|
+
* const flyout = findById("demo-flyout");
|
|
62
|
+
* findById("toggle-flyout").addEventListener("clicked", () => flyout.toggle());
|
|
63
|
+
* </script>
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* By default the panel is a tear-off — a dotted perforation on its
|
|
67
|
+
* leading edge, rounded trailing corners, no shadow. Add
|
|
68
|
+
* `match-surface` to lift the trailing edge with the page's surface
|
|
69
|
+
* edge shadow, so the flyout reads as a raised peer of the content it
|
|
70
|
+
* flies out from while staying attached at the leading perforation:
|
|
71
|
+
*
|
|
72
|
+
* ```html
|
|
73
|
+
* <style>
|
|
74
|
+
* esp-page.flyout-match-demo {
|
|
75
|
+
* --esp-page-max-width: 420px;
|
|
76
|
+
* &::part(wrapper) {
|
|
77
|
+
* min-height: 320px;
|
|
78
|
+
* height: 320px;
|
|
79
|
+
* }
|
|
80
|
+
* > div {
|
|
81
|
+
* padding: var(--esp-size-padding);
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* </style>
|
|
85
|
+
* <esp-page class="flyout-match-demo" align="center">
|
|
86
|
+
* <esp-flyout slot="flyout" heading="More info" id="match-flyout" match-surface standalone>
|
|
87
|
+
* <p>Attached at the perforation, trailing edge raised like the surface.</p>
|
|
88
|
+
* </esp-flyout>
|
|
89
|
+
* <div>
|
|
90
|
+
* <esp-button id="toggle-match" label="Toggle flyout" collapsed></esp-button>
|
|
91
|
+
* </div>
|
|
92
|
+
* </esp-page>
|
|
93
|
+
* <script>
|
|
94
|
+
* const matchFlyout = findById("match-flyout");
|
|
95
|
+
* findById("toggle-match").addEventListener("clicked", () => matchFlyout.toggle());
|
|
96
|
+
* </script>
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* When the page has no spare width to claim — a `kind="full"` page,
|
|
100
|
+
* or a capped page on a viewport at the cap — the open flyout docks
|
|
101
|
+
* as a right sidebar and the content makes room:
|
|
102
|
+
*
|
|
103
|
+
* ```html
|
|
104
|
+
* <style>
|
|
105
|
+
* esp-page.flyout-docked-demo {
|
|
106
|
+
* &::part(wrapper) {
|
|
107
|
+
* min-height: 320px;
|
|
108
|
+
* height: 320px;
|
|
109
|
+
* }
|
|
110
|
+
* > div {
|
|
111
|
+
* padding: var(--esp-size-padding);
|
|
112
|
+
* }
|
|
113
|
+
* }
|
|
114
|
+
* </style>
|
|
115
|
+
* <esp-page class="flyout-docked-demo" kind="full">
|
|
116
|
+
* <esp-flyout slot="flyout" heading="Docked" id="docked-flyout" standalone>
|
|
117
|
+
* <p>No gutter to claim, so the content narrows instead.</p>
|
|
118
|
+
* </esp-flyout>
|
|
119
|
+
* <div>
|
|
120
|
+
* <p>A <code>kind="full"</code> page has no canvas gutters at any
|
|
121
|
+
* width — the flyout squeezes the main well and never covers it.</p>
|
|
122
|
+
* <esp-button id="toggle-docked" label="Toggle flyout" collapsed></esp-button>
|
|
123
|
+
* </div>
|
|
124
|
+
* </esp-page>
|
|
125
|
+
* <script>
|
|
126
|
+
* const dockedFlyout = findById("docked-flyout");
|
|
127
|
+
* findById("toggle-docked").addEventListener("clicked", () => dockedFlyout.toggle());
|
|
128
|
+
* </script>
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* Below the `50em` viewport threshold every flyout becomes a fixed
|
|
132
|
+
* overlay drawer over a vellum — there is no room for a side-by-side
|
|
133
|
+
* split on a phone. `mode="overlay"` forces that presentation at any
|
|
134
|
+
* width (try it here; `Escape` or the vellum closes it):
|
|
135
|
+
*
|
|
136
|
+
* ```html
|
|
137
|
+
* <style>
|
|
138
|
+
* esp-page.flyout-overlay-demo {
|
|
139
|
+
* &::part(wrapper) {
|
|
140
|
+
* min-height: 160px;
|
|
141
|
+
* height: 160px;
|
|
142
|
+
* }
|
|
143
|
+
* > div {
|
|
144
|
+
* padding: var(--esp-size-padding);
|
|
145
|
+
* }
|
|
146
|
+
* }
|
|
147
|
+
* </style>
|
|
148
|
+
* <esp-page class="flyout-overlay-demo">
|
|
149
|
+
* <esp-flyout slot="flyout" heading="Overlay drawer" mode="overlay" id="overlay-flyout" standalone>
|
|
150
|
+
* <p>A fixed drawer over a vellum — what every flyout becomes on
|
|
151
|
+
* small viewports.</p>
|
|
152
|
+
* </esp-flyout>
|
|
153
|
+
* <div>
|
|
154
|
+
* <esp-button id="open-overlay" label="Open overlay flyout" collapsed></esp-button>
|
|
155
|
+
* </div>
|
|
156
|
+
* </esp-page>
|
|
157
|
+
* <script>
|
|
158
|
+
* const overlayFlyout = findById("overlay-flyout");
|
|
159
|
+
* findById("open-overlay").addEventListener("clicked", () => overlayFlyout.toggle());
|
|
160
|
+
* </script>
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* Components that cannot know where the flyout lives can request it
|
|
164
|
+
* over the bus with `showFlyout()` — the same pattern `showToast()`
|
|
165
|
+
* uses. A second request swaps the content in place; it never
|
|
166
|
+
* stacks. Content passed as a string renders as plain text; pass a
|
|
167
|
+
* `Node` for rich content. Pass the triggering element as `anchor` to
|
|
168
|
+
* align the in-grid panel with that control and keep both in the same
|
|
169
|
+
* scroll flow. If the panel would cross the visible viewport's bottom,
|
|
170
|
+
* it shifts up only far enough to fit and returns to its natural trigger
|
|
171
|
+
* alignment as the page scrolls. Content taller than the viewport
|
|
172
|
+
* scrolls inside the panel. Overlay drawers stay viewport-fixed.
|
|
173
|
+
*
|
|
174
|
+
* The bus is a global broadcast, so every listening flyout on the
|
|
175
|
+
* page answers a `showFlyout()` call. The demos above are each driven
|
|
176
|
+
* by their own toggle button, so they are marked `standalone` to opt
|
|
177
|
+
* out of the bus — leaving this one flyout as the page's shared
|
|
178
|
+
* surface. In a real app you typically have a single flyout and need
|
|
179
|
+
* no attribute at all.
|
|
180
|
+
*
|
|
181
|
+
* ```html
|
|
182
|
+
* <style>
|
|
183
|
+
* esp-page.flyout-bus-demo {
|
|
184
|
+
* --esp-page-max-width: 420px;
|
|
185
|
+
* &::part(wrapper) {
|
|
186
|
+
* min-height: 320px;
|
|
187
|
+
* }
|
|
188
|
+
* > div {
|
|
189
|
+
* padding: var(--esp-size-padding);
|
|
190
|
+
* }
|
|
191
|
+
* .flyout-demo-copy {
|
|
192
|
+
* max-inline-size: 42ch;
|
|
193
|
+
* }
|
|
194
|
+
* }
|
|
195
|
+
* </style>
|
|
196
|
+
* <esp-page class="flyout-bus-demo">
|
|
197
|
+
* <esp-flyout slot="flyout"></esp-flyout>
|
|
198
|
+
* <div>
|
|
199
|
+
* <esp-button id="show-apples" label="Apples" collapsed></esp-button>
|
|
200
|
+
* <div class="flyout-demo-copy">
|
|
201
|
+
* <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
|
|
202
|
+
* tempor incididunt ut labore et dolore magna aliqua.</p>
|
|
203
|
+
* <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
|
|
204
|
+
* ut aliquip ex ea commodo consequat.</p>
|
|
205
|
+
* <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
|
|
206
|
+
* dolore eu fugiat nulla pariatur.</p>
|
|
207
|
+
* </div>
|
|
208
|
+
* <esp-button id="show-pears" label="Pears" collapsed></esp-button>
|
|
209
|
+
* <template id="pears-description">
|
|
210
|
+
* <p>Ripen pears at room temperature until the neck yields gently to
|
|
211
|
+
* pressure, then refrigerate them to slow further ripening.</p>
|
|
212
|
+
* <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
|
|
213
|
+
* nec odio. Praesent libero. Sed cursus ante dapibus diam.</p>
|
|
214
|
+
* <p>Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis
|
|
215
|
+
* sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper
|
|
216
|
+
* porta.</p>
|
|
217
|
+
* <p>Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent
|
|
218
|
+
* taciti sociosqu ad litora torquent per conubia nostra.</p>
|
|
219
|
+
* <p>Curabitur sodales ligula in libero. Sed dignissim lacinia nunc.
|
|
220
|
+
* Curabitur tortor. Pellentesque nibh. Aenean quam.</p>
|
|
221
|
+
* <p>In scelerisque sem at dolor. Maecenas mattis. Sed convallis
|
|
222
|
+
* tristique sem. Proin ut ligula vel nunc egestas porttitor.</p>
|
|
223
|
+
* <p>Morbi lectus risus, iaculis vel, suscipit quis, luctus non,
|
|
224
|
+
* massa. Fusce ac turpis quis ligula lacinia aliquet.</p>
|
|
225
|
+
* <p>Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed,
|
|
226
|
+
* euismod in, nibh. Quisque volutpat condimentum velit.</p>
|
|
227
|
+
* </template>
|
|
228
|
+
* <div class="flyout-demo-copy">
|
|
229
|
+
* <p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
|
|
230
|
+
* deserunt mollit anim id est laborum.</p>
|
|
231
|
+
* <p>Curabitur pretium tincidunt lacus. Nulla gravida orci a odio, nullam
|
|
232
|
+
* varius, turpis et commodo pharetra.</p>
|
|
233
|
+
* </div>
|
|
234
|
+
* </div>
|
|
235
|
+
* </esp-page>
|
|
236
|
+
* <script>
|
|
237
|
+
* const applesButton = findById("show-apples");
|
|
238
|
+
* applesButton.addEventListener("clicked", () => {
|
|
239
|
+
* showFlyout({ heading: "Apples", content: "Crisp. Store cold.", anchor: applesButton });
|
|
240
|
+
* });
|
|
241
|
+
* const pearsButton = findById("show-pears");
|
|
242
|
+
* const pearsDescription = findById("pears-description");
|
|
243
|
+
* pearsButton.addEventListener("clicked", () => {
|
|
244
|
+
* showFlyout({
|
|
245
|
+
* heading: "Pears",
|
|
246
|
+
* content: pearsDescription.content.cloneNode(true),
|
|
247
|
+
* anchor: pearsButton,
|
|
248
|
+
* });
|
|
249
|
+
* });
|
|
250
|
+
* </script>
|
|
251
|
+
* ```
|
|
252
|
+
*
|
|
253
|
+
* @slot - The flyout's content.
|
|
254
|
+
*
|
|
255
|
+
* @event {CustomEvent<{}>} flyout-opened - Fired by `show()` when the
|
|
256
|
+
* flyout opens.
|
|
257
|
+
* @event {CustomEvent<{reason: FlyoutCloseReason}>} flyout-closed -
|
|
258
|
+
* Fired by `close()` when the flyout closes. `reason` is `"escape"`,
|
|
259
|
+
* `"vellum"`, `"button"`, or `"programmatic"`.
|
|
260
|
+
* @event {CustomEvent<{}>} flyout-state-changed - Fired on every
|
|
261
|
+
* `open`, `mode`, or `anchor` change, including direct property
|
|
262
|
+
* assignment (not just `show()`/`close()`). `esp-page` uses it to keep
|
|
263
|
+
* its layout in sync; most consumers want
|
|
264
|
+
* `flyout-opened`/`flyout-closed` instead.
|
|
265
|
+
*
|
|
266
|
+
* @csspart panel - The panel surface.
|
|
267
|
+
* @csspart header - The heading/close-button row.
|
|
268
|
+
* @csspart content - The scrollable content region wrapping the slot.
|
|
269
|
+
*
|
|
270
|
+
* @cssprop --esp-flyout-background - The background color of the
|
|
271
|
+
* panel. Defaults to `var(--esp-color-background)`.
|
|
272
|
+
* @cssprop --esp-flyout-border - The border on the panel's leading
|
|
273
|
+
* edge. Defaults to the tear-off perforation,
|
|
274
|
+
* `1px dotted var(--esp-color-border)`.
|
|
275
|
+
* @cssprop --esp-flyout-radius - The radius of the panel's trailing
|
|
276
|
+
* corners. Defaults to `var(--esp-size-border-radius)`; the overlay
|
|
277
|
+
* drawer squares them.
|
|
278
|
+
* @cssprop --esp-flyout-shadow - The panel's shadow. Defaults to
|
|
279
|
+
* `none` in the gutter/docked modes (the perforation does the
|
|
280
|
+
* separating) and to a drawer shadow in overlay mode.
|
|
281
|
+
* @cssprop --esp-flyout-padding - Padding inside the panel's header
|
|
282
|
+
* and content regions. Defaults to `var(--esp-size-padding)`.
|
|
283
|
+
* @cssprop --esp-flyout-z-index - Stack order of the overlay-drawer
|
|
284
|
+
* mode. Defaults to `3000` — above page chrome, below the dialog
|
|
285
|
+
* drop zone (4000). Set it on the `esp-page` (or an ancestor), not on
|
|
286
|
+
* the flyout itself: the page reads the same token to hoist the
|
|
287
|
+
* drawer's aside above its header.
|
|
288
|
+
*
|
|
289
|
+
* @docPageTitle Flyout
|
|
290
|
+
* @docUrl /components/flyout
|
|
291
|
+
* @menuGroup Structure
|
|
292
|
+
* @menuOrder 3
|
|
293
|
+
* @menuLabel Flyout
|
|
294
|
+
* @menuIcon layout
|
|
295
|
+
*
|
|
296
|
+
*/
|
|
297
|
+
export declare class EspalierFlyout extends EspalierElementBase {
|
|
298
|
+
/**
|
|
299
|
+
* Whether the flyout is open. Reflected so the initial state can
|
|
300
|
+
* be declared in markup; `esp-page` mirrors it (via the lifecycle
|
|
301
|
+
* events and the slot) onto its own `flyout-open` attribute to
|
|
302
|
+
* drive the grid.
|
|
303
|
+
*/
|
|
304
|
+
open: boolean;
|
|
305
|
+
/**
|
|
306
|
+
* Heading text for the panel's header row. Also becomes the
|
|
307
|
+
* flyout's accessible name unless the author set an `aria-label`.
|
|
308
|
+
* An open overlay without either uses the fallback name "Flyout" so
|
|
309
|
+
* its dialog is never exposed without an accessible name.
|
|
310
|
+
*/
|
|
311
|
+
heading: string;
|
|
312
|
+
/**
|
|
313
|
+
* Placement behavior.
|
|
314
|
+
*
|
|
315
|
+
* - `"auto"` (default) — the page's placement ladder: gutter,
|
|
316
|
+
* docked sidebar, then overlay drawer below the `50em` viewport
|
|
317
|
+
* threshold.
|
|
318
|
+
* - `"overlay"` — always the fixed overlay drawer, at any width.
|
|
319
|
+
* The page never reserves a grid track for an overlay-mode
|
|
320
|
+
* flyout.
|
|
321
|
+
*/
|
|
322
|
+
mode: "auto" | "overlay";
|
|
323
|
+
/**
|
|
324
|
+
* Triggering element whose block-start edge the in-grid panel should
|
|
325
|
+
* align with. Anchored panels stay in normal page flow, shift upward
|
|
326
|
+
* only while needed to fit the visible scrollport, and return to their
|
|
327
|
+
* natural alignment as the page scrolls. Oversized content scrolls
|
|
328
|
+
* inside the panel. Overlay drawers ignore this geometry and remain
|
|
329
|
+
* fixed to the viewport.
|
|
330
|
+
*/
|
|
331
|
+
anchor: HTMLElement | undefined;
|
|
332
|
+
/**
|
|
333
|
+
* When set on a flyout slotted into an `esp-page`, the panel lifts
|
|
334
|
+
* its **trailing** edge with the page's surface edge shadow, so it
|
|
335
|
+
* reads as a raised peer of the content surface it flies out from
|
|
336
|
+
* rather than the shadowless tear-off. The **leading** edge keeps
|
|
337
|
+
* its dotted perforation and casts no shadow, so the panel stays
|
|
338
|
+
* attached at the tear line instead of floating over the content.
|
|
339
|
+
* The trailing-corner radius is still `--esp-flyout-radius`. No
|
|
340
|
+
* effect on a standalone flyout — there is no page surface to match.
|
|
341
|
+
*/
|
|
342
|
+
matchSurface: boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Whether this flyout ignores the shared `showFlyout()` /
|
|
345
|
+
* `closeFlyout()` bus and is driven only through its own
|
|
346
|
+
* `show()` / `close()` / `toggle()` API.
|
|
347
|
+
*
|
|
348
|
+
* By default a flyout services the bus, so a single flyout in a
|
|
349
|
+
* page "just works" as the target of `showFlyout()` — the same
|
|
350
|
+
* zero-config model as `<esp-toaster>` and `showToast()`. Because
|
|
351
|
+
* the bus is a global broadcast, **every** listening flyout on the
|
|
352
|
+
* page answers a `showFlyout()` call; set `standalone` on any
|
|
353
|
+
* flyout you drive directly so only your one designated help
|
|
354
|
+
* surface responds.
|
|
355
|
+
*/
|
|
356
|
+
standalone: boolean;
|
|
357
|
+
/**
|
|
358
|
+
* Element to return focus to when the flyout closes. In the in-grid
|
|
359
|
+
* modes it is focused only if focus is inside the flyout at close;
|
|
360
|
+
* in the overlay-drawer mode it overrides the modal treatment's
|
|
361
|
+
* automatic restore-to-opener. Usually supplied through
|
|
362
|
+
* `showFlyout({ returnFocusTo })`.
|
|
363
|
+
*/
|
|
364
|
+
returnFocusTo: HTMLElement | undefined;
|
|
365
|
+
connectedCallback(): void;
|
|
366
|
+
disconnectedCallback(): void;
|
|
367
|
+
/**
|
|
368
|
+
* Open the flyout with its current content. In the in-grid modes it
|
|
369
|
+
* does not move focus; in the overlay-drawer mode it moves focus
|
|
370
|
+
* into the drawer as a modal.
|
|
371
|
+
*/
|
|
372
|
+
show(): void;
|
|
373
|
+
/**
|
|
374
|
+
* Close the flyout. In the in-grid modes, if focus is inside the
|
|
375
|
+
* flyout it is returned to `returnFocusTo` when one was provided; in
|
|
376
|
+
* the overlay-drawer mode the modal treatment restores focus to
|
|
377
|
+
* wherever it was when the drawer opened, unless `returnFocusTo`
|
|
378
|
+
* names an explicit target — the explicit target wins.
|
|
379
|
+
*/
|
|
380
|
+
close(reason?: FlyoutCloseReason): void;
|
|
381
|
+
/**
|
|
382
|
+
* Toggle the flyout between open and closed.
|
|
383
|
+
*/
|
|
384
|
+
toggle(): void;
|
|
385
|
+
protected updated(changed: PropertyValues): void;
|
|
386
|
+
protected render(): import("lit-html").TemplateResult<1>;
|
|
387
|
+
static styles: import("lit").CSSResult[];
|
|
388
|
+
}
|
|
389
|
+
declare global {
|
|
390
|
+
interface HTMLElementTagNameMap {
|
|
391
|
+
"esp-flyout": EspalierFlyout;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
var h=function(c,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,t):i,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(c,e,t,i);else for(var a=c.length-1;a>=0;a--)(n=c[a])&&(s=(o<3?n(s):o>3?n(e,t,s):n(e,t))||s);return o>3&&s&&Object.defineProperty(e,t,s),s};import{css as p,html as y,nothing as R}from"lit";import{customElement as k,property as l}from"lit/decorators.js";import{createRef as x,ref as C}from"lit/directives/ref.js";import{EspalierElementBase as v}from"../shared/esp-element-base.js";import{getEspBus as f}from"../shared/bus-events.js";import{OverlayController as T}from"../shared/overlay-controller.js";import{cancelSVG as E}from"../shared/svgs/cancel.js";import{traverseToClosest as b}from"../shared/utilities.js";const P="(max-width: 50em)",O="Flyout",m=p`
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
margin-block-start: 0;
|
|
5
|
+
width: auto;
|
|
6
|
+
|
|
7
|
+
height: 100vh;
|
|
8
|
+
height: 100dvh;
|
|
9
|
+
z-index: var(--esp-flyout-z-index, 3000);
|
|
10
|
+
`,w=p`
|
|
11
|
+
display: block;
|
|
12
|
+
position: absolute;
|
|
13
|
+
inset: 0;
|
|
14
|
+
background-color: var(--esp-vellum-background, var(--esp-color-layer-3));
|
|
15
|
+
opacity: var(--esp-vellum-opacity, 0.85);
|
|
16
|
+
`,g=p`
|
|
17
|
+
position: absolute;
|
|
18
|
+
inset-block: 0;
|
|
19
|
+
inset-inline-end: 0;
|
|
20
|
+
width: min(var(--esp-page-flyout-width, 20rem), 85vw);
|
|
21
|
+
overflow-y: auto;
|
|
22
|
+
|
|
23
|
+
border-start-end-radius: 0;
|
|
24
|
+
border-end-end-radius: 0;
|
|
25
|
+
box-shadow: var(--esp-flyout-shadow, -0.75rem 0 1.5rem -0.75rem var(--esp-color-shadow));
|
|
26
|
+
translate: 0 0;
|
|
27
|
+
transition: translate 0.25s ease;
|
|
28
|
+
|
|
29
|
+
@starting-style {
|
|
30
|
+
translate: 100% 0;
|
|
31
|
+
}
|
|
32
|
+
`;let r=class extends v{constructor(){super(...arguments),this.open=!1,this.heading="",this.mode="auto",this.matchSurface=!1,this.standalone=!1,this.lastGeneratedAriaLabel=null,this.boundKeydown=e=>this.handleKeydown(e),this.boundShowRequest=e=>this.handleShowRequest(e),this.boundCloseRequest=()=>this.close(),this.boundOverlayMediaChange=()=>{this.syncOverlayModal(),this.syncAnchorTracking(),this.syncAnchorGeometry()},this.boundAnchorViewportChange=()=>this.scheduleAnchorGeometrySync(),this.anchorPositionRaf=0,this.trackingAnchorPosition=!1,this.busSubscribed=!1,this.panelRef=x(),this.overlay=new T({host:this,getFocusTrapContainer:()=>this.panelRef.value??null,getFocusFallback:()=>this.panelRef.value??null,promote:!1}),this.overlayActive=!1,this.baseRole="complementary"}get effectiveOverlay(){return this.mode==="overlay"||(this.overlayMediaQuery?.matches??!1)}connectedCallback(){super.connectedCallback(),this.hasAttribute("role")||this.setAttribute("role","complementary"),this.baseRole=this.getAttribute("role")??"complementary",!this.overlayMediaQuery&&typeof window<"u"&&"matchMedia"in window&&(this.overlayMediaQuery=window.matchMedia(P)),this.overlayMediaQuery?.addEventListener("change",this.boundOverlayMediaChange),this.syncBusSubscription(),document.addEventListener("keydown",this.boundKeydown),this.syncOverlayModal(),this.syncAnchorTracking(),this.syncAnchorGeometry()}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeBus(),this.overlayMediaQuery?.removeEventListener("change",this.boundOverlayMediaChange),document.removeEventListener("keydown",this.boundKeydown),this.stopAnchorTracking(),this.overlayActive&&(this.overlayActive=!1,this.setAttribute("role",this.baseRole),this.removeAttribute("aria-modal"),this.updateGeneratedAriaLabel()),this.overlayReturnFocusTo=void 0}syncBusSubscription(){if(this.standalone||!this.isConnected){this.unsubscribeBus();return}this.busSubscribed||(f().subscribe("show-flyout",this.boundShowRequest),f().subscribe("close-flyout",this.boundCloseRequest),this.busSubscribed=!0)}unsubscribeBus(){this.busSubscribed&&(f().unsubscribe("show-flyout",this.boundShowRequest),f().unsubscribe("close-flyout",this.boundCloseRequest),this.busSubscribed=!1)}show(){this.open||(this.open=!0,this.dispatchEvent(new CustomEvent("flyout-opened",{detail:{},bubbles:!0,composed:!0})))}close(e="programmatic"){if(this.open){if(this.open=!1,this.overlayActive)this.overlayReturnFocusTo=this.returnFocusTo;else{const t=this.focusIsInside();this.overlay.close(),t&&this.returnFocusTo?.focus()}this.returnFocusTo=void 0,this.dispatchEvent(new CustomEvent("flyout-closed",{detail:{reason:e},bubbles:!0,composed:!0}))}}toggle(){this.open?this.close():this.show()}handleShowRequest(e){e.heading!==void 0&&(this.heading=e.heading),e.content!==void 0&&this.replaceChildren(typeof e.content=="string"?document.createTextNode(e.content):e.content),this.anchor=e.anchor,this.returnFocusTo=e.returnFocusTo,this.show()}handleKeydown(e){if(this.open){if(this.overlayActive&&e.key==="Tab"){this.overlay.trapFocus(e);return}e.key!=="Escape"||e.defaultPrevented||(e.preventDefault(),this.close("escape"))}}focusIsInside(){const e=document.activeElement;return e&&this.contains(e)?!0:this.shadowRoot?.activeElement!=null}updated(e){super.updated(e),e.has("standalone")&&this.syncBusSubscription(),e.has("heading")&&this.updateGeneratedAriaLabel(),(e.has("anchor")||e.has("open")||e.has("mode"))&&(this.syncAnchorTracking(),this.syncAnchorGeometry()),(e.has("open")||e.has("mode"))&&this.syncOverlayModal(),(e.has("open")||e.has("mode")||e.has("anchor"))&&this.dispatchEvent(new CustomEvent("flyout-state-changed",{detail:{},bubbles:!0,composed:!0}))}syncAnchorGeometry(){const e=b(this,"esp-page"),t=this.anchor?b(this.anchor,"esp-page"):null,i=e?.shadowRoot?.querySelector(".esp-page-main"),o=this.panelRef.value;if(!this.open||this.effectiveOverlay||!this.anchor||!e||t!==e||!i||!o){this.clearAnchorGeometry();return}const s=this.anchor.getBoundingClientRect(),n=Math.max(0,s.top-i.getBoundingClientRect().top),a=this.getVisibleBlockBounds(),d=Math.max(0,a.bottom-a.top);this.setGeometryProperty("--_esp-flyout-anchor-offset",`${n}px`),this.setGeometryProperty("--_esp-flyout-max-block-size",`${d}px`);const u=o.getBoundingClientRect().height,A=Math.max(0,s.top+u-a.bottom);this.setGeometryProperty("--_esp-flyout-viewport-shift",`${A}px`)}getVisibleBlockBounds(){const e=window.visualViewport;let t=e?.offsetTop??0,i=t+(e?.height??window.innerHeight);for(let o=this.composedParent(this);o;o=this.composedParent(o)){const s=getComputedStyle(o).overflowY;if(s!=="auto"&&s!=="scroll")continue;const n=o.getBoundingClientRect(),a=o instanceof HTMLElement?o.clientTop:0,d=o instanceof HTMLElement?o.clientHeight:n.height;if(d<=0)continue;const u=n.top+a;t=Math.max(t,u),i=Math.min(i,u+d)}return{top:t,bottom:Math.max(t,i)}}composedParent(e){if(e.parentElement)return e.parentElement;const t=e.getRootNode();return t instanceof ShadowRoot?t.host:null}setGeometryProperty(e,t){this.style.getPropertyValue(e)!==t&&this.style.setProperty(e,t)}clearAnchorGeometry(){this.style.removeProperty("--_esp-flyout-anchor-offset"),this.style.removeProperty("--_esp-flyout-viewport-shift"),this.style.removeProperty("--_esp-flyout-max-block-size")}scheduleAnchorGeometrySync(){!this.isConnected||this.anchorPositionRaf||(this.anchorPositionRaf=requestAnimationFrame(()=>{this.anchorPositionRaf=0,this.syncAnchorGeometry()}))}syncAnchorTracking(){if(!(this.isConnected&&this.open&&!!this.anchor&&!this.effectiveOverlay)){this.stopAnchorTracking();return}this.trackingAnchorPosition||(this.trackingAnchorPosition=!0,window.addEventListener("scroll",this.boundAnchorViewportChange,{capture:!0,passive:!0}),window.addEventListener("resize",this.boundAnchorViewportChange,{passive:!0}));const t=this.panelRef.value;t&&t!==this.observedAnchorPanel&&typeof ResizeObserver<"u"&&(this.anchorResizeObserver??=new ResizeObserver(this.boundAnchorViewportChange),this.anchorResizeObserver.disconnect(),this.anchorResizeObserver.observe(t),this.observedAnchorPanel=t)}stopAnchorTracking(){this.trackingAnchorPosition&&(window.removeEventListener("scroll",this.boundAnchorViewportChange,{capture:!0}),window.removeEventListener("resize",this.boundAnchorViewportChange),this.trackingAnchorPosition=!1),this.anchorPositionRaf&&(cancelAnimationFrame(this.anchorPositionRaf),this.anchorPositionRaf=0),this.anchorResizeObserver?.disconnect(),this.observedAnchorPanel=void 0}syncOverlayModal(){const e=this.isConnected&&this.open&&this.effectiveOverlay;if(e===this.overlayActive){!e&&!this.open&&this.overlay.close();return}e?(this.overlayActive=!0,this.setAttribute("role","dialog"),this.setAttribute("aria-modal","true"),this.updateGeneratedAriaLabel(),this.overlay.open(),this.updateComplete.then(()=>{this.overlayActive&&this.overlay.moveFocusInto()})):(this.overlayActive=!1,this.overlay.close(),this.overlayReturnFocusTo&&(this.overlayReturnFocusTo.focus(),this.overlayReturnFocusTo=void 0),this.setAttribute("role",this.baseRole),this.removeAttribute("aria-modal"),this.updateGeneratedAriaLabel())}updateGeneratedAriaLabel(){const e=this.getAttribute("aria-label");if(e!==null&&e!==this.lastGeneratedAriaLabel)return;const t=this.heading||(this.overlayActive?O:"");t?(this.setAttribute("aria-label",t),this.lastGeneratedAriaLabel=t):(this.removeAttribute("aria-label"),this.lastGeneratedAriaLabel=null)}render(){return y`
|
|
33
|
+
<div class="vellum" aria-hidden="true" @click=${()=>this.close("vellum")}></div>
|
|
34
|
+
<div class="panel" part="panel" ${C(this.panelRef)}>
|
|
35
|
+
<header part="header">
|
|
36
|
+
${this.heading?y`<h2>${this.heading}</h2>`:R}
|
|
37
|
+
|
|
38
|
+
<button class="close" aria-label="Close" @click=${()=>this.close("button")}>
|
|
39
|
+
${E}
|
|
40
|
+
</button>
|
|
41
|
+
</header>
|
|
42
|
+
<div class="content" part="content">
|
|
43
|
+
<slot @slotchange=${this.boundAnchorViewportChange}></slot>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
`}};r.styles=[...v.styles,p`
|
|
47
|
+
:host {
|
|
48
|
+
display: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:host([open]) {
|
|
52
|
+
display: block;
|
|
53
|
+
|
|
54
|
+
width: var(--esp-page-flyout-width, 20rem);
|
|
55
|
+
margin-block-start: calc(
|
|
56
|
+
var(--_esp-flyout-anchor-offset, 0px) - var(--_esp-flyout-viewport-shift, 0px)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.vellum {
|
|
61
|
+
display: none;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.panel {
|
|
65
|
+
background: var(--esp-flyout-background, var(--esp-color-background));
|
|
66
|
+
|
|
67
|
+
width: var(--esp-page-flyout-width, 20rem);
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
max-block-size: var(--_esp-flyout-max-block-size, none);
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
|
|
73
|
+
border-inline-start: var(--esp-flyout-border, 1px dotted var(--esp-color-border));
|
|
74
|
+
border-start-end-radius: var(--esp-flyout-radius, var(--esp-size-border-radius));
|
|
75
|
+
border-end-end-radius: var(--esp-flyout-radius, var(--esp-size-border-radius));
|
|
76
|
+
box-shadow: var(--esp-flyout-shadow, none);
|
|
77
|
+
font-family: var(--esp-font-body);
|
|
78
|
+
color: var(--esp-color-text);
|
|
79
|
+
|
|
80
|
+
> header {
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
gap: var(--esp-size-tiny-to-small);
|
|
84
|
+
padding: var(--esp-flyout-padding, var(--esp-size-padding));
|
|
85
|
+
padding-block-end: 0;
|
|
86
|
+
|
|
87
|
+
> h2 {
|
|
88
|
+
flex: 1;
|
|
89
|
+
margin: 0;
|
|
90
|
+
font-size: var(--esp-type-large);
|
|
91
|
+
line-height: 1.2;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
> .close {
|
|
95
|
+
margin-inline-start: auto;
|
|
96
|
+
display: inline-flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
border: none;
|
|
100
|
+
background: transparent;
|
|
101
|
+
color: var(--esp-color-text);
|
|
102
|
+
cursor: pointer;
|
|
103
|
+
padding: var(--esp-size-tiny);
|
|
104
|
+
|
|
105
|
+
svg {
|
|
106
|
+
width: 1.25em;
|
|
107
|
+
height: 1.25em;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
> .content {
|
|
113
|
+
min-block-size: 0;
|
|
114
|
+
overflow-y: auto;
|
|
115
|
+
overscroll-behavior-block: contain;
|
|
116
|
+
padding: var(--esp-flyout-padding, var(--esp-size-padding));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
:host([open][mode="overlay"]) {
|
|
122
|
+
${m}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
:host([open][mode="overlay"]) .vellum {
|
|
126
|
+
${w}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
:host([open][mode="overlay"]) .panel {
|
|
130
|
+
${g}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@media (max-width: 50em) {
|
|
135
|
+
:host([open]) {
|
|
136
|
+
${m}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.vellum {
|
|
140
|
+
${w}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.panel {
|
|
144
|
+
${g}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@media (prefers-reduced-motion: reduce) {
|
|
149
|
+
.panel {
|
|
150
|
+
transition: none;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
`],h([l({type:Boolean,reflect:!0})],r.prototype,"open",void 0),h([l({type:String})],r.prototype,"heading",void 0),h([l({reflect:!0})],r.prototype,"mode",void 0),h([l({attribute:!1})],r.prototype,"anchor",void 0),h([l({type:Boolean,reflect:!0,attribute:"match-surface"})],r.prototype,"matchSurface",void 0),h([l({type:Boolean,reflect:!0})],r.prototype,"standalone",void 0),r=h([k("esp-flyout")],r);export{r as EspalierFlyout};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var u=function(t,e,o,n){var
|
|
1
|
+
var u=function(t,e,o,n){var i=arguments.length,s=i<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,o):n,c;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(t,e,o,n);else for(var l=t.length-1;l>=0;l--)(c=t[l])&&(s=(i<3?c(s):i>3?c(e,o,s):c(e,o))||s);return i>3&&s&&Object.defineProperty(e,o,s),s};import"../pickers/esp-pick-one.js";import{customElement as $,property as p,state as G}from"lit/decorators.js";import{EspalierElementBase as A}from"../shared/esp-element-base.js";import{html as N}from"lit";const w=[{family:"Arial / Helvetica",stack:"Arial, Helvetica, sans-serif",category:"sans-serif",kind:"web-safe"},{family:"Georgia / Times New Roman",stack:'Georgia, "Times New Roman", Times, serif',category:"serif",kind:"web-safe"},{family:"Verdana / Geneva",stack:"Verdana, Geneva, sans-serif",category:"sans-serif",kind:"web-safe"},{family:"Tahoma / Geneva",stack:"Tahoma, Geneva, sans-serif",category:"sans-serif",kind:"web-safe"},{family:"Trebuchet MS",stack:'"Trebuchet MS", Arial, sans-serif',category:"sans-serif",kind:"web-safe"},{family:"Courier New",stack:'"Courier New", Courier, monospace',category:"monospace",kind:"web-safe"},{family:"System Sans",stack:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',category:"sans-serif",kind:"web-safe"},{family:"System Serif",stack:'ui-serif, Georgia, Cambria, "Times New Roman", Times, serif',category:"serif",kind:"web-safe"},{family:"System Monospace",stack:'ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", "Courier New", monospace',category:"monospace",kind:"web-safe"}];let f,m=!1;const U=async()=>{if(f)return f;if(m){for(;!f;)await new Promise(n=>setTimeout(n,100));return f}m=!0;const t=document.getElementsByTagName("esp-root")[0];if(!t)throw new Error("<esp-font-picker> requires an <esp-root> ancestor. Wrap your application in <esp-root> to use the font picker.");const e=t.fontDefinitionsUrl||`${t.fontCSSRoot}font-definitions.json`,o=await fetch(e);if(!o.ok)throw m=!1,new Error(`Failed to load font definitions from ${e} (${o.status}). Run 'npm run build-fonts' to generate the font catalog.`);return f=await o.json(),f},k="esp-preview-",V=t=>`${k}${t}`,d=new Map,g=async t=>{if(d.has(t))return!0;try{const e=document.getElementsByTagName("esp-root")[0];if(!e)return!1;const o=t.replaceAll(" ","-"),n=await fetch(`${e.fontCSSRoot}${o}.css`);if(!n.ok)return!1;let i=await n.text();i=i.replace(/font-family:\s*'([^']+)'/g,(c,l)=>`font-family: '${k}${l}'`);const s=document.createElement("style");return s.textContent=i,s.dataset.font=t,document.head.appendChild(s),d.set(t,s),!0}catch(e){return console.warn(`Failed to load CSS for font ${t}:`,e),!1}},v=t=>{const e=d.get(t);e&&(e.remove(),d.delete(t))},F="data-esp-font-picker",b="data-esp-font-picker-root",I=t=>t.closest("esp-root"),C=t=>I(t)?.correlationId??"",E=(t,e)=>`link[${F}="${CSS.escape(t)}"][${b}="${CSS.escape(e)}"]`,S=(t,e)=>{if(!e)return;const o=I(t),n=o?.correlationId??"";if(o?.googleFontLoading==="none"){h(t,e);return}if(document.head.querySelector(E(e,n)))return;const i=encodeURIComponent(e),s=document.createElement("link");s.rel="stylesheet",s.href=`https://fonts.googleapis.com/css2?family=${i}&display=swap`,s.setAttribute(F,e),s.setAttribute(b,n),document.head.appendChild(s)},h=(t,e)=>{if(!e)return;const o=C(t);if(Array.from(document.getElementsByTagName("esp-font-picker")).some(s=>C(s)===o&&s.fontSource==="google"&&s.value===e))return;document.head.querySelector(E(e,o))?.remove()},R=t=>t.kind!=="web-safe",y=t=>R(t)?t.family:t.stack,x=t=>R(t)?`${V(t.family)}, "${t.family}"`:t.stack,_=(t,e)=>t.filter(o=>{switch(e){case"not-display":return o.category!=="display";default:return o.category===e}});let r=class extends A{constructor(){super(...arguments),this.loadedFonts=new Set,this.formItemDescription=null,this._rangeGeneration=0,this._initGeneration=0,this._fontsReady=Promise.resolve(),this.fonts=[],this.category=null,this.fontSource="google",this.value="",this.placeholder="Choose a font...",this.handleItemsInViewEvent=e=>{e.stopPropagation(),this.handleItemsInView(e.detail)}}focus(){this.shadowRoot?.querySelector("esp-pick-one")?.focus()}setFormItemDescription(e){this.formItemDescription=e,this.syncFormItemDescription()}syncFormItemDescription(){this.shadowRoot?.querySelector("esp-pick-one")?.setFormItemDescription?.(this.formItemDescription)}async getUpdateComplete(){const e=await super.getUpdateComplete();return await this._fontsReady,e}firstUpdated(e){super.firstUpdated(e),this._fontsReady=this.initFonts()}updated(e){super.updated(e),this.syncFormItemDescription();const o=e.has("fontSource")&&e.get("fontSource")!==void 0,n=e.has("category")&&e.get("category")!==void 0;if(o||n){if(e.get("fontSource")==="google"&&this.fontSource==="web-safe"){const i=this.value;for(const s of this.loadedFonts)v(s);this.loadedFonts.clear(),this.value="",i&&h(this,i)}this._fontsReady=this.initFonts()}if(e.has("value")&&this.value&&this.fontSource==="google"){const i=e.get("value");i!==this.value&&this.ensureFontLoaded(this.value,i)}}async ensureFontLoaded(e,o){await g(e)&&this.loadedFonts.add(e),this.value===e&&(S(this,e),o&&o!==e&&h(this,o))}async initFonts(){const e=++this._initGeneration;if(this.fontSource==="web-safe"){this.fonts=this.category?_(w,this.category):w;return}const o=await U();if(!(e!==this._initGeneration||this.fontSource!=="google")&&(this.fonts=this.category?_(o,this.category):o,this.value&&this.fonts.some(n=>y(n)===this.value))){const n=this.value;if(await g(n)){if(e!==this._initGeneration||this.fontSource!=="google"||this.value!==n){v(n);return}this.loadedFonts.add(n)}if(e!==this._initGeneration||this.fontSource!=="google"||this.value!==n)return;S(this,n)}}async handleItemsInView(e){if(this.fontSource==="web-safe")return;const o=++this._rangeGeneration,n=3,i=e.items??[],s=new Set,c=Math.max(0,e.first),l=Math.min(e.last+n,i.length);for(let a=c;a<l;a++)s.add(i[a].value);for(const a of s)this.loadedFonts.has(a)||await g(a)&&this.loadedFonts.add(a);if(o!==this._rangeGeneration)return;const T=new Set(Array.from(document.getElementsByTagName("esp-font-picker")).map(a=>a.value).filter(Boolean));for(const a of this.loadedFonts)T.has(a)||s.has(a)||(this.loadedFonts.delete(a),v(a))}render(){return N`<esp-pick-one
|
|
2
2
|
typeahead
|
|
3
3
|
.pickerItems=${this.fonts.map(e=>({text:e.family,value:y(e),selected:this.value===y(e),styles:{fontFamily:x(e)}}))}
|
|
4
4
|
.value=${this.value}
|
|
5
5
|
.placeholder=${this.placeholder}
|
|
6
6
|
@range-changed=${this.handleItemsInViewEvent}
|
|
7
|
-
@value-changed=${async e=>{e.stopPropagation();const o=this.value;if(!e.detail){this.value="",o&&h(this,o),this.dispatchEvent(new CustomEvent("value-changed",{detail:void 0,bubbles:!0,composed:!0}));return}const n=this.fonts.find(
|
|
7
|
+
@value-changed=${async e=>{e.stopPropagation();const o=this.value;if(!e.detail){this.value="",o&&h(this,o),this.dispatchEvent(new CustomEvent("value-changed",{detail:void 0,bubbles:!0,composed:!0}));return}const n=this.fonts.find(i=>y(i)===e.detail.value);this.value=e.detail.value,this.fontSource==="google"&&(await g(this.value)&&this.loadedFonts.add(this.value),S(this,this.value),o&&o!==this.value&&h(this,o)),this.dispatchEvent(new CustomEvent("value-changed",{detail:n,bubbles:!0,composed:!0}))}}
|
|
8
8
|
>
|
|
9
|
-
</esp-pick-one>`}};u([G()],r.prototype,"fonts",void 0),u([p({attribute:"category",type:String})],r.prototype,"category",void 0),u([p({attribute:"font-source",type:String})],r.prototype,"fontSource",void 0),u([p({type:String})],r.prototype,"value",void 0),u([p({type:String})],r.prototype,"placeholder",void 0),r=u([
|
|
9
|
+
</esp-pick-one>`}};u([G()],r.prototype,"fonts",void 0),u([p({attribute:"category",type:String})],r.prototype,"category",void 0),u([p({attribute:"font-source",type:String})],r.prototype,"fontSource",void 0),u([p({type:String})],r.prototype,"value",void 0),u([p({type:String})],r.prototype,"placeholder",void 0),r=u([$("esp-font-picker")],r);const q=()=>{f=void 0,m=!1;for(const t of document.head.querySelectorAll("style[data-font]"))t.remove();d.clear();for(const t of document.head.querySelectorAll(`link[${F}]`))t.remove()};export{r as EspalierFontPicker,w as WEB_SAFE_FONTS,U as getGoogleFonts,V as previewFontFamily,q as resetFontCache};
|