Teren-app/resources/js/Components/ui/chart/ChartAutoLegend.vue

81 lines
2.6 KiB
Vue

<script setup>
import { computed, ref } from 'vue'
import { useChartContext } from './interface'
const props = defineProps({
order: { type: Array, required: false }, // explicit ordering of keys
modelValue: { type: Array, required: false }, // deprecated alias
activeKeys: { type: Array, required: false }, // v-model:activeKeys target
class: { type: [String, Array, Object], required: false },
})
const emit = defineEmits(['update:activeKeys'])
const { config } = useChartContext()
// Derive ordered keys from config
const allKeys = computed(() => {
const keys = Object.keys(config)
if (props.order && props.order.length) {
return props.order.filter(k => keys.includes(k))
}
return keys
})
// Internal active state (if parent not controlling)
const internalActive = ref(allKeys.value.reduce((acc, k) => { acc[k] = true; return acc }, {}))
const activeMap = computed(() => {
// If parent passes controlled array use that
if (props.activeKeys && props.activeKeys.length) {
return props.activeKeys.reduce((acc, k) => { acc[k] = true; return acc }, {})
}
return internalActive.value
})
const items = computed(() => allKeys.value.map(k => {
const series = config[k] || {}
const color = series.color || (series.theme && (series.theme.light || series.theme.dark)) || 'var(--foreground)'
return { key: k, label: series.label || k, color, active: !!activeMap.value[k] }
}))
function toggle(key) {
// controlled mode
if (props.activeKeys) {
const next = items.value.filter(i => i.key === key ? !i.active : i.active).map(i => i.key)
// If item was active we remove it, else add it
const wasActive = activeMap.value[key]
const result = wasActive
? props.activeKeys.filter(k => k !== key)
: [...props.activeKeys, key]
emit('update:activeKeys', result)
return
}
// uncontrolled mode
internalActive.value[key] = !internalActive.value[key]
const result = Object.entries(internalActive.value).filter(([, v]) => v).map(([k]) => k)
emit('update:activeKeys', result)
}
</script>
<template>
<div :class="['flex items-center justify-center flex-wrap gap-4 text-xs select-none', props.class]">
<button
v-for="item in items"
:key="item.key"
type="button"
:class="[
'flex items-center gap-2 transition-colors',
item.active ? 'opacity-100' : 'opacity-40',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm'
]"
@click="toggle(item.key)"
>
<span class="h-2.5 w-2.5 rounded-[3px] border border-border" :style="{ background: item.color }" />
<span>{{ item.label }}</span>
</button>
</div>
</template>
<style scoped></style>