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.
- 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
|