view_component-contrib 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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