@taprootio/espalier 2.1.3 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,s):r,p;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")a=Reflect.decorate(n,e,s,r);else for(var l=n.length-1;l>=0;l--)(p=n[l])&&(a=(d<3?p(a):d>3?p(e,s,a):p(e,s))||a);return d>3&&a&&Object.defineProperty(e,s,a),a};import{css as g,html as f}from"lit";import{customElement as u,property as i}from"lit/decorators.js";import{classMap as m}from"lit/directives/class-map.js";import{createRef as v,ref as w}from"lit/directives/ref.js";import{EspalierElementBase as h}from"../shared/esp-element-base.js";import{BiDirectionalStickyController as c}from"./bi-directional-sticky-controller.js";import{getEspBus as b}from"../shared/bus-events.js";import"../toaster/esp-toaster.js";let t=class extends h{constructor(){super(),this.dialogZone=v(),this.kind="wide",this.align="start",this.contained=!1,this.headerPosition="normal",this.fixedMenus=!1,new c(this,".esp-page-left > .sticky-wrapper"),new c(this,".esp-page-right > .sticky-wrapper")}AddDialog(e){this.dialogZone.value?.appendChild(e)}updated(e){super.updated(e),(e.has("fixedMenus")||e.has("headerPosition"))&&b().publish("fixed-menus-changed",{fixed:this.fixedMenus||this.headerPosition==="fixed"})}render(){const e=this.fixedMenus||this.headerPosition==="fixed",s=!e&&this.headerPosition==="sticky";return f`
2
- <div part="wrapper" class="esp-page ${m({"fixed-menus":e,"fixed-header":e,"sticky-header":s})}">
1
+ var d=function(h,e,s,o){var n=arguments.length,a=n<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,s):o,t;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")a=Reflect.decorate(h,e,s,o);else for(var r=h.length-1;r>=0;r--)(t=h[r])&&(a=(n<3?t(a):n>3?t(e,s,a):t(e,s))||a);return n>3&&a&&Object.defineProperty(e,s,a),a};import{css as f,html as m}from"lit";import{customElement as v,property as l}from"lit/decorators.js";import{classMap as y}from"lit/directives/class-map.js";import{createRef as c,ref as u}from"lit/directives/ref.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import{BiDirectionalStickyController as p}from"./bi-directional-sticky-controller.js";import{getEspBus as w}from"../shared/bus-events.js";import"../toaster/esp-toaster.js";let i=class extends g{constructor(){super(),this.dialogZone=c(),this.flyoutSlot=c(),this.kind="wide",this.align="start",this.contained=!1,this.headerPosition="normal",this.fixedMenus=!1,new p(this,".esp-page-left > .sticky-wrapper"),new p(this,".esp-page-right > .sticky-wrapper"),new p(this,".esp-page-flyout > .sticky-wrapper"),this.addEventListener("flyout-state-changed",e=>this.syncFlyoutState(e))}syncFlyoutState(e){if(e&&e.target?.closest?.("esp-page")!==this)return;const s=t=>{const r=t.mode;return(typeof r=="string"?r:t.getAttribute("mode"))==="overlay"},o=t=>{const r=t.open;return typeof r=="boolean"?r:t.hasAttribute("open")},n=t=>t.anchor!=null,a=(this.flyoutSlot.value?.assignedElements()??[]).filter(t=>t.tagName==="ESP-FLYOUT");this.toggleAttribute("flyout-open",a.some(t=>o(t)&&!s(t))),this.toggleAttribute("flyout-overlay-open",a.some(t=>o(t)&&s(t))),this.toggleAttribute("flyout-anchored",a.some(t=>o(t)&&n(t)))}AddDialog(e){this.dialogZone.value?.appendChild(e)}firstUpdated(e){super.firstUpdated(e),this.syncFlyoutState()}updated(e){super.updated(e),(e.has("fixedMenus")||e.has("headerPosition"))&&w().publish("fixed-menus-changed",{fixed:this.fixedMenus||this.headerPosition==="fixed"})}render(){const e=this.fixedMenus||this.headerPosition==="fixed",s=!e&&this.headerPosition==="sticky";return m`
2
+ <div part="wrapper" class="esp-page ${y({"fixed-menus":e,"fixed-header":e,"sticky-header":s})}">
3
3
  <div part="canvas" class="esp-page-canvas esp-page-canvas--left" aria-hidden="true"></div>
4
4
  <div part="canvas" class="esp-page-canvas esp-page-canvas--right" aria-hidden="true"></div>
5
5
  <div part="surface" class="esp-page-surface" aria-hidden="true"></div>
@@ -19,20 +19,40 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
19
19
  <slot name="right"></slot>
20
20
  </div>
21
21
  </aside>
22
+ <div class="esp-page-flyout">
23
+ <div class="sticky-wrapper">
24
+ <slot
25
+ name="flyout"
26
+ ${u(this.flyoutSlot)}
27
+ @slotchange=${()=>this.syncFlyoutState()}
28
+ ></slot>
29
+ </div>
30
+ </div>
22
31
  <footer>
23
32
  <slot name="footer"></slot>
24
33
  </footer>
25
- <div id="dialog-drop-zone" ${w(this.dialogZone)}></div>
34
+ <div id="dialog-drop-zone" ${u(this.dialogZone)}></div>
26
35
  <esp-toaster></esp-toaster>
27
36
  </div>
28
- `}};t.styles=[...h.styles,g`
37
+ `}};i.styles=[...g.styles,f`
29
38
  :host {
30
39
  --_esp-page-resolved-max-width: var(--esp-page-max-width, 1536px);
31
40
 
32
41
  --_esp-page-main-track: minmax(0, var(--_esp-page-resolved-max-width));
33
42
 
34
- --_esp-page-gutter-left: 0;
43
+ --_esp-page-gutter-left: 0fr;
35
44
  --_esp-page-gutter-right: 1fr;
45
+
46
+ --_esp-page-flyout-min: 0px;
47
+
48
+ --_esp-page-surface-edge-shadow: 0.75rem 0 1.5rem -0.75rem var(--esp-color-shadow);
49
+
50
+ --_esp-page-surface-shadow: var(
51
+ --esp-page-surface-shadow,
52
+ -0.75rem 0 1.5rem -0.75rem var(--esp-color-shadow),
53
+ var(--_esp-page-surface-edge-shadow)
54
+ );
55
+ --_esp-page-surface-border: var(--esp-page-surface-border, none);
36
56
  --_esp-page-fixed-header-offset: var(
37
57
  --esp-page-fixed-header-offset,
38
58
  var(--esp-header-height, calc(4.5 * var(--esp-size-small)))
@@ -52,15 +72,42 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
52
72
 
53
73
  :host([align="end"]) {
54
74
  --_esp-page-gutter-left: 1fr;
55
- --_esp-page-gutter-right: 0;
75
+ --_esp-page-gutter-right: 0fr;
56
76
  }
57
77
 
58
78
 
59
79
  :host([kind="full"]) {
60
80
  --_esp-page-resolved-max-width: var(--esp-page-max-width, none);
61
81
  --_esp-page-main-track: 1fr;
62
- --_esp-page-gutter-left: 0;
63
- --_esp-page-gutter-right: 0;
82
+ --_esp-page-gutter-left: 0fr;
83
+ --_esp-page-gutter-right: 0fr;
84
+ }
85
+
86
+
87
+ :host([flyout-open]) {
88
+ --_esp-page-flyout-min: var(--esp-page-flyout-width, 20rem);
89
+ }
90
+
91
+
92
+ @media (max-width: 50em) {
93
+ :host([flyout-open]) {
94
+ --_esp-page-flyout-min: 0px;
95
+ }
96
+ }
97
+
98
+
99
+ :host([flyout-overlay-open]) .esp-page > div.esp-page-flyout {
100
+ z-index: var(--esp-flyout-z-index, 3000);
101
+ }
102
+
103
+
104
+ :host([flyout-anchored]) .esp-page > div.esp-page-flyout > .sticky-wrapper {
105
+ position: static;
106
+ }
107
+
108
+
109
+ slot[name="flyout"]::slotted(esp-flyout[match-surface]) {
110
+ --esp-flyout-shadow: var(--_esp-page-surface-edge-shadow);
64
111
  }
65
112
 
66
113
 
@@ -116,8 +163,13 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
116
163
  [canvas-left-end surface-start left-start] min-content
117
164
  [left-end main-start] var(--_esp-page-main-track)
118
165
  [main-end right-start] min-content
119
- [right-end surface-end canvas-right-start] var(--_esp-page-gutter-right)
120
- [canvas-right-end full-end];
166
+ [right-end surface-end canvas-right-start flyout-start] minmax(
167
+ var(--_esp-page-flyout-min),
168
+ var(--_esp-page-gutter-right)
169
+ )
170
+ [flyout-end canvas-right-end full-end];
171
+
172
+ transition: grid-template-columns 0.25s ease;
121
173
  grid-template-rows:
122
174
  [top-start] min-content
123
175
  [top-end content-start] 1fr
@@ -173,6 +225,8 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
173
225
  position: relative;
174
226
  overflow: hidden;
175
227
 
228
+ background: var(--esp-page-main-background, transparent);
229
+
176
230
  contain: inline-size;
177
231
  }
178
232
 
@@ -181,6 +235,21 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
181
235
  }
182
236
 
183
237
 
238
+ > div.esp-page-flyout {
239
+
240
+ grid-column: flyout;
241
+ justify-self: start;
242
+ grid-row: content;
243
+ z-index: 5;
244
+ position: relative;
245
+
246
+
247
+ @media (max-width: 50em) {
248
+ z-index: var(--esp-flyout-z-index, 3000);
249
+ }
250
+ }
251
+
252
+
184
253
  > .esp-page-canvas {
185
254
 
186
255
  grid-row: top-start / footer-end;
@@ -204,6 +273,7 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
204
273
  }
205
274
 
206
275
  > .esp-page-canvas--right {
276
+
207
277
  grid-column: canvas-right;
208
278
  }
209
279
 
@@ -214,12 +284,8 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
214
284
  grid-row: top-start / footer-end;
215
285
  z-index: 2;
216
286
  pointer-events: none;
217
- box-shadow: var(
218
- --esp-page-surface-shadow,
219
- -0.75rem 0 1.5rem -0.75rem var(--esp-color-shadow),
220
- 0.75rem 0 1.5rem -0.75rem var(--esp-color-shadow)
221
- );
222
- border-inline: var(--esp-page-surface-border, none);
287
+ box-shadow: var(--_esp-page-surface-shadow);
288
+ border-inline: var(--_esp-page-surface-border);
223
289
  }
224
290
 
225
291
 
@@ -270,6 +336,7 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
270
336
  > div.esp-page-main,
271
337
  > aside.esp-page-left,
272
338
  > aside.esp-page-right,
339
+ > div.esp-page-flyout,
273
340
  > .esp-page-surface,
274
341
  > .esp-page-canvas {
275
342
  margin-top: var(--_esp-page-fixed-header-offset);
@@ -299,4 +366,10 @@ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnP
299
366
  .esp-page:has(esp-dialog[is-open="true"]) {
300
367
  overflow: hidden;
301
368
  }
302
- `],o([i({reflect:!0})],t.prototype,"kind",void 0),o([i({reflect:!0})],t.prototype,"align",void 0),o([i({type:Boolean,reflect:!0})],t.prototype,"contained",void 0),o([i({attribute:"header-position",reflect:!0})],t.prototype,"headerPosition",void 0),o([i({attribute:"fixed-menus",type:Boolean,reflect:!0})],t.prototype,"fixedMenus",void 0),t=o([u("esp-page")],t);export{t as EspalierPage};
369
+
370
+ @media (prefers-reduced-motion: reduce) {
371
+ .esp-page {
372
+ transition: none;
373
+ }
374
+ }
375
+ `],d([l({reflect:!0})],i.prototype,"kind",void 0),d([l({reflect:!0})],i.prototype,"align",void 0),d([l({type:Boolean,reflect:!0})],i.prototype,"contained",void 0),d([l({attribute:"header-position",reflect:!0})],i.prototype,"headerPosition",void 0),d([l({attribute:"fixed-menus",type:Boolean,reflect:!0})],i.prototype,"fixedMenus",void 0),i=d([v("esp-page")],i);export{i as EspalierPage};
@@ -24,6 +24,7 @@
24
24
  */
25
25
  import { EspBus } from "./esp-bus.js";
26
26
  import type { ToastConfig } from "./toast-events.js";
27
+ import type { FlyoutConfig } from "./flyout-events.js";
27
28
  /**
28
29
  * Contract for elements that provide a seed color to their subtree.
29
30
  * Implemented by `EspalierRoot` (the global provider) and
@@ -91,6 +92,22 @@ export interface SchemeEvents {
91
92
  export interface ToastEvents {
92
93
  "show-toast": ToastConfig;
93
94
  }
95
+ /**
96
+ * Flyout surface events.
97
+ *
98
+ * Published by the `showFlyout()` / `closeFlyout()` helpers and
99
+ * subscribed to by `<esp-flyout>`. This is how components that
100
+ * cannot know where the flyout lives (form items, help buttons,
101
+ * dialog content) request the page's flyout surface.
102
+ *
103
+ * @docUrl /api/flyout-events
104
+ * @menuGroup Bus Events
105
+ * @menuLabel FlyoutEvents
106
+ */
107
+ export interface FlyoutEvents {
108
+ "show-flyout": FlyoutConfig;
109
+ "close-flyout": Record<string, never>;
110
+ }
94
111
  /**
95
112
  * Cross-popover coordination events.
96
113
  *
@@ -157,7 +174,7 @@ export interface PageEventMap {
157
174
  * @menuGroup Bus Events
158
175
  * @menuLabel EspBusEventMap
159
176
  */
160
- export type EspBusEventMap = SchemeEvents & ToastEvents & PopoverEvents & SizeEvents & PageEventMap;
177
+ export type EspBusEventMap = SchemeEvents & ToastEvents & FlyoutEvents & PopoverEvents & SizeEvents & PageEventMap;
161
178
  /**
162
179
  * Typed accessor for the singleton bus.
163
180
  *
@@ -26,10 +26,12 @@ export { type GridClickedEvent, type GridDataStateEventDetail, type GridItemsCha
26
26
  export { type DestroyEspalierInfo } from "../info/esp-info.js";
27
27
  export { type ValidityChangedDetail, type ValidationError, VALIDITY_CHANGED_EVENT, } from "./validation.js";
28
28
  export { type ToastConfig } from "./toast-events.js";
29
+ export { type FlyoutConfig, type FlyoutCloseReason } from "./flyout-events.js";
29
30
  export { type PickerItem } from "../pickers/esp-picker-item.js";
30
31
  export { type EspalierUploadImage } from "../image-upload/image-helpers.js";
31
32
  export { type FontPickerValueChangedDetail, type GoogleFont, type WebSafeFont, } from "../font-picker/esp-font-picker.js";
32
33
  import type { EspalierDetails } from "../details/esp-details.js";
34
+ import type { FlyoutCloseReason } from "./flyout-events.js";
33
35
  import type { ValidityChangedDetail } from "./validation.js";
34
36
  import type { GridClickedEvent, GridItemsChangedEventDetail, GridLoadErrorEventDetail, GridLoadStartEventDetail, GridLoadSuccessEventDetail } from "../grid/esp-grid.js";
35
37
  import type { DestroyEspalierInfo } from "../info/esp-info.js";
@@ -63,6 +65,9 @@ export declare const ESP_EVENTS: {
63
65
  readonly ESP_ACCORDION_CHANGE: "esp-accordion-change";
64
66
  readonly DRAWER_OPENED: "drawer-opened";
65
67
  readonly DRAWER_CLOSED: "drawer-closed";
68
+ readonly FLYOUT_OPENED: "flyout-opened";
69
+ readonly FLYOUT_CLOSED: "flyout-closed";
70
+ readonly FLYOUT_STATE_CHANGED: "flyout-state-changed";
66
71
  readonly POPOVER_OPENED: "popover-opened";
67
72
  readonly POPOVER_CLOSED: "popover-closed";
68
73
  readonly GRID_EVENT: "grid-event";
@@ -267,6 +272,14 @@ export interface EspalierMenuEventMap {
267
272
  [ESP_EVENTS.DRAWER_OPENED]: CustomEvent<void>;
268
273
  [ESP_EVENTS.DRAWER_CLOSED]: CustomEvent<void>;
269
274
  }
275
+ /** Events fired by `<esp-flyout>`. */
276
+ export interface EspalierFlyoutEventMap {
277
+ [ESP_EVENTS.FLYOUT_OPENED]: CustomEvent<Record<string, never>>;
278
+ [ESP_EVENTS.FLYOUT_CLOSED]: CustomEvent<{
279
+ reason: FlyoutCloseReason;
280
+ }>;
281
+ [ESP_EVENTS.FLYOUT_STATE_CHANGED]: CustomEvent<Record<string, never>>;
282
+ }
270
283
  /** Events fired by `<esp-header-button>`. */
271
284
  export interface EspalierHeaderButtonEventMap {
272
285
  [ESP_EVENTS.CLICKED]: CustomEvent<Record<string, never>>;
@@ -1 +1 @@
1
- import{VALIDITY_CHANGED_EVENT as r}from"./validation.js";const e={VALUE_CHANGED:"value-changed",VALIDITY_CHANGED:"validity-changed",CLICKED:"clicked",ESP_SUBMIT:"esp-submit",ESP_SUBMIT_RESPONSE:"esp-submit-response",ESP_SUBMIT_ERROR:"esp-submit-error",ESP_TAB_CHANGED:"esp-tab-changed",ESP_TAB_UPDATED:"esp-tab-updated",ESP_TOGGLE:"esp-toggle",ESP_ACCORDION_CHANGE:"esp-accordion-change",DRAWER_OPENED:"drawer-opened",DRAWER_CLOSED:"drawer-closed",POPOVER_OPENED:"popover-opened",POPOVER_CLOSED:"popover-closed",GRID_EVENT:"grid-event",GRID_LOAD_START:"esp-grid-load-start",GRID_LOAD_SUCCESS:"esp-grid-load-success",GRID_LOAD_ERROR:"esp-grid-load-error",GRID_ITEMS_CHANGED:"esp-grid-items-changed",DESTROY:"destroy",FILE_SELECTED:"file-selected",FILE_REMOVED:"file-removed",FILES_SELECTED:"files-selected",FILES_REJECTED:"files-rejected",UPLOAD_RETRY:"upload-retry",RETRY_UPLOAD:"retry-upload",IMAGES_REORDERED:"images-reordered",SEARCH_REQUESTED:"search-requested",RESULT_SELECTED:"result-selected",SEARCH_CLOSED:"search-closed",SELECTION_CHANGED:"selection-changed",CLOSE_MENU:"close-menu",REMOVE_IMAGE:"remove-image"};export{e as ESP_EVENTS,r as VALIDITY_CHANGED_EVENT};
1
+ import{VALIDITY_CHANGED_EVENT as D}from"./validation.js";const e={VALUE_CHANGED:"value-changed",VALIDITY_CHANGED:"validity-changed",CLICKED:"clicked",ESP_SUBMIT:"esp-submit",ESP_SUBMIT_RESPONSE:"esp-submit-response",ESP_SUBMIT_ERROR:"esp-submit-error",ESP_TAB_CHANGED:"esp-tab-changed",ESP_TAB_UPDATED:"esp-tab-updated",ESP_TOGGLE:"esp-toggle",ESP_ACCORDION_CHANGE:"esp-accordion-change",DRAWER_OPENED:"drawer-opened",DRAWER_CLOSED:"drawer-closed",FLYOUT_OPENED:"flyout-opened",FLYOUT_CLOSED:"flyout-closed",FLYOUT_STATE_CHANGED:"flyout-state-changed",POPOVER_OPENED:"popover-opened",POPOVER_CLOSED:"popover-closed",GRID_EVENT:"grid-event",GRID_LOAD_START:"esp-grid-load-start",GRID_LOAD_SUCCESS:"esp-grid-load-success",GRID_LOAD_ERROR:"esp-grid-load-error",GRID_ITEMS_CHANGED:"esp-grid-items-changed",DESTROY:"destroy",FILE_SELECTED:"file-selected",FILE_REMOVED:"file-removed",FILES_SELECTED:"files-selected",FILES_REJECTED:"files-rejected",UPLOAD_RETRY:"upload-retry",RETRY_UPLOAD:"retry-upload",IMAGES_REORDERED:"images-reordered",SEARCH_REQUESTED:"search-requested",RESULT_SELECTED:"result-selected",SEARCH_CLOSED:"search-closed",SELECTION_CHANGED:"selection-changed",CLOSE_MENU:"close-menu",REMOVE_IMAGE:"remove-image"};export{e as ESP_EVENTS,D as VALIDITY_CHANGED_EVENT};
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The reason a flyout closed, carried on the `flyout-closed`
3
+ * event detail.
4
+ *
5
+ * - `"escape"` — the user pressed the Escape key
6
+ * - `"vellum"` — the user clicked the overlay-mode backdrop
7
+ * - `"button"` — the user clicked the flyout's close button
8
+ * - `"programmatic"` — `close()` was called from code (including
9
+ * the `"close-flyout"` bus event)
10
+ *
11
+ * @docUrl /api/flyout-close-reason
12
+ * @menuGroup Event Details
13
+ * @menuLabel FlyoutCloseReason
14
+ */
15
+ export type FlyoutCloseReason = "escape" | "vellum" | "button" | "programmatic";
16
+ /**
17
+ * Configuration for opening a flyout via {@link showFlyout}.
18
+ *
19
+ * @docUrl /api/flyout-config
20
+ * @menuGroup Configuration
21
+ * @menuLabel FlyoutConfig
22
+ */
23
+ export type FlyoutConfig = {
24
+ /**
25
+ * Heading text shown in the flyout's header. Also becomes the
26
+ * flyout's accessible name unless an `aria-label` was set by
27
+ * the author. When omitted, the flyout keeps its current
28
+ * heading.
29
+ */
30
+ heading?: string | undefined;
31
+ /**
32
+ * Content to show. A string is rendered as plain text; pass a
33
+ * `Node` (element or fragment) for rich content. The flyout's
34
+ * existing light-DOM children are **replaced** — a second
35
+ * `showFlyout` swaps content in place, it never stacks. When
36
+ * omitted, the flyout opens with whatever content it already
37
+ * has (e.g. declaratively slotted markup).
38
+ */
39
+ content?: string | Node | undefined;
40
+ /**
41
+ * Triggering element whose block-start edge the in-grid flyout
42
+ * should align with. The flyout stays in the page's normal scroll
43
+ * flow, shifting upward only while needed to fit the visible
44
+ * scrollport. Content taller than that scrollport scrolls inside the
45
+ * panel. Overlay drawers ignore this geometry and remain
46
+ * viewport-fixed. When omitted, the flyout starts at the top of the
47
+ * page's content row.
48
+ */
49
+ anchor?: HTMLElement | undefined;
50
+ /**
51
+ * Element to return focus to when the flyout closes — pass the
52
+ * triggering control. In the in-grid modes (where opening never
53
+ * moves focus) it is focused only if focus is inside the panel at
54
+ * close; in the overlay-drawer mode (a modal, which does move focus
55
+ * in) it overrides the automatic restore-to-opener.
56
+ */
57
+ returnFocusTo?: HTMLElement | undefined;
58
+ };
59
+ /**
60
+ * Open the page's flyout surface. Publishes a `"show-flyout"`
61
+ * event on `EspBus` which is picked up by `<esp-flyout>`.
62
+ *
63
+ * ```ts
64
+ * import { showFlyout } from "@taprootio/espalier";
65
+ *
66
+ * showFlyout({ heading: "Details", content: detailsFragment });
67
+ * ```
68
+ *
69
+ * If no `<esp-flyout>` is connected, the event goes unserviced —
70
+ * callers that need a fallback (e.g. opening a URL in a new tab)
71
+ * should check for a connected flyout themselves.
72
+ *
73
+ * @param config - Flyout configuration.
74
+ * @docUrl /api/show-flyout
75
+ * @menuGroup Functions
76
+ * @menuLabel showFlyout
77
+ */
78
+ export declare function showFlyout(config?: FlyoutConfig): void;
79
+ /**
80
+ * Close the page's flyout surface. Publishes a `"close-flyout"`
81
+ * event on `EspBus`.
82
+ *
83
+ * @docUrl /api/close-flyout
84
+ * @menuGroup Functions
85
+ * @menuLabel closeFlyout
86
+ */
87
+ export declare function closeFlyout(): void;
@@ -0,0 +1 @@
1
+ import{getEspBus as o}from"./bus-events.js";function l(t={}){o().publish("show-flyout",t)}function s(){o().publish("close-flyout",{})}export{s as closeFlyout,l as showFlyout};
@@ -1 +1 @@
1
- const l=['a[href]:not([disabled]):not([tabindex="-1"])','button:not([disabled]):not([tabindex="-1"])','input:not([disabled]):not([tabindex="-1"])','select:not([disabled]):not([tabindex="-1"])','textarea:not([disabled]):not([tabindex="-1"])','[tabindex]:not([tabindex="-1"]):not([disabled])'].join(", "),a="[autofocus]:not([disabled])";class o{static lock(){o._count===0&&(o._savedOverflow=document.body.style.overflow,document.body.style.overflow="hidden"),o._count++}static unlock(){o._count<=0||(o._count--,o._count===0&&(document.body.style.overflow=o._savedOverflow??"",o._savedOverflow=null))}static _reset(){o._count=0,o._savedOverflow=null}}o._count=0,o._savedOverflow=null;function f(){o._reset()}class r{static lock(t){const e=r._counts.get(t);return e!==void 0?(r._counts.set(t,e+1),!0):t.inert?!1:(r._counts.set(t,1),t.inert=!0,!0)}static unlock(t){const e=r._counts.get(t)??0;if(e<=0)return;const s=e-1;s===0?(t.inert=!1,r._counts.delete(t)):r._counts.set(t,s)}static _reset(){r._counts.clear()}}r._counts=new Map;function d(){r._reset()}class _{get isPromoting(){return this._promoting}constructor(t){this._isOpen=!1,this._previouslyFocused=null,this._inertElements=[],this._promoted=!1,this._dropZone=null,this._promoting=!1,this._host=t.host,this._opts=t,t.host.addController(this)}get isOpen(){return this._isOpen}open(){this._isOpen||(this._previouslyFocused=document.activeElement??null,this._isOpen=!0,o.lock(),this._promoteToDropZone(),this._setInert(!0))}close(){this._isOpen&&(this._isOpen=!1,o.unlock(),this._setInert(!1),this._previouslyFocused?.focus(),this._previouslyFocused=null)}trapFocus(t){const e=this.getFocusableElements();if(e.length===0)return;const s=e[0],n=e[e.length-1],i=this._getDeepActiveElement();t.shiftKey?(i===s||this._isOrContains(s,i))&&(t.preventDefault(),n.focus()):(i===n||this._isOrContains(n,i))&&(t.preventDefault(),s.focus())}moveFocusInto(){const t=this._getAutofocusElement();if(t&&(t.focus(),this._autofocusLanded(t)))return;const e=this.getFocusableElements();if(e.length>0){e[0].focus();return}const s=this._opts.getFocusFallback?.();if(s){s.focus();return}this._opts.getFocusTrapContainer()?.focus()}_getAutofocusElement(){return this._getMatchingElements(a)[0]??null}getFocusableElements(){return this._getMatchingElements(l)}_getMatchingElements(t){const e=this._opts.getFocusTrapContainer();if(!e)return[];const s=[];for(const n of Array.from(e.querySelectorAll("*")))if(n instanceof HTMLElement){if(n.matches(t)&&s.push(n),n.shadowRoot){const i=n.shadowRoot.querySelectorAll(t);s.push(...Array.from(i))}if(n instanceof HTMLSlotElement)for(const i of n.assignedElements({flatten:!0})){if(!(i instanceof HTMLElement))continue;i.matches(t)&&s.push(i);const u=i.querySelectorAll(t);if(s.push(...Array.from(u)),i.shadowRoot){const c=i.shadowRoot.querySelectorAll(t);s.push(...Array.from(c))}}}for(const n of Array.from(this._host.children)){if(!(n instanceof HTMLElement))continue;n.matches(t)&&(s.includes(n)||s.push(n));const i=n.querySelectorAll(t);for(const u of Array.from(i))s.includes(u)||s.push(u);if(n.shadowRoot){const u=n.shadowRoot.querySelectorAll(t);for(const c of Array.from(u))s.includes(c)||s.push(c)}}return s}hostConnected(){}hostDisconnected(){this._promoting||this._isOpen&&(this._setInert(!1),o.unlock(),this._isOpen=!1)}_setInert(t){if(t){this._inertElements=[];const e=this._resolveInertAnchor(),s=e.parentElement??document.body;for(const n of s.children)n instanceof HTMLElement&&n!==e&&r.lock(n)&&this._inertElements.push(n)}else{for(const e of this._inertElements)r.unlock(e);this._inertElements=[]}}_resolveInertAnchor(){if(this._dropZone)return this._dropZone;let t=this._host;for(;!t.parentElement;){const e=t.getRootNode();if(e instanceof ShadowRoot&&e.host instanceof HTMLElement)t=e.host;else break}return t}_getDeepActiveElement(){let t=document.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t}_isOrContains(t,e){return e?t===e?!0:t.contains(e):!1}_autofocusLanded(t){const e=this._getActiveElementChain(),s=e[0];return e.some(n=>this._isOrContains(t,n)?!0:n!==s&&n instanceof HTMLElement&&this._isOrContains(n,t))}_getActiveElementChain(){const t=[];let e=document.activeElement;for(;e;){t.push(e);const s=e.shadowRoot?.activeElement??null;if(!s||s===e)break;e=s}return t}_promoteToDropZone(){if(this._promoted&&this._dropZone){this._promoting=!0;try{this._dropZone.appendChild(this._host)}finally{this._promoting=!1}return}const t=this._host,e=t.closest("esp-page");if(e){if(customElements.get("esp-page")){this._tryPromote(e);return}customElements.whenDefined("esp-page").then(()=>{if(!this._isOpen||!t.isConnected)return;const s=t.closest("esp-page");this._tryPromote(s)&&(this._setInert(!1),this._setInert(!0))})}}_tryPromote(t){if(!t||this._promoted)return!1;const e=t.AddDialog;if(typeof e=="function"){this._promoting=!0;try{e.call(t,this._host)}finally{this._promoting=!1}return this._promoted=!0,this._dropZone=this._host.parentElement,!0}return!1}}export{l as FOCUSABLE_SELECTOR,_ as OverlayController,d as _resetInertLock,f as _resetScrollLock};
1
+ const c=['a[href]:not([disabled]):not([tabindex="-1"])','button:not([disabled]):not([tabindex="-1"])','input:not([disabled]):not([tabindex="-1"])','select:not([disabled]):not([tabindex="-1"])','textarea:not([disabled]):not([tabindex="-1"])','[tabindex]:not([tabindex="-1"]):not([disabled])'].join(", "),l="[autofocus]:not([disabled])";class o{static lock(){o._count===0&&(o._savedOverflow=document.body.style.overflow,document.body.style.overflow="hidden"),o._count++}static unlock(){o._count<=0||(o._count--,o._count===0&&(document.body.style.overflow=o._savedOverflow??"",o._savedOverflow=null))}static _reset(){o._count=0,o._savedOverflow=null}}o._count=0,o._savedOverflow=null;function f(){o._reset()}class r{static lock(t){const e=r._counts.get(t);return e!==void 0?(r._counts.set(t,e+1),!0):t.inert?!1:(r._counts.set(t,1),t.inert=!0,!0)}static unlock(t){const e=r._counts.get(t)??0;if(e<=0)return;const s=e-1;s===0?(t.inert=!1,r._counts.delete(t)):r._counts.set(t,s)}static _reset(){r._counts.clear()}}r._counts=new Map;function d(){r._reset()}class _{get isPromoting(){return this._promoting}constructor(t){this._isOpen=!1,this._previouslyFocused=null,this._inertElements=[],this._promoted=!1,this._pendingReactivation=!1,this._dropZone=null,this._promoting=!1,this._host=t.host,this._opts=t,t.host.addController(this)}get isOpen(){return this._isOpen}open(){this._isOpen||(this._pendingReactivation?this._pendingReactivation=!1:this._previouslyFocused=document.activeElement??null,this._isOpen=!0,o.lock(),this._opts.promote!==!1&&this._promoteToDropZone(),this._setInert(!0))}close(){if(this._pendingReactivation=!1,!this._isOpen){this._previouslyFocused?.focus(),this._previouslyFocused=null;return}this._isOpen=!1,o.unlock(),this._setInert(!1),this._previouslyFocused?.focus(),this._previouslyFocused=null}trapFocus(t){const e=this.getFocusableElements();if(e.length===0)return;const s=e[0],n=e[e.length-1],i=this._getDeepActiveElement();t.shiftKey?(i===s||this._isOrContains(s,i))&&(t.preventDefault(),n.focus()):(i===n||this._isOrContains(n,i))&&(t.preventDefault(),s.focus())}moveFocusInto(){const t=this._getAutofocusElement();if(t&&(t.focus(),this._autofocusLanded(t)))return;const e=this.getFocusableElements();if(e.length>0){e[0].focus();return}const s=this._opts.getFocusFallback?.();if(s){s.focus();return}this._opts.getFocusTrapContainer()?.focus()}_getAutofocusElement(){return this._getMatchingElements(l)[0]??null}getFocusableElements(){return this._getMatchingElements(c)}_getMatchingElements(t){const e=this._opts.getFocusTrapContainer();if(!e)return[];const s=[];for(const n of Array.from(e.querySelectorAll("*")))if(n instanceof HTMLElement){if(n.matches(t)&&s.push(n),n.shadowRoot){const i=n.shadowRoot.querySelectorAll(t);s.push(...Array.from(i))}if(n instanceof HTMLSlotElement)for(const i of n.assignedElements({flatten:!0})){if(!(i instanceof HTMLElement))continue;i.matches(t)&&s.push(i);const u=i.querySelectorAll(t);if(s.push(...Array.from(u)),i.shadowRoot){const a=i.shadowRoot.querySelectorAll(t);s.push(...Array.from(a))}}}for(const n of Array.from(this._host.children)){if(!(n instanceof HTMLElement))continue;n.matches(t)&&(s.includes(n)||s.push(n));const i=n.querySelectorAll(t);for(const u of Array.from(i))s.includes(u)||s.push(u);if(n.shadowRoot){const u=n.shadowRoot.querySelectorAll(t);for(const a of Array.from(u))s.includes(a)||s.push(a)}}return s}hostConnected(){}hostDisconnected(){this._promoting||this._isOpen&&(this._setInert(!1),o.unlock(),this._isOpen=!1,this._pendingReactivation=!0)}_setInert(t){if(t){this._inertElements=[];const e=this._resolveInertAnchor(),s=e.parentElement??document.body;for(const n of s.children)n instanceof HTMLElement&&n!==e&&r.lock(n)&&this._inertElements.push(n)}else{for(const e of this._inertElements)r.unlock(e);this._inertElements=[]}}_resolveInertAnchor(){if(this._dropZone)return this._dropZone;let t=this._host;for(;!t.parentElement;){const e=t.getRootNode();if(e instanceof ShadowRoot&&e.host instanceof HTMLElement)t=e.host;else break}return t}_getDeepActiveElement(){let t=document.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t}_isOrContains(t,e){return e?t===e?!0:t.contains(e):!1}_autofocusLanded(t){const e=this._getActiveElementChain(),s=e[0];return e.some(n=>this._isOrContains(t,n)?!0:n!==s&&n instanceof HTMLElement&&this._isOrContains(n,t))}_getActiveElementChain(){const t=[];let e=document.activeElement;for(;e;){t.push(e);const s=e.shadowRoot?.activeElement??null;if(!s||s===e)break;e=s}return t}_promoteToDropZone(){if(this._promoted&&this._dropZone){this._promoting=!0;try{this._dropZone.appendChild(this._host)}finally{this._promoting=!1}return}const t=this._host,e=t.closest("esp-page");if(e){if(customElements.get("esp-page")){this._tryPromote(e);return}customElements.whenDefined("esp-page").then(()=>{if(!this._isOpen||!t.isConnected)return;const s=t.closest("esp-page");this._tryPromote(s)&&(this._setInert(!1),this._setInert(!0))})}}_tryPromote(t){if(!t||this._promoted)return!1;const e=t.AddDialog;if(typeof e=="function"){this._promoting=!0;try{e.call(t,this._host)}finally{this._promoting=!1}return this._promoted=!0,this._dropZone=this._host.parentElement,!0}return!1}}export{c as FOCUSABLE_SELECTOR,_ as OverlayController,d as _resetInertLock,f as _resetScrollLock};
@@ -5,6 +5,27 @@ import { EspalierElementBase } from "../shared/esp-element-base.js";
5
5
  * components. Place one `<esp-toaster>` in your page layout
6
6
  * (it is included automatically inside `<esp-page>`).
7
7
  *
8
+ * If more than one toaster is connected — for example a page that
9
+ * nests several `<esp-page>`s, each of which injects its own — all
10
+ * toasts live in one shared stack rendered by a single toaster, so
11
+ * each `showToast()` renders once, not once per toaster. The renderer
12
+ * is re-chosen whenever a toast arrives, a toaster connects or
13
+ * disconnects, or a toaster's size collapses or expands, preferring a
14
+ * **visible** instance, and the whole live stack migrates with it —
15
+ * a hidden toaster never swallows toasts, and the stack never
16
+ * fragments across instances. This needs no configuration.
17
+ *
18
+ * The migration timing contract: routing always skips instances
19
+ * hidden by `display`, `visibility`, `opacity: 0`, or
20
+ * `content-visibility` at decision time, and a live stack re-routes
21
+ * **immediately** when its renderer is collapsed via `display` (the
22
+ * collapse resizes the toaster, which is observed). A pure
23
+ * `visibility` or `opacity` flip produces no resize, so an
24
+ * already-rendered stack under one re-routes on the **next** toast,
25
+ * connect/disconnect, or resize instead. (The related `esp-flyout`
26
+ * uses an explicit `standalone` opt-out rather than routing, because
27
+ * its instances are distinct surfaces you target individually.)
28
+ *
8
29
  * Toasts auto-dismiss after their `duration` (default 5 seconds).
9
30
  * A duration of `0` creates a persistent toast that the user must
10
31
  * dismiss manually.
@@ -1,15 +1,15 @@
1
- var d=function(a,t,e,o){var i=arguments.length,s=i<3?t:o===null?o=Object.getOwnPropertyDescriptor(t,e):o,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(a,t,e,o);else for(var l=a.length-1;l>=0;l--)(n=a[l])&&(s=(i<3?n(s):i>3?n(t,e,s):n(t,e))||s);return i>3&&s&&Object.defineProperty(t,e,s),s};import{css as m,html as p}from"lit";import{customElement as u,state as f}from"lit/decorators.js";import{EspalierElementBase as c}from"../shared/esp-element-base.js";import{getEspBus as h}from"../shared/bus-events.js";import{getIconHrefForHost as v}from"../shared/intent-values.js";import{renderSpriteIcon as b}from"../shared/svgs/render-sprite-icon.js";let r=class extends c{constructor(){super(...arguments),this.toasts=[],this.boundHandler=t=>this.handleToast(t)}connectedCallback(){super.connectedCallback(),h().subscribe("show-toast",this.boundHandler)}disconnectedCallback(){super.disconnectedCallback(),h().unsubscribe("show-toast",this.boundHandler)}handleToast(t){this.toasts=[...this.toasts,t];const e=t.duration??5;e>0&&setTimeout(()=>{this.toasts=this.toasts.filter(o=>o!==t),t.onClosed?.()},e*1e3)}removeToast(t){this.toasts=this.toasts.filter(e=>e!==t),t.onClosed?.()}getToastIconHref(t){return t.svgPath?.trim()||v(t.icon,this)}render(){return p`
1
+ var u=function(o,e,s,n){var c=arguments.length,r=c<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,s):n,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(o,e,s,n);else for(var d=o.length-1;d>=0;d--)(a=o[d])&&(r=(c<3?a(r):c>3?a(e,s,r):a(e,s))||r);return c>3&&r&&Object.defineProperty(e,s,r),r},t;import{css as f,html as l}from"lit";import{customElement as v,state as h}from"lit/decorators.js";import{EspalierElementBase as p}from"../shared/esp-element-base.js";import{getEspBus as b}from"../shared/bus-events.js";import{getIconHrefForHost as m}from"../shared/intent-values.js";import{renderSpriteIcon as y}from"../shared/svgs/render-sprite-icon.js";let i=t=class extends p{constructor(){super(...arguments),this.toasts=[]}connectedCallback(){super.connectedCallback(),t.connected.push(this),t.busSubscribed||(b().subscribe("show-toast",t.boundDeliver),t.busSubscribed=!0),typeof ResizeObserver<"u"&&(this.resizeObserver=new ResizeObserver(()=>t.syncRenderer()),this.resizeObserver.observe(this)),t.syncRenderer()}disconnectedCallback(){super.disconnectedCallback(),this.resizeObserver?.disconnect(),this.resizeObserver=void 0,t.connected=t.connected.filter(e=>e!==this),t.connected.length===0?(t.busSubscribed&&(b().unsubscribe("show-toast",t.boundDeliver),t.busSubscribed=!1),t.queue=[]):t.syncRenderer()}static deliver(e){t.queue=[...t.queue,e];const s=e.duration??5;s>0&&setTimeout(()=>t.dismiss(e),s*1e3),t.syncRenderer()}static dismiss(e){t.queue.includes(e)&&(t.queue=t.queue.filter(s=>s!==e),e.onClosed?.(),t.syncRenderer())}static syncRenderer(){const e=t.connected.find(s=>s.isVisible())??t.connected[0];for(const s of t.connected){const n=s===e?t.queue:[];s.toasts.length===n.length&&s.toasts.every((c,r)=>c===n[r])||(s.toasts=[...n])}}isVisible(){const e=this;return typeof e.checkVisibility=="function"?e.checkVisibility({visibilityProperty:!0,opacityProperty:!0,checkVisibilityCSS:!0,checkOpacity:!0}):this.offsetParent!==null}removeToast(e){t.dismiss(e)}getToastIconHref(e){return e.svgPath?.trim()||m(e.icon,this)}render(){return l`
2
2
  <div id="toaster" role="region" aria-label="Notifications" aria-live="polite">
3
- ${this.toasts.map(t=>{const e=this.getToastIconHref(t);return p`<esp-info
4
- .destroyable=${(t.duration??5)===0}
5
- .variant=${t.variant??"complementary"}
6
- @destroy=${()=>this.removeToast(t)}
3
+ ${this.toasts.map(e=>{const s=this.getToastIconHref(e);return l`<esp-info
4
+ .destroyable=${(e.duration??5)===0}
5
+ .variant=${e.variant??"complementary"}
6
+ @destroy=${()=>this.removeToast(e)}
7
7
  >
8
- ${e?b(e,{"aria-hidden":null,class:null,slot:"icon-slot"}):p``}
9
- ${t.message}</esp-info
8
+ ${s?y(s,{"aria-hidden":null,class:null,slot:"icon-slot"}):l``}
9
+ ${e.message}</esp-info
10
10
  >`})}
11
11
  </div>
12
- `}};r.styles=[...c.styles,m`
12
+ `}};i.connected=[],i.busSubscribed=!1,i.queue=[],i.boundDeliver=o=>t.deliver(o),i.styles=[...p.styles,f`
13
13
  #toaster {
14
14
  z-index: var(--esp-toaster-z-index, 5000);
15
15
  position: fixed;
@@ -25,4 +25,4 @@ var d=function(a,t,e,o){var i=arguments.length,s=i<3?t:o===null?o=Object.getOwnP
25
25
  box-shadow: 3px 3px 6px var(--esp-color-shadow);
26
26
  pointer-events: all;
27
27
  }
28
- `],d([f()],r.prototype,"toasts",void 0),r=d([u("esp-toaster")],r);export{r as EspalierToaster};
28
+ `],u([h()],i.prototype,"toasts",void 0),i=t=u([v("esp-toaster")],i);export{i as EspalierToaster};
@@ -460,6 +460,42 @@
460
460
  "category": "shared-hook",
461
461
  "description": "Text color used inside the shared field shell. Defaults to `var(--esp-color-text)`."
462
462
  },
463
+ {
464
+ "name": "--esp-flyout-background",
465
+ "category": "component",
466
+ "component": "esp-flyout",
467
+ "description": "The background color of the panel. Defaults to `var(--esp-color-background)`."
468
+ },
469
+ {
470
+ "name": "--esp-flyout-border",
471
+ "category": "component",
472
+ "component": "esp-flyout",
473
+ "description": "The border on the panel's leading edge. Defaults to the tear-off perforation, `1px dotted var(--esp-color-border)`."
474
+ },
475
+ {
476
+ "name": "--esp-flyout-padding",
477
+ "category": "component",
478
+ "component": "esp-flyout",
479
+ "description": "Padding inside the panel's header and content regions. Defaults to `var(--esp-size-padding)`."
480
+ },
481
+ {
482
+ "name": "--esp-flyout-radius",
483
+ "category": "component",
484
+ "component": "esp-flyout",
485
+ "description": "The radius of the panel's trailing corners. Defaults to `var(--esp-size-border-radius)`; the overlay drawer squares them."
486
+ },
487
+ {
488
+ "name": "--esp-flyout-shadow",
489
+ "category": "component",
490
+ "component": "esp-flyout",
491
+ "description": "The panel's shadow. Defaults to `none` in the gutter/docked modes (the perforation does the separating) and to a drawer shadow in overlay mode."
492
+ },
493
+ {
494
+ "name": "--esp-flyout-z-index",
495
+ "category": "component",
496
+ "component": "esp-flyout",
497
+ "description": "Stack order of the overlay-drawer mode. Defaults to `3000` — above page chrome, below the dialog drop zone (4000). Set it on the `esp-page` (or an ancestor), not on the flyout itself: the page reads the same token to hoist the drawer's aside above its header."
498
+ },
463
499
  {
464
500
  "name": "--esp-font-body",
465
501
  "category": "root-theme",
@@ -1267,12 +1303,24 @@
1267
1303
  "component": "esp-page",
1268
1304
  "description": "Offset reserved for fixed headers. Defaults to `var(--esp-header-height)`."
1269
1305
  },
1306
+ {
1307
+ "name": "--esp-page-flyout-width",
1308
+ "category": "component",
1309
+ "component": "esp-page",
1310
+ "description": "The width of the open flyout track (and of the `esp-flyout` overlay drawer). Defaults to `20rem`."
1311
+ },
1270
1312
  {
1271
1313
  "name": "--esp-page-header-z-index",
1272
1314
  "category": "component",
1273
1315
  "component": "esp-page",
1274
1316
  "description": "Z-index for fixed/sticky header regions. Defaults to `20`."
1275
1317
  },
1318
+ {
1319
+ "name": "--esp-page-main-background",
1320
+ "category": "component",
1321
+ "component": "esp-page",
1322
+ "description": "The background of the main content well. Defaults to `transparent` (the well shows the page background). Set it to give the content well its own card color, or pair the transparent default with `--esp-page-surface-shadow: none` for content that floats directly on the page with no frame."
1323
+ },
1276
1324
  {
1277
1325
  "name": "--esp-page-max-width",
1278
1326
  "category": "component",
@@ -1289,7 +1337,7 @@
1289
1337
  "name": "--esp-page-surface-border",
1290
1338
  "category": "component",
1291
1339
  "component": "esp-page",
1292
- "description": "An optional border on the inline edges of the surface, for themes preferring a hairline over a shadow. Defaults to `none` (e.g. `1px solid var(--esp-color-border)`)."
1340
+ "description": "An optional border on the inline edges of the surface, for themes preferring a hairline over a shadow. Defaults to `none` (e.g. `1px solid var(--esp-color-border)`). Combine with `--esp-page-surface-shadow: none` to switch the content frame from a drop shadow to a hairline, or turn both off for no frame."
1293
1341
  },
1294
1342
  {
1295
1343
  "name": "--esp-page-surface-shadow",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taprootio/espalier",
3
- "version": "2.1.3",
3
+ "version": "2.2.0",
4
4
  "description": "Espalier — a themeable, accessible, framework-agnostic, enterprise-grade design system built on web standards and love.",
5
5
  "customElements": "custom-elements.json",
6
6
  "type": "module",