sb-floating-panel-vue 0.1.5 โ 1.0.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/LICENSE +21 -0
- package/README.md +169 -99
- package/dist/components/SbContainer.vue.d.ts +66 -0
- package/dist/components/SbFloating.vue.d.ts +76 -0
- package/dist/components/SbReference.vue.d.ts +41 -0
- package/dist/composables/useSbFloatingPanel.d.ts +81 -0
- package/dist/index.d.ts +4 -1
- package/dist/sb-floating-panel-vue.css +1 -0
- package/dist/sb-floating-panel.es.js +211 -37
- package/dist/sb-floating-panel.umd.js +1 -1
- package/package.json +46 -14
- package/dist/use-sb-floating-panel/useSbFloatingPanel.d.ts +0 -31
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Stefano Biddau
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,158 +1,228 @@
|
|
|
1
1
|
# sb-floating-panel-vue
|
|
2
|
+
|
|
2
3
|
[](https://www.npmjs.com/package/sb-floating-panel-vue)
|
|
3
|
-
[](https://github.com/
|
|
4
|
+
[](https://github.com/stefanBid/sb-floating-panel-vue/blob/main/LICENSE)
|
|
5
|
+
[](https://vuejs.org)
|
|
6
|
+
[](#)
|
|
7
|
+
|
|
8
|
+
## ๐ฅ Features
|
|
9
|
+
|
|
10
|
+
- ๐งฉ Floating panel positioning with arrow and smart shifting
|
|
11
|
+
- โก Built on top of [`@floating-ui/vue`](https://floating-ui.com/)
|
|
12
|
+
- ๐ฏ Support for resize syncing and animated transitions
|
|
13
|
+
- ๐งช Dual usage: composable or plug-and-play components
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## ๐ค Author
|
|
4
18
|
|
|
5
|
-
|
|
19
|
+
Created with โค๏ธ by [Stefano Biddau](https://www.stefano-biddau.com/)
|
|
6
20
|
|
|
7
21
|
---
|
|
8
22
|
|
|
9
|
-
##
|
|
23
|
+
## โ Why This Library?
|
|
10
24
|
|
|
11
|
-
-
|
|
12
|
-
- ๐ฏ Precise floating panel positioning via `@floating-ui/vue`
|
|
13
|
-
- ๐ Optional arrow positioning
|
|
14
|
-
- ๐ Auto-resize support
|
|
15
|
-
- ๐ง TypeScript-first
|
|
25
|
+
`sb-floating-panel-vue` was designed to make it extremely easy to implement dropdowns, tooltips, and floating panels in Vue 3, without worrying about placement logic, arrow positioning, or responsive syncing. It wraps `@floating-ui/vue` into a more ergonomic composable or ready-to-use components.
|
|
16
26
|
|
|
17
27
|
---
|
|
18
28
|
|
|
19
|
-
##
|
|
29
|
+
## ๐ฆ Installation
|
|
20
30
|
|
|
21
31
|
```bash
|
|
32
|
+
# npm
|
|
22
33
|
npm install sb-floating-panel-vue
|
|
23
|
-
|
|
34
|
+
|
|
35
|
+
# yarn
|
|
24
36
|
yarn add sb-floating-panel-vue
|
|
37
|
+
|
|
38
|
+
# pnpm
|
|
39
|
+
pnpm add sb-floating-panel-vue
|
|
25
40
|
```
|
|
26
41
|
|
|
27
42
|
---
|
|
28
43
|
|
|
29
|
-
##
|
|
44
|
+
## ๐ง Composable Usage
|
|
30
45
|
|
|
31
|
-
|
|
46
|
+
Use the composable `useSbFloatingPanel()` for complete control.
|
|
32
47
|
|
|
33
|
-
###
|
|
48
|
+
### Options
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
| Option | Type | Required | Default | Description |
|
|
52
|
+
|------------|------------|----------|---------|--------------------------------------------------|
|
|
53
|
+
| placement | `Placement` | Yes | โ | Placement of the floating panel |
|
|
54
|
+
| strategy | `'absolute'` \| `'fixed'` | Yes | โ | CSS positioning strategy |
|
|
55
|
+
| offsetValue| `number` | Yes | โ | Offset between reference and floating |
|
|
56
|
+
| hasArrow | `boolean` | No | `false` | Whether to render arrow |
|
|
57
|
+
| hasResize | `boolean` | No | `false` | Sync width of floating to reference |
|
|
58
|
+
|
|
59
|
+
### Return Values
|
|
60
|
+
|
|
61
|
+
| Property | Type | Description |
|
|
62
|
+
|-----------------------|--------------------------------------|----------------------------------------|
|
|
63
|
+
| reference | `Ref<HTMLElement \| null>` | Ref for the trigger element |
|
|
64
|
+
| floating | `Ref<FloatingElement \| null>` | Ref for the floating panel |
|
|
65
|
+
| floatingArrow | `Ref<HTMLElement \| null>` | Ref for the arrow element |
|
|
66
|
+
| floatingPlacement | `Ref<Placement>` | The actual resolved placement |
|
|
67
|
+
| floatingStyle | `ComputedRef<CSSProperties>` | Style for the floating panel |
|
|
68
|
+
| floatingArrowStyle | `ComputedRef<CSSProperties>` | Style for the arrow |
|
|
69
|
+
| isOpen | `Ref<boolean>` | Panel visibility |
|
|
70
|
+
| toggle / open / close | `() => void` | Control methods to toggle visibility |
|
|
34
71
|
|
|
35
|
-
```ts
|
|
36
|
-
import { useSbFloatingPanel } from 'sb-floating-panel-vue';
|
|
37
|
-
```
|
|
38
72
|
|
|
39
|
-
###
|
|
73
|
+
### Example
|
|
74
|
+
In your Vue component, you can use the composable like this:
|
|
40
75
|
|
|
76
|
+
In your script tag, import the composable and use it:
|
|
41
77
|
```ts
|
|
78
|
+
import { useSbFloatingPanel } from 'sb-floating-panel-vue';
|
|
79
|
+
|
|
42
80
|
const {
|
|
43
81
|
reference,
|
|
44
82
|
floating,
|
|
45
|
-
|
|
83
|
+
floatingArrow,
|
|
84
|
+
floatingStyle,
|
|
85
|
+
floatingArrowStyle,
|
|
46
86
|
isOpen,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
87
|
+
toggle,
|
|
88
|
+
} = useSbFloatingPanel({
|
|
89
|
+
placement: 'bottom-start',
|
|
90
|
+
strategy: 'absolute',
|
|
91
|
+
offsetValue: 12,
|
|
92
|
+
hasArrow: true,
|
|
93
|
+
});
|
|
52
94
|
```
|
|
95
|
+
In your template, you can bind the refs and styles:
|
|
96
|
+
```html
|
|
97
|
+
<template>
|
|
98
|
+
<button ref="reference" @click="toggle()">Open Panel</button>
|
|
99
|
+
<div v-if="isOpen" ref="floating" :style="floatingStyle">
|
|
100
|
+
Panel
|
|
101
|
+
<div ref="floatingArrow" :style="floatingArrowStyle" />
|
|
102
|
+
</div>
|
|
103
|
+
</template>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
53
107
|
|
|
54
|
-
|
|
108
|
+
## ๐งฑ Component-Based Usage
|
|
55
109
|
|
|
56
|
-
|
|
110
|
+
### Import the style
|
|
111
|
+
|
|
112
|
+
If you use components, you **must** import styles in `main.ts`:
|
|
57
113
|
|
|
58
114
|
```ts
|
|
59
|
-
|
|
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
|
-
}
|
|
115
|
+
import 'sb-floating-panel-vue/style.css';
|
|
66
116
|
```
|
|
67
117
|
|
|
68
|
-
|
|
118
|
+
### Available Components
|
|
69
119
|
|
|
70
|
-
|
|
120
|
+
#### `<SbContainer>`
|
|
71
121
|
|
|
72
|
-
|
|
122
|
+
Wraps everything and provides the context.
|
|
73
123
|
|
|
74
|
-
|
|
124
|
+
| Prop | Type | Default | Description |
|
|
125
|
+
|-------------|---------------------------|-----------------|-----------------------------------------------------------------------------|
|
|
126
|
+
| placement | `Placement` | `'bottom-start'`| Placement of the floating panel relative to the reference element |
|
|
127
|
+
| strategy | `'absolute' \| 'fixed'` | `'absolute'` | CSS positioning strategy for the floating panel |
|
|
128
|
+
| offsetValue | `number` | `15` | Offset in pixels between reference and floating panel |
|
|
129
|
+
| hasArrow | `boolean` | `false` | Whether to render an arrow pointing to the reference |
|
|
130
|
+
| hasResize | `boolean` | `false` | Whether the floating panel should sync its width with the reference |
|
|
75
131
|
|
|
76
|
-
### `floatingPosition`
|
|
77
132
|
|
|
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
133
|
|
|
80
|
-
|
|
134
|
+
#### `<SbReference>`
|
|
81
135
|
|
|
82
|
-
|
|
136
|
+
Trigger element
|
|
83
137
|
|
|
84
|
-
|
|
138
|
+
| Prop | Type | Default | Description |
|
|
139
|
+
|--------------|-----------------------------------|--------------|------------------------------------------------------------------------------|
|
|
140
|
+
| referenceRef | `Ref<HTMLElement \| null>` | **required** | Reference element to which the floating panel is attached |
|
|
141
|
+
| as | `'button' \| 'div' \| 'span' \| etc.` | `'button'` | HTML tag to render. Defaults to `<button>` for accessibility |
|
|
142
|
+
| onClick | `() => void` | โ | Optional click handler, often used to toggle the floating panel visibility |
|
|
85
143
|
|
|
86
|
-
## ๐งช Example
|
|
87
144
|
|
|
88
|
-
|
|
89
|
-
<script setup lang="ts">
|
|
90
|
-
import { ref } from 'vue';
|
|
91
|
-
import { useSbFloatingPanel } from 'sb-floating-panel-vue';
|
|
145
|
+
#### `<SbFloating>`
|
|
92
146
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
147
|
+
Floating panel
|
|
148
|
+
|
|
149
|
+
| Prop | Type | Default | Description |
|
|
150
|
+
|---------------------|----------------------------------------------|-----------------|-----------------------------------------------------------------------------|
|
|
151
|
+
| floatingRef | `Ref<HTMLElement \| null>` | **required** | The target element for the floating panel (popover, tooltip, etc.) |
|
|
152
|
+
| floatingArrowRef | `Ref<HTMLElement \| null>` | optional | The element used as the floating arrow |
|
|
153
|
+
| isOpen | `boolean` | **required** | Controls visibility of the floating panel |
|
|
154
|
+
| floatingPlacement | `Placement` | **required** | Current placement as resolved by `@floating-ui/vue` |
|
|
155
|
+
| floatingStyle | `CSSProperties` | **required** | Inline style object applied to the floating panel |
|
|
156
|
+
| floatingArrowStyle | `CSSProperties` | optional | Inline style object applied to the arrow element |
|
|
157
|
+
| arrowDimensions | `number` | optional | Size (width/height) of the arrow in pixels |
|
|
158
|
+
| zIndex | `number` | `undefined` | Custom z-index applied to the floating and arrow elements |
|
|
159
|
+
| animation | `'fade' \| 'scale-fade' \| 'none'` | `'scale-fade'` | Defines the animation style for enter/leave transitions |
|
|
160
|
+
| duration | `number` | `300` | Duration in ms for the transition animations |
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### ๐งช Component Usage Example
|
|
108
166
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
167
|
+
In your project, you can use the components like this:
|
|
168
|
+
|
|
169
|
+
In your script tag, import the components:
|
|
170
|
+
```ts
|
|
171
|
+
import { SbContainer, SbFloating, SbReference } from 'sb-floating-panel-vue';
|
|
113
172
|
```
|
|
114
173
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
174
|
+
In your template, you can use the components as follows:
|
|
175
|
+
```html
|
|
176
|
+
<SbContainer :has-arrow="true" strategy="fixed">
|
|
177
|
+
<template #default="{
|
|
178
|
+
reference,
|
|
179
|
+
floating,
|
|
180
|
+
floatingArrow,
|
|
181
|
+
floatingPlacement,
|
|
182
|
+
floatingStyle,
|
|
183
|
+
floatingArrowStyle,
|
|
184
|
+
isOpen,
|
|
185
|
+
toggle
|
|
186
|
+
}">
|
|
187
|
+
<SbReference :reference-ref="reference" :onClick="toggle">Toggle</SbReference>
|
|
188
|
+
<SbFloating
|
|
189
|
+
:is-open="isOpen.value"
|
|
190
|
+
:floating-ref="floating"
|
|
191
|
+
:floating-arrow-ref="floatingArrow"
|
|
192
|
+
:floating-placement="floatingPlacement.value"
|
|
193
|
+
:floating-style="floatingStyle.value"
|
|
194
|
+
:floating-arrow-style="floatingArrowStyle.value"
|
|
195
|
+
:arrow-dimensions="12"
|
|
196
|
+
:z-index="200"
|
|
197
|
+
>
|
|
198
|
+
Hello Panel!
|
|
199
|
+
</SbFloating>
|
|
200
|
+
</template>
|
|
201
|
+
</SbContainer>
|
|
128
202
|
```
|
|
129
203
|
|
|
130
204
|
---
|
|
131
205
|
|
|
132
|
-
##
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
background: white;
|
|
149
|
-
transform: rotate(45deg);
|
|
150
|
-
position: absolute;
|
|
151
|
-
}
|
|
206
|
+
## โ ๏ธ Directive Note (Teleport Limitation)
|
|
207
|
+
|
|
208
|
+
Due to `<teleport>` in `<SbFloating>`, if you apply custom directives directly to the component, Vue will warn:
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
[Vue warn]: Extraneous non-props attributes ([directive-name]) were passed to component but could not be automatically inherited because component renders fragment or text or teleport root nodes.
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Solution**: Move the directive to an inner element using the slot.
|
|
215
|
+
|
|
216
|
+
### Example Fix
|
|
217
|
+
|
|
218
|
+
```vue
|
|
219
|
+
<SbFloating ...>
|
|
220
|
+
<div v-click-outside>...</div>
|
|
221
|
+
</SbFloating>
|
|
152
222
|
```
|
|
153
223
|
|
|
154
224
|
---
|
|
155
225
|
|
|
156
226
|
## ๐ License
|
|
157
227
|
|
|
158
|
-
MIT ยฉ [Stefano Biddau](https://
|
|
228
|
+
[MIT License](https://github.com/stefanBid/sb-floating-panel-vue/blob/main/LICENSE) ยฉ [Stefano Biddau](https://www.stefano-biddau.com/)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Placement, Strategy } from '@floating-ui/vue';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the SbContainer component.
|
|
4
|
+
* Serves as a controller and provider for the floating panel system.
|
|
5
|
+
*/
|
|
6
|
+
interface SbContainerProps {
|
|
7
|
+
/**
|
|
8
|
+
* Placement of the floating panel relative to the reference.
|
|
9
|
+
* @default 'bottom-start'
|
|
10
|
+
*/
|
|
11
|
+
placement?: Placement;
|
|
12
|
+
/**
|
|
13
|
+
* Positioning strategy to use ('absolute' or 'fixed').
|
|
14
|
+
* @default 'absolute'
|
|
15
|
+
*/
|
|
16
|
+
strategy?: Strategy;
|
|
17
|
+
/**
|
|
18
|
+
* Pixel offset between the reference and floating panel.
|
|
19
|
+
* @default 15
|
|
20
|
+
*/
|
|
21
|
+
offsetValue?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Whether to render an arrow pointing toward the reference element.
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
hasArrow?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* When true, syncs the floating panel width to the reference width.
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
hasResize?: boolean;
|
|
32
|
+
}
|
|
33
|
+
declare function __VLS_template(): {
|
|
34
|
+
attrs: Partial<{}>;
|
|
35
|
+
slots: {
|
|
36
|
+
default?(_: {
|
|
37
|
+
reference: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
38
|
+
floating: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
39
|
+
floatingArrow: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
40
|
+
floatingPlacement: import('vue').Ref<Placement, Placement>;
|
|
41
|
+
floatingStyle: import('vue').ComputedRef<import('vue').CSSProperties>;
|
|
42
|
+
floatingArrowStyle: import('vue').ComputedRef<import('vue').CSSProperties>;
|
|
43
|
+
isOpen: import('vue').Ref<boolean, boolean>;
|
|
44
|
+
toggle: () => void;
|
|
45
|
+
open: () => void;
|
|
46
|
+
close: () => void;
|
|
47
|
+
}): any;
|
|
48
|
+
};
|
|
49
|
+
refs: {};
|
|
50
|
+
rootEl: any;
|
|
51
|
+
};
|
|
52
|
+
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
53
|
+
declare const __VLS_component: import('vue').DefineComponent<SbContainerProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<SbContainerProps> & Readonly<{}>, {
|
|
54
|
+
placement: Placement;
|
|
55
|
+
strategy: Strategy;
|
|
56
|
+
offsetValue: number;
|
|
57
|
+
hasArrow: boolean;
|
|
58
|
+
hasResize: boolean;
|
|
59
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
60
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
61
|
+
export default _default;
|
|
62
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
63
|
+
new (): {
|
|
64
|
+
$slots: S;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Placement } from '@floating-ui/vue';
|
|
2
|
+
import { CSSProperties, Ref } from 'vue';
|
|
3
|
+
/**
|
|
4
|
+
* Props for the SbFloating component.
|
|
5
|
+
* This component renders the floating panel and (optionally) its arrow using teleport.
|
|
6
|
+
*/
|
|
7
|
+
interface SbFloatingProps {
|
|
8
|
+
/**
|
|
9
|
+
* The ref to bind to the floating panel element.
|
|
10
|
+
*/
|
|
11
|
+
floatingRef: Ref<HTMLElement | null>;
|
|
12
|
+
/**
|
|
13
|
+
* Optional ref to bind to the floating arrow element.
|
|
14
|
+
*/
|
|
15
|
+
floatingArrowRef?: Ref<HTMLElement | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the floating panel is open (visible).
|
|
18
|
+
*/
|
|
19
|
+
isOpen: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The final placement resolved by Floating UI (e.g., 'bottom-start').
|
|
22
|
+
*/
|
|
23
|
+
floatingPlacement: Placement;
|
|
24
|
+
/**
|
|
25
|
+
* Computed inline styles for the floating panel.
|
|
26
|
+
*/
|
|
27
|
+
floatingStyle: CSSProperties;
|
|
28
|
+
/**
|
|
29
|
+
* Computed inline styles for the floating arrow (optional).
|
|
30
|
+
*/
|
|
31
|
+
floatingArrowStyle?: CSSProperties;
|
|
32
|
+
/**
|
|
33
|
+
* Optional dimension (width & height) of the floating arrow.
|
|
34
|
+
* If provided, will override default arrow size.
|
|
35
|
+
*/
|
|
36
|
+
arrowDimensions?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Optional z-index to apply to the floating panel and arrow.
|
|
39
|
+
*/
|
|
40
|
+
zIndex?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Animation name used in Vue <transition>.
|
|
43
|
+
* Supported values: 'fade', 'scale-fade', 'none'.
|
|
44
|
+
* @default 'scale-fade'
|
|
45
|
+
*/
|
|
46
|
+
animation?: 'fade' | 'scale-fade' | 'none';
|
|
47
|
+
/**
|
|
48
|
+
* Duration of the transition animation in milliseconds.
|
|
49
|
+
* @default 300
|
|
50
|
+
*/
|
|
51
|
+
duration?: number;
|
|
52
|
+
}
|
|
53
|
+
declare function __VLS_template(): {
|
|
54
|
+
attrs: Partial<{}>;
|
|
55
|
+
slots: {
|
|
56
|
+
default?(_: {}): any;
|
|
57
|
+
};
|
|
58
|
+
refs: {};
|
|
59
|
+
rootEl: any;
|
|
60
|
+
};
|
|
61
|
+
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
62
|
+
declare const __VLS_component: import('vue').DefineComponent<SbFloatingProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<SbFloatingProps> & Readonly<{}>, {
|
|
63
|
+
floatingArrowStyle: CSSProperties;
|
|
64
|
+
floatingArrowRef: Ref<HTMLElement | null>;
|
|
65
|
+
arrowDimensions: number;
|
|
66
|
+
zIndex: number;
|
|
67
|
+
animation: "fade" | "scale-fade" | "none";
|
|
68
|
+
duration: number;
|
|
69
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
70
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
71
|
+
export default _default;
|
|
72
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
73
|
+
new (): {
|
|
74
|
+
$slots: S;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Props for the SbReference component.
|
|
4
|
+
* Renders the reference element for the floating panel system.
|
|
5
|
+
*/
|
|
6
|
+
interface SbReferenceProps {
|
|
7
|
+
/**
|
|
8
|
+
* The ref to bind to the reference DOM element.
|
|
9
|
+
*/
|
|
10
|
+
referenceRef: Ref<HTMLElement | null>;
|
|
11
|
+
/**
|
|
12
|
+
* HTML tag to render as the reference.
|
|
13
|
+
* Useful for accessibility and customization.
|
|
14
|
+
* @default 'button'
|
|
15
|
+
*/
|
|
16
|
+
as?: 'button' | 'a' | 'div' | 'span';
|
|
17
|
+
/**
|
|
18
|
+
* Optional click handler for toggling the floating panel.
|
|
19
|
+
*/
|
|
20
|
+
onClick?: () => void;
|
|
21
|
+
}
|
|
22
|
+
declare function __VLS_template(): {
|
|
23
|
+
attrs: Partial<{}>;
|
|
24
|
+
slots: {
|
|
25
|
+
default?(_: {}): any;
|
|
26
|
+
};
|
|
27
|
+
refs: {};
|
|
28
|
+
rootEl: any;
|
|
29
|
+
};
|
|
30
|
+
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
31
|
+
declare const __VLS_component: import('vue').DefineComponent<SbReferenceProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<SbReferenceProps> & Readonly<{}>, {
|
|
32
|
+
onClick: () => void;
|
|
33
|
+
as: "button" | "a" | "div" | "span";
|
|
34
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
35
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
36
|
+
export default _default;
|
|
37
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
38
|
+
new (): {
|
|
39
|
+
$slots: S;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { FloatingElement, Placement, Strategy } from '@floating-ui/vue';
|
|
2
|
+
import { CSSProperties, Ref, ComputedRef } from 'vue';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for the `useSbFloatingPanel` composable.
|
|
5
|
+
*/
|
|
6
|
+
interface FloatingSettings {
|
|
7
|
+
/**
|
|
8
|
+
* Defines the preferred placement of the floating element relative to the reference.
|
|
9
|
+
* Example: 'top', 'bottom-start', 'right-end', etc.
|
|
10
|
+
*/
|
|
11
|
+
placement: Placement;
|
|
12
|
+
/**
|
|
13
|
+
* Determines the positioning strategy for the floating element.
|
|
14
|
+
* Can be either 'absolute' or 'fixed'.
|
|
15
|
+
*/
|
|
16
|
+
strategy: Strategy;
|
|
17
|
+
/**
|
|
18
|
+
* Specifies the distance (in pixels) between the reference and floating elements.
|
|
19
|
+
*/
|
|
20
|
+
offsetValue: number;
|
|
21
|
+
/**
|
|
22
|
+
* Enables the use of a directional arrow pointing from the floating element to the reference.
|
|
23
|
+
*/
|
|
24
|
+
hasArrow?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* When enabled, synchronizes the width of the floating element to match the reference element.
|
|
27
|
+
* Useful for dropdowns or inputs.
|
|
28
|
+
*/
|
|
29
|
+
hasResize?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* `useSbFloatingPanel` is a composable that wraps Floating UI logic to manage
|
|
33
|
+
* floating elements with optional arrow and dynamic width support.
|
|
34
|
+
*
|
|
35
|
+
* It provides bindings and style objects ready to apply to your `ref` elements in Vue templates.
|
|
36
|
+
*
|
|
37
|
+
* @param settings - Configuration options for placement, offset, and behavior.
|
|
38
|
+
* @returns Bindings and utility functions to control the floating panel.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const {
|
|
43
|
+
* reference,
|
|
44
|
+
* floating,
|
|
45
|
+
* floatingArrow,
|
|
46
|
+
* floatingPlacement,
|
|
47
|
+
* floatingStyle,
|
|
48
|
+
* floatingArrowStyle,
|
|
49
|
+
* isOpen,
|
|
50
|
+
* toggle,
|
|
51
|
+
* open,
|
|
52
|
+
* close
|
|
53
|
+
* } = useSbFloatingPanel({
|
|
54
|
+
* placement: 'bottom',
|
|
55
|
+
* strategy: 'absolute',
|
|
56
|
+
* offsetValue: 10,
|
|
57
|
+
* hasArrow: true,
|
|
58
|
+
* hasResize: false
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```html
|
|
64
|
+
* <div ref="reference">Anchor</div>
|
|
65
|
+
* <div ref="floating" v-if="isOpen">Panel</div>
|
|
66
|
+
* <div ref="floatingArrow" v-if="isOpen">Arrow</div>
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function useSbFloatingPanel(settings: FloatingSettings): {
|
|
70
|
+
reference: Ref<HTMLElement | null>;
|
|
71
|
+
floating: Ref<FloatingElement | null>;
|
|
72
|
+
floatingArrow: Ref<HTMLElement | null>;
|
|
73
|
+
floatingPlacement: Ref<Placement>;
|
|
74
|
+
floatingStyle: ComputedRef<CSSProperties>;
|
|
75
|
+
floatingArrowStyle: ComputedRef<CSSProperties>;
|
|
76
|
+
isOpen: Ref<boolean>;
|
|
77
|
+
toggle: () => void;
|
|
78
|
+
open: () => void;
|
|
79
|
+
close: () => void;
|
|
80
|
+
};
|
|
81
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
|
-
export { useSbFloatingPanel } from './
|
|
1
|
+
export { useSbFloatingPanel } from './composables/useSbFloatingPanel';
|
|
2
|
+
export { default as SbContainer } from './components/SbContainer.vue';
|
|
3
|
+
export { default as SbReference } from './components/SbReference.vue';
|
|
4
|
+
export { default as SbFloating } from './components/SbFloating.vue';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.floating-container[data-v-33e40585]{width:fit-content;height:fit-content}.fade-enter-active[data-v-366682ad],.fade-leave-active[data-v-366682ad]{transition:opacity var(--sb-transition-duration) ease-in-out}.fade-enter-from[data-v-366682ad],.fade-leave-to[data-v-366682ad]{opacity:0}.fade-enter-to[data-v-366682ad],.fade-leave-from[data-v-366682ad]{opacity:1}.scale-fade-enter-active[data-v-366682ad],.scale-fade-leave-active[data-v-366682ad]{transition:opacity var(--sb-transition-duration) ease-in-out,transform var(--sb-transition-duration) ease-in-out}.scale-fade-enter-from[data-v-366682ad],.scale-fade-leave-to[data-v-366682ad]{opacity:0;transform:scale(.95)}.scale-fade-enter-to[data-v-366682ad],.scale-fade-leave-from[data-v-366682ad]{opacity:1;transform:scale(1)}
|
|
@@ -1,45 +1,219 @@
|
|
|
1
|
-
import { useFloating as
|
|
2
|
-
import { ref as
|
|
3
|
-
function
|
|
4
|
-
const
|
|
5
|
-
let
|
|
6
|
-
const { floatingStyles:
|
|
7
|
-
open:
|
|
1
|
+
import { useFloating as V, autoUpdate as B, offset as M, flip as T, shift as W, arrow as D } from "@floating-ui/vue";
|
|
2
|
+
import { ref as c, computed as u, watch as S, onMounted as E, onUnmounted as K, nextTick as N, defineComponent as k, createElementBlock as x, openBlock as v, renderSlot as z, normalizeProps as U, guardReactiveProps as j, createBlock as A, resolveDynamicComponent as q, mergeProps as $, withKeys as _, withModifiers as w, withCtx as C, useAttrs as G, Teleport as H, createVNode as J, Transition as L, createCommentVNode as R, unref as Q, normalizeStyle as X } from "vue";
|
|
3
|
+
function Y(a) {
|
|
4
|
+
const e = c(null), l = c(null), r = c(null), o = c(!1), s = c(null);
|
|
5
|
+
let t = !1;
|
|
6
|
+
const { floatingStyles: f, placement: i, middlewareData: m } = V(e, l, {
|
|
7
|
+
open: o,
|
|
8
8
|
placement: a.placement,
|
|
9
9
|
strategy: a.strategy,
|
|
10
10
|
transform: !1,
|
|
11
|
-
middleware: [
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
11
|
+
middleware: [M(a.offsetValue), T(), W(), D({ element: r })],
|
|
12
|
+
whileElementsMounted: B
|
|
13
|
+
}), d = (n) => {
|
|
14
|
+
o.value = n;
|
|
15
|
+
}, b = () => d(!0), y = () => d(!1), h = () => d(!o.value), g = () => {
|
|
16
|
+
l.value && e.value && (l.value.style.width = `${e.value.offsetWidth}px`);
|
|
17
|
+
}, O = u(() => ({
|
|
18
|
+
...f.value
|
|
19
|
+
})), P = u(() => {
|
|
20
|
+
const n = m.value.arrow, F = i.value.split("-")[0], p = {
|
|
21
|
+
position: "absolute",
|
|
22
|
+
transform: "rotate(45deg)",
|
|
23
|
+
background: "inherit",
|
|
24
|
+
width: "8px",
|
|
25
|
+
height: "8px",
|
|
26
|
+
left: (n == null ? void 0 : n.x) != null ? `${n.x}px` : "",
|
|
27
|
+
top: (n == null ? void 0 : n.y) != null ? `${n.y}px` : ""
|
|
28
|
+
};
|
|
29
|
+
switch (F) {
|
|
30
|
+
case "top":
|
|
31
|
+
p.bottom = "-4px";
|
|
32
|
+
break;
|
|
33
|
+
case "bottom":
|
|
34
|
+
p.top = "-4px";
|
|
35
|
+
break;
|
|
36
|
+
case "left":
|
|
37
|
+
p.right = "-4px";
|
|
38
|
+
break;
|
|
39
|
+
case "right":
|
|
40
|
+
p.left = "-4px";
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
return p;
|
|
44
|
+
});
|
|
45
|
+
return S(o, async (n) => {
|
|
46
|
+
n && a.hasResize && t && (await N(), g());
|
|
47
|
+
}), S(e, (n) => {
|
|
48
|
+
n && a.hasResize && !t && (t = !0, s.value = new ResizeObserver(g), s.value.observe(n));
|
|
49
|
+
}), E(() => {
|
|
50
|
+
a.hasResize && e.value && (t = !0, s.value = new ResizeObserver(g), s.value.observe(e.value));
|
|
51
|
+
}), K(() => {
|
|
52
|
+
var n;
|
|
53
|
+
a.hasResize && ((n = s.value) == null || n.disconnect());
|
|
32
54
|
}), {
|
|
33
|
-
reference:
|
|
34
|
-
floating:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
reference: e,
|
|
56
|
+
floating: l,
|
|
57
|
+
floatingArrow: r,
|
|
58
|
+
floatingPlacement: i,
|
|
59
|
+
floatingStyle: O,
|
|
60
|
+
floatingArrowStyle: P,
|
|
61
|
+
isOpen: o,
|
|
62
|
+
toggle: h,
|
|
63
|
+
open: b,
|
|
64
|
+
close: y
|
|
41
65
|
};
|
|
42
66
|
}
|
|
67
|
+
const Z = { class: "floating-container" }, ee = /* @__PURE__ */ k({
|
|
68
|
+
__name: "SbContainer",
|
|
69
|
+
props: {
|
|
70
|
+
placement: { default: "bottom-start" },
|
|
71
|
+
strategy: { default: "absolute" },
|
|
72
|
+
offsetValue: { default: 15 },
|
|
73
|
+
hasArrow: { type: Boolean, default: !1 },
|
|
74
|
+
hasResize: { type: Boolean, default: !1 }
|
|
75
|
+
},
|
|
76
|
+
setup(a) {
|
|
77
|
+
const e = a, {
|
|
78
|
+
isOpen: l,
|
|
79
|
+
reference: r,
|
|
80
|
+
floating: o,
|
|
81
|
+
floatingArrow: s,
|
|
82
|
+
floatingPlacement: t,
|
|
83
|
+
floatingStyle: f,
|
|
84
|
+
floatingArrowStyle: i,
|
|
85
|
+
toggle: m,
|
|
86
|
+
open: d,
|
|
87
|
+
close: b
|
|
88
|
+
} = Y({
|
|
89
|
+
placement: e.placement,
|
|
90
|
+
strategy: e.strategy,
|
|
91
|
+
offsetValue: e.offsetValue,
|
|
92
|
+
hasArrow: e.hasArrow,
|
|
93
|
+
hasResize: e.hasResize
|
|
94
|
+
}), y = {
|
|
95
|
+
reference: r,
|
|
96
|
+
floating: o,
|
|
97
|
+
floatingArrow: s,
|
|
98
|
+
floatingPlacement: t,
|
|
99
|
+
floatingStyle: f,
|
|
100
|
+
floatingArrowStyle: i,
|
|
101
|
+
isOpen: l,
|
|
102
|
+
toggle: m,
|
|
103
|
+
open: d,
|
|
104
|
+
close: b
|
|
105
|
+
};
|
|
106
|
+
return (h, g) => (v(), x("div", Z, [
|
|
107
|
+
z(h.$slots, "default", U(j(y)), void 0, !0)
|
|
108
|
+
]));
|
|
109
|
+
}
|
|
110
|
+
}), I = (a, e) => {
|
|
111
|
+
const l = a.__vccOpts || a;
|
|
112
|
+
for (const [r, o] of e)
|
|
113
|
+
l[r] = o;
|
|
114
|
+
return l;
|
|
115
|
+
}, ae = /* @__PURE__ */ I(ee, [["__scopeId", "data-v-33e40585"]]), le = /* @__PURE__ */ k({
|
|
116
|
+
__name: "SbReference",
|
|
117
|
+
props: {
|
|
118
|
+
referenceRef: {},
|
|
119
|
+
as: { default: "button" },
|
|
120
|
+
onClick: { type: Function, default: void 0 }
|
|
121
|
+
},
|
|
122
|
+
setup(a) {
|
|
123
|
+
const e = a, l = u(() => e.as === "button" || e.as === "a");
|
|
124
|
+
return (r, o) => (v(), A(q(e.as), $(r.$attrs, {
|
|
125
|
+
ref: e.referenceRef,
|
|
126
|
+
role: l.value ? "button" : void 0,
|
|
127
|
+
tabindex: l.value ? 0 : void 0,
|
|
128
|
+
onClick: o[0] || (o[0] = w((s) => {
|
|
129
|
+
var t;
|
|
130
|
+
return (t = e.onClick) == null ? void 0 : t.call(e);
|
|
131
|
+
}, ["stop"])),
|
|
132
|
+
onKeydown: [
|
|
133
|
+
o[1] || (o[1] = _(w((s) => {
|
|
134
|
+
var t;
|
|
135
|
+
return l.value && ((t = e.onClick) == null ? void 0 : t.call(e));
|
|
136
|
+
}, ["prevent", "stop"]), ["space"])),
|
|
137
|
+
o[2] || (o[2] = _(w((s) => {
|
|
138
|
+
var t;
|
|
139
|
+
return l.value && ((t = e.onClick) == null ? void 0 : t.call(e));
|
|
140
|
+
}, ["prevent", "stop"]), ["enter"]))
|
|
141
|
+
]
|
|
142
|
+
}), {
|
|
143
|
+
default: C(() => [
|
|
144
|
+
z(r.$slots, "default")
|
|
145
|
+
]),
|
|
146
|
+
_: 3
|
|
147
|
+
}, 16, ["role", "tabindex"]));
|
|
148
|
+
}
|
|
149
|
+
}), te = /* @__PURE__ */ k({
|
|
150
|
+
inheritAttrs: !1,
|
|
151
|
+
__name: "SbFloating",
|
|
152
|
+
props: {
|
|
153
|
+
floatingRef: {},
|
|
154
|
+
floatingArrowRef: { default: () => c(null) },
|
|
155
|
+
isOpen: { type: Boolean },
|
|
156
|
+
floatingPlacement: {},
|
|
157
|
+
floatingStyle: {},
|
|
158
|
+
floatingArrowStyle: { default: void 0 },
|
|
159
|
+
arrowDimensions: { default: void 0 },
|
|
160
|
+
zIndex: { default: void 0 },
|
|
161
|
+
animation: { default: "scale-fade" },
|
|
162
|
+
duration: { default: 300 }
|
|
163
|
+
},
|
|
164
|
+
setup(a) {
|
|
165
|
+
const e = a, l = G(), r = u(() => {
|
|
166
|
+
const t = {
|
|
167
|
+
...e.floatingStyle,
|
|
168
|
+
"--sb-transition-duration": e.duration + "ms"
|
|
169
|
+
};
|
|
170
|
+
return e.zIndex !== void 0 && (t.zIndex = e.zIndex), t;
|
|
171
|
+
}), o = u(() => {
|
|
172
|
+
const t = { ...e.floatingArrowStyle || {} };
|
|
173
|
+
if (e.arrowDimensions) {
|
|
174
|
+
const f = e.arrowDimensions, i = `-${f / 2}px`;
|
|
175
|
+
switch (e.floatingPlacement.split("-")[0]) {
|
|
176
|
+
case "top":
|
|
177
|
+
t.bottom = i;
|
|
178
|
+
break;
|
|
179
|
+
case "bottom":
|
|
180
|
+
t.top = i;
|
|
181
|
+
break;
|
|
182
|
+
case "left":
|
|
183
|
+
t.right = i;
|
|
184
|
+
break;
|
|
185
|
+
case "right":
|
|
186
|
+
t.left = i;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
t.width = `${f}px`, t.height = `${f}px`;
|
|
190
|
+
}
|
|
191
|
+
return e.zIndex !== void 0 && (t.zIndex = e.zIndex), t;
|
|
192
|
+
}), s = u(() => e.animation === "fade" ? "fade" : e.animation === "scale-fade" ? "scale-fade" : "");
|
|
193
|
+
return (t, f) => (v(), A(H, { to: "body" }, [
|
|
194
|
+
J(L, { name: s.value }, {
|
|
195
|
+
default: C(() => [
|
|
196
|
+
e.isOpen ? (v(), x("div", $({
|
|
197
|
+
key: 0,
|
|
198
|
+
ref: e.floatingRef,
|
|
199
|
+
style: r.value
|
|
200
|
+
}, Q(l)), [
|
|
201
|
+
z(t.$slots, "default", {}, void 0, !0),
|
|
202
|
+
e.floatingArrowRef ? (v(), x("div", {
|
|
203
|
+
key: 0,
|
|
204
|
+
ref: e.floatingArrowRef,
|
|
205
|
+
style: X(o.value)
|
|
206
|
+
}, null, 4)) : R("", !0)
|
|
207
|
+
], 16)) : R("", !0)
|
|
208
|
+
]),
|
|
209
|
+
_: 3
|
|
210
|
+
}, 8, ["name"])
|
|
211
|
+
]));
|
|
212
|
+
}
|
|
213
|
+
}), se = /* @__PURE__ */ I(te, [["__scopeId", "data-v-366682ad"]]);
|
|
43
214
|
export {
|
|
44
|
-
|
|
215
|
+
ae as SbContainer,
|
|
216
|
+
se as SbFloating,
|
|
217
|
+
le as SbReference,
|
|
218
|
+
Y as useSbFloatingPanel
|
|
45
219
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(s,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("@floating-ui/vue"),require("vue")):typeof define=="function"&&define.amd?define(["exports","@floating-ui/vue","vue"],c):(s=typeof globalThis<"u"?globalThis:s||self,c(s.SbFloatingPanelVue={},s.FloatingUIVue,s.Vue))})(this,function(s,c,e){"use strict";function k(l){const t=e.ref(null),i=e.ref(null),f=e.ref(null),n=e.ref(!1),r=e.ref(null);let o=!1;const{floatingStyles:p,placement:d,middlewareData:g}=c.useFloating(t,i,{open:n,placement:l.placement,strategy:l.strategy,transform:!1,middleware:[c.offset(l.offsetValue),c.flip(),c.shift(),c.arrow({element:f})],whileElementsMounted:c.autoUpdate}),u=a=>{n.value=a},h=()=>u(!0),y=()=>u(!1),w=()=>u(!n.value),b=()=>{i.value&&t.value&&(i.value.style.width=`${t.value.offsetWidth}px`)},C=e.computed(()=>({...p.value})),B=e.computed(()=>{const a=g.value.arrow,P=d.value.split("-")[0],m={position:"absolute",transform:"rotate(45deg)",background:"inherit",width:"8px",height:"8px",left:(a==null?void 0:a.x)!=null?`${a.x}px`:"",top:(a==null?void 0:a.y)!=null?`${a.y}px`:""};switch(P){case"top":m.bottom="-4px";break;case"bottom":m.top="-4px";break;case"left":m.right="-4px";break;case"right":m.left="-4px";break}return m});return e.watch(n,async a=>{a&&l.hasResize&&o&&(await e.nextTick(),b())}),e.watch(t,a=>{a&&l.hasResize&&!o&&(o=!0,r.value=new ResizeObserver(b),r.value.observe(a))}),e.onMounted(()=>{l.hasResize&&t.value&&(o=!0,r.value=new ResizeObserver(b),r.value.observe(t.value))}),e.onUnmounted(()=>{var a;l.hasResize&&((a=r.value)==null||a.disconnect())}),{reference:t,floating:i,floatingArrow:f,floatingPlacement:d,floatingStyle:C,floatingArrowStyle:B,isOpen:n,toggle:w,open:h,close:y}}const x={class:"floating-container"},_=e.defineComponent({__name:"SbContainer",props:{placement:{default:"bottom-start"},strategy:{default:"absolute"},offsetValue:{default:15},hasArrow:{type:Boolean,default:!1},hasResize:{type:Boolean,default:!1}},setup(l){const t=l,{isOpen:i,reference:f,floating:n,floatingArrow:r,floatingPlacement:o,floatingStyle:p,floatingArrowStyle:d,toggle:g,open:u,close:h}=k({placement:t.placement,strategy:t.strategy,offsetValue:t.offsetValue,hasArrow:t.hasArrow,hasResize:t.hasResize}),y={reference:f,floating:n,floatingArrow:r,floatingPlacement:o,floatingStyle:p,floatingArrowStyle:d,isOpen:i,toggle:g,open:u,close:h};return(w,b)=>(e.openBlock(),e.createElementBlock("div",x,[e.renderSlot(w.$slots,"default",e.normalizeProps(e.guardReactiveProps(y)),void 0,!0)]))}}),S=(l,t)=>{const i=l.__vccOpts||l;for(const[f,n]of t)i[f]=n;return i},z=S(_,[["__scopeId","data-v-33e40585"]]),R=e.defineComponent({__name:"SbReference",props:{referenceRef:{},as:{default:"button"},onClick:{type:Function,default:void 0}},setup(l){const t=l,i=e.computed(()=>t.as==="button"||t.as==="a");return(f,n)=>(e.openBlock(),e.createBlock(e.resolveDynamicComponent(t.as),e.mergeProps(f.$attrs,{ref:t.referenceRef,role:i.value?"button":void 0,tabindex:i.value?0:void 0,onClick:n[0]||(n[0]=e.withModifiers(r=>{var o;return(o=t.onClick)==null?void 0:o.call(t)},["stop"])),onKeydown:[n[1]||(n[1]=e.withKeys(e.withModifiers(r=>{var o;return i.value&&((o=t.onClick)==null?void 0:o.call(t))},["prevent","stop"]),["space"])),n[2]||(n[2]=e.withKeys(e.withModifiers(r=>{var o;return i.value&&((o=t.onClick)==null?void 0:o.call(t))},["prevent","stop"]),["enter"]))]}),{default:e.withCtx(()=>[e.renderSlot(f.$slots,"default")]),_:3},16,["role","tabindex"]))}}),A=S(e.defineComponent({inheritAttrs:!1,__name:"SbFloating",props:{floatingRef:{},floatingArrowRef:{default:()=>e.ref(null)},isOpen:{type:Boolean},floatingPlacement:{},floatingStyle:{},floatingArrowStyle:{default:void 0},arrowDimensions:{default:void 0},zIndex:{default:void 0},animation:{default:"scale-fade"},duration:{default:300}},setup(l){const t=l,i=e.useAttrs(),f=e.computed(()=>{const o={...t.floatingStyle,"--sb-transition-duration":t.duration+"ms"};return t.zIndex!==void 0&&(o.zIndex=t.zIndex),o}),n=e.computed(()=>{const o={...t.floatingArrowStyle||{}};if(t.arrowDimensions){const p=t.arrowDimensions,d=`-${p/2}px`;switch(t.floatingPlacement.split("-")[0]){case"top":o.bottom=d;break;case"bottom":o.top=d;break;case"left":o.right=d;break;case"right":o.left=d;break}o.width=`${p}px`,o.height=`${p}px`}return t.zIndex!==void 0&&(o.zIndex=t.zIndex),o}),r=e.computed(()=>t.animation==="fade"?"fade":t.animation==="scale-fade"?"scale-fade":"");return(o,p)=>(e.openBlock(),e.createBlock(e.Teleport,{to:"body"},[e.createVNode(e.Transition,{name:r.value},{default:e.withCtx(()=>[t.isOpen?(e.openBlock(),e.createElementBlock("div",e.mergeProps({key:0,ref:t.floatingRef,style:f.value},e.unref(i)),[e.renderSlot(o.$slots,"default",{},void 0,!0),t.floatingArrowRef?(e.openBlock(),e.createElementBlock("div",{key:0,ref:t.floatingArrowRef,style:e.normalizeStyle(n.value)},null,4)):e.createCommentVNode("",!0)],16)):e.createCommentVNode("",!0)]),_:3},8,["name"])]))}}),[["__scopeId","data-v-366682ad"]]);s.SbContainer=z,s.SbFloating=A,s.SbReference=R,s.useSbFloatingPanel=k,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -1,7 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sb-floating-panel-vue",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A lightweight Vue 3
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A flexible and lightweight Vue 3 floating panel system powered by @floating-ui/vue โ includes composable hooks and plug-and-play components with arrow and resize support.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vue",
|
|
7
|
+
"vue3",
|
|
8
|
+
"floating-ui",
|
|
9
|
+
"floating panel",
|
|
10
|
+
"tooltip",
|
|
11
|
+
"popover",
|
|
12
|
+
"dropdown",
|
|
13
|
+
"floating",
|
|
14
|
+
"positioning",
|
|
15
|
+
"arrow",
|
|
16
|
+
"teleport",
|
|
17
|
+
"resize",
|
|
18
|
+
"resize-observer",
|
|
19
|
+
"vue-components",
|
|
20
|
+
"composable",
|
|
21
|
+
"vue-library"
|
|
22
|
+
],
|
|
23
|
+
"author": {
|
|
24
|
+
"name": "Stefano Biddau",
|
|
25
|
+
"url": "https://www.stefano-biddau.com"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/stefanBid/sb-floating-panel-vue"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/stefanBid/sb-floating-panel-vue/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/stefanBid/sb-floating-panel-vue#readme",
|
|
5
36
|
"main": "dist/sb-floating-panel.umd.js",
|
|
6
37
|
"module": "dist/sb-floating-panel.es.js",
|
|
7
38
|
"types": "dist/index.d.ts",
|
|
@@ -10,26 +41,26 @@
|
|
|
10
41
|
"types": "./dist/index.d.ts",
|
|
11
42
|
"import": "./dist/sb-floating-panel.es.js",
|
|
12
43
|
"require": "./dist/sb-floating-panel.umd.js"
|
|
44
|
+
},
|
|
45
|
+
"./style.css": {
|
|
46
|
+
"default": "./dist/sb-floating-panel-vue.css"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"typesVersions": {
|
|
50
|
+
"*": {
|
|
51
|
+
"*": ["dist/index.d.ts"]
|
|
13
52
|
}
|
|
14
53
|
},
|
|
15
54
|
"files": [
|
|
16
55
|
"dist"
|
|
17
56
|
],
|
|
57
|
+
"sideEffects": false,
|
|
18
58
|
"scripts": {
|
|
19
59
|
"dev": "vite",
|
|
20
60
|
"build": "vite build",
|
|
21
61
|
"lint": "eslint . --ext .ts",
|
|
22
62
|
"check": "vue-tsc --noEmit"
|
|
23
63
|
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"vue",
|
|
26
|
-
"floating-ui",
|
|
27
|
-
"hook",
|
|
28
|
-
"composable",
|
|
29
|
-
"floating panel"
|
|
30
|
-
],
|
|
31
|
-
"author": "Stefano Biddau",
|
|
32
|
-
"license": "MIT",
|
|
33
64
|
"peerDependencies": {
|
|
34
65
|
"vue": "^3.5.13"
|
|
35
66
|
},
|
|
@@ -37,13 +68,14 @@
|
|
|
37
68
|
"@floating-ui/vue": "^1.1.6"
|
|
38
69
|
},
|
|
39
70
|
"devDependencies": {
|
|
40
|
-
"@types/node": "^22.15.
|
|
41
|
-
"@typescript-eslint/eslint-plugin": "^8.32.
|
|
42
|
-
"@typescript-eslint/parser": "^8.32.
|
|
71
|
+
"@types/node": "^22.15.18",
|
|
72
|
+
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
73
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
43
74
|
"@vitejs/plugin-vue": "^5.2.4",
|
|
44
75
|
"eslint": "^9.26.0",
|
|
45
76
|
"eslint-plugin-prettier": "^5.4.0",
|
|
46
77
|
"eslint-plugin-vue": "^10.1.0",
|
|
78
|
+
"vue-eslint-parser": "10.1.3",
|
|
47
79
|
"prettier": "^3.5.3",
|
|
48
80
|
"typescript": "~5.7.2",
|
|
49
81
|
"vite": "^6.3.5",
|
|
@@ -1,31 +0,0 @@
|
|
|
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 {};
|