view_component_storybook 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -138
- data/app/controllers/view_component/storybook/stories_controller.rb +9 -11
- data/app/views/view_component/storybook/stories/show.html.erb +8 -3
- data/config/locales/en.yml +1 -1
- data/lib/view_component/storybook.rb +14 -2
- data/lib/view_component/storybook/content_concern.rb +42 -0
- data/lib/view_component/storybook/controls.rb +3 -1
- data/lib/view_component/storybook/controls/base_options_config.rb +41 -0
- data/lib/view_component/storybook/controls/control_config.rb +4 -0
- data/lib/view_component/storybook/{dsl/controls_dsl.rb → controls/controls_helpers.rb} +21 -16
- data/lib/view_component/storybook/controls/custom_config.rb +2 -4
- data/lib/view_component/storybook/controls/multi_options_config.rb +46 -0
- data/lib/view_component/storybook/controls/options_config.rb +12 -26
- data/lib/view_component/storybook/controls/simple_control_config.rb +1 -1
- data/lib/view_component/storybook/dsl.rb +0 -2
- data/lib/view_component/storybook/dsl/legacy_controls_dsl.rb +2 -2
- data/lib/view_component/storybook/engine.rb +2 -1
- data/lib/view_component/storybook/method_args/control_method_args.rb +15 -12
- data/lib/view_component/storybook/method_args/method_args.rb +37 -4
- data/lib/view_component/storybook/slots.rb +14 -0
- data/lib/view_component/storybook/slots/slot.rb +24 -0
- data/lib/view_component/storybook/slots/slot_config.rb +44 -0
- data/lib/view_component/storybook/stories.rb +16 -7
- data/lib/view_component/storybook/story.rb +18 -0
- data/lib/view_component/storybook/story_config.rb +115 -24
- data/lib/view_component/storybook/tasks/write_stories_json.rake +1 -1
- data/lib/view_component/storybook/version.rb +1 -1
- metadata +27 -9
- data/lib/view_component/storybook/controls/array_config.rb +0 -37
- data/lib/view_component/storybook/dsl/story_dsl.rb +0 -51
- 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, :
|
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,
|
14
|
+
def initialize(id, name, component_class, layout)
|
14
15
|
@id = id
|
15
16
|
@name = name
|
16
|
-
@
|
17
|
+
@component_class = component_class
|
17
18
|
@layout = layout
|
19
|
+
@slots ||= {}
|
18
20
|
end
|
19
21
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
54
|
-
return if constructor_args.valid?
|
98
|
+
story_content_block = resolve_content_block(params)
|
55
99
|
|
56
|
-
|
57
|
-
|
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
|
-
|
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
|
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.
|
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-
|
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.
|
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.
|
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/
|
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/
|
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.
|
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
|