@fiscozen/composables 0.1.7 → 0.1.8-beta.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiscozen/composables",
3
- "version": "0.1.7",
3
+ "version": "0.1.8-beta.1",
4
4
  "description": "Design System utility composables",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -25,9 +25,9 @@
25
25
  "vite": "^5.0.10",
26
26
  "vitest": "^1.2.0",
27
27
  "vue-tsc": "^1.8.25",
28
- "@fiscozen/eslint-config": "^0.1.0",
28
+ "@fiscozen/tsconfig": "^0.1.0",
29
29
  "@fiscozen/prettier-config": "^0.1.0",
30
- "@fiscozen/tsconfig": "^0.1.0"
30
+ "@fiscozen/eslint-config": "^0.1.0"
31
31
  },
32
32
  "license": "ISC",
33
33
  "scripts": {
@@ -53,14 +53,17 @@ watch(
53
53
  <div ref="opener" class="inline-flex">
54
54
  <slot name="opener" :isOpen :floating></slot>
55
55
  </div>
56
- <div
57
- ref="content"
58
- v-show="$slots.default && (!$slots.opener || ($slots.opener && isOpen))"
59
- class="bg-core-white fixed p-4 z-10"
60
- :class="contentClass"
61
- >
62
- <slot :isOpen :floating></slot>
63
- </div>
56
+ <slot name="opener-end"></slot>
57
+ <Teleport to="body">
58
+ <div
59
+ ref="content"
60
+ v-show="$slots.default && (!$slots.opener || ($slots.opener && isOpen))"
61
+ class="fz__floating__content bg-core-white fixed p-4 z-10"
62
+ :class="contentClass"
63
+ >
64
+ <slot :isOpen :floating></slot>
65
+ </div>
66
+ </Teleport>
64
67
  </div>
65
68
  </template>
66
69
 
@@ -3,7 +3,7 @@
3
3
  exports[`FzFloating > should match snapshot 1`] = `
4
4
  "<div>
5
5
  <div class="inline-flex"><button>opener</button></div>
6
- <div class="bg-core-white pb-4" style="top: 0px; left: 0px; transform: translateY(-100%) translateX(-50%); position: absolute;">
6
+ <div class="bg-core-white absolute p-4 z-10">
7
7
  <div>content</div>
8
8
  </div>
9
9
  </div>"
@@ -12,7 +12,7 @@ exports[`FzFloating > should match snapshot 1`] = `
12
12
  exports[`FzFloating > should match snapshot 2`] = `
13
13
  "<div>
14
14
  <div class="inline-flex"><button>opener</button></div>
15
- <div class="bg-core-white pb-4" style="top: 0px; left: 0px; transform: translateY(-100%) translateX(0%); position: absolute;">
15
+ <div class="bg-core-white absolute p-4 z-10">
16
16
  <div>content</div>
17
17
  </div>
18
18
  </div>"
@@ -21,7 +21,7 @@ exports[`FzFloating > should match snapshot 2`] = `
21
21
  exports[`FzFloating > should match snapshot 3`] = `
22
22
  "<div>
23
23
  <div class="inline-flex"><button>opener</button></div>
24
- <div class="bg-core-white pb-4" style="top: 0px; left: 0px; transform: translateY(-100%) translateX(-100%); position: absolute;">
24
+ <div class="bg-core-white absolute p-4 z-10">
25
25
  <div>content</div>
26
26
  </div>
27
27
  </div>"
@@ -30,7 +30,7 @@ exports[`FzFloating > should match snapshot 3`] = `
30
30
  exports[`FzFloating > should match snapshot 4`] = `
31
31
  "<div>
32
32
  <div class="inline-flex"><button>opener</button></div>
33
- <div class="bg-core-white pr-4" style="top: 0px; left: 0px; transform: translateY(-50%) translateX(-100%); position: absolute;">
33
+ <div class="bg-core-white absolute p-4 z-10">
34
34
  <div>content</div>
35
35
  </div>
36
36
  </div>"
@@ -39,7 +39,7 @@ exports[`FzFloating > should match snapshot 4`] = `
39
39
  exports[`FzFloating > should match snapshot 5`] = `
40
40
  "<div>
41
41
  <div class="inline-flex"><button>opener</button></div>
42
- <div class="bg-core-white pr-4" style="top: 0px; left: 0px; transform: translateY(0%) translateX(-100%); position: absolute;">
42
+ <div class="bg-core-white absolute p-4 z-10">
43
43
  <div>content</div>
44
44
  </div>
45
45
  </div>"
@@ -48,7 +48,7 @@ exports[`FzFloating > should match snapshot 5`] = `
48
48
  exports[`FzFloating > should match snapshot 6`] = `
49
49
  "<div>
50
50
  <div class="inline-flex"><button>opener</button></div>
51
- <div class="bg-core-white pr-4" style="top: 0px; left: 0px; transform: translateY(-100%) translateX(-100%); position: absolute;">
51
+ <div class="bg-core-white absolute p-4 z-10">
52
52
  <div>content</div>
53
53
  </div>
54
54
  </div>"
@@ -57,7 +57,7 @@ exports[`FzFloating > should match snapshot 6`] = `
57
57
  exports[`FzFloating > should match snapshot 7`] = `
58
58
  "<div>
59
59
  <div class="inline-flex"><button>opener</button></div>
60
- <div class="bg-core-white pt-4" style="top: 0px; left: 0px; transform: translateY(0%) translateX(-50%); position: absolute;">
60
+ <div class="bg-core-white absolute p-4 z-10">
61
61
  <div>content</div>
62
62
  </div>
63
63
  </div>"
@@ -66,7 +66,7 @@ exports[`FzFloating > should match snapshot 7`] = `
66
66
  exports[`FzFloating > should match snapshot 8`] = `
67
67
  "<div>
68
68
  <div class="inline-flex"><button>opener</button></div>
69
- <div class="bg-core-white pt-4" style="top: 0px; left: 0px; transform: translateY(0%) translateX(0%); position: absolute;">
69
+ <div class="bg-core-white absolute p-4 z-10">
70
70
  <div>content</div>
71
71
  </div>
72
72
  </div>"
@@ -75,7 +75,7 @@ exports[`FzFloating > should match snapshot 8`] = `
75
75
  exports[`FzFloating > should match snapshot 9`] = `
76
76
  "<div>
77
77
  <div class="inline-flex"><button>opener</button></div>
78
- <div class="bg-core-white pt-4" style="top: 0px; left: 0px; transform: translateY(0%) translateX(-100%); position: absolute;">
78
+ <div class="bg-core-white absolute p-4 z-10">
79
79
  <div>content</div>
80
80
  </div>
81
81
  </div>"
@@ -84,7 +84,7 @@ exports[`FzFloating > should match snapshot 9`] = `
84
84
  exports[`FzFloating > should match snapshot 10`] = `
85
85
  "<div>
86
86
  <div class="inline-flex"><button>opener</button></div>
87
- <div class="bg-core-white pl-4" style="top: 0px; left: 0px; transform: translateY(-50%) translateX(0%); position: absolute;">
87
+ <div class="bg-core-white absolute p-4 z-10">
88
88
  <div>content</div>
89
89
  </div>
90
90
  </div>"
@@ -93,7 +93,7 @@ exports[`FzFloating > should match snapshot 10`] = `
93
93
  exports[`FzFloating > should match snapshot 11`] = `
94
94
  "<div>
95
95
  <div class="inline-flex"><button>opener</button></div>
96
- <div class="bg-core-white pl-4" style="top: 0px; left: 0px; transform: translateY(0%) translateX(0%); position: absolute;">
96
+ <div class="bg-core-white absolute p-4 z-10">
97
97
  <div>content</div>
98
98
  </div>
99
99
  </div>"
@@ -102,7 +102,7 @@ exports[`FzFloating > should match snapshot 11`] = `
102
102
  exports[`FzFloating > should match snapshot 12`] = `
103
103
  "<div>
104
104
  <div class="inline-flex"><button>opener</button></div>
105
- <div class="bg-core-white pl-4" style="top: 0px; left: 0px; transform: translateY(-100%) translateX(0%); position: absolute;">
105
+ <div class="bg-core-white absolute p-4 z-10">
106
106
  <div>content</div>
107
107
  </div>
108
108
  </div>"
@@ -1,3 +1,4 @@
1
1
  export * from './useFloating'
2
2
  export * from './useMediaQuery'
3
3
  export * from './useBreakpoints'
4
+ export * from './useClickOutside'
@@ -0,0 +1,35 @@
1
+ import { onBeforeUnmount, onMounted, Ref } from 'vue'
2
+
3
+ function useClickOutside(component: Ref<HTMLElement | undefined>, callback: () => void) {
4
+ // fail early if any of the required params is missing
5
+ if (!component) {
6
+ throw new Error('A target component has to be provided.')
7
+ }
8
+
9
+ if (!callback) {
10
+ throw new Error('A callback has to be provided.')
11
+ }
12
+
13
+ const listener = (event: MouseEvent) => {
14
+ if (
15
+ !component.value ||
16
+ event.target === component.value ||
17
+ event.composedPath().includes(component.value)
18
+ ) {
19
+ return
20
+ }
21
+ if (typeof callback === 'function') {
22
+ callback()
23
+ }
24
+ }
25
+
26
+ onMounted(() => {
27
+ window.addEventListener('click', listener)
28
+ })
29
+
30
+ onBeforeUnmount(() => {
31
+ window.removeEventListener('click', listener)
32
+ })
33
+ }
34
+
35
+ export { useClickOutside }
@@ -61,6 +61,8 @@ export const useFloating = (
61
61
  rect.value = safeElementDomRef.value.getBoundingClientRect()
62
62
  const openerRect = safeOpenerDomRef.value?.getBoundingClientRect()
63
63
  const containerRect = safeContainerDomRef.value.getBoundingClientRect()
64
+
65
+ const elStyle = window.getComputedStyle(safeElementDomRef.value);
64
66
 
65
67
  // multiple observer calls on same target do not cause multiple registrations
66
68
  floatObserver.value.observe(safeElementDomRef.value)
@@ -72,6 +74,12 @@ export const useFloating = (
72
74
  let translateX = 0
73
75
 
74
76
  if (args.opener && safeOpenerDomRef.value && openerRect) {
77
+
78
+ const leftWithoutXMargin = openerRect.left - parseFloat(elStyle.marginLeft) - parseFloat(elStyle.marginRight);
79
+ const leftWithoutLeftMargin = openerRect.left - parseFloat(elStyle.marginLeft);
80
+ const topWithoutYMargin = openerRect.top - parseFloat(elStyle.marginTop) - parseFloat(elStyle.marginBottom);
81
+ const topWithoutTopMargin = openerRect.top - parseFloat(elStyle.marginTop);
82
+
75
83
  switch (position) {
76
84
  case 'auto':
77
85
  position = getHighestAvailableSpacePos(
@@ -102,13 +110,13 @@ export const useFloating = (
102
110
  switch (position) {
103
111
  case 'bottom':
104
112
  float.position.y = openerRect.bottom
105
- float.position.x = openerRect.left + openerRect.width / 2
113
+ float.position.x = leftWithoutLeftMargin + openerRect.width / 2
106
114
  translateX = -50
107
115
  translateY = 0
108
116
  break
109
117
  case 'bottom-start':
110
118
  float.position.y = openerRect.bottom
111
- float.position.x = openerRect.left
119
+ float.position.x = leftWithoutXMargin
112
120
  translateX = 0
113
121
  translateY = 0
114
122
  break
@@ -119,49 +127,49 @@ export const useFloating = (
119
127
  translateY = 0
120
128
  break
121
129
  case 'left-start':
122
- float.position.y = openerRect.top
123
- float.position.x = openerRect.left
130
+ float.position.y = topWithoutYMargin
131
+ float.position.x = leftWithoutXMargin
124
132
  translateX = -100
125
133
  translateY = 0
126
134
  break
127
135
  case 'left':
128
- float.position.y = openerRect.top + openerRect.height / 2
129
- float.position.x = openerRect.left
136
+ float.position.y = topWithoutTopMargin + openerRect.height / 2
137
+ float.position.x = leftWithoutXMargin
130
138
  translateY = -50
131
139
  translateX = -100
132
140
  break
133
141
  case 'left-end':
134
142
  float.position.y = openerRect.bottom
135
- float.position.x = openerRect.left
143
+ float.position.x = leftWithoutXMargin
136
144
  translateY = -100
137
145
  translateX = -100
138
146
  break
139
147
  case 'top-start':
140
- float.position.y = openerRect.top
141
- float.position.x = openerRect.left
148
+ float.position.y = topWithoutYMargin
149
+ float.position.x = leftWithoutXMargin
142
150
  translateY = -100
143
151
  translateX = 0
144
152
  break
145
153
  case 'top':
146
- float.position.y = openerRect.top
147
- float.position.x = openerRect.left + openerRect.width / 2
154
+ float.position.y = topWithoutYMargin
155
+ float.position.x = leftWithoutLeftMargin + openerRect.width / 2
148
156
  translateX = -50
149
157
  translateY = -100
150
158
  break
151
159
  case 'top-end':
152
- float.position.y = openerRect.top
160
+ float.position.y = topWithoutYMargin
153
161
  float.position.x = openerRect.right
154
162
  translateX = -100
155
163
  translateY = -100
156
164
  break
157
165
  case 'right-start':
158
- float.position.y = openerRect.top
166
+ float.position.y = topWithoutYMargin
159
167
  float.position.x = openerRect.right
160
168
  translateX = 0
161
169
  translateY = 0
162
170
  break
163
171
  case 'right':
164
- float.position.y = openerRect.top + openerRect.height / 2
172
+ float.position.y = topWithoutTopMargin + openerRect.height / 2
165
173
  float.position.x = openerRect.right
166
174
  translateY = -50
167
175
  translateX = 0
@@ -220,7 +228,7 @@ export const useFloating = (
220
228
 
221
229
  const realPos = calcRealPos(rect.value, float.position, translateX, translateY)
222
230
 
223
- float.position.x = realPos.x
231
+ float.position.x = realPos.x
224
232
  float.position.y = realPos.y
225
233
 
226
234
  if (realPos.x < containerRect.left) {
package/src/types.ts CHANGED
@@ -9,6 +9,7 @@ export interface FzFloatingProps {
9
9
  position?: FzFloatingPosition
10
10
  container?: string | null
11
11
  contentClass?: string | string[] | Record<string, boolean|undefined> | Array<string|Record<string,boolean|undefined>>
12
+ openerClass?: string | string[] | Record<string, boolean|undefined> | Array<string|Record<string,boolean|undefined>>
12
13
  }
13
14
 
14
15
  export interface FzAbsolutePosition {