@bagelink/vue 1.15.154 → 1.15.156
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/dist/components/charts/BarChart.vue.d.ts.map +1 -1
- package/dist/components/charts/ChartTooltip.vue.d.ts +12 -2
- package/dist/components/charts/ChartTooltip.vue.d.ts.map +1 -1
- package/dist/components/charts/LineChart.vue.d.ts.map +1 -1
- package/dist/components/layout/AppNav.vue.d.ts +1 -1
- package/dist/components/layout/AppNav.vue.d.ts.map +1 -1
- package/dist/index.cjs +149 -176
- package/dist/index.mjs +35150 -29033
- package/dist/style.css +2 -1
- package/package.json +1 -1
- package/src/components/charts/BarChart.vue +1 -1
- package/src/components/charts/ChartTooltip.vue +73 -16
- package/src/components/charts/Donut.vue +1 -1
- package/src/components/charts/Funnel.vue +1 -1
- package/src/components/charts/LineChart.vue +1 -1
package/package.json
CHANGED
|
@@ -177,7 +177,7 @@ const tooltipStyle = computed(() => {
|
|
|
177
177
|
</svg>
|
|
178
178
|
|
|
179
179
|
<ChartTooltip
|
|
180
|
-
v-if="hoverIdx != null" :style="tooltipStyle"
|
|
180
|
+
v-if="hoverIdx != null" prefer="top" :style="tooltipStyle"
|
|
181
181
|
:label="hoverLabel" :rows="hoverRows" :total="hoverTotal"
|
|
182
182
|
/>
|
|
183
183
|
</div>
|
|
@@ -6,7 +6,13 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Positioned by the host via `style` (absolute left/top); the host owns
|
|
8
8
|
* mouse tracking. Non-interactive (pointer-events: none).
|
|
9
|
+
*
|
|
10
|
+
* Placement is dynamic by default: the tooltip measures itself and flips to
|
|
11
|
+
* the opposite side of its anchor whenever the preferred side would clip past
|
|
12
|
+
* the top/bottom of the viewport. Hosts only express a *preferred* side via
|
|
13
|
+
* `prefer` (or the legacy `above`/`below` flags).
|
|
9
14
|
*/
|
|
15
|
+
import { nextTick, ref, watch } from 'vue'
|
|
10
16
|
import { useI18n } from '@bagelink/vue'
|
|
11
17
|
|
|
12
18
|
export interface TipRow { name: string; color?: string; value: string }
|
|
@@ -16,41 +22,95 @@ defineOptions({ name: 'BglChartTooltip' })
|
|
|
16
22
|
|
|
17
23
|
const { $t } = useI18n()
|
|
18
24
|
|
|
19
|
-
withDefaults(defineProps<{
|
|
25
|
+
const props = withDefaults(defineProps<{
|
|
20
26
|
label?: string
|
|
21
27
|
/** Big focal number (used by single-value charts like the funnel). */
|
|
22
28
|
hero?: string
|
|
23
29
|
rows?: TipRow[]
|
|
24
30
|
total?: string | null
|
|
25
31
|
stats?: TipStat[]
|
|
26
|
-
/**
|
|
32
|
+
/** Preferred side relative to the anchor point. The tooltip still flips to
|
|
33
|
+
the opposite side automatically when the preferred side would clip.
|
|
34
|
+
- `above`/`below`: cursor-anchored charts (a small gap is kept).
|
|
35
|
+
- `top`: pinned to the top of the chart (no vertical flip). */
|
|
36
|
+
prefer?: 'above' | 'below' | 'top'
|
|
37
|
+
/** @deprecated use `prefer="above"`. Float above the anchor point. */
|
|
27
38
|
above?: boolean
|
|
39
|
+
/** @deprecated use `prefer="below"`. Float below the anchor point. */
|
|
40
|
+
below?: boolean
|
|
28
41
|
}>(), {
|
|
29
42
|
rows: () => [],
|
|
30
43
|
stats: () => [],
|
|
44
|
+
prefer: 'below',
|
|
31
45
|
})
|
|
46
|
+
|
|
47
|
+
// Resolve the caller's preferred side (new `prefer` prop wins; fall back to the
|
|
48
|
+
// legacy boolean flags for compatibility).
|
|
49
|
+
function preferredSide(): 'above' | 'below' | 'top' {
|
|
50
|
+
if (props.above) return 'above'
|
|
51
|
+
if (props.below) return 'below'
|
|
52
|
+
return props.prefer
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const el = ref<HTMLElement>()
|
|
56
|
+
// The side actually used after measuring (may differ from the preferred one).
|
|
57
|
+
const side = ref<'above' | 'below' | 'top'>(preferredSide())
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Place the tooltip by the anchor's position in the viewport:
|
|
61
|
+
* anchors in the top half get the tooltip *below* them, anchors in the
|
|
62
|
+
* bottom half get it *above*. `top` placements are pinned to the chart and
|
|
63
|
+
* never flip.
|
|
64
|
+
*/
|
|
65
|
+
function place() {
|
|
66
|
+
const node = el.value
|
|
67
|
+
const want = preferredSide()
|
|
68
|
+
if (!node || want === 'top') { side.value = want; return }
|
|
69
|
+
|
|
70
|
+
// Normalize to the `below` transform first so the measured `top` always
|
|
71
|
+
// reflects the stable anchor point (not a post-flip offset), avoiding
|
|
72
|
+
// flip-flop right around the midpoint.
|
|
73
|
+
side.value = 'below'
|
|
74
|
+
nextTick(() => {
|
|
75
|
+
const n = el.value
|
|
76
|
+
if (!n) return
|
|
77
|
+
const r = n.getBoundingClientRect()
|
|
78
|
+
side.value = r.top < window.innerHeight / 2 ? 'below' : 'above'
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Re-place whenever the anchor moves or the content changes.
|
|
83
|
+
watch(
|
|
84
|
+
() => [props.label, props.hero, props.total, props.rows, props.stats, props.prefer, props.above, props.below],
|
|
85
|
+
place,
|
|
86
|
+
{ immediate: true, deep: true },
|
|
87
|
+
)
|
|
32
88
|
</script>
|
|
33
89
|
|
|
34
90
|
<template>
|
|
35
|
-
<div
|
|
36
|
-
|
|
37
|
-
|
|
91
|
+
<div
|
|
92
|
+
ref="el"
|
|
93
|
+
class="bgl-tip absolute top-0 pointer-events-none nowrap z-5 color-white line-height-16"
|
|
94
|
+
:class="{ 'bgl-tip--above': side === 'above', 'bgl-tip--below': side === 'below' }"
|
|
95
|
+
>
|
|
96
|
+
<p v-if="label" class="opacity-7 txt-075rem m-0 pb-025 ">{{ label }}</p>
|
|
97
|
+
<p v-if="hero" class="m-0 tabular-nums bold pb-025 txt-1-25rem">{{ hero }}</p>
|
|
38
98
|
|
|
39
|
-
<p v-for="(r, i) in rows" :key="i" class="
|
|
99
|
+
<p v-for="(r, i) in rows" :key="i" class="gap-05 flex align-items-center m-0">
|
|
40
100
|
<span v-if="r.color" class="bgl-tip__dot flex-shrink-0" :style="{ background: r.color }" />
|
|
41
101
|
<span v-if="rows.length > 1" class="bgl-tip__name">{{ r.name }}</span>
|
|
42
|
-
<span class="
|
|
102
|
+
<span class="ms-auto tabular-nums semibold">{{ r.value }}</span>
|
|
43
103
|
</p>
|
|
44
104
|
|
|
45
|
-
<p v-if="total" class="
|
|
105
|
+
<p v-if="total" class="gap-05 bgl-tip__total flex align-items-center m-0">
|
|
46
106
|
<span class="bgl-tip__name">{{ $t('charts.total') }}</span>
|
|
47
|
-
<span class="
|
|
107
|
+
<span class="ms-auto tabular-nums semibold">{{ total }}</span>
|
|
48
108
|
</p>
|
|
49
109
|
|
|
50
110
|
<div v-if="stats.length" class="bgl-tip__stats flex column">
|
|
51
|
-
<p v-for="(s, i) in stats" :key="i" class="
|
|
111
|
+
<p v-for="(s, i) in stats" :key="i" class="gap-05 flex align-items-center m-0 space-between">
|
|
52
112
|
<span class="bgl-tip__name">{{ s.label }}</span>
|
|
53
|
-
<span class="
|
|
113
|
+
<span class="ms-auto tabular-nums semibold">{{ s.value }}</span>
|
|
54
114
|
</p>
|
|
55
115
|
</div>
|
|
56
116
|
</div>
|
|
@@ -58,17 +118,14 @@ withDefaults(defineProps<{
|
|
|
58
118
|
|
|
59
119
|
<style scoped>
|
|
60
120
|
.bgl-tip {
|
|
61
|
-
|
|
121
|
+
transform: translateX(-50%); transform-origin: center;
|
|
62
122
|
background: var(--bgl-black); border-radius: 0.5rem; padding: 0.4rem 0.6rem;
|
|
63
123
|
font-size: 0.75rem; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18); min-width: 7rem;
|
|
64
124
|
}
|
|
65
125
|
.bgl-tip--above { transform: translate(-50%, calc(-100% - 0.6rem)); }
|
|
66
|
-
.bgl-
|
|
67
|
-
.bgl-tip__hero { margin-bottom: 0.2rem; font-size: 1.05rem; font-weight: 700; }
|
|
68
|
-
.bgl-tip__row { gap: 0.4rem; }
|
|
126
|
+
.bgl-tip--below { transform: translate(-50%, 0.6rem); }
|
|
69
127
|
.bgl-tip__dot { width: 8px; height: 8px; border-radius: 2px; }
|
|
70
128
|
.bgl-tip__name { opacity: 0.7; }
|
|
71
|
-
.bgl-tip__val { margin-inline-start: auto; font-weight: 600; }
|
|
72
129
|
.bgl-tip__total,
|
|
73
130
|
.bgl-tip__stats {
|
|
74
131
|
margin-top: 0.28rem; padding-top: 0.28rem;
|
|
@@ -190,7 +190,7 @@ const tooltipStyle = computed(() => ({ left: `${tipX.value}px`, top: `${tipY.val
|
|
|
190
190
|
<span v-if="centerLabel" class="color-gray txt12">{{ centerLabel }}</span>
|
|
191
191
|
</div>
|
|
192
192
|
<ChartTooltip
|
|
193
|
-
v-if="hoverArc" above :style="tooltipStyle"
|
|
193
|
+
v-if="hoverArc" prefer="above" :style="tooltipStyle"
|
|
194
194
|
:label="hoverArc.label" :hero="hoverValue" :stats="hoverStats"
|
|
195
195
|
/>
|
|
196
196
|
</div>
|
|
@@ -292,7 +292,7 @@ const tooltipStyle = computed(() => ({ left: `${tipX.value}px`, top: `${tipY.val
|
|
|
292
292
|
|
|
293
293
|
<!-- Shared tooltip -->
|
|
294
294
|
<ChartTooltip
|
|
295
|
-
v-if="hoverStage" above :style="tooltipStyle"
|
|
295
|
+
v-if="hoverStage" prefer="above" :style="tooltipStyle"
|
|
296
296
|
:label="hoverStage.label"
|
|
297
297
|
:hero="isSegmented ? undefined : hoverStage.display"
|
|
298
298
|
:rows="isSegmented ? hoverStage.rows : []"
|
|
@@ -231,7 +231,7 @@ const tooltipStyle = computed(() => {
|
|
|
231
231
|
|
|
232
232
|
<!-- shared tooltip following the mouse -->
|
|
233
233
|
<ChartTooltip
|
|
234
|
-
v-if="hoverIdx != null" :style="tooltipStyle"
|
|
234
|
+
v-if="hoverIdx != null" prefer="top" :style="tooltipStyle"
|
|
235
235
|
:label="hoverLabel" :rows="hoverRows" :total="hoverTotal"
|
|
236
236
|
/>
|
|
237
237
|
</div>
|