view_component_storybook 0.8.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -128
  3. data/app/controllers/view_component/storybook/stories_controller.rb +10 -11
  4. data/app/views/view_component/storybook/stories/show.html.erb +8 -1
  5. data/config/locales/en.yml +32 -0
  6. data/lib/view_component/storybook/content_concern.rb +42 -0
  7. data/lib/view_component/storybook/controls/base_options_config.rb +41 -0
  8. data/lib/view_component/storybook/controls/boolean_config.rb +7 -6
  9. data/lib/view_component/storybook/controls/color_config.rb +4 -5
  10. data/lib/view_component/storybook/controls/control_config.rb +24 -36
  11. data/lib/view_component/storybook/controls/controls_helpers.rb +76 -0
  12. data/lib/view_component/storybook/controls/custom_config.rb +52 -0
  13. data/lib/view_component/storybook/controls/date_config.rb +14 -11
  14. data/lib/view_component/storybook/controls/multi_options_config.rb +46 -0
  15. data/lib/view_component/storybook/controls/number_config.rb +9 -9
  16. data/lib/view_component/storybook/controls/object_config.rb +13 -5
  17. data/lib/view_component/storybook/controls/options_config.rb +17 -30
  18. data/lib/view_component/storybook/controls/simple_control_config.rb +48 -0
  19. data/lib/view_component/storybook/controls/text_config.rb +1 -1
  20. data/lib/view_component/storybook/controls.rb +5 -1
  21. data/lib/view_component/storybook/dsl/{controls_dsl.rb → legacy_controls_dsl.rb} +18 -21
  22. data/lib/view_component/storybook/dsl.rb +1 -2
  23. data/lib/view_component/storybook/engine.rb +13 -2
  24. data/lib/view_component/storybook/method_args/component_constructor_args.rb +23 -0
  25. data/lib/view_component/storybook/method_args/control_method_args.rb +91 -0
  26. data/lib/view_component/storybook/method_args/dry_initializer_component_constructor_args.rb +45 -0
  27. data/lib/view_component/storybook/method_args/method_args.rb +52 -0
  28. data/lib/view_component/storybook/method_args/method_parameters_names.rb +97 -0
  29. data/lib/view_component/storybook/method_args.rb +17 -0
  30. data/lib/view_component/storybook/slots/slot.rb +24 -0
  31. data/lib/view_component/storybook/slots/slot_config.rb +79 -0
  32. data/lib/view_component/storybook/slots.rb +14 -0
  33. data/lib/view_component/storybook/stories.rb +60 -10
  34. data/lib/view_component/storybook/story.rb +18 -0
  35. data/lib/view_component/storybook/story_config.rb +143 -15
  36. data/lib/view_component/storybook/tasks/write_stories_json.rake +6 -0
  37. data/lib/view_component/storybook/version.rb +1 -1
  38. data/lib/view_component/storybook.rb +25 -0
  39. metadata +64 -20
  40. data/lib/view_component/storybook/controls/array_config.rb +0 -36
  41. data/lib/view_component/storybook/dsl/story_dsl.rb +0 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e8c8a3875d64fe89649af8851324d2a07bd40868065abce8b57cf848cbeb5d3
4
- data.tar.gz: 554f43665400373ba30b9bc6e307285843b67d3760e5957e0088fa2ba53b325e
3
+ metadata.gz: 0dd708afcf2aa165339b0b1fde82ae610665554e3633c1e50b25509088b43e79
4
+ data.tar.gz: 950739b2892877a1451c262dc2110d6885a86c740c7fec9cd626a305feb8313d
5
5
  SHA512:
6
- metadata.gz: 398124fee399213bea34acf3aef434877eb01d0c76d9d6f127f5d5493981ecf5ac1f0ddc94ad9850354f6ec3629f1a9e5ca6005b57208abd39d045026415abbd
7
- data.tar.gz: 31a4a06293f40d19e575243a61cb61e1cff2bd7646da950c01de20f8edd73d1179970a7700064a8ee15cbcd3a73b2060f525bdbf427baeaddc9f9bd9ee6b7ebe
6
+ metadata.gz: 3f9b37292f202ac1c79fd4d31b9ace6b067efff03bf60a6f6a7b44a241ce5661c3669a382d9e549461dfe391d9c77fe0b9b98d33a3a5a47ce821d47e9c26ec7d
7
+ data.tar.gz: 8e7db14af389ae4d4b2dbcf269269476ac9309c9e518226afedbef769e31f72d32ed44a61382f9830836cab5a4ceba45a701af0a66861de31f928713be9b6c55
data/README.md CHANGED
@@ -1,142 +1,21 @@
1
1
  # ViewComponent::Storybook
2
2
 
3
- The ViewComponent::Storybook gem provides Ruby api for writing stories describing [View Components](https://github.com/github/view_component) and allowing them to be previewed and tested in [Storybook](https://github.com/storybookjs/storybook/)
3
+ The ViewComponent::Storybook gem provides Ruby api for writing stories describing [View Components](https://github.com/github/view_component) and allowing them to be previewed and tested in [Storybook](https://github.com/storybookjs/storybook/) via its [Server](https://github.com/storybookjs/storybook/tree/next/app/server) support.
4
4
 
5
5
  ## Features
6
- * A Ruby DSL for writing Stories describing View Components
7
- * A Rails controller backend for Storybook Server compatible with Strobook Controls Addon parameters
8
- * Coming Soon: Rake tasks to watch View Components and Stories and trigger Storybook hot reloading
9
6
 
10
- ## Installation
7
+ - A Ruby DSL for writing Stories describing View Components
8
+ - A Rails controller backend for Storybook Server compatible with Storybook Controls Addon parameters
9
+ - Coming Soon: Rake tasks to watch View Components and Stories and trigger Storybook hot reloading
11
10
 
12
- ### Gem Installation
11
+ ## Documentation
13
12
 
14
- 1. Add the `view_component_storybook` gem, to your Gemfile: `gem 'view_component_storybook'`
15
- 2. Run `bundle install`.
16
- 3. Add `require "view_component/storybook/engine"` to `config/application.rb`
17
- 4. Add `**/*.stories.json` to `.gitignore`
18
-
19
- ### Storybook Installation
20
-
21
- 1. Add Storybook server as a dev dependedncy. The Storybook Controls addon isn't needed but is strongly recommended
22
- ```sh
23
- yarn add @storybook/server @storybook/addon-controls --dev
24
- ```
25
- 2. Add an NPM script to your package.json in order to start the storybook later in this guide
26
- ```json
27
- {
28
- "scripts": {
29
- "storybook": "start-storybook"
30
- }
31
- }
32
- ```
33
- 3. Create the .storybook/main.js file to configure Storybook to find the json stories the gem creates. Also configure the Controls addon:
34
- ```javascript
35
- module.exports = {
36
- stories: ['../test/components/**/*.stories.json'],
37
- addons: [
38
- '@storybook/addon-controls',
39
- ],
40
- };
41
- ```
42
- 4. Create the .storybook/preview.js file to configure Storybook with the Rails application url to call for the html content of the stories
43
- ```javascript
44
-
45
- export const parameters = {
46
- server: {
47
- url: `http://localhost:3000/rails/stories`,
48
- },
49
- };
50
- ```
51
-
52
-
53
- Note: `@storybook/server` will be part of the upcoming Storybook 6.0 release. Until that is released you'll need to use an [rc release](https://github.com/storybookjs/storybook/releases/tag/v6.0.0-rc.14)
54
-
55
- ## Usage
56
-
57
- ### Writing Stories
58
-
59
- `ViewComponent::Storybook::Stories` provides a way to preview components in Storybook.
60
-
61
- Suppose our app has a `ButtonComponent` that takes a `button_text` parameter:
62
-
63
- ```ruby
64
- class ButtonComponent < ViewComponent::Base
65
- def initialize(button_text:)
66
- @button_text = button_text
67
- end
68
- end
69
- ```
70
-
71
- We can write a stories desecibing the `ButtonComponent`
72
-
73
- ```ruby
74
- class ButtonComponentStories < ViewComponent::Storybook::Stories
75
- story(:with_short_text) do
76
- controls do
77
- text(:button_text, 'OK')
78
- end
79
- end
80
-
81
- story(:with_long_text) do
82
- controls do
83
- text(:button_text, 'Push Me Please!')
84
- end
85
- end
86
- end
87
- ```
88
-
89
- ### Generating Storybook Stories JSON
90
-
91
- Generate the Storybook JSON stories by tunning the rake task:
92
- ```sh
93
- rake view_component_storybook:write_stories_json
94
- ```
95
-
96
- ### Start the Rails app and Storybook
97
-
98
- In separate shells start the Rails app and Storybook
99
-
100
- ```sh
101
- rails s
102
- ```
103
- ```sh
104
- yarn storybook
105
- ```
106
-
107
- Alternatively you can use tools like [Foreman](https://github.com/ddollar/foreman) to start both Rails and Storybook with one command.
108
-
109
- ### Configuration
110
-
111
- By Default ViewComponent::Storybook expects to find stories in the folder `test/components/stories`. This can be configured but setting `stories_path` in `config/applicaion.rb`. For example is you're using RSpec you might set the following configuration:
112
-
113
- ```ruby
114
- config.view_component_storybook.stories_path = Rails.root.join("spec/components/stories")
115
- ```
116
-
117
- ### The Story DSL
118
-
119
- Coming Soon
120
-
121
- #### Parameters
122
- #### Layout
123
- #### Controls
124
-
125
-
126
- ## Development
127
-
128
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
129
-
130
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
13
+ See [jonspalmer.github.io/view_component_storybook](https://jonspalmer.github.io/view_component_storybook) for documentation.
131
14
 
132
15
  ## Contributing
133
16
 
134
- Bug reports and pull requests are welcome on GitHub at https://github.com/jonspalmer/actionview-component-storybook. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
17
+ This project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. We recommend reading the [contributing guide](./docs/CONTRIBUTING.md) as well.
135
18
 
136
19
  ## License
137
20
 
138
21
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
139
-
140
- ## Code of Conduct
141
-
142
- Everyone interacting in the ViewComponent::Storybook project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/jonspalmer/view_component_storybook/blob/master/CODE_OF_CONDUCT.md).
@@ -8,19 +8,18 @@ module ViewComponent
8
8
  prepend_view_path File.expand_path("../../../views", __dir__)
9
9
  prepend_view_path Rails.root.join("app/views") if defined?(Rails.root)
10
10
 
11
- before_action :find_stories, :find_story, only: :show
11
+ before_action :find_story_configs, :find_story_config, only: :show
12
12
  before_action :require_local!, unless: :show_stories?
13
13
 
14
14
  content_security_policy(false) if respond_to?(:content_security_policy)
15
15
 
16
16
  def show
17
- component_args = @story.values_from_params(params.permit!.to_h)
17
+ params_hash = params.permit!.to_h
18
18
 
19
- @content_block = @story.content_block
19
+ @story = @story_config.story(params_hash)
20
20
 
21
- @component = @story.component.new(**component_args)
21
+ layout = @story_config.layout
22
22
 
23
- layout = @story.layout
24
23
  render layout: layout unless layout.nil?
25
24
  end
26
25
 
@@ -30,17 +29,17 @@ module ViewComponent
30
29
  ViewComponent::Storybook.show_stories
31
30
  end
32
31
 
33
- def find_stories
32
+ def find_story_configs
34
33
  stories_name = params[:stories]
35
- @stories = ViewComponent::Storybook::Stories.find_stories(stories_name)
34
+ @story_configs = Stories.find_story_configs(stories_name)
36
35
 
37
- head :not_found unless @stories
36
+ head :not_found unless @story_configs
38
37
  end
39
38
 
40
- def find_story
39
+ def find_story_config
41
40
  story_name = params[:story]
42
- @story = @stories.find_story(story_name)
43
- head :not_found unless @story
41
+ @story_config = @story_configs.find_story_config(story_name)
42
+ head :not_found unless @story_config
44
43
  end
45
44
  end
46
45
  end
@@ -1 +1,8 @@
1
- <%= render(@component, &@content_block)%>
1
+ <%= render(@story.component) do |c| -%>
2
+ <% @story.slots.each do |slot| -%>
3
+ <%- slot.call do -%>
4
+ <%= instance_eval(&slot.content_block) if slot.content_block -%>
5
+ <%- end -%>
6
+ <%- end -%>
7
+ <%- instance_eval(&@story.content_block) if @story.content_block -%>
8
+ <%- end -%>
@@ -0,0 +1,32 @@
1
+ en:
2
+ activemodel:
3
+ errors:
4
+ models:
5
+ view_component/storybook/method_args/method_args:
6
+ attributes:
7
+ args:
8
+ too_few: expected at least %{min} but found %{count}
9
+ too_many: expected no more than %{max} but found %{count}
10
+ kwargs:
11
+ invalid_arg: "'%{kwarg}' is invalid"
12
+ invalid: expected keys [%{expected_keys}] but found [%{actual_keys}]
13
+ view_component/storybook/method_args/control_method_args:
14
+ attributes:
15
+ controls:
16
+ invalid_control: "'%{control_name}' is invalid: (%{control_errors})"
17
+ view_component/storybook/stories:
18
+ attributes:
19
+ story_configs:
20
+ invalid_story: "'%{story_name}' is invalid: (%{story_errors})"
21
+ duplicate_stories:
22
+ one: duplicate story name %{duplicate_names}
23
+ other: duplicate story names %{duplicate_names}
24
+ view_component/storybook/story_config:
25
+ attributes:
26
+ constructor_args:
27
+ invalid: "invalid: (%{errors})"
28
+ view_component/storybook/controls/custom_config:
29
+ attributes:
30
+ value_method_args:
31
+ invalid: "invalid: (%{errors})"
32
+
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Storybook
5
+ module ContentConcern
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_reader :content_control, :content_block
10
+ end
11
+
12
+ def content(content = nil, &block)
13
+ case content
14
+ when Storybook::Controls::ControlConfig
15
+ @content_control = content.param(content_param)
16
+ @content_block = nil
17
+ when String
18
+ @content_control = nil
19
+ @content_block = proc { content }
20
+ else
21
+ @content_control = nil
22
+ @content_block = block
23
+ end
24
+ end
25
+
26
+ def resolve_content_block(params)
27
+ if content_control
28
+ content = content_control.value_from_params(params)
29
+ proc { content }
30
+ else
31
+ content_block
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def content_param
38
+ :content
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Storybook
5
+ module Controls
6
+ class BaseOptionsConfig < SimpleControlConfig
7
+ attr_reader :type, :options, :labels
8
+
9
+ validates :type, :options, presence: true
10
+
11
+ def initialize(type, options, default_value, labels: nil, param: nil, name: nil)
12
+ super(default_value, param: param, name: name)
13
+ @type = type
14
+ @options = options
15
+ @labels = labels
16
+ normalize_options
17
+ end
18
+
19
+ def to_csf_params
20
+ super.deep_merge(argTypes: { param => { options: options } })
21
+ end
22
+
23
+ private
24
+
25
+ def csf_control_params
26
+ labels.nil? ? super : super.merge(labels: labels)
27
+ end
28
+
29
+ def normalize_options
30
+ return unless options.is_a?(Hash)
31
+
32
+ warning = "Hash options is deprecated and will be removed in v1.0.0. Use array options and `labels` instead."
33
+ ActiveSupport::Deprecation.warn(warning)
34
+
35
+ @labels = options.invert
36
+ @options = options.values
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -3,25 +3,26 @@
3
3
  module ViewComponent
4
4
  module Storybook
5
5
  module Controls
6
- class BooleanConfig < ControlConfig
6
+ class BooleanConfig < SimpleControlConfig
7
7
  BOOLEAN_VALUES = [true, false].freeze
8
8
 
9
- validates :value, inclusion: { in: BOOLEAN_VALUES }, unless: -> { value.nil? }
9
+ validates :default_value, inclusion: { in: BOOLEAN_VALUES }, unless: -> { default_value.nil? }
10
10
 
11
11
  def type
12
12
  :boolean
13
13
  end
14
14
 
15
- def value_from_param(param)
16
- if param.is_a?(String) && param.present?
17
- case param
15
+ def value_from_params(params)
16
+ params_value = super(params)
17
+ if params_value.is_a?(String) && params_value.present?
18
+ case params_value
18
19
  when "true"
19
20
  true
20
21
  when "false"
21
22
  false
22
23
  end
23
24
  else
24
- super(param)
25
+ params_value
25
26
  end
26
27
  end
27
28
  end
@@ -3,11 +3,11 @@
3
3
  module ViewComponent
4
4
  module Storybook
5
5
  module Controls
6
- class ColorConfig < ControlConfig
6
+ class ColorConfig < SimpleControlConfig
7
7
  attr_reader :preset_colors
8
8
 
9
- def initialize(component, param, value, name: nil, preset_colors: nil)
10
- super(component, param, value, name: name)
9
+ def initialize(default_value, preset_colors: nil, param: nil, name: nil)
10
+ super(default_value, param: param, name: name)
11
11
  @preset_colors = preset_colors
12
12
  end
13
13
 
@@ -18,8 +18,7 @@ module ViewComponent
18
18
  private
19
19
 
20
20
  def csf_control_params
21
- params = super
22
- params.merge(presetColors: preset_colors).compact
21
+ super.merge(presetColors: preset_colors).compact
23
22
  end
24
23
  end
25
24
  end
@@ -6,55 +6,43 @@ module ViewComponent
6
6
  class ControlConfig
7
7
  include ActiveModel::Validations
8
8
 
9
- attr_reader :component, :param, :value, :name
9
+ validates :param, presence: true
10
10
 
11
- validates :component, :param, presence: true
12
- validates :param, inclusion: { in: ->(control_config) { control_config.component_param_names } }, if: :should_validate_params?
13
-
14
- def initialize(component, param, value, name: nil)
15
- @component = component
11
+ def initialize(param: nil, name: nil)
16
12
  @param = param
17
- @value = value
18
- @name = name || param.to_s.humanize.titlecase
13
+ @name = name
19
14
  end
20
15
 
21
- def to_csf_params
22
- validate!
23
- {
24
- args: { param => csf_value },
25
- argTypes: { param => { control: csf_control_params, name: name } }
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 value_from_param(param)
30
- param
31
- end
25
+ def param(new_param = nil)
26
+ return @param if new_param.nil?
32
27
 
33
- def component_param_names
34
- @component_param_names ||= component_params&.map(&:last)
28
+ @param = new_param
29
+ self
35
30
  end
36
31
 
37
- private
38
-
39
- # provide extension points for subclasses to vary the value
40
- def csf_value
41
- value
32
+ def prefix_param(prefix)
33
+ param("#{prefix}__#{@param}".to_sym)
42
34
  end
43
35
 
44
- def csf_control_params
45
- { type: type }
46
- end
47
-
48
- def component_accepts_kwargs?
49
- component_params.map(&:first).include?(:keyrest)
50
- end
51
-
52
- def component_params
53
- @component_params ||= component.instance_method(:initialize).parameters
36
+ def to_csf_params
37
+ # :nocov:
38
+ raise NotImplementedError
39
+ # :nocov:
54
40
  end
55
41
 
56
- def should_validate_params?
57
- component.present? && !component_accepts_kwargs?
42
+ def value_from_params(params)
43
+ # :nocov:
44
+ raise NotImplementedError
45
+ # :nocov:
58
46
  end
59
47
  end
60
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,30 +3,33 @@
3
3
  module ViewComponent
4
4
  module Storybook
5
5
  module Controls
6
- class DateConfig < ControlConfig
7
- def initialize(component, param, value, name: nil)
8
- 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)
9
9
  end
10
10
 
11
11
  def type
12
12
  :date
13
13
  end
14
14
 
15
- def value_from_param(param)
16
- if param.is_a?(String)
17
- DateTime.iso8601(param)
15
+ def value_from_params(params)
16
+ params_value = super(params)
17
+ if params_value.is_a?(String)
18
+ DateTime.iso8601(params_value)
18
19
  else
19
- super(param)
20
+ params_value
20
21
  end
21
22
  end
22
23
 
23
24
  private
24
25
 
25
26
  def csf_value
26
- params_value = value
27
- params_value = params_value.in_time_zone if params_value.is_a?(Date)
28
- params_value = params_value.iso8601 if params_value.is_a?(Time)
29
- params_value
27
+ case default_value
28
+ when Date
29
+ default_value.in_time_zone
30
+ when Time
31
+ default_value.iso8601
32
+ end
30
33
  end
31
34
  end
32
35
  end