playbook_ui 16.3.0 → 16.4.0.pre.alpha.PLAY2846reactadvancedtablecalcheaderpinnedrows15356

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.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +17 -4
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +3 -1
  4. data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +5 -2
  5. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +21 -9
  6. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +5 -2
  7. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +9 -11
  8. data/app/pb_kits/playbook/pb_advanced_table/Utilities/ExpansionControlHelpers.tsx +25 -1
  9. data/app/pb_kits/playbook/pb_advanced_table/Utilities/RowModelUtils.ts +100 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +65 -1
  11. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +12 -2
  12. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +2 -2
  13. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +9 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +109 -2
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_cascade_collapse.jsx +50 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_cascade_collapse.md +1 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows_rails.html.erb +57 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows_rails.md +7 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_parent_only.jsx +175 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_parent_only.md +5 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +3 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +3 -1
  23. data/app/pb_kits/playbook/pb_advanced_table/index.js +130 -29
  24. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/advanced_table_sticky_mixin.scss +6 -2
  25. data/app/pb_kits/playbook/pb_advanced_table/table_body.html.erb +21 -4
  26. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +115 -9
  27. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +3 -1
  28. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +12 -1
  29. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +4 -1
  30. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.rb +9 -1
  31. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +6 -1
  32. data/app/pb_kits/playbook/pb_button/docs/_button_full_width_rails.md +19 -0
  33. data/app/pb_kits/playbook/pb_button/docs/_button_full_width_react.md +23 -0
  34. data/app/pb_kits/playbook/pb_circle_icon_button/_circle_icon_button.scss +5 -0
  35. data/app/pb_kits/playbook/pb_collapsible/index.js +15 -26
  36. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +3 -1
  37. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.html.erb +1 -1
  38. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.jsx +6 -3
  39. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height.html.erb +3 -3
  40. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height.jsx +6 -3
  41. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height_placement.html.erb +3 -3
  42. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height_placement.jsx +6 -3
  43. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +3 -0
  44. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +1 -0
  45. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_closing_options_rails.html.erb +16 -0
  46. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_closing_options_rails.md +1 -0
  47. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_custom_event_type.html.erb +224 -0
  48. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_custom_event_type.md +7 -0
  49. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +2 -0
  50. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +8 -1
  51. data/app/pb_kits/playbook/pb_dropdown/index.js +255 -46
  52. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +19 -14
  53. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.scss +4 -0
  54. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.tsx +3 -0
  55. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin.html.erb +46 -0
  56. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin.jsx +42 -0
  57. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin_rails.md +1 -0
  58. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin_react.md +1 -0
  59. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/example.yml +2 -0
  60. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/index.js +2 -1
  61. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.rb +7 -1
  62. data/app/pb_kits/playbook/pb_icon/icon.rb +7 -1
  63. data/app/pb_kits/playbook/pb_list/_list_mixin.scss +4 -4
  64. data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +1 -1
  65. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +27 -16
  66. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_placeholder.html.erb +109 -0
  67. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_placeholder.jsx +127 -0
  68. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_placeholder.md +1 -0
  69. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +2 -0
  70. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +1 -0
  71. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +3 -0
  72. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.test.jsx +27 -0
  73. data/app/pb_kits/playbook/pb_popover/docs/_popover_placement.jsx +81 -0
  74. data/app/pb_kits/playbook/pb_popover/docs/_popover_placement_react.md +1 -0
  75. data/app/pb_kits/playbook/pb_popover/docs/_popover_position.html.erb +128 -0
  76. data/app/pb_kits/playbook/pb_popover/docs/_popover_position_rails.md +1 -0
  77. data/app/pb_kits/playbook/pb_popover/docs/example.yml +2 -0
  78. data/app/pb_kits/playbook/pb_popover/docs/index.js +2 -1
  79. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +35 -134
  80. data/app/pb_kits/playbook/pb_rich_text_editor/_tiptap_editor.tsx +51 -0
  81. data/app/pb_kits/playbook/pb_rich_text_editor/_trix_editor.tsx +206 -0
  82. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.jsx +56 -0
  83. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.md +1 -0
  84. data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +13 -21
  85. data/app/pb_kits/playbook/pb_rich_text_editor/docs/index.js +0 -10
  86. data/app/pb_kits/playbook/pb_rich_text_editor/inlineFocus.ts +5 -4
  87. data/app/pb_kits/playbook/pb_selectable_list/_selectable_list.scss +19 -1
  88. data/app/pb_kits/playbook/pb_table/_table.tsx +24 -21
  89. data/app/pb_kits/playbook/pb_table/docs/_sections.yml +1 -0
  90. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_external_filter_rails.html.erb +45 -0
  91. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_external_filter_rails.md +39 -0
  92. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_rails.md +2 -1
  93. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props.jsx +152 -0
  94. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props.md +17 -0
  95. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props_rails.html.erb +121 -0
  96. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props_rails.md +17 -0
  97. data/app/pb_kits/playbook/pb_table/docs/example.yml +3 -0
  98. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  99. data/app/pb_kits/playbook/pb_table/table.html.erb +17 -13
  100. data/app/pb_kits/playbook/pb_table/table.rb +8 -0
  101. data/app/pb_kits/playbook/pb_table/table.test.js +33 -0
  102. data/app/pb_kits/playbook/pb_textarea/_textarea.scss +4 -1
  103. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +105 -3
  104. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_highlight.jsx +20 -8
  105. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_highlight.md +3 -0
  106. data/app/pb_kits/playbook/utilities/_hover.scss +6 -3
  107. data/app/pb_kits/playbook/utilities/domHelpers.ts +50 -0
  108. data/dist/chunks/{_pb_line_graph-CKBPxTmM.js → _pb_line_graph-D6s5rymw.js} +1 -1
  109. data/dist/chunks/_typeahead-BNp_YiTh.js +1 -0
  110. data/dist/chunks/componentRegistry-DRSp5D_e.js +1 -0
  111. data/dist/chunks/{globalProps-DLCfJwiU.js → globalProps-Ds_6HBhX.js} +1 -1
  112. data/dist/chunks/lib-BaO72ugL.js +29 -0
  113. data/dist/chunks/vendor.js +5 -5
  114. data/dist/menu.yml +3 -2
  115. data/dist/playbook-rails-react-bindings.js +1 -1
  116. data/dist/playbook-rails.js +1 -1
  117. data/dist/playbook.css +1 -1
  118. data/lib/playbook/pb_forms_helper.rb +3 -0
  119. data/lib/playbook/version.rb +2 -2
  120. metadata +42 -32
  121. data/app/pb_kits/playbook/pb_button/docs/_button_full_width.md +0 -1
  122. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_attributes.html.erb +0 -5
  123. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_attributes.jsx +0 -15
  124. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.html.erb +0 -1
  125. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_focus.html.erb +0 -3
  126. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_focus.jsx +0 -17
  127. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_inline.html.erb +0 -6
  128. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_inline.jsx +0 -16
  129. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_label.jsx +0 -28
  130. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_label.md +0 -1
  131. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_preview.html.erb +0 -35
  132. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_preview.jsx +0 -45
  133. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.html.erb +0 -10
  134. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.jsx +0 -22
  135. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.md +0 -3
  136. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_simple.html.erb +0 -1
  137. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_simple.jsx +0 -13
  138. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_sticky.html.erb +0 -1
  139. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_sticky.jsx +0 -15
  140. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_templates.html.erb +0 -115
  141. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_templates.jsx +0 -42
  142. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_toolbar_bottom.html.erb +0 -4
  143. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_toolbar_bottom.jsx +0 -14
  144. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb +0 -5
  145. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.rb +0 -63
  146. data/dist/chunks/_typeahead-B7bktFm6.js +0 -1
  147. data/dist/chunks/componentRegistry-DzmmLR2x.js +0 -1
  148. data/dist/chunks/lib-QT_7rPYf.js +0 -29
@@ -0,0 +1,128 @@
1
+ <%= pb_rails("flex", props: { justify: "around", margin_bottom: "sm", orientation: "row", wrap: true }) do %>
2
+ <%= pb_rails("button", props: { text: "Top", variant: "secondary", id: "placement-popover-top" }) %>
3
+ <%= pb_rails("popover", props: {
4
+ close_on_click: "outside",
5
+ trigger_element_id: "placement-popover-top",
6
+ tooltip_id: "placement-tooltip-top",
7
+ position: "top",
8
+ offset: true
9
+ }) do %>
10
+ Popover: top
11
+ <% end %>
12
+ <%= pb_rails("button", props: { text: "Top start", variant: "secondary", id: "placement-popover-top-start" }) %>
13
+ <%= pb_rails("popover", props: {
14
+ close_on_click: "outside",
15
+ trigger_element_id: "placement-popover-top-start",
16
+ tooltip_id: "placement-tooltip-top-start",
17
+ position: "top-start",
18
+ offset: true
19
+ }) do %>
20
+ Popover: top start
21
+ <% end %>
22
+ <%= pb_rails("button", props: { text: "Top end", variant: "secondary", id: "placement-popover-top-end" }) %>
23
+ <%= pb_rails("popover", props: {
24
+ close_on_click: "outside",
25
+ trigger_element_id: "placement-popover-top-end",
26
+ tooltip_id: "placement-tooltip-top-end",
27
+ position: "top-end",
28
+ offset: true
29
+ }) do %>
30
+ Popover: top end
31
+ <% end %>
32
+ <% end %>
33
+ <%= pb_rails("flex", props: { justify: "around", margin_bottom: "sm", orientation: "row", wrap: true }) do %>
34
+ <%= pb_rails("button", props: { text: "Bottom", variant: "secondary", id: "placement-popover-bottom" }) %>
35
+ <%= pb_rails("popover", props: {
36
+ close_on_click: "outside",
37
+ trigger_element_id: "placement-popover-bottom",
38
+ tooltip_id: "placement-tooltip-bottom",
39
+ position: "bottom",
40
+ offset: true
41
+ }) do %>
42
+ Popover: bottom
43
+ <% end %>
44
+ <%= pb_rails("button", props: { text: "Bottom start", variant: "secondary", id: "placement-popover-bottom-start" }) %>
45
+ <%= pb_rails("popover", props: {
46
+ close_on_click: "outside",
47
+ trigger_element_id: "placement-popover-bottom-start",
48
+ tooltip_id: "placement-tooltip-bottom-start",
49
+ position: "bottom-start",
50
+ offset: true
51
+ }) do %>
52
+ Popover: bottom start
53
+ <% end %>
54
+ <%= pb_rails("button", props: { text: "Bottom end", variant: "secondary", id: "placement-popover-bottom-end" }) %>
55
+ <%= pb_rails("popover", props: {
56
+ close_on_click: "outside",
57
+ trigger_element_id: "placement-popover-bottom-end",
58
+ tooltip_id: "placement-tooltip-bottom-end",
59
+ position: "bottom-end",
60
+ offset: true
61
+ }) do %>
62
+ Popover: bottom end
63
+ <% end %>
64
+ <% end %>
65
+ <%= pb_rails("flex", props: { justify: "around", margin_bottom: "sm", orientation: "row", wrap: true }) do %>
66
+ <%= pb_rails("button", props: { text: "Left", variant: "secondary", id: "placement-popover-left" }) %>
67
+ <%= pb_rails("popover", props: {
68
+ close_on_click: "outside",
69
+ trigger_element_id: "placement-popover-left",
70
+ tooltip_id: "placement-tooltip-left",
71
+ position: "left",
72
+ offset: true
73
+ }) do %>
74
+ Popover: left
75
+ <% end %>
76
+ <%= pb_rails("button", props: { text: "Left start", variant: "secondary", id: "placement-popover-left-start" }) %>
77
+ <%= pb_rails("popover", props: {
78
+ close_on_click: "outside",
79
+ trigger_element_id: "placement-popover-left-start",
80
+ tooltip_id: "placement-tooltip-left-start",
81
+ position: "left-start",
82
+ offset: true
83
+ }) do %>
84
+ Popover: left start
85
+ <% end %>
86
+ <%= pb_rails("button", props: { text: "Left end", variant: "secondary", id: "placement-popover-left-end" }) %>
87
+ <%= pb_rails("popover", props: {
88
+ close_on_click: "outside",
89
+ trigger_element_id: "placement-popover-left-end",
90
+ tooltip_id: "placement-tooltip-left-end",
91
+ position: "left-end",
92
+ offset: true
93
+ }) do %>
94
+ Popover: left end
95
+ <% end %>
96
+ <% end %>
97
+ <%= pb_rails("flex", props: { justify: "around", orientation: "row", wrap: true }) do %>
98
+ <%= pb_rails("button", props: { text: "Right", variant: "secondary", id: "placement-popover-right" }) %>
99
+ <%= pb_rails("popover", props: {
100
+ close_on_click: "outside",
101
+ trigger_element_id: "placement-popover-right",
102
+ tooltip_id: "placement-tooltip-right",
103
+ position: "right",
104
+ offset: true
105
+ }) do %>
106
+ Popover: right
107
+ <% end %>
108
+ <%= pb_rails("button", props: { text: "Right start", variant: "secondary", id: "placement-popover-right-start" }) %>
109
+ <%= pb_rails("popover", props: {
110
+ close_on_click: "outside",
111
+ trigger_element_id: "placement-popover-right-start",
112
+ tooltip_id: "placement-tooltip-right-start",
113
+ position: "right-start",
114
+ offset: true
115
+ }) do %>
116
+ Popover: right start
117
+ <% end %>
118
+ <%= pb_rails("button", props: { text: "Right end", variant: "secondary", id: "placement-popover-right-end" }) %>
119
+ <%= pb_rails("popover", props: {
120
+ close_on_click: "outside",
121
+ trigger_element_id: "placement-popover-right-end",
122
+ tooltip_id: "placement-tooltip-right-end",
123
+ position: "right-end",
124
+ offset: true
125
+ }) do %>
126
+ Popover: right end
127
+ <% end %>
128
+ <% end %>
@@ -0,0 +1 @@
1
+ Use the `position` prop to control where the popover appears relative to its trigger. Valid values include `top`, `bottom`, `left`, `right`, and aligned variants such as `top-start`, `top-end`, `bottom-start`, `bottom-end`, `left-start`, `left-end`, `right-start`, and `right-end`.
@@ -7,6 +7,7 @@ examples:
7
7
  - popover_scroll_height: Scroll and Height Settings
8
8
  - popover_actionable_content: With Actionable Content
9
9
  - popover_append_to: Append To
10
+ - popover_position: Position
10
11
 
11
12
  react:
12
13
  - popover_default: Default
@@ -16,3 +17,4 @@ examples:
16
17
  - popover_scroll_height: Scroll and Height Settings
17
18
  - popover_actionable_content: With Actionable Content
18
19
  - popover_append_to: Append To
20
+ - popover_placement: Placement
@@ -4,4 +4,5 @@ export { default as PopoverClose } from './_popover_close.jsx'
4
4
  export { default as PopoverZIndex } from './_popover_z_index.jsx'
5
5
  export { default as PopoverScrollHeight } from './_popover_scroll_height.jsx'
6
6
  export { default as PopoverActionableContent } from './_popover_actionable_content.jsx'
7
- export { default as PopoverAppendTo } from './_popover_append_to.jsx'
7
+ export { default as PopoverAppendTo } from './_popover_append_to.jsx'
8
+ export { default as PopoverPlacement } from './_popover_placement.jsx'
@@ -1,33 +1,12 @@
1
1
  import React, { useEffect, useState, useRef } from 'react'
2
2
  import classnames from 'classnames'
3
- import { TrixEditor } from 'react-trix'
4
3
 
5
- import inlineFocus from './inlineFocus'
6
- import useFocus from './useFocus'
7
4
  import Caption from '../pb_caption/_caption'
8
5
  import colors from '../tokens/exports/_colors.module.scss'
9
6
  import { globalProps, GlobalProps } from '../utilities/globalProps'
10
7
  import { buildAriaProps, buildDataProps, noop, buildHtmlProps } from '../utilities/props'
11
-
12
- import Trix from 'trix'
13
- import './_dedupe_trix_toolbar'
14
-
15
- Trix.config.textAttributes.inlineCode = {
16
- tagName: 'code',
17
- inheritable: true,
18
- }
19
-
20
- import EditorToolbar from './TipTap/Toolbar'
21
-
22
- type Editor = {
23
- attributeIsActive?: ([any]: string) => boolean,
24
- element?: HTMLElement,
25
- getSelectedDocument?: () => any,
26
- getSelectedRange?: () => Array<number>,
27
- insertHTML?: ([any]: string) => void,
28
- loadHTML?: ([any]: string) => void,
29
- setSelectedRange?: (range: Array<number>) => void,
30
- }
8
+ import TipTapEditor from './_tiptap_editor'
9
+ import TrixTextEditor from './_trix_editor'
31
10
 
32
11
  type RichTextEditorProps = {
33
12
  aria?: { [key: string]: string },
@@ -55,6 +34,8 @@ type RichTextEditorProps = {
55
34
  template: string,
56
35
  value?: string,
57
36
  maxWidth?: string
37
+ TrixEditor?: React.ComponentType<any>,
38
+ trixInstance?: any,
58
39
  } & GlobalProps
59
40
 
60
41
  const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
@@ -84,50 +65,19 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
84
65
  maxWidth = "md",
85
66
  requiredIndicator = false,
86
67
  label,
68
+ TrixEditor,
69
+ trixInstance: trixInstance = undefined,
87
70
  } = props
88
71
 
89
72
  const ariaProps = buildAriaProps(aria),
90
73
  dataProps = buildDataProps(data),
91
- [editor, setEditor] = useState<Editor>(),
92
74
  [showToolbarOnFocus, setShowToolbarOnFocus] = useState(false),
93
75
  containerRef = useRef<HTMLDivElement>(null)
94
76
 
95
77
  const htmlProps = buildHtmlProps(htmlOptions)
96
78
 
97
79
  const fieldId = id ? (id as string) : null
98
- const labelElementId = fieldId ? `${fieldId}-label` : null
99
-
100
- const handleOnEditorReady = (editorInstance: Editor) => {
101
- setEditor(editorInstance)
102
-
103
- setTimeout(() => {
104
- const oldId = editorInstance.element?.getAttribute("input")
105
- if (!oldId) return
106
-
107
- const hiddenInput = document.getElementById(oldId) as HTMLElement | null
108
- if (!hiddenInput) return
109
-
110
- const hiddenInputId = (inputOptions.id as string) || oldId
111
-
112
- if (hiddenInputId !== oldId) {
113
- hiddenInput.id = hiddenInputId
114
- editorInstance.element?.setAttribute("input", hiddenInputId)
115
- }
116
-
117
- if (inputOptions.name) {
118
- hiddenInput.setAttribute("name", inputOptions.name as string)
119
- }
120
-
121
- const editorDomId = (id as string) || `${hiddenInputId}_trix`
122
- const trixLabelId = ((id as string) || hiddenInputId) + "-label"
123
-
124
- if (label) {
125
- editorInstance.element?.setAttribute("aria-labelledby", trixLabelId)
126
- }
127
- editorInstance.element!.id = editorDomId
128
- })
129
- }
130
-
80
+ const labelElementId = fieldId ? `${fieldId}-label` : undefined
131
81
  useEffect(() => {
132
82
  if (!advancedEditor || !fieldId || !labelElementId) return
133
83
 
@@ -139,34 +89,6 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
139
89
  dom.setAttribute("aria-multiline", "true")
140
90
  }, [advancedEditor, fieldId, labelElementId])
141
91
 
142
- // DOM manipulation must wait for editor to be ready
143
- if (editor && editor.element) {
144
- const toolbarElement = editor.element.parentElement.querySelector('trix-toolbar') as HTMLElement,
145
- blockCodeButton = toolbarElement.querySelector('[data-trix-attribute=code]') as HTMLElement
146
-
147
- // replace default trix "block code" button with "inline code" button
148
- let inlineCodeButton = toolbarElement.querySelector('[data-trix-attribute=inlineCode]') as HTMLElement
149
- if (!inlineCodeButton) {
150
- inlineCodeButton = blockCodeButton.cloneNode(true) as HTMLElement
151
- blockCodeButton.hidden = true
152
- // set button attributes
153
- inlineCodeButton.dataset.trixAttribute = 'inlineCode'
154
- blockCodeButton.insertAdjacentElement('afterend', inlineCodeButton)
155
- }
156
-
157
- if (toolbarBottom) editor.element.after(toolbarElement)
158
-
159
- focus
160
- ? (document.addEventListener('trix-focus', useFocus),
161
- document.addEventListener('trix-blur', useFocus),
162
- // eslint-disable-next-line react-hooks/rules-of-hooks
163
- useFocus())
164
- : null
165
-
166
- document.addEventListener('trix-focus', inlineFocus)
167
- document.addEventListener('trix-blur', inlineFocus)
168
- }
169
-
170
92
  //===========focus prop with advanced editor=================
171
93
  const isClickInPopover = (event: Event): boolean => {
172
94
  return !!(event.target as Element).closest('.pb_tiptap_toolbar_dropdown_popover')
@@ -203,26 +125,6 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
203
125
 
204
126
  //============= end focus prop with advanced editor=================
205
127
 
206
- useEffect(() => {
207
- if (!editor || !template) return
208
- editor.loadHTML('')
209
- editor.setSelectedRange([0, 0])
210
- editor.insertHTML(template)
211
- }, [editor, template])
212
-
213
- useEffect(() => {
214
- if (!editor?.element) return
215
- editor.element.addEventListener('click', ({ target }: Event) => {
216
- const trixEditorContainer = (target as Element).closest('.pb_rich_text_editor_kit')
217
- if (!trixEditorContainer) return
218
-
219
- const anchorElement = (target as Element).closest('a')
220
- if (!anchorElement) return
221
-
222
- if (anchorElement.hasAttribute('href')) window.open(anchorElement.href)
223
- })
224
- }, [editor])
225
-
226
128
  // Generate CSS classes
227
129
  const css = classnames(
228
130
  'pb_rich_text_editor_kit',
@@ -279,35 +181,34 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
279
181
 
280
182
  </label>
281
183
  )}
282
- {
283
- advancedEditor ? (
284
- <div
285
- className={classnames(
286
- "pb_rich_text_editor_advanced_container",
287
- { [`input_height_${inputHeight}`]: !!inputHeight,[`input_min_height_${inputMinHeight}`]: !!inputMinHeight ,["toolbar-active"]: shouldShowToolbar }
288
- )}
289
- >
290
- {shouldShowToolbar && (
291
- <EditorToolbar editor={advancedEditor}
292
- extensions={extensions}
293
- simple={simple}
294
- sticky={sticky}
295
- />
296
- )}
297
- { children }
298
- </div>
299
- ) : (
300
- <TrixEditor
301
- className=""
302
- fileParamName={name}
303
- mergeTags={[]}
304
- onChange={onChange}
305
- onEditorReady={handleOnEditorReady}
306
- placeholder={placeholder}
307
- value={value}
308
- />
309
- )
310
- }
184
+ {advancedEditor ? (
185
+ <TipTapEditor
186
+ editor={advancedEditor}
187
+ extensions={extensions}
188
+ inputHeight={inputHeight}
189
+ inputMinHeight={inputMinHeight}
190
+ shouldShowToolbar={shouldShowToolbar}
191
+ simple={simple}
192
+ sticky={sticky}
193
+ >
194
+ {children}
195
+ </TipTapEditor>
196
+ ) : (
197
+ <TrixTextEditor
198
+ TrixEditor={TrixEditor}
199
+ focus={focus}
200
+ id={id}
201
+ inputOptions={inputOptions}
202
+ label={label}
203
+ name={name}
204
+ onChange={onChange}
205
+ placeholder={placeholder}
206
+ template={template}
207
+ toolbarBottom={toolbarBottom}
208
+ trixInstance={trixInstance}
209
+ value={value}
210
+ />
211
+ )}
311
212
  </div>
312
213
  )
313
214
  }
@@ -0,0 +1,51 @@
1
+ import React from 'react'
2
+ import classnames from 'classnames'
3
+
4
+ import EditorToolbar from './TipTap/Toolbar'
5
+
6
+ type TipTapEditorProps = {
7
+ children?: React.ReactNode | React.ReactNode[],
8
+ editor: unknown,
9
+ extensions?: { [key: string]: string }[],
10
+ inputHeight?: 'sm' | 'md' | 'lg',
11
+ inputMinHeight?: 'sm' | 'md' | 'lg',
12
+ shouldShowToolbar: boolean,
13
+ simple?: boolean,
14
+ sticky?: boolean,
15
+ }
16
+
17
+ const TipTapEditor = ({
18
+ children,
19
+ editor,
20
+ extensions,
21
+ inputHeight,
22
+ inputMinHeight,
23
+ shouldShowToolbar,
24
+ simple = false,
25
+ sticky = false,
26
+ }: TipTapEditorProps): React.ReactElement => {
27
+ return (
28
+ <div
29
+ className={classnames(
30
+ 'pb_rich_text_editor_advanced_container',
31
+ {
32
+ [`input_height_${inputHeight}`]: !!inputHeight,
33
+ [`input_min_height_${inputMinHeight}`]: !!inputMinHeight,
34
+ 'toolbar-active': shouldShowToolbar,
35
+ }
36
+ )}
37
+ >
38
+ {shouldShowToolbar && (
39
+ <EditorToolbar
40
+ editor={editor}
41
+ extensions={extensions}
42
+ simple={simple}
43
+ sticky={sticky}
44
+ />
45
+ )}
46
+ {children}
47
+ </div>
48
+ )
49
+ }
50
+
51
+ export default TipTapEditor
@@ -0,0 +1,206 @@
1
+ import React, { useEffect, useState } from 'react'
2
+
3
+ import inlineFocus from './inlineFocus'
4
+ import applyFocusState from './useFocus'
5
+ import './_dedupe_trix_toolbar'
6
+
7
+ type Editor = {
8
+ element?: HTMLElement,
9
+ insertHTML?: (html: string) => void,
10
+ loadHTML?: (html: string) => void,
11
+ setSelectedRange?: (range: Array<number>) => void,
12
+ }
13
+
14
+ type TrixConfig = {
15
+ textAttributes?: {
16
+ inlineCode?: {
17
+ tagName: string,
18
+ inheritable: boolean,
19
+ }
20
+ }
21
+ }
22
+
23
+ type TrixInstance = {
24
+ config: TrixConfig,
25
+ }
26
+
27
+ type TrixEditorComponentProps = {
28
+ className: string,
29
+ fileParamName?: string,
30
+ mergeTags: unknown[],
31
+ onChange: (html: string, text: string) => void,
32
+ onEditorReady: (editorInstance: Editor) => void,
33
+ placeholder?: string,
34
+ value?: string,
35
+ }
36
+
37
+ type TrixTextEditorProps = {
38
+ TrixEditor?: React.ComponentType<TrixEditorComponentProps>,
39
+ focus?: boolean,
40
+ id?: string,
41
+ inputOptions?: { [key: string]: string | number | boolean | (() => void) },
42
+ label?: string,
43
+ name?: string,
44
+ onChange: (html: string, text: string) => void,
45
+ placeholder?: string,
46
+ template: string,
47
+ toolbarBottom?: boolean,
48
+ trixInstance?: TrixInstance,
49
+ value?: string,
50
+ }
51
+
52
+ const TrixTextEditor = ({
53
+ TrixEditor,
54
+ focus = false,
55
+ id,
56
+ inputOptions = {},
57
+ label,
58
+ name,
59
+ onChange,
60
+ placeholder,
61
+ template,
62
+ toolbarBottom = false,
63
+ trixInstance = undefined,
64
+ value = '',
65
+ }: TrixTextEditorProps): React.ReactElement => {
66
+ const [editor, setEditor] = useState<Editor>()
67
+
68
+ useEffect(() => {
69
+ const textAttributes = trixInstance?.config?.textAttributes
70
+ if (!textAttributes) return
71
+
72
+ textAttributes.inlineCode = {
73
+ tagName: 'code',
74
+ inheritable: true,
75
+ }
76
+ }, [trixInstance])
77
+
78
+ const handleOnEditorReady = (editorInstance: Editor) => {
79
+ setEditor(editorInstance)
80
+
81
+ setTimeout(() => {
82
+ const oldId = editorInstance.element?.getAttribute('input')
83
+ if (!oldId) return
84
+
85
+ const hiddenInput = document.getElementById(oldId) as HTMLElement | null
86
+ if (!hiddenInput) return
87
+
88
+ const hiddenInputId = (inputOptions.id as string) || oldId
89
+
90
+ if (hiddenInputId !== oldId) {
91
+ hiddenInput.id = hiddenInputId
92
+ editorInstance.element?.setAttribute('input', hiddenInputId)
93
+ }
94
+
95
+ if (inputOptions.name) {
96
+ hiddenInput.setAttribute('name', inputOptions.name as string)
97
+ }
98
+
99
+ const editorDomId = (id as string) || `${hiddenInputId}_trix`
100
+ const trixLabelId = ((id as string) || hiddenInputId) + '-label'
101
+
102
+ if (label) {
103
+ editorInstance.element?.setAttribute('aria-labelledby', trixLabelId)
104
+ }
105
+ if (editorInstance.element) {
106
+ editorInstance.element.id = editorDomId
107
+ }
108
+ })
109
+ }
110
+
111
+ useEffect(() => {
112
+ if (!editor || !editor.element) return
113
+
114
+ const toolbarElement = editor.element.parentElement?.querySelector('trix-toolbar') as HTMLElement | null
115
+ if (!toolbarElement) return
116
+
117
+ const blockCodeButton = toolbarElement.querySelector('[data-trix-attribute=code]') as HTMLElement | null
118
+ if (!blockCodeButton) return
119
+
120
+ let inlineCodeButton = toolbarElement.querySelector('[data-trix-attribute=inlineCode]') as HTMLElement | null
121
+ if (!inlineCodeButton) {
122
+ inlineCodeButton = blockCodeButton.cloneNode(true) as HTMLElement
123
+ blockCodeButton.hidden = true
124
+ inlineCodeButton.dataset.trixAttribute = 'inlineCode'
125
+ blockCodeButton.insertAdjacentElement('afterend', inlineCodeButton)
126
+ }
127
+
128
+ if (toolbarBottom) {
129
+ editor.element.after(toolbarElement)
130
+ }
131
+ }, [editor, toolbarBottom])
132
+
133
+ useEffect(() => {
134
+ if (!focus) return
135
+
136
+ document.addEventListener('trix-focus', applyFocusState)
137
+ document.addEventListener('trix-blur', applyFocusState)
138
+ applyFocusState()
139
+
140
+ return () => {
141
+ document.removeEventListener('trix-focus', applyFocusState)
142
+ document.removeEventListener('trix-blur', applyFocusState)
143
+ }
144
+ }, [focus])
145
+
146
+ useEffect(() => {
147
+ document.addEventListener('trix-focus', inlineFocus)
148
+ document.addEventListener('trix-blur', inlineFocus)
149
+
150
+ return () => {
151
+ document.removeEventListener('trix-focus', inlineFocus)
152
+ document.removeEventListener('trix-blur', inlineFocus)
153
+ }
154
+ }, [])
155
+
156
+ useEffect(() => {
157
+ if (!editor || !template) return
158
+ editor.loadHTML && editor.loadHTML('')
159
+ editor.setSelectedRange && editor.setSelectedRange([0, 0])
160
+ editor.insertHTML && editor.insertHTML(template)
161
+ }, [editor, template])
162
+
163
+ useEffect(() => {
164
+ if (!editor?.element) return
165
+
166
+ const clickHandler = ({ target }: Event) => {
167
+ const trixEditorContainer = (target as Element).closest('.pb_rich_text_editor_kit')
168
+ if (!trixEditorContainer) return
169
+
170
+ const anchorElement = (target as Element).closest('a') as HTMLAnchorElement | null
171
+ if (!anchorElement) return
172
+
173
+ if (anchorElement.hasAttribute('href')) window.open(anchorElement.href)
174
+ }
175
+
176
+ editor.element.addEventListener('click', clickHandler)
177
+
178
+ return () => {
179
+ editor.element?.removeEventListener('click', clickHandler)
180
+ }
181
+ }, [editor])
182
+
183
+ if (!TrixEditor) {
184
+ return (
185
+ <div style={{ color: 'red', padding: '1em', border: '1px solid #f00', background: '#fff0f0' }}>
186
+ <strong>Trix Editor is not available.</strong>
187
+ <br />
188
+ Please import <code>TrixEditor</code> from <code>react-trix</code> and pass it as a prop to <code>RichTextEditor</code>.
189
+ <br />
190
+ <pre>{`import { TrixEditor } from 'react-trix';\n<RichTextEditor TrixEditor={TrixEditor} ... />`}</pre>
191
+ </div>
192
+ )
193
+ }
194
+
195
+ return React.createElement(TrixEditor, {
196
+ className: '',
197
+ fileParamName: name,
198
+ mergeTags: [],
199
+ onChange,
200
+ onEditorReady: handleOnEditorReady,
201
+ placeholder,
202
+ value,
203
+ })
204
+ }
205
+
206
+ export default TrixTextEditor