v-float 0.10.0 → 0.11.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 +44 -175
- package/dist/index.d.mts +688 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2038 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +74 -75
- package/dist/composables/index.d.ts +0 -4
- package/dist/composables/index.d.ts.map +0 -1
- package/dist/composables/interactions/index.d.ts +0 -7
- package/dist/composables/interactions/index.d.ts.map +0 -1
- package/dist/composables/interactions/polygon.d.ts +0 -38
- package/dist/composables/interactions/polygon.d.ts.map +0 -1
- package/dist/composables/interactions/use-click.d.ts +0 -120
- package/dist/composables/interactions/use-click.d.ts.map +0 -1
- package/dist/composables/interactions/use-escape-key.d.ts +0 -57
- package/dist/composables/interactions/use-escape-key.d.ts.map +0 -1
- package/dist/composables/interactions/use-focus-trap.d.ts +0 -78
- package/dist/composables/interactions/use-focus-trap.d.ts.map +0 -1
- package/dist/composables/interactions/use-focus.d.ts +0 -60
- package/dist/composables/interactions/use-focus.d.ts.map +0 -1
- package/dist/composables/interactions/use-hover.d.ts +0 -78
- package/dist/composables/interactions/use-hover.d.ts.map +0 -1
- package/dist/composables/interactions/use-list-navigation.d.ts +0 -144
- package/dist/composables/interactions/use-list-navigation.d.ts.map +0 -1
- package/dist/composables/middlewares/arrow.d.ts +0 -25
- package/dist/composables/middlewares/arrow.d.ts.map +0 -1
- package/dist/composables/middlewares/index.d.ts +0 -4
- package/dist/composables/middlewares/index.d.ts.map +0 -1
- package/dist/composables/positioning/index.d.ts +0 -5
- package/dist/composables/positioning/index.d.ts.map +0 -1
- package/dist/composables/positioning/use-arrow.d.ts +0 -55
- package/dist/composables/positioning/use-arrow.d.ts.map +0 -1
- package/dist/composables/positioning/use-client-point.d.ts +0 -218
- package/dist/composables/positioning/use-client-point.d.ts.map +0 -1
- package/dist/composables/positioning/use-floating-tree.d.ts +0 -240
- package/dist/composables/positioning/use-floating-tree.d.ts.map +0 -1
- package/dist/composables/positioning/use-floating.d.ts +0 -162
- package/dist/composables/positioning/use-floating.d.ts.map +0 -1
- package/dist/composables/utils/is-using-keyboard.d.ts +0 -2
- package/dist/composables/utils/is-using-keyboard.d.ts.map +0 -1
- package/dist/composables/utils/use-active-descendant.d.ts +0 -8
- package/dist/composables/utils/use-active-descendant.d.ts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/types.d.ts +0 -18
- package/dist/types.d.ts.map +0 -1
- package/dist/utils.d.ts +0 -92
- package/dist/utils.d.ts.map +0 -1
- package/dist/v-float.es.js +0 -3827
- package/dist/v-float.umd.js +0 -8
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# V-Float
|
|
2
2
|
|
|
3
|
-
[
|
|
3
|
+
[status: WIP](#project-status)
|
|
4
4
|
|
|
5
5
|
> Work in progress: This library is under active development. APIs may change without notice and breaking changes can land without deprecation windows or warnings. Not recommended for production use yet.
|
|
6
6
|
|
|
@@ -12,7 +12,6 @@ of [@floating-ui/dom](https://floating-ui.com/) with Vue 3 Composition API.
|
|
|
12
12
|
- **Precise Positioning**: Pixel-perfect positioning with automatic collision detection
|
|
13
13
|
- **Vue 3 Composables**: Reactive composables designed for the Composition API
|
|
14
14
|
- **Interaction Handling**: Built-in hover, focus, click, and dismiss behaviors
|
|
15
|
-
- **Nested Elements**: Support for floating element trees and hierarchies
|
|
16
15
|
- **Arrow Positioning**: `useArrow` composable for positioning arrow elements
|
|
17
16
|
- **Lightweight**: Tree-shakable with minimal bundle impact
|
|
18
17
|
- **Cross-platform**: Works on desktop, mobile, and touch devices
|
|
@@ -37,24 +36,24 @@ yarn add v-float
|
|
|
37
36
|
|
|
38
37
|
```vue
|
|
39
38
|
<script setup lang="ts">
|
|
40
|
-
import { useTemplateRef } from "vue"
|
|
41
|
-
import { useFloating, useHover, offset } from "v-float"
|
|
39
|
+
import { useTemplateRef } from "vue";
|
|
40
|
+
import { useFloating, useHover, offset } from "v-float";
|
|
42
41
|
|
|
43
|
-
const anchorEl = useTemplateRef("anchorEl")
|
|
44
|
-
const floatingEl = useTemplateRef("floatingEl")
|
|
42
|
+
const anchorEl = useTemplateRef("anchorEl");
|
|
43
|
+
const floatingEl = useTemplateRef("floatingEl");
|
|
45
44
|
|
|
46
45
|
const context = useFloating(anchorEl, floatingEl, {
|
|
47
46
|
placement: "top",
|
|
48
47
|
middlewares: [offset(8)],
|
|
49
|
-
})
|
|
48
|
+
});
|
|
50
49
|
|
|
51
|
-
useHover(context)
|
|
50
|
+
useHover(context);
|
|
52
51
|
</script>
|
|
53
52
|
|
|
54
53
|
<template>
|
|
55
54
|
<button ref="anchorEl">Hover me</button>
|
|
56
55
|
|
|
57
|
-
<div v-if="context.open.value" ref="floatingEl" :style="context.
|
|
56
|
+
<div v-if="context.state.open.value" ref="floatingEl" :style="context.position.styles.value">
|
|
58
57
|
This is a tooltip
|
|
59
58
|
</div>
|
|
60
59
|
</template>
|
|
@@ -64,27 +63,27 @@ useHover(context)
|
|
|
64
63
|
|
|
65
64
|
```vue
|
|
66
65
|
<script setup lang="ts">
|
|
67
|
-
import { useTemplateRef } from "vue"
|
|
68
|
-
import { useFloating, useClick, useEscapeKey, offset, flip, shift } from "v-float"
|
|
66
|
+
import { useTemplateRef } from "vue";
|
|
67
|
+
import { useFloating, useClick, useEscapeKey, offset, flip, shift } from "v-float";
|
|
69
68
|
|
|
70
|
-
const triggerEl = useTemplateRef("triggerEl")
|
|
71
|
-
const menuEl = useTemplateRef("menuEl")
|
|
69
|
+
const triggerEl = useTemplateRef("triggerEl");
|
|
70
|
+
const menuEl = useTemplateRef("menuEl");
|
|
72
71
|
|
|
73
72
|
const context = useFloating(triggerEl, menuEl, {
|
|
74
73
|
placement: "bottom-start",
|
|
75
74
|
middlewares: [offset(4), flip(), shift({ padding: 8 })],
|
|
76
|
-
})
|
|
75
|
+
});
|
|
77
76
|
|
|
78
|
-
useClick(context)
|
|
79
|
-
useEscapeKey({
|
|
77
|
+
useClick(context);
|
|
78
|
+
useEscapeKey(context, {
|
|
80
79
|
onEscape: () => context.setOpen(false),
|
|
81
|
-
})
|
|
80
|
+
});
|
|
82
81
|
</script>
|
|
83
82
|
|
|
84
83
|
<template>
|
|
85
84
|
<button ref="triggerEl">Open Menu</button>
|
|
86
85
|
|
|
87
|
-
<div v-if="context.open.value" ref="menuEl" :style="context.
|
|
86
|
+
<div v-if="context.state.open.value" ref="menuEl" :style="context.position.styles.value">
|
|
88
87
|
<div>Menu Item 1</div>
|
|
89
88
|
<div>Menu Item 2</div>
|
|
90
89
|
<div>Menu Item 3</div>
|
|
@@ -96,33 +95,33 @@ useEscapeKey({
|
|
|
96
95
|
|
|
97
96
|
```vue
|
|
98
97
|
<script setup lang="ts">
|
|
99
|
-
import { useTemplateRef } from "vue"
|
|
100
|
-
import { useFloating, useHover, useArrow, offset, flip } from "v-float"
|
|
98
|
+
import { useTemplateRef } from "vue";
|
|
99
|
+
import { useFloating, useHover, useArrow, offset, flip } from "v-float";
|
|
101
100
|
|
|
102
|
-
const anchorEl = useTemplateRef("anchorEl")
|
|
103
|
-
const tooltipEl = useTemplateRef("tooltipEl")
|
|
104
|
-
const arrowEl = useTemplateRef("arrowEl")
|
|
101
|
+
const anchorEl = useTemplateRef("anchorEl");
|
|
102
|
+
const tooltipEl = useTemplateRef("tooltipEl");
|
|
103
|
+
const arrowEl = useTemplateRef("arrowEl");
|
|
105
104
|
|
|
106
105
|
const context = useFloating(anchorEl, tooltipEl, {
|
|
107
106
|
placement: "top",
|
|
108
107
|
middlewares: [offset(8), flip()],
|
|
109
|
-
})
|
|
108
|
+
});
|
|
110
109
|
|
|
111
|
-
useHover(context)
|
|
110
|
+
useHover(context);
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
const { arrowStyles } = useArrow(context, {
|
|
113
|
+
element: arrowEl,
|
|
115
114
|
offset: "-4px",
|
|
116
|
-
})
|
|
115
|
+
});
|
|
117
116
|
</script>
|
|
118
117
|
|
|
119
118
|
<template>
|
|
120
119
|
<button ref="anchorEl">Hover me</button>
|
|
121
120
|
|
|
122
121
|
<div
|
|
123
|
-
v-if="context.open.value"
|
|
122
|
+
v-if="context.state.open.value"
|
|
124
123
|
ref="tooltipEl"
|
|
125
|
-
:style="context.
|
|
124
|
+
:style="context.position.styles.value"
|
|
126
125
|
class="tooltip"
|
|
127
126
|
>
|
|
128
127
|
This is a tooltip with an arrow
|
|
@@ -155,30 +154,29 @@ const { arrowStyles } = useArrow(arrowEl, context, {
|
|
|
155
154
|
|
|
156
155
|
### Positioning
|
|
157
156
|
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
- **`useFloatingTree`**: Manage nested floating element hierarchies
|
|
157
|
+
- `**useFloating**`: Core positioning logic with middleware support
|
|
158
|
+
- `**useArrow**`: Position arrow elements pointing to the anchor
|
|
161
159
|
|
|
162
160
|
### Interactions
|
|
163
161
|
|
|
164
|
-
-
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
-
|
|
168
|
-
-
|
|
162
|
+
- `**useHover**`: Hover interactions with configurable delays
|
|
163
|
+
- `**useFocus**`: Focus/blur event handling for keyboard navigation
|
|
164
|
+
- `**useClick**`: Click event handling with toggle and dismiss options
|
|
165
|
+
- `**useEscapeKey**`: Close on ESC key press with composition handling
|
|
166
|
+
- `**useClientPoint**`: Position floating elements at cursor/touch coordinates
|
|
169
167
|
|
|
170
168
|
### Middleware
|
|
171
169
|
|
|
172
170
|
All [Floating UI middleware](https://floating-ui.com/docs/middleware) are supported:
|
|
173
171
|
|
|
174
|
-
-
|
|
175
|
-
-
|
|
176
|
-
-
|
|
177
|
-
-
|
|
178
|
-
-
|
|
179
|
-
-
|
|
172
|
+
- `**offset**`: Add distance between anchor and floating element
|
|
173
|
+
- `**flip**`: Flip placement when there's insufficient space
|
|
174
|
+
- `**shift**`: Shift floating element to stay in view
|
|
175
|
+
- `**hide**`: Hide floating element when anchor is not visible
|
|
176
|
+
- `**autoPlacement**`: Automatically choose the best placement
|
|
177
|
+
- `**size**`: Resize floating element to fit within viewport
|
|
180
178
|
|
|
181
|
-
**Arrow positioning** is handled by the [
|
|
179
|
+
**Arrow positioning** is handled by the `[useArrow](/api/use-arrow)` composable, which owns arrow registration for the floating context.
|
|
182
180
|
|
|
183
181
|
## Project Status
|
|
184
182
|
|
|
@@ -186,135 +184,6 @@ All [Floating UI middleware](https://floating-ui.com/docs/middleware) are suppor
|
|
|
186
184
|
- API, docs, and examples are subject to change and may be incomplete.
|
|
187
185
|
- Feedback and contributions are welcome while the API stabilizes.
|
|
188
186
|
|
|
189
|
-
## Advanced Features
|
|
190
|
-
|
|
191
|
-
### Floating Trees
|
|
192
|
-
|
|
193
|
-
For nested floating elements like submenus, use `useFloatingTree` to manage hierarchical structures with a streamlined API that eliminates redundant `useFloating` calls.
|
|
194
|
-
|
|
195
|
-
**Clear Separation of Concerns:**
|
|
196
|
-
|
|
197
|
-
- Use `useFloating` for isolated floating elements
|
|
198
|
-
- Use `useFloatingTree` for hierarchical structures
|
|
199
|
-
|
|
200
|
-
Here's how you can set up a parent menu with a submenu using the new API:
|
|
201
|
-
|
|
202
|
-
```vue
|
|
203
|
-
<script setup lang="ts">
|
|
204
|
-
import { useTemplateRef, ref } from "vue"
|
|
205
|
-
import { useFloatingTree, useHover, useClick, offset, flip, shift } from "v-float"
|
|
206
|
-
|
|
207
|
-
const parentTriggerEl = useTemplateRef("parentTriggerRef")
|
|
208
|
-
const parentMenuEl = useTemplateRef("parentMenuRef")
|
|
209
|
-
const isParentOpen = ref(false)
|
|
210
|
-
|
|
211
|
-
const submenuTriggerEl = useTemplateRef("submenuTriggerRef")
|
|
212
|
-
const submenuEl = useTemplateRef("submenuRef")
|
|
213
|
-
const isSubmenuOpen = ref(false)
|
|
214
|
-
|
|
215
|
-
// 1. Create the floating tree with root context automatically
|
|
216
|
-
const tree = useFloatingTree(parentTriggerEl, parentMenuEl, {
|
|
217
|
-
placement: "bottom-start",
|
|
218
|
-
open: isParentOpen,
|
|
219
|
-
middlewares: [offset(4), flip(), shift({ padding: 8 })],
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
// 2. Add submenu node - no separate useFloating call needed!
|
|
223
|
-
const submenuNode = tree.addNode(submenuTriggerEl, submenuEl, {
|
|
224
|
-
placement: "right-start",
|
|
225
|
-
open: isSubmenuOpen,
|
|
226
|
-
middlewares: [offset(4), flip(), shift({ padding: 8 })],
|
|
227
|
-
parentId: tree.root.id, // Link to parent using parentId in options
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
// 3. Add interactions
|
|
231
|
-
useClick(tree.root, { outsideClick: true })
|
|
232
|
-
useHover(submenuNode, { delay: { open: 100, close: 300 } })
|
|
233
|
-
|
|
234
|
-
// Access floating styles from the contexts
|
|
235
|
-
const { floatingStyles: parentStyles } = tree.rootContext
|
|
236
|
-
const { floatingStyles: submenuStyles } = submenuNode.data
|
|
237
|
-
</script>
|
|
238
|
-
|
|
239
|
-
<template>
|
|
240
|
-
<!-- Parent Menu Trigger -->
|
|
241
|
-
<button ref="parentTriggerEl" @click="isParentOpen = !isParentOpen">Open Menu</button>
|
|
242
|
-
|
|
243
|
-
<!-- Parent Menu -->
|
|
244
|
-
<div v-if="isParentOpen" ref="parentMenuEl" :style="parentStyles" class="menu">
|
|
245
|
-
<div class="menu-item">Menu Item 1</div>
|
|
246
|
-
|
|
247
|
-
<!-- Submenu Trigger -->
|
|
248
|
-
<div
|
|
249
|
-
ref="submenuTriggerEl"
|
|
250
|
-
class="menu-item menu-item--submenu"
|
|
251
|
-
@click="isSubmenuOpen = !isSubmenuOpen"
|
|
252
|
-
>
|
|
253
|
-
Menu Item 2 (Has Submenu)
|
|
254
|
-
|
|
255
|
-
<!-- Submenu -->
|
|
256
|
-
<div v-if="isSubmenuOpen" ref="submenuEl" :style="submenuStyles" class="menu submenu">
|
|
257
|
-
<div class="menu-item">Submenu Item A</div>
|
|
258
|
-
<div class="menu-item">Submenu Item B</div>
|
|
259
|
-
<div class="menu-item">Submenu Item C</div>
|
|
260
|
-
</div>
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
<div class="menu-item">Menu Item 3</div>
|
|
264
|
-
</div>
|
|
265
|
-
</template>
|
|
266
|
-
|
|
267
|
-
<style scoped>
|
|
268
|
-
.menu {
|
|
269
|
-
background: white;
|
|
270
|
-
border: 1px solid #ddd;
|
|
271
|
-
border-radius: 4px;
|
|
272
|
-
padding: 4px 0;
|
|
273
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
274
|
-
min-width: 160px;
|
|
275
|
-
z-index: 1000;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
.submenu {
|
|
279
|
-
margin-left: 8px;
|
|
280
|
-
z-index: 1010;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
.menu-item {
|
|
284
|
-
padding: 8px 12px;
|
|
285
|
-
cursor: pointer;
|
|
286
|
-
user-select: none;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
.menu-item:hover {
|
|
290
|
-
background-color: #f5f5f5;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.menu-item--submenu {
|
|
294
|
-
position: relative;
|
|
295
|
-
}
|
|
296
|
-
</style>
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
**API Benefits:**
|
|
300
|
-
|
|
301
|
-
```ts
|
|
302
|
-
// Before: Required separate useFloating calls
|
|
303
|
-
const parentContext = useFloating(parentEl, parentFloating, options)
|
|
304
|
-
const tree = useFloatingTree(parentContext)
|
|
305
|
-
const childContext = useFloating(childEl, childFloating, childOptions)
|
|
306
|
-
const childNode = tree.addNode(childContext, parentContext.nodeId)
|
|
307
|
-
|
|
308
|
-
// After: Streamlined API with internal context creation
|
|
309
|
-
const tree = useFloatingTree(parentEl, parentFloating, options)
|
|
310
|
-
const childNode = tree.addNode(childEl, childFloating, {
|
|
311
|
-
...childOptions,
|
|
312
|
-
parentId: tree.root.id,
|
|
313
|
-
})
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
This approach eliminates redundant calls and provides a clearer separation between isolated floating elements (`useFloating`) and hierarchical structures (`useFloatingTree`).
|
|
317
|
-
|
|
318
187
|
## TypeScript Support
|
|
319
188
|
|
|
320
189
|
V-Float is built with TypeScript and provides comprehensive type definitions:
|
|
@@ -322,7 +191,7 @@ V-Float is built with TypeScript and provides comprehensive type definitions:
|
|
|
322
191
|
## Browser Support
|
|
323
192
|
|
|
324
193
|
- **Modern browsers**: Chrome, Firefox, Safari, Edge
|
|
325
|
-
- **Mobile browsers**: iOS Safari, Chrome Mobile
|
|
194
|
+
- **Mobile browsers**: iOS Safari, Chrome Mobile
|
|
326
195
|
- **Node.js**: SSR compatible (with proper hydration)
|
|
327
196
|
|
|
328
197
|
## Documentation
|