@vingy/vueltip 1.1.0 → 1.3.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 +74 -18
- package/dist/index.d.mts +13 -12
- package/dist/index.mjs +37 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,9 +19,11 @@ pnpm add vueltip
|
|
|
19
19
|
Register the tooltip in your app:
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
import
|
|
22
|
+
import { vueltipPlugin, vueltipDirective } from 'vueltip'
|
|
23
23
|
|
|
24
|
-
createApp(App)
|
|
24
|
+
createApp(App)
|
|
25
|
+
.use(vueltipPlugin, { component: Tooltip })
|
|
26
|
+
.directive('tooltip', vueltipDirective)
|
|
25
27
|
```
|
|
26
28
|
|
|
27
29
|
## Usage
|
|
@@ -49,19 +51,18 @@ First, create a tooltip component using the \`useTooltip\` composable:
|
|
|
49
51
|
</template>
|
|
50
52
|
|
|
51
53
|
<script setup>
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
+
import { useTemplateRef } from 'vue'
|
|
55
|
+
import { useVueltip } from 'vueltip'
|
|
54
56
|
|
|
55
|
-
const tooltipElement =
|
|
56
|
-
const arrowElement =
|
|
57
|
+
const tooltipElement = useTemplateRef('tooltipElement')
|
|
58
|
+
const arrowElement = useTemplateRef('arrowElement')
|
|
57
59
|
|
|
58
60
|
const { tooltipStyles, arrowStyles, show, content } =
|
|
59
|
-
|
|
61
|
+
useVueltip({
|
|
60
62
|
tooltipElement,
|
|
61
63
|
arrowElement,
|
|
62
64
|
offset: 8,
|
|
63
65
|
padding: 8,
|
|
64
|
-
arrowSize: 10,
|
|
65
66
|
})
|
|
66
67
|
</script>
|
|
67
68
|
|
|
@@ -89,14 +90,16 @@ Import and register the tooltip component and plugin in your app's entry point:
|
|
|
89
90
|
// main.ts
|
|
90
91
|
import { createApp } from 'vue'
|
|
91
92
|
import App from './App.vue'
|
|
92
|
-
import
|
|
93
|
+
import { vueltipPlugin, vueltipDirective } from 'vueltip'
|
|
93
94
|
import Tooltip from './components/Tooltip.vue'
|
|
94
95
|
|
|
95
96
|
const app = createApp(App)
|
|
96
97
|
|
|
97
|
-
app
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
app
|
|
99
|
+
.use(vueltipPlugin, {
|
|
100
|
+
component: Tooltip,
|
|
101
|
+
})
|
|
102
|
+
.directive('tooltip', vueltipDirective)
|
|
100
103
|
|
|
101
104
|
app.mount('#app')
|
|
102
105
|
```
|
|
@@ -105,20 +108,23 @@ app.mount('#app')
|
|
|
105
108
|
|
|
106
109
|
Now you can use the `v-tooltip` directive on any element:
|
|
107
110
|
|
|
108
|
-
```
|
|
111
|
+
```vue
|
|
109
112
|
<template>
|
|
110
113
|
<div>
|
|
111
|
-
<button v-tooltip="
|
|
112
|
-
Submit
|
|
113
|
-
</button>
|
|
114
|
+
<button v-tooltip="'Click me to submit'">Submit</button>
|
|
114
115
|
|
|
115
116
|
<input
|
|
116
|
-
v-tooltip="
|
|
117
|
+
v-tooltip="'Enter your email address'"
|
|
117
118
|
type="email"
|
|
118
119
|
placeholder="Email"
|
|
119
120
|
/>
|
|
120
121
|
|
|
121
|
-
<span
|
|
122
|
+
<span
|
|
123
|
+
v-tooltip="{
|
|
124
|
+
content: 'This is a helpful tooltip',
|
|
125
|
+
placement: 'right',
|
|
126
|
+
}"
|
|
127
|
+
>
|
|
122
128
|
Hover over me
|
|
123
129
|
</span>
|
|
124
130
|
</div>
|
|
@@ -126,3 +132,53 @@ Now you can use the `v-tooltip` directive on any element:
|
|
|
126
132
|
```
|
|
127
133
|
|
|
128
134
|
See the demo app in [demo/](../../demo/).
|
|
135
|
+
|
|
136
|
+
## Options
|
|
137
|
+
|
|
138
|
+
### Plugin Options
|
|
139
|
+
|
|
140
|
+
The `vueltipPlugin` accepts the following options:
|
|
141
|
+
|
|
142
|
+
| Option | Type | Default | Description |
|
|
143
|
+
| -------------------------- | -------------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
144
|
+
| `component` | `Component` | Required | The Vue component to render as the tooltip |
|
|
145
|
+
| `showDelay` | `number` | `0` | Delay in milliseconds before the tooltip appears on hover |
|
|
146
|
+
| `hideDelay` | `number` | `200` | Delay in milliseconds before the tooltip disappears when the cursor leaves |
|
|
147
|
+
| `defaultPlacement` | `Placement` | `'top'` | Default tooltip placement: `'top'`, `'bottom'`, `'left'`, `'right'`, etc. |
|
|
148
|
+
| `defaultTruncateDetection` | `'x' \| 'y' \| 'both' \| 'none'` | `'both'` | Direction(s) to check for text truncation (`'x'` for horizontal, `'y'` for vertical, `'both'`, or `'none'` to disable) |
|
|
149
|
+
| `handleDialogModals` | `boolean` | `false` | Whether to handle tooltips within HTML `<dialog>` elements with the `open` attribute (modal dialogs) |
|
|
150
|
+
| `placementAttribute` | `string` | `'vueltip-placement'` | HTML attribute name for tooltip placement overrides |
|
|
151
|
+
| `keyAttribute` | `string` | `'vueltip-key'` | HTML attribute name for tooltip identification |
|
|
152
|
+
| `truncateAttribute` | `string` | `'vueltip-truncate'` | HTML attribute name for truncate detection overrides |
|
|
153
|
+
|
|
154
|
+
### useVueltip Composable Options
|
|
155
|
+
|
|
156
|
+
The `useVueltip` composable accepts the following options:
|
|
157
|
+
|
|
158
|
+
| Option | Type | Default | Description |
|
|
159
|
+
| ----------------- | -------------------------- | -------- | ---------------------------------------------------------- |
|
|
160
|
+
| `tooltipElement` | `Ref<HTMLElement \| null>` | Required | Reference to the tooltip container element |
|
|
161
|
+
| `arrowElement` | `Ref<HTMLElement \| null>` | Optional | Reference to the arrow element for positioning |
|
|
162
|
+
| `offset` | `number` | `0` | Offset distance between the tooltip and the target element |
|
|
163
|
+
| `padding` | `number` | `0` | Padding between the tooltip and the viewport edges |
|
|
164
|
+
| `arrowSize` | `number` | `0` | Size of the arrow element (used for proper positioning) |
|
|
165
|
+
| `floatingOptions` | `UseFloatingOptions` | `{}` | Advanced options for the underlying Floating UI library |
|
|
166
|
+
|
|
167
|
+
### Directive Options
|
|
168
|
+
|
|
169
|
+
The `v-tooltip` directive accepts bindings in two formats:
|
|
170
|
+
|
|
171
|
+
**Simple string (text only):**
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
v-tooltip="'Tooltip text'"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Object with options:**
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
v-tooltip="{
|
|
181
|
+
content: 'Tooltip text',
|
|
182
|
+
placement: 'right' // Placement: 'top', 'bottom', 'left', 'right', etc.
|
|
183
|
+
}"
|
|
184
|
+
```
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __reExport, t as __exportAll } from "./chunk-CtajNgzt.mjs";
|
|
2
2
|
import * as Vue from "vue";
|
|
3
|
-
import { App, Component, Directive, ShallowRef, StyleValue } from "vue";
|
|
3
|
+
import { App, Component, Directive, DirectiveBinding, ShallowRef, StyleValue } from "vue";
|
|
4
4
|
|
|
5
5
|
//#region ../../node_modules/.pnpm/@floating-ui+utils@0.2.10/node_modules/@floating-ui/utils/dist/floating-ui.utils.d.mts
|
|
6
6
|
declare type AlignedPlacement = `${Side}-${Alignment}`;
|
|
@@ -244,16 +244,20 @@ declare type UseFloatingOptions<T extends ReferenceElement = ReferenceElement> =
|
|
|
244
244
|
whileElementsMounted?: (reference: T, floating: FloatingElement, update: () => void) => () => void;
|
|
245
245
|
};
|
|
246
246
|
//#endregion
|
|
247
|
+
//#region ../shared/dist/types.d.mts
|
|
248
|
+
//#region src/types.d.ts
|
|
249
|
+
type Maybe<T> = T | null | undefined; //#endregion
|
|
250
|
+
//#endregion
|
|
247
251
|
//#region src/types.d.ts
|
|
248
252
|
interface Content {
|
|
249
|
-
text: string
|
|
253
|
+
text: Maybe<string>;
|
|
250
254
|
}
|
|
251
|
-
type Binding = string | {
|
|
252
|
-
content: string | Content
|
|
255
|
+
type Binding = Maybe<string> | {
|
|
256
|
+
content: Maybe<string | Content>;
|
|
253
257
|
placement: Placement;
|
|
254
258
|
};
|
|
255
259
|
type Modifier = 'x' | 'y' | 'none' | 'both';
|
|
256
|
-
type TooltipDirective = Directive<HTMLElement, Binding, Modifier>;
|
|
260
|
+
type TooltipDirective = Directive<HTMLElement, Binding, Modifier, Placement>;
|
|
257
261
|
type Options = {
|
|
258
262
|
/** @default 'vueltip-placement' */placementAttribute: string; /** @default 'vueltip-key' */
|
|
259
263
|
keyAttribute: string; /** @default 'vueltip-truncate' */
|
|
@@ -261,7 +265,8 @@ type Options = {
|
|
|
261
265
|
showDelay: number; /** @default 200 */
|
|
262
266
|
hideDelay: number; /** @default false */
|
|
263
267
|
handleDialogModals: boolean; /** @default 'both' */
|
|
264
|
-
defaultTruncateDetection: Modifier;
|
|
268
|
+
defaultTruncateDetection: Modifier; /** @default 'top' */
|
|
269
|
+
defaultPlacement: Placement;
|
|
265
270
|
};
|
|
266
271
|
type UseTooltipOptions = {
|
|
267
272
|
tooltipElement: Readonly<ShallowRef<HTMLElement | null>>;
|
|
@@ -277,10 +282,6 @@ declare module 'vue' {
|
|
|
277
282
|
}
|
|
278
283
|
}
|
|
279
284
|
//#endregion
|
|
280
|
-
//#region ../shared/dist/types.d.mts
|
|
281
|
-
//#region src/types.d.ts
|
|
282
|
-
type Maybe<T> = T | null | undefined; //#endregion
|
|
283
|
-
//#endregion
|
|
284
285
|
//#region src/composables.d.ts
|
|
285
286
|
declare const useVueltip: ({
|
|
286
287
|
tooltipElement,
|
|
@@ -310,8 +311,8 @@ declare const useVueltip: ({
|
|
|
310
311
|
//#endregion
|
|
311
312
|
//#region src/directive.d.ts
|
|
312
313
|
declare const vueltipDirective: {
|
|
313
|
-
updated: (el: HTMLElement, binding:
|
|
314
|
-
created: (el: HTMLElement, binding:
|
|
314
|
+
updated: (el: HTMLElement, binding: DirectiveBinding<Binding, Modifier, Placement>) => void;
|
|
315
|
+
created: (el: HTMLElement, binding: DirectiveBinding<Binding, Modifier, Placement>) => void;
|
|
315
316
|
beforeUnmount: (el: HTMLElement) => void;
|
|
316
317
|
};
|
|
317
318
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -1396,7 +1396,8 @@ let options = {
|
|
|
1396
1396
|
showDelay: 0,
|
|
1397
1397
|
hideDelay: 200,
|
|
1398
1398
|
handleDialogModals: false,
|
|
1399
|
-
defaultTruncateDetection: "both"
|
|
1399
|
+
defaultTruncateDetection: "both",
|
|
1400
|
+
defaultPlacement: "top"
|
|
1400
1401
|
};
|
|
1401
1402
|
const setOptions = (opts) => {
|
|
1402
1403
|
options = {
|
|
@@ -1404,6 +1405,7 @@ const setOptions = (opts) => {
|
|
|
1404
1405
|
...opts
|
|
1405
1406
|
};
|
|
1406
1407
|
};
|
|
1408
|
+
const getOption = (key) => options[key];
|
|
1407
1409
|
|
|
1408
1410
|
//#endregion
|
|
1409
1411
|
//#region src/state.ts
|
|
@@ -1411,10 +1413,10 @@ const tooltipPlacement = ref("top");
|
|
|
1411
1413
|
const debouncedTooltipPlacement = ref("top");
|
|
1412
1414
|
const hoveredElement = ref();
|
|
1413
1415
|
const debouncedHoveredElement = ref();
|
|
1414
|
-
const contentMap = /* @__PURE__ */ new Map();
|
|
1415
|
-
const getContent = (key) => contentMap.get(key);
|
|
1416
|
-
const setContent = (key, value) => contentMap.set(key, value);
|
|
1417
|
-
const deleteContent = (key) => contentMap.delete(key);
|
|
1416
|
+
const contentMap = ref(/* @__PURE__ */ new Map());
|
|
1417
|
+
const getContent = (key) => contentMap.value.get(key);
|
|
1418
|
+
const setContent = (key, value) => contentMap.value.set(key, value);
|
|
1419
|
+
const deleteContent = (key) => contentMap.value.delete(key);
|
|
1418
1420
|
const generateKey = () => crypto.randomUUID();
|
|
1419
1421
|
const tooltipKey = ref();
|
|
1420
1422
|
const tooltipContent = ref();
|
|
@@ -1422,11 +1424,12 @@ let timerId;
|
|
|
1422
1424
|
watch([
|
|
1423
1425
|
tooltipKey,
|
|
1424
1426
|
hoveredElement,
|
|
1425
|
-
tooltipPlacement
|
|
1427
|
+
tooltipPlacement,
|
|
1428
|
+
() => getContent(tooltipKey.value ?? "")
|
|
1426
1429
|
], ([key, el, placement]) => {
|
|
1427
1430
|
if (!key) return;
|
|
1428
1431
|
if (timerId) clearTimeout(timerId);
|
|
1429
|
-
const timeout = el ?
|
|
1432
|
+
const timeout = el ? getOption("showDelay") : getOption("hideDelay");
|
|
1430
1433
|
timerId = setTimeout(() => {
|
|
1431
1434
|
tooltipContent.value = getContent(key);
|
|
1432
1435
|
debouncedHoveredElement.value = el;
|
|
@@ -1479,7 +1482,7 @@ const useVueltip = ({ tooltipElement, arrowElement, offset: _offset, padding, ar
|
|
|
1479
1482
|
};
|
|
1480
1483
|
});
|
|
1481
1484
|
const show = computed(() => !!debouncedHoveredElement.value);
|
|
1482
|
-
if (
|
|
1485
|
+
if (getOption("handleDialogModals")) watch(show, (value) => {
|
|
1483
1486
|
if (!value || !tooltipElement.value || !debouncedHoveredElement.value || !initialParent) return;
|
|
1484
1487
|
const dialogEl = debouncedHoveredElement.value.closest("dialog");
|
|
1485
1488
|
if (!dialogEl) {
|
|
@@ -1510,7 +1513,7 @@ function isTruncated(el) {
|
|
|
1510
1513
|
}
|
|
1511
1514
|
}
|
|
1512
1515
|
function getTruncationDirection(el) {
|
|
1513
|
-
return el.getAttribute(
|
|
1516
|
+
return el.getAttribute(getOption("truncateAttribute")) ?? getOption("defaultTruncateDetection");
|
|
1514
1517
|
}
|
|
1515
1518
|
function elementContainsText(el, text) {
|
|
1516
1519
|
if (isInputElement(el) || isTextAreaElement(el)) return getInputValue(el).includes(text);
|
|
@@ -1529,7 +1532,7 @@ function getInputValue(el) {
|
|
|
1529
1532
|
return el.value;
|
|
1530
1533
|
}
|
|
1531
1534
|
const ensureKey = (el, fn) => {
|
|
1532
|
-
const key = el.getAttribute(
|
|
1535
|
+
const key = el.getAttribute(getOption("keyAttribute"));
|
|
1533
1536
|
if (!key) return;
|
|
1534
1537
|
return fn(key);
|
|
1535
1538
|
};
|
|
@@ -1545,8 +1548,8 @@ const onMouseover = ensureEventTarget((target) => ensureKey(target, (key) => {
|
|
|
1545
1548
|
const content = getContent(key);
|
|
1546
1549
|
if (!content) return;
|
|
1547
1550
|
const { text } = content;
|
|
1548
|
-
if (elementContainsText(target, text) && !isTruncated(target)) return;
|
|
1549
|
-
const placement = target.getAttribute(
|
|
1551
|
+
if (!text || elementContainsText(target, text) && !isTruncated(target)) return;
|
|
1552
|
+
const placement = target.getAttribute(getOption("placementAttribute"));
|
|
1550
1553
|
tooltipKey.value = key;
|
|
1551
1554
|
hoveredElement.value = target;
|
|
1552
1555
|
tooltipPlacement.value = placement;
|
|
@@ -1558,26 +1561,41 @@ const onMouseout = ensureEventTarget((target) => {
|
|
|
1558
1561
|
|
|
1559
1562
|
//#endregion
|
|
1560
1563
|
//#region src/directive.ts
|
|
1561
|
-
const toContent = (value) =>
|
|
1562
|
-
|
|
1564
|
+
const toContent = (value) => {
|
|
1565
|
+
if (value == null) return { text: value };
|
|
1566
|
+
if (typeof value === "string") return { text: value };
|
|
1567
|
+
if (value.content == null) return { text: value.content };
|
|
1568
|
+
if (typeof value.content === "string") return { text: value.content };
|
|
1569
|
+
return value.content;
|
|
1570
|
+
};
|
|
1571
|
+
const extractPlacement = (binding) => {
|
|
1572
|
+
const { value, arg } = binding;
|
|
1573
|
+
if (value && typeof value !== "string" && "placement" in value) return value.placement;
|
|
1574
|
+
if (!arg) return getOption("defaultPlacement");
|
|
1575
|
+
return arg;
|
|
1576
|
+
};
|
|
1563
1577
|
const truncationDirection = (modifiers) => {
|
|
1564
1578
|
if (modifiers.none) return "none";
|
|
1565
1579
|
if (modifiers.both) return "both";
|
|
1566
1580
|
if (modifiers.x && modifiers.y) return "both";
|
|
1567
1581
|
if (modifiers.x) return "x";
|
|
1568
1582
|
if (modifiers.y) return "y";
|
|
1569
|
-
return
|
|
1583
|
+
return getOption("defaultTruncateDetection");
|
|
1570
1584
|
};
|
|
1571
1585
|
const vueltipDirective = {
|
|
1572
1586
|
updated: (el, binding) => {
|
|
1573
|
-
ensureKey(el, (key) =>
|
|
1587
|
+
ensureKey(el, (key) => {
|
|
1588
|
+
el.setAttribute(getOption("placementAttribute"), extractPlacement(binding));
|
|
1589
|
+
el.setAttribute(getOption("truncateAttribute"), truncationDirection(binding.modifiers ?? {}));
|
|
1590
|
+
setContent(key, toContent(binding.value));
|
|
1591
|
+
});
|
|
1574
1592
|
},
|
|
1575
1593
|
created: (el, binding) => {
|
|
1576
1594
|
const key = generateKey();
|
|
1577
1595
|
setContent(key, toContent(binding.value));
|
|
1578
|
-
el.setAttribute(
|
|
1579
|
-
el.setAttribute(
|
|
1580
|
-
el.setAttribute(
|
|
1596
|
+
el.setAttribute(getOption("keyAttribute"), key);
|
|
1597
|
+
el.setAttribute(getOption("placementAttribute"), extractPlacement(binding));
|
|
1598
|
+
el.setAttribute(getOption("truncateAttribute"), truncationDirection(binding.modifiers ?? {}));
|
|
1581
1599
|
el.addEventListener("mouseenter", onMouseover);
|
|
1582
1600
|
el.addEventListener("focus", onMouseover);
|
|
1583
1601
|
el.addEventListener("mouseleave", onMouseout);
|