sb-floating-panel-vue 0.1.5
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
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# sb-floating-panel-vue
|
|
2
|
+
[](https://www.npmjs.com/package/sb-floating-panel-vue)
|
|
3
|
+
[](https://github.com/stefanobiddau/sb-floating-panel-vue/blob/main/LICENSE)
|
|
4
|
+
|
|
5
|
+
> A lightweight Vue 3 composable hook built on top of [@floating-ui/vue](https://github.com/floating-ui/floating-ui) to manage floating panels with arrow and resize support.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## β¨ Features
|
|
10
|
+
|
|
11
|
+
- π¦ Minimal and composable API
|
|
12
|
+
- π― Precise floating panel positioning via `@floating-ui/vue`
|
|
13
|
+
- π Optional arrow positioning
|
|
14
|
+
- π Auto-resize support
|
|
15
|
+
- π§ TypeScript-first
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## π Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install sb-floating-panel-vue
|
|
23
|
+
# or
|
|
24
|
+
yarn add sb-floating-panel-vue
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## π§© Usage
|
|
30
|
+
|
|
31
|
+
The `useSbFloatingPanel` composable provides an easy-to-integrate API to handle floating panels, such as tooltips, popovers, dropdowns, and other UI overlays.
|
|
32
|
+
|
|
33
|
+
### Importing
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { useSbFloatingPanel } from 'sb-floating-panel-vue';
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### π§ API
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
const {
|
|
43
|
+
reference,
|
|
44
|
+
floating,
|
|
45
|
+
popperArrow,
|
|
46
|
+
isOpen,
|
|
47
|
+
floatingPosition,
|
|
48
|
+
floatingStyles,
|
|
49
|
+
floatingArrowStyles,
|
|
50
|
+
changeFloatingVisibility,
|
|
51
|
+
} = useSbFloatingPanel(settings);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Parameters
|
|
55
|
+
|
|
56
|
+
The composable takes a `settings` object:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
interface FloatingSettings {
|
|
60
|
+
placement: Placement; // e.g., 'bottom', 'top-start', etc.
|
|
61
|
+
strategy: Strategy; // 'absolute' | 'fixed'
|
|
62
|
+
offsetValue: number; // offset in pixels from the reference element
|
|
63
|
+
hasArrow?: boolean; // enable arrow positioning
|
|
64
|
+
hasResize?: boolean; // enable auto-resizing with anchor element
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## π Computed Values Explained
|
|
71
|
+
|
|
72
|
+
### `floatingStyles`
|
|
73
|
+
|
|
74
|
+
A Vue `computed` value containing the CSS style object that must be applied to your floating panel. It is dynamically calculated by `@floating-ui/vue` to maintain optimal placement relative to the reference element.
|
|
75
|
+
|
|
76
|
+
### `floatingPosition`
|
|
77
|
+
|
|
78
|
+
The actual resolved placement string, e.g., `'bottom-start'`, useful for adding custom animations or behavior depending on where the panel is placed.
|
|
79
|
+
|
|
80
|
+
### `floatingArrowStyles`
|
|
81
|
+
|
|
82
|
+
An object that includes styles for positioning the optional arrow element (enabled via the `hasArrow` setting). You can directly bind this to the arrowβs `style` attribute.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## π§ͺ Example
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
<script setup lang="ts">
|
|
90
|
+
import { ref } from 'vue';
|
|
91
|
+
import { useSbFloatingPanel } from 'sb-floating-panel-vue';
|
|
92
|
+
|
|
93
|
+
const {
|
|
94
|
+
reference,
|
|
95
|
+
floating,
|
|
96
|
+
popperArrow,
|
|
97
|
+
isOpen,
|
|
98
|
+
floatingStyles,
|
|
99
|
+
floatingArrowStyles,
|
|
100
|
+
changeFloatingVisibility,
|
|
101
|
+
} = useSbFloatingPanel({
|
|
102
|
+
placement: 'bottom',
|
|
103
|
+
strategy: 'absolute',
|
|
104
|
+
offsetValue: 8,
|
|
105
|
+
hasArrow: true,
|
|
106
|
+
hasResize: true,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const togglePanel = () => {
|
|
110
|
+
changeFloatingVisibility(!isOpen.value);
|
|
111
|
+
};
|
|
112
|
+
</script>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```vue
|
|
116
|
+
<template>
|
|
117
|
+
<button ref="reference" @click="togglePanel">Toggle Panel</button>
|
|
118
|
+
<div
|
|
119
|
+
v-if="isOpen"
|
|
120
|
+
ref="floating"
|
|
121
|
+
:style="floatingStyles"
|
|
122
|
+
class="popover"
|
|
123
|
+
>
|
|
124
|
+
I'm a floating panel!
|
|
125
|
+
<div ref="popperArrow" :style="floatingArrowStyles.arrow" class="arrow" />
|
|
126
|
+
</div>
|
|
127
|
+
</template>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## π¨ Styling
|
|
133
|
+
|
|
134
|
+
You can use your own CSS or utility classes (like Tailwind CSS) to style the panel and the arrow. Example:
|
|
135
|
+
|
|
136
|
+
```css
|
|
137
|
+
.popover {
|
|
138
|
+
background: white;
|
|
139
|
+
border: 1px solid #ccc;
|
|
140
|
+
padding: 0.75rem;
|
|
141
|
+
border-radius: 0.5rem;
|
|
142
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.arrow {
|
|
146
|
+
width: 10px;
|
|
147
|
+
height: 10px;
|
|
148
|
+
background: white;
|
|
149
|
+
transform: rotate(45deg);
|
|
150
|
+
position: absolute;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## π License
|
|
157
|
+
|
|
158
|
+
MIT Β© [Stefano Biddau](https://github.com/stefanobiddau)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useSbFloatingPanel } from './use-sb-floating-panel/useSbFloatingPanel';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useFloating as m, autoUpdate as d, offset as w, flip as b, shift as y, arrow as z } from "@floating-ui/vue";
|
|
2
|
+
import { ref as t, watch as f, onMounted as O, onUnmounted as R, nextTick as g } from "vue";
|
|
3
|
+
function F(a) {
|
|
4
|
+
const l = t(null), n = t(null), u = t(null), r = t(!1), o = t(null);
|
|
5
|
+
let i = !1;
|
|
6
|
+
const { floatingStyles: c, placement: v, middlewareData: p } = m(l, n, {
|
|
7
|
+
open: r,
|
|
8
|
+
placement: a.placement,
|
|
9
|
+
strategy: a.strategy,
|
|
10
|
+
transform: !1,
|
|
11
|
+
middleware: [
|
|
12
|
+
w(a.offsetValue),
|
|
13
|
+
b(),
|
|
14
|
+
y(),
|
|
15
|
+
...a.hasArrow ? [z({ element: u })] : []
|
|
16
|
+
],
|
|
17
|
+
whileElementsMounted: d
|
|
18
|
+
}), h = (e) => {
|
|
19
|
+
r.value = e;
|
|
20
|
+
}, s = () => {
|
|
21
|
+
n.value && l.value && (n.value.style.width = `${l.value.offsetWidth}px`);
|
|
22
|
+
};
|
|
23
|
+
return f(r, async (e) => {
|
|
24
|
+
e && a.hasResize && i && (await g(), s());
|
|
25
|
+
}), f(l, (e) => {
|
|
26
|
+
e && a.hasResize && !i && (i = !0, o.value = new ResizeObserver(s), o.value.observe(e));
|
|
27
|
+
}), O(() => {
|
|
28
|
+
a.hasResize && l.value && (i = !0, o.value = new ResizeObserver(s), o.value.observe(l.value));
|
|
29
|
+
}), R(() => {
|
|
30
|
+
var e;
|
|
31
|
+
a.hasResize && ((e = o.value) == null || e.disconnect());
|
|
32
|
+
}), {
|
|
33
|
+
reference: l,
|
|
34
|
+
floating: n,
|
|
35
|
+
popperArrow: u,
|
|
36
|
+
isOpen: r,
|
|
37
|
+
floatingPosition: v,
|
|
38
|
+
floatingStyles: c,
|
|
39
|
+
floatingArrowStyles: p,
|
|
40
|
+
changeFloatingVisibility: h
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
F as useSbFloatingPanel
|
|
45
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(i,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("@floating-ui/vue"),require("vue")):typeof define=="function"&&define.amd?define(["exports","@floating-ui/vue","vue"],e):(i=typeof globalThis<"u"?globalThis:i||self,e(i.SbFloatingPanel={},i.FloatingUIVue,i.Vue))})(this,function(i,e,n){"use strict";function d(o){const a=n.ref(null),r=n.ref(null),c=n.ref(null),s=n.ref(!1),l=n.ref(null);let f=!1;const{floatingStyles:p,placement:h,middlewareData:m}=e.useFloating(a,r,{open:s,placement:o.placement,strategy:o.strategy,transform:!1,middleware:[e.offset(o.offsetValue),e.flip(),e.shift(),...o.hasArrow?[e.arrow({element:c})]:[]],whileElementsMounted:e.autoUpdate}),w=t=>{s.value=t},u=()=>{r.value&&a.value&&(r.value.style.width=`${a.value.offsetWidth}px`)};return n.watch(s,async t=>{t&&o.hasResize&&f&&(await n.nextTick(),u())}),n.watch(a,t=>{t&&o.hasResize&&!f&&(f=!0,l.value=new ResizeObserver(u),l.value.observe(t))}),n.onMounted(()=>{o.hasResize&&a.value&&(f=!0,l.value=new ResizeObserver(u),l.value.observe(a.value))}),n.onUnmounted(()=>{var t;o.hasResize&&((t=l.value)==null||t.disconnect())}),{reference:a,floating:r,popperArrow:c,isOpen:s,floatingPosition:h,floatingStyles:p,floatingArrowStyles:m,changeFloatingVisibility:w}}i.useSbFloatingPanel=d,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Placement, Strategy } from '@floating-ui/vue';
|
|
2
|
+
interface FloatingSettings {
|
|
3
|
+
placement: Placement;
|
|
4
|
+
strategy: Strategy;
|
|
5
|
+
offsetValue: number;
|
|
6
|
+
hasArrow?: boolean;
|
|
7
|
+
hasResize?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function useSbFloatingPanel(settings: FloatingSettings): {
|
|
10
|
+
reference: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
11
|
+
floating: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
12
|
+
popperArrow: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
13
|
+
isOpen: import('vue').Ref<boolean, boolean>;
|
|
14
|
+
floatingPosition: Readonly<import('vue').Ref<Placement, Placement>>;
|
|
15
|
+
floatingStyles: Readonly<import('vue').Ref<{
|
|
16
|
+
position: Strategy;
|
|
17
|
+
top: string;
|
|
18
|
+
left: string;
|
|
19
|
+
transform?: string;
|
|
20
|
+
willChange?: string;
|
|
21
|
+
}, {
|
|
22
|
+
position: Strategy;
|
|
23
|
+
top: string;
|
|
24
|
+
left: string;
|
|
25
|
+
transform?: string;
|
|
26
|
+
willChange?: string;
|
|
27
|
+
}>>;
|
|
28
|
+
floatingArrowStyles: Readonly<import('vue').Ref<import('@floating-ui/core').MiddlewareData, import('@floating-ui/core').MiddlewareData>>;
|
|
29
|
+
changeFloatingVisibility: (newState: boolean) => void;
|
|
30
|
+
};
|
|
31
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sb-floating-panel-vue",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "A lightweight Vue 3 composable hook built on top of @floating-ui/vue to manage floating panels with arrow and resize support.",
|
|
5
|
+
"main": "dist/sb-floating-panel.umd.js",
|
|
6
|
+
"module": "dist/sb-floating-panel.es.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/sb-floating-panel.es.js",
|
|
12
|
+
"require": "./dist/sb-floating-panel.umd.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"dev": "vite",
|
|
20
|
+
"build": "vite build",
|
|
21
|
+
"lint": "eslint . --ext .ts",
|
|
22
|
+
"check": "vue-tsc --noEmit"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"vue",
|
|
26
|
+
"floating-ui",
|
|
27
|
+
"hook",
|
|
28
|
+
"composable",
|
|
29
|
+
"floating panel"
|
|
30
|
+
],
|
|
31
|
+
"author": "Stefano Biddau",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"vue": "^3.5.13"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@floating-ui/vue": "^1.1.6"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^22.15.17",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
|
42
|
+
"@typescript-eslint/parser": "^8.32.0",
|
|
43
|
+
"@vitejs/plugin-vue": "^5.2.4",
|
|
44
|
+
"eslint": "^9.26.0",
|
|
45
|
+
"eslint-plugin-prettier": "^5.4.0",
|
|
46
|
+
"eslint-plugin-vue": "^10.1.0",
|
|
47
|
+
"prettier": "^3.5.3",
|
|
48
|
+
"typescript": "~5.7.2",
|
|
49
|
+
"vite": "^6.3.5",
|
|
50
|
+
"vite-plugin-dts": "^4.5.3",
|
|
51
|
+
"vue-tsc": "^2.2.10"
|
|
52
|
+
}
|
|
53
|
+
}
|