playbook_ui 15.2.0.pre.alpha.play2318draggablelistnoborder11263 → 15.2.0.pre.alpha.play257911600
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 +5 -5
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +18 -3
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +56 -14
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +9 -3
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_control_rails.html.erb +39 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_background_control_rails.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.md +3 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_sort.html.erb +3 -3
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta_subrow_headers.html.erb +3 -3
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_collapsible_trail_rails.html.erb +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.md +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_column_headers_rails.html.erb +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_rails.html.erb +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_rails.md +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control_per_row_rails.html.erb +51 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control_per_row_rails.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control_rails.html.erb +40 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_padding_control_rails.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling_rails.md +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling_react.md +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_rails.html.erb +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/index.js +5 -1
- data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +6 -6
- data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +6 -6
- data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +3 -2
- data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +49 -5
- data/app/pb_kits/playbook/pb_button/_button.scss +6 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_loading.html.erb +7 -3
- data/app/pb_kits/playbook/pb_button/docs/_button_loading.jsx +29 -0
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_range_pattern.jsx +1 -1
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.scss +0 -1
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.tsx +5 -3
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_description.md +2 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.rb +4 -1
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.test.js +10 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -1
- data/app/pb_kits/playbook/pb_pb_bar_graph/_pb_bar_graph.tsx +8 -6
- data/app/pb_kits/playbook/pb_pb_bar_graph/docs/_description.md +3 -0
- data/app/pb_kits/playbook/pb_pb_bar_graph/pb_bar_graph.rb +7 -10
- data/app/pb_kits/playbook/pb_pb_bar_graph/pbbargraph.test.jsx +73 -1
- data/app/pb_kits/playbook/pb_pb_circle_chart/_pb_circle_chart.tsx +1 -1
- data/app/pb_kits/playbook/pb_pb_circle_chart/docs/_description.md +3 -0
- data/app/pb_kits/playbook/pb_pb_circle_chart/pb_circle_chart.rb +7 -10
- data/app/pb_kits/playbook/pb_pb_circle_chart/pb_circle_chart.test.jsx +47 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/_pb_gauge_chart.scss +3 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/_pb_gauge_chart.tsx +69 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_description.md +3 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_color.html.erb +12 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_color.jsx +24 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_color.md +5 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_complex.html.erb +45 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_complex.jsx +119 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_complex.md +1 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_default.html.erb +5 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_default.jsx +17 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_disable_animation.html.erb +12 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_disable_animation.jsx +24 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_full_circle.html.erb +23 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_full_circle.jsx +37 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_height.html.erb +40 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_height.jsx +56 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_live_data.jsx +64 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_min_max.html.erb +27 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_min_max.jsx +40 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_min_max.md +1 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_sizing.html.erb +19 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_sizing.jsx +65 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_sizing.md +3 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_title.html.erb +14 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_title.jsx +27 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_units.html.erb +39 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_units.jsx +58 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/_pb_gauge_chart_units.md +1 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/example.yml +29 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/docs/index.js +11 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/pbGaugeGraphTheme.ts +91 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/pb_gauge_chart.html.erb +1 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/pb_gauge_chart.rb +25 -0
- data/app/pb_kits/playbook/pb_pb_gauge_chart/pb_gauge_chart.test.jsx +80 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/_pb_line_graph.scss +3 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/_pb_line_graph.tsx +61 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_description.md +3 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_colors.html.erb +34 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_colors.jsx +52 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_colors.md +5 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_default.html.erb +34 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_default.jsx +45 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_height.html.erb +47 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_height.jsx +64 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_height.md +3 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_legend.html.erb +24 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_legend.jsx +37 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_legend_nonclickable.html.erb +39 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_legend_nonclickable.jsx +45 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_legend_position.html.erb +86 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_legend_position.jsx +116 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/_pb_line_graph_legend_position.md +11 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/example.yml +20 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/docs/index.js +6 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/pbLineGraphTheme.ts +125 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/pb_line_graph.html.erb +1 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/pb_line_graph.rb +25 -0
- data/app/pb_kits/playbook/pb_pb_line_graph/pb_line_graph.test.jsx +110 -0
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +105 -22
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/Toolbar.tsx +41 -2
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/ToolbarDropdown.tsx +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +60 -20
- data/app/pb_kits/playbook/pb_rich_text_editor/_tiptap_styles.scss +36 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_attributes.jsx +38 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_attributes.md +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_focus.jsx +34 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_focus.md +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_inline.jsx +37 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_inline.md +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_simple.jsx +37 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_sticky.jsx +38 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_sticky.md +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_templates.jsx +69 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_templates.md +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +8 -2
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/index.js +6 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.test.js +127 -1
- data/app/pb_kits/playbook/pb_timeline/_timeline.scss +250 -233
- data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +1 -1
- data/app/pb_kits/playbook/pb_timeline/timeline.test.js +2 -2
- data/app/pb_kits/playbook/tokens/_positioning.scss +1 -0
- data/app/pb_kits/playbook/utilities/_positioning.scss +6 -1
- data/app/pb_kits/playbook/utilities/globalProps.ts +3 -1
- data/dist/chunks/{_line_graph-BxcVBQsJ.js → _line_graph-BnVgr42C.js} +1 -1
- data/dist/chunks/_typeahead-BH_dkgOy.js +6 -0
- data/dist/chunks/{_weekday_stacked-BhPyFGlS.js → _weekday_stacked-B3YOt9GF.js} +3 -3
- data/dist/chunks/vendor.js +1 -1
- data/dist/menu.yml +12 -0
- 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/pb_forms_helper.rb +7 -6
- data/lib/playbook/version.rb +1 -1
- data/lib/playbook/z_index.rb +1 -1
- metadata +83 -5
- data/dist/chunks/_typeahead-eZENQ_Y_.js +0 -6
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { render, screen } from '../utilities/test-utils'
|
|
3
|
+
|
|
4
|
+
import { PbLineGraph } from 'playbook-ui'
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
// Silences error logs within the test suite.
|
|
8
|
+
jest.spyOn(console, 'error');
|
|
9
|
+
jest.spyOn(console, 'warn');
|
|
10
|
+
console.error.mockImplementation(() => {});
|
|
11
|
+
console.warn.mockImplementation(() => {});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
console.error.mockRestore();
|
|
16
|
+
console.warn.mockRestore();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const seriesData = [{
|
|
20
|
+
name: 'Installation',
|
|
21
|
+
data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175],
|
|
22
|
+
}, {
|
|
23
|
+
name: 'Manufacturing',
|
|
24
|
+
data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434],
|
|
25
|
+
}, {
|
|
26
|
+
name: 'Sales & Distribution',
|
|
27
|
+
data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387],
|
|
28
|
+
}, {
|
|
29
|
+
name: 'Project Development',
|
|
30
|
+
data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227],
|
|
31
|
+
}, {
|
|
32
|
+
name: 'Other',
|
|
33
|
+
data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111],
|
|
34
|
+
}]
|
|
35
|
+
|
|
36
|
+
const categories = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
|
37
|
+
|
|
38
|
+
const chartOptions = {
|
|
39
|
+
series: seriesData,
|
|
40
|
+
title: { text: "Solar Employment Growth by Sector, 2010-2016" },
|
|
41
|
+
subtitle: { text: "Source: thesolarfoundation.com" },
|
|
42
|
+
xAxis: {
|
|
43
|
+
categories: categories,
|
|
44
|
+
},
|
|
45
|
+
yAxis: {
|
|
46
|
+
title: {
|
|
47
|
+
text: "Number of Employees",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const testId = 'pblinegraph1';
|
|
53
|
+
|
|
54
|
+
test('Kit to exist', () => {
|
|
55
|
+
render(
|
|
56
|
+
<PbLineGraph
|
|
57
|
+
data={{testid: testId}}
|
|
58
|
+
options={chartOptions}
|
|
59
|
+
/>
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
expect(screen.getByTestId(testId)).toBeInTheDocument()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('Kit to apply base classname', () => {
|
|
66
|
+
render(
|
|
67
|
+
<PbLineGraph
|
|
68
|
+
data={{testid: testId}}
|
|
69
|
+
options={chartOptions}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
expect(screen.getByTestId(testId)).toHaveClass('pb_pb_line_graph')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('Kit to have custom class', () => {
|
|
77
|
+
render(
|
|
78
|
+
<PbLineGraph
|
|
79
|
+
className='custom-class'
|
|
80
|
+
data={{testid: testId}}
|
|
81
|
+
options={chartOptions}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
expect(screen.getByTestId(testId)).toHaveClass('custom-class')
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test('Kit to apply global props', () => {
|
|
89
|
+
render(
|
|
90
|
+
<PbLineGraph
|
|
91
|
+
data={{testid: testId}}
|
|
92
|
+
margin="lg"
|
|
93
|
+
options={chartOptions}
|
|
94
|
+
/>
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
expect(screen.getByTestId(testId)).toHaveClass('m_lg')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('kit to apply id', () => {
|
|
101
|
+
render(
|
|
102
|
+
<PbLineGraph
|
|
103
|
+
data={{testid: testId}}
|
|
104
|
+
id='line-graph-id'
|
|
105
|
+
options={chartOptions}
|
|
106
|
+
/>
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
expect(screen.getByTestId(testId)).toHaveAttribute('id', 'line-graph-id')
|
|
110
|
+
})
|
|
@@ -111,7 +111,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
111
111
|
const inputRef = useRef<HTMLInputElement | null>(null)
|
|
112
112
|
const itiRef = useRef<any>(null);
|
|
113
113
|
const [inputValue, setInputValue] = useState(value)
|
|
114
|
-
const [error, setError] = useState(props.error)
|
|
114
|
+
const [error, setError] = useState(props.error || "")
|
|
115
115
|
const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
|
|
116
116
|
const [selectedData, setSelectedData] = useState()
|
|
117
117
|
const [hasTyped, setHasTyped] = useState(false)
|
|
@@ -124,24 +124,6 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
124
124
|
}
|
|
125
125
|
}, [error, onValidate])
|
|
126
126
|
|
|
127
|
-
/*
|
|
128
|
-
useImperativeHandle exposes the kit's input element to a parent component via a ref.
|
|
129
|
-
See the Playbook docs for use cases.
|
|
130
|
-
Read: https://react.dev/reference/react/useImperativeHandle
|
|
131
|
-
*/
|
|
132
|
-
useImperativeHandle(ref, () => {
|
|
133
|
-
return {
|
|
134
|
-
clearField() {
|
|
135
|
-
setInputValue("")
|
|
136
|
-
setError("")
|
|
137
|
-
setHasTyped(false)
|
|
138
|
-
},
|
|
139
|
-
inputNode() {
|
|
140
|
-
return inputRef.current
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
})
|
|
144
|
-
|
|
145
127
|
const unformatNumber = (formattedNumber: any) => {
|
|
146
128
|
return formattedNumber.replace(/\D/g, "")
|
|
147
129
|
}
|
|
@@ -164,6 +146,13 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
164
146
|
|
|
165
147
|
const validateTooShortNumber = (itiInit: any) => {
|
|
166
148
|
if (!itiInit) return
|
|
149
|
+
|
|
150
|
+
// If field is empty, don't show "too short" error
|
|
151
|
+
if (!inputValue || inputValue.trim() === '') {
|
|
152
|
+
setError('')
|
|
153
|
+
return false
|
|
154
|
+
}
|
|
155
|
+
|
|
167
156
|
if (itiInit.getValidationError() === ValidationError.TooShort) {
|
|
168
157
|
return showFormattedError('too short')
|
|
169
158
|
} else {
|
|
@@ -183,7 +172,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
183
172
|
}
|
|
184
173
|
|
|
185
174
|
const validateUnhandledError = (itiInit: any) => {
|
|
186
|
-
if (!
|
|
175
|
+
if (!itiInit) return
|
|
187
176
|
if (itiInit.getValidationError() === ValidationError.SomethingWentWrong) {
|
|
188
177
|
if (inputValue.length === 1) {
|
|
189
178
|
return showFormattedError('too short')
|
|
@@ -206,14 +195,27 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
206
195
|
|
|
207
196
|
const validateRepeatCountryCode = (itiInit: any) => {
|
|
208
197
|
if (!itiInit) return
|
|
209
|
-
const countryDialCode =
|
|
198
|
+
const countryDialCode = itiRef.current.getSelectedCountryData().dialCode;
|
|
210
199
|
if (unformatNumber(inputValue).startsWith(countryDialCode)) {
|
|
211
200
|
return showFormattedError('repeat country code')
|
|
212
201
|
}
|
|
213
202
|
}
|
|
214
203
|
|
|
204
|
+
const validateRequiredField = () => {
|
|
205
|
+
if (!inputValue || inputValue.trim() === '') {
|
|
206
|
+
setError('Missing phone number')
|
|
207
|
+
return true
|
|
208
|
+
}
|
|
209
|
+
return false
|
|
210
|
+
}
|
|
215
211
|
|
|
216
212
|
const validateErrors = () => {
|
|
213
|
+
// If field is empty, show error message
|
|
214
|
+
if (!inputValue || inputValue.trim() === '') {
|
|
215
|
+
if (validateRequiredField()) return
|
|
216
|
+
return
|
|
217
|
+
}
|
|
218
|
+
|
|
217
219
|
if (!hasTyped && !error) return
|
|
218
220
|
|
|
219
221
|
if (itiRef.current) isValid(itiRef.current.isValidNumber())
|
|
@@ -225,6 +227,87 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
225
227
|
if (validateRepeatCountryCode(itiRef.current)) return
|
|
226
228
|
}
|
|
227
229
|
|
|
230
|
+
/*
|
|
231
|
+
useImperativeHandle exposes the kit's input element to a parent component via a ref.
|
|
232
|
+
See the Playbook docs for use cases.
|
|
233
|
+
Read: https://react.dev/reference/react/useImperativeHandle
|
|
234
|
+
*/
|
|
235
|
+
useImperativeHandle(ref, () => {
|
|
236
|
+
return {
|
|
237
|
+
clearField() {
|
|
238
|
+
setInputValue("")
|
|
239
|
+
setError("")
|
|
240
|
+
setHasTyped(false)
|
|
241
|
+
},
|
|
242
|
+
inputNode() {
|
|
243
|
+
return inputRef.current
|
|
244
|
+
},
|
|
245
|
+
// Expose validation method for React Hook Form
|
|
246
|
+
validate() {
|
|
247
|
+
// Run validation and return error message or true
|
|
248
|
+
const isEmpty = !inputValue || inputValue.trim() === ''
|
|
249
|
+
|
|
250
|
+
if (isEmpty) {
|
|
251
|
+
// Show missing phone number error
|
|
252
|
+
const errorMessage = 'Missing phone number'
|
|
253
|
+
setError(errorMessage)
|
|
254
|
+
setHasTyped(true)
|
|
255
|
+
// Only return error for React Hook Form if field is required
|
|
256
|
+
return required ? errorMessage : true
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (!itiRef.current) {
|
|
260
|
+
return true
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Check for repeat country code first
|
|
264
|
+
const countryDialCode = itiRef.current.getSelectedCountryData().dialCode;
|
|
265
|
+
if (unformatNumber(inputValue).startsWith(countryDialCode)) {
|
|
266
|
+
const countryName = itiRef.current.getSelectedCountryData().name
|
|
267
|
+
const errorMessage = `Invalid ${countryName} phone number (repeat country code)`
|
|
268
|
+
setError(errorMessage)
|
|
269
|
+
setHasTyped(true)
|
|
270
|
+
return errorMessage
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Check if it only contains valid characters
|
|
274
|
+
if (!containOnlyNumbers(inputValue)) {
|
|
275
|
+
const countryName = itiRef.current.getSelectedCountryData().name
|
|
276
|
+
const errorMessage = `Invalid ${countryName} phone number (enter numbers only)`
|
|
277
|
+
setError(errorMessage)
|
|
278
|
+
setHasTyped(true)
|
|
279
|
+
return errorMessage
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Check if valid number
|
|
283
|
+
if (!itiRef.current.isValidNumber()) {
|
|
284
|
+
const countryName = itiRef.current.getSelectedCountryData().name
|
|
285
|
+
const validationError = itiRef.current.getValidationError()
|
|
286
|
+
let errorMessage = ''
|
|
287
|
+
|
|
288
|
+
if (validationError === ValidationError.TooShort) {
|
|
289
|
+
errorMessage = `Invalid ${countryName} phone number (too short)`
|
|
290
|
+
} else if (validationError === ValidationError.TooLong) {
|
|
291
|
+
errorMessage = `Invalid ${countryName} phone number (too long)`
|
|
292
|
+
} else if (validationError === ValidationError.MissingAreaCode) {
|
|
293
|
+
errorMessage = `Invalid ${countryName} phone number (missing area code)`
|
|
294
|
+
} else {
|
|
295
|
+
errorMessage = `Invalid ${countryName} phone number`
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
setError(errorMessage)
|
|
299
|
+
setHasTyped(true)
|
|
300
|
+
|
|
301
|
+
return errorMessage
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Clear error if valid
|
|
305
|
+
setError('')
|
|
306
|
+
return true
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
})
|
|
310
|
+
|
|
228
311
|
const getCurrentSelectedData = (itiInit: any, inputValue: string) => {
|
|
229
312
|
return { ...itiInit.getSelectedCountryData(), number: inputValue }
|
|
230
313
|
}
|
|
@@ -300,7 +383,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps, ref?: React.Ref<unknown>
|
|
|
300
383
|
dark,
|
|
301
384
|
"data-phone-number": JSON.stringify(selectedData),
|
|
302
385
|
disabled,
|
|
303
|
-
error,
|
|
386
|
+
error: hasTyped ? error : props.error,
|
|
304
387
|
type: 'tel',
|
|
305
388
|
id,
|
|
306
389
|
label,
|
|
@@ -11,7 +11,7 @@ import { ToolbarTypes } from "./EditorTypes";
|
|
|
11
11
|
import ToolbarHistoryItems from "./ToolbarHistory";
|
|
12
12
|
import MoreExtensionsDropdown from "./MoreExtensionsDropdown";
|
|
13
13
|
|
|
14
|
-
const EditorToolbar = ({ editor, extensions }: any): React.ReactElement => {
|
|
14
|
+
const EditorToolbar = ({ editor, extensions, simple, sticky }: any): React.ReactElement => {
|
|
15
15
|
const toolbaritems = [
|
|
16
16
|
{
|
|
17
17
|
icon: "bold",
|
|
@@ -33,15 +33,50 @@ const EditorToolbar = ({ editor, extensions }: any): React.ReactElement => {
|
|
|
33
33
|
},
|
|
34
34
|
]
|
|
35
35
|
|
|
36
|
+
const simpleToolbaritems = [
|
|
37
|
+
{
|
|
38
|
+
icon: "bold",
|
|
39
|
+
text: "Bold",
|
|
40
|
+
classname:`toolbar_button ${editor.isActive('bold') ? 'is-active' : ''}`,
|
|
41
|
+
onclick:()=>editor.chain().focus().toggleBold().run(),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
icon: "italic",
|
|
45
|
+
text: "Italic",
|
|
46
|
+
classname:`toolbar_button ${editor.isActive('italic') ? 'is-active' : ''}`,
|
|
47
|
+
onclick:() => editor.chain().focus().toggleItalic().run(),
|
|
48
|
+
},
|
|
49
|
+
]
|
|
50
|
+
|
|
36
51
|
return (
|
|
37
52
|
<Background backgroundColor="white"
|
|
38
|
-
className=
|
|
53
|
+
className={`toolbar ${sticky ? 'pb_rich_text_editor_tiptap_toolbar_sticky' : ''}`}
|
|
54
|
+
|
|
39
55
|
>
|
|
40
56
|
<Flex flex="0"
|
|
41
57
|
justify="between"
|
|
42
58
|
paddingX="sm"
|
|
43
59
|
paddingY="xxs"
|
|
44
60
|
>
|
|
61
|
+
{
|
|
62
|
+
simple ? (
|
|
63
|
+
<>
|
|
64
|
+
<Flex className="toolbar_block">
|
|
65
|
+
{simpleToolbaritems && simpleToolbaritems.map(
|
|
66
|
+
({ icon, text, classname, onclick}: ToolbarTypes, index: number) => (
|
|
67
|
+
<EditorButton
|
|
68
|
+
classname={classname}
|
|
69
|
+
icon={icon}
|
|
70
|
+
key={index}
|
|
71
|
+
onclick={onclick}
|
|
72
|
+
text={text}
|
|
73
|
+
/>
|
|
74
|
+
)
|
|
75
|
+
)}
|
|
76
|
+
</Flex>
|
|
77
|
+
</>
|
|
78
|
+
) : (
|
|
79
|
+
<>
|
|
45
80
|
<FlexItem className="toolbar_block"
|
|
46
81
|
displayFlex
|
|
47
82
|
>
|
|
@@ -69,6 +104,10 @@ const EditorToolbar = ({ editor, extensions }: any): React.ReactElement => {
|
|
|
69
104
|
}
|
|
70
105
|
</FlexItem>
|
|
71
106
|
<ToolbarHistoryItems editor={editor} />
|
|
107
|
+
</>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
72
111
|
</Flex>
|
|
73
112
|
</Background>
|
|
74
113
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
1
|
+
import React, { useEffect, useState, useRef } from 'react'
|
|
2
2
|
import classnames from 'classnames'
|
|
3
3
|
import { TrixEditor } from 'react-trix'
|
|
4
4
|
|
|
@@ -77,7 +77,9 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
77
77
|
|
|
78
78
|
const ariaProps = buildAriaProps(aria),
|
|
79
79
|
dataProps = buildDataProps(data),
|
|
80
|
-
[editor, setEditor] = useState<Editor>()
|
|
80
|
+
[editor, setEditor] = useState<Editor>(),
|
|
81
|
+
[showToolbarOnFocus, setShowToolbarOnFocus] = useState(false),
|
|
82
|
+
containerRef = useRef<HTMLDivElement>(null)
|
|
81
83
|
|
|
82
84
|
const htmlProps = buildHtmlProps(htmlOptions)
|
|
83
85
|
|
|
@@ -128,6 +130,42 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
128
130
|
document.addEventListener('trix-blur', inlineFocus)
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
//===========focus prop with advanced editor=================
|
|
134
|
+
const isClickInPopover = (event: Event): boolean => {
|
|
135
|
+
return !!(event.target as Element).closest('.pb_tiptap_toolbar_dropdown_popover')
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const isClickInContainer = (event: Event): boolean => {
|
|
139
|
+
return !!(containerRef.current && containerRef.current.contains(event.target as Node))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (!advancedEditor || !focus) return
|
|
144
|
+
|
|
145
|
+
const handleFocus = () => setShowToolbarOnFocus(true)
|
|
146
|
+
|
|
147
|
+
const handleClickOutside = (event: Event) => {
|
|
148
|
+
if (isClickInContainer(event) || isClickInPopover(event)) return
|
|
149
|
+
setShowToolbarOnFocus(false)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const editorElement = advancedEditor?.view?.dom
|
|
153
|
+
if (editorElement) {
|
|
154
|
+
editorElement.addEventListener('focus', handleFocus)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
document.addEventListener('mousedown', handleClickOutside)
|
|
158
|
+
|
|
159
|
+
return () => {
|
|
160
|
+
if (editorElement) {
|
|
161
|
+
editorElement.removeEventListener('focus', handleFocus)
|
|
162
|
+
}
|
|
163
|
+
document.removeEventListener('mousedown', handleClickOutside)
|
|
164
|
+
}
|
|
165
|
+
}, [advancedEditor, focus])
|
|
166
|
+
|
|
167
|
+
//============= end focus prop with advanced editor=================
|
|
168
|
+
|
|
131
169
|
useEffect(() => {
|
|
132
170
|
if (!editor || !template) return
|
|
133
171
|
editor.loadHTML('')
|
|
@@ -148,41 +186,43 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
148
186
|
})
|
|
149
187
|
}, [editor])
|
|
150
188
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
stickyClass,
|
|
164
|
-
inlineClass,
|
|
165
|
-
toolbarBottomClass,
|
|
166
|
-
css
|
|
189
|
+
// Generate CSS classes
|
|
190
|
+
const css = classnames(
|
|
191
|
+
'pb_rich_text_editor_kit',
|
|
192
|
+
{
|
|
193
|
+
simple: simple,
|
|
194
|
+
'focus-editor-targets': focus,
|
|
195
|
+
sticky: sticky,
|
|
196
|
+
inline: inline,
|
|
197
|
+
'toolbar-bottom': toolbarBottom,
|
|
198
|
+
},
|
|
199
|
+
globalProps(props, { maxWidth }),
|
|
200
|
+
className
|
|
167
201
|
)
|
|
168
202
|
|
|
203
|
+
// Determine if toolbar should be shown
|
|
204
|
+
const shouldShowToolbar = focus && advancedEditor ? showToolbarOnFocus : advancedEditorToolbar
|
|
205
|
+
|
|
169
206
|
return (
|
|
170
207
|
<div
|
|
171
208
|
{...ariaProps}
|
|
172
209
|
{...dataProps}
|
|
173
210
|
{...htmlProps}
|
|
174
211
|
className={css}
|
|
212
|
+
ref={focus ? containerRef : undefined}
|
|
175
213
|
>
|
|
176
214
|
{
|
|
177
215
|
advancedEditor ? (
|
|
178
216
|
<div
|
|
179
217
|
className={classnames("pb_rich_text_editor_advanced_container", {
|
|
180
|
-
["toolbar-active"]:
|
|
218
|
+
["toolbar-active"]: shouldShowToolbar,
|
|
181
219
|
})}
|
|
182
220
|
>
|
|
183
|
-
{
|
|
221
|
+
{shouldShowToolbar && (
|
|
184
222
|
<EditorToolbar editor={advancedEditor}
|
|
185
223
|
extensions={extensions}
|
|
224
|
+
simple={simple}
|
|
225
|
+
sticky={sticky}
|
|
186
226
|
/>
|
|
187
227
|
)}
|
|
188
228
|
{ children }
|
|
@@ -9,6 +9,37 @@
|
|
|
9
9
|
@import "previewer_mixin";
|
|
10
10
|
|
|
11
11
|
[class^="pb_rich_text_editor_kit"] {
|
|
12
|
+
&.inline {
|
|
13
|
+
.toolbar {
|
|
14
|
+
opacity: 0;
|
|
15
|
+
transition: all 0.3s ease-in-out 0s;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&:focus-within .toolbar {
|
|
19
|
+
opacity: 100;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.ProseMirror {
|
|
23
|
+
border: 1px solid transparent;
|
|
24
|
+
transition: all 0.3s ease-in-out 0s;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&:focus-within .ProseMirror {
|
|
28
|
+
border: 1px solid $border_light;
|
|
29
|
+
border-top: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&:hover {
|
|
33
|
+
.toolbar {
|
|
34
|
+
opacity: 100;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.ProseMirror {
|
|
38
|
+
border: 1px solid $border_light;
|
|
39
|
+
border-top: none;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
12
43
|
.toolbar_button {
|
|
13
44
|
display: flex;
|
|
14
45
|
align-items: center;
|
|
@@ -42,6 +73,11 @@
|
|
|
42
73
|
}
|
|
43
74
|
}
|
|
44
75
|
|
|
76
|
+
.pb_rich_text_editor_tiptap_toolbar_sticky {
|
|
77
|
+
position: sticky;
|
|
78
|
+
top: 0;
|
|
79
|
+
z-index: 10;
|
|
80
|
+
}
|
|
45
81
|
.toolbar {
|
|
46
82
|
border-radius: $border_rad_heaviest $border_rad_heaviest 0 0;
|
|
47
83
|
border: 1px solid $border_light;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import RichTextEditor from '../../pb_rich_text_editor/_rich_text_editor'
|
|
3
|
+
import { useEditor, EditorContent } from "@tiptap/react"
|
|
4
|
+
import StarterKit from "@tiptap/starter-kit"
|
|
5
|
+
import Link from '@tiptap/extension-link'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const RichTextEditorAdvancedAttributes = (props) => {
|
|
9
|
+
|
|
10
|
+
const editor = useEditor({
|
|
11
|
+
extensions: [
|
|
12
|
+
StarterKit,
|
|
13
|
+
Link
|
|
14
|
+
],
|
|
15
|
+
content:"Add your text here. You can format your text, add links, quotes, and bullets."
|
|
16
|
+
})
|
|
17
|
+
if (!editor) {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div>
|
|
26
|
+
<RichTextEditor
|
|
27
|
+
advancedEditor={editor}
|
|
28
|
+
aria={{ label: 'I am a rich text editor' }}
|
|
29
|
+
data={{ 'test-data': 'value', 'test-data2': 'value2' }}
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
<EditorContent editor={editor}/>
|
|
33
|
+
</RichTextEditor>
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default RichTextEditorAdvancedAttributes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Aria labels and data attributes can also be added to the top level div for the RichTextEditor.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import RichTextEditor from '../../pb_rich_text_editor/_rich_text_editor'
|
|
3
|
+
import { useEditor, EditorContent } from "@tiptap/react"
|
|
4
|
+
import StarterKit from "@tiptap/starter-kit"
|
|
5
|
+
import Link from '@tiptap/extension-link'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const RichTextEditorAdvancedFocus = (props) => {
|
|
9
|
+
const editor = useEditor({
|
|
10
|
+
extensions: [
|
|
11
|
+
StarterKit,
|
|
12
|
+
Link
|
|
13
|
+
],
|
|
14
|
+
content:"Click inside to see the toolbar. Click outside to hide it."
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
if (!editor) {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div>
|
|
23
|
+
<RichTextEditor
|
|
24
|
+
advancedEditor={editor}
|
|
25
|
+
focus
|
|
26
|
+
{...props}
|
|
27
|
+
>
|
|
28
|
+
<EditorContent editor={editor}/>
|
|
29
|
+
</RichTextEditor>
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default RichTextEditorAdvancedFocus
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
When the optional `focus` prop is set to true, the toolbar will only show once you click in to the RichTextEditor.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import RichTextEditor from '../../pb_rich_text_editor/_rich_text_editor'
|
|
3
|
+
import { useEditor, EditorContent } from "@tiptap/react"
|
|
4
|
+
import StarterKit from "@tiptap/starter-kit"
|
|
5
|
+
import Link from '@tiptap/extension-link'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const RichTextEditorAdvancedInline = (props) => {
|
|
9
|
+
|
|
10
|
+
const editor = useEditor({
|
|
11
|
+
extensions: [
|
|
12
|
+
StarterKit,
|
|
13
|
+
Link
|
|
14
|
+
],
|
|
15
|
+
content:"Add your text here. You can format your text, add links, quotes, and bullets."
|
|
16
|
+
})
|
|
17
|
+
if (!editor) {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div>
|
|
26
|
+
<RichTextEditor
|
|
27
|
+
advancedEditor={editor}
|
|
28
|
+
inline
|
|
29
|
+
{...props}
|
|
30
|
+
>
|
|
31
|
+
<EditorContent editor={editor}/>
|
|
32
|
+
</RichTextEditor>
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default RichTextEditorAdvancedInline
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
When the optional `inline` prop is set to true, the editor borders and the toolbar will only be visible when hovered or focused on.
|