Skip to content
Permalink
Browse files

feat(b-table): new sorting icons using SVG, plus option to place icon…

… on left of header cell (closes #3687, #3696, #3918, #3966) (#3968)
  • Loading branch information...
tmorehouse committed Aug 29, 2019
1 parent ee13491 commit c4442f4c41231b6c5514e8ff37002088a1d15f9d
@@ -65,11 +65,17 @@ $b-custom-file-height-inner-sm: calc(
$b-table-busy-opacity: 0.55 !default;

// Table sorting
$b-table-sort-icon-null: "\2195" !default; // Up-Down arrow
$b-table-sort-icon-ascending: "\2193" !default; // Down arrow
$b-table-sort-icon-descending: "\2191" !default; // Up arrow
$b-table-sort-icon-margin-left: 0.5em !default;
$b-table-sort-icon-width: 0.5em !default;
$b-table-sort-icon-bg-width: 0.65em !default;
$b-table-sort-icon-bg-height: 1em !default;
// Sort icons are square, but "squished" horizontally by the above variables
$b-table-sort-icon-bg-not-sorted: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'><path fill='black' opacity='.3' d='M51 1l25 23 24 22H1l25-22zM51 101l25-23 24-22H1l25 22z'/></svg>") !default;
$b-table-sort-icon-bg-ascending: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'><path fill='black' d='M51 1l25 23 24 22H1l25-22z'/><path fill='black' opacity='.3' d='M51 101l25-23 24-22H1l25 22z'/></svg>") !default;
$b-table-sort-icon-bg-descending: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'><path fill='black' opacity='.3' d='M51 1l25 23 24 22H1l25-22z'/><path fill='black' d='M51 101l25-23 24-22H1l25 22z'/></svg>") !default;
// Icons to use on dark table or dark header/footer (lighter color icons)
// We simply just replace the fill color 'black' white 'white'
$b-table-sort-icon-bg-dark-not-sorted: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'><path fill='white' opacity='.3' d='M51 1l25 23 24 22H1l25-22zM51 101l25-23 24-22H1l25 22z'/></svg>") !default;
$b-table-sort-icon-bg-dark-ascending: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'><path fill='white' d='M51 1l25 23 24 22H1l25-22z'/><path fill='white' opacity='.3' d='M51 101l25-23 24-22H1l25 22z'/></svg>") !default;
$b-table-sort-icon-bg-dark-descending: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='101' height='101' view-box='0 0 101 101' preserveAspectRatio='none'><path fill='white' opacity='.3' d='M51 1l25 23 24 22H1l25-22z'/><path fill='white' d='M51 101l25-23 24-22H1l25 22z'/></svg>") !default;

// Flag to enable sticky table header and column CSS generation
$bv-enable-table-sticky: true !default;
@@ -1658,21 +1658,20 @@ rows.
## Sorting

As mentioned in the [Fields](#fields-column-definitions) section above, you can make columns
sortable. Clicking on a sortable column header will sort the column in ascending direction (smallest
first), while clicking on it again will switch the direction of sorting. Clicking on a non-sortable
column will clear the sorting. The prop `no-sort-reset` can be used to disable this feature.
sortable in `<b-table>`. Clicking on a sortable column header will sort the column in ascending
direction (smallest first), while clicking on it again will switch the direction of sorting to
descending (largest first). Clicking on a non-sortable column will clear the sorting (the prop
`no-sort-reset` can be used to disable this feature).

You can control which column is pre-sorted and the order of sorting (ascending or descending). To
pre-specify the column to be sorted, set the `sort-by` prop to the field's key. Set the sort
direction by setting `sort-desc` to either `true` (for descending) or `false` (for ascending, the
default).

- **Ascending**: Items are sorted lowest to highest (i.e. `A` to `Z`) and will be displayed with the
lowest value in the first row with progressively higher values in the following rows. The header
indicator arrow will point in the direction of lowest to highest. (i.e. down for ascending).
lowest value in the first row with progressively higher values in the following rows.
- **Descending**: Items are sorted highest to lowest (i.e. `Z` to `A`) and will be displayed with
the highest value in the first row with progressively lower values in the following rows. The
header indicator arrow will point in the direction of lowest to highest (i.e. up for descending).
the highest value in the first row with progressively lower values in the following rows.

The props `sort-by` and `sort-desc` can be turned into _two-way_ (syncable) props by adding the
`.sync` modifier. Your bound variables will then be updated accordingly based on the current sort
@@ -1730,6 +1729,63 @@ clicks in the footer, set the `no-footer-sorting` prop to true.
<!-- b-table-sorting.vue -->
```

### Sort icon alignment

By default the sorting icons appear right aligned in the header cell. You can change the icons to be
left aligned by setting the prop `sort-icon-left` on `<b-table>`.

```html
<template>
<div>
<b-table
:items="items"
:fields="fields"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
sort-icon-left
responsive="sm"
></b-table>

<div>
Sorting By: <b>{{ sortBy }}</b>, Sort Direction:
<b>{{ sortDesc ? 'Descending' : 'Ascending' }}</b>
</div>
</div>
</template>

<script>
export default {
data() {
return {
sortBy: 'age',
sortDesc: false,
fields: [
{ key: 'last_name', sortable: true },
{ key: 'first_name', sortable: true },
{ key: 'age', sortable: true },
{ key: 'isActive', sortable: false }
],
items: [
{ isActive: true, age: 40, first_name: 'Dickerson', last_name: 'Macdonald' },
{ isActive: false, age: 21, first_name: 'Larsen', last_name: 'Shaw' },
{ isActive: false, age: 89, first_name: 'Geneva', last_name: 'Wilson' },
{ isActive: true, age: 38, first_name: 'Jami', last_name: 'Carney' }
]
}
}
}
</script>

<!-- b-table-sorting-left.vue -->
```

### Customizing the sort icons

The sorting icons are generated via the use of SVG background images. The icons can be altered by
updating SASS/SCSS variables and recompiling the SCSS source code. Refer to the
[theming](/docs/reference/theming) section for details on customizing Bootstrap and BootstrapVue's
CSS.

### Sort-compare routine

The internal built-in default `sort-compare` function sorts the specified field `key` based on the
@@ -185,40 +185,108 @@

// --- Header sort styling ---

// Bootstrap v4.4 will include this variable as `$escaped-characters`
// But if we want to preserve backwards compatibility with v4.3, we leave this in
$bv-escaped-characters: (("<", "%3c"), (">", "%3e"), ("#", "%23"));

// Bootstrap v4.4 will include this method as `escape-svg`
// But if we want to preserve backwards compatibility with v4.3, we leave this in
// See https://codepen.io/kevinweber/pen/dXWoRw
@function bv-escape-svg($string) {
@if str-index($string, "data:image/svg+xml") {
@each $char, $encoded in $bv-escaped-characters {
$string: str-replace($string, $char, $encoded);
}
}

@return $string;
}

.table.b-table {
> thead,
> tfoot {
> tr {
> th {
&[aria-sort] {
// `&.sorting`
cursor: pointer;

// Up/down `sort=null` indicator
&::before {
float: right;
margin-left: $b-table-sort-icon-margin-left;
width: $b-table-sort-icon-width;
font-size: inherit;
line-height: inherit;
opacity: 0.4;
content: $b-table-sort-icon-null; // Up/down arrow
speak: none;
}
> [aria-sort] {
cursor: pointer;
background-image: none;
background-repeat: no-repeat;
background-size: $b-table-sort-icon-bg-width $b-table-sort-icon-bg-height;

&:not(.b-table-sort-icon-left) {
// Default is icon on the right
background-position: right calc(#{$table-cell-padding} / 2) center;
padding-right: calc(#{$table-cell-padding} + #{$b-table-sort-icon-bg-width});
}

// Ascending indicator
&[aria-sort="ascending"]::before {
// `&.sorting_asc::after.sorting_asc`
opacity: 1;
content: $b-table-sort-icon-ascending; // Down arrow
}
&.b-table-sort-icon-left {
// Left aligned sort icon
background-position: left calc(#{$table-cell-padding} / 2) center;
padding-left: calc(#{$table-cell-padding} + #{$b-table-sort-icon-bg-width});
}
}

// Descending indicator
&[aria-sort="descending"]::before {
// `&.sorting_desc::after`
opacity: 1;
content: $b-table-sort-icon-descending; // Up arrow
}
> [aria-sort="none"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-not-sorted);
}

> [aria-sort="ascending"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-ascending);
}

> [aria-sort="descending"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-descending);
}
}
}

// Sort icons for dark tables, headers, footers
&.table-dark > thead > tr,
&.table-dark > tfoot > tr,
> .thead-dark > tr {
> [aria-sort="none"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-dark-not-sorted);
}

> [aria-sort="ascending"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-dark-ascending);
}

> [aria-sort="descending"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-dark-descending);
}
}

// Sort icons when header cell has `table-dark` class
> thead > tr > .table-dark,
> tfoot > tr > .table-dark {
&[aria-sort="none"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-dark-not-sorted);
}

&[aria-sort="ascending"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-dark-ascending);
}

&[aria-sort="descending"] {
background-image: bv-escape-svg($b-table-sort-icon-bg-dark-descending);
}
}

// Padding and position adjustment for small tables
&.table-sm {
> thead,
> tfoot {
> tr > [aria-sort] {
&:not(.b-table-sort-icon-left) {
// Default is icon on the right
background-position: right calc(#{$table-cell-padding-sm} / 2) center;
padding-right: calc(#{$table-cell-padding-sm} + #{$b-table-sort-icon-bg-width});
}

&.b-table-sort-icon-left {
// Left aligned sort icon
background-position: left calc(#{$table-cell-padding-sm} / 2) center;
padding-left: calc(#{$table-cell-padding-sm} + #{$b-table-sort-icon-bg-width});
}
}
}
@@ -73,6 +73,11 @@ export default {
noFooterSorting: {
type: Boolean,
default: false
},
sortIconLeft: {
// Place the sorting icon on the left of the header cells
type: Boolean,
default: false
}
},
data() {
@@ -226,8 +231,9 @@ export default {
// methods to compute classes and attrs for thead>th cells
sortTheadThClasses(key, field, isFoot) {
return {
// No Classes for sorting currently...
// All styles targeted using aria-* attrs
// If sortable and sortIconLeft are true, then place sort icon on the left
'b-table-sort-icon-left':
field.sortable && this.sortIconLeft && !(isFoot && this.noFooterSorting)
}
},
sortTheadThAttrs(key, field, isFoot) {

0 comments on commit c4442f4

Please sign in to comment.
You can’t perform that action at this time.