@treeui/vue 0.12.0 → 0.14.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 (94) hide show
  1. package/README.md +5 -1
  2. package/dist/components/TButton.cjs.map +1 -1
  3. package/dist/components/TButton.js.map +1 -1
  4. package/dist/components/TButton.vue.d.ts +2 -2
  5. package/dist/components/TButton.vue.d.ts.map +1 -1
  6. package/dist/components/TButton.vue_vue_type_script_setup_true_lang.cjs +1 -1
  7. package/dist/components/TButton.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  8. package/dist/components/TButton.vue_vue_type_script_setup_true_lang.js +2 -1
  9. package/dist/components/TButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  10. package/dist/components/TChart.cjs +2 -0
  11. package/dist/components/TChart.cjs.map +1 -0
  12. package/dist/components/TChart.js +7 -0
  13. package/dist/components/TChart.js.map +1 -0
  14. package/dist/components/TChart.vue.d.ts +123 -0
  15. package/dist/components/TChart.vue.d.ts.map +1 -0
  16. package/dist/components/TChart.vue_vue_type_script_setup_true_lang.cjs +2 -0
  17. package/dist/components/TChart.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  18. package/dist/components/TChart.vue_vue_type_script_setup_true_lang.js +370 -0
  19. package/dist/components/TChart.vue_vue_type_script_setup_true_lang.js.map +1 -0
  20. package/dist/components/TDonutChart.cjs +2 -0
  21. package/dist/components/TDonutChart.cjs.map +1 -0
  22. package/dist/components/TDonutChart.js +7 -0
  23. package/dist/components/TDonutChart.js.map +1 -0
  24. package/dist/components/TDonutChart.vue.d.ts +75 -0
  25. package/dist/components/TDonutChart.vue.d.ts.map +1 -0
  26. package/dist/components/TDonutChart.vue_vue_type_script_setup_true_lang.cjs +2 -0
  27. package/dist/components/TDonutChart.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  28. package/dist/components/TDonutChart.vue_vue_type_script_setup_true_lang.js +168 -0
  29. package/dist/components/TDonutChart.vue_vue_type_script_setup_true_lang.js.map +1 -0
  30. package/dist/components/TFileUpload.cjs.map +1 -1
  31. package/dist/components/TFileUpload.js.map +1 -1
  32. package/dist/components/TFileUpload.vue.d.ts +77 -10
  33. package/dist/components/TFileUpload.vue.d.ts.map +1 -1
  34. package/dist/components/TFileUpload.vue_vue_type_script_setup_true_lang.cjs +1 -1
  35. package/dist/components/TFileUpload.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  36. package/dist/components/TFileUpload.vue_vue_type_script_setup_true_lang.js +393 -144
  37. package/dist/components/TFileUpload.vue_vue_type_script_setup_true_lang.js.map +1 -1
  38. package/dist/components/TGrid.vue.d.ts +1 -1
  39. package/dist/components/TGrid.vue.d.ts.map +1 -1
  40. package/dist/components/TNavMenu.cjs.map +1 -1
  41. package/dist/components/TNavMenu.js.map +1 -1
  42. package/dist/components/TNavMenu.vue.d.ts +9 -0
  43. package/dist/components/TNavMenu.vue.d.ts.map +1 -1
  44. package/dist/components/TNavMenu.vue_vue_type_script_setup_true_lang.cjs +1 -1
  45. package/dist/components/TNavMenu.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  46. package/dist/components/TNavMenu.vue_vue_type_script_setup_true_lang.js +67 -55
  47. package/dist/components/TNavMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  48. package/dist/components/TPage.cjs +2 -0
  49. package/dist/components/TPage.cjs.map +1 -0
  50. package/dist/components/TPage.js +7 -0
  51. package/dist/components/TPage.js.map +1 -0
  52. package/dist/components/TPage.vue.d.ts +35 -0
  53. package/dist/components/TPage.vue.d.ts.map +1 -0
  54. package/dist/components/TPage.vue_vue_type_script_setup_true_lang.cjs +2 -0
  55. package/dist/components/TPage.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  56. package/dist/components/TPage.vue_vue_type_script_setup_true_lang.js +49 -0
  57. package/dist/components/TPage.vue_vue_type_script_setup_true_lang.js.map +1 -0
  58. package/dist/components/TPageHeader.cjs +2 -0
  59. package/dist/components/TPageHeader.cjs.map +1 -0
  60. package/dist/components/TPageHeader.js +7 -0
  61. package/dist/components/TPageHeader.js.map +1 -0
  62. package/dist/components/TPageHeader.vue.d.ts +40 -0
  63. package/dist/components/TPageHeader.vue.d.ts.map +1 -0
  64. package/dist/components/TPageHeader.vue_vue_type_script_setup_true_lang.cjs +2 -0
  65. package/dist/components/TPageHeader.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  66. package/dist/components/TPageHeader.vue_vue_type_script_setup_true_lang.js +54 -0
  67. package/dist/components/TPageHeader.vue_vue_type_script_setup_true_lang.js.map +1 -0
  68. package/dist/components/TSidebar.vue_vue_type_script_setup_true_lang.cjs +1 -1
  69. package/dist/components/TSidebar.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  70. package/dist/components/TSidebar.vue_vue_type_script_setup_true_lang.js +1 -4
  71. package/dist/components/TSidebar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  72. package/dist/components/TSparkline.cjs +2 -0
  73. package/dist/components/TSparkline.cjs.map +1 -0
  74. package/dist/components/TSparkline.js +7 -0
  75. package/dist/components/TSparkline.js.map +1 -0
  76. package/dist/components/TSparkline.vue.d.ts +40 -0
  77. package/dist/components/TSparkline.vue.d.ts.map +1 -0
  78. package/dist/components/TSparkline.vue_vue_type_script_setup_true_lang.cjs +2 -0
  79. package/dist/components/TSparkline.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  80. package/dist/components/TSparkline.vue_vue_type_script_setup_true_lang.js +107 -0
  81. package/dist/components/TSparkline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  82. package/dist/components/TStack.vue.d.ts +1 -1
  83. package/dist/components/TStack.vue.d.ts.map +1 -1
  84. package/dist/components/index.d.ts +9 -1
  85. package/dist/components/index.d.ts.map +1 -1
  86. package/dist/index.cjs +1 -1
  87. package/dist/index.js +51 -46
  88. package/dist/plugin.cjs +1 -1
  89. package/dist/plugin.cjs.map +1 -1
  90. package/dist/plugin.d.ts.map +1 -1
  91. package/dist/plugin.js +100 -90
  92. package/dist/plugin.js.map +1 -1
  93. package/dist/style.css +1 -1
  94. package/package.json +3 -3
package/README.md CHANGED
@@ -55,6 +55,10 @@ import '@treeui/vue/style.css'
55
55
 
56
56
  `TBadge` · `TAlert` · `TAvatar` · `TEmptyState` · `TTag` · `TTimeline` · `TSpinner` · `TProgress` · `TSkeleton` · `TStat`
57
57
 
58
+ ### Charts
59
+
60
+ `TChart` (line / area / bar) · `TSparkline` · `TDonutChart` — a lightweight, dependency-free data-viz set sharing a framework-agnostic geometry engine in `@treeui/utils` and the `--tree-color-chart-*` palette.
61
+
58
62
  ### Overlay & Interaction
59
63
 
60
64
  `TButton` · `TModal` · `TConfirmDialog` · `TDrawer` · `TDropdown` · `TPopover` · `TTooltip` · `TContextMenu` · `TPagination` · `TToast` · `TToastProvider`
@@ -124,7 +128,7 @@ Some repeated app UI intentionally stays documented as composition guidance inst
124
128
  - Color fields: `TFormField` + native `input[type="color"]`
125
129
  - Tag inputs: `TFormField` + `TInput` + removable `TTag`
126
130
  - Router-backed tabs: `TTabs` + app route state
127
- - Charts: `TCard` + `TStack` + your preferred chart library
131
+ - Charts: `TChart` / `TSparkline` / `TDonutChart` (native, no chart library) — frame them in `TCard` + `TStack` when a titled surface is wanted
128
132
 
129
133
  ## TypeScript
130
134
 
@@ -1 +1 @@
1
- {"version":3,"file":"TButton.cjs","names":[],"sources":["../../src/components/TButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { tv } from '@treeui/utils';\nimport type { TSize, TVariant } from '../types/contracts';\nimport TSpinner from './TSpinner.vue';\n\nconst props = withDefaults(\n defineProps<{\n as?: string;\n variant?: TVariant;\n size?: TSize;\n disabled?: boolean;\n loading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n }>(),\n {\n as: 'button',\n variant: 'solid',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n },\n);\n\nconst emit = defineEmits<{\n click: [event: MouseEvent];\n}>();\n\nconst buttonClass = tv({\n base: 't-button',\n variants: {\n variant: {\n solid: 't-button--solid',\n outline: 't-button--outline',\n ghost: 't-button--ghost',\n soft: 't-button--soft',\n danger: 't-button--danger',\n },\n size: {\n sm: 't-button--sm',\n md: 't-button--md',\n lg: 't-button--lg',\n },\n },\n});\n\nconst isNativeButton = computed(() => props.as === 'button');\nconst isDisabled = computed(() => props.disabled || props.loading);\nconst classes = computed(() =>\n buttonClass({\n variant: props.variant,\n size: props.size,\n class: {\n 'is-loading': props.loading,\n 'is-disabled': isDisabled.value,\n },\n }),\n);\n\nconst onClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n emit('click', event);\n};\n</script>\n\n<template>\n <component\n :is=\"as\"\n :type=\"isNativeButton ? type : undefined\"\n :class=\"classes\"\n :disabled=\"isNativeButton ? isDisabled : undefined\"\n :aria-disabled=\"!isNativeButton && isDisabled ? 'true' : undefined\"\n :aria-busy=\"loading || undefined\"\n :tabindex=\"!isNativeButton && isDisabled ? -1 : undefined\"\n @click=\"onClick\"\n >\n <span\n v-if=\"loading\"\n class=\"t-button__spinner\"\n >\n <TSpinner\n size=\"sm\"\n label=\"Loading\"\n />\n </span>\n <span\n v-if=\"$slots.icon\"\n class=\"t-button__icon\"\n aria-hidden=\"true\"\n >\n <slot name=\"icon\" />\n </span>\n <span class=\"t-button__label\">\n <slot />\n </span>\n </component>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"TButton.cjs","names":[],"sources":["../../src/components/TButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { tv } from '@treeui/utils';\nimport type { TSize, TVariant } from '../types/contracts';\nimport TSpinner from './TSpinner.vue';\n\nconst props = withDefaults(\n defineProps<{\n as?: string;\n variant?: TVariant | 'brand';\n size?: TSize;\n disabled?: boolean;\n loading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n }>(),\n {\n as: 'button',\n variant: 'solid',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n },\n);\n\nconst emit = defineEmits<{\n click: [event: MouseEvent];\n}>();\n\nconst buttonClass = tv({\n base: 't-button',\n variants: {\n variant: {\n solid: 't-button--solid',\n outline: 't-button--outline',\n ghost: 't-button--ghost',\n soft: 't-button--soft',\n danger: 't-button--danger',\n brand: 't-button--brand',\n },\n size: {\n sm: 't-button--sm',\n md: 't-button--md',\n lg: 't-button--lg',\n },\n },\n});\n\nconst isNativeButton = computed(() => props.as === 'button');\nconst isDisabled = computed(() => props.disabled || props.loading);\nconst classes = computed(() =>\n buttonClass({\n variant: props.variant,\n size: props.size,\n class: {\n 'is-loading': props.loading,\n 'is-disabled': isDisabled.value,\n },\n }),\n);\n\nconst onClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n emit('click', event);\n};\n</script>\n\n<template>\n <component\n :is=\"as\"\n :type=\"isNativeButton ? type : undefined\"\n :class=\"classes\"\n :disabled=\"isNativeButton ? isDisabled : undefined\"\n :aria-disabled=\"!isNativeButton && isDisabled ? 'true' : undefined\"\n :aria-busy=\"loading || undefined\"\n :tabindex=\"!isNativeButton && isDisabled ? -1 : undefined\"\n @click=\"onClick\"\n >\n <span\n v-if=\"loading\"\n class=\"t-button__spinner\"\n >\n <TSpinner\n size=\"sm\"\n label=\"Loading\"\n />\n </span>\n <span\n v-if=\"$slots.icon\"\n class=\"t-button__icon\"\n aria-hidden=\"true\"\n >\n <slot name=\"icon\" />\n </span>\n <span class=\"t-button__label\">\n <slot />\n </span>\n </component>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"TButton.js","names":[],"sources":["../../src/components/TButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { tv } from '@treeui/utils';\nimport type { TSize, TVariant } from '../types/contracts';\nimport TSpinner from './TSpinner.vue';\n\nconst props = withDefaults(\n defineProps<{\n as?: string;\n variant?: TVariant;\n size?: TSize;\n disabled?: boolean;\n loading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n }>(),\n {\n as: 'button',\n variant: 'solid',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n },\n);\n\nconst emit = defineEmits<{\n click: [event: MouseEvent];\n}>();\n\nconst buttonClass = tv({\n base: 't-button',\n variants: {\n variant: {\n solid: 't-button--solid',\n outline: 't-button--outline',\n ghost: 't-button--ghost',\n soft: 't-button--soft',\n danger: 't-button--danger',\n },\n size: {\n sm: 't-button--sm',\n md: 't-button--md',\n lg: 't-button--lg',\n },\n },\n});\n\nconst isNativeButton = computed(() => props.as === 'button');\nconst isDisabled = computed(() => props.disabled || props.loading);\nconst classes = computed(() =>\n buttonClass({\n variant: props.variant,\n size: props.size,\n class: {\n 'is-loading': props.loading,\n 'is-disabled': isDisabled.value,\n },\n }),\n);\n\nconst onClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n emit('click', event);\n};\n</script>\n\n<template>\n <component\n :is=\"as\"\n :type=\"isNativeButton ? type : undefined\"\n :class=\"classes\"\n :disabled=\"isNativeButton ? isDisabled : undefined\"\n :aria-disabled=\"!isNativeButton && isDisabled ? 'true' : undefined\"\n :aria-busy=\"loading || undefined\"\n :tabindex=\"!isNativeButton && isDisabled ? -1 : undefined\"\n @click=\"onClick\"\n >\n <span\n v-if=\"loading\"\n class=\"t-button__spinner\"\n >\n <TSpinner\n size=\"sm\"\n label=\"Loading\"\n />\n </span>\n <span\n v-if=\"$slots.icon\"\n class=\"t-button__icon\"\n aria-hidden=\"true\"\n >\n <slot name=\"icon\" />\n </span>\n <span class=\"t-button__label\">\n <slot />\n </span>\n </component>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"TButton.js","names":[],"sources":["../../src/components/TButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { tv } from '@treeui/utils';\nimport type { TSize, TVariant } from '../types/contracts';\nimport TSpinner from './TSpinner.vue';\n\nconst props = withDefaults(\n defineProps<{\n as?: string;\n variant?: TVariant | 'brand';\n size?: TSize;\n disabled?: boolean;\n loading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n }>(),\n {\n as: 'button',\n variant: 'solid',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n },\n);\n\nconst emit = defineEmits<{\n click: [event: MouseEvent];\n}>();\n\nconst buttonClass = tv({\n base: 't-button',\n variants: {\n variant: {\n solid: 't-button--solid',\n outline: 't-button--outline',\n ghost: 't-button--ghost',\n soft: 't-button--soft',\n danger: 't-button--danger',\n brand: 't-button--brand',\n },\n size: {\n sm: 't-button--sm',\n md: 't-button--md',\n lg: 't-button--lg',\n },\n },\n});\n\nconst isNativeButton = computed(() => props.as === 'button');\nconst isDisabled = computed(() => props.disabled || props.loading);\nconst classes = computed(() =>\n buttonClass({\n variant: props.variant,\n size: props.size,\n class: {\n 'is-loading': props.loading,\n 'is-disabled': isDisabled.value,\n },\n }),\n);\n\nconst onClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n emit('click', event);\n};\n</script>\n\n<template>\n <component\n :is=\"as\"\n :type=\"isNativeButton ? type : undefined\"\n :class=\"classes\"\n :disabled=\"isNativeButton ? isDisabled : undefined\"\n :aria-disabled=\"!isNativeButton && isDisabled ? 'true' : undefined\"\n :aria-busy=\"loading || undefined\"\n :tabindex=\"!isNativeButton && isDisabled ? -1 : undefined\"\n @click=\"onClick\"\n >\n <span\n v-if=\"loading\"\n class=\"t-button__spinner\"\n >\n <TSpinner\n size=\"sm\"\n label=\"Loading\"\n />\n </span>\n <span\n v-if=\"$slots.icon\"\n class=\"t-button__icon\"\n aria-hidden=\"true\"\n >\n <slot name=\"icon\" />\n </span>\n <span class=\"t-button__label\">\n <slot />\n </span>\n </component>\n</template>\n"],"mappings":""}
@@ -1,7 +1,7 @@
1
1
  import { TSize, TVariant } from '../types/contracts';
2
2
  type __VLS_Props = {
3
3
  as?: string;
4
- variant?: TVariant;
4
+ variant?: TVariant | 'brand';
5
5
  size?: TSize;
6
6
  disabled?: boolean;
7
7
  loading?: boolean;
@@ -25,7 +25,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}
25
25
  type: "button" | "submit" | "reset";
26
26
  disabled: boolean;
27
27
  size: TSize;
28
- variant: TVariant;
28
+ variant: TVariant | "brand";
29
29
  as: string;
30
30
  loading: boolean;
31
31
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
@@ -1 +1 @@
1
- {"version":3,"file":"TButton.vue.d.ts","sourceRoot":"","sources":["../../src/components/TButton.vue"],"names":[],"mappings":"AA2GA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG1D,KAAK,WAAW,GAAG;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;CACtC,CAAC;AAqEJ,iBAAS,cAAc;WA6ET,OAAO,IAA6B;;sBAXvB,GAAG;yBACA,GAAG;;;;EAehC;AAeD,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAC9D,QAAA,MAAM,eAAe;;;;;UAxKV,QAAQ,GAAG,QAAQ,GAAG,OAAO;cAFzB,OAAO;UADX,KAAK;aADF,QAAQ;QADb,MAAM;aAID,OAAO;6EAkLnB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAAnG,wBAAoG;AAapG,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"TButton.vue.d.ts","sourceRoot":"","sources":["../../src/components/TButton.vue"],"names":[],"mappings":"AA4GA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG1D,KAAK,WAAW,GAAG;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC7B,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;CACtC,CAAC;AAsEJ,iBAAS,cAAc;WA6ET,OAAO,IAA6B;;sBAXvB,GAAG;yBACA,GAAG;;;;EAehC;AAeD,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAC9D,QAAA,MAAM,eAAe;;;;;UAzKV,QAAQ,GAAG,QAAQ,GAAG,OAAO;cAFzB,OAAO;UADX,KAAK;aADF,QAAQ,GAAG,OAAO;QADvB,MAAM;aAID,OAAO;6EAmLnB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAAnG,wBAAoG;AAapG,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
@@ -1,2 +1,2 @@
1
- const e=require("./TSpinner.cjs");let t=require("vue"),n=require("@treeui/utils");var r={key:0,class:`t-button__spinner`},i={key:1,class:`t-button__icon`,"aria-hidden":`true`},a={class:`t-button__label`},o=(0,t.defineComponent)({__name:`TButton`,props:{as:{default:`button`},variant:{default:`solid`},size:{default:`md`},disabled:{type:Boolean,default:!1},loading:{type:Boolean,default:!1},type:{default:`button`}},emits:[`click`],setup(o,{emit:s}){let c=o,l=s,u=(0,n.tv)({base:`t-button`,variants:{variant:{solid:`t-button--solid`,outline:`t-button--outline`,ghost:`t-button--ghost`,soft:`t-button--soft`,danger:`t-button--danger`},size:{sm:`t-button--sm`,md:`t-button--md`,lg:`t-button--lg`}}}),d=(0,t.computed)(()=>c.as===`button`),f=(0,t.computed)(()=>c.disabled||c.loading),p=(0,t.computed)(()=>u({variant:c.variant,size:c.size,class:{"is-loading":c.loading,"is-disabled":f.value}})),m=e=>{if(f.value){e.preventDefault(),e.stopPropagation();return}l(`click`,e)};return(n,s)=>((0,t.openBlock)(),(0,t.createBlock)((0,t.resolveDynamicComponent)(o.as),{type:d.value?o.type:void 0,class:(0,t.normalizeClass)(p.value),disabled:d.value?f.value:void 0,"aria-disabled":!d.value&&f.value?`true`:void 0,"aria-busy":o.loading||void 0,tabindex:!d.value&&f.value?-1:void 0,onClick:m},{default:(0,t.withCtx)(()=>[o.loading?((0,t.openBlock)(),(0,t.createElementBlock)(`span`,r,[(0,t.createVNode)(e.default,{size:`sm`,label:`Loading`})])):(0,t.createCommentVNode)(``,!0),n.$slots.icon?((0,t.openBlock)(),(0,t.createElementBlock)(`span`,i,[(0,t.renderSlot)(n.$slots,`icon`)])):(0,t.createCommentVNode)(``,!0),(0,t.createElementVNode)(`span`,a,[(0,t.renderSlot)(n.$slots,`default`)])]),_:3},8,[`type`,`class`,`disabled`,`aria-disabled`,`aria-busy`,`tabindex`]))}});exports.default=o;
1
+ const e=require("./TSpinner.cjs");let t=require("vue"),n=require("@treeui/utils");var r={key:0,class:`t-button__spinner`},i={key:1,class:`t-button__icon`,"aria-hidden":`true`},a={class:`t-button__label`},o=(0,t.defineComponent)({__name:`TButton`,props:{as:{default:`button`},variant:{default:`solid`},size:{default:`md`},disabled:{type:Boolean,default:!1},loading:{type:Boolean,default:!1},type:{default:`button`}},emits:[`click`],setup(o,{emit:s}){let c=o,l=s,u=(0,n.tv)({base:`t-button`,variants:{variant:{solid:`t-button--solid`,outline:`t-button--outline`,ghost:`t-button--ghost`,soft:`t-button--soft`,danger:`t-button--danger`,brand:`t-button--brand`},size:{sm:`t-button--sm`,md:`t-button--md`,lg:`t-button--lg`}}}),d=(0,t.computed)(()=>c.as===`button`),f=(0,t.computed)(()=>c.disabled||c.loading),p=(0,t.computed)(()=>u({variant:c.variant,size:c.size,class:{"is-loading":c.loading,"is-disabled":f.value}})),m=e=>{if(f.value){e.preventDefault(),e.stopPropagation();return}l(`click`,e)};return(n,s)=>((0,t.openBlock)(),(0,t.createBlock)((0,t.resolveDynamicComponent)(o.as),{type:d.value?o.type:void 0,class:(0,t.normalizeClass)(p.value),disabled:d.value?f.value:void 0,"aria-disabled":!d.value&&f.value?`true`:void 0,"aria-busy":o.loading||void 0,tabindex:!d.value&&f.value?-1:void 0,onClick:m},{default:(0,t.withCtx)(()=>[o.loading?((0,t.openBlock)(),(0,t.createElementBlock)(`span`,r,[(0,t.createVNode)(e.default,{size:`sm`,label:`Loading`})])):(0,t.createCommentVNode)(``,!0),n.$slots.icon?((0,t.openBlock)(),(0,t.createElementBlock)(`span`,i,[(0,t.renderSlot)(n.$slots,`icon`)])):(0,t.createCommentVNode)(``,!0),(0,t.createElementVNode)(`span`,a,[(0,t.renderSlot)(n.$slots,`default`)])]),_:3},8,[`type`,`class`,`disabled`,`aria-disabled`,`aria-busy`,`tabindex`]))}});exports.default=o;
2
2
  //# sourceMappingURL=TButton.vue_vue_type_script_setup_true_lang.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TButton.vue_vue_type_script_setup_true_lang.cjs","names":["$slots"],"sources":["../../src/components/TButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { tv } from '@treeui/utils';\nimport type { TSize, TVariant } from '../types/contracts';\nimport TSpinner from './TSpinner.vue';\n\nconst props = withDefaults(\n defineProps<{\n as?: string;\n variant?: TVariant;\n size?: TSize;\n disabled?: boolean;\n loading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n }>(),\n {\n as: 'button',\n variant: 'solid',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n },\n);\n\nconst emit = defineEmits<{\n click: [event: MouseEvent];\n}>();\n\nconst buttonClass = tv({\n base: 't-button',\n variants: {\n variant: {\n solid: 't-button--solid',\n outline: 't-button--outline',\n ghost: 't-button--ghost',\n soft: 't-button--soft',\n danger: 't-button--danger',\n },\n size: {\n sm: 't-button--sm',\n md: 't-button--md',\n lg: 't-button--lg',\n },\n },\n});\n\nconst isNativeButton = computed(() => props.as === 'button');\nconst isDisabled = computed(() => props.disabled || props.loading);\nconst classes = computed(() =>\n buttonClass({\n variant: props.variant,\n size: props.size,\n class: {\n 'is-loading': props.loading,\n 'is-disabled': isDisabled.value,\n },\n }),\n);\n\nconst onClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n emit('click', event);\n};\n</script>\n\n<template>\n <component\n :is=\"as\"\n :type=\"isNativeButton ? type : undefined\"\n :class=\"classes\"\n :disabled=\"isNativeButton ? isDisabled : undefined\"\n :aria-disabled=\"!isNativeButton && isDisabled ? 'true' : undefined\"\n :aria-busy=\"loading || undefined\"\n :tabindex=\"!isNativeButton && isDisabled ? -1 : undefined\"\n @click=\"onClick\"\n >\n <span\n v-if=\"loading\"\n class=\"t-button__spinner\"\n >\n <TSpinner\n size=\"sm\"\n label=\"Loading\"\n />\n </span>\n <span\n v-if=\"$slots.icon\"\n class=\"t-button__icon\"\n aria-hidden=\"true\"\n >\n <slot name=\"icon\" />\n </span>\n <span class=\"t-button__label\">\n <slot />\n </span>\n </component>\n</template>\n"],"mappings":"icAMA,IAAM,EAAQ,EAmBR,EAAO,EAIP,GAAA,EAAA,EAAA,GAAA,CAAiB,CACrB,KAAM,WACN,SAAU,CACR,QAAS,CACP,MAAO,kBACP,QAAS,oBACT,MAAO,kBACP,KAAM,iBACN,OAAQ,kBACV,EACA,KAAM,CACJ,GAAI,eACJ,GAAI,eACJ,GAAI,cACN,CACF,CACF,CAAC,EAEK,GAAA,EAAA,EAAA,SAAA,KAAgC,EAAM,KAAO,QAAQ,EACrD,GAAA,EAAA,EAAA,SAAA,KAA4B,EAAM,UAAY,EAAM,OAAO,EAC3D,GAAA,EAAA,EAAA,SAAA,KACJ,EAAY,CACV,QAAS,EAAM,QACf,KAAM,EAAM,KACZ,MAAO,CACL,aAAc,EAAM,QACpB,cAAe,EAAW,KAC5B,CACF,CAAC,CACH,EAEM,EAAW,GAAsB,CACrC,GAAI,EAAW,MAAO,CACpB,EAAM,eAAe,EACrB,EAAM,gBAAgB,EACtB,MACF,CAEA,EAAK,QAAS,CAAK,CACrB,kFAKS,EAAA,EAAE,EAAA,CACN,KAAM,EAAA,MAAiB,EAAA,KAAO,IAAA,GAC9B,OAAA,EAAA,EAAA,eAAA,CAAO,EAAA,KAAO,EACd,SAAU,EAAA,MAAiB,EAAA,MAAa,IAAA,GACxC,gBAAa,CAAG,EAAA,OAAkB,EAAA,MAAU,OAAY,IAAA,GACxD,YAAW,EAAA,SAAW,IAAA,GACtB,SAAQ,CAAG,EAAA,OAAkB,EAAA,MAAU,GAAQ,IAAA,GACxC,sCAUD,CAPC,EAAA,UAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAOD,OARP,EAQO,EAAA,EAAA,EAAA,YAAA,CADH,EAAA,QAAA,CAFA,KAAK,KACL,MAAM,+CAIFA,EAAAA,OAAO,OAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAKR,OANP,EAMO,EAAA,EAAA,EAAA,WAAA,CADe,EAAA,OAAA,MAAA,CAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,2BAIf,OAFP,EAEO,EAAA,EAAA,EAAA,WAAA,CADG,EAAA,OAAA,SAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"TButton.vue_vue_type_script_setup_true_lang.cjs","names":["$slots"],"sources":["../../src/components/TButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { tv } from '@treeui/utils';\nimport type { TSize, TVariant } from '../types/contracts';\nimport TSpinner from './TSpinner.vue';\n\nconst props = withDefaults(\n defineProps<{\n as?: string;\n variant?: TVariant | 'brand';\n size?: TSize;\n disabled?: boolean;\n loading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n }>(),\n {\n as: 'button',\n variant: 'solid',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n },\n);\n\nconst emit = defineEmits<{\n click: [event: MouseEvent];\n}>();\n\nconst buttonClass = tv({\n base: 't-button',\n variants: {\n variant: {\n solid: 't-button--solid',\n outline: 't-button--outline',\n ghost: 't-button--ghost',\n soft: 't-button--soft',\n danger: 't-button--danger',\n brand: 't-button--brand',\n },\n size: {\n sm: 't-button--sm',\n md: 't-button--md',\n lg: 't-button--lg',\n },\n },\n});\n\nconst isNativeButton = computed(() => props.as === 'button');\nconst isDisabled = computed(() => props.disabled || props.loading);\nconst classes = computed(() =>\n buttonClass({\n variant: props.variant,\n size: props.size,\n class: {\n 'is-loading': props.loading,\n 'is-disabled': isDisabled.value,\n },\n }),\n);\n\nconst onClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n emit('click', event);\n};\n</script>\n\n<template>\n <component\n :is=\"as\"\n :type=\"isNativeButton ? type : undefined\"\n :class=\"classes\"\n :disabled=\"isNativeButton ? isDisabled : undefined\"\n :aria-disabled=\"!isNativeButton && isDisabled ? 'true' : undefined\"\n :aria-busy=\"loading || undefined\"\n :tabindex=\"!isNativeButton && isDisabled ? -1 : undefined\"\n @click=\"onClick\"\n >\n <span\n v-if=\"loading\"\n class=\"t-button__spinner\"\n >\n <TSpinner\n size=\"sm\"\n label=\"Loading\"\n />\n </span>\n <span\n v-if=\"$slots.icon\"\n class=\"t-button__icon\"\n aria-hidden=\"true\"\n >\n <slot name=\"icon\" />\n </span>\n <span class=\"t-button__label\">\n <slot />\n </span>\n </component>\n</template>\n"],"mappings":"icAMA,IAAM,EAAQ,EAmBR,EAAO,EAIP,GAAA,EAAA,EAAA,GAAA,CAAiB,CACrB,KAAM,WACN,SAAU,CACR,QAAS,CACP,MAAO,kBACP,QAAS,oBACT,MAAO,kBACP,KAAM,iBACN,OAAQ,mBACR,MAAO,iBACT,EACA,KAAM,CACJ,GAAI,eACJ,GAAI,eACJ,GAAI,cACN,CACF,CACF,CAAC,EAEK,GAAA,EAAA,EAAA,SAAA,KAAgC,EAAM,KAAO,QAAQ,EACrD,GAAA,EAAA,EAAA,SAAA,KAA4B,EAAM,UAAY,EAAM,OAAO,EAC3D,GAAA,EAAA,EAAA,SAAA,KACJ,EAAY,CACV,QAAS,EAAM,QACf,KAAM,EAAM,KACZ,MAAO,CACL,aAAc,EAAM,QACpB,cAAe,EAAW,KAC5B,CACF,CAAC,CACH,EAEM,EAAW,GAAsB,CACrC,GAAI,EAAW,MAAO,CACpB,EAAM,eAAe,EACrB,EAAM,gBAAgB,EACtB,MACF,CAEA,EAAK,QAAS,CAAK,CACrB,kFAKS,EAAA,EAAE,EAAA,CACN,KAAM,EAAA,MAAiB,EAAA,KAAO,IAAA,GAC9B,OAAA,EAAA,EAAA,eAAA,CAAO,EAAA,KAAO,EACd,SAAU,EAAA,MAAiB,EAAA,MAAa,IAAA,GACxC,gBAAa,CAAG,EAAA,OAAkB,EAAA,MAAU,OAAY,IAAA,GACxD,YAAW,EAAA,SAAW,IAAA,GACtB,SAAQ,CAAG,EAAA,OAAkB,EAAA,MAAU,GAAQ,IAAA,GACxC,sCAUD,CAPC,EAAA,UAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAOD,OARP,EAQO,EAAA,EAAA,EAAA,YAAA,CADH,EAAA,QAAA,CAFA,KAAK,KACL,MAAM,+CAIFA,EAAAA,OAAO,OAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAKR,OANP,EAMO,EAAA,EAAA,EAAA,WAAA,CADe,EAAA,OAAA,MAAA,CAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,2BAIf,OAFP,EAEO,EAAA,EAAA,EAAA,WAAA,CADG,EAAA,OAAA,SAAA,CAAA,CAAA"}
@@ -35,7 +35,8 @@ var m = {
35
35
  outline: "t-button--outline",
36
36
  ghost: "t-button--ghost",
37
37
  soft: "t-button--soft",
38
- danger: "t-button--danger"
38
+ danger: "t-button--danger",
39
+ brand: "t-button--brand"
39
40
  },
40
41
  size: {
41
42
  sm: "t-button--sm",
@@ -1 +1 @@
1
- {"version":3,"file":"TButton.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../src/components/TButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { tv } from '@treeui/utils';\nimport type { TSize, TVariant } from '../types/contracts';\nimport TSpinner from './TSpinner.vue';\n\nconst props = withDefaults(\n defineProps<{\n as?: string;\n variant?: TVariant;\n size?: TSize;\n disabled?: boolean;\n loading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n }>(),\n {\n as: 'button',\n variant: 'solid',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n },\n);\n\nconst emit = defineEmits<{\n click: [event: MouseEvent];\n}>();\n\nconst buttonClass = tv({\n base: 't-button',\n variants: {\n variant: {\n solid: 't-button--solid',\n outline: 't-button--outline',\n ghost: 't-button--ghost',\n soft: 't-button--soft',\n danger: 't-button--danger',\n },\n size: {\n sm: 't-button--sm',\n md: 't-button--md',\n lg: 't-button--lg',\n },\n },\n});\n\nconst isNativeButton = computed(() => props.as === 'button');\nconst isDisabled = computed(() => props.disabled || props.loading);\nconst classes = computed(() =>\n buttonClass({\n variant: props.variant,\n size: props.size,\n class: {\n 'is-loading': props.loading,\n 'is-disabled': isDisabled.value,\n },\n }),\n);\n\nconst onClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n emit('click', event);\n};\n</script>\n\n<template>\n <component\n :is=\"as\"\n :type=\"isNativeButton ? type : undefined\"\n :class=\"classes\"\n :disabled=\"isNativeButton ? isDisabled : undefined\"\n :aria-disabled=\"!isNativeButton && isDisabled ? 'true' : undefined\"\n :aria-busy=\"loading || undefined\"\n :tabindex=\"!isNativeButton && isDisabled ? -1 : undefined\"\n @click=\"onClick\"\n >\n <span\n v-if=\"loading\"\n class=\"t-button__spinner\"\n >\n <TSpinner\n size=\"sm\"\n label=\"Loading\"\n />\n </span>\n <span\n v-if=\"$slots.icon\"\n class=\"t-button__icon\"\n aria-hidden=\"true\"\n >\n <slot name=\"icon\" />\n </span>\n <span class=\"t-button__label\">\n <slot />\n </span>\n </component>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMA,IAAM,IAAQ,GAmBR,IAAO,GAIP,IAAc,EAAG;GACrB,MAAM;GACN,UAAU;IACR,SAAS;KACP,OAAO;KACP,SAAS;KACT,OAAO;KACP,MAAM;KACN,QAAQ;IACV;IACA,MAAM;KACJ,IAAI;KACJ,IAAI;KACJ,IAAI;IACN;GACF;EACF,CAAC,GAEK,IAAiB,QAAe,EAAM,OAAO,QAAQ,GACrD,IAAa,QAAe,EAAM,YAAY,EAAM,OAAO,GAC3D,IAAU,QACd,EAAY;GACV,SAAS,EAAM;GACf,MAAM,EAAM;GACZ,OAAO;IACL,cAAc,EAAM;IACpB,eAAe,EAAW;GAC5B;EACF,CAAC,CACH,GAEM,KAAW,MAAsB;GACrC,IAAI,EAAW,OAAO;IAEpB,AADA,EAAM,eAAe,GACrB,EAAM,gBAAgB;IACtB;GACF;GAEA,EAAK,SAAS,CAAK;EACrB;yBAIE,EA6BY,EA5BL,EAAA,EAAE,GAAA;GACN,MAAM,EAAA,QAAiB,EAAA,OAAO,KAAA;GAC9B,OAAK,EAAE,EAAA,KAAO;GACd,UAAU,EAAA,QAAiB,EAAA,QAAa,KAAA;GACxC,iBAAa,CAAG,EAAA,SAAkB,EAAA,QAAU,SAAY,KAAA;GACxD,aAAW,EAAA,WAAW,KAAA;GACtB,UAAQ,CAAG,EAAA,SAAkB,EAAA,QAAU,KAAQ,KAAA;GACxC;;oBAUD;IAPC,EAAA,WAAA,EAAA,GADR,EAQO,QARP,GAQO,CAJL,EAGE,GAAA;KAFA,MAAK;KACL,OAAM;;IAIFA,EAAAA,OAAO,QAAA,EAAA,GADf,EAMO,QANP,GAMO,CADL,EAAoB,EAAA,QAAA,MAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;IAEtB,EAEO,QAFP,GAEO,CADL,EAAQ,EAAA,QAAA,SAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"TButton.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../src/components/TButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { tv } from '@treeui/utils';\nimport type { TSize, TVariant } from '../types/contracts';\nimport TSpinner from './TSpinner.vue';\n\nconst props = withDefaults(\n defineProps<{\n as?: string;\n variant?: TVariant | 'brand';\n size?: TSize;\n disabled?: boolean;\n loading?: boolean;\n type?: 'button' | 'submit' | 'reset';\n }>(),\n {\n as: 'button',\n variant: 'solid',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n },\n);\n\nconst emit = defineEmits<{\n click: [event: MouseEvent];\n}>();\n\nconst buttonClass = tv({\n base: 't-button',\n variants: {\n variant: {\n solid: 't-button--solid',\n outline: 't-button--outline',\n ghost: 't-button--ghost',\n soft: 't-button--soft',\n danger: 't-button--danger',\n brand: 't-button--brand',\n },\n size: {\n sm: 't-button--sm',\n md: 't-button--md',\n lg: 't-button--lg',\n },\n },\n});\n\nconst isNativeButton = computed(() => props.as === 'button');\nconst isDisabled = computed(() => props.disabled || props.loading);\nconst classes = computed(() =>\n buttonClass({\n variant: props.variant,\n size: props.size,\n class: {\n 'is-loading': props.loading,\n 'is-disabled': isDisabled.value,\n },\n }),\n);\n\nconst onClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n emit('click', event);\n};\n</script>\n\n<template>\n <component\n :is=\"as\"\n :type=\"isNativeButton ? type : undefined\"\n :class=\"classes\"\n :disabled=\"isNativeButton ? isDisabled : undefined\"\n :aria-disabled=\"!isNativeButton && isDisabled ? 'true' : undefined\"\n :aria-busy=\"loading || undefined\"\n :tabindex=\"!isNativeButton && isDisabled ? -1 : undefined\"\n @click=\"onClick\"\n >\n <span\n v-if=\"loading\"\n class=\"t-button__spinner\"\n >\n <TSpinner\n size=\"sm\"\n label=\"Loading\"\n />\n </span>\n <span\n v-if=\"$slots.icon\"\n class=\"t-button__icon\"\n aria-hidden=\"true\"\n >\n <slot name=\"icon\" />\n </span>\n <span class=\"t-button__label\">\n <slot />\n </span>\n </component>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMA,IAAM,IAAQ,GAmBR,IAAO,GAIP,IAAc,EAAG;GACrB,MAAM;GACN,UAAU;IACR,SAAS;KACP,OAAO;KACP,SAAS;KACT,OAAO;KACP,MAAM;KACN,QAAQ;KACR,OAAO;IACT;IACA,MAAM;KACJ,IAAI;KACJ,IAAI;KACJ,IAAI;IACN;GACF;EACF,CAAC,GAEK,IAAiB,QAAe,EAAM,OAAO,QAAQ,GACrD,IAAa,QAAe,EAAM,YAAY,EAAM,OAAO,GAC3D,IAAU,QACd,EAAY;GACV,SAAS,EAAM;GACf,MAAM,EAAM;GACZ,OAAO;IACL,cAAc,EAAM;IACpB,eAAe,EAAW;GAC5B;EACF,CAAC,CACH,GAEM,KAAW,MAAsB;GACrC,IAAI,EAAW,OAAO;IAEpB,AADA,EAAM,eAAe,GACrB,EAAM,gBAAgB;IACtB;GACF;GAEA,EAAK,SAAS,CAAK;EACrB;yBAIE,EA6BY,EA5BL,EAAA,EAAE,GAAA;GACN,MAAM,EAAA,QAAiB,EAAA,OAAO,KAAA;GAC9B,OAAK,EAAE,EAAA,KAAO;GACd,UAAU,EAAA,QAAiB,EAAA,QAAa,KAAA;GACxC,iBAAa,CAAG,EAAA,SAAkB,EAAA,QAAU,SAAY,KAAA;GACxD,aAAW,EAAA,WAAW,KAAA;GACtB,UAAQ,CAAG,EAAA,SAAkB,EAAA,QAAU,KAAQ,KAAA;GACxC;;oBAUD;IAPC,EAAA,WAAA,EAAA,GADR,EAQO,QARP,GAQO,CAJL,EAGE,GAAA;KAFA,MAAK;KACL,OAAM;;IAIFA,EAAAA,OAAO,QAAA,EAAA,GADf,EAMO,QANP,GAMO,CADL,EAAoB,EAAA,QAAA,MAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;IAEtB,EAEO,QAFP,GAEO,CADL,EAAQ,EAAA,QAAA,SAAA,CAAA,CAAA"}
@@ -0,0 +1,2 @@
1
+ var e=require("./TChart.vue_vue_type_script_setup_true_lang.cjs").default;exports.default=e;
2
+ //# sourceMappingURL=TChart.cjs.map
@@ -0,0 +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":""}
@@ -0,0 +1,7 @@
1
+ import e from "./TChart.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/TChart.vue
3
+ var t = e;
4
+ //#endregion
5
+ export { t as default };
6
+
7
+ //# sourceMappingURL=TChart.js.map
@@ -0,0 +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":""}
@@ -0,0 +1,123 @@
1
+ export type TChartType = 'line' | 'area' | 'bar';
2
+ export interface TChartSeries {
3
+ /** Legend/tooltip name for the series. */
4
+ name: string;
5
+ /** One value per category, aligned to `labels`. */
6
+ data: number[];
7
+ /** Override the series color; defaults to a chart palette token. */
8
+ color?: string;
9
+ }
10
+ export interface TChartActivePayload {
11
+ index: number;
12
+ label: string;
13
+ values: Array<{
14
+ name: string;
15
+ value: number;
16
+ color: string;
17
+ }>;
18
+ }
19
+ type __VLS_Props = {
20
+ /** Visual form of the plot. */
21
+ type?: TChartType;
22
+ /** One or more data series. */
23
+ series?: TChartSeries[];
24
+ /** Category labels for the x-axis, aligned to each series' data. */
25
+ labels?: string[];
26
+ /** Plot height in px (width is fluid). */
27
+ height?: number;
28
+ /** Smooth (curved) line/area. */
29
+ smooth?: boolean;
30
+ /**
31
+ * Stack bar series on top of each other instead of grouping side by side.
32
+ * Negative values are clamped to 0 in stacked mode (grouped mode renders them).
33
+ */
34
+ stacked?: boolean;
35
+ /** Draw horizontal gridlines. */
36
+ showGrid?: boolean;
37
+ /** Show the legend. Defaults to on when there is more than one series. */
38
+ showLegend?: boolean;
39
+ /** Show x-axis category labels. */
40
+ showXAxis?: boolean;
41
+ /** Show y-axis value ticks. */
42
+ showYAxis?: boolean;
43
+ /** Show the hover crosshair + tooltip. */
44
+ showTooltip?: boolean;
45
+ /** Always render markers on line/area points (not just on hover). */
46
+ showPoints?: boolean;
47
+ /** Target number of y-axis ticks. */
48
+ yTicks?: number;
49
+ /** Format axis + tooltip values. */
50
+ valueFormat?: (value: number) => string;
51
+ /** Force the low end of the y domain. */
52
+ minY?: number;
53
+ /** Force the high end of the y domain. */
54
+ maxY?: number;
55
+ /** Animate marks on first render (respects prefers-reduced-motion). */
56
+ animated?: boolean;
57
+ /** Render skeleton placeholders instead of the plot. */
58
+ loading?: boolean;
59
+ /** Accessible summary of the chart. */
60
+ ariaLabel?: string;
61
+ };
62
+ declare function __VLS_template(): {
63
+ attrs: Partial<{}>;
64
+ slots: Readonly<{
65
+ legend?: (props: {
66
+ series: Array<{
67
+ name: string;
68
+ color: string;
69
+ }>;
70
+ }) => unknown;
71
+ tooltip?: (props: TChartActivePayload) => unknown;
72
+ empty?: () => unknown;
73
+ }> & {
74
+ legend?: (props: {
75
+ series: Array<{
76
+ name: string;
77
+ color: string;
78
+ }>;
79
+ }) => unknown;
80
+ tooltip?: (props: TChartActivePayload) => unknown;
81
+ empty?: () => unknown;
82
+ };
83
+ refs: {
84
+ canvasRef: HTMLDivElement;
85
+ };
86
+ rootEl: HTMLDivElement;
87
+ };
88
+ type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
89
+ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
90
+ "point-click": (payload: TChartActivePayload) => any;
91
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
92
+ "onPoint-click"?: ((payload: TChartActivePayload) => any) | undefined;
93
+ }>, {
94
+ type: TChartType;
95
+ height: number;
96
+ loading: boolean;
97
+ smooth: boolean;
98
+ series: TChartSeries[];
99
+ labels: string[];
100
+ stacked: boolean;
101
+ showGrid: boolean;
102
+ showLegend: boolean;
103
+ showXAxis: boolean;
104
+ showYAxis: boolean;
105
+ showTooltip: boolean;
106
+ showPoints: boolean;
107
+ yTicks: number;
108
+ valueFormat: (value: number) => string;
109
+ minY: number;
110
+ maxY: number;
111
+ animated: boolean;
112
+ ariaLabel: string;
113
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
114
+ canvasRef: HTMLDivElement;
115
+ }, HTMLDivElement>;
116
+ declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
117
+ export default _default;
118
+ type __VLS_WithTemplateSlots<T, S> = T & {
119
+ new (): {
120
+ $slots: S;
121
+ };
122
+ };
123
+ //# sourceMappingURL=TChart.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TChart.vue.d.ts","sourceRoot":"","sources":["../../src/components/TChart.vue"],"names":[],"mappings":"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"}
@@ -0,0 +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;
2
+ //# sourceMappingURL=TChart.vue_vue_type_script_setup_true_lang.cjs.map
@@ -0,0 +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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"}