view_component_storybook 0.2.0 → 0.8.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/README.md +16 -17
- data/lib/view_component/storybook.rb +1 -2
- data/lib/view_component/storybook/{knobs.rb → controls.rb} +5 -3
- data/lib/view_component/storybook/{knobs → controls}/array_config.rb +11 -9
- data/lib/view_component/storybook/controls/boolean_config.rb +30 -0
- data/lib/view_component/storybook/controls/color_config.rb +27 -0
- data/lib/view_component/storybook/controls/control_config.rb +62 -0
- data/lib/view_component/storybook/{knobs → controls}/date_config.rb +13 -15
- data/lib/view_component/storybook/controls/number_config.rb +39 -0
- data/lib/view_component/storybook/{knobs → controls}/object_config.rb +3 -5
- data/lib/view_component/storybook/controls/options_config.rb +50 -0
- data/lib/view_component/storybook/controls/text_config.rb +13 -0
- data/lib/view_component/storybook/dsl.rb +1 -1
- data/lib/view_component/storybook/dsl/controls_dsl.rb +101 -0
- data/lib/view_component/storybook/dsl/story_dsl.rb +4 -4
- data/lib/view_component/storybook/stories.rb +1 -10
- data/lib/view_component/storybook/story_config.rb +9 -7
- data/lib/view_component/storybook/version.rb +1 -1
- metadata +34 -18
- data/lib/view_component/storybook/dsl/knobs_dsl.rb +0 -81
- data/lib/view_component/storybook/knobs/knob_config.rb +0 -39
- data/lib/view_component/storybook/knobs/number_config.rb +0 -36
- data/lib/view_component/storybook/knobs/options_config.rb +0 -27
- data/lib/view_component/storybook/knobs/simple_config.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e8c8a3875d64fe89649af8851324d2a07bd40868065abce8b57cf848cbeb5d3
|
4
|
+
data.tar.gz: 554f43665400373ba30b9bc6e307285843b67d3760e5957e0088fa2ba53b325e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 398124fee399213bea34acf3aef434877eb01d0c76d9d6f127f5d5493981ecf5ac1f0ddc94ad9850354f6ec3629f1a9e5ca6005b57208abd39d045026415abbd
|
7
|
+
data.tar.gz: 31a4a06293f40d19e575243a61cb61e1cff2bd7646da950c01de20f8edd73d1179970a7700064a8ee15cbcd3a73b2060f525bdbf427baeaddc9f9bd9ee6b7ebe
|
data/README.md
CHANGED
@@ -1,26 +1,26 @@
|
|
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/)
|
4
4
|
|
5
5
|
## Features
|
6
6
|
* A Ruby DSL for writing Stories describing View Components
|
7
|
-
* A Rails controller backend for Storybook Server compatible with
|
7
|
+
* A Rails controller backend for Storybook Server compatible with Strobook Controls Addon parameters
|
8
8
|
* Coming Soon: Rake tasks to watch View Components and Stories and trigger Storybook hot reloading
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
12
|
-
### Gem Installation
|
12
|
+
### Gem Installation
|
13
13
|
|
14
14
|
1. Add the `view_component_storybook` gem, to your Gemfile: `gem 'view_component_storybook'`
|
15
15
|
2. Run `bundle install`.
|
16
|
-
3. Add `require "
|
16
|
+
3. Add `require "view_component/storybook/engine"` to `config/application.rb`
|
17
17
|
4. Add `**/*.stories.json` to `.gitignore`
|
18
18
|
|
19
19
|
### Storybook Installation
|
20
20
|
|
21
|
-
1. Add Storybook server as a dev dependedncy. The Storybook
|
21
|
+
1. Add Storybook server as a dev dependedncy. The Storybook Controls addon isn't needed but is strongly recommended
|
22
22
|
```sh
|
23
|
-
yarn add @storybook/server @storybook/addon-
|
23
|
+
yarn add @storybook/server @storybook/addon-controls --dev
|
24
24
|
```
|
25
25
|
2. Add an NPM script to your package.json in order to start the storybook later in this guide
|
26
26
|
```json
|
@@ -29,29 +29,28 @@ The ViewComponent::Storybook gem provides Ruby api for writing stories describin
|
|
29
29
|
"storybook": "start-storybook"
|
30
30
|
}
|
31
31
|
}
|
32
|
-
```
|
33
|
-
3. Create the .storybook/main.js file to configure Storybook to find the json stories the gem creates. Also configure the
|
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
34
|
```javascript
|
35
35
|
module.exports = {
|
36
36
|
stories: ['../test/components/**/*.stories.json'],
|
37
37
|
addons: [
|
38
|
-
'@storybook/addon-
|
38
|
+
'@storybook/addon-controls',
|
39
39
|
],
|
40
40
|
};
|
41
41
|
```
|
42
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
43
|
```javascript
|
44
|
-
import { addParameters } from '@storybook/server';
|
45
44
|
|
46
|
-
|
45
|
+
export const parameters = {
|
47
46
|
server: {
|
48
47
|
url: `http://localhost:3000/rails/stories`,
|
49
48
|
},
|
50
|
-
}
|
49
|
+
};
|
51
50
|
```
|
52
|
-
|
53
51
|
|
54
|
-
|
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)
|
55
54
|
|
56
55
|
## Usage
|
57
56
|
|
@@ -74,13 +73,13 @@ We can write a stories desecibing the `ButtonComponent`
|
|
74
73
|
```ruby
|
75
74
|
class ButtonComponentStories < ViewComponent::Storybook::Stories
|
76
75
|
story(:with_short_text) do
|
77
|
-
|
76
|
+
controls do
|
78
77
|
text(:button_text, 'OK')
|
79
78
|
end
|
80
79
|
end
|
81
80
|
|
82
81
|
story(:with_long_text) do
|
83
|
-
|
82
|
+
controls do
|
84
83
|
text(:button_text, 'Push Me Please!')
|
85
84
|
end
|
86
85
|
end
|
@@ -121,7 +120,7 @@ Coming Soon
|
|
121
120
|
|
122
121
|
#### Parameters
|
123
122
|
#### Layout
|
124
|
-
####
|
123
|
+
#### Controls
|
125
124
|
|
126
125
|
|
127
126
|
## Development
|
@@ -2,13 +2,12 @@
|
|
2
2
|
|
3
3
|
require "active_model"
|
4
4
|
require "active_support/dependencies/autoload"
|
5
|
-
require "view_component/storybook/engine"
|
6
5
|
|
7
6
|
module ViewComponent
|
8
7
|
module Storybook
|
9
8
|
extend ActiveSupport::Autoload
|
10
9
|
|
11
|
-
autoload :
|
10
|
+
autoload :Controls
|
12
11
|
autoload :Stories
|
13
12
|
autoload :StoryConfig
|
14
13
|
autoload :Dsl
|
@@ -4,11 +4,13 @@ require "active_support/dependencies/autoload"
|
|
4
4
|
|
5
5
|
module ViewComponent
|
6
6
|
module Storybook
|
7
|
-
module
|
7
|
+
module Controls
|
8
8
|
extend ActiveSupport::Autoload
|
9
9
|
|
10
|
-
autoload :
|
11
|
-
autoload :
|
10
|
+
autoload :ControlConfig
|
11
|
+
autoload :TextConfig
|
12
|
+
autoload :BooleanConfig
|
13
|
+
autoload :ColorConfig
|
12
14
|
autoload :NumberConfig
|
13
15
|
autoload :OptionsConfig
|
14
16
|
autoload :ArrayConfig
|
@@ -2,21 +2,17 @@
|
|
2
2
|
|
3
3
|
module ViewComponent
|
4
4
|
module Storybook
|
5
|
-
module
|
6
|
-
class ArrayConfig <
|
5
|
+
module Controls
|
6
|
+
class ArrayConfig < ControlConfig
|
7
7
|
attr_reader :separator
|
8
8
|
|
9
|
-
validates :
|
9
|
+
validates :separator, presence: true
|
10
10
|
|
11
|
-
def initialize(component, param, value, separator = ",", name: nil
|
12
|
-
super(component, param, value, name: name
|
11
|
+
def initialize(component, param, value, separator = ",", name: nil)
|
12
|
+
super(component, param, value, name: name)
|
13
13
|
@separator = separator
|
14
14
|
end
|
15
15
|
|
16
|
-
def to_csf_params
|
17
|
-
super.merge(value: value, separator: separator)
|
18
|
-
end
|
19
|
-
|
20
16
|
def type
|
21
17
|
:array
|
22
18
|
end
|
@@ -28,6 +24,12 @@ module ViewComponent
|
|
28
24
|
super(param)
|
29
25
|
end
|
30
26
|
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def csf_control_params
|
31
|
+
super.merge(separator: separator)
|
32
|
+
end
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class BooleanConfig < ControlConfig
|
7
|
+
BOOLEAN_VALUES = [true, false].freeze
|
8
|
+
|
9
|
+
validates :value, inclusion: { in: BOOLEAN_VALUES }, unless: -> { value.nil? }
|
10
|
+
|
11
|
+
def type
|
12
|
+
:boolean
|
13
|
+
end
|
14
|
+
|
15
|
+
def value_from_param(param)
|
16
|
+
if param.is_a?(String) && param.present?
|
17
|
+
case param
|
18
|
+
when "true"
|
19
|
+
true
|
20
|
+
when "false"
|
21
|
+
false
|
22
|
+
end
|
23
|
+
else
|
24
|
+
super(param)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class ColorConfig < ControlConfig
|
7
|
+
attr_reader :preset_colors
|
8
|
+
|
9
|
+
def initialize(component, param, value, name: nil, preset_colors: nil)
|
10
|
+
super(component, param, value, name: name)
|
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
|
+
params = super
|
22
|
+
params.merge(presetColors: preset_colors).compact
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class ControlConfig
|
7
|
+
include ActiveModel::Validations
|
8
|
+
|
9
|
+
attr_reader :component, :param, :value, :name
|
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
|
16
|
+
@param = param
|
17
|
+
@value = value
|
18
|
+
@name = name || param.to_s.humanize.titlecase
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_csf_params
|
22
|
+
validate!
|
23
|
+
{
|
24
|
+
args: { param => csf_value },
|
25
|
+
argTypes: { param => { control: csf_control_params, name: name } }
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def value_from_param(param)
|
30
|
+
param
|
31
|
+
end
|
32
|
+
|
33
|
+
def component_param_names
|
34
|
+
@component_param_names ||= component_params&.map(&:last)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# provide extension points for subclasses to vary the value
|
40
|
+
def csf_value
|
41
|
+
value
|
42
|
+
end
|
43
|
+
|
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
|
54
|
+
end
|
55
|
+
|
56
|
+
def should_validate_params?
|
57
|
+
component.present? && !component_accepts_kwargs?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -2,21 +2,10 @@
|
|
2
2
|
|
3
3
|
module ViewComponent
|
4
4
|
module Storybook
|
5
|
-
module
|
6
|
-
class DateConfig <
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(component, param, value, name: nil, group_id: nil)
|
10
|
-
super(component, param, value, name: name, group_id: group_id)
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_csf_params
|
14
|
-
csf_params = super
|
15
|
-
params_value = value
|
16
|
-
params_value = params_value.in_time_zone if params_value.is_a?(Date)
|
17
|
-
params_value = params_value.iso8601 if params_value.is_a?(Time)
|
18
|
-
csf_params[:value] = params_value
|
19
|
-
csf_params
|
5
|
+
module Controls
|
6
|
+
class DateConfig < ControlConfig
|
7
|
+
def initialize(component, param, value, name: nil)
|
8
|
+
super(component, param, value, name: name)
|
20
9
|
end
|
21
10
|
|
22
11
|
def type
|
@@ -30,6 +19,15 @@ module ViewComponent
|
|
30
19
|
super(param)
|
31
20
|
end
|
32
21
|
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
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
|
30
|
+
end
|
33
31
|
end
|
34
32
|
end
|
35
33
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class NumberConfig < ControlConfig
|
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(type, component, param, value, min: nil, max: nil, step: nil, name: nil)
|
15
|
+
super(component, param, value, name: name)
|
16
|
+
@type = type
|
17
|
+
@min = min
|
18
|
+
@max = max
|
19
|
+
@step = step
|
20
|
+
end
|
21
|
+
|
22
|
+
def value_from_param(param)
|
23
|
+
if param.is_a?(String) && param.present?
|
24
|
+
(param.to_f % 1) > 0 ? param.to_f : param.to_i
|
25
|
+
else
|
26
|
+
super(param)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def csf_control_params
|
33
|
+
params = super
|
34
|
+
params.merge(min: min, max: max, step: step).compact
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -2,17 +2,15 @@
|
|
2
2
|
|
3
3
|
module ViewComponent
|
4
4
|
module Storybook
|
5
|
-
module
|
6
|
-
class ObjectConfig <
|
7
|
-
validates :value, presence: true
|
8
|
-
|
5
|
+
module Controls
|
6
|
+
class ObjectConfig < ControlConfig
|
9
7
|
def type
|
10
8
|
:object
|
11
9
|
end
|
12
10
|
|
13
11
|
def value_from_param(param)
|
14
12
|
if param.is_a?(String)
|
15
|
-
JSON.parse(param).
|
13
|
+
JSON.parse(param).deep_symbolize_keys
|
16
14
|
else
|
17
15
|
super(param)
|
18
16
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Controls
|
6
|
+
class OptionsConfig < ControlConfig
|
7
|
+
class << self
|
8
|
+
# support the options being a Hash or an Array. Storybook supports either.
|
9
|
+
def inclusion_in(config)
|
10
|
+
case config.options
|
11
|
+
when Hash
|
12
|
+
config.options.values
|
13
|
+
when Array
|
14
|
+
config.options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
TYPES = %i[select multi-select radio inline-radio check inline-check].freeze
|
20
|
+
|
21
|
+
attr_reader :type, :options, :symbol_value
|
22
|
+
|
23
|
+
validates :type, :options, presence: true
|
24
|
+
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
25
|
+
validates :value, inclusion: { in: method(:inclusion_in) }, unless: -> { options.nil? || value.nil? }
|
26
|
+
|
27
|
+
def initialize(type, component, param, options, default_value, name: nil)
|
28
|
+
super(component, param, default_value, name: name)
|
29
|
+
@type = type
|
30
|
+
@options = options
|
31
|
+
@symbol_value = default_value.is_a?(Symbol)
|
32
|
+
end
|
33
|
+
|
34
|
+
def value_from_param(param)
|
35
|
+
if param.is_a?(String) && symbol_value
|
36
|
+
param.to_sym
|
37
|
+
else
|
38
|
+
super(param)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def csf_control_params
|
45
|
+
super.merge(options: options)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module Storybook
|
5
|
+
module Dsl
|
6
|
+
class ControlsDsl
|
7
|
+
attr_reader :component, :controls
|
8
|
+
|
9
|
+
def initialize(component)
|
10
|
+
@component = component
|
11
|
+
@controls = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def text(param, value, name: nil)
|
15
|
+
controls << Controls::TextConfig.new(component, param, value, name: name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def boolean(param, value, name: nil)
|
19
|
+
controls << Controls::BooleanConfig.new(component, param, value, name: name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def number(param, value, name: nil, min: nil, max: nil, step: nil)
|
23
|
+
controls << Controls::NumberConfig.new(:number, component, param, value, name: name, min: min, max: max, step: step)
|
24
|
+
end
|
25
|
+
|
26
|
+
def range(param, value, name: nil, min: nil, max: nil, step: nil)
|
27
|
+
controls << Controls::NumberConfig.new(:range, component, param, value, name: name, min: min, max: max, step: step)
|
28
|
+
end
|
29
|
+
|
30
|
+
def color(param, value, name: nil, preset_colors: nil)
|
31
|
+
controls << Controls::ColorConfig.new(component, param, value, name: name, preset_colors: preset_colors)
|
32
|
+
end
|
33
|
+
|
34
|
+
def object(param, value, name: nil)
|
35
|
+
controls << Controls::ObjectConfig.new(component, param, value, name: name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def select(param, options, value, name: nil)
|
39
|
+
controls << Controls::OptionsConfig.new(:select, component, param, options, value, name: name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def multi_select(param, options, value, name: nil)
|
43
|
+
controls << Controls::OptionsConfig.new(:'multi-select', component, param, options, value, name: name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def radio(param, options, value, name: nil)
|
47
|
+
controls << Controls::OptionsConfig.new(:radio, component, param, options, value, name: name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def inline_radio(param, options, value, name: nil)
|
51
|
+
controls << Controls::OptionsConfig.new(:'inline-radio', component, param, options, value, name: name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def check(param, options, value, name: nil)
|
55
|
+
controls << Controls::OptionsConfig.new(:check, component, param, options, value, name: name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def inline_check(param, options, value, name: nil)
|
59
|
+
controls << Controls::OptionsConfig.new(:'inline-check', component, param, options, value, name: name)
|
60
|
+
end
|
61
|
+
|
62
|
+
def array(param, value, separator = ",", name: nil)
|
63
|
+
controls << Controls::ArrayConfig.new(component, param, value, separator, name: name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def date(param, value, name: nil)
|
67
|
+
controls << Controls::DateConfig.new(component, param, value, name: name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def respond_to_missing?(_method, *)
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_missing(method, *args)
|
75
|
+
value = args.first
|
76
|
+
control_method = case value
|
77
|
+
when Date
|
78
|
+
:date
|
79
|
+
when Array
|
80
|
+
:array
|
81
|
+
when Hash
|
82
|
+
:object
|
83
|
+
when Numeric
|
84
|
+
:number
|
85
|
+
when TrueClass, FalseClass
|
86
|
+
:boolean
|
87
|
+
when String
|
88
|
+
:text
|
89
|
+
end
|
90
|
+
if control_method
|
91
|
+
send(control_method, method, *args)
|
92
|
+
else
|
93
|
+
super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
Controls = ViewComponent::Storybook::Controls
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -12,10 +12,10 @@ module ViewComponent
|
|
12
12
|
@story_config.parameters = params
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
@story_config.
|
15
|
+
def controls(&block)
|
16
|
+
controls_dsl = ControlsDsl.new(story_config.component)
|
17
|
+
controls_dsl.instance_eval(&block)
|
18
|
+
@story_config.controls = controls_dsl.controls
|
19
19
|
end
|
20
20
|
|
21
21
|
def layout(layout)
|
@@ -26,17 +26,14 @@ module ViewComponent
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def to_csf_params
|
29
|
-
stories_csf = story_configs.map(&:to_csf_params)
|
30
|
-
|
31
29
|
csf_params = { title: title }
|
32
|
-
csf_params[:addons] = ["knobs"] if stories_csf.any? { |csf| csf.key?(:knobs) }
|
33
30
|
csf_params[:parameters] = parameters if parameters.present?
|
34
31
|
csf_params[:stories] = story_configs.map(&:to_csf_params)
|
35
32
|
csf_params
|
36
33
|
end
|
37
34
|
|
38
35
|
def write_csf_json
|
39
|
-
json_path = File.join(
|
36
|
+
json_path = File.join(stories_path, "#{stories_name}.stories.json")
|
40
37
|
File.open(json_path, "w") do |f|
|
41
38
|
f.write(JSON.pretty_generate(to_csf_params))
|
42
39
|
end
|
@@ -84,8 +81,6 @@ module ViewComponent
|
|
84
81
|
|
85
82
|
def default_component
|
86
83
|
name.chomp("Stories").constantize
|
87
|
-
rescue StandardError
|
88
|
-
nil
|
89
84
|
end
|
90
85
|
|
91
86
|
def load_stories
|
@@ -96,10 +91,6 @@ module ViewComponent
|
|
96
91
|
Storybook.stories_path
|
97
92
|
end
|
98
93
|
|
99
|
-
def show_stories
|
100
|
-
Storybook.show_stories
|
101
|
-
end
|
102
|
-
|
103
94
|
def story_id(name)
|
104
95
|
"#{stories_name}/#{name.to_s.parameterize}".underscore
|
105
96
|
end
|
@@ -6,28 +6,30 @@ module ViewComponent
|
|
6
6
|
include ActiveModel::Validations
|
7
7
|
|
8
8
|
attr_reader :id, :name, :component
|
9
|
-
attr_accessor :
|
9
|
+
attr_accessor :controls, :parameters, :layout, :content_block
|
10
10
|
|
11
11
|
def initialize(id, name, component, layout)
|
12
12
|
@id = id
|
13
13
|
@name = name
|
14
14
|
@component = component
|
15
15
|
@layout = layout
|
16
|
-
@
|
16
|
+
@controls = []
|
17
17
|
end
|
18
18
|
|
19
19
|
def to_csf_params
|
20
20
|
csf_params = { name: name, parameters: { server: { id: id } } }
|
21
21
|
csf_params.deep_merge!(parameters: parameters) if parameters.present?
|
22
|
-
|
22
|
+
controls.each do |control|
|
23
|
+
csf_params.deep_merge!(control.to_csf_params)
|
24
|
+
end
|
23
25
|
csf_params
|
24
26
|
end
|
25
27
|
|
26
28
|
def values_from_params(params)
|
27
|
-
|
28
|
-
value =
|
29
|
-
value =
|
30
|
-
[
|
29
|
+
controls.map do |control|
|
30
|
+
value = control.value_from_param(params[control.param])
|
31
|
+
value = control.value if value.nil? # nil only not falsey
|
32
|
+
[control.param, value]
|
31
33
|
end.to_h
|
32
34
|
end
|
33
35
|
|
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.8.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: 2021-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: view_component
|
@@ -100,42 +100,42 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '1.9'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
110
|
+
version: '1.9'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rubocop-rails
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 2.
|
117
|
+
version: 2.9.1
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 2.
|
124
|
+
version: 2.9.1
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: rubocop-rspec
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '1
|
131
|
+
version: '2.1'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '1
|
138
|
+
version: '2.1'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: simplecov
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: 0.18.5
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: simplecov-console
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.9'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0.9'
|
153
167
|
description: Generate Storybook CSF JSON for rendering Rails View Components in Storybook
|
154
168
|
email:
|
155
169
|
- 328224+jonspalmer@users.noreply.github.com
|
@@ -162,18 +176,20 @@ files:
|
|
162
176
|
- app/controllers/view_component/storybook/stories_controller.rb
|
163
177
|
- app/views/view_component/storybook/stories/show.html.erb
|
164
178
|
- lib/view_component/storybook.rb
|
179
|
+
- lib/view_component/storybook/controls.rb
|
180
|
+
- lib/view_component/storybook/controls/array_config.rb
|
181
|
+
- lib/view_component/storybook/controls/boolean_config.rb
|
182
|
+
- lib/view_component/storybook/controls/color_config.rb
|
183
|
+
- lib/view_component/storybook/controls/control_config.rb
|
184
|
+
- lib/view_component/storybook/controls/date_config.rb
|
185
|
+
- lib/view_component/storybook/controls/number_config.rb
|
186
|
+
- lib/view_component/storybook/controls/object_config.rb
|
187
|
+
- lib/view_component/storybook/controls/options_config.rb
|
188
|
+
- lib/view_component/storybook/controls/text_config.rb
|
165
189
|
- lib/view_component/storybook/dsl.rb
|
166
|
-
- lib/view_component/storybook/dsl/
|
190
|
+
- lib/view_component/storybook/dsl/controls_dsl.rb
|
167
191
|
- lib/view_component/storybook/dsl/story_dsl.rb
|
168
192
|
- lib/view_component/storybook/engine.rb
|
169
|
-
- lib/view_component/storybook/knobs.rb
|
170
|
-
- lib/view_component/storybook/knobs/array_config.rb
|
171
|
-
- lib/view_component/storybook/knobs/date_config.rb
|
172
|
-
- lib/view_component/storybook/knobs/knob_config.rb
|
173
|
-
- lib/view_component/storybook/knobs/number_config.rb
|
174
|
-
- lib/view_component/storybook/knobs/object_config.rb
|
175
|
-
- lib/view_component/storybook/knobs/options_config.rb
|
176
|
-
- lib/view_component/storybook/knobs/simple_config.rb
|
177
193
|
- lib/view_component/storybook/stories.rb
|
178
194
|
- lib/view_component/storybook/story_config.rb
|
179
195
|
- lib/view_component/storybook/tasks/write_stories_json.rake
|
@@ -193,7 +209,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
193
209
|
requirements:
|
194
210
|
- - ">="
|
195
211
|
- !ruby/object:Gem::Version
|
196
|
-
version: 2.
|
212
|
+
version: 2.4.0
|
197
213
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
198
214
|
requirements:
|
199
215
|
- - ">="
|
@@ -1,81 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ViewComponent
|
4
|
-
module Storybook
|
5
|
-
module Dsl
|
6
|
-
class KnobsDsl
|
7
|
-
attr_reader :component, :knobs
|
8
|
-
|
9
|
-
def initialize(component)
|
10
|
-
@component = component
|
11
|
-
@knobs = []
|
12
|
-
end
|
13
|
-
|
14
|
-
def text(param, value, group_id: nil, name: nil)
|
15
|
-
knobs << Knobs::SimpleConfig.new(:text, component, param, value, group_id: group_id, name: name)
|
16
|
-
end
|
17
|
-
|
18
|
-
def boolean(param, value, group_id: nil, name: nil)
|
19
|
-
knobs << Knobs::SimpleConfig.new(:boolean, component, param, value, group_id: group_id, name: name)
|
20
|
-
end
|
21
|
-
|
22
|
-
def number(param, value, options = {}, group_id: nil, name: nil)
|
23
|
-
knobs << Knobs::NumberConfig.new(component, param, value, options, group_id: group_id, name: name)
|
24
|
-
end
|
25
|
-
|
26
|
-
def color(param, value, group_id: nil, name: nil)
|
27
|
-
knobs << Knobs::SimpleConfig.new(:color, component, param, value, group_id: group_id, name: name)
|
28
|
-
end
|
29
|
-
|
30
|
-
def object(param, value, group_id: nil, name: nil)
|
31
|
-
knobs << Knobs::ObjectConfig.new(component, param, value, group_id: group_id, name: name)
|
32
|
-
end
|
33
|
-
|
34
|
-
def select(param, options, value, group_id: nil, name: nil)
|
35
|
-
knobs << Knobs::OptionsConfig.new(:select, component, param, options, value, group_id: group_id, name: name)
|
36
|
-
end
|
37
|
-
|
38
|
-
def radios(param, options, value, group_id: nil, name: nil)
|
39
|
-
knobs << Knobs::OptionsConfig.new(:radios, component, param, options, value, group_id: group_id, name: name)
|
40
|
-
end
|
41
|
-
|
42
|
-
def array(param, value, separator = ",", group_id: nil, name: nil)
|
43
|
-
knobs << Knobs::ArrayConfig.new(component, param, value, separator, group_id: group_id, name: name)
|
44
|
-
end
|
45
|
-
|
46
|
-
def date(param, value, group_id: nil, name: nil)
|
47
|
-
knobs << Knobs::DateConfig.new(component, param, value, group_id: group_id, name: name)
|
48
|
-
end
|
49
|
-
|
50
|
-
def respond_to_missing?(_method)
|
51
|
-
true
|
52
|
-
end
|
53
|
-
|
54
|
-
def method_missing(method, *args)
|
55
|
-
value = args.first
|
56
|
-
knob_method = case value
|
57
|
-
when Date
|
58
|
-
:date
|
59
|
-
when Array
|
60
|
-
:array
|
61
|
-
when Hash
|
62
|
-
:object
|
63
|
-
when Numeric
|
64
|
-
:number
|
65
|
-
when TrueClass, FalseClass
|
66
|
-
:boolean
|
67
|
-
when String
|
68
|
-
:text
|
69
|
-
end
|
70
|
-
if knob_method
|
71
|
-
send(knob_method, method, *args)
|
72
|
-
else
|
73
|
-
super
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
Knobs = ViewComponent::Storybook::Knobs
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ViewComponent
|
4
|
-
module Storybook
|
5
|
-
module Knobs
|
6
|
-
class KnobConfig
|
7
|
-
include ActiveModel::Validations
|
8
|
-
|
9
|
-
attr_reader :component, :param, :value, :name, :group_id
|
10
|
-
|
11
|
-
validates :component, :param, presence: true
|
12
|
-
validates :param, inclusion: { in: ->(knob_config) { knob_config.component_params } }, unless: -> { component.nil? }
|
13
|
-
|
14
|
-
def initialize(component, param, value, name: nil, group_id: nil)
|
15
|
-
@component = component
|
16
|
-
@param = param
|
17
|
-
@value = value
|
18
|
-
@name = name || param.to_s.humanize.titlecase
|
19
|
-
@group_id = group_id
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_csf_params
|
23
|
-
validate!
|
24
|
-
params = { type: type, param: param, name: name, value: value }
|
25
|
-
params[:group_id] = group_id if group_id
|
26
|
-
params
|
27
|
-
end
|
28
|
-
|
29
|
-
def value_from_param(param)
|
30
|
-
param
|
31
|
-
end
|
32
|
-
|
33
|
-
def component_params
|
34
|
-
@component_params ||= component && component.instance_method(:initialize).parameters.map(&:last)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ViewComponent
|
4
|
-
module Storybook
|
5
|
-
module Knobs
|
6
|
-
class NumberConfig < KnobConfig
|
7
|
-
attr_reader :options
|
8
|
-
|
9
|
-
validates :value, presence: true
|
10
|
-
|
11
|
-
def initialize(component, param, value, options = {}, name: nil, group_id: nil)
|
12
|
-
super(component, param, value, name: name, group_id: group_id)
|
13
|
-
@options = options
|
14
|
-
end
|
15
|
-
|
16
|
-
def type
|
17
|
-
:number
|
18
|
-
end
|
19
|
-
|
20
|
-
def to_csf_params
|
21
|
-
params = super
|
22
|
-
params[:options] = options unless options.empty?
|
23
|
-
params
|
24
|
-
end
|
25
|
-
|
26
|
-
def value_from_param(param)
|
27
|
-
if param.is_a?(String) && param.present?
|
28
|
-
(param.to_f % 1) > 0 ? param.to_f : param.to_i
|
29
|
-
else
|
30
|
-
super(param)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ViewComponent
|
4
|
-
module Storybook
|
5
|
-
module Knobs
|
6
|
-
class OptionsConfig < KnobConfig
|
7
|
-
TYPES = %i[select radios].freeze
|
8
|
-
|
9
|
-
attr_reader :type, :options
|
10
|
-
|
11
|
-
validates :value, :type, :options, presence: true
|
12
|
-
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
13
|
-
validates :value, inclusion: { in: ->(config) { config.options.values } }, unless: -> { options.nil? || value.nil? }
|
14
|
-
|
15
|
-
def initialize(type, component, param, options, default_value, name: nil, group_id: nil)
|
16
|
-
super(component, param, default_value, name: name, group_id: group_id)
|
17
|
-
@type = type
|
18
|
-
@options = options
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_csf_params
|
22
|
-
super.merge(options: options)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ViewComponent
|
4
|
-
module Storybook
|
5
|
-
module Knobs
|
6
|
-
class SimpleConfig < KnobConfig
|
7
|
-
TYPES = %i[text boolean color].freeze
|
8
|
-
BOOLEAN_VALUES = [true, false].freeze
|
9
|
-
|
10
|
-
attr_reader :type
|
11
|
-
|
12
|
-
validates :value, presence: true, unless: -> { type == :boolean }
|
13
|
-
validates :value, inclusion: { in: BOOLEAN_VALUES }, if: -> { type == :boolean }
|
14
|
-
|
15
|
-
validates :type, presence: true
|
16
|
-
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
|
17
|
-
|
18
|
-
def initialize(type, component, param, value, name: nil, group_id: nil)
|
19
|
-
super(component, param, value, name: name, group_id: group_id)
|
20
|
-
@type = type
|
21
|
-
end
|
22
|
-
|
23
|
-
def value_from_param(param)
|
24
|
-
if type == :boolean && param.is_a?(String) && param.present?
|
25
|
-
case param
|
26
|
-
when "true"
|
27
|
-
true
|
28
|
-
when "false"
|
29
|
-
false
|
30
|
-
end
|
31
|
-
else
|
32
|
-
super(param)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|