Skip to content

Commit

Permalink
feat(table): BS V4.beta.2 New responsive breakpoints and table-dark c…
Browse files Browse the repository at this point in the history
…lass (#1222)

* fix(table): New responive breakpoints and table-dark class

V4.beta.2 adds responsive breakpoint support, and changes class `table-inverse` to `table-dark`

* docs(table): Updated docs

* [table] Updte tests

* Update README.md

* [table] Deprecated 'inverse' prop for new 'dark' prop

To align more closely with new class name

* update test fixture for 'dark' prop

* Update test spec for 'dark' prop

* Update table.vue

* Update table.vue

* Update readme with new `dark` prop

* ESlint fixes

* Update README.md

* Update table.spec.js

* Update demo.html

* Update table.vue

* Update table.vue
  • Loading branch information
tmorehouse committed Oct 23, 2017
1 parent c37cef4 commit febdfd1
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 48 deletions.
73 changes: 64 additions & 9 deletions docs/components/table/README.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -290,12 +290,15 @@ fields: [
| `bordered` | For borders on all sides of the table and cells. | `bordered` | For borders on all sides of the table and cells.
| `small` | To make tables more compact by cutting cell padding in half. | `small` | To make tables more compact by cutting cell padding in half.
| `hover` | To enable a hover highlighting state on table rows within a `<tbody>` | `hover` | To enable a hover highlighting state on table rows within a `<tbody>`
| `inverse` | Invert the colors — with light text on dark backgrounds | `dark` | Invert the colors — with light text on dark backgrounds (equivalent to Bootstrap V4 class `.table-dark`)
| `responsive` | Generate a responsive table to make it scroll horizontally on small devices (under 768px) | `responsive` | Generate a responsive table to make it scroll horizontally. Set to `true` for an always responsive table, or set it to one of the breakpoints `sm`, `md`, `lg`, or `xl` to make the table responsive (horizontally scroll) only on screens smaller than the breakpoint.
| `fixed` | Gnerate a table with equal fixed-width columns (`table-layout: fixed`) | `fixed` | Gnerate a table with equal fixed-width columns (`table-layout: fixed`)
| `foot-clone` | Turns on the table footer, and defaults with the same contents a the table header | `foot-clone` | Turns on the table footer, and defaults with the same contents a the table header
| `head-variant` | Use `default` or `inverse` to make table header appear light or dark gray, respectively | `head-variant` | Use `light` or `dark` to make table header appear light or dark gray, respectively
| `foot-variant` | Use `default` or `inverse` to make table footer appear light or dark gray, respectively. IF not set, used `head-variant`. Has no effect if `foot-clone` is not set | `foot-variant` | Use `light` or `dark` to make table footer appear light or dark gray, respectively. If not set, `head-variant` will be used. Has no effect if `foot-clone` is not set

**Deprecation note:** As of Bootstrap-Vue v1.0.0-beta.10, the prop `inverse` has been deprecated in
favour of prop `dark` to better align with Bootstrap V4.beta.2 CSS class names.


**Example: Bordered table** **Example: Bordered table**
```html ```html
Expand Down Expand Up @@ -341,10 +344,10 @@ export default {
<!-- table-small.vue --> <!-- table-small.vue -->
``` ```


**Example: Inverse table** **Example: Dark table**
```html ```html
<template> <template>
<b-table inverse :items="items" :fields="fields"></b-table> <b-table dark :items="items" :fields="fields"></b-table>
</template> </template>


<script> <script>
Expand Down Expand Up @@ -385,7 +388,59 @@ export default {
<!-- table-footer.vue --> <!-- table-footer.vue -->
``` ```


## Table `<caption>` ## Responsive tables
Responsive tables allow tables to be scrolled horizontally with ease. Make any table
responsive across all viewports by setting the prop `responsive` to `true`. Or, pick a
maximum breakpoint with which to have a responsive table up to by setting the prop
`responsive` to one of the breakpoint values: `sm`, `md`, `lg`, or `xl`.

**Note: Possible vertical clipping/truncation**

Responsive tables make use of `overflow-y: hidden`, which clips off any content that
goes beyond the bottom or top edges of the table. In particular, this can clip off
dropdown menus and other third-party widgets.

**Example: Always responsive table**
```html
<template>
<b-table responsive :items="items"></b-table>
</template>

<script>
export default {
data: {
items: [
{
'heading 1': 'table cell', 'heading 2': 'table cell',
'heading 3': 'table cell', 'heading 4': 'table cell',
'heading 5': 'table cell', 'heading 6': 'table cell',
'heading 7': 'table cell', 'heading 8': 'table cell',
'heading 9': 'table cell', 'heading 10': 'table cell'
},
{
'heading 1': 'table cell', 'heading 2': 'table cell',
'heading 3': 'table cell', 'heading 4': 'table cell',
'heading 5': 'table cell', 'heading 6': 'table cell',
'heading 7': 'table cell', 'heading 8': 'table cell',
'heading 9': 'table cell', 'heading 10': 'table cell'
},
{
'heading 1': 'table cell', 'heading 2': 'table cell',
'heading 3': 'table cell', 'heading 4': 'table cell',
'heading 5': 'table cell', 'heading 6': 'table cell',
'heading 7': 'table cell', 'heading 8': 'table cell',
'heading 9': 'table cell', 'heading 10': 'table cell'
}
]
}
};
</script>

<!-- table-responsive.vue -->
```


## Table caption
Add an optional caption to your table via the prop `caption` or the named Add an optional caption to your table via the prop `caption` or the named
slot `table-caption` (the slot takes precedence over the prop). The default slot `table-caption` (the slot takes precedence over the prop). The default
Bootstrap V4 styling places the caption at the bottom of the table. You can Bootstrap V4 styling places the caption at the bottom of the table. You can
Expand Down Expand Up @@ -416,11 +471,11 @@ export default {
<!-- table-caption.vue --> <!-- table-caption.vue -->
``` ```


## Table `<colgroup>` ## Table colgroup
Use the named slot `table-colgroup` to specify `<colgroup>` and `<col>` elements Use the named slot `table-colgroup` to specify `<colgroup>` and `<col>` elements
for optional grouping and styling of table columns. Note the styles available via `<col>` for optional grouping and styling of table columns. Note the styles available via `<col>`
elements are limited. Refer to [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup) elements are limited. Refer to [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup)
for details and usage. for details and usage of `<colgroup>`




## Custom Data Rendering ## Custom Data Rendering
Expand Down
52 changes: 32 additions & 20 deletions lib/components/table.vue
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@
</template> </template>


<script> <script>
import { warn, pluckProps, looseEqual } from '../utils'; import { warn, looseEqual } from '../utils';
import { keys, assign } from '../utils/object'; import { keys, assign } from '../utils/object';
import { isArray } from '../utils/array' import { isArray } from '../utils/array';
import { listenOnRootMixin } from '../mixins'; import { listenOnRootMixin } from '../mixins';
import startCase from 'lodash.startcase'; import startCase from 'lodash.startcase';
Expand All @@ -148,7 +148,7 @@ function recToString(obj) {
return toString(keys(obj).reduce((o, k) => { return toString(keys(obj).reduce((o, k) => {
// Ignore fields that start with _ // Ignore fields that start with _
if (!/^_/.test(k)) { if (!(/^_/).test(k)) {
o[k] = obj[k]; o[k] = obj[k];
} }
return o; return o;
Expand All @@ -168,16 +168,16 @@ function processField(key, value) {
let field = null; let field = null;
if (typeof value === 'string') { if (typeof value === 'string') {
// Label shortcut // Label shortcut
field = { key: key, label: value }; field = { key, label: value };
} else if (typeof value === 'function') { } else if (typeof value === 'function') {
// Formatter shortcut // Formatter shortcut
field = { key: key, formatter: value }; field = { key, formatter: value };
} else if (typeof value === 'object') { } else if (typeof value === 'object') {
field = assign({}, value); field = assign({}, value);
field.key = field.key || key; field.key = field.key || key;
} else if (value !== false) { } else if (value !== false) {
// Fallback to just key // Fallback to just key
field = { key: key }; field = { key };
} }
return field; return field;
} }
Expand Down Expand Up @@ -233,9 +233,21 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
dark: {
type: Boolean,
default() {
if (this && typeof this.inverse === 'boolean') {
// Deprecate inverse
warn("b-table: prop 'inverse' has been deprecated. Use 'dark' instead");
return this.bark;
}
return false;
}
},
inverse: { inverse: {
// Deprecated in v1.0.0.beta.10 in favor of `dark`
type: Boolean, type: Boolean,
default: false default: null
}, },
hover: { hover: {
type: Boolean, type: Boolean,
Expand All @@ -246,7 +258,7 @@ export default {
default: false default: false
}, },
responsive: { responsive: {
type: Boolean, type: [Boolean, String],
default: false default: false
}, },
fixed: { fixed: {
Expand Down Expand Up @@ -333,7 +345,7 @@ export default {
} }
}, },
context(newVal, oldVal) { context(newVal, oldVal) {
if(!looseEqual(newVal, oldVal)) { if (!looseEqual(newVal, oldVal)) {
this.$emit('context-changed', newVal); this.$emit('context-changed', newVal);
} }
}, },
Expand Down Expand Up @@ -408,14 +420,15 @@ export default {
}, },
computed: { computed: {
tableClasses() { tableClasses() {
const responsive = this.responsive === '' ? true : this.responsive;
return [ return [
'table', 'table',
'b-table', 'b-table',
this.striped ? 'table-striped' : '', this.striped ? 'table-striped' : '',
this.hover ? 'table-hover' : '', this.hover ? 'table-hover' : '',
this.inverse ? 'table-inverse' : '', this.dark ? 'table-dark' : '',
this.bordered ? 'table-bordered' : '', this.bordered ? 'table-bordered' : '',
this.responsive ? 'table-responsive' : '', responsive === true ? 'table-responsive' : (Boolean(responsive) ? `table-responsive-${responsive}` : ''),
this.fixed ? 'table-fixed' : '', this.fixed ? 'table-fixed' : '',
this.small ? 'table-sm' : '' this.small ? 'table-sm' : ''
]; ];
Expand Down Expand Up @@ -470,11 +483,11 @@ export default {
fields.push(field); fields.push(field);
} }
} }
}) });
} else if (this.fields && typeof this.fields === 'object' && keys(this.fields).length > 0) { } else if (this.fields && typeof this.fields === 'object' && keys(this.fields).length > 0) {
// Normalize object Form // Normalize object Form
keys(this.fields).forEach(key => { keys(this.fields).forEach(key => {
let field = processField(key, this.fields[key]) let field = processField(key, this.fields[key]);
if (field) { if (field) {
fields.push(field); fields.push(field);
} }
Expand All @@ -483,7 +496,7 @@ export default {
// If no field provided, take a sample from first record (if exits) // If no field provided, take a sample from first record (if exits)
if (fields.length === 0 && this.computedItems.length > 0) { if (fields.length === 0 && this.computedItems.length > 0) {
const sample = this.computedItems[0] const sample = this.computedItems[0];
keys(sample).forEach(k => { keys(sample).forEach(k => {
fields.push({ key: k , label: startCase(k)}); fields.push({ key: k , label: startCase(k)});
}); });
Expand All @@ -496,9 +509,8 @@ export default {
memo[f.key] = true; memo[f.key] = true;
f.label = f.label || startCase(f.key); f.label = f.label || startCase(f.key);
return true; return true;
} else {
return false;
} }
return false;
}); });
}, },
computedItems() { computedItems() {
Expand Down Expand Up @@ -591,18 +603,18 @@ export default {
tdClasses(field, item) { tdClasses(field, item) {
let cellVariant = ''; let cellVariant = '';
if (item._cellVariants && item._cellVariants[field.key]) { if (item._cellVariants && item._cellVariants[field.key]) {
cellVariant = (this.inverse ? 'bg-' : 'table-') + item._cellVariants[field.key]; cellVariant = `${this.dark ? 'bg' : 'table'}-${item._cellVariants[field.key]}`;
} }
return [ return [
(field.variant && !cellVariant) ? ((this.inverse ? 'bg-' : 'table-') + field.variant) : '', (field.variant && !cellVariant) ? `${this.dark ? 'bg' : 'table'}-${field.variant}` : '',
cellVariant, cellVariant,
field.class ? field.class : '', field.class ? field.class : '',
field.tdClass ? field.tdClass : '' field.tdClass ? field.tdClass : ''
]; ];
}, },
rowClasses(item) { rowClasses(item) {
return [ return [
item._rowVariant ? ((this.inverse ? 'bg-' : 'table-') + item._rowVariant) : '' item._rowVariant ? `${this.dark ? 'bg' : 'table'}-${item._rowVariant}` : ''
]; ];
}, },
rowClicked(e, item, index) { rowClicked(e, item, index) {
Expand Down Expand Up @@ -713,7 +725,7 @@ export default {
return value; return value;
} }
} }
} };
</script> </script>


<style> <style>
Expand Down
28 changes: 14 additions & 14 deletions tests/components/table.spec.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ describe("table", async () => {
"table-responsive" "table-responsive"
]); ]);


expect($refs.table_inverse).toHaveAllClasses([ expect($refs.table_dark).toHaveAllClasses([
"table", "table",
"b-table", "b-table",
"table-sm", "table-sm",
"table-bordered", "table-bordered",
"table-inverse" "table-dark"
]); ]);
}); });


Expand Down Expand Up @@ -58,10 +58,10 @@ describe("table", async () => {
expect(tfoot).toBeDefined(); expect(tfoot).toBeDefined();
}); });


it("table_inverse should have thead and tbody", async () => { it("table_dark should have thead and tbody", async () => {
const { app: { $refs, $el } } = window; const { app: { $refs, $el } } = window;


const parts = [...$refs.table_inverse.$el.children]; const parts = [...$refs.table_dark.$el.children];


const thead = parts.find(el => el.tagName && el.tagName === "THEAD"); const thead = parts.find(el => el.tagName && el.tagName === "THEAD");
expect(thead).toBeDefined(); expect(thead).toBeDefined();
Expand All @@ -73,28 +73,28 @@ describe("table", async () => {
expect(tfoot).not.toBeDefined(); expect(tfoot).not.toBeDefined();
}); });


it("table_paginated thead should contain class thead-inverse", async () => { it("table_paginated thead should contain class thead-dark", async () => {
const { app: { $refs, $el } } = window; const { app: { $refs, $el } } = window;
const thead = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "THEAD"); const thead = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "THEAD");
expect(thead).toBeDefined(); expect(thead).toBeDefined();
if (thead) { if (thead) {
expect(thead.classList.contains("thead-inverse")).toBe(true); expect(thead.classList.contains("thead-dark")).toBe(true);
} }
}); });


it("table_paginated tfoot should contain class thead-default", async () => { it("table_paginated tfoot should contain class thead-light", async () => {
const { app: { $refs, $el } } = window; const { app: { $refs, $el } } = window;
const tfoot = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "TFOOT"); const tfoot = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "TFOOT");
expect(tfoot).toBeDefined(); expect(tfoot).toBeDefined();
if (tfoot) { if (tfoot) {
expect(tfoot.classList.contains("thead-default")).toBe(true); expect(tfoot.classList.contains("thead-light")).toBe(true);
} }
}); });


it("all examples have correct number of columns", async () => { it("all examples have correct number of columns", async () => {
const { app: { $refs, $el } } = window; const { app: { $refs, $el } } = window;


const tables = ["table_basic", "table_paginated", "table_inverse"]; const tables = ["table_basic", "table_paginated", "table_dark"];


tables.forEach((table, idx) => { tables.forEach((table, idx) => {
const vm = $refs[table]; const vm = $refs[table];
Expand All @@ -114,7 +114,7 @@ describe("table", async () => {
const { app: { $refs, $el } } = window; const { app: { $refs, $el } } = window;
const app = window.app; const app = window.app;


const tables = ["table_basic", "table_paginated", "table_inverse"]; const tables = ["table_basic", "table_paginated", "table_dark"];


tables.forEach((table, idx) => { tables.forEach((table, idx) => {
const vm = $refs[table]; const vm = $refs[table];
Expand All @@ -129,7 +129,7 @@ describe("table", async () => {
it("all examples have sortable & unsortable headers", async () => { it("all examples have sortable & unsortable headers", async () => {
const { app: { $refs, $el } } = window; const { app: { $refs, $el } } = window;


const tables = ["table_basic", "table_paginated", "table_inverse"]; const tables = ["table_basic", "table_paginated", "table_dark"];
const sortables = [true, true, false, false]; const sortables = [true, true, false, false];


tables.forEach(table => { tables.forEach(table => {
Expand Down Expand Up @@ -174,7 +174,7 @@ describe("table", async () => {
it('all example tables should have attribute aria-busy="false" when busy is false', async () => { it('all example tables should have attribute aria-busy="false" when busy is false', async () => {
const { app: { $refs, $el } } = window; const { app: { $refs, $el } } = window;


const tables = ["table_basic", "table_paginated", "table_inverse"]; const tables = ["table_basic", "table_paginated", "table_dark"];


await setData(app, "isBusy", false); await setData(app, "isBusy", false);
await nextTick(); await nextTick();
Expand Down Expand Up @@ -239,7 +239,7 @@ describe("table", async () => {
const { app: { $refs, $el } } = window; const { app: { $refs, $el } } = window;
const app = window.app; const app = window.app;


const tables = ["table_basic", "table_paginated", "table_inverse"]; const tables = ["table_basic", "table_paginated", "table_dark"];


const items = app.items.slice(); const items = app.items.slice();
items[0]._rowVariant = "success"; items[0]._rowVariant = "success";
Expand All @@ -252,7 +252,7 @@ describe("table", async () => {
expect(tbody).toBeDefined(); expect(tbody).toBeDefined();
if (tbody) { if (tbody) {
const tr = tbody.children[0]; const tr = tbody.children[0];
const variant = vm.inverse ? "bg-success" : "table-success"; const variant = vm.dark ? "bg-success" : "table-success";
expect(Boolean(tr) && Boolean(tr.classList) && tr.classList.contains(variant)).toBe(true); expect(Boolean(tr) && Boolean(tr.classList) && tr.classList.contains(variant)).toBe(true);
} }
}); });
Expand Down
Loading

0 comments on commit febdfd1

Please sign in to comment.