@treeui/vue 0.14.0 → 0.15.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.
Files changed (144) hide show
  1. package/dist/components/TAppShell.cjs.map +1 -1
  2. package/dist/components/TAppShell.js.map +1 -1
  3. package/dist/components/TAppShell.vue.d.ts +25 -0
  4. package/dist/components/TAppShell.vue.d.ts.map +1 -1
  5. package/dist/components/TAppShell.vue_vue_type_script_setup_true_lang.cjs +1 -1
  6. package/dist/components/TAppShell.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  7. package/dist/components/TAppShell.vue_vue_type_script_setup_true_lang.js +166 -104
  8. package/dist/components/TAppShell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  9. package/dist/components/TButton.cjs.map +1 -1
  10. package/dist/components/TButton.js.map +1 -1
  11. package/dist/components/TButton.vue.d.ts +6 -0
  12. package/dist/components/TButton.vue.d.ts.map +1 -1
  13. package/dist/components/TButton.vue_vue_type_script_setup_true_lang.cjs +1 -1
  14. package/dist/components/TButton.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  15. package/dist/components/TButton.vue_vue_type_script_setup_true_lang.js +10 -2
  16. package/dist/components/TButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  17. package/dist/components/TChart.cjs.map +1 -1
  18. package/dist/components/TChart.js.map +1 -1
  19. package/dist/components/TChart.vue.d.ts.map +1 -1
  20. package/dist/components/TChart.vue_vue_type_script_setup_true_lang.cjs +1 -1
  21. package/dist/components/TChart.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  22. package/dist/components/TChart.vue_vue_type_script_setup_true_lang.js +58 -58
  23. package/dist/components/TChart.vue_vue_type_script_setup_true_lang.js.map +1 -1
  24. package/dist/components/TColorSwatch.cjs +2 -0
  25. package/dist/components/TColorSwatch.cjs.map +1 -0
  26. package/dist/components/TColorSwatch.js +7 -0
  27. package/dist/components/TColorSwatch.js.map +1 -0
  28. package/dist/components/TColorSwatch.vue.d.ts +33 -0
  29. package/dist/components/TColorSwatch.vue.d.ts.map +1 -0
  30. package/dist/components/TColorSwatch.vue_vue_type_script_setup_true_lang.cjs +2 -0
  31. package/dist/components/TColorSwatch.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  32. package/dist/components/TColorSwatch.vue_vue_type_script_setup_true_lang.js +63 -0
  33. package/dist/components/TColorSwatch.vue_vue_type_script_setup_true_lang.js.map +1 -0
  34. package/dist/components/TDropdown.vue.d.ts +1 -1
  35. package/dist/components/TDropdown.vue.d.ts.map +1 -1
  36. package/dist/components/TInput.cjs.map +1 -1
  37. package/dist/components/TInput.js.map +1 -1
  38. package/dist/components/TInput.vue.d.ts +4 -1
  39. package/dist/components/TInput.vue.d.ts.map +1 -1
  40. package/dist/components/TInput.vue_vue_type_script_setup_true_lang.cjs +1 -1
  41. package/dist/components/TInput.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  42. package/dist/components/TInput.vue_vue_type_script_setup_true_lang.js +2 -0
  43. package/dist/components/TInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  44. package/dist/components/TKbd.cjs +2 -0
  45. package/dist/components/TKbd.cjs.map +1 -0
  46. package/dist/components/TKbd.js +7 -0
  47. package/dist/components/TKbd.js.map +1 -0
  48. package/dist/components/TKbd.vue.d.ts +18 -0
  49. package/dist/components/TKbd.vue.d.ts.map +1 -0
  50. package/dist/components/TKbd.vue_vue_type_script_setup_true_lang.cjs +2 -0
  51. package/dist/components/TKbd.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  52. package/dist/components/TKbd.vue_vue_type_script_setup_true_lang.js +12 -0
  53. package/dist/components/TKbd.vue_vue_type_script_setup_true_lang.js.map +1 -0
  54. package/dist/components/TPopover.vue.d.ts +1 -1
  55. package/dist/components/TPopover.vue.d.ts.map +1 -1
  56. package/dist/components/TSelect.cjs.map +1 -1
  57. package/dist/components/TSelect.js.map +1 -1
  58. package/dist/components/TSelect.vue.d.ts +4 -1
  59. package/dist/components/TSelect.vue.d.ts.map +1 -1
  60. package/dist/components/TSelect.vue_vue_type_script_setup_true_lang.cjs +1 -1
  61. package/dist/components/TSelect.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  62. package/dist/components/TSelect.vue_vue_type_script_setup_true_lang.js +2 -0
  63. package/dist/components/TSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  64. package/dist/components/TSpacer.cjs +2 -0
  65. package/dist/components/TSpacer.cjs.map +1 -0
  66. package/dist/components/TSpacer.js +7 -0
  67. package/dist/components/TSpacer.js.map +1 -0
  68. package/dist/components/TSpacer.vue.d.ts +8 -0
  69. package/dist/components/TSpacer.vue.d.ts.map +1 -0
  70. package/dist/components/TSpacer.vue_vue_type_script_setup_true_lang.cjs +2 -0
  71. package/dist/components/TSpacer.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  72. package/dist/components/TSpacer.vue_vue_type_script_setup_true_lang.js +16 -0
  73. package/dist/components/TSpacer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  74. package/dist/components/TSplit.cjs +2 -0
  75. package/dist/components/TSplit.cjs.map +1 -0
  76. package/dist/components/TSplit.js +7 -0
  77. package/dist/components/TSplit.js.map +1 -0
  78. package/dist/components/TSplit.vue.d.ts +38 -0
  79. package/dist/components/TSplit.vue.d.ts.map +1 -0
  80. package/dist/components/TSplit.vue_vue_type_script_setup_true_lang.cjs +2 -0
  81. package/dist/components/TSplit.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  82. package/dist/components/TSplit.vue_vue_type_script_setup_true_lang.js +43 -0
  83. package/dist/components/TSplit.vue_vue_type_script_setup_true_lang.js.map +1 -0
  84. package/dist/components/TStack.cjs.map +1 -1
  85. package/dist/components/TStack.js.map +1 -1
  86. package/dist/components/TStack.vue.d.ts +3 -0
  87. package/dist/components/TStack.vue.d.ts.map +1 -1
  88. package/dist/components/TStack.vue_vue_type_script_setup_true_lang.cjs +1 -1
  89. package/dist/components/TStack.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  90. package/dist/components/TStack.vue_vue_type_script_setup_true_lang.js +6 -1
  91. package/dist/components/TStack.vue_vue_type_script_setup_true_lang.js.map +1 -1
  92. package/dist/components/TStackItem.cjs +2 -0
  93. package/dist/components/TStackItem.cjs.map +1 -0
  94. package/dist/components/TStackItem.js +7 -0
  95. package/dist/components/TStackItem.js.map +1 -0
  96. package/dist/components/TStackItem.vue.d.ts +38 -0
  97. package/dist/components/TStackItem.vue.d.ts.map +1 -0
  98. package/dist/components/TStackItem.vue_vue_type_script_setup_true_lang.cjs +2 -0
  99. package/dist/components/TStackItem.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  100. package/dist/components/TStackItem.vue_vue_type_script_setup_true_lang.js +45 -0
  101. package/dist/components/TStackItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
  102. package/dist/components/TText.cjs +2 -0
  103. package/dist/components/TText.cjs.map +1 -0
  104. package/dist/components/TText.js +7 -0
  105. package/dist/components/TText.js.map +1 -0
  106. package/dist/components/TText.vue.d.ts +39 -0
  107. package/dist/components/TText.vue.d.ts.map +1 -0
  108. package/dist/components/TText.vue_vue_type_script_setup_true_lang.cjs +2 -0
  109. package/dist/components/TText.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  110. package/dist/components/TText.vue_vue_type_script_setup_true_lang.js +32 -0
  111. package/dist/components/TText.vue_vue_type_script_setup_true_lang.js.map +1 -0
  112. package/dist/components/TTextarea.cjs.map +1 -1
  113. package/dist/components/TTextarea.js.map +1 -1
  114. package/dist/components/TTextarea.vue.d.ts +4 -1
  115. package/dist/components/TTextarea.vue.d.ts.map +1 -1
  116. package/dist/components/TTextarea.vue_vue_type_script_setup_true_lang.cjs +1 -1
  117. package/dist/components/TTextarea.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  118. package/dist/components/TTextarea.vue_vue_type_script_setup_true_lang.js +2 -0
  119. package/dist/components/TTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  120. package/dist/components/index.d.ts +8 -0
  121. package/dist/components/index.d.ts.map +1 -1
  122. package/dist/composables/useTheme.cjs +2 -0
  123. package/dist/composables/useTheme.cjs.map +1 -0
  124. package/dist/composables/useTheme.d.ts +38 -0
  125. package/dist/composables/useTheme.d.ts.map +1 -0
  126. package/dist/composables/useTheme.js +54 -0
  127. package/dist/composables/useTheme.js.map +1 -0
  128. package/dist/index.cjs +1 -1
  129. package/dist/index.d.ts +2 -0
  130. package/dist/index.d.ts.map +1 -1
  131. package/dist/index.js +43 -36
  132. package/dist/plugin.cjs +1 -1
  133. package/dist/plugin.cjs.map +1 -1
  134. package/dist/plugin.d.ts.map +1 -1
  135. package/dist/plugin.js +142 -130
  136. package/dist/plugin.js.map +1 -1
  137. package/dist/style.css +1 -1
  138. package/dist/types/contracts.cjs +1 -1
  139. package/dist/types/contracts.cjs.map +1 -1
  140. package/dist/types/contracts.d.ts +8 -1
  141. package/dist/types/contracts.d.ts.map +1 -1
  142. package/dist/types/contracts.js +8 -2
  143. package/dist/types/contracts.js.map +1 -1
  144. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"TChart.cjs","names":[],"sources":["../../src/components/TChart.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue';\nimport {\n buildAreaPath,\n buildLinePath,\n linearScale,\n niceScale,\n type ChartPoint,\n} from '@treeui/utils';\n\nexport type TChartType = 'line' | 'area' | 'bar';\n\nexport interface TChartSeries {\n /** Legend/tooltip name for the series. */\n name: string;\n /** One value per category, aligned to `labels`. */\n data: number[];\n /** Override the series color; defaults to a chart palette token. */\n color?: string;\n}\n\nexport interface TChartActivePayload {\n index: number;\n label: string;\n values: Array<{ name: string; value: number; color: string }>;\n}\n\nconst props = withDefaults(\n defineProps<{\n /** Visual form of the plot. */\n type?: TChartType;\n /** One or more data series. */\n series?: TChartSeries[];\n /** Category labels for the x-axis, aligned to each series' data. */\n labels?: string[];\n /** Plot height in px (width is fluid). */\n height?: number;\n /** Smooth (curved) line/area. */\n smooth?: boolean;\n /**\n * Stack bar series on top of each other instead of grouping side by side.\n * Negative values are clamped to 0 in stacked mode (grouped mode renders them).\n */\n stacked?: boolean;\n /** Draw horizontal gridlines. */\n showGrid?: boolean;\n /** Show the legend. Defaults to on when there is more than one series. */\n showLegend?: boolean;\n /** Show x-axis category labels. */\n showXAxis?: boolean;\n /** Show y-axis value ticks. */\n showYAxis?: boolean;\n /** Show the hover crosshair + tooltip. */\n showTooltip?: boolean;\n /** Always render markers on line/area points (not just on hover). */\n showPoints?: boolean;\n /** Target number of y-axis ticks. */\n yTicks?: number;\n /** Format axis + tooltip values. */\n valueFormat?: (value: number) => string;\n /** Force the low end of the y domain. */\n minY?: number;\n /** Force the high end of the y domain. */\n maxY?: number;\n /** Animate marks on first render (respects prefers-reduced-motion). */\n animated?: boolean;\n /** Render skeleton placeholders instead of the plot. */\n loading?: boolean;\n /** Accessible summary of the chart. */\n ariaLabel?: string;\n }>(),\n {\n type: 'line',\n series: () => [],\n labels: () => [],\n height: 260,\n smooth: false,\n stacked: false,\n showGrid: true,\n showLegend: undefined,\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showPoints: false,\n yTicks: 5,\n valueFormat: undefined,\n minY: undefined,\n maxY: undefined,\n animated: true,\n loading: false,\n ariaLabel: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'point-click': [payload: TChartActivePayload];\n}>();\n\ndefineSlots<{\n legend?: (props: { series: Array<{ name: string; color: string }> }) => unknown;\n tooltip?: (props: TChartActivePayload) => unknown;\n empty?: () => unknown;\n}>();\n\n// --- measurement ----------------------------------------------------------\nconst canvasRef = ref<HTMLElement | null>(null);\nconst width = ref(640);\nlet observer: ResizeObserver | null = null;\n\nonMounted(() => {\n const element = canvasRef.value;\n if (!element) return;\n width.value = element.clientWidth || width.value;\n\n if (typeof ResizeObserver !== 'undefined') {\n observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured) width.value = measured;\n });\n observer.observe(element);\n }\n});\n\nonBeforeUnmount(() => observer?.disconnect());\n\n// --- derived data ---------------------------------------------------------\nconst validSeries = computed(() => props.series.filter((item) => item.data.length > 0));\n\nconst categoryCount = computed(() =>\n Math.max(0, ...validSeries.value.map((item) => item.data.length)),\n);\n\n// Shared category index range, so the a11y table stays rectangular even when\n// series have different lengths.\nconst axisIndices = computed(() =>\n Array.from({ length: categoryCount.value }, (_, index) => index),\n);\n\nconst hasData = computed(() => validSeries.value.length > 0 && categoryCount.value > 0);\n\nconst resolvedShowLegend = computed(() =>\n props.showLegend ?? validSeries.value.length > 1,\n);\n\nconst colorFor = (index: number, series: TChartSeries) =>\n series.color ?? `var(--tree-color-chart-${(index % 8) + 1})`;\n\nconst legendItems = computed(() =>\n validSeries.value.map((series, index) => ({\n name: series.name,\n color: colorFor(index, series),\n })),\n);\n\nconst formatValue = (value: number) => {\n if (props.valueFormat) return props.valueFormat(value);\n if (Math.abs(value) >= 1000) return value.toLocaleString('en-US');\n return `${value}`;\n};\n\n// --- layout ---------------------------------------------------------------\nconst margin = computed(() => ({\n top: 12,\n right: 12,\n bottom: props.showXAxis && props.labels.length ? 28 : 10,\n left: props.showYAxis ? 44 : 10,\n}));\n\nconst plot = computed(() => {\n const { top, right, bottom, left } = margin.value;\n return {\n left,\n right: width.value - right,\n top,\n bottom: props.height - bottom,\n get innerWidth() {\n return this.right - this.left;\n },\n get innerHeight() {\n return this.bottom - this.top;\n },\n };\n});\n\nconst stackedTotals = computed(() => {\n if (!props.stacked || props.type !== 'bar') return [];\n return Array.from({ length: categoryCount.value }, (_, index) =>\n validSeries.value.reduce((sum, series) => sum + Math.max(0, series.data[index] ?? 0), 0),\n );\n});\n\nconst scale = computed(() => {\n const baselineZero = props.type === 'bar' || props.type === 'area';\n const flat = validSeries.value.flatMap((series) => series.data);\n\n const source = props.stacked && props.type === 'bar' ? stackedTotals.value : flat;\n const rawMin = source.length ? Math.min(...source) : 0;\n const rawMax = source.length ? Math.max(...source) : 1;\n\n const min = props.minY ?? (baselineZero ? Math.min(0, rawMin) : rawMin);\n const max = props.maxY ?? Math.max(rawMax, min + 1);\n\n return niceScale(min, max, props.yTicks);\n});\n\nconst yScale = computed(() =>\n linearScale([scale.value.min, scale.value.max], [plot.value.bottom, plot.value.top]),\n);\n\nconst baselineY = computed(() => yScale.value(Math.max(scale.value.min, 0)));\n\n// x-position helpers -------------------------------------------------------\nconst pointX = (index: number) => {\n const count = categoryCount.value;\n if (count <= 1) return plot.value.left + plot.value.innerWidth / 2;\n return plot.value.left + (index / (count - 1)) * plot.value.innerWidth;\n};\n\nconst band = computed(() => plot.value.innerWidth / Math.max(1, categoryCount.value));\nconst bandCenter = (index: number) => plot.value.left + band.value * (index + 0.5);\n\n// active category (for line/area points and axis labels)\nconst activeX = (index: number) =>\n props.type === 'bar' ? bandCenter(index) : pointX(index);\n\n// --- line / area geometry -------------------------------------------------\nconst linePaths = computed(() =>\n props.type === 'bar'\n ? []\n : validSeries.value.map((series, seriesIndex) => {\n const points: ChartPoint[] = series.data.map((value, index) => ({\n x: pointX(index),\n y: yScale.value(value),\n }));\n return {\n color: colorFor(seriesIndex, series),\n line: buildLinePath(points, props.smooth),\n area: props.type === 'area' ? buildAreaPath(points, plot.value.bottom, props.smooth) : '',\n points,\n };\n }),\n);\n\n// --- bar geometry ---------------------------------------------------------\nconst BAR_MAX = 24;\nconst BAR_GAP = 2;\n\nconst bars = computed(() => {\n if (props.type !== 'bar') return [];\n const output: Array<{\n x: number;\n y: number;\n width: number;\n height: number;\n color: string;\n seriesIndex: number;\n index: number;\n }> = [];\n\n const bandWidth = band.value;\n const groupWidth = Math.min(bandWidth * 0.72, BAR_MAX * validSeries.value.length + BAR_GAP);\n\n for (let index = 0; index < categoryCount.value; index += 1) {\n const center = bandCenter(index);\n\n if (props.stacked) {\n const barWidth = Math.min(groupWidth, BAR_MAX);\n let cursorBottom = baselineY.value;\n validSeries.value.forEach((series, seriesIndex) => {\n const value = Math.max(0, series.data[index] ?? 0);\n // Pixel height is proportional to the segment's own value.\n const segmentHeight = baselineY.value - yScale.value(value);\n if (segmentHeight <= 0) return;\n const top = cursorBottom - segmentHeight;\n output.push({\n x: center - barWidth / 2,\n y: top,\n // Trim 2px off each segment for a surface gap between stacked marks.\n height: Math.max(0, segmentHeight - BAR_GAP),\n width: barWidth,\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n cursorBottom = top;\n });\n } else {\n const barWidth = Math.max(1, (groupWidth - BAR_GAP * (validSeries.value.length - 1)) / validSeries.value.length);\n validSeries.value.forEach((series, seriesIndex) => {\n const value = series.data[index] ?? 0;\n const top = yScale.value(value);\n const start = center - groupWidth / 2 + seriesIndex * (barWidth + BAR_GAP);\n output.push({\n x: start,\n y: Math.min(top, baselineY.value),\n width: barWidth,\n height: Math.abs(baselineY.value - top),\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n });\n }\n }\n\n return output;\n});\n\n// --- gridlines & axes -----------------------------------------------------\nconst gridLines = computed(() =>\n scale.value.ticks.map((tick) => ({\n value: tick,\n y: yScale.value(tick),\n label: formatValue(tick),\n })),\n);\n\nconst xLabels = computed(() => {\n if (!props.showXAxis) return [];\n const count = categoryCount.value;\n const maxLabels = Math.max(2, Math.floor(plot.value.innerWidth / 52));\n const step = Math.max(1, Math.ceil(count / maxLabels));\n return props.labels.slice(0, count).map((label, index) => ({\n label,\n x: activeX(index),\n show: index % step === 0 || index === count - 1,\n }));\n});\n\n// --- interaction ----------------------------------------------------------\nconst activeIndex = ref<number | null>(null);\n\nconst pointerToIndex = (clientX: number) => {\n const element = canvasRef.value;\n if (!element) return null;\n const rect = element.getBoundingClientRect();\n const x = clientX - rect.left;\n const count = categoryCount.value;\n if (count === 0) return null;\n\n if (props.type === 'bar') {\n const index = Math.floor((x - plot.value.left) / band.value);\n return Math.min(count - 1, Math.max(0, index));\n }\n\n const ratio = (x - plot.value.left) / Math.max(1, plot.value.innerWidth);\n return Math.min(count - 1, Math.max(0, Math.round(ratio * (count - 1))));\n};\n\nconst onPointerMove = (event: PointerEvent) => {\n if (!props.showTooltip || !hasData.value) return;\n activeIndex.value = pointerToIndex(event.clientX);\n};\n\nconst onPointerLeave = () => {\n activeIndex.value = null;\n};\n\nconst activePayload = computed<TChartActivePayload | null>(() => {\n const index = activeIndex.value;\n if (index === null) return null;\n return {\n index,\n label: props.labels[index] ?? `#${index + 1}`,\n values: validSeries.value.map((series, seriesIndex) => ({\n name: series.name,\n value: series.data[index] ?? 0,\n color: colorFor(seriesIndex, series),\n })),\n };\n});\n\nconst tooltipStyle = computed(() => {\n const index = activeIndex.value;\n if (index === null) return {};\n const x = activeX(index);\n const clamped = Math.min(Math.max(x, 64), width.value - 64);\n return { left: `${clamped}px`, top: `${plot.value.top}px` };\n});\n\nconst activeMarkers = computed(() => {\n const index = activeIndex.value;\n if (index === null || props.type === 'bar') return [];\n return linePaths.value.map((path) => ({\n x: path.points[index]?.x ?? 0,\n y: path.points[index]?.y ?? 0,\n color: path.color,\n }));\n});\n\nconst onClick = () => {\n if (activePayload.value) emit('point-click', activePayload.value);\n};\n\nconst resolvedLabel = computed(\n () => props.ariaLabel ?? `${props.type} chart with ${validSeries.value.length} series`,\n);\n\nconst rootClasses = computed(() => [\n 't-chart',\n `t-chart--${props.type}`,\n {\n 'is-animated': props.animated,\n 'is-loading': props.loading,\n },\n]);\n</script>\n\n<template>\n <div :class=\"rootClasses\">\n <div\n ref=\"canvasRef\"\n class=\"t-chart__canvas\"\n :style=\"{ height: `${height}px` }\"\n >\n <div\n v-if=\"loading\"\n class=\"t-chart__loading\"\n >\n <span\n v-for=\"n in 5\"\n :key=\"n\"\n class=\"t-chart__loading-bar\"\n :style=\"{ height: `${30 + ((n * 37) % 60)}%` }\"\n />\n </div>\n\n <div\n v-else-if=\"!hasData\"\n class=\"t-chart__empty\"\n >\n <slot name=\"empty\">\n No data to display\n </slot>\n </div>\n\n <template v-else>\n <svg\n class=\"t-chart__svg\"\n :width=\"width\"\n :height=\"height\"\n :viewBox=\"`0 0 ${width} ${height}`\"\n aria-hidden=\"true\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"onPointerLeave\"\n @click=\"onClick\"\n >\n <!-- gridlines + y ticks -->\n <g class=\"t-chart__grid\">\n <template\n v-for=\"line in gridLines\"\n :key=\"line.value\"\n >\n <line\n v-if=\"showGrid\"\n class=\"t-chart__gridline\"\n :x1=\"plot.left\"\n :x2=\"plot.right\"\n :y1=\"line.y\"\n :y2=\"line.y\"\n />\n <text\n v-if=\"showYAxis\"\n class=\"t-chart__axis-label t-chart__axis-label--y\"\n :x=\"plot.left - 8\"\n :y=\"line.y\"\n >\n {{ line.label }}\n </text>\n </template>\n </g>\n\n <!-- area fills -->\n <g class=\"t-chart__areas\">\n <path\n v-for=\"(path, index) in linePaths\"\n v-show=\"type === 'area'\"\n :key=\"`area-${index}`\"\n class=\"t-chart__area\"\n :d=\"path.area\"\n :style=\"{ color: path.color }\"\n />\n </g>\n\n <!-- bars -->\n <g class=\"t-chart__bars\">\n <rect\n v-for=\"(bar, index) in bars\"\n :key=\"`bar-${index}`\"\n class=\"t-chart__bar\"\n :x=\"bar.x\"\n :y=\"bar.y\"\n :width=\"bar.width\"\n :height=\"bar.height\"\n :rx=\"Math.min(4, bar.width / 2)\"\n :style=\"{ color: bar.color, animationDelay: `${bar.index * 40}ms` }\"\n :class=\"{ 'is-active': activeIndex === bar.index }\"\n />\n </g>\n\n <!-- lines + optional static points -->\n <g class=\"t-chart__lines\">\n <template\n v-for=\"(path, index) in linePaths\"\n :key=\"`line-${index}`\"\n >\n <path\n v-if=\"type !== 'bar'\"\n class=\"t-chart__line\"\n :d=\"path.line\"\n path-length=\"1\"\n :style=\"{ color: path.color }\"\n />\n <template v-if=\"showPoints && type !== 'bar'\">\n <circle\n v-for=\"(point, pointIndex) in path.points\"\n :key=\"`point-${index}-${pointIndex}`\"\n class=\"t-chart__point\"\n :cx=\"point.x\"\n :cy=\"point.y\"\n r=\"3\"\n :style=\"{ color: path.color }\"\n />\n </template>\n </template>\n </g>\n\n <!-- hover crosshair + active markers -->\n <g\n v-if=\"activeIndex !== null && showTooltip\"\n class=\"t-chart__hover\"\n >\n <line\n class=\"t-chart__crosshair\"\n :x1=\"activeX(activeIndex)\"\n :x2=\"activeX(activeIndex)\"\n :y1=\"plot.top\"\n :y2=\"plot.bottom\"\n />\n <circle\n v-for=\"(marker, index) in activeMarkers\"\n :key=\"`marker-${index}`\"\n class=\"t-chart__marker\"\n :cx=\"marker.x\"\n :cy=\"marker.y\"\n r=\"4\"\n :style=\"{ color: marker.color }\"\n />\n </g>\n\n <!-- x-axis labels -->\n <g\n v-if=\"showXAxis\"\n class=\"t-chart__x-axis\"\n >\n <text\n v-for=\"(item, index) in xLabels\"\n v-show=\"item.show\"\n :key=\"`x-${index}`\"\n class=\"t-chart__axis-label t-chart__axis-label--x\"\n :x=\"item.x\"\n :y=\"height - 8\"\n >\n {{ item.label }}\n </text>\n </g>\n </svg>\n\n <div\n v-if=\"showTooltip && activePayload\"\n class=\"t-chart__tooltip\"\n :style=\"tooltipStyle\"\n role=\"presentation\"\n >\n <slot\n name=\"tooltip\"\n v-bind=\"activePayload\"\n >\n <p class=\"t-chart__tooltip-label\">\n {{ activePayload.label }}\n </p>\n <ul class=\"t-chart__tooltip-list\">\n <li\n v-for=\"(item, index) in activePayload.values\"\n :key=\"index\"\n class=\"t-chart__tooltip-item\"\n >\n <span\n class=\"t-chart__tooltip-dot\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n <span class=\"t-chart__tooltip-name\">{{ item.name }}</span>\n <span class=\"t-chart__tooltip-value\">{{ formatValue(item.value) }}</span>\n </li>\n </ul>\n </slot>\n </div>\n </template>\n </div>\n\n <div\n v-if=\"resolvedShowLegend && hasData\"\n class=\"t-chart__legend\"\n >\n <slot\n name=\"legend\"\n :series=\"legendItems\"\n >\n <span\n v-for=\"(item, index) in legendItems\"\n :key=\"index\"\n class=\"t-chart__legend-item\"\n >\n <span\n class=\"t-chart__legend-swatch\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n {{ item.name }}\n </span>\n </slot>\n </div>\n\n <!-- Accessible data table: the chart's data as text for assistive tech. -->\n <table class=\"t-chart__a11y t-visually-hidden\">\n <caption>{{ resolvedLabel }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">\n Series\n </th>\n <th\n v-for=\"index in axisIndices\"\n :key=\"index\"\n scope=\"col\"\n >\n {{ labels[index] ?? '' }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, rowIndex) in validSeries\"\n :key=\"rowIndex\"\n >\n <th scope=\"row\">\n {{ row.name }}\n </th>\n <td\n v-for=\"index in axisIndices\"\n :key=\"index\"\n >\n {{ row.data[index] === undefined ? '' : formatValue(row.data[index]) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"TChart.cjs","names":[],"sources":["../../src/components/TChart.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue';\nimport {\n buildAreaPath,\n buildLinePath,\n linearScale,\n niceScale,\n type ChartPoint,\n} from '@treeui/utils';\n\nexport type TChartType = 'line' | 'area' | 'bar';\n\nexport interface TChartSeries {\n /** Legend/tooltip name for the series. */\n name: string;\n /** One value per category, aligned to `labels`. */\n data: number[];\n /** Override the series color; defaults to a chart palette token. */\n color?: string;\n}\n\nexport interface TChartActivePayload {\n index: number;\n label: string;\n values: Array<{ name: string; value: number; color: string }>;\n}\n\nconst props = withDefaults(\n defineProps<{\n /** Visual form of the plot. */\n type?: TChartType;\n /** One or more data series. */\n series?: TChartSeries[];\n /** Category labels for the x-axis, aligned to each series' data. */\n labels?: string[];\n /** Plot height in px (width is fluid). */\n height?: number;\n /** Smooth (curved) line/area. */\n smooth?: boolean;\n /**\n * Stack bar series on top of each other instead of grouping side by side.\n * Negative values are clamped to 0 in stacked mode (grouped mode renders them).\n */\n stacked?: boolean;\n /** Draw horizontal gridlines. */\n showGrid?: boolean;\n /** Show the legend. Defaults to on when there is more than one series. */\n showLegend?: boolean;\n /** Show x-axis category labels. */\n showXAxis?: boolean;\n /** Show y-axis value ticks. */\n showYAxis?: boolean;\n /** Show the hover crosshair + tooltip. */\n showTooltip?: boolean;\n /** Always render markers on line/area points (not just on hover). */\n showPoints?: boolean;\n /** Target number of y-axis ticks. */\n yTicks?: number;\n /** Format axis + tooltip values. */\n valueFormat?: (value: number) => string;\n /** Force the low end of the y domain. */\n minY?: number;\n /** Force the high end of the y domain. */\n maxY?: number;\n /** Animate marks on first render (respects prefers-reduced-motion). */\n animated?: boolean;\n /** Render skeleton placeholders instead of the plot. */\n loading?: boolean;\n /** Accessible summary of the chart. */\n ariaLabel?: string;\n }>(),\n {\n type: 'line',\n series: () => [],\n labels: () => [],\n height: 260,\n smooth: false,\n stacked: false,\n showGrid: true,\n showLegend: undefined,\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showPoints: false,\n yTicks: 5,\n valueFormat: undefined,\n minY: undefined,\n maxY: undefined,\n animated: true,\n loading: false,\n ariaLabel: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'point-click': [payload: TChartActivePayload];\n}>();\n\ndefineSlots<{\n legend?: (props: { series: Array<{ name: string; color: string }> }) => unknown;\n tooltip?: (props: TChartActivePayload) => unknown;\n empty?: () => unknown;\n}>();\n\n// --- measurement ----------------------------------------------------------\nconst canvasRef = ref<HTMLElement | null>(null);\nconst width = ref(640);\nlet observer: ResizeObserver | null = null;\n\nonMounted(() => {\n const element = canvasRef.value;\n if (!element) return;\n width.value = element.clientWidth || width.value;\n\n if (typeof ResizeObserver !== 'undefined') {\n observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured) width.value = measured;\n });\n observer.observe(element);\n }\n});\n\nonBeforeUnmount(() => observer?.disconnect());\n\n// --- derived data ---------------------------------------------------------\nconst validSeries = computed(() => props.series.filter((item) => item.data.length > 0));\n\nconst categoryCount = computed(() =>\n Math.max(0, ...validSeries.value.map((item) => item.data.length)),\n);\n\n// Shared category index range, so the a11y table stays rectangular even when\n// series have different lengths.\nconst axisIndices = computed(() =>\n Array.from({ length: categoryCount.value }, (_, index) => index),\n);\n\nconst hasData = computed(() => validSeries.value.length > 0 && categoryCount.value > 0);\n\nconst resolvedShowLegend = computed(() =>\n props.showLegend ?? validSeries.value.length > 1,\n);\n\nconst colorFor = (index: number, series: TChartSeries) =>\n series.color ?? `var(--tree-color-chart-${(index % 8) + 1})`;\n\nconst legendItems = computed(() =>\n validSeries.value.map((series, index) => ({\n name: series.name,\n color: colorFor(index, series),\n })),\n);\n\nconst formatValue = (value: number) => {\n if (props.valueFormat) return props.valueFormat(value);\n if (Math.abs(value) >= 1000) return value.toLocaleString('en-US');\n return `${value}`;\n};\n\n// --- layout ---------------------------------------------------------------\nconst margin = computed(() => ({\n top: 12,\n right: 12,\n bottom: props.showXAxis && props.labels.length ? 28 : 10,\n left: props.showYAxis ? 44 : 10,\n}));\n\nconst plot = computed(() => {\n const { top, right, bottom, left } = margin.value;\n return {\n left,\n right: width.value - right,\n top,\n bottom: props.height - bottom,\n get innerWidth() {\n return this.right - this.left;\n },\n get innerHeight() {\n return this.bottom - this.top;\n },\n };\n});\n\nconst stackedTotals = computed(() => {\n if (!props.stacked || props.type !== 'bar') return [];\n return Array.from({ length: categoryCount.value }, (_, index) =>\n validSeries.value.reduce((sum, series) => sum + Math.max(0, series.data[index] ?? 0), 0),\n );\n});\n\nconst scale = computed(() => {\n const baselineZero = props.type === 'bar' || props.type === 'area';\n const flat = validSeries.value.flatMap((series) => series.data);\n\n const source = props.stacked && props.type === 'bar' ? stackedTotals.value : flat;\n const rawMin = source.length ? Math.min(...source) : 0;\n const rawMax = source.length ? Math.max(...source) : 1;\n\n const min = props.minY ?? (baselineZero ? Math.min(0, rawMin) : rawMin);\n const max = props.maxY ?? Math.max(rawMax, min + 1);\n\n return niceScale(min, max, props.yTicks);\n});\n\nconst yScale = computed(() =>\n linearScale([scale.value.min, scale.value.max], [plot.value.bottom, plot.value.top]),\n);\n\nconst baselineY = computed(() => yScale.value(Math.max(scale.value.min, 0)));\n\n// x-position helpers -------------------------------------------------------\nconst pointX = (index: number) => {\n const count = categoryCount.value;\n if (count <= 1) return plot.value.left + plot.value.innerWidth / 2;\n return plot.value.left + (index / (count - 1)) * plot.value.innerWidth;\n};\n\nconst band = computed(() => plot.value.innerWidth / Math.max(1, categoryCount.value));\nconst bandCenter = (index: number) => plot.value.left + band.value * (index + 0.5);\n\n// active category (for line/area points and axis labels)\nconst activeX = (index: number) =>\n props.type === 'bar' ? bandCenter(index) : pointX(index);\n\n// --- line / area geometry -------------------------------------------------\nconst linePaths = computed(() =>\n props.type === 'bar'\n ? []\n : validSeries.value.map((series, seriesIndex) => {\n const points: ChartPoint[] = series.data.map((value, index) => ({\n x: pointX(index),\n y: yScale.value(value),\n }));\n return {\n color: colorFor(seriesIndex, series),\n line: buildLinePath(points, props.smooth),\n area: props.type === 'area' ? buildAreaPath(points, plot.value.bottom, props.smooth) : '',\n points,\n };\n }),\n);\n\n// --- bar geometry ---------------------------------------------------------\nconst BAR_MAX = 24;\nconst BAR_GAP = 2;\n\nconst bars = computed(() => {\n if (props.type !== 'bar') return [];\n const output: Array<{\n x: number;\n y: number;\n width: number;\n height: number;\n color: string;\n seriesIndex: number;\n index: number;\n }> = [];\n\n const bandWidth = band.value;\n const groupWidth = Math.min(bandWidth * 0.72, BAR_MAX * validSeries.value.length + BAR_GAP);\n\n for (let index = 0; index < categoryCount.value; index += 1) {\n const center = bandCenter(index);\n\n if (props.stacked) {\n const barWidth = Math.min(groupWidth, BAR_MAX);\n let cursorBottom = baselineY.value;\n validSeries.value.forEach((series, seriesIndex) => {\n const value = Math.max(0, series.data[index] ?? 0);\n // Pixel height is proportional to the segment's own value.\n const segmentHeight = baselineY.value - yScale.value(value);\n if (segmentHeight <= 0) return;\n const top = cursorBottom - segmentHeight;\n output.push({\n x: center - barWidth / 2,\n y: top,\n // Trim 2px off each segment for a surface gap between stacked marks.\n height: Math.max(0, segmentHeight - BAR_GAP),\n width: barWidth,\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n cursorBottom = top;\n });\n } else {\n const barWidth = Math.max(1, (groupWidth - BAR_GAP * (validSeries.value.length - 1)) / validSeries.value.length);\n validSeries.value.forEach((series, seriesIndex) => {\n const value = series.data[index] ?? 0;\n const top = yScale.value(value);\n const start = center - groupWidth / 2 + seriesIndex * (barWidth + BAR_GAP);\n output.push({\n x: start,\n y: Math.min(top, baselineY.value),\n width: barWidth,\n height: Math.abs(baselineY.value - top),\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n });\n }\n }\n\n return output;\n});\n\n// --- gridlines & axes -----------------------------------------------------\nconst gridLines = computed(() =>\n scale.value.ticks.map((tick) => ({\n value: tick,\n y: yScale.value(tick),\n label: formatValue(tick),\n })),\n);\n\nconst xLabels = computed(() => {\n if (!props.showXAxis) return [];\n const count = categoryCount.value;\n const maxLabels = Math.max(2, Math.floor(plot.value.innerWidth / 52));\n const step = Math.max(1, Math.ceil(count / maxLabels));\n return props.labels.slice(0, count).map((label, index) => ({\n label,\n x: activeX(index),\n show: index % step === 0 || index === count - 1,\n }));\n});\n\n// --- interaction ----------------------------------------------------------\nconst activeIndex = ref<number | null>(null);\n\nconst pointerToIndex = (clientX: number) => {\n const element = canvasRef.value;\n if (!element) return null;\n const rect = element.getBoundingClientRect();\n const x = clientX - rect.left;\n const count = categoryCount.value;\n if (count === 0) return null;\n\n if (props.type === 'bar') {\n const index = Math.floor((x - plot.value.left) / band.value);\n return Math.min(count - 1, Math.max(0, index));\n }\n\n const ratio = (x - plot.value.left) / Math.max(1, plot.value.innerWidth);\n return Math.min(count - 1, Math.max(0, Math.round(ratio * (count - 1))));\n};\n\nconst onPointerMove = (event: PointerEvent) => {\n if (!props.showTooltip || !hasData.value) return;\n activeIndex.value = pointerToIndex(event.clientX);\n};\n\nconst onPointerLeave = () => {\n activeIndex.value = null;\n};\n\nconst activePayload = computed<TChartActivePayload | null>(() => {\n const index = activeIndex.value;\n if (index === null) return null;\n return {\n index,\n label: props.labels[index] ?? `#${index + 1}`,\n values: validSeries.value.map((series, seriesIndex) => ({\n name: series.name,\n value: series.data[index] ?? 0,\n color: colorFor(seriesIndex, series),\n })),\n };\n});\n\nconst tooltipStyle = computed(() => {\n const index = activeIndex.value;\n if (index === null) return {};\n const x = activeX(index);\n const clamped = Math.min(Math.max(x, 64), width.value - 64);\n return { left: `${clamped}px`, top: `${plot.value.top}px` };\n});\n\nconst activeMarkers = computed(() => {\n const index = activeIndex.value;\n if (index === null || props.type === 'bar') return [];\n return linePaths.value.map((path) => ({\n x: path.points[index]?.x ?? 0,\n y: path.points[index]?.y ?? 0,\n color: path.color,\n }));\n});\n\nconst onClick = () => {\n if (activePayload.value) emit('point-click', activePayload.value);\n};\n\nconst resolvedLabel = computed(\n () => props.ariaLabel ?? `${props.type} chart with ${validSeries.value.length} series`,\n);\n\nconst rootClasses = computed(() => [\n 't-chart',\n `t-chart--${props.type}`,\n {\n 'is-animated': props.animated,\n 'is-loading': props.loading,\n },\n]);\n</script>\n\n<template>\n <div :class=\"rootClasses\">\n <div\n ref=\"canvasRef\"\n class=\"t-chart__canvas\"\n :style=\"{ height: `${height}px` }\"\n >\n <div\n v-if=\"loading\"\n class=\"t-chart__loading\"\n >\n <span\n v-for=\"n in 5\"\n :key=\"n\"\n class=\"t-chart__loading-bar\"\n :style=\"{ height: `${30 + ((n * 37) % 60)}%` }\"\n />\n </div>\n\n <div\n v-else-if=\"!hasData\"\n class=\"t-chart__empty\"\n >\n <slot name=\"empty\">\n No data to display\n </slot>\n </div>\n\n <template v-else>\n <svg\n class=\"t-chart__svg\"\n :width=\"width\"\n :height=\"height\"\n :viewBox=\"`0 0 ${width} ${height}`\"\n aria-hidden=\"true\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"onPointerLeave\"\n @click=\"onClick\"\n >\n <!-- gridlines + y ticks -->\n <g class=\"t-chart__grid\">\n <template\n v-for=\"line in gridLines\"\n :key=\"line.value\"\n >\n <line\n v-if=\"showGrid\"\n class=\"t-chart__gridline\"\n :x1=\"plot.left\"\n :x2=\"plot.right\"\n :y1=\"line.y\"\n :y2=\"line.y\"\n />\n <text\n v-if=\"showYAxis\"\n class=\"t-chart__axis-label t-chart__axis-label--y\"\n :x=\"plot.left - 8\"\n :y=\"line.y\"\n >\n {{ line.label }}\n </text>\n </template>\n </g>\n\n <!-- area fills -->\n <g class=\"t-chart__areas\">\n <path\n v-for=\"(path, index) in linePaths\"\n v-show=\"type === 'area'\"\n :key=\"`area-${index}`\"\n class=\"t-chart__area\"\n :d=\"path.area\"\n :style=\"{ color: path.color }\"\n />\n </g>\n\n <!-- bars -->\n <g class=\"t-chart__bars\">\n <rect\n v-for=\"(bar, index) in bars\"\n :key=\"`bar-${index}`\"\n class=\"t-chart__bar\"\n :x=\"bar.x\"\n :y=\"bar.y\"\n :width=\"bar.width\"\n :height=\"bar.height\"\n :rx=\"Math.min(4, bar.width / 2)\"\n :style=\"{ color: bar.color, animationDelay: `${bar.index * 40}ms` }\"\n :class=\"{ 'is-active': activeIndex === bar.index }\"\n />\n </g>\n\n <!-- lines + optional static points -->\n <g class=\"t-chart__lines\">\n <template\n v-for=\"(path, index) in linePaths\"\n :key=\"`line-${index}`\"\n >\n <path\n v-if=\"type !== 'bar'\"\n class=\"t-chart__line\"\n :d=\"path.line\"\n path-length=\"1\"\n :style=\"{ color: path.color }\"\n />\n <template v-if=\"showPoints && type !== 'bar'\">\n <circle\n v-for=\"(point, pointIndex) in path.points\"\n :key=\"`point-${index}-${pointIndex}`\"\n class=\"t-chart__point\"\n :cx=\"point.x\"\n :cy=\"point.y\"\n r=\"3\"\n :style=\"{ color: path.color }\"\n />\n </template>\n </template>\n </g>\n\n <!-- hover crosshair + active markers -->\n <g\n v-if=\"activeIndex !== null && showTooltip\"\n class=\"t-chart__hover\"\n >\n <line\n class=\"t-chart__crosshair\"\n :x1=\"activeX(activeIndex)\"\n :x2=\"activeX(activeIndex)\"\n :y1=\"plot.top\"\n :y2=\"plot.bottom\"\n />\n <circle\n v-for=\"(marker, index) in activeMarkers\"\n :key=\"`marker-${index}`\"\n class=\"t-chart__marker\"\n :cx=\"marker.x\"\n :cy=\"marker.y\"\n r=\"4\"\n :style=\"{ color: marker.color }\"\n />\n </g>\n\n <!-- x-axis labels -->\n <g\n v-if=\"showXAxis\"\n class=\"t-chart__x-axis\"\n >\n <text\n v-for=\"(item, index) in xLabels\"\n v-show=\"item.show\"\n :key=\"`x-${index}`\"\n class=\"t-chart__axis-label t-chart__axis-label--x\"\n :x=\"item.x\"\n :y=\"height - 8\"\n >\n {{ item.label }}\n </text>\n </g>\n </svg>\n\n <div\n v-if=\"showTooltip && activePayload\"\n class=\"t-chart__tooltip\"\n :style=\"tooltipStyle\"\n role=\"presentation\"\n >\n <slot\n name=\"tooltip\"\n v-bind=\"activePayload\"\n >\n <p class=\"t-chart__tooltip-label\">\n {{ activePayload.label }}\n </p>\n <ul class=\"t-chart__tooltip-list\">\n <li\n v-for=\"(item, index) in activePayload.values\"\n :key=\"index\"\n class=\"t-chart__tooltip-item\"\n >\n <span\n class=\"t-chart__tooltip-dot\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n <span class=\"t-chart__tooltip-name\">{{ item.name }}</span>\n <span class=\"t-chart__tooltip-value\">{{ formatValue(item.value) }}</span>\n </li>\n </ul>\n </slot>\n </div>\n </template>\n </div>\n\n <div\n v-if=\"resolvedShowLegend && hasData\"\n class=\"t-chart__legend\"\n >\n <slot\n name=\"legend\"\n :series=\"legendItems\"\n >\n <span\n v-for=\"(item, index) in legendItems\"\n :key=\"index\"\n class=\"t-chart__legend-item\"\n >\n <span\n class=\"t-chart__legend-swatch\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n {{ item.name }}\n </span>\n </slot>\n </div>\n\n <!--\n Accessible data table: the chart's data as text for assistive tech.\n The visually-hidden class goes on a wrapper, not the table: a <table>\n ignores a width below its min-content, so hiding it directly leaves a\n full-width box that pushes the page's scroll width.\n -->\n <div class=\"t-visually-hidden\">\n <table class=\"t-chart__a11y\">\n <caption>{{ resolvedLabel }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">\n Series\n </th>\n <th\n v-for=\"index in axisIndices\"\n :key=\"index\"\n scope=\"col\"\n >\n {{ labels[index] ?? '' }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, rowIndex) in validSeries\"\n :key=\"rowIndex\"\n >\n <th scope=\"row\">\n {{ row.name }}\n </th>\n <td\n v-for=\"index in axisIndices\"\n :key=\"index\"\n >\n {{ row.data[index] === undefined ? '' : formatValue(row.data[index]) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"TChart.js","names":[],"sources":["../../src/components/TChart.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue';\nimport {\n buildAreaPath,\n buildLinePath,\n linearScale,\n niceScale,\n type ChartPoint,\n} from '@treeui/utils';\n\nexport type TChartType = 'line' | 'area' | 'bar';\n\nexport interface TChartSeries {\n /** Legend/tooltip name for the series. */\n name: string;\n /** One value per category, aligned to `labels`. */\n data: number[];\n /** Override the series color; defaults to a chart palette token. */\n color?: string;\n}\n\nexport interface TChartActivePayload {\n index: number;\n label: string;\n values: Array<{ name: string; value: number; color: string }>;\n}\n\nconst props = withDefaults(\n defineProps<{\n /** Visual form of the plot. */\n type?: TChartType;\n /** One or more data series. */\n series?: TChartSeries[];\n /** Category labels for the x-axis, aligned to each series' data. */\n labels?: string[];\n /** Plot height in px (width is fluid). */\n height?: number;\n /** Smooth (curved) line/area. */\n smooth?: boolean;\n /**\n * Stack bar series on top of each other instead of grouping side by side.\n * Negative values are clamped to 0 in stacked mode (grouped mode renders them).\n */\n stacked?: boolean;\n /** Draw horizontal gridlines. */\n showGrid?: boolean;\n /** Show the legend. Defaults to on when there is more than one series. */\n showLegend?: boolean;\n /** Show x-axis category labels. */\n showXAxis?: boolean;\n /** Show y-axis value ticks. */\n showYAxis?: boolean;\n /** Show the hover crosshair + tooltip. */\n showTooltip?: boolean;\n /** Always render markers on line/area points (not just on hover). */\n showPoints?: boolean;\n /** Target number of y-axis ticks. */\n yTicks?: number;\n /** Format axis + tooltip values. */\n valueFormat?: (value: number) => string;\n /** Force the low end of the y domain. */\n minY?: number;\n /** Force the high end of the y domain. */\n maxY?: number;\n /** Animate marks on first render (respects prefers-reduced-motion). */\n animated?: boolean;\n /** Render skeleton placeholders instead of the plot. */\n loading?: boolean;\n /** Accessible summary of the chart. */\n ariaLabel?: string;\n }>(),\n {\n type: 'line',\n series: () => [],\n labels: () => [],\n height: 260,\n smooth: false,\n stacked: false,\n showGrid: true,\n showLegend: undefined,\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showPoints: false,\n yTicks: 5,\n valueFormat: undefined,\n minY: undefined,\n maxY: undefined,\n animated: true,\n loading: false,\n ariaLabel: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'point-click': [payload: TChartActivePayload];\n}>();\n\ndefineSlots<{\n legend?: (props: { series: Array<{ name: string; color: string }> }) => unknown;\n tooltip?: (props: TChartActivePayload) => unknown;\n empty?: () => unknown;\n}>();\n\n// --- measurement ----------------------------------------------------------\nconst canvasRef = ref<HTMLElement | null>(null);\nconst width = ref(640);\nlet observer: ResizeObserver | null = null;\n\nonMounted(() => {\n const element = canvasRef.value;\n if (!element) return;\n width.value = element.clientWidth || width.value;\n\n if (typeof ResizeObserver !== 'undefined') {\n observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured) width.value = measured;\n });\n observer.observe(element);\n }\n});\n\nonBeforeUnmount(() => observer?.disconnect());\n\n// --- derived data ---------------------------------------------------------\nconst validSeries = computed(() => props.series.filter((item) => item.data.length > 0));\n\nconst categoryCount = computed(() =>\n Math.max(0, ...validSeries.value.map((item) => item.data.length)),\n);\n\n// Shared category index range, so the a11y table stays rectangular even when\n// series have different lengths.\nconst axisIndices = computed(() =>\n Array.from({ length: categoryCount.value }, (_, index) => index),\n);\n\nconst hasData = computed(() => validSeries.value.length > 0 && categoryCount.value > 0);\n\nconst resolvedShowLegend = computed(() =>\n props.showLegend ?? validSeries.value.length > 1,\n);\n\nconst colorFor = (index: number, series: TChartSeries) =>\n series.color ?? `var(--tree-color-chart-${(index % 8) + 1})`;\n\nconst legendItems = computed(() =>\n validSeries.value.map((series, index) => ({\n name: series.name,\n color: colorFor(index, series),\n })),\n);\n\nconst formatValue = (value: number) => {\n if (props.valueFormat) return props.valueFormat(value);\n if (Math.abs(value) >= 1000) return value.toLocaleString('en-US');\n return `${value}`;\n};\n\n// --- layout ---------------------------------------------------------------\nconst margin = computed(() => ({\n top: 12,\n right: 12,\n bottom: props.showXAxis && props.labels.length ? 28 : 10,\n left: props.showYAxis ? 44 : 10,\n}));\n\nconst plot = computed(() => {\n const { top, right, bottom, left } = margin.value;\n return {\n left,\n right: width.value - right,\n top,\n bottom: props.height - bottom,\n get innerWidth() {\n return this.right - this.left;\n },\n get innerHeight() {\n return this.bottom - this.top;\n },\n };\n});\n\nconst stackedTotals = computed(() => {\n if (!props.stacked || props.type !== 'bar') return [];\n return Array.from({ length: categoryCount.value }, (_, index) =>\n validSeries.value.reduce((sum, series) => sum + Math.max(0, series.data[index] ?? 0), 0),\n );\n});\n\nconst scale = computed(() => {\n const baselineZero = props.type === 'bar' || props.type === 'area';\n const flat = validSeries.value.flatMap((series) => series.data);\n\n const source = props.stacked && props.type === 'bar' ? stackedTotals.value : flat;\n const rawMin = source.length ? Math.min(...source) : 0;\n const rawMax = source.length ? Math.max(...source) : 1;\n\n const min = props.minY ?? (baselineZero ? Math.min(0, rawMin) : rawMin);\n const max = props.maxY ?? Math.max(rawMax, min + 1);\n\n return niceScale(min, max, props.yTicks);\n});\n\nconst yScale = computed(() =>\n linearScale([scale.value.min, scale.value.max], [plot.value.bottom, plot.value.top]),\n);\n\nconst baselineY = computed(() => yScale.value(Math.max(scale.value.min, 0)));\n\n// x-position helpers -------------------------------------------------------\nconst pointX = (index: number) => {\n const count = categoryCount.value;\n if (count <= 1) return plot.value.left + plot.value.innerWidth / 2;\n return plot.value.left + (index / (count - 1)) * plot.value.innerWidth;\n};\n\nconst band = computed(() => plot.value.innerWidth / Math.max(1, categoryCount.value));\nconst bandCenter = (index: number) => plot.value.left + band.value * (index + 0.5);\n\n// active category (for line/area points and axis labels)\nconst activeX = (index: number) =>\n props.type === 'bar' ? bandCenter(index) : pointX(index);\n\n// --- line / area geometry -------------------------------------------------\nconst linePaths = computed(() =>\n props.type === 'bar'\n ? []\n : validSeries.value.map((series, seriesIndex) => {\n const points: ChartPoint[] = series.data.map((value, index) => ({\n x: pointX(index),\n y: yScale.value(value),\n }));\n return {\n color: colorFor(seriesIndex, series),\n line: buildLinePath(points, props.smooth),\n area: props.type === 'area' ? buildAreaPath(points, plot.value.bottom, props.smooth) : '',\n points,\n };\n }),\n);\n\n// --- bar geometry ---------------------------------------------------------\nconst BAR_MAX = 24;\nconst BAR_GAP = 2;\n\nconst bars = computed(() => {\n if (props.type !== 'bar') return [];\n const output: Array<{\n x: number;\n y: number;\n width: number;\n height: number;\n color: string;\n seriesIndex: number;\n index: number;\n }> = [];\n\n const bandWidth = band.value;\n const groupWidth = Math.min(bandWidth * 0.72, BAR_MAX * validSeries.value.length + BAR_GAP);\n\n for (let index = 0; index < categoryCount.value; index += 1) {\n const center = bandCenter(index);\n\n if (props.stacked) {\n const barWidth = Math.min(groupWidth, BAR_MAX);\n let cursorBottom = baselineY.value;\n validSeries.value.forEach((series, seriesIndex) => {\n const value = Math.max(0, series.data[index] ?? 0);\n // Pixel height is proportional to the segment's own value.\n const segmentHeight = baselineY.value - yScale.value(value);\n if (segmentHeight <= 0) return;\n const top = cursorBottom - segmentHeight;\n output.push({\n x: center - barWidth / 2,\n y: top,\n // Trim 2px off each segment for a surface gap between stacked marks.\n height: Math.max(0, segmentHeight - BAR_GAP),\n width: barWidth,\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n cursorBottom = top;\n });\n } else {\n const barWidth = Math.max(1, (groupWidth - BAR_GAP * (validSeries.value.length - 1)) / validSeries.value.length);\n validSeries.value.forEach((series, seriesIndex) => {\n const value = series.data[index] ?? 0;\n const top = yScale.value(value);\n const start = center - groupWidth / 2 + seriesIndex * (barWidth + BAR_GAP);\n output.push({\n x: start,\n y: Math.min(top, baselineY.value),\n width: barWidth,\n height: Math.abs(baselineY.value - top),\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n });\n }\n }\n\n return output;\n});\n\n// --- gridlines & axes -----------------------------------------------------\nconst gridLines = computed(() =>\n scale.value.ticks.map((tick) => ({\n value: tick,\n y: yScale.value(tick),\n label: formatValue(tick),\n })),\n);\n\nconst xLabels = computed(() => {\n if (!props.showXAxis) return [];\n const count = categoryCount.value;\n const maxLabels = Math.max(2, Math.floor(plot.value.innerWidth / 52));\n const step = Math.max(1, Math.ceil(count / maxLabels));\n return props.labels.slice(0, count).map((label, index) => ({\n label,\n x: activeX(index),\n show: index % step === 0 || index === count - 1,\n }));\n});\n\n// --- interaction ----------------------------------------------------------\nconst activeIndex = ref<number | null>(null);\n\nconst pointerToIndex = (clientX: number) => {\n const element = canvasRef.value;\n if (!element) return null;\n const rect = element.getBoundingClientRect();\n const x = clientX - rect.left;\n const count = categoryCount.value;\n if (count === 0) return null;\n\n if (props.type === 'bar') {\n const index = Math.floor((x - plot.value.left) / band.value);\n return Math.min(count - 1, Math.max(0, index));\n }\n\n const ratio = (x - plot.value.left) / Math.max(1, plot.value.innerWidth);\n return Math.min(count - 1, Math.max(0, Math.round(ratio * (count - 1))));\n};\n\nconst onPointerMove = (event: PointerEvent) => {\n if (!props.showTooltip || !hasData.value) return;\n activeIndex.value = pointerToIndex(event.clientX);\n};\n\nconst onPointerLeave = () => {\n activeIndex.value = null;\n};\n\nconst activePayload = computed<TChartActivePayload | null>(() => {\n const index = activeIndex.value;\n if (index === null) return null;\n return {\n index,\n label: props.labels[index] ?? `#${index + 1}`,\n values: validSeries.value.map((series, seriesIndex) => ({\n name: series.name,\n value: series.data[index] ?? 0,\n color: colorFor(seriesIndex, series),\n })),\n };\n});\n\nconst tooltipStyle = computed(() => {\n const index = activeIndex.value;\n if (index === null) return {};\n const x = activeX(index);\n const clamped = Math.min(Math.max(x, 64), width.value - 64);\n return { left: `${clamped}px`, top: `${plot.value.top}px` };\n});\n\nconst activeMarkers = computed(() => {\n const index = activeIndex.value;\n if (index === null || props.type === 'bar') return [];\n return linePaths.value.map((path) => ({\n x: path.points[index]?.x ?? 0,\n y: path.points[index]?.y ?? 0,\n color: path.color,\n }));\n});\n\nconst onClick = () => {\n if (activePayload.value) emit('point-click', activePayload.value);\n};\n\nconst resolvedLabel = computed(\n () => props.ariaLabel ?? `${props.type} chart with ${validSeries.value.length} series`,\n);\n\nconst rootClasses = computed(() => [\n 't-chart',\n `t-chart--${props.type}`,\n {\n 'is-animated': props.animated,\n 'is-loading': props.loading,\n },\n]);\n</script>\n\n<template>\n <div :class=\"rootClasses\">\n <div\n ref=\"canvasRef\"\n class=\"t-chart__canvas\"\n :style=\"{ height: `${height}px` }\"\n >\n <div\n v-if=\"loading\"\n class=\"t-chart__loading\"\n >\n <span\n v-for=\"n in 5\"\n :key=\"n\"\n class=\"t-chart__loading-bar\"\n :style=\"{ height: `${30 + ((n * 37) % 60)}%` }\"\n />\n </div>\n\n <div\n v-else-if=\"!hasData\"\n class=\"t-chart__empty\"\n >\n <slot name=\"empty\">\n No data to display\n </slot>\n </div>\n\n <template v-else>\n <svg\n class=\"t-chart__svg\"\n :width=\"width\"\n :height=\"height\"\n :viewBox=\"`0 0 ${width} ${height}`\"\n aria-hidden=\"true\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"onPointerLeave\"\n @click=\"onClick\"\n >\n <!-- gridlines + y ticks -->\n <g class=\"t-chart__grid\">\n <template\n v-for=\"line in gridLines\"\n :key=\"line.value\"\n >\n <line\n v-if=\"showGrid\"\n class=\"t-chart__gridline\"\n :x1=\"plot.left\"\n :x2=\"plot.right\"\n :y1=\"line.y\"\n :y2=\"line.y\"\n />\n <text\n v-if=\"showYAxis\"\n class=\"t-chart__axis-label t-chart__axis-label--y\"\n :x=\"plot.left - 8\"\n :y=\"line.y\"\n >\n {{ line.label }}\n </text>\n </template>\n </g>\n\n <!-- area fills -->\n <g class=\"t-chart__areas\">\n <path\n v-for=\"(path, index) in linePaths\"\n v-show=\"type === 'area'\"\n :key=\"`area-${index}`\"\n class=\"t-chart__area\"\n :d=\"path.area\"\n :style=\"{ color: path.color }\"\n />\n </g>\n\n <!-- bars -->\n <g class=\"t-chart__bars\">\n <rect\n v-for=\"(bar, index) in bars\"\n :key=\"`bar-${index}`\"\n class=\"t-chart__bar\"\n :x=\"bar.x\"\n :y=\"bar.y\"\n :width=\"bar.width\"\n :height=\"bar.height\"\n :rx=\"Math.min(4, bar.width / 2)\"\n :style=\"{ color: bar.color, animationDelay: `${bar.index * 40}ms` }\"\n :class=\"{ 'is-active': activeIndex === bar.index }\"\n />\n </g>\n\n <!-- lines + optional static points -->\n <g class=\"t-chart__lines\">\n <template\n v-for=\"(path, index) in linePaths\"\n :key=\"`line-${index}`\"\n >\n <path\n v-if=\"type !== 'bar'\"\n class=\"t-chart__line\"\n :d=\"path.line\"\n path-length=\"1\"\n :style=\"{ color: path.color }\"\n />\n <template v-if=\"showPoints && type !== 'bar'\">\n <circle\n v-for=\"(point, pointIndex) in path.points\"\n :key=\"`point-${index}-${pointIndex}`\"\n class=\"t-chart__point\"\n :cx=\"point.x\"\n :cy=\"point.y\"\n r=\"3\"\n :style=\"{ color: path.color }\"\n />\n </template>\n </template>\n </g>\n\n <!-- hover crosshair + active markers -->\n <g\n v-if=\"activeIndex !== null && showTooltip\"\n class=\"t-chart__hover\"\n >\n <line\n class=\"t-chart__crosshair\"\n :x1=\"activeX(activeIndex)\"\n :x2=\"activeX(activeIndex)\"\n :y1=\"plot.top\"\n :y2=\"plot.bottom\"\n />\n <circle\n v-for=\"(marker, index) in activeMarkers\"\n :key=\"`marker-${index}`\"\n class=\"t-chart__marker\"\n :cx=\"marker.x\"\n :cy=\"marker.y\"\n r=\"4\"\n :style=\"{ color: marker.color }\"\n />\n </g>\n\n <!-- x-axis labels -->\n <g\n v-if=\"showXAxis\"\n class=\"t-chart__x-axis\"\n >\n <text\n v-for=\"(item, index) in xLabels\"\n v-show=\"item.show\"\n :key=\"`x-${index}`\"\n class=\"t-chart__axis-label t-chart__axis-label--x\"\n :x=\"item.x\"\n :y=\"height - 8\"\n >\n {{ item.label }}\n </text>\n </g>\n </svg>\n\n <div\n v-if=\"showTooltip && activePayload\"\n class=\"t-chart__tooltip\"\n :style=\"tooltipStyle\"\n role=\"presentation\"\n >\n <slot\n name=\"tooltip\"\n v-bind=\"activePayload\"\n >\n <p class=\"t-chart__tooltip-label\">\n {{ activePayload.label }}\n </p>\n <ul class=\"t-chart__tooltip-list\">\n <li\n v-for=\"(item, index) in activePayload.values\"\n :key=\"index\"\n class=\"t-chart__tooltip-item\"\n >\n <span\n class=\"t-chart__tooltip-dot\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n <span class=\"t-chart__tooltip-name\">{{ item.name }}</span>\n <span class=\"t-chart__tooltip-value\">{{ formatValue(item.value) }}</span>\n </li>\n </ul>\n </slot>\n </div>\n </template>\n </div>\n\n <div\n v-if=\"resolvedShowLegend && hasData\"\n class=\"t-chart__legend\"\n >\n <slot\n name=\"legend\"\n :series=\"legendItems\"\n >\n <span\n v-for=\"(item, index) in legendItems\"\n :key=\"index\"\n class=\"t-chart__legend-item\"\n >\n <span\n class=\"t-chart__legend-swatch\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n {{ item.name }}\n </span>\n </slot>\n </div>\n\n <!-- Accessible data table: the chart's data as text for assistive tech. -->\n <table class=\"t-chart__a11y t-visually-hidden\">\n <caption>{{ resolvedLabel }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">\n Series\n </th>\n <th\n v-for=\"index in axisIndices\"\n :key=\"index\"\n scope=\"col\"\n >\n {{ labels[index] ?? '' }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, rowIndex) in validSeries\"\n :key=\"rowIndex\"\n >\n <th scope=\"row\">\n {{ row.name }}\n </th>\n <td\n v-for=\"index in axisIndices\"\n :key=\"index\"\n >\n {{ row.data[index] === undefined ? '' : formatValue(row.data[index]) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"TChart.js","names":[],"sources":["../../src/components/TChart.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue';\nimport {\n buildAreaPath,\n buildLinePath,\n linearScale,\n niceScale,\n type ChartPoint,\n} from '@treeui/utils';\n\nexport type TChartType = 'line' | 'area' | 'bar';\n\nexport interface TChartSeries {\n /** Legend/tooltip name for the series. */\n name: string;\n /** One value per category, aligned to `labels`. */\n data: number[];\n /** Override the series color; defaults to a chart palette token. */\n color?: string;\n}\n\nexport interface TChartActivePayload {\n index: number;\n label: string;\n values: Array<{ name: string; value: number; color: string }>;\n}\n\nconst props = withDefaults(\n defineProps<{\n /** Visual form of the plot. */\n type?: TChartType;\n /** One or more data series. */\n series?: TChartSeries[];\n /** Category labels for the x-axis, aligned to each series' data. */\n labels?: string[];\n /** Plot height in px (width is fluid). */\n height?: number;\n /** Smooth (curved) line/area. */\n smooth?: boolean;\n /**\n * Stack bar series on top of each other instead of grouping side by side.\n * Negative values are clamped to 0 in stacked mode (grouped mode renders them).\n */\n stacked?: boolean;\n /** Draw horizontal gridlines. */\n showGrid?: boolean;\n /** Show the legend. Defaults to on when there is more than one series. */\n showLegend?: boolean;\n /** Show x-axis category labels. */\n showXAxis?: boolean;\n /** Show y-axis value ticks. */\n showYAxis?: boolean;\n /** Show the hover crosshair + tooltip. */\n showTooltip?: boolean;\n /** Always render markers on line/area points (not just on hover). */\n showPoints?: boolean;\n /** Target number of y-axis ticks. */\n yTicks?: number;\n /** Format axis + tooltip values. */\n valueFormat?: (value: number) => string;\n /** Force the low end of the y domain. */\n minY?: number;\n /** Force the high end of the y domain. */\n maxY?: number;\n /** Animate marks on first render (respects prefers-reduced-motion). */\n animated?: boolean;\n /** Render skeleton placeholders instead of the plot. */\n loading?: boolean;\n /** Accessible summary of the chart. */\n ariaLabel?: string;\n }>(),\n {\n type: 'line',\n series: () => [],\n labels: () => [],\n height: 260,\n smooth: false,\n stacked: false,\n showGrid: true,\n showLegend: undefined,\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showPoints: false,\n yTicks: 5,\n valueFormat: undefined,\n minY: undefined,\n maxY: undefined,\n animated: true,\n loading: false,\n ariaLabel: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'point-click': [payload: TChartActivePayload];\n}>();\n\ndefineSlots<{\n legend?: (props: { series: Array<{ name: string; color: string }> }) => unknown;\n tooltip?: (props: TChartActivePayload) => unknown;\n empty?: () => unknown;\n}>();\n\n// --- measurement ----------------------------------------------------------\nconst canvasRef = ref<HTMLElement | null>(null);\nconst width = ref(640);\nlet observer: ResizeObserver | null = null;\n\nonMounted(() => {\n const element = canvasRef.value;\n if (!element) return;\n width.value = element.clientWidth || width.value;\n\n if (typeof ResizeObserver !== 'undefined') {\n observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured) width.value = measured;\n });\n observer.observe(element);\n }\n});\n\nonBeforeUnmount(() => observer?.disconnect());\n\n// --- derived data ---------------------------------------------------------\nconst validSeries = computed(() => props.series.filter((item) => item.data.length > 0));\n\nconst categoryCount = computed(() =>\n Math.max(0, ...validSeries.value.map((item) => item.data.length)),\n);\n\n// Shared category index range, so the a11y table stays rectangular even when\n// series have different lengths.\nconst axisIndices = computed(() =>\n Array.from({ length: categoryCount.value }, (_, index) => index),\n);\n\nconst hasData = computed(() => validSeries.value.length > 0 && categoryCount.value > 0);\n\nconst resolvedShowLegend = computed(() =>\n props.showLegend ?? validSeries.value.length > 1,\n);\n\nconst colorFor = (index: number, series: TChartSeries) =>\n series.color ?? `var(--tree-color-chart-${(index % 8) + 1})`;\n\nconst legendItems = computed(() =>\n validSeries.value.map((series, index) => ({\n name: series.name,\n color: colorFor(index, series),\n })),\n);\n\nconst formatValue = (value: number) => {\n if (props.valueFormat) return props.valueFormat(value);\n if (Math.abs(value) >= 1000) return value.toLocaleString('en-US');\n return `${value}`;\n};\n\n// --- layout ---------------------------------------------------------------\nconst margin = computed(() => ({\n top: 12,\n right: 12,\n bottom: props.showXAxis && props.labels.length ? 28 : 10,\n left: props.showYAxis ? 44 : 10,\n}));\n\nconst plot = computed(() => {\n const { top, right, bottom, left } = margin.value;\n return {\n left,\n right: width.value - right,\n top,\n bottom: props.height - bottom,\n get innerWidth() {\n return this.right - this.left;\n },\n get innerHeight() {\n return this.bottom - this.top;\n },\n };\n});\n\nconst stackedTotals = computed(() => {\n if (!props.stacked || props.type !== 'bar') return [];\n return Array.from({ length: categoryCount.value }, (_, index) =>\n validSeries.value.reduce((sum, series) => sum + Math.max(0, series.data[index] ?? 0), 0),\n );\n});\n\nconst scale = computed(() => {\n const baselineZero = props.type === 'bar' || props.type === 'area';\n const flat = validSeries.value.flatMap((series) => series.data);\n\n const source = props.stacked && props.type === 'bar' ? stackedTotals.value : flat;\n const rawMin = source.length ? Math.min(...source) : 0;\n const rawMax = source.length ? Math.max(...source) : 1;\n\n const min = props.minY ?? (baselineZero ? Math.min(0, rawMin) : rawMin);\n const max = props.maxY ?? Math.max(rawMax, min + 1);\n\n return niceScale(min, max, props.yTicks);\n});\n\nconst yScale = computed(() =>\n linearScale([scale.value.min, scale.value.max], [plot.value.bottom, plot.value.top]),\n);\n\nconst baselineY = computed(() => yScale.value(Math.max(scale.value.min, 0)));\n\n// x-position helpers -------------------------------------------------------\nconst pointX = (index: number) => {\n const count = categoryCount.value;\n if (count <= 1) return plot.value.left + plot.value.innerWidth / 2;\n return plot.value.left + (index / (count - 1)) * plot.value.innerWidth;\n};\n\nconst band = computed(() => plot.value.innerWidth / Math.max(1, categoryCount.value));\nconst bandCenter = (index: number) => plot.value.left + band.value * (index + 0.5);\n\n// active category (for line/area points and axis labels)\nconst activeX = (index: number) =>\n props.type === 'bar' ? bandCenter(index) : pointX(index);\n\n// --- line / area geometry -------------------------------------------------\nconst linePaths = computed(() =>\n props.type === 'bar'\n ? []\n : validSeries.value.map((series, seriesIndex) => {\n const points: ChartPoint[] = series.data.map((value, index) => ({\n x: pointX(index),\n y: yScale.value(value),\n }));\n return {\n color: colorFor(seriesIndex, series),\n line: buildLinePath(points, props.smooth),\n area: props.type === 'area' ? buildAreaPath(points, plot.value.bottom, props.smooth) : '',\n points,\n };\n }),\n);\n\n// --- bar geometry ---------------------------------------------------------\nconst BAR_MAX = 24;\nconst BAR_GAP = 2;\n\nconst bars = computed(() => {\n if (props.type !== 'bar') return [];\n const output: Array<{\n x: number;\n y: number;\n width: number;\n height: number;\n color: string;\n seriesIndex: number;\n index: number;\n }> = [];\n\n const bandWidth = band.value;\n const groupWidth = Math.min(bandWidth * 0.72, BAR_MAX * validSeries.value.length + BAR_GAP);\n\n for (let index = 0; index < categoryCount.value; index += 1) {\n const center = bandCenter(index);\n\n if (props.stacked) {\n const barWidth = Math.min(groupWidth, BAR_MAX);\n let cursorBottom = baselineY.value;\n validSeries.value.forEach((series, seriesIndex) => {\n const value = Math.max(0, series.data[index] ?? 0);\n // Pixel height is proportional to the segment's own value.\n const segmentHeight = baselineY.value - yScale.value(value);\n if (segmentHeight <= 0) return;\n const top = cursorBottom - segmentHeight;\n output.push({\n x: center - barWidth / 2,\n y: top,\n // Trim 2px off each segment for a surface gap between stacked marks.\n height: Math.max(0, segmentHeight - BAR_GAP),\n width: barWidth,\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n cursorBottom = top;\n });\n } else {\n const barWidth = Math.max(1, (groupWidth - BAR_GAP * (validSeries.value.length - 1)) / validSeries.value.length);\n validSeries.value.forEach((series, seriesIndex) => {\n const value = series.data[index] ?? 0;\n const top = yScale.value(value);\n const start = center - groupWidth / 2 + seriesIndex * (barWidth + BAR_GAP);\n output.push({\n x: start,\n y: Math.min(top, baselineY.value),\n width: barWidth,\n height: Math.abs(baselineY.value - top),\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n });\n }\n }\n\n return output;\n});\n\n// --- gridlines & axes -----------------------------------------------------\nconst gridLines = computed(() =>\n scale.value.ticks.map((tick) => ({\n value: tick,\n y: yScale.value(tick),\n label: formatValue(tick),\n })),\n);\n\nconst xLabels = computed(() => {\n if (!props.showXAxis) return [];\n const count = categoryCount.value;\n const maxLabels = Math.max(2, Math.floor(plot.value.innerWidth / 52));\n const step = Math.max(1, Math.ceil(count / maxLabels));\n return props.labels.slice(0, count).map((label, index) => ({\n label,\n x: activeX(index),\n show: index % step === 0 || index === count - 1,\n }));\n});\n\n// --- interaction ----------------------------------------------------------\nconst activeIndex = ref<number | null>(null);\n\nconst pointerToIndex = (clientX: number) => {\n const element = canvasRef.value;\n if (!element) return null;\n const rect = element.getBoundingClientRect();\n const x = clientX - rect.left;\n const count = categoryCount.value;\n if (count === 0) return null;\n\n if (props.type === 'bar') {\n const index = Math.floor((x - plot.value.left) / band.value);\n return Math.min(count - 1, Math.max(0, index));\n }\n\n const ratio = (x - plot.value.left) / Math.max(1, plot.value.innerWidth);\n return Math.min(count - 1, Math.max(0, Math.round(ratio * (count - 1))));\n};\n\nconst onPointerMove = (event: PointerEvent) => {\n if (!props.showTooltip || !hasData.value) return;\n activeIndex.value = pointerToIndex(event.clientX);\n};\n\nconst onPointerLeave = () => {\n activeIndex.value = null;\n};\n\nconst activePayload = computed<TChartActivePayload | null>(() => {\n const index = activeIndex.value;\n if (index === null) return null;\n return {\n index,\n label: props.labels[index] ?? `#${index + 1}`,\n values: validSeries.value.map((series, seriesIndex) => ({\n name: series.name,\n value: series.data[index] ?? 0,\n color: colorFor(seriesIndex, series),\n })),\n };\n});\n\nconst tooltipStyle = computed(() => {\n const index = activeIndex.value;\n if (index === null) return {};\n const x = activeX(index);\n const clamped = Math.min(Math.max(x, 64), width.value - 64);\n return { left: `${clamped}px`, top: `${plot.value.top}px` };\n});\n\nconst activeMarkers = computed(() => {\n const index = activeIndex.value;\n if (index === null || props.type === 'bar') return [];\n return linePaths.value.map((path) => ({\n x: path.points[index]?.x ?? 0,\n y: path.points[index]?.y ?? 0,\n color: path.color,\n }));\n});\n\nconst onClick = () => {\n if (activePayload.value) emit('point-click', activePayload.value);\n};\n\nconst resolvedLabel = computed(\n () => props.ariaLabel ?? `${props.type} chart with ${validSeries.value.length} series`,\n);\n\nconst rootClasses = computed(() => [\n 't-chart',\n `t-chart--${props.type}`,\n {\n 'is-animated': props.animated,\n 'is-loading': props.loading,\n },\n]);\n</script>\n\n<template>\n <div :class=\"rootClasses\">\n <div\n ref=\"canvasRef\"\n class=\"t-chart__canvas\"\n :style=\"{ height: `${height}px` }\"\n >\n <div\n v-if=\"loading\"\n class=\"t-chart__loading\"\n >\n <span\n v-for=\"n in 5\"\n :key=\"n\"\n class=\"t-chart__loading-bar\"\n :style=\"{ height: `${30 + ((n * 37) % 60)}%` }\"\n />\n </div>\n\n <div\n v-else-if=\"!hasData\"\n class=\"t-chart__empty\"\n >\n <slot name=\"empty\">\n No data to display\n </slot>\n </div>\n\n <template v-else>\n <svg\n class=\"t-chart__svg\"\n :width=\"width\"\n :height=\"height\"\n :viewBox=\"`0 0 ${width} ${height}`\"\n aria-hidden=\"true\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"onPointerLeave\"\n @click=\"onClick\"\n >\n <!-- gridlines + y ticks -->\n <g class=\"t-chart__grid\">\n <template\n v-for=\"line in gridLines\"\n :key=\"line.value\"\n >\n <line\n v-if=\"showGrid\"\n class=\"t-chart__gridline\"\n :x1=\"plot.left\"\n :x2=\"plot.right\"\n :y1=\"line.y\"\n :y2=\"line.y\"\n />\n <text\n v-if=\"showYAxis\"\n class=\"t-chart__axis-label t-chart__axis-label--y\"\n :x=\"plot.left - 8\"\n :y=\"line.y\"\n >\n {{ line.label }}\n </text>\n </template>\n </g>\n\n <!-- area fills -->\n <g class=\"t-chart__areas\">\n <path\n v-for=\"(path, index) in linePaths\"\n v-show=\"type === 'area'\"\n :key=\"`area-${index}`\"\n class=\"t-chart__area\"\n :d=\"path.area\"\n :style=\"{ color: path.color }\"\n />\n </g>\n\n <!-- bars -->\n <g class=\"t-chart__bars\">\n <rect\n v-for=\"(bar, index) in bars\"\n :key=\"`bar-${index}`\"\n class=\"t-chart__bar\"\n :x=\"bar.x\"\n :y=\"bar.y\"\n :width=\"bar.width\"\n :height=\"bar.height\"\n :rx=\"Math.min(4, bar.width / 2)\"\n :style=\"{ color: bar.color, animationDelay: `${bar.index * 40}ms` }\"\n :class=\"{ 'is-active': activeIndex === bar.index }\"\n />\n </g>\n\n <!-- lines + optional static points -->\n <g class=\"t-chart__lines\">\n <template\n v-for=\"(path, index) in linePaths\"\n :key=\"`line-${index}`\"\n >\n <path\n v-if=\"type !== 'bar'\"\n class=\"t-chart__line\"\n :d=\"path.line\"\n path-length=\"1\"\n :style=\"{ color: path.color }\"\n />\n <template v-if=\"showPoints && type !== 'bar'\">\n <circle\n v-for=\"(point, pointIndex) in path.points\"\n :key=\"`point-${index}-${pointIndex}`\"\n class=\"t-chart__point\"\n :cx=\"point.x\"\n :cy=\"point.y\"\n r=\"3\"\n :style=\"{ color: path.color }\"\n />\n </template>\n </template>\n </g>\n\n <!-- hover crosshair + active markers -->\n <g\n v-if=\"activeIndex !== null && showTooltip\"\n class=\"t-chart__hover\"\n >\n <line\n class=\"t-chart__crosshair\"\n :x1=\"activeX(activeIndex)\"\n :x2=\"activeX(activeIndex)\"\n :y1=\"plot.top\"\n :y2=\"plot.bottom\"\n />\n <circle\n v-for=\"(marker, index) in activeMarkers\"\n :key=\"`marker-${index}`\"\n class=\"t-chart__marker\"\n :cx=\"marker.x\"\n :cy=\"marker.y\"\n r=\"4\"\n :style=\"{ color: marker.color }\"\n />\n </g>\n\n <!-- x-axis labels -->\n <g\n v-if=\"showXAxis\"\n class=\"t-chart__x-axis\"\n >\n <text\n v-for=\"(item, index) in xLabels\"\n v-show=\"item.show\"\n :key=\"`x-${index}`\"\n class=\"t-chart__axis-label t-chart__axis-label--x\"\n :x=\"item.x\"\n :y=\"height - 8\"\n >\n {{ item.label }}\n </text>\n </g>\n </svg>\n\n <div\n v-if=\"showTooltip && activePayload\"\n class=\"t-chart__tooltip\"\n :style=\"tooltipStyle\"\n role=\"presentation\"\n >\n <slot\n name=\"tooltip\"\n v-bind=\"activePayload\"\n >\n <p class=\"t-chart__tooltip-label\">\n {{ activePayload.label }}\n </p>\n <ul class=\"t-chart__tooltip-list\">\n <li\n v-for=\"(item, index) in activePayload.values\"\n :key=\"index\"\n class=\"t-chart__tooltip-item\"\n >\n <span\n class=\"t-chart__tooltip-dot\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n <span class=\"t-chart__tooltip-name\">{{ item.name }}</span>\n <span class=\"t-chart__tooltip-value\">{{ formatValue(item.value) }}</span>\n </li>\n </ul>\n </slot>\n </div>\n </template>\n </div>\n\n <div\n v-if=\"resolvedShowLegend && hasData\"\n class=\"t-chart__legend\"\n >\n <slot\n name=\"legend\"\n :series=\"legendItems\"\n >\n <span\n v-for=\"(item, index) in legendItems\"\n :key=\"index\"\n class=\"t-chart__legend-item\"\n >\n <span\n class=\"t-chart__legend-swatch\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n {{ item.name }}\n </span>\n </slot>\n </div>\n\n <!--\n Accessible data table: the chart's data as text for assistive tech.\n The visually-hidden class goes on a wrapper, not the table: a <table>\n ignores a width below its min-content, so hiding it directly leaves a\n full-width box that pushes the page's scroll width.\n -->\n <div class=\"t-visually-hidden\">\n <table class=\"t-chart__a11y\">\n <caption>{{ resolvedLabel }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">\n Series\n </th>\n <th\n v-for=\"index in axisIndices\"\n :key=\"index\"\n scope=\"col\"\n >\n {{ labels[index] ?? '' }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, rowIndex) in validSeries\"\n :key=\"rowIndex\"\n >\n <th scope=\"row\">\n {{ row.name }}\n </th>\n <td\n v-for=\"index in axisIndices\"\n :key=\"index\"\n >\n {{ row.data[index] === undefined ? '' : formatValue(row.data[index]) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"TChart.vue.d.ts","sourceRoot":"","sources":["../../src/components/TChart.vue"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TChart.vue.d.ts","sourceRoot":"","sources":["../../src/components/TChart.vue"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- let e=require("vue"),t=require("@treeui/utils");var n={key:0,class:`t-chart__loading`},r={key:1,class:`t-chart__empty`},i=[`width`,`height`,`viewBox`],a={class:`t-chart__grid`},o=[`x1`,`x2`,`y1`,`y2`],s=[`x`,`y`],c={class:`t-chart__areas`},l=[`d`],u={class:`t-chart__bars`},d=[`x`,`y`,`width`,`height`,`rx`],f={class:`t-chart__lines`},p=[`d`],ee=[`cx`,`cy`],m={key:0,class:`t-chart__hover`},h=[`x1`,`x2`,`y1`,`y2`],g=[`cx`,`cy`],_={key:1,class:`t-chart__x-axis`},v=[`x`,`y`],y={class:`t-chart__tooltip-label`},b={class:`t-chart__tooltip-list`},x={class:`t-chart__tooltip-name`},te={class:`t-chart__tooltip-value`},ne={key:0,class:`t-chart__legend`},S={class:`t-chart__a11y t-visually-hidden`},C={scope:`row`},w=24,T=2,E=(0,e.defineComponent)({__name:`TChart`,props:{type:{default:`line`},series:{default:()=>[]},labels:{default:()=>[]},height:{default:260},smooth:{type:Boolean,default:!1},stacked:{type:Boolean,default:!1},showGrid:{type:Boolean,default:!0},showLegend:{type:Boolean,default:void 0},showXAxis:{type:Boolean,default:!0},showYAxis:{type:Boolean,default:!0},showTooltip:{type:Boolean,default:!0},showPoints:{type:Boolean,default:!1},yTicks:{default:5},valueFormat:{type:Function,default:void 0},minY:{default:void 0},maxY:{default:void 0},animated:{type:Boolean,default:!0},loading:{type:Boolean,default:!1},ariaLabel:{default:void 0}},emits:[`point-click`],setup(E,{emit:D}){let O=E,k=D,A=(0,e.ref)(null),j=(0,e.ref)(640),M=null;(0,e.onMounted)(()=>{let e=A.value;e&&(j.value=e.clientWidth||j.value,typeof ResizeObserver<`u`&&(M=new ResizeObserver(e=>{let t=e[0]?.contentRect.width;t&&(j.value=t)}),M.observe(e)))}),(0,e.onBeforeUnmount)(()=>M?.disconnect());let N=(0,e.computed)(()=>O.series.filter(e=>e.data.length>0)),P=(0,e.computed)(()=>Math.max(0,...N.value.map(e=>e.data.length))),F=(0,e.computed)(()=>Array.from({length:P.value},(e,t)=>t)),I=(0,e.computed)(()=>N.value.length>0&&P.value>0),L=(0,e.computed)(()=>O.showLegend??N.value.length>1),R=(e,t)=>t.color??`var(--tree-color-chart-${e%8+1})`,z=(0,e.computed)(()=>N.value.map((e,t)=>({name:e.name,color:R(t,e)}))),B=e=>O.valueFormat?O.valueFormat(e):Math.abs(e)>=1e3?e.toLocaleString(`en-US`):`${e}`,V=(0,e.computed)(()=>({top:12,right:12,bottom:O.showXAxis&&O.labels.length?28:10,left:O.showYAxis?44:10})),H=(0,e.computed)(()=>{let{top:e,right:t,bottom:n,left:r}=V.value;return{left:r,right:j.value-t,top:e,bottom:O.height-n,get innerWidth(){return this.right-this.left},get innerHeight(){return this.bottom-this.top}}}),U=(0,e.computed)(()=>!O.stacked||O.type!==`bar`?[]:Array.from({length:P.value},(e,t)=>N.value.reduce((e,n)=>e+Math.max(0,n.data[t]??0),0))),W=(0,e.computed)(()=>{let e=O.type===`bar`||O.type===`area`,n=N.value.flatMap(e=>e.data),r=O.stacked&&O.type===`bar`?U.value:n,i=r.length?Math.min(...r):0,a=r.length?Math.max(...r):1,o=O.minY??(e?Math.min(0,i):i);return(0,t.niceScale)(o,O.maxY??Math.max(a,o+1),O.yTicks)}),G=(0,e.computed)(()=>(0,t.linearScale)([W.value.min,W.value.max],[H.value.bottom,H.value.top])),K=(0,e.computed)(()=>G.value(Math.max(W.value.min,0))),q=e=>{let t=P.value;return t<=1?H.value.left+H.value.innerWidth/2:H.value.left+e/(t-1)*H.value.innerWidth},J=(0,e.computed)(()=>H.value.innerWidth/Math.max(1,P.value)),Y=e=>H.value.left+J.value*(e+.5),X=e=>O.type===`bar`?Y(e):q(e),Z=(0,e.computed)(()=>O.type===`bar`?[]:N.value.map((e,n)=>{let r=e.data.map((e,t)=>({x:q(t),y:G.value(e)}));return{color:R(n,e),line:(0,t.buildLinePath)(r,O.smooth),area:O.type===`area`?(0,t.buildAreaPath)(r,H.value.bottom,O.smooth):``,points:r}})),re=(0,e.computed)(()=>{if(O.type!==`bar`)return[];let e=[],t=J.value,n=Math.min(t*.72,w*N.value.length+T);for(let t=0;t<P.value;t+=1){let r=Y(t);if(O.stacked){let i=Math.min(n,w),a=K.value;N.value.forEach((n,o)=>{let s=Math.max(0,n.data[t]??0),c=K.value-G.value(s);if(c<=0)return;let l=a-c;e.push({x:r-i/2,y:l,height:Math.max(0,c-T),width:i,color:R(o,n),seriesIndex:o,index:t}),a=l})}else{let i=Math.max(1,(n-T*(N.value.length-1))/N.value.length);N.value.forEach((a,o)=>{let s=a.data[t]??0,c=G.value(s),l=r-n/2+o*(i+T);e.push({x:l,y:Math.min(c,K.value),width:i,height:Math.abs(K.value-c),color:R(o,a),seriesIndex:o,index:t})})}}return e}),ie=(0,e.computed)(()=>W.value.ticks.map(e=>({value:e,y:G.value(e),label:B(e)}))),ae=(0,e.computed)(()=>{if(!O.showXAxis)return[];let e=P.value,t=Math.max(2,Math.floor(H.value.innerWidth/52)),n=Math.max(1,Math.ceil(e/t));return O.labels.slice(0,e).map((t,r)=>({label:t,x:X(r),show:r%n===0||r===e-1}))}),Q=(0,e.ref)(null),oe=e=>{let t=A.value;if(!t)return null;let n=e-t.getBoundingClientRect().left,r=P.value;if(r===0)return null;if(O.type===`bar`){let e=Math.floor((n-H.value.left)/J.value);return Math.min(r-1,Math.max(0,e))}let i=(n-H.value.left)/Math.max(1,H.value.innerWidth);return Math.min(r-1,Math.max(0,Math.round(i*(r-1))))},se=e=>{!O.showTooltip||!I.value||(Q.value=oe(e.clientX))},ce=()=>{Q.value=null},$=(0,e.computed)(()=>{let e=Q.value;return e===null?null:{index:e,label:O.labels[e]??`#${e+1}`,values:N.value.map((t,n)=>({name:t.name,value:t.data[e]??0,color:R(n,t)}))}}),le=(0,e.computed)(()=>{let e=Q.value;if(e===null)return{};let t=X(e);return{left:`${Math.min(Math.max(t,64),j.value-64)}px`,top:`${H.value.top}px`}}),ue=(0,e.computed)(()=>{let e=Q.value;return e===null||O.type===`bar`?[]:Z.value.map(t=>({x:t.points[e]?.x??0,y:t.points[e]?.y??0,color:t.color}))}),de=()=>{$.value&&k(`point-click`,$.value)},fe=(0,e.computed)(()=>O.ariaLabel??`${O.type} chart with ${N.value.length} series`),pe=(0,e.computed)(()=>[`t-chart`,`t-chart--${O.type}`,{"is-animated":O.animated,"is-loading":O.loading}]);return(t,w)=>((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{class:(0,e.normalizeClass)(pe.value)},[(0,e.createElementVNode)(`div`,{ref_key:`canvasRef`,ref:A,class:`t-chart__canvas`,style:(0,e.normalizeStyle)({height:`${E.height}px`})},[E.loading?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,n,[((0,e.openBlock)(),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(5,t=>(0,e.createElementVNode)(`span`,{key:t,class:`t-chart__loading-bar`,style:(0,e.normalizeStyle)({height:`${30+t*37%60}%`})},null,4)),64))])):I.value?((0,e.openBlock)(),(0,e.createElementBlock)(e.Fragment,{key:2},[((0,e.openBlock)(),(0,e.createElementBlock)(`svg`,{class:`t-chart__svg`,width:j.value,height:E.height,viewBox:`0 0 ${j.value} ${E.height}`,"aria-hidden":`true`,onPointermove:se,onPointerleave:ce,onClick:de},[(0,e.createElementVNode)(`g`,a,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(ie.value,t=>((0,e.openBlock)(),(0,e.createElementBlock)(e.Fragment,{key:t.value},[E.showGrid?((0,e.openBlock)(),(0,e.createElementBlock)(`line`,{key:0,class:`t-chart__gridline`,x1:H.value.left,x2:H.value.right,y1:t.y,y2:t.y},null,8,o)):(0,e.createCommentVNode)(``,!0),E.showYAxis?((0,e.openBlock)(),(0,e.createElementBlock)(`text`,{key:1,class:`t-chart__axis-label t-chart__axis-label--y`,x:H.value.left-8,y:t.y},(0,e.toDisplayString)(t.label),9,s)):(0,e.createCommentVNode)(``,!0)],64))),128))]),(0,e.createElementVNode)(`g`,c,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(Z.value,(t,n)=>(0,e.withDirectives)(((0,e.openBlock)(),(0,e.createElementBlock)(`path`,{key:`area-${n}`,class:`t-chart__area`,d:t.area,style:(0,e.normalizeStyle)({color:t.color})},null,12,l)),[[e.vShow,E.type===`area`]])),128))]),(0,e.createElementVNode)(`g`,u,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(re.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`rect`,{key:`bar-${n}`,class:(0,e.normalizeClass)([`t-chart__bar`,{"is-active":Q.value===t.index}]),x:t.x,y:t.y,width:t.width,height:t.height,rx:Math.min(4,t.width/2),style:(0,e.normalizeStyle)({color:t.color,animationDelay:`${t.index*40}ms`})},null,14,d))),128))]),(0,e.createElementVNode)(`g`,f,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(Z.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(e.Fragment,{key:`line-${n}`},[E.type===`bar`?(0,e.createCommentVNode)(``,!0):((0,e.openBlock)(),(0,e.createElementBlock)(`path`,{key:0,class:`t-chart__line`,d:t.line,"path-length":`1`,style:(0,e.normalizeStyle)({color:t.color})},null,12,p)),E.showPoints&&E.type!==`bar`?((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,{key:1},(0,e.renderList)(t.points,(r,i)=>((0,e.openBlock)(),(0,e.createElementBlock)(`circle`,{key:`point-${n}-${i}`,class:`t-chart__point`,cx:r.x,cy:r.y,r:`3`,style:(0,e.normalizeStyle)({color:t.color})},null,12,ee))),128)):(0,e.createCommentVNode)(``,!0)],64))),128))]),Q.value!==null&&E.showTooltip?((0,e.openBlock)(),(0,e.createElementBlock)(`g`,m,[(0,e.createElementVNode)(`line`,{class:`t-chart__crosshair`,x1:X(Q.value),x2:X(Q.value),y1:H.value.top,y2:H.value.bottom},null,8,h),((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(ue.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`circle`,{key:`marker-${n}`,class:`t-chart__marker`,cx:t.x,cy:t.y,r:`4`,style:(0,e.normalizeStyle)({color:t.color})},null,12,g))),128))])):(0,e.createCommentVNode)(``,!0),E.showXAxis?((0,e.openBlock)(),(0,e.createElementBlock)(`g`,_,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(ae.value,(t,n)=>(0,e.withDirectives)(((0,e.openBlock)(),(0,e.createElementBlock)(`text`,{key:`x-${n}`,class:`t-chart__axis-label t-chart__axis-label--x`,x:t.x,y:E.height-8},(0,e.toDisplayString)(t.label),9,v)),[[e.vShow,t.show]])),128))])):(0,e.createCommentVNode)(``,!0)],40,i)),E.showTooltip&&$.value?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{key:0,class:`t-chart__tooltip`,style:(0,e.normalizeStyle)(le.value),role:`presentation`},[(0,e.renderSlot)(t.$slots,`tooltip`,(0,e.normalizeProps)((0,e.guardReactiveProps)($.value)),()=>[(0,e.createElementVNode)(`p`,y,(0,e.toDisplayString)($.value.label),1),(0,e.createElementVNode)(`ul`,b,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)($.value.values,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`li`,{key:n,class:`t-chart__tooltip-item`},[(0,e.createElementVNode)(`span`,{class:`t-chart__tooltip-dot`,style:(0,e.normalizeStyle)({background:t.color}),"aria-hidden":`true`},null,4),(0,e.createElementVNode)(`span`,x,(0,e.toDisplayString)(t.name),1),(0,e.createElementVNode)(`span`,te,(0,e.toDisplayString)(B(t.value)),1)]))),128))])])],4)):(0,e.createCommentVNode)(``,!0)],64)):((0,e.openBlock)(),(0,e.createElementBlock)(`div`,r,[(0,e.renderSlot)(t.$slots,`empty`,{},()=>[w[0]||=(0,e.createTextVNode)(` No data to display `,-1)])]))],4),L.value&&I.value?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,ne,[(0,e.renderSlot)(t.$slots,`legend`,{series:z.value},()=>[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(z.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`span`,{key:n,class:`t-chart__legend-item`},[(0,e.createElementVNode)(`span`,{class:`t-chart__legend-swatch`,style:(0,e.normalizeStyle)({background:t.color}),"aria-hidden":`true`},null,4),(0,e.createTextVNode)(` `+(0,e.toDisplayString)(t.name),1)]))),128))])])):(0,e.createCommentVNode)(``,!0),(0,e.createElementVNode)(`table`,S,[(0,e.createElementVNode)(`caption`,null,(0,e.toDisplayString)(fe.value),1),(0,e.createElementVNode)(`thead`,null,[(0,e.createElementVNode)(`tr`,null,[w[1]||=(0,e.createElementVNode)(`th`,{scope:`col`},` Series `,-1),((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(F.value,t=>((0,e.openBlock)(),(0,e.createElementBlock)(`th`,{key:t,scope:`col`},(0,e.toDisplayString)(E.labels[t]??``),1))),128))])]),(0,e.createElementVNode)(`tbody`,null,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(N.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`tr`,{key:n},[(0,e.createElementVNode)(`th`,C,(0,e.toDisplayString)(t.name),1),((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(F.value,n=>((0,e.openBlock)(),(0,e.createElementBlock)(`td`,{key:n},(0,e.toDisplayString)(t.data[n]===void 0?``:B(t.data[n])),1))),128))]))),128))])])],2))}});exports.default=E;
1
+ let e=require("vue"),t=require("@treeui/utils");var n={key:0,class:`t-chart__loading`},r={key:1,class:`t-chart__empty`},i=[`width`,`height`,`viewBox`],a={class:`t-chart__grid`},o=[`x1`,`x2`,`y1`,`y2`],s=[`x`,`y`],c={class:`t-chart__areas`},l=[`d`],u={class:`t-chart__bars`},d=[`x`,`y`,`width`,`height`,`rx`],f={class:`t-chart__lines`},p=[`d`],ee=[`cx`,`cy`],m={key:0,class:`t-chart__hover`},h=[`x1`,`x2`,`y1`,`y2`],g=[`cx`,`cy`],_={key:1,class:`t-chart__x-axis`},v=[`x`,`y`],y={class:`t-chart__tooltip-label`},b={class:`t-chart__tooltip-list`},x={class:`t-chart__tooltip-name`},te={class:`t-chart__tooltip-value`},ne={key:0,class:`t-chart__legend`},S={class:`t-visually-hidden`},C={class:`t-chart__a11y`},re={scope:`row`},w=24,T=2,E=(0,e.defineComponent)({__name:`TChart`,props:{type:{default:`line`},series:{default:()=>[]},labels:{default:()=>[]},height:{default:260},smooth:{type:Boolean,default:!1},stacked:{type:Boolean,default:!1},showGrid:{type:Boolean,default:!0},showLegend:{type:Boolean,default:void 0},showXAxis:{type:Boolean,default:!0},showYAxis:{type:Boolean,default:!0},showTooltip:{type:Boolean,default:!0},showPoints:{type:Boolean,default:!1},yTicks:{default:5},valueFormat:{type:Function,default:void 0},minY:{default:void 0},maxY:{default:void 0},animated:{type:Boolean,default:!0},loading:{type:Boolean,default:!1},ariaLabel:{default:void 0}},emits:[`point-click`],setup(E,{emit:D}){let O=E,k=D,A=(0,e.ref)(null),j=(0,e.ref)(640),M=null;(0,e.onMounted)(()=>{let e=A.value;e&&(j.value=e.clientWidth||j.value,typeof ResizeObserver<`u`&&(M=new ResizeObserver(e=>{let t=e[0]?.contentRect.width;t&&(j.value=t)}),M.observe(e)))}),(0,e.onBeforeUnmount)(()=>M?.disconnect());let N=(0,e.computed)(()=>O.series.filter(e=>e.data.length>0)),P=(0,e.computed)(()=>Math.max(0,...N.value.map(e=>e.data.length))),F=(0,e.computed)(()=>Array.from({length:P.value},(e,t)=>t)),I=(0,e.computed)(()=>N.value.length>0&&P.value>0),L=(0,e.computed)(()=>O.showLegend??N.value.length>1),R=(e,t)=>t.color??`var(--tree-color-chart-${e%8+1})`,z=(0,e.computed)(()=>N.value.map((e,t)=>({name:e.name,color:R(t,e)}))),B=e=>O.valueFormat?O.valueFormat(e):Math.abs(e)>=1e3?e.toLocaleString(`en-US`):`${e}`,V=(0,e.computed)(()=>({top:12,right:12,bottom:O.showXAxis&&O.labels.length?28:10,left:O.showYAxis?44:10})),H=(0,e.computed)(()=>{let{top:e,right:t,bottom:n,left:r}=V.value;return{left:r,right:j.value-t,top:e,bottom:O.height-n,get innerWidth(){return this.right-this.left},get innerHeight(){return this.bottom-this.top}}}),U=(0,e.computed)(()=>!O.stacked||O.type!==`bar`?[]:Array.from({length:P.value},(e,t)=>N.value.reduce((e,n)=>e+Math.max(0,n.data[t]??0),0))),W=(0,e.computed)(()=>{let e=O.type===`bar`||O.type===`area`,n=N.value.flatMap(e=>e.data),r=O.stacked&&O.type===`bar`?U.value:n,i=r.length?Math.min(...r):0,a=r.length?Math.max(...r):1,o=O.minY??(e?Math.min(0,i):i);return(0,t.niceScale)(o,O.maxY??Math.max(a,o+1),O.yTicks)}),G=(0,e.computed)(()=>(0,t.linearScale)([W.value.min,W.value.max],[H.value.bottom,H.value.top])),K=(0,e.computed)(()=>G.value(Math.max(W.value.min,0))),q=e=>{let t=P.value;return t<=1?H.value.left+H.value.innerWidth/2:H.value.left+e/(t-1)*H.value.innerWidth},J=(0,e.computed)(()=>H.value.innerWidth/Math.max(1,P.value)),Y=e=>H.value.left+J.value*(e+.5),X=e=>O.type===`bar`?Y(e):q(e),Z=(0,e.computed)(()=>O.type===`bar`?[]:N.value.map((e,n)=>{let r=e.data.map((e,t)=>({x:q(t),y:G.value(e)}));return{color:R(n,e),line:(0,t.buildLinePath)(r,O.smooth),area:O.type===`area`?(0,t.buildAreaPath)(r,H.value.bottom,O.smooth):``,points:r}})),ie=(0,e.computed)(()=>{if(O.type!==`bar`)return[];let e=[],t=J.value,n=Math.min(t*.72,w*N.value.length+T);for(let t=0;t<P.value;t+=1){let r=Y(t);if(O.stacked){let i=Math.min(n,w),a=K.value;N.value.forEach((n,o)=>{let s=Math.max(0,n.data[t]??0),c=K.value-G.value(s);if(c<=0)return;let l=a-c;e.push({x:r-i/2,y:l,height:Math.max(0,c-T),width:i,color:R(o,n),seriesIndex:o,index:t}),a=l})}else{let i=Math.max(1,(n-T*(N.value.length-1))/N.value.length);N.value.forEach((a,o)=>{let s=a.data[t]??0,c=G.value(s),l=r-n/2+o*(i+T);e.push({x:l,y:Math.min(c,K.value),width:i,height:Math.abs(K.value-c),color:R(o,a),seriesIndex:o,index:t})})}}return e}),ae=(0,e.computed)(()=>W.value.ticks.map(e=>({value:e,y:G.value(e),label:B(e)}))),oe=(0,e.computed)(()=>{if(!O.showXAxis)return[];let e=P.value,t=Math.max(2,Math.floor(H.value.innerWidth/52)),n=Math.max(1,Math.ceil(e/t));return O.labels.slice(0,e).map((t,r)=>({label:t,x:X(r),show:r%n===0||r===e-1}))}),Q=(0,e.ref)(null),se=e=>{let t=A.value;if(!t)return null;let n=e-t.getBoundingClientRect().left,r=P.value;if(r===0)return null;if(O.type===`bar`){let e=Math.floor((n-H.value.left)/J.value);return Math.min(r-1,Math.max(0,e))}let i=(n-H.value.left)/Math.max(1,H.value.innerWidth);return Math.min(r-1,Math.max(0,Math.round(i*(r-1))))},ce=e=>{!O.showTooltip||!I.value||(Q.value=se(e.clientX))},le=()=>{Q.value=null},$=(0,e.computed)(()=>{let e=Q.value;return e===null?null:{index:e,label:O.labels[e]??`#${e+1}`,values:N.value.map((t,n)=>({name:t.name,value:t.data[e]??0,color:R(n,t)}))}}),ue=(0,e.computed)(()=>{let e=Q.value;if(e===null)return{};let t=X(e);return{left:`${Math.min(Math.max(t,64),j.value-64)}px`,top:`${H.value.top}px`}}),de=(0,e.computed)(()=>{let e=Q.value;return e===null||O.type===`bar`?[]:Z.value.map(t=>({x:t.points[e]?.x??0,y:t.points[e]?.y??0,color:t.color}))}),fe=()=>{$.value&&k(`point-click`,$.value)},pe=(0,e.computed)(()=>O.ariaLabel??`${O.type} chart with ${N.value.length} series`),me=(0,e.computed)(()=>[`t-chart`,`t-chart--${O.type}`,{"is-animated":O.animated,"is-loading":O.loading}]);return(t,w)=>((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{class:(0,e.normalizeClass)(me.value)},[(0,e.createElementVNode)(`div`,{ref_key:`canvasRef`,ref:A,class:`t-chart__canvas`,style:(0,e.normalizeStyle)({height:`${E.height}px`})},[E.loading?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,n,[((0,e.openBlock)(),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(5,t=>(0,e.createElementVNode)(`span`,{key:t,class:`t-chart__loading-bar`,style:(0,e.normalizeStyle)({height:`${30+t*37%60}%`})},null,4)),64))])):I.value?((0,e.openBlock)(),(0,e.createElementBlock)(e.Fragment,{key:2},[((0,e.openBlock)(),(0,e.createElementBlock)(`svg`,{class:`t-chart__svg`,width:j.value,height:E.height,viewBox:`0 0 ${j.value} ${E.height}`,"aria-hidden":`true`,onPointermove:ce,onPointerleave:le,onClick:fe},[(0,e.createElementVNode)(`g`,a,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(ae.value,t=>((0,e.openBlock)(),(0,e.createElementBlock)(e.Fragment,{key:t.value},[E.showGrid?((0,e.openBlock)(),(0,e.createElementBlock)(`line`,{key:0,class:`t-chart__gridline`,x1:H.value.left,x2:H.value.right,y1:t.y,y2:t.y},null,8,o)):(0,e.createCommentVNode)(``,!0),E.showYAxis?((0,e.openBlock)(),(0,e.createElementBlock)(`text`,{key:1,class:`t-chart__axis-label t-chart__axis-label--y`,x:H.value.left-8,y:t.y},(0,e.toDisplayString)(t.label),9,s)):(0,e.createCommentVNode)(``,!0)],64))),128))]),(0,e.createElementVNode)(`g`,c,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(Z.value,(t,n)=>(0,e.withDirectives)(((0,e.openBlock)(),(0,e.createElementBlock)(`path`,{key:`area-${n}`,class:`t-chart__area`,d:t.area,style:(0,e.normalizeStyle)({color:t.color})},null,12,l)),[[e.vShow,E.type===`area`]])),128))]),(0,e.createElementVNode)(`g`,u,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(ie.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`rect`,{key:`bar-${n}`,class:(0,e.normalizeClass)([`t-chart__bar`,{"is-active":Q.value===t.index}]),x:t.x,y:t.y,width:t.width,height:t.height,rx:Math.min(4,t.width/2),style:(0,e.normalizeStyle)({color:t.color,animationDelay:`${t.index*40}ms`})},null,14,d))),128))]),(0,e.createElementVNode)(`g`,f,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(Z.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(e.Fragment,{key:`line-${n}`},[E.type===`bar`?(0,e.createCommentVNode)(``,!0):((0,e.openBlock)(),(0,e.createElementBlock)(`path`,{key:0,class:`t-chart__line`,d:t.line,"path-length":`1`,style:(0,e.normalizeStyle)({color:t.color})},null,12,p)),E.showPoints&&E.type!==`bar`?((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,{key:1},(0,e.renderList)(t.points,(r,i)=>((0,e.openBlock)(),(0,e.createElementBlock)(`circle`,{key:`point-${n}-${i}`,class:`t-chart__point`,cx:r.x,cy:r.y,r:`3`,style:(0,e.normalizeStyle)({color:t.color})},null,12,ee))),128)):(0,e.createCommentVNode)(``,!0)],64))),128))]),Q.value!==null&&E.showTooltip?((0,e.openBlock)(),(0,e.createElementBlock)(`g`,m,[(0,e.createElementVNode)(`line`,{class:`t-chart__crosshair`,x1:X(Q.value),x2:X(Q.value),y1:H.value.top,y2:H.value.bottom},null,8,h),((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(de.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`circle`,{key:`marker-${n}`,class:`t-chart__marker`,cx:t.x,cy:t.y,r:`4`,style:(0,e.normalizeStyle)({color:t.color})},null,12,g))),128))])):(0,e.createCommentVNode)(``,!0),E.showXAxis?((0,e.openBlock)(),(0,e.createElementBlock)(`g`,_,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(oe.value,(t,n)=>(0,e.withDirectives)(((0,e.openBlock)(),(0,e.createElementBlock)(`text`,{key:`x-${n}`,class:`t-chart__axis-label t-chart__axis-label--x`,x:t.x,y:E.height-8},(0,e.toDisplayString)(t.label),9,v)),[[e.vShow,t.show]])),128))])):(0,e.createCommentVNode)(``,!0)],40,i)),E.showTooltip&&$.value?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{key:0,class:`t-chart__tooltip`,style:(0,e.normalizeStyle)(ue.value),role:`presentation`},[(0,e.renderSlot)(t.$slots,`tooltip`,(0,e.normalizeProps)((0,e.guardReactiveProps)($.value)),()=>[(0,e.createElementVNode)(`p`,y,(0,e.toDisplayString)($.value.label),1),(0,e.createElementVNode)(`ul`,b,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)($.value.values,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`li`,{key:n,class:`t-chart__tooltip-item`},[(0,e.createElementVNode)(`span`,{class:`t-chart__tooltip-dot`,style:(0,e.normalizeStyle)({background:t.color}),"aria-hidden":`true`},null,4),(0,e.createElementVNode)(`span`,x,(0,e.toDisplayString)(t.name),1),(0,e.createElementVNode)(`span`,te,(0,e.toDisplayString)(B(t.value)),1)]))),128))])])],4)):(0,e.createCommentVNode)(``,!0)],64)):((0,e.openBlock)(),(0,e.createElementBlock)(`div`,r,[(0,e.renderSlot)(t.$slots,`empty`,{},()=>[w[0]||=(0,e.createTextVNode)(` No data to display `,-1)])]))],4),L.value&&I.value?((0,e.openBlock)(),(0,e.createElementBlock)(`div`,ne,[(0,e.renderSlot)(t.$slots,`legend`,{series:z.value},()=>[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(z.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`span`,{key:n,class:`t-chart__legend-item`},[(0,e.createElementVNode)(`span`,{class:`t-chart__legend-swatch`,style:(0,e.normalizeStyle)({background:t.color}),"aria-hidden":`true`},null,4),(0,e.createTextVNode)(` `+(0,e.toDisplayString)(t.name),1)]))),128))])])):(0,e.createCommentVNode)(``,!0),(0,e.createElementVNode)(`div`,S,[(0,e.createElementVNode)(`table`,C,[(0,e.createElementVNode)(`caption`,null,(0,e.toDisplayString)(pe.value),1),(0,e.createElementVNode)(`thead`,null,[(0,e.createElementVNode)(`tr`,null,[w[1]||=(0,e.createElementVNode)(`th`,{scope:`col`},` Series `,-1),((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(F.value,t=>((0,e.openBlock)(),(0,e.createElementBlock)(`th`,{key:t,scope:`col`},(0,e.toDisplayString)(E.labels[t]??``),1))),128))])]),(0,e.createElementVNode)(`tbody`,null,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(N.value,(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`tr`,{key:n},[(0,e.createElementVNode)(`th`,re,(0,e.toDisplayString)(t.name),1),((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(F.value,n=>((0,e.openBlock)(),(0,e.createElementBlock)(`td`,{key:n},(0,e.toDisplayString)(t.data[n]===void 0?``:B(t.data[n])),1))),128))]))),128))])])])],2))}});exports.default=E;
2
2
  //# sourceMappingURL=TChart.vue_vue_type_script_setup_true_lang.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TChart.vue_vue_type_script_setup_true_lang.cjs","names":[],"sources":["../../src/components/TChart.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue';\nimport {\n buildAreaPath,\n buildLinePath,\n linearScale,\n niceScale,\n type ChartPoint,\n} from '@treeui/utils';\n\nexport type TChartType = 'line' | 'area' | 'bar';\n\nexport interface TChartSeries {\n /** Legend/tooltip name for the series. */\n name: string;\n /** One value per category, aligned to `labels`. */\n data: number[];\n /** Override the series color; defaults to a chart palette token. */\n color?: string;\n}\n\nexport interface TChartActivePayload {\n index: number;\n label: string;\n values: Array<{ name: string; value: number; color: string }>;\n}\n\nconst props = withDefaults(\n defineProps<{\n /** Visual form of the plot. */\n type?: TChartType;\n /** One or more data series. */\n series?: TChartSeries[];\n /** Category labels for the x-axis, aligned to each series' data. */\n labels?: string[];\n /** Plot height in px (width is fluid). */\n height?: number;\n /** Smooth (curved) line/area. */\n smooth?: boolean;\n /**\n * Stack bar series on top of each other instead of grouping side by side.\n * Negative values are clamped to 0 in stacked mode (grouped mode renders them).\n */\n stacked?: boolean;\n /** Draw horizontal gridlines. */\n showGrid?: boolean;\n /** Show the legend. Defaults to on when there is more than one series. */\n showLegend?: boolean;\n /** Show x-axis category labels. */\n showXAxis?: boolean;\n /** Show y-axis value ticks. */\n showYAxis?: boolean;\n /** Show the hover crosshair + tooltip. */\n showTooltip?: boolean;\n /** Always render markers on line/area points (not just on hover). */\n showPoints?: boolean;\n /** Target number of y-axis ticks. */\n yTicks?: number;\n /** Format axis + tooltip values. */\n valueFormat?: (value: number) => string;\n /** Force the low end of the y domain. */\n minY?: number;\n /** Force the high end of the y domain. */\n maxY?: number;\n /** Animate marks on first render (respects prefers-reduced-motion). */\n animated?: boolean;\n /** Render skeleton placeholders instead of the plot. */\n loading?: boolean;\n /** Accessible summary of the chart. */\n ariaLabel?: string;\n }>(),\n {\n type: 'line',\n series: () => [],\n labels: () => [],\n height: 260,\n smooth: false,\n stacked: false,\n showGrid: true,\n showLegend: undefined,\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showPoints: false,\n yTicks: 5,\n valueFormat: undefined,\n minY: undefined,\n maxY: undefined,\n animated: true,\n loading: false,\n ariaLabel: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'point-click': [payload: TChartActivePayload];\n}>();\n\ndefineSlots<{\n legend?: (props: { series: Array<{ name: string; color: string }> }) => unknown;\n tooltip?: (props: TChartActivePayload) => unknown;\n empty?: () => unknown;\n}>();\n\n// --- measurement ----------------------------------------------------------\nconst canvasRef = ref<HTMLElement | null>(null);\nconst width = ref(640);\nlet observer: ResizeObserver | null = null;\n\nonMounted(() => {\n const element = canvasRef.value;\n if (!element) return;\n width.value = element.clientWidth || width.value;\n\n if (typeof ResizeObserver !== 'undefined') {\n observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured) width.value = measured;\n });\n observer.observe(element);\n }\n});\n\nonBeforeUnmount(() => observer?.disconnect());\n\n// --- derived data ---------------------------------------------------------\nconst validSeries = computed(() => props.series.filter((item) => item.data.length > 0));\n\nconst categoryCount = computed(() =>\n Math.max(0, ...validSeries.value.map((item) => item.data.length)),\n);\n\n// Shared category index range, so the a11y table stays rectangular even when\n// series have different lengths.\nconst axisIndices = computed(() =>\n Array.from({ length: categoryCount.value }, (_, index) => index),\n);\n\nconst hasData = computed(() => validSeries.value.length > 0 && categoryCount.value > 0);\n\nconst resolvedShowLegend = computed(() =>\n props.showLegend ?? validSeries.value.length > 1,\n);\n\nconst colorFor = (index: number, series: TChartSeries) =>\n series.color ?? `var(--tree-color-chart-${(index % 8) + 1})`;\n\nconst legendItems = computed(() =>\n validSeries.value.map((series, index) => ({\n name: series.name,\n color: colorFor(index, series),\n })),\n);\n\nconst formatValue = (value: number) => {\n if (props.valueFormat) return props.valueFormat(value);\n if (Math.abs(value) >= 1000) return value.toLocaleString('en-US');\n return `${value}`;\n};\n\n// --- layout ---------------------------------------------------------------\nconst margin = computed(() => ({\n top: 12,\n right: 12,\n bottom: props.showXAxis && props.labels.length ? 28 : 10,\n left: props.showYAxis ? 44 : 10,\n}));\n\nconst plot = computed(() => {\n const { top, right, bottom, left } = margin.value;\n return {\n left,\n right: width.value - right,\n top,\n bottom: props.height - bottom,\n get innerWidth() {\n return this.right - this.left;\n },\n get innerHeight() {\n return this.bottom - this.top;\n },\n };\n});\n\nconst stackedTotals = computed(() => {\n if (!props.stacked || props.type !== 'bar') return [];\n return Array.from({ length: categoryCount.value }, (_, index) =>\n validSeries.value.reduce((sum, series) => sum + Math.max(0, series.data[index] ?? 0), 0),\n );\n});\n\nconst scale = computed(() => {\n const baselineZero = props.type === 'bar' || props.type === 'area';\n const flat = validSeries.value.flatMap((series) => series.data);\n\n const source = props.stacked && props.type === 'bar' ? stackedTotals.value : flat;\n const rawMin = source.length ? Math.min(...source) : 0;\n const rawMax = source.length ? Math.max(...source) : 1;\n\n const min = props.minY ?? (baselineZero ? Math.min(0, rawMin) : rawMin);\n const max = props.maxY ?? Math.max(rawMax, min + 1);\n\n return niceScale(min, max, props.yTicks);\n});\n\nconst yScale = computed(() =>\n linearScale([scale.value.min, scale.value.max], [plot.value.bottom, plot.value.top]),\n);\n\nconst baselineY = computed(() => yScale.value(Math.max(scale.value.min, 0)));\n\n// x-position helpers -------------------------------------------------------\nconst pointX = (index: number) => {\n const count = categoryCount.value;\n if (count <= 1) return plot.value.left + plot.value.innerWidth / 2;\n return plot.value.left + (index / (count - 1)) * plot.value.innerWidth;\n};\n\nconst band = computed(() => plot.value.innerWidth / Math.max(1, categoryCount.value));\nconst bandCenter = (index: number) => plot.value.left + band.value * (index + 0.5);\n\n// active category (for line/area points and axis labels)\nconst activeX = (index: number) =>\n props.type === 'bar' ? bandCenter(index) : pointX(index);\n\n// --- line / area geometry -------------------------------------------------\nconst linePaths = computed(() =>\n props.type === 'bar'\n ? []\n : validSeries.value.map((series, seriesIndex) => {\n const points: ChartPoint[] = series.data.map((value, index) => ({\n x: pointX(index),\n y: yScale.value(value),\n }));\n return {\n color: colorFor(seriesIndex, series),\n line: buildLinePath(points, props.smooth),\n area: props.type === 'area' ? buildAreaPath(points, plot.value.bottom, props.smooth) : '',\n points,\n };\n }),\n);\n\n// --- bar geometry ---------------------------------------------------------\nconst BAR_MAX = 24;\nconst BAR_GAP = 2;\n\nconst bars = computed(() => {\n if (props.type !== 'bar') return [];\n const output: Array<{\n x: number;\n y: number;\n width: number;\n height: number;\n color: string;\n seriesIndex: number;\n index: number;\n }> = [];\n\n const bandWidth = band.value;\n const groupWidth = Math.min(bandWidth * 0.72, BAR_MAX * validSeries.value.length + BAR_GAP);\n\n for (let index = 0; index < categoryCount.value; index += 1) {\n const center = bandCenter(index);\n\n if (props.stacked) {\n const barWidth = Math.min(groupWidth, BAR_MAX);\n let cursorBottom = baselineY.value;\n validSeries.value.forEach((series, seriesIndex) => {\n const value = Math.max(0, series.data[index] ?? 0);\n // Pixel height is proportional to the segment's own value.\n const segmentHeight = baselineY.value - yScale.value(value);\n if (segmentHeight <= 0) return;\n const top = cursorBottom - segmentHeight;\n output.push({\n x: center - barWidth / 2,\n y: top,\n // Trim 2px off each segment for a surface gap between stacked marks.\n height: Math.max(0, segmentHeight - BAR_GAP),\n width: barWidth,\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n cursorBottom = top;\n });\n } else {\n const barWidth = Math.max(1, (groupWidth - BAR_GAP * (validSeries.value.length - 1)) / validSeries.value.length);\n validSeries.value.forEach((series, seriesIndex) => {\n const value = series.data[index] ?? 0;\n const top = yScale.value(value);\n const start = center - groupWidth / 2 + seriesIndex * (barWidth + BAR_GAP);\n output.push({\n x: start,\n y: Math.min(top, baselineY.value),\n width: barWidth,\n height: Math.abs(baselineY.value - top),\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n });\n }\n }\n\n return output;\n});\n\n// --- gridlines & axes -----------------------------------------------------\nconst gridLines = computed(() =>\n scale.value.ticks.map((tick) => ({\n value: tick,\n y: yScale.value(tick),\n label: formatValue(tick),\n })),\n);\n\nconst xLabels = computed(() => {\n if (!props.showXAxis) return [];\n const count = categoryCount.value;\n const maxLabels = Math.max(2, Math.floor(plot.value.innerWidth / 52));\n const step = Math.max(1, Math.ceil(count / maxLabels));\n return props.labels.slice(0, count).map((label, index) => ({\n label,\n x: activeX(index),\n show: index % step === 0 || index === count - 1,\n }));\n});\n\n// --- interaction ----------------------------------------------------------\nconst activeIndex = ref<number | null>(null);\n\nconst pointerToIndex = (clientX: number) => {\n const element = canvasRef.value;\n if (!element) return null;\n const rect = element.getBoundingClientRect();\n const x = clientX - rect.left;\n const count = categoryCount.value;\n if (count === 0) return null;\n\n if (props.type === 'bar') {\n const index = Math.floor((x - plot.value.left) / band.value);\n return Math.min(count - 1, Math.max(0, index));\n }\n\n const ratio = (x - plot.value.left) / Math.max(1, plot.value.innerWidth);\n return Math.min(count - 1, Math.max(0, Math.round(ratio * (count - 1))));\n};\n\nconst onPointerMove = (event: PointerEvent) => {\n if (!props.showTooltip || !hasData.value) return;\n activeIndex.value = pointerToIndex(event.clientX);\n};\n\nconst onPointerLeave = () => {\n activeIndex.value = null;\n};\n\nconst activePayload = computed<TChartActivePayload | null>(() => {\n const index = activeIndex.value;\n if (index === null) return null;\n return {\n index,\n label: props.labels[index] ?? `#${index + 1}`,\n values: validSeries.value.map((series, seriesIndex) => ({\n name: series.name,\n value: series.data[index] ?? 0,\n color: colorFor(seriesIndex, series),\n })),\n };\n});\n\nconst tooltipStyle = computed(() => {\n const index = activeIndex.value;\n if (index === null) return {};\n const x = activeX(index);\n const clamped = Math.min(Math.max(x, 64), width.value - 64);\n return { left: `${clamped}px`, top: `${plot.value.top}px` };\n});\n\nconst activeMarkers = computed(() => {\n const index = activeIndex.value;\n if (index === null || props.type === 'bar') return [];\n return linePaths.value.map((path) => ({\n x: path.points[index]?.x ?? 0,\n y: path.points[index]?.y ?? 0,\n color: path.color,\n }));\n});\n\nconst onClick = () => {\n if (activePayload.value) emit('point-click', activePayload.value);\n};\n\nconst resolvedLabel = computed(\n () => props.ariaLabel ?? `${props.type} chart with ${validSeries.value.length} series`,\n);\n\nconst rootClasses = computed(() => [\n 't-chart',\n `t-chart--${props.type}`,\n {\n 'is-animated': props.animated,\n 'is-loading': props.loading,\n },\n]);\n</script>\n\n<template>\n <div :class=\"rootClasses\">\n <div\n ref=\"canvasRef\"\n class=\"t-chart__canvas\"\n :style=\"{ height: `${height}px` }\"\n >\n <div\n v-if=\"loading\"\n class=\"t-chart__loading\"\n >\n <span\n v-for=\"n in 5\"\n :key=\"n\"\n class=\"t-chart__loading-bar\"\n :style=\"{ height: `${30 + ((n * 37) % 60)}%` }\"\n />\n </div>\n\n <div\n v-else-if=\"!hasData\"\n class=\"t-chart__empty\"\n >\n <slot name=\"empty\">\n No data to display\n </slot>\n </div>\n\n <template v-else>\n <svg\n class=\"t-chart__svg\"\n :width=\"width\"\n :height=\"height\"\n :viewBox=\"`0 0 ${width} ${height}`\"\n aria-hidden=\"true\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"onPointerLeave\"\n @click=\"onClick\"\n >\n <!-- gridlines + y ticks -->\n <g class=\"t-chart__grid\">\n <template\n v-for=\"line in gridLines\"\n :key=\"line.value\"\n >\n <line\n v-if=\"showGrid\"\n class=\"t-chart__gridline\"\n :x1=\"plot.left\"\n :x2=\"plot.right\"\n :y1=\"line.y\"\n :y2=\"line.y\"\n />\n <text\n v-if=\"showYAxis\"\n class=\"t-chart__axis-label t-chart__axis-label--y\"\n :x=\"plot.left - 8\"\n :y=\"line.y\"\n >\n {{ line.label }}\n </text>\n </template>\n </g>\n\n <!-- area fills -->\n <g class=\"t-chart__areas\">\n <path\n v-for=\"(path, index) in linePaths\"\n v-show=\"type === 'area'\"\n :key=\"`area-${index}`\"\n class=\"t-chart__area\"\n :d=\"path.area\"\n :style=\"{ color: path.color }\"\n />\n </g>\n\n <!-- bars -->\n <g class=\"t-chart__bars\">\n <rect\n v-for=\"(bar, index) in bars\"\n :key=\"`bar-${index}`\"\n class=\"t-chart__bar\"\n :x=\"bar.x\"\n :y=\"bar.y\"\n :width=\"bar.width\"\n :height=\"bar.height\"\n :rx=\"Math.min(4, bar.width / 2)\"\n :style=\"{ color: bar.color, animationDelay: `${bar.index * 40}ms` }\"\n :class=\"{ 'is-active': activeIndex === bar.index }\"\n />\n </g>\n\n <!-- lines + optional static points -->\n <g class=\"t-chart__lines\">\n <template\n v-for=\"(path, index) in linePaths\"\n :key=\"`line-${index}`\"\n >\n <path\n v-if=\"type !== 'bar'\"\n class=\"t-chart__line\"\n :d=\"path.line\"\n path-length=\"1\"\n :style=\"{ color: path.color }\"\n />\n <template v-if=\"showPoints && type !== 'bar'\">\n <circle\n v-for=\"(point, pointIndex) in path.points\"\n :key=\"`point-${index}-${pointIndex}`\"\n class=\"t-chart__point\"\n :cx=\"point.x\"\n :cy=\"point.y\"\n r=\"3\"\n :style=\"{ color: path.color }\"\n />\n </template>\n </template>\n </g>\n\n <!-- hover crosshair + active markers -->\n <g\n v-if=\"activeIndex !== null && showTooltip\"\n class=\"t-chart__hover\"\n >\n <line\n class=\"t-chart__crosshair\"\n :x1=\"activeX(activeIndex)\"\n :x2=\"activeX(activeIndex)\"\n :y1=\"plot.top\"\n :y2=\"plot.bottom\"\n />\n <circle\n v-for=\"(marker, index) in activeMarkers\"\n :key=\"`marker-${index}`\"\n class=\"t-chart__marker\"\n :cx=\"marker.x\"\n :cy=\"marker.y\"\n r=\"4\"\n :style=\"{ color: marker.color }\"\n />\n </g>\n\n <!-- x-axis labels -->\n <g\n v-if=\"showXAxis\"\n class=\"t-chart__x-axis\"\n >\n <text\n v-for=\"(item, index) in xLabels\"\n v-show=\"item.show\"\n :key=\"`x-${index}`\"\n class=\"t-chart__axis-label t-chart__axis-label--x\"\n :x=\"item.x\"\n :y=\"height - 8\"\n >\n {{ item.label }}\n </text>\n </g>\n </svg>\n\n <div\n v-if=\"showTooltip && activePayload\"\n class=\"t-chart__tooltip\"\n :style=\"tooltipStyle\"\n role=\"presentation\"\n >\n <slot\n name=\"tooltip\"\n v-bind=\"activePayload\"\n >\n <p class=\"t-chart__tooltip-label\">\n {{ activePayload.label }}\n </p>\n <ul class=\"t-chart__tooltip-list\">\n <li\n v-for=\"(item, index) in activePayload.values\"\n :key=\"index\"\n class=\"t-chart__tooltip-item\"\n >\n <span\n class=\"t-chart__tooltip-dot\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n <span class=\"t-chart__tooltip-name\">{{ item.name }}</span>\n <span class=\"t-chart__tooltip-value\">{{ formatValue(item.value) }}</span>\n </li>\n </ul>\n </slot>\n </div>\n </template>\n </div>\n\n <div\n v-if=\"resolvedShowLegend && hasData\"\n class=\"t-chart__legend\"\n >\n <slot\n name=\"legend\"\n :series=\"legendItems\"\n >\n <span\n v-for=\"(item, index) in legendItems\"\n :key=\"index\"\n class=\"t-chart__legend-item\"\n >\n <span\n class=\"t-chart__legend-swatch\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n {{ item.name }}\n </span>\n </slot>\n </div>\n\n <!-- Accessible data table: the chart's data as text for assistive tech. -->\n <table class=\"t-chart__a11y t-visually-hidden\">\n <caption>{{ resolvedLabel }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">\n Series\n </th>\n <th\n v-for=\"index in axisIndices\"\n :key=\"index\"\n scope=\"col\"\n >\n {{ labels[index] ?? '' }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, rowIndex) in validSeries\"\n :key=\"rowIndex\"\n >\n <th scope=\"row\">\n {{ row.name }}\n </th>\n <td\n v-for=\"index in axisIndices\"\n :key=\"index\"\n >\n {{ row.data[index] === undefined ? '' : formatValue(row.data[index]) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"TChart.vue_vue_type_script_setup_true_lang.cjs","names":[],"sources":["../../src/components/TChart.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue';\nimport {\n buildAreaPath,\n buildLinePath,\n linearScale,\n niceScale,\n type ChartPoint,\n} from '@treeui/utils';\n\nexport type TChartType = 'line' | 'area' | 'bar';\n\nexport interface TChartSeries {\n /** Legend/tooltip name for the series. */\n name: string;\n /** One value per category, aligned to `labels`. */\n data: number[];\n /** Override the series color; defaults to a chart palette token. */\n color?: string;\n}\n\nexport interface TChartActivePayload {\n index: number;\n label: string;\n values: Array<{ name: string; value: number; color: string }>;\n}\n\nconst props = withDefaults(\n defineProps<{\n /** Visual form of the plot. */\n type?: TChartType;\n /** One or more data series. */\n series?: TChartSeries[];\n /** Category labels for the x-axis, aligned to each series' data. */\n labels?: string[];\n /** Plot height in px (width is fluid). */\n height?: number;\n /** Smooth (curved) line/area. */\n smooth?: boolean;\n /**\n * Stack bar series on top of each other instead of grouping side by side.\n * Negative values are clamped to 0 in stacked mode (grouped mode renders them).\n */\n stacked?: boolean;\n /** Draw horizontal gridlines. */\n showGrid?: boolean;\n /** Show the legend. Defaults to on when there is more than one series. */\n showLegend?: boolean;\n /** Show x-axis category labels. */\n showXAxis?: boolean;\n /** Show y-axis value ticks. */\n showYAxis?: boolean;\n /** Show the hover crosshair + tooltip. */\n showTooltip?: boolean;\n /** Always render markers on line/area points (not just on hover). */\n showPoints?: boolean;\n /** Target number of y-axis ticks. */\n yTicks?: number;\n /** Format axis + tooltip values. */\n valueFormat?: (value: number) => string;\n /** Force the low end of the y domain. */\n minY?: number;\n /** Force the high end of the y domain. */\n maxY?: number;\n /** Animate marks on first render (respects prefers-reduced-motion). */\n animated?: boolean;\n /** Render skeleton placeholders instead of the plot. */\n loading?: boolean;\n /** Accessible summary of the chart. */\n ariaLabel?: string;\n }>(),\n {\n type: 'line',\n series: () => [],\n labels: () => [],\n height: 260,\n smooth: false,\n stacked: false,\n showGrid: true,\n showLegend: undefined,\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showPoints: false,\n yTicks: 5,\n valueFormat: undefined,\n minY: undefined,\n maxY: undefined,\n animated: true,\n loading: false,\n ariaLabel: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'point-click': [payload: TChartActivePayload];\n}>();\n\ndefineSlots<{\n legend?: (props: { series: Array<{ name: string; color: string }> }) => unknown;\n tooltip?: (props: TChartActivePayload) => unknown;\n empty?: () => unknown;\n}>();\n\n// --- measurement ----------------------------------------------------------\nconst canvasRef = ref<HTMLElement | null>(null);\nconst width = ref(640);\nlet observer: ResizeObserver | null = null;\n\nonMounted(() => {\n const element = canvasRef.value;\n if (!element) return;\n width.value = element.clientWidth || width.value;\n\n if (typeof ResizeObserver !== 'undefined') {\n observer = new ResizeObserver((entries) => {\n const measured = entries[0]?.contentRect.width;\n if (measured) width.value = measured;\n });\n observer.observe(element);\n }\n});\n\nonBeforeUnmount(() => observer?.disconnect());\n\n// --- derived data ---------------------------------------------------------\nconst validSeries = computed(() => props.series.filter((item) => item.data.length > 0));\n\nconst categoryCount = computed(() =>\n Math.max(0, ...validSeries.value.map((item) => item.data.length)),\n);\n\n// Shared category index range, so the a11y table stays rectangular even when\n// series have different lengths.\nconst axisIndices = computed(() =>\n Array.from({ length: categoryCount.value }, (_, index) => index),\n);\n\nconst hasData = computed(() => validSeries.value.length > 0 && categoryCount.value > 0);\n\nconst resolvedShowLegend = computed(() =>\n props.showLegend ?? validSeries.value.length > 1,\n);\n\nconst colorFor = (index: number, series: TChartSeries) =>\n series.color ?? `var(--tree-color-chart-${(index % 8) + 1})`;\n\nconst legendItems = computed(() =>\n validSeries.value.map((series, index) => ({\n name: series.name,\n color: colorFor(index, series),\n })),\n);\n\nconst formatValue = (value: number) => {\n if (props.valueFormat) return props.valueFormat(value);\n if (Math.abs(value) >= 1000) return value.toLocaleString('en-US');\n return `${value}`;\n};\n\n// --- layout ---------------------------------------------------------------\nconst margin = computed(() => ({\n top: 12,\n right: 12,\n bottom: props.showXAxis && props.labels.length ? 28 : 10,\n left: props.showYAxis ? 44 : 10,\n}));\n\nconst plot = computed(() => {\n const { top, right, bottom, left } = margin.value;\n return {\n left,\n right: width.value - right,\n top,\n bottom: props.height - bottom,\n get innerWidth() {\n return this.right - this.left;\n },\n get innerHeight() {\n return this.bottom - this.top;\n },\n };\n});\n\nconst stackedTotals = computed(() => {\n if (!props.stacked || props.type !== 'bar') return [];\n return Array.from({ length: categoryCount.value }, (_, index) =>\n validSeries.value.reduce((sum, series) => sum + Math.max(0, series.data[index] ?? 0), 0),\n );\n});\n\nconst scale = computed(() => {\n const baselineZero = props.type === 'bar' || props.type === 'area';\n const flat = validSeries.value.flatMap((series) => series.data);\n\n const source = props.stacked && props.type === 'bar' ? stackedTotals.value : flat;\n const rawMin = source.length ? Math.min(...source) : 0;\n const rawMax = source.length ? Math.max(...source) : 1;\n\n const min = props.minY ?? (baselineZero ? Math.min(0, rawMin) : rawMin);\n const max = props.maxY ?? Math.max(rawMax, min + 1);\n\n return niceScale(min, max, props.yTicks);\n});\n\nconst yScale = computed(() =>\n linearScale([scale.value.min, scale.value.max], [plot.value.bottom, plot.value.top]),\n);\n\nconst baselineY = computed(() => yScale.value(Math.max(scale.value.min, 0)));\n\n// x-position helpers -------------------------------------------------------\nconst pointX = (index: number) => {\n const count = categoryCount.value;\n if (count <= 1) return plot.value.left + plot.value.innerWidth / 2;\n return plot.value.left + (index / (count - 1)) * plot.value.innerWidth;\n};\n\nconst band = computed(() => plot.value.innerWidth / Math.max(1, categoryCount.value));\nconst bandCenter = (index: number) => plot.value.left + band.value * (index + 0.5);\n\n// active category (for line/area points and axis labels)\nconst activeX = (index: number) =>\n props.type === 'bar' ? bandCenter(index) : pointX(index);\n\n// --- line / area geometry -------------------------------------------------\nconst linePaths = computed(() =>\n props.type === 'bar'\n ? []\n : validSeries.value.map((series, seriesIndex) => {\n const points: ChartPoint[] = series.data.map((value, index) => ({\n x: pointX(index),\n y: yScale.value(value),\n }));\n return {\n color: colorFor(seriesIndex, series),\n line: buildLinePath(points, props.smooth),\n area: props.type === 'area' ? buildAreaPath(points, plot.value.bottom, props.smooth) : '',\n points,\n };\n }),\n);\n\n// --- bar geometry ---------------------------------------------------------\nconst BAR_MAX = 24;\nconst BAR_GAP = 2;\n\nconst bars = computed(() => {\n if (props.type !== 'bar') return [];\n const output: Array<{\n x: number;\n y: number;\n width: number;\n height: number;\n color: string;\n seriesIndex: number;\n index: number;\n }> = [];\n\n const bandWidth = band.value;\n const groupWidth = Math.min(bandWidth * 0.72, BAR_MAX * validSeries.value.length + BAR_GAP);\n\n for (let index = 0; index < categoryCount.value; index += 1) {\n const center = bandCenter(index);\n\n if (props.stacked) {\n const barWidth = Math.min(groupWidth, BAR_MAX);\n let cursorBottom = baselineY.value;\n validSeries.value.forEach((series, seriesIndex) => {\n const value = Math.max(0, series.data[index] ?? 0);\n // Pixel height is proportional to the segment's own value.\n const segmentHeight = baselineY.value - yScale.value(value);\n if (segmentHeight <= 0) return;\n const top = cursorBottom - segmentHeight;\n output.push({\n x: center - barWidth / 2,\n y: top,\n // Trim 2px off each segment for a surface gap between stacked marks.\n height: Math.max(0, segmentHeight - BAR_GAP),\n width: barWidth,\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n cursorBottom = top;\n });\n } else {\n const barWidth = Math.max(1, (groupWidth - BAR_GAP * (validSeries.value.length - 1)) / validSeries.value.length);\n validSeries.value.forEach((series, seriesIndex) => {\n const value = series.data[index] ?? 0;\n const top = yScale.value(value);\n const start = center - groupWidth / 2 + seriesIndex * (barWidth + BAR_GAP);\n output.push({\n x: start,\n y: Math.min(top, baselineY.value),\n width: barWidth,\n height: Math.abs(baselineY.value - top),\n color: colorFor(seriesIndex, series),\n seriesIndex,\n index,\n });\n });\n }\n }\n\n return output;\n});\n\n// --- gridlines & axes -----------------------------------------------------\nconst gridLines = computed(() =>\n scale.value.ticks.map((tick) => ({\n value: tick,\n y: yScale.value(tick),\n label: formatValue(tick),\n })),\n);\n\nconst xLabels = computed(() => {\n if (!props.showXAxis) return [];\n const count = categoryCount.value;\n const maxLabels = Math.max(2, Math.floor(plot.value.innerWidth / 52));\n const step = Math.max(1, Math.ceil(count / maxLabels));\n return props.labels.slice(0, count).map((label, index) => ({\n label,\n x: activeX(index),\n show: index % step === 0 || index === count - 1,\n }));\n});\n\n// --- interaction ----------------------------------------------------------\nconst activeIndex = ref<number | null>(null);\n\nconst pointerToIndex = (clientX: number) => {\n const element = canvasRef.value;\n if (!element) return null;\n const rect = element.getBoundingClientRect();\n const x = clientX - rect.left;\n const count = categoryCount.value;\n if (count === 0) return null;\n\n if (props.type === 'bar') {\n const index = Math.floor((x - plot.value.left) / band.value);\n return Math.min(count - 1, Math.max(0, index));\n }\n\n const ratio = (x - plot.value.left) / Math.max(1, plot.value.innerWidth);\n return Math.min(count - 1, Math.max(0, Math.round(ratio * (count - 1))));\n};\n\nconst onPointerMove = (event: PointerEvent) => {\n if (!props.showTooltip || !hasData.value) return;\n activeIndex.value = pointerToIndex(event.clientX);\n};\n\nconst onPointerLeave = () => {\n activeIndex.value = null;\n};\n\nconst activePayload = computed<TChartActivePayload | null>(() => {\n const index = activeIndex.value;\n if (index === null) return null;\n return {\n index,\n label: props.labels[index] ?? `#${index + 1}`,\n values: validSeries.value.map((series, seriesIndex) => ({\n name: series.name,\n value: series.data[index] ?? 0,\n color: colorFor(seriesIndex, series),\n })),\n };\n});\n\nconst tooltipStyle = computed(() => {\n const index = activeIndex.value;\n if (index === null) return {};\n const x = activeX(index);\n const clamped = Math.min(Math.max(x, 64), width.value - 64);\n return { left: `${clamped}px`, top: `${plot.value.top}px` };\n});\n\nconst activeMarkers = computed(() => {\n const index = activeIndex.value;\n if (index === null || props.type === 'bar') return [];\n return linePaths.value.map((path) => ({\n x: path.points[index]?.x ?? 0,\n y: path.points[index]?.y ?? 0,\n color: path.color,\n }));\n});\n\nconst onClick = () => {\n if (activePayload.value) emit('point-click', activePayload.value);\n};\n\nconst resolvedLabel = computed(\n () => props.ariaLabel ?? `${props.type} chart with ${validSeries.value.length} series`,\n);\n\nconst rootClasses = computed(() => [\n 't-chart',\n `t-chart--${props.type}`,\n {\n 'is-animated': props.animated,\n 'is-loading': props.loading,\n },\n]);\n</script>\n\n<template>\n <div :class=\"rootClasses\">\n <div\n ref=\"canvasRef\"\n class=\"t-chart__canvas\"\n :style=\"{ height: `${height}px` }\"\n >\n <div\n v-if=\"loading\"\n class=\"t-chart__loading\"\n >\n <span\n v-for=\"n in 5\"\n :key=\"n\"\n class=\"t-chart__loading-bar\"\n :style=\"{ height: `${30 + ((n * 37) % 60)}%` }\"\n />\n </div>\n\n <div\n v-else-if=\"!hasData\"\n class=\"t-chart__empty\"\n >\n <slot name=\"empty\">\n No data to display\n </slot>\n </div>\n\n <template v-else>\n <svg\n class=\"t-chart__svg\"\n :width=\"width\"\n :height=\"height\"\n :viewBox=\"`0 0 ${width} ${height}`\"\n aria-hidden=\"true\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"onPointerLeave\"\n @click=\"onClick\"\n >\n <!-- gridlines + y ticks -->\n <g class=\"t-chart__grid\">\n <template\n v-for=\"line in gridLines\"\n :key=\"line.value\"\n >\n <line\n v-if=\"showGrid\"\n class=\"t-chart__gridline\"\n :x1=\"plot.left\"\n :x2=\"plot.right\"\n :y1=\"line.y\"\n :y2=\"line.y\"\n />\n <text\n v-if=\"showYAxis\"\n class=\"t-chart__axis-label t-chart__axis-label--y\"\n :x=\"plot.left - 8\"\n :y=\"line.y\"\n >\n {{ line.label }}\n </text>\n </template>\n </g>\n\n <!-- area fills -->\n <g class=\"t-chart__areas\">\n <path\n v-for=\"(path, index) in linePaths\"\n v-show=\"type === 'area'\"\n :key=\"`area-${index}`\"\n class=\"t-chart__area\"\n :d=\"path.area\"\n :style=\"{ color: path.color }\"\n />\n </g>\n\n <!-- bars -->\n <g class=\"t-chart__bars\">\n <rect\n v-for=\"(bar, index) in bars\"\n :key=\"`bar-${index}`\"\n class=\"t-chart__bar\"\n :x=\"bar.x\"\n :y=\"bar.y\"\n :width=\"bar.width\"\n :height=\"bar.height\"\n :rx=\"Math.min(4, bar.width / 2)\"\n :style=\"{ color: bar.color, animationDelay: `${bar.index * 40}ms` }\"\n :class=\"{ 'is-active': activeIndex === bar.index }\"\n />\n </g>\n\n <!-- lines + optional static points -->\n <g class=\"t-chart__lines\">\n <template\n v-for=\"(path, index) in linePaths\"\n :key=\"`line-${index}`\"\n >\n <path\n v-if=\"type !== 'bar'\"\n class=\"t-chart__line\"\n :d=\"path.line\"\n path-length=\"1\"\n :style=\"{ color: path.color }\"\n />\n <template v-if=\"showPoints && type !== 'bar'\">\n <circle\n v-for=\"(point, pointIndex) in path.points\"\n :key=\"`point-${index}-${pointIndex}`\"\n class=\"t-chart__point\"\n :cx=\"point.x\"\n :cy=\"point.y\"\n r=\"3\"\n :style=\"{ color: path.color }\"\n />\n </template>\n </template>\n </g>\n\n <!-- hover crosshair + active markers -->\n <g\n v-if=\"activeIndex !== null && showTooltip\"\n class=\"t-chart__hover\"\n >\n <line\n class=\"t-chart__crosshair\"\n :x1=\"activeX(activeIndex)\"\n :x2=\"activeX(activeIndex)\"\n :y1=\"plot.top\"\n :y2=\"plot.bottom\"\n />\n <circle\n v-for=\"(marker, index) in activeMarkers\"\n :key=\"`marker-${index}`\"\n class=\"t-chart__marker\"\n :cx=\"marker.x\"\n :cy=\"marker.y\"\n r=\"4\"\n :style=\"{ color: marker.color }\"\n />\n </g>\n\n <!-- x-axis labels -->\n <g\n v-if=\"showXAxis\"\n class=\"t-chart__x-axis\"\n >\n <text\n v-for=\"(item, index) in xLabels\"\n v-show=\"item.show\"\n :key=\"`x-${index}`\"\n class=\"t-chart__axis-label t-chart__axis-label--x\"\n :x=\"item.x\"\n :y=\"height - 8\"\n >\n {{ item.label }}\n </text>\n </g>\n </svg>\n\n <div\n v-if=\"showTooltip && activePayload\"\n class=\"t-chart__tooltip\"\n :style=\"tooltipStyle\"\n role=\"presentation\"\n >\n <slot\n name=\"tooltip\"\n v-bind=\"activePayload\"\n >\n <p class=\"t-chart__tooltip-label\">\n {{ activePayload.label }}\n </p>\n <ul class=\"t-chart__tooltip-list\">\n <li\n v-for=\"(item, index) in activePayload.values\"\n :key=\"index\"\n class=\"t-chart__tooltip-item\"\n >\n <span\n class=\"t-chart__tooltip-dot\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n <span class=\"t-chart__tooltip-name\">{{ item.name }}</span>\n <span class=\"t-chart__tooltip-value\">{{ formatValue(item.value) }}</span>\n </li>\n </ul>\n </slot>\n </div>\n </template>\n </div>\n\n <div\n v-if=\"resolvedShowLegend && hasData\"\n class=\"t-chart__legend\"\n >\n <slot\n name=\"legend\"\n :series=\"legendItems\"\n >\n <span\n v-for=\"(item, index) in legendItems\"\n :key=\"index\"\n class=\"t-chart__legend-item\"\n >\n <span\n class=\"t-chart__legend-swatch\"\n :style=\"{ background: item.color }\"\n aria-hidden=\"true\"\n />\n {{ item.name }}\n </span>\n </slot>\n </div>\n\n <!--\n Accessible data table: the chart's data as text for assistive tech.\n The visually-hidden class goes on a wrapper, not the table: a <table>\n ignores a width below its min-content, so hiding it directly leaves a\n full-width box that pushes the page's scroll width.\n -->\n <div class=\"t-visually-hidden\">\n <table class=\"t-chart__a11y\">\n <caption>{{ resolvedLabel }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">\n Series\n </th>\n <th\n v-for=\"index in axisIndices\"\n :key=\"index\"\n scope=\"col\"\n >\n {{ labels[index] ?? '' }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, rowIndex) in validSeries\"\n :key=\"rowIndex\"\n >\n <th scope=\"row\">\n {{ row.name }}\n </th>\n <td\n v-for=\"index in axisIndices\"\n :key=\"index\"\n >\n {{ row.data[index] === undefined ? '' : formatValue(row.data[index]) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n"],"mappings":"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"}