playbook_ui 14.23.0 → 14.24.0.pre.alpha.PLAY1984responsivegapprops9652
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +0 -1
- data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +7 -6
- data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +8 -2
- data/app/pb_kits/playbook/pb_advanced_table/Components/SortIconButton.tsx +24 -25
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +10 -10
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +11 -13
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +7 -4
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +112 -2
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +13 -7
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +14 -2
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +90 -0
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table_action_bar.js +16 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers_vertical_border.html.erb +43 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_headers_vertical_border.jsx +64 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control.jsx +60 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control.md +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control_per_row.jsx +57 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control_per_row.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling.html.erb +46 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling_rails.md +7 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header_rails.html.erb +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_rails.html.erb +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_per_column.jsx +55 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_per_column.md +6 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_per_column_for_multi_column.jsx +80 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_per_column_for_multi_column.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_with_custom_header.md +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_with_custom_header_multi_header.jsx +107 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_with_custom_header_multi_header.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_with_custom_header_rails.html.erb +51 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_with_custom_header_rails.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +9 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +6 -0
- data/app/pb_kits/playbook/pb_advanced_table/flat_advanced_table.js +4 -11
- data/app/pb_kits/playbook/pb_advanced_table/index.js +108 -125
- data/app/pb_kits/playbook/pb_advanced_table/scss_partials/advanced_table_sticky_mixin.scss +7 -1
- data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +7 -4
- data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +5 -1
- data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +46 -4
- data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +13 -4
- data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +24 -5
- data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.rb +1 -1
- data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_legend_position.md +1 -1
- data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +12 -1
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +1 -1
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate_rails.md +2 -1
- data/app/pb_kits/playbook/pb_checkbox/index.js +218 -26
- data/app/pb_kits/playbook/pb_circle_chart/docs/_circle_chart_legend_position.md +1 -1
- data/app/pb_kits/playbook/pb_circle_icon_button/circle_icon_button.html.erb +10 -1
- data/app/pb_kits/playbook/pb_circle_icon_button/circle_icon_button.rb +2 -0
- data/app/pb_kits/playbook/pb_circle_icon_button/docs/_circle_icon_button_input_options.html.erb +24 -0
- data/app/pb_kits/playbook/pb_circle_icon_button/docs/_circle_icon_button_input_options.md +3 -0
- data/app/pb_kits/playbook/pb_circle_icon_button/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_date/_date.tsx +5 -3
- data/app/pb_kits/playbook/pb_date/date.html.erb +6 -6
- data/app/pb_kits/playbook/pb_date/date.rb +2 -0
- data/app/pb_kits/playbook/pb_date/docs/_date_with_show_current_year.html.erb +4 -0
- data/app/pb_kits/playbook/pb_date/docs/_date_with_show_current_year.jsx +17 -0
- data/app/pb_kits/playbook/pb_date/docs/_date_with_show_current_year.md +1 -0
- data/app/pb_kits/playbook/pb_date/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_date/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +17 -1
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +6 -0
- data/app/pb_kits/playbook/pb_dropdown/_dropdown_mixin.scss +36 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_active_style_options.jsx +90 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_active_style_options_react.md +4 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_radio_options.jsx +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_radio_options_react.md +1 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +3 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +24 -0
- data/app/pb_kits/playbook/pb_dropdown/index.js +3 -0
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +11 -1
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.tsx +2 -2
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_no_icon.html.erb +22 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_no_icon.jsx +43 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_no_icon.md +1 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.html.erb +2 -1
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.rb +1 -1
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.test.js +6 -0
- data/app/pb_kits/playbook/pb_flex/_flex.tsx +9 -6
- data/app/pb_kits/playbook/pb_flex/docs/_flex_gap.html.erb +12 -1
- data/app/pb_kits/playbook/pb_flex/docs/_flex_gap.jsx +26 -1
- data/app/pb_kits/playbook/pb_flex/docs/_flex_gap_rails.md +11 -0
- data/app/pb_kits/playbook/pb_flex/docs/_flex_gap_react.md +11 -0
- data/app/pb_kits/playbook/pb_flex/flex.rb +6 -12
- data/app/pb_kits/playbook/pb_gauge/docs/_description.md +1 -0
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_colors.jsx +32 -15
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_colors_react.md +2 -0
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.jsx +35 -9
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex_react.md +1 -0
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_default.jsx +26 -14
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_disable_animation.jsx +32 -15
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_full_circle.jsx +45 -17
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_height.jsx +59 -22
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_live_data.jsx +40 -9
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_min_max.jsx +50 -18
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_sizing.jsx +31 -18
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_title.jsx +34 -17
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_units.jsx +64 -23
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_units_react.md +1 -0
- data/app/pb_kits/playbook/pb_gauge/docs/example.yml +0 -1
- data/app/pb_kits/playbook/pb_gauge/docs/index.js +0 -1
- data/app/pb_kits/playbook/pb_gauge/gaugeTheme.ts +7 -1
- data/app/pb_kits/playbook/pb_line_graph/docs/_description.md +1 -3
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_colors.jsx +36 -17
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_colors_react.md +3 -0
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_default.jsx +31 -16
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_height.jsx +63 -31
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_height.md +3 -0
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_legend.jsx +35 -16
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_legend_nonclickable.jsx +41 -16
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_legend_position.jsx +107 -62
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_legend_position.md +4 -7
- data/app/pb_kits/playbook/pb_line_graph/docs/example.yml +0 -1
- data/app/pb_kits/playbook/pb_line_graph/docs/index.js +0 -1
- data/app/pb_kits/playbook/pb_line_graph/lineGraphTheme.ts +16 -1
- data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +18 -9
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +3 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_show_checked_children.html.erb +75 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_show_checked_children.jsx +94 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_show_checked_children.md +3 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +1 -1
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +3 -0
- data/app/pb_kits/playbook/pb_pagination/_pagination.test.jsx +212 -0
- data/app/pb_kits/playbook/pb_pagination/_pagination.tsx +12 -1
- data/app/pb_kits/playbook/pb_pagination/docs/_pagination_default_rails.md +3 -1
- data/app/pb_kits/playbook/pb_pagination/docs/_pagination_default_react.md +3 -1
- data/app/pb_kits/playbook/pb_pagination/docs/_pagination_external_control.jsx +112 -0
- data/app/pb_kits/playbook/pb_pagination/docs/_pagination_external_control_react.md +3 -0
- data/app/pb_kits/playbook/pb_pagination/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_pagination/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +14 -1
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_strict_mode.html.erb +10 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_strict_mode.jsx +26 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_strict_mode.md +3 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +3 -0
- data/app/pb_kits/playbook/pb_select/select.rb +4 -2
- data/app/pb_kits/playbook/pb_table/docs/_table_with_selectable_rows.html.erb +1 -0
- data/app/pb_kits/playbook/pb_table/styles/_vertical_border.scss +49 -1
- data/app/pb_kits/playbook/utilities/_gap.scss +12 -24
- data/app/pb_kits/playbook/utilities/globalPropNames.mjs +2 -0
- data/app/pb_kits/playbook/utilities/globalProps.ts +28 -4
- data/dist/chunks/_line_graph-B9yItXkt.js +1 -0
- data/dist/chunks/_typeahead-Mbp0CWgZ.js +6 -0
- data/dist/chunks/_weekday_stacked-C-5U1QRT.js +37 -0
- data/dist/chunks/lib-CY5ZPzic.js +29 -0
- data/dist/chunks/{pb_form_validation-B7kuYG-_.js → pb_form_validation-D3b0JKHH.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/menu.yml +4 -11
- data/dist/playbook-doc.js +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/classnames.rb +2 -0
- data/lib/playbook/spacing.rb +53 -1
- data/lib/playbook/version.rb +2 -2
- metadata +55 -27
- data/app/pb_kits/playbook/pb_flex/docs/_flex_gap.md +0 -9
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_pb_styles.jsx +0 -30
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_pb_styles.md +0 -1
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_pb_styles.jsx +0 -52
- data/app/pb_kits/playbook/pb_line_graph/docs/_line_graph_pb_styles.md +0 -1
- data/app/pb_kits/playbook/pb_walkthrough/_walkthrough.scss +0 -0
- data/app/pb_kits/playbook/pb_walkthrough/_walkthrough.tsx +0 -202
- data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_continuous.jsx +0 -69
- data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_default.jsx +0 -71
- data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_multi_beacon.jsx +0 -110
- data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_no_beacon.jsx +0 -76
- data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_no_overlay.jsx +0 -76
- data/app/pb_kits/playbook/pb_walkthrough/docs/_walkthrough_styled.jsx +0 -76
- data/app/pb_kits/playbook/pb_walkthrough/docs/example.yml +0 -10
- data/app/pb_kits/playbook/pb_walkthrough/docs/index.js +0 -6
- data/app/pb_kits/playbook/pb_walkthrough/walkthrough.test.jsx +0 -34
- data/dist/chunks/_circle_chart-D01WLw-z.js +0 -1
- data/dist/chunks/_typeahead-mrBE9f17.js +0 -22
- data/dist/chunks/_weekday_stacked-_LSSbN1y.js +0 -45
- data/dist/chunks/lib-CHh_1-Oj.js +0 -29
- /data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_row_styling.md → _advanced_table_row_styling_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_gauge/docs/{_gauge_colors.md → _gauge_colors_rails.md} +0 -0
- /data/app/pb_kits/playbook/pb_gauge/docs/{_gauge_complex.md → _gauge_complex_rails.md} +0 -0
- /data/app/pb_kits/playbook/pb_line_graph/docs/{_line_graph_colors.md → _line_graph_colors_rails.md} +0 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { ensureAccessible, renderKit, render, fireEvent, screen } from '../utilities/test-utils'
|
3
|
+
import Pagination from './_pagination'
|
4
|
+
|
5
|
+
const defaultProps = {
|
6
|
+
data: { testid: 'pagination-test' },
|
7
|
+
total: 10,
|
8
|
+
current: 1,
|
9
|
+
range: 5,
|
10
|
+
}
|
11
|
+
|
12
|
+
describe('Pagination Component', () => {
|
13
|
+
test('returns namespaced class name', () => {
|
14
|
+
const kit = renderKit(Pagination, defaultProps)
|
15
|
+
expect(kit).toBeInTheDocument()
|
16
|
+
expect(kit).toHaveClass('pb_paginate')
|
17
|
+
})
|
18
|
+
|
19
|
+
it("should be accessible", async () => {
|
20
|
+
ensureAccessible(Pagination, defaultProps)
|
21
|
+
})
|
22
|
+
|
23
|
+
test('renders with default props', () => {
|
24
|
+
render(<Pagination {...defaultProps} />)
|
25
|
+
|
26
|
+
const pagination = screen.getByTestId('pagination-test')
|
27
|
+
expect(pagination).toBeInTheDocument()
|
28
|
+
expect(pagination).toHaveClass('pb_paginate')
|
29
|
+
})
|
30
|
+
|
31
|
+
test('renders pagination buttons correctly', () => {
|
32
|
+
render(<Pagination {...defaultProps} />)
|
33
|
+
|
34
|
+
expect(screen.getByText('1')).toBeInTheDocument()
|
35
|
+
expect(screen.getByText('2')).toBeInTheDocument()
|
36
|
+
expect(screen.getByText('3')).toBeInTheDocument()
|
37
|
+
expect(screen.getByText('4')).toBeInTheDocument()
|
38
|
+
expect(screen.getByText('5')).toBeInTheDocument()
|
39
|
+
|
40
|
+
// Check for navigation arrows by looking for the li elements with specific classes
|
41
|
+
const leftArrow = document.querySelector('.pagination-left')
|
42
|
+
const rightArrow = document.querySelector('.pagination-right')
|
43
|
+
expect(leftArrow).toBeInTheDocument()
|
44
|
+
expect(rightArrow).toBeInTheDocument()
|
45
|
+
})
|
46
|
+
|
47
|
+
test('highlights current page as active', () => {
|
48
|
+
render(<Pagination {...defaultProps}
|
49
|
+
current={3}
|
50
|
+
/>)
|
51
|
+
|
52
|
+
const activePage = screen.getByText('3')
|
53
|
+
expect(activePage).toHaveClass('active')
|
54
|
+
})
|
55
|
+
|
56
|
+
test('calls onChange when page is clicked', () => {
|
57
|
+
const mockOnChange = jest.fn()
|
58
|
+
render(<Pagination {...defaultProps}
|
59
|
+
onChange={mockOnChange}
|
60
|
+
/>)
|
61
|
+
|
62
|
+
const pageButton = screen.getByText('3')
|
63
|
+
fireEvent.click(pageButton)
|
64
|
+
|
65
|
+
expect(mockOnChange).toHaveBeenCalledWith(3)
|
66
|
+
})
|
67
|
+
|
68
|
+
test('disables left arrow on first page', () => {
|
69
|
+
render(<Pagination {...defaultProps}
|
70
|
+
current={1}
|
71
|
+
/>)
|
72
|
+
|
73
|
+
const leftArrow = document.querySelector('.pagination-left')
|
74
|
+
expect(leftArrow).toHaveClass('disabled')
|
75
|
+
})
|
76
|
+
|
77
|
+
test('disables right arrow on last page', () => {
|
78
|
+
render(<Pagination {...defaultProps}
|
79
|
+
current={10}
|
80
|
+
/>)
|
81
|
+
|
82
|
+
const rightArrow = document.querySelector('.pagination-right')
|
83
|
+
expect(rightArrow).toHaveClass('disabled')
|
84
|
+
})
|
85
|
+
|
86
|
+
test('does not render when total is 1 or less', () => {
|
87
|
+
const { container } = render(<Pagination {...defaultProps}
|
88
|
+
total={1}
|
89
|
+
/>)
|
90
|
+
|
91
|
+
expect(container.firstChild).toBeNull()
|
92
|
+
})
|
93
|
+
|
94
|
+
test('renders with custom className', () => {
|
95
|
+
render(<Pagination {...defaultProps}
|
96
|
+
className="custom-class"
|
97
|
+
/>)
|
98
|
+
|
99
|
+
const pagination = screen.getByTestId('pagination-test')
|
100
|
+
expect(pagination).toHaveClass('custom-class')
|
101
|
+
})
|
102
|
+
|
103
|
+
test('renders with custom id', () => {
|
104
|
+
render(<Pagination {...defaultProps}
|
105
|
+
id="custom-id"
|
106
|
+
/>)
|
107
|
+
|
108
|
+
const pagination = screen.getByTestId('pagination-test')
|
109
|
+
expect(pagination).toHaveAttribute('id', 'custom-id')
|
110
|
+
})
|
111
|
+
|
112
|
+
test('renders with custom range', () => {
|
113
|
+
render(<Pagination {...defaultProps}
|
114
|
+
range={3}
|
115
|
+
/>)
|
116
|
+
|
117
|
+
expect(screen.getByText('1')).toBeInTheDocument()
|
118
|
+
expect(screen.getByText('2')).toBeInTheDocument()
|
119
|
+
expect(screen.getByText('3')).toBeInTheDocument()
|
120
|
+
expect(screen.getByText('9')).toBeInTheDocument()
|
121
|
+
expect(screen.getByText('10')).toBeInTheDocument()
|
122
|
+
})
|
123
|
+
|
124
|
+
test('handles large number of pages correctly', () => {
|
125
|
+
render(<Pagination {...defaultProps}
|
126
|
+
current={50}
|
127
|
+
range={5}
|
128
|
+
total={100}
|
129
|
+
/>)
|
130
|
+
|
131
|
+
const pagination = screen.getByTestId('pagination-test')
|
132
|
+
expect(pagination).toBeInTheDocument()
|
133
|
+
expect(pagination).toHaveClass('pb_paginate')
|
134
|
+
|
135
|
+
|
136
|
+
expect(screen.getByText('48')).toBeInTheDocument()
|
137
|
+
expect(screen.getByText('49')).toBeInTheDocument()
|
138
|
+
expect(screen.getByText('50')).toBeInTheDocument()
|
139
|
+
expect(screen.getByText('51')).toBeInTheDocument()
|
140
|
+
expect(screen.getByText('52')).toBeInTheDocument()
|
141
|
+
})
|
142
|
+
|
143
|
+
test('syncs with external current prop changes', () => {
|
144
|
+
const { rerender } = render(<Pagination {...defaultProps}
|
145
|
+
current={1}
|
146
|
+
/>)
|
147
|
+
|
148
|
+
expect(screen.getByText('1')).toHaveClass('active')
|
149
|
+
|
150
|
+
rerender(<Pagination {...defaultProps}
|
151
|
+
current={3}
|
152
|
+
/>)
|
153
|
+
|
154
|
+
expect(screen.getByText('3')).toHaveClass('active')
|
155
|
+
expect(screen.getByText('1')).not.toHaveClass('active')
|
156
|
+
})
|
157
|
+
|
158
|
+
test('validates current prop is within valid range', () => {
|
159
|
+
const { rerender } = render(<Pagination {...defaultProps}
|
160
|
+
current={1}
|
161
|
+
/>)
|
162
|
+
|
163
|
+
rerender(<Pagination {...defaultProps}
|
164
|
+
current={0}
|
165
|
+
/>)
|
166
|
+
|
167
|
+
expect(screen.getByText('1')).toHaveClass('active')
|
168
|
+
|
169
|
+
rerender(<Pagination {...defaultProps}
|
170
|
+
current={15}
|
171
|
+
/>)
|
172
|
+
|
173
|
+
expect(screen.getByText('1')).toHaveClass('active')
|
174
|
+
})
|
175
|
+
|
176
|
+
test('handles htmlOptions props', () => {
|
177
|
+
const htmlOptions = { 'data-test': 'test-value' }
|
178
|
+
render(<Pagination {...defaultProps}
|
179
|
+
htmlOptions={htmlOptions}
|
180
|
+
/>)
|
181
|
+
|
182
|
+
const pagination = screen.getByTestId('pagination-test')
|
183
|
+
expect(pagination).toHaveAttribute('data-test', 'test-value')
|
184
|
+
})
|
185
|
+
|
186
|
+
test('renders first and last page buttons when range is small', () => {
|
187
|
+
render(<Pagination {...defaultProps}
|
188
|
+
current={10}
|
189
|
+
range={3}
|
190
|
+
total={20}
|
191
|
+
/>)
|
192
|
+
|
193
|
+
expect(screen.getByText('1')).toBeInTheDocument()
|
194
|
+
expect(screen.getByText('20')).toBeInTheDocument()
|
195
|
+
|
196
|
+
expect(screen.getByText('9')).toBeInTheDocument()
|
197
|
+
expect(screen.getByText('10')).toBeInTheDocument()
|
198
|
+
expect(screen.getByText('11')).toBeInTheDocument()
|
199
|
+
})
|
200
|
+
|
201
|
+
test('renders second and second-to-last page buttons when needed', () => {
|
202
|
+
render(<Pagination {...defaultProps}
|
203
|
+
current={10}
|
204
|
+
range={3}
|
205
|
+
total={20}
|
206
|
+
/>)
|
207
|
+
|
208
|
+
expect(screen.getByText('2')).toBeInTheDocument()
|
209
|
+
|
210
|
+
expect(screen.getByText('19')).toBeInTheDocument()
|
211
|
+
})
|
212
|
+
})
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useState } from "react";
|
1
|
+
import React, { useState, useEffect } from "react";
|
2
2
|
import classnames from 'classnames'
|
3
3
|
import { GlobalProps, globalProps } from '../utilities/globalProps'
|
4
4
|
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
|
@@ -123,6 +123,13 @@ const Pagination = ( props: PaginationProps) => {
|
|
123
123
|
|
124
124
|
return buttons;
|
125
125
|
};
|
126
|
+
|
127
|
+
// Sync internal state with external current prop
|
128
|
+
useEffect(() => {
|
129
|
+
if (current >= 1 && current <= total) {
|
130
|
+
setCurrentPage(current);
|
131
|
+
}
|
132
|
+
}, [current, total]);
|
126
133
|
|
127
134
|
|
128
135
|
const ariaProps = buildAriaProps(aria)
|
@@ -134,6 +141,10 @@ const Pagination = ( props: PaginationProps) => {
|
|
134
141
|
className
|
135
142
|
)
|
136
143
|
|
144
|
+
if (total <= 1) {
|
145
|
+
return null;
|
146
|
+
}
|
147
|
+
|
137
148
|
return (
|
138
149
|
<div
|
139
150
|
{...ariaProps}
|
@@ -3,4 +3,6 @@ Our Pagination kit depends on the <a href="https://github.com/mislav/will_pagina
|
|
3
3
|
|
4
4
|
Once you have perfomed the paginated query in your controller file you can use our kit (see code example below) instead of `<%= will_paginate @users %>` in your view file.
|
5
5
|
|
6
|
-
You need to add: <code>require "playbook/pagination_renderer"</code> in your apps controller file.
|
6
|
+
You need to add: <code>require "playbook/pagination_renderer"</code> in your apps controller file.
|
7
|
+
|
8
|
+
Note: If the total page count is 0 or 1, the Pagination kit will not be displayed as there aren't multiple pages to navigate.
|
@@ -1 +1,3 @@
|
|
1
|
-
The `range` prop determines how many pages to display in the Pagination component. Regardless of this value, the first two and last two pages are always visible to facilitate navigation to the beginning and end of the pagination. If these always-visible pages fall within the specified range, they are included in the display. If they fall outside the range, the pagination will show additional pages up to the number defined by the `range` prop.
|
1
|
+
The `range` prop determines how many pages to display in the Pagination component. Regardless of this value, the first two and last two pages are always visible to facilitate navigation to the beginning and end of the pagination. If these always-visible pages fall within the specified range, they are included in the display. If they fall outside the range, the pagination will show additional pages up to the number defined by the `range` prop.
|
2
|
+
|
3
|
+
Note: If the `total` pages prop is 0 or 1, the Pagination component will not be displayed, as there aren't multiple pages to navigate.
|
@@ -0,0 +1,112 @@
|
|
1
|
+
import React, { useState } from "react";
|
2
|
+
import Flex from '../../pb_flex/_flex'
|
3
|
+
import Pagination from '../../pb_pagination/_pagination'
|
4
|
+
import Select from '../../pb_select/_select'
|
5
|
+
import Table from '../../pb_table/_table'
|
6
|
+
|
7
|
+
import { data } from "./data";
|
8
|
+
|
9
|
+
const PaginationExternalControl = (props) => {
|
10
|
+
const [totalItems, setTotalItems] = useState(20);
|
11
|
+
const [itemsPerPage, setItemsPerPage] = useState(5);
|
12
|
+
const [currentPage, setCurrentPage] = useState(1);
|
13
|
+
|
14
|
+
const totalPages = Math.ceil(totalItems / itemsPerPage);
|
15
|
+
|
16
|
+
const handlePageChange = (page) => {
|
17
|
+
setCurrentPage(page);
|
18
|
+
};
|
19
|
+
|
20
|
+
const limitedData = data.slice(0, totalItems);
|
21
|
+
const startIndex = (currentPage - 1) * itemsPerPage;
|
22
|
+
const paginatedItems = limitedData.slice(startIndex, startIndex + itemsPerPage);
|
23
|
+
|
24
|
+
const handleTotalItemsChange = (event) => {
|
25
|
+
const value = Number(event.target.value);
|
26
|
+
setTotalItems(value);
|
27
|
+
setCurrentPage(1);
|
28
|
+
};
|
29
|
+
|
30
|
+
const handleItemsPerPageChange = (event) => {
|
31
|
+
const value = Number(event.target.value);
|
32
|
+
setItemsPerPage(value);
|
33
|
+
setCurrentPage(1);
|
34
|
+
};
|
35
|
+
|
36
|
+
return (
|
37
|
+
<>
|
38
|
+
<Flex gap="sm">
|
39
|
+
<Select
|
40
|
+
label="Total Items"
|
41
|
+
onChange={handleTotalItemsChange}
|
42
|
+
options={[
|
43
|
+
{ value: "5", text: "5" },
|
44
|
+
{ value: "10", text: "10" },
|
45
|
+
{ value: "20", text: "20" }
|
46
|
+
]}
|
47
|
+
size="sm"
|
48
|
+
value={String(totalItems)}
|
49
|
+
{...props}
|
50
|
+
/>
|
51
|
+
|
52
|
+
<Select
|
53
|
+
label="Items per Page"
|
54
|
+
onChange={handleItemsPerPageChange}
|
55
|
+
options={[
|
56
|
+
{ value: "3", text: "3" },
|
57
|
+
{ value: "5", text: "5" },
|
58
|
+
{ value: "10", text: "10" }
|
59
|
+
]}
|
60
|
+
size="sm"
|
61
|
+
value={String(itemsPerPage)}
|
62
|
+
{...props}
|
63
|
+
/>
|
64
|
+
</Flex>
|
65
|
+
|
66
|
+
<Pagination
|
67
|
+
current={currentPage}
|
68
|
+
key={`pagination-top-${currentPage}`}
|
69
|
+
marginBottom="xs"
|
70
|
+
onChange={handlePageChange}
|
71
|
+
range={5}
|
72
|
+
total={totalPages}
|
73
|
+
{...props}
|
74
|
+
/>
|
75
|
+
<Table
|
76
|
+
marginBottom="xs"
|
77
|
+
responsive="none"
|
78
|
+
size="sm"
|
79
|
+
{...props}
|
80
|
+
>
|
81
|
+
<Table.Head>
|
82
|
+
<Table.Row>
|
83
|
+
<Table.Header>{"Column 1"}</Table.Header>
|
84
|
+
<Table.Header>{"Column 2"}</Table.Header>
|
85
|
+
<Table.Header>{"Column 3"}</Table.Header>
|
86
|
+
<Table.Header>{"Column 4"}</Table.Header>
|
87
|
+
<Table.Header>{"Column 5"}</Table.Header>
|
88
|
+
</Table.Row>
|
89
|
+
</Table.Head>
|
90
|
+
<Table.Body>
|
91
|
+
{paginatedItems.map((row, index) => (
|
92
|
+
<Table.Row key={index}>
|
93
|
+
{row.map((cell, cellIndex) => (
|
94
|
+
<Table.Cell key={cellIndex}>{cell}</Table.Cell>
|
95
|
+
))}
|
96
|
+
</Table.Row>
|
97
|
+
))}
|
98
|
+
</Table.Body>
|
99
|
+
</Table>
|
100
|
+
<Pagination
|
101
|
+
current={currentPage}
|
102
|
+
key={`pagination-bottom-${currentPage}`}
|
103
|
+
onChange={handlePageChange}
|
104
|
+
range={5}
|
105
|
+
total={totalPages}
|
106
|
+
{...props}
|
107
|
+
/>
|
108
|
+
</>
|
109
|
+
)
|
110
|
+
}
|
111
|
+
|
112
|
+
export default PaginationExternalControl
|
@@ -0,0 +1,3 @@
|
|
1
|
+
The Pagination component supports external control of the current page. This allows for programmatically reseting or changing the current page when filters or other criteria change, without needing to unmount and remount the component.
|
2
|
+
|
3
|
+
In this example, changing the "Total Items" or "Items per Page" dropdowns will automatically reset the pagination to page 1, demonstrating how external control works. The pagination component will update its internal state to reflect the new `current` prop value.
|
@@ -38,6 +38,7 @@ type PhoneNumberInputProps = {
|
|
38
38
|
required?: boolean,
|
39
39
|
value?: string,
|
40
40
|
formatAsYouType?: boolean,
|
41
|
+
strictMode?: boolean,
|
41
42
|
countrySearch?: boolean,
|
42
43
|
}
|
43
44
|
|
@@ -94,6 +95,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
94
95
|
preferredCountries = [],
|
95
96
|
value = "",
|
96
97
|
formatAsYouType = false,
|
98
|
+
strictMode = false,
|
97
99
|
countrySearch = false,
|
98
100
|
} = props
|
99
101
|
|
@@ -195,13 +197,22 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
195
197
|
}
|
196
198
|
|
197
199
|
const validateMissingAreaCode = (itiInit: any) => {
|
198
|
-
if (!
|
200
|
+
if (!itiInit) return
|
199
201
|
if (itiInit.getValidationError() === ValidationError.MissingAreaCode) {
|
200
202
|
showFormattedError('missing area code')
|
201
203
|
return true
|
202
204
|
}
|
203
205
|
}
|
204
206
|
|
207
|
+
const validateRepeatCountryCode = (itiInit: any) => {
|
208
|
+
if (!itiInit) return
|
209
|
+
const countryDialCode = itiInit.getSelectedCountryData().dialCode;
|
210
|
+
if (unformatNumber(inputValue).startsWith(countryDialCode)) {
|
211
|
+
return showFormattedError('repeat country code')
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
|
205
216
|
const validateErrors = () => {
|
206
217
|
if (!hasTyped && !error) return
|
207
218
|
|
@@ -211,6 +222,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
211
222
|
if (validateTooShortNumber(itiRef.current)) return
|
212
223
|
if (validateUnhandledError(itiRef.current)) return
|
213
224
|
if (validateMissingAreaCode(itiRef.current)) return
|
225
|
+
if (validateRepeatCountryCode(itiRef.current)) return
|
214
226
|
}
|
215
227
|
|
216
228
|
const getCurrentSelectedData = (itiInit: any, inputValue: string) => {
|
@@ -256,6 +268,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
256
268
|
countrySearch: countrySearch,
|
257
269
|
fixDropdownWidth: false,
|
258
270
|
formatAsYouType: formatAsYouType,
|
271
|
+
strictMode: strictMode,
|
259
272
|
hiddenInput: hiddenInputs ? () => ({
|
260
273
|
phone: `${name}_full`,
|
261
274
|
country: `${name}_country_code`,
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import React from "react";
|
2
|
+
|
3
|
+
import Body from '../../pb_body/_body'
|
4
|
+
import PhoneNumberInput from '../../pb_phone_number_input/_phone_number_input'
|
5
|
+
|
6
|
+
const PhoneNumberInputStrictMode = (props) => {
|
7
|
+
|
8
|
+
return (
|
9
|
+
<>
|
10
|
+
<PhoneNumberInput
|
11
|
+
id="strict"
|
12
|
+
strictMode
|
13
|
+
{...props}
|
14
|
+
/>
|
15
|
+
<Body>With formatAsYouType</Body>
|
16
|
+
<PhoneNumberInput
|
17
|
+
formatAsYouType
|
18
|
+
id="strict"
|
19
|
+
strictMode
|
20
|
+
{...props}
|
21
|
+
/>
|
22
|
+
</>
|
23
|
+
);
|
24
|
+
};
|
25
|
+
|
26
|
+
export default PhoneNumberInputStrictMode;
|
@@ -10,6 +10,7 @@ examples:
|
|
10
10
|
- phone_number_input_clear_field: Clearing the Input Field
|
11
11
|
- phone_number_input_access_input_element: Accessing the Input Element
|
12
12
|
- phone_number_input_format: Format as You Type
|
13
|
+
- phone_number_input_strict_mode: Strict Mode
|
13
14
|
- phone_number_input_country_search: Country Search
|
14
15
|
|
15
16
|
rails:
|
@@ -20,5 +21,6 @@ examples:
|
|
20
21
|
- phone_number_input_exclude_countries: Exclude Countries
|
21
22
|
- phone_number_input_validation: Form Validation
|
22
23
|
- phone_number_input_format: Format as You Type
|
24
|
+
- phone_number_input_strict_mode: Strict Mode
|
23
25
|
- phone_number_input_hidden_inputs: Hidden Inputs
|
24
26
|
- phone_number_input_country_search: Country Search
|
@@ -7,4 +7,5 @@ export { default as PhoneNumberInputValidation } from './_phone_number_input_val
|
|
7
7
|
export { default as PhoneNumberInputClearField } from './_phone_number_input_clear_field'
|
8
8
|
export { default as PhoneNumberInputAccessInputElement } from './_phone_number_input_access_input_element'
|
9
9
|
export { default as PhoneNumberInputFormat } from './_phone_number_input_format'
|
10
|
+
export { default as PhoneNumberInputStrictMode } from './_phone_number_input_strict_mode'
|
10
11
|
export { default as PhoneNumberInputCountrySearch } from './_phone_number_input_country_search'
|
@@ -25,6 +25,8 @@ module Playbook
|
|
25
25
|
default: ""
|
26
26
|
prop :format_as_you_type, type: Playbook::Props::Boolean,
|
27
27
|
default: false
|
28
|
+
prop :strict_mode, type: Playbook::Props::Boolean,
|
29
|
+
default: false
|
28
30
|
prop :hidden_inputs, type: Playbook::Props::Boolean,
|
29
31
|
default: false
|
30
32
|
prop :country_search, type: Playbook::Props::Boolean,
|
@@ -41,6 +43,7 @@ module Playbook
|
|
41
43
|
disabled: disabled,
|
42
44
|
error: error,
|
43
45
|
formatAsYouType: format_as_you_type,
|
46
|
+
strictMode: strict_mode,
|
44
47
|
hiddenInputs: hidden_inputs,
|
45
48
|
initialCountry: initial_country,
|
46
49
|
label: label,
|
@@ -24,7 +24,9 @@ module Playbook
|
|
24
24
|
prop :validation_message, type: Playbook::Props::String, default: ""
|
25
25
|
|
26
26
|
def classnames
|
27
|
-
classname + inline_class
|
27
|
+
([classname] + [inline_class, compact_class, show_arrow_class])
|
28
|
+
.reject(&:empty?)
|
29
|
+
.join(" ")
|
28
30
|
end
|
29
31
|
|
30
32
|
def all_attributes
|
@@ -44,7 +46,7 @@ module Playbook
|
|
44
46
|
end
|
45
47
|
|
46
48
|
def inline_class
|
47
|
-
inline ? "
|
49
|
+
inline ? "inline" : ""
|
48
50
|
end
|
49
51
|
|
50
52
|
def compact_class
|
@@ -7,7 +7,7 @@
|
|
7
7
|
thead tr:not(:first-child) th {
|
8
8
|
border-right: 1px solid $border_light !important;
|
9
9
|
}
|
10
|
-
|
10
|
+
|
11
11
|
@media screen and (min-width: $screen-xs-min) {
|
12
12
|
tr:hover, .pb_table_tr:hover {
|
13
13
|
td:last-child, .pb_table_td:last-child {
|
@@ -15,5 +15,53 @@
|
|
15
15
|
}
|
16
16
|
}
|
17
17
|
}
|
18
|
+
|
19
|
+
// Firefox-specific fix for sticky elements
|
20
|
+
@-moz-document url-prefix() {
|
21
|
+
// Target sticky headers
|
22
|
+
&.sticky-header {
|
23
|
+
th:not(:last-child) {
|
24
|
+
border-right: none !important;
|
25
|
+
box-shadow: 1px 0 0 0 $border_light !important;
|
26
|
+
}
|
27
|
+
|
28
|
+
.pb_advanced_table_body {
|
29
|
+
.pinned-row {
|
30
|
+
td:not(:first-child):not(:last-child) {
|
31
|
+
border-right: none !important;
|
32
|
+
box-shadow: 1px 0 0 0 $border_light !important;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
// Target sticky left columns
|
39
|
+
&.sticky-left-column {
|
40
|
+
td[style="left"], th[style="left"] {
|
41
|
+
border-right: none !important;
|
42
|
+
box-shadow: 1px 0 0 0 $border_light !important;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
// Target sticky right columns
|
47
|
+
&.sticky-right-column {
|
48
|
+
td[style="right"], th[style="right"] {
|
49
|
+
border-right: none !important;
|
50
|
+
box-shadow: 1px 0 0 0 $border_light !important;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
// Handle hover states in Firefox
|
55
|
+
@media screen and (min-width: $screen-xs-min) {
|
56
|
+
tr:hover, .pb_table_tr:hover {
|
57
|
+
td:last-child, .pb_table_td:last-child {
|
58
|
+
&[style="left"], &[style="right"] {
|
59
|
+
border-right: none !important;
|
60
|
+
box-shadow: 1px 0 0 0 darken($border_light, 10%) !important;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
18
66
|
}
|
19
67
|
}
|
@@ -1,29 +1,17 @@
|
|
1
1
|
@import "spacing";
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
$gap_values: (
|
4
|
+
none: 0,
|
5
|
+
xxs: $space_xxs,
|
6
|
+
xs: $space_xs,
|
7
|
+
sm: $space_sm,
|
8
|
+
md: $space_md,
|
9
|
+
lg: $space_lg,
|
10
|
+
xl: $space_xl,
|
11
|
+
);
|
6
12
|
|
7
|
-
|
8
|
-
gap: $space_xxs;
|
9
|
-
}
|
13
|
+
@include global_props_responsive_css($gap_values, 'gap', 'gap');
|
10
14
|
|
11
|
-
|
12
|
-
gap: $space_xs;
|
13
|
-
}
|
15
|
+
@include global_props_responsive_css($gap_values, 'column_gap', 'column-gap');
|
14
16
|
|
15
|
-
|
16
|
-
gap: $space_sm;
|
17
|
-
}
|
18
|
-
|
19
|
-
.gap_md {
|
20
|
-
gap: $space_md;
|
21
|
-
}
|
22
|
-
|
23
|
-
.gap_lg {
|
24
|
-
gap: $space_lg;
|
25
|
-
}
|
26
|
-
|
27
|
-
.gap_xl {
|
28
|
-
gap: $space_xl;
|
29
|
-
}
|
17
|
+
@include global_props_responsive_css($gap_values, 'row_gap', 'row-gap');
|