view_component_storybook 0.9.0 → 0.10.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -138
  3. data/app/controllers/view_component/storybook/stories_controller.rb +9 -11
  4. data/app/views/view_component/storybook/stories/show.html.erb +8 -3
  5. data/config/locales/en.yml +1 -1
  6. data/lib/view_component/storybook.rb +14 -2
  7. data/lib/view_component/storybook/content_concern.rb +42 -0
  8. data/lib/view_component/storybook/controls.rb +3 -1
  9. data/lib/view_component/storybook/controls/base_options_config.rb +41 -0
  10. data/lib/view_component/storybook/controls/control_config.rb +4 -0
  11. data/lib/view_component/storybook/{dsl/controls_dsl.rb → controls/controls_helpers.rb} +21 -16
  12. data/lib/view_component/storybook/controls/custom_config.rb +2 -4
  13. data/lib/view_component/storybook/controls/multi_options_config.rb +46 -0
  14. data/lib/view_component/storybook/controls/options_config.rb +12 -26
  15. data/lib/view_component/storybook/controls/simple_control_config.rb +1 -1
  16. data/lib/view_component/storybook/dsl.rb +0 -2
  17. data/lib/view_component/storybook/dsl/legacy_controls_dsl.rb +2 -2
  18. data/lib/view_component/storybook/engine.rb +2 -1
  19. data/lib/view_component/storybook/method_args/control_method_args.rb +15 -12
  20. data/lib/view_component/storybook/method_args/method_args.rb +37 -4
  21. data/lib/view_component/storybook/slots.rb +14 -0
  22. data/lib/view_component/storybook/slots/slot.rb +24 -0
  23. data/lib/view_component/storybook/slots/slot_config.rb +44 -0
  24. data/lib/view_component/storybook/stories.rb +16 -7
  25. data/lib/view_component/storybook/story.rb +18 -0
  26. data/lib/view_component/storybook/story_config.rb +115 -24
  27. data/lib/view_component/storybook/tasks/write_stories_json.rake +1 -1
  28. data/lib/view_component/storybook/version.rb +1 -1
  29. metadata +27 -9
  30. data/lib/view_component/storybook/controls/array_config.rb +0 -37
  31. data/lib/view_component/storybook/dsl/story_dsl.rb +0 -51
  32. data/lib/view_component/storybook/method_args/validatable_method_args.rb +0 -50
@@ -4,37 +4,76 @@ module ViewComponent
4
4
  module Storybook
5
5
  class StoryConfig
6
6
  include ActiveModel::Validations
7
+ include ContentConcern
8
+ include Controls::ControlsHelpers
7
9
 
8
- attr_reader :id, :name, :component
9
- attr_accessor :parameters, :layout, :content_block
10
+ attr_reader :id, :name, :component_class
10
11
 
11
12
  validate :validate_constructor_args
12
13
 
13
- def initialize(id, name, component, layout)
14
+ def initialize(id, name, component_class, layout)
14
15
  @id = id
15
16
  @name = name
16
- @component = component
17
+ @component_class = component_class
17
18
  @layout = layout
19
+ @slots ||= {}
18
20
  end
19
21
 
20
- def constructor_args(*args, **kwargs, &block)
21
- if args.empty? && kwargs.empty? && block.nil?
22
- @constructor_args ||= ViewComponent::Storybook::MethodArgs::ControlMethodArgs.new(component_constructor)
22
+ def constructor(*args, **kwargs, &block)
23
+ @constructor_args = MethodArgs::ControlMethodArgs.new(
24
+ component_constructor,
25
+ *args,
26
+ **kwargs
27
+ )
28
+ content(nil, &block)
29
+
30
+ self
31
+ end
32
+
33
+ # Once deprecated block version is removed make this a private getter
34
+ def controls(&block)
35
+ if block_given?
36
+ ActiveSupport::Deprecation.warn("`controls` will be removed in v1.0.0. Use `#constructor` instead.")
37
+ controls_dsl = Dsl::LegacyControlsDsl.new
38
+ controls_dsl.instance_eval(&block)
39
+
40
+ controls_hash = controls_dsl.controls.index_by(&:param)
41
+ constructor(**controls_hash)
23
42
  else
24
- @constructor_args = ViewComponent::Storybook::MethodArgs::ControlMethodArgs.new(
25
- component_constructor,
26
- *args,
27
- **kwargs,
28
- &block
29
- )
43
+ list = constructor_args.controls.dup
44
+ list << content_control if content_control
45
+ list += slots.flat_map(&:controls) if slots
46
+ list
30
47
  end
31
48
  end
32
49
 
50
+ def layout(layout = nil)
51
+ @layout = layout unless layout.nil?
52
+ @layout
53
+ end
54
+
55
+ def parameters(parameters = nil)
56
+ @parameters = parameters unless parameters.nil?
57
+ @parameters
58
+ end
59
+
60
+ def method_missing(method_name, *args, **kwargs, &block)
61
+ if component_class.slot_type(method_name)
62
+ slot(method_name, *args, **kwargs, &block)
63
+ else
64
+ super
65
+ end
66
+ end
67
+
68
+ def respond_to_missing?(method_name, _include_private = false)
69
+ component_class.slot_type(method_name).present?
70
+ end
71
+
33
72
  def to_csf_params
34
73
  validate!
35
74
  csf_params = { name: name, parameters: { server: { id: id } } }
36
75
  csf_params.deep_merge!(parameters: parameters) if parameters.present?
37
- constructor_args.controls.each do |control|
76
+ controls.each do |control|
38
77
  csf_params.deep_merge!(control.to_csf_params)
39
78
  end
40
79
  csf_params
@@ -44,17 +83,25 @@ module ViewComponent
44
83
  valid? || raise(ValidationError, self)
45
84
  end
46
85
 
47
- def self.configure(id, name, component, layout, &configuration)
48
- config = new(id, name, component, layout)
49
- ViewComponent::Storybook::Dsl::StoryDsl.evaluate!(config, &configuration)
50
- config
51
- end
86
+ ##
87
+ # Build a Story from this config
88
+ # * Resolves the values of the constructor args from the params
89
+ # * constructs the component
90
+ # * resolve the content_control and content_block to a single block
91
+ # * builds a list of Slots by resolving their args from the params
92
+ def story(params)
93
+ # constructor_args.target_method is UnboundMethod so can't call it directly
94
+ component = constructor_args.call(params) do |*args, **kwargs|
95
+ component_class.new(*args, **kwargs)
96
+ end
52
97
 
53
- def validate_constructor_args
54
- return if constructor_args.valid?
98
+ story_content_block = resolve_content_block(params)
55
99
 
56
- constructor_args_errors = constructor_args.errors.full_messages.join(', ')
57
- errors.add(:constructor_args, :invalid, errors: constructor_args_errors)
100
+ story_slots = slots.map do |slot_config|
101
+ slot_config.slot(component, params)
102
+ end
103
+
104
+ Storybook::Story.new(component, story_content_block, story_slots, layout)
58
105
  end
59
106
 
60
107
  class ValidationError < StandardError
@@ -69,8 +116,52 @@ module ViewComponent
69
116
 
70
117
  private
71
118
 
119
+ def constructor_args
120
+ @constructor_args ||= MethodArgs::ControlMethodArgs.new(component_constructor)
121
+ end
122
+
72
123
  def component_constructor
73
- component.instance_method(:initialize)
124
+ component_class.instance_method(:initialize)
125
+ end
126
+
127
+ def slots
128
+ @slots.values.flatten
129
+ end
130
+
131
+ def validate_constructor_args
132
+ return if constructor_args.valid?
133
+
134
+ constructor_args_errors = constructor_args.errors.full_messages.join(', ')
135
+ errors.add(:constructor_args, :invalid, errors: constructor_args_errors)
136
+ end
137
+
138
+ def slot(slot_name, *args, **kwargs, &block)
139
+ # if the name is a slot then build a SlotConfig with slot_name and param the same
140
+ if component_class.slot_type(slot_name) == :collection_item
141
+ # generate a unique param generated by the count of slots with this name already added
142
+ @slots[slot_name] ||= []
143
+ slot_index = @slots[slot_name].count + 1
144
+ slot_config = Slots::SlotConfig.from_component(
145
+ component_class,
146
+ slot_name,
147
+ "#{slot_name}#{slot_index}".to_sym,
148
+ *args,
149
+ **kwargs,
150
+ &block
151
+ )
152
+ @slots[slot_name] << slot_config
153
+ else
154
+ slot_config = Slots::SlotConfig.from_component(
155
+ component_class,
156
+ slot_name,
157
+ slot_name,
158
+ *args,
159
+ **kwargs,
160
+ &block
161
+ )
162
+ @slots[slot_name] = slot_config
163
+ end
164
+ slot_config
74
165
  end
75
166
  end
76
167
  end
@@ -12,7 +12,7 @@ namespace :view_component_storybook do
12
12
  exceptions << e
13
13
  end
14
14
 
15
- raise StandardError, exceptions.map(:message).join(", ") if exceptions.present?
15
+ raise StandardError, exceptions.map(&:message).join(", ") if exceptions.present?
16
16
 
17
17
  puts "Done"
18
18
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ViewComponent
4
4
  module Storybook
5
- VERSION = "0.9.0"
5
+ VERSION = "0.10.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component_storybook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Palmer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-13 00:00:00.000000000 Z
11
+ date: 2021-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: view_component
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.2'
19
+ version: '2.36'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '2.2'
26
+ version: '2.36'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: capybara
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -177,29 +191,33 @@ files:
177
191
  - app/views/view_component/storybook/stories/show.html.erb
178
192
  - config/locales/en.yml
179
193
  - lib/view_component/storybook.rb
194
+ - lib/view_component/storybook/content_concern.rb
180
195
  - lib/view_component/storybook/controls.rb
181
- - lib/view_component/storybook/controls/array_config.rb
196
+ - lib/view_component/storybook/controls/base_options_config.rb
182
197
  - lib/view_component/storybook/controls/boolean_config.rb
183
198
  - lib/view_component/storybook/controls/color_config.rb
184
199
  - lib/view_component/storybook/controls/control_config.rb
200
+ - lib/view_component/storybook/controls/controls_helpers.rb
185
201
  - lib/view_component/storybook/controls/custom_config.rb
186
202
  - lib/view_component/storybook/controls/date_config.rb
203
+ - lib/view_component/storybook/controls/multi_options_config.rb
187
204
  - lib/view_component/storybook/controls/number_config.rb
188
205
  - lib/view_component/storybook/controls/object_config.rb
189
206
  - lib/view_component/storybook/controls/options_config.rb
190
207
  - lib/view_component/storybook/controls/simple_control_config.rb
191
208
  - lib/view_component/storybook/controls/text_config.rb
192
209
  - lib/view_component/storybook/dsl.rb
193
- - lib/view_component/storybook/dsl/controls_dsl.rb
194
210
  - lib/view_component/storybook/dsl/legacy_controls_dsl.rb
195
- - lib/view_component/storybook/dsl/story_dsl.rb
196
211
  - lib/view_component/storybook/engine.rb
197
212
  - lib/view_component/storybook/method_args.rb
198
213
  - lib/view_component/storybook/method_args/control_method_args.rb
199
214
  - lib/view_component/storybook/method_args/method_args.rb
200
215
  - lib/view_component/storybook/method_args/method_parameters_names.rb
201
- - lib/view_component/storybook/method_args/validatable_method_args.rb
216
+ - lib/view_component/storybook/slots.rb
217
+ - lib/view_component/storybook/slots/slot.rb
218
+ - lib/view_component/storybook/slots/slot_config.rb
202
219
  - lib/view_component/storybook/stories.rb
220
+ - lib/view_component/storybook/story.rb
203
221
  - lib/view_component/storybook/story_config.rb
204
222
  - lib/view_component/storybook/tasks/write_stories_json.rake
205
223
  - lib/view_component/storybook/version.rb
@@ -225,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
243
  - !ruby/object:Gem::Version
226
244
  version: '0'
227
245
  requirements: []
228
- rubygems_version: 3.0.6
246
+ rubygems_version: 3.1.6
229
247
  signing_key:
230
248
  specification_version: 4
231
249
  summary: Storybook for Rails View Components
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- module Storybook
5
- module Controls
6
- class ArrayConfig < SimpleControlConfig
7
- attr_reader :separator
8
-
9
- validates :separator, presence: true
10
-
11
- def initialize(default_value, separator = ",", param: nil, name: nil)
12
- super(default_value, param: param, name: name)
13
- @separator = separator
14
- end
15
-
16
- def type
17
- :array
18
- end
19
-
20
- def value_from_params(params)
21
- params_value = super(params)
22
- if params_value.is_a?(String)
23
- params_value.split(separator)
24
- else
25
- params_value
26
- end
27
- end
28
-
29
- private
30
-
31
- def csf_control_params
32
- super.merge(separator: separator)
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- module Storybook
5
- module Dsl
6
- class StoryDsl
7
- include ControlsDsl
8
-
9
- def self.evaluate!(story_config, &block)
10
- new(story_config).instance_eval(&block)
11
- end
12
-
13
- def parameters(**params)
14
- story_config.parameters = params
15
- end
16
-
17
- def controls(&block)
18
- ActiveSupport::Deprecation.warn("`controls` will be removed in v1.0.0. Use `#constructor` instead.")
19
- controls_dsl = LegacyControlsDsl.new
20
- controls_dsl.instance_eval(&block)
21
-
22
- controls_hash = controls_dsl.controls.index_by(&:param)
23
- story_config.constructor_args(**controls_hash)
24
- end
25
-
26
- def layout(layout)
27
- story_config.layout = layout
28
- end
29
-
30
- def content(&block)
31
- story_config.content_block = block
32
- end
33
-
34
- def constructor(*args, **kwargs, &block)
35
- story_config.constructor_args(*args, **kwargs)
36
- story_config.content_block = block
37
- end
38
-
39
- delegate :component, to: :story_config
40
-
41
- private
42
-
43
- attr_reader :story_config
44
-
45
- def initialize(story_config)
46
- @story_config = story_config
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- module Storybook
5
- module MethodArgs
6
- ##
7
- # Class representing arguments passed to a method which can be validated
8
- # against the args of the target method
9
- class ValidatableMethodArgs < MethodArgs
10
- include ActiveModel::Validations
11
-
12
- attr_reader :target_method_params_names
13
-
14
- validate :validate_args, :validate_kwargs
15
-
16
- def initialize(target_method, *args, **kwargs, &block)
17
- @target_method_params_names = MethodParametersNames.new(target_method)
18
- super(args, kwargs, block)
19
- end
20
-
21
- private
22
-
23
- def validate_args
24
- arg_count = args.count
25
-
26
- if arg_count > target_method_params_names.max_arg_count
27
- errors.add(:args, :too_many, max: target_method_params_names.max_arg_count, count: arg_count)
28
- elsif arg_count < target_method_params_names.min_arg_count
29
- errors.add(:args, :too_few, min: target_method_params_names.min_arg_count, count: arg_count)
30
- end
31
- end
32
-
33
- def validate_kwargs
34
- kwargs.each_key do |kwarg|
35
- unless target_method_params_names.include_kwarg?(kwarg)
36
- errors.add(:kwargs, :invalid_arg, kwarg: kwarg)
37
- end
38
- end
39
-
40
- return if target_method_params_names.covers_required_kwargs?(kwargs.keys)
41
-
42
- expected_keys = target_method_params_names.req_kwarg_names.join(', ')
43
- actual_keys = kwargs.keys.join(', ')
44
-
45
- errors.add(:kwargs, :invalid, expected_keys: expected_keys, actual_keys: actual_keys)
46
- end
47
- end
48
- end
49
- end
50
- end