diff --git a/playbook/app/pb_kits/playbook/pb_table/_table.tsx b/playbook/app/pb_kits/playbook/pb_table/_table.tsx index 2ada123f1d..8430cfc05c 100755 --- a/playbook/app/pb_kits/playbook/pb_table/_table.tsx +++ b/playbook/app/pb_kits/playbook/pb_table/_table.tsx @@ -29,6 +29,7 @@ type TableProps = { size?: "sm" | "md" | "lg", sticky?: boolean, stickyLeftcolumn?: string[], + stickyRightcolumn?: string[], striped?: boolean, tag?: "table" | "div", verticalBorder?: boolean, @@ -53,6 +54,7 @@ const Table = (props: TableProps): React.ReactElement => { size = 'sm', sticky = false, stickyLeftcolumn = [], + stickyRightcolumn= [], striped = false, tag = 'table', verticalBorder = false, @@ -80,6 +82,7 @@ const Table = (props: TableProps): React.ReactElement => { 'no-hover': disableHover, 'sticky-header': sticky, 'sticky-left-column': stickyLeftcolumn, + 'sticky-right-column': stickyRightcolumn, 'striped': striped, [outerPaddingCss]: outerPadding !== '', }, @@ -90,7 +93,8 @@ const Table = (props: TableProps): React.ReactElement => { ) useEffect(() => { - const handleStickyColumns = () => { + const handleStickyLeftColumns = () => { + if (!stickyLeftcolumn.length) return; let accumulatedWidth = 0; stickyLeftcolumn.forEach((colId, index) => { @@ -103,11 +107,11 @@ const Table = (props: TableProps): React.ReactElement => { (header as HTMLElement).style.left = `${accumulatedWidth}px`; if (!isLastColumn) { - header.classList.add('with-border'); - header.classList.remove('sticky-shadow'); + header.classList.add('with-border-right'); + header.classList.remove('sticky-left-shadow'); } else { - header.classList.remove('with-border'); - header.classList.add('sticky-shadow'); + header.classList.remove('with-border-right'); + header.classList.add('sticky-left-shadow'); } accumulatedWidth += (header as HTMLElement).offsetWidth; @@ -118,27 +122,78 @@ const Table = (props: TableProps): React.ReactElement => { (cell as HTMLElement).style.left = `${accumulatedWidth - (header as HTMLElement).offsetWidth}px`; if (!isLastColumn) { - cell.classList.add('with-border'); - cell.classList.remove('sticky-shadow'); + cell.classList.add('with-border-right'); + cell.classList.remove('sticky-left-shadow'); } else { - cell.classList.remove('with-border'); - cell.classList.add('sticky-shadow'); + cell.classList.remove('with-border-right'); + cell.classList.add('sticky-left-shadow'); } }); }); }; setTimeout(() => { - handleStickyColumns(); + handleStickyLeftColumns(); }, 10); - window.addEventListener('resize', handleStickyColumns); + window.addEventListener('resize', handleStickyLeftColumns); return () => { - window.removeEventListener('resize', handleStickyColumns); + window.removeEventListener('resize', handleStickyLeftColumns); }; }, [stickyLeftcolumn]); + useEffect(() => { + const handleStickyRightColumns = () => { + if (!stickyRightcolumn.length) return; + let accumulatedWidth = 0; + + stickyRightcolumn.reverse().forEach((colId, index) => { + const isLastColumn = index === stickyRightcolumn.length - 1; + const header = document.querySelector(`th[id="${colId}"]`); + const cells = document.querySelectorAll(`td[id="${colId}"]`); + + if (header) { + header.classList.add('sticky'); + (header as HTMLElement).style.right = `${accumulatedWidth}px`; + + if (!isLastColumn) { + header.classList.add('with-border-left'); + header.classList.remove('sticky-right-shadow'); + } else { + header.classList.remove('with-border-left'); + header.classList.add('sticky-right-shadow'); + } + + accumulatedWidth += (header as HTMLElement).offsetWidth; + } + + cells.forEach((cell) => { + cell.classList.add('sticky'); + (cell as HTMLElement).style.right = `${accumulatedWidth - (header as HTMLElement).offsetWidth}px`; + + if (!isLastColumn) { + cell.classList.add('with-border-left'); + cell.classList.remove('sticky-right-shadow'); + } else { + cell.classList.remove('with-border-left'); + cell.classList.add('sticky-right-shadow'); + } + }); + }); + }; + + setTimeout(() => { + handleStickyRightColumns(); + }, 10); + + window.addEventListener('resize', handleStickyRightColumns); + + return () => { + window.removeEventListener('resize', handleStickyRightColumns); + }; + }, [stickyRightcolumn]); + useEffect(() => { const instance = new PbTable() instance.connect() diff --git a/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns.jsx b/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns.jsx new file mode 100644 index 0000000000..c28d352088 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns.jsx @@ -0,0 +1,87 @@ +import React from 'react' +import Table from '../_table' + +const TableStickyLeftColumns = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{'Column 1'}{'Column 2'}{'Column 3'}{'Column 4'}{'Column 5'}{'Column 6'}{'Column 7'}{'Column 8'}{'Column 9'}{'Column 10'}{'Column 11'}{'Column 12'}{'Column 13'}{'Column 14'}{'Column 15'}
{'Value 1'}{'Value 2'}{'Value 3'}{'Value 4'}{'Value 5'}{'Value 6'}{'Value 7'}{'Value 8'}{'Value 9'}{'Value 10'}{'Value 11'}{'Value 12'}{'Value 13'}{'Value 14'}{'Value 15'}
{'Value 1'}{'Value 2'}{'Value 3'}{'Value 4'}{'Value 5'}{'Value 6'}{'Value 7'}{'Value 8'}{'Value 9'}{'Value 10'}{'Value 11'}{'Value 12'}{'Value 13'}{'Value 14'}{'Value 15'}
{'Value 1'}{'Value 2'}{'Value 3'}{'Value 4'}{'Value 5'}{'Value 6'}{'Value 7'}{'Value 8'}{'Value 9'}{'Value 10'}{'Value 11'}{'Value 12'}{'Value 13'}{'Value 14'}{'Value 15'}
+ ) +} + +export default TableStickyLeftColumns \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns_react.md b/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns_react.md new file mode 100644 index 0000000000..3d8b9bb4cc --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_right_columns_react.md @@ -0,0 +1,2 @@ +The `stickyRightColumn` prop works in the same way as the above `stickyLeftColumn` prop. It expects an array of the column ids you want to be sticky. Make sure to add the corresponding id to the `` and ``. +If you are using the sub-component variant, then you will pass the id to `` and `` \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_table/docs/example.yml b/playbook/app/pb_kits/playbook/pb_table/docs/example.yml index 74f44bf963..56f38d24ec 100755 --- a/playbook/app/pb_kits/playbook/pb_table/docs/example.yml +++ b/playbook/app/pb_kits/playbook/pb_table/docs/example.yml @@ -35,6 +35,7 @@ examples: - table_lg: Large - table_sticky: Sticky Header - table_sticky_left_columns: Sticky Left Column + - table_sticky_right_columns: Sticky Right Column - table_alignment_row: Row Alignment - table_alignment_column: Cell Alignment - table_alignment_shift_row: Row Shift diff --git a/playbook/app/pb_kits/playbook/pb_table/docs/index.js b/playbook/app/pb_kits/playbook/pb_table/docs/index.js index 3449748f40..bece0a85d6 100755 --- a/playbook/app/pb_kits/playbook/pb_table/docs/index.js +++ b/playbook/app/pb_kits/playbook/pb_table/docs/index.js @@ -26,6 +26,7 @@ export { default as TableWithSubcomponents } from './_table_with_subcomponents.j export { default as TableWithSubcomponentsAsDivs } from './_table_with_subcomponents_as_divs.jsx' export { default as TableOuterPadding } from './_table_outer_padding.jsx' export { default as TableStickyLeftColumns } from './_table_sticky_left_columns.jsx' +export { default as TableStickyRightColumns } from './_table_sticky_right_columns.jsx' export { default as TableWithCollapsible } from './_table_with_collapsible.jsx' export { default as TableWithCollapsibleWithCustomContent } from './_table_with_collapsible_with_custom_content.jsx' export { default as TableWithCollapsibleWithNestedTable } from './_table_with_collapsible_with_nested_table.jsx' diff --git a/playbook/app/pb_kits/playbook/pb_table/index.ts b/playbook/app/pb_kits/playbook/pb_table/index.ts index 9022dcf07b..2d03b2e9f1 100644 --- a/playbook/app/pb_kits/playbook/pb_table/index.ts +++ b/playbook/app/pb_kits/playbook/pb_table/index.ts @@ -2,7 +2,7 @@ import PbEnhancedElement from '../pb_enhanced_element' export default class PbTable extends PbEnhancedElement { private stickyLeftColumns: string[] = []; - private handleStickyColumnsRef: () => void; + private handleStickyLeftColumnsRef: () => void; static get selector(): string { return '.table-responsive-collapse' @@ -31,10 +31,10 @@ export default class PbTable extends PbEnhancedElement { }); // New sticky columns logic - this.initStickyColumns(); + this.initStickyLeftColumns(); } - private initStickyColumns(): void { + private initStickyLeftColumns(): void { // Find tables with sticky-left-column class const tables = document.querySelectorAll('.sticky-left-column'); @@ -52,16 +52,16 @@ export default class PbTable extends PbEnhancedElement { if (this.stickyLeftColumns.length > 0) { setTimeout(() => { - this.handleStickyColumnsRef = this.handleStickyColumns.bind(this); - this.handleStickyColumns(); - window.addEventListener('resize', this.handleStickyColumnsRef); + this.handleStickyLeftColumnsRef = this.handleStickyLeftColumns.bind(this); + this.handleStickyLeftColumns(); + window.addEventListener('resize', this.handleStickyLeftColumnsRef); }, 10); } } }); } - private handleStickyColumns(): void { + private handleStickyLeftColumns(): void { let accumulatedWidth = 0; this.stickyLeftColumns.forEach((colId, index) => { @@ -74,11 +74,11 @@ export default class PbTable extends PbEnhancedElement { (header as HTMLElement).style.left = `${accumulatedWidth}px`; if (!isLastColumn) { - header.classList.add('with-border'); - header.classList.remove('sticky-shadow'); + header.classList.add('with-border-right'); + header.classList.remove('sticky-left-shadow'); } else { - header.classList.remove('with-border'); - header.classList.add('sticky-shadow'); + header.classList.remove('with-border-right'); + header.classList.add('sticky-left-shadow'); } accumulatedWidth += (header as HTMLElement).offsetWidth; @@ -89,11 +89,11 @@ export default class PbTable extends PbEnhancedElement { (cell as HTMLElement).style.left = `${accumulatedWidth - (header as HTMLElement).offsetWidth}px`; if (!isLastColumn) { - cell.classList.add('with-border'); - cell.classList.remove('sticky-shadow'); + cell.classList.add('with-border-right'); + cell.classList.remove('sticky-left-shadow'); } else { - cell.classList.remove('with-border'); - cell.classList.add('sticky-shadow'); + cell.classList.remove('with-border-right'); + cell.classList.add('sticky-left-shadow'); } }); }); @@ -101,8 +101,8 @@ export default class PbTable extends PbEnhancedElement { // Cleanup method to remove event listener disconnect(): void { - if (this.handleStickyColumnsRef) { - window.removeEventListener('resize', this.handleStickyColumnsRef); + if (this.handleStickyLeftColumnsRef) { + window.removeEventListener('resize', this.handleStickyLeftColumnsRef); } } } \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_table/styles/_scroll.scss b/playbook/app/pb_kits/playbook/pb_table/styles/_scroll.scss index 53b4471d6b..5fb7232efd 100644 --- a/playbook/app/pb_kits/playbook/pb_table/styles/_scroll.scss +++ b/playbook/app/pb_kits/playbook/pb_table/styles/_scroll.scss @@ -8,8 +8,24 @@ @media (max-width: 1600px) { &[class*="table-responsive-scroll"] { border-radius: 4px; - box-shadow: 1px 0 0 0px $border_light - } + box-shadow: 1px 0 0 0px $border_light, + -1px 0 0 0px $border_light + } + + &[class^=pb_table].table-sm.table-card thead tr th:first-child, + &[class^=pb_table].table-sm:not(.no-hover).table-card tbody tr td:first-child { + border-left-width: 0px; + } + + &[class^=pb_table].table-md.table-card thead tr th:first-child, + &[class^=pb_table].table-md:not(.no-hover).table-card tbody tr td:first-child { + border-left-width: 0px; + } + + &[class^=pb_table].table-lg.table-card thead tr th:first-child, + &[class^=pb_table].table-lg:not(.no-hover).table-card tbody tr td:first-child { + border-left-width: 0px; + } &[class^=pb_table].table-sm.table-card thead tr th:last-child, &[class^=pb_table].table-sm:not(.no-hover).table-card tbody tr td:last-child { diff --git a/playbook/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss b/playbook/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss index 9fa2143580..530cb8bc9a 100644 --- a/playbook/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss +++ b/playbook/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss @@ -7,11 +7,21 @@ background-color: white; } - .with-border { + // For use with sticky left columns + .sticky-left-shadow { + box-shadow: 4px 0 10px rgba(60, 106, 172, 0.16) !important; + } + + .with-border-right { border-right: 1px solid $border_light !important; } - .sticky-shadow { - box-shadow: 4px 0 10px rgba(60, 106, 172, 0.16) !important; + // For use with sticky right columns + .sticky-right-shadow { + box-shadow: -4px 0 10px rgba(60, 106, 172, 0.16) !important; + } + + .with-border-left { + border-left: 1px solid $border_light !important; } }