ui-thing 0.1.25 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.js +1088 -70
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/comps.ts +68 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui-thing",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "CLI used to add Nuxt 3 components to a project",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -41,15 +41,15 @@
|
|
|
41
41
|
"axios": "^1.7.7",
|
|
42
42
|
"boxen": "^8.0.1",
|
|
43
43
|
"build": "^0.1.4",
|
|
44
|
-
"c12": "^
|
|
44
|
+
"c12": "^2.0.0",
|
|
45
45
|
"commander": "^12.1.0",
|
|
46
46
|
"defu": "^6.1.4",
|
|
47
|
-
"execa": "^9.
|
|
47
|
+
"execa": "^9.4.0",
|
|
48
48
|
"figlet": "^1.7.0",
|
|
49
49
|
"fs-extra": "^11.2.0",
|
|
50
50
|
"kleur": "^4.1.5",
|
|
51
51
|
"lodash": "^4.17.21",
|
|
52
|
-
"nypm": "^0.3.
|
|
52
|
+
"nypm": "^0.3.12",
|
|
53
53
|
"ora": "^8.1.0",
|
|
54
54
|
"prompts": "^2.4.2"
|
|
55
55
|
},
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
|
|
59
59
|
"@types/figlet": "^1.5.8",
|
|
60
60
|
"@types/fs-extra": "^11.0.4",
|
|
61
|
-
"@types/lodash": "^4.17.
|
|
62
|
-
"@types/node": "^22.
|
|
61
|
+
"@types/lodash": "^4.17.10",
|
|
62
|
+
"@types/node": "^22.7.4",
|
|
63
63
|
"@types/prompts": "^2.4.9",
|
|
64
|
-
"@vitest/coverage-v8": "^2.1.
|
|
64
|
+
"@vitest/coverage-v8": "^2.1.2",
|
|
65
65
|
"magicast": "^0.3.5",
|
|
66
|
-
"tsup": "^8.
|
|
66
|
+
"tsup": "^8.3.0",
|
|
67
67
|
"typescript": "^5.6.2",
|
|
68
|
-
"vitest": "^2.1.
|
|
68
|
+
"vitest": "^2.1.2"
|
|
69
69
|
},
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
package/src/comps.ts
CHANGED
|
@@ -76,7 +76,7 @@ export default [
|
|
|
76
76
|
fileName: "shared.styles.ts",
|
|
77
77
|
dirPath: "utils",
|
|
78
78
|
fileContent:
|
|
79
|
-
'// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",\n variants: {\n variant: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",\n outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",\n secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n ghost: "hover:bg-accent hover:text-accent-foreground",\n link: "text-primary underline-offset-4 hover:underline",\n },\n size: {\n default: "h-10 px-4 py-2",\n sm: "h-9 rounded-md px-3",\n lg: "h-11 rounded-md px-8",\n "icon-sm": "h-9 w-9",\n icon: "h-10 w-10",\n },\n disabled: {\n true: "pointer-events-none opacity-50",\n },\n },\n defaultVariants: {\n variant: "default",\n size: "default",\n },\n});\n',
|
|
79
|
+
'// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",\n variants: {\n variant: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",\n outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",\n secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n ghost: "hover:bg-accent hover:text-accent-foreground",\n link: "text-primary underline-offset-4 hover:underline",\n },\n size: {\n default: "h-10 px-4 py-2",\n xs: "h-7 rounded px-2",\n sm: "h-9 rounded-md px-3",\n lg: "h-11 rounded-md px-8",\n "icon-sm": "h-9 w-9",\n icon: "h-10 w-10",\n },\n disabled: {\n true: "pointer-events-none opacity-50",\n },\n },\n defaultVariants: {\n variant: "default",\n size: "default",\n },\n});\n',
|
|
80
80
|
},
|
|
81
81
|
],
|
|
82
82
|
files: [
|
|
@@ -330,7 +330,7 @@ export default [
|
|
|
330
330
|
fileName: "shared.styles.ts",
|
|
331
331
|
dirPath: "utils",
|
|
332
332
|
fileContent:
|
|
333
|
-
'// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",\n variants: {\n variant: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",\n outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",\n secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n ghost: "hover:bg-accent hover:text-accent-foreground",\n link: "text-primary underline-offset-4 hover:underline",\n },\n size: {\n default: "h-10 px-4 py-2",\n sm: "h-9 rounded-md px-3",\n lg: "h-11 rounded-md px-8",\n "icon-sm": "h-9 w-9",\n icon: "h-10 w-10",\n },\n disabled: {\n true: "pointer-events-none opacity-50",\n },\n },\n defaultVariants: {\n variant: "default",\n size: "default",\n },\n});\n',
|
|
333
|
+
'// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",\n variants: {\n variant: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",\n outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",\n secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n ghost: "hover:bg-accent hover:text-accent-foreground",\n link: "text-primary underline-offset-4 hover:underline",\n },\n size: {\n default: "h-10 px-4 py-2",\n xs: "h-7 rounded px-2",\n sm: "h-9 rounded-md px-3",\n lg: "h-11 rounded-md px-8",\n "icon-sm": "h-9 w-9",\n icon: "h-10 w-10",\n },\n disabled: {\n true: "pointer-events-none opacity-50",\n },\n },\n defaultVariants: {\n variant: "default",\n size: "default",\n },\n});\n',
|
|
334
334
|
},
|
|
335
335
|
],
|
|
336
336
|
files: [
|
|
@@ -407,6 +407,72 @@ export default [
|
|
|
407
407
|
composables: [],
|
|
408
408
|
plugins: [],
|
|
409
409
|
},
|
|
410
|
+
{
|
|
411
|
+
name: "Chart",
|
|
412
|
+
value: "chart",
|
|
413
|
+
deps: ["@unovis/ts", "@unovis/vue"],
|
|
414
|
+
components: ["card"],
|
|
415
|
+
utils: [
|
|
416
|
+
{
|
|
417
|
+
fileName: "chart.ts",
|
|
418
|
+
dirPath: "utils",
|
|
419
|
+
fileContent:
|
|
420
|
+
"export function defaultColors(count: number = 3) {\n const quotient = Math.floor(count / 2);\n const remainder = count % 2;\n\n const primaryCount = quotient + remainder;\n const secondaryCount = quotient;\n return [\n ...Array.from(Array(primaryCount).keys()).map(\n (i) => `hsl(var(--vis-primary-color) / ${1 - (1 / primaryCount) * i})`\n ),\n ...Array.from(Array(secondaryCount).keys()).map(\n (i) => `hsl(var(--vis-secondary-color) / ${1 - (1 / secondaryCount) * i})`\n ),\n ];\n}\n",
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
files: [
|
|
424
|
+
{
|
|
425
|
+
fileName: "Chart/Area.vue",
|
|
426
|
+
dirPath: "components/UI",
|
|
427
|
+
fileContent:
|
|
428
|
+
'<template>\n <div :class="styles({ class: props.class })">\n <UiChartLegend\n v-if="showLegend"\n v-model:items="legendItems"\n @legend-item-click="handleLegendItemClick"\n />\n\n <VisXYContainer\n :style="{ height: isMounted ? \'100%\' : \'auto\' }"\n :margin="{ left: 20, right: 20 }"\n :data="data"\n >\n <svg width="0" height="0">\n <defs>\n <linearGradient\n v-for="(color, i) in colors"\n :id="`${chartRef}-color-${i}`"\n :key="i"\n x1="0"\n y1="0"\n x2="0"\n y2="1"\n >\n <template v-if="showGradiant">\n <stop offset="5%" :stop-color="color" stop-opacity="0.4" />\n <stop offset="95%" :stop-color="color" stop-opacity="0" />\n </template>\n <template v-else>\n <stop offset="0%" :stop-color="color" />\n </template>\n </linearGradient>\n </defs>\n </svg>\n\n <UiChartCrosshair\n v-if="showTooltip"\n :colors="colors"\n :items="legendItems"\n :index="index"\n :custom-tooltip="customTooltip"\n />\n\n <template v-for="(category, i) in categories" :key="category">\n <VisArea\n :x="(d: Data, i: number) => i"\n :y="(d: Data) => d[category]"\n color="auto"\n :curve-type="curveType"\n :attributes="{\n [Area.selectors.area]: {\n fill: `url(#${chartRef}-color-${i})`,\n },\n }"\n :opacity="\n legendItems.find((item) => item.name === category)?.inactive ? filterOpacity : 1\n "\n />\n </template>\n\n <template v-for="(category, i) in categories" :key="category">\n <VisLine\n :x="(d: Data, i: number) => i"\n :y="(d: Data) => d[category]"\n :color="colors[i]"\n :curve-type="curveType"\n :attributes="{\n [Line.selectors.line]: {\n opacity: legendItems.find((item) => item.name === category)?.inactive\n ? filterOpacity\n : 1,\n },\n }"\n />\n </template>\n\n <VisAxis\n v-if="showXAxis"\n type="x"\n :tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"\n :grid-line="false"\n :tick-line="false"\n tick-text-color="hsl(var(--vis-text-color))"\n />\n <VisAxis\n v-if="showYAxis"\n type="y"\n :tick-line="false"\n :tick-format="yFormatter"\n :domain-line="false"\n :grid-line="showGridLine"\n :attributes="{\n [Axis.selectors.grid]: {\n class: \'text-muted\',\n },\n }"\n tick-text-color="hsl(var(--vis-text-color))"\n />\n\n <slot />\n </VisXYContainer>\n </div>\n</template>\n\n<script lang="ts">\n import { Area, Axis, CurveType, Line } from "@unovis/ts";\n import { VisArea, VisAxis, VisLine, VisXYContainer } from "@unovis/vue";\n import type { BulletLegendItemInterface, Spacing } from "@unovis/ts";\n\n type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;\n\n export interface AreaChartProps<T extends Record<string, any>> {\n /**\n * The source data, in which each entry is a dictionary.\n */\n data: T[];\n /**\n * Select the categories from your data. Used to populate the legend and toolip.\n */\n categories: KeyOf<T>[];\n /**\n * Sets the key to map the data to the axis.\n */\n index: KeyOf<T>;\n /**\n * Change the default colors.\n */\n colors?: string[];\n /**\n * Margin of each the container\n */\n margin?: Spacing;\n /**\n * Change the opacity of the non-selected field\n * @default 0.2\n */\n filterOpacity?: number;\n /**\n * Function to format X label\n */\n xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;\n /**\n * Function to format Y label\n */\n yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;\n /**\n * Controls the visibility of the X axis.\n * @default true\n */\n showXAxis?: boolean;\n /**\n * Controls the visibility of the Y axis.\n * @default true\n */\n showYAxis?: boolean;\n /**\n * Controls the visibility of tooltip.\n * @default true\n */\n showTooltip?: boolean;\n /**\n * Controls the visibility of legend.\n * @default true\n */\n showLegend?: boolean;\n /**\n * Controls the visibility of gridline.\n * @default true\n */\n showGridLine?: boolean;\n }\n</script>\n\n<script setup lang="ts" generic="T extends Record<string, any>">\n const styles = tv({\n base: "flex h-[400px] w-full flex-col items-end",\n });\n\n const props = withDefaults(\n defineProps<\n AreaChartProps<T> & {\n /**\n * Render custom tooltip component.\n */\n customTooltip?: Component;\n /**\n * Type of curve\n */\n curveType?: CurveType;\n /**\n * Controls the visibility of gradient.\n * @default true\n */\n showGradiant?: boolean;\n /**\n * Additional class to be added to the container.\n */\n class?: any;\n }\n >(),\n {\n curveType: CurveType.MonotoneX,\n filterOpacity: 0.2,\n margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showLegend: true,\n showGridLine: true,\n showGradiant: true,\n }\n );\n\n const emits = defineEmits<{\n legendItemClick: [d: BulletLegendItemInterface, i: number];\n }>();\n\n type KeyOfT = Extract<keyof T, string>;\n type Data = (typeof props.data)[number];\n\n const chartRef = useId();\n\n const index = computed(() => props.index as KeyOfT);\n const colors = computed(() =>\n props.colors?.length ? props.colors : defaultColors(props.categories.length)\n );\n\n const legendItems = ref<BulletLegendItemInterface[]>(\n props.categories.map((category, i) => ({\n name: category,\n color: colors.value[i],\n inactive: false,\n }))\n );\n\n const isMounted = useMounted();\n\n function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {\n emits("legendItemClick", d, i);\n }\n</script>\n',
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
fileName: "Chart/Bar.vue",
|
|
432
|
+
dirPath: "components/UI",
|
|
433
|
+
fileContent:
|
|
434
|
+
'<template>\n <div :class="styles({ class: props.class })">\n <UiChartLegend\n v-if="showLegend"\n v-model:items="legendItems"\n @legend-item-click="handleLegendItemClick"\n />\n\n <VisXYContainer :data="data" :style="{ height: isMounted ? \'100%\' : \'auto\' }" :margin="margin">\n <UiChartCrosshair\n v-if="showTooltip"\n :colors="colors"\n :items="legendItems"\n :custom-tooltip="customTooltip"\n :index="index"\n />\n\n <VisBarComponent\n :x="(d: Data, i: number) => i"\n :y="categories.map((category) => (d: Data) => d[category])"\n :color="colors"\n :rounded-corners="roundedCorners"\n :bar-padding="0.05"\n :attributes="{\n [selectorsBar]: {\n opacity: (d: Data, i: number) => {\n const pos = i % categories.length;\n return legendItems[pos]?.inactive ? filterOpacity : 1;\n },\n },\n }"\n />\n\n <VisAxis\n v-if="showXAxis"\n type="x"\n :tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"\n :grid-line="false"\n :tick-line="false"\n tick-text-color="hsl(var(--vis-text-color))"\n />\n <VisAxis\n v-if="showYAxis"\n type="y"\n :tick-line="false"\n :tick-format="yFormatter"\n :domain-line="false"\n :grid-line="showGridLine"\n :attributes="{\n [Axis.selectors.grid]: {\n class: \'text-muted\',\n },\n }"\n tick-text-color="hsl(var(--vis-text-color))"\n />\n\n <slot />\n </VisXYContainer>\n </div>\n</template>\n\n<script lang="ts">\n import { Axis, GroupedBar, StackedBar } from "@unovis/ts";\n import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from "@unovis/vue";\n import type { BulletLegendItemInterface, Spacing } from "@unovis/ts";\n\n type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;\n\n export interface BarChartProps<T extends Record<string, any>> {\n /**\n * The source data, in which each entry is a dictionary.\n */\n data: T[];\n /**\n * Select the categories from your data. Used to populate the legend and toolip.\n */\n categories: KeyOf<T>[];\n /**\n * Sets the key to map the data to the axis.\n */\n index: KeyOf<T>;\n /**\n * Change the default colors.\n */\n colors?: string[];\n /**\n * Margin of each the container\n */\n margin?: Spacing;\n /**\n * Change the opacity of the non-selected field\n * @default 0.2\n */\n filterOpacity?: number;\n /**\n * Function to format X label\n */\n xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;\n /**\n * Function to format Y label\n */\n yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;\n /**\n * Controls the visibility of the X axis.\n * @default true\n */\n showXAxis?: boolean;\n /**\n * Controls the visibility of the Y axis.\n * @default true\n */\n showYAxis?: boolean;\n /**\n * Controls the visibility of tooltip.\n * @default true\n */\n showTooltip?: boolean;\n /**\n * Controls the visibility of legend.\n * @default true\n */\n showLegend?: boolean;\n /**\n * Controls the visibility of gridline.\n * @default true\n */\n showGridLine?: boolean;\n }\n</script>\n\n<script setup lang="ts" generic="T extends Record<string, any>">\n const styles = tv({\n base: "flex h-[400px] w-full flex-col items-end",\n });\n const props = withDefaults(\n defineProps<\n BarChartProps<T> & {\n /**\n * Render custom tooltip component.\n */\n customTooltip?: Component;\n /**\n * Change the type of the chart\n * @default "grouped"\n */\n type?: "stacked" | "grouped";\n /**\n * Rounded bar corners\n * @default 0\n */\n roundedCorners?: number;\n /**\n * Additional class to be added to the container\n */\n class?: any;\n }\n >(),\n {\n type: "grouped",\n margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),\n filterOpacity: 0.2,\n roundedCorners: 0,\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showLegend: true,\n showGridLine: true,\n }\n );\n const emits = defineEmits<{\n legendItemClick: [d: BulletLegendItemInterface, i: number];\n }>();\n\n type KeyOfT = Extract<keyof T, string>;\n type Data = (typeof props.data)[number];\n\n const index = computed(() => props.index as KeyOfT);\n const colors = computed(() =>\n props.colors?.length ? props.colors : defaultColors(props.categories.length)\n );\n const legendItems = ref<BulletLegendItemInterface[]>(\n props.categories.map((category, i) => ({\n name: category,\n color: colors.value[i],\n inactive: false,\n }))\n );\n\n const isMounted = useMounted();\n\n function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {\n emits("legendItemClick", d, i);\n }\n\n const VisBarComponent = computed(() =>\n props.type === "grouped" ? VisGroupedBar : VisStackedBar\n );\n const selectorsBar = computed(() =>\n props.type === "grouped" ? GroupedBar.selectors.bar : StackedBar.selectors.bar\n );\n</script>\n',
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
fileName: "Chart/Crosshair.vue",
|
|
438
|
+
dirPath: "components/UI",
|
|
439
|
+
fileContent:
|
|
440
|
+
'<template>\n <VisTooltip :horizontal-shift="20" :vertical-shift="20" />\n <VisCrosshair :template="template" :color="color" />\n</template>\n\n<script setup lang="ts">\n import { omit } from "@unovis/ts";\n import { VisCrosshair, VisTooltip } from "@unovis/vue";\n import { UiChartTooltip } from "#components";\n import { createApp } from "vue";\n import type { BulletLegendItemInterface } from "@unovis/ts";\n\n const props = withDefaults(\n defineProps<{\n colors: string[];\n index: string;\n items: BulletLegendItemInterface[];\n customTooltip?: Component;\n }>(),\n {\n colors: () => [],\n }\n );\n\n // Use weakmap to store reference to each datapoint for Tooltip\n const wm = new WeakMap();\n function template(d: any) {\n if (wm.has(d)) {\n return wm.get(d);\n } else {\n const componentDiv = document.createElement("div");\n const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {\n const legendReference = props.items.find((i) => i.name === key);\n return { ...legendReference, value };\n });\n const TooltipComponent = props.customTooltip ?? UiChartTooltip;\n createApp(TooltipComponent, { title: d[props.index].toString(), data: omittedData }).mount(\n componentDiv\n );\n wm.set(d, componentDiv.innerHTML);\n return componentDiv.innerHTML;\n }\n }\n\n function color(d: unknown, i: number) {\n return props.colors[i] ?? "transparent";\n }\n</script>\n',
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
fileName: "Chart/Donut.vue",
|
|
444
|
+
dirPath: "components/UI",
|
|
445
|
+
fileContent:
|
|
446
|
+
'<template>\n <div :class="styles({ class: props.class })">\n <VisSingleContainer\n :style="{ height: isMounted ? \'100%\' : \'auto\' }"\n :margin="{ left: 20, right: 20 }"\n :data="data"\n >\n <UiChartSingleTooltip\n :selector="Donut.selectors.segment"\n :index="category"\n :items="legendItems"\n :value-formatter="valueFormatter"\n :custom-tooltip="customTooltip"\n />\n\n <VisDonut\n :value="(d: Data) => d[category]"\n :sort-function="sortFunction"\n :color="colors"\n :arc-width="type === \'donut\' ? 20 : 0"\n :show-background="false"\n :central-label="type === \'donut\' ? valueFormatter(totalValue) : \'\'"\n :events="{\n [Donut.selectors.segment]: {\n click: (d: Data, ev: PointerEvent, i: number, elements: HTMLElement[]) => {\n if (d?.data?.[index] === activeSegmentKey) {\n activeSegmentKey = undefined;\n elements.forEach((el) => (el.style.opacity = \'1\'));\n } else {\n activeSegmentKey = d?.data?.[index];\n elements.forEach((el) => (el.style.opacity = `${filterOpacity}`));\n elements[i].style.opacity = \'1\';\n }\n },\n },\n }"\n />\n\n <slot />\n </VisSingleContainer>\n </div>\n</template>\n\n<script lang="ts">\n import { Donut } from "@unovis/ts";\n import { VisDonut, VisSingleContainer } from "@unovis/vue";\n import type { Spacing } from "@unovis/ts";\n\n type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;\n\n export interface DonutChartProps<T extends Record<string, any>> {\n /**\n * The source data, in which each entry is a dictionary.\n */\n data: T[];\n /**\n * Sets the key to map the data to the axis.\n */\n index: KeyOf<T>;\n /**\n * Change the default colors.\n */\n colors?: string[];\n /**\n * Margin of each the container\n */\n margin?: Spacing;\n /**\n * Change the opacity of the non-selected field\n * @default 0.2\n */\n filterOpacity?: number;\n /**\n * Controls the visibility of tooltip.\n * @default true\n */\n showTooltip?: boolean;\n /**\n * Controls the visibility of legend.\n * @default true\n */\n showLegend?: boolean;\n }\n</script>\n<script setup lang="ts" generic="T extends Record<string, any>">\n const styles = tv({\n base: "flex h-48 w-full flex-col items-end",\n });\n const props = withDefaults(\n defineProps<\n Pick<\n DonutChartProps<T>,\n "data" | "colors" | "index" | "margin" | "showLegend" | "showTooltip" | "filterOpacity"\n > & {\n /**\n * Sets the name of the key containing the quantitative chart values.\n */\n category: KeyOfT;\n /**\n * Change the type of the chart\n * @default "donut"\n */\n type?: "donut" | "pie";\n /**\n * Function to sort the segment\n */\n sortFunction?: (a: any, b: any) => number | undefined;\n /**\n * Controls the formatting for the label.\n */\n valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string;\n /**\n * Render custom tooltip component.\n */\n customTooltip?: Component;\n /**\n * Custom class\n */\n class?: any;\n }\n >(),\n {\n margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),\n sortFunction: () => undefined,\n valueFormatter: (tick: number) => `${tick}`,\n type: "donut",\n filterOpacity: 0.2,\n showTooltip: true,\n showLegend: true,\n }\n );\n\n type KeyOfT = Extract<keyof T, string>;\n type Data = (typeof props.data)[number];\n\n const category = computed(() => props.category as KeyOfT);\n const index = computed(() => props.index as KeyOfT);\n\n const isMounted = useMounted();\n const activeSegmentKey = ref<string>();\n const colors = computed(() =>\n props.colors?.length\n ? props.colors\n : defaultColors(props.data.filter((d) => d[props.category]).filter(Boolean).length)\n );\n const legendItems = computed(() =>\n props.data.map((item, i) => ({\n name: item[props.index],\n color: colors.value[i],\n inactive: false,\n }))\n );\n\n const totalValue = computed(() =>\n props.data.reduce((prev, curr) => {\n return prev + curr[props.category];\n }, 0)\n );\n</script>\n',
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
fileName: "Chart/Legend.vue",
|
|
450
|
+
dirPath: "components/UI",
|
|
451
|
+
fileContent:
|
|
452
|
+
'<template>\n <div ref="elRef" class="w-max">\n <VisBulletLegend :items="items" :on-legend-item-click="onLegendItemClick" />\n </div>\n</template>\n\n<script setup lang="ts">\n import { BulletLegend } from "@unovis/ts";\n import { VisBulletLegend } from "@unovis/vue";\n import type { BulletLegendItemInterface } from "@unovis/ts";\n\n const props = withDefaults(defineProps<{ items: BulletLegendItemInterface[] }>(), {\n items: () => [],\n });\n\n const emits = defineEmits<{\n legendItemClick: [d: BulletLegendItemInterface, i: number];\n "update:items": [payload: BulletLegendItemInterface[]];\n }>();\n\n const elRef = ref<HTMLElement>();\n\n onMounted(() => {\n const selector = `.${BulletLegend.selectors.item}`;\n nextTick(() => {\n const elements = elRef.value?.querySelectorAll(selector);\n const classes = buttonStyles({ variant: "ghost", size: "xs" }).split(" ");\n elements?.forEach((el) => el.classList.add(...classes, "!inline-flex", "!mr-2"));\n });\n });\n\n function onLegendItemClick(d: BulletLegendItemInterface, i: number) {\n emits("legendItemClick", d, i);\n const isBulletActive = !props.items[i].inactive;\n const isFilterApplied = props.items.some((i) => i.inactive);\n if (isFilterApplied && isBulletActive) {\n // reset filter\n emits(\n "update:items",\n props.items.map((item) => ({ ...item, inactive: false }))\n );\n } else {\n // apply selection, set other item as inactive\n emits(\n "update:items",\n props.items.map((item) =>\n item.name === d.name ? { ...d, inactive: false } : { ...item, inactive: true }\n )\n );\n }\n }\n</script>\n',
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
fileName: "Chart/Line.vue",
|
|
456
|
+
dirPath: "components/UI",
|
|
457
|
+
fileContent:
|
|
458
|
+
'<template>\n <div :class="styles({ class: props.class })">\n <UiChartLegend\n v-if="showLegend"\n v-model:items="legendItems"\n @legend-item-click="handleLegendItemClick"\n />\n\n <VisXYContainer\n :margin="{ left: 20, right: 20 }"\n :data="data"\n :style="{ height: isMounted ? \'100%\' : \'auto\' }"\n >\n <UiChartCrosshair\n v-if="showTooltip"\n :colors="colors"\n :items="legendItems"\n :index="index"\n :custom-tooltip="customTooltip"\n />\n\n <template v-for="(category, i) in categories" :key="category">\n <VisLine\n :x="(d: Data, i: number) => i"\n :y="(d: Data) => d[category]"\n :curve-type="curveType"\n :color="colors[i]"\n :attributes="{\n [Line.selectors.line]: {\n opacity: legendItems.find((item) => item.name === category)?.inactive\n ? filterOpacity\n : 1,\n },\n }"\n />\n </template>\n\n <VisAxis\n v-if="showXAxis"\n type="x"\n :tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"\n :grid-line="false"\n :tick-line="false"\n tick-text-color="hsl(var(--vis-text-color))"\n />\n <VisAxis\n v-if="showYAxis"\n type="y"\n :tick-line="false"\n :tick-format="yFormatter"\n :domain-line="false"\n :grid-line="showGridLine"\n :attributes="{\n [Axis.selectors.grid]: {\n class: \'text-muted\',\n },\n }"\n tick-text-color="hsl(var(--vis-text-color))"\n />\n\n <slot />\n </VisXYContainer>\n </div>\n</template>\n\n<script lang="ts">\n import { Axis, CurveType, Line } from "@unovis/ts";\n import { VisAxis, VisLine, VisXYContainer } from "@unovis/vue";\n import type { BulletLegendItemInterface, Spacing } from "@unovis/ts";\n\n type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;\n\n export interface LineChartProps<T extends Record<string, any>> {\n /**\n * The source data, in which each entry is a dictionary.\n */\n data: T[];\n /**\n * Select the categories from your data. Used to populate the legend and toolip.\n */\n categories: KeyOf<T>[];\n /**\n * Sets the key to map the data to the axis.\n */\n index: KeyOf<T>;\n /**\n * Change the default colors.\n */\n colors?: string[];\n /**\n * Margin of each the container\n */\n margin?: Spacing;\n /**\n * Change the opacity of the non-selected field\n * @default 0.2\n */\n filterOpacity?: number;\n /**\n * Function to format X label\n */\n xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;\n /**\n * Function to format Y label\n */\n yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;\n /**\n * Controls the visibility of the X axis.\n * @default true\n */\n showXAxis?: boolean;\n /**\n * Controls the visibility of the Y axis.\n * @default true\n */\n showYAxis?: boolean;\n /**\n * Controls the visibility of tooltip.\n * @default true\n */\n showTooltip?: boolean;\n /**\n * Controls the visibility of legend.\n * @default true\n */\n showLegend?: boolean;\n /**\n * Controls the visibility of gridline.\n * @default true\n */\n showGridLine?: boolean;\n }\n</script>\n\n<script setup lang="ts" generic="T extends Record<string, any>">\n const styles = tv({\n base: "flex h-[400px] w-full flex-col items-end",\n });\n const props = withDefaults(\n defineProps<\n LineChartProps<T> & {\n /**\n * Render custom tooltip component.\n */\n customTooltip?: Component;\n /**\n * Type of curve\n */\n curveType?: CurveType;\n /**\n * Additional class to be added to the container.\n */\n class?: any;\n }\n >(),\n {\n curveType: CurveType.MonotoneX,\n filterOpacity: 0.2,\n margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),\n showXAxis: true,\n showYAxis: true,\n showTooltip: true,\n showLegend: true,\n showGridLine: true,\n }\n );\n\n const emits = defineEmits<{\n legendItemClick: [d: BulletLegendItemInterface, i: number];\n }>();\n\n type KeyOfT = Extract<keyof T, string>;\n type Data = (typeof props.data)[number];\n\n const index = computed(() => props.index as KeyOfT);\n const colors = computed(() =>\n props.colors?.length ? props.colors : defaultColors(props.categories.length)\n );\n\n const legendItems = ref<BulletLegendItemInterface[]>(\n props.categories.map((category, i) => ({\n name: category,\n color: colors.value[i],\n inactive: false,\n }))\n );\n\n const isMounted = useMounted();\n\n function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {\n emits("legendItemClick", d, i);\n }\n</script>\n',
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
fileName: "Chart/SingleTooltip.vue",
|
|
462
|
+
dirPath: "components/UI",
|
|
463
|
+
fileContent:
|
|
464
|
+
'<template>\n <VisTooltip\n :horizontal-shift="20"\n :vertical-shift="20"\n :triggers="{\n [selector]: template,\n }"\n />\n</template>\n<script setup lang="ts">\n import { omit } from "@unovis/ts";\n import { VisTooltip } from "@unovis/vue";\n import { UiChartTooltip } from "#components";\n import { createApp } from "vue";\n import type { BulletLegendItemInterface } from "@unovis/ts";\n\n const props = withDefaults(\n defineProps<{\n selector: string;\n index: string;\n items?: BulletLegendItemInterface[];\n valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string;\n customTooltip?: Component;\n }>(),\n {\n valueFormatter: (tick: number) => `${tick}`,\n }\n );\n\n // Use weakmap to store reference to each datapoint for Tooltip\n const wm = new WeakMap();\n function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {\n if (props.index in d) {\n if (wm.has(d)) {\n return wm.get(d);\n } else {\n const componentDiv = document.createElement("div");\n const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {\n const legendReference = props.items?.find((i) => i.name === key);\n return { ...legendReference, value: props.valueFormatter(value) };\n });\n const TooltipComponent = props.customTooltip ?? UiChartTooltip;\n createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(\n componentDiv\n );\n wm.set(d, componentDiv.innerHTML);\n return componentDiv.innerHTML;\n }\n } else {\n const data = d.data;\n\n if (wm.has(data)) {\n return wm.get(data);\n } else {\n const style = getComputedStyle(elements[i]);\n const omittedData = [\n { name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill },\n ];\n const componentDiv = document.createElement("div");\n const TooltipComponent = props.customTooltip ?? UiChartTooltip;\n createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(\n componentDiv\n );\n wm.set(d, componentDiv.innerHTML);\n return componentDiv.innerHTML;\n }\n }\n }\n</script>\n',
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
fileName: "Chart/Tooltip.vue",
|
|
468
|
+
dirPath: "components/UI",
|
|
469
|
+
fileContent:
|
|
470
|
+
'<template>\n <UiCard class="text-sm">\n <UiCardHeader v-if="title" class="border-b p-3">\n <UiCardTitle>\n {{ title }}\n </UiCardTitle>\n </UiCardHeader>\n <UiCardContent class="flex min-w-[180px] flex-col gap-1 !p-3">\n <div v-for="(item, key) in data" :key="key" class="flex justify-between">\n <div class="flex items-center">\n <span class="mr-2 h-2.5 w-2.5">\n <svg width="100%" height="100%" viewBox="0 0 30 30">\n <path\n d=" M 15 15 m -14, 0 a 14,14 0 1,1 28,0 a 14,14 0 1,1 -28,0"\n :stroke="item.color"\n :fill="item.color"\n stroke-width="1"\n />\n </svg>\n </span>\n <span>{{ item.name }}</span>\n </div>\n <span class="ml-4 font-semibold">{{ item.value }}</span>\n </div>\n </UiCardContent>\n </UiCard>\n</template>\n\n<script setup lang="ts">\n defineProps<{\n title?: string;\n data: {\n name: string;\n color: string;\n value: any;\n }[];\n }>();\n</script>\n',
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
composables: [],
|
|
474
|
+
plugins: [],
|
|
475
|
+
},
|
|
410
476
|
{
|
|
411
477
|
name: "Checkbox",
|
|
412
478
|
value: "checkbox",
|