view_component_storybook 0.8.0 → 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.
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