view_component_storybook 0.6.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -128
- data/app/controllers/view_component/storybook/stories_controller.rb +10 -11
- data/app/views/view_component/storybook/stories/show.html.erb +8 -1
- data/config/locales/en.yml +32 -0
- data/lib/view_component/storybook.rb +14 -0
- data/lib/view_component/storybook/content_concern.rb +42 -0
- data/lib/view_component/storybook/controls.rb +5 -1
- data/lib/view_component/storybook/controls/base_options_config.rb +41 -0
- data/lib/view_component/storybook/controls/boolean_config.rb +7 -6
- data/lib/view_component/storybook/controls/color_config.rb +4 -6
- data/lib/view_component/storybook/controls/control_config.rb +25 -25
- data/lib/view_component/storybook/controls/controls_helpers.rb +76 -0
- data/lib/view_component/storybook/controls/custom_config.rb +52 -0
- data/lib/view_component/storybook/controls/date_config.rb +14 -13
- data/lib/view_component/storybook/controls/multi_options_config.rb +46 -0
- data/lib/view_component/storybook/controls/number_config.rb +13 -10
- data/lib/view_component/storybook/controls/object_config.rb +13 -7
- data/lib/view_component/storybook/controls/options_config.rb +17 -33
- data/lib/view_component/storybook/controls/simple_control_config.rb +48 -0
- data/lib/view_component/storybook/controls/text_config.rb +1 -3
- data/lib/view_component/storybook/dsl.rb +1 -2
- data/lib/view_component/storybook/dsl/{controls_dsl.rb → legacy_controls_dsl.rb} +19 -22
- data/lib/view_component/storybook/engine.rb +2 -1
- data/lib/view_component/storybook/method_args.rb +16 -0
- data/lib/view_component/storybook/method_args/control_method_args.rb +91 -0
- data/lib/view_component/storybook/method_args/method_args.rb +52 -0
- data/lib/view_component/storybook/method_args/method_parameters_names.rb +97 -0
- 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 +60 -14
- data/lib/view_component/storybook/story.rb +18 -0
- data/lib/view_component/storybook/story_config.rb +140 -15
- data/lib/view_component/storybook/tasks/write_stories_json.rake +6 -0
- data/lib/view_component/storybook/version.rb +1 -1
- metadata +64 -23
- data/lib/view_component/storybook/controls/array_config.rb +0 -36
- data/lib/view_component/storybook/dsl/story_dsl.rb +0 -39
@@ -6,43 +6,43 @@ module ViewComponent
|
|
6
6
|
class ControlConfig
|
7
7
|
include ActiveModel::Validations
|
8
8
|
|
9
|
-
|
9
|
+
validates :param, presence: true
|
10
10
|
|
11
|
-
|
12
|
-
validates :param, inclusion: { in: ->(control_config) { control_config.component_params } }, unless: -> { component.nil? }
|
13
|
-
|
14
|
-
def initialize(component, param, value, name: nil)
|
15
|
-
@component = component
|
11
|
+
def initialize(param: nil, name: nil)
|
16
12
|
@param = param
|
17
|
-
@
|
18
|
-
@name = name || param.to_s.humanize.titlecase
|
13
|
+
@name = name
|
19
14
|
end
|
20
15
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
def name(new_name = nil)
|
17
|
+
if new_name.nil?
|
18
|
+
@name ||= param.to_s.humanize.titlecase
|
19
|
+
else
|
20
|
+
@name = new_name
|
21
|
+
self
|
22
|
+
end
|
27
23
|
end
|
28
24
|
|
29
|
-
def
|
30
|
-
param
|
31
|
-
end
|
25
|
+
def param(new_param = nil)
|
26
|
+
return @param if new_param.nil?
|
32
27
|
|
33
|
-
|
34
|
-
|
28
|
+
@param = new_param
|
29
|
+
self
|
35
30
|
end
|
36
31
|
|
37
|
-
|
32
|
+
def prefix_param(prefix)
|
33
|
+
param("#{prefix}__#{@param}".to_sym)
|
34
|
+
end
|
38
35
|
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
def to_csf_params
|
37
|
+
# :nocov:
|
38
|
+
raise NotImplementedError
|
39
|
+
# :nocov:
|
42
40
|
end
|
43
41
|
|
44
|
-
def
|
45
|
-
|
42
|
+
def value_from_params(params)
|
43
|
+
# :nocov:
|
44
|
+
raise NotImplementedError
|
45
|
+
# :nocov:
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
module ControlsHelpers
|
7
|
+
def text(default_value)
|
8
|
+
Controls::TextConfig.new(default_value)
|
9
|
+
end
|
10
|
+
|
11
|
+
def boolean(default_value)
|
12
|
+
Controls::BooleanConfig.new(default_value)
|
13
|
+
end
|
14
|
+
|
15
|
+
def number(default_value, min: nil, max: nil, step: nil)
|
16
|
+
Controls::NumberConfig.new(:number, default_value, min: min, max: max, step: step)
|
17
|
+
end
|
18
|
+
|
19
|
+
def range(default_value, min: nil, max: nil, step: nil)
|
20
|
+
Controls::NumberConfig.new(:range, default_value, min: min, max: max, step: step)
|
21
|
+
end
|
22
|
+
|
23
|
+
def color(default_value, preset_colors: nil)
|
24
|
+
Controls::ColorConfig.new(default_value, preset_colors: preset_colors)
|
25
|
+
end
|
26
|
+
|
27
|
+
def object(default_value)
|
28
|
+
Controls::ObjectConfig.new(default_value)
|
29
|
+
end
|
30
|
+
|
31
|
+
def select(options, default_value, labels: nil)
|
32
|
+
Controls::OptionsConfig.new(:select, options, default_value, labels: labels)
|
33
|
+
end
|
34
|
+
|
35
|
+
def multi_select(options, default_value, labels: nil)
|
36
|
+
Controls::MultiOptionsConfig.new(:'multi-select', options, default_value, labels: labels)
|
37
|
+
end
|
38
|
+
|
39
|
+
def radio(options, default_value, labels: nil)
|
40
|
+
Controls::OptionsConfig.new(:radio, options, default_value, labels: labels)
|
41
|
+
end
|
42
|
+
|
43
|
+
def inline_radio(options, default_value, labels: nil)
|
44
|
+
Controls::OptionsConfig.new(:'inline-radio', options, default_value, labels: labels)
|
45
|
+
end
|
46
|
+
|
47
|
+
def check(options, default_value, labels: nil)
|
48
|
+
Controls::MultiOptionsConfig.new(:check, options, default_value, labels: labels)
|
49
|
+
end
|
50
|
+
|
51
|
+
def inline_check(options, default_value)
|
52
|
+
Controls::MultiOptionsConfig.new(:'inline-check', options, default_value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def array(default_value, separator = nil)
|
56
|
+
ActiveSupport::Deprecation.warn("`array` `separator` argument will be removed in v1.0.0.") if separator
|
57
|
+
Controls::ObjectConfig.new(default_value)
|
58
|
+
end
|
59
|
+
|
60
|
+
def date(default_value)
|
61
|
+
Controls::DateConfig.new(default_value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def custom(*args, **kwargs, &block)
|
65
|
+
Controls::CustomConfig.new.with_value(*args, **kwargs, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
def klazz(value_class, *args, **kwargs)
|
69
|
+
Controls::CustomConfig.new.with_value(*args, **kwargs) do |*a, **kwa|
|
70
|
+
value_class.new(*a, **kwa)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class CustomConfig < ControlConfig
|
7
|
+
attr_reader :value_method_args
|
8
|
+
|
9
|
+
validate :validate_value_method_args
|
10
|
+
|
11
|
+
def with_value(*args, **kwargs, &block)
|
12
|
+
@value_method_args = MethodArgs::ControlMethodArgs.new(block, *args, **kwargs)
|
13
|
+
@value_method_args.with_param_prefix(param)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def param(new_param = nil)
|
18
|
+
value_method_args.with_param_prefix(new_param) unless new_param.nil?
|
19
|
+
super(new_param)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_csf_params
|
23
|
+
validate!
|
24
|
+
# TODO: Figure out if we can use 'category' with the args table
|
25
|
+
# export default {
|
26
|
+
# argTypes: {
|
27
|
+
# foo: {
|
28
|
+
# table: { category: 'cat', subcategory: 'sub' }
|
29
|
+
# }
|
30
|
+
# }
|
31
|
+
# }
|
32
|
+
value_method_args.controls.reduce({}) do |csf_params, control|
|
33
|
+
csf_params.deep_merge(control.to_csf_params)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def value_from_params(params)
|
38
|
+
value_method_args.call(params)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def validate_value_method_args
|
44
|
+
return if value_method_args.valid?
|
45
|
+
|
46
|
+
value_method_args_errors = value_method_args.errors.full_messages.join(', ')
|
47
|
+
errors.add(:value_method_args, :invalid, errors: value_method_args_errors)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -3,32 +3,33 @@
|
|
3
3
|
module ViewComponent
|
4
4
|
module Storybook
|
5
5
|
module Controls
|
6
|
-
class DateConfig <
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(component, param, value, name: nil)
|
10
|
-
super(component, param, value, name: name)
|
6
|
+
class DateConfig < SimpleControlConfig
|
7
|
+
def initialize(default_value, param: nil, name: nil)
|
8
|
+
super(default_value, param: param, name: name)
|
11
9
|
end
|
12
10
|
|
13
11
|
def type
|
14
12
|
:date
|
15
13
|
end
|
16
14
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
15
|
+
def value_from_params(params)
|
16
|
+
params_value = super(params)
|
17
|
+
if params_value.is_a?(String)
|
18
|
+
DateTime.iso8601(params_value)
|
20
19
|
else
|
21
|
-
|
20
|
+
params_value
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
25
24
|
private
|
26
25
|
|
27
26
|
def csf_value
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
case default_value
|
28
|
+
when Date
|
29
|
+
default_value.in_time_zone
|
30
|
+
when Time
|
31
|
+
default_value.iso8601
|
32
|
+
end
|
32
33
|
end
|
33
34
|
end
|
34
35
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class MultiOptionsConfig < BaseOptionsConfig
|
7
|
+
TYPES = %i[multi-select check inline-check].freeze
|
8
|
+
|
9
|
+
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
10
|
+
validate :validate_default_value, unless: -> { options.nil? || default_value.nil? }
|
11
|
+
|
12
|
+
def initialize(type, options, default_value, labels: nil, param: nil, name: nil)
|
13
|
+
super(type, options, Array.wrap(default_value), labels: labels, param: param, name: name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def value_from_params(params)
|
17
|
+
params_value = super(params)
|
18
|
+
|
19
|
+
if params_value.is_a?(String)
|
20
|
+
params_value = params_value.split(',')
|
21
|
+
params_value = params_value.map(&:to_sym) if symbol_values
|
22
|
+
end
|
23
|
+
params_value
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_csf_params
|
27
|
+
super.deep_merge(argTypes: { param => { options: options } })
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def csf_control_params
|
33
|
+
labels.nil? ? super : super.merge(labels: labels)
|
34
|
+
end
|
35
|
+
|
36
|
+
def symbol_values
|
37
|
+
@symbol_values ||= default_value.first.is_a?(Symbol)
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate_default_value
|
41
|
+
errors.add(:default_value, :inclusion) unless default_value.to_set <= options.to_set
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -3,32 +3,35 @@
|
|
3
3
|
module ViewComponent
|
4
4
|
module Storybook
|
5
5
|
module Controls
|
6
|
-
class NumberConfig <
|
6
|
+
class NumberConfig < SimpleControlConfig
|
7
|
+
TYPES = %i[number range].freeze
|
8
|
+
|
7
9
|
attr_reader :type, :min, :max, :step
|
8
10
|
|
9
|
-
validates :
|
11
|
+
validates :type, presence: true
|
12
|
+
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
10
13
|
|
11
|
-
def initialize(type,
|
12
|
-
super(
|
14
|
+
def initialize(type, default_value, min: nil, max: nil, step: nil, param: nil, name: nil)
|
15
|
+
super(default_value, param: param, name: name)
|
13
16
|
@type = type
|
14
17
|
@min = min
|
15
18
|
@max = max
|
16
19
|
@step = step
|
17
20
|
end
|
18
21
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
+
def value_from_params(params)
|
23
|
+
params_value = super(params)
|
24
|
+
if params_value.is_a?(String) && params_value.present?
|
25
|
+
(params_value.to_f % 1) > 0 ? params_value.to_f : params_value.to_i
|
22
26
|
else
|
23
|
-
|
27
|
+
params_value
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
27
31
|
private
|
28
32
|
|
29
33
|
def csf_control_params
|
30
|
-
|
31
|
-
params.merge(min: min, max: max, step: step).compact
|
34
|
+
super.merge(min: min, max: max, step: step).compact
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
@@ -3,18 +3,24 @@
|
|
3
3
|
module ViewComponent
|
4
4
|
module Storybook
|
5
5
|
module Controls
|
6
|
-
class ObjectConfig <
|
7
|
-
validates :value, presence: true
|
8
|
-
|
6
|
+
class ObjectConfig < SimpleControlConfig
|
9
7
|
def type
|
10
8
|
:object
|
11
9
|
end
|
12
10
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
11
|
+
def value_from_params(params)
|
12
|
+
params_value = super(params)
|
13
|
+
if params_value.is_a?(String)
|
14
|
+
parsed_json = JSON.parse(params_value)
|
15
|
+
if parsed_json.is_a?(Array)
|
16
|
+
parsed_json.map do |item|
|
17
|
+
item.is_a?(Hash) ? item.deep_symbolize_keys : item
|
18
|
+
end
|
19
|
+
else
|
20
|
+
parsed_json.deep_symbolize_keys
|
21
|
+
end
|
16
22
|
else
|
17
|
-
|
23
|
+
params_value
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
@@ -3,49 +3,33 @@
|
|
3
3
|
module ViewComponent
|
4
4
|
module Storybook
|
5
5
|
module Controls
|
6
|
-
class OptionsConfig <
|
6
|
+
class OptionsConfig < BaseOptionsConfig
|
7
|
+
TYPES = %i[select radio inline-radio].freeze
|
7
8
|
|
8
|
-
class << self
|
9
|
-
# support the options being a Hash or an Array. Storybook supports either.
|
10
|
-
def inclusion_in(config)
|
11
|
-
case config.options
|
12
|
-
when Hash
|
13
|
-
config.options.values
|
14
|
-
when Array
|
15
|
-
config.options
|
16
|
-
else
|
17
|
-
[]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
TYPES = %i[select multi-select radio inline-radio check inline-check].freeze
|
23
|
-
|
24
|
-
attr_reader :type, :options, :symbol_value
|
25
|
-
|
26
|
-
validates :value, :type, :options, presence: true
|
27
9
|
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
28
|
-
validates :
|
10
|
+
validates :default_value, inclusion: { in: ->(config) { config.options } }, unless: -> { options.nil? || default_value.nil? }
|
29
11
|
|
30
|
-
def
|
31
|
-
super(
|
32
|
-
|
33
|
-
|
34
|
-
@symbol_value = default_value.is_a?(Symbol)
|
35
|
-
end
|
36
|
-
|
37
|
-
def value_from_param(param)
|
38
|
-
if param.is_a?(String) && symbol_value
|
39
|
-
param.to_sym
|
12
|
+
def value_from_params(params)
|
13
|
+
params_value = super(params)
|
14
|
+
if params_value.is_a?(String) && symbol_value
|
15
|
+
params_value.to_sym
|
40
16
|
else
|
41
|
-
|
17
|
+
params_value
|
42
18
|
end
|
43
19
|
end
|
44
20
|
|
21
|
+
def to_csf_params
|
22
|
+
super.deep_merge(argTypes: { param => { options: options } })
|
23
|
+
end
|
24
|
+
|
45
25
|
private
|
46
26
|
|
47
27
|
def csf_control_params
|
48
|
-
super.merge(
|
28
|
+
labels.nil? ? super : super.merge(labels: labels)
|
29
|
+
end
|
30
|
+
|
31
|
+
def symbol_value
|
32
|
+
@symbol_value ||= default_value.is_a?(Symbol)
|
49
33
|
end
|
50
34
|
end
|
51
35
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
##
|
7
|
+
# A simple Control Config maps to one Storybook Control
|
8
|
+
# It has a value and pulls its value from params by key
|
9
|
+
class SimpleControlConfig < ControlConfig
|
10
|
+
attr_reader :default_value
|
11
|
+
|
12
|
+
def initialize(default_value, param: nil, name: nil)
|
13
|
+
super(param: param, name: name)
|
14
|
+
@default_value = default_value
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_csf_params
|
18
|
+
validate!
|
19
|
+
{
|
20
|
+
args: { param => csf_value },
|
21
|
+
argTypes: { param => { control: csf_control_params, name: name } }
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def value_from_params(params)
|
26
|
+
params.key?(param) ? params[param] : default_value
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# provide extension points for subclasses to vary the value
|
32
|
+
def type
|
33
|
+
# :nocov:
|
34
|
+
raise NotImplementedError
|
35
|
+
# :nocov:
|
36
|
+
end
|
37
|
+
|
38
|
+
def csf_value
|
39
|
+
default_value
|
40
|
+
end
|
41
|
+
|
42
|
+
def csf_control_params
|
43
|
+
{ type: type }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|