tramway 3.0.0.1 → 3.0.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/README.md +33 -11
- data/app/assets/javascripts/tramway/{multiselect_controller.js → tramway-select_controller.js} +44 -6
- data/app/components/tailwind_component.rb +3 -3
- data/app/components/tramway/form/builder.rb +81 -28
- data/app/components/tramway/form/checkbox_component.html.haml +2 -2
- data/app/components/tramway/form/checkbox_component.rb +14 -0
- data/app/components/tramway/form/date_field_component.html.haml +1 -1
- data/app/components/tramway/form/datetime_field_component.html.haml +1 -1
- data/app/components/tramway/form/label_component.html.haml +1 -1
- data/app/components/tramway/form/label_component.rb +2 -1
- data/app/components/tramway/form/number_field_component.html.haml +1 -1
- data/app/components/tramway/form/select_component.html.haml +1 -1
- data/app/components/tramway/form/text_area_component.html.haml +1 -1
- data/app/components/tramway/form/text_field_component.html.haml +1 -1
- data/app/components/tramway/form/time_field_component.html.haml +1 -1
- data/app/components/tramway/form/tramway_select/autocomplete_input_component.html.haml +1 -0
- data/app/components/tramway/form/tramway_select/autocomplete_input_component.rb +10 -0
- data/app/components/tramway/form/{multiselect → tramway_select}/caret_component.rb +1 -1
- data/app/components/tramway/form/{multiselect → tramway_select}/dropdown_container_component.html.haml +1 -1
- data/app/components/tramway/form/{multiselect → tramway_select}/dropdown_container_component.rb +1 -1
- data/app/components/tramway/form/tramway_select/item_container_component.html.haml +2 -0
- data/app/components/tramway/form/{multiselect → tramway_select}/item_container_component.rb +1 -1
- data/app/components/tramway/form/{multiselect → tramway_select}/select_as_input_component.html.haml +1 -1
- data/app/components/tramway/form/{multiselect → tramway_select}/select_as_input_component.rb +1 -1
- data/app/components/tramway/form/{multiselect → tramway_select}/selected_item_template_component.html.haml +1 -1
- data/app/components/tramway/form/tramway_select/selected_item_template_component.rb +29 -0
- data/app/components/tramway/form/tramway_select_component.html.haml +13 -0
- data/app/components/tramway/form/{multiselect_component.rb → tramway_select_component.rb} +38 -15
- data/config/tailwind.config.js +8 -2
- data/docs/AGENTS.md +28 -2
- data/lib/generators/tramway/install/install_generator.rb +4 -4
- data/lib/tramway/engine.rb +1 -1
- data/lib/tramway/helpers/views_helper.rb +6 -6
- data/lib/tramway/utils/field.rb +2 -2
- data/lib/tramway/version.rb +1 -1
- metadata +16 -14
- data/app/components/tramway/form/multiselect/item_container_component.html.haml +0 -2
- data/app/components/tramway/form/multiselect/selected_item_template_component.rb +0 -26
- data/app/components/tramway/form/multiselect_component.html.haml +0 -13
- /data/app/components/tramway/form/{multiselect → tramway_select}/caret_component.html.haml +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: def2792e8c3e1ebae5e4d2fa04b7e5edf92b72e4aed0f892cf8152e203c8daf2
|
|
4
|
+
data.tar.gz: 77eace6936af7c9597f49634ea5da28f699b4011f4ccac811259e659732ca192
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d6f7a8ed6f51a4658625b8df8f1db6ec2eb7619284eafc6acf0b46d67f0fb9eaf3bfe95e818d7226f52a93a6b81eb271e64335acf76640501132b890e000938d
|
|
7
|
+
data.tar.gz: 197a0227f09dbccacf37e82d2e5d15a585928b0ec60863c1ce43c20e012b568037e0880f9ffda49a21846c66dcec72f6b1931ff0790509d9c01b6b8da71727d8
|
data/README.md
CHANGED
|
@@ -1105,7 +1105,7 @@ Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by
|
|
|
1105
1105
|
<%= f.select :role, [:admin, :user] %>
|
|
1106
1106
|
<%= f.date_field :birth_date %>
|
|
1107
1107
|
<%= f.datetime_field :confirmed_at %>
|
|
1108
|
-
<%= f.
|
|
1108
|
+
<%= f.tramway_select :permissions, [['Create User', 'create_user'], ['Update user', 'update_user']] %>
|
|
1109
1109
|
<%= f.file_field :file %>
|
|
1110
1110
|
<%= f.submit 'Create User' %>
|
|
1111
1111
|
<% end %>
|
|
@@ -1144,9 +1144,20 @@ Available form helpers:
|
|
|
1144
1144
|
* date_field
|
|
1145
1145
|
* datetime_field
|
|
1146
1146
|
* time_field
|
|
1147
|
-
*
|
|
1147
|
+
* tramway_select ([Stimulus-based](https://github.com/Purple-Magic/tramway#stimulus-based-inputs))
|
|
1148
1148
|
* submit
|
|
1149
1149
|
|
|
1150
|
+
Autocomplete select example:
|
|
1151
|
+
|
|
1152
|
+
```erb
|
|
1153
|
+
<%= tramway_form_for @user do |f| %>
|
|
1154
|
+
<%= f.select :role, [:admin, :user], autocomplete: true %>
|
|
1155
|
+
<% end %>
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
`autocomplete: true` renders an autocomplete-enabled select. It cannot be used together with `multiselect: true` in the
|
|
1159
|
+
same select field.
|
|
1160
|
+
|
|
1150
1161
|
**Examples**
|
|
1151
1162
|
|
|
1152
1163
|
1. Sign In Form for `devise` authentication
|
|
@@ -1178,44 +1189,55 @@ Available form helpers:
|
|
|
1178
1189
|
|
|
1179
1190
|
`tramway_form_for` provides Tailwind-styled Stimulus-based custom inputs.
|
|
1180
1191
|
|
|
1181
|
-
#####
|
|
1192
|
+
##### Tramway Select
|
|
1182
1193
|
|
|
1183
|
-
In case you want to use tailwind-styled
|
|
1194
|
+
In case you want to use the tailwind-styled Tramway select this way
|
|
1184
1195
|
|
|
1185
1196
|
```erb
|
|
1186
1197
|
<%= tramway_form_for @user do |f| %>
|
|
1187
|
-
<%= f.
|
|
1198
|
+
<%= f.tramway_select :permissions, [['Create User', 'create_user'], ['Update user', 'update_user']] %>
|
|
1188
1199
|
<%# ... %>
|
|
1189
1200
|
<% end %>
|
|
1190
1201
|
```
|
|
1191
1202
|
|
|
1192
|
-
you should add Tramway
|
|
1203
|
+
you should add the Tramway Select Stimulus controller to your application.
|
|
1193
1204
|
|
|
1194
1205
|
Example for [importmap-rails](https://github.com/rails/importmap-rails) config
|
|
1195
1206
|
|
|
1196
1207
|
*config/importmap.rb*
|
|
1197
1208
|
```ruby
|
|
1198
|
-
pin '@tramway/
|
|
1209
|
+
pin '@tramway/tramway-select', to: 'tramway/tramway-select_controller.js'
|
|
1199
1210
|
```
|
|
1200
1211
|
|
|
1201
1212
|
*app/javascript/controllers/index.js*
|
|
1202
1213
|
```js
|
|
1203
1214
|
import { application } from "controllers/application"
|
|
1204
1215
|
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
|
|
1205
|
-
import {
|
|
1216
|
+
import { TramwaySelect } from "@tramway/tramway-select" // importing TramwaySelect controller class
|
|
1206
1217
|
eagerLoadControllersFrom("controllers", application)
|
|
1207
1218
|
|
|
1208
|
-
application.register('
|
|
1219
|
+
application.register('tramway-select', TramwaySelect) // register TramwaySelect controller class as `tramway-select` stimulus controller
|
|
1209
1220
|
```
|
|
1210
1221
|
|
|
1211
|
-
In case you need to use Stimulus `change` action with Tramway
|
|
1222
|
+
In case you need to use Stimulus `change` action with Tramway Select
|
|
1212
1223
|
|
|
1213
1224
|
```erb
|
|
1214
1225
|
<%= tramway_form_for @user do |f| %>
|
|
1215
|
-
<%= f.
|
|
1226
|
+
<%= f.tramway_select :role, data: { action: 'change->user-form#updateForm' } %>
|
|
1216
1227
|
<% end %>
|
|
1217
1228
|
```
|
|
1218
1229
|
|
|
1230
|
+
Remote form example:
|
|
1231
|
+
|
|
1232
|
+
```erb
|
|
1233
|
+
<%= tramway_form_for @user, remote: true do |f| %>
|
|
1234
|
+
<%= f.text_field :name %>
|
|
1235
|
+
<%= f.email_field :email %>
|
|
1236
|
+
<% end %>
|
|
1237
|
+
```
|
|
1238
|
+
|
|
1239
|
+
With `remote: true`, Tramway submits the form on each input `change` via inline JavaScript; no additional controller setup is required.
|
|
1240
|
+
|
|
1219
1241
|
### Tailwind-styled pagination for Kaminari
|
|
1220
1242
|
|
|
1221
1243
|
Tramway uses [Tailwind](https://tailwindcss.com/) by default. It has tailwind-styled pagination for [kaminari](https://github.com/kaminari/kaminari).
|
data/app/assets/javascripts/tramway/{multiselect_controller.js → tramway-select_controller.js}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
|
2
2
|
|
|
3
|
-
export default class
|
|
3
|
+
export default class TramwaySelect extends Controller {
|
|
4
4
|
static targets = ["dropdown", "showSelectedArea", "hiddenInput", "caretDown", "caretUp"]
|
|
5
5
|
|
|
6
6
|
static values = {
|
|
@@ -13,11 +13,15 @@ export default class Multiselect extends Controller {
|
|
|
13
13
|
placeholder: String,
|
|
14
14
|
selectAsInput: String,
|
|
15
15
|
value: Array,
|
|
16
|
-
onChange: String
|
|
16
|
+
onChange: String,
|
|
17
|
+
multiple: Boolean,
|
|
18
|
+
autocomplete: Boolean,
|
|
19
|
+
autocompleteInput: String
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
connect() {
|
|
20
23
|
this.dropdownState = 'closed';
|
|
24
|
+
|
|
21
25
|
this.items = JSON.parse(this.element.dataset.items).map((item, index) => {
|
|
22
26
|
return {
|
|
23
27
|
index,
|
|
@@ -40,9 +44,15 @@ export default class Multiselect extends Controller {
|
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
renderSelectedItems() {
|
|
43
|
-
const allItems = this.fillTemplate(this.element.dataset.selectedItemTemplate, this.selectedItems)
|
|
47
|
+
const allItems = this.fillTemplate(this.element.dataset.selectedItemTemplate, this.selectedItems)
|
|
48
|
+
|
|
49
|
+
let content = allItems;
|
|
50
|
+
|
|
51
|
+
if (this.autocomplete() && this.selectedItems.length === 0) {
|
|
52
|
+
content += this.element.dataset.autocompleteInput;
|
|
53
|
+
}
|
|
44
54
|
|
|
45
|
-
this.showSelectedAreaTarget.innerHTML =
|
|
55
|
+
this.showSelectedAreaTarget.innerHTML = content;
|
|
46
56
|
this.showSelectedAreaTarget.insertAdjacentHTML("beforeEnd", this.input());
|
|
47
57
|
this.updateInputOptions();
|
|
48
58
|
}
|
|
@@ -90,6 +100,7 @@ export default class Multiselect extends Controller {
|
|
|
90
100
|
|
|
91
101
|
closeDropdown() {
|
|
92
102
|
this.dropdownState = 'closed';
|
|
103
|
+
|
|
93
104
|
if (this.dropdown()) {
|
|
94
105
|
this.dropdown().remove();
|
|
95
106
|
}
|
|
@@ -126,6 +137,12 @@ export default class Multiselect extends Controller {
|
|
|
126
137
|
const itemIndex = this.items.findIndex(x => x.value === currentTarget.dataset.value);
|
|
127
138
|
const itemSelectedIndex = this.selectedItems.findIndex(x => x.value === currentTarget.dataset.value);
|
|
128
139
|
|
|
140
|
+
if (!this.multiple()) {
|
|
141
|
+
this.selectedItems = [];
|
|
142
|
+
this.items.forEach(item => item.selected = false);
|
|
143
|
+
this.closeDropdown()
|
|
144
|
+
}
|
|
145
|
+
|
|
129
146
|
if (itemSelectedIndex !== -1) {
|
|
130
147
|
this.selectedItems = this.selectedItems.filter((_, index) => index !== itemSelectedIndex);
|
|
131
148
|
this.items[itemIndex].selected = false;
|
|
@@ -135,7 +152,10 @@ export default class Multiselect extends Controller {
|
|
|
135
152
|
}
|
|
136
153
|
|
|
137
154
|
this.renderSelectedItems();
|
|
138
|
-
|
|
155
|
+
|
|
156
|
+
if (this.multiple()) {
|
|
157
|
+
this.rerenderItems();
|
|
158
|
+
}
|
|
139
159
|
}
|
|
140
160
|
|
|
141
161
|
input() {
|
|
@@ -155,6 +175,24 @@ export default class Multiselect extends Controller {
|
|
|
155
175
|
|
|
156
176
|
this.hiddenInputTarget.value = this.selectedItems.map(item => item.value);
|
|
157
177
|
}
|
|
178
|
+
|
|
179
|
+
multiple() {
|
|
180
|
+
return this.element.dataset.multiple == 'true';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
autocomplete() {
|
|
184
|
+
return this.element.dataset.autocomplete == 'true';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
search(event) {
|
|
188
|
+
const searchTerm = event.target.value.toLowerCase();
|
|
189
|
+
const filteredItems = this.items.filter(item => item.text.toLowerCase().includes(searchTerm) && !item.selected);
|
|
190
|
+
const dropdown = this.dropdown();
|
|
191
|
+
|
|
192
|
+
if (dropdown) {
|
|
193
|
+
dropdown.innerHTML = this.fillTemplate(this.element.dataset.itemContainer, filteredItems);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
158
196
|
}
|
|
159
197
|
|
|
160
|
-
export {
|
|
198
|
+
export { TramwaySelect }
|
|
@@ -18,7 +18,7 @@ class TailwindComponent < Tramway::BaseComponent
|
|
|
18
18
|
select_input: 'text-sm px-2 py-1',
|
|
19
19
|
file_button: 'text-sm px-3 py-1',
|
|
20
20
|
submit_button: 'text-sm px-3 py-1',
|
|
21
|
-
|
|
21
|
+
tramway_select_input: 'text-sm px-2 py-1 h-10',
|
|
22
22
|
checkbox_input: 'h-4 w-4'
|
|
23
23
|
},
|
|
24
24
|
medium: {
|
|
@@ -26,7 +26,7 @@ class TailwindComponent < Tramway::BaseComponent
|
|
|
26
26
|
select_input: 'text-base px-3 py-2',
|
|
27
27
|
file_button: 'text-base px-4 py-2',
|
|
28
28
|
submit_button: 'text-base px-4 py-2',
|
|
29
|
-
|
|
29
|
+
tramway_select_input: 'text-base px-2 py-1 h-12',
|
|
30
30
|
checkbox_input: 'h-5 w-5'
|
|
31
31
|
},
|
|
32
32
|
large: {
|
|
@@ -34,7 +34,7 @@ class TailwindComponent < Tramway::BaseComponent
|
|
|
34
34
|
select_input: 'text-xl px-4 py-3',
|
|
35
35
|
file_button: 'text-xl px-5 py-3',
|
|
36
36
|
submit_button: 'text-xl px-5 py-3',
|
|
37
|
-
|
|
37
|
+
tramway_select_input: 'text-xl px-3 py-2 h-15',
|
|
38
38
|
checkbox_input: 'h-6 w-6'
|
|
39
39
|
}
|
|
40
40
|
}.freeze
|
|
@@ -12,13 +12,19 @@ module Tramway
|
|
|
12
12
|
|
|
13
13
|
def initialize(object_name, object, template, options)
|
|
14
14
|
@horizontal = options[:horizontal] || false
|
|
15
|
+
@remote = options[:remote_submit] || false
|
|
15
16
|
|
|
16
17
|
options.merge!(class: [options[:class], 'flex flex-row items-center gap-2'].compact.join(' ')) if @horizontal
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
@form_object_class = options[:form_object_class]
|
|
20
|
+
|
|
21
|
+
if form_object(object)
|
|
22
|
+
super(object_name, form_object(object), template, options)
|
|
23
|
+
else
|
|
24
|
+
super
|
|
25
|
+
end
|
|
19
26
|
|
|
20
27
|
@form_size = options[:size] || options['size'] || :medium
|
|
21
|
-
@form_object_class = options[:form_object_class]
|
|
22
28
|
end
|
|
23
29
|
|
|
24
30
|
def common_field(component_name, input_method, attribute, **options, &)
|
|
@@ -83,25 +89,11 @@ module Tramway
|
|
|
83
89
|
end
|
|
84
90
|
|
|
85
91
|
def select(attribute, collection, **options, &)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
collection: explicitly_add_blank_option(collection, sanitized_options),
|
|
92
|
-
**default_options(attribute, sanitized_options)
|
|
93
|
-
), &)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def multiselect(attribute, collection, **options, &)
|
|
97
|
-
sanitized_options = sanitize_options(options)
|
|
98
|
-
|
|
99
|
-
render(Tramway::Form::MultiselectComponent.new(
|
|
100
|
-
input: input(:text_field),
|
|
101
|
-
value: sanitized_options[:value] || sanitized_options[:selected] || object.public_send(attribute),
|
|
102
|
-
collection:,
|
|
103
|
-
**default_options(attribute, sanitized_options)
|
|
104
|
-
), &)
|
|
92
|
+
if options[:multiple] || options[:autocomplete]
|
|
93
|
+
tramway_select(attribute, collection, **options, &)
|
|
94
|
+
else
|
|
95
|
+
default_select(attribute, collection, **options, &)
|
|
96
|
+
end
|
|
105
97
|
end
|
|
106
98
|
|
|
107
99
|
def submit(action, **options, &)
|
|
@@ -122,25 +114,84 @@ module Tramway
|
|
|
122
114
|
|
|
123
115
|
attr_reader :form_size
|
|
124
116
|
|
|
117
|
+
def default_select(attribute, collection, **options, &)
|
|
118
|
+
sanitized_options = sanitize_options(options)
|
|
119
|
+
|
|
120
|
+
render(Tramway::Form::SelectComponent.new(
|
|
121
|
+
input: input(:select),
|
|
122
|
+
value: sanitized_options[:selected] || object.public_send(attribute),
|
|
123
|
+
collection: explicitly_add_blank_option(collection, sanitized_options),
|
|
124
|
+
**default_options(attribute, sanitized_options)
|
|
125
|
+
), &)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def tramway_select(attribute, collection, **options, &)
|
|
129
|
+
sanitized_options = sanitize_options(options)
|
|
130
|
+
|
|
131
|
+
render(Tramway::Form::TramwaySelectComponent.new(
|
|
132
|
+
input: input(:text_field),
|
|
133
|
+
value: sanitized_options[:value] || sanitized_options[:selected] || object.public_send(attribute),
|
|
134
|
+
collection:,
|
|
135
|
+
multiple: options[:multiple],
|
|
136
|
+
autocomplete: options[:autocomplete],
|
|
137
|
+
**default_options(attribute, sanitized_options)
|
|
138
|
+
), &)
|
|
139
|
+
end
|
|
140
|
+
|
|
125
141
|
def input(method_name)
|
|
126
142
|
unbound_method = self.class.superclass.instance_method(method_name)
|
|
127
143
|
unbound_method.bind(self)
|
|
128
144
|
end
|
|
129
145
|
|
|
130
|
-
def form_object
|
|
131
|
-
|
|
146
|
+
def form_object(obj = nil)
|
|
147
|
+
return obj if obj.is_a?(Tramway::BaseForm)
|
|
148
|
+
return object if object.is_a?(Tramway::BaseForm)
|
|
149
|
+
|
|
150
|
+
@form_object_class&.new(obj || object)
|
|
132
151
|
end
|
|
133
152
|
|
|
134
153
|
def get_value(attribute, options)
|
|
135
|
-
options[:value]
|
|
154
|
+
return options[:value] if options.key?(:value)
|
|
155
|
+
|
|
156
|
+
form_obj = form_object
|
|
157
|
+
form_value = form_object_value(form_obj, attribute)
|
|
158
|
+
return form_value unless form_value.nil?
|
|
159
|
+
|
|
160
|
+
ensure_object_responds!(attribute, form_obj)
|
|
161
|
+
object_value(attribute)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def form_object_value(form_obj, attribute)
|
|
165
|
+
return if form_obj.blank?
|
|
166
|
+
|
|
167
|
+
form_obj.public_send(attribute)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def ensure_object_responds!(attribute, form_obj)
|
|
171
|
+
return unless object.present? && !object.respond_to?(attribute)
|
|
172
|
+
|
|
173
|
+
form_object_part = form_obj.present? ? "#{form_obj.class} or " : ''
|
|
174
|
+
message = "Neither form object nor object respond to #{attribute}. " \
|
|
175
|
+
"You should define #{attribute} method in #{form_object_part}#{object.class}"
|
|
176
|
+
|
|
177
|
+
raise ArgumentError, message
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def object_value(attribute)
|
|
181
|
+
return if object.blank?
|
|
182
|
+
|
|
183
|
+
object.public_send(attribute)
|
|
136
184
|
end
|
|
137
185
|
|
|
138
186
|
def default_options(attribute, options)
|
|
187
|
+
options.merge!(horizontal: true) if @horizontal
|
|
188
|
+
options.merge!(onchange: 'this.form.requestSubmit()') if @remote
|
|
189
|
+
|
|
139
190
|
{
|
|
140
191
|
attribute:,
|
|
141
192
|
label: label_build(attribute, options),
|
|
142
|
-
for: for_id(attribute),
|
|
143
|
-
options: options
|
|
193
|
+
for: options[:id].presence || for_id(attribute),
|
|
194
|
+
options: options,
|
|
144
195
|
size: form_size
|
|
145
196
|
}
|
|
146
197
|
end
|
|
@@ -157,8 +208,10 @@ module Tramway
|
|
|
157
208
|
|
|
158
209
|
def sanitize_options(options)
|
|
159
210
|
options.dup.tap do |opts|
|
|
160
|
-
|
|
161
|
-
|
|
211
|
+
%i[size multiple autocomplete].each do |key|
|
|
212
|
+
opts.delete(key)
|
|
213
|
+
opts.delete(key.to_s)
|
|
214
|
+
end
|
|
162
215
|
end
|
|
163
216
|
end
|
|
164
217
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
.flex.items-
|
|
1
|
+
.flex.items-center.gap-2.cursor-pointer{ class: default_container_classes }
|
|
2
2
|
- classes = "#{size_class(:checkbox_input)} #{checkbox_base_classes}"
|
|
3
3
|
= @input.call @attribute, **@options.merge(class: classes)
|
|
4
4
|
- if @label
|
|
5
5
|
%div
|
|
6
|
-
= component('tramway/form/label', for: @for) do
|
|
6
|
+
= component('tramway/form/label', for: @for, options: { class: label_classes }) do
|
|
7
7
|
= @label
|
|
@@ -4,6 +4,20 @@ module Tramway
|
|
|
4
4
|
module Form
|
|
5
5
|
# Tailwind-styled checkbox field
|
|
6
6
|
class CheckboxComponent < TailwindComponent
|
|
7
|
+
def label_classes
|
|
8
|
+
default_classes = 'cursor-pointer mb-0'
|
|
9
|
+
|
|
10
|
+
case size
|
|
11
|
+
when :small
|
|
12
|
+
default_classes += ' text-sm'
|
|
13
|
+
when :medium
|
|
14
|
+
default_classes += ' text-base'
|
|
15
|
+
when :large
|
|
16
|
+
default_classes += ' text-lg'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
default_classes
|
|
20
|
+
end
|
|
7
21
|
end
|
|
8
22
|
end
|
|
9
23
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
%div{ class: default_container_classes }
|
|
2
2
|
- if @label
|
|
3
|
-
= component('tramway/form/label', for: @for) do
|
|
3
|
+
= component('tramway/form/label', for: @for, class: 'mb-0') do
|
|
4
4
|
= @label
|
|
5
5
|
- classes = "#{size_class(:text_input)} #{text_input_base_classes}"
|
|
6
6
|
= @input.call @attribute, **@options.merge(class: classes), value: @value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
%div{ class: default_container_classes }
|
|
2
2
|
- if @label
|
|
3
|
-
= component('tramway/form/label', for: @for) do
|
|
3
|
+
= component('tramway/form/label', for: @for, class: 'mb-0') do
|
|
4
4
|
= @label
|
|
5
5
|
- classes = "#{size_class(:text_input)} #{text_input_base_classes}"
|
|
6
6
|
= @input.call @attribute, **@options.merge(class: classes), value: @value
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
%label{ for: @for, class: form_label_classes }
|
|
1
|
+
%label{ for: @for, class: "#{form_label_classes} #{options[:class]}" }
|
|
2
2
|
= content
|
|
@@ -5,10 +5,11 @@ module Tramway
|
|
|
5
5
|
# Form label for all tailwind-styled forms
|
|
6
6
|
class LabelComponent < Tramway::BaseComponent
|
|
7
7
|
option :for
|
|
8
|
+
option :options, optional: true, default: -> { {} }
|
|
8
9
|
|
|
9
10
|
def form_label_classes
|
|
10
11
|
theme_classes(
|
|
11
|
-
classic: 'block
|
|
12
|
+
classic: 'block font-semibold text-white'
|
|
12
13
|
)
|
|
13
14
|
end
|
|
14
15
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
%div{ class: default_container_classes }
|
|
2
2
|
- if @label
|
|
3
|
-
= component('tramway/form/label', for: @for) do
|
|
3
|
+
= component('tramway/form/label', for: @for, class: 'mb-0') do
|
|
4
4
|
= @label
|
|
5
5
|
- classes = "#{size_class(:text_input)} #{text_input_base_classes}"
|
|
6
6
|
= @input.call @attribute, **@options.merge(class: classes), value: @value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
%div{ class: default_container_classes }
|
|
2
2
|
- if @label
|
|
3
|
-
= component('tramway/form/label', for: @for) do
|
|
3
|
+
= component('tramway/form/label', for: @for, class: 'mb-0') do
|
|
4
4
|
= @label
|
|
5
5
|
- classes = "#{size_class(:select_input)} #{select_base_classes}"
|
|
6
6
|
= @input.call(@attribute, @collection, { selected: @value }, @options.merge(class: classes))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
%div{ class: default_container_classes }
|
|
2
2
|
- if @label
|
|
3
|
-
= component('tramway/form/label', for: @for) do
|
|
3
|
+
= component('tramway/form/label', for: @for, class: 'mb-0') do
|
|
4
4
|
= @label
|
|
5
5
|
- classes = "#{size_class(:text_input)} #{text_input_base_classes}"
|
|
6
6
|
= @input.call @attribute, **@options.merge(class: classes), value: @value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
%div{ class: default_container_classes }
|
|
2
2
|
- if @label
|
|
3
|
-
= component('tramway/form/label', for: @for) do
|
|
3
|
+
= component('tramway/form/label', for: @for, class: 'mb-0') do
|
|
4
4
|
= @label
|
|
5
5
|
- classes = "#{size_class(:text_input)} #{text_input_base_classes}"
|
|
6
6
|
= @input.call @attribute, **@options.merge(class: classes), value: @value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
%div{ class: default_container_classes }
|
|
2
2
|
- if @label
|
|
3
|
-
= component('tramway/form/label', for: @for) do
|
|
3
|
+
= component('tramway/form/label', for: @for, class: 'mb-0') do
|
|
4
4
|
= @label
|
|
5
5
|
- classes = "#{size_class(:text_input)} #{text_input_base_classes}"
|
|
6
6
|
= @input.call @attribute, **@options.merge(class: classes), value: @value
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
%input.focus:outline-none.focus:ring-0.w-full{ type: :text, data: { action: "input->tramway-select#search" } }
|
data/app/components/tramway/form/{multiselect → tramway_select}/select_as_input_component.html.haml
RENAMED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
.flex-1
|
|
2
2
|
- classes = "#{@size_class} #{base_classes}"
|
|
3
|
-
= @input.call(@attribute, @options.merge(placeholder: "{{placeholder}}", class: classes, data: { '
|
|
3
|
+
= @input.call(@attribute, @options.merge(placeholder: "{{placeholder}}", class: classes, data: { 'tramway-select-target' => 'hiddenInput' }))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
%div{ class: selected_item_classes, data: { action: "click->
|
|
1
|
+
%div{ class: selected_item_classes, data: { action: "click->tramway-select#toggleItem", text: "{{text}}", value: "{{value}}" } }
|
|
2
2
|
.font-normal.leading-none.max-w-full.flex-initial
|
|
3
3
|
{{text}}
|
|
4
4
|
.flex.flex-auto.flex-row-reverse
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tramway
|
|
4
|
+
module Form
|
|
5
|
+
module TramwaySelect
|
|
6
|
+
# Tailwind-styled tramway select field
|
|
7
|
+
class SelectedItemTemplateComponent < Tramway::BaseComponent
|
|
8
|
+
option :size
|
|
9
|
+
option :multiple
|
|
10
|
+
|
|
11
|
+
SIZE_CLASSES = {
|
|
12
|
+
small: 'text-sm',
|
|
13
|
+
medium: 'text-base',
|
|
14
|
+
large: 'text-lg'
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def selected_item_classes
|
|
18
|
+
classes = 'flex justify-center items-center font-medium py-1 px-2 rounded-xl ' \
|
|
19
|
+
'text-white shadow-md hover:bg-gray-800 cursor-pointer ' \
|
|
20
|
+
'space-x-1 selected-option ' + SIZE_CLASSES[size].to_s
|
|
21
|
+
|
|
22
|
+
classes += ' border border-gray-700' if multiple
|
|
23
|
+
|
|
24
|
+
theme_classes classic: classes
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.relative{ class: default_container_classes }
|
|
2
|
+
- if @label
|
|
3
|
+
= component('tramway/form/label', for: @for, class: 'mb-0') do
|
|
4
|
+
= @label
|
|
5
|
+
%div{ role: :combobox, data: tramway_select_hash, id: "#{@for}_tramway_select", class: tramway_select_classes }
|
|
6
|
+
- classes = "#{size_class(:tramway_select_input)} #{select_base_classes}"
|
|
7
|
+
.flex.flex-end.justify-between{ data: dropdown_data, **dropdown_options }
|
|
8
|
+
.flex.flex-row.flex-nowrap.overflow-x-auto.space-x-1.w-full{ data: { "tramway-select-target" => "showSelectedArea" } }
|
|
9
|
+
.flex.flex-col.justify-center
|
|
10
|
+
.caret-down{ data: { "tramway-select-target" => "caretDown" } }
|
|
11
|
+
= component 'tramway/form/tramway_select/caret', size:, direction: :down
|
|
12
|
+
.caret-up.hidden{ data: { "tramway-select-target" => "caretUp" } }
|
|
13
|
+
= component 'tramway/form/tramway_select/caret', size:, direction: :up
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
module Tramway
|
|
4
4
|
module Form
|
|
5
5
|
# Tailwind-styled multi-select field
|
|
6
|
-
class
|
|
6
|
+
class TramwaySelectComponent < TailwindComponent
|
|
7
7
|
option :collection
|
|
8
|
+
option :multiple, optional: true, default: -> { false }
|
|
9
|
+
option :autocomplete, optional: true, default: -> { false }
|
|
8
10
|
|
|
9
11
|
def before_render
|
|
10
12
|
@collection = collection.map do |(text, value)|
|
|
@@ -13,11 +15,12 @@ module Tramway
|
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
# rubocop:disable Metrics/MethodLength
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
# rubocop:disable Metrics/AbcSize
|
|
19
|
+
def tramway_select_hash
|
|
20
|
+
default = {
|
|
18
21
|
controller:,
|
|
19
22
|
selected_item_template:,
|
|
20
|
-
|
|
23
|
+
tramway_select_selected_items_value:,
|
|
21
24
|
dropdown_container:,
|
|
22
25
|
item_container:,
|
|
23
26
|
items:,
|
|
@@ -25,13 +28,33 @@ module Tramway
|
|
|
25
28
|
select_as_input:,
|
|
26
29
|
placeholder:,
|
|
27
30
|
value:,
|
|
28
|
-
on_change
|
|
31
|
+
on_change:,
|
|
32
|
+
multiple: multiple.to_s,
|
|
33
|
+
autocomplete: autocomplete.to_s
|
|
29
34
|
}.transform_keys { |key| key.to_s.gsub('_', '-') }
|
|
35
|
+
|
|
36
|
+
default.merge!(autocomplete_input:) if autocomplete
|
|
37
|
+
|
|
38
|
+
default
|
|
30
39
|
end
|
|
31
40
|
# rubocop:enable Metrics/MethodLength
|
|
41
|
+
# rubocop:enable Metrics/AbcSize
|
|
42
|
+
|
|
43
|
+
def autocomplete_input
|
|
44
|
+
component 'tramway/form/tramway_select/autocomplete_input'
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def tramway_select_classes
|
|
48
|
+
classes = ''
|
|
49
|
+
|
|
50
|
+
classes += 'select--multiple ' if multiple
|
|
51
|
+
classes += 'select--autocomplete ' if autocomplete
|
|
52
|
+
|
|
53
|
+
classes
|
|
54
|
+
end
|
|
32
55
|
|
|
33
56
|
def controller
|
|
34
|
-
controllers = [
|
|
57
|
+
controllers = ['tramway-select']
|
|
35
58
|
controllers << external_action.split('->').last.split('#').first if external_action
|
|
36
59
|
controllers += external_controllers
|
|
37
60
|
controllers.join(' ')
|
|
@@ -39,7 +62,7 @@ module Tramway
|
|
|
39
62
|
|
|
40
63
|
def dropdown_data
|
|
41
64
|
(options[:data] || {}).merge(
|
|
42
|
-
'
|
|
65
|
+
'tramway-select-target' => 'dropdown',
|
|
43
66
|
'dropdown-container' => dropdown_container,
|
|
44
67
|
'item-container' => item_container
|
|
45
68
|
)
|
|
@@ -50,13 +73,13 @@ module Tramway
|
|
|
50
73
|
end
|
|
51
74
|
|
|
52
75
|
def input_classes
|
|
53
|
-
"#{size_class(:
|
|
76
|
+
"#{size_class(:tramway_select_input)} #{select_base_classes}"
|
|
54
77
|
end
|
|
55
78
|
|
|
56
79
|
private
|
|
57
80
|
|
|
58
81
|
def action
|
|
59
|
-
'click->
|
|
82
|
+
'click->tramway-select#toggleDropdown'
|
|
60
83
|
end
|
|
61
84
|
|
|
62
85
|
def items
|
|
@@ -67,17 +90,17 @@ module Tramway
|
|
|
67
90
|
options[:placeholder]
|
|
68
91
|
end
|
|
69
92
|
|
|
70
|
-
def
|
|
93
|
+
def tramway_select_selected_items_value
|
|
71
94
|
[]
|
|
72
95
|
end
|
|
73
96
|
|
|
74
97
|
def select_as_input
|
|
75
98
|
component(
|
|
76
|
-
'tramway/form/
|
|
99
|
+
'tramway/form/tramway_select/select_as_input',
|
|
77
100
|
options:,
|
|
78
101
|
attribute:,
|
|
79
102
|
input:,
|
|
80
|
-
size_class: size_class(:
|
|
103
|
+
size_class: size_class(:tramway_select_input)
|
|
81
104
|
)
|
|
82
105
|
end
|
|
83
106
|
|
|
@@ -96,15 +119,15 @@ module Tramway
|
|
|
96
119
|
end
|
|
97
120
|
|
|
98
121
|
def selected_item_template
|
|
99
|
-
component
|
|
122
|
+
component 'tramway/form/tramway_select/selected_item_template', size:, multiple:
|
|
100
123
|
end
|
|
101
124
|
|
|
102
125
|
def dropdown_container
|
|
103
|
-
component('tramway/form/
|
|
126
|
+
component('tramway/form/tramway_select/dropdown_container', size:)
|
|
104
127
|
end
|
|
105
128
|
|
|
106
129
|
def item_container
|
|
107
|
-
component('tramway/form/
|
|
130
|
+
component('tramway/form/tramway_select/item_container', size:)
|
|
108
131
|
end
|
|
109
132
|
end
|
|
110
133
|
end
|
data/config/tailwind.config.js
CHANGED
|
@@ -333,8 +333,12 @@ module.exports = {
|
|
|
333
333
|
'bg-red-100',
|
|
334
334
|
'text-red-800',
|
|
335
335
|
'space-x-2',
|
|
336
|
+
'h-5',
|
|
337
|
+
'w-5',
|
|
338
|
+
'rounded-full',
|
|
339
|
+
'mb-0',
|
|
336
340
|
|
|
337
|
-
// ===
|
|
341
|
+
// === Tramway select dropdown positioning ===
|
|
338
342
|
'absolute',
|
|
339
343
|
'relative',
|
|
340
344
|
'shadow',
|
|
@@ -345,7 +349,7 @@ module.exports = {
|
|
|
345
349
|
'border-gray-600',
|
|
346
350
|
'text-gray-100',
|
|
347
351
|
|
|
348
|
-
// ===
|
|
352
|
+
// === Tramway select option styling ===
|
|
349
353
|
'border-b',
|
|
350
354
|
'border',
|
|
351
355
|
'border-l',
|
|
@@ -378,6 +382,8 @@ module.exports = {
|
|
|
378
382
|
'py-1',
|
|
379
383
|
'flex-nowrap',
|
|
380
384
|
'overflow-x-auto',
|
|
385
|
+
'focus:outline-none',
|
|
386
|
+
'focus:ring-0',
|
|
381
387
|
|
|
382
388
|
// === Flash message styles ===
|
|
383
389
|
'fixed',
|
data/docs/AGENTS.md
CHANGED
|
@@ -155,6 +155,9 @@ Use Tramway Button for buttons. Always add a color of the button via `color:` or
|
|
|
155
155
|
### Rule 7
|
|
156
156
|
Use `tramway_form_for` instead `form_with`, `form_for`
|
|
157
157
|
|
|
158
|
+
`tramway_form_for` has an upgraded `select` helper. Use `autocomplete: true` when you need an autocomplete select instead
|
|
159
|
+
of the usual select element. Do not use `autocomplete: true` together with `multiselect: true` on the same field.
|
|
160
|
+
|
|
158
161
|
Available `tramway_form_for` helpers:
|
|
159
162
|
- `text_field`
|
|
160
163
|
- `email_field`
|
|
@@ -167,9 +170,13 @@ Available `tramway_form_for` helpers:
|
|
|
167
170
|
- `date_field`
|
|
168
171
|
- `datetime_field`
|
|
169
172
|
- `time_field`
|
|
170
|
-
- `
|
|
173
|
+
- `tramway_select`
|
|
171
174
|
- `submit`
|
|
172
175
|
|
|
176
|
+
### Rule 7.1
|
|
177
|
+
Use `tramway_form_for(remote: true)` only when the form must submit asynchronously and update part of the current page (for example: modal forms, inline edits, or list updates without full page reload).
|
|
178
|
+
For standard create/update flows that redirect and show regular flash messages, keep it synchronous (do not set `remote: true`).
|
|
179
|
+
|
|
173
180
|
### Rule 8
|
|
174
181
|
Inherit all components from Tramway::BaseComponent
|
|
175
182
|
|
|
@@ -529,7 +536,15 @@ Always `tramway_decorate` and `tramway_form` for creating these types of objects
|
|
|
529
536
|
In Tramway Decorators, use `delegate_attributes` method instead of `delegate :something, to: :object`
|
|
530
537
|
|
|
531
538
|
### Rule 33
|
|
532
|
-
In case you want to use container on the page, use `tramway_container` helper instead of creating a component for that or using a plain div with Tailwind classes.
|
|
539
|
+
In case you want to use container on the page, use `tramway_container` helper instead of creating a component for that or using a plain div with Tailwind classes. In case you need to use container in layout view, use `tramway_main_container` for this. Here is example of using `tramway_main_container` inside application layout.
|
|
540
|
+
|
|
541
|
+
```
|
|
542
|
+
= tramway_main_container do
|
|
543
|
+
- if flash.any?
|
|
544
|
+
= tramway_flash text: flash[:notice].presence || flash[:alert],
|
|
545
|
+
type: flash[:notice].present? ? :will : :rage,
|
|
546
|
+
id: 'flash-container'
|
|
547
|
+
```
|
|
533
548
|
|
|
534
549
|
## Controller Patterns
|
|
535
550
|
|
|
@@ -595,6 +610,17 @@ end
|
|
|
595
610
|
= f.submit 'Save'
|
|
596
611
|
```
|
|
597
612
|
|
|
613
|
+
Autocomplete select example:
|
|
614
|
+
|
|
615
|
+
```ruby
|
|
616
|
+
= tramway_form_for @user do |f|
|
|
617
|
+
= f.select :role, [["Admin", "admin"], ["Manager", "manager"]], autocomplete: true
|
|
618
|
+
= f.submit 'Save'
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
`autocomplete: true` renders an autocomplete select. `autocomplete: true` and `multiselect: true` cannot be used together
|
|
622
|
+
in one select field.
|
|
623
|
+
|
|
598
624
|
`tramway_form_for` supports `horizontal: true` for horizontal form layout.
|
|
599
625
|
|
|
600
626
|
```ruby
|
|
@@ -52,8 +52,8 @@ module Tramway
|
|
|
52
52
|
@importmap_path ||= File.join(destination_root, 'config/importmap.rb')
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
def
|
|
56
|
-
'pin "@tramway/
|
|
55
|
+
def importmap_tramway_select_pin
|
|
56
|
+
'pin "@tramway/tramway-select", to: "tramway/tramway-select_controller.js"'
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def agents_file_path
|
|
@@ -242,11 +242,11 @@ module Tramway
|
|
|
242
242
|
return unless File.exist?(importmap_path)
|
|
243
243
|
|
|
244
244
|
content = File.read(importmap_path)
|
|
245
|
-
return if content.include?(
|
|
245
|
+
return if content.include?(importmap_tramway_select_pin)
|
|
246
246
|
|
|
247
247
|
File.open(importmap_path, 'a') do |file|
|
|
248
248
|
file.write("\n") unless content.empty? || content.end_with?("\n")
|
|
249
|
-
file.write("#{
|
|
249
|
+
file.write("#{importmap_tramway_select_pin}\n")
|
|
250
250
|
end
|
|
251
251
|
end
|
|
252
252
|
end
|
data/lib/tramway/engine.rb
CHANGED
|
@@ -11,12 +11,12 @@ module Tramway
|
|
|
11
11
|
def tramway_form_for(object, *, size: :medium, **options, &)
|
|
12
12
|
form_object_class = object.is_a?(Tramway::BaseForm) ? object.class : nil
|
|
13
13
|
|
|
14
|
-
form_for(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
14
|
+
form_for(object, *, **options.merge(
|
|
15
|
+
builder: Tramway::Form::Builder,
|
|
16
|
+
size: normalize_form_size(size),
|
|
17
|
+
form_object_class:,
|
|
18
|
+
remote_submit: options[:remote] || false
|
|
19
|
+
), &)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def tramway_table(**options, &)
|
data/lib/tramway/utils/field.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Tramway
|
|
|
10
10
|
input_options = field_options(field_data).merge(options.compact)
|
|
11
11
|
|
|
12
12
|
case input_type.to_sym
|
|
13
|
-
when :select, :
|
|
13
|
+
when :select, :tramway_select
|
|
14
14
|
collection = input_options.delete(:collection)
|
|
15
15
|
|
|
16
16
|
public_send(input_name, attribute, collection, **input_options, &)
|
|
@@ -23,7 +23,7 @@ module Tramway
|
|
|
23
23
|
|
|
24
24
|
def field_name(field_data)
|
|
25
25
|
case field_data.to_sym
|
|
26
|
-
when :text_area, :select, :
|
|
26
|
+
when :text_area, :select, :tramway_select, :check_box
|
|
27
27
|
field_data
|
|
28
28
|
when :checkbox
|
|
29
29
|
:check_box
|
data/lib/tramway/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tramway
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kalashnikovisme
|
|
@@ -138,8 +138,8 @@ files:
|
|
|
138
138
|
- MIT-LICENSE
|
|
139
139
|
- README.md
|
|
140
140
|
- Rakefile
|
|
141
|
-
- app/assets/javascripts/tramway/multiselect_controller.js
|
|
142
141
|
- app/assets/javascripts/tramway/table_row_preview_controller.js
|
|
142
|
+
- app/assets/javascripts/tramway/tramway-select_controller.js
|
|
143
143
|
- app/components/tailwind_component.html.haml
|
|
144
144
|
- app/components/tailwind_component.rb
|
|
145
145
|
- app/components/tramway/actions_buttons_container_component.html.haml
|
|
@@ -182,18 +182,6 @@ files:
|
|
|
182
182
|
- app/components/tramway/form/file_field_component.rb
|
|
183
183
|
- app/components/tramway/form/label_component.html.haml
|
|
184
184
|
- app/components/tramway/form/label_component.rb
|
|
185
|
-
- app/components/tramway/form/multiselect/caret_component.html.haml
|
|
186
|
-
- app/components/tramway/form/multiselect/caret_component.rb
|
|
187
|
-
- app/components/tramway/form/multiselect/dropdown_container_component.html.haml
|
|
188
|
-
- app/components/tramway/form/multiselect/dropdown_container_component.rb
|
|
189
|
-
- app/components/tramway/form/multiselect/item_container_component.html.haml
|
|
190
|
-
- app/components/tramway/form/multiselect/item_container_component.rb
|
|
191
|
-
- app/components/tramway/form/multiselect/select_as_input_component.html.haml
|
|
192
|
-
- app/components/tramway/form/multiselect/select_as_input_component.rb
|
|
193
|
-
- app/components/tramway/form/multiselect/selected_item_template_component.html.haml
|
|
194
|
-
- app/components/tramway/form/multiselect/selected_item_template_component.rb
|
|
195
|
-
- app/components/tramway/form/multiselect_component.html.haml
|
|
196
|
-
- app/components/tramway/form/multiselect_component.rb
|
|
197
185
|
- app/components/tramway/form/number_field_component.html.haml
|
|
198
186
|
- app/components/tramway/form/number_field_component.rb
|
|
199
187
|
- app/components/tramway/form/select_component.html.haml
|
|
@@ -204,6 +192,20 @@ files:
|
|
|
204
192
|
- app/components/tramway/form/text_field_component.rb
|
|
205
193
|
- app/components/tramway/form/time_field_component.html.haml
|
|
206
194
|
- app/components/tramway/form/time_field_component.rb
|
|
195
|
+
- app/components/tramway/form/tramway_select/autocomplete_input_component.html.haml
|
|
196
|
+
- app/components/tramway/form/tramway_select/autocomplete_input_component.rb
|
|
197
|
+
- app/components/tramway/form/tramway_select/caret_component.html.haml
|
|
198
|
+
- app/components/tramway/form/tramway_select/caret_component.rb
|
|
199
|
+
- app/components/tramway/form/tramway_select/dropdown_container_component.html.haml
|
|
200
|
+
- app/components/tramway/form/tramway_select/dropdown_container_component.rb
|
|
201
|
+
- app/components/tramway/form/tramway_select/item_container_component.html.haml
|
|
202
|
+
- app/components/tramway/form/tramway_select/item_container_component.rb
|
|
203
|
+
- app/components/tramway/form/tramway_select/select_as_input_component.html.haml
|
|
204
|
+
- app/components/tramway/form/tramway_select/select_as_input_component.rb
|
|
205
|
+
- app/components/tramway/form/tramway_select/selected_item_template_component.html.haml
|
|
206
|
+
- app/components/tramway/form/tramway_select/selected_item_template_component.rb
|
|
207
|
+
- app/components/tramway/form/tramway_select_component.html.haml
|
|
208
|
+
- app/components/tramway/form/tramway_select_component.rb
|
|
207
209
|
- app/components/tramway/native_text_component.html.haml
|
|
208
210
|
- app/components/tramway/native_text_component.rb
|
|
209
211
|
- app/components/tramway/nav/item/button_component.html.haml
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Tramway
|
|
4
|
-
module Form
|
|
5
|
-
module Multiselect
|
|
6
|
-
# Tailwind-styled multi-select field
|
|
7
|
-
class SelectedItemTemplateComponent < Tramway::BaseComponent
|
|
8
|
-
option :size
|
|
9
|
-
|
|
10
|
-
SIZE_CLASSES = {
|
|
11
|
-
small: 'text-sm',
|
|
12
|
-
medium: 'text-base',
|
|
13
|
-
large: 'text-lg'
|
|
14
|
-
}.freeze
|
|
15
|
-
|
|
16
|
-
def selected_item_classes
|
|
17
|
-
theme_classes(
|
|
18
|
-
classic: 'flex justify-center items-center font-medium py-1 px-2 rounded-xl border ' \
|
|
19
|
-
'text-white border-gray-700 shadow-md hover:bg-gray-800 cursor-pointer space-x-1 ' \
|
|
20
|
-
'selected-option ' + SIZE_CLASSES[size].to_s
|
|
21
|
-
)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
.relative{ class: default_container_classes }
|
|
2
|
-
- if @label
|
|
3
|
-
= component('tramway/form/label', for: @for) do
|
|
4
|
-
= @label
|
|
5
|
-
%div{ role: :combobox, data: multiselect_hash, id: "#{@for}_multiselect" }
|
|
6
|
-
- classes = "#{size_class(:multiselect_input)} #{select_base_classes}"
|
|
7
|
-
.flex.flex-end.justify-between{ data: dropdown_data, **dropdown_options }
|
|
8
|
-
.flex.flex-row.flex-nowrap.overflow-x-auto.space-x-1{ data: { "multiselect-target" => "showSelectedArea" } }
|
|
9
|
-
.flex.flex-col.justify-center
|
|
10
|
-
.caret-down{ data: { "multiselect-target" => "caretDown" } }
|
|
11
|
-
= component 'tramway/form/multiselect/caret', size: size, direction: :down
|
|
12
|
-
.caret-up.hidden{ data: { "multiselect-target" => "caretUp" } }
|
|
13
|
-
= component 'tramway/form/multiselect/caret', size: size, direction: :up
|
|
File without changes
|