tramway 0.4.8 → 0.4.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +44 -1
- data/app/assets/javascripts/tramway/multiselect_controller.js +131 -0
- data/app/components/tailwinds/form/builder.rb +11 -2
- data/app/components/tailwinds/form/multiselect/dropdown_container.html.haml +3 -0
- data/app/components/tailwinds/form/multiselect/dropdown_container.rb +11 -0
- data/app/components/tailwinds/form/multiselect/item_container.html.haml +5 -0
- data/app/components/tailwinds/form/multiselect/item_container.rb +11 -0
- data/app/components/tailwinds/form/multiselect/select_as_input.html.haml +2 -0
- data/app/components/tailwinds/form/multiselect/select_as_input.rb +16 -0
- data/app/components/tailwinds/form/multiselect/selected_item_template.html.haml +6 -0
- data/app/components/tailwinds/form/multiselect/selected_item_template.rb +11 -0
- data/app/components/tailwinds/form/multiselect_component.html.haml +10 -0
- data/app/components/tailwinds/form/multiselect_component.rb +73 -0
- data/app/components/tailwinds/form/select_component.rb +1 -1
- data/config/routes.rb +2 -0
- data/lib/rules/turbo_html_attributes_rules.rb +1 -1
- data/lib/tramway/configs/entity.rb +15 -8
- data/lib/tramway/engine.rb +4 -0
- data/lib/tramway/helpers/navbar_helper.rb +1 -1
- data/lib/tramway/helpers/views_helper.rb +2 -2
- data/lib/tramway/navbar.rb +7 -7
- data/lib/tramway/utils/render.rb +2 -2
- data/lib/tramway/version.rb +1 -1
- metadata +13 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 588137c9cafa9b3b22de988ed0593b5ad34bda6480919b99b6eb7899cd8efb14
|
4
|
+
data.tar.gz: dbd1ecd2af4158892bb2e517cb3c962143f4f1109a00b8f392eaae392ad42205
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f3a4841ba2bdbe9e5bb1a12ab10900b90d43b916534af3f33eb57e6be0a33ae88f6148f7c795d584f7a9ac7cadc7b7bc38b411f8ca6694b0a7d23153295f7d8
|
7
|
+
data.tar.gz: 215ba73a338b8ab3d30b923696bb9cc22f189f9c8f1858c2e2a6cec0ce388e4fb4f30fee0345deaab19677416810f35935fa62b658b2c8f6b176e0d02da5a337
|
data/README.md
CHANGED
@@ -8,7 +8,9 @@ Unite Ruby on Rails brilliance. Streamline development with Tramway.
|
|
8
8
|
* [Tramway Form](https://github.com/Purple-Magic/tramway#tramway-form)
|
9
9
|
* [Tramway Navbar](https://github.com/Purple-Magic/tramway#tramway-navbar)
|
10
10
|
* [Tailwind-styled forms](https://github.com/Purple-Magic/tramway#tailwind-styled-forms)
|
11
|
+
* [Stimulus-based inputs](https://github.com/Purple-Magic/tramway#stimulus-based-inputs)
|
11
12
|
* [Tailwind-styled pagination](https://github.com/Purple-Magic/tramway?tab=readme-ov-file#tailwind-styled-pagination-for-kaminari)
|
13
|
+
* [Articles](https://github.com/Purple-Magic/tramway#usage)
|
12
14
|
|
13
15
|
## Installation
|
14
16
|
Add this line to your application's Gemfile:
|
@@ -421,10 +423,11 @@ Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are
|
|
421
423
|
Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by default.
|
422
424
|
|
423
425
|
```ruby
|
424
|
-
= tramway_form_for
|
426
|
+
= tramway_form_for @user do |f|
|
425
427
|
= f.text_field :text
|
426
428
|
= f.password_field :password
|
427
429
|
= f.select :role, [:admin, :user]
|
430
|
+
= f.multiselect :permissions, [['Create User', 'create_user'], ['Update user', 'update_user']]
|
428
431
|
= f.file_field :file
|
429
432
|
= f.submit "Create User"
|
430
433
|
```
|
@@ -436,8 +439,42 @@ Available form helpers:
|
|
436
439
|
* password_field
|
437
440
|
* file_field
|
438
441
|
* select
|
442
|
+
* multiselect ([Stimulus-based](https://github.com/Purple-Magic/tramway#stimulus-based-inputs))
|
439
443
|
* submit
|
440
444
|
|
445
|
+
#### Stimulus-based inputs
|
446
|
+
|
447
|
+
`tramway_form_for` provides Tailwind-styled Stimulus-based custom inputs.
|
448
|
+
|
449
|
+
##### Multiselect
|
450
|
+
|
451
|
+
In case you want to use tailwind-styled multiselect this way
|
452
|
+
|
453
|
+
```haml
|
454
|
+
= tramway_form_for @user do |f|
|
455
|
+
= f.multiselect :permissions, [['Create User', 'create_user'], ['Update user', 'update_user']]
|
456
|
+
#- ...
|
457
|
+
```
|
458
|
+
|
459
|
+
you should add Tramway Multiselect Stimulus controller to your application.
|
460
|
+
|
461
|
+
Example for [importmap-rails](https://github.com/rails/importmap-rails) config
|
462
|
+
|
463
|
+
*config/importmap.rb*
|
464
|
+
```ruby
|
465
|
+
pin '@tramway/multiselect', to: 'tramway/multiselect_controller.js'
|
466
|
+
```
|
467
|
+
|
468
|
+
*app/javascript/controllers/index.js*
|
469
|
+
```js
|
470
|
+
import { application } from "controllers/application"
|
471
|
+
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
|
472
|
+
import { Multiselect } from "@tramway/multiselect" // importing Multiselect controller class
|
473
|
+
eagerLoadControllersFrom("controllers", application)
|
474
|
+
|
475
|
+
application.register('multiselect', Multiselect) // register Multiselect controller class as `multiselect` stimulus controller
|
476
|
+
```
|
477
|
+
|
441
478
|
### Tailwind-styled pagination for Kaminari
|
442
479
|
|
443
480
|
Tramway uses [Tailwind](https://tailwindcss.com/) by default. It has tailwind-styled pagination for [kaminari](https://github.com/kaminari/kaminari).
|
@@ -480,6 +517,12 @@ user_2 = tramway_form User.first
|
|
480
517
|
user_2.object #=> returns pure user object
|
481
518
|
```
|
482
519
|
|
520
|
+
## Articles
|
521
|
+
* [Tramway on Rails](https://kalashnikovisme.medium.com/tramway-on-rails-32158c35ed68)
|
522
|
+
* [Delegating ActiveRecord methods to decorators in Rails](https://kalashnikovisme.medium.com/delegating-activerecord-methods-to-decorators-in-rails-4e4ec1c6b3a6)
|
523
|
+
* [Behave as ActiveRecord. Why do we want objects to be AR lookalikes?](https://kalashnikovisme.medium.com/behave-as-activerecord-why-do-we-want-objects-to-be-ar-lookalikes-d494d692e1d3)
|
524
|
+
* [Decorating associations in Rails with Tramway](https://kalashnikovisme.medium.com/decorating-associations-in-rails-with-tramway-b46a28392f9e)
|
525
|
+
|
483
526
|
## Contributing
|
484
527
|
|
485
528
|
Install [lefthook](https://github.com/evilmartians/lefthook)
|
@@ -0,0 +1,131 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class Multiselect extends Controller {
|
4
|
+
static targets = ["dropdown", "showSelectedArea", "hiddenInput"];
|
5
|
+
|
6
|
+
static values = {
|
7
|
+
items: Array,
|
8
|
+
dropdownContainer: String,
|
9
|
+
itemContainer: String,
|
10
|
+
selectedItemTemplate: String,
|
11
|
+
dropdownState: String,
|
12
|
+
selectedItems: Array,
|
13
|
+
placeholder: String,
|
14
|
+
selectAsInput: String,
|
15
|
+
value: Array
|
16
|
+
}
|
17
|
+
|
18
|
+
connect() {
|
19
|
+
this.dropdownState = 'closed';
|
20
|
+
this.unselectedItems = JSON.parse(this.element.dataset.items).map((item) => {
|
21
|
+
return {
|
22
|
+
text: item.text,
|
23
|
+
value: item.value.toString()
|
24
|
+
}
|
25
|
+
});
|
26
|
+
|
27
|
+
const initialValues = this.element.dataset.value === undefined ? [] : this.element.dataset.value.split(',')
|
28
|
+
this.selectedItems = this.unselectedItems.filter(item => initialValues.includes(item.value));
|
29
|
+
this.unselectedItems = this.unselectedItems.filter(item => !initialValues.includes(item.value));
|
30
|
+
|
31
|
+
this.renderSelectedItems();
|
32
|
+
}
|
33
|
+
|
34
|
+
renderSelectedItems() {
|
35
|
+
const allItems = this.fillTemplate(this.element.dataset.selectedItemTemplate, this.selectedItems);
|
36
|
+
this.showSelectedAreaTarget.innerHTML = allItems;
|
37
|
+
this.showSelectedAreaTarget.insertAdjacentHTML("beforeEnd", this.input());
|
38
|
+
this.updateInputOptions();
|
39
|
+
}
|
40
|
+
|
41
|
+
fillTemplate(template, items) {
|
42
|
+
return items.map((item) => {
|
43
|
+
return template.replace(/{{text}}/g, item.text).replace(/{{value}}/g, item.value)
|
44
|
+
}).join('')
|
45
|
+
}
|
46
|
+
|
47
|
+
closeOnClickOutside(event) {
|
48
|
+
if (this.dropdownState === 'open' && !this.element.contains(event.target)) {
|
49
|
+
this.closeDropdown();
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
toggleDropdown() {
|
54
|
+
if (this.dropdownState === 'closed') {
|
55
|
+
this.openDropdown();
|
56
|
+
} else {
|
57
|
+
this.closeDropdown();
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
rerenderItems() {
|
62
|
+
this.closeDropdown();
|
63
|
+
this.openDropdown();
|
64
|
+
}
|
65
|
+
|
66
|
+
openDropdown() {
|
67
|
+
this.dropdownState = 'open';
|
68
|
+
this.dropdownTarget.insertAdjacentHTML("afterend", this.template);
|
69
|
+
|
70
|
+
if (this.dropdown()) {
|
71
|
+
this.dropdown().addEventListener('click', event => event.stopPropagation());
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
dropdown() {
|
76
|
+
return this.element.querySelector('#dropdown');
|
77
|
+
}
|
78
|
+
|
79
|
+
closeDropdown() {
|
80
|
+
this.dropdownState = 'closed';
|
81
|
+
if (this.dropdown()) {
|
82
|
+
this.dropdown().remove();
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
get template() {
|
87
|
+
return this.element.dataset.dropdownContainer.replace(
|
88
|
+
/{{content}}/g,
|
89
|
+
this.fillTemplate(this.element.dataset.itemContainer, this.unselectedItems)
|
90
|
+
);
|
91
|
+
}
|
92
|
+
|
93
|
+
toggleItem({ currentTarget }) {
|
94
|
+
const item = {
|
95
|
+
text: currentTarget.dataset.text,
|
96
|
+
value: currentTarget.dataset.value
|
97
|
+
};
|
98
|
+
|
99
|
+
const itemIndex = this.selectedItems.findIndex(x => x.value === item.value);
|
100
|
+
if (itemIndex !== -1) {
|
101
|
+
this.selectedItems = this.selectedItems.filter((_, index) => index !== itemIndex);
|
102
|
+
} else {
|
103
|
+
this.selectedItems.push(item);
|
104
|
+
}
|
105
|
+
|
106
|
+
this.unselectedItems = this.unselectedItems.filter(x => x.value !== item.value);
|
107
|
+
|
108
|
+
this.renderSelectedItems();
|
109
|
+
this.rerenderItems();
|
110
|
+
}
|
111
|
+
|
112
|
+
input() {
|
113
|
+
const placeholder = this.selectedItems.length > 0 ? '' : this.element.dataset.placeholder;
|
114
|
+
return this.element.dataset.selectAsInput.replace(/{{placeholder}}/g, placeholder);
|
115
|
+
}
|
116
|
+
|
117
|
+
updateInputOptions() {
|
118
|
+
this.hiddenInputTarget.innerHTML = '';
|
119
|
+
this.selectedItems.forEach(selected => {
|
120
|
+
const option = document.createElement("option");
|
121
|
+
option.text = selected.text;
|
122
|
+
option.value = selected.value;
|
123
|
+
option.setAttribute("selected", true);
|
124
|
+
this.hiddenInputTarget.append(option);
|
125
|
+
});
|
126
|
+
|
127
|
+
this.hiddenInputTarget.value = this.selectedItems.map(item => item.value);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
export { Multiselect }
|
@@ -35,8 +35,17 @@ module Tailwinds
|
|
35
35
|
), &)
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
39
|
-
render(Tailwinds::Form::
|
38
|
+
def multiselect(attribute, collection, **options, &)
|
39
|
+
render(Tailwinds::Form::MultiselectComponent.new(
|
40
|
+
input: input(:text_field),
|
41
|
+
value: options[:value] || options[:selected] || object.public_send(attribute)&.first,
|
42
|
+
collection:,
|
43
|
+
**default_options(attribute, options)
|
44
|
+
), &)
|
45
|
+
end
|
46
|
+
|
47
|
+
def submit(action, **, &)
|
48
|
+
render(Tailwinds::Form::SubmitButtonComponent.new(action, **), &)
|
40
49
|
end
|
41
50
|
|
42
51
|
private
|
@@ -0,0 +1,5 @@
|
|
1
|
+
.cursor-pointer.w-full.border-gray-100.rounded-t.border-b.hover:bg-teal-100{ data: { action: "click->multiselect#toggleItem", text: "{{text}}", value: "{{value}}" } }
|
2
|
+
.flex.w-full.items-center.p-2.pl-2.border-transparent.border-l-2.relative.hover:border-teal-100
|
3
|
+
.w-full.items-center.flex
|
4
|
+
.mx-2.leading-6
|
5
|
+
{{text}}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tailwinds
|
4
|
+
module Form
|
5
|
+
module Multiselect
|
6
|
+
# Renders input as select
|
7
|
+
class SelectAsInput < ViewComponent::Base
|
8
|
+
extend Dry::Initializer[undefined: false]
|
9
|
+
|
10
|
+
option :options
|
11
|
+
option :attribute
|
12
|
+
option :input
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
.flex.justify-center.items-center.m-1.font-medium.py-1.px-2.bg-white.rounded-full.text-teal-700.bg-teal-100.border.border-teal-300
|
2
|
+
.text-xs.font-normal.leading-none.max-w-full.flex-initial
|
3
|
+
{{text}}
|
4
|
+
.flex.flex-auto.flex-row-reverse
|
5
|
+
.cursor-pointer{ data: { action: "click->multiselect#toggleItem", text: "{{text}}", value: "{{value}}" } }
|
6
|
+
⨯
|
@@ -0,0 +1,10 @@
|
|
1
|
+
.mb-4
|
2
|
+
- if @label
|
3
|
+
%label.block.text-gray-700.text-sm.font-bold.mb-2{ for: @for }
|
4
|
+
= @label
|
5
|
+
.flex.flex-col.items-center.relative{ data: multiselect_hash, id: "#{@for}_multiselect" }
|
6
|
+
.min-w-96.w-fit
|
7
|
+
.p-1.flex.border.border-gray-200.bg-white.rounded{ data: { "multiselect-target" => "dropdown" } }
|
8
|
+
.flex.flex-auto.flex-wrap{ data: { "multiselect-target" => "showSelectedArea" } }
|
9
|
+
.text-gray-300.w-8.py-1.pl-2.pr-1.border-l.flex.items-center.border-gray-200
|
10
|
+
^
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tailwinds
|
4
|
+
module Form
|
5
|
+
# Tailwind-styled multi-select field
|
6
|
+
class MultiselectComponent < TailwindComponent
|
7
|
+
option :collection
|
8
|
+
|
9
|
+
def before_render
|
10
|
+
@collection = collection.map do |(text, value)|
|
11
|
+
{ text:, value: }
|
12
|
+
end.to_json
|
13
|
+
end
|
14
|
+
|
15
|
+
def multiselect_hash
|
16
|
+
{
|
17
|
+
controller:, selected_item_template:, multiselect_selected_items_value:, dropdown_container:, item_container:,
|
18
|
+
items:, action:, select_as_input:, placeholder:, value:
|
19
|
+
}.transform_keys { |key| key.to_s.gsub('_', '-') }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def controller
|
25
|
+
:multiselect
|
26
|
+
end
|
27
|
+
|
28
|
+
def action
|
29
|
+
'click->multiselect#toggleDropdown'
|
30
|
+
end
|
31
|
+
|
32
|
+
def items
|
33
|
+
collection
|
34
|
+
end
|
35
|
+
|
36
|
+
def placeholder
|
37
|
+
options[:placeholder]
|
38
|
+
end
|
39
|
+
|
40
|
+
def multiselect_selected_items_value
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
|
44
|
+
def select_as_input
|
45
|
+
render(Tailwinds::Form::Multiselect::SelectAsInput.new(options:, attribute:, input:))
|
46
|
+
end
|
47
|
+
|
48
|
+
def method_missing(method_name, *, &)
|
49
|
+
component = component_name(method_name)
|
50
|
+
|
51
|
+
if method_name.to_s.include?('_') && Object.const_defined?(component)
|
52
|
+
render(component.constantize.new(*, &))
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def respond_to_missing?(method_name, include_private = false)
|
59
|
+
if method_name.to_s.include?('_') && Object.const_defined?(component_name(method_name))
|
60
|
+
true
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# :reek:UtilityFunction { enabled: false }
|
67
|
+
def component_name(method_name)
|
68
|
+
"Tailwinds::Form::Multiselect::#{method_name.to_s.camelize}"
|
69
|
+
end
|
70
|
+
# :reek:UtilityFunction { enabled: true }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/config/routes.rb
CHANGED
@@ -9,18 +9,25 @@ module Tramway
|
|
9
9
|
attribute :name, Types::Coercible::String
|
10
10
|
attribute? :route, Tramway::Configs::Entities::Route
|
11
11
|
|
12
|
+
# Route Struct contains implemented in Tramway CRUD and helpful routes for the entity
|
13
|
+
RouteStruct = Struct.new(:index)
|
14
|
+
|
15
|
+
# HumanNameStruct contains human names forms for the entity
|
16
|
+
HumanNameStruct = Struct.new(:single, :plural)
|
17
|
+
|
12
18
|
def routes
|
13
|
-
|
19
|
+
RouteStruct.new(Rails.application.routes.url_helpers.public_send(route_helper_method))
|
14
20
|
end
|
15
21
|
|
16
22
|
def human_name
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
single, plural = if model_class.present?
|
24
|
+
model_name = model_class.model_name.human
|
25
|
+
[model_name, model_name.pluralize]
|
26
|
+
else
|
27
|
+
[name.capitalize, name.pluralize.capitalize]
|
28
|
+
end
|
29
|
+
|
30
|
+
HumanNameStruct.new(single, plural)
|
24
31
|
end
|
25
32
|
|
26
33
|
private
|
data/lib/tramway/engine.rb
CHANGED
@@ -4,8 +4,8 @@ module Tramway
|
|
4
4
|
module Helpers
|
5
5
|
# Provides view-oriented helpers for ActionView
|
6
6
|
module ViewsHelper
|
7
|
-
def tramway_form_for(object,
|
8
|
-
form_for(object,
|
7
|
+
def tramway_form_for(object, *, **options, &)
|
8
|
+
form_for(object, *, **options.merge(builder: Tailwinds::Form::Builder), &)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
data/lib/tramway/navbar.rb
CHANGED
@@ -33,13 +33,13 @@ module Tramway
|
|
33
33
|
reset_filling
|
34
34
|
end
|
35
35
|
|
36
|
-
def item(text_or_url, url = nil,
|
37
|
-
raise 'You cannot provide an argument and a code block at the same time' if provided_url_and_block?(url, &
|
36
|
+
def item(text_or_url, url = nil, **, &)
|
37
|
+
raise 'You cannot provide an argument and a code block at the same time' if provided_url_and_block?(url, &)
|
38
38
|
|
39
39
|
rendered_item = if url.present?
|
40
|
-
render_ignoring_block(text_or_url, url, **
|
40
|
+
render_ignoring_block(text_or_url, url, **)
|
41
41
|
else
|
42
|
-
render_using_block(text_or_url,
|
42
|
+
render_using_block(text_or_url, **, &)
|
43
43
|
end
|
44
44
|
|
45
45
|
@items[@filling] << rendered_item
|
@@ -79,13 +79,13 @@ module Tramway
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
def render_using_block(text_or_url, method: nil, **options, &
|
82
|
+
def render_using_block(text_or_url, method: nil, **options, &)
|
83
83
|
options.merge!(href: text_or_url)
|
84
84
|
|
85
85
|
if method.present? && method.to_sym != :get
|
86
|
-
context.render(Tailwinds::Nav::Item::ButtonComponent.new(method:, **options), &
|
86
|
+
context.render(Tailwinds::Nav::Item::ButtonComponent.new(method:, **options), &)
|
87
87
|
else
|
88
|
-
context.render(Tailwinds::Nav::Item::LinkComponent.new(method:, **options), &
|
88
|
+
context.render(Tailwinds::Nav::Item::LinkComponent.new(method:, **options), &)
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
data/lib/tramway/utils/render.rb
CHANGED
@@ -5,8 +5,8 @@ module Tramway
|
|
5
5
|
# Provides helper method render that depends on ActionController::Base.render method
|
6
6
|
#
|
7
7
|
module Render
|
8
|
-
def render(
|
9
|
-
ActionController::Base.render(
|
8
|
+
def render(*, &)
|
9
|
+
ActionController::Base.render(*, &)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
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: 0.4.
|
4
|
+
version: 0.4.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kalashnikovisme
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-09-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: dry-struct
|
@@ -67,20 +67,6 @@ dependencies:
|
|
67
67
|
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: rspec-rails
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '0'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - ">="
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '0'
|
84
70
|
description: Tramway Rails Engine
|
85
71
|
email:
|
86
72
|
- kalashnikovisme@gmail.com
|
@@ -91,11 +77,22 @@ files:
|
|
91
77
|
- MIT-LICENSE
|
92
78
|
- README.md
|
93
79
|
- Rakefile
|
80
|
+
- app/assets/javascripts/tramway/multiselect_controller.js
|
94
81
|
- app/components/tailwind_component.html.haml
|
95
82
|
- app/components/tailwind_component.rb
|
96
83
|
- app/components/tailwinds/form/builder.rb
|
97
84
|
- app/components/tailwinds/form/file_field_component.html.haml
|
98
85
|
- app/components/tailwinds/form/file_field_component.rb
|
86
|
+
- app/components/tailwinds/form/multiselect/dropdown_container.html.haml
|
87
|
+
- app/components/tailwinds/form/multiselect/dropdown_container.rb
|
88
|
+
- app/components/tailwinds/form/multiselect/item_container.html.haml
|
89
|
+
- app/components/tailwinds/form/multiselect/item_container.rb
|
90
|
+
- app/components/tailwinds/form/multiselect/select_as_input.html.haml
|
91
|
+
- app/components/tailwinds/form/multiselect/select_as_input.rb
|
92
|
+
- app/components/tailwinds/form/multiselect/selected_item_template.html.haml
|
93
|
+
- app/components/tailwinds/form/multiselect/selected_item_template.rb
|
94
|
+
- app/components/tailwinds/form/multiselect_component.html.haml
|
95
|
+
- app/components/tailwinds/form/multiselect_component.rb
|
99
96
|
- app/components/tailwinds/form/select_component.html.haml
|
100
97
|
- app/components/tailwinds/form/select_component.rb
|
101
98
|
- app/components/tailwinds/form/submit_button_component.html.haml
|