@taprootio/espalier 6.3.0 → 6.5.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.
@@ -136,6 +136,41 @@ export declare class EspalierBox extends EspalierElementBase {
136
136
  * </script>
137
137
  * ```
138
138
  *
139
+ * A full-screen box fills the viewport. Inside a
140
+ * [bounded dialog](/components/dialog) it fills exactly the dialog's
141
+ * rectangle instead: it takes its position and size from the same
142
+ * `--esp-dialog-inset-*` custom properties, set on the `esp-dialog` or any
143
+ * ancestor of the box.
144
+ *
145
+ * ```html
146
+ * <style>
147
+ * esp-dialog.bounded-box {
148
+ * --esp-dialog-inset-block-start: 6rem;
149
+ * --esp-dialog-inset-inline-start: 3rem;
150
+ * --esp-dialog-inset-inline-end: 3rem;
151
+ * --esp-dialog-inset-block-end: 2rem;
152
+ * }
153
+ * </style>
154
+ * <esp-dialog class="bounded-box" full-screen>
155
+ * <esp-box full-screen>
156
+ * <h2>Box in a bounded dialog</h2>
157
+ * <p>This box fills the rectangle the dialog is bounded to.</p>
158
+ * <esp-button intent="danger" label="Close"></esp-button>
159
+ * </esp-box>
160
+ * </esp-dialog>
161
+ * <esp-button label="Show Dialog"></esp-button>
162
+ * <script>
163
+ * const theDialog = findByTagName("esp-dialog")[0];
164
+ * const buttons = findByTagName("esp-button");
165
+ * buttons[0].addEventListener("esp-clicked", () => {
166
+ * theDialog.toggleOpen();
167
+ * });
168
+ * buttons[1].addEventListener("esp-clicked", () => {
169
+ * theDialog.toggleOpen();
170
+ * });
171
+ * </script>
172
+ * ```
173
+ *
139
174
  * @type {boolean}
140
175
  */
141
176
  fullScreen: boolean;
@@ -1,10 +1,10 @@
1
- var n=function(t,e,r,i){var a=arguments.length,o=a<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,r):i,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(t,e,r,i);else for(var p=t.length-1;p>=0;p--)(l=t[p])&&(o=(a<3?l(o):a>3?l(e,r,o):l(e,r))||o);return a>3&&o&&Object.defineProperty(e,r,o),o};import{paintedSurface as c}from"../shared/surface-layer.js";import{css as b,html as v}from"lit";import{customElement as h,property as f}from"lit/decorators.js";import{classMap as u}from"lit/directives/class-map.js";import{EspalierElementBase as d}from"../shared/esp-element-base.js";let s=class extends d{constructor(){super(...arguments),this.fullScreen=!1}render(){const{fullScreen:e}=this;return v`
1
+ var p=function(r,e,s,i){var a=arguments.length,o=a<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,s):i,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(r,e,s,i);else for(var n=r.length-1;n>=0;n--)(l=r[n])&&(o=(a<3?l(o):a>3?l(e,s,o):l(e,s))||o);return a>3&&o&&Object.defineProperty(e,s,o),o};import{paintedSurface as c}from"../shared/surface-layer.js";import{css as v,html as b}from"lit";import{customElement as f,property as h}from"lit/decorators.js";import{classMap as u}from"lit/directives/class-map.js";import{EspalierElementBase as d}from"../shared/esp-element-base.js";let t=class extends d{constructor(){super(...arguments),this.fullScreen=!1}render(){const{fullScreen:e}=this;return b`
2
2
  <div class=${u({"esp-box":!0,"full-screen":e})}>
3
3
  <div part="box">
4
4
  <slot></slot>
5
5
  </div>
6
6
  </div>
7
- `}};s.styles=[...d.styles,c(1),b`
7
+ `}};t.styles=[...d.styles,c(1),v`
8
8
  :host {
9
9
  display: block;
10
10
  }
@@ -42,16 +42,31 @@ var n=function(t,e,r,i){var a=arguments.length,o=a<3?e:i===null?i=Object.getOwnP
42
42
  }
43
43
 
44
44
  &.full-screen {
45
- width: 100vw;
46
-
47
- height: 100vh;
48
- height: 100dvh;
45
+ width: calc(
46
+ 100vw - var(--esp-dialog-inset-inline-start, 0px) - var(
47
+ --esp-dialog-inset-inline-end,
48
+ 0px
49
+ )
50
+ );
51
+ height: calc(
52
+ 100vh - var(--esp-dialog-inset-block-start, 0px) - var(
53
+ --esp-dialog-inset-block-end,
54
+ 0px
55
+ )
56
+ );
57
+ height: calc(
58
+ 100dvh - var(--esp-dialog-inset-block-start, 0px) - var(
59
+ --esp-dialog-inset-block-end,
60
+ 0px
61
+ )
62
+ );
49
63
  position: fixed;
50
- top: 0;
51
- left: 0;
64
+ inset-block-start: var(--esp-dialog-inset-block-start, 0px);
65
+ inset-inline-start: var(--esp-dialog-inset-inline-start, 0px);
52
66
  z-index: 10;
53
67
 
54
68
  > div {
69
+ position: relative;
55
70
  overflow-y: auto;
56
71
 
57
72
  padding-bottom: max(
@@ -61,4 +76,4 @@ var n=function(t,e,r,i){var a=arguments.length,o=a<3?e:i===null?i=Object.getOwnP
61
76
  }
62
77
  }
63
78
  }
64
- `],n([f({attribute:"full-screen",type:Boolean})],s.prototype,"fullScreen",void 0),s=n([h("esp-box")],s);export{s as EspalierBox};
79
+ `],p([h({attribute:"full-screen",type:Boolean})],t.prototype,"fullScreen",void 0),t=p([f("esp-box")],t);export{t as EspalierBox};
@@ -20,6 +20,78 @@ import { LitElement } from "lit";
20
20
  * - Restores focus to the element that was focused before the
21
21
  * dialog was opened.
22
22
  *
23
+ * ### Bounded dialog
24
+ *
25
+ * A dialog covers the whole viewport by default. Set the four inset custom
26
+ * properties on the `esp-dialog` host to confine it to a rectangle and leave
27
+ * the rest of the page visible, for example to keep a header or a live preview
28
+ * on screen while a full-screen editor is open. The vellum (the dialog's
29
+ * scrolling surface) and its backdrop paint only inside the rectangle, and a
30
+ * slotted `esp-box full-screen` fills exactly that rectangle.
31
+ *
32
+ * The insets are lengths (`0px`, `4rem`, `var(--header-height)`), not unitless
33
+ * numbers, and they are measured from the viewport edges. They are logical, so
34
+ * "inline start" is the left edge in left-to-right text and the right edge in
35
+ * right-to-left text. Because custom properties inherit, a dialog nested inside
36
+ * a bounded dialog's markup is bounded the same way unless it sets its own
37
+ * insets.
38
+ *
39
+ * Bounds change only where the dialog paints. What stays reachable is decided
40
+ * by the same rules as an unbounded dialog:
41
+ *
42
+ * - The dialog has no click-outside dismissal, bounded or not. It closes on
43
+ * `Escape`, an `esp-form-dialog-close-requested` event, or `toggleOpen()`, so
44
+ * a click on the uncovered region never counts as an "outside" click.
45
+ * - The dialog marks `inert` the siblings of its anchor element, not the
46
+ * regions its bounds leave uncovered. The anchor is `esp-page`'s dialog drop
47
+ * zone when the dialog sits in the page's markup, so there the page's
48
+ * internal tracks (header, menus, preview, help, footer) are inert and not
49
+ * clickable even where the dialog does not cover them. A dialog that is a
50
+ * direct child of another component's shadow root is anchored on the nearest
51
+ * ancestor host that has a light-DOM parent, and only that host's siblings
52
+ * go inert; the page around it stays live. A dialog wrapped in an element
53
+ * inside that shadow root is anchored on itself, so its siblings in the
54
+ * wrapper go inert instead.
55
+ * - A region that is not inert receives clicks and keyboard focus. The focus
56
+ * trap wraps `Tab` and `Shift+Tab` at the dialog's first and last focusable
57
+ * elements, and `Escape` is handled on the dialog, both only while focus is
58
+ * inside it. A click on an uncovered control moves focus there, and from then
59
+ * on `Tab` continues through the page and `Escape` no longer closes the
60
+ * dialog. Set `inert` on the uncovered regions that must not be reachable
61
+ * while the dialog is open (an inert region is also skipped by screen
62
+ * readers).
63
+ * - Bounds assume a horizontal writing mode: the insets are logical, but the
64
+ * dialog's width and height are physical.
65
+ *
66
+ * ```html
67
+ * <style>
68
+ * esp-dialog.bounded {
69
+ * --esp-dialog-inset-block-start: 6rem;
70
+ * --esp-dialog-inset-inline-start: 3rem;
71
+ * --esp-dialog-inset-inline-end: 3rem;
72
+ * --esp-dialog-inset-block-end: 2rem;
73
+ * }
74
+ * </style>
75
+ * <esp-dialog class="bounded" full-screen>
76
+ * <esp-box full-screen>
77
+ * <h2>Bounded dialog</h2>
78
+ * <p>The page above and around this box stays visible.</p>
79
+ * <esp-button intent="danger" label="Close"></esp-button>
80
+ * </esp-box>
81
+ * </esp-dialog>
82
+ * <esp-button label="Show Dialog"></esp-button>
83
+ * <script>
84
+ * const theDialog = findByTagName("esp-dialog")[0];
85
+ * const buttons = findByTagName("esp-button");
86
+ * buttons[0].addEventListener("esp-clicked", () => {
87
+ * theDialog.toggleOpen();
88
+ * });
89
+ * buttons[1].addEventListener("esp-clicked", () => {
90
+ * theDialog.toggleOpen();
91
+ * });
92
+ * </script>
93
+ * ```
94
+ *
23
95
  * @slot - Place content to show modally in the default slot.
24
96
  *
25
97
  * ```html
@@ -105,6 +177,10 @@ import { LitElement } from "lit";
105
177
  *
106
178
  * @cssprop --esp-color-dialog-bg - The background color of the dialog overlay.
107
179
  * @cssprop --esp-dialog-bg-opacity - The opacity of the dialog overlay background.
180
+ * @cssprop --esp-dialog-inset-block-start - The top edge of the area the dialog covers, as a length from the viewport top. Defaults to `0px`.
181
+ * @cssprop --esp-dialog-inset-inline-start - The leading edge (left in left-to-right text) of the area the dialog covers, as a length from the viewport edge. Defaults to `0px`.
182
+ * @cssprop --esp-dialog-inset-inline-end - The trailing edge (right in left-to-right text) of the area the dialog covers, as a length from the viewport edge. Defaults to `0px`.
183
+ * @cssprop --esp-dialog-inset-block-end - The bottom edge of the area the dialog covers, as a length from the viewport bottom. Defaults to `0px`.
108
184
  * @attr {"1"|"2"|"3"|"4"} surface-layer - Declares the painted surface depth; defaults to layer 3.
109
185
  * @customElement esp-dialog
110
186
  * @docPageTitle Dialog
@@ -1,14 +1,14 @@
1
- var c=function(l,e,t,o){var n=arguments.length,i=n<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,r;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(l,e,t,o);else for(var a=l.length-1;a>=0;a--)(r=l[a])&&(i=(n<3?r(i):n>3?r(e,t,i):r(e,t))||i);return n>3&&i&&Object.defineProperty(e,t,i),i};import{paintedSurface as f,surfaceLayerAttributes as v}from"../shared/surface-layer.js";import{LitElement as m,css as b,html as g,nothing as u}from"lit";import{customElement as y,property as _,state as O}from"lit/decorators.js";import{classMap as k}from"lit/directives/class-map.js";import{createRef as d,ref as h}from"lit/directives/ref.js";import{OverlayController as E}from"../shared/overlay-controller.js";import{ESP_EVENTS as p}from"../shared/events.js";let s=class extends m{constructor(){super(...arguments),this.dialogSlot=d(),this.vellumRef=d(),this.isOpen=!1,this._overlay=new E({host:this,getFocusTrapContainer:()=>this.vellumRef.value??null,getFocusFallback:()=>this.vellumRef.value??null}),this._closeReason="api",this._lifecycleToken=0,this.fullScreen=!1}toggleOpen(){if(this.isOpen){const e=this._closeReason;this._closeReason="api";const t=new CustomEvent(p.DIALOG_CLOSING,{detail:{reason:e},bubbles:!0,composed:!0,cancelable:!0});if(!this.dispatchEvent(t))return;const o=++this._lifecycleToken;this.removeAttribute("is-open"),this.isOpen=!1,this._overlay.close(),this.updateComplete.then(()=>{this.isOpen||this._lifecycleToken!==o||this.dispatchEvent(new CustomEvent(p.DIALOG_CLOSED,{detail:{reason:e},bubbles:!0,composed:!0}))})}else{const e=++this._lifecycleToken;this.setAttribute("is-open","true"),this.isOpen=!0,this._overlay.open(),this.updateComplete.then(()=>{!this.isOpen||this._lifecycleToken!==e||(this._moveFocusIntoDialog(),this.dispatchEvent(new CustomEvent(p.DIALOG_OPENED,{detail:{},bubbles:!0,composed:!0})))})}}_handleKeyDown(e){if(this.isOpen){if(e.key==="Escape"){e.preventDefault(),this._closeReason="escape",this.toggleOpen();return}e.key==="Tab"&&this._overlay.trapFocus(e)}}_moveFocusIntoDialog(){this._overlay.moveFocusInto()}firstUpdated(){this.dialogSlot.value&&this.dialogSlot.value.addEventListener("esp-form-dialog-close-requested",e=>{this._closeReason="close-dialog",this.toggleOpen(),e.preventDefault()})}disconnectedCallback(){super.disconnectedCallback()}render(){const{isOpen:e,fullScreen:t}=this,o={"is-open":e,"full-screen":t};return g`<div
1
+ var p=function(l,e,t,i){var n=arguments.length,s=n<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,t):i,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(l,e,t,i);else for(var r=l.length-1;r>=0;r--)(a=l[r])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s};import{paintedSurface as v,surfaceLayerAttributes as f}from"../shared/surface-layer.js";import{LitElement as g,css as b,html as m,nothing as d}from"lit";import{customElement as y,property as k,state as _}from"lit/decorators.js";import{classMap as x}from"lit/directives/class-map.js";import{createRef as u,ref as h}from"lit/directives/ref.js";import{OverlayController as O}from"../shared/overlay-controller.js";import{ESP_EVENTS as c}from"../shared/events.js";let o=class extends g{constructor(){super(...arguments),this.dialogSlot=u(),this.vellumRef=u(),this.isOpen=!1,this._overlay=new O({host:this,getFocusTrapContainer:()=>this.vellumRef.value??null,getFocusFallback:()=>this.vellumRef.value??null}),this._closeReason="api",this._lifecycleToken=0,this.fullScreen=!1}toggleOpen(){if(this.isOpen){const e=this._closeReason;this._closeReason="api";const t=new CustomEvent(c.DIALOG_CLOSING,{detail:{reason:e},bubbles:!0,composed:!0,cancelable:!0});if(!this.dispatchEvent(t))return;const i=++this._lifecycleToken;this.removeAttribute("is-open"),this.isOpen=!1,this._overlay.close(),this.updateComplete.then(()=>{this.isOpen||this._lifecycleToken!==i||this.dispatchEvent(new CustomEvent(c.DIALOG_CLOSED,{detail:{reason:e},bubbles:!0,composed:!0}))})}else{const e=++this._lifecycleToken;this.setAttribute("is-open","true"),this.isOpen=!0,this._overlay.open(),this.updateComplete.then(()=>{!this.isOpen||this._lifecycleToken!==e||(this._moveFocusIntoDialog(),this.dispatchEvent(new CustomEvent(c.DIALOG_OPENED,{detail:{},bubbles:!0,composed:!0})))})}}_handleKeyDown(e){if(this.isOpen){if(e.key==="Escape"){e.preventDefault(),this._closeReason="escape",this.toggleOpen();return}e.key==="Tab"&&this._overlay.trapFocus(e)}}_moveFocusIntoDialog(){this._overlay.moveFocusInto()}firstUpdated(){this.dialogSlot.value&&this.dialogSlot.value.addEventListener("esp-form-dialog-close-requested",e=>{this._closeReason="close-dialog",this.toggleOpen(),e.preventDefault()})}disconnectedCallback(){super.disconnectedCallback()}render(){const{isOpen:e,fullScreen:t}=this,i={"is-open":e,"full-screen":t};return m`<div
2
2
  ${h(this.vellumRef)}
3
- class="vellum ${k(o)}"
3
+ class="vellum ${x(i)}"
4
4
  data-no-swipe
5
- role=${e?"dialog":u}
6
- aria-modal=${e?"true":u}
5
+ role=${e?"dialog":d}
6
+ aria-modal=${e?"true":d}
7
7
  tabindex="-1"
8
8
  @keydown=${this._handleKeyDown}
9
9
  >
10
10
  <slot ${h(this.dialogSlot)}></slot>
11
- </div>`}};s.styles=[f(3),v(":host"),b`
11
+ </div>`}};o.styles=[v(3),f(":host"),b`
12
12
  :host {
13
13
  display: block;
14
14
  }
@@ -20,12 +20,21 @@ var c=function(l,e,t,o){var n=arguments.length,i=n<3?e:o===null?o=Object.getOwnP
20
20
  visibility: hidden;
21
21
  position: fixed;
22
22
  z-index: 10000;
23
- left: 0;
24
- top: 0;
23
+ inset-inline-start: var(--esp-dialog-inset-inline-start, 0px);
24
+ inset-block-start: var(--esp-dialog-inset-block-start, 0px);
25
25
 
26
- height: 100vh;
27
- height: 100dvh;
28
- width: 100vw;
26
+ width: calc(
27
+ 100vw - var(--esp-dialog-inset-inline-start, 0px) - var(
28
+ --esp-dialog-inset-inline-end,
29
+ 0px
30
+ )
31
+ );
32
+ height: calc(
33
+ 100vh - var(--esp-dialog-inset-block-start, 0px) - var(--esp-dialog-inset-block-end, 0px)
34
+ );
35
+ height: calc(
36
+ 100dvh - var(--esp-dialog-inset-block-start, 0px) - var(--esp-dialog-inset-block-end, 0px)
37
+ );
29
38
  overflow-y: auto;
30
39
  outline: none;
31
40
 
@@ -34,11 +43,18 @@ var c=function(l,e,t,o){var n=arguments.length,i=n<3?e:o===null?o=Object.getOwnP
34
43
  position: relative;
35
44
  }
36
45
 
37
- &::before {
46
+ &::before,
47
+ &::after {
38
48
  content: "";
39
49
  display: block;
40
50
  position: fixed;
41
- inset: 0;
51
+ inset-inline: var(--esp-dialog-inset-inline-start, 0px)
52
+ var(--esp-dialog-inset-inline-end, 0px);
53
+ inset-block: var(--esp-dialog-inset-block-start, 0px)
54
+ var(--esp-dialog-inset-block-end, 0px);
55
+ }
56
+
57
+ &::before {
42
58
  opacity: var(--esp-dialog-bg-opacity, var(--esp-vellum-opacity, 0.85));
43
59
  background: var(
44
60
  --esp-color-dialog-bg,
@@ -48,10 +64,6 @@ var c=function(l,e,t,o){var n=arguments.length,i=n<3?e:o===null?o=Object.getOwnP
48
64
  }
49
65
 
50
66
  &::after {
51
- content: "";
52
- display: block;
53
- position: fixed;
54
- inset: 0;
55
67
  background-image: var(--esp-vellum-background-image, none);
56
68
  background-repeat: repeat;
57
69
  opacity: var(--esp-vellum-background-image-opacity, 0.3);
@@ -74,4 +86,4 @@ var c=function(l,e,t,o){var n=arguments.length,i=n<3?e:o===null?o=Object.getOwnP
74
86
  }
75
87
  }
76
88
  }
77
- `],c([O()],s.prototype,"isOpen",void 0),c([_({attribute:"full-screen",type:Boolean})],s.prototype,"fullScreen",void 0),s=c([y("esp-dialog")],s);export{s as EspalierDialog};
89
+ `],p([_()],o.prototype,"isOpen",void 0),p([k({attribute:"full-screen",type:Boolean})],o.prototype,"fullScreen",void 0),o=p([y("esp-dialog")],o);export{o as EspalierDialog};
@@ -57,7 +57,9 @@ export interface PageWorkspaceResizeDetail {
57
57
  * separators on the dotted internal seams and the exposed trailing edge of the
58
58
  * last auxiliary pane. Preferred pane sizes remain attached to the mounted
59
59
  * page instance and are re-clamped by the same allocator whenever the available
60
- * inline size changes. Opt into collapsing a directly paired
60
+ * inline size changes. A chosen size is a floor while main sits at its
61
+ * configured maximum: the preview, then help, absorb the spare width up to
62
+ * their maximums before any canvas appears. Opt into collapsing a directly paired
61
63
  * header/sidebar navigation to its accessible burger/drawer mode after
62
64
  * auxiliary panes contract and before main is reclaimed. The rail returns
63
65
  * only when doing so preserves the settled pane allocation.
@@ -215,7 +217,8 @@ export interface PageWorkspaceResizeDetail {
215
217
  * established preview-first flexible allocation remains in effect. A retained
216
218
  * pointer or keyboard resize preference supersedes this target.
217
219
  * @cssprop --esp-page-preview-max-width - Maximum preview width. Defaults to
218
- * `48rem`. Preview receives flexible trailing space before help grows.
220
+ * `48rem`. Preview receives flexible trailing space before help grows, and
221
+ * absorbs the width beyond a capped main up to this maximum.
219
222
  * @cssprop --esp-page-flyout-min-width - Minimum in-grid help width. Defaults
220
223
  * to `20rem`.
221
224
  * @cssprop --esp-page-flyout-default-width - Initial automatic in-grid help