winduum 2.2.28 → 3.0.0-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/package.json +19 -12
  2. package/src/base/defaults.css +3 -0
  3. package/src/base/reset.css +4 -0
  4. package/src/common.d.ts +4 -0
  5. package/src/common.js +9 -1
  6. package/src/components/carousel/content.css +1 -0
  7. package/src/components/carousel/index.d.ts +14 -35
  8. package/src/components/carousel/index.js +75 -194
  9. package/src/components/check/props/default.css +1 -1
  10. package/src/components/control/props/select-picker.css +4 -4
  11. package/src/components/control/props/select.css +2 -2
  12. package/src/components/control/tel-country-code.css +24 -0
  13. package/src/components/details/default.css +14 -0
  14. package/src/components/details/index.css +1 -0
  15. package/src/components/details/index.d.ts +2 -6
  16. package/src/components/details/index.js +7 -72
  17. package/src/components/details/readme.md +2 -5
  18. package/src/components/dialog/content.css +8 -2
  19. package/src/components/dialog/default.css +16 -2
  20. package/src/components/dialog/drawer.css +20 -0
  21. package/src/components/dialog/index.css +1 -0
  22. package/src/components/dialog/index.js +8 -79
  23. package/src/components/dialog/readme.md +1 -5
  24. package/src/components/drawer/content.css +2 -1
  25. package/src/components/drawer/default.css +13 -31
  26. package/src/components/drawer/index.css +3 -0
  27. package/src/components/drawer/index.d.ts +8 -15
  28. package/src/components/drawer/index.js +67 -50
  29. package/src/components/drawer/keyframes/default.css +9 -0
  30. package/src/components/drawer/noscript.css +32 -0
  31. package/src/components/drawer/nosnap.css +32 -0
  32. package/src/components/drawer/props/content.css +2 -2
  33. package/src/components/drawer/props/default.css +6 -0
  34. package/src/components/drawer/scroller.css +32 -0
  35. package/src/components/form/index.d.ts +5 -12
  36. package/src/components/form/index.js +35 -70
  37. package/src/components/heading/lg.css +1 -1
  38. package/src/components/heading/props/default.css +1 -1
  39. package/src/components/heading/sm.css +1 -1
  40. package/src/components/index.css +1 -0
  41. package/src/components/label/props/default.css +3 -2
  42. package/src/components/popover/content.css +7 -94
  43. package/src/components/popover/default.css +16 -3
  44. package/src/components/popover/index.css +2 -0
  45. package/src/components/popover/index.d.ts +14 -18
  46. package/src/components/popover/index.js +40 -80
  47. package/src/components/popover/props/content.css +1 -2
  48. package/src/components/popover/props/default.css +4 -0
  49. package/src/components/popover/readme.md +1 -2
  50. package/src/components/popover/tooltip.css +11 -0
  51. package/src/components/tabs/index.d.ts +2 -2
  52. package/src/components/text/content.css +241 -0
  53. package/src/components/text/default.css +0 -238
  54. package/src/components/text/index.css +2 -0
  55. package/src/components/text/props/content.css +9 -0
  56. package/src/components/text/props/default.css +1 -7
  57. package/src/components/toast/default.css +6 -0
  58. package/src/components/toast/index.js +2 -1
  59. package/src/components/toaster/index.d.ts +1 -0
  60. package/src/components/toaster/index.js +18 -0
  61. package/src/components/tooltip/default.css +8 -8
  62. package/src/polyfill.js +13 -0
  63. package/src/supports.js +15 -0
  64. package/src/utilities/container/props/default.css +3 -3
  65. package/tailwindcss/utilities/animation-trigger-fallback.css +18 -0
  66. package/tailwindcss/utilities/index.css +1 -0
  67. package/tailwindcss/utilities/position.css +203 -0
  68. package/types/index.d.ts +20 -58
  69. package/src/components/dialog/index.d.ts +0 -13
@@ -1,78 +1,13 @@
1
1
  /**
2
- * @type {import("./").DefaultOptions}
2
+ * @param {HTMLInputElement} element
3
+ * @param {import("./").ToggleDetailsOptions} options
4
+ * @returns void
3
5
  */
4
- export const defaultOptions = {
5
- selector: 'details',
6
- summarySelector: 'summary',
7
- }
8
-
9
- /**
10
- * @param {HTMLInputElement | HTMLElement} element
11
- * @param {import("./").DefaultOptions} options
12
- * @returns Promise<void>
13
- */
14
- export const showDetails = async (element, options = {}) => {
15
- options = {
16
- ...defaultOptions,
17
- ...options,
18
- }
19
-
20
- const details = element.closest(options.selector)
21
- const { down } = await import('slide-element')
22
- const content = details.querySelector(options.summarySelector).nextElementSibling
23
-
24
- details._isHiding = false
25
- details.open = true
26
-
27
- await down(content, {
28
- display: '',
29
- })
30
- }
31
-
32
- /**
33
- * @param {HTMLInputElement | HTMLElement} element
34
- * @param {import("./").DefaultOptions} options
35
- * @returns Promise<void>
36
- */
37
- export const closeDetails = async (element, options = {}) => {
38
- options = {
39
- ...defaultOptions,
6
+ export const toggleDetails = (element, options = {}) => {
7
+ const { selector } = {
8
+ selector: 'details',
40
9
  ...options,
41
10
  }
42
11
 
43
- const details = element.closest(options.selector)
44
- const { up } = await import('slide-element')
45
- const content = details.querySelector(options.summarySelector).nextElementSibling
46
-
47
- details._isHiding = true
48
-
49
- await up(content, {
50
- display: '',
51
- })
52
-
53
- details._isHiding && (details.open = false)
54
- details._isHiding = false
55
- }
56
-
57
- /**
58
- * @param {HTMLInputElement | HTMLElement} element
59
- * @param {import("./").DefaultOptions} options
60
- * @returns Promise<void>
61
- */
62
- export const toggleDetails = async (element, options = {}) => {
63
- options = {
64
- ...defaultOptions,
65
- ...options,
66
- }
67
-
68
- const details = element.closest(options.selector)
69
-
70
- if (details._isHiding && !element.checked) return
71
-
72
- if (element.checked ?? !details.open) {
73
- await showDetails(element, options)
74
- }
75
- else {
76
- await closeDetails(element, options)
77
- }
12
+ element?.closest(selector)?.toggleAttribute('open', element.checked)
78
13
  }
@@ -1,8 +1,5 @@
1
1
  # [Details](https://winduum.dev/docs/components/details.html)
2
2
 
3
- ## Dependencies
4
- * [slide-element](https://www.npmjs.com/package/slide-element)
5
-
6
3
  ## Installation
7
4
  ```shell
8
5
  npm i winduum
@@ -10,7 +7,7 @@ npm i winduum
10
7
  Learn more how to set up Winduum [here](https://winduum.dev/docs/).
11
8
 
12
9
  ```js
13
- import { showDetails } from 'winduum/src/components/details/index.js'
10
+ import { toggleDetails } from 'winduum/src/components/details/index.js'
14
11
  ```
15
12
 
16
13
  ### Local imports
@@ -18,7 +15,7 @@ By default, imports are directly from `npm` so you can leverage updates.
18
15
  You can also copy and paste the code from this directory to your project and remap the imports to local.
19
16
 
20
17
  ```js
21
- import { showDetails } from '@/components/details/assets/index.js'
18
+ import { toggleDetails } from '@/components/details/assets/index.js'
22
19
  ```
23
20
 
24
21
  ### Docs
@@ -3,10 +3,16 @@
3
3
  border-radius: var(--x-dialog-content-border-radius, var(--radius-3xl));
4
4
  padding: var(--x-dialog-content-padding-block) var(--x-dialog-content-padding-inline);
5
5
  inline-size: min(100%, var(--x-dialog-content-inline-size));
6
- transition: var(--transition-transform), var(--transition-opacity);
6
+ transition: var(--transition-transform), var(--transition-opacity) allow-discrete, var(--transition-display) allow-discrete;
7
7
  margin: auto;
8
+ pointer-events: auto;
8
9
 
9
- :where(dialog[data-closed]) & {
10
+ @starting-style {
11
+ transform: translateY(-2rem);
12
+ opacity: 0%;
13
+ }
14
+
15
+ :where(dialog:not([open])) & {
10
16
  transform: translateY(-2rem);
11
17
  opacity: 0%;
12
18
  }
@@ -7,21 +7,35 @@
7
7
  var(--x-dialog-background-color) var(--x-dialog-background-color-opacity),
8
8
  var(--x-dialog-background-color-mix, transparent)
9
9
  );
10
- transition: var(--transition-background);
10
+ transition: var(--transition-background) allow-discrete, var(--transition-display) allow-discrete, var(--transition-overlay) allow-discrete;
11
11
  display: flex;
12
12
  position: fixed;
13
13
  inset: 0;
14
14
  overflow: auto;
15
15
  overscroll-behavior: contain;
16
16
  -webkit-overflow-scrolling: touch;
17
+ scrollbar-gutter: stable;
18
+
19
+ @starting-style {
20
+ background-color: transparent;
21
+ }
17
22
 
18
23
  &::backdrop,
19
24
  &:not([open]) {
20
25
  display: none;
21
26
  }
22
27
 
23
- &[data-closed] {
28
+ &:not([open]) {
24
29
  background-color: transparent;
30
+
31
+ html:not(:has(.x-dialog[open])) & {
32
+ scrollbar-gutter: auto;
33
+ scrollbar-width: none;
34
+
35
+ &::-webkit-scrollbar {
36
+ display: none;
37
+ }
38
+ }
25
39
  }
26
40
  }
27
41
 
@@ -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
+ }
@@ -2,3 +2,4 @@
2
2
  @import "./props/content.css";
3
3
  @import "./default.css";
4
4
  @import "./content.css";
5
+ @import "./drawer.css";
@@ -1,82 +1,11 @@
1
- import { animationsFinished, nextRepaint } from '../../common.js'
1
+ document.documentElement.addEventListener('click', ({ target }) => {
2
+ const closedBy = target?.getAttribute('closedby')
2
3
 
3
- /**
4
- * @type {import("./").DefaultOptions}
5
- */
6
- export const defaultOptions = {
7
- closedAttribute: 'data-closed',
8
- openAttribute: 'data-open',
9
- scrollbarWidthProperty: '--default-scrollbar-width',
10
- contentSelector: '.x-dialog-content',
11
- closable: true,
12
- modal: true,
13
- }
14
-
15
- /**
16
- * Shows a dialog.
17
- * @param {HTMLDialogElement | HTMLElement} element - The dialog element to show.
18
- * @param {import("./").DefaultOptions} options - The options for showing the dialog.
19
- * @returns Promise<void>
20
- */
21
- export const showDialog = async (element, options = {}) => {
22
- options = {
23
- ...defaultOptions,
24
- ...options,
25
- }
26
-
27
- if (options.scrollbarWidthProperty) {
28
- document.documentElement.style.setProperty(options.scrollbarWidthProperty, `${window.innerWidth - document.body.clientWidth}px`)
29
- }
30
-
31
- if (!element?._dialogHasEvents) {
32
- element.addEventListener('cancel', (e) => {
33
- e.preventDefault()
34
- options.closable && closeDialog(element, options)
35
- })
36
-
37
- element.addEventListener('click', ({ target }) => {
38
- if (target.nodeName === 'DIALOG' && options.closable) {
39
- closeDialog(element, options)
40
- }
41
- })
42
-
43
- element._dialogHasEvents = true
44
- }
45
-
46
- element.setAttribute(options.closedAttribute, '')
47
-
48
- options.modal ? element.showModal() : element.show()
49
- element.scroll(0, 0)
50
-
51
- element.removeAttribute(options.closedAttribute)
52
- await animationsFinished(element.querySelector(options.contentSelector))
53
- element.setAttribute(options.openAttribute, '')
54
-
55
- element.dispatchEvent(new CustomEvent('x-dialog:show'))
56
- }
57
-
58
- /**
59
- * Closes and dismisses a dialog.
60
- * @param {HTMLDialogElement | HTMLElement} element - The dialog element to dismiss.
61
- * @param {import("./").DefaultOptions} options - The options for closing the dialog.
62
- * @returns Promise<void>
63
- */
64
- export const closeDialog = async (element, options = {}) => {
65
- options = {
66
- ...defaultOptions,
67
- ...options,
4
+ if (target?.matches('dialog[open]') && !document.activeElement.matches('input,textarea') && closedBy && closedBy !== 'none') {
5
+ target?.close()
68
6
  }
7
+ })
69
8
 
70
- element.dispatchEvent(new CustomEvent('x-dialog:close'))
71
-
72
- element.removeAttribute(options.openAttribute)
73
- element.setAttribute(options.closedAttribute, '')
74
-
75
- await animationsFinished(element.querySelector(options.contentSelector))
76
-
77
- element.close()
78
-
79
- await nextRepaint()
80
-
81
- options.remove && element.remove()
82
- }
9
+ new ResizeObserver(() => {
10
+ document.documentElement.style.setProperty('--default-scrollbar-width', `${Math.max(0, window.innerWidth - document.body.clientWidth)}px`)
11
+ }).observe(document.body)
@@ -29,12 +29,8 @@ You can also copy and paste the code from this directory to your project and rem
29
29
  @import "@/components/dialog/assets/index.css" layer(components);
30
30
  ```
31
31
 
32
- ```js
33
- import { showDialog } from '@/components/dialog/assets/index.js'
34
- ```
35
-
36
32
  ### Docs
37
- Visit [docs](https://winduum.dev/docs/components/dialog.html) to learn more about Javascript API and see usage examples.
33
+ Visit [docs](https://winduum.dev/docs/components/dialog.html) to learn more about usage examples.
38
34
 
39
35
  ### Frameworks
40
36
  * [winduum/winduum-vue](https://github.com/winduum/winduum-vue/blob/main/src/components/dialog)
@@ -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
- display: flex;
12
- overflow: auto hidden;
13
- scrollbar-width: none;
14
- scroll-behavior: smooth;
15
- -webkit-overflow-scrolling: touch;
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
- display: none;
21
- }
22
-
23
- &::-webkit-scrollbar {
24
- display: none;
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
- &::after {
37
- min-block-size: 100dvh;
18
+ @supports not (animation-timeline: --x) {
19
+ --x-drawer-backdrop-opacity: 1;
38
20
  }
39
21
  }
40
22
  }
@@ -1,4 +1,7 @@
1
1
  @import "./props/default.css";
2
2
  @import "./props/content.css";
3
+ @import "./keyframes/default.css";
3
4
  @import "./default.css";
4
5
  @import "./content.css";
6
+ @import "./scroller.css";
7
+ @import "./noscript.css";
@@ -1,16 +1,9 @@
1
- export interface ScrollDrawerOptions {
2
- snapClass?: string
3
- opacityProperty?: string
4
- opacityRatio?: number
5
- scrollOpen?: number
6
- scrollClose?: number
7
- scrollSize?: number
8
- scrollDirection?:number
9
- }
1
+ export type DrawerPlacement = 'left' | 'right' | 'top' | 'bottom'
10
2
 
11
- export function showDrawer(element: HTMLElement | Element, distance?: number, direction?: 'left' | 'top'): void
12
- export function closeDrawer(element: HTMLElement | Element, distance?: number, direction?: 'left' | 'top'): void
13
- export function scrollInitDrawer(element: HTMLElement | Element, distance?: number, direction?: 'left' | 'top'): void
14
- export function toggleDrawerAttributes(element: HTMLDialogElement | Element, state?: 'open' | 'close', snapClass?: string): void
15
- export function scrollDrawerState(scrollState: number, scrollDirection: number): boolean
16
- export function scrollDrawer(element: HTMLDialogElement | Element, options?: ScrollDrawerOptions): void
3
+ export function isVerticalDrawer(placement: DrawerPlacement): boolean
4
+ export function scrollDrawer(element: HTMLElement | Element, placement: DrawerPlacement, reverse?: boolean, behavior?: 'auto' | 'instant'): void
5
+ export function showDrawer(element: HTMLElement | Element, placement: DrawerPlacement): Promise<void>
6
+ export function closeDrawer(element: HTMLElement | Element, placement: DrawerPlacement): void
7
+ export function drawerEvents(element: HTMLDialogElement | Element, contentElement: HTMLElement | Element, placement: DrawerPlacement, signal?: AbortSignal): void
8
+ export function drawerObserver(element: HTMLDialogElement | Element, placement: DrawerPlacement): IntersectionObserver
9
+ export function drawerProperties(element: HTMLElement | Element, placement: DrawerPlacement): ['top' | 'left', number, number]
@@ -1,85 +1,102 @@
1
+ import { supportsScrollInitialTarget } from '../../supports.js'
1
2
  import { nextRepaint } from '../../common.js'
2
3
 
3
4
  /**
4
- * @param {HTMLElement | Element} element
5
- * @param {number} distance
6
- * @param {'top' | 'left'} direction
7
- * @returns void
5
+ * @param {'left' | 'right' | 'top' | 'bottom'} placement
6
+ * @returns boolean
8
7
  */
9
- export const showDrawer = async (element, distance = 0, direction = 'left') => {
10
- element.scroll({ [direction]: distance })
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 {number} distance
16
- * @param {'top' | 'left'} direction
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 closeDrawer = (element, distance = element.scrollWidth, direction = 'left') => {
20
- element.scroll({ [direction]: distance })
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 {number} distance
26
- * @param {'top' | 'left'} direction
27
+ * @param {'left' | 'right' | 'top' | 'bottom'} placement
27
28
  * @returns void
28
29
  */
29
- export const scrollInitDrawer = async (element, distance = element.scrollWidth, direction = 'left') => {
30
- element.scroll({ [direction]: distance, behavior: 'instant' })
31
- await nextRepaint()
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 {'open' | 'close'} state
37
- * @param {string} snapClass
41
+ * @param {'left' | 'right' | 'top' | 'bottom'} placement
38
42
  * @returns void
39
43
  */
40
- export const toggleDrawerAttributes = (element, state = 'open', snapClass) => {
41
- element.classList[state === 'open' ? 'add' : 'remove'](...snapClass.split(/\s/))
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 {number} scrollState
48
- * @param {number} scrollDirection
49
- * @returns boolean
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 scrollDrawerState = (scrollState, scrollDirection) => {
52
- return scrollState ? Math.ceil(scrollDirection) >= scrollState : Math.floor(scrollDirection) <= scrollState
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 {import("./").ScrollDrawerOptions} options
58
- * @returns void
72
+ * @param {'left' | 'right' | 'top' | 'bottom'} placement
73
+ * @returns IntersectionObserver
59
74
  */
60
- export const scrollDrawer = (element, options = {}) => {
61
- options = {
62
- snapClass: 'snap-x snap-mandatory',
63
- opacityProperty: '--background-color-opacity',
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
- }
71
-
72
- element.style.setProperty(
73
- options.opacityProperty,
74
- `${Math.min(Math.abs((options.scrollDirection / options.scrollSize) - options.opacityRatio), 1)}`,
75
+ export const drawerObserver = (element, placement) => {
76
+ const visibleThreshold = 1 / (
77
+ isVerticalDrawer(placement) ? window.innerHeight : window.innerWidth
75
78
  )
76
79
 
77
- if (scrollDrawerState(options.scrollOpen, options.scrollDirection)) {
78
- toggleDrawerAttributes(element, 'open', options.snapClass)
79
- }
80
+ return new IntersectionObserver((entries) => {
81
+ if (entries.at(-1).intersectionRatio < visibleThreshold) element.close()
82
+ }, {
83
+ root: element,
84
+ threshold: [visibleThreshold, 1],
85
+ })
86
+ }
80
87
 
81
- if (scrollDrawerState(options.scrollClose, options.scrollDirection) && !element.inert) {
82
- toggleDrawerAttributes(element, 'close', options.snapClass)
83
- element.close && element.close()
84
- }
88
+ /**
89
+ * @param {HTMLElement | Element} element
90
+ * @param {'left' | 'right' | 'top' | 'bottom'} placement
91
+ * @returns {['top' | 'left', number, number]}
92
+ */
93
+ export const drawerProperties = (element, placement) => {
94
+ const [openedDistance, closedDistance] = {
95
+ left: [0, element.offsetWidth],
96
+ right: [element.offsetWidth, 0],
97
+ top: [0, element.offsetHeight],
98
+ bottom: [element.offsetHeight, 0],
99
+ }[placement]
100
+
101
+ return [isVerticalDrawer(placement) ? 'top' : 'left', openedDistance, closedDistance]
85
102
  }
@@ -0,0 +1,9 @@
1
+ @keyframes x-drawer-backdrop-opacity {
2
+ 0% {
3
+ --x-drawer-backdrop-opacity: 1;
4
+ }
5
+
6
+ 100% {
7
+ --x-drawer-backdrop-opacity: 0;
8
+ }
9
+ }
@@ -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
+ &:where(.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: 100%;
7
- --x-drawer-content-block-size: 100%;
6
+ --x-drawer-content-inline-size: 50dvw;
7
+ --x-drawer-content-block-size: 100dvh;
8
8
  }
@@ -2,3 +2,9 @@
2
2
  :host {
3
3
  --x-drawer-background-color-opacity: 75%;
4
4
  }
5
+
6
+ @property --x-drawer-backdrop-opacity {
7
+ syntax: "<number>";
8
+ inherits: true;
9
+ initial-value: 0;
10
+ }