tramway 0.5.4 → 0.5.5
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 +13 -1
 - data/app/components/tailwind_component.rb +32 -0
 - data/app/components/tailwinds/form/builder.rb +54 -15
 - data/app/components/tailwinds/form/file_field_component.html.haml +6 -3
 - data/app/components/tailwinds/form/multiselect/dropdown_container.html.haml +1 -1
 - data/app/components/tailwinds/form/multiselect/item_container.html.haml +3 -3
 - data/app/components/tailwinds/form/multiselect/select_as_input.html.haml +11 -1
 - data/app/components/tailwinds/form/multiselect/select_as_input.rb +1 -0
 - data/app/components/tailwinds/form/multiselect/selected_item_template.html.haml +1 -1
 - data/app/components/tailwinds/form/multiselect_component.html.haml +3 -3
 - data/app/components/tailwinds/form/multiselect_component.rb +8 -1
 - data/app/components/tailwinds/form/number_field_component.html.haml +8 -0
 - data/app/components/tailwinds/form/number_field_component.rb +9 -0
 - data/app/components/tailwinds/form/select_component.html.haml +5 -1
 - data/app/components/tailwinds/form/submit_button_component.html.haml +4 -1
 - data/app/components/tailwinds/form/submit_button_component.rb +11 -3
 - data/app/components/tailwinds/form/text_area_component.html.haml +4 -1
 - data/app/components/tailwinds/form/text_field_component.html.haml +4 -1
 - data/app/components/tailwinds/table/header_component.html.haml +1 -1
 - data/app/components/tailwinds/table/header_component.rb +6 -1
 - data/app/components/tailwinds/table_component.html.haml +1 -1
 - data/app/controllers/tramway/entities_controller.rb +2 -1
 - data/lib/tramway/decorators/class_helper.rb +7 -1
 - data/lib/tramway/helpers/views_helper.rb +7 -2
 - data/lib/tramway/version.rb +1 -1
 - metadata +4 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 21ffe76c2224bd46292479de272ccdb59f0095075043507af3dd6098d5559933
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 6547f3ac892439dddb165dbf7d8a06dcb90d8adb6f12b65d921cb277ebf7754a
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 93bdfec725bc98cb5ab5a045604fe00c6669eaf8d89eedb081e0750a4b1073fda7c7f99964a3e4b8bbfb4f668024ca9341f512c5fed77d17ea05eeb31de19f37
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 6d6d161386768b114e82e031888ce118383bfb377c6b5e1551d9f8b7300f077af50eb6cb2bff3a6d4523ab0f43bbc77b69b3af180ed4895d7b8c24558c1876a4
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -40,7 +40,7 @@ Tramway.configure do |config| 
     | 
|
| 
       40 
40 
     | 
    
         
             
              config.entities = [
         
     | 
| 
       41 
41 
     | 
    
         
             
                {
         
     | 
| 
       42 
42 
     | 
    
         
             
                  name: :user,
         
     | 
| 
       43 
     | 
    
         
            -
                  pages: [:index],
         
     | 
| 
      
 43 
     | 
    
         
            +
                  pages: [{ action: :index }],
         
     | 
| 
       44 
44 
     | 
    
         
             
                }
         
     | 
| 
       45 
45 
     | 
    
         
             
              ]
         
     | 
| 
       46 
46 
     | 
    
         
             
            end
         
     | 
| 
         @@ -465,10 +465,22 @@ title_link: Link on Tramway Navbar title. Default: '/' 
     | 
|
| 
       465 
465 
     | 
    
         
             
            background:
         
     | 
| 
       466 
466 
     | 
    
         
             
              color: Css-color. Supports all named CSS colors and HEX colors
         
     | 
| 
       467 
467 
     | 
    
         
             
              intensity: Color intensity. Range: **100..950**. Used by Tailwind. Not supported in case of using HEX color in the background.color
         
     | 
| 
      
 468 
     | 
    
         
            +
            with_entities: Show Tramway Entities index page links to navbar. Default: true
         
     | 
| 
       468 
469 
     | 
    
         
             
            ```
         
     | 
| 
       469 
470 
     | 
    
         | 
| 
       470 
471 
     | 
    
         
             
            **NOTE:** `tramway_navbar` method called without arguments and block of code will render only [Tramway Entities](https://github.com/Purple-Magic/tramway#tramway-entities) links on the left.
         
     | 
| 
       471 
472 
     | 
    
         | 
| 
      
 473 
     | 
    
         
            +
            In case you want to hide entity links you can pass `with_entities: false`.
         
     | 
| 
      
 474 
     | 
    
         
            +
             
     | 
| 
      
 475 
     | 
    
         
            +
            ```haml
         
     | 
| 
      
 476 
     | 
    
         
            +
            - if current_user.present?
         
     | 
| 
      
 477 
     | 
    
         
            +
              = tramway_navbar title: 'WaiWai' do |nav|
         
     | 
| 
      
 478 
     | 
    
         
            +
                - nav.left do
         
     | 
| 
      
 479 
     | 
    
         
            +
                  - nav.item 'Board', admin_board_path
         
     | 
| 
      
 480 
     | 
    
         
            +
            - else
         
     | 
| 
      
 481 
     | 
    
         
            +
              = tramway_navbar title: 'WaiWai', with_entities: false
         
     | 
| 
      
 482 
     | 
    
         
            +
            ```
         
     | 
| 
      
 483 
     | 
    
         
            +
             
     | 
| 
       472 
484 
     | 
    
         
             
            #### nav.left and nav.right
         
     | 
| 
       473 
485 
     | 
    
         | 
| 
       474 
486 
     | 
    
         
             
            Tramway navbar provides `left` and `right` methods that puts items to left and right part of navbar.
         
     | 
| 
         @@ -10,4 +10,36 @@ class TailwindComponent < Tramway::Component::Base 
     | 
|
| 
       10 
10 
     | 
    
         
             
              option :options
         
     | 
| 
       11 
11 
     | 
    
         
             
              option :label
         
     | 
| 
       12 
12 
     | 
    
         
             
              option :for
         
     | 
| 
      
 13 
     | 
    
         
            +
              option :size, default: -> { :middle }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              SIZE_CLASSES = {
         
     | 
| 
      
 16 
     | 
    
         
            +
                small: {
         
     | 
| 
      
 17 
     | 
    
         
            +
                  text_input: 'text-sm px-2 py-1',
         
     | 
| 
      
 18 
     | 
    
         
            +
                  select_input: 'text-sm px-2 py-1',
         
     | 
| 
      
 19 
     | 
    
         
            +
                  file_button: 'text-sm px-3 py-1',
         
     | 
| 
      
 20 
     | 
    
         
            +
                  submit_button: 'text-sm px-3 py-1',
         
     | 
| 
      
 21 
     | 
    
         
            +
                  multiselect_input: 'text-sm px-2 py-1'
         
     | 
| 
      
 22 
     | 
    
         
            +
                },
         
     | 
| 
      
 23 
     | 
    
         
            +
                middle: {
         
     | 
| 
      
 24 
     | 
    
         
            +
                  text_input: 'text-base px-3 py-2',
         
     | 
| 
      
 25 
     | 
    
         
            +
                  select_input: 'text-base px-3 py-2',
         
     | 
| 
      
 26 
     | 
    
         
            +
                  file_button: 'text-base px-4 py-2',
         
     | 
| 
      
 27 
     | 
    
         
            +
                  submit_button: 'text-base px-4 py-2',
         
     | 
| 
      
 28 
     | 
    
         
            +
                  multiselect_input: 'text-base px-3 py-2'
         
     | 
| 
      
 29 
     | 
    
         
            +
                },
         
     | 
| 
      
 30 
     | 
    
         
            +
                large: {
         
     | 
| 
      
 31 
     | 
    
         
            +
                  text_input: 'text-lg px-4 py-3',
         
     | 
| 
      
 32 
     | 
    
         
            +
                  select_input: 'text-lg px-4 py-3',
         
     | 
| 
      
 33 
     | 
    
         
            +
                  file_button: 'text-lg px-5 py-3',
         
     | 
| 
      
 34 
     | 
    
         
            +
                  submit_button: 'text-lg px-5 py-3',
         
     | 
| 
      
 35 
     | 
    
         
            +
                  multiselect_input: 'text-lg px-4 py-3'
         
     | 
| 
      
 36 
     | 
    
         
            +
                }
         
     | 
| 
      
 37 
     | 
    
         
            +
              }.freeze
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              private
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def size_class(key)
         
     | 
| 
      
 42 
     | 
    
         
            +
                size_classes = SIZE_CLASSES.fetch(size) { SIZE_CLASSES[:middle] }
         
     | 
| 
      
 43 
     | 
    
         
            +
                size_classes.fetch(key) { SIZE_CLASSES[:middle].fetch(key) }
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
       13 
45 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,59 +5,90 @@ module Tailwinds 
     | 
|
| 
       5 
5 
     | 
    
         
             
                # Provides Tailwind-styled forms
         
     | 
| 
       6 
6 
     | 
    
         
             
                # :reek:InstanceVariableAssumption
         
     | 
| 
       7 
7 
     | 
    
         
             
                class Builder < Tramway::Views::FormBuilder
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize(object_name, object, template, options)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    super
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    @form_size = options[:size] || options['size'] || :middle
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
       8 
14 
     | 
    
         
             
                  def text_field(attribute, **options, &)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       9 
17 
     | 
    
         
             
                    render(Tailwinds::Form::TextFieldComponent.new(
         
     | 
| 
       10 
18 
     | 
    
         
             
                             input: input(:text_field),
         
     | 
| 
       11 
     | 
    
         
            -
                             value: get_value(attribute,  
     | 
| 
       12 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 19 
     | 
    
         
            +
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
      
 20 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
      
 21 
     | 
    
         
            +
                           ), &)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def number_field(attribute, **options, &)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    render(Tailwinds::Form::NumberFieldComponent.new(
         
     | 
| 
      
 28 
     | 
    
         
            +
                             input: input(:number_field),
         
     | 
| 
      
 29 
     | 
    
         
            +
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
      
 30 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       13 
31 
     | 
    
         
             
                           ), &)
         
     | 
| 
       14 
32 
     | 
    
         
             
                  end
         
     | 
| 
       15 
33 
     | 
    
         | 
| 
       16 
34 
     | 
    
         
             
                  def text_area(attribute, **options, &)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
       17 
37 
     | 
    
         
             
                    render(Tailwinds::Form::TextAreaComponent.new(
         
     | 
| 
       18 
38 
     | 
    
         
             
                             input: input(:text_area),
         
     | 
| 
       19 
     | 
    
         
            -
                             value: get_value(attribute,  
     | 
| 
       20 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 39 
     | 
    
         
            +
                             value: get_value(attribute, sanitized_options),
         
     | 
| 
      
 40 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       21 
41 
     | 
    
         
             
                           ), &)
         
     | 
| 
       22 
42 
     | 
    
         
             
                  end
         
     | 
| 
       23 
43 
     | 
    
         | 
| 
       24 
44 
     | 
    
         
             
                  def password_field(attribute, **options, &)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       25 
47 
     | 
    
         
             
                    render(Tailwinds::Form::TextFieldComponent.new(
         
     | 
| 
       26 
48 
     | 
    
         
             
                             input: input(:password_field),
         
     | 
| 
       27 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 49 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       28 
50 
     | 
    
         
             
                           ), &)
         
     | 
| 
       29 
51 
     | 
    
         
             
                  end
         
     | 
| 
       30 
52 
     | 
    
         | 
| 
       31 
53 
     | 
    
         
             
                  def file_field(attribute, **options, &)
         
     | 
| 
       32 
     | 
    
         
            -
                     
     | 
| 
      
 54 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    input = super(attribute, **sanitized_options.merge(class: :hidden))
         
     | 
| 
       33 
56 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                    render(Tailwinds::Form::FileFieldComponent.new(input:, **default_options(attribute,  
     | 
| 
      
 57 
     | 
    
         
            +
                    render(Tailwinds::Form::FileFieldComponent.new(input:, **default_options(attribute, sanitized_options)), &)
         
     | 
| 
       35 
58 
     | 
    
         
             
                  end
         
     | 
| 
       36 
59 
     | 
    
         | 
| 
       37 
60 
     | 
    
         
             
                  def select(attribute, collection, **options, &)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
       38 
63 
     | 
    
         
             
                    render(Tailwinds::Form::SelectComponent.new(
         
     | 
| 
       39 
64 
     | 
    
         
             
                             input: input(:select),
         
     | 
| 
       40 
     | 
    
         
            -
                             value:  
     | 
| 
       41 
     | 
    
         
            -
                             collection: explicitly_add_blank_option(collection,  
     | 
| 
       42 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 65 
     | 
    
         
            +
                             value: sanitized_options[:selected] || object.public_send(attribute),
         
     | 
| 
      
 66 
     | 
    
         
            +
                             collection: explicitly_add_blank_option(collection, sanitized_options),
         
     | 
| 
      
 67 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       43 
68 
     | 
    
         
             
                           ), &)
         
     | 
| 
       44 
69 
     | 
    
         
             
                  end
         
     | 
| 
       45 
70 
     | 
    
         | 
| 
       46 
71 
     | 
    
         
             
                  def multiselect(attribute, collection, **options, &)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
       47 
74 
     | 
    
         
             
                    render(Tailwinds::Form::MultiselectComponent.new(
         
     | 
| 
       48 
75 
     | 
    
         
             
                             input: input(:text_field),
         
     | 
| 
       49 
     | 
    
         
            -
                             value:  
     | 
| 
      
 76 
     | 
    
         
            +
                             value: sanitized_options[:value] || sanitized_options[:selected] || object.public_send(attribute),
         
     | 
| 
       50 
77 
     | 
    
         
             
                             collection:,
         
     | 
| 
       51 
     | 
    
         
            -
                             **default_options(attribute,  
     | 
| 
      
 78 
     | 
    
         
            +
                             **default_options(attribute, sanitized_options)
         
     | 
| 
       52 
79 
     | 
    
         
             
                           ), &)
         
     | 
| 
       53 
80 
     | 
    
         
             
                  end
         
     | 
| 
       54 
81 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                  def submit(action,  
     | 
| 
       56 
     | 
    
         
            -
                     
     | 
| 
      
 82 
     | 
    
         
            +
                  def submit(action, **options, &)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    sanitized_options = sanitize_options(options)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    render(Tailwinds::Form::SubmitButtonComponent.new(action, size: form_size, **sanitized_options), &)
         
     | 
| 
       57 
86 
     | 
    
         
             
                  end
         
     | 
| 
       58 
87 
     | 
    
         | 
| 
       59 
88 
     | 
    
         
             
                  private
         
     | 
| 
       60 
89 
     | 
    
         | 
| 
      
 90 
     | 
    
         
            +
                  attr_reader :form_size
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
       61 
92 
     | 
    
         
             
                  def input(method_name)
         
     | 
| 
       62 
93 
     | 
    
         
             
                    unbound_method = self.class.superclass.instance_method(method_name)
         
     | 
| 
       63 
94 
     | 
    
         
             
                    unbound_method.bind(self)
         
     | 
| 
         @@ -72,7 +103,8 @@ module Tailwinds 
     | 
|
| 
       72 
103 
     | 
    
         
             
                      attribute:,
         
     | 
| 
       73 
104 
     | 
    
         
             
                      label: label_build(attribute, options),
         
     | 
| 
       74 
105 
     | 
    
         
             
                      for: for_id(attribute),
         
     | 
| 
       75 
     | 
    
         
            -
                      options 
     | 
| 
      
 106 
     | 
    
         
            +
                      options:,
         
     | 
| 
      
 107 
     | 
    
         
            +
                      size: form_size
         
     | 
| 
       76 
108 
     | 
    
         
             
                    }
         
     | 
| 
       77 
109 
     | 
    
         
             
                  end
         
     | 
| 
       78 
110 
     | 
    
         | 
| 
         @@ -88,6 +120,13 @@ module Tailwinds 
     | 
|
| 
       88 
120 
     | 
    
         
             
                    "#{object_name}_#{attribute}"
         
     | 
| 
       89 
121 
     | 
    
         
             
                  end
         
     | 
| 
       90 
122 
     | 
    
         | 
| 
      
 123 
     | 
    
         
            +
                  def sanitize_options(options)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    options.dup.tap do |opts|
         
     | 
| 
      
 125 
     | 
    
         
            +
                      opts.delete(:size)
         
     | 
| 
      
 126 
     | 
    
         
            +
                      opts.delete('size')
         
     | 
| 
      
 127 
     | 
    
         
            +
                    end
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
       91 
130 
     | 
    
         
             
                  # REMOVE IT. WE MUST UNDERSTAND WHY INCLUDE_BLANK DOES NOT WORK
         
     | 
| 
       92 
131 
     | 
    
         
             
                  # :reek:UtilityFunction
         
     | 
| 
       93 
132 
     | 
    
         
             
                  def explicitly_add_blank_option(collection, options)
         
     | 
| 
         @@ -1,5 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            .mb-4
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
                   
     | 
| 
      
 2 
     | 
    
         
            +
                - if @label
         
     | 
| 
      
 3 
     | 
    
         
            +
                  - base_classes = 'inline-block bg-blue-500 hover:bg-blue-700 text-white font-bold rounded cursor-pointer mt-4 '
         
     | 
| 
      
 4 
     | 
    
         
            +
                  - base_classes += 'dark:bg-blue-600 dark:hover:bg-blue-500'
         
     | 
| 
      
 5 
     | 
    
         
            +
                  - classes = "#{size_class(:file_button)} #{base_classes}"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  %label{ for: @for, class: classes }
         
     | 
| 
      
 7 
     | 
    
         
            +
                    = @label
         
     | 
| 
       5 
8 
     | 
    
         
             
              = @input
         
     | 
| 
         @@ -1,3 +1,3 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #dropdown.absolute.shadow.top-11.bg-white.z-40.w-full.lef-0.rounded.max-h-select.overflow-y-auto{ data: { action: "click@window->multiselect#closeOnClickOutside" } }
         
     | 
| 
      
 1 
     | 
    
         
            +
            #dropdown.absolute.shadow.top-11.bg-white.z-40.w-full.lef-0.rounded.max-h-select.overflow-y-auto.dark:bg-gray-800.dark:shadow-lg.dark:ring-1.dark:ring-gray-700{ data: { action: "click@window->multiselect#closeOnClickOutside" } }
         
     | 
| 
       2 
2 
     | 
    
         
             
              .flex.flex-col.w-full
         
     | 
| 
       3 
3 
     | 
    
         
             
                {{content}}
         
     | 
| 
         @@ -1,5 +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
         
     | 
| 
      
 1 
     | 
    
         
            +
            .cursor-pointer.w-full.border-gray-100.rounded-t.border-b.hover:bg-teal-100.dark:border-gray-700.dark:hover:bg-gray-700{ 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.dark:hover:border-gray-600
         
     | 
| 
      
 3 
     | 
    
         
            +
                .w-full.items-center.flex.dark:text-gray-100
         
     | 
| 
       4 
4 
     | 
    
         
             
                  .mx-2.leading-6
         
     | 
| 
       5 
5 
     | 
    
         
             
                    {{text}}
         
     | 
| 
         @@ -1,2 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            .flex-1
         
     | 
| 
       2 
     | 
    
         
            -
               
     | 
| 
      
 2 
     | 
    
         
            +
              - base_classes = 'bg-transparent appearance-none outline-none h-full w-full text-gray-800 hidden '
         
     | 
| 
      
 3 
     | 
    
         
            +
              - base_classes += 'dark:text-white dark:placeholder-white'
         
     | 
| 
      
 4 
     | 
    
         
            +
              - classes = "#{@size_class} #{base_classes}"
         
     | 
| 
      
 5 
     | 
    
         
            +
              = @input.call(
         
     | 
| 
      
 6 
     | 
    
         
            +
                @attribute,
         
     | 
| 
      
 7 
     | 
    
         
            +
                @options.merge(
         
     | 
| 
      
 8 
     | 
    
         
            +
                  placeholder: "{{placeholder}}",
         
     | 
| 
      
 9 
     | 
    
         
            +
                  class: classes,
         
     | 
| 
      
 10 
     | 
    
         
            +
                  data: { 'multiselect-target' => 'hiddenInput' }
         
     | 
| 
      
 11 
     | 
    
         
            +
                )
         
     | 
| 
      
 12 
     | 
    
         
            +
              )
         
     | 
| 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       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
         
     | 
| 
      
 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.dark:bg-teal-900.dark:text-teal-100.dark:border-teal-700
         
     | 
| 
       2 
2 
     | 
    
         
             
              .text-xs.font-normal.leading-none.max-w-full.flex-initial
         
     | 
| 
       3 
3 
     | 
    
         
             
                {{text}}
         
     | 
| 
       4 
4 
     | 
    
         
             
              .flex.flex-auto.flex-row-reverse
         
     | 
| 
         @@ -2,9 +2,9 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
3 
     | 
    
         
             
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
       4 
4 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
     | 
    
         
            -
              .flex.flex-col.relative{ data: multiselect_hash, id: "#{@for}_multiselect" }
         
     | 
| 
      
 5 
     | 
    
         
            +
              .flex.flex-col.relative.dark:text-gray-100{ data: multiselect_hash, id: "#{@for}_multiselect" }
         
     | 
| 
       6 
6 
     | 
    
         
             
                .min-w-96.w-fit
         
     | 
| 
       7 
     | 
    
         
            -
                  .p-1.flex.border.border-gray-200.bg-white.rounded{ data: { "multiselect-target" => "dropdown" } }
         
     | 
| 
      
 7 
     | 
    
         
            +
                  .p-1.flex.border.border-gray-200.bg-white.rounded.dark:border-gray-600.dark:bg-gray-800{ data: { "multiselect-target" => "dropdown" } }
         
     | 
| 
       8 
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
         
     | 
| 
      
 9 
     | 
    
         
            +
                    .text-gray-300.w-8.py-1.pl-2.pr-1.border-l.flex.items-center.border-gray-200.dark:text-gray-500.dark:border-gray-600
         
     | 
| 
       10 
10 
     | 
    
         
             
                      ^
         
     | 
| 
         @@ -45,7 +45,14 @@ module Tailwinds 
     | 
|
| 
       45 
45 
     | 
    
         
             
                  end
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
                  def select_as_input
         
     | 
| 
       48 
     | 
    
         
            -
                    render( 
     | 
| 
      
 48 
     | 
    
         
            +
                    render(
         
     | 
| 
      
 49 
     | 
    
         
            +
                      Tailwinds::Form::Multiselect::SelectAsInput.new(
         
     | 
| 
      
 50 
     | 
    
         
            +
                        options:,
         
     | 
| 
      
 51 
     | 
    
         
            +
                        attribute:,
         
     | 
| 
      
 52 
     | 
    
         
            +
                        input:,
         
     | 
| 
      
 53 
     | 
    
         
            +
                        size_class: size_class(:multiselect_input)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      )
         
     | 
| 
      
 55 
     | 
    
         
            +
                    )
         
     | 
| 
       49 
56 
     | 
    
         
             
                  end
         
     | 
| 
       50 
57 
     | 
    
         | 
| 
       51 
58 
     | 
    
         
             
                  def on_change
         
     | 
| 
         @@ -0,0 +1,8 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            .mb-4
         
     | 
| 
      
 2 
     | 
    
         
            +
              - if @label
         
     | 
| 
      
 3 
     | 
    
         
            +
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  = @label
         
     | 
| 
      
 5 
     | 
    
         
            +
              - base_classes = 'w-full bg-white border border-gray-300 rounded focus:outline-none focus:border-red-500 '
         
     | 
| 
      
 6 
     | 
    
         
            +
              - base_classes += 'dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:border-red-400 dark:placeholder-white'
         
     | 
| 
      
 7 
     | 
    
         
            +
              - classes = "#{size_class(:text_input)} #{base_classes}"
         
     | 
| 
      
 8 
     | 
    
         
            +
              = @input.call @attribute, **@options.merge(class: classes), value: @value
         
     | 
| 
         @@ -2,4 +2,8 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
3 
     | 
    
         
             
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
       4 
4 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              - base_classes = 'bg-white border border-gray-300 text-gray-700 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 '
         
     | 
| 
      
 6 
     | 
    
         
            +
              - base_classes += 'focus:border-transparent disabled:bg-gray-100 disabled:text-gray-400 disabled:cursor-not-allowed '
         
     | 
| 
      
 7 
     | 
    
         
            +
              - base_classes += 'dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:focus:ring-red-400 dark:disabled:bg-gray-800 dark:disabled:text-gray-500'
         
     | 
| 
      
 8 
     | 
    
         
            +
              - classes = "#{size_class(:select_input)} #{base_classes}"
         
     | 
| 
      
 9 
     | 
    
         
            +
              = @input.call(@attribute, @collection, { selected: @value }, @options.merge(class: classes))
         
     | 
| 
         @@ -1,4 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            .flex.items-center.justify-between
         
     | 
| 
       2 
     | 
    
         
            -
               
     | 
| 
      
 2 
     | 
    
         
            +
              - base_classes = 'bg-red-500 hover:bg-red-700 text-white font-bold rounded focus:outline-none focus:shadow-outline cursor-pointer '
         
     | 
| 
      
 3 
     | 
    
         
            +
              - base_classes += 'dark:text-white dark:bg-red-600 dark:hover:bg-red-500 dark:focus:ring-2 dark:focus:ring-red-400'
         
     | 
| 
      
 4 
     | 
    
         
            +
              - classes = "#{size_class(:submit_button)} #{base_classes}"
         
     | 
| 
      
 5 
     | 
    
         
            +
              %button{ type: :submit, name: :commit, class: classes, **@options }
         
     | 
| 
       3 
6 
     | 
    
         
             
                = @text
         
     | 
| 
       4 
7 
     | 
    
         
             
              = @content
         
     | 
| 
         @@ -4,10 +4,18 @@ module Tailwinds 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module Form
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Tailwind-styled submit button
         
     | 
| 
       6 
6 
     | 
    
         
             
                class SubmitButtonComponent < TailwindComponent
         
     | 
| 
       7 
     | 
    
         
            -
                  def initialize(action, **options)
         
     | 
| 
       8 
     | 
    
         
            -
                    @options = options.except :type
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
                  def initialize(action, size: :middle, **options)
         
     | 
| 
       10 
8 
     | 
    
         
             
                    @text = action.is_a?(String) ? action : action.to_s.capitalize
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    super(
         
     | 
| 
      
 11 
     | 
    
         
            +
                      input: nil,
         
     | 
| 
      
 12 
     | 
    
         
            +
                      attribute: nil,
         
     | 
| 
      
 13 
     | 
    
         
            +
                      value: nil,
         
     | 
| 
      
 14 
     | 
    
         
            +
                      options: options.except(:type),
         
     | 
| 
      
 15 
     | 
    
         
            +
                      label: nil,
         
     | 
| 
      
 16 
     | 
    
         
            +
                      for: nil,
         
     | 
| 
      
 17 
     | 
    
         
            +
                      size:
         
     | 
| 
      
 18 
     | 
    
         
            +
                    )
         
     | 
| 
       11 
19 
     | 
    
         
             
                  end
         
     | 
| 
       12 
20 
     | 
    
         
             
                end
         
     | 
| 
       13 
21 
     | 
    
         
             
              end
         
     | 
| 
         @@ -2,4 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
3 
     | 
    
         
             
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
       4 
4 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              - base_classes = 'w-full bg-white border border-gray-300 rounded focus:outline-none focus:border-red-500 '
         
     | 
| 
      
 6 
     | 
    
         
            +
              - base_classes += 'dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:border-red-400 dark:placeholder-white'
         
     | 
| 
      
 7 
     | 
    
         
            +
              - classes = "#{size_class(:text_input)} #{base_classes}"
         
     | 
| 
      
 8 
     | 
    
         
            +
              = @input.call @attribute, **@options.merge(class: classes), value: @value
         
     | 
| 
         @@ -2,4 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
              - if @label
         
     | 
| 
       3 
3 
     | 
    
         
             
                = component('tailwinds/form/label', for: @for) do
         
     | 
| 
       4 
4 
     | 
    
         
             
                  = @label
         
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              - base_classes = 'w-full bg-white border border-gray-300 rounded focus:outline-none focus:border-red-500 '
         
     | 
| 
      
 6 
     | 
    
         
            +
              - base_classes += 'dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:border-red-400 dark:placeholder-white'
         
     | 
| 
      
 7 
     | 
    
         
            +
              - classes = "#{size_class(:text_input)} #{base_classes}"
         
     | 
| 
      
 8 
     | 
    
         
            +
              = @input.call @attribute, **@options.merge(class: classes), value: @value
         
     | 
| 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            .div-table-row.grid.text-white.text-small.gap-4.bg-purple-700.dark:bg-gray-700.dark:text-gray-400{ class: "grid-cols-#{ 
     | 
| 
      
 1 
     | 
    
         
            +
            .div-table-row.grid.text-white.text-small.gap-4.bg-purple-700.dark:bg-gray-700.dark:text-gray-400{ class: "grid-cols-#{columns_count}", aria: { label: "Table Header" }, role: "row" }
         
     | 
| 
       2 
2 
     | 
    
         
             
              - if headers.any?
         
     | 
| 
       3 
3 
     | 
    
         
             
                - headers.each do |header|
         
     | 
| 
       4 
4 
     | 
    
         
             
                  .div-table-cell.py-4.px-6
         
     | 
| 
         @@ -4,7 +4,12 @@ module Tailwinds 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module Table
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Component for rendering a header in a table
         
     | 
| 
       6 
6 
     | 
    
         
             
                class HeaderComponent < Tramway::Component::Base
         
     | 
| 
       7 
     | 
    
         
            -
                  option :headers
         
     | 
| 
      
 7 
     | 
    
         
            +
                  option :headers, optional: true, default: -> { [] }
         
     | 
| 
      
 8 
     | 
    
         
            +
                  option :columns, optional: true, default: -> { 3 }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def columns_count
         
     | 
| 
      
 11 
     | 
    
         
            +
                    headers.present? ? headers.size : columns
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
       8 
13 
     | 
    
         
             
                end
         
     | 
| 
       9 
14 
     | 
    
         
             
              end
         
     | 
| 
       10 
15 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            = helpers.component 'tailwinds/table/row/preview'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            - width_class = options[:class]&.include?('w-') ? '' : 'w-full'
         
     | 
| 
       4 
     | 
    
         
            -
            .div-table.text-left.rtl:text-right.text-gray-500.dark:text-gray-400 
     | 
| 
      
 4 
     | 
    
         
            +
            .div-table.text-left.rtl:text-right.text-gray-500.dark:text-gray-400{ class: "#{options[:class]} #{width_class}", **options.except(:class) }
         
     | 
| 
       5 
5 
     | 
    
         
             
              = content
         
     | 
| 
         @@ -30,7 +30,13 @@ module Tramway 
     | 
|
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                    base_class_name = Tramway::Decorators::NameBuilder.default_decorator_class_name(klass)
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                    namespace.present? ? "#{namespace.to_s.camelize}::#{base_class_name}" : base_class_name
         
     | 
| 
      
 33 
     | 
    
         
            +
                    klass_name = namespace.present? ? "#{namespace.to_s.camelize}::#{base_class_name}" : base_class_name
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    if klass_name.safe_constantize
         
     | 
| 
      
 36 
     | 
    
         
            +
                      klass_name
         
     | 
| 
      
 37 
     | 
    
         
            +
                    else
         
     | 
| 
      
 38 
     | 
    
         
            +
                      raise NameError, "You should define #{klass_name} decorator class in app/decorators/ folder."
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
       34 
40 
     | 
    
         
             
                  end
         
     | 
| 
       35 
41 
     | 
    
         | 
| 
       36 
42 
     | 
    
         
             
                  # :reek:NilCheck { enabled: false }
         
     | 
| 
         @@ -4,8 +4,13 @@ module Tramway 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module Helpers
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Provides view-oriented helpers for ActionView
         
     | 
| 
       6 
6 
     | 
    
         
             
                module ViewsHelper
         
     | 
| 
       7 
     | 
    
         
            -
                  def tramway_form_for(object, *, **options, &)
         
     | 
| 
       8 
     | 
    
         
            -
                    form_for( 
     | 
| 
      
 7 
     | 
    
         
            +
                  def tramway_form_for(object, *, size: :middle, **options, &)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    form_for(
         
     | 
| 
      
 9 
     | 
    
         
            +
                      object,
         
     | 
| 
      
 10 
     | 
    
         
            +
                      *,
         
     | 
| 
      
 11 
     | 
    
         
            +
                      **options.merge(builder: Tailwinds::Form::Builder, size:),
         
     | 
| 
      
 12 
     | 
    
         
            +
                      &
         
     | 
| 
      
 13 
     | 
    
         
            +
                    )
         
     | 
| 
       9 
14 
     | 
    
         
             
                  end
         
     | 
| 
       10 
15 
     | 
    
         
             
                end
         
     | 
| 
       11 
16 
     | 
    
         
             
              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.5. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.5.5
         
     | 
| 
       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: 2025- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2025-10-14 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: anyway_config
         
     | 
| 
         @@ -158,6 +158,8 @@ files: 
     | 
|
| 
       158 
158 
     | 
    
         
             
            - app/components/tailwinds/form/multiselect/selected_item_template.rb
         
     | 
| 
       159 
159 
     | 
    
         
             
            - app/components/tailwinds/form/multiselect_component.html.haml
         
     | 
| 
       160 
160 
     | 
    
         
             
            - app/components/tailwinds/form/multiselect_component.rb
         
     | 
| 
      
 161 
     | 
    
         
            +
            - app/components/tailwinds/form/number_field_component.html.haml
         
     | 
| 
      
 162 
     | 
    
         
            +
            - app/components/tailwinds/form/number_field_component.rb
         
     | 
| 
       161 
163 
     | 
    
         
             
            - app/components/tailwinds/form/select_component.html.haml
         
     | 
| 
       162 
164 
     | 
    
         
             
            - app/components/tailwinds/form/select_component.rb
         
     | 
| 
       163 
165 
     | 
    
         
             
            - app/components/tailwinds/form/submit_button_component.html.haml
         
     |