playbook_ui 16.5.0.pre.alpha.RTEPOC15747 → 16.5.0.pre.alpha.RTEPOC15748

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: e22a1c2088938459e3efb880b3d4e820b0c19aeddd957a828eb585eca3ec45d8
4
- data.tar.gz: c4d23d3f4c261089c3fe9f6a592596d698ad9c767e7c85287a8b06177043471d
3
+ metadata.gz: 8860b0cd8332d8b7d6727c3871dd06ff3b3d429e7cca826855e97657ecc82ce8
4
+ data.tar.gz: fb9521d937a214c6fae9bd4ea0b3856f95b4d5e9be67e387292b279aca0f5f83
5
5
  SHA512:
6
- metadata.gz: 4cd4c8e1c3c86d08e9348ff45eaafb1b1f0f1ee111ec95b0f10d7bcbbfe46f412c7938ac53b71667aea8618460b8e783829aa628f23f082e5125620e7348669f
7
- data.tar.gz: 69e7c97110e36ac166a46f84f57651be2de4304097940a24dee7f6210b1167742ffa34c65ec14c50c43f0ef1ae85e17ce07f8d75629604cc7dfae0a8bfe416a9
6
+ metadata.gz: d74bfc111083f77e948b3fda81623aa925ff89acea5370873345e3ac73d70b591f42c5d06cfbe1302867f1bdd992c3a84fe99827545a91c3eb8361eac01caed3
7
+ data.tar.gz: 6371ded7a68098e54d28074edfadd3ad223d61f8361ce6684ff2081e72686b01e915efc8e5266de664b02b109648a623eee3cc390fde00f28231ac7316104e33
@@ -196,6 +196,12 @@
196
196
  }
197
197
 
198
198
  // Rails TipTap toolbar: mirror React Toolbar.tsx — <Flex paddingX="sm" paddingY="xxs" justify="between">.
199
+ &.rte-rails-toolbar-layout--simple {
200
+ .rte-toolbar-left {
201
+ overflow-x: visible;
202
+ }
203
+ }
204
+
199
205
  &.rte-rails-toolbar-layout {
200
206
  max-width: 100%;
201
207
  min-width: 0;
@@ -10,3 +10,7 @@ The Rails rich text editor is a TipTap surface with no React. The UI (toolbar, b
10
10
 
11
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
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.
13
+
14
+ ### Simple toolbar (`simple: true`)
15
+
16
+ **Bold**, **Italic**, **Undo**, and **Redo** only (no block dropdown / Popover). See the **Rails (TipTap — Simple toolbar)** example.
@@ -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,12 @@
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.
9
+
10
+ ### When to use the default instead
11
+
12
+ Keep the **default** toolbar (omit `simple` or pass `simple: false`) when you need the block-style menu, strikethrough, code block, and link actions in the chrome.
@@ -2,6 +2,7 @@ examples:
2
2
 
3
3
  rails:
4
4
  - rich_text_editor_rails_default: "Rails (TipTap)"
5
+ - rich_text_editor_rails_simple: "Rails (TipTap — Simple toolbar)"
5
6
 
6
7
  react:
7
8
  - rich_text_editor_advanced_default: Advanced Default
@@ -109,8 +109,10 @@
109
109
  "simple": {
110
110
  "type": "boolean",
111
111
  "platforms": [
112
- "react"
113
- ]
112
+ "react",
113
+ "rails"
114
+ ],
115
+ "default": false
114
116
  },
115
117
  "sticky": {
116
118
  "type": "boolean",
@@ -68,7 +68,38 @@
68
68
  </label>
69
69
  <% end %>
70
70
  <input type="hidden" name="<%= object.input_name %>" id="<%= object.input_id %>" value="" />
71
- <div class="pb_rich_text_editor_advanced_container toolbar-active">
71
+ <div class="pb_rich_text_editor_advanced_container toolbar-active<%= " pb_rich_text_editor_rte--simple" if object.simple %>">
72
+ <% if object.simple %>
73
+ <%# Compact toolbar: Bold/Italic + Undo/Redo — no block-style Popover (avoids dialog positioning issues). %>
74
+ <div class="pb_background_kit pb_background_color_white toolbar rte-rails-toolbar-layout rte-rails-toolbar-layout--simple" id="<%= object.toolbar_id %>">
75
+ <div class="rte-rails-toolbar-row">
76
+ <div class="toolbar_block rte-toolbar-left">
77
+ <button type="button" class="toolbar_button" data-action="bold" title="Bold" role="button" tabindex="0">
78
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
79
+ <%= pb_rails("icon", props: { icon: "bold", size: "lg" }) %>
80
+ <% end %>
81
+ </button>
82
+ <button type="button" class="toolbar_button" data-action="italic" title="Italic" role="button" tabindex="0">
83
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
84
+ <%= pb_rails("icon", props: { icon: "italic", size: "lg" }) %>
85
+ <% end %>
86
+ </button>
87
+ </div>
88
+ <div class="toolbar_block rte-toolbar-right">
89
+ <button type="button" class="toolbar_button" data-action="undo" title="Undo" role="button" tabindex="0">
90
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
91
+ <%= pb_rails("icon", props: { icon: "undo", size: "lg" }) %>
92
+ <% end %>
93
+ </button>
94
+ <button type="button" class="toolbar_button" data-action="redo" title="Redo" role="button" tabindex="0">
95
+ <%= pb_rails("flex", props: { align: "center", justify: "center", classname: "toolbar_button_icon" }) do %>
96
+ <%= pb_rails("icon", props: { icon: "redo", size: "lg" }) %>
97
+ <% end %>
98
+ </button>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ <% else %>
72
103
  <% block_style_options = [
73
104
  { value: "paragraph", text: "Paragraph", icon: "paragraph" },
74
105
  { value: "heading-1", text: "Heading 1", icon: "h1" },
@@ -174,6 +205,7 @@
174
205
  </span>
175
206
  <% end %>
176
207
  </div>
208
+ <% end %>
177
209
  <div class="rte-editor-wrap">
178
210
  <div id="<%= object.editor_node_id %>"></div>
179
211
  </div>
@@ -193,8 +225,9 @@
193
225
  const hiddenInput = document.getElementById(inputId);
194
226
  const editorNode = document.getElementById("<%= object.editor_node_id %>");
195
227
  const toolbar = document.getElementById("<%= object.toolbar_id %>");
228
+ const rteSimple = <%= object.simple ? "true" : "false" %> === "true";
196
229
  const blockTooltipId = "<%= object.rte_block_style_tooltip_id %>";
197
- const iconTemplatesRoot = document.getElementById("<%= object.container_id %>-block-icon-templates");
230
+ const iconTemplatesRoot = rteSimple ? null : document.getElementById("<%= object.container_id %>-block-icon-templates");
198
231
  if (!editorNode || !hiddenInput || !toolbar) return;
199
232
 
200
233
  function syncToHiddenInput(editor) {
@@ -239,6 +272,7 @@
239
272
  }
240
273
 
241
274
  function syncBlockTrigger() {
275
+ if (rteSimple) return;
242
276
  const current = getCurrentBlockValue();
243
277
  const triggerRoot = toolbar.querySelector("[data-rte-block-trigger]");
244
278
  let tpl = iconTemplatesRoot && [...iconTemplatesRoot.children].find(
@@ -276,18 +310,20 @@
276
310
  else if (value === "blockquote") chain.toggleBlockquote().run();
277
311
  }
278
312
 
279
- const blockStyleTooltip = document.getElementById(blockTooltipId);
280
- if (blockStyleTooltip) {
281
- blockStyleTooltip.addEventListener("click", (e) => {
282
- const a = e.target.closest("a[href^='#']");
283
- if (!a || !blockStyleTooltip.contains(a)) return;
284
- e.preventDefault();
285
- const href = a.getAttribute("href") || "";
286
- const v = href.startsWith("#") ? href.slice(1) : "";
287
- if (!v) return;
288
- applyBlockType(v);
289
- updateActiveStates();
290
- });
313
+ if (!rteSimple) {
314
+ const blockStyleTooltip = document.getElementById(blockTooltipId);
315
+ if (blockStyleTooltip) {
316
+ blockStyleTooltip.addEventListener("click", (e) => {
317
+ const a = e.target.closest("a[href^='#']");
318
+ if (!a || !blockStyleTooltip.contains(a)) return;
319
+ e.preventDefault();
320
+ const href = a.getAttribute("href") || "";
321
+ const v = href.startsWith("#") ? href.slice(1) : "";
322
+ if (!v) return;
323
+ applyBlockType(v);
324
+ updateActiveStates();
325
+ });
326
+ }
291
327
  }
292
328
 
293
329
  function updateActiveStates() {
@@ -9,6 +9,9 @@ module Playbook
9
9
  prop :input_options, type: Playbook::Props::HashProp, default: {}
10
10
  prop :label
11
11
  prop :required_indicator, type: Playbook::Props::Boolean, default: false
12
+ # When true, TipTap toolbar matches React `simple`: Bold + Italic only (no block-style Popover).
13
+ # Use in modals or narrow layouts where the block dropdown misbehaves.
14
+ prop :simple, type: Playbook::Props::Boolean, default: false
12
15
 
13
16
  # Match React default (globalProps maxWidth "md").
14
17
  def max_width