view_component-storybook 1.0.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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +21 -0
- data/docs/CHANGELOG.md +69 -0
- data/lib/view_component/storybook/collections/controls_collection.rb +80 -0
- data/lib/view_component/storybook/collections/layout_collection.rb +37 -0
- data/lib/view_component/storybook/collections/parameters_collection.rb +40 -0
- data/lib/view_component/storybook/collections/stories_collection.rb +31 -0
- data/lib/view_component/storybook/collections/valid_for_story_concern.rb +15 -0
- data/lib/view_component/storybook/collections.rb +17 -0
- data/lib/view_component/storybook/controls/base_options.rb +30 -0
- data/lib/view_component/storybook/controls/boolean.rb +30 -0
- data/lib/view_component/storybook/controls/color.rb +26 -0
- data/lib/view_component/storybook/controls/control.rb +34 -0
- data/lib/view_component/storybook/controls/date.rb +32 -0
- data/lib/view_component/storybook/controls/multi_options.rb +44 -0
- data/lib/view_component/storybook/controls/number.rb +38 -0
- data/lib/view_component/storybook/controls/object.rb +28 -0
- data/lib/view_component/storybook/controls/options.rb +36 -0
- data/lib/view_component/storybook/controls/simple_control.rb +47 -0
- data/lib/view_component/storybook/controls/text.rb +13 -0
- data/lib/view_component/storybook/controls.rb +23 -0
- data/lib/view_component/storybook/engine.rb +76 -0
- data/lib/view_component/storybook/stories.rb +120 -0
- data/lib/view_component/storybook/stories_parser.rb +48 -0
- data/lib/view_component/storybook/story.rb +25 -0
- data/lib/view_component/storybook/tasks/view_component_storybook.rake +35 -0
- data/lib/view_component/storybook/version.rb +7 -0
- data/lib/view_component/storybook.rb +63 -0
- metadata +285 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dd438eab6c92e5e41e9df2b06d53c5702cb9f3121e7af553a743512058c1ef2c
|
4
|
+
data.tar.gz: 66a3827dd5f7522da5fd429d79a2d1c590e26d142395ab757d57bb7eee391b76
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: be57cabc078e464195eee2ae30b63dfd8629807eea2c15e2dd260ac80e545104bce41b2e51d5aa71b429fc7504cf41e2fc018292a2088a70ce29d0d24c59369a
|
7
|
+
data.tar.gz: 27d2af2dcb91f2acf6c22b083130650e440330bbf649974a746f634e22e9e135f933342fe1a84302d0640b2498f8669fe0c5e39150a18a9a85e6b6cb0d386f51
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Jon Palmer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# ViewComponent::Storybook
|
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/) via its [Server](https://github.com/storybookjs/storybook/tree/next/app/server) support.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
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
|
10
|
+
|
11
|
+
## Documentation
|
12
|
+
|
13
|
+
See [jonspalmer.github.io/view_component-storybook](https://jonspalmer.github.io/view_component-storybook) for documentation.
|
14
|
+
|
15
|
+
## Contributing
|
16
|
+
|
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.
|
18
|
+
|
19
|
+
## License
|
20
|
+
|
21
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/docs/CHANGELOG.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Changelog
|
4
|
+
---
|
5
|
+
|
6
|
+
# Changelog
|
7
|
+
|
8
|
+
## main
|
9
|
+
|
10
|
+
## 0.12.1
|
11
|
+
|
12
|
+
Last 0.x release
|
13
|
+
* Prepare for renaming to `view_component-storybook` to align with Rubygems naming conventions and simpler installation.
|
14
|
+
|
15
|
+
## 0.12.0
|
16
|
+
|
17
|
+
* Allow configuration of story titles via new `stories_title_generator` configuration lambda
|
18
|
+
* Added control descriptions
|
19
|
+
* Fixed bug with autoload paths
|
20
|
+
* Fixed Documentation typos
|
21
|
+
|
22
|
+
## 0.11.1
|
23
|
+
|
24
|
+
* Fix for stories_route by when using deprecated `require "view_component/storybook/engine"`
|
25
|
+
|
26
|
+
## 0.11.0
|
27
|
+
|
28
|
+
* Add support for dry-initializer
|
29
|
+
* Validate Slots
|
30
|
+
|
31
|
+
## 0.10.1
|
32
|
+
|
33
|
+
* Allow Object Controls with arrays of simple values
|
34
|
+
|
35
|
+
## 0.10.0
|
36
|
+
|
37
|
+
* New Stories API
|
38
|
+
* `title` - custom stories title
|
39
|
+
* `constructor` - component args
|
40
|
+
* `slot` - args and content for slots
|
41
|
+
* component and slot content accepts controls
|
42
|
+
* New Controls
|
43
|
+
* Custom Control
|
44
|
+
* Klazz Control
|
45
|
+
* Deprecated Controls DSL
|
46
|
+
* Add support for Object Controls with array values
|
47
|
+
* Remove ArrayConfig - array aliases Object
|
48
|
+
* Updated Options Control to match Storybook 6.2 syntax
|
49
|
+
* `options` as array
|
50
|
+
* add `labels` option
|
51
|
+
* deprecate `options` as Hash
|
52
|
+
* multi select types accept and return array values
|
53
|
+
* Improved validation errors with i18n support
|
54
|
+
* Add `stories_route` config to configure stories endpoint
|
55
|
+
* Jekyll docs
|
56
|
+
|
57
|
+
## 0.9.0
|
58
|
+
|
59
|
+
* Allow view helpers in content blocks
|
60
|
+
|
61
|
+
## 0.8.0
|
62
|
+
|
63
|
+
* Add support for components with keyword argument constructors
|
64
|
+
|
65
|
+
## 0.7.0
|
66
|
+
|
67
|
+
* Add inclusion validation to Number type
|
68
|
+
* Support Objects with nested values
|
69
|
+
* Support nil control values
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Collections
|
6
|
+
class ControlsCollection
|
7
|
+
include Collections::ValidForStoryConcern
|
8
|
+
|
9
|
+
attr_reader :controls
|
10
|
+
|
11
|
+
attr_accessor :code_object
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@controls = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(param, as:, only: nil, except: nil, **opts)
|
18
|
+
controls << { param: param, as: as, only: only, except: except, **opts }
|
19
|
+
end
|
20
|
+
|
21
|
+
def for_story(story_name)
|
22
|
+
# build the controls for the story_name
|
23
|
+
# pass through a hash to get the last valid control declared for each param
|
24
|
+
controls.map do |opts|
|
25
|
+
next unless valid_for_story?(story_name, **opts.slice(:only, :except))
|
26
|
+
|
27
|
+
param = opts[:param]
|
28
|
+
unless opts.key?(:default)
|
29
|
+
opts = opts.merge(default: parse_default(story_name, param))
|
30
|
+
end
|
31
|
+
[param, build_control(param, **opts.except(:param, :only, :except))]
|
32
|
+
end.compact.to_h.values
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def parse_default(story_name, param)
|
38
|
+
code_method = code_object.meths.find { |m| m.name == story_name }
|
39
|
+
default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == param.to_s }
|
40
|
+
return unless default_value_parts
|
41
|
+
|
42
|
+
code_method.instance_eval(default_value_parts[1])
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_control(param, as:, **opts)
|
46
|
+
case as
|
47
|
+
when :text
|
48
|
+
Controls::Text.new(param, **opts)
|
49
|
+
when :boolean
|
50
|
+
Controls::Boolean.new(param, **opts)
|
51
|
+
when :number
|
52
|
+
Controls::Number.new(param, type: :number, **opts)
|
53
|
+
when :range
|
54
|
+
Controls::Number.new(param, type: :range, **opts)
|
55
|
+
when :color
|
56
|
+
Controls::Color.new(param, **opts)
|
57
|
+
when :object, :array
|
58
|
+
Controls::Object.new(param, **opts)
|
59
|
+
when :select
|
60
|
+
Controls::Options.new(param, type: :select, **opts)
|
61
|
+
when :multi_select
|
62
|
+
Controls::MultiOptions.new(param, type: :'multi-select', **opts)
|
63
|
+
when :radio
|
64
|
+
Controls::Options.new(param, type: :radio, **opts)
|
65
|
+
when :inline_radio
|
66
|
+
Controls::Options.new(param, type: :'inline-radio', **opts)
|
67
|
+
when :check
|
68
|
+
Controls::MultiOptions.new(param, type: :check, **opts)
|
69
|
+
when :inline_check
|
70
|
+
Controls::MultiOptions.new(param, type: :'inline-check', **opts)
|
71
|
+
when :date
|
72
|
+
Controls::Date.new(param, **opts)
|
73
|
+
else
|
74
|
+
raise "Unknonwn control type '#{as}'"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Collections
|
6
|
+
class LayoutCollection
|
7
|
+
include Collections::ValidForStoryConcern
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@default = nil
|
11
|
+
@layouts = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def add(layout, only: nil, except: nil)
|
15
|
+
if only.nil? && except.nil?
|
16
|
+
@default = layout
|
17
|
+
else
|
18
|
+
layouts << { layout: layout, only: only, except: except }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Parameters set for the story method
|
23
|
+
def for_story(story_name)
|
24
|
+
story_layout = default
|
25
|
+
layouts.each do |opts|
|
26
|
+
story_layout = opts[:layout] if valid_for_story?(story_name, **opts.slice(:only, :except))
|
27
|
+
end
|
28
|
+
story_layout
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :default, :layouts
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Collections
|
6
|
+
class ParametersCollection
|
7
|
+
include Collections::ValidForStoryConcern
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@all_paramsters = {}
|
11
|
+
@parameters = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def add(params, only: nil, except: nil)
|
15
|
+
if only.nil? && except.nil?
|
16
|
+
all_paramsters.merge!(params)
|
17
|
+
else
|
18
|
+
parameters << { params: params, only: only, except: except }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Parameters set for all stories
|
23
|
+
def for_all
|
24
|
+
all_paramsters
|
25
|
+
end
|
26
|
+
|
27
|
+
# Parameters set for the story method
|
28
|
+
def for_story(story_name)
|
29
|
+
parameters.each_with_object({}) do |opts, accum|
|
30
|
+
accum.merge!(opts[:params]) if valid_for_story?(story_name, **opts.slice(:only, :except))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :all_paramsters, :parameters
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Collections
|
6
|
+
class StoriesCollection
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
delegate_missing_to :stories
|
10
|
+
|
11
|
+
attr_reader :stories
|
12
|
+
|
13
|
+
def load(code_objects)
|
14
|
+
@stories = Array(code_objects).map { |obj| StoriesCollection.stories_from_code_object(obj) }.compact
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.stories_from_code_object(code_object)
|
18
|
+
klass = code_object.path.constantize
|
19
|
+
klass.code_object = code_object
|
20
|
+
klass
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.stories_class?(klass)
|
24
|
+
return unless klass.ancestors.include?(ViewComponent::Storybook::Stories)
|
25
|
+
|
26
|
+
!klass.respond_to?(:abstract_class) || klass.abstract_class != true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Collections
|
6
|
+
module ValidForStoryConcern
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def valid_for_story?(story_name, only:, except:)
|
10
|
+
(only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/dependencies/autoload"
|
4
|
+
|
5
|
+
module ViewComponent
|
6
|
+
module Storybook
|
7
|
+
module Collections
|
8
|
+
extend ActiveSupport::Autoload
|
9
|
+
|
10
|
+
autoload :ValidForStoryConcern
|
11
|
+
autoload :StoriesCollection
|
12
|
+
autoload :ControlsCollection
|
13
|
+
autoload :ParametersCollection
|
14
|
+
autoload :LayoutCollection
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class BaseOptions < SimpleControl
|
7
|
+
attr_reader :type, :options, :labels
|
8
|
+
|
9
|
+
validates :type, :options, presence: true
|
10
|
+
|
11
|
+
def initialize(param, type:, options:, default: nil, labels: nil, name: nil, description: nil, **opts)
|
12
|
+
super(param, default: default, name: name, description: description, **opts)
|
13
|
+
@type = type
|
14
|
+
@options = options
|
15
|
+
@labels = labels
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_csf_params
|
19
|
+
super.deep_merge(argTypes: { param => { options: options } })
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def csf_control_params
|
25
|
+
labels.nil? ? super : super.merge(labels: labels)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class Boolean < SimpleControl
|
7
|
+
BOOLEAN_VALUES = [true, false].freeze
|
8
|
+
|
9
|
+
validates :default, inclusion: { in: BOOLEAN_VALUES }, unless: -> { default.nil? }
|
10
|
+
|
11
|
+
def type
|
12
|
+
:boolean
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_param_value(value)
|
16
|
+
if value.is_a?(String) && value.present?
|
17
|
+
case value
|
18
|
+
when "true"
|
19
|
+
true
|
20
|
+
when "false"
|
21
|
+
false
|
22
|
+
end
|
23
|
+
else
|
24
|
+
value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class Color < SimpleControl
|
7
|
+
attr_reader :preset_colors
|
8
|
+
|
9
|
+
def initialize(param, default: nil, preset_colors: nil, name: nil, description: nil, **opts)
|
10
|
+
super(param, default: default, name: name, description: description, **opts)
|
11
|
+
@preset_colors = preset_colors
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
:color
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def csf_control_params
|
21
|
+
super.merge(presetColors: preset_colors).compact
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class Control
|
7
|
+
include ActiveModel::Validations
|
8
|
+
|
9
|
+
validates :param, presence: true
|
10
|
+
|
11
|
+
attr_reader :param, :name, :description, :default
|
12
|
+
|
13
|
+
def initialize(param, default:, name: nil, description: nil)
|
14
|
+
@param = param
|
15
|
+
@default = default
|
16
|
+
@name = name || param.to_s.humanize.titlecase
|
17
|
+
@description = description
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_csf_params
|
21
|
+
# :nocov:
|
22
|
+
raise NotImplementedError
|
23
|
+
# :nocov:
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_param_value(value)
|
27
|
+
# :nocov:
|
28
|
+
raise NotImplementedError
|
29
|
+
# :nocov:
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class Date < SimpleControl
|
7
|
+
def type
|
8
|
+
:date
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_param_value(value)
|
12
|
+
if value.is_a?(String)
|
13
|
+
DateTime.iso8601(value)
|
14
|
+
else
|
15
|
+
value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def csf_value
|
22
|
+
case default
|
23
|
+
when ::Date
|
24
|
+
default.in_time_zone
|
25
|
+
when Time
|
26
|
+
default.iso8601
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class MultiOptions < BaseOptions
|
7
|
+
TYPES = %i[multi-select check inline-check].freeze
|
8
|
+
|
9
|
+
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
10
|
+
validate :validate_default, unless: -> { options.nil? || default.nil? }
|
11
|
+
|
12
|
+
def initialize(param, type:, options:, default: nil, labels: nil, name: nil, description: nil, **opts)
|
13
|
+
super(param, type: type, options: options, default: Array.wrap(default), labels: labels, name: name, description: description, **opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_param_value(value)
|
17
|
+
if value.is_a?(String)
|
18
|
+
value = value.split(',')
|
19
|
+
value = value.map(&:to_sym) if symbol_values
|
20
|
+
end
|
21
|
+
value
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_csf_params
|
25
|
+
super.deep_merge(argTypes: { param => { options: options } })
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def csf_control_params
|
31
|
+
labels.nil? ? super : super.merge(labels: labels)
|
32
|
+
end
|
33
|
+
|
34
|
+
def symbol_values
|
35
|
+
options.first.is_a?(Symbol)
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_default
|
39
|
+
errors.add(:default, :inclusion) unless default.to_set <= options.to_set
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class Number < SimpleControl
|
7
|
+
TYPES = %i[number range].freeze
|
8
|
+
|
9
|
+
attr_reader :type, :min, :max, :step
|
10
|
+
|
11
|
+
validates :type, presence: true
|
12
|
+
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
13
|
+
|
14
|
+
def initialize(param, type:, default: nil, min: nil, max: nil, step: nil, name: nil, description: nil, **opts)
|
15
|
+
super(param, default: default, name: name, description: description, **opts)
|
16
|
+
@type = type
|
17
|
+
@min = min
|
18
|
+
@max = max
|
19
|
+
@step = step
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_param_value(value)
|
23
|
+
if value.is_a?(String) && value.present?
|
24
|
+
(value.to_f % 1) > 0 ? value.to_f : value.to_i
|
25
|
+
else
|
26
|
+
value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def csf_control_params
|
33
|
+
super.merge(min: min, max: max, step: step).compact
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class Object < SimpleControl
|
7
|
+
def type
|
8
|
+
:object
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_param_value(value)
|
12
|
+
if value.is_a?(String)
|
13
|
+
parsed_json = JSON.parse(value)
|
14
|
+
if parsed_json.is_a?(Array)
|
15
|
+
parsed_json.map do |item|
|
16
|
+
item.is_a?(Hash) ? item.deep_symbolize_keys : item
|
17
|
+
end
|
18
|
+
else
|
19
|
+
parsed_json.deep_symbolize_keys
|
20
|
+
end
|
21
|
+
else
|
22
|
+
value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class Options < BaseOptions
|
7
|
+
TYPES = %i[select radio inline-radio].freeze
|
8
|
+
|
9
|
+
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
10
|
+
validates :default, inclusion: { in: ->(config) { config.options } }, unless: -> { options.nil? || default.nil? }
|
11
|
+
|
12
|
+
def parse_param_value(value)
|
13
|
+
if value.is_a?(String) && symbol_value
|
14
|
+
value.to_sym
|
15
|
+
else
|
16
|
+
value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_csf_params
|
21
|
+
super.deep_merge(argTypes: { param => { options: options } })
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def csf_control_params
|
27
|
+
labels.nil? ? super : super.merge(labels: labels)
|
28
|
+
end
|
29
|
+
|
30
|
+
def symbol_value
|
31
|
+
@symbol_value ||= default.is_a?(Symbol)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|