playbook_ui 16.8.0.pre.rc.1 → 16.8.0.pre.rc.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d85756c416854181a9ff336cf3a2d5d309eda400c625e2f8918138a43b5f1db
4
- data.tar.gz: 00f5ae67a0b0a9fc0e3f5be1e80cd496f934ce7a5c1a86ab134b2322a801f670
3
+ metadata.gz: 6a14d120d9cb3e0ab1458d5b4839ae3487e39835478477c1367b778fef93ada0
4
+ data.tar.gz: 894570ff3e83416909da2778cf54b9c609ee6cc639d4a408e2d06181209903b6
5
5
  SHA512:
6
- metadata.gz: 2809a740ff1791c3b2f02a7b3518ab61ada18eda506c47f1551d8597e2f73d5a535b1aa95c8b6ee0f74b191ddbaa03541524cab321fad3abd6c2b3a596b29236
7
- data.tar.gz: bd8d5a58bb0f5e52cd8b4c1c15e80d15c135afee01d28bab68e8fe868cb988afaf28a8ab18e07abe3cde03247e142bad5c19090f8b0df3c6effce07682d9513e
6
+ metadata.gz: 9eaf2abe5bb9fe7ecdc3dfac5e408e6cb6a25cbb6c969592b7233bba1c2b838f60984c3c92764b77483fb290f922554afeac8981a8a5f57437ceb9bbf5da2f61
7
+ data.tar.gz: 155aaa6c9bb92a86fcdfbe35c7b62708d320940330b61aea3fbe6a56d5249de38f6bf1c8ba9d467e01f9ce5fc732e57ba636a9270ad1c54c2d93cbad2e645b4b
@@ -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": {
@@ -0,0 +1,162 @@
1
+ <%# TipTap loads via full URL dynamic import() in rich_text_editor_rails.js (esm.sh) — no import map, so no clash with Vite/host maps. %>
2
+ <%= pb_content_tag(:div, id: object.container_id, class: object.classname, data: { pb_rte_tiptap: true, input_id: object.input_id, initial_html: object.initial_html, rte_simple: object.simple }) do %>
3
+ <div class="pb_rich_text_editor_kit">
4
+ <% if object.label.present? %>
5
+ <label for="<%= object.input_id %>">
6
+ <% if object.required_indicator %>
7
+ <%= pb_rails("caption", props: { color: "lighter", text: object.label, dark: object.dark }) %><span style="color: #DA0014;"> *</span>
8
+ <% else %>
9
+ <%= pb_rails("caption", props: { color: "lighter", text: object.label, dark: object.dark }) %>
10
+ <% end %>
11
+ </label>
12
+ <% end %>
13
+ <input type="hidden" name="<%= object.input_name %>" id="<%= object.input_id %>" value="" />
14
+ <div class="pb_rich_text_editor_advanced_container toolbar-active<%= " pb_rich_text_editor_rte--simple" if object.simple %>">
15
+ <% if object.simple %>
16
+ <%# Compact toolbar: Bold/Italic + Undo/Redo — no block-style Popover (avoids dialog positioning issues). %>
17
+ <div class="pb_background_kit pb_background_color_white toolbar rte-rails-toolbar-layout rte-rails-toolbar-layout--simple" id="<%= object.toolbar_id %>">
18
+ <div class="rte-rails-toolbar-row">
19
+ <div class="toolbar_block rte-toolbar-left">
20
+ <button type="button" class="toolbar_button" data-action="bold" title="Bold" role="button" tabindex="0">
21
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
22
+ <%= pb_rails("icon", props: { icon: "bold", size: "lg" }) %>
23
+ <% end %>
24
+ </button>
25
+ <button type="button" class="toolbar_button" data-action="italic" title="Italic" role="button" tabindex="0">
26
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
27
+ <%= pb_rails("icon", props: { icon: "italic", size: "lg" }) %>
28
+ <% end %>
29
+ </button>
30
+ </div>
31
+ <div class="toolbar_block rte-toolbar-right">
32
+ <button type="button" class="toolbar_button" data-action="undo" title="Undo" role="button" tabindex="0">
33
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
34
+ <%= pb_rails("icon", props: { icon: "undo", size: "lg" }) %>
35
+ <% end %>
36
+ </button>
37
+ <button type="button" class="toolbar_button" data-action="redo" title="Redo" role="button" tabindex="0">
38
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
39
+ <%= pb_rails("icon", props: { icon: "redo", size: "lg" }) %>
40
+ <% end %>
41
+ </button>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ <% else %>
46
+ <% block_style_options = [
47
+ { value: "paragraph", text: "Paragraph", icon: "paragraph" },
48
+ { value: "heading-1", text: "Heading 1", icon: "h1" },
49
+ { value: "heading-2", text: "Heading 2", icon: "h2" },
50
+ { value: "heading-3", text: "Heading 3", icon: "h3" },
51
+ { value: "bulletList", text: "Bullet List", icon: "list" },
52
+ { value: "orderedList", text: "Ordered List", icon: "list-ol" },
53
+ { value: "blockquote", text: "Block Quote", icon: "block-quote" },
54
+ ] %>
55
+ <div class="pb_background_kit pb_background_color_white toolbar rte-rails-toolbar-layout" id="<%= object.toolbar_id %>">
56
+ <div class="rte-rails-toolbar-row">
57
+ <div class="toolbar_block rte-toolbar-left">
58
+ <span class="pb_popover_reference_wrapper">
59
+ <%# Button kit wraps content in <span class="pb_button_content"> — block <div>s inside are invalid and break layout. Single <span> row + JS sync from templates. %>
60
+ <%= pb_rails("button", props: {
61
+ id: object.rte_block_style_trigger_id,
62
+ variant: "secondary",
63
+ classname: "editor-dropdown-button",
64
+ html_options: {
65
+ type: "button",
66
+ "aria-label": "Text style",
67
+ "aria-haspopup": "true",
68
+ },
69
+ }) do %>
70
+ <span class="pb_flex_kit pb_flex_kit_orientation_row pb_flex_kit_justify_content_left pb_flex_kit_align_items_center pb_flex_kit_spacing_none pb_flex_kit_gap_xs gap_xs rte-block-style-trigger-inner" data-rte-block-trigger>
71
+ <span class="rte-block-style-trigger-icon">
72
+ <%= pb_rails("icon", props: { icon: "paragraph", size: "lg" }) %>
73
+ </span>
74
+ <span class="rte-block-style-trigger-label">Paragraph</span>
75
+ <span class="display_inline_flex rte-block-style-chevron">
76
+ <%= pb_rails("icon", props: { icon: "chevron-down", fixed_width: true }) %>
77
+ </span>
78
+ </span>
79
+ <% end %>
80
+ </span>
81
+ <%= pb_rails("popover", props: {
82
+ trigger_element_id: object.rte_block_style_trigger_id,
83
+ tooltip_id: object.rte_block_style_tooltip_id,
84
+ position: "bottom",
85
+ padding: "none",
86
+ close_on_click: "any",
87
+ offset: true,
88
+ }) do %>
89
+ <%= pb_rails("nav", props: { variant: "subtle", padding_top: "xs", padding_bottom: "xs" }) do %>
90
+ <% block_style_options.each do |opt| %>
91
+ <%= pb_rails("nav/item", props: {
92
+ link: "##{opt[:value]}",
93
+ text: opt[:text],
94
+ icon_left: opt[:icon],
95
+ margin: "none",
96
+ padding_top: "xxs",
97
+ padding_bottom: "xxs",
98
+ }) %>
99
+ <% end %>
100
+ <% end %>
101
+ <% end %>
102
+ <%= pb_rails("section_separator", props: { orientation: "vertical" }) %>
103
+ <button type="button" class="toolbar_button" data-action="bold" title="Bold" role="button" tabindex="0">
104
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
105
+ <%= pb_rails("icon", props: { icon: "bold", size: "lg" }) %>
106
+ <% end %>
107
+ </button>
108
+ <button type="button" class="toolbar_button" data-action="italic" title="Italic" role="button" tabindex="0">
109
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
110
+ <%= pb_rails("icon", props: { icon: "italic", size: "lg" }) %>
111
+ <% end %>
112
+ </button>
113
+ <button type="button" class="toolbar_button" data-action="strike" title="Strikethrough" role="button" tabindex="0">
114
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
115
+ <%= pb_rails("icon", props: { icon: "strikethrough", size: "lg" }) %>
116
+ <% end %>
117
+ </button>
118
+ <%= pb_rails("section_separator", props: { orientation: "vertical" }) %>
119
+ <button type="button" class="toolbar_button" data-action="codeBlock" title="Code block" role="button" tabindex="0">
120
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
121
+ <%= pb_rails("icon", props: { icon: "code", size: "lg" }) %>
122
+ <% end %>
123
+ </button>
124
+ <button type="button" class="toolbar_button" data-action="link" title="Link" role="button" tabindex="0">
125
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
126
+ <%= pb_rails("icon", props: { icon: "link", size: "lg" }) %>
127
+ <% end %>
128
+ </button>
129
+ </div>
130
+ <div class="toolbar_block rte-toolbar-right">
131
+ <button type="button" class="toolbar_button" data-action="undo" title="Undo" role="button" tabindex="0">
132
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
133
+ <%= pb_rails("icon", props: { icon: "undo", size: "lg" }) %>
134
+ <% end %>
135
+ </button>
136
+ <button type="button" class="toolbar_button" data-action="redo" title="Redo" role="button" tabindex="0">
137
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
138
+ <%= pb_rails("icon", props: { icon: "redo", size: "lg" }) %>
139
+ <% end %>
140
+ </button>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ <div id="<%= object.container_id %>-block-icon-templates" hidden aria-hidden="true">
145
+ <% block_style_options.each do |opt| %>
146
+ <span data-block-template-for="<%= opt[:value] %>" data-label="<%= opt[:text] %>">
147
+ <%= pb_rails("icon", props: { icon: opt[:icon], size: "lg" }) %>
148
+ </span>
149
+ <% end %>
150
+ </div>
151
+ <% end %>
152
+ <div class="rte-editor-wrap">
153
+ <div id="<%= object.editor_node_id %>"></div>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ <% end %>
158
+
159
+ <%# Module script: rich_text_editor_rails.js %>
160
+ <script type="module">
161
+ <%= File.read(Playbook.kit_path("rich_text_editor", "rich_text_editor_rails.js")).html_safe %>
162
+ </script>