@x33025/sveltely 0.0.12 → 0.0.14

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.
@@ -7,6 +7,7 @@
7
7
  children: Snippet;
8
8
  class?: string;
9
9
  align?: 'left' | 'right';
10
+ anchor?: 'top' | 'bottom' | 'leading' | 'trailing';
10
11
  closeOnSelect?: boolean;
11
12
  }
12
13
 
@@ -15,21 +16,51 @@
15
16
  children,
16
17
  class: className = '',
17
18
  align = 'left',
19
+ anchor = 'bottom',
18
20
  closeOnSelect = true
19
21
  }: Props = $props();
20
22
 
21
23
  let isOpen = $state(false);
22
24
  let triggerEl = $state<HTMLElement | null>(null);
23
- let menuCoords = $state({ top: 0, left: 0, width: 0 });
25
+ let menuCoords = $state({ top: 0, left: 0 });
26
+ let menuTransform = $state('none');
24
27
 
25
28
  function open() {
26
29
  if (triggerEl) {
27
30
  const rect = triggerEl.getBoundingClientRect();
28
- menuCoords = {
29
- top: rect.bottom + window.scrollY,
30
- left: align === 'left' ? rect.left + window.scrollX : rect.right + window.scrollX,
31
- width: rect.width
32
- };
31
+ const spaceAbove = rect.top;
32
+ const spaceBelow = window.innerHeight - rect.bottom;
33
+ const spaceLeft = rect.left;
34
+ const spaceRight = window.innerWidth - rect.right;
35
+ let resolvedAnchor = anchor;
36
+
37
+ if (anchor === 'bottom' && spaceBelow < spaceAbove) {
38
+ resolvedAnchor = 'top';
39
+ } else if (anchor === 'top' && spaceAbove < spaceBelow) {
40
+ resolvedAnchor = 'bottom';
41
+ } else if (anchor === 'leading' && spaceLeft < spaceRight) {
42
+ resolvedAnchor = 'trailing';
43
+ } else if (anchor === 'trailing' && spaceRight < spaceLeft) {
44
+ resolvedAnchor = 'leading';
45
+ }
46
+
47
+ if (resolvedAnchor === 'top' || resolvedAnchor === 'bottom') {
48
+ const left = align === 'left' ? rect.left + window.scrollX : rect.right + window.scrollX;
49
+ const top =
50
+ resolvedAnchor === 'bottom' ? rect.bottom + window.scrollY : rect.top + window.scrollY;
51
+ menuCoords = { top, left };
52
+ if (resolvedAnchor === 'top' && align === 'right')
53
+ menuTransform = 'translate(-100%, -100%)';
54
+ else if (resolvedAnchor === 'top') menuTransform = 'translateY(-100%)';
55
+ else if (align === 'right') menuTransform = 'translateX(-100%)';
56
+ else menuTransform = 'none';
57
+ } else if (resolvedAnchor === 'leading') {
58
+ menuCoords = { top: rect.top + window.scrollY, left: rect.left + window.scrollX };
59
+ menuTransform = 'translateX(-100%)';
60
+ } else {
61
+ menuCoords = { top: rect.top + window.scrollY, left: rect.right + window.scrollX };
62
+ menuTransform = 'none';
63
+ }
33
64
  }
34
65
  isOpen = true;
35
66
  }
@@ -60,9 +91,15 @@
60
91
 
61
92
  <svelte:window onclick={handleOutsideClick} onscroll={close} onresize={close} />
62
93
 
63
- <div class="dropdown-container relative inline-block text-left {className}">
64
- <div bind:this={triggerEl}>
65
- <button type="button" onclick={toggle} aria-expanded={isOpen} aria-haspopup="true">
94
+ <div class="dropdown-container relative w-full text-left {className}">
95
+ <div class="w-full" bind:this={triggerEl}>
96
+ <button
97
+ type="button"
98
+ class="block w-full text-left"
99
+ onclick={toggle}
100
+ aria-expanded={isOpen}
101
+ aria-haspopup="true"
102
+ >
66
103
  {@render trigger()}
67
104
  </button>
68
105
  </div>
@@ -71,9 +108,7 @@
71
108
  <div
72
109
  use:portal
73
110
  class="dropdown-menu fixed z-50 border border-gray-200 focus:outline-none"
74
- style="top: {menuCoords.top}px; {align === 'left'
75
- ? `left: ${menuCoords.left}px;`
76
- : `right: ${window.innerWidth - menuCoords.left}px;`}; border-radius: var(--dropdown-border-radius); background: var(--dropdown-background); box-shadow: var(--dropdown-shadow);"
111
+ style="top: {menuCoords.top}px; left: {menuCoords.left}px; transform: {menuTransform}; border-radius: var(--dropdown-border-radius); background: var(--dropdown-background); box-shadow: var(--dropdown-shadow);"
77
112
  role="menu"
78
113
  aria-orientation="vertical"
79
114
  tabindex="-1"
@@ -4,6 +4,7 @@ interface Props {
4
4
  children: Snippet;
5
5
  class?: string;
6
6
  align?: 'left' | 'right';
7
+ anchor?: 'top' | 'bottom' | 'leading' | 'trailing';
7
8
  closeOnSelect?: boolean;
8
9
  }
9
10
  declare const Dropdown: import("svelte").Component<Props, {}, "">;
package/dist/style.css CHANGED
@@ -233,9 +233,6 @@
233
233
  .flex {
234
234
  display: flex;
235
235
  }
236
- .inline-block {
237
- display: inline-block;
238
- }
239
236
  .size-4 {
240
237
  width: calc(var(--spacing) * 4);
241
238
  height: calc(var(--spacing) * 4);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x33025/sveltely",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",