view_component-contrib 0.0.1 → 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ <div class="<%= container_class %>">
2
+ <%- if component -%>
3
+ <%= render component %>
4
+ <%- else -%>
5
+ Failed to infer a component from the preview: <%= error %>
6
+ <%- end -%>
7
+ </div>
@@ -1,4 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "view_component/contrib/version"
4
- require "view_component/contrib/railtie" if defined?(Rails::Railtie)
3
+ require "view_component_contrib"
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby-next/language/setup"
4
+ RubyNext::Language.setup_gem_load_path
5
+
6
+ module ViewComponentContrib
7
+ APP_PATH = File.expand_path(File.join(__dir__, "../app"))
8
+
9
+ autoload :TranslationHelper, "view_component_contrib/translation_helper"
10
+ autoload :WrapperComponent, "view_component_contrib/wrapper_component"
11
+ autoload :WrappedHelper, "view_component_contrib/wrapped_helper"
12
+
13
+ autoload :Base, "view_component_contrib/base"
14
+ autoload :Preview, "view_component_contrib/preview"
15
+ end
16
+
17
+ require "view_component_contrib/version"
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ # Base view component class with many extensions already included
5
+ class Base < ViewComponent::Base
6
+ include TranslationHelper
7
+ include WrappedHelper
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ module Preview
5
+ autoload :Base, "view_component_contrib/preview/base"
6
+
7
+ autoload :Abstract, "view_component_contrib/preview/abstract"
8
+ autoload :DefaultTemplate, "view_component_contrib/preview/default_template"
9
+ autoload :Sidecarable, "view_component_contrib/preview/sidecarable"
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ module Preview
5
+ # Adds `abstract_class` accessor and exclude abstract
6
+ # preview classes from index
7
+ module Abstract
8
+ def self.extended(base)
9
+ base.singleton_class.prepend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ attr_accessor :abstract_class
14
+ alias_method :abstract_class?, :abstract_class
15
+
16
+ def all
17
+ super.reject(&:abstract_class?)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ module Preview
5
+ # First, enable abstract classes (if not already extended)
6
+ unless ViewComponent::Preview.singleton_class.is_a?(ViewComponentContrib::Preview::Abstract)
7
+ ViewComponent::Preview.extend ViewComponentContrib::Preview::Abstract
8
+ end
9
+
10
+ # Base view component class with extensions already included
11
+ class Base < ViewComponent::Preview
12
+ self.abstract_class = true
13
+
14
+ include DefaultTemplate
15
+
16
+ DEFAULT_CONTAINER_CLASS = ""
17
+
18
+ class << self
19
+ # Support layout inheritance
20
+ def inherited(child)
21
+ child.layout(@layout) if defined?(@layout)
22
+ super
23
+ end
24
+
25
+ attr_writer :container_class
26
+
27
+ def container_class
28
+ return @container_class if defined?(@container_class)
29
+
30
+ @container_class =
31
+ if superclass.respond_to?(:container_class)
32
+ superclass.container_class
33
+ else
34
+ DEFAULT_CONTAINER_CLASS
35
+ end
36
+ end
37
+
38
+ def render_args(...)
39
+ super.tap do |res|
40
+ res[:locals] ||= {}
41
+ build_component_instance(res[:locals])
42
+ res[:locals][:container_class] ||= container_class
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def build_component_instance(locals)
49
+ return locals unless locals[:component].nil?
50
+ locals[:component] = name.sub(/Preview$/, "Component").safe_constantize&.new
51
+ rescue => e
52
+ locals[:component] = nil
53
+ locals[:error] = e.message
54
+ end
55
+ end
56
+
57
+ # Shortcut for render_with_template(locals: ...)
58
+ def render_with(**locals)
59
+ render_with_template(locals: locals)
60
+ end
61
+
62
+ # Shortcut for render_with_template(locals: {component: ...})
63
+ def render_component(component)
64
+ render_with(component: component)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ module Preview
5
+ module DefaultTemplate
6
+ DEFAULT_TEMPLATE = "view_component_contrib/preview"
7
+
8
+ def self.included(base)
9
+ base.singleton_class.prepend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ attr_writer :default_preview_template
14
+
15
+ def default_preview_template
16
+ return @default_preview_template if defined?(@default_preview_template)
17
+
18
+ @default_preview_template =
19
+ if superclass.respond_to?(:default_preview_template)
20
+ superclass.default_preview_template
21
+ else
22
+ DEFAULT_TEMPLATE
23
+ end
24
+ end
25
+
26
+ def preview_example_template_path(...)
27
+ super
28
+ rescue ViewComponent::PreviewTemplateError
29
+ has_preview_template = preview_paths.find do |path|
30
+ Dir.glob(File.join(path, preview_name, "preview.html.*")).any?
31
+ end
32
+
33
+ has_preview_template ? File.join(preview_name, "preview") : DEFAULT_TEMPLATE
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ ActiveSupport.on_load(:view_component) do
41
+ ViewComponent::Base.preview_paths << File.join(ViewComponentContrib::APP_PATH, "views")
42
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ module Preview
5
+ module Sidecarable
6
+ PREVIEW_GLOB = "**/preview.rb"
7
+
8
+ def self.extended(base)
9
+ base.singleton_class.prepend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def load_previews
14
+ Array(preview_paths).each do |preview_path|
15
+ Dir["#{preview_path}/#{PREVIEW_GLOB}"].sort.each { |file| require_dependency file }
16
+ end
17
+ end
18
+
19
+ def preview_name
20
+ name.chomp("::Preview").underscore
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ module TranslationHelper
5
+ DEFAULT_NAMESPACE = "view_components"
6
+
7
+ def self.included(base)
8
+ base.extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+ attr_writer :i18n_namespace
13
+
14
+ def i18n_namespace
15
+ return @i18n_namespace if defined?(@i18n_namespace)
16
+
17
+ @i18n_namespace =
18
+ if superclass.respond_to?(:i18n_namespace)
19
+ superclass.i18n_namespace
20
+ else
21
+ DEFAULT_NAMESPACE
22
+ end
23
+ end
24
+
25
+ def i18n_scope
26
+ return @i18n_scope if defined?(@i18n_scope)
27
+
28
+ @i18n_scope = name.sub("::Component", "").underscore.split("/")
29
+ end
30
+
31
+ def i18n_scope=(val)
32
+ raise ArgumentError, "Must be array" unless val.is_a?(Array)
33
+
34
+ @i18n_scope = val.dup.freeze
35
+ end
36
+
37
+ def virtual_path
38
+ @contrib_virtual_path ||= [
39
+ i18n_namespace,
40
+ *i18n_scope
41
+ ].join(".")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib # :nodoc:all
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ # Adds `#wrapped` method to automatically wrap self into a WrapperComponent
5
+ module WrappedHelper
6
+ def wrapped
7
+ WrapperComponent.new(self)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ # WrapperComponent allwows to wrap any component with a custom HTML code.
5
+ # The whole wrapper is only rendered when the child component.render? returns true.
6
+ # Thus, wrapper could be used to conditionally render the outer html for components without
7
+ # conditionals in templates.
8
+ class WrapperComponent < ViewComponent::Base
9
+ class DoubleRenderError < StandardError
10
+ def initialize(component)
11
+ super("A child component could only be rendered once within a wrapper: #{component}")
12
+ end
13
+ end
14
+
15
+ attr_reader :component_instance
16
+
17
+ delegate :render?, to: :component_instance
18
+
19
+ def initialize(component)
20
+ @component_instance = component
21
+ end
22
+
23
+ # Simply return the contents of the block passed to #render_component.
24
+ # (Alias couldn't be used here 'cause ViewComponent check for the method presence when
25
+ # choosing between #call and a template.)
26
+ def call
27
+ content
28
+ end
29
+
30
+ # Returns rendered child component
31
+ # The name component is chosen for convienent usage in templates,
32
+ # so we can simply call `= wrapper.component` in the place where we're going
33
+ # to put the component
34
+ def component
35
+ raise DoubleRenderError, component_instance if @rendered
36
+
37
+ @rendered = component_instance.render_in(view_context).html_safe
38
+ end
39
+ end
40
+ end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component-contrib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-22 00:00:00.000000000 Z
11
+ date: 2021-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: view_component
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby-next-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.12.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.12.0
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +52,20 @@ dependencies:
24
52
  - - ">="
25
53
  - !ruby/object:Gem::Version
26
54
  version: '1.15'
55
+ - !ruby/object:Gem::Dependency
56
+ name: capybara
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
27
69
  - !ruby/object:Gem::Dependency
28
70
  name: combustion
29
71
  requirement: !ruby/object:Gem::Requirement
@@ -39,33 +81,61 @@ dependencies:
39
81
  - !ruby/object:Gem::Version
40
82
  version: '1.1'
41
83
  - !ruby/object:Gem::Dependency
42
- name: rake
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '5.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest-focus
43
99
  requirement: !ruby/object:Gem::Requirement
44
100
  requirements:
45
101
  - - ">="
46
102
  - !ruby/object:Gem::Version
47
- version: '13.0'
103
+ version: '0'
48
104
  type: :development
49
105
  prerelease: false
50
106
  version_requirements: !ruby/object:Gem::Requirement
51
107
  requirements:
52
108
  - - ">="
53
109
  - !ruby/object:Gem::Version
54
- version: '13.0'
110
+ version: '0'
55
111
  - !ruby/object:Gem::Dependency
56
- name: rspec
112
+ name: minitest-reporters
57
113
  requirement: !ruby/object:Gem::Requirement
58
114
  requirements:
59
115
  - - ">="
60
116
  - !ruby/object:Gem::Version
61
- version: '3.9'
117
+ version: '0'
62
118
  type: :development
63
119
  prerelease: false
64
120
  version_requirements: !ruby/object:Gem::Requirement
65
121
  requirements:
66
122
  - - ">="
67
123
  - !ruby/object:Gem::Version
68
- version: '3.9'
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '13.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '13.0'
69
139
  description: A collection of extensions and developer tools for ViewComponent
70
140
  email:
71
141
  - dementiev.vm@gmail.com
@@ -76,9 +146,30 @@ files:
76
146
  - CHANGELOG.md
77
147
  - LICENSE.txt
78
148
  - README.md
149
+ - app/templates/install/application_view_component.rb
150
+ - app/templates/install/application_view_component_preview.rb
151
+ - app/templates/install/builder.rb
152
+ - app/templates/install/class_for.rb
153
+ - app/templates/install/generator.rb
154
+ - app/templates/install/identifier.rb
155
+ - app/templates/install/index.js
156
+ - app/templates/install/index.stimulus.js
157
+ - app/templates/install/initializer.rb
158
+ - app/templates/install/postcss-modules.js
159
+ - app/templates/install/template.rb
160
+ - app/views/view_component_contrib/preview.html.erb
79
161
  - lib/view_component-contrib.rb
80
- - lib/view_component/contrib/railtie.rb
81
- - lib/view_component/contrib/version.rb
162
+ - lib/view_component_contrib.rb
163
+ - lib/view_component_contrib/base.rb
164
+ - lib/view_component_contrib/preview.rb
165
+ - lib/view_component_contrib/preview/abstract.rb
166
+ - lib/view_component_contrib/preview/base.rb
167
+ - lib/view_component_contrib/preview/default_template.rb
168
+ - lib/view_component_contrib/preview/sidecarable.rb
169
+ - lib/view_component_contrib/translation_helper.rb
170
+ - lib/view_component_contrib/version.rb
171
+ - lib/view_component_contrib/wrapped_helper.rb
172
+ - lib/view_component_contrib/wrapper_component.rb
82
173
  homepage: http://github.com/palkan/view_component-contrib
83
174
  licenses:
84
175
  - MIT