From 9dced984f198bc13cb34cc68835b277ec794a7e7 Mon Sep 17 00:00:00 2001 From: mm <25961416+mlmoravek@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:55:52 +0200 Subject: [PATCH] feat(table): update `thAttrs` and `tdAttrs` properties (#958) --- packages/docs/components/Table.md | 138 +++++++++--------- .../src/components/pagination/Pagination.vue | 4 +- .../pagination/PaginationButton.vue | 4 +- .../__snapshots__/pagination.test.ts.snap | 4 +- packages/oruga/src/components/table/Table.vue | 29 +++- .../src/components/table/TableColumn.vue | 40 +---- .../src/components/table/examples/sticky.vue | 8 +- .../{tablecolumn.ts => tablecolumn.test.ts} | 0 8 files changed, 109 insertions(+), 118 deletions(-) rename packages/oruga/src/components/table/tests/{tablecolumn.ts => tablecolumn.test.ts} (100%) diff --git a/packages/docs/components/Table.md b/packages/docs/components/Table.md index c3421e3a7..31073cbd7 100644 --- a/packages/docs/components/Table.md +++ b/packages/docs/components/Table.md @@ -41,72 +41,74 @@ sidebarDepth: 2 ### Props -| Prop name | Description | Type | Values | Default | -| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ariaCurrentLabel | Accessibility label for the pagination current page button. | string | - |
From config:
table: {
  ariaCurrentLabel: undefined
}
| -| ariaNextLabel | Accessibility label for the pagination next page button. | string | - |
From config:
table: {
  ariaNextLabel: undefined
}
| -| ariaPageLabel | Accessibility label for the pagination page button. | string | - |
From config:
table: {
  ariaPageLabel: undefined
}
| -| ariaPreviousLabel | Accessibility label for the pagination previous page button. | string | - |
From config:
table: {
  ariaPreviousLabel: undefined
}
| -| backendFiltering | Columns won't be filtered with Javascript, use with `searchable` prop to the columns to filter in your backend | boolean | - |
From config:
table: {
  backendFiltering: false
}
| -| backendPagination | Rows won't be paginated with Javascript, use with `page-change` event to paginate in your backend | boolean | - | false | -| backendSorting | Columns won't be sorted with Javascript, use with `sort` event to sort in your backend | boolean | - |
From config:
table: {
  backendSorting: false
}
| -| bordered | Border to all cells | boolean | - |
From config:
table: {
  bordered: false
}
| -| checkable | Rows can be checked (multiple) | boolean | - | false | -| checkboxPosition | Position of the checkbox when checkable (if checkable) | string | `left`, `right` |
From config:
table: {
  checkboxPosition: "left"
}
| -| checkboxVariant | Color of the checkbox when checkable (if checkable) | string | `primary`, `info`, `success`, `warning`, `danger`, `and any other custom color` |
From config:
table: {
  checkboxVariant: undefined
}
| -| checkedRows | Set which rows are checked, use `v-model:checkedRows` to make it two-way binding (if checkable) | T[] | - | Default function (see source code) | -| columns | Table columns | TableColumn[] | - | Default function (see source code) | -| currentPage | Current page of table data (if paginated), use `v-model:currentPage` to make it two-way binding | number | - | 1 | -| customCompare | Define a custom comparison function to check whether two row elements are equal.
By default a `rowKey` comparison is performed if given. Otherwise a simple object comparison is done. | (a: T, b: T) => boolean | - | | -| customDetailRow | Enable custom style on details (if detailed) | boolean | - | false | -| data | Table data | T[] | - | Default function (see source code) | -| debounceSearch | Filtering debounce time (in milliseconds) | number | - |
From config:
table: {
  debounceSearch: undefined
}
| -| defaultSort | Sets the default sort column and order — e.g. ['first_name', 'desc'] | string \| string[] | - |
From config:
table: {
  defaultSort: undefined
}
| -| defaultSortDirection | Sets the default sort column direction on the first click | string | `asc`, `desc` |
From config:
table: {
  defaultSortDirection: "asc"
}
| -| detailIcon | Icon name of detail action (if detailed) | string | - |
From config:
table: {
  detailIcon: "chevron-right"
}
| -| detailTransition | | string | - |
From config:
table: {
  detailTransition: "slide"
}
| -| detailed | Allow row details | boolean | - | false | -| detailedRows | Set which rows have opened details, use `v-model:detailedRows` to make it two-way binding (if detailed).
Ideal to open details via vue-router. (A unique key is required; check `rowKey` prop) | T[] | - | Default function (see source code) | -| draggable | Allows rows to be draggable | boolean | - | false | -| draggableColumn | Allows columns to be draggable | boolean | - | false | -| filtersEvent | Add a native event to filter | string | - | "" | -| filtersIcon | Icon of the column search input | string | - |
From config:
table: {
  filterIcon: undefined
}
| -| filtersPlaceholder | Placeholder of the column search input | string | - |
From config:
table: {
  filterPlaceholder: undefined
}
| -| headerCheckable | Show check/uncheck all checkbox in table header when checkable (if checkable) | boolean | - | true | -| height | Table fixed height | number\|string | - | | -| hoverable | Rows are highlighted when hovering | boolean | - |
From config:
table: {
  hoverable: false
}
| -| iconPack | Icon pack to use | string | `mdi`, `fa`, `fas and any other custom icon pack` |
From config:
table: {
  iconPack: undefined
}
| -| isDetailedVisible | Controls the visibility of the trigger that toggles the detailed rows (if detailed) | (row: T) => boolean | - |
From config:
table: {
  isDetailedVisible: (row) => true
}
| -| isRowCheckable | Custom method to verify if a row is checkable (if checkable) | (row: T) => boolean | - |
From config:
table: {
  isRowCheckable: (row) => true
}
| -| isRowChecked | Custom method to verify if a row is checked (if checkable). Useful for backend pagination. | (row: T, data: T[]) => boolean | - | | -| isRowSelectable | Custom method to verify if a row is selectable, works when is selectable | (row: T) => boolean | - | Default function (see source code) | -| loading | Enable loading state | boolean | - | false | -| loadingIcon | Icon for the loading state | string | - |
From config:
table: {
  loadingIcon: "loading"
}
| -| loadingLabel | Label for the loading state | string | - |
From config:
table: {
  loadingLabel: undefined
}
| -| mobileBreakpoint | Mobile breakpoint as max-width value | string | - |
From config:
table: {
  mobileBreakpoint: undefined
}
| -| mobileCards | Rows appears as cards on mobile (collapse rows) | boolean | - |
From config:
table: {
  mobileCards: true
}
| -| mobileSortPlaceholder | Select placeholder text when nothing is selected (if mobileCards) | string | - |
From config:
table: {
  mobileSortPlaceholder: undefined
}
| -| narrowed | Makes the cells narrower | boolean | - |
From config:
table: {
  narrowed: false
}
| -| override | Override existing theme classes completely | boolean | - | | -| paginated | Adds pagination to the table | boolean | - |
From config:
table: {
  paginated: false
}
| -| paginationOrder | Pagination buttons order (if paginated) | string | `centered`, `right`, `left` |
From config:
table: {
  paginationOrder: undefined
}
| -| paginationPosition | Pagination position (if paginated) | string | `bottom`, `top`, `both` |
From config:
table: {
  paginationPosition: "bottom"
}
| -| paginationRounded | Enable rounded pagination buttons (if paginated) | boolean | - |
From config:
table: {
  paginationRounded: false
}
| -| paginationSimple | Enable simple style pagination (if paginated) | boolean | - |
From config:
table: {
  paginationSimple: false
}
| -| paginationSize | Size of pagination (if paginated) | string | `small`, `medium`, `large` |
From config:
table: {
  paginationSize: "small"
}
| -| perPage | How many rows per page (if paginated) | number\|string | - |
From config:
table: {
  perPage: 20
}
| -| rowKey | Use a unique key of your data Object for each row. Useful if your data prop has dynamic indices. (id recommended) | string | - |
From config:
table: {
  rowKey: undefined
}
| -| scrollable | Add a horizontal scrollbar when table is too wide | boolean | - | | -| selectable | Table can be focused and user can select rows. Rows can be navigate with keyboard arrows and are highlighted when hovering. | boolean | - |
From config:
table: {
  selectable: false
}
| -| selected | Set which row is selected, use `v-model:selected` to make it two-way binding (if selectable) | T | - | | -| showDetailIcon | Allow detail icon and column to be visible (if detailed) | boolean | - |
From config:
table: {
  showDetailIcon: true
}
| -| showHeader | Show header | boolean | - |
From config:
table: {
  showHeader: true
}
| -| sortIcon | Sets the header sorting icon | string | - |
From config:
table: {
  sortIcon: "arrow-up"
}
| -| sortIconSize | Sets the size of the sorting icon | string | `small`, `medium`, `large` |
From config:
table: {
  sortIconSize: "small"
}
| -| stickyCheckbox | Make the checkbox column sticky (if checkable) | boolean | - | false | -| stickyHeader | Show a sticky table header | boolean | - | false | -| striped | Whether table is striped | boolean | - |
From config:
table: {
  striped: false
}
| -| total | Total number of table data if backend-pagination is enabled | number | - | 0 | +| Prop name | Description | Type | Values | Default | +| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ariaCurrentLabel | Accessibility label for the pagination current page button. | string | - |
From config:
table: {
  ariaCurrentLabel: undefined
}
| +| ariaNextLabel | Accessibility label for the pagination next page button. | string | - |
From config:
table: {
  ariaNextLabel: undefined
}
| +| ariaPageLabel | Accessibility label for the pagination page button. | string | - |
From config:
table: {
  ariaPageLabel: undefined
}
| +| ariaPreviousLabel | Accessibility label for the pagination previous page button. | string | - |
From config:
table: {
  ariaPreviousLabel: undefined
}
| +| backendFiltering | Columns won't be filtered with Javascript, use with `searchable` prop to the columns to filter in your backend | boolean | - |
From config:
table: {
  backendFiltering: false
}
| +| backendPagination | Rows won't be paginated with Javascript, use with `page-change` event to paginate in your backend | boolean | - | false | +| backendSorting | Columns won't be sorted with Javascript, use with `sort` event to sort in your backend | boolean | - |
From config:
table: {
  backendSorting: false
}
| +| bordered | Border to all cells | boolean | - |
From config:
table: {
  bordered: false
}
| +| checkable | Rows can be checked (multiple) | boolean | - | false | +| checkboxPosition | Position of the checkbox when checkable (if checkable) | string | `left`, `right` |
From config:
table: {
  checkboxPosition: "left"
}
| +| checkboxVariant | Color of the checkbox when checkable (if checkable) | string | `primary`, `info`, `success`, `warning`, `danger`, `and any other custom color` |
From config:
table: {
  checkboxVariant: undefined
}
| +| checkedRows | Set which rows are checked, use `v-model:checkedRows` to make it two-way binding (if checkable) | T[] | - | Default function (see source code) | +| columns | Table columns | TableColumn[] | - | Default function (see source code) | +| currentPage | Current page of table data (if paginated), use `v-model:currentPage` to make it two-way binding | number | - | 1 | +| customCompare | Define a custom comparison function to check whether two row elements are equal.
By default a `rowKey` comparison is performed if given. Otherwise a simple object comparison is done. | (a: T, b: T) => boolean | - | | +| customDetailRow | Enable custom style on details (if detailed) | boolean | - | false | +| data | Table data | T[] | - | Default function (see source code) | +| debounceSearch | Filtering debounce time (in milliseconds) | number | - |
From config:
table: {
  debounceSearch: undefined
}
| +| defaultSort | Sets the default sort column and order — e.g. ['first_name', 'desc'] | string \| string[] | - |
From config:
table: {
  defaultSort: undefined
}
| +| defaultSortDirection | Sets the default sort column direction on the first click | string | `asc`, `desc` |
From config:
table: {
  defaultSortDirection: "asc"
}
| +| detailIcon | Icon name of detail action (if detailed) | string | - |
From config:
table: {
  detailIcon: "chevron-right"
}
| +| detailTransition | | string | - |
From config:
table: {
  detailTransition: "slide"
}
| +| detailed | Allow row details | boolean | - | false | +| detailedRows | Set which rows have opened details, use `v-model:detailedRows` to make it two-way binding (if detailed).
Ideal to open details via vue-router. (A unique key is required; check `rowKey` prop) | T[] | - | Default function (see source code) | +| draggable | Allows rows to be draggable | boolean | - | false | +| draggableColumn | Allows columns to be draggable | boolean | - | false | +| filtersEvent | Add a native event to filter | string | - | "" | +| filtersIcon | Icon of the column search input | string | - |
From config:
table: {
  filterIcon: undefined
}
| +| filtersPlaceholder | Placeholder of the column search input | string | - |
From config:
table: {
  filterPlaceholder: undefined
}
| +| headerCheckable | Show check/uncheck all checkbox in table header when checkable (if checkable) | boolean | - | true | +| height | Table fixed height | number\|string | - | | +| hoverable | Rows are highlighted when hovering | boolean | - |
From config:
table: {
  hoverable: false
}
| +| iconPack | Icon pack to use | string | `mdi`, `fa`, `fas and any other custom icon pack` |
From config:
table: {
  iconPack: undefined
}
| +| isDetailedVisible | Controls the visibility of the trigger that toggles the detailed rows (if detailed) | (row: T) => boolean | - |
From config:
table: {
  isDetailedVisible: (row) => true
}
| +| isRowCheckable | Custom method to verify if a row is checkable (if checkable) | (row: T) => boolean | - |
From config:
table: {
  isRowCheckable: (row) => true
}
| +| isRowChecked | Custom method to verify if a row is checked (if checkable). Useful for backend pagination. | (row: T, data: T[]) => boolean | - | | +| isRowSelectable | Custom method to verify if a row is selectable, works when is selectable | (row: T) => boolean | - | Default function (see source code) | +| loading | Enable loading state | boolean | - | false | +| loadingIcon | Icon for the loading state | string | - |
From config:
table: {
  loadingIcon: "loading"
}
| +| loadingLabel | Label for the loading state | string | - |
From config:
table: {
  loadingLabel: undefined
}
| +| mobileBreakpoint | Mobile breakpoint as max-width value | string | - |
From config:
table: {
  mobileBreakpoint: undefined
}
| +| mobileCards | Rows appears as cards on mobile (collapse rows) | boolean | - |
From config:
table: {
  mobileCards: true
}
| +| mobileSortPlaceholder | Select placeholder text when nothing is selected (if mobileCards) | string | - |
From config:
table: {
  mobileSortPlaceholder: undefined
}
| +| narrowed | Makes the cells narrower | boolean | - |
From config:
table: {
  narrowed: false
}
| +| override | Override existing theme classes completely | boolean | - | | +| paginated | Adds pagination to the table | boolean | - |
From config:
table: {
  paginated: false
}
| +| paginationOrder | Pagination buttons order (if paginated) | string | `centered`, `right`, `left` |
From config:
table: {
  paginationOrder: undefined
}
| +| paginationPosition | Pagination position (if paginated) | string | `bottom`, `top`, `both` |
From config:
table: {
  paginationPosition: "bottom"
}
| +| paginationRounded | Enable rounded pagination buttons (if paginated) | boolean | - |
From config:
table: {
  paginationRounded: false
}
| +| paginationSimple | Enable simple style pagination (if paginated) | boolean | - |
From config:
table: {
  paginationSimple: false
}
| +| paginationSize | Size of pagination (if paginated) | string | `small`, `medium`, `large` |
From config:
table: {
  paginationSize: "small"
}
| +| perPage | How many rows per page (if paginated) | number\|string | - |
From config:
table: {
  perPage: 20
}
| +| rowKey | Use a unique key of your data Object for each row. Useful if your data prop has dynamic indices. (id recommended) | string | - |
From config:
table: {
  rowKey: undefined
}
| +| scrollable | Add a horizontal scrollbar when table is too wide | boolean | - | | +| selectable | Table can be focused and user can select rows. Rows can be navigate with keyboard arrows and are highlighted when hovering. | boolean | - |
From config:
table: {
  selectable: false
}
| +| selected | Set which row is selected, use `v-model:selected` to make it two-way binding (if selectable) | T | - | | +| showDetailIcon | Allow detail icon and column to be visible (if detailed) | boolean | - |
From config:
table: {
  showDetailIcon: true
}
| +| showHeader | Show header | boolean | - |
From config:
table: {
  showHeader: true
}
| +| sortIcon | Sets the header sorting icon | string | - |
From config:
table: {
  sortIcon: "arrow-up"
}
| +| sortIconSize | Sets the size of the sorting icon | string | `small`, `medium`, `large` |
From config:
table: {
  sortIconSize: "small"
}
| +| stickyCheckbox | Make the checkbox column sticky (if checkable) | boolean | - | false | +| stickyHeader | Show a sticky table header | boolean | - | false | +| striped | Whether table is striped | boolean | - |
From config:
table: {
  striped: false
}
| +| tdAttrs | Adds native attributes to column td element of a row | (row: T, column: TableColumn<T>) => object | - | | +| thAttrs | Adds native attributes to a column th element | (column: TableColumn<T>) => object | - | | +| total | Total number of table data if backend-pagination is enabled | number | - | 0 | ### Events @@ -188,8 +190,8 @@ sidebarDepth: 2 | sortable | Enable column sortability | boolean | - | false | | sticky | Whether the column is sticky or not | boolean | - | false | | subheading | Define a column sub heading | string | - | | -| tdAttrs | Adds native attributes to td | (row: T, column: typeof props) => object | - | Default function (see source code) | -| thAttrs | Adds native attributes to th | (column: typeof props) => object | - | Default function (see source code) | +| tdAttrs | Adds native attributes to td | object | - | | +| thAttrs | Adds native attributes to th | object | - | | | visible | Define whether the column is visible or not | boolean | - | true | | width | Column fixed width | number\|string | - | | diff --git a/packages/oruga/src/components/pagination/Pagination.vue b/packages/oruga/src/components/pagination/Pagination.vue index 9ef9ae31f..5d6df57d5 100644 --- a/packages/oruga/src/components/pagination/Pagination.vue +++ b/packages/oruga/src/components/pagination/Pagination.vue @@ -424,7 +424,7 @@ defineExpose({ last, first, prev, next }); v-bind="getPage(currentPage - 1, ariaPreviousLabel)"> , default: "button" as DynamicComponent, }, - class: { type: Array as PropType, default: () => [] }, + rootClass: { type: Array as PropType, default: () => [] }, linkClass: { type: Array as PropType, required: true, @@ -36,8 +36,8 @@ const props = defineProps({ // --- Computed Component Classes --- const linkClasses = computed(() => [ + ...props.rootClass, ...props.linkClass, - ...props.class, ...(props.isCurrent ? props.linkCurrentClass : []), ]); diff --git a/packages/oruga/src/components/pagination/tests/__snapshots__/pagination.test.ts.snap b/packages/oruga/src/components/pagination/tests/__snapshots__/pagination.test.ts.snap index 1f0966660..15597f1c2 100644 --- a/packages/oruga/src/components/pagination/tests/__snapshots__/pagination.test.ts.snap +++ b/packages/oruga/src/components/pagination/tests/__snapshots__/pagination.test.ts.snap @@ -8,14 +8,14 @@ exports[`OPagination tests > render correctly 1`] = ` @binding {boolean} isCurrent - if page is current @binding {(event:Event): void} click - onClick handler @binding {string} ariaLabel - aria-label attribute - --> + --> + -->
    diff --git a/packages/oruga/src/components/table/Table.vue b/packages/oruga/src/components/table/Table.vue index 045e6c591..a79856410 100644 --- a/packages/oruga/src/components/table/Table.vue +++ b/packages/oruga/src/components/table/Table.vue @@ -79,6 +79,16 @@ const props = defineProps({ // eslint-disable-next-line @typescript-eslint/no-unused-vars getOption("table.rowClass", (row, index) => "")(row, index), }, + /** Adds native attributes to a column th element */ + thAttrs: { + type: Function as PropType<(column: TableColumn) => object>, + default: undefined, + }, + /** Adds native attributes to column td element of a row */ + tdAttrs: { + type: Function as PropType<(row: T, column: TableColumn) => object>, + default: undefined, + }, /** * Define a custom comparison function to check whether two row elements are equal. * By default a `rowKey` comparison is performed if given. Otherwise a simple object comparison is done. @@ -856,13 +866,18 @@ watch([visibleRows, visibleColumns], () => { if (visibleColumns.value.length && visibleRows.value.length) { for (let i = 0; i < visibleColumns.value.length; i++) { const col = visibleColumns.value[i]; - col.thAttrsData = - typeof col.thAttrs === "function" ? col.thAttrs(col) : {}; - col.tdAttrsData = visibleRows.value.map((data) => - typeof col.tdAttrs === "function" - ? col.tdAttrs(data.value, col) - : {}, - ); + // create additional th attrs data + const thAttrs = + typeof props.thAttrs === "function" ? props.thAttrs(col) : {}; + col.thAttrsData = Object.assign(thAttrs, col.thAttrs); + // create additional td attrs data + col.tdAttrsData = visibleRows.value.map((data) => { + const tdAttrs = + typeof props.tdAttrs === "function" + ? props.tdAttrs(data.value, col) + : {}; + return Object.assign(tdAttrs, col.tdAttrs); + }); } } }); diff --git a/packages/oruga/src/components/table/TableColumn.vue b/packages/oruga/src/components/table/TableColumn.vue index 695785fb7..3ad91acf3 100644 --- a/packages/oruga/src/components/table/TableColumn.vue +++ b/packages/oruga/src/components/table/TableColumn.vue @@ -1,5 +1,5 @@