winduum 3.0.0-next.1 → 3.0.0-next.2
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/dist/main.css +1 -1
- package/dist/tailwind.css +2 -1
- package/package.json +22 -17
- package/src/base/keyframes.css +32 -0
- package/src/components/carousel/content.css +1 -0
- package/src/components/carousel/index.js +58 -192
- package/src/components/dialog/content.css +0 -1
- package/src/components/dialog/drawer.css +20 -0
- package/src/components/dialog/index.css +1 -0
- package/src/components/drawer/content.css +2 -1
- package/src/components/drawer/default.css +13 -31
- package/src/components/drawer/index.css +3 -0
- package/src/components/drawer/index.js +68 -50
- package/src/components/drawer/keyframes/default.css +9 -0
- package/src/components/drawer/noscript.css +32 -0
- package/src/components/drawer/nosnap.css +32 -0
- package/src/components/drawer/props/content.css +2 -2
- package/src/components/drawer/props/default.css +6 -0
- package/src/components/drawer/scroller.css +32 -0
- package/src/polyfills/timelineTrigger.js +54 -0
- package/src/supports.js +19 -0
- package/tailwindcss/theme/config/radius.css +9 -1
- package/tailwindcss/utilities/animation-timeline.css +51 -0
- package/tailwindcss/utilities/animation-trigger.css +33 -0
- package/tailwindcss/utilities/animation.css +88 -0
- package/tailwindcss/utilities/grid-area.css +7 -0
- package/tailwindcss/utilities/index.css +3 -0
- package/tailwindcss/variants/index.css +2 -1
- package/tailwindcss/variants/scroll-state.css +245 -0
- package/types/index.d.ts +8 -0
- package/types/index.d.ts.map +21 -3
|
@@ -1,227 +1,93 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @param {HTMLElement
|
|
3
|
-
* @param {
|
|
4
|
-
* @
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
element.scroll({ left: element?.children[index]?.offsetLeft - (isNaN(scrollPaddingLeft) ? 0 : scrollPaddingLeft) })
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @param {HTMLElement | Element & { _activeIndex: number }} element
|
|
2
|
+
* @param {HTMLElement} element
|
|
3
|
+
* @param {object} options
|
|
4
|
+
* @param {number} [options.direction=1]
|
|
5
|
+
* @param {number} [options.distance]
|
|
6
|
+
* @param {'left' | 'top'} [options.position='left']
|
|
7
|
+
* @param {number} [options.ratio=0.85]
|
|
14
8
|
* @returns void
|
|
15
9
|
*/
|
|
16
|
-
export const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @param {HTMLElement | Element & { _activeIndex: number }} element
|
|
22
|
-
* @returns void
|
|
23
|
-
*/
|
|
24
|
-
export const scrollNext = (element) => {
|
|
25
|
-
scrollTo(element, element._activeIndex + 1)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @param {HTMLElement | Element} element
|
|
30
|
-
* @param {number} scrollWidth
|
|
31
|
-
* @param {boolean} mathFloor
|
|
32
|
-
* @returns number
|
|
33
|
-
*/
|
|
34
|
-
export const getItemCount = (element, scrollWidth = element.scrollWidth - element.clientWidth, mathFloor = false) => {
|
|
35
|
-
const gap = parseInt(getComputedStyle(element).rowGap)
|
|
36
|
-
const mathRound = (value, floor) => floor ? Math.floor(value) : Math.ceil(value)
|
|
37
|
-
|
|
38
|
-
return [...element.children].reduce((count, children) => {
|
|
39
|
-
if (mathRound(scrollWidth / (children.offsetWidth + (isNaN(gap) ? 0 : gap)), mathFloor) > count) {
|
|
40
|
-
return count + 1
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
return count
|
|
44
|
-
}
|
|
45
|
-
}, 0) + 1
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* @param {HTMLElement | Element} element
|
|
50
|
-
* @param {import("./").ObserveCarouselOptions} options
|
|
51
|
-
* @returns IntersectionObserver
|
|
52
|
-
*/
|
|
53
|
-
export const observeCarousel = (element, options = {}) => {
|
|
54
|
-
options = {
|
|
55
|
-
visibleAttribute: 'data-visible',
|
|
56
|
-
observerOptions: {},
|
|
57
|
-
...options,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
element._observer = new IntersectionObserver((entries) => {
|
|
61
|
-
entries.forEach((entry) => {
|
|
62
|
-
entry.target.toggleAttribute(options.visibleAttribute, entry.isIntersecting)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
const activeElement = [...element.children].find(children => children.hasAttribute(options.visibleAttribute))
|
|
66
|
-
|
|
67
|
-
if (activeElement) {
|
|
68
|
-
element._activeIndex = [...element.children].indexOf(activeElement)
|
|
69
|
-
}
|
|
70
|
-
}, {
|
|
71
|
-
root: element,
|
|
72
|
-
threshold: 0.75,
|
|
73
|
-
...options.observerOptions,
|
|
10
|
+
export const scrollBy = (element, { direction = 1, distance, position = 'left', ratio = 0.85 }) => {
|
|
11
|
+
element.scrollBy({
|
|
12
|
+
[position]: (distance ?? element.clientWidth * ratio) * direction,
|
|
74
13
|
})
|
|
75
|
-
|
|
76
|
-
;[...element.children].forEach(children => element._observer.observe(children))
|
|
77
|
-
|
|
78
|
-
return element._observer
|
|
79
14
|
}
|
|
80
15
|
|
|
81
16
|
/**
|
|
82
|
-
* @param {HTMLElement
|
|
83
|
-
* @param {
|
|
17
|
+
* @param {HTMLElement} element
|
|
18
|
+
* @param {object} options
|
|
19
|
+
* @param {HTMLButtonElement | null} [options.prevElement]
|
|
20
|
+
* @param {HTMLButtonElement | null} [options.nextElement]
|
|
21
|
+
* @param {boolean} [options.scrollStart]
|
|
22
|
+
* @param {boolean} [options.scrollEnd]
|
|
23
|
+
* @param {boolean} [options.scrollNone]
|
|
84
24
|
* @returns void
|
|
85
25
|
*/
|
|
86
|
-
export const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const activeItem = getItemCount(element, element.scrollLeft, element.scrollLeft < element._lastScrollLeft)
|
|
93
|
-
const activeItemMax = getItemCount(element)
|
|
26
|
+
export const toggleScrollState = (element, { prevElement, nextElement, scrollStart, scrollEnd, scrollNone }) => {
|
|
27
|
+
scrollStart ??= element.scrollLeft <= 0
|
|
28
|
+
scrollEnd ??= element.scrollLeft >= element.scrollWidth - element.clientWidth
|
|
29
|
+
scrollNone ??= !(element.scrollWidth - element.clientWidth)
|
|
94
30
|
|
|
95
|
-
if (
|
|
96
|
-
|
|
31
|
+
if (prevElement) prevElement.disabled = scrollStart
|
|
32
|
+
if (nextElement) nextElement.disabled = scrollEnd
|
|
97
33
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (options.progressElement) {
|
|
102
|
-
options.progressElement.value = activeItem / activeItemMax * 100
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (options.counterMinElement) {
|
|
106
|
-
options.counterMinElement.innerHTML = `${activeItem}`
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (options.counterMaxElement) {
|
|
110
|
-
options.counterMaxElement.innerHTML = `${activeItemMax}`
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
element._lastScrollLeft = element.scrollLeft <= 0 ? 0 : element.scrollLeft
|
|
34
|
+
element.toggleAttribute('data-scroll-start', scrollStart)
|
|
35
|
+
element.toggleAttribute('data-scroll-end', scrollEnd)
|
|
36
|
+
element.toggleAttribute('data-scroll-none', scrollNone)
|
|
114
37
|
}
|
|
115
38
|
|
|
116
39
|
/**
|
|
117
|
-
* @param {HTMLElement
|
|
118
|
-
* @param {
|
|
40
|
+
* @param {HTMLElement} element
|
|
41
|
+
* @param {number} index
|
|
42
|
+
* @param {string} [attributeName='data-current']
|
|
119
43
|
* @returns void
|
|
120
44
|
*/
|
|
121
|
-
export const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
activeAttribute: 'data-active',
|
|
125
|
-
...options,
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (!options.element) return
|
|
129
|
-
|
|
130
|
-
options.element.insertAdjacentHTML('beforeend', [...Array(getItemCount(element))].map(
|
|
131
|
-
() => options.itemContent,
|
|
132
|
-
).join(''))
|
|
133
|
-
|
|
134
|
-
;[...options.element.children].forEach((children, i) => {
|
|
135
|
-
(i === 0) && children.setAttribute(options.activeAttribute, '')
|
|
136
|
-
children.addEventListener('click', ({ currentTarget }) => {
|
|
137
|
-
scrollTo(element, [...options.element.children].indexOf(currentTarget))
|
|
138
|
-
})
|
|
139
|
-
})
|
|
45
|
+
export const setCurrentAttribute = (element, index, attributeName = 'aria-current') => {
|
|
46
|
+
element.querySelector(`[${attributeName}]`)?.removeAttribute(attributeName)
|
|
47
|
+
element.children[index].setAttribute(attributeName, 'true')
|
|
140
48
|
}
|
|
141
49
|
|
|
142
50
|
/**
|
|
143
|
-
* @param {HTMLElement |
|
|
144
|
-
* @param {
|
|
51
|
+
* @param {HTMLElement & { _markerIndex?: number | null }} element
|
|
52
|
+
* @param {HTMLElement} target
|
|
53
|
+
* @param {HTMLElement | null} markerGroupElement
|
|
145
54
|
* @returns void
|
|
146
55
|
*/
|
|
147
|
-
export const
|
|
148
|
-
|
|
149
|
-
delay: 4000,
|
|
150
|
-
pauseElements: [],
|
|
151
|
-
...options,
|
|
152
|
-
}
|
|
56
|
+
export const setSnappedAttribute = (element, target, markerGroupElement) => {
|
|
57
|
+
const snappedIndex = [...element.children].indexOf(target)
|
|
153
58
|
|
|
154
|
-
|
|
59
|
+
setCurrentAttribute(element, snappedIndex, 'data-snapped')
|
|
155
60
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
element
|
|
159
|
-
})
|
|
61
|
+
if (markerGroupElement) {
|
|
62
|
+
const markerTarget = markerGroupElement.querySelector(`[href="#${target.id}"]`)
|
|
63
|
+
const index = element._markerIndex ?? (markerTarget && [...markerGroupElement.children].indexOf(markerTarget)) ?? snappedIndex
|
|
160
64
|
|
|
161
|
-
|
|
162
|
-
if (paused) return
|
|
65
|
+
setCurrentAttribute(markerGroupElement, index)
|
|
163
66
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
scrollTo(element, 0)
|
|
169
|
-
}
|
|
170
|
-
}, options.delay)
|
|
67
|
+
element._markerIndex = null
|
|
68
|
+
}
|
|
171
69
|
}
|
|
172
70
|
|
|
173
71
|
/**
|
|
174
|
-
* @param {HTMLElement
|
|
175
|
-
* @param {
|
|
72
|
+
* @param {HTMLElement & { _markerIndex?: number | null }} element
|
|
73
|
+
* @param {HTMLElement | HTMLLinkElement} target
|
|
74
|
+
* @param {HTMLElement} markerGroupElement
|
|
75
|
+
* @param {ScrollIntoViewOptions} scrollIntoViewOptions
|
|
176
76
|
* @returns void
|
|
177
77
|
*/
|
|
178
|
-
export const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (!matchMedia('(hover: hover) and (pointer: fine)').matches) {
|
|
185
|
-
return
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
let isDown
|
|
189
|
-
let startX
|
|
190
|
-
let scrollLeft
|
|
191
|
-
let timeout
|
|
192
|
-
|
|
193
|
-
const endGrabbing = () => {
|
|
194
|
-
isDown = false
|
|
195
|
-
element.removeAttribute(options.activeAttribute)
|
|
196
|
-
|
|
197
|
-
scrollTo(element, element._activeIndex)
|
|
198
|
-
|
|
199
|
-
clearTimeout(timeout)
|
|
200
|
-
|
|
201
|
-
timeout = setTimeout(() => {
|
|
202
|
-
element.style.scrollSnapType = ''
|
|
203
|
-
}, 300)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
element.addEventListener('mouseleave', endGrabbing)
|
|
207
|
-
|
|
208
|
-
element.addEventListener('mouseup', endGrabbing)
|
|
209
|
-
|
|
210
|
-
element.addEventListener('mousedown', ({ pageX }) => {
|
|
211
|
-
isDown = true
|
|
212
|
-
startX = pageX - element.offsetLeft
|
|
213
|
-
scrollLeft = element.scrollLeft
|
|
214
|
-
})
|
|
78
|
+
export const scrollToMarker = (element, target, markerGroupElement, scrollIntoViewOptions = {}) => {
|
|
79
|
+
const snappedTarget = document.getElementById(target.getAttribute('href').slice(1))
|
|
80
|
+
const markerTargetIndex = [...markerGroupElement.children].indexOf(target)
|
|
81
|
+
const index = snappedTarget ? [...element.children].indexOf(snappedTarget) : markerTargetIndex
|
|
215
82
|
|
|
216
|
-
element.
|
|
217
|
-
if (!isDown) return
|
|
218
|
-
e.preventDefault()
|
|
83
|
+
element._markerIndex = markerTargetIndex
|
|
219
84
|
|
|
220
|
-
|
|
85
|
+
setCurrentAttribute(markerGroupElement, markerTargetIndex)
|
|
221
86
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
87
|
+
element.children[index]?.scrollIntoView({
|
|
88
|
+
inline: 'start',
|
|
89
|
+
block: 'nearest',
|
|
90
|
+
container: 'nearest',
|
|
91
|
+
...scrollIntoViewOptions,
|
|
226
92
|
})
|
|
227
93
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.x-dialog {
|
|
2
|
+
&:is(.drawer) {
|
|
3
|
+
timeline-scope: --x-drawer-backdrop;
|
|
4
|
+
animation: x-drawer-backdrop-opacity linear both;
|
|
5
|
+
animation-timeline: --x-drawer-backdrop;
|
|
6
|
+
|
|
7
|
+
&::backdrop {
|
|
8
|
+
background-color:
|
|
9
|
+
color-mix(
|
|
10
|
+
in var(--x-drawer-background-color-space, srgb),
|
|
11
|
+
var(--color-dark) calc(var(--x-drawer-backdrop-opacity, 0) * var(--x-drawer-background-color-opacity)),
|
|
12
|
+
var(--x-drawer-background-color-mix, transparent)
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
@supports not (animation-timeline: --x) {
|
|
16
|
+
--x-drawer-backdrop-opacity: 1;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
.x-drawer-content {
|
|
2
|
+
background-color: var(--x-drawer-content-background-color);
|
|
3
|
+
padding: var(--x-drawer-content-padding-block) var(--x-drawer-content-padding-inline);
|
|
2
4
|
inline-size: var(--x-drawer-content-inline-size);
|
|
3
5
|
block-size: var(--x-drawer-content-block-size);
|
|
4
|
-
background-color: var(--x-drawer-content-background-color);
|
|
5
6
|
flex-shrink: 0;
|
|
6
7
|
scroll-snap-align: end;
|
|
7
8
|
}
|
|
@@ -1,40 +1,22 @@
|
|
|
1
1
|
.x-drawer {
|
|
2
|
-
z-index: var(--x-drawer-z-index, var(--z-index-30));
|
|
3
|
-
background-color:
|
|
4
|
-
color-mix(
|
|
5
|
-
in var(--x-drawer-background-color-space, srgb),
|
|
6
|
-
var(--color-dark) calc(var(--background-color-opacity, 0) * var(--x-drawer-background-color-opacity)),
|
|
7
|
-
var(--x-drawer-background-color-mix, transparent)
|
|
8
|
-
);
|
|
9
2
|
position: fixed;
|
|
10
3
|
inset: 0;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
overscroll-behavior: contain;
|
|
4
|
+
width: 100dvw;
|
|
5
|
+
height: 100dvh;
|
|
6
|
+
timeline-scope: --x-drawer-backdrop;
|
|
7
|
+
animation: x-drawer-backdrop-opacity linear both;
|
|
8
|
+
animation-timeline: --x-drawer-backdrop;
|
|
17
9
|
|
|
18
|
-
&:not([open]),
|
|
19
10
|
&::backdrop {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
&::after {
|
|
28
|
-
content: "";
|
|
29
|
-
min-inline-size: 100vw;
|
|
30
|
-
scroll-snap-align: end;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
&.flex-col {
|
|
34
|
-
overflow: hidden auto;
|
|
11
|
+
background-color:
|
|
12
|
+
color-mix(
|
|
13
|
+
in var(--x-drawer-background-color-space, srgb),
|
|
14
|
+
var(--color-dark) calc(var(--x-drawer-backdrop-opacity, 0) * var(--x-drawer-background-color-opacity)),
|
|
15
|
+
var(--x-drawer-background-color-mix, transparent)
|
|
16
|
+
);
|
|
35
17
|
|
|
36
|
-
|
|
37
|
-
|
|
18
|
+
@supports not (animation-timeline: --x) {
|
|
19
|
+
--x-drawer-backdrop-opacity: 1;
|
|
38
20
|
}
|
|
39
21
|
}
|
|
40
22
|
}
|
|
@@ -1,85 +1,103 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { supportsScrollInitialTarget } from '/src/supports.js'
|
|
2
|
+
import { nextRepaint } from '/src/common.js'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
* @param {
|
|
5
|
-
* @
|
|
6
|
-
* @param {'top' | 'left'} direction
|
|
7
|
-
* @returns void
|
|
5
|
+
* @param {'left' | 'right' | 'top' | 'bottom'} placement
|
|
6
|
+
* @returns boolean
|
|
8
7
|
*/
|
|
9
|
-
export const
|
|
10
|
-
|
|
8
|
+
export const isVerticalDrawer = (placement) => {
|
|
9
|
+
return ['top', 'bottom'].includes(placement)
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* @param {HTMLElement | Element} element
|
|
15
|
-
* @param {
|
|
16
|
-
* @param {
|
|
14
|
+
* @param {'left' | 'right' | 'top' | 'bottom'} placement
|
|
15
|
+
* @param {boolean} reverse
|
|
16
|
+
* @param {'auto' | 'instant'} behavior
|
|
17
17
|
* @returns void
|
|
18
18
|
*/
|
|
19
|
-
export const
|
|
20
|
-
|
|
19
|
+
export const scrollDrawer = (element, placement, reverse = false, behavior = 'auto') => {
|
|
20
|
+
const [direction, distance, closedDistance] = drawerProperties(element, placement)
|
|
21
|
+
|
|
22
|
+
element.scroll({ [direction]: reverse ? closedDistance : distance, behavior })
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* @param {HTMLElement | Element} element
|
|
25
|
-
* @param {
|
|
26
|
-
* @param {'top' | 'left'} direction
|
|
27
|
+
* @param {'left' | 'right' | 'top' | 'bottom'} placement
|
|
27
28
|
* @returns void
|
|
28
29
|
*/
|
|
29
|
-
export const
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
export const showDrawer = async (element, placement) => {
|
|
31
|
+
if (!supportsScrollInitialTarget) {
|
|
32
|
+
scrollDrawer(element, placement, true, 'instant')
|
|
33
|
+
await nextRepaint()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
scrollDrawer(element, placement)
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
/**
|
|
35
40
|
* @param {HTMLElement | Element} element
|
|
36
|
-
* @param {'
|
|
37
|
-
* @param {string} snapClass
|
|
41
|
+
* @param {'left' | 'right' | 'top' | 'bottom'} placement
|
|
38
42
|
* @returns void
|
|
39
43
|
*/
|
|
40
|
-
export const
|
|
41
|
-
element
|
|
42
|
-
element.inert = state === 'close'
|
|
43
|
-
element.dispatchEvent(new CustomEvent(`x-drawer:${state}`))
|
|
44
|
+
export const closeDrawer = (element, placement) => {
|
|
45
|
+
scrollDrawer(element, placement, true)
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
|
-
* @param {
|
|
48
|
-
* @param {
|
|
49
|
-
* @
|
|
49
|
+
* @param {HTMLElement | Element} element
|
|
50
|
+
* @param {HTMLElement | Element} contentElement
|
|
51
|
+
* @param {AbortSignal} signal
|
|
52
|
+
* @param {'left' | 'right' | 'top' | 'bottom'} placement
|
|
53
|
+
* @returns void
|
|
50
54
|
*/
|
|
51
|
-
export const
|
|
52
|
-
|
|
55
|
+
export const drawerEvents = (element, contentElement, placement, signal) => {
|
|
56
|
+
element.addEventListener('cancel', (event) => {
|
|
57
|
+
const scroller = element.firstElementChild
|
|
58
|
+
|
|
59
|
+
if (scroller.scrollHeight > 0 || scroller.scrollWidth > 0) event.preventDefault()
|
|
60
|
+
|
|
61
|
+
closeDrawer(scroller, placement)
|
|
62
|
+
}, { signal })
|
|
63
|
+
|
|
64
|
+
element.addEventListener('click', ({ target }) => {
|
|
65
|
+
if (!contentElement.contains(target) && !contentElement.isEqualNode(target))
|
|
66
|
+
closeDrawer(element.firstElementChild, placement)
|
|
67
|
+
}, { signal })
|
|
53
68
|
}
|
|
54
69
|
|
|
55
70
|
/**
|
|
56
71
|
* @param {HTMLDialogElement | Element} element
|
|
57
|
-
* @param {
|
|
58
|
-
* @returns
|
|
72
|
+
* @param {'left' | 'right' | 'top' | 'bottom'} placement
|
|
73
|
+
* @returns IntersectionObserver
|
|
59
74
|
*/
|
|
60
|
-
export const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
opacityRatio: 1,
|
|
65
|
-
scrollOpen: 0,
|
|
66
|
-
scrollClose: element.scrollWidth - element.clientWidth,
|
|
67
|
-
scrollSize: element.scrollWidth - element.clientWidth,
|
|
68
|
-
scrollDirection: element.scrollLeft,
|
|
69
|
-
...options,
|
|
70
|
-
}
|
|
75
|
+
export const drawerObserver = (element, placement) => {
|
|
76
|
+
const visibleThreshold = 1 / (
|
|
77
|
+
isVerticalDrawer(placement) ? window.innerHeight : window.innerWidth
|
|
78
|
+
)
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
return new IntersectionObserver((entries) => {
|
|
81
|
+
if (entries.at(-1).intersectionRatio < visibleThreshold) element.close()
|
|
82
|
+
}, {
|
|
83
|
+
root: element,
|
|
84
|
+
threshold: [visibleThreshold, 1],
|
|
85
|
+
},
|
|
75
86
|
)
|
|
87
|
+
}
|
|
76
88
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
89
|
+
/**
|
|
90
|
+
* @param {HTMLElement | Element} element
|
|
91
|
+
* @param {'left' | 'right' | 'top' | 'bottom'} placement
|
|
92
|
+
* @returns {['top' | 'left', number, number]}
|
|
93
|
+
*/
|
|
94
|
+
export const drawerProperties = (element, placement) => {
|
|
95
|
+
const [openedDistance, closedDistance] = {
|
|
96
|
+
left: [0, element.offsetWidth],
|
|
97
|
+
right: [element.offsetWidth, 0],
|
|
98
|
+
top: [0, element.offsetHeight],
|
|
99
|
+
bottom: [element.offsetHeight, 0],
|
|
100
|
+
}[placement]
|
|
80
101
|
|
|
81
|
-
|
|
82
|
-
toggleDrawerAttributes(element, 'close', options.snapClass)
|
|
83
|
-
element.close && element.close()
|
|
84
|
-
}
|
|
102
|
+
return [isVerticalDrawer(placement) ? 'top' : 'left', openedDistance, closedDistance]
|
|
85
103
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.x-drawer {
|
|
2
|
+
@media (scripting: none) {
|
|
3
|
+
--x-drawer-backdrop-opacity: 1;
|
|
4
|
+
|
|
5
|
+
width: fit-content;
|
|
6
|
+
height: fit-content;
|
|
7
|
+
transition-property: var(--default-transition-property);
|
|
8
|
+
transition-timing-function: var(--ease-in-out);
|
|
9
|
+
transition-duration: var(--default-transition-duration);
|
|
10
|
+
transition-behavior: allow-discrete;
|
|
11
|
+
|
|
12
|
+
&::backdrop {
|
|
13
|
+
transition: inherit;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&:not([open]) {
|
|
17
|
+
&::backdrop {
|
|
18
|
+
opacity: 0%;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@starting-style {
|
|
23
|
+
&[open] {
|
|
24
|
+
opacity: 0%;
|
|
25
|
+
|
|
26
|
+
&::backdrop {
|
|
27
|
+
opacity: 0%;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.x-drawer {
|
|
2
|
+
&:is(.no-snap) {
|
|
3
|
+
--x-drawer-backdrop-opacity: 1;
|
|
4
|
+
|
|
5
|
+
width: fit-content;
|
|
6
|
+
height: fit-content;
|
|
7
|
+
transition-property: var(--default-transition-property);
|
|
8
|
+
transition-timing-function: var(--ease-in-out);
|
|
9
|
+
transition-duration: var(--default-transition-duration);
|
|
10
|
+
transition-behavior: allow-discrete;
|
|
11
|
+
|
|
12
|
+
&::backdrop {
|
|
13
|
+
transition: inherit;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&:not([open]) {
|
|
17
|
+
&::backdrop {
|
|
18
|
+
opacity: 0%;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@starting-style {
|
|
23
|
+
&[open] {
|
|
24
|
+
opacity: 0%;
|
|
25
|
+
|
|
26
|
+
&::backdrop {
|
|
27
|
+
opacity: 0%;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
--x-drawer-content-background-color: var(--color-body-primary);
|
|
4
4
|
--x-drawer-content-padding-block: 2rem;
|
|
5
5
|
--x-drawer-content-padding-inline: 1.5rem;
|
|
6
|
-
--x-drawer-content-inline-size:
|
|
7
|
-
--x-drawer-content-block-size:
|
|
6
|
+
--x-drawer-content-inline-size: 50dvw;
|
|
7
|
+
--x-drawer-content-block-size: 100dvh;
|
|
8
8
|
}
|