@sparklingopinions/sparkling-ui 0.12.0 → 0.13.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.
- package/dist/aliases.d.ts +1 -0
- package/dist/components/DataList/DataList.js.map +1 -1
- package/dist/components/DataList/DataList.vue.d.ts +2 -0
- package/dist/components/DataList/DataList.vue_vue_type_script_setup_true_lang.js +139 -109
- package/dist/components/DataList/DataList.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/package.json +1 -1
package/dist/aliases.d.ts
CHANGED
|
@@ -212,6 +212,7 @@ export declare const List: <T extends Record<string, any>>(__VLS_props: NonNulla
|
|
|
212
212
|
selectable?: boolean | undefined;
|
|
213
213
|
checkboxPlacement?: "gutter" | "leading" | undefined;
|
|
214
214
|
loading?: boolean | undefined;
|
|
215
|
+
loadingGroups?: number[] | undefined;
|
|
215
216
|
variant?: "joined" | "cards" | undefined;
|
|
216
217
|
headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
|
|
217
218
|
groupHeaderTone?: "sunken" | "surface" | "canvas" | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataList.js","names":["_sfc_main","DataList_vue_vue_type_script_setup_true_lang_default","DataList_default"],"sources":["../../../src/components/DataList/DataList.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed, useId, useTemplateRef } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport ContextMenu from '../ContextMenu/ContextMenu.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { DropdownMenuAction, DropdownMenuEntry } from '../internal/menu'\nimport type { DataListGroup } from './types'\n\nexport interface DataListProps<T> {\n groups: DataListGroup<T>[]\n /** The item field that identifies it. An item's `depth` indents it as a child. */\n rowKey?: keyof T & string\n /** A checkbox bound to `v-model:selected`: it shows on hover and focus, and on every row once anything is selected.\n * Shift-click (or Shift+Space) selects a range, Cmd or Ctrl-click toggles one row, Shift+↑ ↓ extends. */\n selectable?: boolean\n /** gutter: the checkbox in its own column. leading: it takes the place of the `leading` slot's first mark. */\n checkboxPlacement?: 'gutter' | 'leading'\n loading?: boolean\n /** joined: one frame, sticky sunken group headers. cards: each group its own card, 12px apart, headers not sticky. */\n variant?: 'joined' | 'cards'\n /** The group headings' level, to fit the page's outline. */\n headingLevel?: 2 | 3 | 4 | 5 | 6\n /** The group headers' ground; by default sunken when joined, surface as cards. */\n groupHeaderTone?: 'sunken' | 'surface' | 'canvas'\n /** The group headers' height in px (36 by default); sets `--sui-list-header`. */\n groupHeaderHeight?: number\n /** Groups fold away under a chevron; a group's own `collapsible` wins. */\n collapsible?: boolean\n /** The rows' height in px, such as 44 (40 by default); sets `--sui-list-row`. */\n rowHeight?: number\n /** A hairline between rows. */\n dividers?: boolean\n /** Wraps each row in a ContextMenu of these items (`@context-item`); return [] for none. */\n contextItems?: (item: T) => DropdownMenuEntry[]\n /** The context menu's accessible name. */\n contextLabel?: string\n /** Makes rows open on click and Enter (`@row-click`). */\n onRowClick?: (item: T) => void\n /** Adds a + to each group's header (`@new`). */\n onNew?: (group: DataListGroup<T>) => void\n /** The + button's name; `{group}` is the group's name. */\n newLabel?: string\n collapseLabel?: string\n expandLabel?: string\n selectLabel?: string\n}\n\nconst props = withDefaults(defineProps<DataListProps<T>>(), {\n rowKey: 'id' as never,\n variant: 'joined',\n checkboxPlacement: 'gutter',\n headingLevel: 3,\n groupHeaderTone: undefined,\n groupHeaderHeight: undefined,\n collapsible: true,\n rowHeight: undefined,\n dividers: false,\n contextItems: undefined,\n contextLabel: undefined,\n onRowClick: undefined,\n onNew: undefined,\n newLabel: 'New in {group}',\n collapseLabel: 'Collapse group',\n expandLabel: 'Expand group',\n selectLabel: 'Select'\n})\n\nconst emit = defineEmits<{ 'context-item': [action: DropdownMenuAction, item: T] }>()\n\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\nconst collapsed = defineModel<string[]>('collapsed', { default: () => [] })\n\nconst slots = defineSlots<{\n /** Marks before a group's name, e.g. a status icon. */\n 'group-leading'?: (props: { group: DataListGroup<T> }) => unknown\n /** Your own group header in place of the name and count, e.g. a status Badge and a count; inside the heading. */\n 'group-header'?: (props: { group: DataListGroup<T>; count: number; collapsed: boolean }) => unknown\n /** Small marks before an item's title: a status icon, an id, an avatar. With `checkboxPlacement=\"leading\"`, the\n * first mark gives way to the checkbox. */\n leading?: (props: { item: T; selected: boolean; selecting: boolean; toggle: () => void }) => unknown\n /** The item's title; `item.name` by default. */\n title?: (props: { item: T }) => unknown\n /** Right-aligned meta: tags, an avatar, a date. Keep it to three or four things. */\n meta?: (props: { item: T }) => unknown\n /** Controls at the end of a group's header, e.g. Show and Hide. */\n 'group-actions'?: (props: { group: DataListGroup<T> }) => unknown\n /** Shown when every group is empty, e.g. an EmptyState. */\n empty?: () => unknown\n}>()\n\nconst id = useId()\nconst root = useTemplateRef<HTMLElement>('root')\n\nconst idOf = (item: T): unknown => item[props.rowKey ?? 'id']\nconst interactive = computed(() => !!props.onRowClick || props.selectable)\nconst isEmpty = computed(() => !props.loading && props.groups.every((group) => group.items.length === 0))\n\nfunction toggleGroup(groupId: string) {\n collapsed.value = collapsed.value.includes(groupId)\n ? collapsed.value.filter((x) => x !== groupId)\n : [...collapsed.value, groupId]\n}\n\nconst collapsibleGroup = (group: DataListGroup<T>) => group.collapsible ?? props.collapsible\nconst isCollapsed = (group: DataListGroup<T>) => collapsibleGroup(group) && collapsed.value.includes(group.id)\nconst visibleItems = computed(() => props.groups.filter((group) => !isCollapsed(group)).flatMap((group) => group.items))\n\n// Where a range starts: the row last toggled.\nlet anchorKey: unknown = undefined\n\nfunction toggle(item: T) {\n const key = idOf(item)\n anchorKey = key\n selected.value = selected.value.includes(key) ? selected.value.filter((x) => x !== key) : [...selected.value, key]\n}\n\nfunction selectRange(item: T) {\n const keys = visibleItems.value.map(idOf)\n const to = keys.indexOf(idOf(item))\n const from = keys.indexOf(anchorKey)\n const span = from < 0 ? [keys[to]] : keys.slice(Math.min(from, to), Math.max(from, to) + 1)\n if (from < 0) anchorKey = idOf(item)\n selected.value = [...selected.value, ...span.filter((key) => !selected.value.includes(key))]\n}\n\nfunction select(...items: T[]) {\n const keys = items.map(idOf).filter((key) => !selected.value.includes(key))\n if (keys.length) selected.value = [...selected.value, ...new Set(keys)]\n}\n\nfunction clickRow(event: MouseEvent, item: T) {\n if (props.selectable && event.shiftKey) selectRange(item)\n else if (props.selectable && (event.metaKey || event.ctrlKey)) toggle(item)\n // Leading checkboxes stand in for the row's mark, so while selecting a click selects, as in a mail list.\n else if (props.selectable && leading.value && selected.value.length) toggle(item)\n else props.onRowClick?.(item)\n}\n\n// A shift-click selects rather than highlighting the text between.\nfunction onRowMousedown(event: MouseEvent) {\n if (props.selectable && event.shiftKey) event.preventDefault()\n}\n\n// ↑ ↓ or j k move between rows, x selects, Enter and Space open; with Shift, ↑ ↓ extend the selection and Space\n// selects a range.\nfunction onKeydown(event: KeyboardEvent, item: T) {\n if (event.target !== event.currentTarget || event.metaKey || event.ctrlKey || event.altKey) return\n // A collapsed group's rows are still in the DOM, hidden.\n const rows = [...(root.value?.querySelectorAll<HTMLElement>('[data-list-row]') ?? [])].filter(\n (row) => row.closest('ul')?.style.display !== 'none'\n )\n const i = rows.indexOf(event.currentTarget as HTMLElement)\n const down = event.key === 'ArrowDown' || event.key === 'j'\n const up = event.key === 'ArrowUp' || event.key === 'k'\n if ((down || up) && event.shiftKey && props.selectable) {\n const j = down ? Math.min(rows.length - 1, i + 1) : Math.max(0, i - 1)\n const next = visibleItems.value[j]\n select(item, ...(next ? [next] : []))\n rows[j]?.focus()\n } else if (down) rows[Math.min(rows.length - 1, i + 1)]?.focus()\n else if (up) rows[Math.max(0, i - 1)]?.focus()\n else if (event.key === ' ' && event.shiftKey && props.selectable) selectRange(item)\n else if (event.key.toLowerCase() === 'x' && props.selectable) toggle(item)\n else if ((event.key === 'Enter' || event.key === ' ') && props.onRowClick) props.onRowClick(item)\n else return\n event.preventDefault()\n}\n\nconst cards = computed(() => props.variant === 'cards')\nconst leading = computed(() => props.selectable && props.checkboxPlacement === 'leading')\nconst gutter = computed(() => props.selectable && props.checkboxPlacement === 'gutter')\nconst tones = { sunken: 'bg-sui-sunken', surface: 'bg-sui-surface', canvas: 'bg-sui-canvas' }\nconst headerTone = computed(() => tones[props.groupHeaderTone ?? (cards.value ? 'surface' : 'sunken')])\nconst sizes = computed(() => {\n const style: Record<string, string> = {}\n if (props.rowHeight !== undefined) style['--sui-list-row'] = `${props.rowHeight}px`\n if (props.groupHeaderHeight !== undefined) style['--sui-list-header'] = `${props.groupHeaderHeight}px`\n return Object.keys(style).length ? style : undefined\n})\nconst card = 'overflow-clip rounded-xl border border-sui-line-subtle bg-sui-surface'\nconst custom = (group: DataListGroup<T>) => !!slots['group-header'] || group.header !== undefined\nconst groupName = (group: DataListGroup<T>) => group.label ?? group.name ?? ''\n\nconst skeletonWidths = ['42%', '58%', '35%', '50%', '46%']\nconst iconButton =\n 'flex size-6 shrink-0 items-center justify-center rounded-md text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-line-subtle hover:text-sui-ink focus-visible:sui-ring-inset'\n</script>\n\n<!-- A grouped list: one dense line per record under sticky, collapsible group headers. -->\n<template>\n <div ref=\"root\" class=\"flex flex-col text-13 text-sui-ink\" :class=\"cards ? 'gap-3' : card\" :style=\"sizes\">\n <div v-if=\"isEmpty && $slots.empty\" :class=\"cards && card\">\n <slot name=\"empty\" />\n </div>\n <section v-else-if=\"loading\" :aria-busy=\"true\" :class=\"cards && card\">\n <div\n v-for=\"(width, i) in skeletonWidths\"\n :key=\"i\"\n aria-hidden=\"true\"\n class=\"flex h-[var(--sui-list-row,2.5rem)] items-center gap-2.5 pr-4 pl-1\"\n >\n <span class=\"w-6 shrink-0\" />\n <Skeleton height=\"0.75rem\" :width=\"width\" />\n <span class=\"flex-1\" />\n <Skeleton height=\"0.75rem\" width=\"64px\" />\n </div>\n </section>\n <template v-else>\n <section\n v-for=\"group in groups\"\n :key=\"group.id\"\n :aria-label=\"group.label\"\n :aria-labelledby=\"!group.label && (group.name || custom(group)) ? `${id}-${group.id}-name` : undefined\"\n :class=\"cards ? card : 'border-t border-sui-line-subtle first:border-t-0'\"\n >\n <header\n v-if=\"group.name || custom(group)\"\n class=\"flex h-[var(--sui-list-header,2.25rem)] items-center gap-2 border-b border-sui-line-subtle pr-2\"\n :class=\"[headerTone, !cards && 'sticky top-0 z-10', collapsibleGroup(group) ? 'pl-1.5' : 'pl-4']\"\n >\n <button\n v-if=\"collapsibleGroup(group)\"\n :aria-controls=\"`${id}-${group.id}`\"\n :aria-expanded=\"!collapsed.includes(group.id)\"\n :aria-label=\"collapsed.includes(group.id) ? expandLabel : collapseLabel\"\n :class=\"iconButton\"\n type=\"button\"\n @click=\"toggleGroup(group.id)\"\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3 fill-none stroke-current transition-transform duration-150\"\n :class=\"isCollapsed(group) && '-rotate-90'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path d=\"M3 4.5 6 7.5l3-3\" />\n </svg>\n </button>\n <component\n :is=\"`h${headingLevel}`\"\n v-if=\"custom(group)\"\n :id=\"`${id}-${group.id}-name`\"\n class=\"m-0 flex min-w-0 items-center gap-2 text-13 font-medium text-sui-ink\"\n >\n <slot\n :collapsed=\"collapsed.includes(group.id)\"\n :count=\"group.count ?? group.items.length\"\n :group=\"group\"\n name=\"group-header\"\n >{{ group.header }}</slot\n >\n </component>\n <template v-else>\n <slot :group=\"group\" name=\"group-leading\" />\n <component\n :is=\"`h${headingLevel}`\"\n :id=\"`${id}-${group.id}-name`\"\n class=\"m-0 text-13 font-medium text-sui-ink\"\n >\n {{ group.name }}\n </component>\n <span class=\"text-13 text-sui-ink-muted tabular-nums\">{{ group.count ?? group.items.length }}</span>\n </template>\n <span class=\"ml-auto flex items-center gap-1\">\n <slot :group=\"group\" name=\"group-actions\" />\n </span>\n <button\n v-if=\"onNew\"\n :aria-label=\"newLabel.replace('{group}', groupName(group))\"\n :class=\"iconButton\"\n type=\"button\"\n @click=\"onNew(group)\"\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 14 14\"\n >\n <path d=\"M7 2.5v9M2.5 7h9\" />\n </svg>\n </button>\n </header>\n <ul v-show=\"!isCollapsed(group)\" :id=\"`${id}-${group.id}`\" class=\"m-0 list-none p-0\">\n <ContextMenu\n v-for=\"item in group.items\"\n :key=\"idOf(item) as PropertyKey\"\n :disabled=\"!contextItems\"\n :items=\"contextItems?.(item)\"\n :label=\"contextLabel\"\n @click-item=\"emit('context-item', $event, item)\"\n >\n <li\n class=\"group/row relative flex h-[var(--sui-list-row,2.5rem)] items-center transition-colors duration-100 has-focus-visible:sui-ring-inset\"\n :class=\"[\n dividers && '[&+&]:border-t [&+&]:border-sui-line-subtle',\n selected.includes(idOf(item))\n ? 'bg-sui-accent-wash'\n : 'hover:bg-sui-sunken has-focus-visible:bg-sui-sunken'\n ]\"\n :style=\"item.depth ? { paddingLeft: `${item.depth * 22}px` } : undefined\"\n >\n <!-- Outside the row, which is a button, over the leading slot's first mark: 16px in, or more for a child. -->\n <span\n v-if=\"leading\"\n class=\"absolute top-1/2 z-[1] flex size-4 -translate-y-1/2 items-center justify-center\"\n :class=\"!selected.length && 'hidden group-hover/row:flex group-has-focus-visible/row:flex'\"\n data-list-check\n :style=\"{ left: `${16 + (item.depth ?? 0) * 22}px` }\"\n >\n <Checkbox\n :aria-label=\"selectLabel\"\n :model-value=\"selected.includes(idOf(item))\"\n tabindex=\"-1\"\n @update:model-value=\"toggle(item)\"\n />\n </span>\n <span\n v-if=\"gutter\"\n class=\"flex w-7 shrink-0 justify-end transition-opacity duration-100\"\n :class=\"selected.length ? 'opacity-100' : 'opacity-0 group-hover/row:opacity-100'\"\n >\n <Checkbox\n :aria-label=\"selectLabel\"\n :model-value=\"selected.includes(idOf(item))\"\n tabindex=\"-1\"\n @update:model-value=\"toggle(item)\"\n />\n </span>\n <div\n class=\"flex h-full min-w-0 flex-1 items-center gap-2.5 pr-4 outline-hidden\"\n :class=\"[gutter ? 'pl-2.5' : 'pl-4', (onRowClick || selectable) && 'cursor-pointer']\"\n data-list-row\n :role=\"onRowClick ? 'button' : undefined\"\n :tabindex=\"interactive ? 0 : undefined\"\n @click=\"clickRow($event, item)\"\n @keydown=\"onKeydown($event, item)\"\n @mousedown=\"onRowMousedown\"\n >\n <span\n v-if=\"$slots.leading\"\n class=\"flex shrink-0 items-center gap-2 text-sui-ink-muted tabular-nums\"\n :class=\"\n leading &&\n (selected.length\n ? '[&>*:first-child]:invisible'\n : 'group-hover/row:[&>*:first-child]:invisible group-has-focus-visible/row:[&>*:first-child]:invisible')\n \"\n >\n <slot\n :item=\"item\"\n name=\"leading\"\n :selected=\"selected.includes(idOf(item))\"\n :selecting=\"selected.length > 0\"\n :toggle=\"() => toggle(item)\"\n />\n </span>\n <span class=\"min-w-0 flex-1 truncate font-medium text-sui-ink\">\n <slot :item=\"item\" name=\"title\">{{ item.name }}</slot>\n </span>\n <span\n v-if=\"$slots.meta\"\n class=\"flex shrink-0 items-center gap-2 text-xs text-sui-ink-muted tabular-nums\"\n >\n <slot :item=\"item\" name=\"meta\" />\n </span>\n </div>\n </li>\n </ContextMenu>\n </ul>\n </section>\n </template>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"DataList.js","names":["_sfc_main","DataList_vue_vue_type_script_setup_true_lang_default","DataList_default"],"sources":["../../../src/components/DataList/DataList.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed, useId, useTemplateRef } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport ContextMenu from '../ContextMenu/ContextMenu.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { DropdownMenuAction, DropdownMenuEntry } from '../internal/menu'\nimport type { DataListGroup } from './types'\n\nexport interface DataListProps<T> {\n groups: DataListGroup<T>[]\n /** The item field that identifies it. An item's `depth` indents it as a child. */\n rowKey?: keyof T & string\n /** A checkbox bound to `v-model:selected`: it shows on hover and focus, and on every row once anything is selected.\n * Shift-click (or Shift+Space) selects a range, Cmd or Ctrl-click toggles one row, Shift+↑ ↓ extends. */\n selectable?: boolean\n /** gutter: the checkbox in its own column. leading: it takes the place of the `leading` slot's first mark. */\n checkboxPlacement?: 'gutter' | 'leading'\n loading?: boolean\n /** While loading, the placeholder groups drawn, as each one's number of rows. */\n loadingGroups?: number[]\n /** joined: one frame, sticky sunken group headers. cards: each group its own card, 12px apart, headers not sticky. */\n variant?: 'joined' | 'cards'\n /** The group headings' level, to fit the page's outline. */\n headingLevel?: 2 | 3 | 4 | 5 | 6\n /** The group headers' ground; by default sunken when joined, surface as cards. */\n groupHeaderTone?: 'sunken' | 'surface' | 'canvas'\n /** The group headers' height in px (36 by default); sets `--sui-list-header`. */\n groupHeaderHeight?: number\n /** Groups fold away under a chevron; a group's own `collapsible` wins. */\n collapsible?: boolean\n /** The rows' height in px, such as 44 (40 by default); sets `--sui-list-row`. */\n rowHeight?: number\n /** A hairline between rows. */\n dividers?: boolean\n /** Wraps each row in a ContextMenu of these items (`@context-item`); return [] for none. */\n contextItems?: (item: T) => DropdownMenuEntry[]\n /** The context menu's accessible name. */\n contextLabel?: string\n /** Makes rows open on click and Enter (`@row-click`). */\n onRowClick?: (item: T) => void\n /** Adds a + to each group's header (`@new`). */\n onNew?: (group: DataListGroup<T>) => void\n /** The + button's name; `{group}` is the group's name. */\n newLabel?: string\n collapseLabel?: string\n expandLabel?: string\n selectLabel?: string\n}\n\nconst props = withDefaults(defineProps<DataListProps<T>>(), {\n rowKey: 'id' as never,\n loadingGroups: () => [4, 2],\n variant: 'joined',\n checkboxPlacement: 'gutter',\n headingLevel: 3,\n groupHeaderTone: undefined,\n groupHeaderHeight: undefined,\n collapsible: true,\n rowHeight: undefined,\n dividers: false,\n contextItems: undefined,\n contextLabel: undefined,\n onRowClick: undefined,\n onNew: undefined,\n newLabel: 'New in {group}',\n collapseLabel: 'Collapse group',\n expandLabel: 'Expand group',\n selectLabel: 'Select'\n})\n\nconst emit = defineEmits<{ 'context-item': [action: DropdownMenuAction, item: T] }>()\n\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\nconst collapsed = defineModel<string[]>('collapsed', { default: () => [] })\n\nconst slots = defineSlots<{\n /** Marks before a group's name, e.g. a status icon. */\n 'group-leading'?: (props: { group: DataListGroup<T> }) => unknown\n /** Your own group header in place of the name and count, e.g. a status Badge and a count; inside the heading. */\n 'group-header'?: (props: { group: DataListGroup<T>; count: number; collapsed: boolean }) => unknown\n /** Small marks before an item's title: a status icon, an id, an avatar. With `checkboxPlacement=\"leading\"`, the\n * first mark gives way to the checkbox. */\n leading?: (props: { item: T; selected: boolean; selecting: boolean; toggle: () => void }) => unknown\n /** The item's title; `item.name` by default. */\n title?: (props: { item: T }) => unknown\n /** Right-aligned meta: tags, an avatar, a date. Keep it to three or four things. */\n meta?: (props: { item: T }) => unknown\n /** Controls at the end of a group's header, e.g. Show and Hide. */\n 'group-actions'?: (props: { group: DataListGroup<T> }) => unknown\n /** Shown when every group is empty, e.g. an EmptyState. */\n empty?: () => unknown\n}>()\n\nconst id = useId()\nconst root = useTemplateRef<HTMLElement>('root')\n\nconst idOf = (item: T): unknown => item[props.rowKey ?? 'id']\nconst interactive = computed(() => !!props.onRowClick || props.selectable)\nconst isEmpty = computed(() => !props.loading && props.groups.every((group) => group.items.length === 0))\n\nfunction toggleGroup(groupId: string) {\n collapsed.value = collapsed.value.includes(groupId)\n ? collapsed.value.filter((x) => x !== groupId)\n : [...collapsed.value, groupId]\n}\n\nconst collapsibleGroup = (group: DataListGroup<T>) => group.collapsible ?? props.collapsible\nconst isCollapsed = (group: DataListGroup<T>) => collapsibleGroup(group) && collapsed.value.includes(group.id)\nconst visibleItems = computed(() => props.groups.filter((group) => !isCollapsed(group)).flatMap((group) => group.items))\n\n// Where a range starts: the row last toggled.\nlet anchorKey: unknown = undefined\n\nfunction toggle(item: T) {\n const key = idOf(item)\n anchorKey = key\n selected.value = selected.value.includes(key) ? selected.value.filter((x) => x !== key) : [...selected.value, key]\n}\n\nfunction selectRange(item: T) {\n const keys = visibleItems.value.map(idOf)\n const to = keys.indexOf(idOf(item))\n const from = keys.indexOf(anchorKey)\n const span = from < 0 ? [keys[to]] : keys.slice(Math.min(from, to), Math.max(from, to) + 1)\n if (from < 0) anchorKey = idOf(item)\n selected.value = [...selected.value, ...span.filter((key) => !selected.value.includes(key))]\n}\n\nfunction select(...items: T[]) {\n const keys = items.map(idOf).filter((key) => !selected.value.includes(key))\n if (keys.length) selected.value = [...selected.value, ...new Set(keys)]\n}\n\nfunction clickRow(event: MouseEvent, item: T) {\n if (props.selectable && event.shiftKey) selectRange(item)\n else if (props.selectable && (event.metaKey || event.ctrlKey)) toggle(item)\n // Leading checkboxes stand in for the row's mark, so while selecting a click selects, as in a mail list.\n else if (props.selectable && leading.value && selected.value.length) toggle(item)\n else props.onRowClick?.(item)\n}\n\n// A shift-click selects rather than highlighting the text between.\nfunction onRowMousedown(event: MouseEvent) {\n if (props.selectable && event.shiftKey) event.preventDefault()\n}\n\n// ↑ ↓ or j k move between rows, x selects, Enter and Space open; with Shift, ↑ ↓ extend the selection and Space\n// selects a range.\nfunction onKeydown(event: KeyboardEvent, item: T) {\n if (event.target !== event.currentTarget || event.metaKey || event.ctrlKey || event.altKey) return\n // A collapsed group's rows are still in the DOM, hidden.\n const rows = [...(root.value?.querySelectorAll<HTMLElement>('[data-list-row]') ?? [])].filter(\n (row) => row.closest('ul')?.style.display !== 'none'\n )\n const i = rows.indexOf(event.currentTarget as HTMLElement)\n const down = event.key === 'ArrowDown' || event.key === 'j'\n const up = event.key === 'ArrowUp' || event.key === 'k'\n if ((down || up) && event.shiftKey && props.selectable) {\n const j = down ? Math.min(rows.length - 1, i + 1) : Math.max(0, i - 1)\n const next = visibleItems.value[j]\n select(item, ...(next ? [next] : []))\n rows[j]?.focus()\n } else if (down) rows[Math.min(rows.length - 1, i + 1)]?.focus()\n else if (up) rows[Math.max(0, i - 1)]?.focus()\n else if (event.key === ' ' && event.shiftKey && props.selectable) selectRange(item)\n else if (event.key.toLowerCase() === 'x' && props.selectable) toggle(item)\n else if ((event.key === 'Enter' || event.key === ' ') && props.onRowClick) props.onRowClick(item)\n else return\n event.preventDefault()\n}\n\nconst cards = computed(() => props.variant === 'cards')\nconst leading = computed(() => props.selectable && props.checkboxPlacement === 'leading')\nconst gutter = computed(() => props.selectable && props.checkboxPlacement === 'gutter')\nconst tones = { sunken: 'bg-sui-sunken', surface: 'bg-sui-surface', canvas: 'bg-sui-canvas' }\nconst headerTone = computed(() => tones[props.groupHeaderTone ?? (cards.value ? 'surface' : 'sunken')])\nconst sizes = computed(() => {\n const style: Record<string, string> = {}\n if (props.rowHeight !== undefined) style['--sui-list-row'] = `${props.rowHeight}px`\n if (props.groupHeaderHeight !== undefined) style['--sui-list-header'] = `${props.groupHeaderHeight}px`\n return Object.keys(style).length ? style : undefined\n})\nconst card = 'overflow-clip rounded-xl border border-sui-line-subtle bg-sui-surface'\nconst custom = (group: DataListGroup<T>) => !!slots['group-header'] || group.header !== undefined\nconst groupName = (group: DataListGroup<T>) => group.label ?? group.name ?? ''\n\nconst skeletonWidths = ['42%', '58%', '35%', '50%', '46%', '38%']\nconst skeletonGroupWidths = ['5.5rem', '4rem', '4.75rem']\n// A Skeleton is sunken, so on a sunken header band its bars go a step darker.\nconst headerBar = computed(() => [\n 'animate-pulse',\n headerTone.value === tones.sunken ? 'bg-sui-line-subtle' : 'bg-sui-sunken'\n])\nconst iconButton =\n 'flex size-6 shrink-0 items-center justify-center rounded-md text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-line-subtle hover:text-sui-ink focus-visible:sui-ring-inset'\n</script>\n\n<!-- A grouped list: one dense line per record under sticky, collapsible group headers. -->\n<template>\n <div ref=\"root\" class=\"flex flex-col text-13 text-sui-ink\" :class=\"cards ? 'gap-3' : card\" :style=\"sizes\">\n <div v-if=\"isEmpty && $slots.empty\" :class=\"cards && card\">\n <slot name=\"empty\" />\n </div>\n <!-- Placeholder groups in the list's own shape: its header, rows, leading marks and meta. -->\n <template v-else-if=\"loading\">\n <section\n v-for=\"(rows, g) in loadingGroups\"\n :key=\"g\"\n aria-busy=\"true\"\n :class=\"cards ? card : 'border-t border-sui-line-subtle first:border-t-0'\"\n >\n <div\n aria-hidden=\"true\"\n class=\"flex h-[var(--sui-list-header,2.25rem)] items-center gap-2 border-b border-sui-line-subtle pr-2\"\n :class=\"[headerTone, collapsible ? 'pl-1.5' : 'pl-4']\"\n >\n <span v-if=\"collapsible\" class=\"size-6 shrink-0\" />\n <span\n v-if=\"$slots['group-leading'] || $slots['group-header']\"\n class=\"size-3.5 rounded-full\"\n :class=\"headerBar\"\n />\n <span class=\"h-2.5 rounded-md\" :class=\"headerBar\" :style=\"{ width: skeletonGroupWidths[g % 3] }\" />\n <span class=\"h-2.5 w-3.5 rounded-md\" :class=\"headerBar\" />\n </div>\n <div\n v-for=\"r in rows\"\n :key=\"r\"\n aria-hidden=\"true\"\n class=\"flex h-[var(--sui-list-row,2.5rem)] items-center gap-2.5 pr-4\"\n :class=\"[gutter ? 'pl-9.5' : 'pl-4', dividers && '[&+&]:border-t [&+&]:border-sui-line-subtle']\"\n >\n <Skeleton v-if=\"$slots.leading || leading\" shape=\"circle\" size=\"1.25rem\" />\n <Skeleton height=\"0.75rem\" :width=\"skeletonWidths[(g * 3 + r) % skeletonWidths.length]\" />\n <span class=\"flex-1\" />\n <template v-if=\"$slots.meta\">\n <Skeleton height=\"0.625rem\" width=\"6rem\" />\n <Skeleton height=\"0.625rem\" width=\"3.5rem\" />\n </template>\n </div>\n </section>\n </template>\n <template v-else>\n <section\n v-for=\"group in groups\"\n :key=\"group.id\"\n :aria-label=\"group.label\"\n :aria-labelledby=\"!group.label && (group.name || custom(group)) ? `${id}-${group.id}-name` : undefined\"\n :class=\"cards ? card : 'border-t border-sui-line-subtle first:border-t-0'\"\n >\n <header\n v-if=\"group.name || custom(group)\"\n class=\"flex h-[var(--sui-list-header,2.25rem)] items-center gap-2 border-b border-sui-line-subtle pr-2\"\n :class=\"[headerTone, !cards && 'sticky top-0 z-10', collapsibleGroup(group) ? 'pl-1.5' : 'pl-4']\"\n >\n <button\n v-if=\"collapsibleGroup(group)\"\n :aria-controls=\"`${id}-${group.id}`\"\n :aria-expanded=\"!collapsed.includes(group.id)\"\n :aria-label=\"collapsed.includes(group.id) ? expandLabel : collapseLabel\"\n :class=\"iconButton\"\n type=\"button\"\n @click=\"toggleGroup(group.id)\"\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3 fill-none stroke-current transition-transform duration-150\"\n :class=\"isCollapsed(group) && '-rotate-90'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path d=\"M3 4.5 6 7.5l3-3\" />\n </svg>\n </button>\n <component\n :is=\"`h${headingLevel}`\"\n v-if=\"custom(group)\"\n :id=\"`${id}-${group.id}-name`\"\n class=\"m-0 flex min-w-0 items-center gap-2 text-13 font-medium text-sui-ink\"\n >\n <slot\n :collapsed=\"collapsed.includes(group.id)\"\n :count=\"group.count ?? group.items.length\"\n :group=\"group\"\n name=\"group-header\"\n >{{ group.header }}</slot\n >\n </component>\n <template v-else>\n <slot :group=\"group\" name=\"group-leading\" />\n <component\n :is=\"`h${headingLevel}`\"\n :id=\"`${id}-${group.id}-name`\"\n class=\"m-0 text-13 font-medium text-sui-ink\"\n >\n {{ group.name }}\n </component>\n <span class=\"text-13 text-sui-ink-muted tabular-nums\">{{ group.count ?? group.items.length }}</span>\n </template>\n <span class=\"ml-auto flex items-center gap-1\">\n <slot :group=\"group\" name=\"group-actions\" />\n </span>\n <button\n v-if=\"onNew\"\n :aria-label=\"newLabel.replace('{group}', groupName(group))\"\n :class=\"iconButton\"\n type=\"button\"\n @click=\"onNew(group)\"\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 14 14\"\n >\n <path d=\"M7 2.5v9M2.5 7h9\" />\n </svg>\n </button>\n </header>\n <ul v-show=\"!isCollapsed(group)\" :id=\"`${id}-${group.id}`\" class=\"m-0 list-none p-0\">\n <ContextMenu\n v-for=\"item in group.items\"\n :key=\"idOf(item) as PropertyKey\"\n :disabled=\"!contextItems\"\n :items=\"contextItems?.(item)\"\n :label=\"contextLabel\"\n @click-item=\"emit('context-item', $event, item)\"\n >\n <li\n class=\"group/row relative flex h-[var(--sui-list-row,2.5rem)] items-center transition-colors duration-100 has-focus-visible:sui-ring-inset\"\n :class=\"[\n dividers && '[&+&]:border-t [&+&]:border-sui-line-subtle',\n selected.includes(idOf(item))\n ? 'bg-sui-accent-wash'\n : 'hover:bg-sui-sunken has-focus-visible:bg-sui-sunken'\n ]\"\n :style=\"item.depth ? { paddingLeft: `${item.depth * 22}px` } : undefined\"\n >\n <!-- Outside the row, which is a button, over the leading slot's first mark: 16px in, or more for a child. -->\n <span\n v-if=\"leading\"\n class=\"absolute top-1/2 z-[1] flex size-4 -translate-y-1/2 items-center justify-center\"\n :class=\"!selected.length && 'hidden group-hover/row:flex group-has-focus-visible/row:flex'\"\n data-list-check\n :style=\"{ left: `${16 + (item.depth ?? 0) * 22}px` }\"\n >\n <Checkbox\n :aria-label=\"selectLabel\"\n :model-value=\"selected.includes(idOf(item))\"\n tabindex=\"-1\"\n @update:model-value=\"toggle(item)\"\n />\n </span>\n <span\n v-if=\"gutter\"\n class=\"flex w-7 shrink-0 justify-end transition-opacity duration-100\"\n :class=\"selected.length ? 'opacity-100' : 'opacity-0 group-hover/row:opacity-100'\"\n >\n <Checkbox\n :aria-label=\"selectLabel\"\n :model-value=\"selected.includes(idOf(item))\"\n tabindex=\"-1\"\n @update:model-value=\"toggle(item)\"\n />\n </span>\n <div\n class=\"flex h-full min-w-0 flex-1 items-center gap-2.5 pr-4 outline-hidden\"\n :class=\"[gutter ? 'pl-2.5' : 'pl-4', (onRowClick || selectable) && 'cursor-pointer']\"\n data-list-row\n :role=\"onRowClick ? 'button' : undefined\"\n :tabindex=\"interactive ? 0 : undefined\"\n @click=\"clickRow($event, item)\"\n @keydown=\"onKeydown($event, item)\"\n @mousedown=\"onRowMousedown\"\n >\n <span\n v-if=\"$slots.leading\"\n class=\"flex shrink-0 items-center gap-2 text-sui-ink-muted tabular-nums\"\n :class=\"\n leading &&\n (selected.length\n ? '[&>*:first-child]:invisible'\n : 'group-hover/row:[&>*:first-child]:invisible group-has-focus-visible/row:[&>*:first-child]:invisible')\n \"\n >\n <slot\n :item=\"item\"\n name=\"leading\"\n :selected=\"selected.includes(idOf(item))\"\n :selecting=\"selected.length > 0\"\n :toggle=\"() => toggle(item)\"\n />\n </span>\n <span class=\"min-w-0 flex-1 truncate font-medium text-sui-ink\">\n <slot :item=\"item\" name=\"title\">{{ item.name }}</slot>\n </span>\n <span\n v-if=\"$slots.meta\"\n class=\"flex shrink-0 items-center gap-2 text-xs text-sui-ink-muted tabular-nums\"\n >\n <slot :item=\"item\" name=\"meta\" />\n </span>\n </div>\n </li>\n </ContextMenu>\n </ul>\n </section>\n </template>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -10,6 +10,8 @@ export interface DataListProps<T> {
|
|
|
10
10
|
/** gutter: the checkbox in its own column. leading: it takes the place of the `leading` slot's first mark. */
|
|
11
11
|
checkboxPlacement?: 'gutter' | 'leading';
|
|
12
12
|
loading?: boolean;
|
|
13
|
+
/** While loading, the placeholder groups drawn, as each one's number of rows. */
|
|
14
|
+
loadingGroups?: number[];
|
|
13
15
|
/** joined: one frame, sticky sunken group headers. cards: each group its own card, 12px apart, headers not sticky. */
|
|
14
16
|
variant?: 'joined' | 'cards';
|
|
15
17
|
/** The group headings' level, to fit the page's outline. */
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import e from "../Skeleton/Skeleton.js";
|
|
2
2
|
import t from "../Checkbox/Checkbox.js";
|
|
3
3
|
import n from "../ContextMenu/ContextMenu.js";
|
|
4
|
-
import { Fragment as r, computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, createTextVNode as l, createVNode as u, defineComponent as d, mergeModels as f, normalizeClass as p, normalizeStyle as m, openBlock as h, renderList as g, renderSlot as _, resolveDynamicComponent as v, toDisplayString as y, unref as b, useId as ee, useModel as x, useSlots as te, useTemplateRef as ne, vShow as
|
|
4
|
+
import { Fragment as r, computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, createTextVNode as l, createVNode as u, defineComponent as d, mergeModels as f, normalizeClass as p, normalizeStyle as m, openBlock as h, renderList as g, renderSlot as _, resolveDynamicComponent as v, toDisplayString as y, unref as b, useId as ee, useModel as x, useSlots as te, useTemplateRef as ne, vShow as S, withCtx as C, withDirectives as re } from "vue";
|
|
5
5
|
//#region src/components/DataList/DataList.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
-
var
|
|
6
|
+
var ie = {
|
|
7
|
+
key: 0,
|
|
8
|
+
class: "size-6 shrink-0"
|
|
9
|
+
}, w = ["aria-label", "aria-labelledby"], T = [
|
|
7
10
|
"aria-controls",
|
|
8
11
|
"aria-expanded",
|
|
9
12
|
"aria-label",
|
|
10
13
|
"onClick"
|
|
11
|
-
],
|
|
14
|
+
], ae = { class: "text-13 text-sui-ink-muted tabular-nums" }, oe = { class: "ml-auto flex items-center gap-1" }, se = ["aria-label", "onClick"], ce = ["id"], E = [
|
|
12
15
|
"role",
|
|
13
16
|
"tabindex",
|
|
14
17
|
"onClick",
|
|
15
18
|
"onKeydown"
|
|
16
|
-
],
|
|
19
|
+
], D = { class: "min-w-0 flex-1 truncate font-medium text-sui-ink" }, O = {
|
|
17
20
|
key: 1,
|
|
18
21
|
class: "flex shrink-0 items-center gap-2 text-xs text-sui-ink-muted tabular-nums"
|
|
19
|
-
},
|
|
22
|
+
}, k = "overflow-clip rounded-xl border border-sui-line-subtle bg-sui-surface", A = "flex size-6 shrink-0 items-center justify-center rounded-md text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-line-subtle hover:text-sui-ink focus-visible:sui-ring-inset", j = /*@__PURE__*/ d({
|
|
20
23
|
__name: "DataList",
|
|
21
24
|
props: /*@__PURE__*/ f({
|
|
22
25
|
groups: {},
|
|
@@ -24,6 +27,7 @@ var w = ["aria-label", "aria-labelledby"], T = [
|
|
|
24
27
|
selectable: { type: Boolean },
|
|
25
28
|
checkboxPlacement: { default: "gutter" },
|
|
26
29
|
loading: { type: Boolean },
|
|
30
|
+
loadingGroups: { default: () => [4, 2] },
|
|
27
31
|
variant: { default: "joined" },
|
|
28
32
|
headingLevel: { default: 3 },
|
|
29
33
|
groupHeaderTone: { default: void 0 },
|
|
@@ -62,120 +66,146 @@ var w = ["aria-label", "aria-labelledby"], T = [
|
|
|
62
66
|
}),
|
|
63
67
|
emits: /*@__PURE__*/ f(["context-item"], ["update:selected", "update:collapsed"]),
|
|
64
68
|
setup(d, { emit: f }) {
|
|
65
|
-
let
|
|
66
|
-
function
|
|
67
|
-
|
|
69
|
+
let j = d, le = f, M = x(d, "selected"), N = x(d, "collapsed"), ue = te(), P = ee(), F = ne("root"), I = (e) => e[j.rowKey ?? "id"], L = i(() => !!j.onRowClick || j.selectable), R = i(() => !j.loading && j.groups.every((e) => e.items.length === 0));
|
|
70
|
+
function z(e) {
|
|
71
|
+
N.value = N.value.includes(e) ? N.value.filter((t) => t !== e) : [...N.value, e];
|
|
68
72
|
}
|
|
69
|
-
let
|
|
70
|
-
function
|
|
71
|
-
let t =
|
|
72
|
-
|
|
73
|
+
let B = (e) => e.collapsible ?? j.collapsible, V = (e) => B(e) && N.value.includes(e.id), H = i(() => j.groups.filter((e) => !V(e)).flatMap((e) => e.items)), U;
|
|
74
|
+
function W(e) {
|
|
75
|
+
let t = I(e);
|
|
76
|
+
U = t, M.value = M.value.includes(t) ? M.value.filter((e) => e !== t) : [...M.value, t];
|
|
73
77
|
}
|
|
74
|
-
function
|
|
75
|
-
let t =
|
|
76
|
-
r < 0 && (
|
|
78
|
+
function G(e) {
|
|
79
|
+
let t = H.value.map(I), n = t.indexOf(I(e)), r = t.indexOf(U), i = r < 0 ? [t[n]] : t.slice(Math.min(r, n), Math.max(r, n) + 1);
|
|
80
|
+
r < 0 && (U = I(e)), M.value = [...M.value, ...i.filter((e) => !M.value.includes(e))];
|
|
77
81
|
}
|
|
78
|
-
function
|
|
79
|
-
let t = e.map(
|
|
80
|
-
t.length && (
|
|
82
|
+
function de(...e) {
|
|
83
|
+
let t = e.map(I).filter((e) => !M.value.includes(e));
|
|
84
|
+
t.length && (M.value = [...M.value, ...new Set(t)]);
|
|
81
85
|
}
|
|
82
|
-
function
|
|
83
|
-
|
|
86
|
+
function fe(e, t) {
|
|
87
|
+
j.selectable && e.shiftKey ? G(t) : j.selectable && (e.metaKey || e.ctrlKey) || j.selectable && q.value && M.value.length ? W(t) : j.onRowClick?.(t);
|
|
84
88
|
}
|
|
85
|
-
function
|
|
86
|
-
|
|
89
|
+
function pe(e) {
|
|
90
|
+
j.selectable && e.shiftKey && e.preventDefault();
|
|
87
91
|
}
|
|
88
|
-
function
|
|
92
|
+
function me(e, t) {
|
|
89
93
|
if (e.target !== e.currentTarget || e.metaKey || e.ctrlKey || e.altKey) return;
|
|
90
|
-
let n = [...
|
|
91
|
-
if ((i || a) && e.shiftKey &&
|
|
92
|
-
let e = i ? Math.min(n.length - 1, r + 1) : Math.max(0, r - 1), a =
|
|
93
|
-
|
|
94
|
+
let n = [...F.value?.querySelectorAll("[data-list-row]") ?? []].filter((e) => e.closest("ul")?.style.display !== "none"), r = n.indexOf(e.currentTarget), i = e.key === "ArrowDown" || e.key === "j", a = e.key === "ArrowUp" || e.key === "k";
|
|
95
|
+
if ((i || a) && e.shiftKey && j.selectable) {
|
|
96
|
+
let e = i ? Math.min(n.length - 1, r + 1) : Math.max(0, r - 1), a = H.value[e];
|
|
97
|
+
de(t, ...a ? [a] : []), n[e]?.focus();
|
|
94
98
|
} else if (i) n[Math.min(n.length - 1, r + 1)]?.focus();
|
|
95
99
|
else if (a) n[Math.max(0, r - 1)]?.focus();
|
|
96
|
-
else if (e.key === " " && e.shiftKey &&
|
|
97
|
-
else if (e.key.toLowerCase() === "x" &&
|
|
98
|
-
else if ((e.key === "Enter" || e.key === " ") &&
|
|
100
|
+
else if (e.key === " " && e.shiftKey && j.selectable) G(t);
|
|
101
|
+
else if (e.key.toLowerCase() === "x" && j.selectable) W(t);
|
|
102
|
+
else if ((e.key === "Enter" || e.key === " ") && j.onRowClick) j.onRowClick(t);
|
|
99
103
|
else return;
|
|
100
104
|
e.preventDefault();
|
|
101
105
|
}
|
|
102
|
-
let
|
|
106
|
+
let K = i(() => j.variant === "cards"), q = i(() => j.selectable && j.checkboxPlacement === "leading"), J = i(() => j.selectable && j.checkboxPlacement === "gutter"), Y = {
|
|
103
107
|
sunken: "bg-sui-sunken",
|
|
104
108
|
surface: "bg-sui-surface",
|
|
105
109
|
canvas: "bg-sui-canvas"
|
|
106
|
-
},
|
|
110
|
+
}, X = i(() => Y[j.groupHeaderTone ?? (K.value ? "surface" : "sunken")]), he = i(() => {
|
|
107
111
|
let e = {};
|
|
108
|
-
return
|
|
109
|
-
}),
|
|
112
|
+
return j.rowHeight !== void 0 && (e["--sui-list-row"] = `${j.rowHeight}px`), j.groupHeaderHeight !== void 0 && (e["--sui-list-header"] = `${j.groupHeaderHeight}px`), Object.keys(e).length ? e : void 0;
|
|
113
|
+
}), Z = (e) => !!ue["group-header"] || e.header !== void 0, ge = (e) => e.label ?? e.name ?? "", Q = [
|
|
110
114
|
"42%",
|
|
111
115
|
"58%",
|
|
112
116
|
"35%",
|
|
113
117
|
"50%",
|
|
114
|
-
"46%"
|
|
115
|
-
|
|
118
|
+
"46%",
|
|
119
|
+
"38%"
|
|
120
|
+
], _e = [
|
|
121
|
+
"5.5rem",
|
|
122
|
+
"4rem",
|
|
123
|
+
"4.75rem"
|
|
124
|
+
], $ = i(() => ["animate-pulse", X.value === Y.sunken ? "bg-sui-line-subtle" : "bg-sui-sunken"]);
|
|
116
125
|
return (i, f) => (h(), s("div", {
|
|
117
126
|
ref_key: "root",
|
|
118
|
-
ref:
|
|
119
|
-
class: p(["flex flex-col text-13 text-sui-ink",
|
|
120
|
-
style: m(
|
|
121
|
-
}, [
|
|
127
|
+
ref: F,
|
|
128
|
+
class: p(["flex flex-col text-13 text-sui-ink", K.value ? "gap-3" : k]),
|
|
129
|
+
style: m(he.value)
|
|
130
|
+
}, [R.value && i.$slots.empty ? (h(), s("div", {
|
|
122
131
|
key: 0,
|
|
123
|
-
class: p(
|
|
124
|
-
}, [_(i.$slots, "empty")], 2)) : d.loading ? (h(), s("section", {
|
|
125
|
-
key: 1,
|
|
126
|
-
"aria-busy": !0,
|
|
127
|
-
class: p(Y.value && j)
|
|
128
|
-
}, [(h(), s(r, null, g(me, (t, n) => c("div", {
|
|
132
|
+
class: p(K.value && k)
|
|
133
|
+
}, [_(i.$slots, "empty")], 2)) : d.loading ? (h(!0), s(r, { key: 1 }, g(d.loadingGroups, (t, n) => (h(), s("section", {
|
|
129
134
|
key: n,
|
|
135
|
+
"aria-busy": "true",
|
|
136
|
+
class: p(K.value ? k : "border-t border-sui-line-subtle first:border-t-0")
|
|
137
|
+
}, [c("div", {
|
|
130
138
|
"aria-hidden": "true",
|
|
131
|
-
class: "flex h-[var(--sui-list-
|
|
139
|
+
class: p(["flex h-[var(--sui-list-header,2.25rem)] items-center gap-2 border-b border-sui-line-subtle pr-2", [X.value, d.collapsible ? "pl-1.5" : "pl-4"]])
|
|
132
140
|
}, [
|
|
133
|
-
|
|
141
|
+
d.collapsible ? (h(), s("span", ie)) : o("", !0),
|
|
142
|
+
i.$slots["group-leading"] || i.$slots["group-header"] ? (h(), s("span", {
|
|
143
|
+
key: 1,
|
|
144
|
+
class: p(["size-3.5 rounded-full", $.value])
|
|
145
|
+
}, null, 2)) : o("", !0),
|
|
146
|
+
c("span", {
|
|
147
|
+
class: p(["h-2.5 rounded-md", $.value]),
|
|
148
|
+
style: m({ width: _e[n % 3] })
|
|
149
|
+
}, null, 6),
|
|
150
|
+
c("span", { class: p(["h-2.5 w-3.5 rounded-md", $.value]) }, null, 2)
|
|
151
|
+
], 2), (h(!0), s(r, null, g(t, (t) => (h(), s("div", {
|
|
152
|
+
key: t,
|
|
153
|
+
"aria-hidden": "true",
|
|
154
|
+
class: p(["flex h-[var(--sui-list-row,2.5rem)] items-center gap-2.5 pr-4", [J.value ? "pl-9.5" : "pl-4", d.dividers && "[&+&]:border-t [&+&]:border-sui-line-subtle"]])
|
|
155
|
+
}, [
|
|
156
|
+
i.$slots.leading || q.value ? (h(), a(e, {
|
|
157
|
+
key: 0,
|
|
158
|
+
shape: "circle",
|
|
159
|
+
size: "1.25rem"
|
|
160
|
+
})) : o("", !0),
|
|
134
161
|
u(e, {
|
|
135
162
|
height: "0.75rem",
|
|
136
|
-
width: t
|
|
163
|
+
width: Q[(n * 3 + t) % Q.length]
|
|
137
164
|
}, null, 8, ["width"]),
|
|
138
|
-
f[
|
|
139
|
-
u(e, {
|
|
140
|
-
height: "0.
|
|
141
|
-
width: "
|
|
142
|
-
})
|
|
143
|
-
|
|
165
|
+
f[0] ||= c("span", { class: "flex-1" }, null, -1),
|
|
166
|
+
i.$slots.meta ? (h(), s(r, { key: 1 }, [u(e, {
|
|
167
|
+
height: "0.625rem",
|
|
168
|
+
width: "6rem"
|
|
169
|
+
}), u(e, {
|
|
170
|
+
height: "0.625rem",
|
|
171
|
+
width: "3.5rem"
|
|
172
|
+
})], 64)) : o("", !0)
|
|
173
|
+
], 2))), 128))], 2))), 128)) : (h(!0), s(r, { key: 2 }, g(d.groups, (e) => (h(), s("section", {
|
|
144
174
|
key: e.id,
|
|
145
175
|
"aria-label": e.label,
|
|
146
|
-
"aria-labelledby": !e.label && (e.name ||
|
|
147
|
-
class: p(
|
|
148
|
-
}, [e.name ||
|
|
176
|
+
"aria-labelledby": !e.label && (e.name || Z(e)) ? `${b(P)}-${e.id}-name` : void 0,
|
|
177
|
+
class: p(K.value ? k : "border-t border-sui-line-subtle first:border-t-0")
|
|
178
|
+
}, [e.name || Z(e) ? (h(), s("header", {
|
|
149
179
|
key: 0,
|
|
150
180
|
class: p(["flex h-[var(--sui-list-header,2.25rem)] items-center gap-2 border-b border-sui-line-subtle pr-2", [
|
|
151
|
-
|
|
152
|
-
!
|
|
153
|
-
|
|
181
|
+
X.value,
|
|
182
|
+
!K.value && "sticky top-0 z-10",
|
|
183
|
+
B(e) ? "pl-1.5" : "pl-4"
|
|
154
184
|
]])
|
|
155
185
|
}, [
|
|
156
|
-
|
|
186
|
+
B(e) ? (h(), s("button", {
|
|
157
187
|
key: 0,
|
|
158
|
-
"aria-controls": `${b(
|
|
159
|
-
"aria-expanded": !
|
|
160
|
-
"aria-label":
|
|
161
|
-
class: p(
|
|
188
|
+
"aria-controls": `${b(P)}-${e.id}`,
|
|
189
|
+
"aria-expanded": !N.value.includes(e.id),
|
|
190
|
+
"aria-label": N.value.includes(e.id) ? d.expandLabel : d.collapseLabel,
|
|
191
|
+
class: p(A),
|
|
162
192
|
type: "button",
|
|
163
|
-
onClick: (t) =>
|
|
193
|
+
onClick: (t) => z(e.id)
|
|
164
194
|
}, [(h(), s("svg", {
|
|
165
195
|
"aria-hidden": "true",
|
|
166
|
-
class: p(["size-3 fill-none stroke-current transition-transform duration-150",
|
|
196
|
+
class: p(["size-3 fill-none stroke-current transition-transform duration-150", V(e) && "-rotate-90"]),
|
|
167
197
|
"stroke-linecap": "round",
|
|
168
198
|
"stroke-linejoin": "round",
|
|
169
199
|
"stroke-width": "1.5",
|
|
170
200
|
viewBox: "0 0 12 12"
|
|
171
|
-
}, [...f[
|
|
172
|
-
|
|
201
|
+
}, [...f[1] ||= [c("path", { d: "M3 4.5 6 7.5l3-3" }, null, -1)]], 2))], 8, T)) : o("", !0),
|
|
202
|
+
Z(e) ? (h(), a(v(`h${d.headingLevel}`), {
|
|
173
203
|
key: 1,
|
|
174
|
-
id: `${b(
|
|
204
|
+
id: `${b(P)}-${e.id}-name`,
|
|
175
205
|
class: "m-0 flex min-w-0 items-center gap-2 text-13 font-medium text-sui-ink"
|
|
176
206
|
}, {
|
|
177
|
-
default:
|
|
178
|
-
collapsed:
|
|
207
|
+
default: C(() => [_(i.$slots, "group-header", {
|
|
208
|
+
collapsed: N.value.includes(e.id),
|
|
179
209
|
count: e.count ?? e.items.length,
|
|
180
210
|
group: e
|
|
181
211
|
}, () => [l(y(e.header), 1)])]),
|
|
@@ -183,91 +213,91 @@ var w = ["aria-label", "aria-labelledby"], T = [
|
|
|
183
213
|
}, 1032, ["id"])) : (h(), s(r, { key: 2 }, [
|
|
184
214
|
_(i.$slots, "group-leading", { group: e }),
|
|
185
215
|
(h(), a(v(`h${d.headingLevel}`), {
|
|
186
|
-
id: `${b(
|
|
216
|
+
id: `${b(P)}-${e.id}-name`,
|
|
187
217
|
class: "m-0 text-13 font-medium text-sui-ink"
|
|
188
218
|
}, {
|
|
189
|
-
default:
|
|
219
|
+
default: C(() => [l(y(e.name), 1)]),
|
|
190
220
|
_: 2
|
|
191
221
|
}, 1032, ["id"])),
|
|
192
|
-
c("span",
|
|
222
|
+
c("span", ae, y(e.count ?? e.items.length), 1)
|
|
193
223
|
], 64)),
|
|
194
|
-
c("span",
|
|
224
|
+
c("span", oe, [_(i.$slots, "group-actions", { group: e })]),
|
|
195
225
|
d.onNew ? (h(), s("button", {
|
|
196
226
|
key: 3,
|
|
197
|
-
"aria-label": d.newLabel.replace("{group}",
|
|
198
|
-
class: p(
|
|
227
|
+
"aria-label": d.newLabel.replace("{group}", ge(e)),
|
|
228
|
+
class: p(A),
|
|
199
229
|
type: "button",
|
|
200
230
|
onClick: (t) => d.onNew(e)
|
|
201
|
-
}, [...f[
|
|
231
|
+
}, [...f[2] ||= [c("svg", {
|
|
202
232
|
"aria-hidden": "true",
|
|
203
233
|
class: "size-3.5 fill-none stroke-current",
|
|
204
234
|
"stroke-linecap": "round",
|
|
205
235
|
"stroke-width": "1.5",
|
|
206
236
|
viewBox: "0 0 14 14"
|
|
207
|
-
}, [c("path", { d: "M7 2.5v9M2.5 7h9" })], -1)]], 8,
|
|
208
|
-
], 2)) : o("", !0),
|
|
209
|
-
id: `${b(
|
|
237
|
+
}, [c("path", { d: "M7 2.5v9M2.5 7h9" })], -1)]], 8, se)) : o("", !0)
|
|
238
|
+
], 2)) : o("", !0), re(c("ul", {
|
|
239
|
+
id: `${b(P)}-${e.id}`,
|
|
210
240
|
class: "m-0 list-none p-0"
|
|
211
241
|
}, [(h(!0), s(r, null, g(e.items, (e) => (h(), a(n, {
|
|
212
|
-
key:
|
|
242
|
+
key: I(e),
|
|
213
243
|
disabled: !d.contextItems,
|
|
214
244
|
items: d.contextItems?.(e),
|
|
215
245
|
label: d.contextLabel,
|
|
216
|
-
onClickItem: (t) =>
|
|
246
|
+
onClickItem: (t) => le("context-item", t, e)
|
|
217
247
|
}, {
|
|
218
|
-
default:
|
|
219
|
-
class: p(["group/row relative flex h-[var(--sui-list-row,2.5rem)] items-center transition-colors duration-100 has-focus-visible:sui-ring-inset", [d.dividers && "[&+&]:border-t [&+&]:border-sui-line-subtle",
|
|
248
|
+
default: C(() => [c("li", {
|
|
249
|
+
class: p(["group/row relative flex h-[var(--sui-list-row,2.5rem)] items-center transition-colors duration-100 has-focus-visible:sui-ring-inset", [d.dividers && "[&+&]:border-t [&+&]:border-sui-line-subtle", M.value.includes(I(e)) ? "bg-sui-accent-wash" : "hover:bg-sui-sunken has-focus-visible:bg-sui-sunken"]]),
|
|
220
250
|
style: m(e.depth ? { paddingLeft: `${e.depth * 22}px` } : void 0)
|
|
221
251
|
}, [
|
|
222
|
-
|
|
252
|
+
q.value ? (h(), s("span", {
|
|
223
253
|
key: 0,
|
|
224
|
-
class: p(["absolute top-1/2 z-[1] flex size-4 -translate-y-1/2 items-center justify-center", !
|
|
254
|
+
class: p(["absolute top-1/2 z-[1] flex size-4 -translate-y-1/2 items-center justify-center", !M.value.length && "hidden group-hover/row:flex group-has-focus-visible/row:flex"]),
|
|
225
255
|
"data-list-check": "",
|
|
226
256
|
style: m({ left: `${16 + (e.depth ?? 0) * 22}px` })
|
|
227
257
|
}, [u(t, {
|
|
228
258
|
"aria-label": d.selectLabel,
|
|
229
|
-
"model-value":
|
|
259
|
+
"model-value": M.value.includes(I(e)),
|
|
230
260
|
tabindex: "-1",
|
|
231
|
-
"onUpdate:modelValue": (t) =>
|
|
261
|
+
"onUpdate:modelValue": (t) => W(e)
|
|
232
262
|
}, null, 8, [
|
|
233
263
|
"aria-label",
|
|
234
264
|
"model-value",
|
|
235
265
|
"onUpdate:modelValue"
|
|
236
266
|
])], 6)) : o("", !0),
|
|
237
|
-
|
|
267
|
+
J.value ? (h(), s("span", {
|
|
238
268
|
key: 1,
|
|
239
|
-
class: p(["flex w-7 shrink-0 justify-end transition-opacity duration-100",
|
|
269
|
+
class: p(["flex w-7 shrink-0 justify-end transition-opacity duration-100", M.value.length ? "opacity-100" : "opacity-0 group-hover/row:opacity-100"])
|
|
240
270
|
}, [u(t, {
|
|
241
271
|
"aria-label": d.selectLabel,
|
|
242
|
-
"model-value":
|
|
272
|
+
"model-value": M.value.includes(I(e)),
|
|
243
273
|
tabindex: "-1",
|
|
244
|
-
"onUpdate:modelValue": (t) =>
|
|
274
|
+
"onUpdate:modelValue": (t) => W(e)
|
|
245
275
|
}, null, 8, [
|
|
246
276
|
"aria-label",
|
|
247
277
|
"model-value",
|
|
248
278
|
"onUpdate:modelValue"
|
|
249
279
|
])], 2)) : o("", !0),
|
|
250
280
|
c("div", {
|
|
251
|
-
class: p(["flex h-full min-w-0 flex-1 items-center gap-2.5 pr-4 outline-hidden", [
|
|
281
|
+
class: p(["flex h-full min-w-0 flex-1 items-center gap-2.5 pr-4 outline-hidden", [J.value ? "pl-2.5" : "pl-4", (d.onRowClick || d.selectable) && "cursor-pointer"]]),
|
|
252
282
|
"data-list-row": "",
|
|
253
283
|
role: d.onRowClick ? "button" : void 0,
|
|
254
|
-
tabindex:
|
|
255
|
-
onClick: (t) =>
|
|
256
|
-
onKeydown: (t) =>
|
|
257
|
-
onMousedown:
|
|
284
|
+
tabindex: L.value ? 0 : void 0,
|
|
285
|
+
onClick: (t) => fe(t, e),
|
|
286
|
+
onKeydown: (t) => me(t, e),
|
|
287
|
+
onMousedown: pe
|
|
258
288
|
}, [
|
|
259
289
|
i.$slots.leading ? (h(), s("span", {
|
|
260
290
|
key: 0,
|
|
261
|
-
class: p(["flex shrink-0 items-center gap-2 text-sui-ink-muted tabular-nums",
|
|
291
|
+
class: p(["flex shrink-0 items-center gap-2 text-sui-ink-muted tabular-nums", q.value && (M.value.length ? "[&>*:first-child]:invisible" : "group-hover/row:[&>*:first-child]:invisible group-has-focus-visible/row:[&>*:first-child]:invisible")])
|
|
262
292
|
}, [_(i.$slots, "leading", {
|
|
263
293
|
item: e,
|
|
264
|
-
selected:
|
|
265
|
-
selecting:
|
|
266
|
-
toggle: () =>
|
|
294
|
+
selected: M.value.includes(I(e)),
|
|
295
|
+
selecting: M.value.length > 0,
|
|
296
|
+
toggle: () => W(e)
|
|
267
297
|
})], 2)) : o("", !0),
|
|
268
|
-
c("span",
|
|
269
|
-
i.$slots.meta ? (h(), s("span",
|
|
270
|
-
], 42,
|
|
298
|
+
c("span", D, [_(i.$slots, "title", { item: e }, () => [l(y(e.name), 1)])]),
|
|
299
|
+
i.$slots.meta ? (h(), s("span", O, [_(i.$slots, "meta", { item: e })])) : o("", !0)
|
|
300
|
+
], 42, E)
|
|
271
301
|
], 6)]),
|
|
272
302
|
_: 2
|
|
273
303
|
}, 1032, [
|
|
@@ -275,10 +305,10 @@ var w = ["aria-label", "aria-labelledby"], T = [
|
|
|
275
305
|
"items",
|
|
276
306
|
"label",
|
|
277
307
|
"onClickItem"
|
|
278
|
-
]))), 128))], 8,
|
|
308
|
+
]))), 128))], 8, ce), [[S, !V(e)]])], 10, w))), 128))], 6));
|
|
279
309
|
}
|
|
280
310
|
});
|
|
281
311
|
//#endregion
|
|
282
|
-
export {
|
|
312
|
+
export { j as default };
|
|
283
313
|
|
|
284
314
|
//# sourceMappingURL=DataList.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataList.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","_useSlots","_openBlock","_createElementBlock","_normalizeClass","_normalizeStyle","_renderSlot","_Fragment","_renderList","_createElementVNode","_createVNode","Skeleton","_unref","_createCommentVNode","_createBlock","_resolveDynamicComponent","_withCtx","_createTextVNode","_toDisplayString","_withDirectives","ContextMenu","Checkbox","_vShow","Skeleton_default","Checkbox_default","ContextMenu_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","card","iconButton","DataList_vue_vue_type_script_setup_true_lang_default","\"selected\"","\"selectedModifiers\"","\"collapsed\"","\"collapsedModifiers\"","__emit","props","__props","emit","selected","useModel","collapsed","slots","useSlots","id","useId","root","useTemplateRef","idOf","item","interactive","computed","isEmpty","group","toggleGroup","groupId","x","collapsibleGroup","isCollapsed","visibleItems","anchorKey","toggle","key","selectRange","keys","to","from","span","select","items","clickRow","event","leading","onRowMousedown","onKeydown","rows","row","i","down","up","j","next","cards","gutter","tones","headerTone","sizes","style","custom","groupName","skeletonWidths","openBlock","createElementBlock","normalizeClass","normalizeStyle","_ctx","renderSlot","Fragment","renderList","createElementVNode","_cache","createVNode","unref","createCommentVNode","createBlock","resolveDynamicComponent","withCtx","createTextVNode","toDisplayString","withDirectives","$event","vShow"],"sources":["../../../src/components/DataList/DataList.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed, useId, useTemplateRef } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport ContextMenu from '../ContextMenu/ContextMenu.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { DropdownMenuAction, DropdownMenuEntry } from '../internal/menu'\nimport type { DataListGroup } from './types'\n\nexport interface DataListProps<T> {\n groups: DataListGroup<T>[]\n /** The item field that identifies it. An item's `depth` indents it as a child. */\n rowKey?: keyof T & string\n /** A checkbox bound to `v-model:selected`: it shows on hover and focus, and on every row once anything is selected.\n * Shift-click (or Shift+Space) selects a range, Cmd or Ctrl-click toggles one row, Shift+↑ ↓ extends. */\n selectable?: boolean\n /** gutter: the checkbox in its own column. leading: it takes the place of the `leading` slot's first mark. */\n checkboxPlacement?: 'gutter' | 'leading'\n loading?: boolean\n /** joined: one frame, sticky sunken group headers. cards: each group its own card, 12px apart, headers not sticky. */\n variant?: 'joined' | 'cards'\n /** The group headings' level, to fit the page's outline. */\n headingLevel?: 2 | 3 | 4 | 5 | 6\n /** The group headers' ground; by default sunken when joined, surface as cards. */\n groupHeaderTone?: 'sunken' | 'surface' | 'canvas'\n /** The group headers' height in px (36 by default); sets `--sui-list-header`. */\n groupHeaderHeight?: number\n /** Groups fold away under a chevron; a group's own `collapsible` wins. */\n collapsible?: boolean\n /** The rows' height in px, such as 44 (40 by default); sets `--sui-list-row`. */\n rowHeight?: number\n /** A hairline between rows. */\n dividers?: boolean\n /** Wraps each row in a ContextMenu of these items (`@context-item`); return [] for none. */\n contextItems?: (item: T) => DropdownMenuEntry[]\n /** The context menu's accessible name. */\n contextLabel?: string\n /** Makes rows open on click and Enter (`@row-click`). */\n onRowClick?: (item: T) => void\n /** Adds a + to each group's header (`@new`). */\n onNew?: (group: DataListGroup<T>) => void\n /** The + button's name; `{group}` is the group's name. */\n newLabel?: string\n collapseLabel?: string\n expandLabel?: string\n selectLabel?: string\n}\n\nconst props = withDefaults(defineProps<DataListProps<T>>(), {\n rowKey: 'id' as never,\n variant: 'joined',\n checkboxPlacement: 'gutter',\n headingLevel: 3,\n groupHeaderTone: undefined,\n groupHeaderHeight: undefined,\n collapsible: true,\n rowHeight: undefined,\n dividers: false,\n contextItems: undefined,\n contextLabel: undefined,\n onRowClick: undefined,\n onNew: undefined,\n newLabel: 'New in {group}',\n collapseLabel: 'Collapse group',\n expandLabel: 'Expand group',\n selectLabel: 'Select'\n})\n\nconst emit = defineEmits<{ 'context-item': [action: DropdownMenuAction, item: T] }>()\n\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\nconst collapsed = defineModel<string[]>('collapsed', { default: () => [] })\n\nconst slots = defineSlots<{\n /** Marks before a group's name, e.g. a status icon. */\n 'group-leading'?: (props: { group: DataListGroup<T> }) => unknown\n /** Your own group header in place of the name and count, e.g. a status Badge and a count; inside the heading. */\n 'group-header'?: (props: { group: DataListGroup<T>; count: number; collapsed: boolean }) => unknown\n /** Small marks before an item's title: a status icon, an id, an avatar. With `checkboxPlacement=\"leading\"`, the\n * first mark gives way to the checkbox. */\n leading?: (props: { item: T; selected: boolean; selecting: boolean; toggle: () => void }) => unknown\n /** The item's title; `item.name` by default. */\n title?: (props: { item: T }) => unknown\n /** Right-aligned meta: tags, an avatar, a date. Keep it to three or four things. */\n meta?: (props: { item: T }) => unknown\n /** Controls at the end of a group's header, e.g. Show and Hide. */\n 'group-actions'?: (props: { group: DataListGroup<T> }) => unknown\n /** Shown when every group is empty, e.g. an EmptyState. */\n empty?: () => unknown\n}>()\n\nconst id = useId()\nconst root = useTemplateRef<HTMLElement>('root')\n\nconst idOf = (item: T): unknown => item[props.rowKey ?? 'id']\nconst interactive = computed(() => !!props.onRowClick || props.selectable)\nconst isEmpty = computed(() => !props.loading && props.groups.every((group) => group.items.length === 0))\n\nfunction toggleGroup(groupId: string) {\n collapsed.value = collapsed.value.includes(groupId)\n ? collapsed.value.filter((x) => x !== groupId)\n : [...collapsed.value, groupId]\n}\n\nconst collapsibleGroup = (group: DataListGroup<T>) => group.collapsible ?? props.collapsible\nconst isCollapsed = (group: DataListGroup<T>) => collapsibleGroup(group) && collapsed.value.includes(group.id)\nconst visibleItems = computed(() => props.groups.filter((group) => !isCollapsed(group)).flatMap((group) => group.items))\n\n// Where a range starts: the row last toggled.\nlet anchorKey: unknown = undefined\n\nfunction toggle(item: T) {\n const key = idOf(item)\n anchorKey = key\n selected.value = selected.value.includes(key) ? selected.value.filter((x) => x !== key) : [...selected.value, key]\n}\n\nfunction selectRange(item: T) {\n const keys = visibleItems.value.map(idOf)\n const to = keys.indexOf(idOf(item))\n const from = keys.indexOf(anchorKey)\n const span = from < 0 ? [keys[to]] : keys.slice(Math.min(from, to), Math.max(from, to) + 1)\n if (from < 0) anchorKey = idOf(item)\n selected.value = [...selected.value, ...span.filter((key) => !selected.value.includes(key))]\n}\n\nfunction select(...items: T[]) {\n const keys = items.map(idOf).filter((key) => !selected.value.includes(key))\n if (keys.length) selected.value = [...selected.value, ...new Set(keys)]\n}\n\nfunction clickRow(event: MouseEvent, item: T) {\n if (props.selectable && event.shiftKey) selectRange(item)\n else if (props.selectable && (event.metaKey || event.ctrlKey)) toggle(item)\n // Leading checkboxes stand in for the row's mark, so while selecting a click selects, as in a mail list.\n else if (props.selectable && leading.value && selected.value.length) toggle(item)\n else props.onRowClick?.(item)\n}\n\n// A shift-click selects rather than highlighting the text between.\nfunction onRowMousedown(event: MouseEvent) {\n if (props.selectable && event.shiftKey) event.preventDefault()\n}\n\n// ↑ ↓ or j k move between rows, x selects, Enter and Space open; with Shift, ↑ ↓ extend the selection and Space\n// selects a range.\nfunction onKeydown(event: KeyboardEvent, item: T) {\n if (event.target !== event.currentTarget || event.metaKey || event.ctrlKey || event.altKey) return\n // A collapsed group's rows are still in the DOM, hidden.\n const rows = [...(root.value?.querySelectorAll<HTMLElement>('[data-list-row]') ?? [])].filter(\n (row) => row.closest('ul')?.style.display !== 'none'\n )\n const i = rows.indexOf(event.currentTarget as HTMLElement)\n const down = event.key === 'ArrowDown' || event.key === 'j'\n const up = event.key === 'ArrowUp' || event.key === 'k'\n if ((down || up) && event.shiftKey && props.selectable) {\n const j = down ? Math.min(rows.length - 1, i + 1) : Math.max(0, i - 1)\n const next = visibleItems.value[j]\n select(item, ...(next ? [next] : []))\n rows[j]?.focus()\n } else if (down) rows[Math.min(rows.length - 1, i + 1)]?.focus()\n else if (up) rows[Math.max(0, i - 1)]?.focus()\n else if (event.key === ' ' && event.shiftKey && props.selectable) selectRange(item)\n else if (event.key.toLowerCase() === 'x' && props.selectable) toggle(item)\n else if ((event.key === 'Enter' || event.key === ' ') && props.onRowClick) props.onRowClick(item)\n else return\n event.preventDefault()\n}\n\nconst cards = computed(() => props.variant === 'cards')\nconst leading = computed(() => props.selectable && props.checkboxPlacement === 'leading')\nconst gutter = computed(() => props.selectable && props.checkboxPlacement === 'gutter')\nconst tones = { sunken: 'bg-sui-sunken', surface: 'bg-sui-surface', canvas: 'bg-sui-canvas' }\nconst headerTone = computed(() => tones[props.groupHeaderTone ?? (cards.value ? 'surface' : 'sunken')])\nconst sizes = computed(() => {\n const style: Record<string, string> = {}\n if (props.rowHeight !== undefined) style['--sui-list-row'] = `${props.rowHeight}px`\n if (props.groupHeaderHeight !== undefined) style['--sui-list-header'] = `${props.groupHeaderHeight}px`\n return Object.keys(style).length ? style : undefined\n})\nconst card = 'overflow-clip rounded-xl border border-sui-line-subtle bg-sui-surface'\nconst custom = (group: DataListGroup<T>) => !!slots['group-header'] || group.header !== undefined\nconst groupName = (group: DataListGroup<T>) => group.label ?? group.name ?? ''\n\nconst skeletonWidths = ['42%', '58%', '35%', '50%', '46%']\nconst iconButton =\n 'flex size-6 shrink-0 items-center justify-center rounded-md text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-line-subtle hover:text-sui-ink focus-visible:sui-ring-inset'\n</script>\n\n<!-- A grouped list: one dense line per record under sticky, collapsible group headers. -->\n<template>\n <div ref=\"root\" class=\"flex flex-col text-13 text-sui-ink\" :class=\"cards ? 'gap-3' : card\" :style=\"sizes\">\n <div v-if=\"isEmpty && $slots.empty\" :class=\"cards && card\">\n <slot name=\"empty\" />\n </div>\n <section v-else-if=\"loading\" :aria-busy=\"true\" :class=\"cards && card\">\n <div\n v-for=\"(width, i) in skeletonWidths\"\n :key=\"i\"\n aria-hidden=\"true\"\n class=\"flex h-[var(--sui-list-row,2.5rem)] items-center gap-2.5 pr-4 pl-1\"\n >\n <span class=\"w-6 shrink-0\" />\n <Skeleton height=\"0.75rem\" :width=\"width\" />\n <span class=\"flex-1\" />\n <Skeleton height=\"0.75rem\" width=\"64px\" />\n </div>\n </section>\n <template v-else>\n <section\n v-for=\"group in groups\"\n :key=\"group.id\"\n :aria-label=\"group.label\"\n :aria-labelledby=\"!group.label && (group.name || custom(group)) ? `${id}-${group.id}-name` : undefined\"\n :class=\"cards ? card : 'border-t border-sui-line-subtle first:border-t-0'\"\n >\n <header\n v-if=\"group.name || custom(group)\"\n class=\"flex h-[var(--sui-list-header,2.25rem)] items-center gap-2 border-b border-sui-line-subtle pr-2\"\n :class=\"[headerTone, !cards && 'sticky top-0 z-10', collapsibleGroup(group) ? 'pl-1.5' : 'pl-4']\"\n >\n <button\n v-if=\"collapsibleGroup(group)\"\n :aria-controls=\"`${id}-${group.id}`\"\n :aria-expanded=\"!collapsed.includes(group.id)\"\n :aria-label=\"collapsed.includes(group.id) ? expandLabel : collapseLabel\"\n :class=\"iconButton\"\n type=\"button\"\n @click=\"toggleGroup(group.id)\"\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3 fill-none stroke-current transition-transform duration-150\"\n :class=\"isCollapsed(group) && '-rotate-90'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path d=\"M3 4.5 6 7.5l3-3\" />\n </svg>\n </button>\n <component\n :is=\"`h${headingLevel}`\"\n v-if=\"custom(group)\"\n :id=\"`${id}-${group.id}-name`\"\n class=\"m-0 flex min-w-0 items-center gap-2 text-13 font-medium text-sui-ink\"\n >\n <slot\n :collapsed=\"collapsed.includes(group.id)\"\n :count=\"group.count ?? group.items.length\"\n :group=\"group\"\n name=\"group-header\"\n >{{ group.header }}</slot\n >\n </component>\n <template v-else>\n <slot :group=\"group\" name=\"group-leading\" />\n <component\n :is=\"`h${headingLevel}`\"\n :id=\"`${id}-${group.id}-name`\"\n class=\"m-0 text-13 font-medium text-sui-ink\"\n >\n {{ group.name }}\n </component>\n <span class=\"text-13 text-sui-ink-muted tabular-nums\">{{ group.count ?? group.items.length }}</span>\n </template>\n <span class=\"ml-auto flex items-center gap-1\">\n <slot :group=\"group\" name=\"group-actions\" />\n </span>\n <button\n v-if=\"onNew\"\n :aria-label=\"newLabel.replace('{group}', groupName(group))\"\n :class=\"iconButton\"\n type=\"button\"\n @click=\"onNew(group)\"\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 14 14\"\n >\n <path d=\"M7 2.5v9M2.5 7h9\" />\n </svg>\n </button>\n </header>\n <ul v-show=\"!isCollapsed(group)\" :id=\"`${id}-${group.id}`\" class=\"m-0 list-none p-0\">\n <ContextMenu\n v-for=\"item in group.items\"\n :key=\"idOf(item) as PropertyKey\"\n :disabled=\"!contextItems\"\n :items=\"contextItems?.(item)\"\n :label=\"contextLabel\"\n @click-item=\"emit('context-item', $event, item)\"\n >\n <li\n class=\"group/row relative flex h-[var(--sui-list-row,2.5rem)] items-center transition-colors duration-100 has-focus-visible:sui-ring-inset\"\n :class=\"[\n dividers && '[&+&]:border-t [&+&]:border-sui-line-subtle',\n selected.includes(idOf(item))\n ? 'bg-sui-accent-wash'\n : 'hover:bg-sui-sunken has-focus-visible:bg-sui-sunken'\n ]\"\n :style=\"item.depth ? { paddingLeft: `${item.depth * 22}px` } : undefined\"\n >\n <!-- Outside the row, which is a button, over the leading slot's first mark: 16px in, or more for a child. -->\n <span\n v-if=\"leading\"\n class=\"absolute top-1/2 z-[1] flex size-4 -translate-y-1/2 items-center justify-center\"\n :class=\"!selected.length && 'hidden group-hover/row:flex group-has-focus-visible/row:flex'\"\n data-list-check\n :style=\"{ left: `${16 + (item.depth ?? 0) * 22}px` }\"\n >\n <Checkbox\n :aria-label=\"selectLabel\"\n :model-value=\"selected.includes(idOf(item))\"\n tabindex=\"-1\"\n @update:model-value=\"toggle(item)\"\n />\n </span>\n <span\n v-if=\"gutter\"\n class=\"flex w-7 shrink-0 justify-end transition-opacity duration-100\"\n :class=\"selected.length ? 'opacity-100' : 'opacity-0 group-hover/row:opacity-100'\"\n >\n <Checkbox\n :aria-label=\"selectLabel\"\n :model-value=\"selected.includes(idOf(item))\"\n tabindex=\"-1\"\n @update:model-value=\"toggle(item)\"\n />\n </span>\n <div\n class=\"flex h-full min-w-0 flex-1 items-center gap-2.5 pr-4 outline-hidden\"\n :class=\"[gutter ? 'pl-2.5' : 'pl-4', (onRowClick || selectable) && 'cursor-pointer']\"\n data-list-row\n :role=\"onRowClick ? 'button' : undefined\"\n :tabindex=\"interactive ? 0 : undefined\"\n @click=\"clickRow($event, item)\"\n @keydown=\"onKeydown($event, item)\"\n @mousedown=\"onRowMousedown\"\n >\n <span\n v-if=\"$slots.leading\"\n class=\"flex shrink-0 items-center gap-2 text-sui-ink-muted tabular-nums\"\n :class=\"\n leading &&\n (selected.length\n ? '[&>*:first-child]:invisible'\n : 'group-hover/row:[&>*:first-child]:invisible group-has-focus-visible/row:[&>*:first-child]:invisible')\n \"\n >\n <slot\n :item=\"item\"\n name=\"leading\"\n :selected=\"selected.includes(idOf(item))\"\n :selecting=\"selected.length > 0\"\n :toggle=\"() => toggle(item)\"\n />\n </span>\n <span class=\"min-w-0 flex-1 truncate font-medium text-sui-ink\">\n <slot :item=\"item\" name=\"title\">{{ item.name }}</slot>\n </span>\n <span\n v-if=\"$slots.meta\"\n class=\"flex shrink-0 items-center gap-2 text-xs text-sui-ink-muted tabular-nums\"\n >\n <slot :item=\"item\" name=\"meta\" />\n </span>\n </div>\n </li>\n </ContextMenu>\n </ul>\n </section>\n </template>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DataList.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","_useSlots","_openBlock","_createElementBlock","_normalizeClass","_normalizeStyle","_renderSlot","_Fragment","_renderList","_createElementVNode","_createCommentVNode","_createBlock","Skeleton","_createVNode","_unref","_resolveDynamicComponent","_withCtx","_createTextVNode","_toDisplayString","_withDirectives","ContextMenu","Checkbox","_vShow","Skeleton_default","Checkbox_default","ContextMenu_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","card","iconButton","DataList_vue_vue_type_script_setup_true_lang_default","\"selected\"","\"selectedModifiers\"","\"collapsed\"","\"collapsedModifiers\"","__emit","props","__props","emit","selected","useModel","collapsed","slots","useSlots","id","useId","root","useTemplateRef","idOf","item","interactive","computed","isEmpty","group","toggleGroup","groupId","x","collapsibleGroup","isCollapsed","visibleItems","anchorKey","toggle","key","selectRange","keys","to","from","span","select","items","clickRow","event","leading","onRowMousedown","onKeydown","rows","row","i","down","up","j","next","cards","gutter","tones","headerTone","sizes","style","custom","groupName","skeletonWidths","skeletonGroupWidths","headerBar","openBlock","createElementBlock","normalizeClass","normalizeStyle","_ctx","renderSlot","Fragment","renderList","g","createElementVNode","createCommentVNode","r","createBlock","createVNode","_cache","unref","resolveDynamicComponent","withCtx","createTextVNode","toDisplayString","withDirectives","$event","vShow"],"sources":["../../../src/components/DataList/DataList.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed, useId, useTemplateRef } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport ContextMenu from '../ContextMenu/ContextMenu.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { DropdownMenuAction, DropdownMenuEntry } from '../internal/menu'\nimport type { DataListGroup } from './types'\n\nexport interface DataListProps<T> {\n groups: DataListGroup<T>[]\n /** The item field that identifies it. An item's `depth` indents it as a child. */\n rowKey?: keyof T & string\n /** A checkbox bound to `v-model:selected`: it shows on hover and focus, and on every row once anything is selected.\n * Shift-click (or Shift+Space) selects a range, Cmd or Ctrl-click toggles one row, Shift+↑ ↓ extends. */\n selectable?: boolean\n /** gutter: the checkbox in its own column. leading: it takes the place of the `leading` slot's first mark. */\n checkboxPlacement?: 'gutter' | 'leading'\n loading?: boolean\n /** While loading, the placeholder groups drawn, as each one's number of rows. */\n loadingGroups?: number[]\n /** joined: one frame, sticky sunken group headers. cards: each group its own card, 12px apart, headers not sticky. */\n variant?: 'joined' | 'cards'\n /** The group headings' level, to fit the page's outline. */\n headingLevel?: 2 | 3 | 4 | 5 | 6\n /** The group headers' ground; by default sunken when joined, surface as cards. */\n groupHeaderTone?: 'sunken' | 'surface' | 'canvas'\n /** The group headers' height in px (36 by default); sets `--sui-list-header`. */\n groupHeaderHeight?: number\n /** Groups fold away under a chevron; a group's own `collapsible` wins. */\n collapsible?: boolean\n /** The rows' height in px, such as 44 (40 by default); sets `--sui-list-row`. */\n rowHeight?: number\n /** A hairline between rows. */\n dividers?: boolean\n /** Wraps each row in a ContextMenu of these items (`@context-item`); return [] for none. */\n contextItems?: (item: T) => DropdownMenuEntry[]\n /** The context menu's accessible name. */\n contextLabel?: string\n /** Makes rows open on click and Enter (`@row-click`). */\n onRowClick?: (item: T) => void\n /** Adds a + to each group's header (`@new`). */\n onNew?: (group: DataListGroup<T>) => void\n /** The + button's name; `{group}` is the group's name. */\n newLabel?: string\n collapseLabel?: string\n expandLabel?: string\n selectLabel?: string\n}\n\nconst props = withDefaults(defineProps<DataListProps<T>>(), {\n rowKey: 'id' as never,\n loadingGroups: () => [4, 2],\n variant: 'joined',\n checkboxPlacement: 'gutter',\n headingLevel: 3,\n groupHeaderTone: undefined,\n groupHeaderHeight: undefined,\n collapsible: true,\n rowHeight: undefined,\n dividers: false,\n contextItems: undefined,\n contextLabel: undefined,\n onRowClick: undefined,\n onNew: undefined,\n newLabel: 'New in {group}',\n collapseLabel: 'Collapse group',\n expandLabel: 'Expand group',\n selectLabel: 'Select'\n})\n\nconst emit = defineEmits<{ 'context-item': [action: DropdownMenuAction, item: T] }>()\n\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\nconst collapsed = defineModel<string[]>('collapsed', { default: () => [] })\n\nconst slots = defineSlots<{\n /** Marks before a group's name, e.g. a status icon. */\n 'group-leading'?: (props: { group: DataListGroup<T> }) => unknown\n /** Your own group header in place of the name and count, e.g. a status Badge and a count; inside the heading. */\n 'group-header'?: (props: { group: DataListGroup<T>; count: number; collapsed: boolean }) => unknown\n /** Small marks before an item's title: a status icon, an id, an avatar. With `checkboxPlacement=\"leading\"`, the\n * first mark gives way to the checkbox. */\n leading?: (props: { item: T; selected: boolean; selecting: boolean; toggle: () => void }) => unknown\n /** The item's title; `item.name` by default. */\n title?: (props: { item: T }) => unknown\n /** Right-aligned meta: tags, an avatar, a date. Keep it to three or four things. */\n meta?: (props: { item: T }) => unknown\n /** Controls at the end of a group's header, e.g. Show and Hide. */\n 'group-actions'?: (props: { group: DataListGroup<T> }) => unknown\n /** Shown when every group is empty, e.g. an EmptyState. */\n empty?: () => unknown\n}>()\n\nconst id = useId()\nconst root = useTemplateRef<HTMLElement>('root')\n\nconst idOf = (item: T): unknown => item[props.rowKey ?? 'id']\nconst interactive = computed(() => !!props.onRowClick || props.selectable)\nconst isEmpty = computed(() => !props.loading && props.groups.every((group) => group.items.length === 0))\n\nfunction toggleGroup(groupId: string) {\n collapsed.value = collapsed.value.includes(groupId)\n ? collapsed.value.filter((x) => x !== groupId)\n : [...collapsed.value, groupId]\n}\n\nconst collapsibleGroup = (group: DataListGroup<T>) => group.collapsible ?? props.collapsible\nconst isCollapsed = (group: DataListGroup<T>) => collapsibleGroup(group) && collapsed.value.includes(group.id)\nconst visibleItems = computed(() => props.groups.filter((group) => !isCollapsed(group)).flatMap((group) => group.items))\n\n// Where a range starts: the row last toggled.\nlet anchorKey: unknown = undefined\n\nfunction toggle(item: T) {\n const key = idOf(item)\n anchorKey = key\n selected.value = selected.value.includes(key) ? selected.value.filter((x) => x !== key) : [...selected.value, key]\n}\n\nfunction selectRange(item: T) {\n const keys = visibleItems.value.map(idOf)\n const to = keys.indexOf(idOf(item))\n const from = keys.indexOf(anchorKey)\n const span = from < 0 ? [keys[to]] : keys.slice(Math.min(from, to), Math.max(from, to) + 1)\n if (from < 0) anchorKey = idOf(item)\n selected.value = [...selected.value, ...span.filter((key) => !selected.value.includes(key))]\n}\n\nfunction select(...items: T[]) {\n const keys = items.map(idOf).filter((key) => !selected.value.includes(key))\n if (keys.length) selected.value = [...selected.value, ...new Set(keys)]\n}\n\nfunction clickRow(event: MouseEvent, item: T) {\n if (props.selectable && event.shiftKey) selectRange(item)\n else if (props.selectable && (event.metaKey || event.ctrlKey)) toggle(item)\n // Leading checkboxes stand in for the row's mark, so while selecting a click selects, as in a mail list.\n else if (props.selectable && leading.value && selected.value.length) toggle(item)\n else props.onRowClick?.(item)\n}\n\n// A shift-click selects rather than highlighting the text between.\nfunction onRowMousedown(event: MouseEvent) {\n if (props.selectable && event.shiftKey) event.preventDefault()\n}\n\n// ↑ ↓ or j k move between rows, x selects, Enter and Space open; with Shift, ↑ ↓ extend the selection and Space\n// selects a range.\nfunction onKeydown(event: KeyboardEvent, item: T) {\n if (event.target !== event.currentTarget || event.metaKey || event.ctrlKey || event.altKey) return\n // A collapsed group's rows are still in the DOM, hidden.\n const rows = [...(root.value?.querySelectorAll<HTMLElement>('[data-list-row]') ?? [])].filter(\n (row) => row.closest('ul')?.style.display !== 'none'\n )\n const i = rows.indexOf(event.currentTarget as HTMLElement)\n const down = event.key === 'ArrowDown' || event.key === 'j'\n const up = event.key === 'ArrowUp' || event.key === 'k'\n if ((down || up) && event.shiftKey && props.selectable) {\n const j = down ? Math.min(rows.length - 1, i + 1) : Math.max(0, i - 1)\n const next = visibleItems.value[j]\n select(item, ...(next ? [next] : []))\n rows[j]?.focus()\n } else if (down) rows[Math.min(rows.length - 1, i + 1)]?.focus()\n else if (up) rows[Math.max(0, i - 1)]?.focus()\n else if (event.key === ' ' && event.shiftKey && props.selectable) selectRange(item)\n else if (event.key.toLowerCase() === 'x' && props.selectable) toggle(item)\n else if ((event.key === 'Enter' || event.key === ' ') && props.onRowClick) props.onRowClick(item)\n else return\n event.preventDefault()\n}\n\nconst cards = computed(() => props.variant === 'cards')\nconst leading = computed(() => props.selectable && props.checkboxPlacement === 'leading')\nconst gutter = computed(() => props.selectable && props.checkboxPlacement === 'gutter')\nconst tones = { sunken: 'bg-sui-sunken', surface: 'bg-sui-surface', canvas: 'bg-sui-canvas' }\nconst headerTone = computed(() => tones[props.groupHeaderTone ?? (cards.value ? 'surface' : 'sunken')])\nconst sizes = computed(() => {\n const style: Record<string, string> = {}\n if (props.rowHeight !== undefined) style['--sui-list-row'] = `${props.rowHeight}px`\n if (props.groupHeaderHeight !== undefined) style['--sui-list-header'] = `${props.groupHeaderHeight}px`\n return Object.keys(style).length ? style : undefined\n})\nconst card = 'overflow-clip rounded-xl border border-sui-line-subtle bg-sui-surface'\nconst custom = (group: DataListGroup<T>) => !!slots['group-header'] || group.header !== undefined\nconst groupName = (group: DataListGroup<T>) => group.label ?? group.name ?? ''\n\nconst skeletonWidths = ['42%', '58%', '35%', '50%', '46%', '38%']\nconst skeletonGroupWidths = ['5.5rem', '4rem', '4.75rem']\n// A Skeleton is sunken, so on a sunken header band its bars go a step darker.\nconst headerBar = computed(() => [\n 'animate-pulse',\n headerTone.value === tones.sunken ? 'bg-sui-line-subtle' : 'bg-sui-sunken'\n])\nconst iconButton =\n 'flex size-6 shrink-0 items-center justify-center rounded-md text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-line-subtle hover:text-sui-ink focus-visible:sui-ring-inset'\n</script>\n\n<!-- A grouped list: one dense line per record under sticky, collapsible group headers. -->\n<template>\n <div ref=\"root\" class=\"flex flex-col text-13 text-sui-ink\" :class=\"cards ? 'gap-3' : card\" :style=\"sizes\">\n <div v-if=\"isEmpty && $slots.empty\" :class=\"cards && card\">\n <slot name=\"empty\" />\n </div>\n <!-- Placeholder groups in the list's own shape: its header, rows, leading marks and meta. -->\n <template v-else-if=\"loading\">\n <section\n v-for=\"(rows, g) in loadingGroups\"\n :key=\"g\"\n aria-busy=\"true\"\n :class=\"cards ? card : 'border-t border-sui-line-subtle first:border-t-0'\"\n >\n <div\n aria-hidden=\"true\"\n class=\"flex h-[var(--sui-list-header,2.25rem)] items-center gap-2 border-b border-sui-line-subtle pr-2\"\n :class=\"[headerTone, collapsible ? 'pl-1.5' : 'pl-4']\"\n >\n <span v-if=\"collapsible\" class=\"size-6 shrink-0\" />\n <span\n v-if=\"$slots['group-leading'] || $slots['group-header']\"\n class=\"size-3.5 rounded-full\"\n :class=\"headerBar\"\n />\n <span class=\"h-2.5 rounded-md\" :class=\"headerBar\" :style=\"{ width: skeletonGroupWidths[g % 3] }\" />\n <span class=\"h-2.5 w-3.5 rounded-md\" :class=\"headerBar\" />\n </div>\n <div\n v-for=\"r in rows\"\n :key=\"r\"\n aria-hidden=\"true\"\n class=\"flex h-[var(--sui-list-row,2.5rem)] items-center gap-2.5 pr-4\"\n :class=\"[gutter ? 'pl-9.5' : 'pl-4', dividers && '[&+&]:border-t [&+&]:border-sui-line-subtle']\"\n >\n <Skeleton v-if=\"$slots.leading || leading\" shape=\"circle\" size=\"1.25rem\" />\n <Skeleton height=\"0.75rem\" :width=\"skeletonWidths[(g * 3 + r) % skeletonWidths.length]\" />\n <span class=\"flex-1\" />\n <template v-if=\"$slots.meta\">\n <Skeleton height=\"0.625rem\" width=\"6rem\" />\n <Skeleton height=\"0.625rem\" width=\"3.5rem\" />\n </template>\n </div>\n </section>\n </template>\n <template v-else>\n <section\n v-for=\"group in groups\"\n :key=\"group.id\"\n :aria-label=\"group.label\"\n :aria-labelledby=\"!group.label && (group.name || custom(group)) ? `${id}-${group.id}-name` : undefined\"\n :class=\"cards ? card : 'border-t border-sui-line-subtle first:border-t-0'\"\n >\n <header\n v-if=\"group.name || custom(group)\"\n class=\"flex h-[var(--sui-list-header,2.25rem)] items-center gap-2 border-b border-sui-line-subtle pr-2\"\n :class=\"[headerTone, !cards && 'sticky top-0 z-10', collapsibleGroup(group) ? 'pl-1.5' : 'pl-4']\"\n >\n <button\n v-if=\"collapsibleGroup(group)\"\n :aria-controls=\"`${id}-${group.id}`\"\n :aria-expanded=\"!collapsed.includes(group.id)\"\n :aria-label=\"collapsed.includes(group.id) ? expandLabel : collapseLabel\"\n :class=\"iconButton\"\n type=\"button\"\n @click=\"toggleGroup(group.id)\"\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3 fill-none stroke-current transition-transform duration-150\"\n :class=\"isCollapsed(group) && '-rotate-90'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path d=\"M3 4.5 6 7.5l3-3\" />\n </svg>\n </button>\n <component\n :is=\"`h${headingLevel}`\"\n v-if=\"custom(group)\"\n :id=\"`${id}-${group.id}-name`\"\n class=\"m-0 flex min-w-0 items-center gap-2 text-13 font-medium text-sui-ink\"\n >\n <slot\n :collapsed=\"collapsed.includes(group.id)\"\n :count=\"group.count ?? group.items.length\"\n :group=\"group\"\n name=\"group-header\"\n >{{ group.header }}</slot\n >\n </component>\n <template v-else>\n <slot :group=\"group\" name=\"group-leading\" />\n <component\n :is=\"`h${headingLevel}`\"\n :id=\"`${id}-${group.id}-name`\"\n class=\"m-0 text-13 font-medium text-sui-ink\"\n >\n {{ group.name }}\n </component>\n <span class=\"text-13 text-sui-ink-muted tabular-nums\">{{ group.count ?? group.items.length }}</span>\n </template>\n <span class=\"ml-auto flex items-center gap-1\">\n <slot :group=\"group\" name=\"group-actions\" />\n </span>\n <button\n v-if=\"onNew\"\n :aria-label=\"newLabel.replace('{group}', groupName(group))\"\n :class=\"iconButton\"\n type=\"button\"\n @click=\"onNew(group)\"\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 14 14\"\n >\n <path d=\"M7 2.5v9M2.5 7h9\" />\n </svg>\n </button>\n </header>\n <ul v-show=\"!isCollapsed(group)\" :id=\"`${id}-${group.id}`\" class=\"m-0 list-none p-0\">\n <ContextMenu\n v-for=\"item in group.items\"\n :key=\"idOf(item) as PropertyKey\"\n :disabled=\"!contextItems\"\n :items=\"contextItems?.(item)\"\n :label=\"contextLabel\"\n @click-item=\"emit('context-item', $event, item)\"\n >\n <li\n class=\"group/row relative flex h-[var(--sui-list-row,2.5rem)] items-center transition-colors duration-100 has-focus-visible:sui-ring-inset\"\n :class=\"[\n dividers && '[&+&]:border-t [&+&]:border-sui-line-subtle',\n selected.includes(idOf(item))\n ? 'bg-sui-accent-wash'\n : 'hover:bg-sui-sunken has-focus-visible:bg-sui-sunken'\n ]\"\n :style=\"item.depth ? { paddingLeft: `${item.depth * 22}px` } : undefined\"\n >\n <!-- Outside the row, which is a button, over the leading slot's first mark: 16px in, or more for a child. -->\n <span\n v-if=\"leading\"\n class=\"absolute top-1/2 z-[1] flex size-4 -translate-y-1/2 items-center justify-center\"\n :class=\"!selected.length && 'hidden group-hover/row:flex group-has-focus-visible/row:flex'\"\n data-list-check\n :style=\"{ left: `${16 + (item.depth ?? 0) * 22}px` }\"\n >\n <Checkbox\n :aria-label=\"selectLabel\"\n :model-value=\"selected.includes(idOf(item))\"\n tabindex=\"-1\"\n @update:model-value=\"toggle(item)\"\n />\n </span>\n <span\n v-if=\"gutter\"\n class=\"flex w-7 shrink-0 justify-end transition-opacity duration-100\"\n :class=\"selected.length ? 'opacity-100' : 'opacity-0 group-hover/row:opacity-100'\"\n >\n <Checkbox\n :aria-label=\"selectLabel\"\n :model-value=\"selected.includes(idOf(item))\"\n tabindex=\"-1\"\n @update:model-value=\"toggle(item)\"\n />\n </span>\n <div\n class=\"flex h-full min-w-0 flex-1 items-center gap-2.5 pr-4 outline-hidden\"\n :class=\"[gutter ? 'pl-2.5' : 'pl-4', (onRowClick || selectable) && 'cursor-pointer']\"\n data-list-row\n :role=\"onRowClick ? 'button' : undefined\"\n :tabindex=\"interactive ? 0 : undefined\"\n @click=\"clickRow($event, item)\"\n @keydown=\"onKeydown($event, item)\"\n @mousedown=\"onRowMousedown\"\n >\n <span\n v-if=\"$slots.leading\"\n class=\"flex shrink-0 items-center gap-2 text-sui-ink-muted tabular-nums\"\n :class=\"\n leading &&\n (selected.length\n ? '[&>*:first-child]:invisible'\n : 'group-hover/row:[&>*:first-child]:invisible group-has-focus-visible/row:[&>*:first-child]:invisible')\n \"\n >\n <slot\n :item=\"item\"\n name=\"leading\"\n :selected=\"selected.includes(idOf(item))\"\n :selecting=\"selected.length > 0\"\n :toggle=\"() => toggle(item)\"\n />\n </span>\n <span class=\"min-w-0 flex-1 truncate font-medium text-sui-ink\">\n <slot :item=\"item\" name=\"title\">{{ item.name }}</slot>\n </span>\n <span\n v-if=\"$slots.meta\"\n class=\"flex shrink-0 items-center gap-2 text-xs text-sui-ink-muted tabular-nums\"\n >\n <slot :item=\"item\" name=\"meta\" />\n </span>\n </div>\n </li>\n </ContextMenu>\n </ul>\n </section>\n </template>\n </div>\n</template>\n"],"mappings":"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"}
|