@rcarls/rc-bottom-sheet 0.4.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/README.md +74 -0
- package/dist/custom-elements.json +619 -0
- package/dist/rc-bottom-sheet-DbzpQjd0.js +215 -0
- package/dist/rc-bottom-sheet-DbzpQjd0.js.map +1 -0
- package/dist/rc-bottom-sheet-define.js +6 -0
- package/dist/rc-bottom-sheet-define.js.map +1 -0
- package/dist/rc-bottom-sheet.js +5 -0
- package/dist/rc-bottom-sheet.js.map +1 -0
- package/dist/types/packages/rc-bottom-sheet/src/define.d.ts +1 -0
- package/dist/types/packages/rc-bottom-sheet/src/index.d.ts +1 -0
- package/dist/types/packages/rc-bottom-sheet/src/rc-bottom-sheet.d.ts +156 -0
- package/dist/types/packages/rc-bottom-sheet/src/rc-bottom-sheet.test.d.ts +0 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# `@rcarls/rc-bottom-sheet`
|
|
2
|
+
|
|
3
|
+
Modal bottom-sheet wrapper for a native `<dialog>`.
|
|
4
|
+
|
|
5
|
+
Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-bottom-sheet](https://richardcarls.github.io/rc-webcomponents/components/rc-bottom-sheet).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @rcarls/rc-bottom-sheet
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
yarn add @rcarls/rc-bottom-sheet
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import '@rcarls/rc-bottom-sheet/define';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
Place a `<dialog>` element directly inside `<rc-bottom-sheet>`. The inner dialog
|
|
24
|
+
must have `aria-labelledby` or `aria-label`.
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<rc-bottom-sheet id="filters" snap-points="40dvh 70dvh 100dvh">
|
|
28
|
+
<dialog aria-label="Filter recipes">
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
data-rc-bottom-sheet-handle
|
|
32
|
+
data-rc-dialog-resize-axis="y"
|
|
33
|
+
data-rc-dialog-resize-origin="top"
|
|
34
|
+
aria-label="Resize sheet"
|
|
35
|
+
></button>
|
|
36
|
+
<button value="close" formmethod="dialog">Done</button>
|
|
37
|
+
</dialog>
|
|
38
|
+
</rc-bottom-sheet>
|
|
39
|
+
|
|
40
|
+
<script type="module">
|
|
41
|
+
document.querySelector('#filters').showModal();
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`rc-bottom-sheet` inherits `rc-dialog` methods and events, including
|
|
46
|
+
`showModal()`, `show()`, `close()`, `requestClose()`, `rc-dialog-toggle`, and
|
|
47
|
+
`rc-dialog-request-close`. It defaults to light dismiss, vertical top-origin
|
|
48
|
+
resize, downward swipe-dismiss, and fixed positioning at the viewport's bottom
|
|
49
|
+
edge. Add an optional
|
|
50
|
+
`[data-rc-bottom-sheet-handle]` element inside the dialog for an authored
|
|
51
|
+
handle. Handles without a theme use the same centered 32 by 4 pixel pill
|
|
52
|
+
geometry as the splitter-style drag indicator inside a full-width, 48 pixel-high pointer
|
|
53
|
+
target. Keep a direct-child handle at the top of the dialog so that target
|
|
54
|
+
starts at the sheet's draggable edge; when authoring custom dialog padding,
|
|
55
|
+
leave its block-start padding at zero.
|
|
56
|
+
|
|
57
|
+
For an embedded non-modal sheet, place the component in a positioned container,
|
|
58
|
+
set `--rc-bottom-sheet-position: absolute`, and open it with `show()`. The sheet
|
|
59
|
+
then docks to that container's block-end edge instead of the viewport.
|
|
60
|
+
|
|
61
|
+
List `snap-points` as CSS heights in ascending order. Slow drag releases
|
|
62
|
+
settle at the nearest point; a swipe at `swipe-velocity` or faster settles at
|
|
63
|
+
the first or last point. Settling animates unless the user prefers reduced
|
|
64
|
+
motion.
|
|
65
|
+
|
|
66
|
+
Call `snapTo(index)` to move programmatically. The
|
|
67
|
+
`rc-bottom-sheet-snap` event reports the selected `index`, effective target
|
|
68
|
+
`height` after CSS size constraints, and whether the trigger was a drag or API
|
|
69
|
+
call. Constrained targets remain docked to the same block-end edge.
|
|
70
|
+
|
|
71
|
+
Set `--rc-bottom-sheet-snap-duration` and
|
|
72
|
+
`--rc-bottom-sheet-snap-easing` on the dialog to customize its settle motion.
|
|
73
|
+
Themes can map these to their own spatial motion tokens; reduced motion still
|
|
74
|
+
settles instantly.
|
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"readme": "",
|
|
4
|
+
"modules": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "javascript-module",
|
|
7
|
+
"path": "src/define.ts",
|
|
8
|
+
"declarations": [],
|
|
9
|
+
"exports": [
|
|
10
|
+
{
|
|
11
|
+
"kind": "custom-element-definition",
|
|
12
|
+
"name": "rc-bottom-sheet",
|
|
13
|
+
"declaration": {
|
|
14
|
+
"name": "RCBottomSheet",
|
|
15
|
+
"module": "/src/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"kind": "js",
|
|
20
|
+
"name": "*",
|
|
21
|
+
"declaration": {
|
|
22
|
+
"name": "*",
|
|
23
|
+
"module": "src/index.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"kind": "javascript-module",
|
|
30
|
+
"path": "src/index.ts",
|
|
31
|
+
"declarations": [],
|
|
32
|
+
"exports": [
|
|
33
|
+
{
|
|
34
|
+
"kind": "js",
|
|
35
|
+
"name": "*",
|
|
36
|
+
"declaration": {
|
|
37
|
+
"name": "*",
|
|
38
|
+
"module": "src/rc-bottom-sheet.js"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"kind": "javascript-module",
|
|
45
|
+
"path": "src/rc-bottom-sheet.ts",
|
|
46
|
+
"declarations": [
|
|
47
|
+
{
|
|
48
|
+
"kind": "class",
|
|
49
|
+
"description": "Modal bottom-sheet wrapper for a native `<dialog>`, built on `rc-dialog`.\n\nThe direct child `<dialog>` remains the semantic dialog surface and owns\ncontent, labels, and form behavior. `rc-bottom-sheet` supplies the same\nopen/close lifecycle, focus restoration, cancel/request-close events, and\nlight-dismiss affordance as `rc-dialog`. The component docks the sheet to\nthe viewport block-end by default, while themes provide its visual surface.\n\nDragging the resize handle past a decisive velocity in either direction\n(a \"swipe\" or \"fling,\" distinct from a slow deliberate drag) snaps\nstraight to the extreme `snap-points` entry in that direction — swipe up\nto fully expand, swipe down to fully collapse — regardless of how close\nthe release position was to some other point. Below that velocity, the\nsheet settles to whichever declared snap point is nearest the release\nheight. All settling, whether from a drag or from `snapTo()`, animates\nover `--rc-bottom-sheet-snap-duration`, follows\n`--rc-bottom-sheet-snap-easing`, and is skipped for\n`prefers-reduced-motion: reduce`.",
|
|
50
|
+
"name": "RCBottomSheet",
|
|
51
|
+
"cssProperties": [
|
|
52
|
+
{
|
|
53
|
+
"description": "Sheet surface background.",
|
|
54
|
+
"name": "--rc-bottom-sheet-bg",
|
|
55
|
+
"default": "Canvas"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"description": "Sheet text color.",
|
|
59
|
+
"name": "--rc-bottom-sheet-color",
|
|
60
|
+
"default": "CanvasText"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"description": "Sheet corner radius.",
|
|
64
|
+
"name": "--rc-bottom-sheet-radius",
|
|
65
|
+
"default": "1rem 1rem 0 0"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"description": "Sheet elevation shadow.",
|
|
69
|
+
"name": "--rc-bottom-sheet-shadow",
|
|
70
|
+
"default": "none"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"description": "Positioning scheme. Use `absolute` with `show()` to dock a non-modal sheet to a positioned ancestor.",
|
|
74
|
+
"name": "--rc-bottom-sheet-position",
|
|
75
|
+
"default": "fixed"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"description": "Distance from the positioning container's block-end edge.",
|
|
79
|
+
"name": "--rc-bottom-sheet-inset-block-end",
|
|
80
|
+
"default": "0px"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"description": "Inline-axis inset used with automatic margins.",
|
|
84
|
+
"name": "--rc-bottom-sheet-inset-inline",
|
|
85
|
+
"default": "0px"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"description": "Maximum sheet width.",
|
|
89
|
+
"name": "--rc-bottom-sheet-max-inline-size",
|
|
90
|
+
"default": "40rem"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"description": "Maximum sheet height.",
|
|
94
|
+
"name": "--rc-bottom-sheet-max-block-size",
|
|
95
|
+
"default": "70dvh"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"description": "Sheet padding.",
|
|
99
|
+
"name": "--rc-bottom-sheet-padding",
|
|
100
|
+
"default": "0 1rem 1rem"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"description": "Modal backdrop color.",
|
|
104
|
+
"name": "--rc-bottom-sheet-scrim",
|
|
105
|
+
"default": "var(--rc-dialog-scrim)"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"description": "Resize handle color.",
|
|
109
|
+
"name": "--rc-bottom-sheet-handle-color",
|
|
110
|
+
"default": "GrayText"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"description": "Resize handle width.",
|
|
114
|
+
"name": "--rc-bottom-sheet-handle-inline-size",
|
|
115
|
+
"default": "2rem"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"description": "Resize handle height.",
|
|
119
|
+
"name": "--rc-bottom-sheet-handle-block-size",
|
|
120
|
+
"default": "0.25rem"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"description": "Resize handle corner radius.",
|
|
124
|
+
"name": "--rc-bottom-sheet-handle-radius",
|
|
125
|
+
"default": "999px"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"description": "Pointer target width for a direct-child handle.",
|
|
129
|
+
"name": "--rc-bottom-sheet-handle-target-inline-size",
|
|
130
|
+
"default": "100%"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"description": "Pointer target height for a direct-child handle.",
|
|
134
|
+
"name": "--rc-bottom-sheet-handle-target-block-size",
|
|
135
|
+
"default": "3rem"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"description": "Margin around a direct-child handle target.",
|
|
139
|
+
"name": "--rc-bottom-sheet-handle-target-margin",
|
|
140
|
+
"default": "0"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"description": "Duration of the settle animation after a drag release or `snapTo()` call.",
|
|
144
|
+
"name": "--rc-bottom-sheet-snap-duration",
|
|
145
|
+
"default": "300ms"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"description": "Easing for the settle animation after a drag release or `snapTo()` call.",
|
|
149
|
+
"name": "--rc-bottom-sheet-snap-easing",
|
|
150
|
+
"default": "cubic-bezier(0.4, 0, 0.2, 1)"
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
"slots": [
|
|
154
|
+
{
|
|
155
|
+
"description": "Place a `<dialog>` element with the sheet content and optional `[data-rc-bottom-sheet-handle]` resize handle here.",
|
|
156
|
+
"name": ""
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
"members": [
|
|
160
|
+
{
|
|
161
|
+
"kind": "field",
|
|
162
|
+
"name": "swipeDismissThreshold",
|
|
163
|
+
"type": {
|
|
164
|
+
"text": "number"
|
|
165
|
+
},
|
|
166
|
+
"privacy": "private",
|
|
167
|
+
"static": true,
|
|
168
|
+
"readonly": true,
|
|
169
|
+
"default": "96"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"kind": "field",
|
|
173
|
+
"name": "_styledRoots",
|
|
174
|
+
"privacy": "private",
|
|
175
|
+
"static": true,
|
|
176
|
+
"readonly": true,
|
|
177
|
+
"default": "new Set<Document | ShadowRoot>()"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"kind": "method",
|
|
181
|
+
"name": "_ensureBaseStyles",
|
|
182
|
+
"privacy": "private",
|
|
183
|
+
"static": true,
|
|
184
|
+
"return": {
|
|
185
|
+
"type": {
|
|
186
|
+
"text": "void"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"parameters": [
|
|
190
|
+
{
|
|
191
|
+
"name": "root",
|
|
192
|
+
"type": {
|
|
193
|
+
"text": "Document | ShadowRoot"
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"kind": "field",
|
|
200
|
+
"name": "lightDismiss",
|
|
201
|
+
"type": {
|
|
202
|
+
"text": "boolean"
|
|
203
|
+
},
|
|
204
|
+
"default": "true",
|
|
205
|
+
"description": "Bottom sheets light-dismiss by default.\n\nSet `light-dismiss=\"false\"` as a property from JavaScript when a sheet must\nbe closed only by explicit actions.",
|
|
206
|
+
"attribute": "light-dismiss"
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"kind": "field",
|
|
210
|
+
"name": "resize",
|
|
211
|
+
"type": {
|
|
212
|
+
"text": "ResizeDirection"
|
|
213
|
+
},
|
|
214
|
+
"default": "'vertical'",
|
|
215
|
+
"description": "Bottom sheets resize vertically from the top edge by default.",
|
|
216
|
+
"attribute": "resize",
|
|
217
|
+
"reflects": true
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"kind": "field",
|
|
221
|
+
"name": "resizeOrigin",
|
|
222
|
+
"type": {
|
|
223
|
+
"text": "ResizeOrigin"
|
|
224
|
+
},
|
|
225
|
+
"default": "'top'",
|
|
226
|
+
"description": "Top-origin resizing keeps the sheet docked to the viewport bottom.",
|
|
227
|
+
"attribute": "resize-origin"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"kind": "field",
|
|
231
|
+
"name": "resizeHandle",
|
|
232
|
+
"type": {
|
|
233
|
+
"text": "string"
|
|
234
|
+
},
|
|
235
|
+
"default": "'[data-rc-bottom-sheet-handle]'",
|
|
236
|
+
"description": "Default optional handle selector. Falls back to top-edge resize when absent.",
|
|
237
|
+
"attribute": "resize-handle"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"kind": "field",
|
|
241
|
+
"name": "snapPoints",
|
|
242
|
+
"type": {
|
|
243
|
+
"text": "string"
|
|
244
|
+
},
|
|
245
|
+
"default": "''",
|
|
246
|
+
"description": "Whitespace-separated CSS heights in ascending order.\n\nEach height becomes an addressable snap target. Slow releases choose the\nnearest target, while decisive swipes choose the first or last target.",
|
|
247
|
+
"attribute": "snap-points"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"kind": "field",
|
|
251
|
+
"name": "swipeDismiss",
|
|
252
|
+
"type": {
|
|
253
|
+
"text": "boolean"
|
|
254
|
+
},
|
|
255
|
+
"default": "true",
|
|
256
|
+
"description": "Whether a downward pointer resize of at least 96 pixels requests close.\n\nWhen false, a decisive downward swipe settles at the first snap point.",
|
|
257
|
+
"attribute": "swipe-dismiss"
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"kind": "field",
|
|
261
|
+
"name": "swipeVelocity",
|
|
262
|
+
"type": {
|
|
263
|
+
"text": "number"
|
|
264
|
+
},
|
|
265
|
+
"default": "500",
|
|
266
|
+
"description": "Minimum release velocity, in pixels per second, that counts as a decisive\nswipe rather than a slow deliberate drag. A swipe jumps straight to the\nextreme `snap-points` entry in its direction; below this, the release\nsettles to the nearest point instead.",
|
|
267
|
+
"attribute": "swipe-velocity"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"kind": "field",
|
|
271
|
+
"name": "_reducedMotion",
|
|
272
|
+
"privacy": "private",
|
|
273
|
+
"readonly": true
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"kind": "field",
|
|
277
|
+
"name": "_activeSnapAnimation",
|
|
278
|
+
"type": {
|
|
279
|
+
"text": "Animation | null"
|
|
280
|
+
},
|
|
281
|
+
"privacy": "private",
|
|
282
|
+
"default": "null"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"kind": "method",
|
|
286
|
+
"name": "snapTo",
|
|
287
|
+
"return": {
|
|
288
|
+
"type": {
|
|
289
|
+
"text": "void"
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
"parameters": [
|
|
293
|
+
{
|
|
294
|
+
"name": "index",
|
|
295
|
+
"type": {
|
|
296
|
+
"text": "number"
|
|
297
|
+
},
|
|
298
|
+
"description": "zero-based index into `snapPoints`"
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"name": "behavior",
|
|
302
|
+
"default": "'animated'",
|
|
303
|
+
"type": {
|
|
304
|
+
"text": "'animated' | 'instant'"
|
|
305
|
+
},
|
|
306
|
+
"description": "whether to animate the movement"
|
|
307
|
+
}
|
|
308
|
+
],
|
|
309
|
+
"description": "Snaps to a declared target by zero-based index.\n\nFinite fractional indices are truncated and out-of-range indices clamp to\nthe nearest endpoint. Non-finite indices and calls without valid snap\npoints have no effect."
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
"kind": "method",
|
|
313
|
+
"name": "_onResizeEnd",
|
|
314
|
+
"privacy": "protected",
|
|
315
|
+
"return": {
|
|
316
|
+
"type": {
|
|
317
|
+
"text": "void"
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
"parameters": [
|
|
321
|
+
{
|
|
322
|
+
"name": "detail",
|
|
323
|
+
"type": {
|
|
324
|
+
"text": "ResizeLifecycleDetail"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
]
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"kind": "method",
|
|
331
|
+
"name": "_shouldSwipeDismiss",
|
|
332
|
+
"privacy": "private",
|
|
333
|
+
"return": {
|
|
334
|
+
"type": {
|
|
335
|
+
"text": "boolean"
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
"parameters": [
|
|
339
|
+
{
|
|
340
|
+
"name": "detail",
|
|
341
|
+
"type": {
|
|
342
|
+
"text": "ResizeLifecycleDetail"
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
]
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"kind": "method",
|
|
349
|
+
"name": "_snapToNearestPoint",
|
|
350
|
+
"privacy": "private",
|
|
351
|
+
"return": {
|
|
352
|
+
"type": {
|
|
353
|
+
"text": "void"
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
"parameters": [
|
|
357
|
+
{
|
|
358
|
+
"name": "trigger",
|
|
359
|
+
"default": "'api'",
|
|
360
|
+
"type": {
|
|
361
|
+
"text": "'drag' | 'api'"
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
]
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"kind": "method",
|
|
368
|
+
"name": "_snapToIndex",
|
|
369
|
+
"privacy": "private",
|
|
370
|
+
"return": {
|
|
371
|
+
"type": {
|
|
372
|
+
"text": "void"
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
"parameters": [
|
|
376
|
+
{
|
|
377
|
+
"name": "index",
|
|
378
|
+
"type": {
|
|
379
|
+
"text": "number"
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"name": "behavior",
|
|
384
|
+
"type": {
|
|
385
|
+
"text": "'animated' | 'instant'"
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"name": "trigger",
|
|
390
|
+
"type": {
|
|
391
|
+
"text": "'drag' | 'api'"
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"kind": "method",
|
|
398
|
+
"name": "_applySnap",
|
|
399
|
+
"privacy": "private",
|
|
400
|
+
"return": {
|
|
401
|
+
"type": {
|
|
402
|
+
"text": "void"
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
"parameters": [
|
|
406
|
+
{
|
|
407
|
+
"name": "$dialog",
|
|
408
|
+
"type": {
|
|
409
|
+
"text": "HTMLDialogElement"
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
"name": "top",
|
|
414
|
+
"type": {
|
|
415
|
+
"text": "number"
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"name": "height",
|
|
420
|
+
"type": {
|
|
421
|
+
"text": "number"
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
"name": "behavior",
|
|
426
|
+
"type": {
|
|
427
|
+
"text": "'animated' | 'instant'"
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
]
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"kind": "method",
|
|
434
|
+
"name": "_snapDuration",
|
|
435
|
+
"privacy": "private",
|
|
436
|
+
"return": {
|
|
437
|
+
"type": {
|
|
438
|
+
"text": "number"
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
"parameters": [
|
|
442
|
+
{
|
|
443
|
+
"name": "$dialog",
|
|
444
|
+
"type": {
|
|
445
|
+
"text": "HTMLDialogElement"
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
]
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"kind": "method",
|
|
452
|
+
"name": "_snapEasing",
|
|
453
|
+
"privacy": "private",
|
|
454
|
+
"return": {
|
|
455
|
+
"type": {
|
|
456
|
+
"text": "string"
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
"parameters": [
|
|
460
|
+
{
|
|
461
|
+
"name": "$dialog",
|
|
462
|
+
"type": {
|
|
463
|
+
"text": "HTMLDialogElement"
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
]
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"kind": "method",
|
|
470
|
+
"name": "_resolvedSnapPoints",
|
|
471
|
+
"privacy": "private",
|
|
472
|
+
"return": {
|
|
473
|
+
"type": {
|
|
474
|
+
"text": "number[]"
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"kind": "method",
|
|
480
|
+
"name": "_resolveSnapPoint",
|
|
481
|
+
"privacy": "private",
|
|
482
|
+
"return": {
|
|
483
|
+
"type": {
|
|
484
|
+
"text": "number"
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
"parameters": [
|
|
488
|
+
{
|
|
489
|
+
"name": "point",
|
|
490
|
+
"type": {
|
|
491
|
+
"text": "string"
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
]
|
|
495
|
+
}
|
|
496
|
+
],
|
|
497
|
+
"events": [
|
|
498
|
+
{
|
|
499
|
+
"name": "rc-bottom-sheet-snap",
|
|
500
|
+
"type": {
|
|
501
|
+
"text": "CustomEvent"
|
|
502
|
+
},
|
|
503
|
+
"description": "Fires when a drag release or `snapTo()` call selects a snap target. `detail: { index, height, trigger }`"
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
"description": "Inherited from `rc-dialog`; fired when the sheet opens.",
|
|
507
|
+
"name": "rc-dialog-open"
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
"description": "Inherited from `rc-dialog`; fired when user/native interaction changes open state.",
|
|
511
|
+
"name": "rc-dialog-toggle"
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"description": "Inherited from `rc-dialog`; cancelable close request.",
|
|
515
|
+
"name": "rc-dialog-request-close"
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
"description": "Inherited from `rc-dialog`; backward-compatible cancel alias.",
|
|
519
|
+
"name": "rc-dialog-cancel"
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
"description": "Inherited from `rc-dialog`; fired after the sheet closes.",
|
|
523
|
+
"name": "rc-dialog-close"
|
|
524
|
+
}
|
|
525
|
+
],
|
|
526
|
+
"attributes": [
|
|
527
|
+
{
|
|
528
|
+
"description": "Bottom sheets light-dismiss by default.\n\nSet `light-dismiss=\"false\"` as a property from JavaScript when a sheet must\nbe closed only by explicit actions.",
|
|
529
|
+
"name": "light-dismiss",
|
|
530
|
+
"type": {
|
|
531
|
+
"text": "boolean"
|
|
532
|
+
},
|
|
533
|
+
"default": "true",
|
|
534
|
+
"fieldName": "lightDismiss"
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
"description": "Bottom sheets resize vertically from the top edge by default.",
|
|
538
|
+
"name": "resize",
|
|
539
|
+
"type": {
|
|
540
|
+
"text": "ResizeDirection"
|
|
541
|
+
},
|
|
542
|
+
"default": "'vertical'",
|
|
543
|
+
"fieldName": "resize"
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
"description": "Top-origin resizing keeps the sheet docked to the viewport bottom.",
|
|
547
|
+
"name": "resize-origin",
|
|
548
|
+
"type": {
|
|
549
|
+
"text": "ResizeOrigin"
|
|
550
|
+
},
|
|
551
|
+
"default": "'top'",
|
|
552
|
+
"fieldName": "resizeOrigin"
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"description": "Default optional handle selector. Falls back to top-edge resize when absent.",
|
|
556
|
+
"name": "resize-handle",
|
|
557
|
+
"type": {
|
|
558
|
+
"text": "string"
|
|
559
|
+
},
|
|
560
|
+
"default": "'[data-rc-bottom-sheet-handle]'",
|
|
561
|
+
"fieldName": "resizeHandle"
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
"description": "Whitespace-separated CSS heights in ascending order.\n\nEach height becomes an addressable snap target. Slow releases choose the\nnearest target, while decisive swipes choose the first or last target.",
|
|
565
|
+
"name": "snap-points",
|
|
566
|
+
"type": {
|
|
567
|
+
"text": "string"
|
|
568
|
+
},
|
|
569
|
+
"default": "''",
|
|
570
|
+
"fieldName": "snapPoints"
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
"description": "Whether a downward pointer resize of at least 96 pixels requests close.\n\nWhen false, a decisive downward swipe settles at the first snap point.",
|
|
574
|
+
"name": "swipe-dismiss",
|
|
575
|
+
"type": {
|
|
576
|
+
"text": "boolean"
|
|
577
|
+
},
|
|
578
|
+
"default": "true",
|
|
579
|
+
"fieldName": "swipeDismiss"
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
"description": "Minimum release velocity, in pixels per second, that counts as a decisive\nswipe rather than a slow deliberate drag. A swipe jumps straight to the\nextreme `snap-points` entry in its direction; below this, the release\nsettles to the nearest point instead.",
|
|
583
|
+
"name": "swipe-velocity",
|
|
584
|
+
"type": {
|
|
585
|
+
"text": "number"
|
|
586
|
+
},
|
|
587
|
+
"default": "500",
|
|
588
|
+
"fieldName": "swipeVelocity"
|
|
589
|
+
}
|
|
590
|
+
],
|
|
591
|
+
"superclass": {
|
|
592
|
+
"name": "RCDialog",
|
|
593
|
+
"package": "@rcarls/rc-dialog"
|
|
594
|
+
},
|
|
595
|
+
"tagName": "rc-bottom-sheet",
|
|
596
|
+
"customElement": true
|
|
597
|
+
}
|
|
598
|
+
],
|
|
599
|
+
"exports": [
|
|
600
|
+
{
|
|
601
|
+
"kind": "js",
|
|
602
|
+
"name": "RCBottomSheet",
|
|
603
|
+
"declaration": {
|
|
604
|
+
"name": "RCBottomSheet",
|
|
605
|
+
"module": "src/rc-bottom-sheet.ts"
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"kind": "js",
|
|
610
|
+
"name": "default",
|
|
611
|
+
"declaration": {
|
|
612
|
+
"name": "RCBottomSheet",
|
|
613
|
+
"module": "src/rc-bottom-sheet.ts"
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
]
|
|
617
|
+
}
|
|
618
|
+
]
|
|
619
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { property as h } from "lit/decorators.js";
|
|
2
|
+
import { RCDialog as b } from "@rcarls/rc-dialog";
|
|
3
|
+
import { findExtremeSnapIndex as g, findNearestSnapIndex as y, pinElementBox as v } from "@rcarls/rc-common";
|
|
4
|
+
var _ = Object.defineProperty, c = (l, t, e, n) => {
|
|
5
|
+
for (var i = void 0, s = l.length - 1, o; s >= 0; s--)
|
|
6
|
+
(o = l[s]) && (i = o(t, e, i) || i);
|
|
7
|
+
return i && _(t, e, i), i;
|
|
8
|
+
};
|
|
9
|
+
const f = 300, S = "cubic-bezier(0.4, 0, 0.2, 1)", x = `
|
|
10
|
+
@layer rc-base {
|
|
11
|
+
rc-bottom-sheet > dialog {
|
|
12
|
+
position: var(--rc-bottom-sheet-position, fixed);
|
|
13
|
+
inset-block-start: auto;
|
|
14
|
+
inset-block-end: var(--rc-bottom-sheet-inset-block-end, 0px);
|
|
15
|
+
inset-inline: var(--rc-bottom-sheet-inset-inline, 0px);
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
inline-size: 100%;
|
|
18
|
+
max-inline-size: var(--rc-bottom-sheet-max-inline-size, 40rem);
|
|
19
|
+
max-block-size: var(--rc-bottom-sheet-max-block-size, 70dvh);
|
|
20
|
+
margin-block: 0;
|
|
21
|
+
margin-inline: auto;
|
|
22
|
+
overflow: auto;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
rc-bottom-sheet > dialog [data-rc-bottom-sheet-handle] {
|
|
26
|
+
box-sizing: border-box;
|
|
27
|
+
cursor: ns-resize;
|
|
28
|
+
touch-action: none;
|
|
29
|
+
-webkit-tap-highlight-color: transparent;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
rc-bottom-sheet > dialog > [data-rc-bottom-sheet-handle] {
|
|
33
|
+
position: relative;
|
|
34
|
+
display: block;
|
|
35
|
+
inline-size: var(--rc-bottom-sheet-handle-target-inline-size, 100%);
|
|
36
|
+
min-block-size: var(--rc-bottom-sheet-handle-target-block-size, 3rem);
|
|
37
|
+
margin: var(--rc-bottom-sheet-handle-target-margin, 0);
|
|
38
|
+
padding: 0;
|
|
39
|
+
border: 0;
|
|
40
|
+
border-radius: inherit;
|
|
41
|
+
background: transparent;
|
|
42
|
+
appearance: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
rc-bottom-sheet > dialog > [data-rc-bottom-sheet-handle]::before {
|
|
46
|
+
content: '';
|
|
47
|
+
position: absolute;
|
|
48
|
+
inset-block-start: 50%;
|
|
49
|
+
inset-inline-start: 50%;
|
|
50
|
+
inline-size: var(--rc-bottom-sheet-handle-inline-size, 2rem);
|
|
51
|
+
block-size: var(--rc-bottom-sheet-handle-block-size, 0.25rem);
|
|
52
|
+
border-radius: var(--rc-bottom-sheet-handle-radius, 999px);
|
|
53
|
+
background: var(--rc-bottom-sheet-handle-color, GrayText);
|
|
54
|
+
translate: -50% -50%;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
rc-bottom-sheet > dialog [data-rc-bottom-sheet-handle]:focus-visible {
|
|
58
|
+
outline: auto;
|
|
59
|
+
outline-offset: -0.25rem;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
`, z = 24;
|
|
63
|
+
var r;
|
|
64
|
+
const a = (r = class extends b {
|
|
65
|
+
constructor() {
|
|
66
|
+
super(...arguments), this.lightDismiss = !0, this.resize = "vertical", this.resizeOrigin = "top", this.resizeHandle = "[data-rc-bottom-sheet-handle]", this.snapPoints = "", this.swipeDismiss = !0, this.swipeVelocity = 500, this._reducedMotion = typeof window < "u" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null, this._activeSnapAnimation = null;
|
|
67
|
+
}
|
|
68
|
+
static _ensureBaseStyles(t) {
|
|
69
|
+
if (r._styledRoots.has(t))
|
|
70
|
+
return;
|
|
71
|
+
r._styledRoots.add(t);
|
|
72
|
+
const e = document.createElement("style");
|
|
73
|
+
e.setAttribute("data-rc-light-dom-base", "rc-bottom-sheet"), e.textContent = x, t instanceof Document ? t.head.append(e) : t.append(e);
|
|
74
|
+
}
|
|
75
|
+
connectedCallback() {
|
|
76
|
+
super.connectedCallback(), r._ensureBaseStyles(this.getRootNode());
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Snaps to a declared target by zero-based index.
|
|
80
|
+
*
|
|
81
|
+
* Finite fractional indices are truncated and out-of-range indices clamp to
|
|
82
|
+
* the nearest endpoint. Non-finite indices and calls without valid snap
|
|
83
|
+
* points have no effect.
|
|
84
|
+
*
|
|
85
|
+
* @param index - zero-based index into `snapPoints`
|
|
86
|
+
* @param behavior - whether to animate the movement
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* const sheet = document.querySelector('rc-bottom-sheet');
|
|
90
|
+
* sheet.snapTo(1);
|
|
91
|
+
*/
|
|
92
|
+
snapTo(t, e = "animated") {
|
|
93
|
+
Number.isFinite(t) && this._snapToIndex(Math.trunc(t), e, "api");
|
|
94
|
+
}
|
|
95
|
+
_onResizeEnd(t) {
|
|
96
|
+
if (t.inputType === "pointer" && this.swipeDismiss && this._shouldSwipeDismiss(t)) {
|
|
97
|
+
this.requestClose();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const e = this._resolvedSnapPoints(), n = t.edge.includes("n") ? -t.velocityY : t.velocityY, i = Math.abs(t.height - t.startHeight);
|
|
101
|
+
if (t.inputType === "pointer" && e.length > 0 && i >= z && Math.abs(n) >= this.swipeVelocity) {
|
|
102
|
+
const s = g(e, n > 0 ? 1 : -1);
|
|
103
|
+
this._snapToIndex(s, "animated", "drag");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this._snapToNearestPoint("drag");
|
|
107
|
+
}
|
|
108
|
+
_shouldSwipeDismiss(t) {
|
|
109
|
+
return t.edge.includes("n") && t.startHeight - t.height >= r.swipeDismissThreshold;
|
|
110
|
+
}
|
|
111
|
+
_snapToNearestPoint(t = "api") {
|
|
112
|
+
const e = this._$dialog, n = this._resolvedSnapPoints();
|
|
113
|
+
if (!e || n.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
const i = e.getBoundingClientRect().height, s = y(n, i);
|
|
116
|
+
this._snapToIndex(s, "animated", t);
|
|
117
|
+
}
|
|
118
|
+
_snapToIndex(t, e, n) {
|
|
119
|
+
const i = this._$dialog, s = this._resolvedSnapPoints();
|
|
120
|
+
if (!i || s.length === 0)
|
|
121
|
+
return;
|
|
122
|
+
const o = v(i), d = Math.max(0, Math.min(t, s.length - 1)), m = s[d];
|
|
123
|
+
this._activeSnapAnimation?.cancel(), this._activeSnapAnimation = null, i.style.height = `${m}px`;
|
|
124
|
+
const p = i.getBoundingClientRect().height;
|
|
125
|
+
i.style.top = `${o.top}px`, i.style.height = `${o.height}px`;
|
|
126
|
+
const u = o.bottom - p;
|
|
127
|
+
this._applySnap(i, u, p, e), this.dispatchEvent(
|
|
128
|
+
new CustomEvent("rc-bottom-sheet-snap", {
|
|
129
|
+
bubbles: !0,
|
|
130
|
+
composed: !0,
|
|
131
|
+
detail: { index: d, height: p, trigger: n }
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
_applySnap(t, e, n, i) {
|
|
136
|
+
const s = t.getBoundingClientRect();
|
|
137
|
+
if (this._activeSnapAnimation?.cancel(), this._activeSnapAnimation = null, i === "instant" || this._reducedMotion?.matches) {
|
|
138
|
+
t.style.top = `${e}px`, t.style.height = `${n}px`;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (s.top === e && s.height === n)
|
|
142
|
+
return;
|
|
143
|
+
const o = t.animate(
|
|
144
|
+
[
|
|
145
|
+
{ top: `${s.top}px`, height: `${s.height}px` },
|
|
146
|
+
{ top: `${e}px`, height: `${n}px` }
|
|
147
|
+
],
|
|
148
|
+
{
|
|
149
|
+
duration: this._snapDuration(t),
|
|
150
|
+
easing: this._snapEasing(t),
|
|
151
|
+
fill: "forwards"
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
this._activeSnapAnimation = o, o.finished.then(() => o.commitStyles()).catch(() => {
|
|
155
|
+
}).finally(() => {
|
|
156
|
+
o.cancel(), this._activeSnapAnimation === o && (this._activeSnapAnimation = null);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
_snapDuration(t) {
|
|
160
|
+
const e = getComputedStyle(t).getPropertyValue("--rc-bottom-sheet-snap-duration").trim(), n = Number.parseFloat(e);
|
|
161
|
+
return Number.isFinite(n) ? n : f;
|
|
162
|
+
}
|
|
163
|
+
_snapEasing(t) {
|
|
164
|
+
return getComputedStyle(t).getPropertyValue("--rc-bottom-sheet-snap-easing").trim() || S;
|
|
165
|
+
}
|
|
166
|
+
_resolvedSnapPoints() {
|
|
167
|
+
return this.snapPoints.trim() ? this.snapPoints.trim().split(/\s+/).map((t) => this._resolveSnapPoint(t)).filter((t) => Number.isFinite(t) && t > 0) : [];
|
|
168
|
+
}
|
|
169
|
+
_resolveSnapPoint(t) {
|
|
170
|
+
const e = Number.parseFloat(t);
|
|
171
|
+
if (!Number.isFinite(e))
|
|
172
|
+
return Number.NaN;
|
|
173
|
+
if (t.endsWith("%"))
|
|
174
|
+
return window.innerHeight * (e / 100);
|
|
175
|
+
if (t.endsWith("px") || String(e) === t)
|
|
176
|
+
return e;
|
|
177
|
+
const n = document.createElement("div");
|
|
178
|
+
Object.assign(n.style, {
|
|
179
|
+
position: "fixed",
|
|
180
|
+
visibility: "hidden",
|
|
181
|
+
pointerEvents: "none",
|
|
182
|
+
blockSize: t,
|
|
183
|
+
inlineSize: "0",
|
|
184
|
+
inset: "0 auto auto 0"
|
|
185
|
+
}), document.body.append(n);
|
|
186
|
+
const i = n.getBoundingClientRect().height;
|
|
187
|
+
return n.remove(), i;
|
|
188
|
+
}
|
|
189
|
+
}, r.swipeDismissThreshold = 96, r._styledRoots = /* @__PURE__ */ new Set(), r);
|
|
190
|
+
c([
|
|
191
|
+
h({ type: Boolean, attribute: "light-dismiss" })
|
|
192
|
+
], a.prototype, "lightDismiss");
|
|
193
|
+
c([
|
|
194
|
+
h({ type: String, reflect: !0 })
|
|
195
|
+
], a.prototype, "resize");
|
|
196
|
+
c([
|
|
197
|
+
h({ type: String, attribute: "resize-origin" })
|
|
198
|
+
], a.prototype, "resizeOrigin");
|
|
199
|
+
c([
|
|
200
|
+
h({ type: String, attribute: "resize-handle" })
|
|
201
|
+
], a.prototype, "resizeHandle");
|
|
202
|
+
c([
|
|
203
|
+
h({ type: String, attribute: "snap-points" })
|
|
204
|
+
], a.prototype, "snapPoints");
|
|
205
|
+
c([
|
|
206
|
+
h({ type: Boolean, attribute: "swipe-dismiss" })
|
|
207
|
+
], a.prototype, "swipeDismiss");
|
|
208
|
+
c([
|
|
209
|
+
h({ type: Number, attribute: "swipe-velocity" })
|
|
210
|
+
], a.prototype, "swipeVelocity");
|
|
211
|
+
let k = a;
|
|
212
|
+
export {
|
|
213
|
+
k as R
|
|
214
|
+
};
|
|
215
|
+
//# sourceMappingURL=rc-bottom-sheet-DbzpQjd0.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-bottom-sheet-DbzpQjd0.js","sources":["../src/rc-bottom-sheet.ts"],"sourcesContent":["import { property } from 'lit/decorators.js';\n\nimport { RCDialog } from '@rcarls/rc-dialog';\nimport {\n findExtremeSnapIndex,\n findNearestSnapIndex,\n pinElementBox,\n type ResizeDirection,\n type ResizeLifecycleDetail,\n type ResizeOrigin,\n} from '@rcarls/rc-common';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-bottom-sheet': RCBottomSheet;\n }\n\n interface HTMLElementEventMap {\n 'rc-bottom-sheet-snap': CustomEvent<RCBottomSheetSnapDetail>;\n }\n}\n\n/** Detail shape for `rc-bottom-sheet-snap`. */\nexport interface RCBottomSheetSnapDetail {\n /** Index into the resolved `snap-points` list selected as the target. */\n index: number;\n\n /** Effective target height in pixels, after CSS size constraints. */\n height: number;\n\n /** Whether the snap came from a drag release or a `snapTo()` call. */\n trigger: 'drag' | 'api';\n}\n\nconst DEFAULT_SNAP_DURATION_MS = 300;\nconst DEFAULT_SNAP_EASING = 'cubic-bezier(0.4, 0, 0.2, 1)';\n\nconst LIGHT_DOM_CSS = `\n@layer rc-base {\n rc-bottom-sheet > dialog {\n position: var(--rc-bottom-sheet-position, fixed);\n inset-block-start: auto;\n inset-block-end: var(--rc-bottom-sheet-inset-block-end, 0px);\n inset-inline: var(--rc-bottom-sheet-inset-inline, 0px);\n box-sizing: border-box;\n inline-size: 100%;\n max-inline-size: var(--rc-bottom-sheet-max-inline-size, 40rem);\n max-block-size: var(--rc-bottom-sheet-max-block-size, 70dvh);\n margin-block: 0;\n margin-inline: auto;\n overflow: auto;\n }\n\n rc-bottom-sheet > dialog [data-rc-bottom-sheet-handle] {\n box-sizing: border-box;\n cursor: ns-resize;\n touch-action: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n rc-bottom-sheet > dialog > [data-rc-bottom-sheet-handle] {\n position: relative;\n display: block;\n inline-size: var(--rc-bottom-sheet-handle-target-inline-size, 100%);\n min-block-size: var(--rc-bottom-sheet-handle-target-block-size, 3rem);\n margin: var(--rc-bottom-sheet-handle-target-margin, 0);\n padding: 0;\n border: 0;\n border-radius: inherit;\n background: transparent;\n appearance: none;\n }\n\n rc-bottom-sheet > dialog > [data-rc-bottom-sheet-handle]::before {\n content: '';\n position: absolute;\n inset-block-start: 50%;\n inset-inline-start: 50%;\n inline-size: var(--rc-bottom-sheet-handle-inline-size, 2rem);\n block-size: var(--rc-bottom-sheet-handle-block-size, 0.25rem);\n border-radius: var(--rc-bottom-sheet-handle-radius, 999px);\n background: var(--rc-bottom-sheet-handle-color, GrayText);\n translate: -50% -50%;\n }\n\n rc-bottom-sheet > dialog [data-rc-bottom-sheet-handle]:focus-visible {\n outline: auto;\n outline-offset: -0.25rem;\n }\n}\n`;\n\n// Floor so a noisy near-zero-distance release can't misread as a decisive\n// fling; a real swipe travels at least this far even if it's very quick.\nconst MIN_SWIPE_DISTANCE = 24;\n\n/**\n * Modal bottom-sheet wrapper for a native `<dialog>`, built on `rc-dialog`.\n *\n * The direct child `<dialog>` remains the semantic dialog surface and owns\n * content, labels, and form behavior. `rc-bottom-sheet` supplies the same\n * open/close lifecycle, focus restoration, cancel/request-close events, and\n * light-dismiss affordance as `rc-dialog`. The component docks the sheet to\n * the viewport block-end by default, while themes provide its visual surface.\n *\n * Dragging the resize handle past a decisive velocity in either direction\n * (a \"swipe\" or \"fling,\" distinct from a slow deliberate drag) snaps\n * straight to the extreme `snap-points` entry in that direction — swipe up\n * to fully expand, swipe down to fully collapse — regardless of how close\n * the release position was to some other point. Below that velocity, the\n * sheet settles to whichever declared snap point is nearest the release\n * height. All settling, whether from a drag or from `snapTo()`, animates\n * over `--rc-bottom-sheet-snap-duration`, follows\n * `--rc-bottom-sheet-snap-easing`, and is skipped for\n * `prefers-reduced-motion: reduce`.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-bottom-sheet rc-bottom-sheet docs}\n * @see {@link https://m3.material.io/components/bottom-sheets/overview Material Design bottom sheets}\n *\n * @slot - Place a `<dialog>` element with the sheet content and optional\n * `[data-rc-bottom-sheet-handle]` resize handle here.\n *\n * @fires rc-dialog-open - Inherited from `rc-dialog`; fired when the sheet opens.\n * @fires rc-dialog-toggle - Inherited from `rc-dialog`; fired when user/native interaction changes open state.\n * @fires rc-dialog-request-close - Inherited from `rc-dialog`; cancelable close request.\n * @fires rc-dialog-cancel - Inherited from `rc-dialog`; backward-compatible cancel alias.\n * @fires rc-dialog-close - Inherited from `rc-dialog`; fired after the sheet closes.\n * @fires rc-bottom-sheet-snap - Fires when a drag release or `snapTo()` call\n * selects a snap target. `detail: { index, height, trigger }`\n *\n * @attr light-dismiss - When present, a click on the backdrop area calls `requestClose()`.\n * Present by default; inherited from `rc-dialog`.\n * @attr resize - Enables edge resizing, mirroring the CSS `resize` property values.\n * Defaults to `vertical`; inherited from `rc-dialog`.\n * @attr resize-origin - Origin for resize edge hit-testing or explicit handles. Defaults to\n * `top`; inherited from `rc-dialog`.\n * @attr resize-handle - CSS selector, scoped to the inner `<dialog>`, for explicit resize\n * handles. Defaults to `[data-rc-bottom-sheet-handle]`; inherited from `rc-dialog`.\n * @attr snap-points - Whitespace-separated CSS heights, in ascending order, addressable by\n * `snapTo()` and settled to on drag release.\n * @attr swipe-dismiss - Whether a decisive downward swipe of at least 96 pixels requests close.\n * @attr swipe-velocity - Minimum release velocity, in pixels per second, that counts as a\n * decisive swipe rather than a slow deliberate drag.\n *\n * @cssprop [--rc-bottom-sheet-bg=Canvas] - Sheet surface background.\n * @cssprop [--rc-bottom-sheet-color=CanvasText] - Sheet text color.\n * @cssprop [--rc-bottom-sheet-radius=1rem 1rem 0 0] - Sheet corner radius.\n * @cssprop [--rc-bottom-sheet-shadow=none] - Sheet elevation shadow.\n * @cssprop [--rc-bottom-sheet-position=fixed] - Positioning scheme. Use `absolute` with `show()` to dock a non-modal sheet to a positioned ancestor.\n * @cssprop [--rc-bottom-sheet-inset-block-end=0px] - Distance from the positioning container's block-end edge.\n * @cssprop [--rc-bottom-sheet-inset-inline=0px] - Inline-axis inset used with automatic margins.\n * @cssprop [--rc-bottom-sheet-max-inline-size=40rem] - Maximum sheet width.\n * @cssprop [--rc-bottom-sheet-max-block-size=70dvh] - Maximum sheet height.\n * @cssprop [--rc-bottom-sheet-padding=0 1rem 1rem] - Sheet padding.\n * @cssprop [--rc-bottom-sheet-scrim=var(--rc-dialog-scrim)] - Modal backdrop color.\n * @cssprop [--rc-bottom-sheet-handle-color=GrayText] - Resize handle color.\n * @cssprop [--rc-bottom-sheet-handle-inline-size=2rem] - Resize handle width.\n * @cssprop [--rc-bottom-sheet-handle-block-size=0.25rem] - Resize handle height.\n * @cssprop [--rc-bottom-sheet-handle-radius=999px] - Resize handle corner radius.\n * @cssprop [--rc-bottom-sheet-handle-target-inline-size=100%] - Pointer target width for a direct-child handle.\n * @cssprop [--rc-bottom-sheet-handle-target-block-size=3rem] - Pointer target height for a direct-child handle.\n * @cssprop [--rc-bottom-sheet-handle-target-margin=0] - Margin around a direct-child handle target.\n * @cssprop [--rc-bottom-sheet-snap-duration=300ms] - Duration of the settle animation\n * after a drag release or `snapTo()` call.\n * @cssprop [--rc-bottom-sheet-snap-easing=cubic-bezier(0.4, 0, 0.2, 1)] - Easing\n * for the settle animation after a drag release or `snapTo()` call.\n */\nexport class RCBottomSheet extends RCDialog {\n private static readonly swipeDismissThreshold = 96;\n private static readonly _styledRoots = new Set<Document | ShadowRoot>();\n\n private static _ensureBaseStyles(root: Document | ShadowRoot): void {\n if (RCBottomSheet._styledRoots.has(root)) {\n return;\n }\n\n RCBottomSheet._styledRoots.add(root);\n\n const $style = document.createElement('style');\n\n $style.setAttribute('data-rc-light-dom-base', 'rc-bottom-sheet');\n $style.textContent = LIGHT_DOM_CSS;\n\n if (root instanceof Document) {\n root.head.append($style);\n } else {\n root.append($style);\n }\n }\n\n /**\n * Bottom sheets light-dismiss by default.\n *\n * Set `light-dismiss=\"false\"` as a property from JavaScript when a sheet must\n * be closed only by explicit actions.\n */\n @property({ type: Boolean, attribute: 'light-dismiss' })\n override lightDismiss = true;\n\n /** Bottom sheets resize vertically from the top edge by default. */\n @property({ type: String, reflect: true })\n override resize: ResizeDirection = 'vertical';\n\n /** Top-origin resizing keeps the sheet docked to the viewport bottom. */\n @property({ type: String, attribute: 'resize-origin' })\n override resizeOrigin: ResizeOrigin = 'top';\n\n /** Default optional handle selector. Falls back to top-edge resize when absent. */\n @property({ type: String, attribute: 'resize-handle' })\n override resizeHandle = '[data-rc-bottom-sheet-handle]';\n\n /**\n * Whitespace-separated CSS heights in ascending order.\n *\n * Each height becomes an addressable snap target. Slow releases choose the\n * nearest target, while decisive swipes choose the first or last target.\n */\n @property({ type: String, attribute: 'snap-points' })\n snapPoints = '';\n\n /**\n * Whether a downward pointer resize of at least 96 pixels requests close.\n *\n * When false, a decisive downward swipe settles at the first snap point.\n */\n @property({ type: Boolean, attribute: 'swipe-dismiss' })\n swipeDismiss = true;\n\n /**\n * Minimum release velocity, in pixels per second, that counts as a decisive\n * swipe rather than a slow deliberate drag. A swipe jumps straight to the\n * extreme `snap-points` entry in its direction; below this, the release\n * settles to the nearest point instead.\n */\n @property({ type: Number, attribute: 'swipe-velocity' })\n swipeVelocity = 500;\n\n private readonly _reducedMotion =\n typeof window !== 'undefined' ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;\n\n private _activeSnapAnimation: Animation | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n RCBottomSheet._ensureBaseStyles(this.getRootNode() as Document | ShadowRoot);\n }\n\n /**\n * Snaps to a declared target by zero-based index.\n *\n * Finite fractional indices are truncated and out-of-range indices clamp to\n * the nearest endpoint. Non-finite indices and calls without valid snap\n * points have no effect.\n *\n * @param index - zero-based index into `snapPoints`\n * @param behavior - whether to animate the movement\n *\n * @example\n * const sheet = document.querySelector('rc-bottom-sheet');\n * sheet.snapTo(1);\n */\n snapTo(index: number, behavior: 'animated' | 'instant' = 'animated'): void {\n if (!Number.isFinite(index)) {\n return;\n }\n\n this._snapToIndex(Math.trunc(index), behavior, 'api');\n }\n\n protected override _onResizeEnd(detail: ResizeLifecycleDetail): void {\n if (detail.inputType === 'pointer' && this.swipeDismiss && this._shouldSwipeDismiss(detail)) {\n this.requestClose();\n\n return;\n }\n\n const points = this._resolvedSnapPoints();\n const velocity = detail.edge.includes('n') ? -detail.velocityY : detail.velocityY;\n const distance = Math.abs(detail.height - detail.startHeight);\n\n if (\n detail.inputType === 'pointer' &&\n points.length > 0 &&\n distance >= MIN_SWIPE_DISTANCE &&\n Math.abs(velocity) >= this.swipeVelocity\n ) {\n // Decisive fling: jump to the extreme point in the swipe direction,\n // regardless of proximity to some other point. Height grows as the\n // sheet is dragged upward, so a positive velocity is a swipe up.\n const targetIndex = findExtremeSnapIndex(points, velocity > 0 ? 1 : -1);\n\n this._snapToIndex(targetIndex, 'animated', 'drag');\n\n return;\n }\n\n this._snapToNearestPoint('drag');\n }\n\n private _shouldSwipeDismiss(detail: ResizeLifecycleDetail): boolean {\n return (\n detail.edge.includes('n') &&\n detail.startHeight - detail.height >= RCBottomSheet.swipeDismissThreshold\n );\n }\n\n private _snapToNearestPoint(trigger: 'drag' | 'api' = 'api'): void {\n const $dialog = this._$dialog;\n const points = this._resolvedSnapPoints();\n\n if (!$dialog || points.length === 0) {\n return;\n }\n\n const height = $dialog.getBoundingClientRect().height;\n const nearestIndex = findNearestSnapIndex(points, height);\n\n this._snapToIndex(nearestIndex, 'animated', trigger);\n }\n\n private _snapToIndex(\n index: number,\n behavior: 'animated' | 'instant',\n trigger: 'drag' | 'api',\n ): void {\n const $dialog = this._$dialog;\n const points = this._resolvedSnapPoints();\n\n if (!$dialog || points.length === 0) {\n return;\n }\n\n // Pinning (border-box, explicit left/top/width/height) is normally\n // established by the first drag gesture; snapTo() must do the same so a\n // sheet that has never been dragged still measures and sets height\n // consistently.\n const rect = pinElementBox($dialog);\n const clampedIndex = Math.max(0, Math.min(index, points.length - 1));\n const requestedHeight = points[clampedIndex];\n\n // An in-flight animation wins over inline geometry in the cascade. Pin\n // its current visual box before cancelling so the constrained target can\n // be measured without jumping back to the prior snap point.\n this._activeSnapAnimation?.cancel();\n this._activeSnapAnimation = null;\n\n $dialog.style.height = `${requestedHeight}px`;\n\n const targetHeight = $dialog.getBoundingClientRect().height;\n\n // Restore the current visual box before applying or animating the target.\n // CSS min/max block-size can make targetHeight differ from the authored\n // snap point; anchoring from the effective height keeps the block-end edge\n // fixed in either case.\n $dialog.style.top = `${rect.top}px`;\n $dialog.style.height = `${rect.height}px`;\n\n const targetTop = rect.bottom - targetHeight;\n\n this._applySnap($dialog, targetTop, targetHeight, behavior);\n\n this.dispatchEvent(\n new CustomEvent<RCBottomSheetSnapDetail>('rc-bottom-sheet-snap', {\n bubbles: true,\n composed: true,\n detail: { index: clampedIndex, height: targetHeight, trigger },\n }),\n );\n }\n\n private _applySnap(\n $dialog: HTMLDialogElement,\n top: number,\n height: number,\n behavior: 'animated' | 'instant',\n ): void {\n // Measure before cancelling any in-flight animation. `_snapToIndex()`\n // normally pins and cancels first, while this ordering also keeps direct\n // calls robust if applying a snap is refactored later.\n const fromRect = $dialog.getBoundingClientRect();\n\n this._activeSnapAnimation?.cancel();\n this._activeSnapAnimation = null;\n\n if (behavior === 'instant' || this._reducedMotion?.matches) {\n $dialog.style.top = `${top}px`;\n $dialog.style.height = `${height}px`;\n\n return;\n }\n\n if (fromRect.top === top && fromRect.height === height) {\n return;\n }\n\n const animation = $dialog.animate(\n [\n { top: `${fromRect.top}px`, height: `${fromRect.height}px` },\n { top: `${top}px`, height: `${height}px` },\n ],\n {\n duration: this._snapDuration($dialog),\n easing: this._snapEasing($dialog),\n fill: 'forwards',\n },\n );\n\n this._activeSnapAnimation = animation;\n\n animation.finished\n .then(() => animation.commitStyles())\n .catch(() => {\n // Interrupted by a newer gesture or snapTo() call, which owns applying\n // its own final styles.\n })\n .finally(() => {\n animation.cancel();\n\n if (this._activeSnapAnimation === animation) {\n this._activeSnapAnimation = null;\n }\n });\n }\n\n private _snapDuration($dialog: HTMLDialogElement): number {\n const raw = getComputedStyle($dialog)\n .getPropertyValue('--rc-bottom-sheet-snap-duration')\n .trim();\n const parsed = Number.parseFloat(raw);\n\n return Number.isFinite(parsed) ? parsed : DEFAULT_SNAP_DURATION_MS;\n }\n\n private _snapEasing($dialog: HTMLDialogElement): string {\n return (\n getComputedStyle($dialog).getPropertyValue('--rc-bottom-sheet-snap-easing').trim() ||\n DEFAULT_SNAP_EASING\n );\n }\n\n private _resolvedSnapPoints(): number[] {\n if (!this.snapPoints.trim()) {\n return [];\n }\n\n return this.snapPoints\n .trim()\n .split(/\\s+/)\n .map((point) => this._resolveSnapPoint(point))\n .filter((point): point is number => Number.isFinite(point) && point > 0);\n }\n\n private _resolveSnapPoint(point: string): number {\n const numeric = Number.parseFloat(point);\n\n if (!Number.isFinite(numeric)) {\n return Number.NaN;\n }\n\n if (point.endsWith('%')) {\n return window.innerHeight * (numeric / 100);\n }\n\n if (point.endsWith('px') || String(numeric) === point) {\n return numeric;\n }\n\n const probe = document.createElement('div');\n\n Object.assign(probe.style, {\n position: 'fixed',\n visibility: 'hidden',\n pointerEvents: 'none',\n blockSize: point,\n inlineSize: '0',\n inset: '0 auto auto 0',\n });\n\n document.body.append(probe);\n\n const height = probe.getBoundingClientRect().height;\n\n probe.remove();\n\n return height;\n }\n}\n\nexport default RCBottomSheet;\n"],"names":["DEFAULT_SNAP_DURATION_MS","DEFAULT_SNAP_EASING","LIGHT_DOM_CSS","MIN_SWIPE_DISTANCE","_RCBottomSheet","_a","RCDialog","root","$style","index","behavior","detail","points","velocity","distance","targetIndex","findExtremeSnapIndex","trigger","$dialog","height","nearestIndex","findNearestSnapIndex","rect","pinElementBox","clampedIndex","requestedHeight","targetHeight","targetTop","top","fromRect","animation","raw","parsed","point","numeric","probe","__decorateClass","property","RCBottomSheet"],"mappings":";;;;;;;;AAkCA,MAAMA,IAA2B,KAC3BC,IAAsB,gCAEtBC,IAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAyDhBC,IAAqB;;AAyEpB,MAAMC,KAANC,IAAA,cAA4BC,EAAS;AAAA,EAArC,cAAA;AAAA,UAAA,GAAA,SAAA,GA8BL,KAAS,eAAe,IAIxB,KAAS,SAA0B,YAInC,KAAS,eAA6B,OAItC,KAAS,eAAe,iCASxB,KAAA,aAAa,IAQb,KAAA,eAAe,IASf,KAAA,gBAAgB,KAEhB,KAAiB,iBACf,OAAO,SAAW,MAAc,OAAO,WAAW,kCAAkC,IAAI,MAE1F,KAAQ,uBAAyC;AAAA,EAAA;AAAA,EArEjD,OAAe,kBAAkBC,GAAmC;AAClE,QAAIF,EAAc,aAAa,IAAIE,CAAI;AACrC;AAGF,IAAAF,EAAc,aAAa,IAAIE,CAAI;AAEnC,UAAMC,IAAS,SAAS,cAAc,OAAO;AAE7C,IAAAA,EAAO,aAAa,0BAA0B,iBAAiB,GAC/DA,EAAO,cAAcN,GAEjBK,aAAgB,WAClBA,EAAK,KAAK,OAAOC,CAAM,IAEvBD,EAAK,OAAOC,CAAM;AAAA,EAEtB;AAAA,EAsDS,oBAA0B;AACjC,UAAM,kBAAA,GACNH,EAAc,kBAAkB,KAAK,aAAsC;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,OAAOI,GAAeC,IAAmC,YAAkB;AACzE,IAAK,OAAO,SAASD,CAAK,KAI1B,KAAK,aAAa,KAAK,MAAMA,CAAK,GAAGC,GAAU,KAAK;AAAA,EACtD;AAAA,EAEmB,aAAaC,GAAqC;AACnE,QAAIA,EAAO,cAAc,aAAa,KAAK,gBAAgB,KAAK,oBAAoBA,CAAM,GAAG;AAC3F,WAAK,aAAA;AAEL;AAAA,IACF;AAEA,UAAMC,IAAS,KAAK,oBAAA,GACdC,IAAWF,EAAO,KAAK,SAAS,GAAG,IAAI,CAACA,EAAO,YAAYA,EAAO,WAClEG,IAAW,KAAK,IAAIH,EAAO,SAASA,EAAO,WAAW;AAE5D,QACEA,EAAO,cAAc,aACrBC,EAAO,SAAS,KAChBE,KAAYX,KACZ,KAAK,IAAIU,CAAQ,KAAK,KAAK,eAC3B;AAIA,YAAME,IAAcC,EAAqBJ,GAAQC,IAAW,IAAI,IAAI,EAAE;AAEtE,WAAK,aAAaE,GAAa,YAAY,MAAM;AAEjD;AAAA,IACF;AAEA,SAAK,oBAAoB,MAAM;AAAA,EACjC;AAAA,EAEQ,oBAAoBJ,GAAwC;AAClE,WACEA,EAAO,KAAK,SAAS,GAAG,KACxBA,EAAO,cAAcA,EAAO,UAAUN,EAAc;AAAA,EAExD;AAAA,EAEQ,oBAAoBY,IAA0B,OAAa;AACjE,UAAMC,IAAU,KAAK,UACfN,IAAS,KAAK,oBAAA;AAEpB,QAAI,CAACM,KAAWN,EAAO,WAAW;AAChC;AAGF,UAAMO,IAASD,EAAQ,sBAAA,EAAwB,QACzCE,IAAeC,EAAqBT,GAAQO,CAAM;AAExD,SAAK,aAAaC,GAAc,YAAYH,CAAO;AAAA,EACrD;AAAA,EAEQ,aACNR,GACAC,GACAO,GACM;AACN,UAAMC,IAAU,KAAK,UACfN,IAAS,KAAK,oBAAA;AAEpB,QAAI,CAACM,KAAWN,EAAO,WAAW;AAChC;AAOF,UAAMU,IAAOC,EAAcL,CAAO,GAC5BM,IAAe,KAAK,IAAI,GAAG,KAAK,IAAIf,GAAOG,EAAO,SAAS,CAAC,CAAC,GAC7Da,IAAkBb,EAAOY,CAAY;AAK3C,SAAK,sBAAsB,OAAA,GAC3B,KAAK,uBAAuB,MAE5BN,EAAQ,MAAM,SAAS,GAAGO,CAAe;AAEzC,UAAMC,IAAeR,EAAQ,sBAAA,EAAwB;AAMrD,IAAAA,EAAQ,MAAM,MAAM,GAAGI,EAAK,GAAG,MAC/BJ,EAAQ,MAAM,SAAS,GAAGI,EAAK,MAAM;AAErC,UAAMK,IAAYL,EAAK,SAASI;AAEhC,SAAK,WAAWR,GAASS,GAAWD,GAAchB,CAAQ,GAE1D,KAAK;AAAA,MACH,IAAI,YAAqC,wBAAwB;AAAA,QAC/D,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,OAAOc,GAAc,QAAQE,GAAc,SAAAT,EAAA;AAAA,MAAQ,CAC9D;AAAA,IAAA;AAAA,EAEL;AAAA,EAEQ,WACNC,GACAU,GACAT,GACAT,GACM;AAIN,UAAMmB,IAAWX,EAAQ,sBAAA;AAKzB,QAHA,KAAK,sBAAsB,OAAA,GAC3B,KAAK,uBAAuB,MAExBR,MAAa,aAAa,KAAK,gBAAgB,SAAS;AAC1D,MAAAQ,EAAQ,MAAM,MAAM,GAAGU,CAAG,MAC1BV,EAAQ,MAAM,SAAS,GAAGC,CAAM;AAEhC;AAAA,IACF;AAEA,QAAIU,EAAS,QAAQD,KAAOC,EAAS,WAAWV;AAC9C;AAGF,UAAMW,IAAYZ,EAAQ;AAAA,MACxB;AAAA,QACE,EAAE,KAAK,GAAGW,EAAS,GAAG,MAAM,QAAQ,GAAGA,EAAS,MAAM,KAAA;AAAA,QACtD,EAAE,KAAK,GAAGD,CAAG,MAAM,QAAQ,GAAGT,CAAM,KAAA;AAAA,MAAK;AAAA,MAE3C;AAAA,QACE,UAAU,KAAK,cAAcD,CAAO;AAAA,QACpC,QAAQ,KAAK,YAAYA,CAAO;AAAA,QAChC,MAAM;AAAA,MAAA;AAAA,IACR;AAGF,SAAK,uBAAuBY,GAE5BA,EAAU,SACP,KAAK,MAAMA,EAAU,cAAc,EACnC,MAAM,MAAM;AAAA,IAGb,CAAC,EACA,QAAQ,MAAM;AACb,MAAAA,EAAU,OAAA,GAEN,KAAK,yBAAyBA,MAChC,KAAK,uBAAuB;AAAA,IAEhC,CAAC;AAAA,EACL;AAAA,EAEQ,cAAcZ,GAAoC;AACxD,UAAMa,IAAM,iBAAiBb,CAAO,EACjC,iBAAiB,iCAAiC,EAClD,KAAA,GACGc,IAAS,OAAO,WAAWD,CAAG;AAEpC,WAAO,OAAO,SAASC,CAAM,IAAIA,IAAShC;AAAA,EAC5C;AAAA,EAEQ,YAAYkB,GAAoC;AACtD,WACE,iBAAiBA,CAAO,EAAE,iBAAiB,+BAA+B,EAAE,UAC5EjB;AAAA,EAEJ;AAAA,EAEQ,sBAAgC;AACtC,WAAK,KAAK,WAAW,SAId,KAAK,WACT,OACA,MAAM,KAAK,EACX,IAAI,CAACgC,MAAU,KAAK,kBAAkBA,CAAK,CAAC,EAC5C,OAAO,CAACA,MAA2B,OAAO,SAASA,CAAK,KAAKA,IAAQ,CAAC,IAPhE,CAAA;AAAA,EAQX;AAAA,EAEQ,kBAAkBA,GAAuB;AAC/C,UAAMC,IAAU,OAAO,WAAWD,CAAK;AAEvC,QAAI,CAAC,OAAO,SAASC,CAAO;AAC1B,aAAO,OAAO;AAGhB,QAAID,EAAM,SAAS,GAAG;AACpB,aAAO,OAAO,eAAeC,IAAU;AAGzC,QAAID,EAAM,SAAS,IAAI,KAAK,OAAOC,CAAO,MAAMD;AAC9C,aAAOC;AAGT,UAAMC,IAAQ,SAAS,cAAc,KAAK;AAE1C,WAAO,OAAOA,EAAM,OAAO;AAAA,MACzB,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,WAAWF;AAAA,MACX,YAAY;AAAA,MACZ,OAAO;AAAA,IAAA,CACR,GAED,SAAS,KAAK,OAAOE,CAAK;AAE1B,UAAMhB,IAASgB,EAAM,sBAAA,EAAwB;AAE7C,WAAAA,EAAM,OAAA,GAEChB;AAAA,EACT;AACF,GA9TEd,EAAwB,wBAAwB,IAChDA,EAAwB,mCAAmB,IAAA,GAFtCA;AA8BI+B,EAAA;AAAA,EADRC,EAAS,EAAE,MAAM,SAAS,WAAW,iBAAiB;AAAA,GA7B5CjC,EA8BF,WAAA,cAAA;AAIAgC,EAAA;AAAA,EADRC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAjC9BjC,EAkCF,WAAA,QAAA;AAIAgC,EAAA;AAAA,EADRC,EAAS,EAAE,MAAM,QAAQ,WAAW,iBAAiB;AAAA,GArC3CjC,EAsCF,WAAA,cAAA;AAIAgC,EAAA;AAAA,EADRC,EAAS,EAAE,MAAM,QAAQ,WAAW,iBAAiB;AAAA,GAzC3CjC,EA0CF,WAAA,cAAA;AASTgC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,WAAW,eAAe;AAAA,GAlDzCjC,EAmDX,WAAA,YAAA;AAQAgC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,WAAW,iBAAiB;AAAA,GA1D5CjC,EA2DX,WAAA,cAAA;AASAgC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,WAAW,kBAAkB;AAAA,GAnE5CjC,EAoEX,WAAA,eAAA;AApEK,IAAMkC,IAANlC;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-bottom-sheet-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCBottomSheet } from './index.js';\n\ncustomElements.get('rc-bottom-sheet') || customElements.define('rc-bottom-sheet', RCBottomSheet);\n\nexport * from './index.js';\n"],"names":["RCBottomSheet"],"mappings":";AAEA,eAAe,IAAI,iBAAiB,KAAK,eAAe,OAAO,mBAAmBA,CAAa;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-bottom-sheet.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './rc-bottom-sheet.js';
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { RCDialog } from '@rcarls/rc-dialog';
|
|
2
|
+
import { ResizeDirection, ResizeLifecycleDetail, ResizeOrigin } from '@rcarls/rc-common';
|
|
3
|
+
declare global {
|
|
4
|
+
interface HTMLElementTagNameMap {
|
|
5
|
+
'rc-bottom-sheet': RCBottomSheet;
|
|
6
|
+
}
|
|
7
|
+
interface HTMLElementEventMap {
|
|
8
|
+
'rc-bottom-sheet-snap': CustomEvent<RCBottomSheetSnapDetail>;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** Detail shape for `rc-bottom-sheet-snap`. */
|
|
12
|
+
export interface RCBottomSheetSnapDetail {
|
|
13
|
+
/** Index into the resolved `snap-points` list selected as the target. */
|
|
14
|
+
index: number;
|
|
15
|
+
/** Effective target height in pixels, after CSS size constraints. */
|
|
16
|
+
height: number;
|
|
17
|
+
/** Whether the snap came from a drag release or a `snapTo()` call. */
|
|
18
|
+
trigger: 'drag' | 'api';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Modal bottom-sheet wrapper for a native `<dialog>`, built on `rc-dialog`.
|
|
22
|
+
*
|
|
23
|
+
* The direct child `<dialog>` remains the semantic dialog surface and owns
|
|
24
|
+
* content, labels, and form behavior. `rc-bottom-sheet` supplies the same
|
|
25
|
+
* open/close lifecycle, focus restoration, cancel/request-close events, and
|
|
26
|
+
* light-dismiss affordance as `rc-dialog`. The component docks the sheet to
|
|
27
|
+
* the viewport block-end by default, while themes provide its visual surface.
|
|
28
|
+
*
|
|
29
|
+
* Dragging the resize handle past a decisive velocity in either direction
|
|
30
|
+
* (a "swipe" or "fling," distinct from a slow deliberate drag) snaps
|
|
31
|
+
* straight to the extreme `snap-points` entry in that direction — swipe up
|
|
32
|
+
* to fully expand, swipe down to fully collapse — regardless of how close
|
|
33
|
+
* the release position was to some other point. Below that velocity, the
|
|
34
|
+
* sheet settles to whichever declared snap point is nearest the release
|
|
35
|
+
* height. All settling, whether from a drag or from `snapTo()`, animates
|
|
36
|
+
* over `--rc-bottom-sheet-snap-duration`, follows
|
|
37
|
+
* `--rc-bottom-sheet-snap-easing`, and is skipped for
|
|
38
|
+
* `prefers-reduced-motion: reduce`.
|
|
39
|
+
*
|
|
40
|
+
* @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-bottom-sheet rc-bottom-sheet docs}
|
|
41
|
+
* @see {@link https://m3.material.io/components/bottom-sheets/overview Material Design bottom sheets}
|
|
42
|
+
*
|
|
43
|
+
* @slot - Place a `<dialog>` element with the sheet content and optional
|
|
44
|
+
* `[data-rc-bottom-sheet-handle]` resize handle here.
|
|
45
|
+
*
|
|
46
|
+
* @fires rc-dialog-open - Inherited from `rc-dialog`; fired when the sheet opens.
|
|
47
|
+
* @fires rc-dialog-toggle - Inherited from `rc-dialog`; fired when user/native interaction changes open state.
|
|
48
|
+
* @fires rc-dialog-request-close - Inherited from `rc-dialog`; cancelable close request.
|
|
49
|
+
* @fires rc-dialog-cancel - Inherited from `rc-dialog`; backward-compatible cancel alias.
|
|
50
|
+
* @fires rc-dialog-close - Inherited from `rc-dialog`; fired after the sheet closes.
|
|
51
|
+
* @fires rc-bottom-sheet-snap - Fires when a drag release or `snapTo()` call
|
|
52
|
+
* selects a snap target. `detail: { index, height, trigger }`
|
|
53
|
+
*
|
|
54
|
+
* @attr light-dismiss - When present, a click on the backdrop area calls `requestClose()`.
|
|
55
|
+
* Present by default; inherited from `rc-dialog`.
|
|
56
|
+
* @attr resize - Enables edge resizing, mirroring the CSS `resize` property values.
|
|
57
|
+
* Defaults to `vertical`; inherited from `rc-dialog`.
|
|
58
|
+
* @attr resize-origin - Origin for resize edge hit-testing or explicit handles. Defaults to
|
|
59
|
+
* `top`; inherited from `rc-dialog`.
|
|
60
|
+
* @attr resize-handle - CSS selector, scoped to the inner `<dialog>`, for explicit resize
|
|
61
|
+
* handles. Defaults to `[data-rc-bottom-sheet-handle]`; inherited from `rc-dialog`.
|
|
62
|
+
* @attr snap-points - Whitespace-separated CSS heights, in ascending order, addressable by
|
|
63
|
+
* `snapTo()` and settled to on drag release.
|
|
64
|
+
* @attr swipe-dismiss - Whether a decisive downward swipe of at least 96 pixels requests close.
|
|
65
|
+
* @attr swipe-velocity - Minimum release velocity, in pixels per second, that counts as a
|
|
66
|
+
* decisive swipe rather than a slow deliberate drag.
|
|
67
|
+
*
|
|
68
|
+
* @cssprop [--rc-bottom-sheet-bg=Canvas] - Sheet surface background.
|
|
69
|
+
* @cssprop [--rc-bottom-sheet-color=CanvasText] - Sheet text color.
|
|
70
|
+
* @cssprop [--rc-bottom-sheet-radius=1rem 1rem 0 0] - Sheet corner radius.
|
|
71
|
+
* @cssprop [--rc-bottom-sheet-shadow=none] - Sheet elevation shadow.
|
|
72
|
+
* @cssprop [--rc-bottom-sheet-position=fixed] - Positioning scheme. Use `absolute` with `show()` to dock a non-modal sheet to a positioned ancestor.
|
|
73
|
+
* @cssprop [--rc-bottom-sheet-inset-block-end=0px] - Distance from the positioning container's block-end edge.
|
|
74
|
+
* @cssprop [--rc-bottom-sheet-inset-inline=0px] - Inline-axis inset used with automatic margins.
|
|
75
|
+
* @cssprop [--rc-bottom-sheet-max-inline-size=40rem] - Maximum sheet width.
|
|
76
|
+
* @cssprop [--rc-bottom-sheet-max-block-size=70dvh] - Maximum sheet height.
|
|
77
|
+
* @cssprop [--rc-bottom-sheet-padding=0 1rem 1rem] - Sheet padding.
|
|
78
|
+
* @cssprop [--rc-bottom-sheet-scrim=var(--rc-dialog-scrim)] - Modal backdrop color.
|
|
79
|
+
* @cssprop [--rc-bottom-sheet-handle-color=GrayText] - Resize handle color.
|
|
80
|
+
* @cssprop [--rc-bottom-sheet-handle-inline-size=2rem] - Resize handle width.
|
|
81
|
+
* @cssprop [--rc-bottom-sheet-handle-block-size=0.25rem] - Resize handle height.
|
|
82
|
+
* @cssprop [--rc-bottom-sheet-handle-radius=999px] - Resize handle corner radius.
|
|
83
|
+
* @cssprop [--rc-bottom-sheet-handle-target-inline-size=100%] - Pointer target width for a direct-child handle.
|
|
84
|
+
* @cssprop [--rc-bottom-sheet-handle-target-block-size=3rem] - Pointer target height for a direct-child handle.
|
|
85
|
+
* @cssprop [--rc-bottom-sheet-handle-target-margin=0] - Margin around a direct-child handle target.
|
|
86
|
+
* @cssprop [--rc-bottom-sheet-snap-duration=300ms] - Duration of the settle animation
|
|
87
|
+
* after a drag release or `snapTo()` call.
|
|
88
|
+
* @cssprop [--rc-bottom-sheet-snap-easing=cubic-bezier(0.4, 0, 0.2, 1)] - Easing
|
|
89
|
+
* for the settle animation after a drag release or `snapTo()` call.
|
|
90
|
+
*/
|
|
91
|
+
export declare class RCBottomSheet extends RCDialog {
|
|
92
|
+
private static readonly swipeDismissThreshold;
|
|
93
|
+
private static readonly _styledRoots;
|
|
94
|
+
private static _ensureBaseStyles;
|
|
95
|
+
/**
|
|
96
|
+
* Bottom sheets light-dismiss by default.
|
|
97
|
+
*
|
|
98
|
+
* Set `light-dismiss="false"` as a property from JavaScript when a sheet must
|
|
99
|
+
* be closed only by explicit actions.
|
|
100
|
+
*/
|
|
101
|
+
lightDismiss: boolean;
|
|
102
|
+
/** Bottom sheets resize vertically from the top edge by default. */
|
|
103
|
+
resize: ResizeDirection;
|
|
104
|
+
/** Top-origin resizing keeps the sheet docked to the viewport bottom. */
|
|
105
|
+
resizeOrigin: ResizeOrigin;
|
|
106
|
+
/** Default optional handle selector. Falls back to top-edge resize when absent. */
|
|
107
|
+
resizeHandle: string;
|
|
108
|
+
/**
|
|
109
|
+
* Whitespace-separated CSS heights in ascending order.
|
|
110
|
+
*
|
|
111
|
+
* Each height becomes an addressable snap target. Slow releases choose the
|
|
112
|
+
* nearest target, while decisive swipes choose the first or last target.
|
|
113
|
+
*/
|
|
114
|
+
snapPoints: string;
|
|
115
|
+
/**
|
|
116
|
+
* Whether a downward pointer resize of at least 96 pixels requests close.
|
|
117
|
+
*
|
|
118
|
+
* When false, a decisive downward swipe settles at the first snap point.
|
|
119
|
+
*/
|
|
120
|
+
swipeDismiss: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Minimum release velocity, in pixels per second, that counts as a decisive
|
|
123
|
+
* swipe rather than a slow deliberate drag. A swipe jumps straight to the
|
|
124
|
+
* extreme `snap-points` entry in its direction; below this, the release
|
|
125
|
+
* settles to the nearest point instead.
|
|
126
|
+
*/
|
|
127
|
+
swipeVelocity: number;
|
|
128
|
+
private readonly _reducedMotion;
|
|
129
|
+
private _activeSnapAnimation;
|
|
130
|
+
connectedCallback(): void;
|
|
131
|
+
/**
|
|
132
|
+
* Snaps to a declared target by zero-based index.
|
|
133
|
+
*
|
|
134
|
+
* Finite fractional indices are truncated and out-of-range indices clamp to
|
|
135
|
+
* the nearest endpoint. Non-finite indices and calls without valid snap
|
|
136
|
+
* points have no effect.
|
|
137
|
+
*
|
|
138
|
+
* @param index - zero-based index into `snapPoints`
|
|
139
|
+
* @param behavior - whether to animate the movement
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* const sheet = document.querySelector('rc-bottom-sheet');
|
|
143
|
+
* sheet.snapTo(1);
|
|
144
|
+
*/
|
|
145
|
+
snapTo(index: number, behavior?: 'animated' | 'instant'): void;
|
|
146
|
+
protected _onResizeEnd(detail: ResizeLifecycleDetail): void;
|
|
147
|
+
private _shouldSwipeDismiss;
|
|
148
|
+
private _snapToNearestPoint;
|
|
149
|
+
private _snapToIndex;
|
|
150
|
+
private _applySnap;
|
|
151
|
+
private _snapDuration;
|
|
152
|
+
private _snapEasing;
|
|
153
|
+
private _resolvedSnapPoints;
|
|
154
|
+
private _resolveSnapPoint;
|
|
155
|
+
}
|
|
156
|
+
export default RCBottomSheet;
|
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rcarls/rc-bottom-sheet",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.4.0",
|
|
7
|
+
"description": "Modal bottom-sheet wrapper for a native <dialog>.",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/richardcarls/rc-webcomponents.git",
|
|
11
|
+
"directory": "packages/rc-bottom-sheet"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://richardcarls.github.io/rc-webcomponents/components/rc-bottom-sheet",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"module": "./dist/rc-bottom-sheet.js",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/types/packages/rc-bottom-sheet/src/index.d.ts",
|
|
24
|
+
"default": "./dist/rc-bottom-sheet.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./define": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/types/packages/rc-bottom-sheet/src/define.d.ts",
|
|
30
|
+
"default": "./dist/rc-bottom-sheet-define.js"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"types": "./dist/types/packages/rc-bottom-sheet/src/index.d.ts",
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"./dist/rc-bottom-sheet-define.js"
|
|
37
|
+
],
|
|
38
|
+
"customElements": "dist/custom-elements.json",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc && vite build && cem analyze",
|
|
41
|
+
"cem:analyze": "cem analyze",
|
|
42
|
+
"preview": "vite preview",
|
|
43
|
+
"test:browser": "vitest --run",
|
|
44
|
+
"test:browser:chrome": "vitest --run --project=chromium",
|
|
45
|
+
"test:browser:firefox": "vitest --run --project=firefox"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@rcarls/rc-common": "workspace:*",
|
|
49
|
+
"@rcarls/rc-dialog": "workspace:*"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
53
|
+
"@vitest/browser-playwright": "4.1.5",
|
|
54
|
+
"lit": "^3.0.0",
|
|
55
|
+
"playwright": "^1.56.0",
|
|
56
|
+
"rollup": "^4.60.2",
|
|
57
|
+
"typescript": "~5.9.3",
|
|
58
|
+
"vite": "^7.1.7",
|
|
59
|
+
"vite-plugin-dts": "^4.5.4",
|
|
60
|
+
"vitest": "^4.0.6",
|
|
61
|
+
"vitest-browser-lit": "^1.0.1"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"lit": "^3.0.0"
|
|
65
|
+
}
|
|
66
|
+
}
|