vue-pointing-bubble 0.1.0 → 0.4.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 +35 -384
- package/dist/index.d.ts +3 -44
- package/dist/pointing-bubble/PointingBubble.vue.d.ts +45 -0
- package/dist/pointing-bubble/core.d.ts +13 -0
- package/dist/pointing-bubble/createBubbleController.d.ts +31 -0
- package/dist/pointing-bubble/ease.d.ts +9 -0
- package/dist/pointing-bubble/geometry.d.ts +14 -0
- package/dist/pointing-bubble/index.d.ts +11 -0
- package/dist/pointing-bubble/measure.d.ts +5 -0
- package/dist/pointing-bubble/resolveTarget.d.ts +7 -0
- package/dist/pointing-bubble/styles.d.ts +3 -0
- package/dist/pointing-bubble/tail.d.ts +12 -0
- package/dist/pointing-bubble/types.d.ts +66 -0
- package/dist/vue-pointing-bubble.cjs +9 -0
- package/dist/vue-pointing-bubble.js +510 -310
- package/package.json +48 -51
- package/dist/vue-pointing-bubble.umd.cjs +0 -9
- package/registry/ui/pointing-bubble/PointingBubble.vue +0 -408
- package/registry/ui/pointing-bubble/index.ts +0 -1
- package/src/index.d.ts +0 -44
- package/src/index.js +0 -9
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Geometry, TailPaths } from './types';
|
|
2
|
+
export interface BuildTailOptions {
|
|
3
|
+
geometry: Geometry;
|
|
4
|
+
strokeWidth: number;
|
|
5
|
+
radius: string;
|
|
6
|
+
tailBaseWidth: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Build fill + stroke SVG path `d` for the tail from the box wall facing the tip.
|
|
10
|
+
* Fill extends 1px past the border inner edge to cover zoom snapping seams.
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildTailPaths(opts: BuildTailOptions): TailPaths | null;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type Placement = 'auto' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'manual';
|
|
2
|
+
export type ResolvedPlacement = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'manual' | 'none';
|
|
3
|
+
export type TargetAnchor = 'center' | 'edge';
|
|
4
|
+
export interface Point {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
/** Core target: coords, DOM element, CSS selector, or null (box-only / in-flow). */
|
|
9
|
+
export type BubbleTarget = Point | Element | string | null;
|
|
10
|
+
export interface FrameRect {
|
|
11
|
+
left: number;
|
|
12
|
+
top: number;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
scaleX: number;
|
|
16
|
+
scaleY: number;
|
|
17
|
+
viewportWidth: number;
|
|
18
|
+
viewportHeight: number;
|
|
19
|
+
}
|
|
20
|
+
export interface LocalRect {
|
|
21
|
+
left: number;
|
|
22
|
+
top: number;
|
|
23
|
+
right: number;
|
|
24
|
+
bottom: number;
|
|
25
|
+
}
|
|
26
|
+
export interface BoxMeasure {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
fill: string;
|
|
32
|
+
stroke: string;
|
|
33
|
+
strokeWidth: number;
|
|
34
|
+
radius: string;
|
|
35
|
+
zIndex: string;
|
|
36
|
+
}
|
|
37
|
+
export interface Geometry {
|
|
38
|
+
placement: ResolvedPlacement;
|
|
39
|
+
tx: number;
|
|
40
|
+
ty: number;
|
|
41
|
+
bx: number;
|
|
42
|
+
by: number;
|
|
43
|
+
w: number;
|
|
44
|
+
h: number;
|
|
45
|
+
}
|
|
46
|
+
export interface Room {
|
|
47
|
+
left: number;
|
|
48
|
+
right: number;
|
|
49
|
+
}
|
|
50
|
+
export interface TailPaths {
|
|
51
|
+
fill: string;
|
|
52
|
+
stroke: string | null;
|
|
53
|
+
}
|
|
54
|
+
export interface BubbleConfig {
|
|
55
|
+
target: BubbleTarget;
|
|
56
|
+
placement: Placement;
|
|
57
|
+
targetAnchor: TargetAnchor;
|
|
58
|
+
maxWidth?: number;
|
|
59
|
+
tailLength: number;
|
|
60
|
+
tailBaseWidth: number;
|
|
61
|
+
padding: number | string;
|
|
62
|
+
shadow: boolean;
|
|
63
|
+
transitionDuration: number;
|
|
64
|
+
}
|
|
65
|
+
export declare const DEFAULT_BUBBLE_CONFIG: BubbleConfig;
|
|
66
|
+
export type StyleMap = Record<string, string | number | undefined>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const m=require("vue"),P={target:null,placement:"auto",targetAnchor:"center",tailLength:45,tailBaseWidth:24,padding:8,shadow:!0,transitionDuration:200},T="pointing-bubble-styles",q=`:where(.pointing-bubble__inner) {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
width: var(--pb-width, max-content);
|
|
4
|
+
max-width: var(--pb-max-width, none);
|
|
5
|
+
padding: var(--pb-padding);
|
|
6
|
+
background: white;
|
|
7
|
+
border: 2px solid gray;
|
|
8
|
+
border-radius: 8px;
|
|
9
|
+
}`,_="drop-shadow(0 6px 8px rgba(0, 0, 0, 0.25))";function H(e=document){if(e.getElementById(T))return;const t=e.createElement("style");t.id=T,t.textContent=q,e.head.prepend(t)}function D(e){return typeof e=="object"&&e!==null&&typeof e.x=="number"&&typeof e.y=="number"&&e.nodeType!==1}function O(e){return typeof Element>"u"||e==null?null:typeof e=="string"?document.querySelector(e):e instanceof Element?e:null}function A(e,t){return!e||!t?!1:Object.keys(e).every(n=>e[n]===t[n])}function X(e){const t=e.getBoundingClientRect(),n=getComputedStyle(e),a=parseFloat(n.width)||0,l=parseFloat(n.height)||0;return{left:t.left,top:t.top,width:a,height:l,scaleX:a?t.width/a:1,scaleY:l?t.height/l:1,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight}}function Z(e,t,n,a){const l=getComputedStyle(e),{scaleX:i,scaleY:d}=n,r=e.getBoundingClientRect(),f=t.getBoundingClientRect();return{x:a?(r.left-f.left)/i:0,y:a?(r.top-f.top)/d:0,width:r.width/i,height:r.height/d,fill:l.backgroundColor,stroke:l.borderTopColor,strokeWidth:parseFloat(l.borderTopWidth)||0,radius:l.borderTopLeftRadius,zIndex:l.zIndex}}function F(e,t,n){const a=e.x-n;let l=a,i=t.width?t.width-e.x-n:1/0;return t.viewportWidth&&(l=Math.min(l,t.left/t.scaleX+a),i=Math.min(i,(t.viewportWidth-t.left)/t.scaleX-e.x-n)),{left:Math.max(0,l),right:Math.max(0,i)}}function j(e){return e.left>e.right?"left":"right"}function N(e){const{tip:t,box:n,frame:a,placement:l,targetRect:i,room:d,tailLength:r}=e;if(!n.width||!n.height)return null;const{width:f,height:p}=n,{x:b,y}=t,k=l==="manual",o=e.targetAnchor==="edge"?i:null;if(k){if(o){const v=n.x+f/2,w=n.y+p/2;if(!(v>=o.left&&v<=o.right&&w>=o.top&&w<=o.bottom)){const x=Math.min(o.right,Math.max(o.left,v)),g=Math.min(o.bottom,Math.max(o.top,w));return{placement:"manual",tx:x,ty:g,bx:n.x,by:n.y,w:f,h:p}}}return{placement:"manual",tx:b,ty:y,bx:n.x,by:n.y,w:f,h:p}}const E=v=>o?v==="top"?o.top:o.bottom:y;let B=l;if(l==="auto"){let v=y>(a.height||600)/2?"top":"bottom",w=j(d);const{scaleX:u,scaleY:x}=a;if(a.viewportHeight){const g=a.top+(E("top")-p-r)*x>=0,S=a.top+(E("bottom")+p+r)*x<=a.viewportHeight;v==="top"&&!g&&S?v="bottom":v==="bottom"&&!S&&g&&(v="top")}if(a.viewportWidth){const g=a.left+(b-f-r)*u>=0,S=a.left+(b+f+r)*u<=a.viewportWidth;w==="left"&&!g&&S?w="right":w==="right"&&!S&&g&&(w="left")}B=`${v}-${w}`}const[W,C]=B.split("-"),I=E(W);return{placement:B,tx:b,ty:I,bx:C==="left"?b-f-r:b+r,by:W==="top"?I-p-r:I+r,w:f,h:p}}const G=["tx","ty","bx","by"],V=["tx","ty"];function K(){return typeof matchMedia<"u"&&matchMedia("(prefers-reduced-motion: reduce)").matches}function Q(e,t,n,a){let l=0;const i=()=>{typeof cancelAnimationFrame<"u"&&cancelAnimationFrame(l)};if(!t||!e||n<=0||typeof requestAnimationFrame>"u"||K())return a(t),{cancel:i};const d=performance.now(),r=f=>{const p=Math.min(1,(f-d)/n),b=1-Math.pow(1-p,3),y={...t},k=t.placement==="manual"?V:G;for(const o of k)y[o]=e[o]+(t[o]-e[o])*b;a(y),p<1&&(l=requestAnimationFrame(r))};return l=requestAnimationFrame(r),{cancel:i}}function Y(e){const{geometry:t,strokeWidth:n,radius:a,tailBaseWidth:l}=e,{placement:i,tx:d,ty:r,bx:f,by:p,w:b,h:y}=t,k=parseFloat(a)*(a.endsWith("%")?Math.min(b,y)/100:1)||0,o=l/2,E=(s,c,h)=>c>h?(c+h)/2:Math.min(h,Math.max(c,s));let B=null,W=0;if(i==="manual"){const s=Math.max(f-d,d-(f+b),0),c=Math.max(p-r,r-(p+y),0);if(s>0&&s>=c)B=d<f?"left":"right",W=r;else if(c>0)B=r<p?"top":"bottom",W=d;else return null}else if(i!=="none"){const[s,c]=i.split("-");B=c==="left"?"right":"left",W=p+y*(s==="top"?.65:.35)}else return null;const C=1,I=B==="top"||B==="bottom",v={left:(s,c)=>[f-c,s],right:(s,c)=>[f+b+c,s],top:(s,c)=>[s,p-c],bottom:(s,c)=>[s,p+y+c]}[B],w={left:f-d,right:d-f-b,top:p-r,bottom:r-p-y}[B],u=I?E(W,f+k+o+n/2,f+b-k-o-n/2):E(W,p+k+o+n/2,p+y-k-o-n/2),x=Math.max(0,Math.min(n,w/2)),g=([s,c])=>`${s} ${c}`,S=(s,c)=>{const h=v(s,x),$=Math.hypot(d-h[0],r-h[1])||1,R=[h[0]+(d-h[0])*x/$,h[1]+(r-h[1])*x/$];return{inner:g(v(s,c)),outer:g(v(s,0)),ctrl:g(h),end:g(R)}},M=s=>{const c=S(u-o,s),h=S(u+o,s);return`M ${c.inner} L ${c.outer} Q ${c.ctrl} ${c.end} L ${d} ${r} L ${h.end} Q ${h.ctrl} ${h.outer} L ${h.inner}`};return{fill:`${M(-n-C)} Z`,stroke:n?M(-n):null}}function J(e){return{hasTarget:e,placement:"none",tip:null,slotTip:null,overlayStyle:{},boxStyle:{},rootIsBox:!e,tail:null,boxFill:"",boxStroke:"",boxStrokeWidth:0,boxZIndex:"auto"}}function z(e,t){return e===t?!0:!e||!t?!1:e.x===t.x&&e.y===t.y}function tt(e,t){return e.hasTarget===t.hasTarget&&e.placement===t.placement&&e.rootIsBox===t.rootIsBox&&e.boxFill===t.boxFill&&e.boxStroke===t.boxStroke&&e.boxStrokeWidth===t.boxStrokeWidth&&e.boxZIndex===t.boxZIndex&&z(e.tip,t.tip)&&z(e.slotTip,t.slotTip)&&A(e.overlayStyle,t.overlayStyle)&&A(e.boxStyle,t.boxStyle)&&e.tail?.fill===t.tail?.fill&&e.tail?.stroke===t.tail?.stroke}function U(e){H();let t={...P},n=null,a=null,l=null,i={left:0,top:0,width:0,height:0,scaleX:1,scaleY:1,viewportWidth:0,viewportHeight:0},d=null,r=null,f=null,p=null,b=J(!1);const y=()=>{const u=k();tt(b,u)||(b=u,e.onChange?.(b))};function k(){const u=t.target!=null,x=t.placement==="manual",g=u?d?.placement??"none":"none",S={position:"absolute",inset:"0",pointerEvents:"none",filter:t.shadow?_:void 0},M=l?.zIndex;M&&M!=="auto"&&(S.zIndex=M);const s={"--pb-padding":typeof t.padding=="number"?`${t.padding}px`:t.padding};if(t.maxWidth!=null&&(s["--pb-max-width"]=`${t.maxWidth}px`),!u)s["--pb-width"]="fit-content",t.shadow&&(s.filter=_);else if(Object.assign(s,{position:"absolute",pointerEvents:"auto",visibility:d?"visible":"hidden"}),x)s["--pb-width"]="fit-content";else if(Object.assign(s,{left:`${d?.bx??0}px`,top:`${d?.by??0}px`,margin:"0"}),t.maxWidth==null&&n){const h=F(n,i,t.tailLength),$=r?.placement??t.placement,R=$==="auto"?j(h):$.split("-")[1];s["--pb-max-width"]=`${h[R]}px`}const c=u&&d&&l?Y({geometry:d,strokeWidth:l.strokeWidth,radius:l.radius,tailBaseWidth:t.tailBaseWidth}):null;return{hasTarget:u,placement:g,tip:n,slotTip:r?{x:r.tx,y:r.ty}:n,overlayStyle:S,boxStyle:s,rootIsBox:!u,tail:c,boxFill:l?.fill??"",boxStroke:l?.stroke??"",boxStrokeWidth:l?.strokeWidth??0,boxZIndex:l?.zIndex??"auto"}}function o(){if(!n||!l){r=null,E(null);return}const u=F(n,i,t.tailLength);r=N({tip:n,box:l,frame:i,placement:t.placement,targetAnchor:t.targetAnchor,targetRect:a,room:u,tailLength:t.tailLength}),E(r)}function E(u){f?.cancel(),f=Q(d,u,t.transitionDuration,x=>{d=x,y()})}function B(){const u=e.getRootEl(),x=e.getBoxEl();if(!x||t.target==null||!u)return;const g=Z(x,u,i,t.placement==="manual");A(g,l)||(l=g)}function W(){const u=e.getRootEl();if(t.target==null||!u){n=null,a=null,l=null,r=null,d=null,y();return}i=X(u);const x=O(t.target);if(x){const g=x.getBoundingClientRect(),{scaleX:S,scaleY:M,left:s,top:c}=i,h={left:(g.left-s)/S,top:(g.top-c)/M,right:(g.right-s)/S,bottom:(g.bottom-c)/M};A(h,a)||(a=h),n={x:(h.left+h.right)/2,y:(h.top+h.bottom)/2}}else if(D(t.target))a=null,n={x:t.target.x,y:t.target.y};else{a=null,n=null,l=null,r=null,d=null,y();return}B(),o()}function C(){W()}typeof window<"u"&&(window.addEventListener("resize",C),window.addEventListener("scroll",C,!0));function I(){if(typeof ResizeObserver>"u")return;p?.disconnect(),p=new ResizeObserver(()=>W());const u=e.getRootEl(),x=e.getBoxEl();u&&p.observe(u),x&&p.observe(x)}const v=W;function w(){I(),v()}return{update:w,setConfig(u){t={...t,...u},w()},getConfig:()=>t,getState:()=>b,destroy(){f?.cancel(),p?.disconnect(),typeof window<"u"&&(window.removeEventListener("resize",C),window.removeEventListener("scroll",C,!0))}}}const et=["data-placement"],nt=["d","fill"],ot=["d","stroke","stroke-width"],L=m.defineComponent({name:"PointingBubble",inheritAttrs:!1,__name:"PointingBubble",props:{target:{default:null},placement:{default:"auto"},targetAnchor:{default:"center"},maxWidth:{default:void 0},tailLength:{default:45},tailBaseWidth:{default:24},padding:{default:8},shadow:{type:Boolean,default:!0},transitionDuration:{default:200}},setup(e,{expose:t}){const n=e,a=m.ref(null),l=m.ref(null),i=m.ref({hasTarget:!1,placement:"none",tip:null,slotTip:null,overlayStyle:{},boxStyle:{},rootIsBox:!0,tail:null,boxFill:"",boxStroke:"",boxStrokeWidth:0,boxZIndex:"auto"});function d(o){return o==null?null:typeof o=="string"||typeof Element<"u"&&o instanceof Element?o:typeof o=="object"&&"$el"in o&&o.$el instanceof Element?o.$el:typeof o=="object"&&typeof o.x=="number"&&typeof o.y=="number"?o:null}const r=U({getRootEl:()=>a.value,getBoxEl:()=>l.value,onChange:o=>{i.value=o}});function f(){r.setConfig({target:d(n.target),placement:n.placement,targetAnchor:n.targetAnchor,maxWidth:n.maxWidth,tailLength:n.tailLength,tailBaseWidth:n.tailBaseWidth,padding:n.padding,shadow:n.shadow,transitionDuration:n.transitionDuration})}m.watch(()=>[n.target,typeof n.target=="object"&&n.target&&"x"in n.target?n.target.x:null,typeof n.target=="object"&&n.target&&"y"in n.target?n.target.y:null,n.placement,n.targetAnchor,n.maxWidth,n.tailLength,n.tailBaseWidth,n.padding,n.shadow,n.transitionDuration],f,{flush:"post"}),m.onMounted(()=>{f()}),m.onBeforeUnmount(()=>{r.destroy()});function p(){r.update()}t({update:p});const b=m.computed(()=>i.value.rootIsBox?i.value.boxStyle:i.value.overlayStyle),y=m.computed(()=>i.value.rootIsBox?{display:"contents"}:i.value.boxStyle),k=m.computed(()=>({position:"absolute",inset:"0",width:"100%",height:"100%",overflow:"visible",zIndex:i.value.boxZIndex}));return(o,E)=>(m.openBlock(),m.createElementBlock("div",m.mergeProps({ref_key:"rootRef",ref:a,class:["pointing-bubble",{"pointing-bubble__inner":!e.target}],"data-placement":i.value.placement},e.target?{}:o.$attrs,{style:b.value}),[m.createElementVNode("div",m.mergeProps({ref_key:"boxRef",ref:l,class:{"pointing-bubble__inner":!!e.target}},e.target?o.$attrs:{},{style:y.value}),[m.renderSlot(o.$slots,"default",{placement:i.value.placement,tip:i.value.slotTip},()=>[E[0]||(E[0]=m.createElementVNode("p",{style:{margin:0,fontSize:"14px",fontWeight:600,color:"#1e293b"}}," Callout content ",-1))])],16),e.target&&i.value.tail?(m.openBlock(),m.createElementBlock("svg",{key:0,class:"pointing-bubble__svg",style:m.normalizeStyle(k.value)},[m.createElementVNode("path",{class:"pointing-bubble__path",d:i.value.tail.fill,fill:i.value.boxFill},null,8,nt),i.value.tail.stroke?(m.openBlock(),m.createElementBlock("path",{key:0,class:"pointing-bubble__path",d:i.value.tail.stroke,fill:"none",stroke:i.value.boxStroke,"stroke-width":i.value.boxStrokeWidth,"stroke-linejoin":"round","stroke-linecap":"butt"},null,8,ot)):m.createCommentVNode("",!0)],4)):m.createCommentVNode("",!0)],16,et))}}),lt={install(e,t={}){const n=t.name??"PointingBubble";e.component(n,L),e.component("Callout",L)}};exports.Callout=L;exports.DEFAULT_BUBBLE_CONFIG=P;exports.PointingBubble=L;exports.PointingBubblePlugin=lt;exports.buildTailPaths=Y;exports.computeGeometry=N;exports.createBubbleController=U;exports.default=L;exports.isPoint=D;exports.resolveElement=O;
|