playbook_ui 17.2.0.pre.rc.1 → 17.2.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 +4 -4
- data/app/pb_kits/playbook/pb_form/docs/_description.md +2 -5
- data/app/pb_kits/playbook/pb_form/docs/_footer.md +2 -1
- data/app/pb_kits/playbook/pb_form/docs/_form_default_values.html.erb +183 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_default_values.md +3 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_defaults.html.erb +180 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_defaults.md +1 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_docs_demo.js +226 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_vs.html.erb +36 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_vs.md +1 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_loading.html.erb +39 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_loading.md +1 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_multi_column.html.erb +60 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_multi_column.md +3 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_validation.html.erb +224 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_validation.md +27 -0
- data/app/pb_kits/playbook/pb_form/docs/_sample_data.ruby +148 -0
- data/app/pb_kits/playbook/pb_form/docs/example.yml +6 -6
- data/app/pb_kits/playbook/pb_form/docs/snippets/comparison_playbook.txt +7 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/comparison_rails.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_checkbox.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_collection_select.txt +8 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_date_picker.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_dropdown.txt +11 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_email_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_multi_level_select.txt +25 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_multi_select.txt +11 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_number_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_password_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_phone_number.txt +4 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_search_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_select.txt +3 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_star_rating.txt +2 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_text_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_textarea.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_time_picker.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_time_zone_select.txt +3 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_typeahead.txt +13 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_typeahead_default.txt +13 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/default_values_url_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_checkbox.txt +4 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_collection_select.txt +7 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_date_picker.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_dropdown.txt +7 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_email_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_multi_level_select.txt +19 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_multi_select.txt +7 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_number_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_password_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_phone_number.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_scoped_fields.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_search_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_select.txt +2 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_star_rating.txt +2 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_text_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_textarea.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_time_picker.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_time_zone_select.txt +3 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_typeahead.txt +8 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_typeahead_default.txt +13 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/defaults_url_field.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/multi_column.txt +14 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_checkbox.txt +4 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_collection_select.txt +12 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_date_picker.txt +6 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_dropdown.txt +7 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_email_field.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_multi_level_select.txt +25 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_multi_select.txt +11 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_number_field.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_password_field.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_phone_number.txt +4 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_search_field.txt +8 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_select.txt +7 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_star_rating.txt +2 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_text_field.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_textarea.txt +1 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_time_picker.txt +5 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_time_zone_select.txt +7 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_typeahead.txt +14 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_typeahead_default.txt +14 -0
- data/app/pb_kits/playbook/pb_form/docs/snippets/validation_url_field.txt +5 -0
- data/lib/playbook/forms/builder/checkbox_field.rb +1 -1
- data/lib/playbook/forms/builder/dropdown_field.rb +1 -1
- data/lib/playbook/forms/builder/star_rating_field.rb +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +80 -11
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +0 -175
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb +0 -39
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md +0 -1
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +0 -176
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.md +0 -1
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validation_msg.html.erb +0 -90
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validation_msg.md +0 -13
- data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb +0 -173
- data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.md +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 672b9baf425e982f8d59fe03e71b4211cd715c2975de0f0c3a30895201d6b780
|
|
4
|
+
data.tar.gz: ed5012fd921338fdcc088c046e07e0a44f54b11f61e9921309958307b324fdfa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8291cbace8ba3b7abebdf73b25d577d4a464fc49b1c8de677c1e990b42409a90e3b59a1b76f11312a7443c45ddb18bae51e481e501e602bfc3c735aa8ff98422
|
|
7
|
+
data.tar.gz: e1277c1934e5ecd79e9740070ca25dee5966f39916501d5cd257055bb96aaade4fa9d5ed924badab1a53666e725caaaef2644a6ec55393d1f06032cf5b250b6f
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
### Form Helpers
|
|
4
|
-
|
|
5
|
-
This kit uses rails `form_with` with our custom builder to render forms using other kits such as text_input, select, and typeahead to name a few. Doing so provides UI consistency within forms and makes adding a form to your page easier.
|
|
1
|
+
Use `pb_form_with` to build Rails forms with Playbook kits. It wraps Rails [`form_with`](https://guides.rubyonrails.org/form_helpers.html) and supplies a custom form builder so fields like text inputs, selects, and typeaheads render with consistent Playbook styling and behavior.
|
|
6
2
|
|
|
3
|
+
Pick an input below to see Defaults, Validation, Default Values, and Multi-Column layout patterns one field at a time.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
<%
|
|
2
|
+
load Playbook.kit_path("form", "docs", "_sample_data.ruby").to_s
|
|
3
|
+
demo_id = "default_values"
|
|
4
|
+
input_types = PlaybookFormDocsSampleData.input_types
|
|
5
|
+
default_key = PlaybookFormDocsSampleData.default_input_key
|
|
6
|
+
select_choices = PlaybookFormDocsSampleData.select_choices
|
|
7
|
+
dropdown_options = PlaybookFormDocsSampleData.dropdown_options("-dv")
|
|
8
|
+
typeahead_options = PlaybookFormDocsSampleData.typeahead_options
|
|
9
|
+
collection = PlaybookFormDocsSampleData.collection
|
|
10
|
+
tree_data = PlaybookFormDocsSampleData.tree_data("default-values")
|
|
11
|
+
form_open_source = PlaybookFormDocsSampleData.form_open(scope: demo_id)
|
|
12
|
+
form_close_source = PlaybookFormDocsSampleData.form_close
|
|
13
|
+
%>
|
|
14
|
+
|
|
15
|
+
<div data-form-docs-demo="<%= demo_id %>">
|
|
16
|
+
<div hidden data-form-docs-open><%= raw render_code(form_open_source, "erb") %></div>
|
|
17
|
+
<div hidden data-form-docs-close><%= raw render_code(form_close_source, "erb") %></div>
|
|
18
|
+
<%= pb_rails("body", props: {
|
|
19
|
+
text: "Select one or more inputs to add them to the form.",
|
|
20
|
+
color: "light",
|
|
21
|
+
margin_bottom: "xs",
|
|
22
|
+
}) %>
|
|
23
|
+
<%= pb_rails("flex", props: { gap: "xs", wrap: true, margin_bottom: "md" }) do %>
|
|
24
|
+
<% input_types.each do |input_type| %>
|
|
25
|
+
<div data-form-docs-pill="<%= input_type[:key] %>"
|
|
26
|
+
role="button"
|
|
27
|
+
tabindex="0"
|
|
28
|
+
style="cursor: pointer">
|
|
29
|
+
<%= pb_rails("pill", props: {
|
|
30
|
+
text: input_type[:label],
|
|
31
|
+
text_transform: "none",
|
|
32
|
+
variant: input_type[:key] == default_key ? "primary" : "neutral",
|
|
33
|
+
}) %>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
36
|
+
<% end %>
|
|
37
|
+
|
|
38
|
+
<%= pb_rails("flex", props: PlaybookFormDocsSampleData.demo_panel_flex_props) do %>
|
|
39
|
+
<div style="<%= PlaybookFormDocsSampleData.demo_form_column_style %>">
|
|
40
|
+
<%= pb_rails("card", props: PlaybookFormDocsSampleData.demo_form_card_props) do %>
|
|
41
|
+
<%= pb_form_with(scope: :default_values, url: "", method: :get, html: { onsubmit: "return false;" }) do |form| %>
|
|
42
|
+
<% input_types.each do |input_type| %>
|
|
43
|
+
<div data-form-docs-panel="<%= input_type[:key] %>"
|
|
44
|
+
style="<%= input_type[:key] == default_key ? "" : "display: none;" %>">
|
|
45
|
+
<div data-form-docs-snippet hidden><%= raw render_code(
|
|
46
|
+
PlaybookFormDocsSampleData.form_body_snippet(
|
|
47
|
+
File.read(Playbook.kit_path("form", "docs", "snippets", "default_values_#{input_type[:key]}.txt"))
|
|
48
|
+
),
|
|
49
|
+
"erb"
|
|
50
|
+
) %></div>
|
|
51
|
+
<% case input_type[:key]
|
|
52
|
+
when "text_field" %>
|
|
53
|
+
<%= form.text_field :full_name, props: { label: "Full Name", value: "John Doe" } %>
|
|
54
|
+
<% when "email_field" %>
|
|
55
|
+
<%= form.email_field :email, props: { label: "Email", value: "jane@example.com" } %>
|
|
56
|
+
<% when "number_field" %>
|
|
57
|
+
<%= form.number_field :quantity, props: { label: "Quantity", value: 3 } %>
|
|
58
|
+
<% when "search_field" %>
|
|
59
|
+
<%= form.search_field :project_number, props: { label: "Project Number", value: "33-12345" } %>
|
|
60
|
+
<% when "password_field" %>
|
|
61
|
+
<%= form.password_field :password, props: { label: "Password", value: "secret" } %>
|
|
62
|
+
<% when "url_field" %>
|
|
63
|
+
<%= form.url_field :website, props: { label: "Website", value: "https://example.com" } %>
|
|
64
|
+
<% when "textarea" %>
|
|
65
|
+
<%= form.text_area :bio, props: { label: "Bio", value: "Loves building with Playbook." } %>
|
|
66
|
+
<% when "select" %>
|
|
67
|
+
<%= form.select :favorite_color, select_choices,
|
|
68
|
+
{ selected: "blue" },
|
|
69
|
+
props: { label: "Favorite Color", blank_selection: "Select one..." } %>
|
|
70
|
+
<% when "collection_select" %>
|
|
71
|
+
<%= form.collection_select :state, collection, :value, :name,
|
|
72
|
+
{ selected: 2 },
|
|
73
|
+
props: { label: "State", blank_selection: "Select one..." } %>
|
|
74
|
+
<% when "dropdown" %>
|
|
75
|
+
<%= form.dropdown_field "default_values[country]",
|
|
76
|
+
props: {
|
|
77
|
+
label: "Country",
|
|
78
|
+
options: dropdown_options,
|
|
79
|
+
default_value: { label: "Canada", value: "Canada", id: "ca-dv" },
|
|
80
|
+
} %>
|
|
81
|
+
<% when "multi_select" %>
|
|
82
|
+
<%= form.dropdown_field "default_values[countries]",
|
|
83
|
+
props: {
|
|
84
|
+
label: "Countries",
|
|
85
|
+
options: dropdown_options,
|
|
86
|
+
multi_select: true,
|
|
87
|
+
default_value: [{ label: "Canada", value: "Canada", id: "ca-dv" }],
|
|
88
|
+
} %>
|
|
89
|
+
<% when "checkbox" %>
|
|
90
|
+
<%= form.check_box :newsletter,
|
|
91
|
+
props: { text: "Subscribe to newsletter", label: "Checkbox" },
|
|
92
|
+
checked: true,
|
|
93
|
+
checked_value: "yes",
|
|
94
|
+
unchecked_value: "no" %>
|
|
95
|
+
<% when "date_picker" %>
|
|
96
|
+
<%= form.date_picker :start_date, props: {
|
|
97
|
+
label: "Start Date",
|
|
98
|
+
allow_input: true,
|
|
99
|
+
default_date: "06/15/2026",
|
|
100
|
+
} %>
|
|
101
|
+
<% when "time_picker" %>
|
|
102
|
+
<%= form.time_picker :start_time, props: { label: "Start Time", default_time: "09:30" } %>
|
|
103
|
+
<% when "time_zone_select" %>
|
|
104
|
+
<%= form.time_zone_select_field :time_zone, ActiveSupport::TimeZone.us_zones,
|
|
105
|
+
{ default: "Pacific Time (US & Canada)" },
|
|
106
|
+
props: { label: "Time Zone" } %>
|
|
107
|
+
<% when "typeahead_default" %>
|
|
108
|
+
<%= form.typeahead "default_values[color_search_single]",
|
|
109
|
+
props: {
|
|
110
|
+
options: typeahead_options,
|
|
111
|
+
is_multi: false,
|
|
112
|
+
label: "Favorite Color",
|
|
113
|
+
placeholder: "Search for a color",
|
|
114
|
+
default_options: [{ label: "Blue", value: "#0000FF" }],
|
|
115
|
+
} %>
|
|
116
|
+
<% when "typeahead" %>
|
|
117
|
+
<%= form.typeahead "default_values[color_search]",
|
|
118
|
+
props: {
|
|
119
|
+
options: typeahead_options,
|
|
120
|
+
pills: true,
|
|
121
|
+
label: "Favorite Color",
|
|
122
|
+
placeholder: "Search for a color",
|
|
123
|
+
default_options: [{ label: "Blue", value: "#0000FF" }],
|
|
124
|
+
} %>
|
|
125
|
+
<% when "phone_number" %>
|
|
126
|
+
<%= form.phone_number_field "default_values[phone]", props: {
|
|
127
|
+
label: "Phone Number",
|
|
128
|
+
value: "5551234567",
|
|
129
|
+
} %>
|
|
130
|
+
<% when "star_rating" %>
|
|
131
|
+
<%= form.star_rating_field "default_values[rating]",
|
|
132
|
+
props: { variant: "interactive", label: "Rating", rating: 4 } %>
|
|
133
|
+
<% when "multi_level_select" %>
|
|
134
|
+
<%= form.multi_level_select "default_values[department]",
|
|
135
|
+
props: {
|
|
136
|
+
id: "mls-default-values",
|
|
137
|
+
tree_data: tree_data,
|
|
138
|
+
margin_bottom: "sm",
|
|
139
|
+
label: "Department",
|
|
140
|
+
selected_ids: ["default-values-102"],
|
|
141
|
+
} %>
|
|
142
|
+
<% end %>
|
|
143
|
+
</div>
|
|
144
|
+
<% end %>
|
|
145
|
+
|
|
146
|
+
<%= form.actions do |action| %>
|
|
147
|
+
<%= action.submit %>
|
|
148
|
+
<%= action.button props: { type: "reset", text: "Cancel", variant: "secondary" } %>
|
|
149
|
+
<% end %>
|
|
150
|
+
<% end %>
|
|
151
|
+
<% end %>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div style="<%= PlaybookFormDocsSampleData.demo_data_column_style %>">
|
|
155
|
+
<%= pb_rails("caption", props: { text: "Submitted Form Data", margin_bottom: "xs" }) %>
|
|
156
|
+
<%= pb_rails("card", props: { background: "light", padding: "md" }) do %>
|
|
157
|
+
<div data-form-docs-empty>
|
|
158
|
+
<%= pb_rails("body", props: { text: "No data submitted yet.", color: "light" }) %>
|
|
159
|
+
</div>
|
|
160
|
+
<pre data-form-docs-output
|
|
161
|
+
style="display: none; margin: 0; overflow: auto; font-size: 12px; line-height: 1.5; white-space: pre-wrap;"></pre>
|
|
162
|
+
<% end %>
|
|
163
|
+
</div>
|
|
164
|
+
<% end %>
|
|
165
|
+
|
|
166
|
+
<%= pb_rails("body", props: {
|
|
167
|
+
text: "Submit the form to see the data on the right.",
|
|
168
|
+
color: "light",
|
|
169
|
+
margin_top: "sm",
|
|
170
|
+
margin_bottom: "sm",
|
|
171
|
+
}) %>
|
|
172
|
+
|
|
173
|
+
<%= pb_rails("card", props: { background: "dark", dark: true, padding: "none" }) do %>
|
|
174
|
+
<div class="pb--codeCopy pb--codeCopy_compact">
|
|
175
|
+
<pre class="highlight" data-form-docs-code style="margin: 0; overflow: auto; font-size: 12px; line-height: 1.5; white-space: pre;"></pre>
|
|
176
|
+
</div>
|
|
177
|
+
<% end %>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<script>
|
|
181
|
+
<%= raw File.read(Playbook.kit_path("form", "docs", "_form_docs_demo.js")) %>
|
|
182
|
+
PbFormDocsDemo("<%= demo_id %>")
|
|
183
|
+
</script>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
Toggle pills to add pre-filled inputs. Initial values come from builder props (for example `value` on text inputs). Submit to see the selected fields' data on the right.
|
|
2
|
+
|
|
3
|
+
For `typeahead`, `phone_number_field`, and `dropdown_field`, pass a scoped string name that matches the form scope (for example `"default_values[phone]"` when `scope: :default_values`) — see Defaults for details.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<%
|
|
2
|
+
load Playbook.kit_path("form", "docs", "_sample_data.ruby").to_s
|
|
3
|
+
demo_id = "defaults"
|
|
4
|
+
input_types = PlaybookFormDocsSampleData.input_types
|
|
5
|
+
default_key = PlaybookFormDocsSampleData.default_input_key
|
|
6
|
+
select_choices = PlaybookFormDocsSampleData.select_choices
|
|
7
|
+
dropdown_options = PlaybookFormDocsSampleData.dropdown_options
|
|
8
|
+
typeahead_options = PlaybookFormDocsSampleData.typeahead_options
|
|
9
|
+
collection = PlaybookFormDocsSampleData.collection
|
|
10
|
+
tree_data = PlaybookFormDocsSampleData.tree_data("defaults")
|
|
11
|
+
form_open_source = PlaybookFormDocsSampleData.form_open(scope: demo_id)
|
|
12
|
+
form_close_source = PlaybookFormDocsSampleData.form_close
|
|
13
|
+
%>
|
|
14
|
+
|
|
15
|
+
<div data-form-docs-demo="<%= demo_id %>">
|
|
16
|
+
<div hidden data-form-docs-open><%= raw render_code(form_open_source, "erb") %></div>
|
|
17
|
+
<div hidden data-form-docs-close><%= raw render_code(form_close_source, "erb") %></div>
|
|
18
|
+
<%= pb_rails("body", props: {
|
|
19
|
+
text: "Select one or more inputs to add them to the form.",
|
|
20
|
+
color: "light",
|
|
21
|
+
margin_bottom: "xs",
|
|
22
|
+
}) %>
|
|
23
|
+
<%= pb_rails("flex", props: { gap: "xs", wrap: true, margin_bottom: "md" }) do %>
|
|
24
|
+
<% input_types.each do |input_type| %>
|
|
25
|
+
<div data-form-docs-pill="<%= input_type[:key] %>"
|
|
26
|
+
role="button"
|
|
27
|
+
tabindex="0"
|
|
28
|
+
style="cursor: pointer">
|
|
29
|
+
<%= pb_rails("pill", props: {
|
|
30
|
+
text: input_type[:label],
|
|
31
|
+
text_transform: "none",
|
|
32
|
+
variant: input_type[:key] == default_key ? "primary" : "neutral",
|
|
33
|
+
}) %>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
36
|
+
<% end %>
|
|
37
|
+
|
|
38
|
+
<%= pb_rails("flex", props: PlaybookFormDocsSampleData.demo_panel_flex_props) do %>
|
|
39
|
+
<div style="<%= PlaybookFormDocsSampleData.demo_form_column_style %>">
|
|
40
|
+
<%= pb_rails("card", props: PlaybookFormDocsSampleData.demo_form_card_props) do %>
|
|
41
|
+
<%= pb_form_with(scope: :defaults, url: "", method: :get, html: { onsubmit: "return false;" }) do |form| %>
|
|
42
|
+
<% input_types.each do |input_type| %>
|
|
43
|
+
<div data-form-docs-panel="<%= input_type[:key] %>"
|
|
44
|
+
style="<%= input_type[:key] == default_key ? "" : "display: none;" %>">
|
|
45
|
+
<div data-form-docs-snippet hidden><%= raw render_code(
|
|
46
|
+
PlaybookFormDocsSampleData.form_body_snippet(
|
|
47
|
+
File.read(Playbook.kit_path("form", "docs", "snippets", "defaults_#{input_type[:key]}.txt"))
|
|
48
|
+
),
|
|
49
|
+
"erb"
|
|
50
|
+
) %></div>
|
|
51
|
+
<% case input_type[:key]
|
|
52
|
+
when "text_field" %>
|
|
53
|
+
<%= form.text_field :full_name, props: { label: "Full Name" } %>
|
|
54
|
+
<% when "email_field" %>
|
|
55
|
+
<%= form.email_field :email, props: { label: "Email" } %>
|
|
56
|
+
<% when "number_field" %>
|
|
57
|
+
<%= form.number_field :quantity, props: { label: "Quantity" } %>
|
|
58
|
+
<% when "search_field" %>
|
|
59
|
+
<%= form.search_field :project_number, props: { label: "Project Number" } %>
|
|
60
|
+
<% when "password_field" %>
|
|
61
|
+
<%= form.password_field :password, props: { label: "Password" } %>
|
|
62
|
+
<% when "url_field" %>
|
|
63
|
+
<%= form.url_field :website, props: { label: "Website" } %>
|
|
64
|
+
<% when "textarea" %>
|
|
65
|
+
<%= form.text_area :bio, props: { label: "Bio" } %>
|
|
66
|
+
<% when "select" %>
|
|
67
|
+
<%= form.select :favorite_color, select_choices,
|
|
68
|
+
props: { label: "Favorite Color", blank_selection: "Select one..." } %>
|
|
69
|
+
<% when "collection_select" %>
|
|
70
|
+
<%= form.collection_select :state, collection, :value, :name,
|
|
71
|
+
props: { label: "State", blank_selection: "Select one..." } %>
|
|
72
|
+
<% when "dropdown" %>
|
|
73
|
+
<%= form.dropdown_field "defaults[country]",
|
|
74
|
+
props: { label: "Country", options: dropdown_options } %>
|
|
75
|
+
<% when "multi_select" %>
|
|
76
|
+
<%= form.dropdown_field "defaults[countries]",
|
|
77
|
+
props: {
|
|
78
|
+
label: "Countries",
|
|
79
|
+
options: dropdown_options,
|
|
80
|
+
multi_select: true,
|
|
81
|
+
} %>
|
|
82
|
+
<% when "checkbox" %>
|
|
83
|
+
<%= form.check_box :newsletter,
|
|
84
|
+
props: { text: "Subscribe to newsletter", label: "Checkbox" },
|
|
85
|
+
checked_value: "yes",
|
|
86
|
+
unchecked_value: "no" %>
|
|
87
|
+
<% when "date_picker" %>
|
|
88
|
+
<%= form.date_picker :start_date, props: { label: "Start Date", allow_input: true } %>
|
|
89
|
+
<% when "time_picker" %>
|
|
90
|
+
<%= form.time_picker :start_time, props: { label: "Start Time" } %>
|
|
91
|
+
<% when "time_zone_select" %>
|
|
92
|
+
<%= form.time_zone_select_field :time_zone, ActiveSupport::TimeZone.us_zones,
|
|
93
|
+
{ default: "Eastern Time (US & Canada)" },
|
|
94
|
+
props: { label: "Time Zone" } %>
|
|
95
|
+
<% when "typeahead_default" %>
|
|
96
|
+
<%= form.typeahead "defaults[color_search_single]",
|
|
97
|
+
props: {
|
|
98
|
+
options: typeahead_options,
|
|
99
|
+
is_multi: false,
|
|
100
|
+
label: "Favorite Color",
|
|
101
|
+
placeholder: "Search for a color",
|
|
102
|
+
} %>
|
|
103
|
+
<% when "typeahead" %>
|
|
104
|
+
<%= form.typeahead "defaults[color_search]",
|
|
105
|
+
props: {
|
|
106
|
+
options: typeahead_options,
|
|
107
|
+
pills: true,
|
|
108
|
+
label: "Favorite Color",
|
|
109
|
+
placeholder: "Search for a color",
|
|
110
|
+
} %>
|
|
111
|
+
<% when "phone_number" %>
|
|
112
|
+
<%= form.phone_number_field "defaults[phone]", props: { label: "Phone Number" } %>
|
|
113
|
+
<% when "star_rating" %>
|
|
114
|
+
<%= form.star_rating_field "defaults[rating]",
|
|
115
|
+
props: { variant: "interactive", label: "Rating" } %>
|
|
116
|
+
<% when "multi_level_select" %>
|
|
117
|
+
<%= form.multi_level_select "defaults[department]",
|
|
118
|
+
props: {
|
|
119
|
+
id: "mls-defaults",
|
|
120
|
+
tree_data: tree_data,
|
|
121
|
+
margin_bottom: "sm",
|
|
122
|
+
label: "Department",
|
|
123
|
+
} %>
|
|
124
|
+
<% end %>
|
|
125
|
+
</div>
|
|
126
|
+
<% end %>
|
|
127
|
+
|
|
128
|
+
<%= form.actions do |action| %>
|
|
129
|
+
<%= action.submit %>
|
|
130
|
+
<%= action.button props: { type: "reset", text: "Cancel", variant: "secondary" } %>
|
|
131
|
+
<% end %>
|
|
132
|
+
<% end %>
|
|
133
|
+
<% end %>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<div style="<%= PlaybookFormDocsSampleData.demo_data_column_style %>">
|
|
137
|
+
<%= pb_rails("caption", props: { text: "Submitted Form Data", margin_bottom: "xs" }) %>
|
|
138
|
+
<%= pb_rails("card", props: { background: "light", padding: "md" }) do %>
|
|
139
|
+
<div data-form-docs-empty>
|
|
140
|
+
<%= pb_rails("body", props: { text: "No data submitted yet.", color: "light" }) %>
|
|
141
|
+
</div>
|
|
142
|
+
<pre data-form-docs-output
|
|
143
|
+
style="display: none; margin: 0; overflow: auto; font-size: 12px; line-height: 1.5; white-space: pre-wrap;"></pre>
|
|
144
|
+
<% end %>
|
|
145
|
+
</div>
|
|
146
|
+
<% end %>
|
|
147
|
+
|
|
148
|
+
<%= pb_rails("body", props: {
|
|
149
|
+
text: "Submit the form to see the data on the right.",
|
|
150
|
+
color: "light",
|
|
151
|
+
margin_top: "sm",
|
|
152
|
+
margin_bottom: "sm",
|
|
153
|
+
}) %>
|
|
154
|
+
|
|
155
|
+
<%= pb_rails("card", props: { background: "dark", dark: true, padding: "none" }) do %>
|
|
156
|
+
<div class="pb--codeCopy pb--codeCopy_compact">
|
|
157
|
+
<pre class="highlight" data-form-docs-code style="margin: 0; overflow: auto; font-size: 12px; line-height: 1.5; white-space: pre;"></pre>
|
|
158
|
+
</div>
|
|
159
|
+
<% end %>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<%= pb_rails("title", props: { size: 4, text: "Naming kit fields under a scope", margin_top: "md", margin_bottom: "sm" }) %>
|
|
163
|
+
<%= pb_rails("body", props: { tag: "div", margin_bottom: "sm" }) do %>
|
|
164
|
+
<p><code>text_field</code>, <code>select</code>, <code>check_box</code>, and similar Rails-backed helpers nest under the form <code>scope</code> automatically (<code>defaults[full_name]</code> when <code>scope: :defaults</code>).</p>
|
|
165
|
+
<p>Playbook-only helpers — <code>typeahead</code>, <code>phone_number_field</code>, and <code>dropdown_field</code> — do not. Pass an explicit string that matches the form scope so params stay nested:</p>
|
|
166
|
+
<% end %>
|
|
167
|
+
<%= pb_rails("card", props: { background: "dark", dark: true, padding: "none", margin_bottom: "sm" }) do %>
|
|
168
|
+
<div class="pb--codeCopy pb--codeCopy_compact">
|
|
169
|
+
<pre class="highlight" style="margin: 0; overflow: auto; font-size: 12px; line-height: 1.5; white-space: pre;"><%= raw render_code(
|
|
170
|
+
File.read(Playbook.kit_path("form", "docs", "snippets", "defaults_scoped_fields.txt")),
|
|
171
|
+
"erb"
|
|
172
|
+
) %></pre>
|
|
173
|
+
</div>
|
|
174
|
+
<% end %>
|
|
175
|
+
<%= pb_rails("body", props: { text: "Submitted params then land under params[:defaults], matching the code you copy.", color: "light" }) %>
|
|
176
|
+
|
|
177
|
+
<script>
|
|
178
|
+
<%= raw File.read(Playbook.kit_path("form", "docs", "_form_docs_demo.js")) %>
|
|
179
|
+
PbFormDocsDemo("<%= demo_id %>")
|
|
180
|
+
</script>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Toggle pills to add or remove inputs from the form. Submit to see values for the selected fields on the right. The code snippet updates to match the current selection.
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
window.PbFormDocsDemo = window.PbFormDocsDemo || function (demoId) {
|
|
2
|
+
var root = document.querySelector('[data-form-docs-demo="' + demoId + '"]')
|
|
3
|
+
if (!root || root.dataset.pbFormDocsReady === "true") return
|
|
4
|
+
root.dataset.pbFormDocsReady = "true"
|
|
5
|
+
|
|
6
|
+
var dataOutput = root.querySelector("[data-form-docs-output]")
|
|
7
|
+
var emptyState = root.querySelector("[data-form-docs-empty]")
|
|
8
|
+
var codeOutput = root.querySelector("[data-form-docs-code]")
|
|
9
|
+
var formOpenEl = root.querySelector("[data-form-docs-open]")
|
|
10
|
+
var formCloseEl = root.querySelector("[data-form-docs-close]")
|
|
11
|
+
var formOpenHtml = formOpenEl ? formOpenEl.innerHTML.trim() : ""
|
|
12
|
+
var formCloseHtml = formCloseEl ? trimHighlightHtml(formCloseEl.innerHTML) : ""
|
|
13
|
+
|
|
14
|
+
function trimHighlightHtml(html) {
|
|
15
|
+
// Rouge keeps leading indent as literal spaces before the first span.
|
|
16
|
+
// String trim() would strip those; only drop trailing newlines.
|
|
17
|
+
return html.replace(/\n+$/g, "")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function clearSubmittedData() {
|
|
21
|
+
if (dataOutput) {
|
|
22
|
+
dataOutput.textContent = ""
|
|
23
|
+
dataOutput.style.display = "none"
|
|
24
|
+
}
|
|
25
|
+
if (emptyState) emptyState.style.display = ""
|
|
26
|
+
clearQueryParams()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function clearQueryParams() {
|
|
30
|
+
var url = window.location.pathname + window.location.hash
|
|
31
|
+
if (window.location.search) history.replaceState(null, "", url)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function formDataToQueryString(form) {
|
|
35
|
+
var params = new URLSearchParams()
|
|
36
|
+
var formData = new FormData(form)
|
|
37
|
+
|
|
38
|
+
formData.forEach(function (value, key) {
|
|
39
|
+
if (key === "authenticity_token" || key === "utf8" || key === "_method") return
|
|
40
|
+
params.append(key, value)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
return params.toString()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function updateQueryParams(form) {
|
|
47
|
+
var query = formDataToQueryString(form)
|
|
48
|
+
var url = window.location.pathname + window.location.hash
|
|
49
|
+
if (query) url += "?" + query
|
|
50
|
+
history.replaceState(null, "", url)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function setPillActive(pillEl, active) {
|
|
54
|
+
var kit = pillEl.querySelector("[class*='pb_pill_kit_']")
|
|
55
|
+
if (!kit) return
|
|
56
|
+
kit.className = kit.className
|
|
57
|
+
.replace(/pb_pill_kit_primary_/g, "pb_pill_kit_TEMP_")
|
|
58
|
+
.replace(/pb_pill_kit_neutral_/g, active ? "pb_pill_kit_primary_" : "pb_pill_kit_neutral_")
|
|
59
|
+
.replace(/pb_pill_kit_TEMP_/g, active ? "pb_pill_kit_primary_" : "pb_pill_kit_neutral_")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function setPanelEnabled(panel, enabled) {
|
|
63
|
+
panel.style.display = enabled ? "" : "none"
|
|
64
|
+
panel.querySelectorAll("input, select, textarea").forEach(function (el) {
|
|
65
|
+
el.disabled = !enabled
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function selectedKeys() {
|
|
70
|
+
var keys = []
|
|
71
|
+
root.querySelectorAll("[data-form-docs-pill]").forEach(function (pillEl) {
|
|
72
|
+
var kit = pillEl.querySelector("[class*='pb_pill_kit_primary_']")
|
|
73
|
+
if (kit) keys.push(pillEl.getAttribute("data-form-docs-pill"))
|
|
74
|
+
})
|
|
75
|
+
return keys
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function updateCodeSnippet(keys) {
|
|
79
|
+
if (!codeOutput) return
|
|
80
|
+
|
|
81
|
+
// Match visible panel order (fixed kit order), not click/selection order.
|
|
82
|
+
var selected = {}
|
|
83
|
+
keys.forEach(function (key) { selected[key] = true })
|
|
84
|
+
|
|
85
|
+
var fieldSnippets = []
|
|
86
|
+
root.querySelectorAll("[data-form-docs-panel]").forEach(function (panel) {
|
|
87
|
+
var key = panel.getAttribute("data-form-docs-panel")
|
|
88
|
+
if (!selected[key]) return
|
|
89
|
+
var snippetEl = panel.querySelector("[data-form-docs-snippet]")
|
|
90
|
+
if (snippetEl) fieldSnippets.push(trimHighlightHtml(snippetEl.innerHTML))
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
codeOutput.innerHTML = [formOpenHtml].concat(fieldSnippets).concat([formCloseHtml]).join("\n")
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function syncSelection(keys) {
|
|
97
|
+
root.querySelectorAll("[data-form-docs-pill]").forEach(function (pillEl) {
|
|
98
|
+
var key = pillEl.getAttribute("data-form-docs-pill")
|
|
99
|
+
setPillActive(pillEl, keys.indexOf(key) !== -1)
|
|
100
|
+
})
|
|
101
|
+
root.querySelectorAll("[data-form-docs-panel]").forEach(function (panel) {
|
|
102
|
+
var key = panel.getAttribute("data-form-docs-panel")
|
|
103
|
+
setPanelEnabled(panel, keys.indexOf(key) !== -1)
|
|
104
|
+
})
|
|
105
|
+
updateCodeSnippet(keys)
|
|
106
|
+
clearSubmittedData()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function toggleKey(key) {
|
|
110
|
+
var keys = selectedKeys()
|
|
111
|
+
var index = keys.indexOf(key)
|
|
112
|
+
if (index === -1) {
|
|
113
|
+
keys.push(key)
|
|
114
|
+
} else if (keys.length > 1) {
|
|
115
|
+
keys.splice(index, 1)
|
|
116
|
+
}
|
|
117
|
+
syncSelection(keys)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function assignFormValue(result, key, value) {
|
|
121
|
+
var path = []
|
|
122
|
+
var asArray = false
|
|
123
|
+
var rest = key
|
|
124
|
+
var bareMatch = rest.match(/^([^[\]]+)/)
|
|
125
|
+
|
|
126
|
+
if (!bareMatch) {
|
|
127
|
+
result[key] = value
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
path.push(bareMatch[1])
|
|
132
|
+
rest = rest.slice(bareMatch[1].length)
|
|
133
|
+
|
|
134
|
+
while (rest.length > 0) {
|
|
135
|
+
if (rest.indexOf("[]") === 0) {
|
|
136
|
+
asArray = true
|
|
137
|
+
rest = rest.slice(2)
|
|
138
|
+
break
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
var bracketMatch = rest.match(/^\[([^\]]+)\]/)
|
|
142
|
+
if (!bracketMatch) {
|
|
143
|
+
result[key] = value
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
path.push(bracketMatch[1])
|
|
148
|
+
rest = rest.slice(bracketMatch[0].length)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (rest.length > 0) {
|
|
152
|
+
result[key] = value
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
var cursor = result
|
|
157
|
+
for (var i = 0; i < path.length - 1; i++) {
|
|
158
|
+
var segment = path[i]
|
|
159
|
+
if (!cursor[segment] || typeof cursor[segment] !== "object" || Array.isArray(cursor[segment])) {
|
|
160
|
+
cursor[segment] = {}
|
|
161
|
+
}
|
|
162
|
+
cursor = cursor[segment]
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
var last = path[path.length - 1]
|
|
166
|
+
if (asArray) {
|
|
167
|
+
if (!Array.isArray(cursor[last])) cursor[last] = []
|
|
168
|
+
cursor[last].push(value)
|
|
169
|
+
} else if (Object.prototype.hasOwnProperty.call(cursor, last)) {
|
|
170
|
+
if (!Array.isArray(cursor[last])) cursor[last] = [cursor[last]]
|
|
171
|
+
cursor[last].push(value)
|
|
172
|
+
} else {
|
|
173
|
+
cursor[last] = value
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function formDataToObject(form) {
|
|
178
|
+
var result = {}
|
|
179
|
+
var formData = new FormData(form)
|
|
180
|
+
|
|
181
|
+
formData.forEach(function (value, key) {
|
|
182
|
+
if (key === "authenticity_token" || key === "utf8" || key === "_method") return
|
|
183
|
+
assignFormValue(result, key, value)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
return result
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function showSubmittedData(data) {
|
|
190
|
+
if (emptyState) emptyState.style.display = "none"
|
|
191
|
+
if (dataOutput) {
|
|
192
|
+
dataOutput.style.display = ""
|
|
193
|
+
dataOutput.textContent = JSON.stringify(data, null, 2)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
root.querySelectorAll("[data-form-docs-pill]").forEach(function (pillEl) {
|
|
198
|
+
pillEl.addEventListener("click", function () {
|
|
199
|
+
toggleKey(pillEl.getAttribute("data-form-docs-pill"))
|
|
200
|
+
})
|
|
201
|
+
pillEl.addEventListener("keydown", function (event) {
|
|
202
|
+
if (event.key !== "Enter" && event.key !== " ") return
|
|
203
|
+
event.preventDefault()
|
|
204
|
+
toggleKey(pillEl.getAttribute("data-form-docs-pill"))
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
root.querySelectorAll("form").forEach(function (form) {
|
|
209
|
+
// Docs demos never navigate. Capture + return false cover the window before
|
|
210
|
+
// this script runs (live examples delay inline scripts ~100ms) and Turbo.
|
|
211
|
+
form.setAttribute("onsubmit", "return false;")
|
|
212
|
+
form.addEventListener("submit", function (event) {
|
|
213
|
+
event.preventDefault()
|
|
214
|
+
event.stopPropagation()
|
|
215
|
+
if (typeof form.reportValidity === "function" && !form.reportValidity()) return
|
|
216
|
+
showSubmittedData(formDataToObject(form))
|
|
217
|
+
updateQueryParams(form)
|
|
218
|
+
}, true)
|
|
219
|
+
|
|
220
|
+
form.addEventListener("reset", function () {
|
|
221
|
+
setTimeout(clearSubmittedData, 0)
|
|
222
|
+
})
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
syncSelection(selectedKeys())
|
|
226
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<%= pb_rails("flex", props: { align: "stretch", gap: "md", margin_bottom: "md", orientation: "column" }) do %>
|
|
2
|
+
<%= pb_rails("flex/flex_item") do %>
|
|
3
|
+
<%= pb_rails("caption", props: { text: "Rails form_with", margin_bottom: "xs" }) %>
|
|
4
|
+
<%= pb_rails("card", props: { background: "dark", dark: true, padding: "none" }) do %>
|
|
5
|
+
<div class="pb--codeCopy pb--codeCopy_compact">
|
|
6
|
+
<pre class="highlight" style="margin: 0; overflow: auto; font-size: 12px; line-height: 1.5; white-space: pre;"><%= raw render_code(
|
|
7
|
+
File.read(Playbook.kit_path("form", "docs", "snippets", "comparison_rails.txt")),
|
|
8
|
+
"erb"
|
|
9
|
+
) %></pre>
|
|
10
|
+
</div>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<%= pb_rails("flex/flex_item") do %>
|
|
15
|
+
<%= pb_rails("caption", props: { text: "Playbook pb_form_with", margin_bottom: "xs" }) %>
|
|
16
|
+
<%= pb_rails("card", props: { background: "dark", dark: true, padding: "none" }) do %>
|
|
17
|
+
<div class="pb--codeCopy pb--codeCopy_compact">
|
|
18
|
+
<pre class="highlight" style="margin: 0; overflow: auto; font-size: 12px; line-height: 1.5; white-space: pre;"><%= raw render_code(
|
|
19
|
+
File.read(Playbook.kit_path("form", "docs", "snippets", "comparison_playbook.txt")),
|
|
20
|
+
"erb"
|
|
21
|
+
) %></pre>
|
|
22
|
+
</div>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% end %>
|
|
26
|
+
|
|
27
|
+
<%= pb_rails("title", props: { size: 4, text: "What pb_form_with adds", margin_bottom: "sm" }) %>
|
|
28
|
+
<%= pb_rails("body", props: { tag: "div" }) do %>
|
|
29
|
+
<ul style="margin: 0; padding-left: 1.25rem;">
|
|
30
|
+
<li>Automatic Playbook styling via the <code>pb-form</code> class and kit-backed fields</li>
|
|
31
|
+
<li>A custom form builder for inputs such as <code>text_field</code>, <code>select</code>, <code>typeahead</code>, and more</li>
|
|
32
|
+
<li>Consistent spacing and action buttons through <code>form.actions</code></li>
|
|
33
|
+
<li>Optional client-side validation with <code>validate: true</code> and field-level messages</li>
|
|
34
|
+
<li>For <code>typeahead</code>, <code>phone_number_field</code>, and <code>dropdown_field</code>, pass a scoped string name that matches the form scope (e.g. <code>"user[phone]"</code> when <code>scope: :user</code>) so params nest together</li>
|
|
35
|
+
</ul>
|
|
36
|
+
<% end %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Standard Rails `form_with` still works, but it does not apply Playbook kit styling or the form builder helpers. Prefer `pb_form_with` when building forms in Playbook apps.
|