@bagelink/vue 1.15.202 → 1.15.207

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.
Files changed (75) hide show
  1. package/dist/components/AddressSearch.vue.d.ts.map +1 -1
  2. package/dist/components/Swiper.vue.d.ts +2 -2
  3. package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
  4. package/dist/components/charts/BarChart.vue.d.ts.map +1 -1
  5. package/dist/components/charts/ChartTooltip.vue.d.ts.map +1 -1
  6. package/dist/components/charts/Donut.vue.d.ts.map +1 -1
  7. package/dist/components/charts/Funnel.vue.d.ts.map +1 -1
  8. package/dist/components/charts/Gauge.vue.d.ts.map +1 -1
  9. package/dist/components/charts/LineChart.vue.d.ts.map +1 -1
  10. package/dist/components/charts/MapChart.vue.d.ts +25 -0
  11. package/dist/components/charts/MapChart.vue.d.ts.map +1 -0
  12. package/dist/components/charts/RadialBars.vue.d.ts.map +1 -1
  13. package/dist/components/charts/RankBars.vue.d.ts.map +1 -1
  14. package/dist/components/charts/StatCard.vue.d.ts.map +1 -1
  15. package/dist/components/charts/core/arc.d.ts +6 -0
  16. package/dist/components/charts/core/arc.d.ts.map +1 -0
  17. package/dist/components/charts/core/useChartTip.d.ts +13 -0
  18. package/dist/components/charts/core/useChartTip.d.ts.map +1 -0
  19. package/dist/components/charts/core/world-paths.d.ts +13 -0
  20. package/dist/components/charts/core/world-paths.d.ts.map +1 -0
  21. package/dist/components/charts/index.d.ts +2 -0
  22. package/dist/components/charts/index.d.ts.map +1 -1
  23. package/dist/components/charts/mapTypes.d.ts +7 -0
  24. package/dist/components/charts/mapTypes.d.ts.map +1 -0
  25. package/dist/components/dataTable/DataTable.vue.d.ts.map +1 -1
  26. package/dist/components/form/inputs/DateInput.vue.d.ts +3 -0
  27. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  28. package/dist/components/form/inputs/NumberInput.vue.d.ts.map +1 -1
  29. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  30. package/dist/components/form/inputs/index.d.ts +0 -1
  31. package/dist/components/form/inputs/index.d.ts.map +1 -1
  32. package/dist/components/index.d.ts +2 -2
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/form-flow/FormFlowPlayer.vue.d.ts +18 -0
  35. package/dist/form-flow/FormFlowPlayer.vue.d.ts.map +1 -1
  36. package/dist/form-flow/structure.d.ts +12 -0
  37. package/dist/form-flow/structure.d.ts.map +1 -1
  38. package/dist/index.cjs +177 -154
  39. package/dist/index.d.ts +1 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.mjs +37519 -42750
  42. package/dist/style.css +1 -2
  43. package/dist/utils/BagelFormUtils.d.ts +111 -0
  44. package/dist/utils/BagelFormUtils.d.ts.map +1 -0
  45. package/package.json +1 -1
  46. package/src/components/charts/BarChart.vue +15 -15
  47. package/src/components/charts/ChartTooltip.vue +7 -6
  48. package/src/components/charts/Donut.vue +25 -40
  49. package/src/components/charts/Funnel.vue +10 -12
  50. package/src/components/charts/Gauge.vue +4 -2
  51. package/src/components/charts/LineChart.vue +15 -17
  52. package/src/components/charts/MapChart.vue +198 -0
  53. package/src/components/charts/RadialBars.vue +3 -1
  54. package/src/components/charts/RankBars.vue +2 -0
  55. package/src/components/charts/Sparkline.vue +1 -1
  56. package/src/components/charts/StatCard.vue +2 -0
  57. package/src/components/charts/core/arc.ts +53 -0
  58. package/src/components/charts/core/useChartTip.ts +35 -0
  59. package/src/components/charts/core/world-paths.ts +351 -0
  60. package/src/components/charts/index.ts +3 -0
  61. package/src/components/charts/mapTypes.ts +6 -0
  62. package/src/components/dataTable/useTableVirtualization.ts +5 -5
  63. package/src/components/form/inputs/DateInput.vue +9 -1
  64. package/src/components/form/inputs/NumberInput.vue +17 -6
  65. package/src/components/form/inputs/index.ts +0 -1
  66. package/src/components/index.ts +2 -2
  67. package/src/form-flow/FormFlowPlayer.vue +49 -0
  68. package/src/form-flow/structure.ts +12 -0
  69. package/src/index.ts +1 -0
  70. package/src/utils/BagelFormUtils.ts +341 -0
  71. package/dist/components/dataTable/useTableVirtualization.d.ts +0 -25
  72. package/dist/components/dataTable/useTableVirtualization.d.ts.map +0 -1
  73. package/dist/components/form/inputs/JSONInput.vue.d.ts +0 -21
  74. package/dist/components/form/inputs/JSONInput.vue.d.ts.map +0 -1
  75. package/src/components/form/inputs/JSONInput.vue +0 -60
@@ -0,0 +1,198 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * MapChart — SVG choropleth of countries (ISO-3166-1 alpha-2). Pure SVG, no
4
+ * tiles. Same “plot only / wrap in Card” contract as BarChart / Donut.
5
+ *
6
+ * <MapChart :data="[{ id: 'US', value: 4200 }, { id: 'IL', label: 'Israel', value: 900 }]" />
7
+ * <MapChart :data="rows" color="green" :height="280" />
8
+ */
9
+ import { computed, ref } from 'vue'
10
+ import type { ThemeType } from '../../types'
11
+ import ChartTooltip from './ChartTooltip.vue'
12
+ import { formatValue, type ValueFormat } from './core/format'
13
+ import { resolveColor } from './core/palette'
14
+ import { useChartAnim } from './core/useChartAnim'
15
+ import { tipFollowStyle, trackLocalPointer } from './core/useChartTip'
16
+ import { WORLD_NAMES, WORLD_PATHS, WORLD_VIEWBOX } from './core/world-paths'
17
+ import type { MapDatum } from './mapTypes'
18
+
19
+ defineOptions({ name: 'BglMapChart' })
20
+
21
+ export type { MapDatum }
22
+
23
+ const props = withDefaults(defineProps<{
24
+ data: MapDatum[]
25
+ /** Base tone for the value ramp (low → high intensity). */
26
+ color?: ThemeType | string
27
+ height?: number
28
+ /** Show min→max legend strip under the map. */
29
+ legend?: boolean
30
+ currency?: string
31
+ prefix?: string
32
+ suffix?: string
33
+ animated?: boolean
34
+ }>(), {
35
+ color: 'primary',
36
+ height: 280,
37
+ legend: true,
38
+ animated: true,
39
+ })
40
+
41
+ const el = ref<HTMLElement>()
42
+ const { progress } = useChartAnim({ el, enabled: props.animated, duration: 700 })
43
+
44
+ const fmt = computed<ValueFormat>(() => ({
45
+ currency: props.currency,
46
+ prefix: props.prefix,
47
+ suffix: props.suffix,
48
+ compact: true,
49
+ }))
50
+
51
+ const byId = computed(() => {
52
+ const map = new Map<string, MapDatum>()
53
+ for (const d of props.data) {
54
+ const id = d.id?.toUpperCase?.() ?? ''
55
+ if (!id) continue
56
+ const prev = map.get(id)
57
+ map.set(id, prev
58
+ ? { ...d, id, value: prev.value + d.value, label: d.label ?? prev.label }
59
+ : { ...d, id })
60
+ }
61
+ return map
62
+ })
63
+
64
+ const maxValue = computed(() => Math.max(0, ...[...byId.value.values()].map(d => d.value)))
65
+
66
+ const baseColor = computed(() => resolveColor(props.color))
67
+ const emptyFill = 'color-mix(in srgb, var(--bgl-gray) 12%, var(--bgl-box-bg))'
68
+ const strokeColor = 'color-mix(in srgb, var(--bgl-gray) 28%, var(--bgl-box-bg))'
69
+
70
+ /** Continuous ramp: empty → light tint → full base color by value share. */
71
+ function fillFor(value: number | undefined): string {
72
+ if (value == null || value <= 0 || maxValue.value <= 0) return emptyFill
73
+ const t = Math.sqrt(value / maxValue.value) // sqrt so mid values stay visible
74
+ const pct = 28 + t * 72 * progress.value
75
+ return `color-mix(in srgb, ${baseColor.value} ${pct}%, var(--bgl-box-bg))`
76
+ }
77
+
78
+ interface CountryPath {
79
+ id: string
80
+ d: string
81
+ label: string
82
+ value: number | undefined
83
+ fill: string
84
+ hasData: boolean
85
+ }
86
+
87
+ const countries = computed<CountryPath[]>(() =>
88
+ Object.entries(WORLD_PATHS).map(([id, d]) => {
89
+ const row = byId.value.get(id)
90
+ const value = row?.value
91
+ return {
92
+ id,
93
+ d,
94
+ label: row?.label || WORLD_NAMES[id] || id,
95
+ value,
96
+ fill: fillFor(value),
97
+ hasData: value != null && value > 0,
98
+ }
99
+ }),
100
+ )
101
+
102
+ const hoverId = ref<string | null>(null)
103
+ const tipX = ref(0)
104
+ const tipY = ref(0)
105
+
106
+ function onEnter(id: string) { hoverId.value = id }
107
+ function onLeave() { hoverId.value = null }
108
+ function onMove(e: MouseEvent) { trackLocalPointer(e, tipX, tipY) }
109
+
110
+ const hover = computed(() => {
111
+ if (!hoverId.value) return null
112
+ const c = countries.value.find(x => x.id === hoverId.value)
113
+ return c?.hasData ? c : null
114
+ })
115
+
116
+ const hoverRows = computed(() => hover.value
117
+ ? [{ name: hover.value.label, color: hover.value.fill, value: formatValue(hover.value.value!, fmt.value) }]
118
+ : [])
119
+
120
+ const tooltipStyle = tipFollowStyle(tipX, tipY)
121
+
122
+ const legendMin = computed(() => formatValue(0, fmt.value))
123
+ const legendMax = computed(() => formatValue(maxValue.value, fmt.value))
124
+ </script>
125
+
126
+ <template>
127
+ <div ref="el" class="bgl-map w-100p flex column gap-075">
128
+ <div
129
+ class="bgl-map__plot relative w-100p"
130
+ :style="{ height: `${height}px` }"
131
+ @mousemove="onMove"
132
+ @mouseleave="onLeave"
133
+ >
134
+ <svg
135
+ class="bgl-map__svg"
136
+ dir="ltr"
137
+ :viewBox="`0 0 ${WORLD_VIEWBOX.width} ${WORLD_VIEWBOX.height}`"
138
+ preserveAspectRatio="xMidYMid meet"
139
+ width="100%"
140
+ height="100%"
141
+ >
142
+ <path
143
+ v-for="c in countries"
144
+ :key="c.id"
145
+ :d="c.d"
146
+ :fill="c.fill"
147
+ :stroke="strokeColor"
148
+ stroke-width="0.6"
149
+ vector-effect="non-scaling-stroke"
150
+ class="bgl-map__country"
151
+ :class="{
152
+ 'opacity-5': hoverId != null && hoverId !== c.id,
153
+ 'bgl-map__country--hot': hoverId === c.id && c.hasData,
154
+ }"
155
+ @mouseenter="onEnter(c.id)"
156
+ />
157
+ </svg>
158
+
159
+ <ChartTooltip
160
+ v-if="hover"
161
+ prefer="above"
162
+ :style="tooltipStyle"
163
+ :label="hover.label"
164
+ :rows="hoverRows"
165
+ />
166
+ </div>
167
+
168
+ <div
169
+ v-if="legend && maxValue > 0"
170
+ class="bgl-map__legend flex align-items-center gap-05 txt12 color-gray"
171
+ >
172
+ <span class="tabular-nums">{{ legendMin }}</span>
173
+ <div
174
+ class="bgl-map__ramp flex-1"
175
+ :style="{
176
+ background: `linear-gradient(to right, color-mix(in srgb, ${baseColor} 28%, var(--bgl-box-bg)), ${baseColor})`,
177
+ }"
178
+ />
179
+ <span class="tabular-nums">{{ legendMax }}</span>
180
+ </div>
181
+ </div>
182
+ </template>
183
+
184
+ <style scoped>
185
+ .bgl-map__plot { min-height: 0; }
186
+ .bgl-map__svg { display: block; overflow: visible; }
187
+ .bgl-map__country {
188
+ cursor: default;
189
+ transition: opacity 0.15s ease, fill 0.15s ease;
190
+ outline: none;
191
+ }
192
+ .bgl-map__country--hot { stroke: var(--bgl-gray); stroke-width: 1.2; }
193
+ .bgl-map__ramp {
194
+ height: 0.5rem;
195
+ border-radius: 999px;
196
+ min-width: 4rem;
197
+ }
198
+ </style>
@@ -11,6 +11,8 @@ import { alpha, resolveColor } from './core/palette'
11
11
  import { useChartAnim } from './core/useChartAnim'
12
12
  import type { ThemeType } from '../../types'
13
13
 
14
+ defineOptions({ name: 'BglRadialBars' })
15
+
14
16
  interface Ring { label: string; value: number; color?: ThemeType | string; max?: number }
15
17
 
16
18
  const props = withDefaults(defineProps<{
@@ -37,7 +39,7 @@ const props = withDefaults(defineProps<{
37
39
  })
38
40
 
39
41
  const el = ref<HTMLElement>()
40
- const { progress } = useChartAnim({ el, enabled: props.animated, duration: 900 })
42
+ const { progress } = useChartAnim({ el, enabled: props.animated, duration: 700 })
41
43
 
42
44
  const cx = computed(() => props.size / 2)
43
45
 
@@ -11,6 +11,8 @@ import { ramp, resolveColor } from './core/palette'
11
11
  import { formatValue, type ValueFormat } from './core/format'
12
12
  import type { ThemeType } from '../../types'
13
13
 
14
+ defineOptions({ name: 'BglRankBars' })
15
+
14
16
  interface Row { label: string; value: number; color?: ThemeType | string }
15
17
 
16
18
  const props = withDefaults(defineProps<{
@@ -37,7 +37,7 @@ const props = withDefaults(defineProps<{
37
37
  })
38
38
 
39
39
  const el = ref<HTMLElement>()
40
- const { progress } = useChartAnim({ el, enabled: props.animated, duration: 600 })
40
+ const { progress } = useChartAnim({ el, enabled: props.animated, duration: 700 })
41
41
 
42
42
  const stroke = computed(() => resolveColor(props.color))
43
43
  const points = computed(() => normalizeSeries(props.data, undefined)[0]?.points ?? [])
@@ -15,6 +15,8 @@ import { formatValue } from './core/format'
15
15
  import { resolveColor } from './core/palette'
16
16
  import type { ThemeType } from '../../types'
17
17
 
18
+ defineOptions({ name: 'BglStatCard' })
19
+
18
20
  const props = withDefaults(defineProps<{
19
21
  label: string
20
22
  value: number | string
@@ -0,0 +1,53 @@
1
+ /**
2
+ * SVG arc helpers for pie / donut slices.
3
+ * Full 360° arcs must be split — a single SVG arc with coincident endpoints collapses.
4
+ */
5
+ const TWO_PI = Math.PI * 2
6
+ const EPS = 1e-6
7
+
8
+ /**
9
+ * Build an SVG path for a pie wedge (`ri === 0`) or donut slice (`ri > 0`)
10
+ * spanning `sweep` radians clockwise from `a0` (0 = east, −π/2 = north).
11
+ */
12
+ export function slicePath(
13
+ cx: number,
14
+ cy: number,
15
+ r: number,
16
+ ri: number,
17
+ a0: number,
18
+ sweep: number,
19
+ ): string {
20
+ if (sweep <= EPS || r <= 0) return ''
21
+
22
+ // Full circle / ring — two semicircle arcs (SVG can't draw 360° in one A).
23
+ if (sweep >= TWO_PI - EPS) {
24
+ if (ri <= 0) {
25
+ return `M ${cx + r} ${cy} A ${r} ${r} 0 1 1 ${cx - r} ${cy} A ${r} ${r} 0 1 1 ${cx + r} ${cy} Z`
26
+ }
27
+ return [
28
+ `M ${cx + r} ${cy}`,
29
+ `A ${r} ${r} 0 1 1 ${cx - r} ${cy}`,
30
+ `A ${r} ${r} 0 1 1 ${cx + r} ${cy}`,
31
+ `L ${cx + ri} ${cy}`,
32
+ `A ${ri} ${ri} 0 1 0 ${cx - ri} ${cy}`,
33
+ `A ${ri} ${ri} 0 1 0 ${cx + ri} ${cy}`,
34
+ 'Z',
35
+ ].join(' ')
36
+ }
37
+
38
+ const a1 = a0 + sweep
39
+ const large = sweep > Math.PI ? 1 : 0
40
+ const x0 = cx + r * Math.cos(a0)
41
+ const y0 = cy + r * Math.sin(a0)
42
+ const x1 = cx + r * Math.cos(a1)
43
+ const y1 = cy + r * Math.sin(a1)
44
+
45
+ if (ri > 0) {
46
+ const xi1 = cx + ri * Math.cos(a1)
47
+ const yi1 = cy + ri * Math.sin(a1)
48
+ const xi0 = cx + ri * Math.cos(a0)
49
+ const yi0 = cy + ri * Math.sin(a0)
50
+ return `M ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1} L ${xi1} ${yi1} A ${ri} ${ri} 0 ${large} 0 ${xi0} ${yi0} Z`
51
+ }
52
+ return `M ${cx} ${cy} L ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1} Z`
53
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared tooltip anchoring helpers for charts.
3
+ *
4
+ * Two placement modes (match ChartTooltip `prefer`):
5
+ * - **follow** (`prefer="above"`): cursor-anchored — Donut, Map, Funnel
6
+ * - **pinned** (`prefer="top"`): top of chart, x follows mouse — Line, Bar
7
+ */
8
+ import { computed, type Ref } from 'vue'
9
+
10
+ /** Update tip coords from a mouse event relative to `currentTarget`. */
11
+ export function trackLocalPointer(
12
+ e: MouseEvent,
13
+ tipX: Ref<number>,
14
+ tipY?: Ref<number>,
15
+ ) {
16
+ const el = e.currentTarget as HTMLElement | null
17
+ if (!el) return
18
+ const rect = el.getBoundingClientRect()
19
+ tipX.value = e.clientX - rect.left
20
+ if (tipY) tipY.value = e.clientY - rect.top
21
+ }
22
+
23
+ /** Cursor-follow style: `{ left, top }` for `prefer="above"|"below"`. */
24
+ export function tipFollowStyle(tipX: Ref<number>, tipY: Ref<number>) {
25
+ return computed(() => ({ left: `${tipX.value}px`, top: `${tipY.value}px` }))
26
+ }
27
+
28
+ /** Pinned-to-top style: `{ left }` clamped inside the chart for `prefer="top"`. */
29
+ export function tipPinnedStyle(tipX: Ref<number>, width: Ref<number>, half = 70) {
30
+ return computed(() => {
31
+ const w = width.value
32
+ const x = Math.min(Math.max(tipX.value, half), Math.max(half, w - half))
33
+ return { left: `${x}px` }
34
+ })
35
+ }