view_component 2.11.0 → 2.14.1
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.
Potentially problematic release.
This version of view_component might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -0
- data/README.md +153 -8
- data/lib/view_component/base.rb +14 -2
- data/lib/view_component/collection.rb +1 -1
- data/lib/view_component/engine.rb +35 -12
- data/lib/view_component/preview.rb +3 -3
- data/lib/view_component/previewable.rb +4 -1
- data/lib/view_component/render_component_helper.rb +9 -0
- data/lib/view_component/render_component_to_string_helper.rb +9 -0
- data/lib/view_component/rendering_component_helper.rb +9 -0
- data/lib/view_component/slot.rb +7 -0
- data/lib/view_component/slotable.rb +121 -0
- data/lib/view_component/test_helpers.rb +7 -2
- data/lib/view_component/version.rb +2 -2
- metadata +7 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: '084152c558b71f87f41d620f9cdce42e689e0b4159cdfa68f3cb041a7bbea3ba'
         | 
| 4 | 
            +
              data.tar.gz: 45324159a07873ce92562650fe7c2ad6e8a279c3db216b3460a6075f71033180
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 58f994aac7efdf81146972a351a12726131658e4ccbd8bf0661eb135d7935ff396c64752d9f9edd6dda50b90a4829aeb506f24edee712279aa1cf4bf4f15886d
         | 
| 7 | 
            +
              data.tar.gz: 430b55482aaafaea6a27e73593861f897620cb635c2a2f14f14b5a772846a8f5a7b42bd973f637cd587816762891bcc432ced92dbac04fe1d391bf7734873a6a
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,50 @@ | |
| 1 1 | 
             
            # master
         | 
| 2 2 |  | 
| 3 | 
            +
            # 2.14.1
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            * Allow using `render_inline` in test when the render monkey patch is disabled with `config.view_component.render_monkey_patch_enabled = false` in versions of Rails < 6.1.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                *Clément Joubert*
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            * Fix kwargs warnings in slotable.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                Fixes:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                ```
         | 
| 14 | 
            +
                view_component/lib/view_component/slotable.rb:98: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
         | 
| 15 | 
            +
                view_component/test/app/components/slots_component.rb:18: warning: The called method `initialize' is defined here
         | 
| 16 | 
            +
                ```
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                *Eileen M. Uchitelle*
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            # 2.14.0
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            * Add `config.preview_paths` to support multiple locations of component preview files. Deprecate `config.preview_path`.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                *Tomas Celizna*
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            * Only print warning about a missing capybara dependency if the `DEBUG` environment variable is set.
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                *Richard Macklin*
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            # 2.13.0
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            * Add the ability to disable the render monkey patch with `config.view_component.render_monkey_patch_enabled`. In versions of Rails < 6.1, add `render_component` and `render_component_to_string` methods which can be used for rendering components instead of `render`.
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                *Johannes Engl*
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            # 2.12.0
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            * Implement Slots as potential successor to Content Areas.
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                *Jens Ljungblad, Brian Bugh, Jon Palmer, Joel Hawksley*
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            # 2.11.1
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            * Fix kwarg warnings in Ruby 2.7.
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                *Joel Hawksley*
         | 
| 47 | 
            +
             | 
| 3 48 | 
             
            # 2.11.0
         | 
| 4 49 |  | 
| 5 50 | 
             
            * Ensure Rails configuration is available within components.
         | 
    
        data/README.md
    CHANGED
    
    | @@ -160,6 +160,133 @@ Returning: | |
| 160 160 | 
             
            </div>
         | 
| 161 161 | 
             
            ```
         | 
| 162 162 |  | 
| 163 | 
            +
            #### Slots (experimental)
         | 
| 164 | 
            +
             | 
| 165 | 
            +
            _Slots are currently under development as a successor to Content Areas. The Slot APIs should be considered unfinished and subject to breaking changes in non-major releases of ViewComponent._
         | 
| 166 | 
            +
             | 
| 167 | 
            +
            Slots enable multiple blocks of content to be passed to a single ViewComponent.
         | 
| 168 | 
            +
             | 
| 169 | 
            +
            Slots exist in two forms: normal slots and collection slots.
         | 
| 170 | 
            +
             | 
| 171 | 
            +
            Normal slots can be rendered once per component. They expose an accessor with the name of the slot that returns an instance of `ViewComponent::Slot`, etc.
         | 
| 172 | 
            +
             | 
| 173 | 
            +
            Collection slots can be rendered multiple times. They expose an accessor with the pluralized name of the slot (`#rows`), which is an Array of `ViewComponent::Slot` instances.
         | 
| 174 | 
            +
             | 
| 175 | 
            +
            To learn more about the design of the Slots API, see https://github.com/github/view_component/pull/348.
         | 
| 176 | 
            +
             | 
| 177 | 
            +
            ##### Defining Slots
         | 
| 178 | 
            +
             | 
| 179 | 
            +
            Slots are defined by the `with_slot` macro:
         | 
| 180 | 
            +
             | 
| 181 | 
            +
            `with_slot :header`
         | 
| 182 | 
            +
             | 
| 183 | 
            +
            To define a collection slot, add `collection: true`:
         | 
| 184 | 
            +
             | 
| 185 | 
            +
            `with_slot :row, collection: true`
         | 
| 186 | 
            +
             | 
| 187 | 
            +
            To define a slot with a custom class, pass `class_name`:
         | 
| 188 | 
            +
             | 
| 189 | 
            +
            `with_slot :body, class_name: 'BodySlot`
         | 
| 190 | 
            +
             | 
| 191 | 
            +
            Slot classes should be subclasses of `ViewComponent::Slot`.
         | 
| 192 | 
            +
             | 
| 193 | 
            +
            ##### Example ViewComponent with Slots
         | 
| 194 | 
            +
             | 
| 195 | 
            +
            `# box_component.rb`
         | 
| 196 | 
            +
            ```ruby
         | 
| 197 | 
            +
            class BoxComponent < ViewComponent::Base
         | 
| 198 | 
            +
              include ViewComponent::Slotable
         | 
| 199 | 
            +
             | 
| 200 | 
            +
              with_slot :body, :footer
         | 
| 201 | 
            +
              with_slot :header, class_name: "Header"
         | 
| 202 | 
            +
              with_slot :row, collection: true, class_name: "Row"
         | 
| 203 | 
            +
             | 
| 204 | 
            +
              class Header < ViewComponent::Slot
         | 
| 205 | 
            +
                def initialize(class_names: "")
         | 
| 206 | 
            +
                  @class_names = class_names
         | 
| 207 | 
            +
                end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                def class_names
         | 
| 210 | 
            +
                  "Box-header #{@class_names}"
         | 
| 211 | 
            +
                end
         | 
| 212 | 
            +
              end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
              class Row < ViewComponent::Slot
         | 
| 215 | 
            +
                def initialize(theme: :gray)
         | 
| 216 | 
            +
                  @theme = theme
         | 
| 217 | 
            +
                end
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                def theme_class_name
         | 
| 220 | 
            +
                  case @theme
         | 
| 221 | 
            +
                  when :gray
         | 
| 222 | 
            +
                    "Box-row--gray"
         | 
| 223 | 
            +
                  when :hover_gray
         | 
| 224 | 
            +
                    "Box-row--hover-gray"
         | 
| 225 | 
            +
                  when :yellow
         | 
| 226 | 
            +
                    "Box-row--yellow"
         | 
| 227 | 
            +
                  when :blue
         | 
| 228 | 
            +
                    "Box-row--blue"
         | 
| 229 | 
            +
                  when :hover_blue
         | 
| 230 | 
            +
                    "Box-row--hover-blue"
         | 
| 231 | 
            +
                  else
         | 
| 232 | 
            +
                    "Box-row--gray"
         | 
| 233 | 
            +
                  end
         | 
| 234 | 
            +
                end
         | 
| 235 | 
            +
              end
         | 
| 236 | 
            +
            end
         | 
| 237 | 
            +
            ```
         | 
| 238 | 
            +
             | 
| 239 | 
            +
            `# box_component.html.erb`
         | 
| 240 | 
            +
            ```erb
         | 
| 241 | 
            +
            <div class="Box">
         | 
| 242 | 
            +
              <% if header %>
         | 
| 243 | 
            +
                <div class="<%= header.class_names %>">
         | 
| 244 | 
            +
                  <%= header.content %>
         | 
| 245 | 
            +
                </div>
         | 
| 246 | 
            +
              <% end %>
         | 
| 247 | 
            +
              <% if body %>
         | 
| 248 | 
            +
                <div class="Box-body">
         | 
| 249 | 
            +
                  <%= body.content %>
         | 
| 250 | 
            +
                </div>
         | 
| 251 | 
            +
              <% end %>
         | 
| 252 | 
            +
              <% if rows.any? %>
         | 
| 253 | 
            +
                <ul>
         | 
| 254 | 
            +
                  <% rows.each do |row| %>
         | 
| 255 | 
            +
                    <li class="Box-row <%= row.theme_class_name %>">
         | 
| 256 | 
            +
                      <%= row.content %>
         | 
| 257 | 
            +
                    </li>
         | 
| 258 | 
            +
                  <% end %>
         | 
| 259 | 
            +
                </ul>
         | 
| 260 | 
            +
              <% end %>
         | 
| 261 | 
            +
              <% if footer %>
         | 
| 262 | 
            +
                <div class="Box-footer">
         | 
| 263 | 
            +
                  <%= footer %>
         | 
| 264 | 
            +
                </div>
         | 
| 265 | 
            +
              <% end %>
         | 
| 266 | 
            +
            </div>
         | 
| 267 | 
            +
            ```
         | 
| 268 | 
            +
             | 
| 269 | 
            +
            `# index.html.erb`
         | 
| 270 | 
            +
            ```erb
         | 
| 271 | 
            +
            <%= render(BoxComponent.new) do |component| %>
         | 
| 272 | 
            +
              <% component.slot(:header, class_names: "my-class-name") do %>
         | 
| 273 | 
            +
                This is my header!
         | 
| 274 | 
            +
              <% end %>
         | 
| 275 | 
            +
              <% component.slot(:body) do %>
         | 
| 276 | 
            +
                This is the body.
         | 
| 277 | 
            +
              <% end %>
         | 
| 278 | 
            +
              <% component.slot(:row) do %>
         | 
| 279 | 
            +
                Row one
         | 
| 280 | 
            +
              <% end %>
         | 
| 281 | 
            +
              <% component.slot(:row, theme: :yellow) do %>
         | 
| 282 | 
            +
                Yellow row
         | 
| 283 | 
            +
              <% end %>
         | 
| 284 | 
            +
              <% component.slot(:footer) do %>
         | 
| 285 | 
            +
                This is the footer.
         | 
| 286 | 
            +
              <% end %>
         | 
| 287 | 
            +
            <% end %>
         | 
| 288 | 
            +
            ```
         | 
| 289 | 
            +
             | 
| 163 290 | 
             
            ### Inline Component
         | 
| 164 291 |  | 
| 165 292 | 
             
            ViewComponents can render without a template file, by defining a `call` method:
         | 
| @@ -537,11 +664,11 @@ class TestComponentPreview < ViewComponent::Preview | |
| 537 664 | 
             
            end
         | 
| 538 665 | 
             
            ```
         | 
| 539 666 |  | 
| 540 | 
            -
            Preview classes live in `test/components/previews`, which can be configured using the ` | 
| 667 | 
            +
            Preview classes live in `test/components/previews`, which can be configured using the `preview_paths` option:
         | 
| 541 668 |  | 
| 542 669 | 
             
            `config/application.rb`
         | 
| 543 670 | 
             
            ```ruby
         | 
| 544 | 
            -
            config.view_component. | 
| 671 | 
            +
            config.view_component.preview_paths << "#{Rails.root}/lib/component_previews"
         | 
| 545 672 | 
             
            ```
         | 
| 546 673 |  | 
| 547 674 | 
             
            Previews are served from <http://localhost:3000/rails/view_components> by default. To use a different endpoint, set the `preview_route` option:
         | 
| @@ -581,7 +708,19 @@ To use component previews: | |
| 581 708 |  | 
| 582 709 | 
             
            `config/application.rb`
         | 
| 583 710 | 
             
            ```ruby
         | 
| 584 | 
            -
            config.view_component. | 
| 711 | 
            +
            config.view_component.preview_paths << "#{Rails.root}/spec/components/previews"
         | 
| 712 | 
            +
            ```
         | 
| 713 | 
            +
             | 
| 714 | 
            +
            ### Disabling the render monkey patch (Rails < 6.1)
         | 
| 715 | 
            +
             | 
| 716 | 
            +
            In order to [avoid conflicts](https://github.com/github/view_component/issues/288) between ViewComponent and other gems that also monkey patch the `render` method, it is possible to configure ViewComponent to not include the render monkey patch:
         | 
| 717 | 
            +
             | 
| 718 | 
            +
            `config.view_component.render_monkey_patch_enabled = false # defaults to true`
         | 
| 719 | 
            +
             | 
| 720 | 
            +
            With the monkey patch disabled, use `render_component` (or  `render_component_to_string`) instead:
         | 
| 721 | 
            +
             | 
| 722 | 
            +
            ```
         | 
| 723 | 
            +
            <%= render_component Component.new(message: "bar") %>
         | 
| 585 724 | 
             
            ```
         | 
| 586 725 |  | 
| 587 726 | 
             
            ### Sidecar assets (experimental)
         | 
| @@ -731,7 +870,8 @@ ViewComponent is far from a novel idea! Popular implementations of view componen | |
| 731 870 | 
             
            ## Resources
         | 
| 732 871 |  | 
| 733 872 | 
             
            - [Encapsulating Views, RailsConf 2020](https://youtu.be/YVYRus_2KZM)
         | 
| 734 | 
            -
            - [Rethinking the View Layer with Components  | 
| 873 | 
            +
            - [Rethinking the View Layer with Components, Ruby Rogues Podcast](https://devchat.tv/ruby-rogues/rr-461-rethinking-the-view-layer-with-components-with-joel-hawksley/)
         | 
| 874 | 
            +
            - [ViewComponents in Action with Andrew Mason, Ruby on Rails Podcast](https://5by5.tv/rubyonrails/320)
         | 
| 735 875 | 
             
            - [ViewComponent at GitHub with Joel Hawksley](https://the-ruby-blend.fireside.fm/9)
         | 
| 736 876 | 
             
            - [Components, HAML vs ERB, and Design Systems](https://the-ruby-blend.fireside.fm/4)
         | 
| 737 877 | 
             
            - [Choosing the Right Tech Stack with Dave Paola](https://5by5.tv/rubyonrails/307)
         | 
| @@ -784,10 +924,15 @@ ViewComponent is built by: | |
| 784 924 | 
             
            |@simonrand|@fugufish|@cover|@franks921|@fsateler|
         | 
| 785 925 | 
             
            |Dublin, Ireland|Salt Lake City, Utah|Barcelona|South Africa|Chile|
         | 
| 786 926 |  | 
| 787 | 
            -
            |<img src="https://avatars.githubusercontent.com/maxbeizer?s=256" alt="maxbeizer" width="128" />|<img src="https://avatars.githubusercontent.com/franco?s=256" alt="franco" width="128" />|<img src="https://avatars.githubusercontent.com/tbroad-ramsey?s=256" alt="tbroad-ramsey" width="128" />|
         | 
| 788 | 
            -
             | 
| 789 | 
            -
            |@maxbeizer|@franco|@tbroad-ramsey|
         | 
| 790 | 
            -
            |Nashville, TN|Switzerland|Spring Hill, TN|
         | 
| 927 | 
            +
            |<img src="https://avatars.githubusercontent.com/maxbeizer?s=256" alt="maxbeizer" width="128" />|<img src="https://avatars.githubusercontent.com/franco?s=256" alt="franco" width="128" />|<img src="https://avatars.githubusercontent.com/tbroad-ramsey?s=256" alt="tbroad-ramsey" width="128" />|<img src="https://avatars.githubusercontent.com/jensljungblad?s=256" alt="jensljungblad" width="128" />|<img src="https://avatars.githubusercontent.com/bbugh?s=256" alt="bbugh" width="128" />|
         | 
| 928 | 
            +
            |:---:|:---:|:---:|:---:|:---:|
         | 
| 929 | 
            +
            |@maxbeizer|@franco|@tbroad-ramsey|@jensljungblad|@bbugh|
         | 
| 930 | 
            +
            |Nashville, TN|Switzerland|Spring Hill, TN|New York, NY|Austin, TX|
         | 
| 931 | 
            +
             | 
| 932 | 
            +
            |<img src="https://avatars.githubusercontent.com/johannesengl?s=256" alt="johannesengl" width="128" />|<img src="https://avatars.githubusercontent.com/czj?s=256" alt="czj" width="128" />|
         | 
| 933 | 
            +
            |:---:|:---:|
         | 
| 934 | 
            +
            |@johannesengl|@czj|
         | 
| 935 | 
            +
            |Berlin, Germany|Paris, France|
         | 
| 791 936 |  | 
| 792 937 | 
             
            ## License
         | 
| 793 938 |  | 
    
        data/lib/view_component/base.rb
    CHANGED
    
    | @@ -5,6 +5,7 @@ require "active_support/configurable" | |
| 5 5 | 
             
            require "view_component/collection"
         | 
| 6 6 | 
             
            require "view_component/compile_cache"
         | 
| 7 7 | 
             
            require "view_component/previewable"
         | 
| 8 | 
            +
            require "view_component/slotable"
         | 
| 8 9 |  | 
| 9 10 | 
             
            module ViewComponent
         | 
| 10 11 | 
             
              class Base < ActionView::Base
         | 
| @@ -17,6 +18,10 @@ module ViewComponent | |
| 17 18 | 
             
                class_attribute :content_areas
         | 
| 18 19 | 
             
                self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
         | 
| 19 20 |  | 
| 21 | 
            +
                # Hash of registered Slots
         | 
| 22 | 
            +
                class_attribute :slots
         | 
| 23 | 
            +
                self.slots = {}
         | 
| 24 | 
            +
             | 
| 20 25 | 
             
                # Entrypoint for rendering components.
         | 
| 21 26 | 
             
                #
         | 
| 22 27 | 
             
                # view_context: ActionView context from calling view
         | 
| @@ -157,12 +162,15 @@ module ViewComponent | |
| 157 162 | 
             
                mattr_accessor :test_controller
         | 
| 158 163 | 
             
                @@test_controller = "ApplicationController"
         | 
| 159 164 |  | 
| 165 | 
            +
                # Configure if render monkey patches should be included or not in Rails <6.1.
         | 
| 166 | 
            +
                mattr_accessor :render_monkey_patch_enabled, instance_writer: false, default: true
         | 
| 167 | 
            +
             | 
| 160 168 | 
             
                class << self
         | 
| 161 169 | 
             
                  attr_accessor :source_location
         | 
| 162 170 |  | 
| 163 171 | 
             
                  # Render a component collection.
         | 
| 164 | 
            -
                  def with_collection( | 
| 165 | 
            -
                    Collection.new(self,  | 
| 172 | 
            +
                  def with_collection(collection, **args)
         | 
| 173 | 
            +
                    Collection.new(self, collection, **args)
         | 
| 166 174 | 
             
                  end
         | 
| 167 175 |  | 
| 168 176 | 
             
                  # Provide identifier for ActionView template annotations
         | 
| @@ -181,6 +189,10 @@ module ViewComponent | |
| 181 189 | 
             
                    # has been re-defined by the consuming application, likely in ApplicationComponent.
         | 
| 182 190 | 
             
                    child.source_location = caller_locations(1, 10).reject { |l| l.label == "inherited" }[0].absolute_path
         | 
| 183 191 |  | 
| 192 | 
            +
                    # Clone slot configuration into child class
         | 
| 193 | 
            +
                    # see #test_slots_pollution
         | 
| 194 | 
            +
                    child.slots = self.slots.clone
         | 
| 195 | 
            +
             | 
| 184 196 | 
             
                    super
         | 
| 185 197 | 
             
                  end
         | 
| 186 198 |  | 
| @@ -9,7 +9,7 @@ module ViewComponent | |
| 9 9 | 
             
                  @component.validate_collection_parameter!(validate_default: true)
         | 
| 10 10 |  | 
| 11 11 | 
             
                  @collection.map do |item|
         | 
| 12 | 
            -
                    content = @component.new(component_options(item, iterator)).render_in(view_context, &block)
         | 
| 12 | 
            +
                    content = @component.new(**component_options(item, iterator)).render_in(view_context, &block)
         | 
| 13 13 | 
             
                    iterator.iterate!
         | 
| 14 14 | 
             
                    content
         | 
| 15 15 | 
             
                  end.join.html_safe
         | 
| @@ -6,15 +6,24 @@ require "view_component" | |
| 6 6 | 
             
            module ViewComponent
         | 
| 7 7 | 
             
              class Engine < Rails::Engine # :nodoc:
         | 
| 8 8 | 
             
                config.view_component = ActiveSupport::OrderedOptions.new
         | 
| 9 | 
            +
                config.view_component.preview_paths ||= []
         | 
| 9 10 |  | 
| 10 11 | 
             
                initializer "view_component.set_configs" do |app|
         | 
| 11 12 | 
             
                  options = app.config.view_component
         | 
| 12 13 |  | 
| 14 | 
            +
                  options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil?
         | 
| 13 15 | 
             
                  options.show_previews = Rails.env.development? if options.show_previews.nil?
         | 
| 14 16 | 
             
                  options.preview_route ||= ViewComponent::Base.preview_route
         | 
| 15 17 |  | 
| 16 18 | 
             
                  if options.show_previews
         | 
| 17 | 
            -
                    options. | 
| 19 | 
            +
                    options.preview_paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    if options.preview_path.present?
         | 
| 22 | 
            +
                      ActiveSupport::Deprecation.warn(
         | 
| 23 | 
            +
                        "`preview_path` will be removed in v3.0.0. Use `preview_paths` instead."
         | 
| 24 | 
            +
                      )
         | 
| 25 | 
            +
                      options.preview_paths << options.preview_path
         | 
| 26 | 
            +
                    end
         | 
| 18 27 | 
             
                  end
         | 
| 19 28 |  | 
| 20 29 | 
             
                  ActiveSupport.on_load(:view_component) do
         | 
| @@ -42,21 +51,35 @@ module ViewComponent | |
| 42 51 | 
             
                  end
         | 
| 43 52 | 
             
                end
         | 
| 44 53 |  | 
| 45 | 
            -
                initializer "view_component.monkey_patch_render" do
         | 
| 54 | 
            +
                initializer "view_component.monkey_patch_render" do |app|
         | 
| 55 | 
            +
                  next if Rails.version.to_f >= 6.1 || !app.config.view_component.render_monkey_patch_enabled
         | 
| 56 | 
            +
             | 
| 46 57 | 
             
                  ActiveSupport.on_load(:action_view) do
         | 
| 47 | 
            -
                     | 
| 48 | 
            -
             | 
| 49 | 
            -
                      ActionView::Base.prepend ViewComponent::RenderMonkeyPatch
         | 
| 50 | 
            -
                    end
         | 
| 58 | 
            +
                    require "view_component/render_monkey_patch"
         | 
| 59 | 
            +
                    ActionView::Base.prepend ViewComponent::RenderMonkeyPatch
         | 
| 51 60 | 
             
                  end
         | 
| 52 61 |  | 
| 53 62 | 
             
                  ActiveSupport.on_load(:action_controller) do
         | 
| 54 | 
            -
                     | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 63 | 
            +
                    require "view_component/rendering_monkey_patch"
         | 
| 64 | 
            +
                    require "view_component/render_to_string_monkey_patch"
         | 
| 65 | 
            +
                    ActionController::Base.prepend ViewComponent::RenderingMonkeyPatch
         | 
| 66 | 
            +
                    ActionController::Base.prepend ViewComponent::RenderToStringMonkeyPatch
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                initializer "view_component.include_render_component" do |app|
         | 
| 71 | 
            +
                  next if Rails.version.to_f >= 6.1
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  ActiveSupport.on_load(:action_view) do
         | 
| 74 | 
            +
                    require "view_component/render_component_helper"
         | 
| 75 | 
            +
                    ActionView::Base.include ViewComponent::RenderComponentHelper
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  ActiveSupport.on_load(:action_controller) do
         | 
| 79 | 
            +
                    require "view_component/rendering_component_helper"
         | 
| 80 | 
            +
                    require "view_component/render_component_to_string_helper"
         | 
| 81 | 
            +
                    ActionController::Base.include ViewComponent::RenderingComponentHelper
         | 
| 82 | 
            +
                    ActionController::Base.include ViewComponent::RenderComponentToStringHelper
         | 
| 60 83 | 
             
                  end
         | 
| 61 84 | 
             
                end
         | 
| 62 85 |  | 
| @@ -65,13 +65,13 @@ module ViewComponent # :nodoc: | |
| 65 65 | 
             
                  private
         | 
| 66 66 |  | 
| 67 67 | 
             
                  def load_previews
         | 
| 68 | 
            -
                     | 
| 68 | 
            +
                    Array(preview_paths).each do |preview_path|
         | 
| 69 69 | 
             
                      Dir["#{preview_path}/**/*_preview.rb"].sort.each { |file| require_dependency file }
         | 
| 70 70 | 
             
                    end
         | 
| 71 71 | 
             
                  end
         | 
| 72 72 |  | 
| 73 | 
            -
                  def  | 
| 74 | 
            -
                    Base. | 
| 73 | 
            +
                  def preview_paths
         | 
| 74 | 
            +
                    Base.preview_paths
         | 
| 75 75 | 
             
                  end
         | 
| 76 76 |  | 
| 77 77 | 
             
                  def show_previews
         | 
| @@ -9,8 +9,11 @@ module ViewComponent # :nodoc: | |
| 9 9 | 
             
                included do
         | 
| 10 10 | 
             
                  # Set the location of component previews through app configuration:
         | 
| 11 11 | 
             
                  #
         | 
| 12 | 
            -
                  #     config.view_component. | 
| 12 | 
            +
                  #     config.view_component.preview_paths << "#{Rails.root}/lib/component_previews"
         | 
| 13 13 | 
             
                  #
         | 
| 14 | 
            +
                  mattr_accessor :preview_paths, instance_writer: false
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  # TODO: deprecated, remove in v3.0.0
         | 
| 14 17 | 
             
                  mattr_accessor :preview_path, instance_writer: false
         | 
| 15 18 |  | 
| 16 19 | 
             
                  # Enable or disable component previews through app configuration:
         | 
| @@ -0,0 +1,121 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "active_support/concern"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require "view_component/slot"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module ViewComponent
         | 
| 8 | 
            +
              module Slotable
         | 
| 9 | 
            +
                extend ActiveSupport::Concern
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                class_methods do
         | 
| 12 | 
            +
                  # support initializing slots as:
         | 
| 13 | 
            +
                  #
         | 
| 14 | 
            +
                  # with_slot(
         | 
| 15 | 
            +
                  #   :header,
         | 
| 16 | 
            +
                  #   collection: true|false,
         | 
| 17 | 
            +
                  #   class_name: "Header" # class name string, used to instantiate Slot
         | 
| 18 | 
            +
                  # )
         | 
| 19 | 
            +
                  def with_slot(*slot_names, collection: false, class_name: nil)
         | 
| 20 | 
            +
                    slot_names.each do |slot_name|
         | 
| 21 | 
            +
                      # Ensure slot_name is not already declared
         | 
| 22 | 
            +
                      if self.slots.key?(slot_name)
         | 
| 23 | 
            +
                        raise ArgumentError.new("#{slot_name} slot declared multiple times")
         | 
| 24 | 
            +
                      end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                      # Ensure slot name is not :content
         | 
| 27 | 
            +
                      if slot_name == :content
         | 
| 28 | 
            +
                        raise ArgumentError.new ":content is a reserved slot name. Please use another name, such as ':body'"
         | 
| 29 | 
            +
                      end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                      # Set the name of the method used to access the Slot(s)
         | 
| 32 | 
            +
                      accessor_name =
         | 
| 33 | 
            +
                        if collection
         | 
| 34 | 
            +
                          # If Slot is a collection, set the accessor
         | 
| 35 | 
            +
                          # name to the pluralized form of the slot name
         | 
| 36 | 
            +
                          # For example: :tab => :tabs
         | 
| 37 | 
            +
                          ActiveSupport::Inflector.pluralize(slot_name)
         | 
| 38 | 
            +
                        else
         | 
| 39 | 
            +
                          slot_name
         | 
| 40 | 
            +
                        end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                      instance_variable_name = "@#{accessor_name}"
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                      # If the slot is a collection, define an accesor that defaults to an empty array
         | 
| 45 | 
            +
                      if collection
         | 
| 46 | 
            +
                        class_eval <<-RUBY
         | 
| 47 | 
            +
                          def #{accessor_name}
         | 
| 48 | 
            +
                            #{instance_variable_name} ||= []
         | 
| 49 | 
            +
                          end
         | 
| 50 | 
            +
                        RUBY
         | 
| 51 | 
            +
                      else
         | 
| 52 | 
            +
                        attr_reader accessor_name
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                      # Default class_name to ViewComponent::Slot
         | 
| 56 | 
            +
                      class_name = "ViewComponent::Slot" unless class_name.present?
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                      # Register the slot on the component
         | 
| 59 | 
            +
                      self.slots[slot_name] = {
         | 
| 60 | 
            +
                        class_name: class_name,
         | 
| 61 | 
            +
                        instance_variable_name: instance_variable_name,
         | 
| 62 | 
            +
                        collection: collection
         | 
| 63 | 
            +
                      }
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                # Build a Slot instance on a component,
         | 
| 69 | 
            +
                # exposing it for use inside the
         | 
| 70 | 
            +
                # component template.
         | 
| 71 | 
            +
                #
         | 
| 72 | 
            +
                # slot: Name of Slot, in symbol form
         | 
| 73 | 
            +
                # **args: Arguments to be passed to Slot initializer
         | 
| 74 | 
            +
                #
         | 
| 75 | 
            +
                # For example:
         | 
| 76 | 
            +
                # <%= render(SlotsComponent.new) do |component| %>
         | 
| 77 | 
            +
                #   <% component.slot(:footer, class_names: "footer-class") do %>
         | 
| 78 | 
            +
                #     <p>This is my footer!</p>
         | 
| 79 | 
            +
                #   <% end %>
         | 
| 80 | 
            +
                # <% end %>
         | 
| 81 | 
            +
                #
         | 
| 82 | 
            +
                def slot(slot_name, **args, &block)
         | 
| 83 | 
            +
                  # Raise ArgumentError if `slot` does not exist
         | 
| 84 | 
            +
                  unless slots.keys.include?(slot_name)
         | 
| 85 | 
            +
                    raise ArgumentError.new "Unknown slot '#{slot_name}' - expected one of '#{slots.keys}'"
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  slot = slots[slot_name]
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  # The class name of the Slot, such as Header
         | 
| 91 | 
            +
                  slot_class = self.class.const_get(slot[:class_name])
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  unless slot_class <= ViewComponent::Slot
         | 
| 94 | 
            +
                    raise ArgumentError.new "#{slot[:class_name]} must inherit from ViewComponent::Slot"
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  # Instantiate Slot class, accommodating Slots that don't accept arguments
         | 
| 98 | 
            +
                  slot_instance = args.present? ? slot_class.new(**args) : slot_class.new
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  # Capture block and assign to slot_instance#content
         | 
| 101 | 
            +
                  slot_instance.content = view_context.capture(&block) if block_given?
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  if slot[:collection]
         | 
| 104 | 
            +
                    # Initialize instance variable as an empty array
         | 
| 105 | 
            +
                    # if slot is a collection and has yet to be initialized
         | 
| 106 | 
            +
                    unless instance_variable_defined?(slot[:instance_variable_name])
         | 
| 107 | 
            +
                      instance_variable_set(slot[:instance_variable_name], [])
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    # Append Slot instance to collection accessor Array
         | 
| 111 | 
            +
                    instance_variable_get(slot[:instance_variable_name]) << slot_instance
         | 
| 112 | 
            +
                  else
         | 
| 113 | 
            +
                     # Assign the Slot instance to the slot accessor
         | 
| 114 | 
            +
                    instance_variable_set(slot[:instance_variable_name], slot_instance)
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                  # Return nil, as this method should not output anything to the view itself.
         | 
| 118 | 
            +
                  nil
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
              end
         | 
| 121 | 
            +
            end
         | 
| @@ -14,13 +14,18 @@ module ViewComponent | |
| 14 14 | 
             
                    assert_no_selector("body")
         | 
| 15 15 | 
             
                  end
         | 
| 16 16 | 
             
                rescue LoadError
         | 
| 17 | 
            -
                  warn "WARNING in `ViewComponent::TestHelpers`: You must add `capybara` to your Gemfile to use Capybara assertions."
         | 
| 17 | 
            +
                  warn "WARNING in `ViewComponent::TestHelpers`: You must add `capybara` to your Gemfile to use Capybara assertions." if ENV["DEBUG"]
         | 
| 18 18 | 
             
                end
         | 
| 19 19 |  | 
| 20 20 | 
             
                attr_reader :rendered_component
         | 
| 21 21 |  | 
| 22 22 | 
             
                def render_inline(component, **args, &block)
         | 
| 23 | 
            -
                  @rendered_component = | 
| 23 | 
            +
                  @rendered_component =
         | 
| 24 | 
            +
                    if Rails.version.to_f >= 6.1
         | 
| 25 | 
            +
                      controller.view_context.render(component, args, &block)
         | 
| 26 | 
            +
                    else
         | 
| 27 | 
            +
                      controller.view_context.render_component(component, &block)
         | 
| 28 | 
            +
                    end
         | 
| 24 29 |  | 
| 25 30 | 
             
                  Nokogiri::HTML.fragment(@rendered_component)
         | 
| 26 31 | 
             
                end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: view_component
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2. | 
| 4 | 
            +
              version: 2.14.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - GitHub Open Source
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020- | 
| 11 | 
            +
            date: 2020-07-10 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activesupport
         | 
| @@ -204,9 +204,14 @@ files: | |
| 204 204 | 
             
            - lib/view_component/engine.rb
         | 
| 205 205 | 
             
            - lib/view_component/preview.rb
         | 
| 206 206 | 
             
            - lib/view_component/previewable.rb
         | 
| 207 | 
            +
            - lib/view_component/render_component_helper.rb
         | 
| 208 | 
            +
            - lib/view_component/render_component_to_string_helper.rb
         | 
| 207 209 | 
             
            - lib/view_component/render_monkey_patch.rb
         | 
| 208 210 | 
             
            - lib/view_component/render_to_string_monkey_patch.rb
         | 
| 211 | 
            +
            - lib/view_component/rendering_component_helper.rb
         | 
| 209 212 | 
             
            - lib/view_component/rendering_monkey_patch.rb
         | 
| 213 | 
            +
            - lib/view_component/slot.rb
         | 
| 214 | 
            +
            - lib/view_component/slotable.rb
         | 
| 210 215 | 
             
            - lib/view_component/template_error.rb
         | 
| 211 216 | 
             
            - lib/view_component/test_case.rb
         | 
| 212 217 | 
             
            - lib/view_component/test_helpers.rb
         |