playbook_ui 16.7.0 → 16.8.0.pre.alpha.PLAY2935formbuilderrequiredindicatorbug16780

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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +2 -0
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +2 -0
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/VirtualizedTableView.tsx +5 -1
  5. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +24 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/Utilities/ColumnLayoutHelper.ts +138 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +144 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.jsx +1 -0
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.md +6 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_width.jsx +57 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_width.md +66 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_enable_toggle_expansion_rails.html.erb +62 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_enable_toggle_expansion_rails.md +7 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header.jsx +12 -4
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header.md +4 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header_rails.html.erb +16 -2
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_header_rails.md +4 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_scroll_limitation.jsx +68 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sticky_scroll_limitation.md +7 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.html.erb +16 -2
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.jsx +12 -5
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_rails.md +4 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_react.md +5 -3
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_playground.json +180 -5839
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_playground.overrides.json +5 -30
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_column_definitions_styling.json +4 -1
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +3 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -0
  29. data/app/pb_kits/playbook/pb_card/_card.tsx +1 -1
  30. data/app/pb_kits/playbook/pb_card/card.html.erb +1 -1
  31. data/app/pb_kits/playbook/pb_currency/_currency.tsx +9 -6
  32. data/app/pb_kits/playbook/pb_currency/currency.rb +5 -10
  33. data/app/pb_kits/playbook/pb_currency/currency.test.js +44 -1
  34. data/app/pb_kits/playbook/pb_date/docs/_playground.json +13 -17
  35. data/app/pb_kits/playbook/pb_date/docs/_playground.overrides.json +13 -16
  36. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +3 -2
  37. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +38 -23
  38. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +2 -1
  39. data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +31 -0
  40. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_dialog_submission.jsx +2 -2
  41. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.html.erb +0 -2
  42. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.jsx +0 -2
  43. data/app/pb_kits/playbook/pb_date_picker/docs/_playground.json +136 -42
  44. data/app/pb_kits/playbook/pb_date_picker/docs/_playground.overrides.json +113 -45
  45. data/app/pb_kits/playbook/pb_date_range_inline/docs/_playground.json +48 -6
  46. data/app/pb_kits/playbook/pb_date_range_inline/docs/_playground.overrides.json +57 -0
  47. data/app/pb_kits/playbook/pb_date_range_stacked/docs/_playground.json +28 -5
  48. data/app/pb_kits/playbook/pb_date_range_stacked/docs/_playground.overrides.json +38 -0
  49. data/app/pb_kits/playbook/pb_date_stacked/docs/_playground.json +1 -1
  50. data/app/pb_kits/playbook/pb_date_stacked/docs/_playground.overrides.json +1 -1
  51. data/app/pb_kits/playbook/pb_date_time/docs/_playground.json +16 -3
  52. data/app/pb_kits/playbook/pb_date_time/docs/_playground.overrides.json +16 -3
  53. data/app/pb_kits/playbook/pb_date_time_stacked/docs/_playground.json +11 -15
  54. data/app/pb_kits/playbook/pb_date_time_stacked/docs/_playground.overrides.json +11 -15
  55. data/app/pb_kits/playbook/pb_date_year_stacked/docs/_playground.json +4 -4
  56. data/app/pb_kits/playbook/pb_date_year_stacked/docs/_playground.overrides.json +4 -4
  57. data/app/pb_kits/playbook/pb_detail/docs/_playground.json +12 -18
  58. data/app/pb_kits/playbook/pb_detail/docs/_playground.overrides.json +13 -12
  59. data/app/pb_kits/playbook/pb_dialog/docs/_playground.json +108 -42
  60. data/app/pb_kits/playbook/pb_dialog/docs/_playground.overrides.json +88 -40
  61. data/app/pb_kits/playbook/pb_distribution_bar/docs/_playground.json +65 -7
  62. data/app/pb_kits/playbook/pb_distribution_bar/docs/_playground.overrides.json +45 -0
  63. data/app/pb_kits/playbook/pb_draggable/_draggable.scss +19 -0
  64. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.md +2 -0
  65. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_react.md +1 -0
  66. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_rails.md +2 -0
  67. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_react.md +3 -1
  68. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_selectable_list_rails.md +3 -1
  69. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_selectable_list_react.md +3 -1
  70. data/app/pb_kits/playbook/pb_draggable/draggable.test.jsx +16 -0
  71. data/app/pb_kits/playbook/pb_draggable/draggable_container.html.erb +3 -1
  72. data/app/pb_kits/playbook/pb_draggable/draggable_item.html.erb +1 -0
  73. data/app/pb_kits/playbook/pb_draggable/index.js +149 -7
  74. data/app/pb_kits/playbook/pb_draggable/subcomponents/DraggableContainer.tsx +1 -0
  75. data/app/pb_kits/playbook/pb_draggable/subcomponents/DraggableItem.tsx +67 -1
  76. data/app/pb_kits/playbook/pb_draggable/touchDrag.test.js +38 -0
  77. data/app/pb_kits/playbook/pb_draggable/utilities/touchDrag.ts +173 -0
  78. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.json +318 -21
  79. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json +192 -19
  80. data/app/pb_kits/playbook/pb_empty_state/docs/_playground.json +77 -12
  81. data/app/pb_kits/playbook/pb_empty_state/docs/_playground.overrides.json +79 -0
  82. data/app/pb_kits/playbook/pb_file_upload/docs/_playground.json +98 -13
  83. data/app/pb_kits/playbook/pb_file_upload/docs/_playground.overrides.json +99 -0
  84. data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb +20 -19
  85. data/app/pb_kits/playbook/pb_icon/_icon.scss +2 -1
  86. data/app/pb_kits/playbook/pb_icon/docs/example.yml +0 -2
  87. data/app/pb_kits/playbook/pb_icon/docs/index.js +0 -1
  88. data/app/pb_kits/playbook/pb_link/docs/_playground.json +81 -40
  89. data/app/pb_kits/playbook/pb_link/docs/_playground.overrides.json +88 -30
  90. data/app/pb_kits/playbook/pb_list/_list_item.tsx +4 -1
  91. data/app/pb_kits/playbook/pb_list/item.html.erb +1 -1
  92. data/app/pb_kits/playbook/pb_pb_circle_chart/docs/_pb_circle_chart_centered_data.html.erb +90 -0
  93. data/app/pb_kits/playbook/pb_pb_circle_chart/docs/_pb_circle_chart_centered_data.jsx +100 -0
  94. data/app/pb_kits/playbook/pb_pb_circle_chart/docs/_pb_circle_chart_centered_data.md +1 -0
  95. data/app/pb_kits/playbook/pb_pb_circle_chart/docs/_pb_circle_chart_default.jsx +1 -1
  96. data/app/pb_kits/playbook/pb_pb_circle_chart/docs/example.yml +2 -0
  97. data/app/pb_kits/playbook/pb_pb_circle_chart/docs/index.js +2 -1
  98. data/app/pb_kits/playbook/pb_phone_number_input/docs/_playground.json +4 -2
  99. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +1 -1
  100. data/app/pb_kits/playbook/pb_rich_text_editor/_tiptap_styles.scss +262 -43
  101. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.html.erb +1 -0
  102. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.md +12 -0
  103. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_simple.html.erb +9 -0
  104. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_simple.md +8 -0
  105. data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +2 -0
  106. data/app/pb_kits/playbook/pb_rich_text_editor/kit.schema.json +18 -9
  107. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb +162 -0
  108. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.rb +71 -0
  109. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.js +202 -0
  110. data/app/pb_kits/playbook/pb_table/docs/_table_sticky.html.erb +85 -83
  111. data/app/pb_kits/playbook/pb_table/docs/_table_sticky.jsx +88 -86
  112. data/app/pb_kits/playbook/pb_table/docs/_table_sticky.md +3 -1
  113. data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_variant_external_filter_rails.md +1 -1
  114. data/app/pb_kits/playbook/pb_text_input/_text_input.scss +37 -0
  115. data/app/pb_kits/playbook/pb_title/docs/_playground.json +72 -23
  116. data/app/pb_kits/playbook/pb_title/docs/_playground.overrides.json +80 -16
  117. data/app/pb_kits/playbook/pb_tooltip/_tooltip.scss +133 -102
  118. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +54 -41
  119. data/app/pb_kits/playbook/pb_tooltip/tooltip.test.jsx +60 -2
  120. data/dist/chunks/{_pb_line_graph-CIWJe3Gr.js → _pb_line_graph-BgsTI0CL.js} +1 -1
  121. data/dist/chunks/_typeahead-DA__Kgp5.js +5 -0
  122. data/dist/chunks/{globalProps-CqO4Tko1.js → globalProps-DOB47YGB.js} +1 -1
  123. data/dist/chunks/{lib-czQnE40X.js → lib-BzglXly2.js} +2 -2
  124. data/dist/chunks/vendor.js +4 -4
  125. data/dist/menu.yml +71 -132
  126. data/dist/playbook-rails-react-bindings.js +1 -1
  127. data/dist/playbook-rails.js +1 -1
  128. data/dist/playbook.css +1 -1
  129. data/lib/playbook/forms/builder/form_field_builder.rb +2 -0
  130. data/lib/playbook/version.rb +2 -2
  131. metadata +31 -10
  132. data/app/pb_kits/playbook/pb_icon/docs/_icon_fa_kit.html.erb +0 -1
  133. data/app/pb_kits/playbook/pb_icon/docs/_icon_fa_kit.jsx +0 -21
  134. data/app/pb_kits/playbook/pb_icon/docs/_icon_fa_kit.md +0 -7
  135. data/dist/chunks/_typeahead-B_Ac4z84.js +0 -1
@@ -0,0 +1,100 @@
1
+ import React from "react";
2
+ import PbCircleChart from "../_pb_circle_chart";
3
+
4
+ const data = [
5
+ {
6
+ name: "EV",
7
+ y: 23.9,
8
+ },
9
+ {
10
+ name: "Hybrids",
11
+ y: 12.6,
12
+ },
13
+ {
14
+ name: "Diesel",
15
+ y: 37.0,
16
+ },
17
+ {
18
+ name: "Petrol",
19
+ y: 26.4,
20
+ },
21
+ ];
22
+
23
+ const total = data.reduce((sum, point) => sum + point.y, 0);
24
+ const subtitleRows = data.map((point) => `${point.name}: ${point.y}%`).join("<br>");
25
+
26
+ const chartOptions = {
27
+ chart: {
28
+ type: "pie",
29
+ },
30
+ accessibility: {
31
+ point: {
32
+ valueSuffix: "%",
33
+ },
34
+ },
35
+ title: {
36
+ text: "2023 Norway car registrations",
37
+ floating: true,
38
+ align: "center",
39
+ verticalAlign: "top",
40
+ y: 8,
41
+ },
42
+ subtitle: {
43
+ text: `Total<br><strong>${total.toFixed(1)}</strong><br><br>${subtitleRows}`,
44
+ useHTML: true,
45
+ floating: true,
46
+ align: "center",
47
+ verticalAlign: "middle",
48
+ y: 8,
49
+ style: {
50
+ textAlign: "center",
51
+ },
52
+ },
53
+ tooltip: {
54
+ pointFormat: "{series.name}: <b>{point.percentage:.0f}%</b>",
55
+ },
56
+ legend: {
57
+ enabled: false,
58
+ },
59
+ plotOptions: {
60
+ series: {
61
+ allowPointSelect: true,
62
+ cursor: "pointer",
63
+ borderRadius: 8,
64
+ dataLabels: [
65
+ {
66
+ enabled: true,
67
+ distance: 20,
68
+ format: "{point.name}",
69
+ },
70
+ {
71
+ enabled: true,
72
+ distance: -15,
73
+ format: "{point.percentage:.0f}%",
74
+ style: {
75
+ fontSize: "0.9em",
76
+ },
77
+ },
78
+ ],
79
+ showInLegend: true,
80
+ },
81
+ },
82
+ series: [
83
+ {
84
+ name: "Registrations",
85
+ colorByPoint: true,
86
+ center: ["50%", "50%"],
87
+ innerSize: "75%",
88
+ data,
89
+ },
90
+ ],
91
+ };
92
+
93
+ const PbCircleChartCenteredData = (props) => (
94
+ <PbCircleChart
95
+ options={chartOptions}
96
+ {...props}
97
+ />
98
+ );
99
+
100
+ export default PbCircleChartCenteredData;
@@ -0,0 +1 @@
1
+ This example shows how to achieve centered data. This data will remain in the center of all screen sizes.
@@ -30,4 +30,4 @@ const PbCircleChartDefault = (props) => (
30
30
  </div>
31
31
  );
32
32
 
33
- export default PbCircleChartDefault;
33
+ export default PbCircleChartDefault;
@@ -11,6 +11,7 @@ examples:
11
11
  - pb_circle_chart_with_title: With Title
12
12
  - pb_circle_chart_inner_sizes: Inner Circle Size Options
13
13
  - pb_circle_chart_custom_tooltip: Tooltip Customization
14
+ - pb_circle_chart_centered_data: Centered Data
14
15
 
15
16
 
16
17
  react:
@@ -25,5 +26,6 @@ examples:
25
26
  - pb_circle_chart_with_title: With Title
26
27
  - pb_circle_chart_inner_sizes: Inner Circle Size Options
27
28
  - pb_circle_chart_custom_tooltip: Tooltip Customization
29
+ - pb_circle_chart_centered_data: Centered Data
28
30
 
29
31
 
@@ -8,4 +8,5 @@ export { default as PbCircleChartDataWithLegend } from './_pb_circle_chart_data_
8
8
  export { default as PbCircleChartDataLegendPosition } from './_pb_circle_chart_data_legend_position.jsx'
9
9
  export { default as PbCircleChartWithTitle } from './_pb_circle_chart_with_title.jsx'
10
10
  export { default as PbCircleChartInnerSizes } from './_pb_circle_chart_inner_sizes.jsx'
11
- export { default as PbCircleChartCustomTooltip } from './_pb_circle_chart_custom_tooltip.jsx'
11
+ export { default as PbCircleChartCustomTooltip } from './_pb_circle_chart_custom_tooltip.jsx'
12
+ export { default as PbCircleChartCenteredData } from './_pb_circle_chart_centered_data.jsx'
@@ -13,7 +13,8 @@
13
13
  "value": "",
14
14
  "formatAsYouType": false,
15
15
  "strictMode": false,
16
- "countrySearch": false
16
+ "countrySearch": false,
17
+ "showPlaceholder": false
17
18
  },
18
19
  "groups": [
19
20
  {
@@ -37,7 +38,8 @@
37
38
  "value",
38
39
  "formatAsYouType",
39
40
  "strictMode",
40
- "countrySearch"
41
+ "countrySearch",
42
+ "showPlaceholder"
41
43
  ]
42
44
  }
43
45
  ],
@@ -142,7 +142,7 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
142
142
  // Determine if toolbar should be shown
143
143
  const shouldShowToolbar = focus && advancedEditor ? showToolbarOnFocus : advancedEditorToolbar
144
144
 
145
- const labelFor = advancedEditor ? fieldId : (id ? id : (inputOptions.id ? `${inputOptions.id}_trix` : undefined))
145
+ const labelFor = advancedEditor ? fieldId : (id ? id : (inputOptions?.id ? `${inputOptions.id}_trix` : undefined))
146
146
 
147
147
  return (
148
148
  <div
@@ -8,38 +8,53 @@
8
8
  @import "../tokens/transition";
9
9
  @import "previewer_mixin";
10
10
 
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 $input_border_default;
29
- border-top: none;
30
- }
31
-
32
- &:hover {
33
- .toolbar {
34
- opacity: 100;
35
- }
36
-
37
- .ProseMirror {
38
- border: 1px solid $input_border_default;
39
- border-top: none;
40
- }
41
- }
11
+ // Rails TipTap root: flex/grid children default to min-width: auto, so the toolbar’s
12
+ // intrinsic width can force horizontal page/dialog scroll. Pin the kit to the parent width.
13
+ [data-pb-rte-tiptap="true"] {
14
+ box-sizing: border-box;
15
+ display: block;
16
+ max-width: 100%;
17
+ min-width: 0;
18
+ width: 100%;
19
+ }
20
+
21
+ .pb_rich_text_editor_kit {
22
+ box-sizing: border-box;
23
+ max-width: 100%;
24
+ min-width: 0;
25
+
26
+ &.inline {
27
+ .toolbar {
28
+ opacity: 0;
29
+ transition: all 0.3s ease-in-out 0s;
30
+ }
31
+
32
+ &:focus-within .toolbar {
33
+ opacity: 100;
34
+ }
35
+
36
+ .ProseMirror {
37
+ border: 1px solid transparent;
38
+ transition: all 0.3s ease-in-out 0s;
39
+ }
40
+
41
+ &:focus-within .ProseMirror {
42
+ border: 1px solid $input_border_default;
43
+ border-top: none;
44
+ }
45
+
46
+ &:hover {
47
+ .toolbar {
48
+ opacity: 100;
49
+ }
50
+
51
+ .ProseMirror {
52
+ border: 1px solid $input_border_default;
53
+ border-top: none;
42
54
  }
55
+ }
56
+ }
57
+
43
58
  .toolbar_button {
44
59
  display: flex;
45
60
  align-items: center;
@@ -73,18 +88,76 @@
73
88
  }
74
89
  }
75
90
 
91
+ // Active state for toolbar (Rails kit uses pb_button_kit pb_button_link; override link variant when active)
92
+ .toolbar button.pb_button_kit.is-active {
93
+ color: $primary;
94
+ background-color: $bg_light;
95
+ }
96
+
76
97
  .pb_rich_text_editor_tiptap_toolbar_sticky {
77
98
  position: sticky;
78
99
  top: 0;
79
100
  z-index: 10;
80
101
  }
102
+
103
+ .rte-editor-wrap {
104
+ box-sizing: border-box;
105
+ max-width: 100%;
106
+ min-width: 0;
107
+ }
108
+
109
+ .pb_rich_text_editor_advanced_container {
110
+ max-width: 100%;
111
+ min-width: 0;
112
+ }
113
+
81
114
  .toolbar {
82
115
  border-radius: $border_rad_heaviest $border_rad_heaviest 0 0;
83
116
  border: 1px solid $input_border_default;
84
117
  overflow-x: auto;
118
+ // Single horizontal row + scroll in narrow modals/sidebars (wrap used to stack controls vertically).
85
119
  &_block {
120
+ align-items: center;
121
+ display: flex;
122
+ flex-wrap: nowrap;
86
123
  gap: $space_xs;
124
+ min-width: 0;
125
+ overflow-x: auto;
126
+ -webkit-overflow-scrolling: touch;
127
+ }
128
+
129
+ // React: full-width row with history on the far right; horizontal scroll stays on .toolbar.
130
+ &:not(.rte-rails-toolbar-layout) {
131
+ > .pb_flex_kit.pb_flex_kit_justify_content_between {
132
+ box-sizing: border-box;
133
+ column-gap: $space_sm;
134
+ flex-wrap: nowrap;
135
+ justify-content: space-between;
136
+ min-width: 100%;
137
+ width: max-content;
138
+ }
139
+
140
+ > .pb_flex_kit > .pb_flex_item_kit.toolbar_block {
141
+ flex: 0 0 auto;
142
+ min-width: 0;
143
+ overflow-x: visible;
144
+ }
145
+
146
+ > .pb_flex_kit > .pb_flex_item_kit:last-child {
147
+ flex: 0 0 auto;
148
+ }
87
149
  }
150
+
151
+ // Vertical section separators use ::before/::after with height: 100%. With
152
+ // align-items: center on .toolbar_block the kit’s cross size was 0, so the
153
+ // lines disappeared (master only had gap on .toolbar_block, default stretch).
154
+ .pb_section_separator_kit.pb_section_separator_vertical {
155
+ align-self: center;
156
+ flex-shrink: 0;
157
+ height: $space_xl;
158
+ }
159
+
160
+ // React ToolbarDropdown — match master (fixed width trigger; prod playbook.cloud).
88
161
  .editor-dropdown-button {
89
162
  background: transparent;
90
163
  border: none;
@@ -93,23 +166,115 @@
93
166
  font-weight: $light;
94
167
  padding: ($space_xs - 1) 0px;
95
168
  width: $space_xl * 3;
169
+
96
170
  &:focus-visible {
97
171
  box-shadow: unset;
98
172
  }
99
173
  }
174
+
175
+ &.rte-rails-toolbar-layout {
176
+ max-width: 100%;
177
+ min-width: 0;
178
+
179
+ .rte-rails-toolbar-row {
180
+ align-items: center;
181
+ box-sizing: border-box;
182
+ column-gap: $space_sm;
183
+ display: flex;
184
+ flex-wrap: nowrap;
185
+ justify-content: space-between;
186
+ min-width: 100%;
187
+ padding: $space_xxs $space_sm;
188
+ width: max-content;
189
+ }
190
+
191
+ .rte-toolbar-left {
192
+ align-items: center;
193
+ display: flex;
194
+ flex: 0 0 auto;
195
+ flex-wrap: nowrap;
196
+ gap: $space_xs;
197
+ min-width: 0;
198
+ overflow-x: visible;
199
+ }
200
+
201
+ .rte-toolbar-right {
202
+ align-items: center;
203
+ display: flex;
204
+ flex: 0 0 auto;
205
+ gap: $space_xs;
206
+ }
207
+
208
+ // Align dropdown trigger with icon row (React wraps Popover + SectionSeparator in one flex line).
209
+ .pb_popover_reference_wrapper {
210
+ align-items: center;
211
+ display: inline-flex;
212
+ }
213
+
214
+ // Override master’s fixed-width React trigger: Rails block-style label + icons needs flexible width.
215
+ .editor-dropdown-button {
216
+ justify-content: flex-start;
217
+ letter-spacing: normal;
218
+ line-height: 1;
219
+ max-width: 100%;
220
+ min-height: unset;
221
+ padding: ($space_xs - 1) $space_xs;
222
+ text-align: left;
223
+ width: auto;
224
+
225
+ .pb_button_content {
226
+ align-items: center;
227
+ display: inline-flex;
228
+ line-height: 1;
229
+ }
230
+
231
+ .pb_button_content > .pb_flex_kit {
232
+ align-items: center;
233
+ }
234
+
235
+ .rte-block-style-trigger-inner {
236
+ align-items: center;
237
+ }
238
+
239
+ .rte-block-style-trigger-icon,
240
+ .rte-block-style-chevron {
241
+ display: inline-flex;
242
+ flex-shrink: 0;
243
+ line-height: 0;
244
+
245
+ .pb_icon_kit {
246
+ align-items: center;
247
+ display: flex;
248
+ line-height: 0;
249
+ }
250
+
251
+ svg {
252
+ display: block;
253
+ }
254
+ }
255
+
256
+ .rte-block-style-trigger-label {
257
+ align-items: center;
258
+ display: inline-flex;
259
+ line-height: 1.2;
260
+ }
261
+
262
+ &:focus-visible {
263
+ box-shadow: unset;
264
+ }
265
+ }
266
+ }
100
267
  }
101
268
 
269
+ // TipTap content — match master (prod playbook React tab).
102
270
  .ProseMirror {
103
271
  background: $white;
104
272
  border: 1px solid $input_border_default;
105
273
  border-radius: $border_rad_heaviest;
106
274
  height: 100%;
107
- padding: 1rem 1.5rem 1.5rem 1.5rem;
108
275
  line-height: $lh_loose;
276
+ padding: 1rem 1.5rem 1.5rem 1.5rem;
109
277
  @include transition_default;
110
- :first-child {
111
- margin-top: 0;
112
- }
113
278
 
114
279
  h4,
115
280
  h5,
@@ -161,9 +326,32 @@
161
326
  ul {
162
327
  @include preview_tiptap_ul;
163
328
  }
329
+
330
+ // After heading mixins: first block should not pick up extra top margin (wins over `p { margin-top: 1rem }`).
331
+ > :first-child {
332
+ margin-top: 0;
333
+ }
334
+ }
335
+
336
+ // Toolbar + editor stack: toolbar keeps its border; editor has no top stroke (classic layout).
337
+ // Avoid relying on a wrapper-only frame — partial deploys then looked “borderless” because
338
+ // ProseMirror had been forced to border: none.
339
+ .pb_rich_text_editor_advanced_container.toolbar-active {
340
+ .ProseMirror {
341
+ border-top: none;
342
+ border-top-left-radius: initial;
343
+ border-top-right-radius: initial;
344
+ }
164
345
  }
165
346
  }
166
347
 
348
+ // Rails-only: outer kit sets `data-pb-rte-tiptap` — roomier padding + wrapping for vanilla TipTap in forms/dialogs.
349
+ [data-pb-rte-tiptap="true"] .pb_rich_text_editor_kit .ProseMirror {
350
+ overflow-wrap: anywhere;
351
+ padding: 1.25rem 1.5rem 1.5rem 1.5rem;
352
+ word-break: break-word;
353
+ }
354
+
167
355
  .pb_tiptap_toolbar_dropdown_list_item {
168
356
  &.is-active,
169
357
  &:active {
@@ -188,20 +376,51 @@
188
376
  }
189
377
  }
190
378
  }
191
- .pb_rich_text_editor_advanced_container {
379
+
380
+ // Rails RTE: block-style menu uses Nav (popover) instead of React NavItem class hook.
381
+ .pb_rich_text_editor_kit .pb_popover_tooltip .pb_nav_list_item_link.is-active {
382
+ background-color: $bg_light;
383
+ border-radius: unset !important;
384
+ color: $primary;
385
+
386
+ .pb_nav_list_item_text,
387
+ .pb_nav_list_item_icon_left {
388
+ color: $primary !important;
389
+ }
390
+ }
391
+
392
+ .pb_rich_text_editor_kit .pb_popover_tooltip .pb_nav_list_kit_item:hover .pb_nav_list_item_link:not(.is-active) {
393
+ background-color: $neutral_subtle;
394
+ border-radius: unset !important;
395
+
396
+ .pb_nav_list_item_text,
397
+ .pb_nav_list_item_icon_left {
398
+ background-color: unset;
399
+ color: $text_lt_light !important;
400
+ }
401
+ }
402
+
403
+ // No toolbar: ring the whole control.
404
+ .pb_rich_text_editor_advanced_container:not(.toolbar-active) {
192
405
  transition: box-shadow 0.3s ease-in-out, border-radius 0.3s ease-in-out;
193
406
  &:focus-visible,
194
407
  &:focus-within {
195
- outline: unset;
196
- box-shadow: 0 0 0 1px $input_border_state;
197
408
  border-radius: $border_rad_heaviest;
409
+ box-shadow: 0 0 0 1px $input_border_state;
410
+ outline: unset;
198
411
  transition: box-shadow 0.3s ease-in-out, border-radius 0.3s ease-in-out;
199
412
  }
200
- &.toolbar-active {
201
- .ProseMirror {
202
- border-top: none;
203
- border-top-left-radius: initial;
204
- border-top-right-radius: initial;
413
+ }
414
+
415
+ // Toolbar + editor: use border color (not an outer box-shadow) so the bottom isn’t doubled.
416
+ .pb_rich_text_editor_advanced_container.toolbar-active {
417
+ &:focus-within {
418
+ .toolbar {
419
+ border-color: $input_border_state;
420
+ }
421
+
422
+ .ProseMirror {
423
+ border-color: $input_border_state;
205
424
  }
206
425
  }
207
426
  }
@@ -0,0 +1 @@
1
+ <%= pb_rails("rich_text_editor", props: { input_options: { id: 'hidden_input_id', name: "hidden_input_name" }, value: "Add your text here. You can format your text, add links, quotes, and bullets." }) %>
@@ -0,0 +1,12 @@
1
+ The Rails rich text editor is a TipTap surface with no React. The UI (toolbar, block-style menu, formatting actions) is rendered with Playbook Rails kits (`pb_rails`). The editor document is a vanilla TipTap `Editor` instance; HTML is synced to a hidden `<input>` so standard Rails forms can submit the value.
2
+
3
+ ### How TipTap is loaded (Rails)
4
+
5
+ - The kit’s module script (`rich_text_editor_rails.js`) uses `import()` with **full URLs** on [esm.sh](https://esm.sh) (e.g. `@tiptap/core@2.8.0`). esm.sh resolves dependencies server-side, so **no `<script type="importmap">`** is required—this avoids conflicts when the host page already has an import map (e.g. Vite in dev, or another app map) because Firefox only applies one native map.
6
+ - You do not need TipTap in your app’s npm dependencies or Gemfile for this kit; the browser loads modules from esm.sh when the page runs.
7
+ - Ensure **CSP** allows loading scripts from `https://esm.sh` (and esm.sh’s redirected module URLs) if you use a strict `script-src` / `connect-src`.
8
+
9
+ ### Relation to the React implementation
10
+
11
+ - Same core: both use TipTap v2 on top of ProseMirror; styling lives in Playbook SCSS (`_tiptap_styles.scss`) so the editor chrome lines up between platforms.
12
+ - Different shell: Rails uses ERB + Playbook Rails components + inline module script. React uses `RichTextEditor` / `_tiptap_editor.tsx` and TipTap wired through the bundled Playbook React package—see Advanced Default for that stack and when you need TipTap installed in your JavaScript bundle.
@@ -0,0 +1,9 @@
1
+ <%= pb_rails("rich_text_editor", props: {
2
+ simple: true,
3
+ label: "Notes",
4
+ input_options: {
5
+ id: "rails_rte_simple_demo",
6
+ name: "content",
7
+ },
8
+ value: "<p>Use <strong>Bold</strong> and <em>Italic</em> from the toolbar.</p>",
9
+ }) %>
@@ -0,0 +1,8 @@
1
+ ### Simple toolbar (`simple: true`)
2
+
3
+ Pass **`simple: true`** for a compact toolbar: **Bold**, **Italic**, **Undo**, and **Redo** (same history controls as the full toolbar—plain buttons, not popovers).
4
+
5
+ - No block-style dropdown (no “Paragraph” / headings / lists in the menu).
6
+ - No **`pb_popover`** on the toolbar—useful in **native `<dialog>`** modals, turbo-loaded panels, or other tight layouts where the full block menu is awkward to position.
7
+
8
+ The underlying TipTap document still accepts the same HTML as the default Rails editor; `simple` only changes which **toolbar controls** are shown.
@@ -1,6 +1,8 @@
1
1
  examples:
2
2
 
3
3
  rails:
4
+ - rich_text_editor_rails_default: "Rails (TipTap)"
5
+ - rich_text_editor_rails_simple: "Rails (TipTap — Simple toolbar)"
4
6
 
5
7
  react:
6
8
  - rich_text_editor_advanced_default: Advanced Default
@@ -3,7 +3,8 @@
3
3
  "name": "RichTextEditor",
4
4
  "description": "RichTextEditor component",
5
5
  "platforms": [
6
- "react"
6
+ "react",
7
+ "rails"
7
8
  ],
8
9
  "props": {
9
10
  "advancedEditor": {
@@ -33,7 +34,8 @@
33
34
  "inputOptions": {
34
35
  "type": "GenericObject",
35
36
  "platforms": [
36
- "react"
37
+ "react",
38
+ "rails"
37
39
  ]
38
40
  },
39
41
  "inline": {
@@ -45,7 +47,8 @@
45
47
  "label": {
46
48
  "type": "string",
47
49
  "platforms": [
48
- "react"
50
+ "react",
51
+ "rails"
49
52
  ]
50
53
  },
51
54
  "extensions": {
@@ -69,7 +72,8 @@
69
72
  "placeholder": {
70
73
  "type": "string",
71
74
  "platforms": [
72
- "react"
75
+ "react",
76
+ "rails"
73
77
  ]
74
78
  },
75
79
  "inputHeight": {
@@ -97,14 +101,18 @@
97
101
  "requiredIndicator": {
98
102
  "type": "boolean",
99
103
  "platforms": [
100
- "react"
101
- ]
104
+ "react",
105
+ "rails"
106
+ ],
107
+ "default": false
102
108
  },
103
109
  "simple": {
104
110
  "type": "boolean",
105
111
  "platforms": [
106
- "react"
107
- ]
112
+ "react",
113
+ "rails"
114
+ ],
115
+ "default": false
108
116
  },
109
117
  "sticky": {
110
118
  "type": "boolean",
@@ -121,7 +129,8 @@
121
129
  "value": {
122
130
  "type": "string",
123
131
  "platforms": [
124
- "react"
132
+ "react",
133
+ "rails"
125
134
  ]
126
135
  },
127
136
  "maxWidth": {