diff --git a/playbook/CHANGELOG.md b/playbook/CHANGELOG.md index 73a075a7e3..af9122789d 100644 --- a/playbook/CHANGELOG.md +++ b/playbook/CHANGELOG.md @@ -1,3 +1,37 @@ +# 🐉 Draggable Kit Now Available For Rails! ✨ +##### November 18, 2024 + +![playbookrelease14-8-0](https://github.com/user-attachments/assets/5248b47b-d84f-486c-b77d-453731ff6584) + +Now introducing the Draggable Kit for Rails! It’s easy to implement with a simple, flexible subcomponent structure right out of the box and works with almost any kit. Like its React counterpart, it’s fully customizable to fit your Rails project’s unique needs. + +[14.8.0](https://github.com/powerhome/playbook/tree/14.8.0) full list of changes: + +**Kit Enhancements:** +- Remove react-modal from Drawer Kit ([\#3891](https://github.com/powerhome/playbook/pull/3891)) ([@markdoeswork](https://github.com/markdoeswork)) +- Add Color Hover Docs and Fix Background Hover ([\#3874](https://github.com/powerhome/playbook/pull/3874)) ([@markdoeswork](https://github.com/markdoeswork)) +- Adding defaultDate Prop to Date Picker Quick Pick Variant ([\#3907](https://github.com/powerhome/playbook/pull/3907)) ([@carloslimasd](https://github.com/carloslimasd)) +- Timeline Small Variant: Add "Gap" Prop to Timeline Kit ([\#3903](https://github.com/powerhome/playbook/pull/3903)) ([@skduncan](https://github.com/skduncan)) + + +**Fixed Bugs:** +- Fix Dark Mode Date Colors- Dots, Icons, and Captions ([\#3894](https://github.com/powerhome/playbook/pull/3894)) ([@kangaree](https://github.com/kangaree)) + + +**Improvements:** +- Global Hover Visibility Prop ([\#3905](https://github.com/powerhome/playbook/pull/3905)) ([@kangaree](https://github.com/kangaree)) +- Bump intl-tel-input from 24.6.0 to 24.7.0 ([\#3895](https://github.com/powerhome/playbook/pull/3895)) ([@dependabot](https://github.com/dependabot)) +- Fixing Github Action Errors ([\#3904](https://github.com/powerhome/playbook/pull/3904)) ([@jasperfurniss](https://github.com/jasperfurniss)) +- Semver Targets Trigger Correct RCs - Update Version ([\#3831](https://github.com/powerhome/playbook/pull/3831)) ([@skduncan](https://github.com/skduncan)) +- Semver Targets Trigger Correct RCs - Check Label ([\#3822](https://github.com/powerhome/playbook/pull/3822)) ([@skduncan](https://github.com/skduncan)) + +**New Kits:** +- Draggable Kit in Rails ([\#3863](https://github.com/powerhome/playbook/pull/3863)) ([@nidaqg](https://github.com/nidaqg)) + + +[Full Changelog](https://github.com/powerhome/playbook/compare/14.7.0...14.8.0) + + # Go Further With Our Custom Timelines! ##### November 8, 2024 diff --git a/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.html.erb b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.html.erb index 329d451b73..f11cc444b5 100644 --- a/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.html.erb +++ b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.html.erb @@ -30,4 +30,4 @@ } ] %> -<%= pb_rails("advanced_table", props: {table_data: @table_data, column_definitions: column_definitions}) %> +<%= pb_rails("advanced_table", props: { id: "beta_table", table_data: @table_data, column_definitions: column_definitions }) %> diff --git a/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb index 77aa012f69..6b987f9b57 100644 --- a/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb +++ b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb @@ -55,5 +55,5 @@ <%= pb_rails("advanced_table", props: { table_data: @table_data, column_definitions: column_definitions }) do %> <%= pb_rails("advanced_table/table_header", props: { column_definitions: column_definitions }) %> - <%= pb_rails("advanced_table/table_body", props: { id: "subrow_headers", table_data: @table_data, column_definitions: column_definitions, subrow_headers: subrow_headers, enable_toggle_expansion: "all" }) %> + <%= pb_rails("advanced_table/table_body", props: { id: "beta_sort", table_data: @table_data, column_definitions: column_definitions, subrow_headers: subrow_headers, enable_toggle_expansion: "all" }) %> <% end %> diff --git a/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell_rails.html.erb b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell_rails.html.erb new file mode 100644 index 0000000000..a128beabd6 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell_rails.html.erb @@ -0,0 +1,53 @@ +<% + column_definitions = [ + { + accessor: "year", + label: "Year", + cellAccessors: ["quarter", "month", "day"], + custom_renderer: ->(row, value) { + capture do + pb_rails("flex") do + pb_rails("title", props: { text: value, size: 4 }) + + pb_rails("badge", props: { dark: true, margin_left: "xxs", text: row[:newEnrollments].to_i > 20 ? "High" : "Low", variant: "neutral" }) + end + end + } + }, + { + accessor: "newEnrollments", + label: "New Enrollments", + custom_renderer: ->(row, value) { pb_rails("pill", props: { text: value, variant: "success" }) } + }, + { + accessor: "scheduledMeetings", + label: "Scheduled Meetings", + custom_renderer: ->(row, value) { content_tag(:a, value, href: "#") } + }, + { + accessor: "attendanceRate", + label: "Attendance Rate", + custom_renderer: ->(row, value) { + capture do + pb_rails("flex", props: { align_items: "end", orientation: "column" }) do + pb_rails("detail", props: { bold: true, color: "default", text: value }) + + pb_rails("caption", props: { size: "xs", text: row[:graduatedStudents] }) + end + end + } + }, + { + accessor: "completedClasses", + label: "Completed Classes", + }, + { + accessor: "classCompletionRate", + label: "Class Completion Rate", + }, + { + accessor: "graduatedStudents", + label: "Graduated Students", + } + ] +%> + +<%= pb_rails("advanced_table", props: { id: "custom_cell", table_data: @table_data, column_definitions: column_definitions }) %> diff --git a/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell_rails.md b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell_rails.md new file mode 100644 index 0000000000..6f3e9c2c19 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_custom_cell_rails.md @@ -0,0 +1,5 @@ +The Advanced Table also allows for rendering custom components within individual Cells. To achieve this, you can make use of the optional `custom_renderer` item within each column_definitions. This function gives you access to the current Cell's value if you just want to use that with a custom Kit, but it also gives you access to the entire `row` object. The row object provides all data for the current row. + +See [here](https://playbook.powerapp.cloud/kits/advanced_table/rails#column_definitions) for more indepth information on column_definitions are how to use them. + +See [here](https://github.com/powerhome/playbook/tree/master/playbook/app/pb_kits/playbook/pb_advanced_table#readme) for the structure of the table_data used. \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_advanced_table/docs/example.yml b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/example.yml index 87fb7abf3d..8a3994a0b2 100644 --- a/playbook/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +++ b/playbook/app/pb_kits/playbook/pb_advanced_table/docs/example.yml @@ -3,6 +3,7 @@ examples: - advanced_table_beta: Default (Required Props) - advanced_table_beta_subrow_headers: SubRow Headers - advanced_table_beta_sort: Enable Sorting + - advanced_table_custom_cell_rails: Custom Components for Cells react: - advanced_table_default: Default (Required Props) diff --git a/playbook/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb b/playbook/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb index 30dd7e5950..4a16f93f2d 100644 --- a/playbook/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +++ b/playbook/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb @@ -11,7 +11,9 @@ <% end %> <%= pb_rails("flex/flex_item", props:{padding_left: index.zero? && object.row[:children].present? ? "none" : "xs"}) do %> - <% if index.zero? %> + <% if column[:custom_renderer].present? %> + <%= raw(column[:custom_renderer].call(object.row, custom_renderer_value(column, index))) %> + <% elsif index.zero? %> <% if object.depth.zero? %> <%= object.row[column[:accessor].to_sym] %> <% else %> diff --git a/playbook/app/pb_kits/playbook/pb_advanced_table/table_row.rb b/playbook/app/pb_kits/playbook/pb_advanced_table/table_row.rb index cdf81e9ab3..57bb025708 100644 --- a/playbook/app/pb_kits/playbook/pb_advanced_table/table_row.rb +++ b/playbook/app/pb_kits/playbook/pb_advanced_table/table_row.rb @@ -26,6 +26,21 @@ def depth_accessors private + def custom_renderer_value(column, index) + if index.zero? + if depth.zero? + row[column[:accessor].to_sym] + else + depth_accessors.each_with_index do |item, accessor_index| + key = item.to_sym + return row[key] if depth - 1 == accessor_index + end + end + else + row[column[:accessor].to_sym] + end + end + def subrow_depth_classname depth.positive? ? "depth-sub-row-#{depth}" : "" end diff --git a/playbook/app/pb_kits/playbook/pb_table/_table.tsx b/playbook/app/pb_kits/playbook/pb_table/_table.tsx index be965cf5a4..35e9f6d923 100755 --- a/playbook/app/pb_kits/playbook/pb_table/_table.tsx +++ b/playbook/app/pb_kits/playbook/pb_table/_table.tsx @@ -4,11 +4,11 @@ import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/pro import { globalProps, GlobalProps, globalInlineProps } from '../utilities/globalProps' import PbTable from '.' import { - TableHead, - TableHeader, - TableBody, - TableRow, - TableCell, + TableHead, + TableHeader, + TableBody, + TableRow, + TableCell, } from "./subcomponents"; type TableProps = { @@ -28,6 +28,7 @@ type TableProps = { singleLine?: boolean, size?: "sm" | "md" | "lg", sticky?: boolean, + stickyLeftcolumn?: string[], striped?: boolean, tag?: "table" | "div", verticalBorder?: boolean, @@ -51,6 +52,7 @@ const Table = (props: TableProps): React.ReactElement => { singleLine = false, size = 'sm', sticky = false, + stickyLeftcolumn = [], striped = false, tag = 'table', verticalBorder = false, @@ -77,6 +79,7 @@ const Table = (props: TableProps): React.ReactElement => { 'single-line': singleLine, 'no-hover': disableHover, 'sticky-header': sticky, + 'sticky-left-column': stickyLeftcolumn, 'striped': striped, [outerPaddingCss]: outerPadding !== '', }, @@ -86,6 +89,56 @@ const Table = (props: TableProps): React.ReactElement => { className ) + useEffect(() => { + const handleStickyColumns = () => { + let accumulatedWidth = 0; + + stickyLeftcolumn.forEach((colId, index) => { + const isLastColumn = index === stickyLeftcolumn.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.left = `${accumulatedWidth}px`; + + if (!isLastColumn) { + header.classList.add('with-border'); + header.classList.remove('sticky-shadow'); + } else { + header.classList.remove('with-border'); + header.classList.add('sticky-shadow'); + } + + accumulatedWidth += (header as HTMLElement).offsetWidth; + } + + cells.forEach((cell) => { + cell.classList.add('sticky'); + (cell as HTMLElement).style.left = `${accumulatedWidth - (header as HTMLElement).offsetWidth}px`; + + if (!isLastColumn) { + cell.classList.add('with-border'); + cell.classList.remove('sticky-shadow'); + } else { + cell.classList.remove('with-border'); + cell.classList.add('sticky-shadow'); + } + }); + }); + }; + + setTimeout(() => { + handleStickyColumns(); + }, 10); + + window.addEventListener('resize', handleStickyColumns); + + return () => { + window.removeEventListener('resize', handleStickyColumns); + }; + }, [stickyLeftcolumn]); + useEffect(() => { const instance = new PbTable() instance.connect() @@ -93,27 +146,56 @@ const Table = (props: TableProps): React.ReactElement => { return ( <> - {isTableTag ? ( - - {children} -
- ) : ( -
- {children} + {responsive === 'scroll' ? ( +
+ {isTableTag ? ( + + {children} +
+ ) : ( +
+ {children} +
+ )}
+ ) : ( + isTableTag ? ( + + {children} +
+ ) : ( +
+ {children} +
+ ) )} ) diff --git a/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns.jsx b/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns.jsx new file mode 100644 index 0000000000..d4c72f15d3 --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_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_left_columns_react.md b/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_react.md new file mode 100644 index 0000000000..74f8819cca --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_react.md @@ -0,0 +1,2 @@ +The `stickyLeftColumn` prop 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/index.js b/playbook/app/pb_kits/playbook/pb_table/docs/index.js index 9177df3e46..fa0d611648 100755 --- a/playbook/app/pb_kits/playbook/pb_table/docs/index.js +++ b/playbook/app/pb_kits/playbook/pb_table/docs/index.js @@ -25,3 +25,4 @@ export { default as TableDiv } from './_table_div.jsx' export { default as TableWithSubcomponents } from './_table_with_subcomponents.jsx' 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' diff --git a/playbook/app/pb_kits/playbook/pb_table/styles/_all.scss b/playbook/app/pb_kits/playbook/pb_table/styles/_all.scss index cbeeeca4e8..1c2a77bdc1 100755 --- a/playbook/app/pb_kits/playbook/pb_table/styles/_all.scss +++ b/playbook/app/pb_kits/playbook/pb_table/styles/_all.scss @@ -20,3 +20,5 @@ @import "table_header"; @import "striped"; @import "outer_padding"; +@import "sticky_columns"; +@import "scroll"; \ 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 new file mode 100644 index 0000000000..b1eead69ac --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_table/styles/_scroll.scss @@ -0,0 +1,4 @@ + .table-responsive-scroll { + display: block; + overflow-x: auto; + } 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 new file mode 100644 index 0000000000..55da8880ea --- /dev/null +++ b/playbook/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss @@ -0,0 +1,18 @@ +@import "../../tokens/colors"; + +[class^="pb_table"] { + .sticky { + position: sticky !important; + left: 0; + z-index: 1; + background-color: white; + } + + .with-border { + border-right: 1px solid $border_light !important; + } + + .sticky-shadow { + box-shadow: 4px 0 10px rgba(60, 106, 172, 0.16) !important; + } +}