playbook_ui_docs 16.5.0.pre.alpha.RTEPOC15747 → 16.5.0.pre.alpha.RTEPOC15779

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: 8a806ad5d907c96b5ce2fb296234544b72dd3260aa09de2932052773eeb4d5bd
4
- data.tar.gz: 6d77e7356b438ac256486427cf3035abd3f191ac4d5e0fdfc83479af1a0d6acd
3
+ metadata.gz: daff09d10222b547b82f212e8dbb9ceeef8b1bbfd0415193a0ece5c353c6c374
4
+ data.tar.gz: cb0302b29bdcbd23442d3cd9650c6b13bd7a41bc769c9ceb37b7a5ddd147300a
5
5
  SHA512:
6
- metadata.gz: a756673e6d39f0268cb35bc28293b9a108897d3a17e42ab5d8cb7d640bab5eac303f442cf43fe22e9ec740e9e517946ba6d57bacbf80b72267223fd797254117
7
- data.tar.gz: 9dc2c8113c8924397d69f0d5af945f5dc3b933bcc3081909c9712b4400c76bc468805346d42b4edfecd8767e2268135e1abb7b90732ffcda6e933d425d82b7f3
6
+ metadata.gz: a515afc8cf6b109a416ca443dcd730147f79a25318d40217f7b2f5062d484f7b30067e70324ceff778c1973a58191a7d46b1f3ddc52d1c0b5f6068a527e334b5
7
+ data.tar.gz: 700b0d3be286512d07a3d420887e143b1224740ea782845b0b27f3070ec42341d22ec04fbfe3f4785aeabd8af9750de2f95930d68cd3681faad6b22e32617e4a
@@ -0,0 +1,62 @@
1
+ import React, { useState } from "react";
2
+ import { Button, Dialog, DatePicker } from "playbook-ui";
3
+
4
+ const DatePickerDialogSubmission = () => {
5
+ const [isOpen, setIsOpen] = useState(false);
6
+ const [dateFixed, setDateFixed] = useState("");
7
+ const [pickerInstance, setPickerInstance] = useState(0);
8
+
9
+ const close = (clearDate = false) => {
10
+ if (clearDate) setDateFixed("");
11
+ setIsOpen(false);
12
+ };
13
+
14
+ const open = () => {
15
+ setPickerInstance((current) => current + 1);
16
+ setIsOpen(true);
17
+ };
18
+
19
+ const handleSubmit = () => {
20
+ if (!dateFixed.trim()) return;
21
+ close();
22
+ };
23
+
24
+ return (
25
+ <>
26
+ <Button
27
+ onClick={open}
28
+ text="Open Dialog"
29
+ />
30
+ <Dialog
31
+ onClose={() => close(true)}
32
+ opened={isOpen}
33
+ size="md"
34
+ title="Date Picker: Dialog Submission Example"
35
+ >
36
+ <Dialog.Body>
37
+ <DatePicker
38
+ defaultDate={dateFixed || undefined}
39
+ key={`fixed-${pickerInstance}`}
40
+ label="Date"
41
+ onChange={(dateStr) => setDateFixed(dateStr || "")}
42
+ pickerId={`datePickerFixed-${pickerInstance}`}
43
+ staticPosition={false}
44
+ />
45
+ </Dialog.Body>
46
+ <Dialog.Footer>
47
+ <Button
48
+ onClick={handleSubmit}
49
+ text="Submit"
50
+ />
51
+ <Button
52
+ onClick={() => close(true)}
53
+ text="Cancel"
54
+ variant="link"
55
+ />
56
+ </Dialog.Footer>
57
+ </Dialog>
58
+ </>
59
+ );
60
+ };
61
+
62
+ export default DatePickerDialogSubmission;
@@ -0,0 +1 @@
1
+ Use this pattern when a DatePicker lives inside a Dialog and needs to submit a selected value before closing. A unique `key` and `pickerId` will force the datePicker to remount each time the dialog opens.
@@ -66,3 +66,4 @@ examples:
66
66
  - date_picker_positions: Custom Positions
67
67
  - date_picker_positions_element: Custom Position (based on element)
68
68
  - date_picker_required_indicator: Required Indicator
69
+ - date_picker_dialog_submission: Dialog Form Submission
@@ -29,3 +29,4 @@ export { default as DatePickerQuickPickDefaultDate } from './_date_picker_quick_
29
29
  export { default as DatePickerRangePattern } from './_date_picker_range_pattern'
30
30
  export { default as DatePickerAndDropdownRange } from './_date_picker_and_dropdown_range.jsx'
31
31
  export { default as DatePickerRequiredIndicator } from "./_date_picker_required_indicator.jsx";
32
+ export { default as DatePickerDialogSubmission } from "./_date_picker_dialog_submission.jsx";
@@ -97,8 +97,8 @@
97
97
  }] %>
98
98
 
99
99
  <%= pb_form_with(scope: :example, method: :get, url: "", validate: true) do |form| %>
100
- <%= form.typeahead :example_typeahead_validation, props: { data: { typeahead_example2: true, user: {} }, label: true, placeholder: "Search for a user", required: true, validation: { message: "Please select a user." } } %>
101
- <%= form.typeahead :example_typeahead_validation_react, props: { options: example_typeahead_options, pills: true, label: "Example Typeahead (React Rendered)", placeholder: "Search for a user", required: true, validation: { message: "Please select a color." } } %>
100
+ <%= form.typeahead :example_typeahead_validation, props: { data: { typeahead_example2: true, user: {} }, label: true, placeholder: "Search for a user", required: true } %>
101
+ <%= form.typeahead :example_typeahead_validation_react, props: { options: example_typeahead_options, pills: true, label: "Example Typeahead (React Rendered)", placeholder: "Search for a user", required: true } %>
102
102
  <%= form.typeahead :example_typeahead_validation_react_2, props: { options: example_typeahead_options, pills: true, label: "Example Typeahead 2 (React Rendered)", placeholder: "Search for a user", required: true } %>
103
103
  <%= form.text_field :example_text_field_validation, props: { label: true, required: true } %>
104
104
  <%= form.phone_number_field :example_phone_number_field_validation, props: { label: "Example phone field", hidden_inputs: true, required: true } %>
@@ -110,14 +110,14 @@
110
110
  <%= form.text_area :example_text_area_validation, props: { label: true, required: true } %>
111
111
  <%= form.dropdown_field :example_dropdown_validation, props: { label: true, options: example_dropdown_options, required: true } %>
112
112
  <%= form.dropdown_field :example_dropdown_validation_multi, props: { label: true, options: example_dropdown_options, multi_select: true, required: true } %>
113
- <%= form.select :example_select_validation, [ ["Yes", 1], ["No", 2] ], props: { label: true, blank_selection: "Select One...", required: true, validation_message: "Please, select an option." } %>
113
+ <%= form.select :example_select_validation, [ ["Yes", 1], ["No", 2] ], props: { label: true, blank_selection: "Select One...", required: true } %>
114
114
  <%= form.collection_select :example_collection_select_validation, example_collection, :value, :name, props: { label: true, blank_selection: "Select One...", required: true } %>
115
115
  <%= form.check_box :example_checkbox_validation, props: { text: "Example Checkbox Validation", label: true, required: true }, checked_value: "1", unchecked_value: "0" %>
116
- <%= form.date_picker :example_date_picker_2, props: { label: true, required: true, validation_message: "Please, select a date.", allow_input: true } %>
116
+ <%= form.date_picker :example_date_picker_2, props: { label: true, required: true, allow_input: true } %>
117
117
  <%= form.star_rating_field :example_star_rating_validation, props: { variant: "interactive", label: true, required: true } %>
118
118
  <%= form.time_zone_select_field :example_time_zone_select, ActiveSupport::TimeZone.us_zones, { default: "Eastern Time (US & Canada)" }, props: { label: true, blank_selection: "Select a Time Zone...", required: true } %>
119
119
  <%= form.multi_level_select :example_multi_level_select, props: { id: "multi-level-select-form", tree_data: treeData, margin_bottom: "sm", required: true, label: "Example Multi Level Select field" } %>
120
- <%= form.time_picker :example_time_picker_validation, props: { label: true, required: true, validation_message: "Please select a time." } %>
120
+ <%= form.time_picker :example_time_picker_validation, props: { label: true, required: true } %>
121
121
 
122
122
  <%= form.actions do |action| %>
123
123
  <%= action.submit %>
@@ -0,0 +1,90 @@
1
+ <%
2
+ example_collection = [
3
+ OpenStruct.new(name: "Alabama", value: 1),
4
+ OpenStruct.new(name: "Alaska", value: 2),
5
+ OpenStruct.new(name: "Arizona", value: 3),
6
+ OpenStruct.new(name: "Arkansas", value: 4),
7
+ OpenStruct.new(name: "California", value: 5),
8
+ OpenStruct.new(name: "Colorado", value: 6),
9
+ OpenStruct.new(name: "Connecticut", value: 7),
10
+ OpenStruct.new(name: "Delaware", value: 8),
11
+ OpenStruct.new(name: "Florida", value: 9),
12
+ OpenStruct.new(name: "Georgia", value: 10),
13
+ ]
14
+ %>
15
+
16
+
17
+ <%
18
+ example_typeahead_options = [
19
+ { label: 'Orange', value: '#FFA500' },
20
+ { label: 'Red', value: '#FF0000' },
21
+ { label: 'Green', value: '#00FF00' },
22
+ { label: 'Blue', value: '#0000FF' },
23
+ ]
24
+ %>
25
+
26
+
27
+ <%= pb_form_with(scope: :example, method: :get, url: "", validate: true) do |form| %>
28
+ <%= form.text_field :example_text_field_validation_msg, props: { label: "Text Field With Validation Message", required: true, validation: { message: "I am a custom validation message for text field." } } %>
29
+ <%= form.typeahead :example_typeahead_validation_msg, props: { data: { typeahead_example_msg: true, user: {} }, label: "Typeahead With Validation Message", placeholder: "Search for a user", required: true, validation: { message: "I am a custom validation message for typeahead." } } %>
30
+ <%= form.typeahead :example_typeahead_validation_react_msg, props: { options: example_typeahead_options, pills: true, label: "Typeahead With Validation Message (React Rendered)", placeholder: "Search for a color", required: true, validation: { message: "I am a custom validation message for React typeahead." } } %>
31
+ <%= form.select :example_select_validation_msg, [ ["Yes", 1], ["No", 2] ], props: { label: true, blank_selection: "Select One...", required: true, validation_message: "I am a custom validation message for select." } %>
32
+ <%= form.collection_select :example_collection_select_validation_msg, example_collection, :value, :name, props: { label: "Collection Select With Validation Message", blank_selection: "Select a State...", required: true, validation_message: "I am a custom validation message for collection select." } %>
33
+ <%= form.date_picker :example_date_picker_validation_msg, props: { label: "Date Picker With Validation Message", required: true, validation_message: "I am a custom validation message for date picker.", allow_input: true } %>
34
+ <%= form.time_picker :example_time_picker_validation_msg, props: { label: "Time Picker With Validation Message", required: true, validation_message: "I am a custom validation message for time picker." } %>
35
+
36
+ <%= form.actions do |action| %>
37
+ <%= action.submit %>
38
+ <%= action.button props: { type: "reset", text: "Cancel", variant: "secondary" } %>
39
+ <% end %>
40
+ <% end %>
41
+
42
+ <!-- form.typeahead user results example template -->
43
+ <template data-typeahead-example-result-option>
44
+ <%= pb_rails("user", props: {
45
+ name: tag(:slot, name: "name"),
46
+ orientation: "horizontal",
47
+ align: "left",
48
+ avatar_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGP6zwAAAgcBApocMXEAAAAASUVORK5CYII=",
49
+ avatar: true
50
+ }) %>
51
+ </template>
52
+
53
+ <!-- form.typeahead JS example implementation -->
54
+ <%= javascript_tag defer: "defer" do %>
55
+ document.addEventListener("pb-typeahead-kit-search", function(event) {
56
+ if (!event.target.dataset || !event.target.dataset.typeaheadExampleMsg) return
57
+
58
+ fetch(`https://api.github.com/search/users?q=${encodeURIComponent(event.detail.searchingFor)}`)
59
+ .then(response => response.json())
60
+ .then((result) => {
61
+ const resultOptionTemplate = document.querySelector("[data-typeahead-example-result-option]")
62
+
63
+ event.detail.setResults((result.items || []).map((user) => {
64
+ const wrapper = resultOptionTemplate.content.cloneNode(true)
65
+ wrapper.children[0].dataset.user = JSON.stringify(user)
66
+ wrapper.querySelector('slot[name="name"]').replaceWith(user.login)
67
+ wrapper.querySelector('img').dataset.src = user.avatar_url
68
+ return wrapper
69
+ }))
70
+ })
71
+ })
72
+
73
+
74
+ document.addEventListener("pb-typeahead-kit-result-option-selected", function(event) {
75
+ if (!event.target.dataset.typeaheadExampleMsg) return
76
+
77
+ const selectedUserJSON = event.detail.selected.firstElementChild.dataset.user
78
+ const selectedUserData = JSON.parse(selectedUserJSON)
79
+
80
+ // set the input field's value
81
+ event.target.querySelector('input[name=example_typeahead_validation_msg]').value = selectedUserData.login
82
+
83
+ // log the selected option's dataset
84
+ console.log('The selected user data:')
85
+ console.dir(selectedUserData)
86
+
87
+ // do even more with the data later - TBD
88
+ event.target.dataset.user = selectedUserJSON
89
+ })
90
+ <% end %>
@@ -0,0 +1,13 @@
1
+ Custom validation messages allow you to override the browser's default validation text with your own messaging. This provides a better user experience by giving specific, actionable feedback.
2
+
3
+ **Text-based inputs** (TextInput, Typeahead) use the `validation` prop with a `message` key:
4
+ ```ruby
5
+ validation: { message: "Please enter a valid email address." }
6
+ ```
7
+
8
+ **Selection-based inputs** (Select, DatePicker, TimePicker) use the `validation_message` prop:
9
+ ```ruby
10
+ validation_message: "Please select an option."
11
+ ```
12
+
13
+ When a required field is left empty or fails validation, your custom message will display instead of the generic browser default.
@@ -3,5 +3,6 @@ examples:
3
3
  rails:
4
4
  - form_form_with: Default
5
5
  - form_form_with_validate: Default + Validation
6
+ - form_form_with_validation_msg: Validation + Custom Validation Message
6
7
  - form_form_with_loading: Default + Loading
7
8
  - form_with_required_indicator: With Optional Required Indicator
@@ -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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: playbook_ui_docs
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.5.0.pre.alpha.RTEPOC15747
4
+ version: 16.5.0.pre.alpha.RTEPOC15779
5
5
  platform: ruby
6
6
  authors:
7
7
  - Power UX
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2026-04-14 00:00:00.000000000 Z
12
+ date: 2026-04-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: playbook_ui
@@ -600,6 +600,8 @@ files:
600
600
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default_date.html.erb
601
601
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default_date.jsx
602
602
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default_date.md
603
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_dialog_submission.jsx
604
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_dialog_submission.md
603
605
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_disabled.html.erb
604
606
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_disabled.jsx
605
607
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_error.html.erb
@@ -1119,6 +1121,8 @@ files:
1119
1121
  - app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md
1120
1122
  - app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb
1121
1123
  - app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.md
1124
+ - app/pb_kits/playbook/pb_form/docs/_form_form_with_validation_msg.html.erb
1125
+ - app/pb_kits/playbook/pb_form/docs/_form_form_with_validation_msg.md
1122
1126
  - app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb
1123
1127
  - app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.md
1124
1128
  - app/pb_kits/playbook/pb_form/docs/example.yml
@@ -2000,6 +2004,8 @@ files:
2000
2004
  - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_more_extensions.md
2001
2005
  - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.html.erb
2002
2006
  - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.md
2007
+ - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_simple.html.erb
2008
+ - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_simple.md
2003
2009
  - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_toolbar_disabled.jsx
2004
2010
  - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_toolbar_disabled.md
2005
2011
  - app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml