@taprootio/espalier 2.10.0 → 2.11.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 +54 -0
- package/custom-elements.json +5718 -5206
- package/dist/flyout/esp-flyout.d.ts +20 -12
- package/dist/flyout/esp-flyout.js +75 -22
- package/dist/page/bi-directional-sticky-controller.js +1 -1
- package/dist/page/esp-page.d.ts +129 -39
- package/dist/page/esp-page.js +165 -31
- package/espalier.token-manifest.json +58 -4
- package/package.json +1 -1
|
@@ -2,12 +2,14 @@ import { type PropertyValues } from "lit";
|
|
|
2
2
|
import { EspalierElementBase } from "../shared/esp-element-base.js";
|
|
3
3
|
import { type FlyoutCloseReason } from "../shared/flyout-events.js";
|
|
4
4
|
/**
|
|
5
|
-
* A transient panel for help
|
|
6
|
-
*
|
|
5
|
+
* A transient panel for help and more-info content that claims designed spare
|
|
6
|
+
* width before ever covering the page.
|
|
7
7
|
*
|
|
8
8
|
* Place one `esp-flyout` in an `esp-page`'s `flyout` slot. The panel
|
|
9
|
-
* lives on the canvas, outside the content
|
|
10
|
-
*
|
|
9
|
+
* lives on the canvas after any persistent preview, outside the content
|
|
10
|
+
* surface. It negotiates between `--esp-page-flyout-min-width` and
|
|
11
|
+
* `--esp-page-flyout-max-width`; preview receives flexible room first. The page
|
|
12
|
+
* decides where help goes, from widest viewport to narrowest:
|
|
11
13
|
*
|
|
12
14
|
* 1. **Gutter** — the panel occupies the right canvas gutter. When the
|
|
13
15
|
* gutter already has room, it claims existing spare canvas and the
|
|
@@ -18,19 +20,25 @@ import { type FlyoutCloseReason } from "../shared/flyout-events.js";
|
|
|
18
20
|
* 3. **Docked sidebar** — once the gutter is gone, the panel competes
|
|
19
21
|
* for width with the main well; content narrows but is never
|
|
20
22
|
* covered.
|
|
21
|
-
* 4. **Overlay drawer** —
|
|
22
|
-
*
|
|
23
|
+
* 4. **Overlay drawer** — when the complete sidebar + main + help
|
|
24
|
+
* minimums do not fit, or below the mobile threshold (`50em`, the
|
|
25
|
+
* same one the `esp-menu` drawer uses), the panel becomes a fixed
|
|
23
26
|
* drawer over a vellum backdrop. Set `mode="overlay"` to get this
|
|
24
27
|
* presentation at every width.
|
|
25
28
|
*
|
|
26
29
|
* The panel is styled as a tear-off piece: a dotted perforation on
|
|
27
30
|
* its leading edge, rounded trailing corners, and no shadow — all
|
|
28
31
|
* overridable through the `--esp-flyout-*` tokens below.
|
|
32
|
+
* An anchored panel shown with preview keeps its caret at the main/preview
|
|
33
|
+
* edge and receives a non-interactive dotted bridge across preview from the
|
|
34
|
+
* page. A short, thick terminus on the preview/help seam completes that
|
|
35
|
+
* connection; no consumer positioning is required.
|
|
29
36
|
*
|
|
30
37
|
* A11y follows the presentation. In the in-grid modes (1–3) the
|
|
31
38
|
* flyout is a non-modal `complementary` landmark named by its
|
|
32
|
-
* `heading`,
|
|
33
|
-
* mode (4) it is a true
|
|
39
|
+
* `heading`, opening it never steals focus, and boundary scrolling chains
|
|
40
|
+
* back to the main document. In the overlay-drawer mode (4) it is a true
|
|
41
|
+
* modal: `role="dialog"` + `aria-modal`, the
|
|
34
42
|
* background goes inert, scroll is locked, focus moves into the drawer
|
|
35
43
|
* and is trapped, and focus is restored on close. `Escape` closes it
|
|
36
44
|
* in every mode.
|
|
@@ -38,7 +46,7 @@ import { type FlyoutCloseReason } from "../shared/flyout-events.js";
|
|
|
38
46
|
* ```html
|
|
39
47
|
* <style>
|
|
40
48
|
* esp-page.flyout-demo {
|
|
41
|
-
* --esp-page-max-width: 420px;
|
|
49
|
+
* --esp-page-main-max-width: 420px;
|
|
42
50
|
* --esp-page-canvas-background: var(--esp-color-layer-1);
|
|
43
51
|
* &::part(wrapper) {
|
|
44
52
|
* min-height: 320px;
|
|
@@ -72,7 +80,7 @@ import { type FlyoutCloseReason } from "../shared/flyout-events.js";
|
|
|
72
80
|
* ```html
|
|
73
81
|
* <style>
|
|
74
82
|
* esp-page.flyout-match-demo {
|
|
75
|
-
* --esp-page-max-width: 420px;
|
|
83
|
+
* --esp-page-main-max-width: 420px;
|
|
76
84
|
* &::part(wrapper) {
|
|
77
85
|
* min-height: 320px;
|
|
78
86
|
* height: 320px;
|
|
@@ -317,8 +325,8 @@ export declare class EspalierFlyout extends EspalierElementBase {
|
|
|
317
325
|
* Placement behavior.
|
|
318
326
|
*
|
|
319
327
|
* - `"auto"` (default) — the page's placement ladder: gutter,
|
|
320
|
-
* docked sidebar, then overlay drawer
|
|
321
|
-
* threshold.
|
|
328
|
+
* docked sidebar, then overlay drawer when the complete in-grid
|
|
329
|
+
* minimums do not fit or below the `50em` viewport threshold.
|
|
322
330
|
* - `"overlay"` — always the fixed overlay drawer, at any width.
|
|
323
331
|
* The page never reserves a grid track for an overlay-mode
|
|
324
332
|
* flyout.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var l=function(d,e,t,r){var o=arguments.length,s=o<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(d,e,t,r);else for(var i=d.length-1;i>=0;i--)(n=d[i])&&(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 w,nothing as T}from"lit";import{customElement as O,property as h}from"lit/decorators.js";import{classMap as _}from"lit/directives/class-map.js";import{createRef as F,ref as L}from"lit/directives/ref.js";import{EspalierElementBase as k}from"../shared/esp-element-base.js";import{getEspBus as f}from"../shared/bus-events.js";import{FLYOUT_FULL_HEIGHT_REQUEST_EVENT as A,markFlyoutRequestServiced as M}from"../shared/flyout-events.js";import{OverlayController as q}from"../shared/overlay-controller.js";import{cancelSVG as G}from"../shared/svgs/cancel.js";import{traverseToClosest as v}from"../shared/utilities.js";const B="(max-width: 50em)",H="Flyout",R=p`
|
|
2
2
|
position: fixed;
|
|
3
3
|
inset: 0;
|
|
4
4
|
margin-block-start: 0;
|
|
@@ -13,13 +13,13 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
13
13
|
inset: 0;
|
|
14
14
|
background-color: var(--esp-vellum-background, var(--esp-color-layer-3));
|
|
15
15
|
opacity: var(--esp-vellum-opacity, 0.85);
|
|
16
|
-
`,
|
|
16
|
+
`,z=p`
|
|
17
17
|
position: absolute;
|
|
18
18
|
inset-block: 0;
|
|
19
19
|
inset-inline-end: 0;
|
|
20
20
|
block-size: auto;
|
|
21
21
|
max-block-size: none;
|
|
22
|
-
width: min(var(--esp-page-flyout-width,
|
|
22
|
+
width: min(var(--esp-page-flyout-width, var(--esp-page-flyout-max-width, 30rem)), 85vw);
|
|
23
23
|
overflow-y: auto;
|
|
24
24
|
|
|
25
25
|
border-start-end-radius: 0;
|
|
@@ -31,25 +31,26 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
31
31
|
@starting-style {
|
|
32
32
|
translate: 100% 0;
|
|
33
33
|
}
|
|
34
|
-
`;let
|
|
34
|
+
`;let a=class extends k{constructor(){super(...arguments),this.open=!1,this.heading="",this.mode="auto",this.pageOverlayRequested=!1,this.fullHeight=!1,this.matchSurface=!1,this.standalone=!1,this.scope="outermost",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.dispatchEvent(new CustomEvent("flyout-state-changed",{detail:{},bubbles:!0,composed:!0}))},this.boundAnchorViewportChange=()=>this.scheduleAnchorGeometrySync(),this.boundFullHeightRequest=e=>{e.stopPropagation(),this.fullHeight=!0},this.anchorPositionRaf=0,this.trackingAnchorPosition=!1,this.busSubscribed=!1,this.panelRef=F(),this.overlay=new q({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.pageOverlayRequested||(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(B)),this.overlayMediaQuery?.addEventListener("change",this.boundOverlayMediaChange),this.syncBusSubscription(),document.addEventListener("keydown",this.boundKeydown),this.addEventListener(A,this.boundFullHeightRequest),this.syncOverlayModal(),this.syncAnchorTracking(),this.syncAnchorGeometry()}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeBus(),this.overlayMediaQuery?.removeEventListener("change",this.boundOverlayMediaChange),document.removeEventListener("keydown",this.boundKeydown),this.removeEventListener(A,this.boundFullHeightRequest),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){this.shouldHandleShowRequest(e)&&(M(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.fullHeight=e.fullHeight??!1,this.returnFocusTo=e.returnFocusTo,this.show())}shouldHandleShowRequest(e){const t=v(this,"esp-page"),r=e.anchor??e.returnFocusTo;if(!r){if(!t)return!0;const i=this.getPageChain(t);return this.scope==="outermost"&&i[i.length-1]===t}const o=this.getPageChain(r);if(o.length===0)return t===null;const s=o.find(i=>this.hasNearestScopeFlyout(i)),n=s??o[o.length-1];return t!==n?!1:s?this.scope==="nearest":this.scope==="outermost"}getPageChain(e){const t=[];let r=e;for(;r;){const o=v(r,"esp-page");if(!o||t.includes(o))break;t.push(o),r=this.composedParent(o)}return t}hasNearestScopeFlyout(e){return Array.from(e.querySelectorAll("esp-flyout")).some(t=>!t.standalone&&t.scope==="nearest"&&v(t,"esp-page")===e)}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("fullHeight")||e.has("open")||e.has("mode")||e.has("pageOverlayRequested"))&&(this.syncAnchorTracking(),this.syncAnchorGeometry()),(e.has("open")||e.has("mode")||e.has("pageOverlayRequested"))&&this.syncOverlayModal(),(e.has("open")||e.has("mode")||e.has("anchor")||e.has("pageOverlayRequested"))&&this.dispatchEvent(new CustomEvent("flyout-state-changed",{detail:{},bubbles:!0,composed:!0}))}syncAnchorGeometry(){const e=v(this,"esp-page"),t=this.anchor?this.getPageChain(this.anchor):[],r=e?.shadowRoot?.querySelector(".esp-page-main"),o=this.panelRef.value;if(!this.open||this.effectiveOverlay||!this.anchor||!e||!t.includes(e)||!r||!o){this.clearAnchorGeometry();return}const s=this.anchor.getBoundingClientRect(),n=Math.max(0,s.top-r.getBoundingClientRect().top),i=this.getVisibleBlockBounds(),u=Math.max(0,i.bottom-i.top),c=Number.isFinite(s.height)?s.height:0;this.setGeometryProperty("--_esp-flyout-anchor-offset",`${n}px`),this.setGeometryProperty("--_esp-flyout-max-block-size",`${u}px`),this.setGeometryProperty("--_esp-flyout-anchor-block-size",`${c}px`);const y=o.getBoundingClientRect().height||u,b=Math.max(0,s.top+y-i.bottom),P=Math.max(0,y-c),g=this.fullHeight?b:Math.min(b,P);this.setGeometryProperty("--_esp-flyout-viewport-shift",`${g}px`);const C=s.top-g,m=8,E=s.top+c/2,S=Math.min(Math.max(m,y-m),Math.max(m,E-C));this.setGeometryProperty("--_esp-flyout-anchor-marker-offset",`${S}px`)}getVisibleBlockBounds(){const e=window.visualViewport;let t=e?.offsetTop??0,r=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(),i=o instanceof HTMLElement?o.clientTop:0,u=o instanceof HTMLElement?o.clientHeight:n.height;if(u<=0)continue;const c=n.top+i;t=Math.max(t,c),r=Math.min(r,c+u)}return{top:t,bottom:Math.max(t,r)}}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"),this.style.removeProperty("--_esp-flyout-anchor-block-size"),this.style.removeProperty("--_esp-flyout-anchor-marker-offset")}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?H:"");t?(this.setAttribute("aria-label",t),this.lastGeneratedAriaLabel=t):(this.removeAttribute("aria-label"),this.lastGeneratedAriaLabel=null)}render(){return w`
|
|
35
35
|
<div class="vellum" aria-hidden="true" @click=${()=>this.close("vellum")}></div>
|
|
36
36
|
<div
|
|
37
|
-
class=${
|
|
37
|
+
class=${_({panel:!0,anchored:!!this.anchor,"full-height":this.fullHeight})}
|
|
38
38
|
part="panel"
|
|
39
|
-
${
|
|
39
|
+
${L(this.panelRef)}
|
|
40
40
|
>
|
|
41
|
+
<span class="anchor-terminus" aria-hidden="true"></span>
|
|
41
42
|
<header part="header">
|
|
42
|
-
${this.heading?w`<h2>${this.heading}</h2>`:
|
|
43
|
+
${this.heading?w`<h2>${this.heading}</h2>`:T}
|
|
43
44
|
|
|
44
45
|
<button class="close" aria-label="Close" @click=${()=>this.close("button")}>
|
|
45
|
-
${
|
|
46
|
+
${G}
|
|
46
47
|
</button>
|
|
47
48
|
</header>
|
|
48
49
|
<div class="content" part="content">
|
|
49
50
|
<slot @slotchange=${this.boundAnchorViewportChange}></slot>
|
|
50
51
|
</div>
|
|
51
52
|
</div>
|
|
52
|
-
`}};
|
|
53
|
+
`}};a.styles=[...k.styles,p`
|
|
53
54
|
:host {
|
|
54
55
|
display: none;
|
|
55
56
|
}
|
|
@@ -57,7 +58,10 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
57
58
|
:host([open]) {
|
|
58
59
|
display: block;
|
|
59
60
|
|
|
60
|
-
width: var(
|
|
61
|
+
width: var(
|
|
62
|
+
--_esp-flyout-used-width,
|
|
63
|
+
var(--esp-page-flyout-width, var(--esp-page-flyout-min-width, 20rem))
|
|
64
|
+
);
|
|
61
65
|
margin-block-start: calc(
|
|
62
66
|
var(--_esp-flyout-anchor-offset, 0px) - var(--_esp-flyout-viewport-shift, 0px)
|
|
63
67
|
);
|
|
@@ -70,7 +74,10 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
70
74
|
.panel {
|
|
71
75
|
background: var(--esp-flyout-background, var(--esp-color-background));
|
|
72
76
|
|
|
73
|
-
width: var(
|
|
77
|
+
width: var(
|
|
78
|
+
--_esp-flyout-used-width,
|
|
79
|
+
var(--esp-page-flyout-width, var(--esp-page-flyout-min-width, 20rem))
|
|
80
|
+
);
|
|
74
81
|
display: flex;
|
|
75
82
|
flex-direction: column;
|
|
76
83
|
position: relative;
|
|
@@ -96,17 +103,34 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
96
103
|
&.full-height {
|
|
97
104
|
block-size: var(--_esp-flyout-max-block-size, 100dvh);
|
|
98
105
|
|
|
99
|
-
&::before
|
|
106
|
+
&::before,
|
|
107
|
+
&::after,
|
|
108
|
+
> .anchor-terminus {
|
|
100
109
|
display: none;
|
|
101
110
|
}
|
|
102
111
|
}
|
|
103
112
|
|
|
113
|
+
> .anchor-terminus {
|
|
114
|
+
display: block;
|
|
115
|
+
position: absolute;
|
|
116
|
+
z-index: 2;
|
|
117
|
+
inset-block-start: var(--_esp-flyout-anchor-marker-offset, 50%);
|
|
118
|
+
inset-inline-start: -2px;
|
|
119
|
+
inline-size: 4px;
|
|
120
|
+
block-size: var(--esp-size-medium);
|
|
121
|
+
translate: 0 -50%;
|
|
122
|
+
background: var(--esp-color-border);
|
|
123
|
+
pointer-events: none;
|
|
124
|
+
}
|
|
125
|
+
|
|
104
126
|
&::before {
|
|
105
127
|
content: "";
|
|
106
128
|
position: absolute;
|
|
107
129
|
z-index: 1;
|
|
108
130
|
inset-block-start: var(--_esp-flyout-anchor-marker-offset, 50%);
|
|
109
|
-
inset-inline-start: calc(
|
|
131
|
+
inset-inline-start: calc(
|
|
132
|
+
-1 * (var(--esp-size-small) + var(--_esp-flyout-preview-bridge-width, 0px))
|
|
133
|
+
);
|
|
110
134
|
inline-size: var(--esp-size-small);
|
|
111
135
|
block-size: var(--esp-size-medium);
|
|
112
136
|
translate: 0 -50%;
|
|
@@ -114,6 +138,24 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
114
138
|
background: var(--esp-color-border);
|
|
115
139
|
pointer-events: none;
|
|
116
140
|
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
&::after {
|
|
144
|
+
content: "";
|
|
145
|
+
position: absolute;
|
|
146
|
+
z-index: 1;
|
|
147
|
+
inset-block-start: var(--_esp-flyout-anchor-marker-offset, 50%);
|
|
148
|
+
inset-inline-start: calc(-1 * var(--_esp-flyout-preview-bridge-width, 0px));
|
|
149
|
+
inline-size: var(--_esp-flyout-preview-bridge-width, 0px);
|
|
150
|
+
border-block-start: 2px dotted var(--esp-color-border);
|
|
151
|
+
opacity: 0.4;
|
|
152
|
+
translate: 0 -50%;
|
|
153
|
+
pointer-events: none;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
> .anchor-terminus {
|
|
158
|
+
display: none;
|
|
117
159
|
}
|
|
118
160
|
|
|
119
161
|
> header {
|
|
@@ -152,25 +194,34 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
152
194
|
flex: 1;
|
|
153
195
|
min-block-size: 0;
|
|
154
196
|
overflow-y: auto;
|
|
155
|
-
|
|
197
|
+
|
|
198
|
+
overscroll-behavior-block: auto;
|
|
156
199
|
padding: var(--esp-flyout-padding, var(--esp-size-padding));
|
|
157
200
|
}
|
|
158
201
|
}
|
|
159
202
|
|
|
160
203
|
|
|
161
|
-
:host([open][mode="overlay"])
|
|
204
|
+
:host([open][mode="overlay"]),
|
|
205
|
+
:host([open][data-page-overlay]) {
|
|
162
206
|
${R}
|
|
163
207
|
}
|
|
164
208
|
|
|
165
|
-
:host([open][mode="overlay"]) .vellum
|
|
209
|
+
:host([open][mode="overlay"]) .vellum,
|
|
210
|
+
:host([open][data-page-overlay]) .vellum {
|
|
166
211
|
${x}
|
|
167
212
|
}
|
|
168
213
|
|
|
169
|
-
:host([open][mode="overlay"]) .panel
|
|
170
|
-
|
|
214
|
+
:host([open][mode="overlay"]) .panel,
|
|
215
|
+
:host([open][data-page-overlay]) .panel {
|
|
216
|
+
${z}
|
|
171
217
|
}
|
|
172
218
|
|
|
173
|
-
:host([open][mode="overlay"]) .panel.anchored::before
|
|
219
|
+
:host([open][mode="overlay"]) .panel.anchored::before,
|
|
220
|
+
:host([open][mode="overlay"]) .panel.anchored::after,
|
|
221
|
+
:host([open][mode="overlay"]) .panel.anchored > .anchor-terminus,
|
|
222
|
+
:host([open][data-page-overlay]) .panel.anchored::before,
|
|
223
|
+
:host([open][data-page-overlay]) .panel.anchored::after,
|
|
224
|
+
:host([open][data-page-overlay]) .panel.anchored > .anchor-terminus {
|
|
174
225
|
display: none;
|
|
175
226
|
}
|
|
176
227
|
|
|
@@ -185,10 +236,12 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
185
236
|
}
|
|
186
237
|
|
|
187
238
|
.panel {
|
|
188
|
-
${
|
|
239
|
+
${z}
|
|
189
240
|
}
|
|
190
241
|
|
|
191
|
-
.panel.anchored::before
|
|
242
|
+
.panel.anchored::before,
|
|
243
|
+
.panel.anchored::after,
|
|
244
|
+
.panel.anchored > .anchor-terminus {
|
|
192
245
|
display: none;
|
|
193
246
|
}
|
|
194
247
|
}
|
|
@@ -198,4 +251,4 @@ var h=function(d,e,t,i){var o=arguments.length,s=o<3?e:i===null?i=Object.getOwnP
|
|
|
198
251
|
transition: none;
|
|
199
252
|
}
|
|
200
253
|
}
|
|
201
|
-
`],
|
|
254
|
+
`],l([h({type:Boolean,reflect:!0})],a.prototype,"open",void 0),l([h({type:String})],a.prototype,"heading",void 0),l([h({reflect:!0})],a.prototype,"mode",void 0),l([h({type:Boolean,reflect:!0,attribute:"data-page-overlay"})],a.prototype,"pageOverlayRequested",void 0),l([h({attribute:!1})],a.prototype,"anchor",void 0),l([h({type:Boolean,reflect:!0,attribute:"full-height"})],a.prototype,"fullHeight",void 0),l([h({type:Boolean,reflect:!0,attribute:"match-surface"})],a.prototype,"matchSurface",void 0),l([h({type:Boolean,reflect:!0})],a.prototype,"standalone",void 0),l([h({type:String,reflect:!0})],a.prototype,"scope",void 0),a=l([O("esp-flyout")],a);export{a as EspalierFlyout};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getEspBus as
|
|
1
|
+
import{getEspBus as p}from"../shared/bus-events.js";class g{getEffectiveTopOffset(){const s=this.topOffsetOverride?.();if(s!==void 0)return s;if(this.isHeaderFixed)return this.headerHeight;if(!this.headerElement)return 0;const n=this.headerElement.getBoundingClientRect().bottom;return Math.max(0,Math.min(n,this.headerHeight))}constructor(s,n,a={}){this.lastScrollY=0,this.mode="natural",this.headerHeight=0,this.isHeaderFixed=!1,this.frozenDocumentTop=0,this.scrollDirection=null,this.headerElement=null,this._pendingSetup=null,this.bus=p(),this.onFixedMenusChanged=({fixed:e})=>{this.isHeaderFixed=e,this.detectHeaderState(),this.mode="natural",this.scrollDirection=null;const t=this.host.shadowRoot?.querySelector(this.targetSelector);t&&(t.style.top=`${this.getEffectiveTopOffset()}px`),this.lastScrollY=window.scrollY},this.handleResize=()=>{this.detectHeaderState(),this.mode="natural",this.scrollDirection=null;const e=this.host.shadowRoot?.querySelector(this.targetSelector);e&&(e.style.top=`${this.getEffectiveTopOffset()}px`),this.lastScrollY=window.scrollY},this.handleScroll=()=>{const e=this.host.shadowRoot?.querySelector(this.targetSelector);if(!e)return;const t=window.scrollY,h=window.innerHeight,c=e.offsetHeight;if(t===this.lastScrollY)return;const d=t>this.lastScrollY,o=this.getEffectiveTopOffset();if(c+o<=h){e.style.top=`${o}px`,this.mode="natural",this.lastScrollY=t;return}const i=e.getBoundingClientRect(),l=h-c;if(d)switch(this.mode){case"natural":e.style.top=`${l}px`,this.mode="stuck-bottom";break;case"stuck-top":this.frozenDocumentTop=i.top+t,this.scrollDirection="down",this.mode="scrolling",e.style.top=`${i.top}px`;break;case"scrolling":if(this.scrollDirection==="down"){const r=this.frozenDocumentTop-t;r<=l?(e.style.top=`${l}px`,this.mode="stuck-bottom"):e.style.top=`${r}px`}else this.frozenDocumentTop=i.top+t,this.scrollDirection="down",e.style.top=`${i.top}px`;break;case"stuck-bottom":break}else switch(this.mode){case"natural":e.style.top=`${o}px`,this.mode="stuck-top";break;case"stuck-bottom":this.frozenDocumentTop=i.top+t,this.scrollDirection="up",this.mode="scrolling",e.style.top=`${i.top}px`;break;case"scrolling":if(this.scrollDirection==="up"){const r=this.frozenDocumentTop-t;r>=o?(e.style.top=`${o}px`,this.mode="stuck-top"):e.style.top=`${r}px`}else this.frozenDocumentTop=i.top+t,this.scrollDirection="up",e.style.top=`${i.top}px`;break;case"stuck-top":this.isHeaderFixed||(e.style.top=`${o}px`);break}this.lastScrollY=t},(this.host=s).addController(this),this.targetSelector=n,this.topOffsetOverride=a.topOffset,this.resizeObserver=new ResizeObserver(()=>this.handleResize())}hostConnected(){window.addEventListener("scroll",this.handleScroll,{passive:!0}),window.addEventListener("resize",this.handleResize),this.bus.subscribe("fixed-menus-changed",this.onFixedMenusChanged),this.setupTargetObservation()}hostDisconnected(){window.removeEventListener("scroll",this.handleScroll),window.removeEventListener("resize",this.handleResize),this.bus.unsubscribe("fixed-menus-changed",this.onFixedMenusChanged),this.resizeObserver.disconnect(),this._pendingSetup!==null&&(clearTimeout(this._pendingSetup),this._pendingSetup=null)}setupTargetObservation(){if(this._pendingSetup=null,!this.host.isConnected)return;const s=this.host.shadowRoot?.querySelector(this.targetSelector);s?(this.resizeObserver.observe(s),this.detectHeaderState(),this.lastScrollY=window.scrollY,s.style.top=`${this.getEffectiveTopOffset()}px`):this._pendingSetup=setTimeout(()=>this.setupTargetObservation(),100)}detectHeaderState(){this.headerElement=this.host.shadowRoot?.querySelector(".esp-page-top")??null,this.headerElement&&(this.headerHeight=this.headerElement.offsetHeight);const s=this.host.shadowRoot?.querySelector(".esp-page");this.isHeaderFixed=s?.classList.contains("fixed-header")||s?.classList.contains("fixed-menus")||!1}}export{g as BiDirectionalStickyController};
|
package/dist/page/esp-page.d.ts
CHANGED
|
@@ -32,38 +32,30 @@ type HeaderPosition = "normal" | "sticky" | "fixed";
|
|
|
32
32
|
* </esp-page>
|
|
33
33
|
* ```
|
|
34
34
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* ```html
|
|
40
|
-
* <esp-page
|
|
41
|
-
* preview-open
|
|
42
|
-
* preview-collapse-sidebar
|
|
43
|
-
* style="--esp-page-preview-width: 20rem; --esp-page-preview-min-main-width: 900px;"
|
|
44
|
-
* >
|
|
45
|
-
* <esp-header slot="header" drawer-target="site-nav"></esp-header>
|
|
46
|
-
* <esp-menu id="site-nav" slot="sidebar" mode="vertical"></esp-menu>
|
|
47
|
-
* <article>Primary content</article>
|
|
48
|
-
* <aside slot="preview">Preview content</aside>
|
|
49
|
-
* </esp-page>
|
|
50
|
-
* ```
|
|
35
|
+
* The authoring workspace is ordered main, preview, then help. Each region
|
|
36
|
+
* negotiates between public minimum and maximum widths; preview grows first,
|
|
37
|
+
* then help. Opt into collapsing a directly paired header/sidebar navigation
|
|
38
|
+
* to its accessible burger/drawer mode when the combined workspace needs it.
|
|
51
39
|
*
|
|
52
40
|
* @slot sidebar - Contextual navigation placed in the left aside.
|
|
53
41
|
* @slot right - Content to place in the right aside.
|
|
54
|
-
* @slot preview - Persistent preview content
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
42
|
+
* @slot preview - Persistent preview content placed after the main surface and
|
|
43
|
+
* before help. It grows from `--esp-page-preview-min-width` to
|
|
44
|
+
* `--esp-page-preview-max-width`, starts at viewport top, and gives its content
|
|
45
|
+
* an independent `100dvh` vertical scroller. At either scroll boundary, wheel
|
|
46
|
+
* and trackpad motion chains back to the main document. Unlike flyout content,
|
|
47
|
+
* preview content is never replaced by the flyout request bus.
|
|
58
48
|
* @slot flyout - A transient `esp-flyout` panel that lives on the
|
|
59
|
-
* canvas
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* gutter exists, and becomes an overlay drawer on small viewports.
|
|
49
|
+
* canvas after preview. Closed it costs no width; open it grows from
|
|
50
|
+
* `--esp-page-flyout-min-width` to `--esp-page-flyout-max-width` after preview
|
|
51
|
+
* receives flexible space, then docks as a width-competing right sidebar when
|
|
52
|
+
* no gutter exists, and becomes an overlay drawer on small viewports.
|
|
64
53
|
* The persistent `right` aside and the transient flyout are
|
|
65
54
|
* complementary, not alternatives. A flyout opened with an `anchor`
|
|
66
|
-
* aligns to that trigger and stays in the same document scroll flow.
|
|
55
|
+
* aligns to that trigger and stays in the same document scroll flow. When a
|
|
56
|
+
* preview is visible, its caret and non-interactive dotted bridge cross the
|
|
57
|
+
* preview back to the anchor, ending at a short thick marker on the
|
|
58
|
+
* preview/help seam.
|
|
67
59
|
* @slot footer - Content to place in the footer. Slot `esp-footer` directly
|
|
68
60
|
* to receive the page's surface-alignment custom-property contract. A wrapper
|
|
69
61
|
* can preserve landmark semantics but does not receive that direct contract.
|
|
@@ -131,10 +123,13 @@ type HeaderPosition = "normal" | "sticky" | "fixed";
|
|
|
131
123
|
* @cssprop --esp-page-background - The background color of the page. Fills
|
|
132
124
|
* both the surface and the canvas gutters; the canvas tokens paint over it
|
|
133
125
|
* in the gutters only. Defaults to `var(--esp-color-background)`.
|
|
134
|
-
* @cssprop --esp-page-
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
126
|
+
* @cssprop --esp-page-main-min-width - Minimum width of the main content well
|
|
127
|
+
* while preview or in-grid help competes for space. Defaults to `30rem`.
|
|
128
|
+
* @cssprop --esp-page-main-max-width - Maximum width of the main content well.
|
|
129
|
+
* Defaults from `kind`: `1536px` (wide), `768px` (narrow), or unbounded (full).
|
|
130
|
+
* Surplus width beyond it becomes canvas gutters.
|
|
131
|
+
* @cssprop --esp-page-max-width - Legacy fallback for
|
|
132
|
+
* `--esp-page-main-max-width`.
|
|
138
133
|
* @cssprop --esp-page-background-image - The background image to
|
|
139
134
|
* display behind page content. Defaults to `none`.
|
|
140
135
|
* @cssprop --esp-page-background-image-opacity - The opacity of the
|
|
@@ -162,14 +157,27 @@ type HeaderPosition = "normal" | "sticky" | "fixed";
|
|
|
162
157
|
* background). Set it to give the content well its own card color, or
|
|
163
158
|
* pair the transparent default with `--esp-page-surface-shadow: none`
|
|
164
159
|
* for content that floats directly on the page with no frame.
|
|
165
|
-
* @cssprop --esp-page-
|
|
166
|
-
*
|
|
167
|
-
* @cssprop --esp-page-preview-
|
|
168
|
-
*
|
|
169
|
-
* @cssprop --esp-page-preview-
|
|
170
|
-
* the
|
|
171
|
-
*
|
|
172
|
-
*
|
|
160
|
+
* @cssprop --esp-page-preview-background - Background of the persistent
|
|
161
|
+
* preview surface. Defaults to the main background, then the page background.
|
|
162
|
+
* @cssprop --esp-page-preview-border - Leading tear-off edge between main and
|
|
163
|
+
* preview. Defaults to `1px dotted var(--esp-color-border)`.
|
|
164
|
+
* @cssprop --esp-page-preview-shadow - Shadow cast from the preview's trailing
|
|
165
|
+
* edge. Defaults to the page surface edge shadow. Set to `none` for a flat
|
|
166
|
+
* additive surface.
|
|
167
|
+
* @cssprop --esp-page-preview-min-width - Minimum preview width. Defaults to
|
|
168
|
+
* `22.5rem` (360px, a reasonable mobile-device surface).
|
|
169
|
+
* @cssprop --esp-page-preview-max-width - Maximum preview width. Defaults to
|
|
170
|
+
* `48rem`. Preview receives flexible trailing space before help grows.
|
|
171
|
+
* @cssprop --esp-page-flyout-min-width - Minimum in-grid help width. Defaults
|
|
172
|
+
* to `20rem`.
|
|
173
|
+
* @cssprop --esp-page-flyout-max-width - Maximum help width and overlay drawer
|
|
174
|
+
* cap before the `85vw` viewport cap. Defaults to `30rem`.
|
|
175
|
+
* @cssprop --esp-page-preview-width - Legacy fixed-width alias that pins both
|
|
176
|
+
* preview bounds.
|
|
177
|
+
* @cssprop --esp-page-flyout-width - Legacy fixed-width alias that pins both
|
|
178
|
+
* help bounds.
|
|
179
|
+
* @cssprop --esp-page-preview-min-main-width - Legacy fallback for
|
|
180
|
+
* `--esp-page-main-min-width`.
|
|
173
181
|
* @cssprop --esp-page-fixed-header-offset - Offset reserved for fixed
|
|
174
182
|
* headers. Defaults to `var(--esp-header-height)`.
|
|
175
183
|
* @cssprop --esp-page-sticky-header-top - Top inset for sticky headers.
|
|
@@ -230,6 +238,88 @@ type HeaderPosition = "normal" | "sticky" | "fixed";
|
|
|
230
238
|
* @menuLabel Page
|
|
231
239
|
* @menuIcon layout
|
|
232
240
|
*
|
|
241
|
+
*
|
|
242
|
+
* @example Main, preview, and contextual help
|
|
243
|
+
* ```html
|
|
244
|
+
* <style>
|
|
245
|
+
* .page-workspace-demo {
|
|
246
|
+
* --esp-page-main-min-width: 26rem;
|
|
247
|
+
* --esp-page-main-max-width: 48rem;
|
|
248
|
+
* --esp-page-preview-min-width: 18rem;
|
|
249
|
+
* --esp-page-preview-max-width: 26rem;
|
|
250
|
+
* --esp-page-flyout-min-width: 18rem;
|
|
251
|
+
* --esp-page-flyout-max-width: 22rem;
|
|
252
|
+
* }
|
|
253
|
+
*
|
|
254
|
+
* .page-workspace-demo > main,
|
|
255
|
+
* .page-workspace-demo > [slot="preview"] {
|
|
256
|
+
* box-sizing: border-box;
|
|
257
|
+
* padding: var(--esp-size-padding-page);
|
|
258
|
+
* }
|
|
259
|
+
*
|
|
260
|
+
* .page-workspace-demo > main {
|
|
261
|
+
* min-block-size: 120vh;
|
|
262
|
+
* }
|
|
263
|
+
* </style>
|
|
264
|
+
*
|
|
265
|
+
* <esp-page
|
|
266
|
+
* id="page-workspace-demo"
|
|
267
|
+
* class="page-workspace-demo"
|
|
268
|
+
* preview-open
|
|
269
|
+
* preview-label="Rendered page preview"
|
|
270
|
+
* >
|
|
271
|
+
* <main>
|
|
272
|
+
* <h2>Page details</h2>
|
|
273
|
+
* <esp-form-item label="Site title">
|
|
274
|
+
* <esp-input id="page-workspace-title" name="title" value="Field notes"></esp-input>
|
|
275
|
+
* </esp-form-item>
|
|
276
|
+
* <p>
|
|
277
|
+
* Help is anchored to the title field in this main editor. Its caret and
|
|
278
|
+
* dotted connector cross the persistent preview without blocking it.
|
|
279
|
+
* </p>
|
|
280
|
+
* <esp-button id="page-workspace-preview-toggle" label="Toggle preview"></esp-button>
|
|
281
|
+
* <esp-button id="page-workspace-help-toggle" label="Toggle title help"></esp-button>
|
|
282
|
+
* </main>
|
|
283
|
+
*
|
|
284
|
+
* <article slot="preview">
|
|
285
|
+
* <h2>Field notes</h2>
|
|
286
|
+
* <p>This preview is a full-viewport secondary surface with its own scroller.</p>
|
|
287
|
+
* </article>
|
|
288
|
+
*
|
|
289
|
+
* <esp-flyout
|
|
290
|
+
* id="page-workspace-help"
|
|
291
|
+
* slot="flyout"
|
|
292
|
+
* heading="Site title help"
|
|
293
|
+
* standalone
|
|
294
|
+
* >
|
|
295
|
+
* <p>Use a short, recognizable title. It appears in navigation and browser tabs.</p>
|
|
296
|
+
* </esp-flyout>
|
|
297
|
+
* </esp-page>
|
|
298
|
+
*
|
|
299
|
+
* <script>
|
|
300
|
+
* const page = findById("page-workspace-demo");
|
|
301
|
+
* const title = findById("page-workspace-title");
|
|
302
|
+
* const help = findById("page-workspace-help");
|
|
303
|
+
* help.anchor = title;
|
|
304
|
+
*
|
|
305
|
+
* const syncMainWidth = () => {
|
|
306
|
+
* page.kind = page.previewOpen || help.open ? "wide" : "full";
|
|
307
|
+
* };
|
|
308
|
+
*
|
|
309
|
+
* findById("page-workspace-preview-toggle").addEventListener("clicked", () => {
|
|
310
|
+
* page.togglePreview();
|
|
311
|
+
* syncMainWidth();
|
|
312
|
+
* });
|
|
313
|
+
* findById("page-workspace-help-toggle").addEventListener("clicked", () => {
|
|
314
|
+
* help.anchor = title;
|
|
315
|
+
* help.toggle();
|
|
316
|
+
* syncMainWidth();
|
|
317
|
+
* });
|
|
318
|
+
* help.addEventListener("flyout-opened", syncMainWidth);
|
|
319
|
+
* help.addEventListener("flyout-closed", syncMainWidth);
|
|
320
|
+
* syncMainWidth();
|
|
321
|
+
* </script>
|
|
322
|
+
* ```
|
|
233
323
|
*/
|
|
234
324
|
export declare class EspalierPage extends EspalierElementBase {
|
|
235
325
|
constructor();
|
|
@@ -315,7 +405,7 @@ export declare class EspalierPage extends EspalierElementBase {
|
|
|
315
405
|
previewVisible: boolean;
|
|
316
406
|
/**
|
|
317
407
|
* Whether preview is currently reserving width and allowing the main well
|
|
318
|
-
* to shrink toward `--esp-page-
|
|
408
|
+
* to shrink toward `--esp-page-main-min-width`. Managed by the page.
|
|
319
409
|
*/
|
|
320
410
|
previewReclaiming: boolean;
|
|
321
411
|
/** Request the persistent preview without moving focus. */
|