bullet_train 1.5.1 → 1.5.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: 28b3ba5f50dac3b25183a892b754c22e23ff75a757293050c3124401037e5fd9
4
- data.tar.gz: 20c4f020b91dabe7a2bc85f006de605d187d71a943976a2f6eeb729cebb2dba5
3
+ metadata.gz: 26d50ad6167e3e1f7d3b8a550313094548a2b82bba8c60106ec8549db38abd51
4
+ data.tar.gz: ffe18a2a1265a052929fc52bd9213de99f565327384d022bf644b43cb4aa3174
5
5
  SHA512:
6
- metadata.gz: 88d77c764443e6de40f3ef8187c0add73aa76b4a3d1fc605dabba7335031a227b280d7db58ebf4ec5f4baf8087e9d1e1b54e3d364bccd5332337e2a23638ac74
7
- data.tar.gz: d12805a0a7a1bfb764e867d03d898062ea67423882786805ce60407fc5176eabacc10dbc94654f96279bde26cb38d3bfdb3c20ddd5f3a73323a492df43bec6ea
6
+ metadata.gz: d7e1ddd05c6a9bebad198f5cf6e48db86e09fa8194ef8ae5cc83bb12a141efe174716ea98b6b6b3032cc13a4d466dd6ed3a85dd044643aa717c3a72a58ba5c75
7
+ data.tar.gz: 04c8e18fea2b7db8ed9e08876cfa2f0fb51264f99c4cfb1a54323bb3497f3c7f2a42a4699cadaefe8ca639f42a78391138b79424e3a8493de6721efa85e6fbb2
@@ -0,0 +1,28 @@
1
+ # Examples for the `address_field` Field Partial
2
+
3
+ The address field partial adds a block of fields to your form. It creates and stores an instance of the `Address` model and associates it to your record.
4
+
5
+ ## Sub-Fields Included in the Partial
6
+
7
+ | Field Label | Name | Data Type | Notes |
8
+ |---------------------------|---------------|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
9
+ | Country | `country_id` | `Addresses::Country` | For country values, see `config/address/countries.json` in bullet_train-core/bullet_train. |
10
+ | Address | `address_one` | `string` | |
11
+ | Address (cont'd) | `address_two` | `string` | |
12
+ | City | `city` | `string` | |
13
+ | State / Province / Region | `region_id` | `Addresses::Region` | Depending on the country selected, the label will change (e.g. Prefecture for Japan, Province or Territory for Canada). For all region values, see `config/addresses/states.json` in bullet_train-core/bullet_train. |
14
+ | Postal code | `postal_code` | `string` | Depending on the country selected, the label will change (e.g. Zip code for the United States). |
15
+
16
+ If you'd like to add or remove fields, you'll need to update your own version of the `Address` model and eject and modify the `shared/fields/address_field` partial.
17
+
18
+ ## Dynamically Updating `region_id` and `postal_code` Fields and Labels
19
+
20
+ The `address_field` partial implements Bullet Train's [Dependent Fields Pattern](/docs/field-partials/dynamic-forms-dependent-fields.md) to automatically update the `region_id` and `postal_code` fields and their labels based on the value of the selected `country_id`.
21
+
22
+ ## Customizing the Address Output
23
+
24
+ By default, `show` screens get a multi-line output and `index` table columns get a one-line format (use the `one_line: true` param).
25
+
26
+ To customize this output, eject the `shared/attributes/address` partial.
27
+
28
+ See the [Showcase preview](https://github.com/bullet-train-co/showcase)<i class="ti ti-new-window ml-2"></i> for the example output.
@@ -40,3 +40,12 @@ You can allow multiple buttons to be selected using the `multiple` option, like
40
40
  <%= render 'shared/fields/buttons', form: form, method: :category_ids,
41
41
  options: Category.all.map { |category| [category.id, category.label_string] }, multiple: true %>
42
42
  ```
43
+
44
+ ## Dynamically Updating Form Fields
45
+
46
+ If you'd like to:
47
+
48
+ * modify other fields based on the value of your `buttons` field, or
49
+ * modify your `buttons` field based on the value of other fields
50
+
51
+ See [Dynamic Forms and Dependent Fields](/docs/field-partials/dynamic-forms-dependent-fields.md).
@@ -0,0 +1,123 @@
1
+ # Dynamic Forms and Dependent Fields
2
+
3
+ Bullet Train introduces two new concepts to make your Hotwire-powered forms update dynamically on field changes.
4
+
5
+ 1. Dependent Fields Pattern
6
+ 2. Dependent Fields Frame
7
+
8
+ ## Dependent Fields Pattern
9
+
10
+ Let's say we have a `super_select` for a "Where have you heard from us?" field. And we'll have a `text_field` for "Other", `disabled` by default.
11
+
12
+ ```erb
13
+ <%= render 'shared/fields/super_select',
14
+ method: :heard_from,
15
+ options: {include_blank: true},
16
+ other_options: {search: true}
17
+ %>
18
+ <%= render 'shared/fields/text_field',
19
+ method: :heard_from_other,
20
+ options: {disabled: true}
21
+ %>
22
+ ```
23
+
24
+ Our goal: if `other` is selected, enable the "Other" field.
25
+
26
+ We'll wire the `super_select` field with the `dependable` Stimulus controller. We'll also tie both fields using the `dependable-dependents-selector-value`. In this case, the `id` of the the `heard_from_other` field.
27
+
28
+ ```erb
29
+ <%= render 'shared/fields/super_select',
30
+ method: :heard_from,
31
+ options: {include_blank: true},
32
+ other_options: {search: true},
33
+ wrapper_options: {
34
+ data: {
35
+ 'controller': "dependable",
36
+ 'action': '$change->dependable#updateDependents',
37
+ 'dependable-dependents-selector-value': "##{form.field_id(:heard_from_other)}"
38
+ }
39
+ }
40
+ %>
41
+ <%= render 'shared/fields/text_field',
42
+ method: :heard_from_other,
43
+ id: form.field_id(:heard_from_other),
44
+ options: {disabled: true}
45
+ %>
46
+ ```
47
+
48
+ On `$change` ([See `super_select` dispatched events](/docs/field-partials/super-select#events)), a custom `dependable:updated` event will be dispatched to all elements matching the `dependable-dependents-selector-value`. This gives us flexibility: disparate form fields don't need to be wrapped with a common Stimulus controlled-wrapper. This approach is favored over Stimulus `outlets` because here we're not coupling the functionality of the `dependable` and `dependent` fields. We're just dispatching Custom Events and using CSS selectors, preferably good old `form.field_id`'s.
49
+
50
+ To let our `:heard_from_other` field handle the `dependable:updated` event, we'll assume we have created a custom `field-availability` Stimulus controller, with a `#toggle` method, looking for the `expected` value on the incoming event `target` element, in this case the `dependable` field.
51
+
52
+ ```erb
53
+ <%= render 'shared/fields/text_field',
54
+ method: :heard_from_other,
55
+ id: form.field_id(:heard_from_other),
56
+ options: {disabled: true},
57
+ data: {
58
+ controller: "field-availability",
59
+ action: "dependable:updated->field-availability#toggle",
60
+ field_availability_expected_value: "other"
61
+ }
62
+ %>
63
+ ```
64
+
65
+ Note: `field-availability` here is not implemented in Bullet Train. It serves as an example.
66
+
67
+ Next, we'll find a way to only serve the `:heard_from_other` field to the user if "other" is selected, this time by using server-side conditionals in a `turbo_frame`.
68
+
69
+ ## Dependent Fields Frame
70
+
71
+ What if you'd instead want to:
72
+
73
+ * Not rely on a custom Stimulus controller to control the `disabled` state of the "Other" field
74
+ * Show/hide multiple dependent fields based on the value of the `dependable` field.
75
+ * Update more than the field itself, but also the value of its `label`. As an example, the [`address_field`](/docs/field-partials/address-field.md) partial shows an empty "State / Province / Region" sub-field by default, and on changing the `:country_id` field to the United States, changes the whole `:region_id` to "State" as its label and with all US States as its choices.
76
+
77
+ For these situations, Bullet Train has a `dependent_fields_turbo_frame` partial that's made to listen to `dependable:updated` events by default.
78
+
79
+ ```erb
80
+ # update the super-select `dependable-dependents-selector-value` to "##{form.field_id(:heard_from, :dependent_fields)}" to match
81
+
82
+ <%= render "shared/fields/dependent_fields_frame",
83
+ id: form.field_id(:heard_from, :dependent_fields),
84
+ form: form,
85
+ dependable_fields: [:heard_from] do %>
86
+
87
+ <% if form.object&.heard_from == "other" %>
88
+ <%# no need for a custom `id` or the `disabled` attribute %>
89
+ <%= render 'shared/fields/text_field', method: :heard_from_other %>
90
+ <% end %>
91
+
92
+ <%# include additional fields if "other" is selected %>
93
+ <% end %>
94
+ ```
95
+
96
+ This `dependent_fields_frame` serves two purposes:
97
+
98
+ 1. Handle the `dependable:updated` event, so that the frame can...
99
+ 2. Re-fetch the current form URL (it could be for a `#new` or a `#edit`, it works in both situations) with a GET request (not a submit) that contains the `heard_from` value as a `query_string` param. It then ensures that our `form.object.heard_from` value gets populated with the value found in the `query_string` param automatically, with **no changes needed to the resource controller**. That's all handled by the `dependent_fields_frame` partial by reading its `dependable_fields` param.
100
+
101
+ With this functionality, the contents of the underlying `turbo_frame` will be populated with the updated fields.
102
+
103
+ ---
104
+
105
+ Now let's say we want to come back to the `disabled` use case above, while using the `dependent_fields_frame` approach.
106
+
107
+ We'll move the conditional on the `disabled` property. And we'll also let the `dependent_fields_frame` underlying controller handle disabling the field automatically when the `turbo_frame` awaits updates.
108
+
109
+ ```erb
110
+ <%= render "shared/fields/dependent_fields_frame",
111
+ id: form.field_id(:heard_from, :dependent_fields),
112
+ form: form,
113
+ dependable_fields: [:heard_from] do |dependent_fields_controller_name| %>
114
+
115
+ <%= render 'shared/fields/text_field',
116
+ method: :heard_from_other,
117
+ options: {disabled: form.object&.heard_from != "other"},
118
+ data: {"#{dependent_fields_controller_name}-target": "field"}
119
+ %>
120
+ <% end %>
121
+ ```
122
+
123
+ To learn more about its inner functionality, search the `bullet-train-core` repo for `dependable_controller.js`, `dependent_fields_frame_controller.js` and `_dependent_fields_frame.html.erb`. You can also see an implementation by looking at the `_address_field.html.erb` partial.
@@ -144,3 +144,12 @@ You can pass these options to the super select partial like so:
144
144
  ```
145
145
 
146
146
  *Passing options like this doesn't allow JS callbacks or functions to be used, so you must extend the Stimulus controller and add options to the `optionsOverride` getter if you want to do so.
147
+
148
+ ## Dynamically Updating Form Fields
149
+
150
+ If you'd like to:
151
+
152
+ * modify other fields based on the value of your `super_select`, or
153
+ * modify your `super_select` based on the value of other fields
154
+
155
+ See [Dynamic Forms and Dependent Fields](/docs/field-partials/dynamic-forms-dependent-fields.md).
@@ -122,25 +122,26 @@ Certain form field partials like `buttons` and `super_select` can also have thei
122
122
 
123
123
  ## Available Field Partials
124
124
 
125
- | Field Partial | Data Type | Multiple Values? | Assignment Helpers | JavaScript Library | Description |
126
- |--------------------------------------------------------|--------------|------------------|-------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
127
- | `boolean` | `boolean` | | `assign_boolean` | | |
128
- | [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | |
129
- | `image` | `string` or `attachment`* | | | | |
130
- | `color_picker` | `string` | | | [pickr](https://simonwep.github.io/pickr/) | |
131
- | `date_and_time_field` | `datetime` | | | [Date Range Picker](https://www.daterangepicker.com) | |
132
- | `date_field` | `date` | | | [Date Range Picker](https://www.daterangepicker.com) | |
133
- | `email_field` | `string` | | | | |
134
- | `emoji_field` | `string` | | | [Emoji Mart](https://missiveapp.com/open/emoji-mart) | A front-end library which allows users to browse and select emojis with ease. | |
135
- | [`file_field`](/docs/field-partials/file-field.md) | `attachment` | | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | |
136
- | `options` | `string` | Optionally | `assign_checkboxes` | | |
137
- | `password_field` | `string` | | | | |
138
- | `phone_field` | `string` | | | [International Telephone Input](https://intl-tel-input.com) | Ensures telephone numbers are in a format that can be used by providers like Twilio. |
139
- | [`super_select`](/docs/field-partials/super-select.md) | `string` | Optionally | `assign_select_options` | [Select2](https://select2.org) | Provides powerful option search, AJAX search, and multi-select functionality. |
140
- | `text_area` | `text` | | | | |
141
- | `text_field` | `string` | | | | |
142
- | `number_field` | `integer` | | | | |
143
- | `trix_editor` | `text` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. |
125
+ | Field Partial | Data Type | Multiple Values? | Assignment Helpers | JavaScript Library | Description |
126
+ |----------------------------------------------------------|---------------------------|------------------|-------------------------|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
127
+ | [`address_field`](/docs/field-partials/address-field.md) | `Address` | | | | Adds a block of address fields. On change, its country super-select auto-updates the state/province/region super-select and postal/zip code field label. |
128
+ | `boolean` | `boolean` | | `assign_boolean` | | |
129
+ | [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | |
130
+ | `image` | `string` or `attachment`* | | | | |
131
+ | `color_picker` | `string` | | | [pickr](https://simonwep.github.io/pickr/) | |
132
+ | `date_and_time_field` | `datetime` | | | [Date Range Picker](https://www.daterangepicker.com) | |
133
+ | `date_field` | `date` | | | [Date Range Picker](https://www.daterangepicker.com) | |
134
+ | `email_field` | `string` | | | | |
135
+ | `emoji_field` | `string` | | | [Emoji Mart](https://missiveapp.com/open/emoji-mart) | A front-end library which allows users to browse and select emojis with ease. | |
136
+ | [`file_field`](/docs/field-partials/file-field.md) | `attachment` | | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | |
137
+ | `options` | `string` | Optionally | `assign_checkboxes` | | |
138
+ | `password_field` | `string` | | | | |
139
+ | `phone_field` | `string` | | | [International Telephone Input](https://intl-tel-input.com) | Ensures telephone numbers are in a format that can be used by providers like Twilio. |
140
+ | [`super_select`](/docs/field-partials/super-select.md) | `string` | Optionally | `assign_select_options` | [Select2](https://select2.org) | Provides powerful option search, AJAX search, and multi-select functionality. |
141
+ | `text_area` | `text` | | | | |
142
+ | `text_field` | `string` | | | | |
143
+ | `number_field` | `integer` | | | | |
144
+ | `trix_editor` | `text` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. |
144
145
 
145
146
  * The data type for `image` fields will vary based on whether you're using Cloudinary or ActiveStorage.
146
147
  For Cloudinary you should use `string`, and for ActiveStorage you should use `attachment`.
@@ -161,7 +162,19 @@ After Super Scaffolding a `date` or `date_and_time` field, you can pass a format
161
162
 
162
163
  Please refer to the [Ruby on Rails documentation](https://guides.rubyonrails.org/i18n.html#adding-date-time-formats) for more information.
163
164
 
165
+ ## Dynamic Forms and Dependent Fields
166
+
167
+ To dynamically update your forms on field changes, Bullet Train introduces two new concepts:
168
+
169
+ 1. Dependent Fields Pattern
170
+ 2. Dependent Fields Frame
171
+
172
+ These concepts are currently used by the `address_field` to dynamically update the _State / Province / Region_ field on _Country_ change, as well as the label for the _Postal Code_ field.
173
+
174
+ [Read more about Dynamic Forms and Dependent Fields](/docs/field-partials/dynamic-forms-dependent-fields.md)
175
+
164
176
  ## Additional Field Partials Documentation
177
+ - [`address_field`](/docs/field-partials/address-field.md)
165
178
  - [`buttons`](/docs/field-partials/buttons.md)
166
179
  - [`super_select`](/docs/field-partials/super-select.md)
167
180
  - [`file_field`](/docs/field-partials/file-field.md)
@@ -1,3 +1,3 @@
1
1
  module BulletTrain
2
- VERSION = "1.5.1"
2
+ VERSION = "1.5.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet_train
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-02 00:00:00.000000000 Z
11
+ date: 2023-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard
@@ -725,8 +725,10 @@ files:
725
725
  - docs/billing/usage.md
726
726
  - docs/desktop.md
727
727
  - docs/field-partials.md
728
+ - docs/field-partials/address-field.md
728
729
  - docs/field-partials/buttons.md
729
730
  - docs/field-partials/date-related-fields.md
731
+ - docs/field-partials/dynamic-forms-dependent-fields.md
730
732
  - docs/field-partials/file-field.md
731
733
  - docs/field-partials/super-select.md
732
734
  - docs/font-awesome-pro.md