view_component_storybook 0.10.1 → 0.11.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/lib/view_component/storybook/engine.rb +11 -1
- data/lib/view_component/storybook/method_args/component_constructor_args.rb +23 -0
- data/lib/view_component/storybook/method_args/dry_initializer_component_constructor_args.rb +45 -0
- data/lib/view_component/storybook/method_args/method_parameters_names.rb +1 -1
- data/lib/view_component/storybook/method_args.rb +2 -1
- data/lib/view_component/storybook/slots/slot_config.rb +40 -5
- data/lib/view_component/storybook/stories.rb +1 -3
- data/lib/view_component/storybook/story_config.rb +11 -8
- data/lib/view_component/storybook/version.rb +1 -1
- data/lib/view_component/storybook.rb +11 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0dd708afcf2aa165339b0b1fde82ae610665554e3633c1e50b25509088b43e79
|
4
|
+
data.tar.gz: 950739b2892877a1451c262dc2110d6885a86c740c7fec9cd626a305feb8313d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f9b37292f202ac1c79fd4d31b9ace6b067efff03bf60a6f6a7b44a241ce5661c3669a382d9e549461dfe391d9c77fe0b9b98d33a3a5a47ce821d47e9c26ec7d
|
7
|
+
data.tar.gz: 8e7db14af389ae4d4b2dbcf269269476ac9309c9e518226afedbef769e31f72d32ed44a61382f9830836cab5a4ceba45a701af0a66861de31f928713be9b6c55
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails"
|
4
|
-
require "view_component/storybook"
|
5
4
|
|
6
5
|
module ViewComponent
|
7
6
|
module Storybook
|
@@ -45,3 +44,14 @@ module ViewComponent
|
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
47
|
+
|
48
|
+
# :nocov:
|
49
|
+
unless defined?(ViewComponent::Storybook)
|
50
|
+
ActiveSupport::Deprecation.warn(
|
51
|
+
"This manually engine loading is deprecated and will be removed in v1.0.0. " \
|
52
|
+
"Remove `require \"view_component/storybook/engine\"`."
|
53
|
+
)
|
54
|
+
|
55
|
+
require "view_component/storybook"
|
56
|
+
end
|
57
|
+
# :nocov:
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module MethodArgs
|
6
|
+
##
|
7
|
+
# Class representing the constructor args for a Component
|
8
|
+
class ComponentConstructorArgs < ControlMethodArgs
|
9
|
+
def self.from_component_class(component_class, *args, **kwargs)
|
10
|
+
if DryInitializerComponentConstructorArgs.dry_initialize?(component_class)
|
11
|
+
DryInitializerComponentConstructorArgs.new(component_class, *args, **kwargs)
|
12
|
+
else
|
13
|
+
new(component_class, *args, **kwargs)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(component_class, *args, **kwargs)
|
18
|
+
super(component_class.instance_method(:initialize), *args, **kwargs)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module MethodArgs
|
6
|
+
##
|
7
|
+
# Class representing the constructor args for a Component the extends dry-initializer
|
8
|
+
class DryInitializerComponentConstructorArgs < ControlMethodArgs
|
9
|
+
INITIALIZE_METHOD = :__dry_initializer_initialize__
|
10
|
+
|
11
|
+
##
|
12
|
+
# Method Parameters names that are dry-initialize aware
|
13
|
+
# THe main difference is that Dry Initializer keyword args cannot be deduced from the constructor initialize params
|
14
|
+
# Instead we have to introspect the dry_initializer config for the option definitions
|
15
|
+
class DryConstructorParametersNames < MethodParametersNames
|
16
|
+
attr_reader :dry_initializer
|
17
|
+
|
18
|
+
def initialize(component_class)
|
19
|
+
super(component_class.instance_method(INITIALIZE_METHOD))
|
20
|
+
@dry_initializer = component_class.dry_initializer
|
21
|
+
end
|
22
|
+
|
23
|
+
# Required keywords are the only thing we need.
|
24
|
+
# We could define kwarg_names similarly but wihout the `optional` check. However, dry-initializer
|
25
|
+
# always ends has supports_keyrest? == true so kwarg_names isn't needed
|
26
|
+
def req_kwarg_names
|
27
|
+
@req_kwarg_names ||= dry_initializer.definitions.map do |name, definition|
|
28
|
+
name if definition.option && !definition.optional
|
29
|
+
end.compact
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.dry_initialize?(component_class)
|
34
|
+
component_class.private_method_defined?(INITIALIZE_METHOD)
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(component_class, *args, **kwargs)
|
38
|
+
super(component_class.instance_method(INITIALIZE_METHOD), *args, **kwargs)
|
39
|
+
|
40
|
+
@target_method_params_names = DryConstructorParametersNames.new(component_class)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -9,8 +9,9 @@ module ViewComponent
|
|
9
9
|
|
10
10
|
autoload :MethodArgs
|
11
11
|
autoload :MethodParametersNames
|
12
|
-
autoload :ValidatableMethodArgs
|
13
12
|
autoload :ControlMethodArgs
|
13
|
+
autoload :ComponentConstructorArgs
|
14
|
+
autoload :DryInitializerComponentConstructorArgs
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -4,10 +4,13 @@ module ViewComponent
|
|
4
4
|
module Storybook
|
5
5
|
module Slots
|
6
6
|
class SlotConfig
|
7
|
+
include ActiveModel::Validations
|
7
8
|
include ContentConcern
|
8
9
|
|
9
10
|
attr_reader :slot_name, :slot_method_args, :param, :content_block
|
10
11
|
|
12
|
+
validate :validate_slot_method_args
|
13
|
+
|
11
14
|
def initialize(slot_name, slot_method_args, param, content_block)
|
12
15
|
@slot_name = slot_name
|
13
16
|
@slot_method_args = slot_method_args
|
@@ -16,11 +19,12 @@ module ViewComponent
|
|
16
19
|
end
|
17
20
|
|
18
21
|
def self.from_component(component_class, slot_name, param, *args, **kwargs, &block)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
new(
|
23
|
+
slot_name,
|
24
|
+
slot_method_args(component_class, slot_name, *args, **kwargs).with_param_prefix(param),
|
25
|
+
param,
|
26
|
+
block
|
27
|
+
)
|
24
28
|
end
|
25
29
|
|
26
30
|
def slot(componeont, params)
|
@@ -38,6 +42,37 @@ module ViewComponent
|
|
38
42
|
def content_param
|
39
43
|
"#{param}__content".to_sym
|
40
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def validate_slot_method_args
|
49
|
+
return if slot_method_args.valid?
|
50
|
+
|
51
|
+
slot_method_args_errors = slot_method_args.errors.full_messages.join(', ')
|
52
|
+
errors.add(:slot_method_args, :invalid, errors: slot_method_args_errors)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.slot_method_args(component_class, slot_name, *args, **kwargs)
|
56
|
+
# Reverse engineer the signature of the slot so that we can validate control args to the slot
|
57
|
+
# The slot methods themselves just have rest params so we can't introspect them. Instead we
|
58
|
+
# look for 'renderable' details of the registered slot
|
59
|
+
# This approach is tightly coupled to internal ViewCopmonent apis and might prove to be brittle
|
60
|
+
registred_slot_name = component_class.slot_type(slot_name) == :collection_item ? ActiveSupport::Inflector.pluralize(slot_name).to_sym : slot_name
|
61
|
+
|
62
|
+
registered_slot = component_class.registered_slots[registred_slot_name]
|
63
|
+
|
64
|
+
if registered_slot[:renderable] || registered_slot[:renderable_class_name]
|
65
|
+
# The slot is a component - either a class or a string representing the class
|
66
|
+
component_class = registered_slot[:renderable] || component_class.const_get(registered_slot[:renderable_class_name])
|
67
|
+
MethodArgs::ComponentConstructorArgs.from_component_class(component_class, *args, **kwargs)
|
68
|
+
else
|
69
|
+
# the slot is a lamba or a simple content slot
|
70
|
+
slot_lamba = registered_slot[:renderable_function] || proc {}
|
71
|
+
MethodArgs::ControlMethodArgs.new(slot_lamba, *args, **kwargs)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private_class_method :slot_method_args
|
41
76
|
end
|
42
77
|
end
|
43
78
|
end
|
@@ -47,9 +47,7 @@ module ViewComponent
|
|
47
47
|
|
48
48
|
def write_csf_json
|
49
49
|
json_path = File.join(stories_path, "#{stories_name}.stories.json")
|
50
|
-
File.
|
51
|
-
f.write(JSON.pretty_generate(to_csf_params))
|
52
|
-
end
|
50
|
+
File.write(json_path, JSON.pretty_generate(to_csf_params))
|
53
51
|
json_path
|
54
52
|
end
|
55
53
|
|
@@ -9,7 +9,7 @@ module ViewComponent
|
|
9
9
|
|
10
10
|
attr_reader :id, :name, :component_class
|
11
11
|
|
12
|
-
validate :validate_constructor_args
|
12
|
+
validate :validate_constructor_args, :validate_slots_args
|
13
13
|
|
14
14
|
def initialize(id, name, component_class, layout)
|
15
15
|
@id = id
|
@@ -20,8 +20,8 @@ module ViewComponent
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def constructor(*args, **kwargs, &block)
|
23
|
-
@constructor_args = MethodArgs::
|
24
|
-
|
23
|
+
@constructor_args = MethodArgs::ComponentConstructorArgs.from_component_class(
|
24
|
+
component_class,
|
25
25
|
*args,
|
26
26
|
**kwargs
|
27
27
|
)
|
@@ -117,11 +117,7 @@ module ViewComponent
|
|
117
117
|
private
|
118
118
|
|
119
119
|
def constructor_args
|
120
|
-
@constructor_args ||= MethodArgs::
|
121
|
-
end
|
122
|
-
|
123
|
-
def component_constructor
|
124
|
-
component_class.instance_method(:initialize)
|
120
|
+
@constructor_args ||= MethodArgs::ComponentConstructorArgs.from_component_class(component_class)
|
125
121
|
end
|
126
122
|
|
127
123
|
def slots
|
@@ -135,6 +131,13 @@ module ViewComponent
|
|
135
131
|
errors.add(:constructor_args, :invalid, errors: constructor_args_errors)
|
136
132
|
end
|
137
133
|
|
134
|
+
def validate_slots_args
|
135
|
+
slots.reject(&:valid?).each do |slot_config|
|
136
|
+
slot_errors = slot_config.errors.full_messages.join(', ')
|
137
|
+
errors.add(:slots, :invalid, errors: slot_errors)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
138
141
|
def slot(slot_name, *args, **kwargs, &block)
|
139
142
|
# if the name is a slot then build a SlotConfig with slot_name and param the same
|
140
143
|
if component_class.slot_type(slot_name) == :collection_item
|
@@ -41,6 +41,17 @@ module ViewComponent
|
|
41
41
|
"/rails/stories"
|
42
42
|
end
|
43
43
|
|
44
|
+
# :nocov:
|
45
|
+
if defined?(ViewComponent::Storybook::Engine)
|
46
|
+
ActiveSupport::Deprecation.warn(
|
47
|
+
"This manually engine loading is deprecated and will be removed in v1.0.0. " \
|
48
|
+
"Remove `require \"view_component/storybook/engine\"`."
|
49
|
+
)
|
50
|
+
elsif defined?(Rails::Engine)
|
51
|
+
require "view_component/storybook/engine"
|
52
|
+
end
|
53
|
+
# :nocov:
|
54
|
+
|
44
55
|
ActiveSupport.run_load_hooks(:view_component_storybook, self)
|
45
56
|
end
|
46
57
|
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.11.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:
|
11
|
+
date: 2022-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: view_component
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dry-initializer
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.0.4
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.0.4
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -210,7 +224,9 @@ files:
|
|
210
224
|
- lib/view_component/storybook/dsl/legacy_controls_dsl.rb
|
211
225
|
- lib/view_component/storybook/engine.rb
|
212
226
|
- lib/view_component/storybook/method_args.rb
|
227
|
+
- lib/view_component/storybook/method_args/component_constructor_args.rb
|
213
228
|
- lib/view_component/storybook/method_args/control_method_args.rb
|
229
|
+
- lib/view_component/storybook/method_args/dry_initializer_component_constructor_args.rb
|
214
230
|
- lib/view_component/storybook/method_args/method_args.rb
|
215
231
|
- lib/view_component/storybook/method_args/method_parameters_names.rb
|
216
232
|
- lib/view_component/storybook/slots.rb
|
@@ -228,6 +244,7 @@ metadata:
|
|
228
244
|
allowed_push_host: https://rubygems.org
|
229
245
|
homepage_uri: https://github.com/jonspalmer/view_component_storybook
|
230
246
|
source_code_uri: https://github.com/jonspalmer/view_component_storybook
|
247
|
+
rubygems_mfa_required: 'true'
|
231
248
|
post_install_message:
|
232
249
|
rdoc_options: []
|
233
250
|
require_paths:
|
@@ -243,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
243
260
|
- !ruby/object:Gem::Version
|
244
261
|
version: '0'
|
245
262
|
requirements: []
|
246
|
-
rubygems_version: 3.
|
263
|
+
rubygems_version: 3.0.6
|
247
264
|
signing_key:
|
248
265
|
specification_version: 4
|
249
266
|
summary: Storybook for Rails View Components
|