/** * 可排序卡片列表的折叠状态:所有带展开区的卡片默认收起,点击行头展开/收起。 * * 状态按行的稳定 key 记录(而不是下标),拖拽换位后每张卡片保持自己的开合状态。 * 行头属性统一由 collapseHeadAttrs 生成:可点击、可键盘操作(Enter / Space)、 * 带 aria-expanded,样式见 styles/sortable-list.css。 */ import { ref } from 'vue' export function collapseHeadAttrs(open, toggle) { return { class: 'is-clickable', role: 'button', tabindex: 0, 'aria-expanded': open ? 'true' : 'false', onClick: toggle, onKeydown: (event) => { // 只响应行头本身的按键,行内按钮 / 输入框的 Enter、空格不触发折叠。 if (event.target !== event.currentTarget) return if (event.key !== 'Enter' && event.key !== ' ') return event.preventDefault() toggle() }, } } export function useCollapsibleItems() { const openKeys = ref(new Set()) function isOpen(key) { return openKeys.value.has(key) } function toggle(key) { const next = new Set(openKeys.value) if (next.has(key)) next.delete(key) else next.add(key) openKeys.value = next } function headAttrs(key) { return collapseHeadAttrs(isOpen(key), () => toggle(key)) } return { isOpen, toggle, headAttrs } }