@rotki/ui-library 3.0.0-beta.5 → 3.0.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/components/forms/auto-complete/RuiAutoCompleteSelection.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js +9 -6
- package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiDataTable.js.map +1 -1
- package/dist/components/tables/RuiDataTable.vue.d.ts +5 -0
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +12 -6
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableBody.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js +4 -3
- package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableRow.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table-styles.js +4 -4
- package/dist/components/tables/data-table-styles.js.map +1 -1
- package/dist/composables/tables/data-table/page-scroll.js +11 -1
- package/dist/composables/tables/data-table/page-scroll.js.map +1 -1
- package/dist/style.css +77 -11
- package/dist/web-types.json +11 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiAutoCompleteSelection.js","names":["_sfc_main"],"sources":["../../../../src/components/forms/auto-complete/RuiAutoCompleteSelection.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"TItem\">\nimport RuiChip from '@/components/chips/RuiChip.vue';\nimport { getTextToken } from '@/utils/helpers';\n\nexport interface AutoCompleteSelectionProps<TItem> {\n items: TItem[];\n chips: boolean;\n dense: boolean;\n multiple: boolean;\n searchInputFocused: boolean;\n hideSelectionWrapper: boolean;\n getIdentifier: (item: TItem) => unknown;\n getText: (item: TItem) => string | undefined;\n chipAttrs: (item: TItem, index: number) => Record<string, unknown>;\n /** The chip Backspace and Delete act on, -1 for none, drawn with a ring though it never takes focus. */\n selectedIndex: number;\n /** Selects a clicked chip, with focus left in the input. */\n selectChip: (index: number) => void;\n}\n\nconst {\n chipAttrs,\n selectChip,\n selectedIndex,\n chips,\n dense,\n getIdentifier,\n getText,\n hideSelectionWrapper,\n items,\n multiple,\n searchInputFocused,\n} = defineProps<AutoCompleteSelectionProps<TItem>>();\n\nconst slots = defineSlots<{\n prepend?: (props: { index: number; item: TItem }) => any;\n default?: (props: { index: number; item: TItem; chipAttrs: Record<string, unknown> }) => any;\n}>();\n\n/**\n * Without a chip, a selected value is only drawn when it cannot be read off the\n * search input: while picking several values, or while the input is unfocused\n * and a slot renders the selection itself.\n */\nconst showPlainSelection = computed<boolean>(() =>\n multiple || (!searchInputFocused && (!!slots.prepend || !!slots.default)),\n);\n</script>\n\n<template>\n <template\n v-for=\"(item, i) in items\"\n :key=\"getIdentifier(item)?.toString()\"\n >\n <!--\n Not a clickable chip: that would make it a button around its own close button. It never takes\n focus either, which stays in the input; the wrapper, which takes no box, selects it on a click.\n -->\n <span\n v-if=\"chips\"\n class=\"contents\"\n @click.stop=\"selectChip(i)\"\n >\n <RuiChip\n :key=\"getTextToken(getIdentifier(item))\"\n :size=\"dense ? 'sm' : 'md'\"\n closeable\n close-unfocusable\n :class=\"{\n 'leading-3': dense,\n // drawn inside the chip's edge: the field clips anything outside it\n 'outline-2 outline-solid outline-rui-primary -outline-offset-2': i === selectedIndex,\n }\"\n :data-selected=\"i === selectedIndex || undefined\"\n v-bind=\"chipAttrs(item, i)\"\n >\n <
|
|
1
|
+
{"version":3,"file":"RuiAutoCompleteSelection.js","names":["_sfc_main"],"sources":["../../../../src/components/forms/auto-complete/RuiAutoCompleteSelection.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"TItem\">\nimport RuiChip from '@/components/chips/RuiChip.vue';\nimport { getTextToken } from '@/utils/helpers';\n\nexport interface AutoCompleteSelectionProps<TItem> {\n items: TItem[];\n chips: boolean;\n dense: boolean;\n multiple: boolean;\n searchInputFocused: boolean;\n hideSelectionWrapper: boolean;\n getIdentifier: (item: TItem) => unknown;\n getText: (item: TItem) => string | undefined;\n chipAttrs: (item: TItem, index: number) => Record<string, unknown>;\n /** The chip Backspace and Delete act on, -1 for none, drawn with a ring though it never takes focus. */\n selectedIndex: number;\n /** Selects a clicked chip, with focus left in the input. */\n selectChip: (index: number) => void;\n}\n\nconst {\n chipAttrs,\n selectChip,\n selectedIndex,\n chips,\n dense,\n getIdentifier,\n getText,\n hideSelectionWrapper,\n items,\n multiple,\n searchInputFocused,\n} = defineProps<AutoCompleteSelectionProps<TItem>>();\n\nconst slots = defineSlots<{\n prepend?: (props: { index: number; item: TItem }) => any;\n default?: (props: { index: number; item: TItem; chipAttrs: Record<string, unknown> }) => any;\n}>();\n\n/**\n * Without a chip, a selected value is only drawn when it cannot be read off the\n * search input: while picking several values, or while the input is unfocused\n * and a slot renders the selection itself.\n */\nconst showPlainSelection = computed<boolean>(() =>\n multiple || (!searchInputFocused && (!!slots.prepend || !!slots.default)),\n);\n</script>\n\n<template>\n <template\n v-for=\"(item, i) in items\"\n :key=\"getIdentifier(item)?.toString()\"\n >\n <!--\n Not a clickable chip: that would make it a button around its own close button. It never takes\n focus either, which stays in the input; the wrapper, which takes no box, selects it on a click.\n -->\n <span\n v-if=\"chips\"\n class=\"contents\"\n @click.stop=\"selectChip(i)\"\n >\n <RuiChip\n :key=\"getTextToken(getIdentifier(item))\"\n :size=\"dense ? 'sm' : 'md'\"\n closeable\n close-unfocusable\n :class=\"{\n 'leading-3': dense,\n // drawn inside the chip's edge: the field clips anything outside it\n 'outline-2 outline-solid outline-rui-primary -outline-offset-2': i === selectedIndex,\n }\"\n :data-selected=\"i === selectedIndex || undefined\"\n v-bind=\"chipAttrs(item, i)\"\n >\n <template\n v-if=\"slots.prepend\"\n #prepend\n >\n <slot\n name=\"prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n </template>\n <slot\n :index=\"i\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n {{ getText(item) }}\n </slot>\n </RuiChip>\n </span>\n <div\n v-else-if=\"showPlainSelection\"\n :class=\"hideSelectionWrapper ? 'contents' : 'flex'\"\n >\n <slot\n name=\"prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n <slot\n v-if=\"multiple || !!slots.default\"\n :index=\"i\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n <!-- plain values are joined with a comma, the value row's gap standing in for the space -->\n {{ getText(item) }}{{ multiple && i < items.length - 1 ? ',' : '' }}\n </slot>\n </div>\n </template>\n</template>\n"],"mappings":""}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import RuiChip_default from "../../chips/RuiChip.js";
|
|
2
2
|
import { getTextToken } from "../../../utils/helpers.js";
|
|
3
|
-
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock,
|
|
3
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createSlots, createTextVNode, defineComponent, mergeProps, normalizeClass, openBlock, renderList, renderSlot, toDisplayString, unref, useSlots, withCtx, withModifiers } from "vue";
|
|
4
4
|
//#region src/components/forms/auto-complete/RuiAutoCompleteSelection.vue?vue&type=script&setup=true&lang.ts
|
|
5
5
|
var _hoisted_1 = ["onClick"];
|
|
6
|
-
var _hoisted_2 = { class: "flex" };
|
|
7
6
|
var RuiAutoCompleteSelection_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
8
7
|
__name: "RuiAutoCompleteSelection",
|
|
9
8
|
props: {
|
|
@@ -43,13 +42,17 @@ var RuiAutoCompleteSelection_vue_vue_type_script_setup_true_lang_default = /*@__
|
|
|
43
42
|
"outline-2 outline-solid outline-rui-primary -outline-offset-2": i === __props.selectedIndex
|
|
44
43
|
},
|
|
45
44
|
"data-selected": i === __props.selectedIndex || void 0
|
|
46
|
-
}, { ref_for: true }, __props.chipAttrs(item, i)), {
|
|
47
|
-
default: withCtx(() => [
|
|
45
|
+
}, { ref_for: true }, __props.chipAttrs(item, i)), createSlots({
|
|
46
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default", mergeProps({ index: i }, { ref_for: true }, {
|
|
48
47
|
item,
|
|
49
48
|
chipAttrs: __props.chipAttrs(item, i)
|
|
50
|
-
}), () => [createTextVNode(toDisplayString(__props.getText(item)), 1)])])
|
|
49
|
+
}), () => [createTextVNode(toDisplayString(__props.getText(item)), 1)])]),
|
|
51
50
|
_: 2
|
|
52
|
-
},
|
|
51
|
+
}, [slots.prepend ? {
|
|
52
|
+
name: "prepend",
|
|
53
|
+
fn: withCtx(() => [renderSlot(_ctx.$slots, "prepend", mergeProps({ index: i }, { ref_for: true }, { item }))]),
|
|
54
|
+
key: "0"
|
|
55
|
+
} : void 0]), 1040, [
|
|
53
56
|
"size",
|
|
54
57
|
"class",
|
|
55
58
|
"data-selected"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js","names":["_useSlots","_openBlock","_createElementBlock","_Fragment","_renderList","_withModifiers","_createBlock","RuiChip","_mergeProps","_unref","
|
|
1
|
+
{"version":3,"file":"RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js","names":["_useSlots","_openBlock","_createElementBlock","_Fragment","_renderList","_withModifiers","_createBlock","RuiChip","_mergeProps","_unref","_createSlots","_withCtx","_renderSlot","_createTextVNode","_toDisplayString","_normalizeClass","_createCommentVNode"],"sources":["../../../../src/components/forms/auto-complete/RuiAutoCompleteSelection.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"TItem\">\nimport RuiChip from '@/components/chips/RuiChip.vue';\nimport { getTextToken } from '@/utils/helpers';\n\nexport interface AutoCompleteSelectionProps<TItem> {\n items: TItem[];\n chips: boolean;\n dense: boolean;\n multiple: boolean;\n searchInputFocused: boolean;\n hideSelectionWrapper: boolean;\n getIdentifier: (item: TItem) => unknown;\n getText: (item: TItem) => string | undefined;\n chipAttrs: (item: TItem, index: number) => Record<string, unknown>;\n /** The chip Backspace and Delete act on, -1 for none, drawn with a ring though it never takes focus. */\n selectedIndex: number;\n /** Selects a clicked chip, with focus left in the input. */\n selectChip: (index: number) => void;\n}\n\nconst {\n chipAttrs,\n selectChip,\n selectedIndex,\n chips,\n dense,\n getIdentifier,\n getText,\n hideSelectionWrapper,\n items,\n multiple,\n searchInputFocused,\n} = defineProps<AutoCompleteSelectionProps<TItem>>();\n\nconst slots = defineSlots<{\n prepend?: (props: { index: number; item: TItem }) => any;\n default?: (props: { index: number; item: TItem; chipAttrs: Record<string, unknown> }) => any;\n}>();\n\n/**\n * Without a chip, a selected value is only drawn when it cannot be read off the\n * search input: while picking several values, or while the input is unfocused\n * and a slot renders the selection itself.\n */\nconst showPlainSelection = computed<boolean>(() =>\n multiple || (!searchInputFocused && (!!slots.prepend || !!slots.default)),\n);\n</script>\n\n<template>\n <template\n v-for=\"(item, i) in items\"\n :key=\"getIdentifier(item)?.toString()\"\n >\n <!--\n Not a clickable chip: that would make it a button around its own close button. It never takes\n focus either, which stays in the input; the wrapper, which takes no box, selects it on a click.\n -->\n <span\n v-if=\"chips\"\n class=\"contents\"\n @click.stop=\"selectChip(i)\"\n >\n <RuiChip\n :key=\"getTextToken(getIdentifier(item))\"\n :size=\"dense ? 'sm' : 'md'\"\n closeable\n close-unfocusable\n :class=\"{\n 'leading-3': dense,\n // drawn inside the chip's edge: the field clips anything outside it\n 'outline-2 outline-solid outline-rui-primary -outline-offset-2': i === selectedIndex,\n }\"\n :data-selected=\"i === selectedIndex || undefined\"\n v-bind=\"chipAttrs(item, i)\"\n >\n <template\n v-if=\"slots.prepend\"\n #prepend\n >\n <slot\n name=\"prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n </template>\n <slot\n :index=\"i\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n {{ getText(item) }}\n </slot>\n </RuiChip>\n </span>\n <div\n v-else-if=\"showPlainSelection\"\n :class=\"hideSelectionWrapper ? 'contents' : 'flex'\"\n >\n <slot\n name=\"prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n <slot\n v-if=\"multiple || !!slots.default\"\n :index=\"i\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n <!-- plain values are joined with a comma, the value row's gap standing in for the space -->\n {{ getText(item) }}{{ multiple && i < items.length - 1 ? ',' : '' }}\n </slot>\n </div>\n </template>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAkCA,MAAM,QAAQA,SAAA;;;;;;EAUd,MAAM,qBAAqB,eACzB,QAAA,YAAa,CAAC,QAAA,uBAAuB,CAAC,CAAC,MAAM,WAAW,CAAC,CAAC,MAAM,QAClE;;GAIE,OAAAC,UAAA,IAAA,GAAAC,mBA8DWC,UAAA,MAAAC,WA7DW,QAAA,QAAZ,MAAM,MAAC;IACT,OAAA,UAAA,GAAA,mBAAA,UAAA,EAAA,KAAA,QAAA,cAAc,IAAI,CAAA,EAAG,SAAQ,EAAA,GAAA,CAO3B,QAAA,SADRH,UAAA,GAAAC,mBAmCO,QAAA;;KAjCL,OAAM;KACL,SAAKG,eAAA,WAAO,QAAA,WAAW,CAAC,GAAA,CAAA,MAAA,CAAA;IAEzBJ,GAAAA,EAAAA,UAAA,GAAAK,YA6BUC,iBA7BVC,WA6BU;KA5BP,KAAKC,MAAA,YAAA,CAAY,CAAC,QAAA,cAAc,IAAI,CAAA;KACpC,MAAM,QAAA,QAAK,OAAA;KACZ,WAAA;KACA,qBAAA;KACC,OAAK;MAA2B,aAAA,QAAA;MAAiK,iEAAA,MAAM,QAAA;;KAKvM,iBAAe,MAAM,QAAA,iBAAiB,KAAA;IAC/B,GAAA,EAAA,SAAA,KAAA,GAAA,QAAA,UAAU,MAAM,CAAC,CAAA,GAAAC,YAAA;KAYzB,SAAAC,cAKO,CALPC,WAKO,KAAA,QAAA,WALPJ,WAKO,EAJJ,OAAO,EAAC,GAAA,EAAA,SAAA,KAAA,GAAA;MACC;MAAI,WAAa,QAAA,UAAU,MAAM,CAAC;KAAA,CAAA,SAGvC,CADFK,gBAAAC,gBAAA,QAAA,QAAQ,IAAI,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;IAbT,GAAA,CAAA,MAAM,UAAA;KACX,MAAA;KAED,IAAAH,cAIE,CAJFC,WAIE,KAAA,QAAA,WAJFJ,WAIE,EAFC,OAAO,EAAC,GAAA,EAAA,SAAA,KAAA,GAAA,EACC,KAAI,CAAA,CAAA,CAAA,CAAA;;;;;;IAYTC,CAAAA,EAAAA,GAAAA,GAAAA,UAAAA,KAAAA,MAAA,kBAAA,KADbR,UAAA,GAAAC,mBAiBM,OAAA;;KAfH,OAAKa,eAAE,QAAA,uBAAoB,aAAA,MAAA;IAE5BH,GAAAA,CAAAA,WAIE,KAAA,QAAA,WAJFJ,WAIE,EAFC,OAAO,EAAC,GAAA,EAAA,SAAA,KAAA,GAAA,EACC,KAAI,CAAA,CAAA,GAGR,QAAA,YAAQ,CAAA,CAAM,MAAM,UAD5BI,WAOO,KAAA,QAAA,WAPPJ,WAOO,EALJ,OAAO,EAAC,GAAA,EAAA,SAAA,KAAA,GAAA;KACC;KAAI,WAAa,QAAA,UAAU,MAAM,CAAC;IAAA,CAAA,SAIvC,CADFK,gBAAAC,gBAAA,QAAA,QAAQ,IAAI,CAAA,IAAAA,gBAAO,QAAA,YAAY,IAAI,QAAA,MAAM,SAAM,IAAA,MAAA,EAAA,GAAA,CAAA,CAAA,GAAA,KAAA,GAAA,CAAA,IAAA,mBAAA,IAAA,IAAA,CAAA,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,CAAA,GAAA,EAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDataTable.js","names":["_sfc_main"],"sources":["../../../src/components/tables/RuiDataTable.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object, IdType extends keyof T = keyof T\">\nimport type { GroupHeader } from '@/composables/tables/data-table/types';\nimport { dataTableStyles } from '@/components/tables/data-table-styles';\nimport { type DataTableClasses, type DataTableGroupLabel, provideDataTableContext, provideDataTableNested, useDataTableNested } from '@/components/tables/data-table/context';\nimport RuiDataTableBody from '@/components/tables/data-table/RuiDataTableBody.vue';\nimport RuiDataTableMobileSort from '@/components/tables/data-table/RuiDataTableMobileSort.vue';\nimport RuiTableHead, {\n type GroupData,\n type TableColumn,\n type TableRowKeyData,\n type TableSortData,\n} from '@/components/tables/RuiTableHead.vue';\nimport RuiTablePagination, {\n type TablePaginationData,\n} from '@/components/tables/RuiTablePagination.vue';\nimport { GroupExpandButtonPosition } from '@/components/tables/table-props';\nimport { useTable } from '@/composables/defaults/table';\nimport { useKeyboardScroll } from '@/composables/keyboard-scroll';\nimport { useStickyTableHeader } from '@/composables/sticky-header';\nimport { useTableColumns } from '@/composables/tables/data-table/columns';\nimport { useTableExpansion } from '@/composables/tables/data-table/expansion';\nimport { useTableGrouping } from '@/composables/tables/data-table/grouping';\nimport { usePageScroll, useStickyBottomInset, useStickyPaginationBar } from '@/composables/tables/data-table/page-scroll';\nimport { useTablePagination } from '@/composables/tables/data-table/pagination';\nimport { useTableSelection } from '@/composables/tables/data-table/selection';\nimport { useTableSort } from '@/composables/tables/data-table/sort';\n\nexport type { GroupedTableRow, GroupHeader, TableOptions } from '@/composables/tables/data-table/types';\n\nexport interface Props<T, K extends keyof T> {\n /**\n * list of items for each row\n */\n rows: readonly T[];\n /**\n * the attribute used to identify each row uniquely for selection, usually `id`\n */\n rowAttr: K;\n /**\n * model for internal searching\n */\n search?: string;\n /**\n * model for items per page\n * will be used if the `pagination` model isn't specified\n */\n itemsPerPage?: number;\n /**\n * list of column definitions\n */\n cols?: TableColumn<T>[];\n /**\n * attribute to use from column definitions to display column titles\n */\n columnAttr?: keyof TableColumn<T>;\n /**\n * flag to show a more or less spacious table\n */\n dense?: boolean;\n /**\n * flag to outline the flag with a border\n */\n outlined?: boolean;\n /**\n * should add zebra-striping to the table row\n */\n striped?: boolean;\n /**\n * flag to show loading state of the table\n * triggers indefinite progress at the bottom of the table header\n */\n loading?: boolean;\n disablePerPage?: boolean;\n /**\n * Maximum number of pages before the jump-to-page dropdown is replaced with\n * a numeric input. Defaults to `500`. Forwarded to `RuiTablePagination`.\n */\n rangesThreshold?: number;\n /**\n * The text and icon shown when there are no rows, e.g.\n * `:empty=\"\\{ icon: 'transactions-line', label: 'No transactions found' \\}\"`\n */\n empty?: {\n label?: string;\n description?: string;\n };\n /**\n * Why the last read failed. Shown above any rows kept from an earlier read,\n * or in place of the empty state; `loading` still takes precedence.\n */\n error?: string;\n /** Heading for that failure. */\n errorTitle?: string;\n /** Label for the retry control; without one, no control is offered. */\n retryText?: string;\n /**\n * Hide the pagination bar. The bar sits under the table and sticks to the bottom of the view\n * while the table runs past it.\n */\n hidePagination?: boolean;\n\n rounded?: 'sm' | 'md' | 'lg';\n /**\n * make expansion work like accordion\n */\n singleExpand?: boolean;\n /**\n * make table head stick to top on scroll\n */\n stickyHeader?: boolean;\n stickyOffset?: number;\n /**\n * Affects how the items per page work across the app.\n * When true, changing the items per page setting in one table will affect other tables.\n */\n globalItemsPerPage?: boolean;\n groupExpandButtonPosition?: GroupExpandButtonPosition;\n disabledRows?: readonly T[];\n multiPageSelect?: boolean;\n itemClass?: ((item: T) => string) | string;\n /**\n * Render each row as a stacked card instead of a table row once the measured\n * width is narrower than this width (in pixels). Columns flagged with\n * `mobileHidden` are dropped in this layout. Falls back to the global\n * `mobileBreakpoint` table default; leave both unset to keep the default table\n * layout at every width.\n */\n mobileBreakpoint?: number;\n /**\n * What the `mobileBreakpoint` is measured against: the browser `viewport`\n * (default) or this table's own `container` width. Use `container` when the\n * table lives in a narrow region of a wider window. Falls back to the global\n * `mobileBreakpointBasis` table default.\n */\n mobileBreakpointBasis?: 'viewport' | 'container';\n /**\n * Force the stacked mobile card layout on (`true`) or off (`false`),\n * regardless of `mobileBreakpoint`. Leave unset to derive it from the width.\n */\n mobile?: boolean;\n}\n\ndefineOptions({\n name: 'RuiDataTable',\n});\n\nconst selectedData = defineModel<T[IdType][]>();\n\nconst expanded = defineModel<T[]>('expanded');\n\nconst [pagination, paginationModifiers] = defineModel<TablePaginationData, 'external'>('pagination');\n\nconst [sort, sortModifiers] = defineModel<TableSortData<T>, 'external'>('sort');\n\nconst group = defineModel<TableRowKeyData<T>>('group');\n\nconst collapsed = defineModel<T[]>('collapsed');\n\nconst {\n rows,\n rowAttr,\n search = '',\n itemsPerPage = 10,\n cols,\n columnAttr = 'label',\n dense = false,\n outlined = false,\n striped = false,\n loading = false,\n disablePerPage = false,\n rangesThreshold = 500,\n empty = { label: 'No item found' },\n error = '',\n errorTitle = '',\n retryText = '',\n hidePagination = false,\n rounded = 'md',\n singleExpand = false,\n stickyHeader = false,\n stickyOffset,\n globalItemsPerPage = undefined,\n groupExpandButtonPosition = GroupExpandButtonPosition.start,\n disabledRows,\n multiPageSelect = false,\n itemClass = '',\n mobileBreakpoint,\n mobileBreakpointBasis,\n mobile,\n} = defineProps<Props<T, IdType>>();\n\nconst emit = defineEmits<{\n 'update:options': [value: { pagination?: TablePaginationData; sort?: TableSortData<T> }];\n 'copy:group': [value: GroupData<T>];\n 'retry': [];\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`header.${string}`, (props: { column: TableColumn<T> }) => any> &\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend': (props: { colspan: number }) => any;\n 'body.append': (props: { colspan: number }) => any;\n 'group.header': (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content': (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item': (props: { row: T; index: number }) => any;\n /**\n * A full-width row after every row, read as the second half of the same item: no divider between\n * them, one hover, the row's selected or open shade and stripe. For a long field, such as notes,\n * that would otherwise widen the table. It comes before an open expanded panel.\n */\n 'row-append': (props: { row: T; index: number }) => any;\n 'no-data': () => any;\n 'empty-description': () => any;\n 'error': () => any;\n 'tfoot': () => any;\n }\n>>();\n\nconst tableDefaults = useTable();\n\nconst tableWrapper = useTemplateRef<HTMLElement>('tableWrapper');\nconst paginationSentinel = useTemplateRef<HTMLElement>('paginationSentinel');\nconst paginationBar = useTemplateRef<InstanceType<typeof RuiTablePagination>>('paginationBar');\nconst { width: windowWidth } = useWindowSize();\nconst { width: containerWidth } = useElementSize(tableWrapper);\n\n// Per-table props win, then the global table defaults.\nconst resolvedMobileBreakpoint = computed<number | undefined>(() => {\n if (mobileBreakpoint !== undefined)\n return mobileBreakpoint;\n const globalBreakpoint = tableDefaults.mobileBreakpoint;\n return globalBreakpoint === undefined ? undefined : get(globalBreakpoint);\n});\nconst resolvedMobileBasis = computed<'viewport' | 'container'>(() => {\n if (mobileBreakpointBasis !== undefined)\n return mobileBreakpointBasis;\n const globalBasis = tableDefaults.mobileBreakpointBasis;\n return globalBasis === undefined ? 'viewport' : get(globalBasis);\n});\n\n/**\n * Whether the stacked card layout is showing.\n *\n * Vue coerces an absent Boolean prop to `false`, so `mobile` cannot say\n * \"unset\": with no breakpoint configured it is the manual switch, defaulting\n * to desktop, and with one configured the breakpoint drives the layout while\n * `mobile === true` can still force the stacked layout on.\n */\nconst isMobile = computed<boolean>(() => {\n const breakpoint = get(resolvedMobileBreakpoint);\n if (breakpoint === undefined)\n return mobile;\n if (mobile)\n return true;\n // `containerWidth` is 0 until measured; the viewport keeps the first paint off mobile\n const width = get(resolvedMobileBasis) === 'container'\n ? (get(containerWidth) || get(windowWidth))\n : get(windowWidth);\n return width < breakpoint;\n});\n\nconst stickyHeaderOffset = computed<number | undefined>(() =>\n stickyOffset !== undefined ? stickyOffset : get(tableDefaults.stickyOffset),\n);\n\n/**\n * A table rendered inside an expanded row must not pin its own toolbar: only\n * the outermost table sticks, otherwise the bars stack and collide.\n */\nconst isNestedTable = useDataTableNested();\nprovideDataTableNested();\n\n/**\n * On mobile there is no column header to pin, so `stickyHeader` pins the\n * pagination and sort toolbar instead while the card list scrolls.\n */\nconst stickyMobileToolbar = computed<boolean>(() => stickyHeader && get(isMobile) && !isNestedTable);\n\nconst table = useTemplateRef<HTMLTableElement>('table');\nconst tableScroller = useTemplateRef<HTMLElement>('tableScroller');\nconst scrollerTabindex = useKeyboardScroll(tableScroller);\n\nconst { stick } = useStickyTableHeader(\n () => stickyHeader,\n stickyHeaderOffset,\n { table },\n);\n\nconst { width: scrollerWidth } = useElementSize(tableScroller);\n\n/**\n * The visible width of the table, which an expanded row caps its content to.\n * Without the cap a wide panel, such as a nested table, sets the minimum width\n * of the whole table and pushes every column past the scroller. `initial`\n * resets the variable, so a nested table never inherits its parent's width.\n */\nconst viewportStyle = computed<Record<string, string>>(() => {\n const width = get(scrollerWidth);\n return { '--rui-table-viewport': width > 0 && !get(isMobile) ? `${width}px` : 'initial' };\n});\n\nconst { expandable, isExpanded, onToggleExpand } = useTableExpansion<T, IdType>(\n { rowAttr, singleExpand },\n { expanded },\n);\n\nfunction emitUpdateOptions(opts: { sort?: TableSortData<T>; pagination?: TablePaginationData }): void {\n emit('update:options', opts);\n}\n\nconst {\n sortData,\n sortedMap,\n sorted,\n onSort: applySort,\n} = useTableSort<T>(\n { rows: () => rows, search: () => search, sortModifiersExternal: sortModifiers.external },\n {\n sort,\n pagination,\n emitUpdateOptions,\n },\n);\n\nconst {\n groupKeys,\n groupKey,\n grouped,\n mappedGroups,\n isExpandedGroup,\n isHiddenRow,\n onToggleExpandGroup,\n onUngroup,\n} = useTableGrouping<T, IdType>(\n { rowAttr },\n {\n group,\n collapsed,\n sorted,\n },\n);\n\nconst {\n paginationData,\n filtered,\n setInternalTotal,\n resetPagination,\n} = useTablePagination<T>(\n {\n itemsPerPage,\n paginationModifiersExternal: paginationModifiers.external,\n globalItemsPerPage,\n },\n {\n pagination,\n grouped,\n isHiddenRow,\n sort,\n emitUpdateOptions,\n tableDefaults,\n },\n);\n\nconst noData = computed<boolean>(() => get(filtered).length === 0);\n\n// one loader at a time: the header bar marks a refetch over rows, and an empty table shows only its spinner row\nconst headerLoading = computed<boolean>(() => loading && !get(noData));\n\n/**\n * A nested table (a breakdown in an expanded row) that pages its own rows drops the bar when they all fit\n * the smallest page size: no control on it could change what shows, and in a breakdown it is pure noise.\n * A top-level table keeps it as a summary; a server-paged one keeps it, since only the server knows the total.\n */\nconst fitsSmallestPage = computed<boolean>(() => {\n if (!isNestedTable || paginationModifiers.external)\n return false;\n const { limits } = get(paginationData);\n const sizes = limits ?? toValue(tableDefaults.limits);\n // the rows themselves, not the pagination total, which is only filled in after mount\n return sizes.length > 0 && get(sorted).length <= Math.min(...sizes);\n});\n\nconst showPagination = computed<boolean>(() => !!get(paginationData) && !hidePagination && !get(fitsSmallestPage));\n\n/**\n * The one pagination bar sticks to the bottom of the view, so a long page can be turned without\n * scrolling down to it. `position: sticky` keeps it inside this table, so stacked and side-by-side\n * tables each hold their own bar. A nested table's bar stays in place: two stuck bars would stack.\n */\nconst canStickPagination = useStickyPaginationBar(tableWrapper, () => !isNestedTable && get(showPagination));\nconst stickyPagination = computed<boolean>(() => !isNestedTable && get(canStickPagination));\n\nconst paginationBarElement = computed<HTMLElement | undefined>(() => {\n const element: unknown = get(paginationBar)?.$el;\n return element instanceof HTMLElement ? element : undefined;\n});\n\n// while the bar is stuck to the page, `--rui-sticky-bottom` tells the page's floating parts to rise above it\nuseStickyBottomInset(paginationSentinel, paginationBarElement, stickyPagination);\n\n/**\n * Grouped columns leave the column list, so their labels come from `cols`.\n */\nconst groupLabels = computed<DataTableGroupLabel[]>(() => get(groupKeys).map((key) => {\n const label = cols?.find(column => column.key === key)?.[columnAttr];\n return {\n key: String(key),\n label: label === undefined || label === null ? String(key) : String(label),\n };\n}));\n\n/** Each group's list starts with its header entry, which is not a row. */\nfunction getGroupSize(identifier: string): number {\n return Math.max((get(mappedGroups)[identifier]?.length ?? 0) - 1, 0);\n}\n\nconst ui = computed<ReturnType<typeof dataTableStyles>>(() => dataTableStyles({\n outlined,\n rounded,\n dense,\n striped,\n mobile: get(isMobile),\n}));\n\nconst { columns, colspan, headerSlots, cellValue } = useTableColumns<T, IdType>({\n cols: () => cols,\n columnAttr,\n rows: () => rows,\n expandable,\n groupKeys,\n selectedData,\n slots,\n isMobile,\n tdResolver: options => get(ui).td(options),\n});\n\nconst showMobileSort = computed<boolean>(() =>\n get(isMobile) && !!get(sortData) && get(columns).some(column => column.sortable),\n);\n\nconst ITEM_SLOT_PREFIX = 'item.';\n\n// Slot keys are static for the component lifetime — no reactivity needed\nconst itemSlotKeys: Set<string> = new Set(\n Object.keys(slots)\n .filter((key): key is `item.${string}` => key.startsWith(ITEM_SLOT_PREFIX))\n .map(key => key.slice(ITEM_SLOT_PREFIX.length)),\n);\n\nconst {\n isAllSelected,\n indeterminate,\n isSelected,\n isDisabledRow,\n onToggleAll,\n onSelect,\n onCheckboxClick,\n deselectRemovedRows,\n resetCheckboxShiftState,\n} = useTableSelection<T, IdType>(\n { rowAttr, multiPageSelect, disabledRows: () => disabledRows },\n { selectedData, filtered },\n);\n\n/**\n * Sorting clears the selection. That lives here rather than in either\n * composable, which would make sort and selection depend on each other.\n */\nfunction onSort(payload: Parameters<typeof applySort>[0]): void {\n applySort(payload);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n}\n\nconst { revealTableTop } = usePageScroll(tableWrapper, stickyHeaderOffset);\n\nasync function onPaginate(): Promise<void> {\n if ((get(expanded)?.length ?? 0) > 0)\n set(expanded, []);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n await revealTableTop();\n}\n\n// Reset pagination page to 1 on search query change\nwatch(() => search, () => {\n resetPagination();\n onToggleAll(false);\n resetCheckboxShiftState();\n});\n\nwatch(sorted, (items) => {\n if (!multiPageSelect)\n deselectRemovedRows();\n setInternalTotal(items);\n});\n\nonMounted(() => {\n setInternalTotal(get(sorted));\n});\n\nconst classes = computed<DataTableClasses>(() => {\n const s = get(ui);\n return {\n td: s.td(),\n tr: s.tr(),\n trSelected: s.tr({ rowVariant: 'selected' }),\n trExpandable: s.tr({ rowVariant: 'expandable' }),\n trExpandedParent: s.tr({ rowVariant: 'expandedParent' }),\n trGroup: s.tr({ rowVariant: 'group' }),\n trEmpty: s.tr({ rowVariant: 'empty' }),\n checkbox: s.checkbox(),\n tbody: s.tbody(),\n tbodyLoader: s.tbodyLoader(),\n };\n});\n\nprovideDataTableContext<T, IdType>({\n // Reactive (ComputedRef/Ref) — destructuring preserves reactivity via Vue template auto-unwrap\n classes,\n columns,\n colspan,\n expandable,\n groupKey,\n groupLabels,\n isMobile,\n selectedData,\n // Static values\n cellValue,\n columnAttr,\n dense,\n getGroupSize,\n getRowId: (row: T) => row[rowAttr],\n itemSlotKeys,\n groupExpandButtonPosition,\n isDisabledRow,\n isExpanded,\n isExpandedGroup,\n isSelected,\n itemClass,\n onCheckboxClick,\n onCopyGroup: (header: GroupHeader<T>) => emit('copy:group', { key: get(groupKey) ?? '', value: header.group }),\n onSelect,\n onToggleExpand,\n onToggleExpandGroup,\n onUngroup,\n});\n</script>\n\n<template>\n <div\n ref=\"tableWrapper\"\n :class=\"ui.wrapper()\"\n data-id=\"table-wrapper\"\n >\n <div\n v-if=\"showMobileSort\"\n :class=\"stickyMobileToolbar ? 'sticky z-rui-raised bg-rui-background pt-2' : 'contents'\"\n :style=\"stickyMobileToolbar ? { top: `${stickyHeaderOffset ?? 0}px` } : undefined\"\n data-id=\"table-mobile-toolbar-sticky\"\n >\n <div\n class=\"flex justify-end p-2\"\n data-id=\"table-mobile-toolbar\"\n >\n <RuiDataTableMobileSort\n :columns=\"columns\"\n :column-attr=\"columnAttr\"\n :sorted-map=\"sortedMap\"\n :dense=\"dense\"\n @sort=\"onSort($event)\"\n />\n </div>\n </div>\n <div\n ref=\"tableScroller\"\n :class=\"[ui.scroller(), isMobile && !showMobileSort ? 'pt-2' : '']\"\n :tabindex=\"scrollerTabindex\"\n data-id=\"table-scroller\"\n >\n <table\n ref=\"table\"\n :class=\"ui.table()\"\n :style=\"viewportStyle\"\n :aria-busy=\"loading\"\n >\n <RuiTableHead\n v-if=\"!isMobile\"\n :loading=\"headerLoading\"\n :indeterminate=\"indeterminate\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :disable-check-all=\"!filtered?.length\"\n :is-all-selected=\"isAllSelected\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n :stick=\"stick\"\n :sticky-header=\"stickyHeader\"\n @sort=\"onSort($event)\"\n @select:all=\"onToggleAll($event)\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiTableHead\n v-if=\"stickyHeader && !isMobile\"\n :loading=\"headerLoading\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n data-id=\"head-clone\"\n class=\"opacity-0 invisible\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiDataTableBody\n :filtered=\"filtered\"\n :loading=\"loading\"\n :no-data=\"noData\"\n :empty=\"empty\"\n :error=\"error\"\n :error-title=\"errorTitle\"\n :retry-text=\"retryText\"\n @retry=\"emit('retry')\"\n >\n <template\n v-if=\"slots.error\"\n #error\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"error\" />\n </template>\n <template\n v-if=\"slots['body.prepend']\"\n #body.prepend=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.prepend\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header']\"\n #group.header=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header.content']\"\n #group.header.content=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header.content\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-for=\"key in itemSlotKeys\"\n #[`item.${key}`]=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n :name=\"`item.${key}`\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['row-append']\"\n #row-append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['no-data']\"\n #no-data\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"no-data\" />\n </template>\n <template\n v-if=\"slots['empty-description']\"\n #empty-description\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"empty-description\" />\n </template>\n <template\n v-if=\"slots['body.append']\"\n #body.append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableBody>\n <tfoot>\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"tfoot\" />\n </tfoot>\n </table>\n </div>\n <!-- the bar's own place after the rows: below the view, the bar is stuck; no divider of its own -->\n <div\n v-if=\"paginationData && showPagination && !isNestedTable\"\n ref=\"paginationSentinel\"\n class=\"border-0!\"\n aria-hidden=\"true\"\n data-id=\"table-pagination-sentinel\"\n />\n <RuiTablePagination\n v-if=\"paginationData && showPagination\"\n ref=\"paginationBar\"\n v-model=\"paginationData\"\n :class=\"ui.pagination({ sticky: stickyPagination })\"\n :dense=\"dense\"\n :loading=\"loading\"\n :mobile=\"isMobile\"\n :disable-per-page=\"disablePerPage\"\n :ranges-threshold=\"rangesThreshold\"\n :data-sticky=\"stickyPagination || undefined\"\n data-id=\"table-pagination\"\n @update:model-value=\"onPaginate()\"\n />\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RuiDataTable.js","names":["_sfc_main"],"sources":["../../../src/components/tables/RuiDataTable.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object, IdType extends keyof T = keyof T\">\nimport type { GroupHeader } from '@/composables/tables/data-table/types';\nimport { dataTableStyles } from '@/components/tables/data-table-styles';\nimport { type DataTableClasses, type DataTableGroupLabel, provideDataTableContext, provideDataTableNested, useDataTableNested } from '@/components/tables/data-table/context';\nimport RuiDataTableBody from '@/components/tables/data-table/RuiDataTableBody.vue';\nimport RuiDataTableMobileSort from '@/components/tables/data-table/RuiDataTableMobileSort.vue';\nimport RuiTableHead, {\n type GroupData,\n type TableColumn,\n type TableRowKeyData,\n type TableSortData,\n} from '@/components/tables/RuiTableHead.vue';\nimport RuiTablePagination, {\n type TablePaginationData,\n} from '@/components/tables/RuiTablePagination.vue';\nimport { GroupExpandButtonPosition } from '@/components/tables/table-props';\nimport { useTable } from '@/composables/defaults/table';\nimport { useKeyboardScroll } from '@/composables/keyboard-scroll';\nimport { useStickyTableHeader } from '@/composables/sticky-header';\nimport { useTableColumns } from '@/composables/tables/data-table/columns';\nimport { useTableExpansion } from '@/composables/tables/data-table/expansion';\nimport { useTableGrouping } from '@/composables/tables/data-table/grouping';\nimport { usePageScroll, useStickyBottomInset, useStickyPaginationBar } from '@/composables/tables/data-table/page-scroll';\nimport { useTablePagination } from '@/composables/tables/data-table/pagination';\nimport { useTableSelection } from '@/composables/tables/data-table/selection';\nimport { useTableSort } from '@/composables/tables/data-table/sort';\n\nexport type { GroupedTableRow, GroupHeader, TableOptions } from '@/composables/tables/data-table/types';\n\nexport interface Props<T, K extends keyof T> {\n /**\n * list of items for each row\n */\n rows: readonly T[];\n /**\n * the attribute used to identify each row uniquely for selection, usually `id`\n */\n rowAttr: K;\n /**\n * model for internal searching\n */\n search?: string;\n /**\n * model for items per page\n * will be used if the `pagination` model isn't specified\n */\n itemsPerPage?: number;\n /**\n * list of column definitions\n */\n cols?: TableColumn<T>[];\n /**\n * attribute to use from column definitions to display column titles\n */\n columnAttr?: keyof TableColumn<T>;\n /**\n * flag to show a more or less spacious table\n */\n dense?: boolean;\n /**\n * flag to outline the flag with a border\n */\n outlined?: boolean;\n /**\n * should add zebra-striping to the table row\n */\n striped?: boolean;\n /**\n * flag to show loading state of the table\n * triggers indefinite progress at the bottom of the table header\n */\n loading?: boolean;\n disablePerPage?: boolean;\n /**\n * Maximum number of pages before the jump-to-page dropdown is replaced with\n * a numeric input. Defaults to `500`. Forwarded to `RuiTablePagination`.\n */\n rangesThreshold?: number;\n /**\n * The text and icon shown when there are no rows, e.g.\n * `:empty=\"\\{ icon: 'transactions-line', label: 'No transactions found' \\}\"`\n */\n empty?: {\n label?: string;\n description?: string;\n };\n /**\n * Why the last read failed. Shown above any rows kept from an earlier read,\n * or in place of the empty state; `loading` still takes precedence.\n */\n error?: string;\n /** Heading for that failure. */\n errorTitle?: string;\n /** Label for the retry control; without one, no control is offered. */\n retryText?: string;\n /**\n * Hide the pagination bar. The bar sits under the table and sticks to the bottom of the view\n * while the table runs past it.\n */\n hidePagination?: boolean;\n\n rounded?: 'sm' | 'md' | 'lg';\n /**\n * make expansion work like accordion\n */\n singleExpand?: boolean;\n /**\n * make table head stick to top on scroll\n */\n stickyHeader?: boolean;\n stickyOffset?: number;\n /**\n * keep the pagination bar at the table's end instead of pinning it to the bottom of the view while\n * the rows run past it, for a table that is one section of a longer page\n */\n disableStickyPagination?: boolean;\n /**\n * Affects how the items per page work across the app.\n * When true, changing the items per page setting in one table will affect other tables.\n */\n globalItemsPerPage?: boolean;\n groupExpandButtonPosition?: GroupExpandButtonPosition;\n disabledRows?: readonly T[];\n multiPageSelect?: boolean;\n itemClass?: ((item: T) => string) | string;\n /**\n * Render each row as a stacked card instead of a table row once the measured\n * width is narrower than this width (in pixels). Columns flagged with\n * `mobileHidden` are dropped in this layout. Falls back to the global\n * `mobileBreakpoint` table default; leave both unset to keep the default table\n * layout at every width.\n */\n mobileBreakpoint?: number;\n /**\n * What the `mobileBreakpoint` is measured against: the browser `viewport`\n * (default) or this table's own `container` width. Use `container` when the\n * table lives in a narrow region of a wider window. Falls back to the global\n * `mobileBreakpointBasis` table default.\n */\n mobileBreakpointBasis?: 'viewport' | 'container';\n /**\n * Force the stacked mobile card layout on (`true`) or off (`false`),\n * regardless of `mobileBreakpoint`. Leave unset to derive it from the width.\n */\n mobile?: boolean;\n}\n\ndefineOptions({\n name: 'RuiDataTable',\n});\n\nconst selectedData = defineModel<T[IdType][]>();\n\nconst expanded = defineModel<T[]>('expanded');\n\nconst [pagination, paginationModifiers] = defineModel<TablePaginationData, 'external'>('pagination');\n\nconst [sort, sortModifiers] = defineModel<TableSortData<T>, 'external'>('sort');\n\nconst group = defineModel<TableRowKeyData<T>>('group');\n\nconst collapsed = defineModel<T[]>('collapsed');\n\nconst {\n rows,\n rowAttr,\n search = '',\n itemsPerPage = 10,\n cols,\n columnAttr = 'label',\n dense = false,\n outlined = false,\n striped = false,\n loading = false,\n disablePerPage = false,\n rangesThreshold = 500,\n empty = { label: 'No item found' },\n error = '',\n errorTitle = '',\n retryText = '',\n hidePagination = false,\n rounded = 'md',\n singleExpand = false,\n stickyHeader = false,\n stickyOffset,\n disableStickyPagination = false,\n globalItemsPerPage = undefined,\n groupExpandButtonPosition = GroupExpandButtonPosition.start,\n disabledRows,\n multiPageSelect = false,\n itemClass = '',\n mobileBreakpoint,\n mobileBreakpointBasis,\n mobile,\n} = defineProps<Props<T, IdType>>();\n\nconst emit = defineEmits<{\n 'update:options': [value: { pagination?: TablePaginationData; sort?: TableSortData<T> }];\n 'copy:group': [value: GroupData<T>];\n 'retry': [];\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`header.${string}`, (props: { column: TableColumn<T> }) => any> &\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend': (props: { colspan: number }) => any;\n 'body.append': (props: { colspan: number }) => any;\n 'group.header': (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content': (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item': (props: { row: T; index: number }) => any;\n /**\n * A full-width row after every row, read as the second half of the same item: no divider between\n * them, one hover, the row's selected or open shade and stripe. For a long field, such as notes,\n * that would otherwise widen the table. It comes before an open expanded panel.\n */\n 'row-append': (props: { row: T; index: number }) => any;\n 'no-data': () => any;\n 'empty-description': () => any;\n 'error': () => any;\n 'tfoot': () => any;\n }\n>>();\n\nconst tableDefaults = useTable();\n\nconst tableWrapper = useTemplateRef<HTMLElement>('tableWrapper');\nconst paginationSentinel = useTemplateRef<HTMLElement>('paginationSentinel');\nconst paginationBar = useTemplateRef<InstanceType<typeof RuiTablePagination>>('paginationBar');\nconst { width: windowWidth } = useWindowSize();\nconst { width: containerWidth } = useElementSize(tableWrapper);\n\n// Per-table props win, then the global table defaults.\nconst resolvedMobileBreakpoint = computed<number | undefined>(() => {\n if (mobileBreakpoint !== undefined)\n return mobileBreakpoint;\n const globalBreakpoint = tableDefaults.mobileBreakpoint;\n return globalBreakpoint === undefined ? undefined : get(globalBreakpoint);\n});\nconst resolvedMobileBasis = computed<'viewport' | 'container'>(() => {\n if (mobileBreakpointBasis !== undefined)\n return mobileBreakpointBasis;\n const globalBasis = tableDefaults.mobileBreakpointBasis;\n return globalBasis === undefined ? 'viewport' : get(globalBasis);\n});\n\n/**\n * Whether the stacked card layout is showing.\n *\n * Vue coerces an absent Boolean prop to `false`, so `mobile` cannot say\n * \"unset\": with no breakpoint configured it is the manual switch, defaulting\n * to desktop, and with one configured the breakpoint drives the layout while\n * `mobile === true` can still force the stacked layout on.\n */\nconst isMobile = computed<boolean>(() => {\n const breakpoint = get(resolvedMobileBreakpoint);\n if (breakpoint === undefined)\n return mobile;\n if (mobile)\n return true;\n // `containerWidth` is 0 until measured; the viewport keeps the first paint off mobile\n const width = get(resolvedMobileBasis) === 'container'\n ? (get(containerWidth) || get(windowWidth))\n : get(windowWidth);\n return width < breakpoint;\n});\n\nconst stickyHeaderOffset = computed<number | undefined>(() =>\n stickyOffset !== undefined ? stickyOffset : get(tableDefaults.stickyOffset),\n);\n\n/**\n * A table rendered inside an expanded row must not pin its own toolbar: only\n * the outermost table sticks, otherwise the bars stack and collide.\n */\nconst isNestedTable = useDataTableNested();\nprovideDataTableNested();\n\n/**\n * On mobile there is no column header to pin, so `stickyHeader` pins the\n * pagination and sort toolbar instead while the card list scrolls.\n */\nconst stickyMobileToolbar = computed<boolean>(() => stickyHeader && get(isMobile) && !isNestedTable);\n\nconst table = useTemplateRef<HTMLTableElement>('table');\nconst tableScroller = useTemplateRef<HTMLElement>('tableScroller');\nconst scrollerTabindex = useKeyboardScroll(tableScroller);\n\nconst { stick } = useStickyTableHeader(\n () => stickyHeader,\n stickyHeaderOffset,\n { table },\n);\n\nconst { width: scrollerWidth } = useElementSize(tableScroller);\n\n/**\n * The visible width of the table, which an expanded row caps its content to.\n * Without the cap a wide panel, such as a nested table, sets the minimum width\n * of the whole table and pushes every column past the scroller. `initial`\n * resets the variable, so a nested table never inherits its parent's width.\n */\nconst viewportStyle = computed<Record<string, string>>(() => {\n const width = get(scrollerWidth);\n return { '--rui-table-viewport': width > 0 && !get(isMobile) ? `${width}px` : 'initial' };\n});\n\nconst { expandable, isExpanded, onToggleExpand } = useTableExpansion<T, IdType>(\n { rowAttr, singleExpand },\n { expanded },\n);\n\nfunction emitUpdateOptions(opts: { sort?: TableSortData<T>; pagination?: TablePaginationData }): void {\n emit('update:options', opts);\n}\n\nconst {\n sortData,\n sortedMap,\n sorted,\n onSort: applySort,\n} = useTableSort<T>(\n { rows: () => rows, search: () => search, sortModifiersExternal: sortModifiers.external },\n {\n sort,\n pagination,\n emitUpdateOptions,\n },\n);\n\nconst {\n groupKeys,\n groupKey,\n grouped,\n mappedGroups,\n isExpandedGroup,\n isHiddenRow,\n onToggleExpandGroup,\n onUngroup,\n} = useTableGrouping<T, IdType>(\n { rowAttr },\n {\n group,\n collapsed,\n sorted,\n },\n);\n\nconst {\n paginationData,\n filtered,\n setInternalTotal,\n resetPagination,\n} = useTablePagination<T>(\n {\n itemsPerPage,\n paginationModifiersExternal: paginationModifiers.external,\n globalItemsPerPage,\n },\n {\n pagination,\n grouped,\n isHiddenRow,\n sort,\n emitUpdateOptions,\n tableDefaults,\n },\n);\n\nconst noData = computed<boolean>(() => get(filtered).length === 0);\n\n// one loader at a time: the header bar marks a refetch over rows, and an empty table shows only its spinner row\nconst headerLoading = computed<boolean>(() => loading && !get(noData));\n\n/**\n * A nested table (a breakdown in an expanded row) that pages its own rows drops the bar when they all fit\n * the smallest page size: no control on it could change what shows, and in a breakdown it is pure noise.\n * A top-level table keeps it as a summary; a server-paged one keeps it, since only the server knows the total.\n */\nconst fitsSmallestPage = computed<boolean>(() => {\n if (!isNestedTable || paginationModifiers.external)\n return false;\n const { limits } = get(paginationData);\n const sizes = limits ?? toValue(tableDefaults.limits);\n // the rows themselves, not the pagination total, which is only filled in after mount\n return sizes.length > 0 && get(sorted).length <= Math.min(...sizes);\n});\n\nconst showPagination = computed<boolean>(() => !!get(paginationData) && !hidePagination && !get(fitsSmallestPage));\n\n/**\n * The one pagination bar sticks to the bottom of the view, so a long page can be turned without\n * scrolling down to it. `position: sticky` keeps it inside this table, so stacked and side-by-side\n * tables each hold their own bar. A nested table's bar stays in place, since two stuck bars would\n * stack, as does the bar of a table with `disableStickyPagination`.\n */\nconst paginationMayStick = computed<boolean>(() => !disableStickyPagination && !isNestedTable);\nconst canStickPagination = useStickyPaginationBar(tableWrapper, () => get(paginationMayStick) && get(showPagination));\nconst paginationStuck = computed<boolean>(() => get(paginationMayStick) && get(canStickPagination));\n\nconst paginationBarElement = computed<HTMLElement | undefined>(() => {\n const element: unknown = get(paginationBar)?.$el;\n return element instanceof HTMLElement ? element : undefined;\n});\n\n// while the bar is stuck to the page, `--rui-sticky-bottom` tells the page's floating parts to rise above it\nuseStickyBottomInset(paginationSentinel, paginationBarElement, paginationStuck);\n\n/**\n * Grouped columns leave the column list, so their labels come from `cols`.\n */\nconst groupLabels = computed<DataTableGroupLabel[]>(() => get(groupKeys).map((key) => {\n const label = cols?.find(column => column.key === key)?.[columnAttr];\n return {\n key: String(key),\n label: label === undefined || label === null ? String(key) : String(label),\n };\n}));\n\n/** Each group's list starts with its header entry, which is not a row. */\nfunction getGroupSize(identifier: string): number {\n return Math.max((get(mappedGroups)[identifier]?.length ?? 0) - 1, 0);\n}\n\nconst ui = computed<ReturnType<typeof dataTableStyles>>(() => dataTableStyles({\n outlined,\n rounded,\n dense,\n striped,\n mobile: get(isMobile),\n}));\n\nconst { columns, colspan, headerSlots, cellValue } = useTableColumns<T, IdType>({\n cols: () => cols,\n columnAttr,\n rows: () => rows,\n expandable,\n groupKeys,\n selectedData,\n slots,\n isMobile,\n tdResolver: options => get(ui).td(options),\n});\n\nconst showMobileSort = computed<boolean>(() =>\n get(isMobile) && !!get(sortData) && get(columns).some(column => column.sortable),\n);\n\nconst ITEM_SLOT_PREFIX = 'item.';\n\n// Slot keys are static for the component lifetime — no reactivity needed\nconst itemSlotKeys: Set<string> = new Set(\n Object.keys(slots)\n .filter((key): key is `item.${string}` => key.startsWith(ITEM_SLOT_PREFIX))\n .map(key => key.slice(ITEM_SLOT_PREFIX.length)),\n);\n\nconst {\n isAllSelected,\n indeterminate,\n isSelected,\n isDisabledRow,\n onToggleAll,\n onSelect,\n onCheckboxClick,\n deselectRemovedRows,\n resetCheckboxShiftState,\n} = useTableSelection<T, IdType>(\n { rowAttr, multiPageSelect, disabledRows: () => disabledRows },\n { selectedData, filtered },\n);\n\n/**\n * Sorting clears the selection. That lives here rather than in either\n * composable, which would make sort and selection depend on each other.\n */\nfunction onSort(payload: Parameters<typeof applySort>[0]): void {\n applySort(payload);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n}\n\nconst { revealTableTop } = usePageScroll(tableWrapper, stickyHeaderOffset);\n\nasync function onPaginate(): Promise<void> {\n if ((get(expanded)?.length ?? 0) > 0)\n set(expanded, []);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n await revealTableTop();\n}\n\n// Reset pagination page to 1 on search query change\nwatch(() => search, () => {\n resetPagination();\n onToggleAll(false);\n resetCheckboxShiftState();\n});\n\nwatch(sorted, (items) => {\n if (!multiPageSelect)\n deselectRemovedRows();\n setInternalTotal(items);\n});\n\nonMounted(() => {\n setInternalTotal(get(sorted));\n});\n\nconst classes = computed<DataTableClasses>(() => {\n const s = get(ui);\n return {\n td: s.td(),\n tr: s.tr(),\n trSelected: s.tr({ rowVariant: 'selected' }),\n trExpandable: s.tr({ rowVariant: 'expandable' }),\n trExpandedParent: s.tr({ rowVariant: 'expandedParent' }),\n trGroup: s.tr({ rowVariant: 'group' }),\n trEmpty: s.tr({ rowVariant: 'empty' }),\n checkbox: s.checkbox(),\n tbody: s.tbody(),\n tbodyLoader: s.tbodyLoader(),\n };\n});\n\nprovideDataTableContext<T, IdType>({\n // Reactive (ComputedRef/Ref) — destructuring preserves reactivity via Vue template auto-unwrap\n classes,\n columns,\n colspan,\n expandable,\n groupKey,\n groupLabels,\n isMobile,\n selectedData,\n // Static values\n cellValue,\n columnAttr,\n dense,\n getGroupSize,\n getRowId: (row: T) => row[rowAttr],\n itemSlotKeys,\n groupExpandButtonPosition,\n isDisabledRow,\n isExpanded,\n isExpandedGroup,\n isSelected,\n itemClass,\n onCheckboxClick,\n onCopyGroup: (header: GroupHeader<T>) => emit('copy:group', { key: get(groupKey) ?? '', value: header.group }),\n onSelect,\n onToggleExpand,\n onToggleExpandGroup,\n onUngroup,\n});\n</script>\n\n<template>\n <div\n ref=\"tableWrapper\"\n :class=\"ui.wrapper()\"\n data-id=\"table-wrapper\"\n >\n <div\n v-if=\"showMobileSort\"\n :class=\"stickyMobileToolbar ? 'sticky z-rui-raised bg-rui-background pt-2' : 'contents'\"\n :style=\"stickyMobileToolbar ? { top: `${stickyHeaderOffset ?? 0}px` } : undefined\"\n data-id=\"table-mobile-toolbar-sticky\"\n >\n <div\n class=\"flex justify-end p-2\"\n data-id=\"table-mobile-toolbar\"\n >\n <RuiDataTableMobileSort\n :columns=\"columns\"\n :column-attr=\"columnAttr\"\n :sorted-map=\"sortedMap\"\n :dense=\"dense\"\n @sort=\"onSort($event)\"\n />\n </div>\n </div>\n <div\n ref=\"tableScroller\"\n :class=\"[ui.scroller(), isMobile && !showMobileSort ? 'pt-2' : '']\"\n :tabindex=\"scrollerTabindex\"\n data-id=\"table-scroller\"\n >\n <table\n ref=\"table\"\n :class=\"ui.table()\"\n :style=\"viewportStyle\"\n :aria-busy=\"loading\"\n >\n <RuiTableHead\n v-if=\"!isMobile\"\n :loading=\"headerLoading\"\n :indeterminate=\"indeterminate\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :disable-check-all=\"!filtered?.length\"\n :is-all-selected=\"isAllSelected\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n :stick=\"stick\"\n :sticky-header=\"stickyHeader\"\n @sort=\"onSort($event)\"\n @select:all=\"onToggleAll($event)\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiTableHead\n v-if=\"stickyHeader && !isMobile\"\n :loading=\"headerLoading\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n data-id=\"head-clone\"\n class=\"opacity-0 invisible\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiDataTableBody\n :filtered=\"filtered\"\n :loading=\"loading\"\n :no-data=\"noData\"\n :empty=\"empty\"\n :error=\"error\"\n :error-title=\"errorTitle\"\n :retry-text=\"retryText\"\n @retry=\"emit('retry')\"\n >\n <template\n v-if=\"slots.error\"\n #error\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"error\" />\n </template>\n <template\n v-if=\"slots['body.prepend']\"\n #body.prepend=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.prepend\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header']\"\n #group.header=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header.content']\"\n #group.header.content=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header.content\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-for=\"key in itemSlotKeys\"\n #[`item.${key}`]=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n :name=\"`item.${key}`\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['row-append']\"\n #row-append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['no-data']\"\n #no-data\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"no-data\" />\n </template>\n <template\n v-if=\"slots['empty-description']\"\n #empty-description\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"empty-description\" />\n </template>\n <template\n v-if=\"slots['body.append']\"\n #body.append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableBody>\n <tfoot>\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"tfoot\" />\n </tfoot>\n </table>\n </div>\n <!-- the bar's own place after the rows: below the view, the bar is stuck; no divider of its own -->\n <div\n v-if=\"paginationData && showPagination && !isNestedTable\"\n ref=\"paginationSentinel\"\n class=\"border-0!\"\n aria-hidden=\"true\"\n data-id=\"table-pagination-sentinel\"\n />\n <RuiTablePagination\n v-if=\"paginationData && showPagination\"\n ref=\"paginationBar\"\n v-model=\"paginationData\"\n :class=\"ui.pagination({ sticky: paginationStuck })\"\n :dense=\"dense\"\n :loading=\"loading\"\n :mobile=\"isMobile\"\n :disable-per-page=\"disablePerPage\"\n :ranges-threshold=\"rangesThreshold\"\n :data-sticky=\"paginationStuck || undefined\"\n data-id=\"table-pagination\"\n @update:model-value=\"onPaginate()\"\n />\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -84,6 +84,11 @@ export interface Props<T, K extends keyof T> {
|
|
|
84
84
|
*/
|
|
85
85
|
stickyHeader?: boolean;
|
|
86
86
|
stickyOffset?: number;
|
|
87
|
+
/**
|
|
88
|
+
* keep the pagination bar at the table's end instead of pinning it to the bottom of the view while
|
|
89
|
+
* the rows run past it, for a table that is one section of a longer page
|
|
90
|
+
*/
|
|
91
|
+
disableStickyPagination?: boolean;
|
|
87
92
|
/**
|
|
88
93
|
* Affects how the items per page work across the app.
|
|
89
94
|
* When true, changing the items per page setting in one table will affect other tables.
|
|
@@ -75,6 +75,10 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
|
|
|
75
75
|
default: false
|
|
76
76
|
},
|
|
77
77
|
stickyOffset: {},
|
|
78
|
+
disableStickyPagination: {
|
|
79
|
+
type: Boolean,
|
|
80
|
+
default: false
|
|
81
|
+
},
|
|
78
82
|
globalItemsPerPage: {
|
|
79
83
|
type: Boolean,
|
|
80
84
|
default: () => void 0
|
|
@@ -234,15 +238,17 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
|
|
|
234
238
|
/**
|
|
235
239
|
* The one pagination bar sticks to the bottom of the view, so a long page can be turned without
|
|
236
240
|
* scrolling down to it. `position: sticky` keeps it inside this table, so stacked and side-by-side
|
|
237
|
-
* tables each hold their own bar. A nested table's bar stays in place
|
|
241
|
+
* tables each hold their own bar. A nested table's bar stays in place, since two stuck bars would
|
|
242
|
+
* stack, as does the bar of a table with `disableStickyPagination`.
|
|
238
243
|
*/
|
|
239
|
-
const
|
|
240
|
-
const
|
|
244
|
+
const paginationMayStick = computed(() => !__props.disableStickyPagination && !isNestedTable);
|
|
245
|
+
const canStickPagination = useStickyPaginationBar(tableWrapper, () => get(paginationMayStick) && get(showPagination));
|
|
246
|
+
const paginationStuck = computed(() => get(paginationMayStick) && get(canStickPagination));
|
|
241
247
|
const paginationBarElement = computed(() => {
|
|
242
248
|
const element = get(paginationBar)?.$el;
|
|
243
249
|
return element instanceof HTMLElement ? element : void 0;
|
|
244
250
|
});
|
|
245
|
-
useStickyBottomInset(paginationSentinel, paginationBarElement,
|
|
251
|
+
useStickyBottomInset(paginationSentinel, paginationBarElement, paginationStuck);
|
|
246
252
|
/**
|
|
247
253
|
* Grouped columns leave the column list, so their labels come from `cols`.
|
|
248
254
|
*/
|
|
@@ -550,13 +556,13 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
|
|
|
550
556
|
ref: paginationBar,
|
|
551
557
|
modelValue: unref(paginationData),
|
|
552
558
|
"onUpdate:modelValue": [_cache[4] || (_cache[4] = ($event) => isRef(paginationData) ? paginationData.value = $event : null), _cache[5] || (_cache[5] = ($event) => onPaginate())],
|
|
553
|
-
class: normalizeClass(unref(ui).pagination({ sticky: unref(
|
|
559
|
+
class: normalizeClass(unref(ui).pagination({ sticky: unref(paginationStuck) })),
|
|
554
560
|
dense: __props.dense,
|
|
555
561
|
loading: __props.loading,
|
|
556
562
|
mobile: unref(isMobile),
|
|
557
563
|
"disable-per-page": __props.disablePerPage,
|
|
558
564
|
"ranges-threshold": __props.rangesThreshold,
|
|
559
|
-
"data-sticky": unref(
|
|
565
|
+
"data-sticky": unref(paginationStuck) || void 0,
|
|
560
566
|
"data-id": "table-pagination"
|
|
561
567
|
}, null, 8, [
|
|
562
568
|
"modelValue",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDataTable.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_useSlots","_openBlock","_createElementBlock","_normalizeClass","_unref","_normalizeStyle","_createElementVNode","_createVNode","RuiDataTableMobileSort","_createCommentVNode","_createBlock","RuiTableHead","_createSlots","_renderList","_withCtx","_renderSlot","_normalizeProps","_guardReactiveProps","RuiDataTableBody","RuiTablePagination","_isRef"],"sources":["../../../src/components/tables/RuiDataTable.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object, IdType extends keyof T = keyof T\">\nimport type { GroupHeader } from '@/composables/tables/data-table/types';\nimport { dataTableStyles } from '@/components/tables/data-table-styles';\nimport { type DataTableClasses, type DataTableGroupLabel, provideDataTableContext, provideDataTableNested, useDataTableNested } from '@/components/tables/data-table/context';\nimport RuiDataTableBody from '@/components/tables/data-table/RuiDataTableBody.vue';\nimport RuiDataTableMobileSort from '@/components/tables/data-table/RuiDataTableMobileSort.vue';\nimport RuiTableHead, {\n type GroupData,\n type TableColumn,\n type TableRowKeyData,\n type TableSortData,\n} from '@/components/tables/RuiTableHead.vue';\nimport RuiTablePagination, {\n type TablePaginationData,\n} from '@/components/tables/RuiTablePagination.vue';\nimport { GroupExpandButtonPosition } from '@/components/tables/table-props';\nimport { useTable } from '@/composables/defaults/table';\nimport { useKeyboardScroll } from '@/composables/keyboard-scroll';\nimport { useStickyTableHeader } from '@/composables/sticky-header';\nimport { useTableColumns } from '@/composables/tables/data-table/columns';\nimport { useTableExpansion } from '@/composables/tables/data-table/expansion';\nimport { useTableGrouping } from '@/composables/tables/data-table/grouping';\nimport { usePageScroll, useStickyBottomInset, useStickyPaginationBar } from '@/composables/tables/data-table/page-scroll';\nimport { useTablePagination } from '@/composables/tables/data-table/pagination';\nimport { useTableSelection } from '@/composables/tables/data-table/selection';\nimport { useTableSort } from '@/composables/tables/data-table/sort';\n\nexport type { GroupedTableRow, GroupHeader, TableOptions } from '@/composables/tables/data-table/types';\n\nexport interface Props<T, K extends keyof T> {\n /**\n * list of items for each row\n */\n rows: readonly T[];\n /**\n * the attribute used to identify each row uniquely for selection, usually `id`\n */\n rowAttr: K;\n /**\n * model for internal searching\n */\n search?: string;\n /**\n * model for items per page\n * will be used if the `pagination` model isn't specified\n */\n itemsPerPage?: number;\n /**\n * list of column definitions\n */\n cols?: TableColumn<T>[];\n /**\n * attribute to use from column definitions to display column titles\n */\n columnAttr?: keyof TableColumn<T>;\n /**\n * flag to show a more or less spacious table\n */\n dense?: boolean;\n /**\n * flag to outline the flag with a border\n */\n outlined?: boolean;\n /**\n * should add zebra-striping to the table row\n */\n striped?: boolean;\n /**\n * flag to show loading state of the table\n * triggers indefinite progress at the bottom of the table header\n */\n loading?: boolean;\n disablePerPage?: boolean;\n /**\n * Maximum number of pages before the jump-to-page dropdown is replaced with\n * a numeric input. Defaults to `500`. Forwarded to `RuiTablePagination`.\n */\n rangesThreshold?: number;\n /**\n * The text and icon shown when there are no rows, e.g.\n * `:empty=\"\\{ icon: 'transactions-line', label: 'No transactions found' \\}\"`\n */\n empty?: {\n label?: string;\n description?: string;\n };\n /**\n * Why the last read failed. Shown above any rows kept from an earlier read,\n * or in place of the empty state; `loading` still takes precedence.\n */\n error?: string;\n /** Heading for that failure. */\n errorTitle?: string;\n /** Label for the retry control; without one, no control is offered. */\n retryText?: string;\n /**\n * Hide the pagination bar. The bar sits under the table and sticks to the bottom of the view\n * while the table runs past it.\n */\n hidePagination?: boolean;\n\n rounded?: 'sm' | 'md' | 'lg';\n /**\n * make expansion work like accordion\n */\n singleExpand?: boolean;\n /**\n * make table head stick to top on scroll\n */\n stickyHeader?: boolean;\n stickyOffset?: number;\n /**\n * Affects how the items per page work across the app.\n * When true, changing the items per page setting in one table will affect other tables.\n */\n globalItemsPerPage?: boolean;\n groupExpandButtonPosition?: GroupExpandButtonPosition;\n disabledRows?: readonly T[];\n multiPageSelect?: boolean;\n itemClass?: ((item: T) => string) | string;\n /**\n * Render each row as a stacked card instead of a table row once the measured\n * width is narrower than this width (in pixels). Columns flagged with\n * `mobileHidden` are dropped in this layout. Falls back to the global\n * `mobileBreakpoint` table default; leave both unset to keep the default table\n * layout at every width.\n */\n mobileBreakpoint?: number;\n /**\n * What the `mobileBreakpoint` is measured against: the browser `viewport`\n * (default) or this table's own `container` width. Use `container` when the\n * table lives in a narrow region of a wider window. Falls back to the global\n * `mobileBreakpointBasis` table default.\n */\n mobileBreakpointBasis?: 'viewport' | 'container';\n /**\n * Force the stacked mobile card layout on (`true`) or off (`false`),\n * regardless of `mobileBreakpoint`. Leave unset to derive it from the width.\n */\n mobile?: boolean;\n}\n\ndefineOptions({\n name: 'RuiDataTable',\n});\n\nconst selectedData = defineModel<T[IdType][]>();\n\nconst expanded = defineModel<T[]>('expanded');\n\nconst [pagination, paginationModifiers] = defineModel<TablePaginationData, 'external'>('pagination');\n\nconst [sort, sortModifiers] = defineModel<TableSortData<T>, 'external'>('sort');\n\nconst group = defineModel<TableRowKeyData<T>>('group');\n\nconst collapsed = defineModel<T[]>('collapsed');\n\nconst {\n rows,\n rowAttr,\n search = '',\n itemsPerPage = 10,\n cols,\n columnAttr = 'label',\n dense = false,\n outlined = false,\n striped = false,\n loading = false,\n disablePerPage = false,\n rangesThreshold = 500,\n empty = { label: 'No item found' },\n error = '',\n errorTitle = '',\n retryText = '',\n hidePagination = false,\n rounded = 'md',\n singleExpand = false,\n stickyHeader = false,\n stickyOffset,\n globalItemsPerPage = undefined,\n groupExpandButtonPosition = GroupExpandButtonPosition.start,\n disabledRows,\n multiPageSelect = false,\n itemClass = '',\n mobileBreakpoint,\n mobileBreakpointBasis,\n mobile,\n} = defineProps<Props<T, IdType>>();\n\nconst emit = defineEmits<{\n 'update:options': [value: { pagination?: TablePaginationData; sort?: TableSortData<T> }];\n 'copy:group': [value: GroupData<T>];\n 'retry': [];\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`header.${string}`, (props: { column: TableColumn<T> }) => any> &\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend': (props: { colspan: number }) => any;\n 'body.append': (props: { colspan: number }) => any;\n 'group.header': (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content': (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item': (props: { row: T; index: number }) => any;\n /**\n * A full-width row after every row, read as the second half of the same item: no divider between\n * them, one hover, the row's selected or open shade and stripe. For a long field, such as notes,\n * that would otherwise widen the table. It comes before an open expanded panel.\n */\n 'row-append': (props: { row: T; index: number }) => any;\n 'no-data': () => any;\n 'empty-description': () => any;\n 'error': () => any;\n 'tfoot': () => any;\n }\n>>();\n\nconst tableDefaults = useTable();\n\nconst tableWrapper = useTemplateRef<HTMLElement>('tableWrapper');\nconst paginationSentinel = useTemplateRef<HTMLElement>('paginationSentinel');\nconst paginationBar = useTemplateRef<InstanceType<typeof RuiTablePagination>>('paginationBar');\nconst { width: windowWidth } = useWindowSize();\nconst { width: containerWidth } = useElementSize(tableWrapper);\n\n// Per-table props win, then the global table defaults.\nconst resolvedMobileBreakpoint = computed<number | undefined>(() => {\n if (mobileBreakpoint !== undefined)\n return mobileBreakpoint;\n const globalBreakpoint = tableDefaults.mobileBreakpoint;\n return globalBreakpoint === undefined ? undefined : get(globalBreakpoint);\n});\nconst resolvedMobileBasis = computed<'viewport' | 'container'>(() => {\n if (mobileBreakpointBasis !== undefined)\n return mobileBreakpointBasis;\n const globalBasis = tableDefaults.mobileBreakpointBasis;\n return globalBasis === undefined ? 'viewport' : get(globalBasis);\n});\n\n/**\n * Whether the stacked card layout is showing.\n *\n * Vue coerces an absent Boolean prop to `false`, so `mobile` cannot say\n * \"unset\": with no breakpoint configured it is the manual switch, defaulting\n * to desktop, and with one configured the breakpoint drives the layout while\n * `mobile === true` can still force the stacked layout on.\n */\nconst isMobile = computed<boolean>(() => {\n const breakpoint = get(resolvedMobileBreakpoint);\n if (breakpoint === undefined)\n return mobile;\n if (mobile)\n return true;\n // `containerWidth` is 0 until measured; the viewport keeps the first paint off mobile\n const width = get(resolvedMobileBasis) === 'container'\n ? (get(containerWidth) || get(windowWidth))\n : get(windowWidth);\n return width < breakpoint;\n});\n\nconst stickyHeaderOffset = computed<number | undefined>(() =>\n stickyOffset !== undefined ? stickyOffset : get(tableDefaults.stickyOffset),\n);\n\n/**\n * A table rendered inside an expanded row must not pin its own toolbar: only\n * the outermost table sticks, otherwise the bars stack and collide.\n */\nconst isNestedTable = useDataTableNested();\nprovideDataTableNested();\n\n/**\n * On mobile there is no column header to pin, so `stickyHeader` pins the\n * pagination and sort toolbar instead while the card list scrolls.\n */\nconst stickyMobileToolbar = computed<boolean>(() => stickyHeader && get(isMobile) && !isNestedTable);\n\nconst table = useTemplateRef<HTMLTableElement>('table');\nconst tableScroller = useTemplateRef<HTMLElement>('tableScroller');\nconst scrollerTabindex = useKeyboardScroll(tableScroller);\n\nconst { stick } = useStickyTableHeader(\n () => stickyHeader,\n stickyHeaderOffset,\n { table },\n);\n\nconst { width: scrollerWidth } = useElementSize(tableScroller);\n\n/**\n * The visible width of the table, which an expanded row caps its content to.\n * Without the cap a wide panel, such as a nested table, sets the minimum width\n * of the whole table and pushes every column past the scroller. `initial`\n * resets the variable, so a nested table never inherits its parent's width.\n */\nconst viewportStyle = computed<Record<string, string>>(() => {\n const width = get(scrollerWidth);\n return { '--rui-table-viewport': width > 0 && !get(isMobile) ? `${width}px` : 'initial' };\n});\n\nconst { expandable, isExpanded, onToggleExpand } = useTableExpansion<T, IdType>(\n { rowAttr, singleExpand },\n { expanded },\n);\n\nfunction emitUpdateOptions(opts: { sort?: TableSortData<T>; pagination?: TablePaginationData }): void {\n emit('update:options', opts);\n}\n\nconst {\n sortData,\n sortedMap,\n sorted,\n onSort: applySort,\n} = useTableSort<T>(\n { rows: () => rows, search: () => search, sortModifiersExternal: sortModifiers.external },\n {\n sort,\n pagination,\n emitUpdateOptions,\n },\n);\n\nconst {\n groupKeys,\n groupKey,\n grouped,\n mappedGroups,\n isExpandedGroup,\n isHiddenRow,\n onToggleExpandGroup,\n onUngroup,\n} = useTableGrouping<T, IdType>(\n { rowAttr },\n {\n group,\n collapsed,\n sorted,\n },\n);\n\nconst {\n paginationData,\n filtered,\n setInternalTotal,\n resetPagination,\n} = useTablePagination<T>(\n {\n itemsPerPage,\n paginationModifiersExternal: paginationModifiers.external,\n globalItemsPerPage,\n },\n {\n pagination,\n grouped,\n isHiddenRow,\n sort,\n emitUpdateOptions,\n tableDefaults,\n },\n);\n\nconst noData = computed<boolean>(() => get(filtered).length === 0);\n\n// one loader at a time: the header bar marks a refetch over rows, and an empty table shows only its spinner row\nconst headerLoading = computed<boolean>(() => loading && !get(noData));\n\n/**\n * A nested table (a breakdown in an expanded row) that pages its own rows drops the bar when they all fit\n * the smallest page size: no control on it could change what shows, and in a breakdown it is pure noise.\n * A top-level table keeps it as a summary; a server-paged one keeps it, since only the server knows the total.\n */\nconst fitsSmallestPage = computed<boolean>(() => {\n if (!isNestedTable || paginationModifiers.external)\n return false;\n const { limits } = get(paginationData);\n const sizes = limits ?? toValue(tableDefaults.limits);\n // the rows themselves, not the pagination total, which is only filled in after mount\n return sizes.length > 0 && get(sorted).length <= Math.min(...sizes);\n});\n\nconst showPagination = computed<boolean>(() => !!get(paginationData) && !hidePagination && !get(fitsSmallestPage));\n\n/**\n * The one pagination bar sticks to the bottom of the view, so a long page can be turned without\n * scrolling down to it. `position: sticky` keeps it inside this table, so stacked and side-by-side\n * tables each hold their own bar. A nested table's bar stays in place: two stuck bars would stack.\n */\nconst canStickPagination = useStickyPaginationBar(tableWrapper, () => !isNestedTable && get(showPagination));\nconst stickyPagination = computed<boolean>(() => !isNestedTable && get(canStickPagination));\n\nconst paginationBarElement = computed<HTMLElement | undefined>(() => {\n const element: unknown = get(paginationBar)?.$el;\n return element instanceof HTMLElement ? element : undefined;\n});\n\n// while the bar is stuck to the page, `--rui-sticky-bottom` tells the page's floating parts to rise above it\nuseStickyBottomInset(paginationSentinel, paginationBarElement, stickyPagination);\n\n/**\n * Grouped columns leave the column list, so their labels come from `cols`.\n */\nconst groupLabels = computed<DataTableGroupLabel[]>(() => get(groupKeys).map((key) => {\n const label = cols?.find(column => column.key === key)?.[columnAttr];\n return {\n key: String(key),\n label: label === undefined || label === null ? String(key) : String(label),\n };\n}));\n\n/** Each group's list starts with its header entry, which is not a row. */\nfunction getGroupSize(identifier: string): number {\n return Math.max((get(mappedGroups)[identifier]?.length ?? 0) - 1, 0);\n}\n\nconst ui = computed<ReturnType<typeof dataTableStyles>>(() => dataTableStyles({\n outlined,\n rounded,\n dense,\n striped,\n mobile: get(isMobile),\n}));\n\nconst { columns, colspan, headerSlots, cellValue } = useTableColumns<T, IdType>({\n cols: () => cols,\n columnAttr,\n rows: () => rows,\n expandable,\n groupKeys,\n selectedData,\n slots,\n isMobile,\n tdResolver: options => get(ui).td(options),\n});\n\nconst showMobileSort = computed<boolean>(() =>\n get(isMobile) && !!get(sortData) && get(columns).some(column => column.sortable),\n);\n\nconst ITEM_SLOT_PREFIX = 'item.';\n\n// Slot keys are static for the component lifetime — no reactivity needed\nconst itemSlotKeys: Set<string> = new Set(\n Object.keys(slots)\n .filter((key): key is `item.${string}` => key.startsWith(ITEM_SLOT_PREFIX))\n .map(key => key.slice(ITEM_SLOT_PREFIX.length)),\n);\n\nconst {\n isAllSelected,\n indeterminate,\n isSelected,\n isDisabledRow,\n onToggleAll,\n onSelect,\n onCheckboxClick,\n deselectRemovedRows,\n resetCheckboxShiftState,\n} = useTableSelection<T, IdType>(\n { rowAttr, multiPageSelect, disabledRows: () => disabledRows },\n { selectedData, filtered },\n);\n\n/**\n * Sorting clears the selection. That lives here rather than in either\n * composable, which would make sort and selection depend on each other.\n */\nfunction onSort(payload: Parameters<typeof applySort>[0]): void {\n applySort(payload);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n}\n\nconst { revealTableTop } = usePageScroll(tableWrapper, stickyHeaderOffset);\n\nasync function onPaginate(): Promise<void> {\n if ((get(expanded)?.length ?? 0) > 0)\n set(expanded, []);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n await revealTableTop();\n}\n\n// Reset pagination page to 1 on search query change\nwatch(() => search, () => {\n resetPagination();\n onToggleAll(false);\n resetCheckboxShiftState();\n});\n\nwatch(sorted, (items) => {\n if (!multiPageSelect)\n deselectRemovedRows();\n setInternalTotal(items);\n});\n\nonMounted(() => {\n setInternalTotal(get(sorted));\n});\n\nconst classes = computed<DataTableClasses>(() => {\n const s = get(ui);\n return {\n td: s.td(),\n tr: s.tr(),\n trSelected: s.tr({ rowVariant: 'selected' }),\n trExpandable: s.tr({ rowVariant: 'expandable' }),\n trExpandedParent: s.tr({ rowVariant: 'expandedParent' }),\n trGroup: s.tr({ rowVariant: 'group' }),\n trEmpty: s.tr({ rowVariant: 'empty' }),\n checkbox: s.checkbox(),\n tbody: s.tbody(),\n tbodyLoader: s.tbodyLoader(),\n };\n});\n\nprovideDataTableContext<T, IdType>({\n // Reactive (ComputedRef/Ref) — destructuring preserves reactivity via Vue template auto-unwrap\n classes,\n columns,\n colspan,\n expandable,\n groupKey,\n groupLabels,\n isMobile,\n selectedData,\n // Static values\n cellValue,\n columnAttr,\n dense,\n getGroupSize,\n getRowId: (row: T) => row[rowAttr],\n itemSlotKeys,\n groupExpandButtonPosition,\n isDisabledRow,\n isExpanded,\n isExpandedGroup,\n isSelected,\n itemClass,\n onCheckboxClick,\n onCopyGroup: (header: GroupHeader<T>) => emit('copy:group', { key: get(groupKey) ?? '', value: header.group }),\n onSelect,\n onToggleExpand,\n onToggleExpandGroup,\n onUngroup,\n});\n</script>\n\n<template>\n <div\n ref=\"tableWrapper\"\n :class=\"ui.wrapper()\"\n data-id=\"table-wrapper\"\n >\n <div\n v-if=\"showMobileSort\"\n :class=\"stickyMobileToolbar ? 'sticky z-rui-raised bg-rui-background pt-2' : 'contents'\"\n :style=\"stickyMobileToolbar ? { top: `${stickyHeaderOffset ?? 0}px` } : undefined\"\n data-id=\"table-mobile-toolbar-sticky\"\n >\n <div\n class=\"flex justify-end p-2\"\n data-id=\"table-mobile-toolbar\"\n >\n <RuiDataTableMobileSort\n :columns=\"columns\"\n :column-attr=\"columnAttr\"\n :sorted-map=\"sortedMap\"\n :dense=\"dense\"\n @sort=\"onSort($event)\"\n />\n </div>\n </div>\n <div\n ref=\"tableScroller\"\n :class=\"[ui.scroller(), isMobile && !showMobileSort ? 'pt-2' : '']\"\n :tabindex=\"scrollerTabindex\"\n data-id=\"table-scroller\"\n >\n <table\n ref=\"table\"\n :class=\"ui.table()\"\n :style=\"viewportStyle\"\n :aria-busy=\"loading\"\n >\n <RuiTableHead\n v-if=\"!isMobile\"\n :loading=\"headerLoading\"\n :indeterminate=\"indeterminate\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :disable-check-all=\"!filtered?.length\"\n :is-all-selected=\"isAllSelected\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n :stick=\"stick\"\n :sticky-header=\"stickyHeader\"\n @sort=\"onSort($event)\"\n @select:all=\"onToggleAll($event)\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiTableHead\n v-if=\"stickyHeader && !isMobile\"\n :loading=\"headerLoading\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n data-id=\"head-clone\"\n class=\"opacity-0 invisible\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiDataTableBody\n :filtered=\"filtered\"\n :loading=\"loading\"\n :no-data=\"noData\"\n :empty=\"empty\"\n :error=\"error\"\n :error-title=\"errorTitle\"\n :retry-text=\"retryText\"\n @retry=\"emit('retry')\"\n >\n <template\n v-if=\"slots.error\"\n #error\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"error\" />\n </template>\n <template\n v-if=\"slots['body.prepend']\"\n #body.prepend=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.prepend\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header']\"\n #group.header=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header.content']\"\n #group.header.content=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header.content\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-for=\"key in itemSlotKeys\"\n #[`item.${key}`]=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n :name=\"`item.${key}`\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['row-append']\"\n #row-append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['no-data']\"\n #no-data\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"no-data\" />\n </template>\n <template\n v-if=\"slots['empty-description']\"\n #empty-description\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"empty-description\" />\n </template>\n <template\n v-if=\"slots['body.append']\"\n #body.append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableBody>\n <tfoot>\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"tfoot\" />\n </tfoot>\n </table>\n </div>\n <!-- the bar's own place after the rows: below the view, the bar is stuck; no divider of its own -->\n <div\n v-if=\"paginationData && showPagination && !isNestedTable\"\n ref=\"paginationSentinel\"\n class=\"border-0!\"\n aria-hidden=\"true\"\n data-id=\"table-pagination-sentinel\"\n />\n <RuiTablePagination\n v-if=\"paginationData && showPagination\"\n ref=\"paginationBar\"\n v-model=\"paginationData\"\n :class=\"ui.pagination({ sticky: stickyPagination })\"\n :dense=\"dense\"\n :loading=\"loading\"\n :mobile=\"isMobile\"\n :disable-per-page=\"disablePerPage\"\n :ranges-threshold=\"rangesThreshold\"\n :data-sticky=\"stickyPagination || undefined\"\n data-id=\"table-pagination\"\n @update:model-value=\"onPaginate()\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RuiDataTable.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_useSlots","_openBlock","_createElementBlock","_normalizeClass","_unref","_normalizeStyle","_createElementVNode","_createVNode","RuiDataTableMobileSort","_createCommentVNode","_createBlock","RuiTableHead","_createSlots","_renderList","_withCtx","_renderSlot","_normalizeProps","_guardReactiveProps","RuiDataTableBody","RuiTablePagination","_isRef"],"sources":["../../../src/components/tables/RuiDataTable.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object, IdType extends keyof T = keyof T\">\nimport type { GroupHeader } from '@/composables/tables/data-table/types';\nimport { dataTableStyles } from '@/components/tables/data-table-styles';\nimport { type DataTableClasses, type DataTableGroupLabel, provideDataTableContext, provideDataTableNested, useDataTableNested } from '@/components/tables/data-table/context';\nimport RuiDataTableBody from '@/components/tables/data-table/RuiDataTableBody.vue';\nimport RuiDataTableMobileSort from '@/components/tables/data-table/RuiDataTableMobileSort.vue';\nimport RuiTableHead, {\n type GroupData,\n type TableColumn,\n type TableRowKeyData,\n type TableSortData,\n} from '@/components/tables/RuiTableHead.vue';\nimport RuiTablePagination, {\n type TablePaginationData,\n} from '@/components/tables/RuiTablePagination.vue';\nimport { GroupExpandButtonPosition } from '@/components/tables/table-props';\nimport { useTable } from '@/composables/defaults/table';\nimport { useKeyboardScroll } from '@/composables/keyboard-scroll';\nimport { useStickyTableHeader } from '@/composables/sticky-header';\nimport { useTableColumns } from '@/composables/tables/data-table/columns';\nimport { useTableExpansion } from '@/composables/tables/data-table/expansion';\nimport { useTableGrouping } from '@/composables/tables/data-table/grouping';\nimport { usePageScroll, useStickyBottomInset, useStickyPaginationBar } from '@/composables/tables/data-table/page-scroll';\nimport { useTablePagination } from '@/composables/tables/data-table/pagination';\nimport { useTableSelection } from '@/composables/tables/data-table/selection';\nimport { useTableSort } from '@/composables/tables/data-table/sort';\n\nexport type { GroupedTableRow, GroupHeader, TableOptions } from '@/composables/tables/data-table/types';\n\nexport interface Props<T, K extends keyof T> {\n /**\n * list of items for each row\n */\n rows: readonly T[];\n /**\n * the attribute used to identify each row uniquely for selection, usually `id`\n */\n rowAttr: K;\n /**\n * model for internal searching\n */\n search?: string;\n /**\n * model for items per page\n * will be used if the `pagination` model isn't specified\n */\n itemsPerPage?: number;\n /**\n * list of column definitions\n */\n cols?: TableColumn<T>[];\n /**\n * attribute to use from column definitions to display column titles\n */\n columnAttr?: keyof TableColumn<T>;\n /**\n * flag to show a more or less spacious table\n */\n dense?: boolean;\n /**\n * flag to outline the flag with a border\n */\n outlined?: boolean;\n /**\n * should add zebra-striping to the table row\n */\n striped?: boolean;\n /**\n * flag to show loading state of the table\n * triggers indefinite progress at the bottom of the table header\n */\n loading?: boolean;\n disablePerPage?: boolean;\n /**\n * Maximum number of pages before the jump-to-page dropdown is replaced with\n * a numeric input. Defaults to `500`. Forwarded to `RuiTablePagination`.\n */\n rangesThreshold?: number;\n /**\n * The text and icon shown when there are no rows, e.g.\n * `:empty=\"\\{ icon: 'transactions-line', label: 'No transactions found' \\}\"`\n */\n empty?: {\n label?: string;\n description?: string;\n };\n /**\n * Why the last read failed. Shown above any rows kept from an earlier read,\n * or in place of the empty state; `loading` still takes precedence.\n */\n error?: string;\n /** Heading for that failure. */\n errorTitle?: string;\n /** Label for the retry control; without one, no control is offered. */\n retryText?: string;\n /**\n * Hide the pagination bar. The bar sits under the table and sticks to the bottom of the view\n * while the table runs past it.\n */\n hidePagination?: boolean;\n\n rounded?: 'sm' | 'md' | 'lg';\n /**\n * make expansion work like accordion\n */\n singleExpand?: boolean;\n /**\n * make table head stick to top on scroll\n */\n stickyHeader?: boolean;\n stickyOffset?: number;\n /**\n * keep the pagination bar at the table's end instead of pinning it to the bottom of the view while\n * the rows run past it, for a table that is one section of a longer page\n */\n disableStickyPagination?: boolean;\n /**\n * Affects how the items per page work across the app.\n * When true, changing the items per page setting in one table will affect other tables.\n */\n globalItemsPerPage?: boolean;\n groupExpandButtonPosition?: GroupExpandButtonPosition;\n disabledRows?: readonly T[];\n multiPageSelect?: boolean;\n itemClass?: ((item: T) => string) | string;\n /**\n * Render each row as a stacked card instead of a table row once the measured\n * width is narrower than this width (in pixels). Columns flagged with\n * `mobileHidden` are dropped in this layout. Falls back to the global\n * `mobileBreakpoint` table default; leave both unset to keep the default table\n * layout at every width.\n */\n mobileBreakpoint?: number;\n /**\n * What the `mobileBreakpoint` is measured against: the browser `viewport`\n * (default) or this table's own `container` width. Use `container` when the\n * table lives in a narrow region of a wider window. Falls back to the global\n * `mobileBreakpointBasis` table default.\n */\n mobileBreakpointBasis?: 'viewport' | 'container';\n /**\n * Force the stacked mobile card layout on (`true`) or off (`false`),\n * regardless of `mobileBreakpoint`. Leave unset to derive it from the width.\n */\n mobile?: boolean;\n}\n\ndefineOptions({\n name: 'RuiDataTable',\n});\n\nconst selectedData = defineModel<T[IdType][]>();\n\nconst expanded = defineModel<T[]>('expanded');\n\nconst [pagination, paginationModifiers] = defineModel<TablePaginationData, 'external'>('pagination');\n\nconst [sort, sortModifiers] = defineModel<TableSortData<T>, 'external'>('sort');\n\nconst group = defineModel<TableRowKeyData<T>>('group');\n\nconst collapsed = defineModel<T[]>('collapsed');\n\nconst {\n rows,\n rowAttr,\n search = '',\n itemsPerPage = 10,\n cols,\n columnAttr = 'label',\n dense = false,\n outlined = false,\n striped = false,\n loading = false,\n disablePerPage = false,\n rangesThreshold = 500,\n empty = { label: 'No item found' },\n error = '',\n errorTitle = '',\n retryText = '',\n hidePagination = false,\n rounded = 'md',\n singleExpand = false,\n stickyHeader = false,\n stickyOffset,\n disableStickyPagination = false,\n globalItemsPerPage = undefined,\n groupExpandButtonPosition = GroupExpandButtonPosition.start,\n disabledRows,\n multiPageSelect = false,\n itemClass = '',\n mobileBreakpoint,\n mobileBreakpointBasis,\n mobile,\n} = defineProps<Props<T, IdType>>();\n\nconst emit = defineEmits<{\n 'update:options': [value: { pagination?: TablePaginationData; sort?: TableSortData<T> }];\n 'copy:group': [value: GroupData<T>];\n 'retry': [];\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`header.${string}`, (props: { column: TableColumn<T> }) => any> &\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend': (props: { colspan: number }) => any;\n 'body.append': (props: { colspan: number }) => any;\n 'group.header': (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content': (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item': (props: { row: T; index: number }) => any;\n /**\n * A full-width row after every row, read as the second half of the same item: no divider between\n * them, one hover, the row's selected or open shade and stripe. For a long field, such as notes,\n * that would otherwise widen the table. It comes before an open expanded panel.\n */\n 'row-append': (props: { row: T; index: number }) => any;\n 'no-data': () => any;\n 'empty-description': () => any;\n 'error': () => any;\n 'tfoot': () => any;\n }\n>>();\n\nconst tableDefaults = useTable();\n\nconst tableWrapper = useTemplateRef<HTMLElement>('tableWrapper');\nconst paginationSentinel = useTemplateRef<HTMLElement>('paginationSentinel');\nconst paginationBar = useTemplateRef<InstanceType<typeof RuiTablePagination>>('paginationBar');\nconst { width: windowWidth } = useWindowSize();\nconst { width: containerWidth } = useElementSize(tableWrapper);\n\n// Per-table props win, then the global table defaults.\nconst resolvedMobileBreakpoint = computed<number | undefined>(() => {\n if (mobileBreakpoint !== undefined)\n return mobileBreakpoint;\n const globalBreakpoint = tableDefaults.mobileBreakpoint;\n return globalBreakpoint === undefined ? undefined : get(globalBreakpoint);\n});\nconst resolvedMobileBasis = computed<'viewport' | 'container'>(() => {\n if (mobileBreakpointBasis !== undefined)\n return mobileBreakpointBasis;\n const globalBasis = tableDefaults.mobileBreakpointBasis;\n return globalBasis === undefined ? 'viewport' : get(globalBasis);\n});\n\n/**\n * Whether the stacked card layout is showing.\n *\n * Vue coerces an absent Boolean prop to `false`, so `mobile` cannot say\n * \"unset\": with no breakpoint configured it is the manual switch, defaulting\n * to desktop, and with one configured the breakpoint drives the layout while\n * `mobile === true` can still force the stacked layout on.\n */\nconst isMobile = computed<boolean>(() => {\n const breakpoint = get(resolvedMobileBreakpoint);\n if (breakpoint === undefined)\n return mobile;\n if (mobile)\n return true;\n // `containerWidth` is 0 until measured; the viewport keeps the first paint off mobile\n const width = get(resolvedMobileBasis) === 'container'\n ? (get(containerWidth) || get(windowWidth))\n : get(windowWidth);\n return width < breakpoint;\n});\n\nconst stickyHeaderOffset = computed<number | undefined>(() =>\n stickyOffset !== undefined ? stickyOffset : get(tableDefaults.stickyOffset),\n);\n\n/**\n * A table rendered inside an expanded row must not pin its own toolbar: only\n * the outermost table sticks, otherwise the bars stack and collide.\n */\nconst isNestedTable = useDataTableNested();\nprovideDataTableNested();\n\n/**\n * On mobile there is no column header to pin, so `stickyHeader` pins the\n * pagination and sort toolbar instead while the card list scrolls.\n */\nconst stickyMobileToolbar = computed<boolean>(() => stickyHeader && get(isMobile) && !isNestedTable);\n\nconst table = useTemplateRef<HTMLTableElement>('table');\nconst tableScroller = useTemplateRef<HTMLElement>('tableScroller');\nconst scrollerTabindex = useKeyboardScroll(tableScroller);\n\nconst { stick } = useStickyTableHeader(\n () => stickyHeader,\n stickyHeaderOffset,\n { table },\n);\n\nconst { width: scrollerWidth } = useElementSize(tableScroller);\n\n/**\n * The visible width of the table, which an expanded row caps its content to.\n * Without the cap a wide panel, such as a nested table, sets the minimum width\n * of the whole table and pushes every column past the scroller. `initial`\n * resets the variable, so a nested table never inherits its parent's width.\n */\nconst viewportStyle = computed<Record<string, string>>(() => {\n const width = get(scrollerWidth);\n return { '--rui-table-viewport': width > 0 && !get(isMobile) ? `${width}px` : 'initial' };\n});\n\nconst { expandable, isExpanded, onToggleExpand } = useTableExpansion<T, IdType>(\n { rowAttr, singleExpand },\n { expanded },\n);\n\nfunction emitUpdateOptions(opts: { sort?: TableSortData<T>; pagination?: TablePaginationData }): void {\n emit('update:options', opts);\n}\n\nconst {\n sortData,\n sortedMap,\n sorted,\n onSort: applySort,\n} = useTableSort<T>(\n { rows: () => rows, search: () => search, sortModifiersExternal: sortModifiers.external },\n {\n sort,\n pagination,\n emitUpdateOptions,\n },\n);\n\nconst {\n groupKeys,\n groupKey,\n grouped,\n mappedGroups,\n isExpandedGroup,\n isHiddenRow,\n onToggleExpandGroup,\n onUngroup,\n} = useTableGrouping<T, IdType>(\n { rowAttr },\n {\n group,\n collapsed,\n sorted,\n },\n);\n\nconst {\n paginationData,\n filtered,\n setInternalTotal,\n resetPagination,\n} = useTablePagination<T>(\n {\n itemsPerPage,\n paginationModifiersExternal: paginationModifiers.external,\n globalItemsPerPage,\n },\n {\n pagination,\n grouped,\n isHiddenRow,\n sort,\n emitUpdateOptions,\n tableDefaults,\n },\n);\n\nconst noData = computed<boolean>(() => get(filtered).length === 0);\n\n// one loader at a time: the header bar marks a refetch over rows, and an empty table shows only its spinner row\nconst headerLoading = computed<boolean>(() => loading && !get(noData));\n\n/**\n * A nested table (a breakdown in an expanded row) that pages its own rows drops the bar when they all fit\n * the smallest page size: no control on it could change what shows, and in a breakdown it is pure noise.\n * A top-level table keeps it as a summary; a server-paged one keeps it, since only the server knows the total.\n */\nconst fitsSmallestPage = computed<boolean>(() => {\n if (!isNestedTable || paginationModifiers.external)\n return false;\n const { limits } = get(paginationData);\n const sizes = limits ?? toValue(tableDefaults.limits);\n // the rows themselves, not the pagination total, which is only filled in after mount\n return sizes.length > 0 && get(sorted).length <= Math.min(...sizes);\n});\n\nconst showPagination = computed<boolean>(() => !!get(paginationData) && !hidePagination && !get(fitsSmallestPage));\n\n/**\n * The one pagination bar sticks to the bottom of the view, so a long page can be turned without\n * scrolling down to it. `position: sticky` keeps it inside this table, so stacked and side-by-side\n * tables each hold their own bar. A nested table's bar stays in place, since two stuck bars would\n * stack, as does the bar of a table with `disableStickyPagination`.\n */\nconst paginationMayStick = computed<boolean>(() => !disableStickyPagination && !isNestedTable);\nconst canStickPagination = useStickyPaginationBar(tableWrapper, () => get(paginationMayStick) && get(showPagination));\nconst paginationStuck = computed<boolean>(() => get(paginationMayStick) && get(canStickPagination));\n\nconst paginationBarElement = computed<HTMLElement | undefined>(() => {\n const element: unknown = get(paginationBar)?.$el;\n return element instanceof HTMLElement ? element : undefined;\n});\n\n// while the bar is stuck to the page, `--rui-sticky-bottom` tells the page's floating parts to rise above it\nuseStickyBottomInset(paginationSentinel, paginationBarElement, paginationStuck);\n\n/**\n * Grouped columns leave the column list, so their labels come from `cols`.\n */\nconst groupLabels = computed<DataTableGroupLabel[]>(() => get(groupKeys).map((key) => {\n const label = cols?.find(column => column.key === key)?.[columnAttr];\n return {\n key: String(key),\n label: label === undefined || label === null ? String(key) : String(label),\n };\n}));\n\n/** Each group's list starts with its header entry, which is not a row. */\nfunction getGroupSize(identifier: string): number {\n return Math.max((get(mappedGroups)[identifier]?.length ?? 0) - 1, 0);\n}\n\nconst ui = computed<ReturnType<typeof dataTableStyles>>(() => dataTableStyles({\n outlined,\n rounded,\n dense,\n striped,\n mobile: get(isMobile),\n}));\n\nconst { columns, colspan, headerSlots, cellValue } = useTableColumns<T, IdType>({\n cols: () => cols,\n columnAttr,\n rows: () => rows,\n expandable,\n groupKeys,\n selectedData,\n slots,\n isMobile,\n tdResolver: options => get(ui).td(options),\n});\n\nconst showMobileSort = computed<boolean>(() =>\n get(isMobile) && !!get(sortData) && get(columns).some(column => column.sortable),\n);\n\nconst ITEM_SLOT_PREFIX = 'item.';\n\n// Slot keys are static for the component lifetime — no reactivity needed\nconst itemSlotKeys: Set<string> = new Set(\n Object.keys(slots)\n .filter((key): key is `item.${string}` => key.startsWith(ITEM_SLOT_PREFIX))\n .map(key => key.slice(ITEM_SLOT_PREFIX.length)),\n);\n\nconst {\n isAllSelected,\n indeterminate,\n isSelected,\n isDisabledRow,\n onToggleAll,\n onSelect,\n onCheckboxClick,\n deselectRemovedRows,\n resetCheckboxShiftState,\n} = useTableSelection<T, IdType>(\n { rowAttr, multiPageSelect, disabledRows: () => disabledRows },\n { selectedData, filtered },\n);\n\n/**\n * Sorting clears the selection. That lives here rather than in either\n * composable, which would make sort and selection depend on each other.\n */\nfunction onSort(payload: Parameters<typeof applySort>[0]): void {\n applySort(payload);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n}\n\nconst { revealTableTop } = usePageScroll(tableWrapper, stickyHeaderOffset);\n\nasync function onPaginate(): Promise<void> {\n if ((get(expanded)?.length ?? 0) > 0)\n set(expanded, []);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n await revealTableTop();\n}\n\n// Reset pagination page to 1 on search query change\nwatch(() => search, () => {\n resetPagination();\n onToggleAll(false);\n resetCheckboxShiftState();\n});\n\nwatch(sorted, (items) => {\n if (!multiPageSelect)\n deselectRemovedRows();\n setInternalTotal(items);\n});\n\nonMounted(() => {\n setInternalTotal(get(sorted));\n});\n\nconst classes = computed<DataTableClasses>(() => {\n const s = get(ui);\n return {\n td: s.td(),\n tr: s.tr(),\n trSelected: s.tr({ rowVariant: 'selected' }),\n trExpandable: s.tr({ rowVariant: 'expandable' }),\n trExpandedParent: s.tr({ rowVariant: 'expandedParent' }),\n trGroup: s.tr({ rowVariant: 'group' }),\n trEmpty: s.tr({ rowVariant: 'empty' }),\n checkbox: s.checkbox(),\n tbody: s.tbody(),\n tbodyLoader: s.tbodyLoader(),\n };\n});\n\nprovideDataTableContext<T, IdType>({\n // Reactive (ComputedRef/Ref) — destructuring preserves reactivity via Vue template auto-unwrap\n classes,\n columns,\n colspan,\n expandable,\n groupKey,\n groupLabels,\n isMobile,\n selectedData,\n // Static values\n cellValue,\n columnAttr,\n dense,\n getGroupSize,\n getRowId: (row: T) => row[rowAttr],\n itemSlotKeys,\n groupExpandButtonPosition,\n isDisabledRow,\n isExpanded,\n isExpandedGroup,\n isSelected,\n itemClass,\n onCheckboxClick,\n onCopyGroup: (header: GroupHeader<T>) => emit('copy:group', { key: get(groupKey) ?? '', value: header.group }),\n onSelect,\n onToggleExpand,\n onToggleExpandGroup,\n onUngroup,\n});\n</script>\n\n<template>\n <div\n ref=\"tableWrapper\"\n :class=\"ui.wrapper()\"\n data-id=\"table-wrapper\"\n >\n <div\n v-if=\"showMobileSort\"\n :class=\"stickyMobileToolbar ? 'sticky z-rui-raised bg-rui-background pt-2' : 'contents'\"\n :style=\"stickyMobileToolbar ? { top: `${stickyHeaderOffset ?? 0}px` } : undefined\"\n data-id=\"table-mobile-toolbar-sticky\"\n >\n <div\n class=\"flex justify-end p-2\"\n data-id=\"table-mobile-toolbar\"\n >\n <RuiDataTableMobileSort\n :columns=\"columns\"\n :column-attr=\"columnAttr\"\n :sorted-map=\"sortedMap\"\n :dense=\"dense\"\n @sort=\"onSort($event)\"\n />\n </div>\n </div>\n <div\n ref=\"tableScroller\"\n :class=\"[ui.scroller(), isMobile && !showMobileSort ? 'pt-2' : '']\"\n :tabindex=\"scrollerTabindex\"\n data-id=\"table-scroller\"\n >\n <table\n ref=\"table\"\n :class=\"ui.table()\"\n :style=\"viewportStyle\"\n :aria-busy=\"loading\"\n >\n <RuiTableHead\n v-if=\"!isMobile\"\n :loading=\"headerLoading\"\n :indeterminate=\"indeterminate\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :disable-check-all=\"!filtered?.length\"\n :is-all-selected=\"isAllSelected\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n :stick=\"stick\"\n :sticky-header=\"stickyHeader\"\n @sort=\"onSort($event)\"\n @select:all=\"onToggleAll($event)\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiTableHead\n v-if=\"stickyHeader && !isMobile\"\n :loading=\"headerLoading\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n data-id=\"head-clone\"\n class=\"opacity-0 invisible\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiDataTableBody\n :filtered=\"filtered\"\n :loading=\"loading\"\n :no-data=\"noData\"\n :empty=\"empty\"\n :error=\"error\"\n :error-title=\"errorTitle\"\n :retry-text=\"retryText\"\n @retry=\"emit('retry')\"\n >\n <template\n v-if=\"slots.error\"\n #error\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"error\" />\n </template>\n <template\n v-if=\"slots['body.prepend']\"\n #body.prepend=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.prepend\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header']\"\n #group.header=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header.content']\"\n #group.header.content=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header.content\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-for=\"key in itemSlotKeys\"\n #[`item.${key}`]=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n :name=\"`item.${key}`\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['row-append']\"\n #row-append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['no-data']\"\n #no-data\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"no-data\" />\n </template>\n <template\n v-if=\"slots['empty-description']\"\n #empty-description\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"empty-description\" />\n </template>\n <template\n v-if=\"slots['body.append']\"\n #body.append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableBody>\n <tfoot>\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"tfoot\" />\n </tfoot>\n </table>\n </div>\n <!-- the bar's own place after the rows: below the view, the bar is stuck; no divider of its own -->\n <div\n v-if=\"paginationData && showPagination && !isNestedTable\"\n ref=\"paginationSentinel\"\n class=\"border-0!\"\n aria-hidden=\"true\"\n data-id=\"table-pagination-sentinel\"\n />\n <RuiTablePagination\n v-if=\"paginationData && showPagination\"\n ref=\"paginationBar\"\n v-model=\"paginationData\"\n :class=\"ui.pagination({ sticky: paginationStuck })\"\n :dense=\"dense\"\n :loading=\"loading\"\n :mobile=\"isMobile\"\n :disable-per-page=\"disablePerPage\"\n :ranges-threshold=\"rangesThreshold\"\n :data-sticky=\"paginationStuck || undefined\"\n data-id=\"table-pagination\"\n @update:model-value=\"onPaginate()\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDataTableBody.js","names":["_sfc_main"],"sources":["../../../../src/components/tables/data-table/RuiDataTableBody.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport { useDataTableColumns, useDataTableRowIdentity, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableEmptyRow from '@/components/tables/data-table/RuiDataTableEmptyRow.vue';\nimport RuiDataTableErrorRow from '@/components/tables/data-table/RuiDataTableErrorRow.vue';\nimport RuiDataTableGroupRow from '@/components/tables/data-table/RuiDataTableGroupRow.vue';\nimport RuiDataTableLoadingRow from '@/components/tables/data-table/RuiDataTableLoadingRow.vue';\nimport RuiDataTableRow from '@/components/tables/data-table/RuiDataTableRow.vue';\nimport { type GroupHeader, isRow } from '@/composables/tables/data-table/types';\n\nconst { error, loading, noData } = defineProps<{\n filtered: (T | GroupHeader<T>)[];\n loading: boolean;\n noData: boolean;\n empty: { label?: string; description?: string };\n error: string;\n errorTitle: string;\n retryText: string;\n}>();\n\nconst emit = defineEmits<{\n retry: [];\n}>();\n\ndefineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend'?: (props: { colspan: number }) => any;\n 'body.append'?: (props: { colspan: number }) => any;\n 'group.header'?: (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content'?: (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n 'no-data'?: () => any;\n 'empty-description'?: () => any;\n 'error'?: () => any;\n }\n>>();\n\nconst { classes, colspan } = useDataTableStyling();\nconst { itemSlotKeys } = useDataTableColumns<T>();\nconst { getRowId } = useDataTableRowIdentity<T>();\n\n/**\n * Loading outranks a failure, which outranks the empty state: rows that did\n * not arrive are not rows that are not there. Rows kept from an earlier read\n * stay below the error.\n */\nconst showError = computed<boolean>(() => !!error && !loading);\n\n/**\n * Rows shown while a read is in flight are the previous result
|
|
1
|
+
{"version":3,"file":"RuiDataTableBody.js","names":["_sfc_main"],"sources":["../../../../src/components/tables/data-table/RuiDataTableBody.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport { useDataTableColumns, useDataTableRowIdentity, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableEmptyRow from '@/components/tables/data-table/RuiDataTableEmptyRow.vue';\nimport RuiDataTableErrorRow from '@/components/tables/data-table/RuiDataTableErrorRow.vue';\nimport RuiDataTableGroupRow from '@/components/tables/data-table/RuiDataTableGroupRow.vue';\nimport RuiDataTableLoadingRow from '@/components/tables/data-table/RuiDataTableLoadingRow.vue';\nimport RuiDataTableRow from '@/components/tables/data-table/RuiDataTableRow.vue';\nimport { type GroupHeader, isRow } from '@/composables/tables/data-table/types';\n\nconst { error, loading, noData } = defineProps<{\n filtered: (T | GroupHeader<T>)[];\n loading: boolean;\n noData: boolean;\n empty: { label?: string; description?: string };\n error: string;\n errorTitle: string;\n retryText: string;\n}>();\n\nconst emit = defineEmits<{\n retry: [];\n}>();\n\ndefineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend'?: (props: { colspan: number }) => any;\n 'body.append'?: (props: { colspan: number }) => any;\n 'group.header'?: (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content'?: (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n 'no-data'?: () => any;\n 'empty-description'?: () => any;\n 'error'?: () => any;\n }\n>>();\n\nconst { classes, colspan } = useDataTableStyling();\nconst { itemSlotKeys } = useDataTableColumns<T>();\nconst { getRowId } = useDataTableRowIdentity<T>();\n\n/**\n * Loading outranks a failure, which outranks the empty state: rows that did\n * not arrive are not rows that are not there. Rows kept from an earlier read\n * stay below the error.\n */\nconst showError = computed<boolean>(() => !!error && !loading);\n\n/**\n * Rows shown while a read is in flight are the previous result. They stay at\n * full strength and usable, since a refresh can run for minutes; the header\n * bar marks the read, and `data-stale` lets a consumer style them.\n */\nconst stale = computed<boolean>(() => loading && !noData);\n</script>\n\n<template>\n <tbody\n :class=\"classes.tbody\"\n :data-stale=\"stale || undefined\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n v-if=\"$slots['body.prepend']\"\n :colspan=\"colspan\"\n name=\"body.prepend\"\n />\n <RuiDataTableErrorRow\n v-if=\"showError\"\n :message=\"error\"\n :title=\"errorTitle\"\n :retry-text=\"retryText\"\n @retry=\"emit('retry')\"\n >\n <template\n v-if=\"$slots.error\"\n #error\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"error\" />\n </template>\n </RuiDataTableErrorRow>\n <template v-for=\"(row, index) in filtered\">\n <RuiDataTableGroupRow\n v-if=\"!isRow(row)\"\n :key=\"`group-${row.identifier}`\"\n :row=\"row\"\n >\n <template\n v-if=\"$slots['group.header']\"\n #group.header=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"$slots['group.header.content']\"\n #group.header.content=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header.content\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableGroupRow>\n <RuiDataTableRow\n v-else\n :key=\"`row-${getRowId(row)}`\"\n :row=\"row\"\n :index=\"index\"\n >\n <template\n v-for=\"key in itemSlotKeys\"\n #[`item.${key}`]=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n :name=\"`item.${key}`\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"$slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"$slots['row-append']\"\n #row-append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableRow>\n </template>\n <RuiDataTableLoadingRow v-if=\"loading && noData\" />\n <RuiDataTableEmptyRow\n v-if=\"noData && empty && !loading && !showError\"\n :empty=\"empty\"\n >\n <template\n v-if=\"$slots['no-data']\"\n #no-data\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"no-data\" />\n </template>\n <template\n v-if=\"$slots['empty-description']\"\n #empty-description\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"empty-description\" />\n </template>\n </RuiDataTableEmptyRow>\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n v-if=\"$slots['body.append']\"\n :colspan=\"colspan\"\n name=\"body.append\"\n />\n </tbody>\n</template>\n"],"mappings":""}
|
package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -32,13 +32,14 @@ var RuiDataTableBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
32
32
|
*/
|
|
33
33
|
const showError = computed(() => !!__props.error && !__props.loading);
|
|
34
34
|
/**
|
|
35
|
-
* Rows shown while a read is in flight are the previous result
|
|
36
|
-
*
|
|
35
|
+
* Rows shown while a read is in flight are the previous result. They stay at
|
|
36
|
+
* full strength and usable, since a refresh can run for minutes; the header
|
|
37
|
+
* bar marks the read, and `data-stale` lets a consumer style them.
|
|
37
38
|
*/
|
|
38
39
|
const stale = computed(() => __props.loading && !__props.noData);
|
|
39
40
|
return (_ctx, _cache) => {
|
|
40
41
|
return openBlock(), createElementBlock("tbody", {
|
|
41
|
-
class: normalizeClass(
|
|
42
|
+
class: normalizeClass(unref(classes).tbody),
|
|
42
43
|
"data-stale": unref(stale) || void 0
|
|
43
44
|
}, [
|
|
44
45
|
_ctx.$slots["body.prepend"] ? renderSlot(_ctx.$slots, "body.prepend", { colspan: unref(colspan) }, void 0, void 0, 0) : createCommentVNode("", true),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDataTableBody.vue_vue_type_script_setup_true_lang.js","names":["$slots","_openBlock","_createElementBlock","_normalizeClass","_unref","_renderSlot","_createCommentVNode","_createBlock","RuiDataTableErrorRow","_createSlots","_withCtx","_Fragment","_renderList","RuiDataTableGroupRow","_mergeProps","RuiDataTableRow","RuiDataTableLoadingRow","RuiDataTableEmptyRow"],"sources":["../../../../src/components/tables/data-table/RuiDataTableBody.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport { useDataTableColumns, useDataTableRowIdentity, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableEmptyRow from '@/components/tables/data-table/RuiDataTableEmptyRow.vue';\nimport RuiDataTableErrorRow from '@/components/tables/data-table/RuiDataTableErrorRow.vue';\nimport RuiDataTableGroupRow from '@/components/tables/data-table/RuiDataTableGroupRow.vue';\nimport RuiDataTableLoadingRow from '@/components/tables/data-table/RuiDataTableLoadingRow.vue';\nimport RuiDataTableRow from '@/components/tables/data-table/RuiDataTableRow.vue';\nimport { type GroupHeader, isRow } from '@/composables/tables/data-table/types';\n\nconst { error, loading, noData } = defineProps<{\n filtered: (T | GroupHeader<T>)[];\n loading: boolean;\n noData: boolean;\n empty: { label?: string; description?: string };\n error: string;\n errorTitle: string;\n retryText: string;\n}>();\n\nconst emit = defineEmits<{\n retry: [];\n}>();\n\ndefineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend'?: (props: { colspan: number }) => any;\n 'body.append'?: (props: { colspan: number }) => any;\n 'group.header'?: (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content'?: (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n 'no-data'?: () => any;\n 'empty-description'?: () => any;\n 'error'?: () => any;\n }\n>>();\n\nconst { classes, colspan } = useDataTableStyling();\nconst { itemSlotKeys } = useDataTableColumns<T>();\nconst { getRowId } = useDataTableRowIdentity<T>();\n\n/**\n * Loading outranks a failure, which outranks the empty state: rows that did\n * not arrive are not rows that are not there. Rows kept from an earlier read\n * stay below the error.\n */\nconst showError = computed<boolean>(() => !!error && !loading);\n\n/**\n * Rows shown while a read is in flight are the previous result
|
|
1
|
+
{"version":3,"file":"RuiDataTableBody.vue_vue_type_script_setup_true_lang.js","names":["$slots","_openBlock","_createElementBlock","_normalizeClass","_unref","_renderSlot","_createCommentVNode","_createBlock","RuiDataTableErrorRow","_createSlots","_withCtx","_Fragment","_renderList","RuiDataTableGroupRow","_mergeProps","RuiDataTableRow","RuiDataTableLoadingRow","RuiDataTableEmptyRow"],"sources":["../../../../src/components/tables/data-table/RuiDataTableBody.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport { useDataTableColumns, useDataTableRowIdentity, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableEmptyRow from '@/components/tables/data-table/RuiDataTableEmptyRow.vue';\nimport RuiDataTableErrorRow from '@/components/tables/data-table/RuiDataTableErrorRow.vue';\nimport RuiDataTableGroupRow from '@/components/tables/data-table/RuiDataTableGroupRow.vue';\nimport RuiDataTableLoadingRow from '@/components/tables/data-table/RuiDataTableLoadingRow.vue';\nimport RuiDataTableRow from '@/components/tables/data-table/RuiDataTableRow.vue';\nimport { type GroupHeader, isRow } from '@/composables/tables/data-table/types';\n\nconst { error, loading, noData } = defineProps<{\n filtered: (T | GroupHeader<T>)[];\n loading: boolean;\n noData: boolean;\n empty: { label?: string; description?: string };\n error: string;\n errorTitle: string;\n retryText: string;\n}>();\n\nconst emit = defineEmits<{\n retry: [];\n}>();\n\ndefineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend'?: (props: { colspan: number }) => any;\n 'body.append'?: (props: { colspan: number }) => any;\n 'group.header'?: (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content'?: (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n 'no-data'?: () => any;\n 'empty-description'?: () => any;\n 'error'?: () => any;\n }\n>>();\n\nconst { classes, colspan } = useDataTableStyling();\nconst { itemSlotKeys } = useDataTableColumns<T>();\nconst { getRowId } = useDataTableRowIdentity<T>();\n\n/**\n * Loading outranks a failure, which outranks the empty state: rows that did\n * not arrive are not rows that are not there. Rows kept from an earlier read\n * stay below the error.\n */\nconst showError = computed<boolean>(() => !!error && !loading);\n\n/**\n * Rows shown while a read is in flight are the previous result. They stay at\n * full strength and usable, since a refresh can run for minutes; the header\n * bar marks the read, and `data-stale` lets a consumer style them.\n */\nconst stale = computed<boolean>(() => loading && !noData);\n</script>\n\n<template>\n <tbody\n :class=\"classes.tbody\"\n :data-stale=\"stale || undefined\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n v-if=\"$slots['body.prepend']\"\n :colspan=\"colspan\"\n name=\"body.prepend\"\n />\n <RuiDataTableErrorRow\n v-if=\"showError\"\n :message=\"error\"\n :title=\"errorTitle\"\n :retry-text=\"retryText\"\n @retry=\"emit('retry')\"\n >\n <template\n v-if=\"$slots.error\"\n #error\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"error\" />\n </template>\n </RuiDataTableErrorRow>\n <template v-for=\"(row, index) in filtered\">\n <RuiDataTableGroupRow\n v-if=\"!isRow(row)\"\n :key=\"`group-${row.identifier}`\"\n :row=\"row\"\n >\n <template\n v-if=\"$slots['group.header']\"\n #group.header=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"$slots['group.header.content']\"\n #group.header.content=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header.content\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableGroupRow>\n <RuiDataTableRow\n v-else\n :key=\"`row-${getRowId(row)}`\"\n :row=\"row\"\n :index=\"index\"\n >\n <template\n v-for=\"key in itemSlotKeys\"\n #[`item.${key}`]=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n :name=\"`item.${key}`\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"$slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"$slots['row-append']\"\n #row-append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableRow>\n </template>\n <RuiDataTableLoadingRow v-if=\"loading && noData\" />\n <RuiDataTableEmptyRow\n v-if=\"noData && empty && !loading && !showError\"\n :empty=\"empty\"\n >\n <template\n v-if=\"$slots['no-data']\"\n #no-data\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"no-data\" />\n </template>\n <template\n v-if=\"$slots['empty-description']\"\n #empty-description\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"empty-description\" />\n </template>\n </RuiDataTableEmptyRow>\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n v-if=\"$slots['body.append']\"\n :colspan=\"colspan\"\n name=\"body.append\"\n />\n </tbody>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDataTableRow.js","names":["_sfc_main"],"sources":["../../../../src/components/tables/data-table/RuiDataTableRow.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport RuiCheckbox from '@/components/forms/checkbox/RuiCheckbox.vue';\nimport { useDataTableColumns, useDataTableExpansion, useDataTableRowIdentity, useDataTableSelection, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableAppendRow from '@/components/tables/data-table/RuiDataTableAppendRow.vue';\nimport RuiDataTableCell from '@/components/tables/data-table/RuiDataTableCell.vue';\nimport RuiDataTableExpandedRow from '@/components/tables/data-table/RuiDataTableExpandedRow.vue';\nimport RuiExpandButton from '@/components/tables/RuiExpandButton.vue';\n\nconst {\n row,\n index,\n} = defineProps<{\n row: T;\n index: number;\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n }\n>>();\n\nconst { classes, dense, isMobile } = useDataTableStyling();\nconst { cellValue, columns, itemSlotKeys } = useDataTableColumns<T>();\nconst { isDisabledRow, isSelected, onCheckboxClick, onSelect, selectedData } = useDataTableSelection<T>();\nconst { expandable, isExpanded, onToggleExpand } = useDataTableExpansion<T>();\nconst { getRowId, itemClass } = useDataTableRowIdentity<T>();\n\nconst rowId = computed<T[keyof T]>(() => getRowId(row));\nconst selected = computed<boolean>(() => isSelected(get(rowId)));\nconst disabled = computed<boolean>(() => isDisabledRow(get(rowId)));\nconst expanded = computed<boolean>(() => get(expandable) && !!slots['expanded-item'] && isExpanded(get(rowId)));\n\n/** How long a closing panel stays to fade out; matches its `duration-100`. */\nconst PANEL_LEAVE_MS = 100;\n\nconst reducedMotion = usePreferredReducedMotion();\n\n/**\n * Whether the panel is in the DOM, which outlasts `expanded` by its fade-out.\n *\n * @remarks\n * Not a `<Transition>`: test utilities stub that with an element, which lands inside the consumer's\n * `<tbody>` and shifts every `tr:nth-child` its specs count. The fade-in is CSS `@starting-style`.\n */\nconst panelShown = ref<boolean>(get(expanded));\nconst panelClosing = ref<boolean>(false);\n\nconst { start: finishClosing, stop: cancelClosing } = useTimeoutFn(() => {\n set(panelShown, false);\n set(panelClosing, false);\n}, PANEL_LEAVE_MS, { immediate: false });\n\nwatch(expanded, (open) => {\n if (open) {\n cancelClosing();\n set(panelClosing, false);\n set(panelShown, true);\n return;\n }\n if (!get(panelShown))\n return;\n if (get(reducedMotion) === 'reduce') {\n set(panelShown, false);\n return;\n }\n set(panelClosing, true);\n finishClosing();\n});\n\nconst rowClass = computed<string>(() => typeof itemClass === 'string' ? itemClass : itemClass(row));\n\n/** Selection wins over the open-panel shade, so a selected row still reads as selected. */\nconst stateClass = computed<string>(() => {\n if (get(selected))\n return get(classes).trSelected;\n if (get(expanded))\n return get(classes).trExpandedParent;\n return get(classes).tr;\n});\n\n/** Whether the row has a follow-up row, which reads as the second half of the same item. */\nconst appended = computed<boolean>(() => !!slots['row-append']);\n\n/**\n * The stripe follows the item, not the `<tr>`: counting rows would shade an item and its follow-up\n * differently, and an open panel would flip every stripe below it. The table's `striped` variant\n * shades the marked rows.\n */\nconst stripe = computed<'' | undefined>(() => (index % 2 === 1 ? '' : undefined));\n\n/**\n * The two rows of an item highlight together, whichever one the pointer is over. An open row keeps\n * its band rather than taking the hover, as it does without a follow-up.\n */\nconst pairHoverClass = computed<string>(() => {\n if (!get(appended) || get(expanded) || get(isMobile))\n return '';\n return 'has-[+[data-id=row-append]:hover]:bg-rui-hover';\n});\nconst appendHoverClass = computed<string>(() => {\n if (get(expanded) || get(isMobile))\n return '';\n return '[[data-id=row]:hover+&]:bg-rui-hover';\n});\n\n/**\n * On mobile the follow-up is the bottom of the item's card: square on top, against the card, and\n * rounded below unless an open panel follows it.\n */\nconst mobileAppendClass = computed<string>(() => {\n const shared = 'block border-x border-b! border-rui-divider overflow-hidden';\n return get(expanded) ? shared : `${shared} rounded-b-rui-card mb-3`;\n});\n\n/**\n * A column is pinned to the mobile card header when it is flagged\n * `mobileHeader`, typically an action column, or when it is the\n * auto-generated expand column.\n */\nfunction isMobileHeaderColumn(column: TableColumn<T>): boolean {\n return !!column.mobileHeader || column.key === 'expand';\n}\n\n/**\n * A pinned column only earns a spot in the header if it renders something: the\n * expand toggle, a provided item slot, or a non-empty cell value. Without this,\n * a pinned column with no content, such as an action column whose\n * `#item.action` slot a nested table does not provide, leaves an empty header\n * bar with just its divider line.\n */\nfunction mobileHeaderColumnHasContent(column: TableColumn<T>): boolean {\n if (column.key === 'expand')\n return true;\n if (itemSlotKeys.has(column.key.toString()))\n return true;\n const value = cellValue(row, column.key);\n return value !== undefined && value !== null && value !== '';\n}\n\n/**\n * In the stacked mobile layout, header columns render in the card header row\n * instead of as a label/value pair. Everything else stacks below in the body.\n */\nconst mobileHeaderColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => isMobileHeaderColumn(column) && mobileHeaderColumnHasContent(column)) : [],\n);\nconst bodyColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => !isMobileHeaderColumn(column)) : get(columns),\n);\nconst showMobileHeader = computed<boolean>(() =>\n get(isMobile) && (!!get(selectedData) || get(mobileHeaderColumns).length > 0),\n);\n\n/**\n * Without a selection checkbox the header bar would hold only the pinned\n * actions, so they float in the card's top-right corner instead and the first\n * field row makes room for them.\n */\nconst compactMobileHeader = computed<boolean>(() =>\n get(showMobileHeader) && !get(selectedData) && get(bodyColumns).length > 0,\n);\n\n/** Room for each floating action, about one small icon button wide. */\nconst firstRowInset = computed<Record<string, string> | undefined>(() =>\n get(compactMobileHeader) ? { paddingRight: `${get(mobileHeaderColumns).length * 2 + 1}rem` } : undefined,\n);\n\n/**\n * `border-y!` defeats the `divide-y-0` on the mobile tbody, which otherwise\n * zeroes the top and bottom border on every card except the first. An expanded\n * card flattens its bottom edge so the expanded panel attaches flush beneath\n * it. A card with a follow-up row drops its bottom border too, so the\n * follow-up continues it with no line between them, as on desktop.\n *\n * These bindings do not run through the class merger, so each state picks its\n * own utilities rather than emitting conflicting ones.\n */\nconst mobileCardClass = computed<string>(() => {\n if (get(appended))\n return 'relative flex flex-col border-x border-t! border-rui-divider overflow-hidden rounded-t-rui-card mb-0';\n const shared = 'relative flex flex-col border border-y! border-rui-divider overflow-hidden';\n return get(expanded)\n ? `${shared} rounded-t-rui-card mb-0`\n : `${shared} rounded-rui-card mb-3 last:mb-0`;\n});\n</script>\n\n<template>\n <tr\n :class=\"[stateClass, rowClass, pairHoverClass, isMobile ? mobileCardClass : '']\"\n :aria-selected=\"selectedData ? selected : undefined\"\n :data-stripe=\"stripe\"\n data-id=\"row\"\n >\n <!-- Mobile card header: checkbox on the left, pinned action columns on the right -->\n <td\n v-if=\"showMobileHeader\"\n :class=\"compactMobileHeader\n ? 'absolute top-0 right-0 z-1 flex items-center gap-1 px-2 py-1'\n : 'flex items-center justify-between gap-2 px-4 py-2 border-b border-rui-divider'\"\n data-id=\"mobile-card-header\"\n >\n <RuiCheckbox\n v-if=\"selectedData\"\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n <span v-else-if=\"!compactMobileHeader\" />\n\n <div\n v-if=\"mobileHeaderColumns.length > 0\"\n class=\"flex items-center gap-1 min-w-0\"\n >\n <template\n v-for=\"(column, headerIndex) in mobileHeaderColumns\"\n :key=\"`header-${headerIndex}`\"\n >\n <slot\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n :name=\"`item.${column.key.toString()}`\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n />\n <RuiExpandButton\n v-else-if=\"column.key === 'expand'\"\n :expanded=\"isExpanded(rowId)\"\n @click=\"onToggleExpand(row)\"\n />\n <template v-else>\n {{ cellValue(row, column.key) }}\n </template>\n </template>\n </div>\n </td>\n\n <!-- Desktop checkbox cell -->\n <td\n v-else-if=\"selectedData && !isMobile\"\n :class=\"classes.checkbox\"\n colspan=\"1\"\n rowspan=\"1\"\n >\n <RuiCheckbox\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n </td>\n\n <RuiDataTableCell\n v-for=\"(column, subIndex) in bodyColumns\"\n :key=\"subIndex\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n :row-id=\"rowId\"\n :style=\"subIndex === 0 ? firstRowInset : undefined\"\n >\n <template\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n #default=\"slotData\"\n >\n <slot\n :name=\"`item.${column.key.toString()}`\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableCell>\n </tr>\n\n <!-- no divider above: with its row it is one item, sharing the row's state, stripe and hover -->\n <RuiDataTableAppendRow\n v-if=\"slots['row-append']\"\n class=\"border-t-0!\"\n :class=\"[stateClass, rowClass, appendHoverClass, isMobile ? mobileAppendClass : '']\"\n :data-stripe=\"stripe\"\n :row=\"row\"\n :index=\"index\"\n >\n <template #row-append=\"slotData\">\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableAppendRow>\n\n <!-- opacity only: the rows below move once, at once, rather than sliding with a growing height -->\n <RuiDataTableExpandedRow\n v-if=\"panelShown\"\n class=\"transition-opacity starting:opacity-0 motion-reduce:transition-none\"\n :class=\"panelClosing ? 'opacity-0 duration-100 ease-in' : 'duration-150 ease-out'\"\n :row=\"row\"\n :index=\"index\"\n >\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableExpandedRow>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RuiDataTableRow.js","names":["_sfc_main"],"sources":["../../../../src/components/tables/data-table/RuiDataTableRow.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport RuiCheckbox from '@/components/forms/checkbox/RuiCheckbox.vue';\nimport { useDataTableColumns, useDataTableExpansion, useDataTableRowIdentity, useDataTableSelection, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableAppendRow from '@/components/tables/data-table/RuiDataTableAppendRow.vue';\nimport RuiDataTableCell from '@/components/tables/data-table/RuiDataTableCell.vue';\nimport RuiDataTableExpandedRow from '@/components/tables/data-table/RuiDataTableExpandedRow.vue';\nimport RuiExpandButton from '@/components/tables/RuiExpandButton.vue';\n\nconst {\n row,\n index,\n} = defineProps<{\n row: T;\n index: number;\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n }\n>>();\n\nconst { classes, dense, isMobile } = useDataTableStyling();\nconst { cellValue, columns, itemSlotKeys } = useDataTableColumns<T>();\nconst { isDisabledRow, isSelected, onCheckboxClick, onSelect, selectedData } = useDataTableSelection<T>();\nconst { expandable, isExpanded, onToggleExpand } = useDataTableExpansion<T>();\nconst { getRowId, itemClass } = useDataTableRowIdentity<T>();\n\nconst rowId = computed<T[keyof T]>(() => getRowId(row));\nconst selected = computed<boolean>(() => isSelected(get(rowId)));\nconst disabled = computed<boolean>(() => isDisabledRow(get(rowId)));\nconst expanded = computed<boolean>(() => get(expandable) && !!slots['expanded-item'] && isExpanded(get(rowId)));\n\n/** How long a closing panel stays to fade out; matches its `duration-100`. */\nconst PANEL_LEAVE_MS = 100;\n\nconst reducedMotion = usePreferredReducedMotion();\n\n/**\n * Whether the panel is in the DOM, which outlasts `expanded` by its fade-out.\n *\n * @remarks\n * Not a `<Transition>`: test utilities stub that with an element, which lands inside the consumer's\n * `<tbody>` and shifts every `tr:nth-child` its specs count. The fade-in is CSS `@starting-style`.\n */\nconst panelShown = ref<boolean>(get(expanded));\nconst panelClosing = ref<boolean>(false);\n\nconst { start: finishClosing, stop: cancelClosing } = useTimeoutFn(() => {\n set(panelShown, false);\n set(panelClosing, false);\n}, PANEL_LEAVE_MS, { immediate: false });\n\nwatch(expanded, (open) => {\n if (open) {\n cancelClosing();\n set(panelClosing, false);\n set(panelShown, true);\n return;\n }\n if (!get(panelShown))\n return;\n if (get(reducedMotion) === 'reduce') {\n set(panelShown, false);\n return;\n }\n set(panelClosing, true);\n finishClosing();\n});\n\nconst rowClass = computed<string>(() => typeof itemClass === 'string' ? itemClass : itemClass(row));\n\n/** Selection wins over the open-panel shade, so a selected row still reads as selected. */\nconst stateClass = computed<string>(() => {\n if (get(selected))\n return get(classes).trSelected;\n if (get(expanded))\n return get(classes).trExpandedParent;\n return get(classes).tr;\n});\n\n/** Whether the row has a follow-up row, which reads as the second half of the same item. */\nconst appended = computed<boolean>(() => !!slots['row-append']);\n\n/**\n * The stripe follows the item, not the `<tr>`: counting rows would shade an item and its follow-up\n * differently, and an open panel would flip every stripe below it. The table's `striped` variant\n * shades the marked rows.\n */\nconst stripe = computed<'' | undefined>(() => (index % 2 === 1 ? '' : undefined));\n\n/**\n * The two rows of an item highlight together, whichever one the pointer is over. An open row keeps\n * its band rather than taking the hover, as it does without a follow-up.\n */\nconst pairHoverClass = computed<string>(() => {\n if (!get(appended) || get(expanded) || get(isMobile))\n return '';\n return 'has-[+[data-id=row-append]:hover]:bg-rui-neutral-950/[0.03] dark:has-[+[data-id=row-append]:hover]:bg-white/[0.04]';\n});\nconst appendHoverClass = computed<string>(() => {\n if (get(expanded) || get(isMobile))\n return '';\n return '[[data-id=row]:hover+&]:bg-rui-neutral-950/[0.03] dark:[[data-id=row]:hover+&]:bg-white/[0.04]';\n});\n\n/**\n * On mobile the follow-up is the bottom of the item's card: square on top, against the card, and\n * rounded below unless an open panel follows it.\n */\nconst mobileAppendClass = computed<string>(() => {\n const shared = 'block border-x border-b! border-rui-divider overflow-hidden';\n return get(expanded) ? shared : `${shared} rounded-b-rui-card mb-3`;\n});\n\n/**\n * A column is pinned to the mobile card header when it is flagged\n * `mobileHeader`, typically an action column, or when it is the\n * auto-generated expand column.\n */\nfunction isMobileHeaderColumn(column: TableColumn<T>): boolean {\n return !!column.mobileHeader || column.key === 'expand';\n}\n\n/**\n * A pinned column only earns a spot in the header if it renders something: the\n * expand toggle, a provided item slot, or a non-empty cell value. Without this,\n * a pinned column with no content, such as an action column whose\n * `#item.action` slot a nested table does not provide, leaves an empty header\n * bar with just its divider line.\n */\nfunction mobileHeaderColumnHasContent(column: TableColumn<T>): boolean {\n if (column.key === 'expand')\n return true;\n if (itemSlotKeys.has(column.key.toString()))\n return true;\n const value = cellValue(row, column.key);\n return value !== undefined && value !== null && value !== '';\n}\n\n/**\n * In the stacked mobile layout, header columns render in the card header row\n * instead of as a label/value pair. Everything else stacks below in the body.\n */\nconst mobileHeaderColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => isMobileHeaderColumn(column) && mobileHeaderColumnHasContent(column)) : [],\n);\nconst bodyColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => !isMobileHeaderColumn(column)) : get(columns),\n);\nconst showMobileHeader = computed<boolean>(() =>\n get(isMobile) && (!!get(selectedData) || get(mobileHeaderColumns).length > 0),\n);\n\n/**\n * Without a selection checkbox the header bar would hold only the pinned\n * actions, so they float in the card's top-right corner instead and the first\n * field row makes room for them.\n */\nconst compactMobileHeader = computed<boolean>(() =>\n get(showMobileHeader) && !get(selectedData) && get(bodyColumns).length > 0,\n);\n\n/** Room for each floating action, about one small icon button wide. */\nconst firstRowInset = computed<Record<string, string> | undefined>(() =>\n get(compactMobileHeader) ? { paddingRight: `${get(mobileHeaderColumns).length * 2 + 1}rem` } : undefined,\n);\n\n/**\n * `border-y!` defeats the `divide-y-0` on the mobile tbody, which otherwise\n * zeroes the top and bottom border on every card except the first. An expanded\n * card flattens its bottom edge so the expanded panel attaches flush beneath\n * it. A card with a follow-up row drops its bottom border too, so the\n * follow-up continues it with no line between them, as on desktop.\n *\n * These bindings do not run through the class merger, so each state picks its\n * own utilities rather than emitting conflicting ones.\n */\nconst mobileCardClass = computed<string>(() => {\n if (get(appended))\n return 'relative flex flex-col border-x border-t! border-rui-divider overflow-hidden rounded-t-rui-card mb-0';\n const shared = 'relative flex flex-col border border-y! border-rui-divider overflow-hidden';\n return get(expanded)\n ? `${shared} rounded-t-rui-card mb-0`\n : `${shared} rounded-rui-card mb-3 last:mb-0`;\n});\n</script>\n\n<template>\n <tr\n :class=\"[stateClass, rowClass, pairHoverClass, isMobile ? mobileCardClass : '']\"\n :aria-selected=\"selectedData ? selected : undefined\"\n :data-stripe=\"stripe\"\n data-id=\"row\"\n >\n <!-- Mobile card header: checkbox on the left, pinned action columns on the right -->\n <td\n v-if=\"showMobileHeader\"\n :class=\"compactMobileHeader\n ? 'absolute top-0 right-0 z-1 flex items-center gap-1 px-2 py-1'\n : 'flex items-center justify-between gap-2 px-4 py-2 border-b border-rui-divider'\"\n data-id=\"mobile-card-header\"\n >\n <RuiCheckbox\n v-if=\"selectedData\"\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n <span v-else-if=\"!compactMobileHeader\" />\n\n <div\n v-if=\"mobileHeaderColumns.length > 0\"\n class=\"flex items-center gap-1 min-w-0\"\n >\n <template\n v-for=\"(column, headerIndex) in mobileHeaderColumns\"\n :key=\"`header-${headerIndex}`\"\n >\n <slot\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n :name=\"`item.${column.key.toString()}`\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n />\n <RuiExpandButton\n v-else-if=\"column.key === 'expand'\"\n :expanded=\"isExpanded(rowId)\"\n @click=\"onToggleExpand(row)\"\n />\n <template v-else>\n {{ cellValue(row, column.key) }}\n </template>\n </template>\n </div>\n </td>\n\n <!-- Desktop checkbox cell -->\n <td\n v-else-if=\"selectedData && !isMobile\"\n :class=\"classes.checkbox\"\n colspan=\"1\"\n rowspan=\"1\"\n >\n <RuiCheckbox\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n </td>\n\n <RuiDataTableCell\n v-for=\"(column, subIndex) in bodyColumns\"\n :key=\"subIndex\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n :row-id=\"rowId\"\n :style=\"subIndex === 0 ? firstRowInset : undefined\"\n >\n <template\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n #default=\"slotData\"\n >\n <slot\n :name=\"`item.${column.key.toString()}`\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableCell>\n </tr>\n\n <!-- no divider above: with its row it is one item, sharing the row's state, stripe and hover -->\n <RuiDataTableAppendRow\n v-if=\"slots['row-append']\"\n class=\"border-t-0!\"\n :class=\"[stateClass, rowClass, appendHoverClass, isMobile ? mobileAppendClass : '']\"\n :data-stripe=\"stripe\"\n :row=\"row\"\n :index=\"index\"\n >\n <template #row-append=\"slotData\">\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableAppendRow>\n\n <!-- opacity only: the rows below move once, at once, rather than sliding with a growing height -->\n <RuiDataTableExpandedRow\n v-if=\"panelShown\"\n class=\"transition-opacity starting:opacity-0 motion-reduce:transition-none\"\n :class=\"panelClosing ? 'opacity-0 duration-100 ease-in' : 'duration-150 ease-out'\"\n :row=\"row\"\n :index=\"index\"\n >\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableExpandedRow>\n</template>\n"],"mappings":""}
|
package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -83,11 +83,11 @@ var RuiDataTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
83
83
|
*/
|
|
84
84
|
const pairHoverClass = computed(() => {
|
|
85
85
|
if (!get(appended) || get(expanded) || get(isMobile)) return "";
|
|
86
|
-
return "has-[+[data-id=row-append]:hover]:bg-rui-hover";
|
|
86
|
+
return "has-[+[data-id=row-append]:hover]:bg-rui-neutral-950/[0.03] dark:has-[+[data-id=row-append]:hover]:bg-white/[0.04]";
|
|
87
87
|
});
|
|
88
88
|
const appendHoverClass = computed(() => {
|
|
89
89
|
if (get(expanded) || get(isMobile)) return "";
|
|
90
|
-
return "[[data-id=row]:hover+&]:bg-rui-hover";
|
|
90
|
+
return "[[data-id=row]:hover+&]:bg-rui-neutral-950/[0.03] dark:[[data-id=row]:hover+&]:bg-white/[0.04]";
|
|
91
91
|
});
|
|
92
92
|
/**
|
|
93
93
|
* On mobile the follow-up is the bottom of the item's card: square on top, against the card, and
|
package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDataTableRow.vue_vue_type_script_setup_true_lang.js","names":["_useSlots","_openBlock","_createElementBlock","_Fragment","_createElementVNode","_normalizeClass","_unref","_createBlock","RuiCheckbox","_createCommentVNode","_renderList","_renderSlot","RuiExpandButton","_createTextVNode","_toDisplayString","_createVNode","RuiDataTableCell","_normalizeStyle","_createSlots","_withCtx","_mergeProps","RuiDataTableAppendRow","_normalizeProps","_guardReactiveProps","RuiDataTableExpandedRow"],"sources":["../../../../src/components/tables/data-table/RuiDataTableRow.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport RuiCheckbox from '@/components/forms/checkbox/RuiCheckbox.vue';\nimport { useDataTableColumns, useDataTableExpansion, useDataTableRowIdentity, useDataTableSelection, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableAppendRow from '@/components/tables/data-table/RuiDataTableAppendRow.vue';\nimport RuiDataTableCell from '@/components/tables/data-table/RuiDataTableCell.vue';\nimport RuiDataTableExpandedRow from '@/components/tables/data-table/RuiDataTableExpandedRow.vue';\nimport RuiExpandButton from '@/components/tables/RuiExpandButton.vue';\n\nconst {\n row,\n index,\n} = defineProps<{\n row: T;\n index: number;\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n }\n>>();\n\nconst { classes, dense, isMobile } = useDataTableStyling();\nconst { cellValue, columns, itemSlotKeys } = useDataTableColumns<T>();\nconst { isDisabledRow, isSelected, onCheckboxClick, onSelect, selectedData } = useDataTableSelection<T>();\nconst { expandable, isExpanded, onToggleExpand } = useDataTableExpansion<T>();\nconst { getRowId, itemClass } = useDataTableRowIdentity<T>();\n\nconst rowId = computed<T[keyof T]>(() => getRowId(row));\nconst selected = computed<boolean>(() => isSelected(get(rowId)));\nconst disabled = computed<boolean>(() => isDisabledRow(get(rowId)));\nconst expanded = computed<boolean>(() => get(expandable) && !!slots['expanded-item'] && isExpanded(get(rowId)));\n\n/** How long a closing panel stays to fade out; matches its `duration-100`. */\nconst PANEL_LEAVE_MS = 100;\n\nconst reducedMotion = usePreferredReducedMotion();\n\n/**\n * Whether the panel is in the DOM, which outlasts `expanded` by its fade-out.\n *\n * @remarks\n * Not a `<Transition>`: test utilities stub that with an element, which lands inside the consumer's\n * `<tbody>` and shifts every `tr:nth-child` its specs count. The fade-in is CSS `@starting-style`.\n */\nconst panelShown = ref<boolean>(get(expanded));\nconst panelClosing = ref<boolean>(false);\n\nconst { start: finishClosing, stop: cancelClosing } = useTimeoutFn(() => {\n set(panelShown, false);\n set(panelClosing, false);\n}, PANEL_LEAVE_MS, { immediate: false });\n\nwatch(expanded, (open) => {\n if (open) {\n cancelClosing();\n set(panelClosing, false);\n set(panelShown, true);\n return;\n }\n if (!get(panelShown))\n return;\n if (get(reducedMotion) === 'reduce') {\n set(panelShown, false);\n return;\n }\n set(panelClosing, true);\n finishClosing();\n});\n\nconst rowClass = computed<string>(() => typeof itemClass === 'string' ? itemClass : itemClass(row));\n\n/** Selection wins over the open-panel shade, so a selected row still reads as selected. */\nconst stateClass = computed<string>(() => {\n if (get(selected))\n return get(classes).trSelected;\n if (get(expanded))\n return get(classes).trExpandedParent;\n return get(classes).tr;\n});\n\n/** Whether the row has a follow-up row, which reads as the second half of the same item. */\nconst appended = computed<boolean>(() => !!slots['row-append']);\n\n/**\n * The stripe follows the item, not the `<tr>`: counting rows would shade an item and its follow-up\n * differently, and an open panel would flip every stripe below it. The table's `striped` variant\n * shades the marked rows.\n */\nconst stripe = computed<'' | undefined>(() => (index % 2 === 1 ? '' : undefined));\n\n/**\n * The two rows of an item highlight together, whichever one the pointer is over. An open row keeps\n * its band rather than taking the hover, as it does without a follow-up.\n */\nconst pairHoverClass = computed<string>(() => {\n if (!get(appended) || get(expanded) || get(isMobile))\n return '';\n return 'has-[+[data-id=row-append]:hover]:bg-rui-hover';\n});\nconst appendHoverClass = computed<string>(() => {\n if (get(expanded) || get(isMobile))\n return '';\n return '[[data-id=row]:hover+&]:bg-rui-hover';\n});\n\n/**\n * On mobile the follow-up is the bottom of the item's card: square on top, against the card, and\n * rounded below unless an open panel follows it.\n */\nconst mobileAppendClass = computed<string>(() => {\n const shared = 'block border-x border-b! border-rui-divider overflow-hidden';\n return get(expanded) ? shared : `${shared} rounded-b-rui-card mb-3`;\n});\n\n/**\n * A column is pinned to the mobile card header when it is flagged\n * `mobileHeader`, typically an action column, or when it is the\n * auto-generated expand column.\n */\nfunction isMobileHeaderColumn(column: TableColumn<T>): boolean {\n return !!column.mobileHeader || column.key === 'expand';\n}\n\n/**\n * A pinned column only earns a spot in the header if it renders something: the\n * expand toggle, a provided item slot, or a non-empty cell value. Without this,\n * a pinned column with no content, such as an action column whose\n * `#item.action` slot a nested table does not provide, leaves an empty header\n * bar with just its divider line.\n */\nfunction mobileHeaderColumnHasContent(column: TableColumn<T>): boolean {\n if (column.key === 'expand')\n return true;\n if (itemSlotKeys.has(column.key.toString()))\n return true;\n const value = cellValue(row, column.key);\n return value !== undefined && value !== null && value !== '';\n}\n\n/**\n * In the stacked mobile layout, header columns render in the card header row\n * instead of as a label/value pair. Everything else stacks below in the body.\n */\nconst mobileHeaderColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => isMobileHeaderColumn(column) && mobileHeaderColumnHasContent(column)) : [],\n);\nconst bodyColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => !isMobileHeaderColumn(column)) : get(columns),\n);\nconst showMobileHeader = computed<boolean>(() =>\n get(isMobile) && (!!get(selectedData) || get(mobileHeaderColumns).length > 0),\n);\n\n/**\n * Without a selection checkbox the header bar would hold only the pinned\n * actions, so they float in the card's top-right corner instead and the first\n * field row makes room for them.\n */\nconst compactMobileHeader = computed<boolean>(() =>\n get(showMobileHeader) && !get(selectedData) && get(bodyColumns).length > 0,\n);\n\n/** Room for each floating action, about one small icon button wide. */\nconst firstRowInset = computed<Record<string, string> | undefined>(() =>\n get(compactMobileHeader) ? { paddingRight: `${get(mobileHeaderColumns).length * 2 + 1}rem` } : undefined,\n);\n\n/**\n * `border-y!` defeats the `divide-y-0` on the mobile tbody, which otherwise\n * zeroes the top and bottom border on every card except the first. An expanded\n * card flattens its bottom edge so the expanded panel attaches flush beneath\n * it. A card with a follow-up row drops its bottom border too, so the\n * follow-up continues it with no line between them, as on desktop.\n *\n * These bindings do not run through the class merger, so each state picks its\n * own utilities rather than emitting conflicting ones.\n */\nconst mobileCardClass = computed<string>(() => {\n if (get(appended))\n return 'relative flex flex-col border-x border-t! border-rui-divider overflow-hidden rounded-t-rui-card mb-0';\n const shared = 'relative flex flex-col border border-y! border-rui-divider overflow-hidden';\n return get(expanded)\n ? `${shared} rounded-t-rui-card mb-0`\n : `${shared} rounded-rui-card mb-3 last:mb-0`;\n});\n</script>\n\n<template>\n <tr\n :class=\"[stateClass, rowClass, pairHoverClass, isMobile ? mobileCardClass : '']\"\n :aria-selected=\"selectedData ? selected : undefined\"\n :data-stripe=\"stripe\"\n data-id=\"row\"\n >\n <!-- Mobile card header: checkbox on the left, pinned action columns on the right -->\n <td\n v-if=\"showMobileHeader\"\n :class=\"compactMobileHeader\n ? 'absolute top-0 right-0 z-1 flex items-center gap-1 px-2 py-1'\n : 'flex items-center justify-between gap-2 px-4 py-2 border-b border-rui-divider'\"\n data-id=\"mobile-card-header\"\n >\n <RuiCheckbox\n v-if=\"selectedData\"\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n <span v-else-if=\"!compactMobileHeader\" />\n\n <div\n v-if=\"mobileHeaderColumns.length > 0\"\n class=\"flex items-center gap-1 min-w-0\"\n >\n <template\n v-for=\"(column, headerIndex) in mobileHeaderColumns\"\n :key=\"`header-${headerIndex}`\"\n >\n <slot\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n :name=\"`item.${column.key.toString()}`\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n />\n <RuiExpandButton\n v-else-if=\"column.key === 'expand'\"\n :expanded=\"isExpanded(rowId)\"\n @click=\"onToggleExpand(row)\"\n />\n <template v-else>\n {{ cellValue(row, column.key) }}\n </template>\n </template>\n </div>\n </td>\n\n <!-- Desktop checkbox cell -->\n <td\n v-else-if=\"selectedData && !isMobile\"\n :class=\"classes.checkbox\"\n colspan=\"1\"\n rowspan=\"1\"\n >\n <RuiCheckbox\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n </td>\n\n <RuiDataTableCell\n v-for=\"(column, subIndex) in bodyColumns\"\n :key=\"subIndex\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n :row-id=\"rowId\"\n :style=\"subIndex === 0 ? firstRowInset : undefined\"\n >\n <template\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n #default=\"slotData\"\n >\n <slot\n :name=\"`item.${column.key.toString()}`\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableCell>\n </tr>\n\n <!-- no divider above: with its row it is one item, sharing the row's state, stripe and hover -->\n <RuiDataTableAppendRow\n v-if=\"slots['row-append']\"\n class=\"border-t-0!\"\n :class=\"[stateClass, rowClass, appendHoverClass, isMobile ? mobileAppendClass : '']\"\n :data-stripe=\"stripe\"\n :row=\"row\"\n :index=\"index\"\n >\n <template #row-append=\"slotData\">\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableAppendRow>\n\n <!-- opacity only: the rows below move once, at once, rather than sliding with a growing height -->\n <RuiDataTableExpandedRow\n v-if=\"panelShown\"\n class=\"transition-opacity starting:opacity-0 motion-reduce:transition-none\"\n :class=\"panelClosing ? 'opacity-0 duration-100 ease-in' : 'duration-150 ease-out'\"\n :row=\"row\"\n :index=\"index\"\n >\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableExpandedRow>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;AAoCA,IAAM,iBAAiB;;;;;;;;EAnBvB,MAAM,QAAQA,SAAA;EAOd,MAAM,EAAE,SAAS,OAAO,aAAa,oBAAoB;EACzD,MAAM,EAAE,WAAW,SAAS,iBAAiB,oBAAuB;EACpE,MAAM,EAAE,eAAe,YAAY,iBAAiB,UAAU,iBAAiB,sBAAyB;EACxG,MAAM,EAAE,YAAY,YAAY,mBAAmB,sBAAyB;EAC5E,MAAM,EAAE,UAAU,cAAc,wBAA2B;EAE3D,MAAM,QAAQ,eAA2B,SAAS,QAAA,GAAG,CAAC;EACtD,MAAM,WAAW,eAAwB,WAAW,IAAI,KAAK,CAAC,CAAC;EAC/D,MAAM,WAAW,eAAwB,cAAc,IAAI,KAAK,CAAC,CAAC;EAClE,MAAM,WAAW,eAAwB,IAAI,UAAU,KAAK,CAAC,CAAC,MAAM,oBAAoB,WAAW,IAAI,KAAK,CAAC,CAAC;;EAK9G,MAAM,gBAAgB,0BAA0B;;;;;;;;EAShD,MAAM,aAAa,IAAa,IAAI,QAAQ,CAAC;EAC7C,MAAM,eAAe,IAAa,KAAK;EAEvC,MAAM,EAAE,OAAO,eAAe,MAAM,kBAAkB,mBAAmB;GACvE,IAAI,YAAY,KAAK;GACrB,IAAI,cAAc,KAAK;EACzB,GAAG,gBAAgB,EAAE,WAAW,MAAM,CAAC;EAEvC,MAAM,WAAW,SAAS;GACxB,IAAI,MAAM;IACR,cAAc;IACd,IAAI,cAAc,KAAK;IACvB,IAAI,YAAY,IAAI;IACpB;GACF;GACA,IAAI,CAAC,IAAI,UAAU,GACjB;GACF,IAAI,IAAI,aAAa,MAAM,UAAU;IACnC,IAAI,YAAY,KAAK;IACrB;GACF;GACA,IAAI,cAAc,IAAI;GACtB,cAAc;EAChB,CAAC;EAED,MAAM,WAAW,eAAuB,OAAO,cAAc,WAAW,YAAY,UAAU,QAAA,GAAG,CAAC;;EAGlG,MAAM,aAAa,eAAuB;GACxC,IAAI,IAAI,QAAQ,GACd,OAAO,IAAI,OAAO,CAAC,CAAC;GACtB,IAAI,IAAI,QAAQ,GACd,OAAO,IAAI,OAAO,CAAC,CAAC;GACtB,OAAO,IAAI,OAAO,CAAC,CAAC;EACtB,CAAC;;EAGD,MAAM,WAAW,eAAwB,CAAC,CAAC,MAAM,aAAa;;;;;;EAO9D,MAAM,SAAS,eAAgC,QAAA,QAAQ,MAAM,IAAI,KAAK,KAAA,CAAU;;;;;EAMhF,MAAM,iBAAiB,eAAuB;GAC5C,IAAI,CAAC,IAAI,QAAQ,KAAK,IAAI,QAAQ,KAAK,IAAI,QAAQ,GACjD,OAAO;GACT,OAAO;EACT,CAAC;EACD,MAAM,mBAAmB,eAAuB;GAC9C,IAAI,IAAI,QAAQ,KAAK,IAAI,QAAQ,GAC/B,OAAO;GACT,OAAO;EACT,CAAC;;;;;EAMD,MAAM,oBAAoB,eAAuB;GAC/C,MAAM,SAAS;GACf,OAAO,IAAI,QAAQ,IAAI,SAAS,GAAG,OAAO;EAC5C,CAAC;;;;;;EAOD,SAAS,qBAAqB,QAAiC;GAC7D,OAAO,CAAC,CAAC,OAAO,gBAAgB,OAAO,QAAQ;EACjD;;;;;;;;EASA,SAAS,6BAA6B,QAAiC;GACrE,IAAI,OAAO,QAAQ,UACjB,OAAO;GACT,IAAI,aAAa,IAAI,OAAO,IAAI,SAAS,CAAC,GACxC,OAAO;GACT,MAAM,QAAQ,UAAU,QAAA,KAAK,OAAO,GAAG;GACvC,OAAO,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU;EAC5D;;;;;EAMA,MAAM,sBAAsB,eAC1B,IAAI,QAAQ,IAAI,IAAI,OAAO,CAAC,CAAC,QAAO,WAAU,qBAAqB,MAAM,KAAK,6BAA6B,MAAM,CAAC,IAAI,CAAC,CACzH;EACA,MAAM,cAAc,eAClB,IAAI,QAAQ,IAAI,IAAI,OAAO,CAAC,CAAC,QAAO,WAAU,CAAC,qBAAqB,MAAM,CAAC,IAAI,IAAI,OAAO,CAC5F;EACA,MAAM,mBAAmB,eACvB,IAAI,QAAQ,MAAM,CAAC,CAAC,IAAI,YAAY,KAAK,IAAI,mBAAmB,CAAC,CAAC,SAAS,EAC7E;;;;;;EAOA,MAAM,sBAAsB,eAC1B,IAAI,gBAAgB,KAAK,CAAC,IAAI,YAAY,KAAK,IAAI,WAAW,CAAC,CAAC,SAAS,CAC3E;;EAGA,MAAM,gBAAgB,eACpB,IAAI,mBAAmB,IAAI,EAAE,cAAc,GAAG,IAAI,mBAAmB,CAAC,CAAC,SAAS,IAAI,EAAE,KAAK,IAAI,KAAA,CACjG;;;;;;;;;;;EAYA,MAAM,kBAAkB,eAAuB;GAC7C,IAAI,IAAI,QAAQ,GACd,OAAO;GACT,MAAM,SAAS;GACf,OAAO,IAAI,QAAQ,IACf,GAAG,OAAO,4BACV,GAAG,OAAO;EAChB,CAAC;;;IAICI,mBAgGK,MAAA;KA/FF,OAAKC,eAAA;MAAGC,MAAA,UAAA;MAAYA,MAAA,QAAA;MAAUA,MAAA,cAAA;MAAgBA,MAAA,QAAA,IAAWA,MAAA,eAAA,IAAe;KAAA,CAAA;KACxE,iBAAeA,MAAA,YAAA,IAAeA,MAAA,QAAA,IAAW,KAAA;KACzC,eAAaA,MAAA,MAAA;KACd,WAAQ;IAIAA,GAAAA,CAAAA,MAAA,gBAAA,KADRL,UAAA,GAAAC,mBA+CK,MAAA;;KA7CF,OAAKG,eAAEC,MAAA,mBAAA,IAAA,iEAAA,+EAAA;KAGR,WAAQ;IAGAA,GAAAA,CAAAA,MAAA,YAAA,KADRL,UAAA,GAAAM,YAYEC,qBAAA;;KAVC,WAAO,sBAAwB,QAAA;KAChC,cAAW;KACV,eAAaF,MAAA,QAAA;KACb,UAAUA,MAAA,QAAA;KACV,MAAMA,MAAA,KAAA,IAAK,OAAU,KAAA;KACtB,OAAM;KACN,OAAM;KACN,gBAAA;KACC,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAEA,MAAA,QAAA,CAAQ,CAAC,QAAQA,MAAA,KAAA,GAAK,IAAA;KAC1C,SAAK,OAAA,OAAA,OAAA,MAAA,WAAEA,MAAA,eAAA,CAAe,CAAC,QAAQA,MAAA,KAAA,GAAO,QAAA,KAAK;;;;;;IAE5B,CAAA,KAAA,CAAAA,MAAA,mBAAA,KAAlBL,UAAA,GAAAC,mBAAyC,QAAA,UAAA,KAAA,mBAAA,IAAA,IAAA,GAGjCI,MAAA,mBAAA,CAAmB,CAAC,SAAM,KADlCL,UAAA,GAAAC,mBAwBM,OAxBN,YAwBM,EApBJD,UAAA,IAAA,GAAAC,mBAmBWC,UAAA,MAAAO,WAlBuBJ,MAAA,mBAAA,IAAxB,QAAQ,gBAAW;KACX,OAAA,UAAA,GAAA,mBAAA,UAAA,EAAA,KAAA,UAAA,cAAA,GAAA,CAGRA,MAAA,YAAA,CAAY,CAAC,IAAI,OAAO,IAAI,SAAQ,CAAA,IAD5CK,WAME,KAAA,QAAA,QAJe,OAAO,IAAI,SAAQ,KAAA;MACzB;MACR,KAAK,QAAA;MACL,OAAO,QAAA;KAGG,GAAA,KAAA,GAAA,KAAA,GAAA,CAAA,IAAA,OAAO,QAAG,YADvBV,UAAA,GAAAM,YAIEK,yBAAA;;MAFC,UAAUN,MAAA,UAAA,CAAU,CAACA,MAAA,KAAA,CAAK;MAC1B,SAAK,OAAA,OAAA,OAAA,MAAA,WAAEA,MAAA,cAAA,CAAc,CAAC,QAAA,GAAG;KAE5BL,GAAAA,MAAAA,GAAAA,CAAAA,UAAAA,CAAAA,MAAAA,UAAA,GAAAC,mBAEWC,UAAA,EAAA,KAAA,EAAA,GAAA,CADNU,gBAAAC,gBAAAR,MAAA,SAAA,CAAS,CAAC,QAAA,KAAK,OAAO,GAAG,CAAA,GAAA,CAAA,CAAA,GAAA,EAAA,EAAA,GAAA,EAAA;IAQvBA,CAAAA,GAAAA,GAAAA,EAAAA,CAAAA,KAAAA,mBAAAA,IAAAA,IAAAA,CAAAA,GAAAA,CAAAA,KAAAA,MAAA,YAAA,KAAY,CAAKA,MAAA,QAAA,KAD9BL,UAAA,GAAAC,mBAkBK,MAAA;;KAhBF,OAAKG,eAAEC,MAAA,OAAA,CAAO,CAAC,QAAQ;KACxB,SAAQ;KACR,SAAQ;IAERS,GAAAA,CAAAA,YAWEP,qBAAA;KAVC,WAAO,sBAAwB,QAAA;KAChC,cAAW;KACV,eAAaF,MAAA,QAAA;KACb,UAAUA,MAAA,QAAA;KACV,MAAMA,MAAA,KAAA,IAAK,OAAU,KAAA;KACtB,OAAM;KACN,OAAM;KACN,gBAAA;KACC,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAEA,MAAA,QAAA,CAAQ,CAAC,QAAQA,MAAA,KAAA,GAAK,IAAA;KAC1C,SAAK,OAAA,OAAA,OAAA,MAAA,WAAEA,MAAA,eAAA,CAAe,CAAC,QAAQA,MAAA,KAAA,GAAO,QAAA,KAAK;;;;;;IAIhDL,CAAAA,CAAAA,GAAAA,CAAAA,KAAAA,mBAAAA,IAAAA,IAAAA,IAAAA,UAAA,IAAA,GAAAC,mBAkBmBC,UAAA,MAAAO,WAjBYJ,MAAA,WAAA,IAArB,QAAQ,aAAQ;KAD1B,OAAAL,UAAA,GAAAM,YAkBmBS,0BAAA;MAhBhB,KAAK;MACG;MACR,KAAK,QAAA;MACL,OAAO,QAAA;MACP,UAAQV,MAAA,KAAA;MACR,OAAKW,eAAE,aAAQ,IAASX,MAAA,aAAA,IAAgB,KAAA,CAAS;KAG1CA,GAAAA,YAAAA,EAAAA,GAAAA,EAAAA,GAAAA,CAAAA,MAAA,YAAA,CAAY,CAAC,IAAI,OAAO,IAAI,SAAQ,CAAA,IAAA;MACzC,MAAA;MAED,IAAAa,SAFU,aAAQ,CAElBR,WAGE,KAAA,QAAA,QAFe,OAAO,IAAI,SAAQ,KADpCS,WAGE,EAAA,SAAA,KAAA,GADQ,QAAQ,CAAA,CAAA,CAAA;;;;;;;;;;IAQhB,MAAK,iBADbnB,UAAA,GAAAM,YAewBc,+BAAA;;KAbtB,OAAKhB,eAAA,CAAC,eAAa;MACVC,MAAA,UAAA;MAAYA,MAAA,QAAA;MAAUA,MAAA,gBAAA;MAAkBA,MAAA,QAAA,IAAWA,MAAA,iBAAA,IAAiB;KAAA,CAAA,CAAA;KAC5E,eAAaA,MAAA,MAAA;KACb,KAAK,QAAA;KACL,OAAO,QAAA;;KAEG,cAAUa,SAAE,aAAQ,CAE7BR,WAGE,KAAA,QAAA,cAAAW,eAAAC,mBADQ,QAAQ,CAAA,CAAA,CAAA,CAAA;;;;;;;;IAOdjB,MAAA,UAAA,KADRL,UAAA,GAAAM,YAiB0BiB,iCAAA;;KAfxB,OAAKnB,eAAA,CAAC,uEACEC,MAAA,YAAA,IAAY,mCAAA,uBAAA,CAAA;KACnB,KAAK,QAAA;KACL,OAAO,QAAA;IAGA,GAAA,YAAA,EAAA,GAAA,EAAA,GAAA,CAAA,MAAK,mBAAA;KACV,MAAA;KAGD,IAAAa,SAHgB,aAAQ,CAGxBR,WAGE,KAAA,QAAA,iBAAAW,eAAAC,mBADQ,QAAQ,CAAA,CAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"RuiDataTableRow.vue_vue_type_script_setup_true_lang.js","names":["_useSlots","_openBlock","_createElementBlock","_Fragment","_createElementVNode","_normalizeClass","_unref","_createBlock","RuiCheckbox","_createCommentVNode","_renderList","_renderSlot","RuiExpandButton","_createTextVNode","_toDisplayString","_createVNode","RuiDataTableCell","_normalizeStyle","_createSlots","_withCtx","_mergeProps","RuiDataTableAppendRow","_normalizeProps","_guardReactiveProps","RuiDataTableExpandedRow"],"sources":["../../../../src/components/tables/data-table/RuiDataTableRow.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport RuiCheckbox from '@/components/forms/checkbox/RuiCheckbox.vue';\nimport { useDataTableColumns, useDataTableExpansion, useDataTableRowIdentity, useDataTableSelection, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableAppendRow from '@/components/tables/data-table/RuiDataTableAppendRow.vue';\nimport RuiDataTableCell from '@/components/tables/data-table/RuiDataTableCell.vue';\nimport RuiDataTableExpandedRow from '@/components/tables/data-table/RuiDataTableExpandedRow.vue';\nimport RuiExpandButton from '@/components/tables/RuiExpandButton.vue';\n\nconst {\n row,\n index,\n} = defineProps<{\n row: T;\n index: number;\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n }\n>>();\n\nconst { classes, dense, isMobile } = useDataTableStyling();\nconst { cellValue, columns, itemSlotKeys } = useDataTableColumns<T>();\nconst { isDisabledRow, isSelected, onCheckboxClick, onSelect, selectedData } = useDataTableSelection<T>();\nconst { expandable, isExpanded, onToggleExpand } = useDataTableExpansion<T>();\nconst { getRowId, itemClass } = useDataTableRowIdentity<T>();\n\nconst rowId = computed<T[keyof T]>(() => getRowId(row));\nconst selected = computed<boolean>(() => isSelected(get(rowId)));\nconst disabled = computed<boolean>(() => isDisabledRow(get(rowId)));\nconst expanded = computed<boolean>(() => get(expandable) && !!slots['expanded-item'] && isExpanded(get(rowId)));\n\n/** How long a closing panel stays to fade out; matches its `duration-100`. */\nconst PANEL_LEAVE_MS = 100;\n\nconst reducedMotion = usePreferredReducedMotion();\n\n/**\n * Whether the panel is in the DOM, which outlasts `expanded` by its fade-out.\n *\n * @remarks\n * Not a `<Transition>`: test utilities stub that with an element, which lands inside the consumer's\n * `<tbody>` and shifts every `tr:nth-child` its specs count. The fade-in is CSS `@starting-style`.\n */\nconst panelShown = ref<boolean>(get(expanded));\nconst panelClosing = ref<boolean>(false);\n\nconst { start: finishClosing, stop: cancelClosing } = useTimeoutFn(() => {\n set(panelShown, false);\n set(panelClosing, false);\n}, PANEL_LEAVE_MS, { immediate: false });\n\nwatch(expanded, (open) => {\n if (open) {\n cancelClosing();\n set(panelClosing, false);\n set(panelShown, true);\n return;\n }\n if (!get(panelShown))\n return;\n if (get(reducedMotion) === 'reduce') {\n set(panelShown, false);\n return;\n }\n set(panelClosing, true);\n finishClosing();\n});\n\nconst rowClass = computed<string>(() => typeof itemClass === 'string' ? itemClass : itemClass(row));\n\n/** Selection wins over the open-panel shade, so a selected row still reads as selected. */\nconst stateClass = computed<string>(() => {\n if (get(selected))\n return get(classes).trSelected;\n if (get(expanded))\n return get(classes).trExpandedParent;\n return get(classes).tr;\n});\n\n/** Whether the row has a follow-up row, which reads as the second half of the same item. */\nconst appended = computed<boolean>(() => !!slots['row-append']);\n\n/**\n * The stripe follows the item, not the `<tr>`: counting rows would shade an item and its follow-up\n * differently, and an open panel would flip every stripe below it. The table's `striped` variant\n * shades the marked rows.\n */\nconst stripe = computed<'' | undefined>(() => (index % 2 === 1 ? '' : undefined));\n\n/**\n * The two rows of an item highlight together, whichever one the pointer is over. An open row keeps\n * its band rather than taking the hover, as it does without a follow-up.\n */\nconst pairHoverClass = computed<string>(() => {\n if (!get(appended) || get(expanded) || get(isMobile))\n return '';\n return 'has-[+[data-id=row-append]:hover]:bg-rui-neutral-950/[0.03] dark:has-[+[data-id=row-append]:hover]:bg-white/[0.04]';\n});\nconst appendHoverClass = computed<string>(() => {\n if (get(expanded) || get(isMobile))\n return '';\n return '[[data-id=row]:hover+&]:bg-rui-neutral-950/[0.03] dark:[[data-id=row]:hover+&]:bg-white/[0.04]';\n});\n\n/**\n * On mobile the follow-up is the bottom of the item's card: square on top, against the card, and\n * rounded below unless an open panel follows it.\n */\nconst mobileAppendClass = computed<string>(() => {\n const shared = 'block border-x border-b! border-rui-divider overflow-hidden';\n return get(expanded) ? shared : `${shared} rounded-b-rui-card mb-3`;\n});\n\n/**\n * A column is pinned to the mobile card header when it is flagged\n * `mobileHeader`, typically an action column, or when it is the\n * auto-generated expand column.\n */\nfunction isMobileHeaderColumn(column: TableColumn<T>): boolean {\n return !!column.mobileHeader || column.key === 'expand';\n}\n\n/**\n * A pinned column only earns a spot in the header if it renders something: the\n * expand toggle, a provided item slot, or a non-empty cell value. Without this,\n * a pinned column with no content, such as an action column whose\n * `#item.action` slot a nested table does not provide, leaves an empty header\n * bar with just its divider line.\n */\nfunction mobileHeaderColumnHasContent(column: TableColumn<T>): boolean {\n if (column.key === 'expand')\n return true;\n if (itemSlotKeys.has(column.key.toString()))\n return true;\n const value = cellValue(row, column.key);\n return value !== undefined && value !== null && value !== '';\n}\n\n/**\n * In the stacked mobile layout, header columns render in the card header row\n * instead of as a label/value pair. Everything else stacks below in the body.\n */\nconst mobileHeaderColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => isMobileHeaderColumn(column) && mobileHeaderColumnHasContent(column)) : [],\n);\nconst bodyColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => !isMobileHeaderColumn(column)) : get(columns),\n);\nconst showMobileHeader = computed<boolean>(() =>\n get(isMobile) && (!!get(selectedData) || get(mobileHeaderColumns).length > 0),\n);\n\n/**\n * Without a selection checkbox the header bar would hold only the pinned\n * actions, so they float in the card's top-right corner instead and the first\n * field row makes room for them.\n */\nconst compactMobileHeader = computed<boolean>(() =>\n get(showMobileHeader) && !get(selectedData) && get(bodyColumns).length > 0,\n);\n\n/** Room for each floating action, about one small icon button wide. */\nconst firstRowInset = computed<Record<string, string> | undefined>(() =>\n get(compactMobileHeader) ? { paddingRight: `${get(mobileHeaderColumns).length * 2 + 1}rem` } : undefined,\n);\n\n/**\n * `border-y!` defeats the `divide-y-0` on the mobile tbody, which otherwise\n * zeroes the top and bottom border on every card except the first. An expanded\n * card flattens its bottom edge so the expanded panel attaches flush beneath\n * it. A card with a follow-up row drops its bottom border too, so the\n * follow-up continues it with no line between them, as on desktop.\n *\n * These bindings do not run through the class merger, so each state picks its\n * own utilities rather than emitting conflicting ones.\n */\nconst mobileCardClass = computed<string>(() => {\n if (get(appended))\n return 'relative flex flex-col border-x border-t! border-rui-divider overflow-hidden rounded-t-rui-card mb-0';\n const shared = 'relative flex flex-col border border-y! border-rui-divider overflow-hidden';\n return get(expanded)\n ? `${shared} rounded-t-rui-card mb-0`\n : `${shared} rounded-rui-card mb-3 last:mb-0`;\n});\n</script>\n\n<template>\n <tr\n :class=\"[stateClass, rowClass, pairHoverClass, isMobile ? mobileCardClass : '']\"\n :aria-selected=\"selectedData ? selected : undefined\"\n :data-stripe=\"stripe\"\n data-id=\"row\"\n >\n <!-- Mobile card header: checkbox on the left, pinned action columns on the right -->\n <td\n v-if=\"showMobileHeader\"\n :class=\"compactMobileHeader\n ? 'absolute top-0 right-0 z-1 flex items-center gap-1 px-2 py-1'\n : 'flex items-center justify-between gap-2 px-4 py-2 border-b border-rui-divider'\"\n data-id=\"mobile-card-header\"\n >\n <RuiCheckbox\n v-if=\"selectedData\"\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n <span v-else-if=\"!compactMobileHeader\" />\n\n <div\n v-if=\"mobileHeaderColumns.length > 0\"\n class=\"flex items-center gap-1 min-w-0\"\n >\n <template\n v-for=\"(column, headerIndex) in mobileHeaderColumns\"\n :key=\"`header-${headerIndex}`\"\n >\n <slot\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n :name=\"`item.${column.key.toString()}`\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n />\n <RuiExpandButton\n v-else-if=\"column.key === 'expand'\"\n :expanded=\"isExpanded(rowId)\"\n @click=\"onToggleExpand(row)\"\n />\n <template v-else>\n {{ cellValue(row, column.key) }}\n </template>\n </template>\n </div>\n </td>\n\n <!-- Desktop checkbox cell -->\n <td\n v-else-if=\"selectedData && !isMobile\"\n :class=\"classes.checkbox\"\n colspan=\"1\"\n rowspan=\"1\"\n >\n <RuiCheckbox\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n </td>\n\n <RuiDataTableCell\n v-for=\"(column, subIndex) in bodyColumns\"\n :key=\"subIndex\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n :row-id=\"rowId\"\n :style=\"subIndex === 0 ? firstRowInset : undefined\"\n >\n <template\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n #default=\"slotData\"\n >\n <slot\n :name=\"`item.${column.key.toString()}`\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableCell>\n </tr>\n\n <!-- no divider above: with its row it is one item, sharing the row's state, stripe and hover -->\n <RuiDataTableAppendRow\n v-if=\"slots['row-append']\"\n class=\"border-t-0!\"\n :class=\"[stateClass, rowClass, appendHoverClass, isMobile ? mobileAppendClass : '']\"\n :data-stripe=\"stripe\"\n :row=\"row\"\n :index=\"index\"\n >\n <template #row-append=\"slotData\">\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableAppendRow>\n\n <!-- opacity only: the rows below move once, at once, rather than sliding with a growing height -->\n <RuiDataTableExpandedRow\n v-if=\"panelShown\"\n class=\"transition-opacity starting:opacity-0 motion-reduce:transition-none\"\n :class=\"panelClosing ? 'opacity-0 duration-100 ease-in' : 'duration-150 ease-out'\"\n :row=\"row\"\n :index=\"index\"\n >\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableExpandedRow>\n</template>\n"],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ var dataTableStyles = tv({
|
|
|
19
19
|
scroller: "overflow-x-auto overflow-y-hidden [clip-path:inset(0_0_0_0)] outline-hidden focus-visible:focus-ring focus-visible:-outline-offset-2",
|
|
20
20
|
table: "min-w-full table-fixed between:border-t between:border-b-0 between:border-rui-divider whitespace-nowrap mx-auto my-0 max-w-fit relative border-rui-divider",
|
|
21
21
|
tbody: "between:border-t between:border-b-0 between:border-rui-divider",
|
|
22
|
-
tr: "hover:bg-rui-hover",
|
|
22
|
+
tr: "hover:bg-rui-neutral-950/[0.03] dark:hover:bg-white/[0.04]",
|
|
23
23
|
td: "[:where(&)]:px-4 text-rui-text text-body-2 tabular-nums [text-wrap:initial]",
|
|
24
24
|
checkbox: "px-2 w-[3.625rem] max-w-[3.625rem] [&_label]:ml-0",
|
|
25
25
|
tbodyLoader: "text-center",
|
|
@@ -37,13 +37,13 @@ var dataTableStyles = tv({
|
|
|
37
37
|
true: {},
|
|
38
38
|
false: {}
|
|
39
39
|
},
|
|
40
|
-
striped: { true: { tbody: "[:where(&>tr[data-stripe])]:bg-rui-neutral-950/[0.
|
|
40
|
+
striped: { true: { tbody: "[:where(&>tr[data-stripe])]:bg-rui-neutral-950/[0.015] dark:[:where(&>tr[data-stripe])]:bg-white/[0.02]" } },
|
|
41
41
|
rowVariant: {
|
|
42
42
|
selected: { tr: "bg-rui-primary-soft" },
|
|
43
|
-
empty: { tr: "hover:bg-transparent" },
|
|
43
|
+
empty: { tr: "hover:bg-transparent dark:hover:bg-transparent" },
|
|
44
44
|
expandable: { tr: `bg-rui-neutral-950/[0.07] hover:bg-rui-neutral-950/[0.07] dark:bg-white/[0.09] dark:hover:bg-white/[0.09] ${NESTED_BAND} [[data-id=row-expanded]_&]:hover:bg-rui-neutral-950/[0.11] dark:[[data-id=row-expanded]_&]:hover:bg-white/[0.14] ${OPEN_ROW_RAIL} !border-t-0` },
|
|
45
45
|
expandedParent: { tr: `bg-rui-neutral-950/[0.07] dark:bg-white/[0.09] ${NESTED_BAND} ${OPEN_ROW_RAIL}` },
|
|
46
|
-
group: { tr: "bg-rui-neutral-100 dark:bg-white/[0.05]" }
|
|
46
|
+
group: { tr: "bg-rui-neutral-100 hover:bg-rui-neutral-100 dark:bg-white/[0.05] dark:hover:bg-white/[0.05]" }
|
|
47
47
|
},
|
|
48
48
|
mobile: { true: {
|
|
49
49
|
wrapper: "between:border-t-0 border-0 rounded-none overflow-visible",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table-styles.js","names":[],"sources":["../../../src/components/tables/data-table-styles.ts"],"sourcesContent":["import { tv } from '@/utils/tv';\n\n/** A 2px primary rail down the left edge of an open row and its panel; out of flow, so the cell keeps its padding. */\nconst OPEN_ROW_RAIL = '[&>td:first-child]:relative [&>td:first-child]:before:absolute [&>td:first-child]:before:inset-y-0 [&>td:first-child]:before:left-0 [&>td:first-child]:before:w-0.5 [&>td:first-child]:before:bg-rui-primary';\n\n/**\n * The band of an open row inside another table's panel: a step darker than the outer band, so the two\n * levels never share a grey while the rows between them keep the plain surface.\n */\nconst NESTED_BAND = '[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.11] dark:[[data-id=row-expanded]_&]:bg-white/[0.14]';\n\n/**\n * Header and pagination of a nested table, stepped by depth to stand off the band around them (about\n * 1.12:1 or more) as well as their own rows: past the lighter band one panel deep, short of the darker\n * band two deep. Nested bars never stick, so the tint can be translucent over the table's own surface.\n */\nexport const NESTED_BAR = '[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.13] dark:[[data-id=row-expanded]_&]:bg-white/[0.16] [[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.06] dark:[[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-white/[0.07]';\n\nexport const dataTableStyles = tv({\n slots: {\n // `clip`, not `hidden`, which may shrink the item below its rows; its own surface reads the same anywhere\n wrapper: 'relative between:border-t between:border-b-0 between:border-rui-divider overflow-clip bg-rui-surface',\n // focusable only while it scrolls with nothing to tab to (useKeyboardScroll), ring drawn inside\n scroller: 'overflow-x-auto overflow-y-hidden [clip-path:inset(0_0_0_0)] outline-hidden focus-visible:focus-ring focus-visible:-outline-offset-2',\n table: 'min-w-full table-fixed between:border-t between:border-b-0 between:border-rui-divider whitespace-nowrap mx-auto my-0 max-w-fit relative border-rui-divider',\n tbody: 'between:border-t between:border-b-0 between:border-rui-divider',\n tr: 'hover:bg-rui-hover',\n // numbers line up in columns; no slashed zero, which in Inter reads as a second, monospace font beside zero-free values\n td: '[:where(&)]:px-4 text-rui-text text-body-2 tabular-nums [text-wrap:initial]',\n checkbox: 'px-2 w-[3.625rem] max-w-[3.625rem] [&_label]:ml-0',\n tbodyLoader: 'text-center',\n // tinted like the column header, the pair framing the body; opaque, so rows scroll behind a stuck bar\n pagination: `bg-rui-surface-muted ${NESTED_BAR}`,\n },\n variants: {\n sticky: {\n true: { pagination: 'sticky bottom-0 z-rui-raised' },\n },\n outlined: {\n true: { wrapper: 'border border-rui-divider' },\n },\n rounded: {\n sm: { wrapper: 'rounded-rui-sm' },\n md: { wrapper: 'rounded-rui-card' },\n lg: { wrapper: 'rounded-rui-lg' },\n },\n dense: {\n true: {},\n false: {},\n },\n // under every row state through `:where()
|
|
1
|
+
{"version":3,"file":"data-table-styles.js","names":[],"sources":["../../../src/components/tables/data-table-styles.ts"],"sourcesContent":["import { tv } from '@/utils/tv';\n\n/** A 2px primary rail down the left edge of an open row and its panel; out of flow, so the cell keeps its padding. */\nconst OPEN_ROW_RAIL = '[&>td:first-child]:relative [&>td:first-child]:before:absolute [&>td:first-child]:before:inset-y-0 [&>td:first-child]:before:left-0 [&>td:first-child]:before:w-0.5 [&>td:first-child]:before:bg-rui-primary';\n\n/**\n * The band of an open row inside another table's panel: a step darker than the outer band, so the two\n * levels never share a grey while the rows between them keep the plain surface.\n */\nconst NESTED_BAND = '[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.11] dark:[[data-id=row-expanded]_&]:bg-white/[0.14]';\n\n/**\n * Header and pagination of a nested table, stepped by depth to stand off the band around them (about\n * 1.12:1 or more) as well as their own rows: past the lighter band one panel deep, short of the darker\n * band two deep. Nested bars never stick, so the tint can be translucent over the table's own surface.\n */\nexport const NESTED_BAR = '[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.13] dark:[[data-id=row-expanded]_&]:bg-white/[0.16] [[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.06] dark:[[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-white/[0.07]';\n\nexport const dataTableStyles = tv({\n slots: {\n // `clip`, not `hidden`, which may shrink the item below its rows; its own surface reads the same anywhere\n wrapper: 'relative between:border-t between:border-b-0 between:border-rui-divider overflow-clip bg-rui-surface',\n // focusable only while it scrolls with nothing to tab to (useKeyboardScroll), ring drawn inside\n scroller: 'overflow-x-auto overflow-y-hidden [clip-path:inset(0_0_0_0)] outline-hidden focus-visible:focus-ring focus-visible:-outline-offset-2',\n table: 'min-w-full table-fixed between:border-t between:border-b-0 between:border-rui-divider whitespace-nowrap mx-auto my-0 max-w-fit relative border-rui-divider',\n tbody: 'between:border-t between:border-b-0 between:border-rui-divider',\n // its own tint, lighter than `rui-hover`, which lands on the header and pagination grey\n tr: 'hover:bg-rui-neutral-950/[0.03] dark:hover:bg-white/[0.04]',\n // numbers line up in columns; no slashed zero, which in Inter reads as a second, monospace font beside zero-free values\n td: '[:where(&)]:px-4 text-rui-text text-body-2 tabular-nums [text-wrap:initial]',\n checkbox: 'px-2 w-[3.625rem] max-w-[3.625rem] [&_label]:ml-0',\n tbodyLoader: 'text-center',\n // tinted like the column header, the pair framing the body; opaque, so rows scroll behind a stuck bar\n pagination: `bg-rui-surface-muted ${NESTED_BAR}`,\n },\n variants: {\n sticky: {\n true: { pagination: 'sticky bottom-0 z-rui-raised' },\n },\n outlined: {\n true: { wrapper: 'border border-rui-divider' },\n },\n rounded: {\n sm: { wrapper: 'rounded-rui-sm' },\n md: { wrapper: 'rounded-rui-card' },\n lg: { wrapper: 'rounded-rui-lg' },\n },\n dense: {\n true: {},\n false: {},\n },\n // under every row state through `:where()`, per item (`data-stripe`); half the row hover, so a striped row still darkens on hover\n striped: {\n true: { tbody: '[:where(&>tr[data-stripe])]:bg-rui-neutral-950/[0.015] dark:[:where(&>tr[data-stripe])]:bg-white/[0.02]' },\n },\n rowVariant: {\n selected: { tr: 'bg-rui-primary-soft' },\n empty: { tr: 'hover:bg-transparent dark:hover:bg-transparent' },\n // a grey band darker than the header so the two never match, a step darker again inside another panel\n expandable: { tr: `bg-rui-neutral-950/[0.07] hover:bg-rui-neutral-950/[0.07] dark:bg-white/[0.09] dark:hover:bg-white/[0.09] ${NESTED_BAND} [[data-id=row-expanded]_&]:hover:bg-rui-neutral-950/[0.11] dark:[[data-id=row-expanded]_&]:hover:bg-white/[0.14] ${OPEN_ROW_RAIL} !border-t-0` },\n expandedParent: { tr: `bg-rui-neutral-950/[0.07] dark:bg-white/[0.09] ${NESTED_BAND} ${OPEN_ROW_RAIL}` },\n group: { tr: 'bg-rui-neutral-100 hover:bg-rui-neutral-100 dark:bg-white/[0.05] dark:hover:bg-white/[0.05]' },\n },\n mobile: {\n true: {\n wrapper: 'between:border-t-0 border-0 rounded-none overflow-visible',\n scroller: 'overflow-visible [clip-path:none]',\n table: 'block min-w-0 max-w-none w-full whitespace-normal between:border-t-0 border-0',\n tbody: 'block between:border-t-0',\n tr: 'block',\n td: 'block px-4 py-2',\n },\n },\n },\n /**\n * A fixed row height keeps a row of plain text as tall as one holding an\n * icon button. Padding and floor sit in `:where()` so a consumer's `cellClass`\n * (`py-0` is common) still wins at any stylesheet order, and each density\n * sets its own because the class merger cannot dedupe these.\n */\n compoundVariants: [\n // a 4px inset under the height floor fits a 36px button in a 44px row (a 28px one in a dense 36px row)\n { dense: false, mobile: false, class: { td: '[:where(&)]:py-1 [:where(&)]:h-11' } },\n { dense: true, mobile: false, class: { td: '[:where(&)]:py-1 [:where(&)]:h-9' } },\n ],\n defaultVariants: {\n dense: false,\n mobile: false,\n },\n});\n"],"mappings":";;;AAGA,IAAM,gBAAgB;;;;;AAMtB,IAAM,cAAc;;;;;;AAOpB,IAAa,aAAa;AAE1B,IAAa,kBAAkB,GAAG;CAChC,OAAO;EAEL,SAAS;EAET,UAAU;EACV,OAAO;EACP,OAAO;EAEP,IAAI;EAEJ,IAAI;EACJ,UAAU;EACV,aAAa;EAEb,YAAY,wBAAwB;CACtC;CACA,UAAU;EACR,QAAQ,EACN,MAAM,EAAE,YAAY,+BAA+B,EACrD;EACA,UAAU,EACR,MAAM,EAAE,SAAS,4BAA4B,EAC/C;EACA,SAAS;GACP,IAAI,EAAE,SAAS,iBAAiB;GAChC,IAAI,EAAE,SAAS,mBAAmB;GAClC,IAAI,EAAE,SAAS,iBAAiB;EAClC;EACA,OAAO;GACL,MAAM,CAAC;GACP,OAAO,CAAC;EACV;EAEA,SAAS,EACP,MAAM,EAAE,OAAO,0GAA0G,EAC3H;EACA,YAAY;GACV,UAAU,EAAE,IAAI,sBAAsB;GACtC,OAAO,EAAE,IAAI,iDAAiD;GAE9D,YAAY,EAAE,IAAI,6GAA6G,YAAY,oHAAoH,cAAc,cAAc;GAC3R,gBAAgB,EAAE,IAAI,kDAAkD,YAAY,GAAG,gBAAgB;GACvG,OAAO,EAAE,IAAI,8FAA8F;EAC7G;EACA,QAAQ,EACN,MAAM;GACJ,SAAS;GACT,UAAU;GACV,OAAO;GACP,OAAO;GACP,IAAI;GACJ,IAAI;EACN,EACF;CACF;;;;;;;CAOA,kBAAkB,CAEhB;EAAE,OAAO;EAAO,QAAQ;EAAO,OAAO,EAAE,IAAI,oCAAoC;CAAE,GAClF;EAAE,OAAO;EAAM,QAAQ;EAAO,OAAO,EAAE,IAAI,mCAAmC;CAAE,CAClF;CACA,iBAAiB;EACf,OAAO;EACP,QAAQ;CACV;AACF,CAAC"}
|
|
@@ -99,11 +99,21 @@ function useStickyBottomInset(sentinel, bar, canStick) {
|
|
|
99
99
|
const { height } = useElementSize(bar, void 0, { box: "border-box" });
|
|
100
100
|
const { height: viewHeight } = useWindowSize();
|
|
101
101
|
let frame = 0;
|
|
102
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* From the bar's top to the view's bottom; a stuck bar sits on that bottom, so this is its height.
|
|
104
|
+
* It first checks the sentinel is still below the band: one jump can carry it from below the band to
|
|
105
|
+
* above the view without the observer ever seeing it intersect, which would leave the bar counted
|
|
106
|
+
* while it sits far above the view.
|
|
107
|
+
*/
|
|
103
108
|
function measureCovered() {
|
|
104
109
|
frame = 0;
|
|
105
110
|
const element = unrefElement(bar);
|
|
106
111
|
if (!element) return;
|
|
112
|
+
const place = get(sentinel)?.getBoundingClientRect().top;
|
|
113
|
+
if (place !== void 0 && place < get(viewHeight) - Math.ceil(get(height)) - RESTING_CLEARANCE) {
|
|
114
|
+
set(belowView, false);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
107
117
|
set(covered, Math.max(get(height), Math.ceil(get(viewHeight) - element.getBoundingClientRect().top)));
|
|
108
118
|
}
|
|
109
119
|
/** A resting bar moves with the page, so while it is in the band, follow it once per frame. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-scroll.js","names":[],"sources":["../../../../src/composables/tables/data-table/page-scroll.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref } from 'vue';\nimport type { MaybeElementRef } from '@/types/dom';\n\nexport interface UsePageScrollReturn {\n /** Scroll the table's top into view, if it has scrolled above the visible area. */\n revealTableTop: () => Promise<void>;\n}\n\n/**\n * How much of a table, from its top, must be on screen before its pagination bar sticks: the\n * column header and the first rows. A table just scrolling in from below keeps its bar under the\n * rows, rather than showing the bar on top of the header.\n */\nconst STICK_AFTER = 128;\n\n/**\n * The nearest ancestor that scrolls vertically. `undefined` means the page itself does, through\n * the window or a scrolling `<body>`, which is where a sticky offset such as an app bar applies.\n */\nfunction findScroller(element: HTMLElement): HTMLElement | undefined {\n let node = element.parentElement;\n while (node && node !== document.body && node !== document.documentElement) {\n const { overflowY } = getComputedStyle(node);\n if ((overflowY === 'auto' || overflowY === 'scroll') && node.scrollHeight > node.clientHeight)\n return node;\n node = node.parentElement;\n }\n return undefined;\n}\n\nfunction scrollPageBy(top: number): void {\n const body = document.body;\n if (body.scrollHeight > body.clientHeight && ['auto', 'scroll'].includes(getComputedStyle(body).overflowY))\n body.scrollBy({ top });\n else\n window.scrollBy({ top });\n}\n\n/**\n * After a page change, brings the table's first row back into view so the new page reads from the\n * top. It scrolls only when the table's top sits above the visible area, as it does after paging\n * from the bottom bar of a long page; a table that already shows its top stays put, so paging never\n * makes the view jump.\n */\nexport function usePageScroll(\n wrapper: Readonly<Ref<HTMLElement | null | undefined>>,\n stickyOffset: MaybeRefOrGetter<number | undefined>,\n): UsePageScrollReturn {\n async function revealTableTop(): Promise<void> {\n await nextTick();\n const element = get(wrapper);\n if (!element)\n return;\n\n const scroller = findScroller(element);\n const viewTop = scroller ? scroller.getBoundingClientRect().top : (toValue(stickyOffset) ?? 0);\n const distance = element.getBoundingClientRect().top - viewTop;\n if (distance >= 0)\n return;\n\n if (scroller)\n scroller.scrollBy({ top: distance });\n else\n scrollPageBy(distance);\n }\n\n return { revealTableTop };\n}\n\n/**\n * Whether the pagination bar may stick: true once the top {@link STICK_AFTER}px of the table are\n * inside its scrolling area. It starts true, so a page without IntersectionObserver keeps the bar\n * sticky.\n */\nexport function useStickyPaginationBar(\n wrapper: Readonly<Ref<HTMLElement | null | undefined>>,\n enabled: MaybeRefOrGetter<boolean>,\n): Readonly<Ref<boolean>> {\n const canStick = shallowRef<boolean>(true);\n const root = shallowRef<HTMLElement>();\n\n onMounted(() => {\n const element = get(wrapper);\n if (element)\n set(root, findScroller(element));\n });\n\n useIntersectionObserver(\n () => (toValue(enabled) ? get(wrapper) : undefined),\n ([entry]) => {\n if (!entry)\n return;\n // also true once the table has scrolled past the top, when the bar is out of view anyway\n set(canStick, entry.isIntersecting || entry.boundingClientRect.bottom <= (entry.rootBounds?.top ?? 0));\n },\n { root, rootMargin: `0px 0px -${STICK_AFTER}px 0px` },\n );\n\n return canStick;\n}\n\n/**\n * How far above the bar a bar resting at its own place still counts as covered: a part docked in the\n * bottom corner (rotki's task dock is 82px with its offset) reaches over the bar's top by about this much.\n */\nconst RESTING_CLEARANCE = 48;\n\n/** How much of the view's bottom each pagination bar covers, by table; the page's floating parts clear the most. */\nconst stuckBarHeights = new Map<symbol, number>();\n\nfunction publishStickyBottom(): void {\n if (typeof document === 'undefined')\n return;\n const style = document.documentElement.style;\n if (stuckBarHeights.size === 0)\n style.removeProperty('--rui-sticky-bottom');\n else\n style.setProperty('--rui-sticky-bottom', `${Math.max(...stuckBarHeights.values())}px`);\n}\n\n/**\n * Publishes how much of the view's bottom a stuck pagination bar covers, as `--rui-sticky-bottom` on\n * the document root, so the page's own floating parts (a dock, a FAB) can rise above the bar instead of\n * covering its page buttons. A bar resting at its own place in the bottom band of the view counts too,\n * since it sits in the same corner; it covers from its top down, which is more than its height when it\n * rests above the view's bottom, so the parts keep the same gap above it as above a stuck bar. Only a\n * bar at page level counts: one inside a scrolling area sits under nothing the page floats.\n *\n * @param sentinel - an empty element at the bar's own place after the rows; while it is below the view's bottom band, the bar covers that corner\n * @param bar - the bar, measured for its height\n * @param canStick - whether the bar may stick at all\n */\nexport function useStickyBottomInset(\n sentinel: Readonly<Ref<HTMLElement | null | undefined>>,\n bar: MaybeElementRef,\n canStick: MaybeRefOrGetter<boolean>,\n): void {\n const id = Symbol('sticky-pagination-bar');\n const belowView = shallowRef<boolean>(false);\n const pageLevel = shallowRef<boolean>(false);\n const covered = shallowRef<number>(0);\n const { height } = useElementSize(bar, undefined, { box: 'border-box' });\n const { height: viewHeight } = useWindowSize();\n let frame = 0;\n\n /** From the bar's top to the view's bottom; a stuck bar sits on that bottom, so this is its height. */\n function measureCovered(): void {\n frame = 0;\n const element = unrefElement(bar);\n if (!element)\n return;\n set(covered, Math.max(get(height), Math.ceil(get(viewHeight) - element.getBoundingClientRect().top)));\n }\n\n /** A resting bar moves with the page, so while it is in the band, follow it once per frame. */\n function scheduleMeasure(): void {\n if (get(belowView) && !frame)\n frame = requestAnimationFrame(measureCovered);\n }\n\n useEventListener('scroll', scheduleMeasure, { capture: true, passive: true });\n\n onMounted(() => {\n const element = get(sentinel);\n set(pageLevel, !!element && !findScroller(element));\n });\n\n useIntersectionObserver(sentinel, ([entry]) => {\n if (!entry)\n return;\n // no root bounds (a cross-origin frame) reads as not stuck, which leaves the floating parts where they are\n set(belowView, !entry.isIntersecting && entry.boundingClientRect.top >= (entry.rootBounds?.bottom ?? Number.POSITIVE_INFINITY));\n }, {\n // the view's bottom edge, raised by the band a resting bar covers\n rootMargin: () => `0px 0px -${Math.ceil(get(height)) + RESTING_CLEARANCE}px 0px`,\n });\n\n watch([belowView, height, viewHeight], () => measureCovered());\n\n watchEffect(() => {\n if (get(pageLevel) && toValue(canStick) && get(belowView) && get(height) > 0)\n stuckBarHeights.set(id, Math.max(get(height), get(covered)));\n else\n stuckBarHeights.delete(id);\n publishStickyBottom();\n });\n\n onScopeDispose(() => {\n if (frame)\n cancelAnimationFrame(frame);\n stuckBarHeights.delete(id);\n publishStickyBottom();\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"page-scroll.js","names":[],"sources":["../../../../src/composables/tables/data-table/page-scroll.ts"],"sourcesContent":["import type { MaybeRefOrGetter, Ref } from 'vue';\nimport type { MaybeElementRef } from '@/types/dom';\n\nexport interface UsePageScrollReturn {\n /** Scroll the table's top into view, if it has scrolled above the visible area. */\n revealTableTop: () => Promise<void>;\n}\n\n/**\n * How much of a table, from its top, must be on screen before its pagination bar sticks: the\n * column header and the first rows. A table just scrolling in from below keeps its bar under the\n * rows, rather than showing the bar on top of the header.\n */\nconst STICK_AFTER = 128;\n\n/**\n * The nearest ancestor that scrolls vertically. `undefined` means the page itself does, through\n * the window or a scrolling `<body>`, which is where a sticky offset such as an app bar applies.\n */\nfunction findScroller(element: HTMLElement): HTMLElement | undefined {\n let node = element.parentElement;\n while (node && node !== document.body && node !== document.documentElement) {\n const { overflowY } = getComputedStyle(node);\n if ((overflowY === 'auto' || overflowY === 'scroll') && node.scrollHeight > node.clientHeight)\n return node;\n node = node.parentElement;\n }\n return undefined;\n}\n\nfunction scrollPageBy(top: number): void {\n const body = document.body;\n if (body.scrollHeight > body.clientHeight && ['auto', 'scroll'].includes(getComputedStyle(body).overflowY))\n body.scrollBy({ top });\n else\n window.scrollBy({ top });\n}\n\n/**\n * After a page change, brings the table's first row back into view so the new page reads from the\n * top. It scrolls only when the table's top sits above the visible area, as it does after paging\n * from the bottom bar of a long page; a table that already shows its top stays put, so paging never\n * makes the view jump.\n */\nexport function usePageScroll(\n wrapper: Readonly<Ref<HTMLElement | null | undefined>>,\n stickyOffset: MaybeRefOrGetter<number | undefined>,\n): UsePageScrollReturn {\n async function revealTableTop(): Promise<void> {\n await nextTick();\n const element = get(wrapper);\n if (!element)\n return;\n\n const scroller = findScroller(element);\n const viewTop = scroller ? scroller.getBoundingClientRect().top : (toValue(stickyOffset) ?? 0);\n const distance = element.getBoundingClientRect().top - viewTop;\n if (distance >= 0)\n return;\n\n if (scroller)\n scroller.scrollBy({ top: distance });\n else\n scrollPageBy(distance);\n }\n\n return { revealTableTop };\n}\n\n/**\n * Whether the pagination bar may stick: true once the top {@link STICK_AFTER}px of the table are\n * inside its scrolling area. It starts true, so a page without IntersectionObserver keeps the bar\n * sticky.\n */\nexport function useStickyPaginationBar(\n wrapper: Readonly<Ref<HTMLElement | null | undefined>>,\n enabled: MaybeRefOrGetter<boolean>,\n): Readonly<Ref<boolean>> {\n const canStick = shallowRef<boolean>(true);\n const root = shallowRef<HTMLElement>();\n\n onMounted(() => {\n const element = get(wrapper);\n if (element)\n set(root, findScroller(element));\n });\n\n useIntersectionObserver(\n () => (toValue(enabled) ? get(wrapper) : undefined),\n ([entry]) => {\n if (!entry)\n return;\n // also true once the table has scrolled past the top, when the bar is out of view anyway\n set(canStick, entry.isIntersecting || entry.boundingClientRect.bottom <= (entry.rootBounds?.top ?? 0));\n },\n { root, rootMargin: `0px 0px -${STICK_AFTER}px 0px` },\n );\n\n return canStick;\n}\n\n/**\n * How far above the bar a bar resting at its own place still counts as covered: a part docked in the\n * bottom corner (rotki's task dock is 82px with its offset) reaches over the bar's top by about this much.\n */\nconst RESTING_CLEARANCE = 48;\n\n/** How much of the view's bottom each pagination bar covers, by table; the page's floating parts clear the most. */\nconst stuckBarHeights = new Map<symbol, number>();\n\nfunction publishStickyBottom(): void {\n if (typeof document === 'undefined')\n return;\n const style = document.documentElement.style;\n if (stuckBarHeights.size === 0)\n style.removeProperty('--rui-sticky-bottom');\n else\n style.setProperty('--rui-sticky-bottom', `${Math.max(...stuckBarHeights.values())}px`);\n}\n\n/**\n * Publishes how much of the view's bottom a stuck pagination bar covers, as `--rui-sticky-bottom` on\n * the document root, so the page's own floating parts (a dock, a FAB) can rise above the bar instead of\n * covering its page buttons. A bar resting at its own place in the bottom band of the view counts too,\n * since it sits in the same corner; it covers from its top down, which is more than its height when it\n * rests above the view's bottom, so the parts keep the same gap above it as above a stuck bar. Only a\n * bar at page level counts: one inside a scrolling area sits under nothing the page floats.\n *\n * @param sentinel - an empty element at the bar's own place after the rows; while it is below the view's bottom band, the bar covers that corner\n * @param bar - the bar, measured for its height\n * @param canStick - whether the bar may stick at all\n */\nexport function useStickyBottomInset(\n sentinel: Readonly<Ref<HTMLElement | null | undefined>>,\n bar: MaybeElementRef,\n canStick: MaybeRefOrGetter<boolean>,\n): void {\n const id = Symbol('sticky-pagination-bar');\n const belowView = shallowRef<boolean>(false);\n const pageLevel = shallowRef<boolean>(false);\n const covered = shallowRef<number>(0);\n const { height } = useElementSize(bar, undefined, { box: 'border-box' });\n const { height: viewHeight } = useWindowSize();\n let frame = 0;\n\n /**\n * From the bar's top to the view's bottom; a stuck bar sits on that bottom, so this is its height.\n * It first checks the sentinel is still below the band: one jump can carry it from below the band to\n * above the view without the observer ever seeing it intersect, which would leave the bar counted\n * while it sits far above the view.\n */\n function measureCovered(): void {\n frame = 0;\n const element = unrefElement(bar);\n if (!element)\n return;\n const place = get(sentinel)?.getBoundingClientRect().top;\n if (place !== undefined && place < get(viewHeight) - Math.ceil(get(height)) - RESTING_CLEARANCE) {\n set(belowView, false);\n return;\n }\n set(covered, Math.max(get(height), Math.ceil(get(viewHeight) - element.getBoundingClientRect().top)));\n }\n\n /** A resting bar moves with the page, so while it is in the band, follow it once per frame. */\n function scheduleMeasure(): void {\n if (get(belowView) && !frame)\n frame = requestAnimationFrame(measureCovered);\n }\n\n useEventListener('scroll', scheduleMeasure, { capture: true, passive: true });\n\n onMounted(() => {\n const element = get(sentinel);\n set(pageLevel, !!element && !findScroller(element));\n });\n\n useIntersectionObserver(sentinel, ([entry]) => {\n if (!entry)\n return;\n // no root bounds (a cross-origin frame) reads as not stuck, which leaves the floating parts where they are\n set(belowView, !entry.isIntersecting && entry.boundingClientRect.top >= (entry.rootBounds?.bottom ?? Number.POSITIVE_INFINITY));\n }, {\n // the view's bottom edge, raised by the band a resting bar covers\n rootMargin: () => `0px 0px -${Math.ceil(get(height)) + RESTING_CLEARANCE}px 0px`,\n });\n\n watch([belowView, height, viewHeight], () => measureCovered());\n\n watchEffect(() => {\n if (get(pageLevel) && toValue(canStick) && get(belowView) && get(height) > 0)\n stuckBarHeights.set(id, Math.max(get(height), get(covered)));\n else\n stuckBarHeights.delete(id);\n publishStickyBottom();\n });\n\n onScopeDispose(() => {\n if (frame)\n cancelAnimationFrame(frame);\n stuckBarHeights.delete(id);\n publishStickyBottom();\n });\n}\n"],"mappings":"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"}
|
package/dist/style.css
CHANGED
|
@@ -4377,6 +4377,10 @@
|
|
|
4377
4377
|
}
|
|
4378
4378
|
}
|
|
4379
4379
|
|
|
4380
|
+
.hover\:bg-rui-neutral-100:hover {
|
|
4381
|
+
background-color: rgb(var(--rui-neutral-100));
|
|
4382
|
+
}
|
|
4383
|
+
|
|
4380
4384
|
.hover\:bg-rui-neutral-200:hover {
|
|
4381
4385
|
background-color: rgb(var(--rui-neutral-200));
|
|
4382
4386
|
}
|
|
@@ -4385,6 +4389,16 @@
|
|
|
4385
4389
|
background-color: rgb(var(--rui-neutral-400));
|
|
4386
4390
|
}
|
|
4387
4391
|
|
|
4392
|
+
.hover\:bg-rui-neutral-950\/\[0\.03\]:hover {
|
|
4393
|
+
background-color: rgb(var(--rui-neutral-950));
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
4397
|
+
.hover\:bg-rui-neutral-950\/\[0\.03\]:hover {
|
|
4398
|
+
background-color: color-mix(in oklab, rgb(var(--rui-neutral-950)) 3%, transparent);
|
|
4399
|
+
}
|
|
4400
|
+
}
|
|
4401
|
+
|
|
4388
4402
|
.hover\:bg-rui-neutral-950\/\[0\.07\]:hover {
|
|
4389
4403
|
background-color: rgb(var(--rui-neutral-950));
|
|
4390
4404
|
}
|
|
@@ -4708,8 +4722,14 @@
|
|
|
4708
4722
|
color: var(--rui-text-disabled) !important;
|
|
4709
4723
|
}
|
|
4710
4724
|
|
|
4711
|
-
.has-\[\+\[data-id\=row-append\]\:hover\]\:bg-rui-
|
|
4712
|
-
background-color: var(--rui-
|
|
4725
|
+
.has-\[\+\[data-id\=row-append\]\:hover\]\:bg-rui-neutral-950\/\[0\.03\]:has( + [data-id="row-append"]:hover) {
|
|
4726
|
+
background-color: rgb(var(--rui-neutral-950));
|
|
4727
|
+
}
|
|
4728
|
+
|
|
4729
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
4730
|
+
.has-\[\+\[data-id\=row-append\]\:hover\]\:bg-rui-neutral-950\/\[0\.03\]:has( + [data-id="row-append"]:hover) {
|
|
4731
|
+
background-color: color-mix(in oklab, rgb(var(--rui-neutral-950)) 3%, transparent);
|
|
4732
|
+
}
|
|
4713
4733
|
}
|
|
4714
4734
|
|
|
4715
4735
|
.data-\[active\]\:bg-rui-surface[data-active] {
|
|
@@ -5213,6 +5233,26 @@
|
|
|
5213
5233
|
background-color: #0000;
|
|
5214
5234
|
}
|
|
5215
5235
|
|
|
5236
|
+
.dark\:hover\:bg-white\/\[0\.04\]:is(.dark *, [data-theme="dark"] *):hover {
|
|
5237
|
+
background-color: #ffffff0a;
|
|
5238
|
+
}
|
|
5239
|
+
|
|
5240
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
5241
|
+
.dark\:hover\:bg-white\/\[0\.04\]:is(.dark *, [data-theme="dark"] *):hover {
|
|
5242
|
+
background-color: color-mix(in oklab, var(--color-white) 4%, transparent);
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
|
|
5246
|
+
.dark\:hover\:bg-white\/\[0\.05\]:is(.dark *, [data-theme="dark"] *):hover {
|
|
5247
|
+
background-color: #ffffff0d;
|
|
5248
|
+
}
|
|
5249
|
+
|
|
5250
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
5251
|
+
.dark\:hover\:bg-white\/\[0\.05\]:is(.dark *, [data-theme="dark"] *):hover {
|
|
5252
|
+
background-color: color-mix(in oklab, var(--color-white) 5%, transparent);
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
|
|
5216
5256
|
.dark\:hover\:bg-white\/\[0\.09\]:is(.dark *, [data-theme="dark"] *):hover {
|
|
5217
5257
|
background-color: #ffffff17;
|
|
5218
5258
|
}
|
|
@@ -5288,6 +5328,16 @@
|
|
|
5288
5328
|
--tw-inset-ring-color: var(--rui-text-disabled);
|
|
5289
5329
|
}
|
|
5290
5330
|
|
|
5331
|
+
.dark\:has-\[\+\[data-id\=row-append\]\:hover\]\:bg-white\/\[0\.04\]:is(.dark *, [data-theme="dark"] *):has( + [data-id="row-append"]:hover) {
|
|
5332
|
+
background-color: #ffffff0a;
|
|
5333
|
+
}
|
|
5334
|
+
|
|
5335
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
5336
|
+
.dark\:has-\[\+\[data-id\=row-append\]\:hover\]\:bg-white\/\[0\.04\]:is(.dark *, [data-theme="dark"] *):has( + [data-id="row-append"]:hover) {
|
|
5337
|
+
background-color: color-mix(in oklab, var(--color-white) 4%, transparent);
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
|
|
5291
5341
|
.dark\:data-\[active\]\:bg-rui-neutral-700:is(.dark *, [data-theme="dark"] *)[data-active] {
|
|
5292
5342
|
background-color: rgb(var(--rui-neutral-700));
|
|
5293
5343
|
}
|
|
@@ -5665,23 +5715,23 @@
|
|
|
5665
5715
|
color: var(--rui-text-secondary);
|
|
5666
5716
|
}
|
|
5667
5717
|
|
|
5668
|
-
:where(.\[\:where\(\&\>tr\[data-stripe\]\)\]\:bg-rui-neutral-950\/\[0\.
|
|
5718
|
+
:where(.\[\:where\(\&\>tr\[data-stripe\]\)\]\:bg-rui-neutral-950\/\[0\.015\] > tr[data-stripe]) {
|
|
5669
5719
|
background-color: rgb(var(--rui-neutral-950));
|
|
5670
5720
|
}
|
|
5671
5721
|
|
|
5672
5722
|
@supports (color: color-mix(in lab, red, red)) {
|
|
5673
|
-
:where(.\[\:where\(\&\>tr\[data-stripe\]\)\]\:bg-rui-neutral-950\/\[0\.
|
|
5674
|
-
background-color: color-mix(in oklab, rgb(var(--rui-neutral-950))
|
|
5723
|
+
:where(.\[\:where\(\&\>tr\[data-stripe\]\)\]\:bg-rui-neutral-950\/\[0\.015\] > tr[data-stripe]) {
|
|
5724
|
+
background-color: color-mix(in oklab, rgb(var(--rui-neutral-950)) 1.5%, transparent);
|
|
5675
5725
|
}
|
|
5676
5726
|
}
|
|
5677
5727
|
|
|
5678
|
-
:where(.dark\:\[\:where\(\&\>tr\[data-stripe\]\)\]\:bg-white\/\[0\.
|
|
5679
|
-
background-color: #
|
|
5728
|
+
:where(.dark\:\[\:where\(\&\>tr\[data-stripe\]\)\]\:bg-white\/\[0\.02\]:is(.dark *, [data-theme="dark"] *) > tr[data-stripe]) {
|
|
5729
|
+
background-color: #ffffff05;
|
|
5680
5730
|
}
|
|
5681
5731
|
|
|
5682
5732
|
@supports (color: color-mix(in lab, red, red)) {
|
|
5683
|
-
:where(.dark\:\[\:where\(\&\>tr\[data-stripe\]\)\]\:bg-white\/\[0\.
|
|
5684
|
-
background-color: color-mix(in oklab, var(--color-white)
|
|
5733
|
+
:where(.dark\:\[\:where\(\&\>tr\[data-stripe\]\)\]\:bg-white\/\[0\.02\]:is(.dark *, [data-theme="dark"] *) > tr[data-stripe]) {
|
|
5734
|
+
background-color: color-mix(in oklab, var(--color-white) 2%, transparent);
|
|
5685
5735
|
}
|
|
5686
5736
|
}
|
|
5687
5737
|
|
|
@@ -5769,8 +5819,24 @@
|
|
|
5769
5819
|
}
|
|
5770
5820
|
}
|
|
5771
5821
|
|
|
5772
|
-
[data-id="row"]:hover + .\[\[data-id\=row\]\:hover\+\&\]\:bg-rui-
|
|
5773
|
-
background-color: var(--rui-
|
|
5822
|
+
[data-id="row"]:hover + .\[\[data-id\=row\]\:hover\+\&\]\:bg-rui-neutral-950\/\[0\.03\] {
|
|
5823
|
+
background-color: rgb(var(--rui-neutral-950));
|
|
5824
|
+
}
|
|
5825
|
+
|
|
5826
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
5827
|
+
[data-id="row"]:hover + .\[\[data-id\=row\]\:hover\+\&\]\:bg-rui-neutral-950\/\[0\.03\] {
|
|
5828
|
+
background-color: color-mix(in oklab, rgb(var(--rui-neutral-950)) 3%, transparent);
|
|
5829
|
+
}
|
|
5830
|
+
}
|
|
5831
|
+
|
|
5832
|
+
[data-id="row"]:hover + .dark\:\[\[data-id\=row\]\:hover\+\&\]\:bg-white\/\[0\.04\]:is(.dark *, [data-theme="dark"] *) {
|
|
5833
|
+
background-color: #ffffff0a;
|
|
5834
|
+
}
|
|
5835
|
+
|
|
5836
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
5837
|
+
[data-id="row"]:hover + .dark\:\[\[data-id\=row\]\:hover\+\&\]\:bg-white\/\[0\.04\]:is(.dark *, [data-theme="dark"] *) {
|
|
5838
|
+
background-color: color-mix(in oklab, var(--color-white) 4%, transparent);
|
|
5839
|
+
}
|
|
5774
5840
|
}
|
|
5775
5841
|
}
|
|
5776
5842
|
|
package/dist/web-types.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "http://json.schemastore.org/web-types",
|
|
3
3
|
"framework": "vue",
|
|
4
4
|
"name": "@rotki/ui-library",
|
|
5
|
-
"version": "3.0.0
|
|
5
|
+
"version": "3.0.0",
|
|
6
6
|
"js-types-syntax": "typescript",
|
|
7
7
|
"description-markup": "markdown",
|
|
8
8
|
"contributions": {
|
|
@@ -2503,6 +2503,16 @@
|
|
|
2503
2503
|
"type": "number | undefined"
|
|
2504
2504
|
}
|
|
2505
2505
|
},
|
|
2506
|
+
{
|
|
2507
|
+
"name": "disable-sticky-pagination",
|
|
2508
|
+
"description": "keep the pagination bar at the table's end instead of pinning it to the bottom of the view while\nthe rows run past it, for a table that is one section of a longer page",
|
|
2509
|
+
"required": false,
|
|
2510
|
+
"default": "false",
|
|
2511
|
+
"value": {
|
|
2512
|
+
"kind": "expression",
|
|
2513
|
+
"type": "boolean | undefined"
|
|
2514
|
+
}
|
|
2515
|
+
},
|
|
2506
2516
|
{
|
|
2507
2517
|
"name": "global-items-per-page",
|
|
2508
2518
|
"description": "Affects how the items per page work across the app.\nWhen true, changing the items per page setting in one table will affect other tables.",
|