diff --git a/src/components/base/table/table.scss b/src/components/base/table/table.scss index b9f89f7c02f65aa7668cb56d9fd2cff9ba503e71..40d5e35895f7f417d81bb011998914d6af01459e 100644 --- a/src/components/base/table/table.scss +++ b/src/components/base/table/table.scss @@ -27,9 +27,22 @@ table.gl-table { @include gl-focus; position: relative; z-index: 1; + background: $white; + + &:hover { + background: $gray-50; + } } } + // Sticky header + &--sticky-header thead tr { + position: sticky; + top: -1px; + background: $white; + box-shadow: inset 0 -1px 0 $gray-100; + } + .table-primary, .table-primary:hover { > td { diff --git a/src/components/base/table/table.spec.js b/src/components/base/table/table.spec.js index e760402cdd821d19402d52284cf67a3e39407d1e..ef3b0a049af48bf09ccdd3f280d7a11e3e8acf06 100644 --- a/src/components/base/table/table.spec.js +++ b/src/components/base/table/table.spec.js @@ -55,7 +55,17 @@ describe('GlTable', () => { it('adds gl-table class to tableClass prop', () => { factory({ props: { tableClass: 'test-class' } }); - expect(findBTable().props().tableClass).toEqual(['gl-table', 'test-class']); + expect(findBTable().props().tableClass).toEqual(['gl-table', 'test-class', null]); + }); + + it('adds sticky header class to tableClass prop', () => { + factory({ props: { stickyHeader: true } }); + + expect(findBTable().props().tableClass).toEqual([ + 'gl-table', + undefined, + 'gl-table--sticky-header', + ]); }); it('adds gl-table fields to table prop', () => { diff --git a/src/components/base/table/table.stories.js b/src/components/base/table/table.stories.js index 1bfc29cbc13166c6ba82e74c81fed72d6e0518c1..74413c58e4fb7fd6a3b6a695c6051b4e800b6fdd 100644 --- a/src/components/base/table/table.stories.js +++ b/src/components/base/table/table.stories.js @@ -20,11 +20,13 @@ const tableItems = [ ]; const generateProps = ({ + stickyHeader = false, fixed = false, footClone = false, stacked = false, caption = '', } = {}) => ({ + stickyHeader, fixed, footClone, stacked, @@ -36,6 +38,7 @@ export const Default = (args, { argTypes }) => ({ props: Object.keys(argTypes), template: ` ({
({ }); WithFilter.args = generateProps(); +export const WithStickyHeader = (args, { argTypes }) => ({ + components: { ...components, GlFormInput }, + props: Object.keys(argTypes), + template: `
+ +
+ +
`, + items: [ + ...tableItems, + ...tableItems, + ...tableItems, + ...tableItems, + ...tableItems, + ...tableItems, + ...tableItems, + ...tableItems, + ...tableItems, + ...tableItems, + ], + data() { + return { + filter: null, + }; + }, +}); +WithStickyHeader.args = generateProps({ stickyHeader: true }); + export default { title: 'base/table/table', component: GlTable, @@ -120,5 +163,9 @@ export default { options: ['sm', 'md', 'lg', 'xl', true, false], control: 'select', }, + stickyHeader: { + options: [false, true], + control: 'boolean', + }, }, }; diff --git a/src/components/base/table/table.vue b/src/components/base/table/table.vue index 62521d7987d572647a316dfd9eb053d7fbe10e6b..5f72755f5410091eec201ae12947fb0f61b60c52 100644 --- a/src/components/base/table/table.vue +++ b/src/components/base/table/table.vue @@ -26,10 +26,18 @@ export default { required: false, default: null, }, + stickyHeader: { + type: Boolean, + default: false, + required: false, + }, }, computed: { + stickyHeaderClass() { + return this.stickyHeader ? 'gl-table--sticky-header' : null; + }, localTableClass() { - return ['gl-table', this.tableClass]; + return ['gl-table', this.tableClass, this.stickyHeaderClass]; }, }, mounted() { diff --git a/src/components/base/table_lite/table_lite.spec.js b/src/components/base/table_lite/table_lite.spec.js index a4321055929d6f2a80ef30f521b1f1801164afc9..b642dd883a5a03d36fe929570fc7a58a80dfa5b4 100644 --- a/src/components/base/table_lite/table_lite.spec.js +++ b/src/components/base/table_lite/table_lite.spec.js @@ -16,7 +16,17 @@ describe('GlTableLite', () => { it('adds gl-table class to tableClass prop', () => { factory({ tableClass: 'test-class' }); - expect(findBTableLite().props().tableClass).toEqual(['gl-table', 'test-class']); + expect(findBTableLite().props().tableClass).toEqual(['gl-table', 'test-class', null]); + }); + + it('adds sticky header class to tableClass prop', () => { + factory({ stickyHeader: true }); + + expect(findBTableLite().props().tableClass).toEqual([ + 'gl-table', + undefined, + 'gl-table--sticky-header', + ]); }); it('adds gl-table fields to table prop', () => { diff --git a/src/components/base/table_lite/table_lite.stories.js b/src/components/base/table_lite/table_lite.stories.js index 7b4d03da104f6e2b1d16c52b6ff680e20e130efe..6672ac3f9b7c8fa9a79395702448ebe2ddee4aa6 100644 --- a/src/components/base/table_lite/table_lite.stories.js +++ b/src/components/base/table_lite/table_lite.stories.js @@ -31,7 +31,12 @@ const tableItemsMock = [ }, ]; -const generateProps = ({ items = tableItemsMock, fields = fieldsMock } = {}) => ({ +const generateProps = ({ + stickyHeader = false, + items = tableItemsMock, + fields = fieldsMock, +} = {}) => ({ + stickyHeader, items, fields, }); @@ -40,7 +45,8 @@ const Template = (args, { argTypes }) => ({ components: { GlTableLite }, props: Object.keys(argTypes), template: ` - `, @@ -59,5 +65,10 @@ export default { }, }, }, - argTypes: {}, + argTypes: { + stickyHeader: { + options: [false, true], + control: 'boolean', + }, + }, }; diff --git a/src/components/base/table_lite/table_lite.vue b/src/components/base/table_lite/table_lite.vue index 5186477354deb9aee40633946a3c0ebb4645aa54..df6814b23686fc76934ef99ae0cfe13b87048758 100644 --- a/src/components/base/table_lite/table_lite.vue +++ b/src/components/base/table_lite/table_lite.vue @@ -16,10 +16,18 @@ export default { required: false, default: null, }, + stickyHeader: { + type: Boolean, + default: false, + required: false, + }, }, computed: { + stickyHeaderClass() { + return this.stickyHeader ? 'gl-table--sticky-header' : null; + }, localTableClass() { - return ['gl-table', this.tableClass]; + return ['gl-table', this.tableClass, this.stickyHeaderClass]; }, }, }; diff --git a/tests/__image_snapshots__/storyshots-spec-js-image-storyshots-base-table-table-with-sticky-header-1-snap.png b/tests/__image_snapshots__/storyshots-spec-js-image-storyshots-base-table-table-with-sticky-header-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..39a2003eb2866820217459c79079c7b72a565177 Binary files /dev/null and b/tests/__image_snapshots__/storyshots-spec-js-image-storyshots-base-table-table-with-sticky-header-1-snap.png differ