@data-slot/tooltip 0.2.140 → 0.2.142
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 +104 -20
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ const tooltip = createTooltip(element, {
|
|
|
59
59
|
|--------|------|---------|-------------|
|
|
60
60
|
| `delay` | `number` | `300` | Delay before showing tooltip (ms) |
|
|
61
61
|
| `skipDelayDuration` | `number` | `300` | Duration to skip delay after closing (ms). Set to `0` to disable warm-up. |
|
|
62
|
-
| `side` | `"top" \| "right" \| "bottom" \| "left"` | `"top"` | Preferred side relative to trigger |
|
|
62
|
+
| `side` | `"top" \| "right" \| "bottom" \| "left" \| "inline-start" \| "inline-end"` | `"top"` | Preferred side relative to trigger |
|
|
63
63
|
| `align` | `"start" \| "center" \| "end"` | `"center"` | Preferred alignment |
|
|
64
64
|
| `sideOffset` | `number` | `4` | Distance from trigger in pixels |
|
|
65
65
|
| `alignOffset` | `number` | `0` | Offset from alignment edge in pixels |
|
|
@@ -85,7 +85,7 @@ Placement attributes (`data-side`, `data-align`, `data-side-offset`, `data-align
|
|
|
85
85
|
|-----------|------|---------|-------------|
|
|
86
86
|
| `data-delay` | number | `300` | Delay before showing tooltip (ms) |
|
|
87
87
|
| `data-skip-delay-duration` | number | `300` | Duration to skip delay after closing (ms) |
|
|
88
|
-
| `data-side` | string | `"top"` | Side relative to trigger |
|
|
88
|
+
| `data-side` | string | `"top"` | Side relative to trigger (`top`, `right`, `bottom`, `left`, `inline-start`, `inline-end`) |
|
|
89
89
|
| `data-align` | string | `"center"` | Alignment along the side |
|
|
90
90
|
| `data-side-offset` | number | `4` | Distance from trigger (px) |
|
|
91
91
|
| `data-align-offset` | number | `0` | Alignment edge offset (px) |
|
|
@@ -130,7 +130,10 @@ Placement attributes (`data-side`, `data-align`, `data-side-offset`, `data-align
|
|
|
130
130
|
```html
|
|
131
131
|
<div data-slot="tooltip">
|
|
132
132
|
<button data-slot="tooltip-trigger">Trigger</button>
|
|
133
|
-
<div data-slot="tooltip-content">
|
|
133
|
+
<div data-slot="tooltip-content">
|
|
134
|
+
Content
|
|
135
|
+
<div data-slot="tooltip-arrow"></div>
|
|
136
|
+
</div>
|
|
134
137
|
</div>
|
|
135
138
|
```
|
|
136
139
|
|
|
@@ -143,6 +146,7 @@ Placement attributes (`data-side`, `data-align`, `data-side-offset`, `data-align
|
|
|
143
146
|
|
|
144
147
|
- `tooltip-positioner` - Optional authored positioning wrapper
|
|
145
148
|
- `tooltip-portal` - Optional authored portal wrapper that can contain `tooltip-positioner`
|
|
149
|
+
- `tooltip-arrow` - Optional arrow element positioned against the trigger
|
|
146
150
|
|
|
147
151
|
### Composed Portal Markup (Optional)
|
|
148
152
|
|
|
@@ -151,7 +155,10 @@ Placement attributes (`data-side`, `data-align`, `data-side-offset`, `data-align
|
|
|
151
155
|
<button data-slot="tooltip-trigger">Trigger</button>
|
|
152
156
|
<div data-slot="tooltip-portal">
|
|
153
157
|
<div data-slot="tooltip-positioner">
|
|
154
|
-
<div data-slot="tooltip-content">
|
|
158
|
+
<div data-slot="tooltip-content">
|
|
159
|
+
Content
|
|
160
|
+
<div data-slot="tooltip-arrow"></div>
|
|
161
|
+
</div>
|
|
155
162
|
</div>
|
|
156
163
|
</div>
|
|
157
164
|
</div>
|
|
@@ -163,16 +170,28 @@ The component sets these attributes automatically:
|
|
|
163
170
|
|
|
164
171
|
| Element | Attribute | Values |
|
|
165
172
|
|---------|-----------|--------|
|
|
166
|
-
| Root | `data-state` | `"open"` \| `"closed"` |
|
|
173
|
+
| Root | `data-state` | `"open"` \| `"closed"` (legacy compatibility) |
|
|
167
174
|
| Root | `data-open` / `data-closed` | Present when matching state |
|
|
168
|
-
| Root | `data-instant` |
|
|
169
|
-
| Content | `data-state` | `"open"` \| `"closed"` |
|
|
175
|
+
| Root | `data-instant` | `"delay"` \| `"focus"` \| `"dismiss"` |
|
|
176
|
+
| Content | `data-state` | `"open"` \| `"closed"` (legacy compatibility) |
|
|
170
177
|
| Content | `data-open` / `data-closed` | Present when matching state |
|
|
171
|
-
| Content | `data-
|
|
172
|
-
| Content | `data-
|
|
178
|
+
| Content | `data-starting-style` | Present while opening |
|
|
179
|
+
| Content | `data-ending-style` | Present while closing |
|
|
180
|
+
| Content | `data-instant` | `"delay"` \| `"focus"` \| `"dismiss"` |
|
|
181
|
+
| Content | `data-side` | `"top"` \| `"right"` \| `"bottom"` \| `"left"` \| `"inline-start"` \| `"inline-end"` |
|
|
173
182
|
| Content | `data-align` | `"start"` \| `"center"` \| `"end"` |
|
|
174
183
|
| Content | `role` | `"tooltip"` |
|
|
175
184
|
| Content | `aria-hidden` | `"true"` when closed, `"false"` when open |
|
|
185
|
+
| Positioner | `data-open` / `data-closed` | Present when matching state |
|
|
186
|
+
| Positioner | `data-instant` | `"delay"` \| `"focus"` \| `"dismiss"` |
|
|
187
|
+
| Positioner | `data-side` | `"top"` \| `"right"` \| `"bottom"` \| `"left"` \| `"inline-start"` \| `"inline-end"` |
|
|
188
|
+
| Positioner | `data-align` | `"start"` \| `"center"` \| `"end"` |
|
|
189
|
+
| Arrow | `data-open` / `data-closed` | Present when matching state |
|
|
190
|
+
| Arrow | `data-instant` | `"delay"` \| `"focus"` \| `"dismiss"` |
|
|
191
|
+
| Arrow | `data-side` | `"top"` \| `"right"` \| `"bottom"` \| `"left"` \| `"inline-start"` \| `"inline-end"` |
|
|
192
|
+
| Arrow | `data-align` | `"start"` \| `"center"` \| `"end"` |
|
|
193
|
+
| Arrow | `data-uncentered` | Present when the arrow cannot stay perfectly centered |
|
|
194
|
+
| Arrow | `aria-hidden` | `"true"` |
|
|
176
195
|
| Trigger | `aria-describedby` | Content ID when open, removed when closed |
|
|
177
196
|
|
|
178
197
|
## Styling
|
|
@@ -180,23 +199,42 @@ The component sets these attributes automatically:
|
|
|
180
199
|
Position is computed in JavaScript and applied to the positioner as `position: absolute` + `transform: translate3d(...)`.
|
|
181
200
|
By default, content is portaled to `document.body` while open.
|
|
182
201
|
The positioned element (`tooltip-positioner`, or `tooltip-content` when `portal` is disabled) gets `--transform-origin`, which `tooltip-content` can use for transform animations via CSS inheritance.
|
|
183
|
-
Use `data-open` / `data-closed`, `data-side`, and `data-
|
|
202
|
+
Use `data-open` / `data-closed`, `data-starting-style` / `data-ending-style`, `data-side`, `data-align`, and `data-instant` for styling and animations.
|
|
184
203
|
Placement uses layout dimensions, so `scale`/`zoom` animations on `tooltip-content` remain stable without adding an extra wrapper.
|
|
204
|
+
Tooltip arrow geometry is runtime-owned: the controller writes inline `top` / `left` coordinates and `position: absolute` on `tooltip-arrow`. CSS should only handle edge attachment, rotation, and optional cosmetic nudges. Avoid overriding the arrow cross-axis with helpers like `top-1/2`, `left-1/2`, or `-translate-y-1/2`.
|
|
185
205
|
|
|
186
206
|
### Recommended CSS
|
|
187
207
|
|
|
188
|
-
The
|
|
208
|
+
The example below matches the Base/shadcn composition style: real `tooltip-arrow`, logical side support, and valued `data-instant`.
|
|
189
209
|
|
|
190
210
|
```css
|
|
191
211
|
[data-slot="tooltip-content"] {
|
|
212
|
+
position: absolute;
|
|
213
|
+
display: inline-flex;
|
|
214
|
+
align-items: center;
|
|
215
|
+
gap: 0.375rem;
|
|
216
|
+
padding: 0.375rem 0.75rem;
|
|
217
|
+
border-radius: 1rem;
|
|
218
|
+
font-size: 0.75rem;
|
|
192
219
|
white-space: nowrap;
|
|
220
|
+
background: #111827;
|
|
221
|
+
color: white;
|
|
193
222
|
opacity: 0;
|
|
194
223
|
visibility: hidden;
|
|
195
224
|
pointer-events: none;
|
|
196
|
-
transform-origin: var(--transform-origin, center);
|
|
225
|
+
transform-origin: var(--transform-origin, center center);
|
|
226
|
+
--tooltip-slide-x: 0px;
|
|
227
|
+
--tooltip-slide-y: 0px;
|
|
197
228
|
transition: opacity 0.15s ease, visibility 0s linear 0.15s;
|
|
198
229
|
}
|
|
199
230
|
|
|
231
|
+
[data-slot="tooltip-content"][data-side="top"] { --tooltip-slide-y: 8px; }
|
|
232
|
+
[data-slot="tooltip-content"][data-side="bottom"] { --tooltip-slide-y: -8px; }
|
|
233
|
+
[data-slot="tooltip-content"][data-side="left"] { --tooltip-slide-x: 8px; }
|
|
234
|
+
[data-slot="tooltip-content"][data-side="right"] { --tooltip-slide-x: -8px; }
|
|
235
|
+
[data-slot="tooltip-content"][data-side="inline-start"] { --tooltip-slide-x: 8px; }
|
|
236
|
+
[data-slot="tooltip-content"][data-side="inline-end"] { --tooltip-slide-x: -8px; }
|
|
237
|
+
|
|
200
238
|
[data-slot="tooltip-content"][data-open] {
|
|
201
239
|
opacity: 1;
|
|
202
240
|
visibility: visible;
|
|
@@ -212,27 +250,68 @@ The visibility transition trick keeps the tooltip visible during fade-out, then
|
|
|
212
250
|
transition: none;
|
|
213
251
|
animation: none;
|
|
214
252
|
}
|
|
253
|
+
|
|
254
|
+
[data-slot="tooltip-arrow"] {
|
|
255
|
+
width: 0.625rem;
|
|
256
|
+
height: 0.625rem;
|
|
257
|
+
background: inherit;
|
|
258
|
+
border-radius: 2px;
|
|
259
|
+
transform: rotate(45deg);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
[data-slot="tooltip-arrow"][data-side="top"] { bottom: -0.25rem; }
|
|
263
|
+
[data-slot="tooltip-arrow"][data-side="bottom"] { top: -0.25rem; }
|
|
264
|
+
[data-slot="tooltip-arrow"][data-side="left"] {
|
|
265
|
+
right: -0.25rem;
|
|
266
|
+
transform: translateX(-1.5px) rotate(45deg);
|
|
267
|
+
}
|
|
268
|
+
[data-slot="tooltip-arrow"][data-side="right"] {
|
|
269
|
+
left: -0.25rem;
|
|
270
|
+
transform: translateX(1.5px) rotate(45deg);
|
|
271
|
+
}
|
|
272
|
+
[data-slot="tooltip-arrow"][data-side="inline-start"] {
|
|
273
|
+
right: -0.25rem;
|
|
274
|
+
transform: translateX(-1.5px) rotate(45deg);
|
|
275
|
+
}
|
|
276
|
+
[data-slot="tooltip-arrow"][data-side="inline-end"] {
|
|
277
|
+
left: -0.25rem;
|
|
278
|
+
transform: translateX(1.5px) rotate(45deg);
|
|
279
|
+
}
|
|
215
280
|
```
|
|
216
281
|
|
|
217
282
|
### Tailwind Example
|
|
218
283
|
|
|
219
|
-
Use
|
|
284
|
+
Use content and arrow data attributes for open-state styling:
|
|
220
285
|
|
|
221
286
|
```html
|
|
222
287
|
<div data-slot="tooltip">
|
|
223
288
|
<button data-slot="tooltip-trigger">
|
|
224
289
|
Hover me
|
|
225
290
|
</button>
|
|
226
|
-
<div
|
|
227
|
-
data-slot="tooltip-content"
|
|
291
|
+
<div
|
|
292
|
+
data-slot="tooltip-content"
|
|
228
293
|
data-side="top"
|
|
229
294
|
class="px-2 py-1
|
|
230
295
|
bg-gray-900 text-white text-sm rounded
|
|
231
296
|
opacity-0 pointer-events-none transition-opacity duration-150
|
|
232
|
-
data-[open]:opacity-100
|
|
233
|
-
data-[
|
|
297
|
+
data-[open]:opacity-100 data-[open]:pointer-events-auto
|
|
298
|
+
data-[instant]:transition-none"
|
|
234
299
|
>
|
|
235
300
|
Tooltip text
|
|
301
|
+
<div
|
|
302
|
+
data-slot="tooltip-arrow"
|
|
303
|
+
class="absolute size-2.5 rotate-45 bg-gray-900
|
|
304
|
+
data-[side=top]:-bottom-1
|
|
305
|
+
data-[side=bottom]:-top-1
|
|
306
|
+
data-[side=left]:-right-1
|
|
307
|
+
data-[side=left]:-translate-x-[1.5px]
|
|
308
|
+
data-[side=right]:-left-1
|
|
309
|
+
data-[side=right]:translate-x-[1.5px]
|
|
310
|
+
data-[side=inline-start]:-right-1
|
|
311
|
+
data-[side=inline-start]:-translate-x-[1.5px]
|
|
312
|
+
data-[side=inline-end]:-left-1
|
|
313
|
+
data-[side=inline-end]:translate-x-[1.5px]"
|
|
314
|
+
></div>
|
|
236
315
|
</div>
|
|
237
316
|
</div>
|
|
238
317
|
```
|
|
@@ -243,8 +322,9 @@ When a user closes one tooltip and quickly hovers another, the second tooltip sh
|
|
|
243
322
|
|
|
244
323
|
- Controlled by `skipDelayDuration` option
|
|
245
324
|
- Set to `0` to disable this behavior
|
|
246
|
-
- Warm-up
|
|
247
|
-
-
|
|
325
|
+
- Warm-up opens and warm handoff closes use `data-instant="delay"`
|
|
326
|
+
- Focus-triggered opens use `data-instant="focus"`
|
|
327
|
+
- Dismiss-style closes (for example `Escape`) use `data-instant="dismiss"`
|
|
248
328
|
- Warm window is set only when a tooltip actually closes (not when a pending open is cancelled)
|
|
249
329
|
|
|
250
330
|
## Accessibility
|
|
@@ -325,7 +405,11 @@ element.dispatchEvent(
|
|
|
325
405
|
|
|
326
406
|
#### Deprecated Shapes
|
|
327
407
|
|
|
328
|
-
The following
|
|
408
|
+
The following attributes and shapes are deprecated and will be removed in v1.0:
|
|
409
|
+
|
|
410
|
+
- Legacy `data-state="open|closed"` styling on `tooltip` root and `tooltip-content`
|
|
411
|
+
|
|
412
|
+
Use `data-open` / `data-closed`, `data-starting-style`, `data-ending-style`, and `data-instant` instead.
|
|
329
413
|
|
|
330
414
|
```javascript
|
|
331
415
|
// Deprecated: { value: boolean }
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@data-slot/core`);const t=`@data-slot/tooltip`;let n=0;const r=new Set,i=new Set,a=(e,t)=>{if(!e)return!1;for(let n of r)if(n!==t&&n.contains(e))return!0;return!1},o=(e,t)=>{for(let n of i)n(e,t)},s=[`top`,`right`,`bottom`,`left`],c=[`start`,`center`,`end`];function
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@data-slot/core`);const t=`@data-slot/tooltip`;let n=0;const r=new Set,i=new Set,a=(e,t)=>{if(!e)return!1;for(let n of r)if(n!==t&&n.contains(e))return!0;return!1},o=(e,t)=>{for(let n of i)n(e,t)},s=[`top`,`right`,`bottom`,`left`,`inline-start`,`inline-end`],c=[`start`,`center`,`end`],l=(e,t)=>e===`inline-start`?t===`rtl`?`right`:`left`:e===`inline-end`?t===`rtl`?`left`:`right`:e,u=(...e)=>[...new Set(e.filter(e=>e!=null))];function d(d,f={}){let p=(0,e.reuseRootBinding)(d,t,`[@data-slot/tooltip] createTooltip() called more than once for the same root. Returning the existing controller. Destroy it before rebinding with new options.`);if(p)return p;let m=(0,e.getPart)(d,`tooltip-trigger`),h=(0,e.getPart)(d,`tooltip-content`),g=h?.querySelector(`[data-slot="tooltip-arrow"]`)??null,_=(0,e.getPart)(d,`tooltip-positioner`),v=_&&h&&_.contains(h)?_:null,y=(0,e.getPart)(d,`tooltip-portal`),b=y&&v&&y.contains(v)?y:null;if(!m||!h)throw Error(`Tooltip requires trigger and content slots`);g&&(g.setAttribute(`aria-hidden`,`true`),g.style.position=`absolute`);let x=f.delay??(0,e.getDataNumber)(d,`delay`)??300,S=f.skipDelayDuration??(0,e.getDataNumber)(d,`skipDelayDuration`)??300,C=f.onOpenChange,w=f.portal??(0,e.getDataBool)(h,`portal`)??(0,e.getDataBool)(d,`portal`)??!0,T=(t,n)=>(0,e.getDataEnum)(h,t,n)??(v?(0,e.getDataEnum)(v,t,n):void 0)??(0,e.getDataEnum)(d,t,n),E=t=>(0,e.getDataNumber)(h,t)??(v?(0,e.getDataNumber)(v,t):void 0)??(0,e.getDataNumber)(d,t),D=t=>(0,e.getDataBool)(h,t)??(v?(0,e.getDataBool)(v,t):void 0)??(0,e.getDataBool)(d,t),O=f.side??T(`side`,s)??`top`,k=f.align??T(`align`,c)??`center`,ee=f.sideOffset??E(`sideOffset`)??4,A=f.alignOffset??E(`alignOffset`)??0,j=f.avoidCollisions??D(`avoidCollisions`)??!0,M=f.collisionPadding??E(`collisionPadding`)??8,N=!1,P=null,F=!1,I=!1,L=null,R=[],z=(0,e.createPortalLifecycle)({content:h,root:d,enabled:w,wrapperSlot:v?void 0:`tooltip-positioner`,container:v??void 0,mountTarget:v?b??v:void 0}),B=(0,e.ensureId)(h,`tooltip-content`);h.setAttribute(`role`,`tooltip`);let te=()=>{let e=d instanceof HTMLElement?d:null;return(e?.getAttribute(`dir`)??m.getAttribute(`dir`))===`rtl`||(getComputedStyle(m).direction||(e?getComputedStyle(e).direction:``)||d.ownerDocument.documentElement.getAttribute(`dir`)||``)===`rtl`?`rtl`:`ltr`},V=(e,t)=>{let n=z.container;for(let r of u(h,n,g))r.setAttribute(`data-side`,e),r.setAttribute(`data-align`,t)},H=e=>{let t=z.container;for(let n of u(d,h,t,g))e?n.setAttribute(`data-instant`,e):n.removeAttribute(`data-instant`)},U=(e,t,n,r)=>{if(!g)return;g.style.position=`absolute`;let i=g.getBoundingClientRect(),a=g.offsetWidth>0?g.offsetWidth:i.width,o=g.offsetHeight>0?g.offsetHeight:i.height;if(a<=0||o<=0){g.style.removeProperty(`left`),g.style.removeProperty(`top`),g.removeAttribute(`data-uncentered`);return}let s=l(e,t);if(s===`top`||s===`bottom`){let e=n.left+n.width/2-r.left-a/2,t=Math.max(5,r.width-a-5),i=Math.min(Math.max(e,5),t);g.style.left=`${i}px`,g.style.removeProperty(`top`),Math.abs(i-e)>.5?g.setAttribute(`data-uncentered`,``):g.removeAttribute(`data-uncentered`);return}let c=n.top+n.height/2-r.top-o/2,u=Math.max(5,r.height-o-5),d=Math.min(Math.max(c,5),u);g.style.top=`${d}px`,g.style.removeProperty(`left`),Math.abs(d-c)>.5?g.setAttribute(`data-uncentered`,``):g.removeAttribute(`data-uncentered`)},W=e=>{let t=z.container;if(d.setAttribute(`data-state`,e),h.setAttribute(`data-state`,e),H(P),e===`open`){for(let e of u(d,h,t,g))e.setAttribute(`data-open`,``),e.removeAttribute(`data-closed`);return}for(let e of u(d,h,t,g))e.setAttribute(`data-closed`,``),e.removeAttribute(`data-open`)},G=()=>{let t=z.container,n=d.ownerDocument.defaultView??window,r=te(),i=m.getBoundingClientRect(),a=(0,e.computeFloatingPosition)({anchorRect:i,contentRect:(0,e.measurePopupContentRect)(h),side:O,align:k,sideOffset:ee,alignOffset:A,avoidCollisions:j,collisionPadding:M,direction:r}),o=(0,e.computeFloatingTransformOrigin)({side:a.side,align:a.align,anchorRect:i,popupX:a.x,popupY:a.y,direction:r});t.style.position=`absolute`,t.style.top=`0px`,t.style.left=`0px`,t.style.transform=`translate3d(${a.x+n.scrollX}px, ${a.y+n.scrollY}px, 0)`,t.style.setProperty(`--transform-origin`,o),t.style.willChange=`transform`,t.style.margin=`0`,V(a.side,a.align),U(a.side,r,i,h.getBoundingClientRect())},K=(0,e.createPresenceLifecycle)({element:h,onExitComplete:()=>{I||(z.restore(),h.hidden=!0)}}),q=(0,e.createPositionSync)({observedElements:[m,h],isActive:()=>N,ancestorScroll:!1,onUpdate:G}),J=()=>m.hasAttribute(`disabled`)||m.getAttribute(`aria-disabled`)===`true`,Y=(t,r,i=null)=>{N!==t&&(!t&&N&&S>0&&(n=Date.now()+S),P=i,N=t,N?(m.setAttribute(`aria-describedby`,B),h.setAttribute(`aria-hidden`,`false`),z.mount(),h.hidden=!1,W(`open`),K.enter(),G(),q.start(),q.update()):(W(`closed`),m.removeAttribute(`aria-describedby`),h.setAttribute(`aria-hidden`,`true`),K.exit(),q.stop()),(0,e.emit)(d,`tooltip:change`,{open:N,trigger:m,content:h,reason:r}),C?.(N))},X=e=>{if(L&&=(clearTimeout(L),null),Date.now()<n){Y(!0,e,`delay`);return}L=setTimeout(()=>{Y(!0,e,e===`focus`?`focus`:null),L=null},x)},Z=(e,t=null)=>{L&&=(clearTimeout(L),null),Y(!1,e,t)},Q=(e,t)=>{e===m||!N||(F=!1,Z(t,`delay`))};r.add(m),i.add(Q),R.push(()=>{i.delete(Q),r.delete(m)}),h.hidden=!0,h.setAttribute(`aria-hidden`,`true`),V(O,k),W(`closed`),R.push((0,e.on)(m,`pointerenter`,e=>{e.pointerType!==`touch`&&(J()||(o(m,`pointer`),X(`pointer`)))}),(0,e.on)(m,`pointerleave`,e=>{if(e.pointerType===`touch`||F)return;let t=e.relatedTarget;if(!(t&&h.contains(t))){if(a(t,m)){Z(`pointer`,`delay`);return}Z(`pointer`)}}),(0,e.on)(m,`click`,()=>{if(!J()){if(L){clearTimeout(L),L=null;return}N&&Z(`pointer`,`dismiss`)}}),(0,e.on)(m,`focus`,()=>{F=!0,!J()&&(o(m,`focus`),X(`focus`))}),(0,e.on)(m,`blur`,e=>{F=!1;let t=e.relatedTarget;if(a(t,m)){Z(`blur`,`delay`);return}Z(`blur`)})),R.push((0,e.on)(h,`pointerleave`,e=>{if(e.pointerType===`touch`||F)return;let t=e.relatedTarget;if(!(t&&m.contains(t))){if(a(t,m)){Z(`pointer`,`delay`);return}Z(`pointer`)}})),R.push((0,e.on)(d,`tooltip:set`,e=>{let t=e.detail,n;if(t?.open===void 0?t?.value!==void 0&&(n=t.value):n=t.open,typeof n==`boolean`)if(n){if(J())return;L&&=(clearTimeout(L),null),Y(!0,`api`)}else Z(`api`)})),R.push((0,e.createDismissLayer)({root:d,isOpen:()=>N,onDismiss:()=>Z(`escape`,`dismiss`),closeOnClickOutside:!1,closeOnEscape:!0,preventEscapeDefault:!1}));let $={show:()=>{J()||(L&&=(clearTimeout(L),null),Y(!0,`api`))},hide:()=>Z(`api`),get isOpen(){return N},destroy:()=>{I=!0,L&&clearTimeout(L),q.stop(),K.cleanup(),z.cleanup(),R.forEach(e=>e()),R.length=0,(0,e.clearRootBinding)(d,t,$)}};return(0,e.setRootBinding)(d,t,$),$}function f(n=document){let r=[];for(let i of(0,e.getRoots)(n,`tooltip`))(0,e.hasRootBinding)(i,t)||r.push(d(i));return r}exports.create=f,exports.createTooltip=d;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/index.d.ts
|
|
2
|
-
type TooltipSide = "top" | "right" | "bottom" | "left";
|
|
2
|
+
type TooltipSide = "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end";
|
|
3
3
|
type TooltipAlign = "start" | "center" | "end";
|
|
4
4
|
type TooltipReason = "pointer" | "focus" | "blur" | "escape" | "api";
|
|
5
5
|
interface TooltipOptions {
|
|
@@ -48,7 +48,7 @@ interface TooltipController {
|
|
|
48
48
|
* ```
|
|
49
49
|
*
|
|
50
50
|
* Placement data attributes are resolved as: content -> authored positioner -> root.
|
|
51
|
-
* - `data-side`: 'top' | 'right' | 'bottom' | 'left' (bind-time preferred side)
|
|
51
|
+
* - `data-side`: 'top' | 'right' | 'bottom' | 'left' | 'inline-start' | 'inline-end' (bind-time preferred side)
|
|
52
52
|
* - `data-align`: 'start' | 'center' | 'end' (bind-time preferred align)
|
|
53
53
|
* - `data-side-offset`: number (px)
|
|
54
54
|
* - `data-align-offset`: number (px)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/index.d.ts
|
|
2
|
-
type TooltipSide = "top" | "right" | "bottom" | "left";
|
|
2
|
+
type TooltipSide = "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end";
|
|
3
3
|
type TooltipAlign = "start" | "center" | "end";
|
|
4
4
|
type TooltipReason = "pointer" | "focus" | "blur" | "escape" | "api";
|
|
5
5
|
interface TooltipOptions {
|
|
@@ -48,7 +48,7 @@ interface TooltipController {
|
|
|
48
48
|
* ```
|
|
49
49
|
*
|
|
50
50
|
* Placement data attributes are resolved as: content -> authored positioner -> root.
|
|
51
|
-
* - `data-side`: 'top' | 'right' | 'bottom' | 'left' (bind-time preferred side)
|
|
51
|
+
* - `data-side`: 'top' | 'right' | 'bottom' | 'left' | 'inline-start' | 'inline-end' (bind-time preferred side)
|
|
52
52
|
* - `data-align`: 'start' | 'center' | 'end' (bind-time preferred align)
|
|
53
53
|
* - `data-side-offset`: number (px)
|
|
54
54
|
* - `data-align-offset`: number (px)
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{clearRootBinding as e,computeFloatingPosition as t,computeFloatingTransformOrigin as n,createDismissLayer as r,createPortalLifecycle as i,createPositionSync as a,createPresenceLifecycle as o,emit as s,ensureId as
|
|
1
|
+
import{clearRootBinding as e,computeFloatingPosition as t,computeFloatingTransformOrigin as n,createDismissLayer as r,createPortalLifecycle as i,createPositionSync as a,createPresenceLifecycle as o,emit as s,ensureId as c,getDataBool as l,getDataEnum as u,getDataNumber as d,getPart as f,getRoots as p,hasRootBinding as m,measurePopupContentRect as ee,on as h,reuseRootBinding as te,setRootBinding as ne}from"@data-slot/core";const g=`@data-slot/tooltip`;let _=0;const v=new Set,y=new Set,b=(e,t)=>{if(!e)return!1;for(let n of v)if(n!==t&&n.contains(e))return!0;return!1},x=(e,t)=>{for(let n of y)n(e,t)},re=[`top`,`right`,`bottom`,`left`,`inline-start`,`inline-end`],ie=[`start`,`center`,`end`],ae=(e,t)=>e===`inline-start`?t===`rtl`?`right`:`left`:e===`inline-end`?t===`rtl`?`left`:`right`:e,S=(...e)=>[...new Set(e.filter(e=>e!=null))];function C(p,m={}){let C=te(p,g,`[@data-slot/tooltip] createTooltip() called more than once for the same root. Returning the existing controller. Destroy it before rebinding with new options.`);if(C)return C;let w=f(p,`tooltip-trigger`),T=f(p,`tooltip-content`),E=T?.querySelector(`[data-slot="tooltip-arrow"]`)??null,D=f(p,`tooltip-positioner`),O=D&&T&&D.contains(T)?D:null,k=f(p,`tooltip-portal`),oe=k&&O&&k.contains(O)?k:null;if(!w||!T)throw Error(`Tooltip requires trigger and content slots`);E&&(E.setAttribute(`aria-hidden`,`true`),E.style.position=`absolute`);let se=m.delay??d(p,`delay`)??300,A=m.skipDelayDuration??d(p,`skipDelayDuration`)??300,ce=m.onOpenChange,le=m.portal??l(T,`portal`)??l(p,`portal`)??!0,j=(e,t)=>u(T,e,t)??(O?u(O,e,t):void 0)??u(p,e,t),M=e=>d(T,e)??(O?d(O,e):void 0)??d(p,e),N=e=>l(T,e)??(O?l(O,e):void 0)??l(p,e),P=m.side??j(`side`,re)??`top`,F=m.align??j(`align`,ie)??`center`,ue=m.sideOffset??M(`sideOffset`)??4,de=m.alignOffset??M(`alignOffset`)??0,fe=m.avoidCollisions??N(`avoidCollisions`)??!0,pe=m.collisionPadding??M(`collisionPadding`)??8,I=!1,L=null,R=!1,z=!1,B=null,V=[],H=i({content:T,root:p,enabled:le,wrapperSlot:O?void 0:`tooltip-positioner`,container:O??void 0,mountTarget:O?oe??O:void 0}),me=c(T,`tooltip-content`);T.setAttribute(`role`,`tooltip`);let he=()=>{let e=p instanceof HTMLElement?p:null;return(e?.getAttribute(`dir`)??w.getAttribute(`dir`))===`rtl`||(getComputedStyle(w).direction||(e?getComputedStyle(e).direction:``)||p.ownerDocument.documentElement.getAttribute(`dir`)||``)===`rtl`?`rtl`:`ltr`},U=(e,t)=>{let n=H.container;for(let r of S(T,n,E))r.setAttribute(`data-side`,e),r.setAttribute(`data-align`,t)},ge=e=>{let t=H.container;for(let n of S(p,T,t,E))e?n.setAttribute(`data-instant`,e):n.removeAttribute(`data-instant`)},_e=(e,t,n,r)=>{if(!E)return;E.style.position=`absolute`;let i=E.getBoundingClientRect(),a=E.offsetWidth>0?E.offsetWidth:i.width,o=E.offsetHeight>0?E.offsetHeight:i.height;if(a<=0||o<=0){E.style.removeProperty(`left`),E.style.removeProperty(`top`),E.removeAttribute(`data-uncentered`);return}let s=ae(e,t);if(s===`top`||s===`bottom`){let e=n.left+n.width/2-r.left-a/2,t=Math.max(5,r.width-a-5),i=Math.min(Math.max(e,5),t);E.style.left=`${i}px`,E.style.removeProperty(`top`),Math.abs(i-e)>.5?E.setAttribute(`data-uncentered`,``):E.removeAttribute(`data-uncentered`);return}let c=n.top+n.height/2-r.top-o/2,l=Math.max(5,r.height-o-5),u=Math.min(Math.max(c,5),l);E.style.top=`${u}px`,E.style.removeProperty(`left`),Math.abs(u-c)>.5?E.setAttribute(`data-uncentered`,``):E.removeAttribute(`data-uncentered`)},W=e=>{let t=H.container;if(p.setAttribute(`data-state`,e),T.setAttribute(`data-state`,e),ge(L),e===`open`){for(let e of S(p,T,t,E))e.setAttribute(`data-open`,``),e.removeAttribute(`data-closed`);return}for(let e of S(p,T,t,E))e.setAttribute(`data-closed`,``),e.removeAttribute(`data-open`)},G=()=>{let e=H.container,r=p.ownerDocument.defaultView??window,i=he(),a=w.getBoundingClientRect(),o=t({anchorRect:a,contentRect:ee(T),side:P,align:F,sideOffset:ue,alignOffset:de,avoidCollisions:fe,collisionPadding:pe,direction:i}),s=n({side:o.side,align:o.align,anchorRect:a,popupX:o.x,popupY:o.y,direction:i});e.style.position=`absolute`,e.style.top=`0px`,e.style.left=`0px`,e.style.transform=`translate3d(${o.x+r.scrollX}px, ${o.y+r.scrollY}px, 0)`,e.style.setProperty(`--transform-origin`,s),e.style.willChange=`transform`,e.style.margin=`0`,U(o.side,o.align),_e(o.side,i,a,T.getBoundingClientRect())},K=o({element:T,onExitComplete:()=>{z||(H.restore(),T.hidden=!0)}}),q=a({observedElements:[w,T],isActive:()=>I,ancestorScroll:!1,onUpdate:G}),J=()=>w.hasAttribute(`disabled`)||w.getAttribute(`aria-disabled`)===`true`,Y=(e,t,n=null)=>{I!==e&&(!e&&I&&A>0&&(_=Date.now()+A),L=n,I=e,I?(w.setAttribute(`aria-describedby`,me),T.setAttribute(`aria-hidden`,`false`),H.mount(),T.hidden=!1,W(`open`),K.enter(),G(),q.start(),q.update()):(W(`closed`),w.removeAttribute(`aria-describedby`),T.setAttribute(`aria-hidden`,`true`),K.exit(),q.stop()),s(p,`tooltip:change`,{open:I,trigger:w,content:T,reason:t}),ce?.(I))},X=e=>{if(B&&=(clearTimeout(B),null),Date.now()<_){Y(!0,e,`delay`);return}B=setTimeout(()=>{Y(!0,e,e===`focus`?`focus`:null),B=null},se)},Z=(e,t=null)=>{B&&=(clearTimeout(B),null),Y(!1,e,t)},Q=(e,t)=>{e===w||!I||(R=!1,Z(t,`delay`))};v.add(w),y.add(Q),V.push(()=>{y.delete(Q),v.delete(w)}),T.hidden=!0,T.setAttribute(`aria-hidden`,`true`),U(P,F),W(`closed`),V.push(h(w,`pointerenter`,e=>{e.pointerType!==`touch`&&(J()||(x(w,`pointer`),X(`pointer`)))}),h(w,`pointerleave`,e=>{if(e.pointerType===`touch`||R)return;let t=e.relatedTarget;if(!(t&&T.contains(t))){if(b(t,w)){Z(`pointer`,`delay`);return}Z(`pointer`)}}),h(w,`click`,()=>{if(!J()){if(B){clearTimeout(B),B=null;return}I&&Z(`pointer`,`dismiss`)}}),h(w,`focus`,()=>{R=!0,!J()&&(x(w,`focus`),X(`focus`))}),h(w,`blur`,e=>{R=!1;let t=e.relatedTarget;if(b(t,w)){Z(`blur`,`delay`);return}Z(`blur`)})),V.push(h(T,`pointerleave`,e=>{if(e.pointerType===`touch`||R)return;let t=e.relatedTarget;if(!(t&&w.contains(t))){if(b(t,w)){Z(`pointer`,`delay`);return}Z(`pointer`)}})),V.push(h(p,`tooltip:set`,e=>{let t=e.detail,n;if(t?.open===void 0?t?.value!==void 0&&(n=t.value):n=t.open,typeof n==`boolean`)if(n){if(J())return;B&&=(clearTimeout(B),null),Y(!0,`api`)}else Z(`api`)})),V.push(r({root:p,isOpen:()=>I,onDismiss:()=>Z(`escape`,`dismiss`),closeOnClickOutside:!1,closeOnEscape:!0,preventEscapeDefault:!1}));let $={show:()=>{J()||(B&&=(clearTimeout(B),null),Y(!0,`api`))},hide:()=>Z(`api`),get isOpen(){return I},destroy:()=>{z=!0,B&&clearTimeout(B),q.stop(),K.cleanup(),H.cleanup(),V.forEach(e=>e()),V.length=0,e(p,g,$)}};return ne(p,g,$),$}function w(e=document){let t=[];for(let n of p(e,`tooltip`))m(n,g)||t.push(C(n));return t}export{w as create,C as createTooltip};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@data-slot/tooltip",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.142",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -34,6 +34,6 @@
|
|
|
34
34
|
],
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@data-slot/core": "0.2.
|
|
37
|
+
"@data-slot/core": "0.2.142"
|
|
38
38
|
}
|
|
39
39
|
}
|