@sparklingopinions/sparkling-ui 0.4.1 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"Table.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","_useSlots","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_createCommentVNode","_Fragment","_renderList","_normalizeStyle","_normalizeClass","_createVNode","Checkbox","_createBlock","_resolveDynamicComponent","_withCtx","_createTextVNode","_renderSlot","Skeleton","_withModifiers","Skeleton_default","Checkbox_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","checkCell","Table_vue_vue_type_script_setup_true_lang_default","\"sort\"","\"sortModifiers\"","\"selected\"","\"selectedModifiers\"","props","__props","sort","useModel","selected","slots","useSlots","idOf","row","ids","computed","allSelected","id","someSelected","toggleAll","toggle","x","sortBy","dir","key","next","dirOf","ariaSort","column","state","columnCount","alignClass","skeletonWidths","sm","th","td","pad","headPad","openBlock","createElementBlock","createElementVNode","toDisplayString","createCommentVNode","Fragment","renderList","normalizeStyle","normalizeClass","createVNode","createBlock","resolveDynamicComponent","withCtx","createTextVNode","renderSlot","_ctx","i","j","_cache","withModifiers"],"sources":["../../../src/components/Table/Table.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { TableColumn, TableSort } from './types'\n\nexport interface TableProps<T> {\n columns: TableColumn[]\n rows: T[]\n /** The row field that identifies it. */\n rowKey?: keyof T & string\n /** A checkbox column bound to `v-model:selected`; selected rows tint accent-wash. */\n selectable?: boolean\n /** Skeleton rows in place of the body. */\n loading?: boolean\n loadingRows?: number\n /** md: 57px rows. sm: 40px, for dense lists. */\n size?: 'md' | 'sm'\n /** The table's name for screen readers. */\n caption?: string\n selectAllLabel?: string\n selectRowLabel?: string\n /** Makes rows clickable (`@row-click`), e.g. to open the record. */\n onRowClick?: (row: T) => void\n}\n\nconst props = withDefaults(defineProps<TableProps<T>>(), {\n rowKey: 'id' as never,\n loadingRows: 5,\n size: 'md',\n caption: undefined,\n selectAllLabel: 'Select all rows',\n selectRowLabel: 'Select row',\n onRowClick: undefined\n})\n\nconst sort = defineModel<TableSort | null>('sort', { default: null })\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\n\nconst slots = defineSlots<\n {\n /** Shown in place of the body when there are no rows, e.g. an EmptyState. */\n empty?: () => unknown\n /** Replaces the body when given, e.g. an inset danger Alert with a retry. */\n error?: () => unknown\n /** A canvas strip under the rows: a rows-per-page Select, the range, Pagination. */\n footer?: () => unknown\n } & {\n [K in `cell-${string}`]?: (props: { row: T; value: unknown }) => unknown\n }\n>()\n\nconst idOf = (row: T): unknown => row[props.rowKey ?? 'id']\nconst ids = computed(() => props.rows.map(idOf))\nconst allSelected = computed(() => ids.value.length > 0 && ids.value.every((id) => selected.value.includes(id)))\nconst someSelected = computed(() => !allSelected.value && ids.value.some((id) => selected.value.includes(id)))\n\nfunction toggleAll() {\n selected.value = allSelected.value\n ? selected.value.filter((id) => !ids.value.includes(id))\n : [...new Set([...selected.value, ...ids.value])]\n}\n\nfunction toggle(id: unknown) {\n selected.value = selected.value.includes(id) ? selected.value.filter((x) => x !== id) : [...selected.value, id]\n}\n\n// Sorting a column cycles ascending, descending, unsorted.\nfunction sortBy(key: string) {\n const dir = sort.value?.key === key ? sort.value.dir : null\n const next = dir === null ? 'asc' : dir === 'asc' ? 'desc' : null\n sort.value = next ? { key, dir: next } : null\n}\n\nfunction dirOf(key: string) {\n return sort.value?.key === key ? sort.value.dir : null\n}\n\nfunction ariaSort(column: TableColumn) {\n const dir = dirOf(column.key)\n if (dir) return dir === 'asc' ? 'ascending' : 'descending'\n return column.sortable ? 'none' : undefined\n}\n\nconst state = computed(() => {\n if (slots.error) return 'error'\n if (props.loading) return 'loading'\n return props.rows.length === 0 && slots.empty ? 'empty' : 'rows'\n})\n\nconst columnCount = computed(() => props.columns.length + (props.selectable ? 1 : 0))\nconst alignClass = { left: 'text-left', center: 'text-center', right: 'text-right' }\nconst skeletonWidths = ['60%', '45%', '70%', '35%', '55%']\n\nconst sm = computed(() => props.size === 'sm')\nconst th = computed(() => [\n 'border-b border-sui-line-subtle text-13 font-medium whitespace-nowrap',\n sm.value ? 'h-9' : 'h-11'\n])\nconst td = computed(() => [\n 'truncate border-b border-sui-line-subtle align-middle text-sui-ink-body group-last/row:border-b-0',\n sm.value ? 'h-10' : 'h-[3.5625rem]'\n])\nconst pad = computed(() => (sm.value ? 'px-3 py-1.5' : 'px-4 py-3'))\nconst headPad = computed(() => (sm.value ? 'px-3' : 'px-4'))\nconst checkCell = 'w-12 pl-4'\n</script>\n\n<!-- A data table: sunken header strip, sortable headers, selection, loading, empty and error states, a footer. -->\n<template>\n <div class=\"overflow-hidden rounded-xl border border-sui-line-subtle bg-sui-surface text-sm text-sui-ink\">\n <div class=\"overflow-x-auto\">\n <table class=\"w-full min-w-[var(--sui-table-min,720px)] table-fixed border-collapse\">\n <caption v-if=\"caption\" class=\"sr-only\">\n {{\n caption\n }}\n </caption>\n <colgroup>\n <col v-if=\"selectable\" class=\"w-12\" />\n <col\n v-for=\"column in columns\"\n :key=\"column.key\"\n :style=\"{ width: typeof column.width === 'number' ? `${column.width}px` : column.width }\"\n />\n </colgroup>\n <thead>\n <tr>\n <th v-if=\"selectable\" class=\"bg-sui-sunken\" :class=\"[th, checkCell]\">\n <Checkbox\n :aria-label=\"selectAllLabel\"\n :disabled=\"loading || rows.length === 0\"\n :indeterminate=\"someSelected\"\n :model-value=\"allSelected\"\n @update:model-value=\"toggleAll\"\n />\n </th>\n <component\n :is=\"column.label ? 'th' : 'td'\"\n v-for=\"column in columns\"\n :key=\"column.key\"\n :aria-sort=\"ariaSort(column)\"\n :class=\"[\n th,\n headPad,\n alignClass[column.align ?? 'left'],\n dirOf(column.key) ? 'bg-sui-accent-wash text-sui-accent' : 'bg-sui-sunken text-sui-ink-subtle'\n ]\"\n :scope=\"column.label ? 'col' : undefined\"\n >\n <button\n v-if=\"column.sortable\"\n class=\"inline-flex h-full w-full items-center gap-1.5 rounded-md outline-hidden focus-visible:sui-ring-inset\"\n :class=\"[\n column.align === 'right' && 'justify-end',\n column.align === 'center' && 'justify-center',\n !dirOf(column.key) && 'hover:text-sui-ink'\n ]\"\n type=\"button\"\n @click=\"sortBy(column.key)\"\n >\n {{ column.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3 shrink-0 fill-none stroke-current\"\n :class=\"!dirOf(column.key) && 'opacity-50'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path v-if=\"dirOf(column.key) === 'asc'\" d=\"M3 7.5 6 4.5l3 3\" />\n <path v-else-if=\"dirOf(column.key) === 'desc'\" d=\"M3 4.5 6 7.5l3-3\" />\n <path v-else d=\"M3.5 4.5 6 2l2.5 2.5M3.5 7.5 6 10l2.5-2.5\" />\n </svg>\n </button>\n <template v-else>{{ column.label }}</template>\n </component>\n </tr>\n </thead>\n <tbody :aria-busy=\"loading || undefined\">\n <tr v-if=\"state === 'error' || state === 'empty'\">\n <td class=\"p-0\" :colspan=\"columnCount\">\n <slot :name=\"state\" />\n </td>\n </tr>\n <template v-else-if=\"state === 'loading'\">\n <tr v-for=\"i in loadingRows\" :key=\"i\" aria-hidden=\"true\" class=\"group/row\">\n <td v-if=\"selectable\" :class=\"[td, checkCell]\"><Skeleton size=\"1rem\" /></td>\n <td v-for=\"(column, j) in columns\" :key=\"column.key\" :class=\"[td, pad]\">\n <Skeleton height=\"0.75rem\" :width=\"skeletonWidths[(i + j) % 5]\" />\n </td>\n </tr>\n </template>\n <template v-else>\n <tr\n v-for=\"row in rows\"\n :key=\"idOf(row) as PropertyKey\"\n :aria-selected=\"selectable ? selected.includes(idOf(row)) : undefined\"\n class=\"group/row transition-colors duration-150\"\n :class=\"[\n selected.includes(idOf(row)) ? 'bg-sui-accent-wash' : 'hover:bg-sui-sunken',\n onRowClick && 'cursor-pointer'\n ]\"\n @click=\"onRowClick?.(row)\"\n >\n <td v-if=\"selectable\" :class=\"[td, checkCell]\" @click.stop>\n <Checkbox\n :aria-label=\"selectRowLabel\"\n :model-value=\"selected.includes(idOf(row))\"\n @update:model-value=\"toggle(idOf(row))\"\n />\n </td>\n <td v-for=\"column in columns\" :key=\"column.key\" :class=\"[td, pad, alignClass[column.align ?? 'left']]\">\n <slot :name=\"`cell-${column.key}`\" :row=\"row\" :value=\"row[column.key]\">\n <template v-if=\"row[column.key] != null && row[column.key] !== ''\">{{ row[column.key] }}</template>\n <span v-else class=\"text-sui-ink-muted\">–</span>\n </slot>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n <div\n v-if=\"$slots.footer\"\n class=\"flex flex-wrap items-center justify-between gap-3 border-t border-sui-line-subtle bg-sui-canvas py-2 pr-3 pl-4 text-13 text-sui-ink-muted\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"Table.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","_useSlots","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_createCommentVNode","_Fragment","_renderList","_normalizeStyle","_normalizeClass","_createVNode","Checkbox","_createBlock","_resolveDynamicComponent","_withCtx","_createTextVNode","_renderSlot","Skeleton","_withModifiers","Skeleton_default","Checkbox_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","checkCell","Table_vue_vue_type_script_setup_true_lang_default","\"sort\"","\"sortModifiers\"","\"selected\"","\"selectedModifiers\"","props","__props","sort","useModel","selected","slots","useSlots","idOf","row","ids","computed","allSelected","id","someSelected","toggleAll","toggle","x","sortBy","dir","key","next","dirOf","ariaSort","column","state","columnCount","alignClass","skeletonWidths","sm","th","td","pad","headPad","openBlock","createElementBlock","createElementVNode","toDisplayString","createCommentVNode","Fragment","renderList","normalizeStyle","normalizeClass","createVNode","createBlock","resolveDynamicComponent","withCtx","createTextVNode","renderSlot","_ctx","i","j","_cache","withModifiers"],"sources":["../../../src/components/Table/Table.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { computed } from 'vue'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Skeleton from '../Skeleton/Skeleton.vue'\nimport type { TableColumn, TableSort } from './types'\n\nexport interface TableProps<T> {\n columns: TableColumn[]\n rows: T[]\n /** The row field that identifies it. */\n rowKey?: keyof T & string\n /** A checkbox column bound to `v-model:selected`; selected rows tint accent-wash. */\n selectable?: boolean\n /** Skeleton rows in place of the body. */\n loading?: boolean\n loadingRows?: number\n /** md: 57px rows. sm: 40px, for dense lists. */\n size?: 'md' | 'sm'\n /** The table's name for screen readers. */\n caption?: string\n selectAllLabel?: string\n selectRowLabel?: string\n /** Makes rows clickable (`@row-click`), e.g. to open the record. */\n onRowClick?: (row: T) => void\n}\n\nconst props = withDefaults(defineProps<TableProps<T>>(), {\n rowKey: 'id' as never,\n loadingRows: 5,\n size: 'md',\n caption: undefined,\n selectAllLabel: 'Select all rows',\n selectRowLabel: 'Select row',\n onRowClick: undefined\n})\n\nconst sort = defineModel<TableSort | null>('sort', { default: null })\nconst selected = defineModel<unknown[]>('selected', { default: () => [] })\n\nconst slots = defineSlots<\n {\n /** Shown in place of the body when there are no rows, e.g. an EmptyState. */\n empty?: () => unknown\n /** Replaces the body when given, e.g. an inset danger Alert with a retry. */\n error?: () => unknown\n /** A canvas strip under the rows: a rows-per-page Select, the range, Pagination. */\n footer?: () => unknown\n } & {\n [K in `cell-${string}`]?: (props: { row: T; value: unknown }) => unknown\n }\n>()\n\nconst idOf = (row: T): unknown => row[props.rowKey ?? 'id']\nconst ids = computed(() => props.rows.map(idOf))\nconst allSelected = computed(() => ids.value.length > 0 && ids.value.every((id) => selected.value.includes(id)))\nconst someSelected = computed(() => !allSelected.value && ids.value.some((id) => selected.value.includes(id)))\n\nfunction toggleAll() {\n selected.value = allSelected.value\n ? selected.value.filter((id) => !ids.value.includes(id))\n : [...new Set([...selected.value, ...ids.value])]\n}\n\nfunction toggle(id: unknown) {\n selected.value = selected.value.includes(id) ? selected.value.filter((x) => x !== id) : [...selected.value, id]\n}\n\n// Sorting a column cycles ascending, descending, unsorted.\nfunction sortBy(key: string) {\n const dir = sort.value?.key === key ? sort.value.dir : null\n const next = dir === null ? 'asc' : dir === 'asc' ? 'desc' : null\n sort.value = next ? { key, dir: next } : null\n}\n\nfunction dirOf(key: string) {\n return sort.value?.key === key ? sort.value.dir : null\n}\n\nfunction ariaSort(column: TableColumn) {\n const dir = dirOf(column.key)\n if (dir) return dir === 'asc' ? 'ascending' : 'descending'\n return column.sortable ? 'none' : undefined\n}\n\nconst state = computed(() => {\n if (slots.error) return 'error'\n if (props.loading) return 'loading'\n return props.rows.length === 0 && slots.empty ? 'empty' : 'rows'\n})\n\nconst columnCount = computed(() => props.columns.length + (props.selectable ? 1 : 0))\nconst alignClass = { left: 'text-left', center: 'text-center', right: 'text-right' }\nconst skeletonWidths = ['60%', '45%', '70%', '35%', '55%']\n\nconst sm = computed(() => props.size === 'sm')\nconst th = computed(() => [\n 'border-b border-sui-line-subtle text-13 font-medium whitespace-nowrap',\n sm.value ? 'h-9' : 'h-11'\n])\nconst td = computed(() => [\n 'border-b border-sui-line-subtle align-middle text-sui-ink-body group-last/row:border-b-0',\n sm.value ? 'h-10' : 'h-[3.5625rem]'\n])\nconst pad = computed(() => (sm.value ? 'px-3 py-1.5' : 'px-4 py-3'))\nconst headPad = computed(() => (sm.value ? 'px-3' : 'px-4'))\nconst checkCell = 'w-12 pl-4'\n</script>\n\n<!-- A data table: sunken header strip, sortable headers, selection, loading, empty and error states, a footer. -->\n<template>\n <div class=\"overflow-hidden rounded-xl border border-sui-line-subtle bg-sui-surface text-sm text-sui-ink\">\n <div class=\"overflow-x-auto\">\n <table class=\"w-full min-w-[var(--sui-table-min,720px)] table-fixed border-collapse\">\n <caption v-if=\"caption\" class=\"sr-only\">\n {{\n caption\n }}\n </caption>\n <colgroup>\n <col v-if=\"selectable\" class=\"w-12\" />\n <col\n v-for=\"column in columns\"\n :key=\"column.key\"\n :style=\"{ width: typeof column.width === 'number' ? `${column.width}px` : column.width }\"\n />\n </colgroup>\n <thead>\n <tr>\n <th v-if=\"selectable\" class=\"bg-sui-sunken\" :class=\"[th, checkCell]\">\n <Checkbox\n :aria-label=\"selectAllLabel\"\n :disabled=\"loading || rows.length === 0\"\n :indeterminate=\"someSelected\"\n :model-value=\"allSelected\"\n @update:model-value=\"toggleAll\"\n />\n </th>\n <component\n :is=\"column.label ? 'th' : 'td'\"\n v-for=\"column in columns\"\n :key=\"column.key\"\n :aria-sort=\"ariaSort(column)\"\n :class=\"[\n th,\n headPad,\n alignClass[column.align ?? 'left'],\n dirOf(column.key) ? 'bg-sui-accent-wash text-sui-accent' : 'bg-sui-sunken text-sui-ink-subtle'\n ]\"\n :scope=\"column.label ? 'col' : undefined\"\n >\n <button\n v-if=\"column.sortable\"\n class=\"inline-flex h-full w-full items-center gap-1.5 rounded-md outline-hidden focus-visible:sui-ring-inset\"\n :class=\"[\n column.align === 'right' && 'justify-end',\n column.align === 'center' && 'justify-center',\n !dirOf(column.key) && 'hover:text-sui-ink'\n ]\"\n type=\"button\"\n @click=\"sortBy(column.key)\"\n >\n {{ column.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3 shrink-0 fill-none stroke-current\"\n :class=\"!dirOf(column.key) && 'opacity-50'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 12 12\"\n >\n <path v-if=\"dirOf(column.key) === 'asc'\" d=\"M3 7.5 6 4.5l3 3\" />\n <path v-else-if=\"dirOf(column.key) === 'desc'\" d=\"M3 4.5 6 7.5l3-3\" />\n <path v-else d=\"M3.5 4.5 6 2l2.5 2.5M3.5 7.5 6 10l2.5-2.5\" />\n </svg>\n </button>\n <template v-else>{{ column.label }}</template>\n </component>\n </tr>\n </thead>\n <tbody :aria-busy=\"loading || undefined\">\n <tr v-if=\"state === 'error' || state === 'empty'\">\n <td class=\"p-0\" :colspan=\"columnCount\">\n <slot :name=\"state\" />\n </td>\n </tr>\n <template v-else-if=\"state === 'loading'\">\n <tr v-for=\"i in loadingRows\" :key=\"i\" aria-hidden=\"true\" class=\"group/row\">\n <td v-if=\"selectable\" :class=\"[td, checkCell]\"><Skeleton size=\"1rem\" /></td>\n <td v-for=\"(column, j) in columns\" :key=\"column.key\" :class=\"[td, pad]\">\n <Skeleton height=\"0.75rem\" :width=\"skeletonWidths[(i + j) % 5]\" />\n </td>\n </tr>\n </template>\n <template v-else>\n <tr\n v-for=\"row in rows\"\n :key=\"idOf(row) as PropertyKey\"\n :aria-selected=\"selectable ? selected.includes(idOf(row)) : undefined\"\n class=\"group/row transition-colors duration-150\"\n :class=\"[\n selected.includes(idOf(row)) ? 'bg-sui-accent-wash' : 'hover:bg-sui-sunken',\n onRowClick && 'cursor-pointer'\n ]\"\n @click=\"onRowClick?.(row)\"\n >\n <td v-if=\"selectable\" :class=\"[td, checkCell]\" @click.stop>\n <Checkbox\n :aria-label=\"selectRowLabel\"\n :model-value=\"selected.includes(idOf(row))\"\n @update:model-value=\"toggle(idOf(row))\"\n />\n </td>\n <td\n v-for=\"column in columns\"\n :key=\"column.key\"\n :class=\"[\n td,\n pad,\n alignClass[column.align ?? 'left'],\n column.wrap ? 'break-words whitespace-normal' : 'truncate'\n ]\"\n >\n <slot :name=\"`cell-${column.key}`\" :row=\"row\" :value=\"row[column.key]\">\n <template v-if=\"row[column.key] != null && row[column.key] !== ''\">{{ row[column.key] }}</template>\n <span v-else class=\"text-sui-ink-muted\">–</span>\n </slot>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n <div\n v-if=\"$slots.footer\"\n class=\"flex flex-wrap items-center justify-between gap-3 border-t border-sui-line-subtle bg-sui-canvas py-2 pr-3 pl-4 text-13 text-sui-ink-muted\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n"],"mappings":"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"}
@@ -5,6 +5,8 @@ export interface TableColumn {
5
5
  width?: number | string;
6
6
  align?: 'left' | 'center' | 'right';
7
7
  sortable?: boolean;
8
+ /** Lets the cell's content wrap onto more lines, e.g. a name over a summary; cells otherwise truncate to one. */
9
+ wrap?: boolean;
8
10
  }
9
11
  export interface TableSort {
10
12
  key: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sparklingopinions/sparkling-ui",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "A product-agnostic Vue 3 component library, themed by semantic tokens",
5
5
  "type": "module",
6
6
  "license": "MIT",