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
+ [![npm](https://img.shields.io/npm/v/sb-floating-panel-vue.svg)](https://www.npmjs.com/package/sb-floating-panel-vue)
3
+ [![license](https://img.shields.io/npm/l/sb-floating-panel-vue.svg)](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)
@@ -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
+ }