@excom/content-drawer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.rush/temp/chunked-rush-logs/content-drawer.apply-exports.chunks.jsonl +1 -0
  2. package/.rush/temp/chunked-rush-logs/content-drawer.build_docs.chunks.jsonl +1 -0
  3. package/.rush/temp/chunked-rush-logs/content-drawer.build_package-metas.chunks.jsonl +1 -0
  4. package/.rush/temp/operation/apply-exports/all.log +1 -0
  5. package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
  6. package/.rush/temp/operation/apply-exports/state.json +3 -0
  7. package/.rush/temp/operation/build_docs/all.log +1 -0
  8. package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
  9. package/.rush/temp/operation/build_docs/state.json +3 -0
  10. package/.rush/temp/operation/build_package-metas/all.log +1 -0
  11. package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
  12. package/.rush/temp/operation/build_package-metas/state.json +3 -0
  13. package/.rush/temp/shrinkwrap-deps.json +3 -0
  14. package/config/rig.json +5 -0
  15. package/content-drawer.ts +205 -0
  16. package/index.css +5 -0
  17. package/index.ts +17 -0
  18. package/package.json +44 -0
  19. package/rush-logs/content-drawer.apply-exports.cache.log +1 -0
  20. package/rush-logs/content-drawer.apply-exports.log +1 -0
  21. package/rush-logs/content-drawer.build_docs.cache.log +1 -0
  22. package/rush-logs/content-drawer.build_docs.log +1 -0
  23. package/rush-logs/content-drawer.build_package-metas.cache.log +1 -0
  24. package/rush-logs/content-drawer.build_package-metas.log +1 -0
  25. package/src/content-drawer.css +344 -0
  26. package/support/custom-elements.json +360 -0
  27. package/support/demos/disappear.html +8 -0
  28. package/support/demos/dismiss.html +16 -0
  29. package/support/demos/from-side.html +9 -0
  30. package/support/demos/simple.html +12 -0
  31. package/support/demos/singleton.html +16 -0
  32. package/support/demos/stages.html +18 -0
  33. package/support/dist-docs/content-drawer.md +252 -0
  34. package/support/docs/README.md +69 -0
  35. package/support/package-meta.json +299 -0
  36. package/support/tests/content-drawer.test.ts +388 -0
  37. package/support/tests/disappear.view.test.ts +32 -0
  38. package/support/tests/dismiss.view.test.ts +61 -0
  39. package/support/tests/from-side.view.test.ts +32 -0
  40. package/support/tests/simple.view.test.ts +40 -0
  41. package/support/tests/singleton.view.test.ts +35 -0
  42. package/support/tests/stages.view.test.ts +39 -0
  43. package/tsconfig.json +5 -0
@@ -0,0 +1,8 @@
1
+ <section>
2
+ <button type="button" command="--open" commandfor="demo-drawer-disappear">
3
+ Show success
4
+ </button>
5
+ <content-drawer id="demo-drawer-disappear" class="absolute" disappear-after="2">
6
+ <h2>Saved!</h2>
7
+ </content-drawer>
8
+ </section>
@@ -0,0 +1,16 @@
1
+ <section>
2
+ <quark-sheet>
3
+ :scope {
4
+ content-drawer[is-open] dismiss-watcher { is-active: ""; }
5
+ content-drawer:not([is-open]) dismiss-watcher { is-active: none; }
6
+ }
7
+ </quark-sheet>
8
+ <button type="button" command="--open" commandfor="demo-drawer-dismiss">
9
+ Open drawer
10
+ </button>
11
+ <content-drawer id="demo-drawer-dismiss" class="absolute">
12
+ <dismiss-watcher watch-escape watch-outside-click command-name="--close"></dismiss-watcher>
13
+ <nav>Menu</nav>
14
+ </content-drawer>
15
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
16
+ </section>
@@ -0,0 +1,9 @@
1
+ <section>
2
+ <button type="button" command="--toggle" commandfor="demo-drawer-side">
3
+ Toggle drawer
4
+ </button>
5
+ <content-drawer id="demo-drawer-side" class="absolute" from-side="left">
6
+ <nav>Menu</nav>
7
+ </content-drawer>
8
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
9
+ </section>
@@ -0,0 +1,12 @@
1
+ <section>
2
+ <button type="button" command="--toggle" commandfor="demo-drawer-simple">
3
+ Toggle sheet
4
+ </button>
5
+ <content-drawer id="demo-drawer-simple" class="absolute">
6
+ <header>
7
+ <button type="button" rel="prev" command="--close" commandfor="demo-drawer-simple" aria-label="Close"></button>
8
+ <h2>Sheet open</h2>
9
+ </header>
10
+ </content-drawer>
11
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
12
+ </section>
@@ -0,0 +1,16 @@
1
+ <section>
2
+ <button type="button" command="--open" commandfor="drawer-a">Open A</button>
3
+ <button type="button" command="--open" commandfor="drawer-b">Open B</button>
4
+ <content-drawer id="drawer-a" class="absolute" singleton-name="demo">
5
+ <header>
6
+ <button type="button" rel="prev" command="--close" commandfor="drawer-a" aria-label="Close"></button>
7
+ <h2>Drawer A</h2>
8
+ </header>
9
+ </content-drawer>
10
+ <content-drawer id="drawer-b" class="absolute" singleton-name="demo">
11
+ <header>
12
+ <button type="button" rel="prev" command="--close" commandfor="drawer-b" aria-label="Close"></button>
13
+ <h2>Drawer B</h2>
14
+ </header>
15
+ </content-drawer>
16
+ </section>
@@ -0,0 +1,18 @@
1
+ <section>
2
+ <button type="button" command="--open" commandfor="demo-drawer-stages" data-open-stage="0">
3
+ Full (100%)
4
+ </button>
5
+ <button type="button" command="--open" commandfor="demo-drawer-stages" data-open-stage="1">
6
+ Half (50%)
7
+ </button>
8
+ <button type="button" command="--open" commandfor="demo-drawer-stages" data-open-stage="2">
9
+ Peek (25%)
10
+ </button>
11
+ <content-drawer id="demo-drawer-stages" class="absolute">
12
+ <header>
13
+ <button type="button" rel="prev" command="--close" commandfor="demo-drawer-stages" aria-label="Close"></button>
14
+ <h2>Open stages</h2>
15
+ </header>
16
+ <p>Full / half / peek via <code>data-open-stage</code> on the button.</p>
17
+ </content-drawer>
18
+ </section>
@@ -0,0 +1,252 @@
1
+ # content-drawer
2
+
3
+ Slide-in drawers and sheets for nav menus, filters, confirmations, and side panels — any edge, with peek stages.
4
+
5
+
6
+ ```html
7
+ <section>
8
+ <button type="button" command="--toggle" commandfor="demo-drawer-simple">
9
+ Toggle sheet
10
+ </button>
11
+ <content-drawer id="demo-drawer-simple" class="absolute">
12
+ <header>
13
+ <button type="button" rel="prev" command="--close" commandfor="demo-drawer-simple" aria-label="Close"></button>
14
+ <h2>Sheet open</h2>
15
+ </header>
16
+ </content-drawer>
17
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
18
+ </section>
19
+ ```
20
+
21
+
22
+ ## Features
23
+
24
+ - **Any edge** Bottom (default), top, left, or right via `from-side`
25
+ - **Peek stages** Full, half, or peek via `open-stage`
26
+ - **Command-driven** `--open` / `--close` / `--toggle` from any `<button command commandfor>`
27
+ - **Dismissal** Outside click + Escape via `<dismiss-watcher>`
28
+ - **Backdrop** Valence.css dimmer — sibling `[role="presentation"]` / `.tag-backdrop`
29
+ - **Auto-dismiss** `disappear-after` for toast-style confirmations
30
+ - **Singleton groups** One open drawer per `singleton-name`
31
+ - **Layout modes** Viewport sheet (default, `position: fixed`), `.absolute` (inside its parent), `.relative`, or `.sticky`
32
+ - **Scrubbable** Wrap in [`gesture-handler`](/nucleus/packages/gesture-handler): the sheet follows the finger via `is-scrubbing` + `--content-drawer-open-progress`
33
+
34
+ ## Installation
35
+
36
+
37
+ `@excom/content-drawer` v0.1.0
38
+
39
+ ```bash
40
+ pnpm add @excom/content-drawer
41
+ ```
42
+
43
+ ```bash
44
+ npm install @excom/content-drawer
45
+ ```
46
+
47
+ ```bash
48
+ yarn add @excom/content-drawer
49
+ ```
50
+
51
+ ### Import
52
+
53
+ ```ts
54
+ import "@excom/content-drawer";
55
+ ```
56
+
57
+
58
+
59
+ ## Usage
60
+
61
+ Put content inside `<content-drawer>` and invoke `--open`, `--close`, or `--toggle` on it — a native `<button command commandfor>`, or `<event-handler command-name target-ref>` when the invoker is not a button. Its parent automatically becomes `position: relative; overflow: hidden`, so give the parent a real size along the drawer's axis.
62
+
63
+ ```html
64
+ <button type="button" command="--toggle" commandfor="sheet">Toggle sheet</button>
65
+ <content-drawer id="sheet" class="absolute">
66
+ <h2>Saved!</h2>
67
+ </content-drawer>
68
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
69
+ ```
70
+
71
+ ### API Reference
72
+
73
+
74
+ #### Attributes
75
+
76
+ | Name | Surface | Type | Default | Values | Description |
77
+ | --- | --- | --- | --- | --- | --- |
78
+ | `from-side` | option | `string` | `"bottom"` | `"bottom"` \| `"top"` \| `"left"` \| `"right"` | Edge the drawer slides from. |
79
+ | `disappear-after` | option | `number` | | | Auto-close after this many seconds once opened — toast-style / transient confirmations. |
80
+ | `singleton-name` | option | `string` | | | Shared group name. Opening one drawer closes others with the same name (singleton coordination). |
81
+ | `open-stage` | hybrid | `number` | | `"0"` \| `"1"` \| `"2"` | How far the drawer opens: `0` full, `1` half, `2` peek. Unset = full. Set statically, or per open through `data-open-stage` on the `--open` / `--toggle` invoker. |
82
+ | `is-open` | hybrid | `boolean` | | | Open state. Toggle directly, or through the `--open` / `--close` / `--toggle` commands. For Escape / outside-click dismissal pair with `<dismiss-watcher command-name="--close">`. |
83
+
84
+ #### Fires
85
+
86
+ | Name | Type | Description |
87
+ | --- | --- | --- |
88
+ | `content-drawer-opened` | `ContentDrawerOpenedEvent` (`CustomEvent & { type: "content-drawer-opened"; detail: HTMLElement; bubbles: true; cancelable: true; composed: true }`) | After open (`is-open` set), `detail` is the drawer. When `singleton-name` is set it is also broadcast so drawers sharing that name close. |
89
+ | `content-drawer-closed` | `ContentDrawerClosedEvent` (`CustomEvent & { type: "content-drawer-closed"; detail: HTMLElement; bubbles: true; cancelable: true; composed: true }`) | After close (`is-open` unset), `detail` is the drawer. |
90
+
91
+ #### Commands
92
+
93
+ | Command | Action |
94
+ | --- | --- |
95
+ | `--open` | Opens the drawer (`is-open` set). `data-*` attributes on the invoker that name a declared prop (`data-open-stage`, `data-from-side`, …) are applied first; unknown, private and `isOpen` keys are ignored. |
96
+ | `--close` | Closes the drawer (`is-open` unset). |
97
+ | `--toggle` | Toggles open / closed. Reads the invoker's `data-*` like `--open`. |
98
+
99
+ #### CSS Custom Properties
100
+
101
+ | Name | Syntax | Default | Description |
102
+ | --- | --- | --- | --- |
103
+ | `--content-drawer-transition-duration` | `<time>` | `0.25s` | Slide transition duration. |
104
+ | `--content-drawer-transition-ease` | `<easing-function>` | `ease-out` | Slide transition easing. |
105
+ | `--content-drawer-closed` | `<percentage>` | `101%` | Off-screen translate amount (closed). |
106
+ | `--content-drawer-open-full` | `<percentage>` | `0%` | Full-open translate (`open-stage` unset or `0`). |
107
+ | `--content-drawer-open-half` | `<percentage>` | `50%` | Half-open translate (`open-stage="1"`). |
108
+ | `--content-drawer-open-peek` | `<percentage>` | `75%` | Peek translate (`open-stage="2"`). |
109
+ | `--content-drawer-relative-max-width` | `<length>` | `200px` | Max width when open in `.relative` mode, used unless `--content-drawer-max-width` is set. |
110
+ | `--content-drawer-z-index` | `<integer>` | `3` | Stack order for the drawer panel. |
111
+ | `--content-drawer-overlay-z-index` | `<integer>` | `2` | Stack order for the sibling backdrop (`:--dialog-backdrop-aliases`). |
112
+ | `--content-drawer-open-progress` | `<number>` | `var(--gesture-progress, 0)` | How far open the drawer is while `is-scrubbing`: `0` closed, `1` full. Declared on the drawer (not `:root`) so it follows a wrapping `<gesture-handler>`'s inherited `--gesture-progress` unless set explicitly — a swipe-to-open / drag-to-close bottom sheet. |
113
+ | `--content-drawer-max-width` | `<length>` | | Overrides `--content-drawer-relative-max-width` for this drawer only. |
114
+
115
+ #### CSS Classes
116
+
117
+ | Name | Description |
118
+ | --- | --- |
119
+ | `.close` | Close control — empty `.close` / `[rel="prev"]` button or link (theme close icon). |
120
+ | `.sticky` | `position: sticky` instead of the default `absolute` placement. |
121
+ | `.absolute` | `position: absolute` instead of the default `fixed` placement — a sheet inside its (`position: relative`) parent. |
122
+ | `.relative` | In-flow mode: the drawer participates in layout and animates `max-width` instead of overlaying via `position`, pushing sibling content aside as it opens. Currently only affects `from-side="left"`. |
123
+
124
+ #### CSS Aliases
125
+
126
+ | Alias | Kind | Matches | Description |
127
+ | --- | --- | --- | --- |
128
+ | `:--content-drawer` | element | `content-drawer`, `.tag-content-drawer` | |
129
+ | `:--content-drawer--is-open` | state | `[is-open]`, `[aria-expanded="true"]` | |
130
+ | `:--content-drawer--is-scrubbing` | state | `[is-scrubbing][is-scrubbing]`, `[data-scrubbing][data-scrubbing]` | |
131
+ | `:--content-drawer--open-stage-1` | state | `[open-stage="1"]`, `[data-open="1"]` | |
132
+ | `:--content-drawer--open-stage-2` | state | `[open-stage="2"]`, `[data-open="2"]` | |
133
+ | `:--content-drawer--from-side` | state | `[from-side]`, `[data-placement]` | |
134
+ | `:--content-drawer--from-side-bottom` | state | `[from-side="bottom"]`, `[data-placement="bottom"]` | |
135
+ | `:--content-drawer--from-side-top` | state | `[from-side="top"]`, `[data-placement="top"]` | |
136
+ | `:--content-drawer--from-side-left` | state | `[from-side="left"]`, `[data-placement="left"]` | |
137
+ | `:--content-drawer--from-side-right` | state | `[from-side="right"]`, `[data-placement="right"]` | |
138
+
139
+
140
+
141
+ ### Examples
142
+
143
+ #### Peek stages
144
+
145
+ `--open` with `data-open-stage` on the button sets the stage — `0` full, `1` half, `2` peek. The exact heights of each stage are configurable through CSS variables.
146
+
147
+
148
+ ```html
149
+ <section>
150
+ <button type="button" command="--open" commandfor="demo-drawer-stages" data-open-stage="0">
151
+ Full (100%)
152
+ </button>
153
+ <button type="button" command="--open" commandfor="demo-drawer-stages" data-open-stage="1">
154
+ Half (50%)
155
+ </button>
156
+ <button type="button" command="--open" commandfor="demo-drawer-stages" data-open-stage="2">
157
+ Peek (25%)
158
+ </button>
159
+ <content-drawer id="demo-drawer-stages" class="absolute">
160
+ <header>
161
+ <button type="button" rel="prev" command="--close" commandfor="demo-drawer-stages" aria-label="Close"></button>
162
+ <h2>Open stages</h2>
163
+ </header>
164
+ <p>Full / half / peek via <code>data-open-stage</code> on the button.</p>
165
+ </content-drawer>
166
+ </section>
167
+ ```
168
+
169
+
170
+ #### Dismissal
171
+
172
+ `<dismiss-watcher command-name="--close">` as the drawer's first child closes it on outside click or Escape / back gesture; the sheet gates its `is-active` on `content-drawer[is-open]` (with the inverse rule). Open with `--open`, not `--toggle` — an outside `mouseup` on the button closes first, the `click` then re-opens. Immediate next sibling `[role="presentation"]` / `.tag-backdrop` is the Valence.css modal dimmer; `<event-handler command-name="--close">` on that node closes on click.
173
+
174
+
175
+ ```html
176
+ <section>
177
+ <quark-sheet>
178
+ :scope {
179
+ content-drawer[is-open] dismiss-watcher { is-active: ""; }
180
+ content-drawer:not([is-open]) dismiss-watcher { is-active: none; }
181
+ }
182
+ </quark-sheet>
183
+ <button type="button" command="--open" commandfor="demo-drawer-dismiss">
184
+ Open drawer
185
+ </button>
186
+ <content-drawer id="demo-drawer-dismiss" class="absolute">
187
+ <dismiss-watcher watch-escape watch-outside-click command-name="--close"></dismiss-watcher>
188
+ <nav>Menu</nav>
189
+ </content-drawer>
190
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
191
+ </section>
192
+ ```
193
+
194
+
195
+ #### Side drawer
196
+
197
+ `from-side` slides from left / right / top instead of the default bottom.
198
+
199
+
200
+ ```html
201
+ <section>
202
+ <button type="button" command="--toggle" commandfor="demo-drawer-side">
203
+ Toggle drawer
204
+ </button>
205
+ <content-drawer id="demo-drawer-side" class="absolute" from-side="left">
206
+ <nav>Menu</nav>
207
+ </content-drawer>
208
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
209
+ </section>
210
+ ```
211
+
212
+
213
+ #### Auto-dismiss
214
+
215
+ `disappear-after` closes the drawer after N seconds — useful for success toasts.
216
+
217
+
218
+ ```html
219
+ <section>
220
+ <button type="button" command="--open" commandfor="demo-drawer-disappear">
221
+ Show success
222
+ </button>
223
+ <content-drawer id="demo-drawer-disappear" class="absolute" disappear-after="2">
224
+ <h2>Saved!</h2>
225
+ </content-drawer>
226
+ </section>
227
+ ```
228
+
229
+
230
+ #### Singleton group
231
+
232
+ Drawers sharing `singleton-name` — opening one closes the other.
233
+
234
+
235
+ ```html
236
+ <section>
237
+ <button type="button" command="--open" commandfor="drawer-a">Open A</button>
238
+ <button type="button" command="--open" commandfor="drawer-b">Open B</button>
239
+ <content-drawer id="drawer-a" class="absolute" singleton-name="demo">
240
+ <header>
241
+ <button type="button" rel="prev" command="--close" commandfor="drawer-a" aria-label="Close"></button>
242
+ <h2>Drawer A</h2>
243
+ </header>
244
+ </content-drawer>
245
+ <content-drawer id="drawer-b" class="absolute" singleton-name="demo">
246
+ <header>
247
+ <button type="button" rel="prev" command="--close" commandfor="drawer-b" aria-label="Close"></button>
248
+ <h2>Drawer B</h2>
249
+ </header>
250
+ </content-drawer>
251
+ </section>
252
+ ```
@@ -0,0 +1,69 @@
1
+ # content-drawer
2
+
3
+ Slide-in drawers and sheets for nav menus, filters, confirmations, and side panels — any edge, with peek stages.
4
+
5
+ <include-content data-demo="simple"></include-content>
6
+
7
+ ## Features
8
+
9
+ - **Any edge** Bottom (default), top, left, or right via `from-side`
10
+ - **Peek stages** Full, half, or peek via `open-stage`
11
+ - **Command-driven** `--open` / `--close` / `--toggle` from any `<button command commandfor>`
12
+ - **Dismissal** Outside click + Escape via `<dismiss-watcher>`
13
+ - **Backdrop** Valence.css dimmer — sibling `[role="presentation"]` / `.tag-backdrop`
14
+ - **Auto-dismiss** `disappear-after` for toast-style confirmations
15
+ - **Singleton groups** One open drawer per `singleton-name`
16
+ - **Layout modes** Viewport sheet (default, `position: fixed`), `.absolute` (inside its parent), `.relative`, or `.sticky`
17
+ - **Scrubbable** Wrap in [`gesture-handler`](/nucleus/packages/gesture-handler): the sheet follows the finger via `is-scrubbing` + `--content-drawer-open-progress`
18
+
19
+ ## Installation
20
+
21
+ <include-content is-active template-ref="/views/install-section/install-section.html"></include-content>
22
+
23
+ ## Usage
24
+
25
+ Put content inside `<content-drawer>` and invoke `--open`, `--close`, or `--toggle` on it — a native `<button command commandfor>`, or `<event-handler command-name target-ref>` when the invoker is not a button. Its parent automatically becomes `position: relative; overflow: hidden`, so give the parent a real size along the drawer's axis.
26
+
27
+ ```html
28
+ <button type="button" command="--toggle" commandfor="sheet">Toggle sheet</button>
29
+ <content-drawer id="sheet" class="absolute">
30
+ <h2>Saved!</h2>
31
+ </content-drawer>
32
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
33
+ ```
34
+
35
+ ### API Reference
36
+
37
+ <include-content is-active template-ref="/views/api-reference/api-reference.html"></include-content>
38
+
39
+ ### Examples
40
+
41
+ #### Peek stages
42
+
43
+ `--open` with `data-open-stage` on the button sets the stage — `0` full, `1` half, `2` peek. The exact heights of each stage are configurable through CSS variables.
44
+
45
+ <include-content data-demo="stages"></include-content>
46
+
47
+ #### Dismissal
48
+
49
+ `<dismiss-watcher command-name="--close">` as the drawer's first child closes it on outside click or Escape / back gesture; the sheet gates its `is-active` on `content-drawer[is-open]` (with the inverse rule). Open with `--open`, not `--toggle` — an outside `mouseup` on the button closes first, the `click` then re-opens. Immediate next sibling `[role="presentation"]` / `.tag-backdrop` is the Valence.css modal dimmer; `<event-handler command-name="--close">` on that node closes on click.
50
+
51
+ <include-content data-demo="dismiss"></include-content>
52
+
53
+ #### Side drawer
54
+
55
+ `from-side` slides from left / right / top instead of the default bottom.
56
+
57
+ <include-content data-demo="from-side"></include-content>
58
+
59
+ #### Auto-dismiss
60
+
61
+ `disappear-after` closes the drawer after N seconds — useful for success toasts.
62
+
63
+ <include-content data-demo="disappear"></include-content>
64
+
65
+ #### Singleton group
66
+
67
+ Drawers sharing `singleton-name` — opening one closes the other.
68
+
69
+ <include-content data-demo="singleton"></include-content>