I like to watch ice_hockey, basketball, and baseball
+
My favorite food is hot_dog
+
I'm feeling sad
+
Other things about me {"hair":"Blonde","eyes":"Green","weight":"175"}
+
+ HTML
+
+ expect(body_div).to eq(expected_html)
+ end
+
+ it "renders the compoent with supplied parameters" do
+ get "/rails/view_components/demo/button_component/short_button", params: { button_text: "My Button" }
+
+ expect(response.body).to have_button(text: "My Button")
+ end
+
+ it "renders a compoent with custom controls" do
+ get "/rails/view_components/custom_control/custom_text", params: { greeting: "Hello", name: "Nemo" }
+
+ expect(response.body).to have_button(text: "Hello Nemo")
+ end
+
+ it "renders a compoent with custom controls for rest args" do
+ get "/rails/view_components/custom_control/custom_rest_args",
+ params: {
+ verb_one: "Heavy",
+ noun_one: "Rock",
+ verb_two: "Light",
+ noun_two: "Feather",
+ }
+
+ expect(response.body).to have_selector("p", text: "Heavy Rock")
+ expect(response.body).to have_selector("p", text: "Light Feather")
+ end
+
+ xit "renders a slotable_v2 component with default values" do
+ get "/rails/view_components/slotable_v2/default",
+ params: {}
+
+ expect(response.body).to have_selector(".card.mt-4")
+
+ expect(response.body).to have_selector(".title", text: "This is my title!")
+
+ expect(response.body).to have_selector(".subtitle", text: "This is my subtitle!")
+
+ expect(response.body).to have_selector(".tab", text: "Tab A")
+ expect(response.body).to have_selector(".tab", text: "Tab B")
+
+ expect(response.body).to have_selector(".item", count: 3)
+ expect(response.body).to have_selector(".item.highlighted", count: 1)
+ expect(response.body).to have_selector(".item.normal", count: 2)
+
+ expect(response.body).to have_selector(".footer.text-blue")
+ end
+
+ xit "renders a slotable_v2 component with params values" do
+ get "/rails/view_components/slotable_v2/default",
+ params: {
+ classes: "mb-6",
+ subtitle__content: "Subtitle Override!",
+ tab2__content: "Tab 2",
+ item2__highlighted: "false",
+ footer__classes: "text-green"
+ }
+
+ expect(response.body).to have_selector(".card.mb-6")
+
+ expect(response.body).to have_selector(".title", text: "This is my title!")
+
+ expect(response.body).to have_selector(".subtitle", text: "Subtitle Override!")
+
+ expect(response.body).to have_selector(".tab", text: "Tab A")
+ expect(response.body).to have_selector(".tab", text: "Tab 2")
+
+ expect(response.body).to have_selector(".item", count: 3)
+ expect(response.body).to have_selector(".item.highlighted", count: 0)
+ expect(response.body).to have_selector(".item.normal", count: 3)
+
+ expect(response.body).to have_selector(".footer.text-green")
+ end
+
+ it "ignores query params that don't match the the compoents args" do
+ get "/rails/view_components/demo/button_component/short_button", params: { button_text: "My Button", junk: true }
+
+ expect(response.body).to have_button(text: "My Button")
+ end
+
+ it "raises ActionNotFound error for stories that don't exist" do
+ expect { get "/rails/view_components/missing_component/short_button" }.to raise_exception(AbstractController::ActionNotFound)
+ end
+
+ it "raises ActionNotFound error story that doesn't exist" do
+ expect { get "/rails/view_components/demo/button_component/junk" }.to raise_exception(NameError)
+ end
+
+ it "returns 200 for a stories index" do
+ get "/rails/view_components/demo/button_component"
+
+ expect(response).to have_http_status(:ok)
+ end
+
+ describe "component content" do
+ it "renders the component string content" do
+ get "/rails/view_components/content_component/with_string_content"
+
+ expect(response.body).to have_selector("h1", text: "Hello World!")
+ end
+
+ it "renders the component control content" do
+ get "/rails/view_components/content_component/with_control_content"
+
+ expect(response.body).to include("
Hello World!
")
+ end
+
+ it "renders the component control content overriden by params" do
+ get "/rails/view_components/content_component/with_control_content", params: { content: "Hi!" }
+
+ expect(response.body).to include("
I like to watch ice_hockey, basketball, and baseball
-
My favorite food is hot_dog
-
I'm feeling sad
-
Other things about me {"hair":"Blonde","eyes":"Green","weight":"175"}
-
- HTML
-
- expect(body_div).to eq(expected_html)
- end
-
- it "renders the compoent with supplied parameters" do
- get "/rails/stories/demo/button_component/short_button", params: { button_text: "My Button" }
-
- expect(response.body).to have_button(text: "My Button")
- end
-
- it "renders a compoent with custom controls" do
- get "/rails/stories/custom_control/custom_text", params: { button_text__greeting: "Hello", button_text__name: "Nemo" }
-
- expect(response.body).to have_button(text: "Hello Nemo")
- end
-
- it "renders a compoent with custom controls for rest args" do
- get "/rails/stories/custom_control/custom_rest_args",
- params: {
- items0__verb: "Heavy",
- items0__noun: "Rock",
- items1__verb: "Light",
- items1__noun: "Feather",
- }
-
- expect(response.body).to have_selector("p", text: "Heavy Rock")
- expect(response.body).to have_selector("p", text: "Light Feather")
- end
-
- it "renders a slotable_v2 component with default values" do
- get "/rails/stories/slotable_v2/default",
- params: {}
-
- expect(response.body).to have_selector(".card.mt-4")
-
- expect(response.body).to have_selector(".title", text: "This is my title!")
-
- expect(response.body).to have_selector(".subtitle", text: "This is my subtitle!")
-
- expect(response.body).to have_selector(".tab", text: "Tab A")
- expect(response.body).to have_selector(".tab", text: "Tab B")
-
- expect(response.body).to have_selector(".item", count: 3)
- expect(response.body).to have_selector(".item.highlighted", count: 1)
- expect(response.body).to have_selector(".item.normal", count: 2)
-
- expect(response.body).to have_selector(".footer.text-blue")
- end
-
- it "renders a slotable_v2 component with params values" do
- get "/rails/stories/slotable_v2/default",
- params: {
- classes: "mb-6",
- subtitle__content: "Subtitle Override!",
- tab2__content: "Tab 2",
- item2__highlighted: "false",
- footer__classes: "text-green"
- }
-
- expect(response.body).to have_selector(".card.mb-6")
-
- expect(response.body).to have_selector(".title", text: "This is my title!")
-
- expect(response.body).to have_selector(".subtitle", text: "Subtitle Override!")
-
- expect(response.body).to have_selector(".tab", text: "Tab A")
- expect(response.body).to have_selector(".tab", text: "Tab 2")
-
- expect(response.body).to have_selector(".item", count: 3)
- expect(response.body).to have_selector(".item.highlighted", count: 0)
- expect(response.body).to have_selector(".item.normal", count: 3)
-
- expect(response.body).to have_selector(".footer.text-green")
- end
-
- it "ignores query params that don't match the the compoents args" do
- get "/rails/stories/demo/button_component/short_button", params: { button_text: "My Button", junk: true }
-
- expect(response.body).to have_button(text: "My Button")
- end
-
- it "returns 404 for a stories that don't exist" do
- get "/rails/stories/missing_component/short_button"
-
- expect(response).to have_http_status(:not_found)
- end
-
- it "returns 404 for a story that doesn't exist" do
- get "/rails/stories/demo/button_component/junk"
-
- expect(response).to have_http_status(:not_found)
- end
-
- it "returns 404 for a missing story param" do
- get "/rails/stories/demo/button_component"
-
- expect(response).to have_http_status(:not_found)
- end
-
- describe "component content" do
- it "renders the component string content" do
- get "/rails/stories/content_component/with_string_content"
-
- expect(response.body).to have_selector("h1", text: "Hello World!")
- end
-
- it "renders the component control content" do
- get "/rails/stories/content_component/with_control_content"
-
- expect(response.body).to include("
Hello World!
")
- end
-
- it "renders the component block content" do
- get "/rails/stories/content_component/with_block_content"
-
- expect(response.body).to have_selector("h1", text: "Hello World!")
- end
-
- it "renders the component block content with helper" do
- get "/rails/stories/content_component/with_helper_content"
-
- expect(response.body).to have_css("h1 a[href='#']", text: "Hello World!")
- end
-
- it "renders the component content with constructor" do
- get "/rails/stories/content_component/with_constructor_content"
-
- expect(response.body).to have_selector("h1", text: "Hello World!")
- end
- end
-
- describe "layout" do
- it "defaults to the application layout" do
- get "/rails/stories/demo/button_component/short_button"
-
- expect(response.body).to have_title("Stories Dummy App")
- end
-
- it "allows stories to set the layout" do
- get "/rails/stories/layout/default"
-
- expect(response.body).to have_title( "Stories Dummy App - Admin")
- end
-
- it "allows story to override the stories layout" do
- get "/rails/stories/layout/mobile_layout"
-
- expect(response.body).to have_title("Stories Dummy App - Mobile")
- end
-
- it "allows story to override with no layout" do
- get "/rails/stories/layout/no_layout"
-
- expect(response.body).to eq("")
- end
-
- it "allows stories to set no layout" do
- get "/rails/stories/no_layout/default"
-
- expect(response.body).to eq("")
- end
-
- it "allows story to override no layout with a layout" do
- get "/rails/stories/no_layout/mobile_layout"
-
- expect(response.body).to have_title("Stories Dummy App - Mobile")
- end
- end
-end
diff --git a/spec/view_component/storybook/stories_route_spec.rb b/spec/view_component/storybook/stories_route_spec.rb
deleted file mode 100644
index f20a0ab..0000000
--- a/spec/view_component/storybook/stories_route_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "ViewComponent::Storybook.stories_route", type: :request do
- around(:all) do |example|
- config = Rails.application.config.view_component_storybook
-
- old_route = config.stories_route
- config.stories_route = "/stories"
- app.reloader.reload!
-
- example.run
-
- config.stories_route = old_route
- app.reloader.reload!
- end
-
- it "returns ok" do
- get "/stories/content_component/with_string_content"
-
- expect(response).to have_http_status(:ok)
- end
-end
From 41c5ffc9a6eca26129416bd96bd56809132e1d49 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 17 Dec 2022 15:59:39 -0500
Subject: [PATCH 06/35] cleanup
---
lib/view_component/storybook/controls.rb | 1 -
.../storybook/controls/control_config.rb | 4 ---
.../storybook/controls/controls_collection.rb | 32 -------------------
.../storybook/controls/controls_helpers.rb | 4 +--
lib/view_component/storybook/engine.rb | 6 ++--
lib/view_component/storybook/stories.rb | 2 +-
.../storybook/stories_config.rb | 2 +-
.../stories/demo/heading_component_stories.rb | 6 +---
.../test/components/stories/layout_stories.rb | 2 +-
.../components/stories/parameters_stories.rb | 2 +-
spec/support/controls_examples.rb | 8 -----
....rb => view_components_controller_spec.rb} | 0
12 files changed, 8 insertions(+), 61 deletions(-)
delete mode 100644 lib/view_component/storybook/controls/controls_collection.rb
rename spec/view_component/storybook/{previews_controller_spec.rb => view_components_controller_spec.rb} (100%)
diff --git a/lib/view_component/storybook/controls.rb b/lib/view_component/storybook/controls.rb
index bf42430..89963cb 100644
--- a/lib/view_component/storybook/controls.rb
+++ b/lib/view_component/storybook/controls.rb
@@ -20,7 +20,6 @@ module Controls
autoload :ObjectConfig
autoload :CustomConfig
autoload :ControlsHelpers
- autoload :ControlsCollection
end
end
end
diff --git a/lib/view_component/storybook/controls/control_config.rb b/lib/view_component/storybook/controls/control_config.rb
index ec42329..a4eee5f 100644
--- a/lib/view_component/storybook/controls/control_config.rb
+++ b/lib/view_component/storybook/controls/control_config.rb
@@ -40,10 +40,6 @@ def param(new_param = nil)
self
end
- def prefix_param(prefix)
- param("#{prefix}__#{@param}".to_sym)
- end
-
def to_csf_params
# :nocov:
raise NotImplementedError
diff --git a/lib/view_component/storybook/controls/controls_collection.rb b/lib/view_component/storybook/controls/controls_collection.rb
deleted file mode 100644
index 29cb837..0000000
--- a/lib/view_component/storybook/controls/controls_collection.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- module Controls
- class ControlsCollection
- attr_reader :controls_by_story, :story_default_values
-
- def initialize(story_methods)
- @controls_by_story = story_methods.to_h { |method| [method.name, {}] }
-
- class_string = File.read(story_methods.first.source_location[0])
- # code_object = YARD.parse_string(class_string)
- # # puts "code_object: #{code_object}"
- # # puts "code_object.meths: #{code_object.meths}"
- # puts "YARD::Registry.all: #{YARD::Registry.all(:class)}"
-
- # parsed = Parser::CurrentRuby.parse(class_string)
- # p "Parser: #{parsed}"
- # p parsed.methods
-
- story_methods.each do |method|
- Rails.logger.debug { "method.source_location: #{method.source_location}" }
- source_location = method.source_location
- # File.readlines(source_location[0].each {|line| puts line}
- Rails.logger.debug { "method def: #{File.readlines(source_location[0])[source_location[1] - 1]}" }
- end
- end
- end
- end
- end
-end
diff --git a/lib/view_component/storybook/controls/controls_helpers.rb b/lib/view_component/storybook/controls/controls_helpers.rb
index 9dd2dac..b76dc0c 100644
--- a/lib/view_component/storybook/controls/controls_helpers.rb
+++ b/lib/view_component/storybook/controls/controls_helpers.rb
@@ -35,7 +35,7 @@ def control(param, as:, default:, name: nil, description: nil, **opts)
Controls::NumberConfig.new(:range, default, param: param, name: name, description: description, **opts)
when :color
Controls::ColorConfig.new(default, param: param, name: name, description: description, **opts)
- when :object
+ when :object, :array
Controls::ObjectConfig.new(default, param: param, name: name, description: description, **opts)
when :select
options = opts.delete(:options)
@@ -57,8 +57,6 @@ def control(param, as:, default:, name: nil, description: nil, **opts)
Controls::MultiOptionsConfig.new(:'inline-check', options, default, param: param, name: name, description: description, **opts)
when :date
Controls::DateConfig.new(default, param: param, name: name, description: description, **opts)
- when :array
- Controls::ObjectConfig.new(default, param: param, name: name, description: description, **opts)
else
raise "Unknonwn control type '#{as}'"
end
diff --git a/lib/view_component/storybook/engine.rb b/lib/view_component/storybook/engine.rb
index 9e70a0f..3c672d0 100644
--- a/lib/view_component/storybook/engine.rb
+++ b/lib/view_component/storybook/engine.rb
@@ -14,9 +14,7 @@ class Engine < Rails::Engine
options.show_stories = Rails.env.development? if options.show_stories.nil?
options.stories_route ||= "/rails/stories"
- if options.show_stories && (defined?(Rails.root) && Dir.exist?(
- "#{Rails.root}/test/components/stories"
- ))
+ if options.show_stories && (defined?(Rails.root) && Rails.root.join("test/components/stories").exist?)
options.stories_paths << Rails.root.join("test/components/stories").to_s
end
@@ -62,7 +60,7 @@ class Engine < Rails::Engine
end
def parser
- @_parser ||= StoriesParser.new(ViewComponent::Storybook.stories_paths) # , Engine.tags)
+ @parser ||= StoriesParser.new(ViewComponent::Storybook.stories_paths) # , Engine.tags)
end
class << self
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 55d9b51..4155844 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -60,7 +60,7 @@ def render_args(story_name, params: {})
story_config = find_story_config(story_name)
control_parsed_params = provided_params.to_h do |param, value|
- control = story_config.controls.find { |control| control.param == param }
+ control = story_config.controls.find { |c| c.param == param }
if control
[param, control.value_from_params(params)]
else
diff --git a/lib/view_component/storybook/stories_config.rb b/lib/view_component/storybook/stories_config.rb
index 333883c..c114ccd 100644
--- a/lib/view_component/storybook/stories_config.rb
+++ b/lib/view_component/storybook/stories_config.rb
@@ -4,7 +4,7 @@ module ViewComponent
module Storybook
class StoriesConfig
delegate :title, :parameters, :stories_name, to: :stories_class
- attr_reader :story_configs, :stories_class, :stories_json_path
+ attr_reader :stories_class, :stories_json_path
def initialize(code_object)
@code_object = code_object
diff --git a/spec/dummy/test/components/stories/demo/heading_component_stories.rb b/spec/dummy/test/components/stories/demo/heading_component_stories.rb
index 225d65e..537a836 100644
--- a/spec/dummy/test/components/stories/demo/heading_component_stories.rb
+++ b/spec/dummy/test/components/stories/demo/heading_component_stories.rb
@@ -4,14 +4,10 @@ module Demo
class HeadingComponentStories < ViewComponent::Storybook::Stories
title 'Heading Component'
- # controls do
- # text(:heading_text, "Heading")
- # end
-
control :heading_text, as: :text, default: "Heading"
def default(heading_text: "Heading")
- render HeadingComponent.new(heading_text: button_text)
+ render HeadingComponent.new(heading_text: heading_text)
end
end
end
diff --git a/spec/dummy/test/components/stories/layout_stories.rb b/spec/dummy/test/components/stories/layout_stories.rb
index 15a6e22..ea38d39 100644
--- a/spec/dummy/test/components/stories/layout_stories.rb
+++ b/spec/dummy/test/components/stories/layout_stories.rb
@@ -4,7 +4,7 @@ class LayoutStories < ViewComponent::Storybook::Stories
layout "admin"
control :button_text, as: :text, default: "OK"
-
+
def default(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
end
diff --git a/spec/dummy/test/components/stories/parameters_stories.rb b/spec/dummy/test/components/stories/parameters_stories.rb
index 9dbf24f..42fdeaa 100644
--- a/spec/dummy/test/components/stories/parameters_stories.rb
+++ b/spec/dummy/test/components/stories/parameters_stories.rb
@@ -10,7 +10,7 @@ def stories_parameters(button_text: "OK")
end
# @parameters {size: :large, color: :red}
- def stories_parameters(button_text: "OK")
+ def stories_parameter_override(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
end
diff --git a/spec/support/controls_examples.rb b/spec/support/controls_examples.rb
index 7d2ab5c..0ed5799 100644
--- a/spec/support/controls_examples.rb
+++ b/spec/support/controls_examples.rb
@@ -65,14 +65,6 @@
end
end
- describe "#prefix_param" do
- it "prefixes the param" do
- subject.param(:name).prefix_param(:author)
-
- expect(subject.param).to eq(:author__name)
- end
- end
-
describe "#valid?" do
it "true for param that the component supports" do
expect(subject.valid?).to be(true)
diff --git a/spec/view_component/storybook/previews_controller_spec.rb b/spec/view_component/storybook/view_components_controller_spec.rb
similarity index 100%
rename from spec/view_component/storybook/previews_controller_spec.rb
rename to spec/view_component/storybook/view_components_controller_spec.rb
From 8e9e75d4b5c7195d16e183097220b37298efcc2f Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 17 Dec 2022 17:16:35 -0500
Subject: [PATCH 07/35] Fix the controls api
---
.../storybook/controls/base_options_config.rb | 15 +--
.../storybook/controls/boolean_config.rb | 2 +-
.../storybook/controls/color_config.rb | 4 +-
.../storybook/controls/control_config.rb | 43 ++++-----
.../storybook/controls/controls_helpers.rb | 93 +++----------------
.../storybook/controls/date_config.rb | 10 +-
.../controls/multi_options_config.rb | 10 +-
.../storybook/controls/number_config.rb | 4 +-
.../storybook/controls/options_config.rb | 4 +-
.../controls/simple_control_config.rb | 11 +--
spec/support/controls_examples.rb | 50 ++--------
.../storybook/controls/boolean_config_spec.rb | 2 +-
.../storybook/controls/color_config_spec.rb | 4 +-
.../controls/controls_helpers_spec.rb | 60 +++++++-----
.../storybook/controls/date_config_spec.rb | 6 +-
.../controls/multi_options_config_spec.rb | 26 +++---
.../storybook/controls/number_config_spec.rb | 8 +-
.../storybook/controls/object_config_spec.rb | 2 +-
.../storybook/controls/options_config_spec.rb | 16 ++--
.../storybook/controls/text_config_spec.rb | 2 +-
20 files changed, 136 insertions(+), 236 deletions(-)
diff --git a/lib/view_component/storybook/controls/base_options_config.rb b/lib/view_component/storybook/controls/base_options_config.rb
index a821e22..2f89ba7 100644
--- a/lib/view_component/storybook/controls/base_options_config.rb
+++ b/lib/view_component/storybook/controls/base_options_config.rb
@@ -8,12 +8,11 @@ class BaseOptionsConfig < SimpleControlConfig
validates :type, :options, presence: true
- def initialize(type, options, default_value, labels: nil, param: nil, name: nil, description: nil, **opts)
- super(default_value, param: param, name: name, description: description, **opts)
+ def initialize(param, type, options, default: , labels: nil, name: nil, description: nil, **opts)
+ super(param, default: default, name: name, description: description, **opts)
@type = type
@options = options
@labels = labels
- normalize_options
end
def to_csf_params
@@ -25,16 +24,6 @@ def to_csf_params
def csf_control_params
labels.nil? ? super : super.merge(labels: labels)
end
-
- def normalize_options
- return unless options.is_a?(Hash)
-
- warning = "Hash options is deprecated and will be removed in v1.0.0. Use array options and `labels` instead."
- ActiveSupport::Deprecation.warn(warning)
-
- @labels = options.invert
- @options = options.values
- end
end
end
end
diff --git a/lib/view_component/storybook/controls/boolean_config.rb b/lib/view_component/storybook/controls/boolean_config.rb
index fcc361e..ac1f849 100644
--- a/lib/view_component/storybook/controls/boolean_config.rb
+++ b/lib/view_component/storybook/controls/boolean_config.rb
@@ -6,7 +6,7 @@ module Controls
class BooleanConfig < SimpleControlConfig
BOOLEAN_VALUES = [true, false].freeze
- validates :default_value, inclusion: { in: BOOLEAN_VALUES }, unless: -> { default_value.nil? }
+ validates :default, inclusion: { in: BOOLEAN_VALUES }, unless: -> { default.nil? }
def type
:boolean
diff --git a/lib/view_component/storybook/controls/color_config.rb b/lib/view_component/storybook/controls/color_config.rb
index ec2dc86..b9dbf4c 100644
--- a/lib/view_component/storybook/controls/color_config.rb
+++ b/lib/view_component/storybook/controls/color_config.rb
@@ -6,8 +6,8 @@ module Controls
class ColorConfig < SimpleControlConfig
attr_reader :preset_colors
- def initialize(default_value, preset_colors: nil, param: nil, name: nil, description: nil, **opts)
- super(default_value, param: param, name: name, description: description, **opts)
+ def initialize(param, default: , preset_colors: nil, name: nil, description: nil, **opts)
+ super(param, default: default, name: name, description: description, **opts)
@preset_colors = preset_colors
end
diff --git a/lib/view_component/storybook/controls/control_config.rb b/lib/view_component/storybook/controls/control_config.rb
index a4eee5f..657fc89 100644
--- a/lib/view_component/storybook/controls/control_config.rb
+++ b/lib/view_component/storybook/controls/control_config.rb
@@ -8,37 +8,38 @@ class ControlConfig
validates :param, presence: true
- attr_reader :opts
+ attr_reader :param, :default, :name, :description, :opts
- def initialize(param: nil, name: nil, description: nil, **opts)
+ def initialize(param, default: , name: nil, description: nil, **opts)
@param = param
- @name = name
+ @default = default
+ @name = name || param.to_s.humanize.titlecase
@description = description
@opts = opts
end
- def name(new_name = nil)
- if new_name.nil?
- @name ||= param.to_s.humanize.titlecase
- else
- @name = new_name
- self
- end
- end
+ # def name(new_name = nil)
+ # if new_name.nil?
+ # @name ||= param.to_s.humanize.titlecase
+ # else
+ # @name = new_name
+ # self
+ # end
+ # end
- def description(new_description = nil)
- return @description if new_description.nil?
+ # def description(new_description = nil)
+ # return @description if new_description.nil?
- @description = new_description
- self
- end
+ # @description = new_description
+ # self
+ # end
- def param(new_param = nil)
- return @param if new_param.nil?
+ # def param(new_param = nil)
+ # return @param if new_param.nil?
- @param = new_param
- self
- end
+ # @param = new_param
+ # self
+ # end
def to_csf_params
# :nocov:
diff --git a/lib/view_component/storybook/controls/controls_helpers.rb b/lib/view_component/storybook/controls/controls_helpers.rb
index b76dc0c..28c8f9f 100644
--- a/lib/view_component/storybook/controls/controls_helpers.rb
+++ b/lib/view_component/storybook/controls/controls_helpers.rb
@@ -26,109 +26,42 @@ def inherited(other)
def control(param, as:, default:, name: nil, description: nil, **opts)
controls << case as
when :text
- Controls::TextConfig.new(default, param: param, name: name, description: description, **opts)
+ Controls::TextConfig.new(param, default: default, name: name, description: description, **opts)
when :boolean
- Controls::BooleanConfig.new(default, param: param, name: name, description: description, **opts)
+ Controls::BooleanConfig.new(param, default: default, name: name, description: description, **opts)
when :number
- Controls::NumberConfig.new(:number, default, param: param, name: name, description: description, **opts)
+ Controls::NumberConfig.new(param, :number, default: default, name: name, description: description, **opts)
when :range
- Controls::NumberConfig.new(:range, default, param: param, name: name, description: description, **opts)
+ Controls::NumberConfig.new(param, :range, default: default, name: name, description: description, **opts)
when :color
- Controls::ColorConfig.new(default, param: param, name: name, description: description, **opts)
+ Controls::ColorConfig.new(param, default: default, name: name, description: description, **opts)
when :object, :array
- Controls::ObjectConfig.new(default, param: param, name: name, description: description, **opts)
+ Controls::ObjectConfig.new(param, default: default, name: name, description: description, **opts)
when :select
options = opts.delete(:options)
- Controls::OptionsConfig.new(:select, options, default, param: param, name: name, description: description, **opts)
+ Controls::OptionsConfig.new(param, :select, options, default: default, name: name, description: description, **opts)
when :multi_select
options = opts.delete(:options)
- Controls::MultiOptionsConfig.new(:'multi-select', options, default, param: param, name: name, description: description, **opts)
+ Controls::MultiOptionsConfig.new(param, :'multi-select', options, default: default, name: name, description: description, **opts)
when :radio
options = opts.delete(:options)
- Controls::OptionsConfig.new(:radio, options, default, param: param, name: name, description: description, **opts)
+ Controls::OptionsConfig.new(param, :radio, options, default: default, name: name, description: description, **opts)
when :inline_radio
options = opts.delete(:options)
- Controls::MultiOptionsConfigptionsConfig.new(:'inline-radio', options, default, param: param, name: name, description: description, **opts)
+ Controls::OptionsConfig.new(param, :'inline-radio', options, default: default, name: name, description: description, **opts)
when :check
options = opts.delete(:options)
- Controls::MultiOptionsConfig.new(:check, options, default, param: param, name: name, description: description, **opts)
+ Controls::MultiOptionsConfig.new(param, :check, options, default: default, name: name, description: description, **opts)
when :inline_check
options = opts.delete(:options)
- Controls::MultiOptionsConfig.new(:'inline-check', options, default, param: param, name: name, description: description, **opts)
+ Controls::MultiOptionsConfig.new(param, :'inline-check', options, default: default, name: name, description: description, **opts)
when :date
- Controls::DateConfig.new(default, param: param, name: name, description: description, **opts)
+ Controls::DateConfig.new(param, default: default, name: name, description: description, **opts)
else
raise "Unknonwn control type '#{as}'"
end
end
end
-
- def text(default_value)
- Controls::TextConfig.new(default_value)
- end
-
- def boolean(default_value)
- Controls::BooleanConfig.new(default_value)
- end
-
- def number(default_value, min: nil, max: nil, step: nil)
- Controls::NumberConfig.new(:number, default_value, min: min, max: max, step: step)
- end
-
- def range(default_value, min: nil, max: nil, step: nil)
- Controls::NumberConfig.new(:range, default_value, min: min, max: max, step: step)
- end
-
- def color(default_value, preset_colors: nil)
- Controls::ColorConfig.new(default_value, preset_colors: preset_colors)
- end
-
- def object(default_value)
- Controls::ObjectConfig.new(default_value)
- end
-
- def select(options, default_value, labels: nil)
- Controls::OptionsConfig.new(:select, options, default_value, labels: labels)
- end
-
- def multi_select(options, default_value, labels: nil)
- Controls::MultiOptionsConfig.new(:'multi-select', options, default_value, labels: labels)
- end
-
- def radio(options, default_value, labels: nil)
- Controls::OptionsConfig.new(:radio, options, default_value, labels: labels)
- end
-
- def inline_radio(options, default_value, labels: nil)
- Controls::OptionsConfig.new(:'inline-radio', options, default_value, labels: labels)
- end
-
- def check(options, default_value, labels: nil)
- Controls::MultiOptionsConfig.new(:check, options, default_value, labels: labels)
- end
-
- def inline_check(options, default_value)
- Controls::MultiOptionsConfig.new(:'inline-check', options, default_value)
- end
-
- def array(default_value, separator = nil)
- ActiveSupport::Deprecation.warn("`array` `separator` argument will be removed in v1.0.0.") if separator
- Controls::ObjectConfig.new(default_value)
- end
-
- def date(default_value)
- Controls::DateConfig.new(default_value)
- end
-
- def custom(*args, **kwargs, &block)
- Controls::CustomConfig.new.with_value(*args, **kwargs, &block)
- end
-
- def klazz(value_class, *args, **kwargs)
- Controls::CustomConfig.new.with_value(*args, **kwargs) do |*a, **kwa|
- value_class.new(*a, **kwa)
- end
- end
end
end
end
diff --git a/lib/view_component/storybook/controls/date_config.rb b/lib/view_component/storybook/controls/date_config.rb
index b57bfee..0998477 100644
--- a/lib/view_component/storybook/controls/date_config.rb
+++ b/lib/view_component/storybook/controls/date_config.rb
@@ -4,8 +4,8 @@ module ViewComponent
module Storybook
module Controls
class DateConfig < SimpleControlConfig
- def initialize(default_value, param: nil, name: nil, description: nil, **opts)
- super(default_value, param: param, name: name, description: description, **opts)
+ def initialize(param, default: , name: nil, description: nil, **opts)
+ super(param, default: default, name: name, description: description, **opts)
end
def type
@@ -24,11 +24,11 @@ def value_from_params(params)
private
def csf_value
- case default_value
+ case default
when Date
- default_value.in_time_zone
+ default.in_time_zone
when Time
- default_value.iso8601
+ default.iso8601
end
end
end
diff --git a/lib/view_component/storybook/controls/multi_options_config.rb b/lib/view_component/storybook/controls/multi_options_config.rb
index ba4ac9a..8075ea3 100644
--- a/lib/view_component/storybook/controls/multi_options_config.rb
+++ b/lib/view_component/storybook/controls/multi_options_config.rb
@@ -7,10 +7,10 @@ class MultiOptionsConfig < BaseOptionsConfig
TYPES = %i[multi-select check inline-check].freeze
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
- validate :validate_default_value, unless: -> { options.nil? || default_value.nil? }
+ validate :validate_default_value, unless: -> { options.nil? || default.nil? }
- def initialize(type, options, default_value, labels: nil, param: nil, name: nil, description: nil, **opts)
- super(type, options, Array.wrap(default_value), labels: labels, param: param, name: name, description: description, **opts)
+ def initialize(param, type, options, default:, labels: nil, name: nil, description: nil, **opts)
+ super(param, type, options, default: Array.wrap(default), labels: labels, param: param, name: name, description: description, **opts)
end
def value_from_params(params)
@@ -34,11 +34,11 @@ def csf_control_params
end
def symbol_values
- @symbol_values ||= default_value.first.is_a?(Symbol)
+ @symbol_values ||= default.first.is_a?(Symbol)
end
def validate_default_value
- errors.add(:default_value, :inclusion) unless default_value.to_set <= options.to_set
+ errors.add(:default, :inclusion) unless default.to_set <= options.to_set
end
end
end
diff --git a/lib/view_component/storybook/controls/number_config.rb b/lib/view_component/storybook/controls/number_config.rb
index 748b2c6..c94acf8 100644
--- a/lib/view_component/storybook/controls/number_config.rb
+++ b/lib/view_component/storybook/controls/number_config.rb
@@ -11,8 +11,8 @@ class NumberConfig < SimpleControlConfig
validates :type, presence: true
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
- def initialize(type, default_value, min: nil, max: nil, step: nil, param: nil, name: nil, description: nil, **opts)
- super(default_value, param: param, name: name, description: description, **opts)
+ def initialize(param, type, default: , min: nil, max: nil, step: nil, name: nil, description: nil, **opts)
+ super(param, default: default, name: name, description: description, **opts)
@type = type
@min = min
@max = max
diff --git a/lib/view_component/storybook/controls/options_config.rb b/lib/view_component/storybook/controls/options_config.rb
index fbc76f5..0ad602a 100644
--- a/lib/view_component/storybook/controls/options_config.rb
+++ b/lib/view_component/storybook/controls/options_config.rb
@@ -7,7 +7,7 @@ class OptionsConfig < BaseOptionsConfig
TYPES = %i[select radio inline-radio].freeze
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
- validates :default_value, inclusion: { in: ->(config) { config.options } }, unless: -> { options.nil? || default_value.nil? }
+ validates :default, inclusion: { in: ->(config) { config.options } }, unless: -> { options.nil? || default.nil? }
def value_from_params(params)
params_value = super(params)
@@ -29,7 +29,7 @@ def csf_control_params
end
def symbol_value
- @symbol_value ||= default_value.is_a?(Symbol)
+ @symbol_value ||= default.is_a?(Symbol)
end
end
end
diff --git a/lib/view_component/storybook/controls/simple_control_config.rb b/lib/view_component/storybook/controls/simple_control_config.rb
index 297a493..3bef16d 100644
--- a/lib/view_component/storybook/controls/simple_control_config.rb
+++ b/lib/view_component/storybook/controls/simple_control_config.rb
@@ -7,11 +7,8 @@ module Controls
# A simple Control Config maps to one Storybook Control
# It has a value and pulls its value from params by key
class SimpleControlConfig < ControlConfig
- attr_accessor :default_value
-
- def initialize(default_value, param: nil, name: nil, description: nil, **opts)
- super(param: param, name: name, description: description, **opts)
- @default_value = default_value
+ def initialize(param, default: , name: nil, description: nil, **opts)
+ super(param, default: default, name: name, description: description, **opts)
end
def to_csf_params
@@ -25,7 +22,7 @@ def to_csf_params
end
def value_from_params(params)
- params.key?(param) ? params[param] : default_value
+ params.key?(param) ? params[param] : default
end
private
@@ -38,7 +35,7 @@ def type
end
def csf_value
- default_value
+ default
end
def csf_control_params
diff --git a/spec/support/controls_examples.rb b/spec/support/controls_examples.rb
index 0ed5799..2735ddb 100644
--- a/spec/support/controls_examples.rb
+++ b/spec/support/controls_examples.rb
@@ -5,17 +5,17 @@
let(:name) { nil }
let(:description) { nil }
- describe "#param" do
- it "can be set" do
- subject.param(:name)
+ # describe "#param" do
+ # it "can be set" do
+ # subject.param(:name)
- expect(subject.param).to eq(:name)
- end
+ # expect(subject.param).to eq(:name)
+ # end
- it "set returns the control" do
- expect(subject.param(:name)).to eq(subject)
- end
- end
+ # it "set returns the control" do
+ # expect(subject.param(:name)).to eq(subject)
+ # end
+ # end
describe "#name" do
it "by default is derived from the param" do
@@ -29,16 +29,6 @@
expect(subject.name).to eq("Button")
end
end
-
- it "can be set" do
- subject.name("Button")
-
- expect(subject.name).to eq("Button")
- end
-
- it "set returns the control" do
- expect(subject.name("Button")).to eq(subject)
- end
end
describe '#description' do
@@ -53,16 +43,6 @@
expect(subject.description).to eq("Text for the button")
end
end
-
- it "can be set" do
- subject.description("Text for the button")
-
- expect(subject.description).to eq("Text for the button")
- end
-
- it "set returns the control" do
- expect(subject.description("Text for the button")).to eq(subject)
- end
end
describe "#valid?" do
@@ -180,16 +160,4 @@
}
end
end
-
- context "with hash options" do
- subject { described_class.new(type, options, default_value) }
-
- let(:default_value) { default_value }
- let(:options) { { "Hot Dog" => :hot_dog, "Pizza" => :pizza } }
-
- it "converts options to labels" do
- expect(subject.options).to eq([:hot_dog, :pizza])
- expect(subject.labels).to eq(hot_dog: "Hot Dog", pizza: "Pizza")
- end
- end
end
diff --git a/spec/view_component/storybook/controls/boolean_config_spec.rb b/spec/view_component/storybook/controls/boolean_config_spec.rb
index b59bb97..c84bfec 100644
--- a/spec/view_component/storybook/controls/boolean_config_spec.rb
+++ b/spec/view_component/storybook/controls/boolean_config_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe ViewComponent::Storybook::Controls::BooleanConfig do
- subject { described_class.new(default_value, param: param, name: name, description: description) }
+ subject { described_class.new(param, default: default_value, name: name, description: description) }
let(:type) { :boolean }
diff --git a/spec/view_component/storybook/controls/color_config_spec.rb b/spec/view_component/storybook/controls/color_config_spec.rb
index 5152fe1..2d6d9b3 100644
--- a/spec/view_component/storybook/controls/color_config_spec.rb
+++ b/spec/view_component/storybook/controls/color_config_spec.rb
@@ -1,14 +1,14 @@
# frozen_string_literal: true
RSpec.describe ViewComponent::Storybook::Controls::ColorConfig do
- subject { described_class.new(default_value, param: param, name: name, description: description) }
+ subject { described_class.new(param, default: default_value, name: name, description: description) }
let(:type) { :color }
it_behaves_like "a simple controls config"
context "with :preset_color array" do
- subject { described_class.new(default_value, param: param, name: name, description: description, preset_colors: preset_colors) }
+ subject { described_class.new(param, default: default_value, name: name, description: description, preset_colors: preset_colors) }
let(:preset_colors) { %w[red green blue] }
diff --git a/spec/view_component/storybook/controls/controls_helpers_spec.rb b/spec/view_component/storybook/controls/controls_helpers_spec.rb
index 34945a5..200b895 100644
--- a/spec/view_component/storybook/controls/controls_helpers_spec.rb
+++ b/spec/view_component/storybook/controls/controls_helpers_spec.rb
@@ -3,6 +3,8 @@
RSpec.describe ViewComponent::Storybook::Controls::ControlsHelpers do
include described_class
+ subject { controls.first }
+
shared_examples "has controls attributes" do |control_attributes|
it "has expected attributes" do
expect(subject).to have_attributes(control_attributes)
@@ -10,34 +12,37 @@
end
describe "#text" do
- subject { text("Jane Doe") }
+ control :name, as: :text, default: "Jane Doe"
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::TextConfig,
- default_value: "Jane Doe"
+ param: :name,
+ default: "Jane Doe"
}
end
describe "#boolean" do
- subject { boolean(true) }
+ control :active, as: :boolean, default: true
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::BooleanConfig,
- default_value: true
+ param: :active,
+ default: true
}
end
describe "#number" do
context "with minimal args" do
- subject { number(2) }
+ control :count, as: :number, default: 2
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::NumberConfig,
+ param: :count,
type: :number,
- default_value: 2,
+ default: 2,
min: nil,
max: nil,
step: nil
@@ -45,13 +50,14 @@
end
context "with all args" do
- subject { number(2, min: 0, max: 10, step: 1) }
+ control :count, as: :number, default: 2, min: 0, max: 10, step: 1
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::NumberConfig,
+ param: :count,
type: :number,
- default_value: 2,
+ default: 2,
min: 0,
max: 10,
step: 1
@@ -61,13 +67,14 @@
describe "#range" do
context "with minimal args" do
- subject { range(2) }
+ control :count, as: :range, default: 2
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::NumberConfig,
+ param: :count,
type: :range,
- default_value: 2,
+ default: 2,
min: nil,
max: nil,
step: nil
@@ -75,13 +82,14 @@
end
context "with all args" do
- subject { range(2, min: 0, max: 10, step: 1) }
+ control :count, as: :range, default: 2, min: 0, max: 10, step: 1
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::NumberConfig,
+ param: :count,
type: :range,
- default_value: 2,
+ default: 2,
min: 0,
max: 10,
step: 1
@@ -90,52 +98,56 @@
end
describe "#color" do
- subject { color("red") }
+ control :favorite, as: :color, default: "red"
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::ColorConfig,
- default_value: "red"
+ param: :favorite,
+ default: "red"
}
end
describe "#object" do
- subject { object({ hair: "Brown", eyes: "Blue" }) }
+ control :description, as: :object, default: { hair: "Brown", eyes: "Blue" }
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::ObjectConfig,
- default_value: { hair: "Brown", eyes: "Blue" }
+ param: :description,
+ default: { hair: "Brown", eyes: "Blue" }
}
end
%w[select radio inline-radio].each do |type|
- dsl_method = type.underscore
+ control_type = type.underscore
- describe "##{dsl_method}" do
- subject { send(dsl_method, [:hot_dog, :pizza], :pizza) }
+ describe "##{control_type}" do
+ control :food, as: control_type.to_sym, options: [:hot_dog, :pizza], default: :pizza
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::OptionsConfig,
+ param: :food,
type: type.to_sym,
- default_value: :pizza,
+ default: :pizza,
options: [:hot_dog, :pizza]
}
end
end
%w[multi-select check inline-check].each do |type|
- dsl_method = type.underscore
+ control_type = type.underscore
- describe "##{dsl_method}" do
- subject { send(dsl_method, [:hot_dog, :pizza], [:pizza]) }
+ describe "##{control_type}" do
+ control :food, as: control_type.to_sym, options: [:hot_dog, :pizza], default: :pizza
include_examples "has controls attributes",
{
class: ViewComponent::Storybook::Controls::MultiOptionsConfig,
+ param: :food,
type: type.to_sym,
- default_value: [:pizza],
+ default: [:pizza],
options: [:hot_dog, :pizza]
}
end
diff --git a/spec/view_component/storybook/controls/date_config_spec.rb b/spec/view_component/storybook/controls/date_config_spec.rb
index 30c092d..c3852fc 100644
--- a/spec/view_component/storybook/controls/date_config_spec.rb
+++ b/spec/view_component/storybook/controls/date_config_spec.rb
@@ -1,16 +1,16 @@
# frozen_string_literal: true
RSpec.describe ViewComponent::Storybook::Controls::DateConfig do
- subject { described_class.new(default_value, param: param, name: name, description: description) }
+ subject { described_class.new(param, default: default_value, name: name, description: description) }
shared_examples "valid with object value" do
it "has a value" do
- expect(subject.default_value).to eq(default_value)
+ expect(subject.default).to eq(default_value)
end
it "to_csf_params should leave value alone" do
subject.to_csf_params
- expect(subject.default_value).to eq(default_value)
+ expect(subject.default).to eq(default_value)
end
it "is valid" do
diff --git a/spec/view_component/storybook/controls/multi_options_config_spec.rb b/spec/view_component/storybook/controls/multi_options_config_spec.rb
index 39f434b..56d1b99 100644
--- a/spec/view_component/storybook/controls/multi_options_config_spec.rb
+++ b/spec/view_component/storybook/controls/multi_options_config_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe ViewComponent::Storybook::Controls::MultiOptionsConfig do
described_class::TYPES.each do |type|
context "type: #{type}" do
- subject { described_class.new(type, options, default_value, labels: labels, param: param, name: name, description: description) }
+ subject { described_class.new(param, type, options, default: default_value, labels: labels, name: name, description: description) }
let(:type) { type }
let(:labels) { {} }
@@ -29,7 +29,7 @@
end
describe "#value_from_params" do
- subject { described_class.new(:check, options, defualt_value, param: :opt) }
+ subject { described_class.new(:opt, :check, options, default: defualt_value) }
context "with array options" do
let(:options) { %w[red blue yellow] }
@@ -62,32 +62,32 @@
let(:options) { %w[red blue yellow] }
it "valid with single array value" do
- subject = described_class.new(:check, options, ["blue"], param: :button_text)
+ subject = described_class.new(:button_text, :check, options, default: ["blue"])
expect(subject.valid?).to be(true)
end
it "valid with multi array value" do
- subject = described_class.new(:check, options, ["blue", "red"], param: :button_text)
+ subject = described_class.new(:button_text, :check, options, default: ["blue", "red"])
expect(subject.valid?).to be(true)
end
it "valid with non-array value" do
- subject = described_class.new(:check, options, "blue", param: :button_text)
+ subject = described_class.new(:button_text, :check, options, default: "blue")
expect(subject.valid?).to be(true)
end
- it "valid with nil default_value provided its in the options list" do
+ it "valid with nil default provided its in the options list" do
options << nil
- subject = described_class.new(:check, options, nil, param: :button_text)
+ subject = described_class.new(:button_text, :check, options, default: nil)
expect(subject.valid?).to be(true)
end
it "invalid without type" do
- subject = described_class.new(nil, options, ["blue"], param: :button_text)
+ subject = described_class.new(:button_text, nil, options, default: ["blue"])
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -95,7 +95,7 @@
end
it "invalid with unsupported type" do
- subject = described_class.new(:foo, options, ["blue"], param: :button_text)
+ subject = described_class.new(:button_text, :foo, options, default: ["blue"])
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -103,19 +103,19 @@
end
it "invalid with value not in the options list" do
- subject = described_class.new(:check, options, ["green"], param: :button_text)
+ subject = described_class.new(:button_text, :check, options, default: ["green"] )
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
- expect(subject.errors[:default_value]).to eq(["is not included in the list"])
+ expect(subject.errors[:default]).to eq(["is not included in the list"])
end
it "invalid with value partially in the options list" do
- subject = described_class.new(:check, options, ["green", "red"], param: :button_text)
+ subject = described_class.new(:button_text, :check, options, default: ["green", "red"])
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
- expect(subject.errors[:default_value]).to eq(["is not included in the list"])
+ expect(subject.errors[:default]).to eq(["is not included in the list"])
end
end
end
diff --git a/spec/view_component/storybook/controls/number_config_spec.rb b/spec/view_component/storybook/controls/number_config_spec.rb
index 6ec822b..7dda731 100644
--- a/spec/view_component/storybook/controls/number_config_spec.rb
+++ b/spec/view_component/storybook/controls/number_config_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe ViewComponent::Storybook::Controls::NumberConfig do
described_class::TYPES.each do |number_type|
context "with '#{number_type}' type" do
- subject { described_class.new(number_type, default_value, param: param, name: name, description: description) }
+ subject { described_class.new(param, number_type, default: default_value, name: name, description: description) }
it_behaves_like "a simple controls config" do
let(:type) { number_type }
@@ -20,7 +20,7 @@
end
context "with options" do
- subject { described_class.new(number_type, default_value, **number_options, param: param, name: name, description: description) }
+ subject { described_class.new(param, number_type, default: default_value, **number_options, name: name, description: description) }
let(:number_options) { { min: 60, max: 90, step: 1 } }
@@ -37,7 +37,7 @@
describe "#valid?" do
it "invalid without type" do
- subject = described_class.new(nil, "blue", param: :button_text)
+ subject = described_class.new(:button_text, nil, default: "blue")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -45,7 +45,7 @@
end
it "invalid with unsupported type" do
- subject = described_class.new(:foo, "blue", param: :button_text)
+ subject = described_class.new(:button_text, :foo, default: "blue")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
diff --git a/spec/view_component/storybook/controls/object_config_spec.rb b/spec/view_component/storybook/controls/object_config_spec.rb
index b04ac28..b8d90dc 100644
--- a/spec/view_component/storybook/controls/object_config_spec.rb
+++ b/spec/view_component/storybook/controls/object_config_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe ViewComponent::Storybook::Controls::ObjectConfig do
- subject { described_class.new(default_value, param: param, name: name, description: description) }
+ subject { described_class.new(param, default: default_value, name: name, description: description) }
let(:separator) { "," }
let(:type) { :object }
diff --git a/spec/view_component/storybook/controls/options_config_spec.rb b/spec/view_component/storybook/controls/options_config_spec.rb
index d1a7ce6..2577006 100644
--- a/spec/view_component/storybook/controls/options_config_spec.rb
+++ b/spec/view_component/storybook/controls/options_config_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe ViewComponent::Storybook::Controls::OptionsConfig do
described_class::TYPES.each do |type|
context "type: #{type}" do
- subject { described_class.new(type, options, default_value, labels: labels, param: param, name: name, description: description) }
+ subject { described_class.new(param, type, options, default: default_value, labels: labels, name: name, description: description) }
let(:type) { type }
let(:labels) { {} }
@@ -33,13 +33,13 @@
let(:options) { %w[red blue yellow] }
it "valid with value" do
- subject = described_class.new(:radio, options, "blue", param: :button_text)
+ subject = described_class.new(:button_text, :radio, options, default: "blue")
expect(subject.valid?).to be(true)
end
it "invalid without type" do
- subject = described_class.new(nil, options, "blue", param: :button_text)
+ subject = described_class.new(:button_text, nil, options, default: "blue")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -47,7 +47,7 @@
end
it "invalid with unsupported type" do
- subject = described_class.new(:foo, options, "blue", param: :button_text)
+ subject = described_class.new(:button_text, :foo, options, default: "blue")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -55,16 +55,16 @@
end
it "invalid with value not in the options list" do
- subject = described_class.new(:radio, options, "green", param: :button_text)
+ subject = described_class.new(:button_text, :radio, options, default: "green")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
- expect(subject.errors[:default_value]).to eq(["is not included in the list"])
+ expect(subject.errors[:default]).to eq(["is not included in the list"])
end
- it "valid with nil default_value provided its in the options list" do
+ it "valid with nil default provided its in the options list" do
options << nil
- subject = described_class.new(:radio, options, nil, param: :button_text)
+ subject = described_class.new(:button_text, :radio, options, default: nil)
expect(subject.valid?).to be(true)
end
diff --git a/spec/view_component/storybook/controls/text_config_spec.rb b/spec/view_component/storybook/controls/text_config_spec.rb
index 2432885..1660411 100644
--- a/spec/view_component/storybook/controls/text_config_spec.rb
+++ b/spec/view_component/storybook/controls/text_config_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe ViewComponent::Storybook::Controls::TextConfig do
- subject { described_class.new(default_value, param: param, name: name, description: description) }
+ subject { described_class.new(param, default: default_value, name: name, description: description) }
let(:type) { :text }
From dc256cea88458dea9f0d5f40c3943e8008736e0b Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 17 Dec 2022 20:37:50 -0500
Subject: [PATCH 08/35] Change control signature
---
.../storybook/controls/base_options_config.rb | 2 +-
.../storybook/controls/color_config.rb | 2 +-
.../storybook/controls/control_config.rb | 2 +-
.../storybook/controls/controls_helpers.rb | 34 ++++++++-----------
.../storybook/controls/date_config.rb | 2 +-
.../controls/multi_options_config.rb | 4 +--
.../storybook/controls/number_config.rb | 2 +-
.../controls/simple_control_config.rb | 2 +-
.../controls/controls_helpers_spec.rb | 2 +-
.../controls/multi_options_config_spec.rb | 20 +++++------
.../storybook/controls/number_config_spec.rb | 8 ++---
.../storybook/controls/options_config_spec.rb | 12 +++----
12 files changed, 43 insertions(+), 49 deletions(-)
diff --git a/lib/view_component/storybook/controls/base_options_config.rb b/lib/view_component/storybook/controls/base_options_config.rb
index 2f89ba7..1b9233c 100644
--- a/lib/view_component/storybook/controls/base_options_config.rb
+++ b/lib/view_component/storybook/controls/base_options_config.rb
@@ -8,7 +8,7 @@ class BaseOptionsConfig < SimpleControlConfig
validates :type, :options, presence: true
- def initialize(param, type, options, default: , labels: nil, name: nil, description: nil, **opts)
+ def initialize(param, type:, options:, default:, labels: nil, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
@type = type
@options = options
diff --git a/lib/view_component/storybook/controls/color_config.rb b/lib/view_component/storybook/controls/color_config.rb
index b9dbf4c..eb45f9e 100644
--- a/lib/view_component/storybook/controls/color_config.rb
+++ b/lib/view_component/storybook/controls/color_config.rb
@@ -6,7 +6,7 @@ module Controls
class ColorConfig < SimpleControlConfig
attr_reader :preset_colors
- def initialize(param, default: , preset_colors: nil, name: nil, description: nil, **opts)
+ def initialize(param, default:, preset_colors: nil, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
@preset_colors = preset_colors
end
diff --git a/lib/view_component/storybook/controls/control_config.rb b/lib/view_component/storybook/controls/control_config.rb
index 657fc89..d029277 100644
--- a/lib/view_component/storybook/controls/control_config.rb
+++ b/lib/view_component/storybook/controls/control_config.rb
@@ -10,7 +10,7 @@ class ControlConfig
attr_reader :param, :default, :name, :description, :opts
- def initialize(param, default: , name: nil, description: nil, **opts)
+ def initialize(param, default:, name: nil, description: nil, **opts)
@param = param
@default = default
@name = name || param.to_s.humanize.titlecase
diff --git a/lib/view_component/storybook/controls/controls_helpers.rb b/lib/view_component/storybook/controls/controls_helpers.rb
index 28c8f9f..61e00a3 100644
--- a/lib/view_component/storybook/controls/controls_helpers.rb
+++ b/lib/view_component/storybook/controls/controls_helpers.rb
@@ -23,40 +23,34 @@ def inherited(other)
other.controls = []
end
- def control(param, as:, default:, name: nil, description: nil, **opts)
+ def control(param, as:, default:, **opts)
controls << case as
when :text
- Controls::TextConfig.new(param, default: default, name: name, description: description, **opts)
+ Controls::TextConfig.new(param, default: default, **opts)
when :boolean
- Controls::BooleanConfig.new(param, default: default, name: name, description: description, **opts)
+ Controls::BooleanConfig.new(param, default: default, **opts)
when :number
- Controls::NumberConfig.new(param, :number, default: default, name: name, description: description, **opts)
+ Controls::NumberConfig.new(param, type: :number, default: default, **opts)
when :range
- Controls::NumberConfig.new(param, :range, default: default, name: name, description: description, **opts)
+ Controls::NumberConfig.new(param, type: :range, default: default, **opts)
when :color
- Controls::ColorConfig.new(param, default: default, name: name, description: description, **opts)
+ Controls::ColorConfig.new(param, default: default, **opts)
when :object, :array
- Controls::ObjectConfig.new(param, default: default, name: name, description: description, **opts)
+ Controls::ObjectConfig.new(param, default: default, **opts)
when :select
- options = opts.delete(:options)
- Controls::OptionsConfig.new(param, :select, options, default: default, name: name, description: description, **opts)
+ Controls::OptionsConfig.new(param, type: :select, default: default, **opts)
when :multi_select
- options = opts.delete(:options)
- Controls::MultiOptionsConfig.new(param, :'multi-select', options, default: default, name: name, description: description, **opts)
+ Controls::MultiOptionsConfig.new(param, type: :'multi-select', default: default, **opts)
when :radio
- options = opts.delete(:options)
- Controls::OptionsConfig.new(param, :radio, options, default: default, name: name, description: description, **opts)
+ Controls::OptionsConfig.new(param, type: :radio, default: default, **opts)
when :inline_radio
- options = opts.delete(:options)
- Controls::OptionsConfig.new(param, :'inline-radio', options, default: default, name: name, description: description, **opts)
+ Controls::OptionsConfig.new(param, type: :'inline-radio', default: default, **opts)
when :check
- options = opts.delete(:options)
- Controls::MultiOptionsConfig.new(param, :check, options, default: default, name: name, description: description, **opts)
+ Controls::MultiOptionsConfig.new(param, type: :check, default: default, **opts)
when :inline_check
- options = opts.delete(:options)
- Controls::MultiOptionsConfig.new(param, :'inline-check', options, default: default, name: name, description: description, **opts)
+ Controls::MultiOptionsConfig.new(param, type: :'inline-check', default: default, **opts)
when :date
- Controls::DateConfig.new(param, default: default, name: name, description: description, **opts)
+ Controls::DateConfig.new(param, default: default, **opts)
else
raise "Unknonwn control type '#{as}'"
end
diff --git a/lib/view_component/storybook/controls/date_config.rb b/lib/view_component/storybook/controls/date_config.rb
index 0998477..f952b34 100644
--- a/lib/view_component/storybook/controls/date_config.rb
+++ b/lib/view_component/storybook/controls/date_config.rb
@@ -4,7 +4,7 @@ module ViewComponent
module Storybook
module Controls
class DateConfig < SimpleControlConfig
- def initialize(param, default: , name: nil, description: nil, **opts)
+ def initialize(param, default:, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
end
diff --git a/lib/view_component/storybook/controls/multi_options_config.rb b/lib/view_component/storybook/controls/multi_options_config.rb
index 8075ea3..d24dcf3 100644
--- a/lib/view_component/storybook/controls/multi_options_config.rb
+++ b/lib/view_component/storybook/controls/multi_options_config.rb
@@ -9,8 +9,8 @@ class MultiOptionsConfig < BaseOptionsConfig
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
validate :validate_default_value, unless: -> { options.nil? || default.nil? }
- def initialize(param, type, options, default:, labels: nil, name: nil, description: nil, **opts)
- super(param, type, options, default: Array.wrap(default), labels: labels, param: param, name: name, description: description, **opts)
+ def initialize(param, type:, options:, default:, labels: nil, name: nil, description: nil, **opts)
+ super(param, type: type, options: options, default: Array.wrap(default), labels: labels, param: param, name: name, description: description, **opts)
end
def value_from_params(params)
diff --git a/lib/view_component/storybook/controls/number_config.rb b/lib/view_component/storybook/controls/number_config.rb
index c94acf8..4fc91bc 100644
--- a/lib/view_component/storybook/controls/number_config.rb
+++ b/lib/view_component/storybook/controls/number_config.rb
@@ -11,7 +11,7 @@ class NumberConfig < SimpleControlConfig
validates :type, presence: true
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
- def initialize(param, type, default: , min: nil, max: nil, step: nil, name: nil, description: nil, **opts)
+ def initialize(param, type:, default:, min: nil, max: nil, step: nil, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
@type = type
@min = min
diff --git a/lib/view_component/storybook/controls/simple_control_config.rb b/lib/view_component/storybook/controls/simple_control_config.rb
index 3bef16d..4bfc345 100644
--- a/lib/view_component/storybook/controls/simple_control_config.rb
+++ b/lib/view_component/storybook/controls/simple_control_config.rb
@@ -7,7 +7,7 @@ module Controls
# A simple Control Config maps to one Storybook Control
# It has a value and pulls its value from params by key
class SimpleControlConfig < ControlConfig
- def initialize(param, default: , name: nil, description: nil, **opts)
+ def initialize(param, default:, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
end
diff --git a/spec/view_component/storybook/controls/controls_helpers_spec.rb b/spec/view_component/storybook/controls/controls_helpers_spec.rb
index 200b895..3caf9be 100644
--- a/spec/view_component/storybook/controls/controls_helpers_spec.rb
+++ b/spec/view_component/storybook/controls/controls_helpers_spec.rb
@@ -67,7 +67,7 @@
describe "#range" do
context "with minimal args" do
- control :count, as: :range, default: 2
+ control :count, as: :range, default: 2
include_examples "has controls attributes",
{
diff --git a/spec/view_component/storybook/controls/multi_options_config_spec.rb b/spec/view_component/storybook/controls/multi_options_config_spec.rb
index 56d1b99..5277454 100644
--- a/spec/view_component/storybook/controls/multi_options_config_spec.rb
+++ b/spec/view_component/storybook/controls/multi_options_config_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe ViewComponent::Storybook::Controls::MultiOptionsConfig do
described_class::TYPES.each do |type|
context "type: #{type}" do
- subject { described_class.new(param, type, options, default: default_value, labels: labels, name: name, description: description) }
+ subject { described_class.new(param, type: type, options: options, default: default_value, labels: labels, name: name, description: description) }
let(:type) { type }
let(:labels) { {} }
@@ -29,7 +29,7 @@
end
describe "#value_from_params" do
- subject { described_class.new(:opt, :check, options, default: defualt_value) }
+ subject { described_class.new(:opt, type: :check, options: options, default: defualt_value) }
context "with array options" do
let(:options) { %w[red blue yellow] }
@@ -62,32 +62,32 @@
let(:options) { %w[red blue yellow] }
it "valid with single array value" do
- subject = described_class.new(:button_text, :check, options, default: ["blue"])
+ subject = described_class.new(:button_text, type: :check, options: options, default: ["blue"])
expect(subject.valid?).to be(true)
end
it "valid with multi array value" do
- subject = described_class.new(:button_text, :check, options, default: ["blue", "red"])
+ subject = described_class.new(:button_text, type: :check, options: options, default: ["blue", "red"])
expect(subject.valid?).to be(true)
end
it "valid with non-array value" do
- subject = described_class.new(:button_text, :check, options, default: "blue")
+ subject = described_class.new(:button_text, type: :check, options: options, default: "blue")
expect(subject.valid?).to be(true)
end
it "valid with nil default provided its in the options list" do
options << nil
- subject = described_class.new(:button_text, :check, options, default: nil)
+ subject = described_class.new(:button_text, type: :check, options: options, default: nil)
expect(subject.valid?).to be(true)
end
it "invalid without type" do
- subject = described_class.new(:button_text, nil, options, default: ["blue"])
+ subject = described_class.new(:button_text, type: nil, options: options, default: ["blue"])
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -95,7 +95,7 @@
end
it "invalid with unsupported type" do
- subject = described_class.new(:button_text, :foo, options, default: ["blue"])
+ subject = described_class.new(:button_text, type: :foo, options: options, default: ["blue"])
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -103,7 +103,7 @@
end
it "invalid with value not in the options list" do
- subject = described_class.new(:button_text, :check, options, default: ["green"] )
+ subject = described_class.new(:button_text, type: :check, options: options, default: ["green"] )
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -111,7 +111,7 @@
end
it "invalid with value partially in the options list" do
- subject = described_class.new(:button_text, :check, options, default: ["green", "red"])
+ subject = described_class.new(:button_text, type: :check, options: options, default: ["green", "red"])
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
diff --git a/spec/view_component/storybook/controls/number_config_spec.rb b/spec/view_component/storybook/controls/number_config_spec.rb
index 7dda731..ad531a2 100644
--- a/spec/view_component/storybook/controls/number_config_spec.rb
+++ b/spec/view_component/storybook/controls/number_config_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe ViewComponent::Storybook::Controls::NumberConfig do
described_class::TYPES.each do |number_type|
context "with '#{number_type}' type" do
- subject { described_class.new(param, number_type, default: default_value, name: name, description: description) }
+ subject { described_class.new(param, type: number_type, default: default_value, name: name, description: description) }
it_behaves_like "a simple controls config" do
let(:type) { number_type }
@@ -20,7 +20,7 @@
end
context "with options" do
- subject { described_class.new(param, number_type, default: default_value, **number_options, name: name, description: description) }
+ subject { described_class.new(param, type: number_type, default: default_value, **number_options, name: name, description: description) }
let(:number_options) { { min: 60, max: 90, step: 1 } }
@@ -37,7 +37,7 @@
describe "#valid?" do
it "invalid without type" do
- subject = described_class.new(:button_text, nil, default: "blue")
+ subject = described_class.new(:button_text, type: nil, default: "blue")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -45,7 +45,7 @@
end
it "invalid with unsupported type" do
- subject = described_class.new(:button_text, :foo, default: "blue")
+ subject = described_class.new(:button_text, type: :foo, default: "blue")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
diff --git a/spec/view_component/storybook/controls/options_config_spec.rb b/spec/view_component/storybook/controls/options_config_spec.rb
index 2577006..a80dabf 100644
--- a/spec/view_component/storybook/controls/options_config_spec.rb
+++ b/spec/view_component/storybook/controls/options_config_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe ViewComponent::Storybook::Controls::OptionsConfig do
described_class::TYPES.each do |type|
context "type: #{type}" do
- subject { described_class.new(param, type, options, default: default_value, labels: labels, name: name, description: description) }
+ subject { described_class.new(param, type: type, options: options, default: default_value, labels: labels, name: name, description: description) }
let(:type) { type }
let(:labels) { {} }
@@ -33,13 +33,13 @@
let(:options) { %w[red blue yellow] }
it "valid with value" do
- subject = described_class.new(:button_text, :radio, options, default: "blue")
+ subject = described_class.new(:button_text, type: :radio, options: options, default: "blue")
expect(subject.valid?).to be(true)
end
it "invalid without type" do
- subject = described_class.new(:button_text, nil, options, default: "blue")
+ subject = described_class.new(:button_text, type: nil, options: options, default: "blue")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -47,7 +47,7 @@
end
it "invalid with unsupported type" do
- subject = described_class.new(:button_text, :foo, options, default: "blue")
+ subject = described_class.new(:button_text, type: :foo, options: options, default: "blue")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -55,7 +55,7 @@
end
it "invalid with value not in the options list" do
- subject = described_class.new(:button_text, :radio, options, default: "green")
+ subject = described_class.new(:button_text, type: :radio, options: options, default: "green")
expect(subject.valid?).to be(false)
expect(subject.errors.size).to eq(1)
@@ -64,7 +64,7 @@
it "valid with nil default provided its in the options list" do
options << nil
- subject = described_class.new(:button_text, :radio, options, default: nil)
+ subject = described_class.new(:button_text, type: :radio, options: options, default: nil)
expect(subject.valid?).to be(true)
end
From c2bd37c911f7bebdb8ffec133139e92fad7c9587 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 17 Dec 2022 20:46:51 -0500
Subject: [PATCH 09/35] More cleanup
---
lib/view_component/storybook.rb | 6 -
.../storybook/content_concern.rb | 42 -----
lib/view_component/storybook/dsl.rb | 13 --
lib/view_component/storybook/method_args.rb | 17 --
lib/view_component/storybook/stories_v1.rb | 150 ------------------
spec/view_component/storybook/stories_spec.rb | 4 +-
6 files changed, 2 insertions(+), 230 deletions(-)
delete mode 100644 lib/view_component/storybook/content_concern.rb
delete mode 100644 lib/view_component/storybook/dsl.rb
delete mode 100644 lib/view_component/storybook/method_args.rb
delete mode 100644 lib/view_component/storybook/stories_v1.rb
diff --git a/lib/view_component/storybook.rb b/lib/view_component/storybook.rb
index 044d4d8..e33ea94 100644
--- a/lib/view_component/storybook.rb
+++ b/lib/view_component/storybook.rb
@@ -9,17 +9,11 @@ module Storybook
autoload :Controls
autoload :Stories
- autoload :StoriesV2
autoload :StoriesParser
autoload :StoriesCollection
autoload :StoriesConfig
- autoload :StoryConfig
autoload :Story
- autoload :StoryV2
autoload :Slots
- autoload :ContentConcern
- autoload :MethodArgs
- autoload :Dsl
include ActiveSupport::Configurable
# Set the location of component previews through app configuration:
diff --git a/lib/view_component/storybook/content_concern.rb b/lib/view_component/storybook/content_concern.rb
deleted file mode 100644
index bdc24ba..0000000
--- a/lib/view_component/storybook/content_concern.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- module ContentConcern
- extend ActiveSupport::Concern
-
- included do
- attr_reader :content_control, :content_block
- end
-
- def content(content = nil, &block)
- case content
- when Storybook::Controls::ControlConfig
- @content_control = content.param(content_param)
- @content_block = nil
- when String
- @content_control = nil
- @content_block = proc { content }
- else
- @content_control = nil
- @content_block = block
- end
- end
-
- def resolve_content_block(params)
- if content_control
- content = content_control.value_from_params(params)
- proc { content }
- else
- content_block
- end
- end
-
- private
-
- def content_param
- :content
- end
- end
- end
-end
diff --git a/lib/view_component/storybook/dsl.rb b/lib/view_component/storybook/dsl.rb
deleted file mode 100644
index f7e3945..0000000
--- a/lib/view_component/storybook/dsl.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-require "active_support/dependencies/autoload"
-
-module ViewComponent
- module Storybook
- module Dsl
- extend ActiveSupport::Autoload
-
- autoload :LegacyControlsDsl
- end
- end
-end
diff --git a/lib/view_component/storybook/method_args.rb b/lib/view_component/storybook/method_args.rb
deleted file mode 100644
index 76e9fb7..0000000
--- a/lib/view_component/storybook/method_args.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require "active_support/dependencies/autoload"
-
-module ViewComponent
- module Storybook
- module MethodArgs
- extend ActiveSupport::Autoload
-
- autoload :MethodArgs
- autoload :MethodParametersNames
- autoload :ControlMethodArgs
- autoload :ComponentConstructorArgs
- autoload :DryInitializerComponentConstructorArgs
- end
- end
-end
diff --git a/lib/view_component/storybook/stories_v1.rb b/lib/view_component/storybook/stories_v1.rb
deleted file mode 100644
index faada8c..0000000
--- a/lib/view_component/storybook/stories_v1.rb
+++ /dev/null
@@ -1,150 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- class StoriesV1
- extend ActiveSupport::DescendantsTracker
- include ActiveModel::Validations
-
- class_attribute :story_configs, default: []
- class_attribute :stories_parameters, :stories_title, :stories_layout
-
- validate :validate_story_configs
-
- class << self
- def title(title = nil)
- # if no argument is passed act like a getter
- self.stories_title = title unless title.nil?
- stories_title
- end
-
- def story(name, component = default_component, &block)
- story_config = StoryConfig.new(story_id(name), name, component, layout, &block)
- story_config.instance_eval(&block)
- story_configs << story_config
- story_config
- end
-
- def parameters(params = nil)
- # if no argument is passed act like a getter
- self.stories_parameters = params unless params.nil?
- stories_parameters
- end
-
- def layout(layout = nil)
- # if no argument is passed act like a getter
- self.stories_layout = layout unless layout.nil?
- stories_layout
- end
-
- def to_csf_params
- validate!
- csf_params = { title: title }
- csf_params[:parameters] = parameters if parameters.present?
- csf_params[:stories] = story_configs.map(&:to_csf_params)
- csf_params
- end
-
- def write_csf_json
- json_path = File.join(stories_path, "#{stories_name}.stories.json")
- File.write(json_path, JSON.pretty_generate(to_csf_params))
- json_path
- end
-
- def stories_name
- name.chomp("Stories").underscore
- end
-
- # Returns all component stories classes.
- def all
- load_stories if descendants.empty?
- descendants
- end
-
- # Returns +true+ if the stories exist.
- def stories_exists?(stories_name)
- all.any? { |stories| stories.stories_name == stories_name }
- end
-
- # Find a component stories by its underscored class name.
- def find_story_configs(stories_name)
- all.find { |stories| stories.stories_name == stories_name }
- end
-
- # Returns +true+ if the story of the component stories exists.
- def story_exists?(name)
- story_configs.map(&:name).include?(name.to_sym)
- end
-
- # find the story by name
- def find_story_config(name)
- story_configs.find { |config| config.name == name.to_sym }
- end
-
- # validation - ActiveModel::Validations like but on the class vs the instance
- def valid?
- # use an instance so we can enjoy the benefits of ActiveModel::Validations
- @validation_instance = new
- @validation_instance.valid?
- end
-
- delegate :errors, to: :@validation_instance
-
- def validate!
- valid? || raise(ValidationError, @validation_instance)
- end
-
- private
-
- def inherited(other)
- super(other)
- # setup class defaults
- other.stories_title = Storybook.stories_title_generator.call(other)
- other.story_configs = []
- end
-
- def default_component
- name.chomp("Stories").constantize
- end
-
- def load_stories
- Dir["#{stories_path}/**/*_stories.rb"].sort.each { |file| require_dependency file } if stories_path
- end
-
- def stories_path
- Storybook.stories_path
- end
-
- def story_id(name)
- "#{stories_name}/#{name.to_s.parameterize}".underscore
- end
- end
-
- protected
-
- def validate_story_configs
- story_configs.reject(&:valid?).each do |story_config|
- story_errors = story_config.errors.full_messages.join(', ')
- errors.add(:story_configs, :invalid_story, story_name: story_config.name, story_errors: story_errors)
- end
-
- story_names = story_configs.map(&:name)
- duplicate_names = story_names.group_by(&:itself).map { |k, v| k if v.length > 1 }.compact
- return if duplicate_names.empty?
-
- duplicate_name_sentence = duplicate_names.map { |name| "'#{name}'" }.to_sentence
- errors.add(:story_configs, :duplicate_stories, count: duplicate_names.count, duplicate_names: duplicate_name_sentence)
- end
-
- class ValidationError < StandardError
- attr_reader :stories
-
- def initialize(stories)
- @stories = stories
-
- super("#{@stories.class.name} invalid: (#{@stories.errors.full_messages.join(', ')})")
- end
- end
- end
- end
-end
diff --git a/spec/view_component/storybook/stories_spec.rb b/spec/view_component/storybook/stories_spec.rb
index 40d21b2..5e382e2 100644
--- a/spec/view_component/storybook/stories_spec.rb
+++ b/spec/view_component/storybook/stories_spec.rb
@@ -295,7 +295,7 @@
Class.new(described_class) do
class << self
def name
- "Demo::MoreButtonComponentStoriesV2"
+ "Demo::MoreButtonComponentStories"
end
end
end
@@ -329,7 +329,7 @@ def name
end
xit "converts Stories with parameters" do
- expect(ParametersStoriesV2.to_csf_params).to eq(
+ expect(ParametersStories.to_csf_params).to eq(
title: "Parameters",
parameters: { size: :small },
stories: [
From 88413965d62bad581c39c5c375e6d39a626da72c Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 17 Dec 2022 22:02:00 -0500
Subject: [PATCH 10/35] Fix story ordering
---
config/locales/en.yml | 32 ---------
lib/view_component/storybook.rb | 1 -
lib/view_component/storybook/engine.rb | 12 +---
lib/view_component/storybook/stories.rb | 36 +++++++---
.../storybook/stories_collection.rb | 12 ++--
.../storybook/stories_config.rb | 67 -------------------
.../storybook/stories_parser.rb | 9 +--
.../tasks/view_component_storybook.rake | 2 +-
.../stories/combined_control_stories.rb | 4 +-
spec/view_component/storybook/stories_spec.rb | 7 +-
10 files changed, 41 insertions(+), 141 deletions(-)
delete mode 100644 config/locales/en.yml
delete mode 100644 lib/view_component/storybook/stories_config.rb
diff --git a/config/locales/en.yml b/config/locales/en.yml
deleted file mode 100644
index 3362591..0000000
--- a/config/locales/en.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-en:
- activemodel:
- errors:
- models:
- view_component/storybook/method_args/method_args:
- attributes:
- args:
- too_few: expected at least %{min} but found %{count}
- too_many: expected no more than %{max} but found %{count}
- kwargs:
- invalid_arg: "'%{kwarg}' is invalid"
- invalid: expected keys [%{expected_keys}] but found [%{actual_keys}]
- view_component/storybook/method_args/control_method_args:
- attributes:
- controls:
- invalid_control: "'%{control_name}' is invalid: (%{control_errors})"
- view_component/storybook/stories:
- attributes:
- story_configs:
- invalid_story: "'%{story_name}' is invalid: (%{story_errors})"
- duplicate_stories:
- one: duplicate story name %{duplicate_names}
- other: duplicate story names %{duplicate_names}
- view_component/storybook/story_config:
- attributes:
- constructor_args:
- invalid: "invalid: (%{errors})"
- view_component/storybook/controls/custom_config:
- attributes:
- value_method_args:
- invalid: "invalid: (%{errors})"
-
\ No newline at end of file
diff --git a/lib/view_component/storybook.rb b/lib/view_component/storybook.rb
index e33ea94..0bfcf07 100644
--- a/lib/view_component/storybook.rb
+++ b/lib/view_component/storybook.rb
@@ -11,7 +11,6 @@ module Storybook
autoload :Stories
autoload :StoriesParser
autoload :StoriesCollection
- autoload :StoriesConfig
autoload :Story
autoload :Slots
diff --git a/lib/view_component/storybook/engine.rb b/lib/view_component/storybook/engine.rb
index 3c672d0..612a5c6 100644
--- a/lib/view_component/storybook/engine.rb
+++ b/lib/view_component/storybook/engine.rb
@@ -41,16 +41,6 @@ class Engine < Rails::Engine
end
end
- # config.after_initialize do |app|
- # options = app.config.view_component_storybook
-
- # if options.show_stories
- # app.routes.prepend do
- # get "#{options.stories_route}/*stories/:story" => "view_component/storybook/stories#show", :internal => true
- # end
- # end
- # end
-
config.after_initialize do
parser.parse
end
@@ -60,7 +50,7 @@ class Engine < Rails::Engine
end
def parser
- @parser ||= StoriesParser.new(ViewComponent::Storybook.stories_paths) # , Engine.tags)
+ @parser ||= StoriesParser.new(ViewComponent::Storybook.stories_paths)
end
class << self
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 4155844..41d14ee 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -7,7 +7,7 @@ module Storybook
class Stories < ViewComponent::Preview
include Controls::ControlsHelpers
- class_attribute :stories_parameters, :stories_title, :stories_config
+ class_attribute :stories_parameters, :stories_title, :code_object
class << self
def title(title = nil)
@@ -33,23 +33,24 @@ def preview_name
def to_csf_params
csf_params = { title: title }
csf_params[:parameters] = parameters if parameters.present?
- csf_params[:stories] = story_configs.map(&:to_csf_params)
+ csf_params[:stories] = stories.map(&:to_csf_params)
csf_params
end
def write_csf_json
# json_path = File.join(stories_path, "#{stories_name}.stories.json")
+ Rails.logger.debug { "stories_json_path: #{stories_json_path}" }
File.write(stories_json_path, JSON.pretty_generate(to_csf_params))
stories_json_path
end
- def story_configs
- @story_configs ||= story_names.map { |method| Story.new(story_id(method), method, {}, controls_for_story(method)) }
+ def stories
+ @stories ||= story_names.map { |method| Story.new(story_id(method), method, {}, controls_for_story(method)) }
end
# find the story by name
def find_story_config(name)
- story_configs.find { |config| config.name == name.to_sym }
+ stories.find { |config| config.name == name.to_sym }
end
# Returns the arguments for rendering of the component in its layout
@@ -84,19 +85,34 @@ def inherited(other)
end
def stories_json_path
- @stories_json_path ||= File.join(File.dirname(__FILE__), "#{File.basename(__FILE__, '.rb')}.stories.json")
+ @stories_json_path ||= begin
+ dir = File.dirname(code_object.file)
+ json_filename = code_object.path.demodulize.underscore
+
+ File.join(dir, "#{json_filename}.stories.json")
+ end
end
def story_id(name)
"#{stories_name}/#{name.to_s.parameterize}".underscore
end
- def story_methods
- @story_methods ||= public_instance_methods(false).map { |name| instance_method(name) }
- end
+ # def story_methods
+ # @story_methods ||= public_instance_methods(false).map { |name| instance_method(name) }
+ # end
def story_names
- @story_names ||= story_methods.map(&:name)
+ @story_names ||= begin
+ public_methods = public_instance_methods(false)
+ if code_object
+ # use the code_object to sort the methods to the order that they're declared
+ code_object.meths.select { |m| public_methods.include?(m.name) }.map(&:name)
+ else
+ # there is no code_object in some specs, particularly where we create Stories after Yard parsing
+ # in these cases just use the names as returned by the public_methods
+ public_methods.map(&:name)
+ end
+ end
end
def controls_for_story(story_name)
diff --git a/lib/view_component/storybook/stories_collection.rb b/lib/view_component/storybook/stories_collection.rb
index 1250770..0afa317 100644
--- a/lib/view_component/storybook/stories_collection.rb
+++ b/lib/view_component/storybook/stories_collection.rb
@@ -6,17 +6,13 @@ class StoriesCollection
attr_reader :stories
def load(code_objects)
- @stories = Array(code_objects).map { |obj| StoriesCollection.stories_config_from_code_object(obj) }.compact
+ @stories = Array(code_objects).map { |obj| StoriesCollection.stories_from_code_object(obj) }.compact
end
- def self.stories_config_from_code_object(code_object)
+ def self.stories_from_code_object(code_object)
klass = code_object.path.constantize
-
- ViewComponent::Storybook::StoriesConfig.new(code_object) if stories_class?(klass)
- # rescue => exception
- # puts exception.to_s
- # # Lookbook.logger.error exception.to_s
- # nil
+ klass.code_object = code_object
+ klass
end
def self.stories_class?(klass)
diff --git a/lib/view_component/storybook/stories_config.rb b/lib/view_component/storybook/stories_config.rb
deleted file mode 100644
index c114ccd..0000000
--- a/lib/view_component/storybook/stories_config.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- class StoriesConfig
- delegate :title, :parameters, :stories_name, to: :stories_class
- attr_reader :stories_class, :stories_json_path
-
- def initialize(code_object)
- @code_object = code_object
- @stories_class = code_object.path.constantize
-
- dir = File.dirname(@code_object.file)
- json_filename = code_object.path.demodulize.underscore
-
- @stories_json_path = File.join(dir, "#{json_filename}.stories.json")
-
- @stories_class.stories_config = self
- end
-
- # def story_configs
- # @story_configs =
- # end
-
- def to_csf_params
- csf_params = { title: title }
- csf_params[:parameters] = parameters if parameters.present?
- csf_params[:stories] = story_configs.map(&:to_csf_params)
- csf_params
- end
-
- def write_csf_json
- # json_path = File.join(stories_path, "#{stories_name}.stories.json")
- File.write(stories_json_path, JSON.pretty_generate(to_csf_params))
- stories_json_path
- end
-
- def story_configs
- @story_configs ||= begin
- public_methods = stories_class.public_instance_methods(false)
- method_objects = @code_object.meths.select { |m| public_methods.include?(m.name) }
- method_objects.map { |code_object| StoryV2.from_code_object(code_object, self) }
- end
- end
-
- # # Returns +true+ if the stories exist.
- # def stories_exists?(stories_name)
- # all.any? { |stories| stories.stories_name == stories_name }
- # end
-
- # # Find a component stories by its underscored class name.
- # def find_story_configs(stories_name)
- # all.find { |stories| stories.stories_name == stories_name }
- # end
-
- # # Returns +true+ if the story of the component stories exists.
- # def story_exists?(name)
- # story_configs.map(&:name).include?(name.to_sym)
- # end
-
- # # find the story by name
- # def find_story_config(name)
- # story_configs.find { |config| config.name == name.to_sym }
- # end
- end
- end
-end
diff --git a/lib/view_component/storybook/stories_parser.rb b/lib/view_component/storybook/stories_parser.rb
index 00cd8ce..d07e8da 100644
--- a/lib/view_component/storybook/stories_parser.rb
+++ b/lib/view_component/storybook/stories_parser.rb
@@ -5,13 +5,12 @@
module ViewComponent
module Storybook
class StoriesParser
- def initialize(paths, tags = nil)
+ def initialize(paths)
@paths = paths
@after_parse_callbacks = []
@after_parse_once_callbacks = []
@parsing = false
- define_tags(tags)
YARD::Parser::SourceParser.after_parse_list { run_callbacks }
end
@@ -44,12 +43,6 @@ def run_callbacks
@after_parse_once_callbacks = []
@parsing = false
end
-
- def define_tags(tags = nil)
- # tags.to_h.each do |name, tag|
- # YARD::Tags::Library.define_tag(tag[:label], name, Lookbook::TagProvider)
- # end
- end
end
end
end
diff --git a/lib/view_component/storybook/tasks/view_component_storybook.rake b/lib/view_component/storybook/tasks/view_component_storybook.rake
index e3cc2a3..ebded1f 100644
--- a/lib/view_component/storybook/tasks/view_component_storybook.rake
+++ b/lib/view_component/storybook/tasks/view_component_storybook.rake
@@ -5,7 +5,7 @@ namespace :view_component_storybook do
task write_stories_json: :environment do
puts "Writing Stories JSON"
exceptions = []
- ViewComponent::Storybook::Stories.all.each do |stories|
+ ViewComponent::Storybook::Engine.stories.each do |stories|
json_path = stories.write_csf_json
puts "#{stories.name} => #{json_path}"
rescue StandardError => e
diff --git a/spec/dummy/test/components/stories/combined_control_stories.rb b/spec/dummy/test/components/stories/combined_control_stories.rb
index a28fbaa..5aceb2c 100644
--- a/spec/dummy/test/components/stories/combined_control_stories.rb
+++ b/spec/dummy/test/components/stories/combined_control_stories.rb
@@ -11,13 +11,13 @@ def combined_text(greeting: "Hi!", name: "Sarah")
control :verb_one, as: :text, default: "Big", only: :combined_rest_args
control :noun_one, as: :text, default: "Car", only: :combined_rest_args
control :verb_two, as: :text, default: "Small", only: :combined_rest_args
- control :noun_tow, as: :text, default: "Boat", only: :combined_rest_args
+ control :noun_two, as: :text, default: "Boat", only: :combined_rest_args
def combined_rest_args(verb_one: "Big", noun_one: "Car", verb_two: "Small", noun_two: "Boat")
render ArgsComponent.new("#{verb_one} #{noun_one}", "#{verb_two} #{noun_two}")
end
- control :greeting, as: :text, default: "DO NOT PUSH!", description: "Make this irresistible.", only: :described_control
+ control :button_text, as: :text, default: "DO NOT PUSH!", description: "Make this irresistible.", only: :described_control
def described_control(button_text: 'DO NOT PUSH!' )
render Demo::ButtonComponent.new(button_text: button_text)
diff --git a/spec/view_component/storybook/stories_spec.rb b/spec/view_component/storybook/stories_spec.rb
index 5e382e2..401cf5d 100644
--- a/spec/view_component/storybook/stories_spec.rb
+++ b/spec/view_component/storybook/stories_spec.rb
@@ -421,7 +421,7 @@ def name
button_text: { control: { type: :text }, description: "Make this irresistible.", name: "Button Text" }
},
parameters: {
- server: { id: "custom_control/described_control" }
+ server: { id: "combined_control/described_control" }
}
}
]
@@ -468,6 +468,11 @@ def name
File.delete(subject)
end
+ it "writes file" do
+ expect(subject).to eq(Rails.root.join("test/components/stories/content_component_stories.stories.json").to_s)
+ expect(File.exist?(subject)).to be(true)
+ end
+
it "writes stories to json files" do
json_file = File.read(subject)
expect(json_file).to eq(
From 44365caa9de2d7b6592bc28a10ae3f819a237252 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 17 Dec 2022 22:32:27 -0500
Subject: [PATCH 11/35] Read control default values from parsed params
---
.../storybook/controls/base_options_config.rb | 2 +-
.../storybook/controls/color_config.rb | 2 +-
.../storybook/controls/control_config.rb | 26 ++---------------
.../storybook/controls/controls_helpers.rb | 28 +++++++++----------
.../storybook/controls/date_config.rb | 6 ++--
.../storybook/controls/number_config.rb | 2 +-
.../controls/simple_control_config.rb | 2 +-
lib/view_component/storybook/stories.rb | 11 ++++++++
.../stories/combined_control_stories.rb | 16 +++++------
.../stories/content_component_stories.rb | 4 +--
.../stories/demo/button_component_stories.rb | 6 +---
.../stories/dry_component_stories.rb | 2 +-
.../stories/kitchen_sink_component_stories.rb | 18 ++++++------
.../stories/kwargs_component_stories.rb | 8 +++---
.../test/components/stories/layout_stories.rb | 2 +-
.../stories/mixed_args_component_stories.rb | 4 +--
.../components/stories/no_layout_stories.rb | 2 +-
.../components/stories/parameters_stories.rb | 2 +-
.../test/components/stories/slots_stories.rb | 14 +++++-----
19 files changed, 71 insertions(+), 86 deletions(-)
diff --git a/lib/view_component/storybook/controls/base_options_config.rb b/lib/view_component/storybook/controls/base_options_config.rb
index 1b9233c..e18aa24 100644
--- a/lib/view_component/storybook/controls/base_options_config.rb
+++ b/lib/view_component/storybook/controls/base_options_config.rb
@@ -8,7 +8,7 @@ class BaseOptionsConfig < SimpleControlConfig
validates :type, :options, presence: true
- def initialize(param, type:, options:, default:, labels: nil, name: nil, description: nil, **opts)
+ def initialize(param, type:, options:, default: nil, labels: nil, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
@type = type
@options = options
diff --git a/lib/view_component/storybook/controls/color_config.rb b/lib/view_component/storybook/controls/color_config.rb
index eb45f9e..9bc32fc 100644
--- a/lib/view_component/storybook/controls/color_config.rb
+++ b/lib/view_component/storybook/controls/color_config.rb
@@ -6,7 +6,7 @@ module Controls
class ColorConfig < SimpleControlConfig
attr_reader :preset_colors
- def initialize(param, default:, preset_colors: nil, name: nil, description: nil, **opts)
+ def initialize(param, default: nil, preset_colors: nil, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
@preset_colors = preset_colors
end
diff --git a/lib/view_component/storybook/controls/control_config.rb b/lib/view_component/storybook/controls/control_config.rb
index d029277..5439fec 100644
--- a/lib/view_component/storybook/controls/control_config.rb
+++ b/lib/view_component/storybook/controls/control_config.rb
@@ -8,7 +8,8 @@ class ControlConfig
validates :param, presence: true
- attr_reader :param, :default, :name, :description, :opts
+ attr_reader :param, :name, :description, :opts
+ attr_accessor :default
def initialize(param, default:, name: nil, description: nil, **opts)
@param = param
@@ -18,29 +19,6 @@ def initialize(param, default:, name: nil, description: nil, **opts)
@opts = opts
end
- # def name(new_name = nil)
- # if new_name.nil?
- # @name ||= param.to_s.humanize.titlecase
- # else
- # @name = new_name
- # self
- # end
- # end
-
- # def description(new_description = nil)
- # return @description if new_description.nil?
-
- # @description = new_description
- # self
- # end
-
- # def param(new_param = nil)
- # return @param if new_param.nil?
-
- # @param = new_param
- # self
- # end
-
def to_csf_params
# :nocov:
raise NotImplementedError
diff --git a/lib/view_component/storybook/controls/controls_helpers.rb b/lib/view_component/storybook/controls/controls_helpers.rb
index 61e00a3..e5aeb1e 100644
--- a/lib/view_component/storybook/controls/controls_helpers.rb
+++ b/lib/view_component/storybook/controls/controls_helpers.rb
@@ -23,34 +23,34 @@ def inherited(other)
other.controls = []
end
- def control(param, as:, default:, **opts)
+ def control(param, as:, **opts)
controls << case as
when :text
- Controls::TextConfig.new(param, default: default, **opts)
+ Controls::TextConfig.new(param, **opts)
when :boolean
- Controls::BooleanConfig.new(param, default: default, **opts)
+ Controls::BooleanConfig.new(param, **opts)
when :number
- Controls::NumberConfig.new(param, type: :number, default: default, **opts)
+ Controls::NumberConfig.new(param, type: :number, **opts)
when :range
- Controls::NumberConfig.new(param, type: :range, default: default, **opts)
+ Controls::NumberConfig.new(param, type: :range, **opts)
when :color
- Controls::ColorConfig.new(param, default: default, **opts)
+ Controls::ColorConfig.new(param, **opts)
when :object, :array
- Controls::ObjectConfig.new(param, default: default, **opts)
+ Controls::ObjectConfig.new(param, **opts)
when :select
- Controls::OptionsConfig.new(param, type: :select, default: default, **opts)
+ Controls::OptionsConfig.new(param, type: :select, **opts)
when :multi_select
- Controls::MultiOptionsConfig.new(param, type: :'multi-select', default: default, **opts)
+ Controls::MultiOptionsConfig.new(param, type: :'multi-select', **opts)
when :radio
- Controls::OptionsConfig.new(param, type: :radio, default: default, **opts)
+ Controls::OptionsConfig.new(param, type: :radio, **opts)
when :inline_radio
- Controls::OptionsConfig.new(param, type: :'inline-radio', default: default, **opts)
+ Controls::OptionsConfig.new(param, type: :'inline-radio', **opts)
when :check
- Controls::MultiOptionsConfig.new(param, type: :check, default: default, **opts)
+ Controls::MultiOptionsConfig.new(param, type: :check, **opts)
when :inline_check
- Controls::MultiOptionsConfig.new(param, type: :'inline-check', default: default, **opts)
+ Controls::MultiOptionsConfig.new(param, type: :'inline-check', **opts)
when :date
- Controls::DateConfig.new(param, default: default, **opts)
+ Controls::DateConfig.new(param, **opts)
else
raise "Unknonwn control type '#{as}'"
end
diff --git a/lib/view_component/storybook/controls/date_config.rb b/lib/view_component/storybook/controls/date_config.rb
index f952b34..a2da6c3 100644
--- a/lib/view_component/storybook/controls/date_config.rb
+++ b/lib/view_component/storybook/controls/date_config.rb
@@ -4,9 +4,9 @@ module ViewComponent
module Storybook
module Controls
class DateConfig < SimpleControlConfig
- def initialize(param, default:, name: nil, description: nil, **opts)
- super(param, default: default, name: name, description: description, **opts)
- end
+ # def initialize(param, default: nil , name: nil, description: nil, **opts)
+ # super(param, default: default, name: name, description: description, **opts)
+ # end
def type
:date
diff --git a/lib/view_component/storybook/controls/number_config.rb b/lib/view_component/storybook/controls/number_config.rb
index 4fc91bc..1a7d6b3 100644
--- a/lib/view_component/storybook/controls/number_config.rb
+++ b/lib/view_component/storybook/controls/number_config.rb
@@ -11,7 +11,7 @@ class NumberConfig < SimpleControlConfig
validates :type, presence: true
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
- def initialize(param, type:, default:, min: nil, max: nil, step: nil, name: nil, description: nil, **opts)
+ def initialize(param, type:, default: nil, min: nil, max: nil, step: nil, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
@type = type
@min = min
diff --git a/lib/view_component/storybook/controls/simple_control_config.rb b/lib/view_component/storybook/controls/simple_control_config.rb
index 4bfc345..a7693ac 100644
--- a/lib/view_component/storybook/controls/simple_control_config.rb
+++ b/lib/view_component/storybook/controls/simple_control_config.rb
@@ -7,7 +7,7 @@ module Controls
# A simple Control Config maps to one Storybook Control
# It has a value and pulls its value from params by key
class SimpleControlConfig < ControlConfig
- def initialize(param, default:, name: nil, description: nil, **opts)
+ def initialize(param, default: nil, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
end
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 41d14ee..9f075ea 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -106,6 +106,7 @@ def story_names
public_methods = public_instance_methods(false)
if code_object
# use the code_object to sort the methods to the order that they're declared
+
code_object.meths.select { |m| public_methods.include?(m.name) }.map(&:name)
else
# there is no code_object in some specs, particularly where we create Stories after Yard parsing
@@ -116,11 +117,21 @@ def story_names
end
def controls_for_story(story_name)
+ code_method = code_object.meths.find { |m| m.name == story_name }
+
controls.select do |control|
control.valid_for_story?(story_name)
+ end.map do |control|
+ dup_control = control.dup
+ default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == control.param.to_s }
+ if default_value_parts
+ dup_control.default = code_method.instance_eval(default_value_parts[1])
+ end
+ dup_control
end
end
end
end
end
end
+
diff --git a/spec/dummy/test/components/stories/combined_control_stories.rb b/spec/dummy/test/components/stories/combined_control_stories.rb
index 5aceb2c..6bc7e7d 100644
--- a/spec/dummy/test/components/stories/combined_control_stories.rb
+++ b/spec/dummy/test/components/stories/combined_control_stories.rb
@@ -1,23 +1,23 @@
# frozen_string_literal: true
class CombinedControlStories < ViewComponent::Storybook::Stories
- control :greeting, as: :text, default: "Hi", only: :combined_text
- control :name, as: :text, default: "Sarah", only: :combined_text
+ control :greeting, as: :text, only: :combined_text
+ control :name, as: :text, only: :combined_text
- def combined_text(greeting: "Hi!", name: "Sarah")
+ def combined_text(greeting: "Hi", name: "Sarah")
render Demo::ButtonComponent.new(button_text: "#{greeting} #{name}")
end
- control :verb_one, as: :text, default: "Big", only: :combined_rest_args
- control :noun_one, as: :text, default: "Car", only: :combined_rest_args
- control :verb_two, as: :text, default: "Small", only: :combined_rest_args
- control :noun_two, as: :text, default: "Boat", only: :combined_rest_args
+ control :verb_one, as: :text, only: :combined_rest_args
+ control :noun_one, as: :text, only: :combined_rest_args
+ control :verb_two, as: :text, only: :combined_rest_args
+ control :noun_two, as: :text, only: :combined_rest_args
def combined_rest_args(verb_one: "Big", noun_one: "Car", verb_two: "Small", noun_two: "Boat")
render ArgsComponent.new("#{verb_one} #{noun_one}", "#{verb_two} #{noun_two}")
end
- control :button_text, as: :text, default: "DO NOT PUSH!", description: "Make this irresistible.", only: :described_control
+ control :button_text, as: :text, description: "Make this irresistible.", only: :described_control
def described_control(button_text: 'DO NOT PUSH!' )
render Demo::ButtonComponent.new(button_text: button_text)
diff --git a/spec/dummy/test/components/stories/content_component_stories.rb b/spec/dummy/test/components/stories/content_component_stories.rb
index 64f5d13..bb80b03 100644
--- a/spec/dummy/test/components/stories/content_component_stories.rb
+++ b/spec/dummy/test/components/stories/content_component_stories.rb
@@ -7,7 +7,7 @@ def with_string_content
end
end
- control :content, as: :text, default: "Hello World!", only: :with_control_content
+ control :content, as: :text, only: :with_control_content
def with_control_content(content: "Hello World!")
render(ContentComponent.new) do
@@ -15,7 +15,7 @@ def with_control_content(content: "Hello World!")
end
end
- control :content, as: :text, default: "Hello World!", description: "My first computer program.", only: :with_described_control
+ control :content, as: :text, description: "My first computer program.", only: :with_described_control
def with_described_control(content: "Hello World!")
render(ContentComponent.new) do
diff --git a/spec/dummy/test/components/stories/demo/button_component_stories.rb b/spec/dummy/test/components/stories/demo/button_component_stories.rb
index 5c224d1..3fbbb6d 100644
--- a/spec/dummy/test/components/stories/demo/button_component_stories.rb
+++ b/spec/dummy/test/components/stories/demo/button_component_stories.rb
@@ -2,20 +2,16 @@
module Demo
class ButtonComponentStories < ViewComponent::Storybook::Stories
- control :button_text, as: :text, default: "OK", only: :short_button
+ control :button_text, as: :text
def short_button(button_text: "OK")
render ButtonComponent.new(button_text: button_text)
end
- control :button_text, as: :text, default: "Push Me!", only: :medium_button
-
def medium_button(button_text: "Push Me!")
render ButtonComponent.new(button_text: button_text)
end
- control :button_text, as: :text, default: "Really Really Long Button Text", only: :long_button
-
def long_button(button_text: "Really Really Long Button Text")
render ButtonComponent.new(button_text: button_text)
end
diff --git a/spec/dummy/test/components/stories/dry_component_stories.rb b/spec/dummy/test/components/stories/dry_component_stories.rb
index a747d04..59cc1a5 100644
--- a/spec/dummy/test/components/stories/dry_component_stories.rb
+++ b/spec/dummy/test/components/stories/dry_component_stories.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class DryComponentStories < ViewComponent::Storybook::Stories
- control :title, as: :text, default: "Hello World!"
+ control :title, as: :text
def default(title: "Hello World!")
render DryComponent.new(title: title)
diff --git a/spec/dummy/test/components/stories/kitchen_sink_component_stories.rb b/spec/dummy/test/components/stories/kitchen_sink_component_stories.rb
index 1284a76..5b63cbd 100644
--- a/spec/dummy/test/components/stories/kitchen_sink_component_stories.rb
+++ b/spec/dummy/test/components/stories/kitchen_sink_component_stories.rb
@@ -33,15 +33,15 @@ class KitchenSinkComponentStories < ViewComponent::Storybook::Stories
# object(:other_things, { hair: "Brown", eyes: "Blue" })
# end
- control :name, as: :text, default: "Jane Doe"
- control :birthday, as: :date, default: Date.new(1950, 3, 26)
- control :favorite_color, as: :color, default: "red"
- control :like_people, as: :boolean, default: true
- control :number_pets, as: :number, default: 2
- control :sports, as: :array, default: %w[football baseball]
- control :favorite_food, as: :select, default: "Ice Cream", options: ["Burgers", "Hot Dog", "Ice Cream", "Pizza"]
- control :mood, as: :radio, default: :happy, options: [:happy, :sad, :angry, :content], labels: { happy: "Happy", sad: "Sad", angry: "Angry", content: "Content" }
- control :other_things, as: :object, default: { hair: "Brown", eyes: "Blue" }
+ control :name, as: :text
+ control :birthday, as: :date
+ control :favorite_color, as: :color
+ control :like_people, as: :boolean
+ control :number_pets, as: :number
+ control :sports, as: :array
+ control :favorite_food, as: :select, options: ["Burgers", "Hot Dog", "Ice Cream", "Pizza"]
+ control :mood, as: :radio, options: [:happy, :sad, :angry, :content], labels: { happy: "Happy", sad: "Sad", angry: "Angry", content: "Content" }
+ control :other_things, as: :object
def jane_doe(
name: "Jane Doe",
diff --git a/spec/dummy/test/components/stories/kwargs_component_stories.rb b/spec/dummy/test/components/stories/kwargs_component_stories.rb
index 4675ba8..519b14b 100644
--- a/spec/dummy/test/components/stories/kwargs_component_stories.rb
+++ b/spec/dummy/test/components/stories/kwargs_component_stories.rb
@@ -1,15 +1,15 @@
# frozen_string_literal: true
class KwargsComponentStories < ViewComponent::Storybook::Stories
- control :message, as: :text, default: "Hello World!", only: :default
- control :param, as: :number, default: 1, only: :default
- control :other_param, as: :boolean, default: true, only: :default
+ control :message, as: :text, only: :default
+ control :param, as: :number, only: :default
+ control :other_param, as: :boolean, only: :default
def default(message: "Hello World!", param: 1, other_param: true)
render KwargsComponent.new(message: message, param: param, other_param: other_param)
end
- control :message, as: :text, default: "Hello World!", only: :fixed_args
+ control :message, as: :text, only: :fixed_args
def fixed_args(message: "Hello World!")
render KwargsComponent.new(message: message, param: 1, other_param: true)
end
diff --git a/spec/dummy/test/components/stories/layout_stories.rb b/spec/dummy/test/components/stories/layout_stories.rb
index ea38d39..08f3597 100644
--- a/spec/dummy/test/components/stories/layout_stories.rb
+++ b/spec/dummy/test/components/stories/layout_stories.rb
@@ -3,7 +3,7 @@
class LayoutStories < ViewComponent::Storybook::Stories
layout "admin"
- control :button_text, as: :text, default: "OK"
+ control :button_text, as: :text
def default(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
diff --git a/spec/dummy/test/components/stories/mixed_args_component_stories.rb b/spec/dummy/test/components/stories/mixed_args_component_stories.rb
index e51a679..3e8ab8f 100644
--- a/spec/dummy/test/components/stories/mixed_args_component_stories.rb
+++ b/spec/dummy/test/components/stories/mixed_args_component_stories.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
class MixedArgsComponentStories < ViewComponent::Storybook::Stories
- control :title, as: :text, default: "Hello World!", only: :default
- control :message, as: :text, default: "How you doing?", only: :default
+ control :title, as: :text, only: :default
+ control :message, as: :text, only: :default
def default(title: "Hello World!", message: "How you doing?")
render MixedArgsComponent.new(title, message: message)
diff --git a/spec/dummy/test/components/stories/no_layout_stories.rb b/spec/dummy/test/components/stories/no_layout_stories.rb
index 6b7c53a..bcf79a0 100644
--- a/spec/dummy/test/components/stories/no_layout_stories.rb
+++ b/spec/dummy/test/components/stories/no_layout_stories.rb
@@ -3,7 +3,7 @@
class NoLayoutStories < ViewComponent::Storybook::Stories
layout false
- control :button_text, as: :text, default: "OK"
+ control :button_text, as: :text
def default(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
diff --git a/spec/dummy/test/components/stories/parameters_stories.rb b/spec/dummy/test/components/stories/parameters_stories.rb
index 42fdeaa..b24fe1c 100644
--- a/spec/dummy/test/components/stories/parameters_stories.rb
+++ b/spec/dummy/test/components/stories/parameters_stories.rb
@@ -3,7 +3,7 @@
class ParametersStories < ViewComponent::Storybook::Stories
parameters( size: :small )
- control :button_text, as: :text, default: "OK"
+ control :button_text, as: :text
def stories_parameters(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
diff --git a/spec/dummy/test/components/stories/slots_stories.rb b/spec/dummy/test/components/stories/slots_stories.rb
index 296f38c..1d1c915 100644
--- a/spec/dummy/test/components/stories/slots_stories.rb
+++ b/spec/dummy/test/components/stories/slots_stories.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
class SlotsStories < ViewComponent::Storybook::Stories
- control :classes, as: :text, default: "mt-4"
- control :title, as: :text, default: "This is my title!"
- control :subtitle, as: :text, default: "This is my subtitle!"
- control :tab2, as: :text, default: "Tab B"
- control :item2_highlighted, as: :boolean, default: true
- control :item3, as: :text, default: "Item C"
- control :footer_classes, as: :text, default: "text-blue"
+ control :classes, as: :text
+ control :title, as: :text
+ control :subtitle, as: :text
+ control :tab2, as: :text
+ control :item2_highlighted, as: :boolean
+ control :item3, as: :text
+ control :footer_classes, as: :text
def default(classes: "mt-4", title: "This is my title!", subtitle: "This is my subtitle!", tab2: "Tab B", item2_highlighted: true, item3: "Item C", footer_classes: "text-blue")
render SlotsComponent.new(classes: classes) do |c|
From 72c5013133971215df7b13db5a4f8584338e963b Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 17 Dec 2022 22:34:34 -0500
Subject: [PATCH 12/35] rubocop
---
lib/view_component/storybook/stories.rb | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 9f075ea..42432a9 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -134,4 +134,3 @@ def controls_for_story(story_name)
end
end
end
-
From c6993c38c286960e7175b80a0f5b56c5f7352393 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 17 Dec 2022 22:39:49 -0500
Subject: [PATCH 13/35] cleanup
---
lib/view_component/storybook/story.rb | 7 -------
1 file changed, 7 deletions(-)
diff --git a/lib/view_component/storybook/story.rb b/lib/view_component/storybook/story.rb
index 5862108..43c1e27 100644
--- a/lib/view_component/storybook/story.rb
+++ b/lib/view_component/storybook/story.rb
@@ -20,13 +20,6 @@ def to_csf_params
end
csf_params
end
-
- def self.from_code_object(code_object, stories_config)
- name = code_object.name
- id = "#{stories_config.stories_name}/#{name.to_s.parameterize}".underscore
-
- new(id, name, {}, [])
- end
end
end
end
From cdafef450267e19fcdb054f0f79dd5db685a7aa2 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sun, 18 Dec 2022 07:38:11 -0500
Subject: [PATCH 14/35] Update gemspec
---
view_component_storybook.gemspec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/view_component_storybook.gemspec b/view_component_storybook.gemspec
index 3fa462a..aa1a3b0 100644
--- a/view_component_storybook.gemspec
+++ b/view_component_storybook.gemspec
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
"public gem pushes."
end
- spec.files = Dir["CHANGELOG.md", "LICENSE.txt", "README.md", "app/**/*", "config/**/*", "lib/**/*"]
+ spec.files = Dir["docs/CHANGELOG.md", "LICENSE.txt", "README.md", "lib/**/*"]
spec.require_paths = ["lib"]
From 8b5054a1f8255c73acc4c76b2e2378d933a8f69c Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sun, 18 Dec 2022 08:23:14 -0500
Subject: [PATCH 15/35] make StoriesCollection enumerable
---
lib/view_component/storybook/stories_collection.rb | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lib/view_component/storybook/stories_collection.rb b/lib/view_component/storybook/stories_collection.rb
index 0afa317..ee475b4 100644
--- a/lib/view_component/storybook/stories_collection.rb
+++ b/lib/view_component/storybook/stories_collection.rb
@@ -3,6 +3,10 @@
module ViewComponent
module Storybook
class StoriesCollection
+ include Enumerable
+
+ delegate_missing_to :stories
+
attr_reader :stories
def load(code_objects)
From b5622285a2f0c464894709cf9c7e947181bbfff7 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sun, 18 Dec 2022 09:15:50 -0500
Subject: [PATCH 16/35] Simplify control param parsing api
---
.../storybook/controls/boolean_config.rb | 9 ++++-----
.../storybook/controls/control_config.rb | 2 +-
.../storybook/controls/date_config.rb | 9 ++++-----
.../controls/multi_options_config.rb | 20 +++++++++----------
.../storybook/controls/number_config.rb | 9 ++++-----
.../storybook/controls/object_config.rb | 9 ++++-----
.../storybook/controls/options_config.rb | 9 ++++-----
.../controls/simple_control_config.rb | 4 ++--
lib/view_component/storybook/stories.rb | 18 ++++++-----------
spec/support/controls_examples.rb | 10 +++-------
.../controls/multi_options_config_spec.rb | 16 +++++++--------
11 files changed, 49 insertions(+), 66 deletions(-)
diff --git a/lib/view_component/storybook/controls/boolean_config.rb b/lib/view_component/storybook/controls/boolean_config.rb
index ac1f849..28b8661 100644
--- a/lib/view_component/storybook/controls/boolean_config.rb
+++ b/lib/view_component/storybook/controls/boolean_config.rb
@@ -12,17 +12,16 @@ def type
:boolean
end
- def value_from_params(params)
- params_value = super(params)
- if params_value.is_a?(String) && params_value.present?
- case params_value
+ def parse_param_value(value)
+ if value.is_a?(String) && value.present?
+ case value
when "true"
true
when "false"
false
end
else
- params_value
+ value
end
end
end
diff --git a/lib/view_component/storybook/controls/control_config.rb b/lib/view_component/storybook/controls/control_config.rb
index 5439fec..795e434 100644
--- a/lib/view_component/storybook/controls/control_config.rb
+++ b/lib/view_component/storybook/controls/control_config.rb
@@ -25,7 +25,7 @@ def to_csf_params
# :nocov:
end
- def value_from_params(params)
+ def parse_param_value(value)
# :nocov:
raise NotImplementedError
# :nocov:
diff --git a/lib/view_component/storybook/controls/date_config.rb b/lib/view_component/storybook/controls/date_config.rb
index a2da6c3..431072d 100644
--- a/lib/view_component/storybook/controls/date_config.rb
+++ b/lib/view_component/storybook/controls/date_config.rb
@@ -12,12 +12,11 @@ def type
:date
end
- def value_from_params(params)
- params_value = super(params)
- if params_value.is_a?(String)
- DateTime.iso8601(params_value)
+ def parse_param_value(value)
+ if value.is_a?(String)
+ DateTime.iso8601(value)
else
- params_value
+ value
end
end
diff --git a/lib/view_component/storybook/controls/multi_options_config.rb b/lib/view_component/storybook/controls/multi_options_config.rb
index d24dcf3..f4b68c3 100644
--- a/lib/view_component/storybook/controls/multi_options_config.rb
+++ b/lib/view_component/storybook/controls/multi_options_config.rb
@@ -7,20 +7,18 @@ class MultiOptionsConfig < BaseOptionsConfig
TYPES = %i[multi-select check inline-check].freeze
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
- validate :validate_default_value, unless: -> { options.nil? || default.nil? }
+ validate :validate_default, unless: -> { options.nil? || default.nil? }
- def initialize(param, type:, options:, default:, labels: nil, name: nil, description: nil, **opts)
+ def initialize(param, type:, options:, default: nil, labels: nil, name: nil, description: nil, **opts)
super(param, type: type, options: options, default: Array.wrap(default), labels: labels, param: param, name: name, description: description, **opts)
end
- def value_from_params(params)
- params_value = super(params)
-
- if params_value.is_a?(String)
- params_value = params_value.split(',')
- params_value = params_value.map(&:to_sym) if symbol_values
+ def parse_param_value(value)
+ if value.is_a?(String)
+ value = value.split(',')
+ value = value.map(&:to_sym) if symbol_values
end
- params_value
+ value
end
def to_csf_params
@@ -34,10 +32,10 @@ def csf_control_params
end
def symbol_values
- @symbol_values ||= default.first.is_a?(Symbol)
+ options.first.is_a?(Symbol)
end
- def validate_default_value
+ def validate_default
errors.add(:default, :inclusion) unless default.to_set <= options.to_set
end
end
diff --git a/lib/view_component/storybook/controls/number_config.rb b/lib/view_component/storybook/controls/number_config.rb
index 1a7d6b3..a60c2ed 100644
--- a/lib/view_component/storybook/controls/number_config.rb
+++ b/lib/view_component/storybook/controls/number_config.rb
@@ -19,12 +19,11 @@ def initialize(param, type:, default: nil, min: nil, max: nil, step: nil, name:
@step = step
end
- def value_from_params(params)
- params_value = super(params)
- if params_value.is_a?(String) && params_value.present?
- (params_value.to_f % 1) > 0 ? params_value.to_f : params_value.to_i
+ def parse_param_value(value)
+ if value.is_a?(String) && value.present?
+ (value.to_f % 1) > 0 ? value.to_f : value.to_i
else
- params_value
+ value
end
end
diff --git a/lib/view_component/storybook/controls/object_config.rb b/lib/view_component/storybook/controls/object_config.rb
index c6220dc..420e00b 100644
--- a/lib/view_component/storybook/controls/object_config.rb
+++ b/lib/view_component/storybook/controls/object_config.rb
@@ -8,10 +8,9 @@ def type
:object
end
- def value_from_params(params)
- params_value = super(params)
- if params_value.is_a?(String)
- parsed_json = JSON.parse(params_value)
+ def parse_param_value(value)
+ if value.is_a?(String)
+ parsed_json = JSON.parse(value)
if parsed_json.is_a?(Array)
parsed_json.map do |item|
item.is_a?(Hash) ? item.deep_symbolize_keys : item
@@ -20,7 +19,7 @@ def value_from_params(params)
parsed_json.deep_symbolize_keys
end
else
- params_value
+ value
end
end
end
diff --git a/lib/view_component/storybook/controls/options_config.rb b/lib/view_component/storybook/controls/options_config.rb
index 0ad602a..c78e55d 100644
--- a/lib/view_component/storybook/controls/options_config.rb
+++ b/lib/view_component/storybook/controls/options_config.rb
@@ -9,12 +9,11 @@ class OptionsConfig < BaseOptionsConfig
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
validates :default, inclusion: { in: ->(config) { config.options } }, unless: -> { options.nil? || default.nil? }
- def value_from_params(params)
- params_value = super(params)
- if params_value.is_a?(String) && symbol_value
- params_value.to_sym
+ def parse_param_value(value)
+ if value.is_a?(String) && symbol_value
+ value.to_sym
else
- params_value
+ value
end
end
diff --git a/lib/view_component/storybook/controls/simple_control_config.rb b/lib/view_component/storybook/controls/simple_control_config.rb
index a7693ac..ae88fca 100644
--- a/lib/view_component/storybook/controls/simple_control_config.rb
+++ b/lib/view_component/storybook/controls/simple_control_config.rb
@@ -21,8 +21,8 @@ def to_csf_params
}
end
- def value_from_params(params)
- params.key?(param) ? params[param] : default
+ def parse_param_value(value)
+ value
end
private
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 42432a9..51b2823 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -23,7 +23,7 @@ def parameters(params = nil)
end
def stories_name
- name.chomp("V2").chomp("Stories").underscore
+ name.chomp("Stories").underscore
end
def preview_name
@@ -38,7 +38,6 @@ def to_csf_params
end
def write_csf_json
- # json_path = File.join(stories_path, "#{stories_name}.stories.json")
Rails.logger.debug { "stories_json_path: #{stories_json_path}" }
File.write(stories_json_path, JSON.pretty_generate(to_csf_params))
stories_json_path
@@ -55,6 +54,7 @@ def find_story_config(name)
# Returns the arguments for rendering of the component in its layout
def render_args(story_name, params: {})
+ # mostly reimplementing the super method but adding logic to parse the params through the controls
story_params_names = instance_method(story_name).parameters.map(&:last)
provided_params = params.slice(*story_params_names).to_h.symbolize_keys
@@ -62,11 +62,9 @@ def render_args(story_name, params: {})
control_parsed_params = provided_params.to_h do |param, value|
control = story_config.controls.find { |c| c.param == param }
- if control
- [param, control.value_from_params(params)]
- else
- [param, value]
- end
+ value = control.parse_param_value(value) if control
+
+ [param, value]
end
result = control_parsed_params.empty? ? new.public_send(story_name) : new.public_send(story_name, **control_parsed_params)
@@ -97,16 +95,12 @@ def story_id(name)
"#{stories_name}/#{name.to_s.parameterize}".underscore
end
- # def story_methods
- # @story_methods ||= public_instance_methods(false).map { |name| instance_method(name) }
- # end
-
def story_names
@story_names ||= begin
public_methods = public_instance_methods(false)
if code_object
+ # ordering of public_instance_methods isn't consistent
# use the code_object to sort the methods to the order that they're declared
-
code_object.meths.select { |m| public_methods.include?(m.name) }.map(&:name)
else
# there is no code_object in some specs, particularly where we create Stories after Yard parsing
diff --git a/spec/support/controls_examples.rb b/spec/support/controls_examples.rb
index 2735ddb..0c294ab 100644
--- a/spec/support/controls_examples.rb
+++ b/spec/support/controls_examples.rb
@@ -127,17 +127,13 @@
end
let(:param_value) { "OK" }
- describe "#value_from_params" do
+ describe "#parse_param_value" do
it "parses param_value" do
- expect(subject.value_from_params(subject.param => param_value)).to eq(default_value)
+ expect(subject.parse_param_value(param_value)).to eq(default_value)
end
it "parses nil param_value" do
- expect(subject.value_from_params(subject.param => nil)).to be_nil
- end
-
- it "returns default_value if param is missing" do
- expect(subject.value_from_params({})).to eq(default_value)
+ expect(subject.parse_param_value(nil)).to be_nil
end
end
end
diff --git a/spec/view_component/storybook/controls/multi_options_config_spec.rb b/spec/view_component/storybook/controls/multi_options_config_spec.rb
index 5277454..c6488d5 100644
--- a/spec/view_component/storybook/controls/multi_options_config_spec.rb
+++ b/spec/view_component/storybook/controls/multi_options_config_spec.rb
@@ -28,32 +28,32 @@
end
end
- describe "#value_from_params" do
- subject { described_class.new(:opt, type: :check, options: options, default: defualt_value) }
+ describe "#parse_param_value" do
+ subject { described_class.new(:opt, type: :check, options: options) }
context "with array options" do
let(:options) { %w[red blue yellow] }
- let(:defualt_value) { ["blue"] }
+ # let(:defualt_value) { ["blue"] }
it "parses single param_value" do
- expect(subject.value_from_params(opt: "blue")).to eq(["blue"])
+ expect(subject.parse_param_value("blue")).to eq(["blue"])
end
it "parses multiple param_value" do
- expect(subject.value_from_params(opt: "blue,red")).to eq(%w[blue red])
+ expect(subject.parse_param_value("blue,red")).to eq(%w[blue red])
end
end
context "with symbol options" do
let(:options) { %i[red blue yellow] }
- let(:defualt_value) { [:blue] }
+ # let(:defualt_value) { [:blue] }
it "parses single param_value" do
- expect(subject.value_from_params(opt: "blue")).to eq([:blue])
+ expect(subject.parse_param_value("blue")).to eq([:blue])
end
it "parses multiple param_value" do
- expect(subject.value_from_params(opt: "blue,red")).to eq(%i[blue red])
+ expect(subject.parse_param_value("blue,red")).to eq(%i[blue red])
end
end
end
From 820a8270da056e66d7d9c75567d48b9c1162e3c0 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sun, 18 Dec 2022 09:45:36 -0500
Subject: [PATCH 17/35] Rename Control
---
docs/CHANGELOG.md | 6 ++---
lib/view_component/storybook/controls.rb | 23 ++++++++--------
...base_options_config.rb => base_options.rb} | 2 +-
.../{boolean_config.rb => boolean.rb} | 2 +-
.../controls/{color_config.rb => color.rb} | 2 +-
.../{control_config.rb => control.rb} | 2 +-
.../storybook/controls/controls_helpers.rb | 26 +++++++++----------
.../controls/{date_config.rb => date.rb} | 8 ++----
...lti_options_config.rb => multi_options.rb} | 2 +-
.../controls/{number_config.rb => number.rb} | 2 +-
.../controls/{object_config.rb => object.rb} | 2 +-
.../{options_config.rb => options.rb} | 2 +-
...le_control_config.rb => simple_control.rb} | 2 +-
.../controls/{text_config.rb => text.rb} | 2 +-
.../storybook/controls/boolean_config_spec.rb | 2 +-
.../storybook/controls/color_config_spec.rb | 2 +-
.../controls/controls_helpers_spec.rb | 20 +++++++-------
.../storybook/controls/date_config_spec.rb | 4 +--
.../controls/multi_options_config_spec.rb | 2 +-
.../storybook/controls/number_config_spec.rb | 2 +-
.../storybook/controls/object_config_spec.rb | 2 +-
.../storybook/controls/options_config_spec.rb | 2 +-
.../storybook/controls/text_config_spec.rb | 2 +-
23 files changed, 58 insertions(+), 63 deletions(-)
rename lib/view_component/storybook/controls/{base_options_config.rb => base_options.rb} (93%)
rename lib/view_component/storybook/controls/{boolean_config.rb => boolean.rb} (92%)
rename lib/view_component/storybook/controls/{color_config.rb => color.rb} (92%)
rename lib/view_component/storybook/controls/{control_config.rb => control.rb} (97%)
rename lib/view_component/storybook/controls/{date_config.rb => date.rb} (66%)
rename lib/view_component/storybook/controls/{multi_options_config.rb => multi_options.rb} (96%)
rename lib/view_component/storybook/controls/{number_config.rb => number.rb} (95%)
rename lib/view_component/storybook/controls/{object_config.rb => object.rb} (92%)
rename lib/view_component/storybook/controls/{options_config.rb => options.rb} (94%)
rename lib/view_component/storybook/controls/{simple_control_config.rb => simple_control.rb} (95%)
rename lib/view_component/storybook/controls/{text_config.rb => text.rb} (78%)
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index eaea6fa..a4249ac 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -44,7 +44,7 @@ Last 0.x release
* Klazz Control
* Deprecated Controls DSL
* Add support for Object Controls with array values
-* Remove ArrayConfig - array aliases ObjectConfig
+* Remove ArrayConfig - array aliases Object
* Updated Options Control to match Storybook 6.2 syntax
* `options` as array
* add `labels` option
@@ -64,6 +64,6 @@ Last 0.x release
## 0.7.0
-* Add inclusion validation to NumberConfig type
-* Support ObjectConfigs with nested values
+* Add inclusion validation to Number type
+* Support Objects with nested values
* Support nil control values
\ No newline at end of file
diff --git a/lib/view_component/storybook/controls.rb b/lib/view_component/storybook/controls.rb
index 89963cb..92154f4 100644
--- a/lib/view_component/storybook/controls.rb
+++ b/lib/view_component/storybook/controls.rb
@@ -7,18 +7,17 @@ module Storybook
module Controls
extend ActiveSupport::Autoload
- autoload :ControlConfig
- autoload :SimpleControlConfig
- autoload :TextConfig
- autoload :BooleanConfig
- autoload :ColorConfig
- autoload :NumberConfig
- autoload :BaseOptionsConfig
- autoload :OptionsConfig
- autoload :MultiOptionsConfig
- autoload :DateConfig
- autoload :ObjectConfig
- autoload :CustomConfig
+ autoload :Control
+ autoload :SimpleControl
+ autoload :Text
+ autoload :Boolean
+ autoload :Color
+ autoload :Number
+ autoload :BaseOptions
+ autoload :Options
+ autoload :MultiOptions
+ autoload :Date
+ autoload :Object
autoload :ControlsHelpers
end
end
diff --git a/lib/view_component/storybook/controls/base_options_config.rb b/lib/view_component/storybook/controls/base_options.rb
similarity index 93%
rename from lib/view_component/storybook/controls/base_options_config.rb
rename to lib/view_component/storybook/controls/base_options.rb
index e18aa24..3d3967f 100644
--- a/lib/view_component/storybook/controls/base_options_config.rb
+++ b/lib/view_component/storybook/controls/base_options.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class BaseOptionsConfig < SimpleControlConfig
+ class BaseOptions < SimpleControl
attr_reader :type, :options, :labels
validates :type, :options, presence: true
diff --git a/lib/view_component/storybook/controls/boolean_config.rb b/lib/view_component/storybook/controls/boolean.rb
similarity index 92%
rename from lib/view_component/storybook/controls/boolean_config.rb
rename to lib/view_component/storybook/controls/boolean.rb
index 28b8661..f2351dc 100644
--- a/lib/view_component/storybook/controls/boolean_config.rb
+++ b/lib/view_component/storybook/controls/boolean.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class BooleanConfig < SimpleControlConfig
+ class Boolean < SimpleControl
BOOLEAN_VALUES = [true, false].freeze
validates :default, inclusion: { in: BOOLEAN_VALUES }, unless: -> { default.nil? }
diff --git a/lib/view_component/storybook/controls/color_config.rb b/lib/view_component/storybook/controls/color.rb
similarity index 92%
rename from lib/view_component/storybook/controls/color_config.rb
rename to lib/view_component/storybook/controls/color.rb
index 9bc32fc..3bc1acd 100644
--- a/lib/view_component/storybook/controls/color_config.rb
+++ b/lib/view_component/storybook/controls/color.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class ColorConfig < SimpleControlConfig
+ class Color < SimpleControl
attr_reader :preset_colors
def initialize(param, default: nil, preset_colors: nil, name: nil, description: nil, **opts)
diff --git a/lib/view_component/storybook/controls/control_config.rb b/lib/view_component/storybook/controls/control.rb
similarity index 97%
rename from lib/view_component/storybook/controls/control_config.rb
rename to lib/view_component/storybook/controls/control.rb
index 795e434..60a2144 100644
--- a/lib/view_component/storybook/controls/control_config.rb
+++ b/lib/view_component/storybook/controls/control.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class ControlConfig
+ class Control
include ActiveModel::Validations
validates :param, presence: true
diff --git a/lib/view_component/storybook/controls/controls_helpers.rb b/lib/view_component/storybook/controls/controls_helpers.rb
index e5aeb1e..2c357bf 100644
--- a/lib/view_component/storybook/controls/controls_helpers.rb
+++ b/lib/view_component/storybook/controls/controls_helpers.rb
@@ -26,31 +26,31 @@ def inherited(other)
def control(param, as:, **opts)
controls << case as
when :text
- Controls::TextConfig.new(param, **opts)
+ Controls::Text.new(param, **opts)
when :boolean
- Controls::BooleanConfig.new(param, **opts)
+ Controls::Boolean.new(param, **opts)
when :number
- Controls::NumberConfig.new(param, type: :number, **opts)
+ Controls::Number.new(param, type: :number, **opts)
when :range
- Controls::NumberConfig.new(param, type: :range, **opts)
+ Controls::Number.new(param, type: :range, **opts)
when :color
- Controls::ColorConfig.new(param, **opts)
+ Controls::Color.new(param, **opts)
when :object, :array
- Controls::ObjectConfig.new(param, **opts)
+ Controls::Object.new(param, **opts)
when :select
- Controls::OptionsConfig.new(param, type: :select, **opts)
+ Controls::Options.new(param, type: :select, **opts)
when :multi_select
- Controls::MultiOptionsConfig.new(param, type: :'multi-select', **opts)
+ Controls::MultiOptions.new(param, type: :'multi-select', **opts)
when :radio
- Controls::OptionsConfig.new(param, type: :radio, **opts)
+ Controls::Options.new(param, type: :radio, **opts)
when :inline_radio
- Controls::OptionsConfig.new(param, type: :'inline-radio', **opts)
+ Controls::Options.new(param, type: :'inline-radio', **opts)
when :check
- Controls::MultiOptionsConfig.new(param, type: :check, **opts)
+ Controls::MultiOptions.new(param, type: :check, **opts)
when :inline_check
- Controls::MultiOptionsConfig.new(param, type: :'inline-check', **opts)
+ Controls::MultiOptions.new(param, type: :'inline-check', **opts)
when :date
- Controls::DateConfig.new(param, **opts)
+ Controls::Date.new(param, **opts)
else
raise "Unknonwn control type '#{as}'"
end
diff --git a/lib/view_component/storybook/controls/date_config.rb b/lib/view_component/storybook/controls/date.rb
similarity index 66%
rename from lib/view_component/storybook/controls/date_config.rb
rename to lib/view_component/storybook/controls/date.rb
index 431072d..3e1d9a4 100644
--- a/lib/view_component/storybook/controls/date_config.rb
+++ b/lib/view_component/storybook/controls/date.rb
@@ -3,11 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class DateConfig < SimpleControlConfig
- # def initialize(param, default: nil , name: nil, description: nil, **opts)
- # super(param, default: default, name: name, description: description, **opts)
- # end
-
+ class Date < SimpleControl
def type
:date
end
@@ -24,7 +20,7 @@ def parse_param_value(value)
def csf_value
case default
- when Date
+ when ::Date
default.in_time_zone
when Time
default.iso8601
diff --git a/lib/view_component/storybook/controls/multi_options_config.rb b/lib/view_component/storybook/controls/multi_options.rb
similarity index 96%
rename from lib/view_component/storybook/controls/multi_options_config.rb
rename to lib/view_component/storybook/controls/multi_options.rb
index f4b68c3..a9a4f97 100644
--- a/lib/view_component/storybook/controls/multi_options_config.rb
+++ b/lib/view_component/storybook/controls/multi_options.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class MultiOptionsConfig < BaseOptionsConfig
+ class MultiOptions < BaseOptions
TYPES = %i[multi-select check inline-check].freeze
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
diff --git a/lib/view_component/storybook/controls/number_config.rb b/lib/view_component/storybook/controls/number.rb
similarity index 95%
rename from lib/view_component/storybook/controls/number_config.rb
rename to lib/view_component/storybook/controls/number.rb
index a60c2ed..04dde63 100644
--- a/lib/view_component/storybook/controls/number_config.rb
+++ b/lib/view_component/storybook/controls/number.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class NumberConfig < SimpleControlConfig
+ class Number < SimpleControl
TYPES = %i[number range].freeze
attr_reader :type, :min, :max, :step
diff --git a/lib/view_component/storybook/controls/object_config.rb b/lib/view_component/storybook/controls/object.rb
similarity index 92%
rename from lib/view_component/storybook/controls/object_config.rb
rename to lib/view_component/storybook/controls/object.rb
index 420e00b..ffe892c 100644
--- a/lib/view_component/storybook/controls/object_config.rb
+++ b/lib/view_component/storybook/controls/object.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class ObjectConfig < SimpleControlConfig
+ class Object < SimpleControl
def type
:object
end
diff --git a/lib/view_component/storybook/controls/options_config.rb b/lib/view_component/storybook/controls/options.rb
similarity index 94%
rename from lib/view_component/storybook/controls/options_config.rb
rename to lib/view_component/storybook/controls/options.rb
index c78e55d..cc7a10e 100644
--- a/lib/view_component/storybook/controls/options_config.rb
+++ b/lib/view_component/storybook/controls/options.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class OptionsConfig < BaseOptionsConfig
+ class Options < BaseOptions
TYPES = %i[select radio inline-radio].freeze
validates :type, inclusion: { in: TYPES }, unless: -> { type.nil? }
diff --git a/lib/view_component/storybook/controls/simple_control_config.rb b/lib/view_component/storybook/controls/simple_control.rb
similarity index 95%
rename from lib/view_component/storybook/controls/simple_control_config.rb
rename to lib/view_component/storybook/controls/simple_control.rb
index ae88fca..e50d6cc 100644
--- a/lib/view_component/storybook/controls/simple_control_config.rb
+++ b/lib/view_component/storybook/controls/simple_control.rb
@@ -6,7 +6,7 @@ module Controls
##
# A simple Control Config maps to one Storybook Control
# It has a value and pulls its value from params by key
- class SimpleControlConfig < ControlConfig
+ class SimpleControl < Control
def initialize(param, default: nil, name: nil, description: nil, **opts)
super(param, default: default, name: name, description: description, **opts)
end
diff --git a/lib/view_component/storybook/controls/text_config.rb b/lib/view_component/storybook/controls/text.rb
similarity index 78%
rename from lib/view_component/storybook/controls/text_config.rb
rename to lib/view_component/storybook/controls/text.rb
index 45970e5..47e1116 100644
--- a/lib/view_component/storybook/controls/text_config.rb
+++ b/lib/view_component/storybook/controls/text.rb
@@ -3,7 +3,7 @@
module ViewComponent
module Storybook
module Controls
- class TextConfig < SimpleControlConfig
+ class Text < SimpleControl
def type
:text
end
diff --git a/spec/view_component/storybook/controls/boolean_config_spec.rb b/spec/view_component/storybook/controls/boolean_config_spec.rb
index c84bfec..f000cd7 100644
--- a/spec/view_component/storybook/controls/boolean_config_spec.rb
+++ b/spec/view_component/storybook/controls/boolean_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::Controls::BooleanConfig do
+RSpec.describe ViewComponent::Storybook::Controls::Boolean do
subject { described_class.new(param, default: default_value, name: name, description: description) }
let(:type) { :boolean }
diff --git a/spec/view_component/storybook/controls/color_config_spec.rb b/spec/view_component/storybook/controls/color_config_spec.rb
index 2d6d9b3..8feda74 100644
--- a/spec/view_component/storybook/controls/color_config_spec.rb
+++ b/spec/view_component/storybook/controls/color_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::Controls::ColorConfig do
+RSpec.describe ViewComponent::Storybook::Controls::Color do
subject { described_class.new(param, default: default_value, name: name, description: description) }
let(:type) { :color }
diff --git a/spec/view_component/storybook/controls/controls_helpers_spec.rb b/spec/view_component/storybook/controls/controls_helpers_spec.rb
index 3caf9be..7ccde85 100644
--- a/spec/view_component/storybook/controls/controls_helpers_spec.rb
+++ b/spec/view_component/storybook/controls/controls_helpers_spec.rb
@@ -16,7 +16,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::TextConfig,
+ class: ViewComponent::Storybook::Controls::Text,
param: :name,
default: "Jane Doe"
}
@@ -27,7 +27,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::BooleanConfig,
+ class: ViewComponent::Storybook::Controls::Boolean,
param: :active,
default: true
}
@@ -39,7 +39,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::NumberConfig,
+ class: ViewComponent::Storybook::Controls::Number,
param: :count,
type: :number,
default: 2,
@@ -54,7 +54,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::NumberConfig,
+ class: ViewComponent::Storybook::Controls::Number,
param: :count,
type: :number,
default: 2,
@@ -71,7 +71,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::NumberConfig,
+ class: ViewComponent::Storybook::Controls::Number,
param: :count,
type: :range,
default: 2,
@@ -86,7 +86,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::NumberConfig,
+ class: ViewComponent::Storybook::Controls::Number,
param: :count,
type: :range,
default: 2,
@@ -102,7 +102,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::ColorConfig,
+ class: ViewComponent::Storybook::Controls::Color,
param: :favorite,
default: "red"
}
@@ -113,7 +113,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::ObjectConfig,
+ class: ViewComponent::Storybook::Controls::Object,
param: :description,
default: { hair: "Brown", eyes: "Blue" }
}
@@ -127,7 +127,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::OptionsConfig,
+ class: ViewComponent::Storybook::Controls::Options,
param: :food,
type: type.to_sym,
default: :pizza,
@@ -144,7 +144,7 @@
include_examples "has controls attributes",
{
- class: ViewComponent::Storybook::Controls::MultiOptionsConfig,
+ class: ViewComponent::Storybook::Controls::MultiOptions,
param: :food,
type: type.to_sym,
default: [:pizza],
diff --git a/spec/view_component/storybook/controls/date_config_spec.rb b/spec/view_component/storybook/controls/date_config_spec.rb
index c3852fc..96acf21 100644
--- a/spec/view_component/storybook/controls/date_config_spec.rb
+++ b/spec/view_component/storybook/controls/date_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::Controls::DateConfig do
+RSpec.describe ViewComponent::Storybook::Controls::Date do
subject { described_class.new(param, default: default_value, name: name, description: description) }
shared_examples "valid with object value" do
@@ -17,7 +17,7 @@
expect(subject.valid?).to be(true)
end
- it "has an integer value in csf_params" do
+ it "has an expected value in csf_params" do
expect(subject.to_csf_params).to eq(
{
args: {
diff --git a/spec/view_component/storybook/controls/multi_options_config_spec.rb b/spec/view_component/storybook/controls/multi_options_config_spec.rb
index c6488d5..6346e15 100644
--- a/spec/view_component/storybook/controls/multi_options_config_spec.rb
+++ b/spec/view_component/storybook/controls/multi_options_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::Controls::MultiOptionsConfig do
+RSpec.describe ViewComponent::Storybook::Controls::MultiOptions do
described_class::TYPES.each do |type|
context "type: #{type}" do
subject { described_class.new(param, type: type, options: options, default: default_value, labels: labels, name: name, description: description) }
diff --git a/spec/view_component/storybook/controls/number_config_spec.rb b/spec/view_component/storybook/controls/number_config_spec.rb
index ad531a2..4d02ed1 100644
--- a/spec/view_component/storybook/controls/number_config_spec.rb
+++ b/spec/view_component/storybook/controls/number_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::Controls::NumberConfig do
+RSpec.describe ViewComponent::Storybook::Controls::Number do
described_class::TYPES.each do |number_type|
context "with '#{number_type}' type" do
subject { described_class.new(param, type: number_type, default: default_value, name: name, description: description) }
diff --git a/spec/view_component/storybook/controls/object_config_spec.rb b/spec/view_component/storybook/controls/object_config_spec.rb
index b8d90dc..4e723aa 100644
--- a/spec/view_component/storybook/controls/object_config_spec.rb
+++ b/spec/view_component/storybook/controls/object_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::Controls::ObjectConfig do
+RSpec.describe ViewComponent::Storybook::Controls::Object do
subject { described_class.new(param, default: default_value, name: name, description: description) }
let(:separator) { "," }
diff --git a/spec/view_component/storybook/controls/options_config_spec.rb b/spec/view_component/storybook/controls/options_config_spec.rb
index a80dabf..a6dc47d 100644
--- a/spec/view_component/storybook/controls/options_config_spec.rb
+++ b/spec/view_component/storybook/controls/options_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::Controls::OptionsConfig do
+RSpec.describe ViewComponent::Storybook::Controls::Options do
described_class::TYPES.each do |type|
context "type: #{type}" do
subject { described_class.new(param, type: type, options: options, default: default_value, labels: labels, name: name, description: description) }
diff --git a/spec/view_component/storybook/controls/text_config_spec.rb b/spec/view_component/storybook/controls/text_config_spec.rb
index 1660411..4154bdf 100644
--- a/spec/view_component/storybook/controls/text_config_spec.rb
+++ b/spec/view_component/storybook/controls/text_config_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::Controls::TextConfig do
+RSpec.describe ViewComponent::Storybook::Controls::Text do
subject { described_class.new(param, default: default_value, name: name, description: description) }
let(:type) { :text }
From c2511f23e862939efb95214ead683e333a1f0b68 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sun, 18 Dec 2022 11:43:30 -0500
Subject: [PATCH 18/35] Update docs
---
docs/configuration.md | 10 +-
docs/guide/constructor.md | 75 -------
docs/guide/content.md | 119 ----------
docs/guide/controls.md | 211 ++++++++++--------
docs/guide/getting-started.md | 39 ++--
docs/guide/legacy_controls_dsl.md | 30 ---
docs/guide/parameters.md | 17 +-
docs/guide/slots.md | 2 +-
docs/guide/stories.md | 67 +-----
lib/view_component/storybook/stories.rb | 8 +-
.../stories/control_default_stories.rb | 11 +
spec/view_component/storybook/stories_spec.rb | 20 ++
12 files changed, 186 insertions(+), 423 deletions(-)
delete mode 100644 docs/guide/constructor.md
delete mode 100644 docs/guide/content.md
delete mode 100644 docs/guide/legacy_controls_dsl.md
create mode 100644 spec/dummy/test/components/stories/control_default_stories.rb
diff --git a/docs/configuration.md b/docs/configuration.md
index d644be8..3a20cc1 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -14,7 +14,7 @@ FOr local development this is typically:
// .storybook/preview.js
export const parameters = {
server: {
- url: `http://localhost:3000/rails/stories`,
+ url: `http://localhost:3000/rails/view_components`,
},
};
```
@@ -27,20 +27,22 @@ Story classes live in `test/components/stories`, which can be configured using t
```ruby
# config/application.rb
-config.view_component_storybook.stories_path = Rails.root.join("spec/components/stories")
+config.view_component_storybook.stories_paths << Rails.root.join("spec/components/stories")
```
## Stories Route
-Stories are served from by default. To use a different endpoint, set the `stories_route` option:
+Stories are served from the same route as ViewComponent previews by default. To use a different endpoint, set the ViewComponent `previews_route` option:
```ruby
# config/application.rb
-config.view_component_storybook.stories_route = "/stories"
+config.view_component.preview_route = "/stories"
```
This example will make the previews available from .
+For more details see the [ViewCompontent `preview_route` documentation](https://viewcomponent.org/api.html#preview_route--string)
+
## Stories Title Generation
You may wish to customize how the title of stories are generated, this can be done by setting a custom `stories_title_generator` lambda function:
diff --git a/docs/guide/constructor.md b/docs/guide/constructor.md
deleted file mode 100644
index bb6480d..0000000
--- a/docs/guide/constructor.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-layout: default
-title: Constructor
-parent: Writing ViewComponent Stories
-nav_order: 3
----
-
-# Constructor
-
-Sotries configure arguments passed to the component's constructor with `constructor`.
-
-Given a header class that looks like the following:
-
-```ruby
-class HeaderComponent < ViewComponent::Base
- def initialize(tag, bold:)
- @tag = tag
- @bold = bold
- end
-end
-```
-
-To render a HeaderComponent, use the `constructor` method.
-
-```ruby
-class HeaderComponentStories < ViewComponent::Storybook::Stories
- story(:h1) do
- constructor("h1", bold: false)
- end
-end
-```
-
-`constructor` supports positional and keyword arguments as well as optional arguments with default values.
-
-## Controls
-
-`constructor` arguments also support controls making the values dynamicaly configurable in Storybook:
-
-```ruby
-class HeaderComponentStories < ViewComponent::Storybook::Stories
- story(:h1) do
- constructor(text("h1"), bold: boolean(false))
- end
-end
-```
-
-The list of Control options is described in [Controls](controls.md)
-
-## Validation
-
-ViewComponent Storybook validates that the constructor arguments match allowed arguments of the component constructor throwing a `ViewComponent::Storybook::StoryConfig::ValidationError` if there is a mismatch.
-
-Each of these examples result in an validation exception:
-
-```ruby
-class HeaderComponentStories < ViewComponent::Storybook::Stories
- story(:not_enough_positional_args) do
- constructor(bold: false)
- end
-
- story(:too_many_positional_args) do
- constructor("h1", "p", bold: false)
- end
-
- story(:missing_kwargs) do
- constructor("h1")
- end
-
- story(:extra_kwargs) do
- constructor("h1", bold: false, size: "2em")
- end
-end
-```
-
-_To view documentation for controls DSL (deprecated) see [legacy_controls_dsl](/guide/legacy_controls_dsl.md)._
\ No newline at end of file
diff --git a/docs/guide/content.md b/docs/guide/content.md
deleted file mode 100644
index a1ca84b..0000000
--- a/docs/guide/content.md
+++ /dev/null
@@ -1,119 +0,0 @@
----
-layout: default
-title: Content
-parent: Writing ViewComponent Stories
-nav_order: 5
----
-
-# Content
-
-ViewComponents support content passed as a block to their constructor. See ViewComponent [documentation](https://viewcomponent.org/guide/getting-started.html#implementation) for full details.
-
-Stories provide this feature via a block passed to the `constructor` method:
-
-```ruby
-# app/components/example_component.rb
-class ExampleComponent < ViewComponent::Base
- def initialize(title:)
- @title = title
- end
-end
-```
-```erb
-<%# app/components/example_component.html.erb %>
-<%= content %>
-```
-```ruby
-# test/components/stories/example_component_stories.rb
-class ExampleComponentStories < ViewComponent::Storybook::Stories
- story :hello do
- constructor(title: "my title") do
- "Hello World!"
- end
- end
-end
-```
-
-Returning the rendered html to Storybook:
-
-```html
-Hello, World!
-```
-
-## Content View Helpers
-
-The `constructor` block is evaluated in the context of the view allowing view helpers
-when generating the content. For example:
-
-```ruby
-# test/components/stories/example_component_stories.rb
-class ExampleComponentStories < ViewComponent::Storybook::Stories
- story :hello_link do
- constructor(title: "my title") do
- link_to "Hello World!", "#"
- end
- end
-end
-```
-
-Returning the rendered html to Storybook:
-
-```html
-Hello, World!
-```
-
-## #content
-
-In addition to passing content as a block to `constructor` ViewComponent Storybook accepts content with `content`. Content is passed as a string value or a block that supports view helpers.
-
-```ruby
-# test/components/stories/example_component_stories.rb
-class ExampleComponentStories < ViewComponent::Storybook::Stories
- story :hello_content do
- constructor(title: "my title")
- content("Hello World!")
- end
-
- story :hello_content_block do
- constructor(title: "my title")
- content do
- "Hello World!"
- end
- end
-
- story :hello_content_block_link do
- constructor(title: "my title")
- content do
- link_to "Hello World!", "#"
- end
- end
-end
-```
-
-## Dynamic content with Controls
-
-Passing a Control to `content` enables dynamic rendering of the content in Storybook:
-
-```ruby
-# test/components/stories/example_component_stories.rb
-class ExampleComponentStories < ViewComponent::Storybook::Stories
- story :hello_content do
- constructor(title: "my title")
- content(text("Hello World!"))
- end
-end
-```
-
-### Content control naming
-
-By default the Storybook control will have the name "Content". Like all controls The name is customized with [`name`](controls.md#customizing-the-control-name):
-
-```ruby
-# test/components/stories/example_component_stories.rb
-class ExampleComponentStories < ViewComponent::Storybook::Stories
- story :hello_content do
- constructor(title: "my title")
- content(text("Hello World!").name("Message"))
- end
-end
-```
diff --git a/docs/guide/controls.md b/docs/guide/controls.md
index 54f6838..6254dae 100644
--- a/docs/guide/controls.md
+++ b/docs/guide/controls.md
@@ -2,100 +2,100 @@
layout: default
title: Controls
parent: Writing ViewComponent Stories
-nav_order: 4
+nav_order: 3
---
# Controls
-Controls define Storybook [controls](https://storybook.js.org/docs/react/essentials/controls) that enable dynamic rendering of story content. They can be used are arguments to Story [constructors](constructor.md), [content](content.md) or [slots](slots.md).
+Controls define Storybook [controls](https://storybook.js.org/docs/react/essentials/controls) that enable dynamic rendering of story content. Control values are passed to the Story method where they can be used to render dynamic content.
## Boolean Controls
-### boolean(default_value)
+### control(param, as: :boolean, default: default_value)
-Render a boolean control as a checkbox input
+Render a boolean control as a toogle input
```ruby
-boolean(true)
+control :active, as: :boolean, default: true
```
## Number Controls
-### number(default_value, min: nil, max: nil, step: nil)
+### control(param, as: :number, default: default_value, min: nil, max: nil, step: nil)
Render a number control as a numeric text box input:
```ruby
-number(5)
+control :count, as: :number, default: 5
```
Supports `min`, `max`, and `step` arguments that restrict the allowed values:
```ruby
-number(5, min: 0, max: 100, step 5)
+control :actcountive, as: :number, default: 5, min: 0, max: 100, step 5
```
-### range(default_value, min: nil, max: nil, step: nil)
+### control(param, as: :range, default: default_value, min: nil, max: nil, step: nil)
Render a number control as a range slider input:
```ruby
-range(5, min: 0, max: 100, step 5)
+control :count, as: :range, default: 5, min: 0, max: 100, step 5
```
## Text Controls
-### color(default_value, preset_colors: nil)
+### control(param, as: :color, default: default_value, preset_colors: nil)
Render a color control as a color picker input that assumes strings are color values:
```ruby
-color("red")
-color("ff0000")
-color("rgba(255, 0, 0, 1")
+control :favorite, as: :color, default: "red"
+control :favorite, as: :color, default: "ff0000"
+control :actfavoriteive, as: :color, default: "rgba(255, 0, 0, 1)"
```
Supports preset_colors that define a list of color options:
```ruby
-color("red", preset_colors, ["green", "yellow", "blue"])
+control :favorite, as: :color, default: "red", preset_colors, ["green", "yellow", "blue"]
```
-### date(default_value)
+### control(param, as: :date, default: default_value
Render a date control as a date picker input:
```ruby
-date(Date.today)
+control :created, as: :date, default: Date.today
```
-### text(default_value)
+### control(param, as: :text, default: default_value
Render a text control as a simple text input:
```ruby
-text("Welcome")
+control :message, as: :date, default: "Welcome"
```
## Object Controls
-### object(default_value)
+### control(param, as: :object, default: default_value
Render a hash control as a json text editor:
```ruby
-object(title: "Welcome", message: "How are you?")
+control :greeting, as: :object, default: {title: "Welcome", message: "How are you?"}
```
-### array(default_value)
-
Render an array control as a json text editor:
```ruby
-array(["Football", "Baseball", "Basketball", "Hockey"])
+control :sports, as: :object, default: ["Football", "Baseball", "Basketball", "Hockey"]
```
## Enum Controls
-### select(options, default_value, labels: nil)
+### control(param, as: :select, default: default_value, options: options, labels: nil)
Render an enum control as a select dropdown input:
```ruby
-select([:small, :medium, :large, :xlarge], :small)
+control :size, as: :select, default: :small, options: [:small, :medium, :large, :xlarge]
```
Supports labels:
```ruby
-select(
- [:small, :medium, :large, :xlarge],
- :small
+control(
+ :size,
+ as: :select,
+ default: :small,
+ options: [:small, :medium, :large, :xlarge],
labels: {
small: "Small",
medium: "Medium",
@@ -105,142 +105,163 @@ select(
)
```
-
-### multi_select(options, default_value, labels: nil)
+### control(param, as: :multo_select, default: default_value, options: options, labels: nil)
Render an enum control as a multi-select dropdown input:
```ruby
-select([:small, :medium, :large, :xlarge], [:small, :large])
+control :size, as: :select, default: [:small, :large], options: [:small, :medium, :large, :xlarge]
```
Supports labels see [select](#selectoptions-default_value-labels-nil)
-### radio(options, default_value, labels: nil)
+### control(param, as: :radio, default: default_value, options: options, labels: nil)
Render an enum control as a radio button inputs:
```ruby
-radio([:small, :medium, :large, :xlarge], :small)
+control :size, as: :radio, default: :small, options: [:small, :medium, :large, :xlarge]
```
Supports labels see [select](#selectoptions-default_value-labels-nil)
-### inline_radio(options, default_value, labels: nil)
+### control(param, as: :inline_radio, default: default_value, options: options, labels: nil)
Render an enum control as a inline radio button inputs:
```ruby
-inline_radio([:small, :medium, :large, :xlarge], :small)
+control :size, as: :inline_radio, default: :small, options: [:small, :medium, :large, :xlarge]
```
Supports labels see [select](#selectoptions-default_value-labels-nil)
-### check(options, default_value, labels: nil)
+### control(param, as: :check, default: default_value, options: options, labels: nil)
Render an enum control as a multi-select checkbox inputs:
```ruby
-check([:small, :medium, :large, :xlarge], [:small, :large])
+control :size, as: :check, default: [:small, :large], options: [:small, :medium, :large, :xlarge]
```
Supports labels see [select](#selectoptions-default_value-labels-nil)
-### inline_check(options, default_value, labels: nil)
+### control(param, as: :inline_check, default: default_value, options: options, labels: nil)
Render an enum control as a multi-select checkbox inputs:
```ruby
-inline_check([:small, :medium, :large, :xlarge], [:small, :large])
+control :size, as: :inine_check, default: [:small, :large], options: [:small, :medium, :large, :xlarge]
```
Supports labels see [select](#selectoptions-default_value-labels-nil)
-## Custom Controls
+## Control Default Values
-Custom controls enable composition of controls to build arguments for a constructor, content or slot
+The default value for a control is read from the default value of the story method.
+
+For example, in the following stories the default value of the content control will be `Hellow World!` and `Goodby...` for the respetive stories.
```ruby
-# test/components/stories/button_component_stories.rb
-class ButtonComponentStories < ViewComponent::Storybook::Stories
- story :simple_button do
- button_text = custom(greeting: text("Hi"), name: text("Sarah")) do |greeting:, name:|
- "#{greeting} #{name}"
- end
- constructor(
- button_text: button_text
- )
+# test/components/stories/message_component_stories.rb
+class MessageComponentStories < ViewComponent::Storybook::Stories
+ control :content, as: :text
+
+ def hello_world(content: "Hello World!")
+ render MessageComponent.new do
+ content
+ end
+ end
+
+ def goodbye(content: "Goodbye...")
+ render MessageComponent.new do
+ content
+ end
end
end
```
-This generates two Storybook text controls, `greeting` and `name`. The block is called with their values and the result, by default `"Hi Sarah"`, is passed as the `button_text` argument to the component's constructor.
-
-## Klazz Controls
-
-Storybook controls support primitive object type - strings, dates, numbers etc. It is common for ViewComponents to take domain models are arguments. The `klazz` control provides a convenient shortcut to building those objects
-by composing one or more primitive controls:
+The default can also be set via the `default` parameter when declaring the control.
```ruby
-# app/models/author.rb
-class Author
- def initialize(first_name:, last_name:)
- @first_name = first_name
- @last_name = last_name
+# test/components/stories/message_component_stories.rb
+class MessageComponentStories < ViewComponent::Storybook::Stories
+ control :content, as: :text, default: "Hello World!"
+
+ def hello_world(content: )
+ render MessageComponent.new do
+ content
+ end
end
end
-```
+```
+
+## Restricting Controls to certain stories
+
+By default control is declared for all story methods. This is convinient when different stories only differ in their default values.
+
```ruby
-# app/components/book_component.rb
-class BookComponent < ViewComponent::Base
- def initialize(author)
- @author = author
+# test/components/stories/header_component_stories.rb
+class HeaderComponentStories < ViewComponent::Storybook::Stories
+ control :tag, as: :text
+
+ def h1(tag: "h1")
+ render HeaderComponent.new(tag)
+ end
+
+ def h2(tag: "h2")
+ render HeaderComponent.new(tag)
end
end
```
+However, controls can be declared to apply to `only` a particualr story:
+
```ruby
-# test/components/stories/book_component_stories.rb
-class BookComponentStories < ViewComponent::Storybook::Stories
- story :book do
- constructor(
- author: klazz(Author, first_name: "J.R.R.", last_name: "Tolkien")
- )
+# test/components/stories/header_component_stories.rb
+class HeaderComponentStories < ViewComponent::Storybook::Stories
+ control :tag, as: :text
+
+ def h1(tag: "h1")
+ render HeaderComponent.new(tag)
end
-end
-```
-This generates two Storybook text controls, `first_name` and `last_name`. An `Author` model is constructed from their values and passed as the `author` aurgument to the `BookComponent` constructor.
+ control :content, as: :text, only: :h2
+
+ def h2(tag: "h2", content: "Hello World!")
+ render HeaderComponent.new(tag) do
+ content
+ end
+ end
+end
## Customizing the Control Name
-By default the name of the control in Storybook is derived from the name of the positional or keyword argument.
+By default the name of the control in Storybook is derived from the control's parameter.
For example this story results in two controls with names "First Name" and "Last Name"
```ruby
# test/components/stories/person_component_stories.rb
class PersonComponentStories < ViewComponent::Storybook::Stories
- story :person do
- constructor(
- first_name: text("Nelson"),
- last_name: text("Mandela")
- )
+ control :first_name, as: :text
+ control :last_name, as: :text
+
+ def person(first_name: "Nelson", last_name: "Mandela")
+ render PersonComponent.new(first_name: first_name, last_name: last_name)
end
end
```
-The control name is configured using `name`:
+The control's name is configured using the `name` parameter:
```ruby
# test/components/stories/person_component_stories.rb
class PersonComponentStories < ViewComponent::Storybook::Stories
- story :person do
- constructor(
- first_name: text("Nelson").name("First"),
- last_name: text("Mandela").name("Last")
- )
+ control :first_name, as: :text, name: "First"
+ control :last_name, as: :text, name: "Last"
+
+ def person(first_name: "Nelson", last_name: "Mandela")
+ render PersonComponent.new(first_name: first_name, last_name: last_name)
end
end
```
## Adding a description to the control
-You can provide additional information about the control by passing a string
-into the `description` method.
+You can provide additional information about the control by adding a `description` option.
```ruby
# test/components/stories/person_component_stories.rb
class PersonComponentStories < ViewComponent::Storybook::Stories
- story :person do
- constructor(
- first_name: text("Nelson").description("The person's first name"),
- last_name: text("Mandela").description("The person's last name")
- )
+ control :first_name, as: :text, name: "First", description: "The person's first name"
+ control :last_name, as: :text, name: "Last", description: "The person's last name"
+
+ def person(first_name: "Nelson", last_name: "Mandela")
+ render PersonComponent.new(first_name: first_name, last_name: last_name)
end
end
```
diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md
index 88d9a07..a9764b4 100644
--- a/docs/guide/getting-started.md
+++ b/docs/guide/getting-started.md
@@ -100,13 +100,15 @@ Add a template for the new component:
### Write a story for ExampleComponent
+Stories are ViewComponent Previews with some Storybook magic sprinkled in.
+
```ruby
# test/components/stories/example_component_stories.rb
class ExampleComponentStories < ViewComponent::Storybook::Stories
- story :hello_world do
- constructor(title: "my title") do
+ def hello_world
+ render ExampleComponent.new(title: "my title") do
"Hello World!"
- end
+ end
end
end
```
@@ -140,39 +142,26 @@ yarn storybook
The second command will open the Storybook app in your browser rendering your ExampleComponent story!
![Hello World]({{ site.baseurl }}/assets/images/hello_world.png)
-## Implementation
-
-When Storybook calls the Rails app for the html story content the ViewComponent::Storybook
-passes the string "my title" to the component constructor and "Hello World!" as the component content.
-Effectively the component is rendered in a view as:
-
-```erb
-<%= render(ExampleComponent.new(title: "my title")) do %>
- Hello, World!
-<% end %>
-```
-
-Returning the rendered html to Storybook:
-
-```html
-Hello, World!
-```
## Dynamic Stories with Controls
-Storybook isn't just for rendering static stories. Storybook [controls](https://storybook.js.org/docs/react/essentials/controls) enable dynamic stories with variable inputs. ViewComponent Storybook exposes a similar api to describe dynamic inputs to component stories. For example add the `text` control to make `title` and `content` dynamic:
+Storybook isn't just for rendering static stories. Storybook [controls](https://storybook.js.org/docs/react/essentials/controls) enable dynamic stories with variable inputs. ViewComponent Storybook exposes a similar api to describe dynamic inputs to component stories. For example add `text` controls to make `title` and `content` dynamic:
```ruby
# test/components/stories/example_component_stories.rb
class ExampleComponentStories < ViewComponent::Storybook::Stories
- story :hello_world do
- constructor(title: text("my title"))
- content(text("Hello World!"))
+
+ control :title, as: :text
+ control :content, as: :text
+ def hello_world(title: "my title", content: "Hello World!")
+ render ExampleComponent.new(title: title) do
+ content
+ end
end
end
```
-This adds text controls to the Storybook Controls panel. Changing the values re-renders the compoent.
+This adds text controls to the Storybook Controls panel. Changing the values re-renders the component.
![Hello World Controls]({{ site.baseurl }}/assets/images/hello_world_controls.png)
Available controls and their options are documented on the [Controls](controls.md) page.
diff --git a/docs/guide/legacy_controls_dsl.md b/docs/guide/legacy_controls_dsl.md
deleted file mode 100644
index 9c73613..0000000
--- a/docs/guide/legacy_controls_dsl.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-nav_exclude: true
----
-
-# Legacy Controls DSL (deprecated)
-
-_Controls DSL is now deprectaed and will be removed in 1.0. Please migrate to [Constructor](constructor.md)_
-
-```ruby
-class ButtonComponentStories < ViewComponent::Storybook::Stories
- story(:default) do
- controls do
- text(:button_text, 'Push Me Please!')
- boolean(:disabled, false)
- number(:width_in_percent, min: 0, max: 100, step: 1)
- range(:width_in_percent, min: 0, max: 100, step: 1)
- color(:background_color, preset_colors: ["#8CDED0", "#F7F6F7", "#83B8FE"])
- object(:additional_attributes, { "aria-label": "Button label"})
- select(:size, [:sm, :md, :base, :lg], :base)
- multi_select(:variants, [:rounded, :striped, :primary, :secondary], [:primary, :rounded])
- radio(:size, [:sm, :md, :base, :lg], :base)
- inline_radio(:size, [:sm, :md, :base, :lg], :base)
- check(:variants, [:rounded, :striped, :primary, :secondary], [:primary, :rounded])
- inline_check(:variants, [:rounded, :striped, :primary, :secondary], [:primary, :rounded])
- array(:variants, "rounded, striped, primary, secondary", ",")
- date(:expiration_date, Date.today)
- end
- end
-end
-```
diff --git a/docs/guide/parameters.md b/docs/guide/parameters.md
index 056aca6..3f8816d 100644
--- a/docs/guide/parameters.md
+++ b/docs/guide/parameters.md
@@ -2,12 +2,12 @@
layout: default
title: Parameters
parent: Writing ViewComponent Stories
-nav_order: 8
+nav_order: 5
---
# Parameters
-Configure Storybook addons with `parameters`. Global parameters are defined in `.storybook/preview.js` - this is how the Storybook Rails [application url](/configuration.html#application-url). Parameters specified at the Stories and Story level are merged in that order. For example disable the a11y addon for all stories and enable it for one:
+Configure Storybook addons with `parameters`. Global parameters are defined in `.storybook/preview.js` - this is how the Storybook Rails [application url](/configuration.html#application-url).
```ruby
@@ -16,15 +16,10 @@ class HeaderComponentStories < ViewComponent::Storybook::Stories
# disable a11y for all stories in this class
parameters(a11y: { disable: true ))
- story :h1 do
- constructor("h1")
- end
-
- story :h2 do
- # enable a11y addom for just this story
- parameters(a11y: { disable: false ))
-
- constructor("h2")
+ def h1
+ render HeaderComponent.new("h1") do
+ "Hello World!"
+ end
end
end
```
diff --git a/docs/guide/slots.md b/docs/guide/slots.md
index 0ab2d5b..e4e60fe 100644
--- a/docs/guide/slots.md
+++ b/docs/guide/slots.md
@@ -2,7 +2,7 @@
layout: default
title: Slots
parent: Writing ViewComponent Stories
-nav_order: 6
+nav_order: 4
---
# Slots
diff --git a/docs/guide/stories.md b/docs/guide/stories.md
index a78a067..ae9d8b0 100644
--- a/docs/guide/stories.md
+++ b/docs/guide/stories.md
@@ -7,17 +7,17 @@ nav_order: 2
# Stories
-Stories are Ruby classes that inherit from `ViewComponent::Storybook::Stories`. Stories can have one or more stories defined with `story(story_name)`:
+Stories are Ruby classes that inherit from `ViewComponent::Storybook::Stories`. Stories are just an extension of [ViewComponent Previews](https://viewcomponent.org/guide/previews.html) Stories can have one or more story defined as public methods:
```ruby
# test/components/stories/header_component_stories.rb
class HeaderComponentStories < ViewComponent::Storybook::Stories
- story :h1 do
- constructor("h1")
+ def h1
+ render HeaderComponent.new("h1")
end
- story :h2 do
- constructor("h2")
+ def h2
+ render HeaderComponent.new("h2")
end
end.
```
@@ -31,27 +31,8 @@ By default the stories title derives from the stories class name. The class `Hea
class HeaderComponentStories < ViewComponent::Storybook::Stories
title "H1 Headers Stories"
- story :h1 do
- constructor("h1")
- end
-end
-```
-
-## Story Component
-
-By default the story ViewComponent derives from the stories class name. The class `HeaderComponentStories` will
-default to `HeaderComponent`. This supports a common convention of grouping all stories for a particular component
-together. The second argument to the `story` method configures the component class:
-
-```ruby
-# test/components/stories/header_component_stories.rb
-class HeaderComponentStories < ViewComponent::Storybook::Stories
- story :h1 do
- constructor("h1")
- end
-
- story(:subheader, HeaderSubheaderComponent) do
- constructor("h1", "h2")
+ def h1
+ render HeaderComponent.new("h1")
end
end
```
@@ -71,40 +52,6 @@ class HeaderComponentStories < ViewComponent::Storybook::Stories
end
```
-### Overriding Story Layout
-
-Individual stories can define their own layout that overrides the stories setting:
-
-```ruby
-# test/components/stories/header_component_stories.rb
-class HeaderComponentStories < ViewComponent::Storybook::Stories
- layout :desktop
-
- story :h1 do
- constructor("h1")
- end
-
- story :mobile_h1 do
- layout :mobile
- constructor("h1")
- end
-end
-```
-
-### No Layout
-
-Setting layout to false renders the component in isolation:
-
-```ruby
-# test/components/stories/header_component_stories.rb
-class HeaderComponentStories < ViewComponent::Storybook::Stories
- story :no_layout_h1 do
- layout false
- constructor("h1")
- end
-end
-```
-
### Default Story Layout
Stories layout is inherited by Stories classes. Create an `AppplicationStories` class to define a default
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 51b2823..4f53dae 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -117,9 +117,11 @@ def controls_for_story(story_name)
control.valid_for_story?(story_name)
end.map do |control|
dup_control = control.dup
- default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == control.param.to_s }
- if default_value_parts
- dup_control.default = code_method.instance_eval(default_value_parts[1])
+ unless dup_control.default.present?
+ default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == control.param.to_s }
+ if default_value_parts
+ dup_control.default = code_method.instance_eval(default_value_parts[1])
+ end
end
dup_control
end
diff --git a/spec/dummy/test/components/stories/control_default_stories.rb b/spec/dummy/test/components/stories/control_default_stories.rb
new file mode 100644
index 0000000..c77d7bb
--- /dev/null
+++ b/spec/dummy/test/components/stories/control_default_stories.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class ControlDefaultStories < ViewComponent::Storybook::Stories
+ control :content, as: :text, default: "Hello World!"
+
+ def example(content: "Ignored")
+ render(ContentComponent.new) do
+ content
+ end
+ end
+end
diff --git a/spec/view_component/storybook/stories_spec.rb b/spec/view_component/storybook/stories_spec.rb
index 401cf5d..fdb478d 100644
--- a/spec/view_component/storybook/stories_spec.rb
+++ b/spec/view_component/storybook/stories_spec.rb
@@ -173,6 +173,26 @@
)
end
+ it "converts controls with default " do
+ expect(ControlDefaultStories.to_csf_params).to eq(
+ title: "Control Default",
+ stories: [
+ {
+ name: :example,
+ parameters: {
+ server: { id: "control_default/example" }
+ },
+ args: {
+ content: "Hello World!"
+ },
+ argTypes: {
+ content: { control: { type: :text }, name: "Content" }
+ }
+ },
+ ]
+ )
+ end
+
it "converts kitchen sink" do
expect(KitchenSinkComponentStories.to_csf_params).to eq(
title: "Kitchen Sink Component",
From 39acb874524397d5528aa0093fb13aef5ef16933 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sun, 18 Dec 2022 11:44:57 -0500
Subject: [PATCH 19/35] rubocop
---
lib/view_component/storybook/stories.rb | 2 +-
spec/view_component/storybook/stories_spec.rb | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 4f53dae..3acc080 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -117,7 +117,7 @@ def controls_for_story(story_name)
control.valid_for_story?(story_name)
end.map do |control|
dup_control = control.dup
- unless dup_control.default.present?
+ if dup_control.default.blank?
default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == control.param.to_s }
if default_value_parts
dup_control.default = code_method.instance_eval(default_value_parts[1])
diff --git a/spec/view_component/storybook/stories_spec.rb b/spec/view_component/storybook/stories_spec.rb
index fdb478d..4b0a9d1 100644
--- a/spec/view_component/storybook/stories_spec.rb
+++ b/spec/view_component/storybook/stories_spec.rb
@@ -173,7 +173,7 @@
)
end
- it "converts controls with default " do
+ it "converts controls with default" do
expect(ControlDefaultStories.to_csf_params).to eq(
title: "Control Default",
stories: [
From 9bca96908ab50cec350e8391d487ab110f4bf437 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Tue, 20 Dec 2022 13:03:33 -0500
Subject: [PATCH 20/35] Expand only and excet options for controls
---
docs/guide/controls.md | 43 ++-
lib/view_component/storybook.rb | 1 +
lib/view_component/storybook/controls.rb | 1 -
.../storybook/controls/control.rb | 6 -
.../storybook/controls/controls_helpers.rb | 62 ----
.../storybook/controls_collection.rb | 80 +++++
lib/view_component/storybook/stories.rb | 75 ++---
.../controls/controls_helpers_spec.rb | 155 ----------
.../storybook/controls_collection_spec.rb | 282 ++++++++++++++++++
9 files changed, 435 insertions(+), 270 deletions(-)
delete mode 100644 lib/view_component/storybook/controls/controls_helpers.rb
create mode 100644 lib/view_component/storybook/controls_collection.rb
delete mode 100644 spec/view_component/storybook/controls/controls_helpers_spec.rb
create mode 100644 spec/view_component/storybook/controls_collection_spec.rb
diff --git a/docs/guide/controls.md b/docs/guide/controls.md
index 6254dae..c23b667 100644
--- a/docs/guide/controls.md
+++ b/docs/guide/controls.md
@@ -199,25 +199,62 @@ class HeaderComponentStories < ViewComponent::Storybook::Stories
end
```
-However, controls can be declared to apply to `only` a particualr story:
+### `only: story_name` or `only: [story_one, story_two]`
+Controls can be declared to apply to `only` a particualr story or array of stories:
```ruby
# test/components/stories/header_component_stories.rb
class HeaderComponentStories < ViewComponent::Storybook::Stories
- control :tag, as: :text
+ control :tag, as: :text, only: :h1
def h1(tag: "h1")
render HeaderComponent.new(tag)
end
- control :content, as: :text, only: :h2
+ control :content, as: :text, only: [:h2, :h3]
def h2(tag: "h2", content: "Hello World!")
render HeaderComponent.new(tag) do
content
end
end
+
+ def h3(tag: "h3", content: "How are you today?")
+ render HeaderComponent.new(tag) do
+ content
+ end
+ end
end
+```
+
+### `except: story_name` or `except: [story_one, story_two]`
+Controls can be declared to apply to all stories `except` a particualr story or array of stories:
+
+```ruby
+# test/components/stories/header_component_stories.rb
+class HeaderComponentStories < ViewComponent::Storybook::Stories
+ control :tag, as: :text, except: [:h2, :h3]
+
+ def h1(tag: "h1")
+ render HeaderComponent.new(tag)
+ end
+
+ control :content, as: :text, except: [:h1]
+
+ def h2(tag: "h2", content: "Hello World!")
+ render HeaderComponent.new(tag) do
+ content
+ end
+ end
+
+ def h3(tag: "h3", content: "How are you today?")
+ render HeaderComponent.new(tag) do
+ content
+ end
+ end
+end
+```
+
## Customizing the Control Name
diff --git a/lib/view_component/storybook.rb b/lib/view_component/storybook.rb
index 0bfcf07..aecc39f 100644
--- a/lib/view_component/storybook.rb
+++ b/lib/view_component/storybook.rb
@@ -11,6 +11,7 @@ module Storybook
autoload :Stories
autoload :StoriesParser
autoload :StoriesCollection
+ autoload :ControlsCollection
autoload :Story
autoload :Slots
diff --git a/lib/view_component/storybook/controls.rb b/lib/view_component/storybook/controls.rb
index 92154f4..929e617 100644
--- a/lib/view_component/storybook/controls.rb
+++ b/lib/view_component/storybook/controls.rb
@@ -18,7 +18,6 @@ module Controls
autoload :MultiOptions
autoload :Date
autoload :Object
- autoload :ControlsHelpers
end
end
end
diff --git a/lib/view_component/storybook/controls/control.rb b/lib/view_component/storybook/controls/control.rb
index 60a2144..6fad499 100644
--- a/lib/view_component/storybook/controls/control.rb
+++ b/lib/view_component/storybook/controls/control.rb
@@ -30,12 +30,6 @@ def parse_param_value(value)
raise NotImplementedError
# :nocov:
end
-
- def valid_for_story?(story_name)
- # expand to include arrays of names
- # expand to include except
- opts[:only].nil? || opts[:only] == story_name
- end
end
end
end
diff --git a/lib/view_component/storybook/controls/controls_helpers.rb b/lib/view_component/storybook/controls/controls_helpers.rb
deleted file mode 100644
index 2c357bf..0000000
--- a/lib/view_component/storybook/controls/controls_helpers.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- module Controls
- module ControlsHelpers
- extend ActiveSupport::Concern
-
- included do
- class_attribute :controls
- end
-
- def inherited(other)
- super(other)
- # setup class defaults
- other.controls = []
- end
-
- class_methods do
- def inherited(other)
- super(other)
- # setup class defaults
- other.controls = []
- end
-
- def control(param, as:, **opts)
- controls << case as
- when :text
- Controls::Text.new(param, **opts)
- when :boolean
- Controls::Boolean.new(param, **opts)
- when :number
- Controls::Number.new(param, type: :number, **opts)
- when :range
- Controls::Number.new(param, type: :range, **opts)
- when :color
- Controls::Color.new(param, **opts)
- when :object, :array
- Controls::Object.new(param, **opts)
- when :select
- Controls::Options.new(param, type: :select, **opts)
- when :multi_select
- Controls::MultiOptions.new(param, type: :'multi-select', **opts)
- when :radio
- Controls::Options.new(param, type: :radio, **opts)
- when :inline_radio
- Controls::Options.new(param, type: :'inline-radio', **opts)
- when :check
- Controls::MultiOptions.new(param, type: :check, **opts)
- when :inline_check
- Controls::MultiOptions.new(param, type: :'inline-check', **opts)
- when :date
- Controls::Date.new(param, **opts)
- else
- raise "Unknonwn control type '#{as}'"
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/view_component/storybook/controls_collection.rb b/lib/view_component/storybook/controls_collection.rb
new file mode 100644
index 0000000..6d0e5a4
--- /dev/null
+++ b/lib/view_component/storybook/controls_collection.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Storybook
+ class ControlsCollection
+ attr_reader :controls
+
+ attr_accessor :code_object
+
+ def initialize
+ @controls = []
+ end
+
+ def add(param, as:, only: nil, except: nil, **opts)
+ controls << { param: param, as: as, only: Array.wrap(only), except: Array.wrap(except), **opts }
+ end
+
+ def for_story(story_name)
+ # build the controls for the story_name
+ # pass through a hash to get the last valid control declared for each param
+ controls.map do |opts|
+ next unless valid_for_story?(story_name, opts.slice(:only, :except))
+
+ param = opts[:param]
+ unless opts.key?(:default)
+ opts = opts.merge(default: parse_default(story_name, param))
+ end
+ [param, build_control(param, **opts)]
+ end.compact.to_h.values
+ end
+
+ private
+
+ def valid_for_story?(story_name, only:, except:)
+ (only.empty? || only.include?(story_name)) && (except.empty? || !except.include?(story_name))
+ end
+
+ def parse_default(story_name, param)
+ code_method = code_object.meths.find { |m| m.name == story_name }
+ default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == param.to_s }
+ if default_value_parts
+ code_method.instance_eval(default_value_parts[1])
+ end
+ end
+
+ def build_control(param, as:, **opts)
+ case as
+ when :text
+ Controls::Text.new(param, **opts)
+ when :boolean
+ Controls::Boolean.new(param, **opts)
+ when :number
+ Controls::Number.new(param, type: :number, **opts)
+ when :range
+ Controls::Number.new(param, type: :range, **opts)
+ when :color
+ Controls::Color.new(param, **opts)
+ when :object, :array
+ Controls::Object.new(param, **opts)
+ when :select
+ Controls::Options.new(param, type: :select, **opts)
+ when :multi_select
+ Controls::MultiOptions.new(param, type: :'multi-select', **opts)
+ when :radio
+ Controls::Options.new(param, type: :radio, **opts)
+ when :inline_radio
+ Controls::Options.new(param, type: :'inline-radio', **opts)
+ when :check
+ Controls::MultiOptions.new(param, type: :check, **opts)
+ when :inline_check
+ Controls::MultiOptions.new(param, type: :'inline-check', **opts)
+ when :date
+ Controls::Date.new(param, **opts)
+ else
+ raise "Unknonwn control type '#{as}'"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 3acc080..7a06e90 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -5,9 +5,9 @@
module ViewComponent
module Storybook
class Stories < ViewComponent::Preview
- include Controls::ControlsHelpers
+ # include Controls::ControlsHelpers
- class_attribute :stories_parameters, :stories_title, :code_object
+ class_attribute :stories_parameters, :stories_title, :stories_json_path
class << self
def title(title = nil)
@@ -22,6 +22,10 @@ def parameters(params = nil)
stories_parameters
end
+ def control(param, as:, **opts)
+ controls.add(param, as: as, **opts)
+ end
+
def stories_name
name.chomp("Stories").underscore
end
@@ -44,12 +48,12 @@ def write_csf_json
end
def stories
- @stories ||= story_names.map { |method| Story.new(story_id(method), method, {}, controls_for_story(method)) }
+ @stories ||= story_names.map { |method| Story.new(story_id(method), method, {}, controls.for_story(method)) }
end
# find the story by name
- def find_story_config(name)
- stories.find { |config| config.name == name.to_sym }
+ def find_story(name)
+ stories.find { |story| story.name == name.to_sym }
end
# Returns the arguments for rendering of the component in its layout
@@ -58,10 +62,10 @@ def render_args(story_name, params: {})
story_params_names = instance_method(story_name).parameters.map(&:last)
provided_params = params.slice(*story_params_names).to_h.symbolize_keys
- story_config = find_story_config(story_name)
+ story = find_story(story_name)
control_parsed_params = provided_params.to_h do |param, value|
- control = story_config.controls.find { |c| c.param == param }
+ control = story.controls.find { |c| c.param == param }
value = control.parse_param_value(value) if control
[param, value]
@@ -74,6 +78,24 @@ def render_args(story_name, params: {})
result.merge(layout: @layout)
end
+ attr_reader :code_object
+
+ def code_object=(object)
+ @code_object = object
+ self.stories_json_path ||= begin
+ dir = File.dirname(object.file)
+ json_filename = object.path.demodulize.underscore
+
+ File.join(dir, "#{json_filename}.stories.json")
+ end
+
+ controls.code_object = object
+
+ # ordering of public_instance_methods isn't consistent
+ # use the code_object to sort the methods to the order that they're declared
+ @story_names = object.meths.select { |m| story_names.include?(m.name) }.map(&:name)
+ end
+
private
def inherited(other)
@@ -82,13 +104,8 @@ def inherited(other)
other.stories_title = Storybook.stories_title_generator.call(other)
end
- def stories_json_path
- @stories_json_path ||= begin
- dir = File.dirname(code_object.file)
- json_filename = code_object.path.demodulize.underscore
-
- File.join(dir, "#{json_filename}.stories.json")
- end
+ def controls
+ @controls ||= ControlsCollection.new
end
def story_id(name)
@@ -96,35 +113,7 @@ def story_id(name)
end
def story_names
- @story_names ||= begin
- public_methods = public_instance_methods(false)
- if code_object
- # ordering of public_instance_methods isn't consistent
- # use the code_object to sort the methods to the order that they're declared
- code_object.meths.select { |m| public_methods.include?(m.name) }.map(&:name)
- else
- # there is no code_object in some specs, particularly where we create Stories after Yard parsing
- # in these cases just use the names as returned by the public_methods
- public_methods.map(&:name)
- end
- end
- end
-
- def controls_for_story(story_name)
- code_method = code_object.meths.find { |m| m.name == story_name }
-
- controls.select do |control|
- control.valid_for_story?(story_name)
- end.map do |control|
- dup_control = control.dup
- if dup_control.default.blank?
- default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == control.param.to_s }
- if default_value_parts
- dup_control.default = code_method.instance_eval(default_value_parts[1])
- end
- end
- dup_control
- end
+ @story_names ||= public_instance_methods(false)
end
end
end
diff --git a/spec/view_component/storybook/controls/controls_helpers_spec.rb b/spec/view_component/storybook/controls/controls_helpers_spec.rb
deleted file mode 100644
index 7ccde85..0000000
--- a/spec/view_component/storybook/controls/controls_helpers_spec.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe ViewComponent::Storybook::Controls::ControlsHelpers do
- include described_class
-
- subject { controls.first }
-
- shared_examples "has controls attributes" do |control_attributes|
- it "has expected attributes" do
- expect(subject).to have_attributes(control_attributes)
- end
- end
-
- describe "#text" do
- control :name, as: :text, default: "Jane Doe"
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Text,
- param: :name,
- default: "Jane Doe"
- }
- end
-
- describe "#boolean" do
- control :active, as: :boolean, default: true
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Boolean,
- param: :active,
- default: true
- }
- end
-
- describe "#number" do
- context "with minimal args" do
- control :count, as: :number, default: 2
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Number,
- param: :count,
- type: :number,
- default: 2,
- min: nil,
- max: nil,
- step: nil
- }
- end
-
- context "with all args" do
- control :count, as: :number, default: 2, min: 0, max: 10, step: 1
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Number,
- param: :count,
- type: :number,
- default: 2,
- min: 0,
- max: 10,
- step: 1
- }
- end
- end
-
- describe "#range" do
- context "with minimal args" do
- control :count, as: :range, default: 2
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Number,
- param: :count,
- type: :range,
- default: 2,
- min: nil,
- max: nil,
- step: nil
- }
- end
-
- context "with all args" do
- control :count, as: :range, default: 2, min: 0, max: 10, step: 1
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Number,
- param: :count,
- type: :range,
- default: 2,
- min: 0,
- max: 10,
- step: 1
- }
- end
- end
-
- describe "#color" do
- control :favorite, as: :color, default: "red"
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Color,
- param: :favorite,
- default: "red"
- }
- end
-
- describe "#object" do
- control :description, as: :object, default: { hair: "Brown", eyes: "Blue" }
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Object,
- param: :description,
- default: { hair: "Brown", eyes: "Blue" }
- }
- end
-
- %w[select radio inline-radio].each do |type|
- control_type = type.underscore
-
- describe "##{control_type}" do
- control :food, as: control_type.to_sym, options: [:hot_dog, :pizza], default: :pizza
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::Options,
- param: :food,
- type: type.to_sym,
- default: :pizza,
- options: [:hot_dog, :pizza]
- }
- end
- end
-
- %w[multi-select check inline-check].each do |type|
- control_type = type.underscore
-
- describe "##{control_type}" do
- control :food, as: control_type.to_sym, options: [:hot_dog, :pizza], default: :pizza
-
- include_examples "has controls attributes",
- {
- class: ViewComponent::Storybook::Controls::MultiOptions,
- param: :food,
- type: type.to_sym,
- default: [:pizza],
- options: [:hot_dog, :pizza]
- }
- end
- end
-end
diff --git a/spec/view_component/storybook/controls_collection_spec.rb b/spec/view_component/storybook/controls_collection_spec.rb
new file mode 100644
index 0000000..7ec4414
--- /dev/null
+++ b/spec/view_component/storybook/controls_collection_spec.rb
@@ -0,0 +1,282 @@
+# frozen_string_literal: true
+
+RSpec.describe ViewComponent::Storybook::ControlsCollection do
+ subject do
+ collection = described_class.new
+ # borromw the code_object from Demo::ButtonComponentStories as an example
+ collection.code_object = Demo::ButtonComponentStories.code_object
+ collection
+ end
+
+ let(:short_controls) { subject.for_story(:short_button) }
+ let(:medium_controls) { subject.for_story(:medium_button) }
+ let(:long_controls) { subject.for_story(:long_button) }
+
+ describe "control builders" do
+ it "builds text controls" do
+ subject.add :name, as: :text, default: "Jane Doe"
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Text,
+ param: :name,
+ default: "Jane Doe"
+ )
+ end
+
+ it "builds boolean controls" do
+ subject.add :active, as: :boolean, default: true
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Boolean,
+ param: :active,
+ default: true
+ )
+ end
+
+ it "builds number controls with minimal args" do
+ subject.add :count, as: :number, default: 2
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Number,
+ param: :count,
+ type: :number,
+ default: 2,
+ min: nil,
+ max: nil,
+ step: nil
+ )
+ end
+
+ it "builds number controls with all args" do
+ subject.add :count, as: :number, default: 2, min: 0, max: 10, step: 1
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Number,
+ param: :count,
+ type: :number,
+ default: 2,
+ min: 0,
+ max: 10,
+ step: 1
+ )
+ end
+
+ it "builds #range controls with minimal args" do
+ subject.add :count, as: :range, default: 2
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Number,
+ param: :count,
+ type: :range,
+ default: 2,
+ min: nil,
+ max: nil,
+ step: nil
+ )
+ end
+
+ it "builds range controls with all args" do
+ subject.add :count, as: :range, default: 2, min: 0, max: 10, step: 1
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Number,
+ param: :count,
+ type: :range,
+ default: 2,
+ min: 0,
+ max: 10,
+ step: 1
+ )
+ end
+
+ it "builds color controls" do
+ subject.add :favorite, as: :color, default: "red"
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Color,
+ param: :favorite,
+ default: "red"
+ )
+ end
+
+ it "builds object controls" do
+ subject.add :description, as: :object, default: { hair: "Brown", eyes: "Blue" }
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Object,
+ param: :description,
+ default: { hair: "Brown", eyes: "Blue" }
+ )
+ end
+
+ %w[select radio inline-radio].each do |type|
+ control_type = type.underscore
+
+ it "builds #{control_type} controls" do
+ subject.add :food, as: control_type.to_sym, options: [:hot_dog, :pizza], default: :pizza
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Options,
+ param: :food,
+ type: type.to_sym,
+ default: :pizza,
+ options: [:hot_dog, :pizza]
+ )
+ end
+ end
+
+ %w[multi-select check inline-check].each do |type|
+ control_type = type.underscore
+
+ it "builds #{control_type} controls" do
+ subject.add :food, as: control_type.to_sym, options: [:hot_dog, :pizza], default: :pizza
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::MultiOptions,
+ param: :food,
+ type: type.to_sym,
+ default: [:pizza],
+ options: [:hot_dog, :pizza]
+ )
+ end
+ end
+ end
+
+ describe "control defaults" do
+ it "reads default value from method params" do
+ subject.add :button_text, as: :text
+
+ expect(short_controls.first.default).to eq("OK")
+ expect(medium_controls.first.default).to eq("Push Me!")
+ expect(long_controls.first.default).to eq("Really Really Long Button Text")
+ end
+
+ it "uses default from add methods over value from method params" do
+ subject.add :button_text, as: :text, default: "Hi"
+
+ expect(short_controls.first.default).to eq("Hi")
+ expect(medium_controls.first.default).to eq("Hi")
+ expect(long_controls.first.default).to eq("Hi")
+ end
+
+ it "uses default from add methods over value from method params when restricted to only methods" do
+ subject.add :button_text, as: :text
+ subject.add :button_text, as: :text, default: "Hi", only: :short_button
+
+ expect(short_controls.first.default).to eq("Hi")
+ expect(medium_controls.first.default).to eq("Push Me!")
+ expect(long_controls.first.default).to eq("Really Really Long Button Text")
+ end
+ end
+
+ describe "control restrictions" do
+ it "restricts only: story_name" do
+ subject.add :button_text, as: :text, default: "Hi", only: :short_button
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Text,
+ param: :button_text,
+ default: "Hi"
+ )
+ expect(medium_controls).to be_empty
+ end
+
+ it "overwrites control declaration" do
+ subject.add :button_text, as: :text, default: "Hi"
+ subject.add :button_text, as: :color, default: "Bye"
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Color,
+ param: :button_text,
+ default: "Bye"
+ )
+ end
+
+ it "overwrites control declaration for only: story_name" do
+ subject.add :button_text, as: :text, default: "Hi"
+ subject.add :button_text, as: :color, default: "Red", only: :medium_button
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Text,
+ param: :button_text,
+ default: "Hi"
+ )
+
+ expect(medium_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Color,
+ param: :button_text,
+ default: "Red"
+ )
+ end
+
+ it "overwrites control declaration for only: Array(*story_names)" do
+ subject.add :button_text, as: :text, default: "Hi"
+ subject.add :button_text, as: :color, default: "Red", only: [:medium_button, :long_button]
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Text,
+ param: :button_text,
+ default: "Hi"
+ )
+
+ expect(medium_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Color,
+ param: :button_text,
+ default: "Red"
+ )
+
+ expect(long_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Color,
+ param: :button_text,
+ default: "Red"
+ )
+ end
+
+
+ it "overwrites control declaration for except: story_name" do
+ subject.add :button_text, as: :text, default: "Hi"
+ subject.add :button_text, as: :color, default: "Red", except: :medium_button
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Color,
+ param: :button_text,
+ default: "Red"
+ )
+
+ expect(medium_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Text,
+ param: :button_text,
+ default: "Hi"
+ )
+
+ expect(long_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Color,
+ param: :button_text,
+ default: "Red"
+ )
+ end
+
+ it "overwrites control declaration for only: Array(*story_names)" do
+ subject.add :button_text, as: :text, default: "Hi"
+ subject.add :button_text, as: :color, default: "Red", except: [:medium_button, :long_button]
+
+ expect(short_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Color,
+ param: :button_text,
+ default: "Red"
+ )
+
+ expect(medium_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Text,
+ param: :button_text,
+ default: "Hi"
+ )
+
+ expect(long_controls.first).to have_attributes(
+ class: ViewComponent::Storybook::Controls::Text,
+ param: :button_text,
+ default: "Hi"
+ )
+ end
+ end
+end
From 0de85492988d11549fd904467d491cb084a73ba7 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Tue, 20 Dec 2022 13:03:53 -0500
Subject: [PATCH 21/35] rubocop
---
.../storybook/controls_collection.rb | 2 +-
.../storybook/controls_collection_spec.rb | 21 +++++++++----------
2 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/lib/view_component/storybook/controls_collection.rb b/lib/view_component/storybook/controls_collection.rb
index 6d0e5a4..d5c7fe4 100644
--- a/lib/view_component/storybook/controls_collection.rb
+++ b/lib/view_component/storybook/controls_collection.rb
@@ -32,7 +32,7 @@ def for_story(story_name)
private
def valid_for_story?(story_name, only:, except:)
- (only.empty? || only.include?(story_name)) && (except.empty? || !except.include?(story_name))
+ (only.empty? || only.include?(story_name)) && (except.empty? || except.exclude?(story_name))
end
def parse_default(story_name, param)
diff --git a/spec/view_component/storybook/controls_collection_spec.rb b/spec/view_component/storybook/controls_collection_spec.rb
index 7ec4414..c7ec124 100644
--- a/spec/view_component/storybook/controls_collection_spec.rb
+++ b/spec/view_component/storybook/controls_collection_spec.rb
@@ -172,7 +172,7 @@
describe "control restrictions" do
it "restricts only: story_name" do
subject.add :button_text, as: :text, default: "Hi", only: :short_button
-
+
expect(short_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Text,
param: :button_text,
@@ -184,7 +184,7 @@
it "overwrites control declaration" do
subject.add :button_text, as: :text, default: "Hi"
subject.add :button_text, as: :color, default: "Bye"
-
+
expect(short_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Color,
param: :button_text,
@@ -195,13 +195,13 @@
it "overwrites control declaration for only: story_name" do
subject.add :button_text, as: :text, default: "Hi"
subject.add :button_text, as: :color, default: "Red", only: :medium_button
-
+
expect(short_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Text,
param: :button_text,
default: "Hi"
)
-
+
expect(medium_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Color,
param: :button_text,
@@ -212,13 +212,13 @@
it "overwrites control declaration for only: Array(*story_names)" do
subject.add :button_text, as: :text, default: "Hi"
subject.add :button_text, as: :color, default: "Red", only: [:medium_button, :long_button]
-
+
expect(short_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Text,
param: :button_text,
default: "Hi"
)
-
+
expect(medium_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Color,
param: :button_text,
@@ -232,17 +232,16 @@
)
end
-
it "overwrites control declaration for except: story_name" do
subject.add :button_text, as: :text, default: "Hi"
subject.add :button_text, as: :color, default: "Red", except: :medium_button
-
+
expect(short_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Color,
param: :button_text,
default: "Red"
)
-
+
expect(medium_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Text,
param: :button_text,
@@ -259,13 +258,13 @@
it "overwrites control declaration for only: Array(*story_names)" do
subject.add :button_text, as: :text, default: "Hi"
subject.add :button_text, as: :color, default: "Red", except: [:medium_button, :long_button]
-
+
expect(short_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Color,
param: :button_text,
default: "Red"
)
-
+
expect(medium_controls.first).to have_attributes(
class: ViewComponent::Storybook::Controls::Text,
param: :button_text,
From 5b750b962f446627f891317ecbc5613137a15797 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Tue, 20 Dec 2022 13:59:46 -0500
Subject: [PATCH 22/35] More cleanup
---
lib/view_component/storybook/controls/control.rb | 6 ++----
lib/view_component/storybook/controls/multi_options.rb | 2 +-
lib/view_component/storybook/controls_collection.rb | 2 +-
spec/view_component/storybook/controls_collection_spec.rb | 6 +++---
4 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/lib/view_component/storybook/controls/control.rb b/lib/view_component/storybook/controls/control.rb
index 6fad499..af88053 100644
--- a/lib/view_component/storybook/controls/control.rb
+++ b/lib/view_component/storybook/controls/control.rb
@@ -8,15 +8,13 @@ class Control
validates :param, presence: true
- attr_reader :param, :name, :description, :opts
- attr_accessor :default
+ attr_reader :param, :name, :description, :default
- def initialize(param, default:, name: nil, description: nil, **opts)
+ def initialize(param, default:, name: nil, description: nil)
@param = param
@default = default
@name = name || param.to_s.humanize.titlecase
@description = description
- @opts = opts
end
def to_csf_params
diff --git a/lib/view_component/storybook/controls/multi_options.rb b/lib/view_component/storybook/controls/multi_options.rb
index a9a4f97..c68b9a0 100644
--- a/lib/view_component/storybook/controls/multi_options.rb
+++ b/lib/view_component/storybook/controls/multi_options.rb
@@ -10,7 +10,7 @@ class MultiOptions < BaseOptions
validate :validate_default, unless: -> { options.nil? || default.nil? }
def initialize(param, type:, options:, default: nil, labels: nil, name: nil, description: nil, **opts)
- super(param, type: type, options: options, default: Array.wrap(default), labels: labels, param: param, name: name, description: description, **opts)
+ super(param, type: type, options: options, default: Array.wrap(default), labels: labels, name: name, description: description, **opts)
end
def parse_param_value(value)
diff --git a/lib/view_component/storybook/controls_collection.rb b/lib/view_component/storybook/controls_collection.rb
index d5c7fe4..0eef3dd 100644
--- a/lib/view_component/storybook/controls_collection.rb
+++ b/lib/view_component/storybook/controls_collection.rb
@@ -25,7 +25,7 @@ def for_story(story_name)
unless opts.key?(:default)
opts = opts.merge(default: parse_default(story_name, param))
end
- [param, build_control(param, **opts)]
+ [param, build_control(param, **opts.except(:param, :only, :except))]
end.compact.to_h.values
end
diff --git a/spec/view_component/storybook/controls_collection_spec.rb b/spec/view_component/storybook/controls_collection_spec.rb
index c7ec124..0b2d493 100644
--- a/spec/view_component/storybook/controls_collection_spec.rb
+++ b/spec/view_component/storybook/controls_collection_spec.rb
@@ -112,7 +112,7 @@
%w[select radio inline-radio].each do |type|
control_type = type.underscore
- it "builds #{control_type} controls" do
+ it "builds #{control_type} single option controls" do
subject.add :food, as: control_type.to_sym, options: [:hot_dog, :pizza], default: :pizza
expect(short_controls.first).to have_attributes(
@@ -128,7 +128,7 @@
%w[multi-select check inline-check].each do |type|
control_type = type.underscore
- it "builds #{control_type} controls" do
+ it "builds #{control_type} multi-option controls" do
subject.add :food, as: control_type.to_sym, options: [:hot_dog, :pizza], default: :pizza
expect(short_controls.first).to have_attributes(
@@ -255,7 +255,7 @@
)
end
- it "overwrites control declaration for only: Array(*story_names)" do
+ it "overwrites control declaration for except: Array(*story_names)" do
subject.add :button_text, as: :text, default: "Hi"
subject.add :button_text, as: :color, default: "Red", except: [:medium_button, :long_button]
From 322c3dc9c8e8e21d2f3c25e10851f12e2225fd0c Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Thu, 22 Dec 2022 08:10:28 -0500
Subject: [PATCH 23/35] Add settings parameters for stories
---
docs/guide/parameters.md | 30 ++++++++++++-
lib/view_component/storybook.rb | 1 +
.../storybook/controls_collection.rb | 4 +-
.../storybook/parameters_collection.rb | 40 +++++++++++++++++
lib/view_component/storybook/stories.rb | 43 ++++++++-----------
.../components/stories/parameters_stories.rb | 6 ++-
.../storybook/controls_collection_spec.rb | 8 ++++
spec/view_component/storybook/stories_spec.rb | 2 +-
8 files changed, 103 insertions(+), 31 deletions(-)
create mode 100644 lib/view_component/storybook/parameters_collection.rb
diff --git a/docs/guide/parameters.md b/docs/guide/parameters.md
index 3f8816d..69f99c8 100644
--- a/docs/guide/parameters.md
+++ b/docs/guide/parameters.md
@@ -7,7 +7,9 @@ nav_order: 5
# Parameters
-Configure Storybook addons with `parameters`. Global parameters are defined in `.storybook/preview.js` - this is how the Storybook Rails [application url](/configuration.html#application-url).
+Configure Storybook addons with `parameters`. Global parameters are defined in `.storybook/preview.js` - this is how the Storybook Rails [application url](/configuration.html#application-url).
+
+Parameters can be defined for all stories with the `parameters` method:
```ruby
@@ -20,6 +22,32 @@ class HeaderComponentStories < ViewComponent::Storybook::Stories
render HeaderComponent.new("h1") do
"Hello World!"
end
+end
+```
+
+## Restricting parameters to certain stories
+
+Parameters specified at the Stories and Story level are merged in that order. the `paameters` method suports `only` and `except` options in the same format as the `controls` method. For example disable the a11y addon for all stories and enable it for one:
+
+
+```ruby
+# test/components/stories/header_component_stories.rb
+class HeaderComponentStories < ViewComponent::Storybook::Stories
+ # disable a11y for all stories in this class
+ parameters(a11y: { disable: true ))
+
+ def h1
+ render HeaderComponent.new("h1") do
+ "Hello World!"
+ end
+
+
+ parameters(a11y: { disable: false ), only: :h2)
+
+ def h2
+ render HeaderComponent.new("h2") do
+ "How are you?"
+ end
end
end
```
diff --git a/lib/view_component/storybook.rb b/lib/view_component/storybook.rb
index aecc39f..a68061c 100644
--- a/lib/view_component/storybook.rb
+++ b/lib/view_component/storybook.rb
@@ -12,6 +12,7 @@ module Storybook
autoload :StoriesParser
autoload :StoriesCollection
autoload :ControlsCollection
+ autoload :ParametersCollection
autoload :Story
autoload :Slots
diff --git a/lib/view_component/storybook/controls_collection.rb b/lib/view_component/storybook/controls_collection.rb
index 0eef3dd..f7f6137 100644
--- a/lib/view_component/storybook/controls_collection.rb
+++ b/lib/view_component/storybook/controls_collection.rb
@@ -12,7 +12,7 @@ def initialize
end
def add(param, as:, only: nil, except: nil, **opts)
- controls << { param: param, as: as, only: Array.wrap(only), except: Array.wrap(except), **opts }
+ controls << { param: param, as: as, only: only, except: except, **opts }
end
def for_story(story_name)
@@ -32,7 +32,7 @@ def for_story(story_name)
private
def valid_for_story?(story_name, only:, except:)
- (only.empty? || only.include?(story_name)) && (except.empty? || except.exclude?(story_name))
+ (only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
end
def parse_default(story_name, param)
diff --git a/lib/view_component/storybook/parameters_collection.rb b/lib/view_component/storybook/parameters_collection.rb
new file mode 100644
index 0000000..547ea4e
--- /dev/null
+++ b/lib/view_component/storybook/parameters_collection.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Storybook
+ class ParametersCollection
+ def initialize
+ @all_paramsters = {}
+ @parameters = []
+ end
+
+ def add(params, only: nil, except: nil)
+ if only.nil? && except.nil?
+ all_paramsters.merge!(params)
+ else
+ parameters << { params: params, only: only, except: except }
+ end
+ end
+
+ # Parameters set for all stories
+ def for_all
+ all_paramsters
+ end
+
+ # Parameters set for the story method
+ def for_story(story_name)
+ parameters.each_with_object({}) do |opts, accum|
+ accum.merge!(opts[:params]) if valid_for_story?(story_name, opts.slice(:only, :except))
+ end
+ end
+
+ private
+
+ attr_reader :all_paramsters, :parameters
+
+ def valid_for_story?(story_name, only:, except:)
+ (only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
+ end
+ end
+ end
+end
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 7a06e90..34eb1e1 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -5,21 +5,13 @@
module ViewComponent
module Storybook
class Stories < ViewComponent::Preview
- # include Controls::ControlsHelpers
-
- class_attribute :stories_parameters, :stories_title, :stories_json_path
-
class << self
def title(title = nil)
- # if no argument is passed act like a getter
- self.stories_title = title unless title.nil?
- stories_title
+ @stories_title = title
end
- def parameters(params = nil)
- # if no argument is passed act like a getter
- self.stories_parameters = params unless params.nil?
- stories_parameters
+ def parameters(params, only: nil, except: nil)
+ parameters_collection.add(params, only: only, except: except)
end
def control(param, as:, **opts)
@@ -35,20 +27,19 @@ def preview_name
end
def to_csf_params
- csf_params = { title: title }
- csf_params[:parameters] = parameters if parameters.present?
+ csf_params = { title: stories_title }
+ csf_params[:parameters] = parameters_collection.for_all if parameters_collection.for_all.present?
csf_params[:stories] = stories.map(&:to_csf_params)
csf_params
end
def write_csf_json
- Rails.logger.debug { "stories_json_path: #{stories_json_path}" }
File.write(stories_json_path, JSON.pretty_generate(to_csf_params))
stories_json_path
end
def stories
- @stories ||= story_names.map { |method| Story.new(story_id(method), method, {}, controls.for_story(method)) }
+ @stories ||= story_names.map { |name| Story.new(story_id(name), name, parameters_collection.for_story(name), controls.for_story(name)) }
end
# find the story by name
@@ -78,11 +69,11 @@ def render_args(story_name, params: {})
result.merge(layout: @layout)
end
- attr_reader :code_object
+ attr_reader :code_object, :stories_json_path
def code_object=(object)
@code_object = object
- self.stories_json_path ||= begin
+ @stories_json_path ||= begin
dir = File.dirname(object.file)
json_filename = object.path.demodulize.underscore
@@ -98,23 +89,25 @@ def code_object=(object)
private
- def inherited(other)
- super(other)
- # setup class defaults
- other.stories_title = Storybook.stories_title_generator.call(other)
- end
-
def controls
@controls ||= ControlsCollection.new
end
- def story_id(name)
- "#{stories_name}/#{name.to_s.parameterize}".underscore
+ def stories_title
+ @stories_title ||= Storybook.stories_title_generator.call(self)
+ end
+
+ def parameters_collection
+ @parameters_collection ||= ParametersCollection.new
end
def story_names
@story_names ||= public_instance_methods(false)
end
+
+ def story_id(name)
+ "#{stories_name}/#{name.to_s.parameterize}".underscore
+ end
end
end
end
diff --git a/spec/dummy/test/components/stories/parameters_stories.rb b/spec/dummy/test/components/stories/parameters_stories.rb
index b24fe1c..4835598 100644
--- a/spec/dummy/test/components/stories/parameters_stories.rb
+++ b/spec/dummy/test/components/stories/parameters_stories.rb
@@ -9,12 +9,14 @@ def stories_parameters(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
end
- # @parameters {size: :large, color: :red}
+ parameters({ size: :large, color: :red }, only: :stories_parameter_override)
+
def stories_parameter_override(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
end
- # @parameters {color: :red}
+ parameters({ color: :red }, only: :additional_parameters)
+
def additional_parameters(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
end
diff --git a/spec/view_component/storybook/controls_collection_spec.rb b/spec/view_component/storybook/controls_collection_spec.rb
index 0b2d493..023c5fc 100644
--- a/spec/view_component/storybook/controls_collection_spec.rb
+++ b/spec/view_component/storybook/controls_collection_spec.rb
@@ -232,6 +232,14 @@
)
end
+ it "ignored for empty only array" do
+ subject.add :button_text, as: :text, default: "Hi", only: []
+
+ expect(short_controls).to be_empty
+ expect(medium_controls).to be_empty
+ expect(long_controls).to be_empty
+ end
+
it "overwrites control declaration for except: story_name" do
subject.add :button_text, as: :text, default: "Hi"
subject.add :button_text, as: :color, default: "Red", except: :medium_button
diff --git a/spec/view_component/storybook/stories_spec.rb b/spec/view_component/storybook/stories_spec.rb
index 4b0a9d1..b11b641 100644
--- a/spec/view_component/storybook/stories_spec.rb
+++ b/spec/view_component/storybook/stories_spec.rb
@@ -348,7 +348,7 @@ def name
end
end
- xit "converts Stories with parameters" do
+ it "converts Stories with parameters" do
expect(ParametersStories.to_csf_params).to eq(
title: "Parameters",
parameters: { size: :small },
From 564810ea3ddf34bdce70b977552bd38daa3d8e00 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Thu, 22 Dec 2022 08:16:57 -0500
Subject: [PATCH 24/35] Rubocop
---
Gemfile.lock | 2 +-
lib/view_component/storybook/controls_collection.rb | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index 3d49395..2703ff9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -186,7 +186,7 @@ GEM
rspec-mocks (~> 3.10)
rspec-support (~> 3.10)
rspec-support (3.12.0)
- rubocop (1.40.0)
+ rubocop (1.41.1)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.1.2.1)
diff --git a/lib/view_component/storybook/controls_collection.rb b/lib/view_component/storybook/controls_collection.rb
index f7f6137..3d90ef7 100644
--- a/lib/view_component/storybook/controls_collection.rb
+++ b/lib/view_component/storybook/controls_collection.rb
@@ -35,12 +35,12 @@ def valid_for_story?(story_name, only:, except:)
(only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
end
- def parse_default(story_name, param)
+ def parse_default(story_name, _param)
code_method = code_object.meths.find { |m| m.name == story_name }
default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == param.to_s }
- if default_value_parts
- code_method.instance_eval(default_value_parts[1])
- end
+ return unless default_value_parts
+
+ code_method.instance_eval(default_value_parts[1])
end
def build_control(param, as:, **opts)
From 00cd077eba7f9d9a8245d980bf4313a6ca32afc9 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Thu, 22 Dec 2022 08:20:26 -0500
Subject: [PATCH 25/35] fixes
---
lib/view_component/storybook/controls_collection.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/view_component/storybook/controls_collection.rb b/lib/view_component/storybook/controls_collection.rb
index 3d90ef7..a340902 100644
--- a/lib/view_component/storybook/controls_collection.rb
+++ b/lib/view_component/storybook/controls_collection.rb
@@ -35,7 +35,7 @@ def valid_for_story?(story_name, only:, except:)
(only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
end
- def parse_default(story_name, _param)
+ def parse_default(story_name, param)
code_method = code_object.meths.find { |m| m.name == story_name }
default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == param.to_s }
return unless default_value_parts
From 8086fd538f65f798e98e404b58a370836531e154 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Thu, 22 Dec 2022 08:24:41 -0500
Subject: [PATCH 26/35] fixes
---
spec/dummy/test/components/stories/parameters_stories.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/dummy/test/components/stories/parameters_stories.rb b/spec/dummy/test/components/stories/parameters_stories.rb
index 4835598..c037c20 100644
--- a/spec/dummy/test/components/stories/parameters_stories.rb
+++ b/spec/dummy/test/components/stories/parameters_stories.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class ParametersStories < ViewComponent::Storybook::Stories
- parameters( size: :small )
+ parameters({size: :small})
control :button_text, as: :text
From 9ce63bbde3badf27fe5f233d8b406d8be7083de3 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Thu, 22 Dec 2022 08:25:43 -0500
Subject: [PATCH 27/35] rubocop
---
spec/dummy/test/components/stories/parameters_stories.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/dummy/test/components/stories/parameters_stories.rb b/spec/dummy/test/components/stories/parameters_stories.rb
index c037c20..f6f1359 100644
--- a/spec/dummy/test/components/stories/parameters_stories.rb
+++ b/spec/dummy/test/components/stories/parameters_stories.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class ParametersStories < ViewComponent::Storybook::Stories
- parameters({size: :small})
+ parameters({ size: :small })
control :button_text, as: :text
From 95e52d437017a7c51d97dd84b8c74dd5aaaa8da0 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Thu, 22 Dec 2022 08:30:01 -0500
Subject: [PATCH 28/35] ruby 3 fixes
---
lib/view_component/storybook/controls_collection.rb | 2 +-
lib/view_component/storybook/parameters_collection.rb | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/view_component/storybook/controls_collection.rb b/lib/view_component/storybook/controls_collection.rb
index a340902..06e01dc 100644
--- a/lib/view_component/storybook/controls_collection.rb
+++ b/lib/view_component/storybook/controls_collection.rb
@@ -19,7 +19,7 @@ def for_story(story_name)
# build the controls for the story_name
# pass through a hash to get the last valid control declared for each param
controls.map do |opts|
- next unless valid_for_story?(story_name, opts.slice(:only, :except))
+ next unless valid_for_story?(story_name, **opts.slice(:only, :except))
param = opts[:param]
unless opts.key?(:default)
diff --git a/lib/view_component/storybook/parameters_collection.rb b/lib/view_component/storybook/parameters_collection.rb
index 547ea4e..ba404d0 100644
--- a/lib/view_component/storybook/parameters_collection.rb
+++ b/lib/view_component/storybook/parameters_collection.rb
@@ -24,7 +24,7 @@ def for_all
# Parameters set for the story method
def for_story(story_name)
parameters.each_with_object({}) do |opts, accum|
- accum.merge!(opts[:params]) if valid_for_story?(story_name, opts.slice(:only, :except))
+ accum.merge!(opts[:params]) if valid_for_story?(story_name, **opts.slice(:only, :except))
end
end
From 3cc4b26c2b4d77ef9620576fe65fdfa453df4398 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 7 Jan 2023 09:28:19 -0500
Subject: [PATCH 29/35] fix requires
---
lib/view_component/storybook/stories.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 34eb1e1..8c16eb0 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require "yard"
+require "view_component-preview"
module ViewComponent
module Storybook
From ffa937d5fda4040a14aa8eca02b1108b6fc97421 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 7 Jan 2023 09:30:50 -0500
Subject: [PATCH 30/35] fix the require
---
lib/view_component/storybook/stories.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 8c16eb0..6511a0b 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require "yard"
-require "view_component-preview"
+require "view_component/preview"
module ViewComponent
module Storybook
From 6a18d7076b5099e484de5b12a843a4e89a6555fd Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 7 Jan 2023 09:42:59 -0500
Subject: [PATCH 31/35] Reorg requires
---
lib/view_component/storybook/engine.rb | 4 +++-
lib/view_component/storybook/stories.rb | 3 ---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/lib/view_component/storybook/engine.rb b/lib/view_component/storybook/engine.rb
index 612a5c6..881a09c 100644
--- a/lib/view_component/storybook/engine.rb
+++ b/lib/view_component/storybook/engine.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
-require "rails"
+require "view_component"
+require "action_cable/engine"
+require "yard"
module ViewComponent
module Storybook
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 6511a0b..e8df7aa 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -1,8 +1,5 @@
# frozen_string_literal: true
-require "yard"
-require "view_component/preview"
-
module ViewComponent
module Storybook
class Stories < ViewComponent::Preview
From f99be4e7dd3fa2205f0627fc8a567822899640e2 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 7 Jan 2023 11:16:14 -0500
Subject: [PATCH 32/35] Add layout options
---
Gemfile.lock | 4 +-
docs/guide/stories.md | 54 ++++++++++++++++---
lib/view_component/storybook.rb | 1 +
.../storybook/layout_collection.rb | 37 +++++++++++++
lib/view_component/storybook/stories.rb | 12 ++++-
lib/view_component/storybook/version.rb | 2 +-
.../test/components/stories/layout_stories.rb | 18 ++++---
.../components/stories/no_layout_stories.rb | 8 +--
.../view_components_controller_spec.rb | 14 ++---
...emspec => view_component-storybook.gemspec | 8 +--
10 files changed, 122 insertions(+), 36 deletions(-)
create mode 100644 lib/view_component/storybook/layout_collection.rb
rename view_component_storybook.gemspec => view_component-storybook.gemspec (87%)
diff --git a/Gemfile.lock b/Gemfile.lock
index 2703ff9..17bd15b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- view_component_storybook (0.12.1)
+ view_component-storybook (1.0.0)
view_component (>= 2.54)
yard (~> 0.9.25)
@@ -261,7 +261,7 @@ DEPENDENCIES
simplecov (~> 0.21.2)
simplecov-console (~> 0.9)
sprockets-rails (~> 3.4.2)
- view_component_storybook!
+ view_component-storybook!
BUNDLED WITH
2.3.26
diff --git a/docs/guide/stories.md b/docs/guide/stories.md
index ae9d8b0..7881212 100644
--- a/docs/guide/stories.md
+++ b/docs/guide/stories.md
@@ -44,10 +44,52 @@ Components are rendered in the default application layout. The layout for a set
```ruby
# test/components/stories/header_component_stories.rb
class HeaderComponentStories < ViewComponent::Storybook::Stories
- layout :desktop
+ layout "desktop"
- story :h1 do
- constructor("h1")
+ def h1
+ render HeaderComponent.new("h1")
+ end
+end
+```
+
+### Overriding Story Layout
+
+Individual stories can define their own layout that overrides the stories setting:
+
+```ruby
+# test/components/stories/header_component_stories.rb
+class HeaderComponentStories < ViewComponent::Storybook::Stories
+ layout "desktop"
+
+ def h1
+ render HeaderComponent.new("h1")
+ end
+
+ layout "mobile", only: :mobile_h1
+
+ def mobile_h1
+ render HeaderComponent.new("h1")
+ end
+end
+```
+
+### No Layout
+
+Setting layout to false renders the component in isolation:
+
+```ruby
+# test/components/stories/header_component_stories.rb
+class HeaderComponentStories < ViewComponent::Storybook::Stories
+ layout "desktop"
+
+ def h1
+ render HeaderComponent.new("h1")
+ end
+
+ layout false, only: :no_layout_h1
+
+ def no_layout_h1
+ render HeaderComponent.new("h1")
end
end
```
@@ -60,12 +102,12 @@ stories layout:
```ruby
# test/components/stories/application_stories.rb
class ApplicationStories < ViewComponent::Storybook::Stories
- layout :stories
+ layout "stories"
# test/components/stories/header_component_stories.rb
class HeaderComponentStories < ApplicationStories
- story :h1 do
- constructor("h1")
+ def h1
+ render HeaderComponent.new("h1")
end
end
```
diff --git a/lib/view_component/storybook.rb b/lib/view_component/storybook.rb
index a68061c..c701bd0 100644
--- a/lib/view_component/storybook.rb
+++ b/lib/view_component/storybook.rb
@@ -13,6 +13,7 @@ module Storybook
autoload :StoriesCollection
autoload :ControlsCollection
autoload :ParametersCollection
+ autoload :LayoutCollection
autoload :Story
autoload :Slots
diff --git a/lib/view_component/storybook/layout_collection.rb b/lib/view_component/storybook/layout_collection.rb
new file mode 100644
index 0000000..479433d
--- /dev/null
+++ b/lib/view_component/storybook/layout_collection.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Storybook
+ class LayoutCollection
+ def initialize
+ @default = nil
+ @layouts = []
+ end
+
+ def add(layout, only: nil, except: nil)
+ if only.nil? && except.nil?
+ @default = layout
+ else
+ layouts << { layout: layout, only: only, except: except }
+ end
+ end
+
+ # Parameters set for the story method
+ def for_story(story_name)
+ story_layout = default
+ layouts.each do |opts|
+ story_layout = opts[:layout] if valid_for_story?(story_name, **opts.slice(:only, :except))
+ end
+ story_layout
+ end
+
+ private
+
+ attr_reader :default, :layouts
+
+ def valid_for_story?(story_name, only:, except:)
+ (only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
+ end
+ end
+ end
+end
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index e8df7aa..93b173c 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -12,6 +12,10 @@ def parameters(params, only: nil, except: nil)
parameters_collection.add(params, only: only, except: except)
end
+ def layout(layout, only: nil, except: nil)
+ layout_collection.add(layout, only: only, except: except)
+ end
+
def control(param, as:, **opts)
controls.add(param, as: as, **opts)
end
@@ -47,7 +51,7 @@ def find_story(name)
# Returns the arguments for rendering of the component in its layout
def render_args(story_name, params: {})
- # mostly reimplementing the super method but adding logic to parse the params through the controls
+ # mostly reimplementing the super method but adding logic to parse the params through the controls and find the layout
story_params_names = instance_method(story_name).parameters.map(&:last)
provided_params = params.slice(*story_params_names).to_h.symbolize_keys
@@ -63,7 +67,7 @@ def render_args(story_name, params: {})
result = control_parsed_params.empty? ? new.public_send(story_name) : new.public_send(story_name, **control_parsed_params)
result ||= {}
result[:template] = preview_example_template_path(story_name) if result[:template].nil?
- @layout = nil unless defined?(@layout)
+ @layout = layout_collection.for_story(story_name.to_sym)
result.merge(layout: @layout)
end
@@ -99,6 +103,10 @@ def parameters_collection
@parameters_collection ||= ParametersCollection.new
end
+ def layout_collection
+ @layout_collection ||= LayoutCollection.new
+ end
+
def story_names
@story_names ||= public_instance_methods(false)
end
diff --git a/lib/view_component/storybook/version.rb b/lib/view_component/storybook/version.rb
index ee68eb3..95c4133 100644
--- a/lib/view_component/storybook/version.rb
+++ b/lib/view_component/storybook/version.rb
@@ -2,6 +2,6 @@
module ViewComponent
module Storybook
- VERSION = "0.12.1"
+ VERSION = "1.0.0"
end
end
diff --git a/spec/dummy/test/components/stories/layout_stories.rb b/spec/dummy/test/components/stories/layout_stories.rb
index 08f3597..16ebacb 100644
--- a/spec/dummy/test/components/stories/layout_stories.rb
+++ b/spec/dummy/test/components/stories/layout_stories.rb
@@ -9,13 +9,15 @@ def default(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
end
- # # @layout mobile
- # def mobile_layout(button_text: "OK")
- # render Demo::ButtonComponent.new(button_text: button_text)
- # end
+ layout("mobile", only: :mobile_layout)
- # # @layout false
- # def no_layout(button_text: "OK")
- # render Demo::ButtonComponent.new(button_text: button_text)
- # end
+ def mobile_layout(button_text: "OK")
+ render Demo::ButtonComponent.new(button_text: button_text)
+ end
+
+ layout(false, only: :no_layout)
+
+ def no_layout(button_text: "OK")
+ render Demo::ButtonComponent.new(button_text: button_text)
+ end
end
diff --git a/spec/dummy/test/components/stories/no_layout_stories.rb b/spec/dummy/test/components/stories/no_layout_stories.rb
index bcf79a0..c87292f 100644
--- a/spec/dummy/test/components/stories/no_layout_stories.rb
+++ b/spec/dummy/test/components/stories/no_layout_stories.rb
@@ -9,8 +9,8 @@ def default(button_text: "OK")
render Demo::ButtonComponent.new(button_text: button_text)
end
- # # @layout mobile
- # def mobile_layout(button_text: "OK")
- # render Demo::ButtonComponent.new(button_text: button_text)
- # end
+ layout("mobile", only: :mobile_layout)
+ def mobile_layout(button_text: "OK")
+ render Demo::ButtonComponent.new(button_text: button_text)
+ end
end
diff --git a/spec/view_component/storybook/view_components_controller_spec.rb b/spec/view_component/storybook/view_components_controller_spec.rb
index 625875f..96956c6 100644
--- a/spec/view_component/storybook/view_components_controller_spec.rb
+++ b/spec/view_component/storybook/view_components_controller_spec.rb
@@ -237,16 +237,16 @@
expect(response.body).to have_title( "Stories Dummy App - Admin")
end
- xit "allows story to override the stories layout" do
- get "/rails/view_components/layout_stories_v2/mobile_layout"
+ it "allows story to override the stories layout" do
+ get "/rails/view_components/layout/mobile_layout"
expect(response.body).to have_title("Stories Dummy App - Mobile")
end
- xit "allows story to override with no layout" do
- get "/rails/view_components/layout_stories_v2/no_layout"
+ it "allows story to override with no layout" do
+ get "/rails/view_components/layout/no_layout"
- expect(response.body).to eq("")
+ expect(response.body.strip).to eq("")
end
it "allows stories to set no layout" do
@@ -255,8 +255,8 @@
expect(response.body.strip).to eq("")
end
- xit "allows story to override no layout with a layout" do
- get "/rails/view_components/no_layout_stories_v2/mobile_layout"
+ it "allows story to override no layout with a layout" do
+ get "/rails/view_components/no_layout/mobile_layout"
expect(response.body).to have_title("Stories Dummy App - Mobile")
end
diff --git a/view_component_storybook.gemspec b/view_component-storybook.gemspec
similarity index 87%
rename from view_component_storybook.gemspec
rename to view_component-storybook.gemspec
index aa1a3b0..d5e3df4 100644
--- a/view_component_storybook.gemspec
+++ b/view_component-storybook.gemspec
@@ -5,17 +5,13 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "view_component/storybook/version"
Gem::Specification.new do |spec|
- spec.name = "view_component_storybook"
+ spec.name = "view_component-storybook"
spec.version = ViewComponent::Storybook::VERSION
spec.authors = ["Jon Palmer"]
spec.email = ["328224+jonspalmer@users.noreply.github.com"]
spec.summary = "Storybook for Rails View Components"
- spec.description = <<-DESC
- Generate Storybook CSF JSON for rendering Rails View Components in Storybook
-
- NOTE: As of v1.0.0 this gem has been renamed to view_component-storybook. See https://rubygems.org/gems/view_component-storybook
- DESC
+ spec.description = "Generate Storybook CSF JSON for rendering Rails View Components in Storybook"
spec.homepage = "https://github.com/jonspalmer/view_component-storybook"
spec.license = "MIT"
From b8e55474f93c6593628c1685480f4f47b0490329 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 7 Jan 2023 11:35:07 -0500
Subject: [PATCH 33/35] Disable main ci until we can fix rubygems version
weirdness
---
.github/workflows/ci.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3d01ff6..b4edbc0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- rails_version: [6.0.6, 6.1.7, 7.0.4, main]
+ rails_version: [6.0.6, 6.1.7, 7.0.4]
ruby_version: [2.6.10, 2.7.7, 3.0.5, 3.1.3]
exclude:
- rails_version: 6.0.6
@@ -36,8 +36,8 @@ jobs:
ruby_version: 2.5.9
- rails_version: 7.0.4
ruby_version: 2.6.10
- - rails_version: main
- ruby_version: 2.6.10
+ # - rails_version: main
+ # ruby_version: 2.6.10
steps:
- uses: actions/checkout@master
- name: Setup Ruby
From 68103900a2eceaf8dccbac49649cff60c93ffc7f Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 7 Jan 2023 13:24:35 -0500
Subject: [PATCH 34/35] Move all the collections
---
lib/view_component/storybook.rb | 6 +-
lib/view_component/storybook/collections.rb | 17 ++++
.../collections/controls_collection.rb | 80 +++++++++++++++++++
.../collections/layout_collection.rb | 37 +++++++++
.../collections/parameters_collection.rb | 40 ++++++++++
.../collections/stories_collection.rb | 31 +++++++
.../collections/valid_for_story_concern.rb | 15 ++++
.../storybook/controls_collection.rb | 80 -------------------
lib/view_component/storybook/engine.rb | 2 +-
.../storybook/layout_collection.rb | 37 ---------
.../storybook/parameters_collection.rb | 40 ----------
lib/view_component/storybook/stories.rb | 6 +-
.../storybook/stories_collection.rb | 29 -------
.../controls_collection_spec.rb | 2 +-
14 files changed, 227 insertions(+), 195 deletions(-)
create mode 100644 lib/view_component/storybook/collections.rb
create mode 100644 lib/view_component/storybook/collections/controls_collection.rb
create mode 100644 lib/view_component/storybook/collections/layout_collection.rb
create mode 100644 lib/view_component/storybook/collections/parameters_collection.rb
create mode 100644 lib/view_component/storybook/collections/stories_collection.rb
create mode 100644 lib/view_component/storybook/collections/valid_for_story_concern.rb
delete mode 100644 lib/view_component/storybook/controls_collection.rb
delete mode 100644 lib/view_component/storybook/layout_collection.rb
delete mode 100644 lib/view_component/storybook/parameters_collection.rb
delete mode 100644 lib/view_component/storybook/stories_collection.rb
rename spec/view_component/storybook/{ => collections}/controls_collection_spec.rb (99%)
diff --git a/lib/view_component/storybook.rb b/lib/view_component/storybook.rb
index c701bd0..cb84b3e 100644
--- a/lib/view_component/storybook.rb
+++ b/lib/view_component/storybook.rb
@@ -8,12 +8,10 @@ module Storybook
extend ActiveSupport::Autoload
autoload :Controls
+ autoload :Collections
autoload :Stories
autoload :StoriesParser
- autoload :StoriesCollection
- autoload :ControlsCollection
- autoload :ParametersCollection
- autoload :LayoutCollection
+
autoload :Story
autoload :Slots
diff --git a/lib/view_component/storybook/collections.rb b/lib/view_component/storybook/collections.rb
new file mode 100644
index 0000000..f3b90ae
--- /dev/null
+++ b/lib/view_component/storybook/collections.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require "active_support/dependencies/autoload"
+
+module ViewComponent
+ module Storybook
+ module Collections
+ extend ActiveSupport::Autoload
+
+ autoload :ValidForStoryConcern
+ autoload :StoriesCollection
+ autoload :ControlsCollection
+ autoload :ParametersCollection
+ autoload :LayoutCollection
+ end
+ end
+end
diff --git a/lib/view_component/storybook/collections/controls_collection.rb b/lib/view_component/storybook/collections/controls_collection.rb
new file mode 100644
index 0000000..fe2646c
--- /dev/null
+++ b/lib/view_component/storybook/collections/controls_collection.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Storybook
+ module Collections
+ class ControlsCollection
+ include Collections::ValidForStoryConcern
+
+ attr_reader :controls
+
+ attr_accessor :code_object
+
+ def initialize
+ @controls = []
+ end
+
+ def add(param, as:, only: nil, except: nil, **opts)
+ controls << { param: param, as: as, only: only, except: except, **opts }
+ end
+
+ def for_story(story_name)
+ # build the controls for the story_name
+ # pass through a hash to get the last valid control declared for each param
+ controls.map do |opts|
+ next unless valid_for_story?(story_name, **opts.slice(:only, :except))
+
+ param = opts[:param]
+ unless opts.key?(:default)
+ opts = opts.merge(default: parse_default(story_name, param))
+ end
+ [param, build_control(param, **opts.except(:param, :only, :except))]
+ end.compact.to_h.values
+ end
+
+ private
+
+ def parse_default(story_name, param)
+ code_method = code_object.meths.find { |m| m.name == story_name }
+ default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == param.to_s }
+ return unless default_value_parts
+
+ code_method.instance_eval(default_value_parts[1])
+ end
+
+ def build_control(param, as:, **opts)
+ case as
+ when :text
+ Controls::Text.new(param, **opts)
+ when :boolean
+ Controls::Boolean.new(param, **opts)
+ when :number
+ Controls::Number.new(param, type: :number, **opts)
+ when :range
+ Controls::Number.new(param, type: :range, **opts)
+ when :color
+ Controls::Color.new(param, **opts)
+ when :object, :array
+ Controls::Object.new(param, **opts)
+ when :select
+ Controls::Options.new(param, type: :select, **opts)
+ when :multi_select
+ Controls::MultiOptions.new(param, type: :'multi-select', **opts)
+ when :radio
+ Controls::Options.new(param, type: :radio, **opts)
+ when :inline_radio
+ Controls::Options.new(param, type: :'inline-radio', **opts)
+ when :check
+ Controls::MultiOptions.new(param, type: :check, **opts)
+ when :inline_check
+ Controls::MultiOptions.new(param, type: :'inline-check', **opts)
+ when :date
+ Controls::Date.new(param, **opts)
+ else
+ raise "Unknonwn control type '#{as}'"
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/view_component/storybook/collections/layout_collection.rb b/lib/view_component/storybook/collections/layout_collection.rb
new file mode 100644
index 0000000..ed7fea7
--- /dev/null
+++ b/lib/view_component/storybook/collections/layout_collection.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Storybook
+ module Collections
+ class LayoutCollection
+ include Collections::ValidForStoryConcern
+
+ def initialize
+ @default = nil
+ @layouts = []
+ end
+
+ def add(layout, only: nil, except: nil)
+ if only.nil? && except.nil?
+ @default = layout
+ else
+ layouts << { layout: layout, only: only, except: except }
+ end
+ end
+
+ # Parameters set for the story method
+ def for_story(story_name)
+ story_layout = default
+ layouts.each do |opts|
+ story_layout = opts[:layout] if valid_for_story?(story_name, **opts.slice(:only, :except))
+ end
+ story_layout
+ end
+
+ private
+
+ attr_reader :default, :layouts
+ end
+ end
+ end
+end
diff --git a/lib/view_component/storybook/collections/parameters_collection.rb b/lib/view_component/storybook/collections/parameters_collection.rb
new file mode 100644
index 0000000..53583ea
--- /dev/null
+++ b/lib/view_component/storybook/collections/parameters_collection.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Storybook
+ module Collections
+ class ParametersCollection
+ include Collections::ValidForStoryConcern
+
+ def initialize
+ @all_paramsters = {}
+ @parameters = []
+ end
+
+ def add(params, only: nil, except: nil)
+ if only.nil? && except.nil?
+ all_paramsters.merge!(params)
+ else
+ parameters << { params: params, only: only, except: except }
+ end
+ end
+
+ # Parameters set for all stories
+ def for_all
+ all_paramsters
+ end
+
+ # Parameters set for the story method
+ def for_story(story_name)
+ parameters.each_with_object({}) do |opts, accum|
+ accum.merge!(opts[:params]) if valid_for_story?(story_name, **opts.slice(:only, :except))
+ end
+ end
+
+ private
+
+ attr_reader :all_paramsters, :parameters
+ end
+ end
+ end
+end
diff --git a/lib/view_component/storybook/collections/stories_collection.rb b/lib/view_component/storybook/collections/stories_collection.rb
new file mode 100644
index 0000000..f2d7972
--- /dev/null
+++ b/lib/view_component/storybook/collections/stories_collection.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Storybook
+ module Collections
+ class StoriesCollection
+ include Enumerable
+
+ delegate_missing_to :stories
+
+ attr_reader :stories
+
+ def load(code_objects)
+ @stories = Array(code_objects).map { |obj| StoriesCollection.stories_from_code_object(obj) }.compact
+ end
+
+ def self.stories_from_code_object(code_object)
+ klass = code_object.path.constantize
+ klass.code_object = code_object
+ klass
+ end
+
+ def self.stories_class?(klass)
+ return unless klass.ancestors.include?(ViewComponent::Storybook::Stories)
+
+ !klass.respond_to?(:abstract_class) || klass.abstract_class != true
+ end
+ end
+ end
+ end
+end
diff --git a/lib/view_component/storybook/collections/valid_for_story_concern.rb b/lib/view_component/storybook/collections/valid_for_story_concern.rb
new file mode 100644
index 0000000..6f8ee0a
--- /dev/null
+++ b/lib/view_component/storybook/collections/valid_for_story_concern.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Storybook
+ module Collections
+ module ValidForStoryConcern
+ extend ActiveSupport::Concern
+
+ def valid_for_story?(story_name, only:, except:)
+ (only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/view_component/storybook/controls_collection.rb b/lib/view_component/storybook/controls_collection.rb
deleted file mode 100644
index 06e01dc..0000000
--- a/lib/view_component/storybook/controls_collection.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- class ControlsCollection
- attr_reader :controls
-
- attr_accessor :code_object
-
- def initialize
- @controls = []
- end
-
- def add(param, as:, only: nil, except: nil, **opts)
- controls << { param: param, as: as, only: only, except: except, **opts }
- end
-
- def for_story(story_name)
- # build the controls for the story_name
- # pass through a hash to get the last valid control declared for each param
- controls.map do |opts|
- next unless valid_for_story?(story_name, **opts.slice(:only, :except))
-
- param = opts[:param]
- unless opts.key?(:default)
- opts = opts.merge(default: parse_default(story_name, param))
- end
- [param, build_control(param, **opts.except(:param, :only, :except))]
- end.compact.to_h.values
- end
-
- private
-
- def valid_for_story?(story_name, only:, except:)
- (only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
- end
-
- def parse_default(story_name, param)
- code_method = code_object.meths.find { |m| m.name == story_name }
- default_value_parts = code_method.parameters.find { |parts| parts[0].chomp(":") == param.to_s }
- return unless default_value_parts
-
- code_method.instance_eval(default_value_parts[1])
- end
-
- def build_control(param, as:, **opts)
- case as
- when :text
- Controls::Text.new(param, **opts)
- when :boolean
- Controls::Boolean.new(param, **opts)
- when :number
- Controls::Number.new(param, type: :number, **opts)
- when :range
- Controls::Number.new(param, type: :range, **opts)
- when :color
- Controls::Color.new(param, **opts)
- when :object, :array
- Controls::Object.new(param, **opts)
- when :select
- Controls::Options.new(param, type: :select, **opts)
- when :multi_select
- Controls::MultiOptions.new(param, type: :'multi-select', **opts)
- when :radio
- Controls::Options.new(param, type: :radio, **opts)
- when :inline_radio
- Controls::Options.new(param, type: :'inline-radio', **opts)
- when :check
- Controls::MultiOptions.new(param, type: :check, **opts)
- when :inline_check
- Controls::MultiOptions.new(param, type: :'inline-check', **opts)
- when :date
- Controls::Date.new(param, **opts)
- else
- raise "Unknonwn control type '#{as}'"
- end
- end
- end
- end
-end
diff --git a/lib/view_component/storybook/engine.rb b/lib/view_component/storybook/engine.rb
index 881a09c..f036fa4 100644
--- a/lib/view_component/storybook/engine.rb
+++ b/lib/view_component/storybook/engine.rb
@@ -57,7 +57,7 @@ def parser
class << self
def stories
- @stories ||= StoriesCollection.new
+ @stories ||= Collections::StoriesCollection.new
end
end
end
diff --git a/lib/view_component/storybook/layout_collection.rb b/lib/view_component/storybook/layout_collection.rb
deleted file mode 100644
index 479433d..0000000
--- a/lib/view_component/storybook/layout_collection.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- class LayoutCollection
- def initialize
- @default = nil
- @layouts = []
- end
-
- def add(layout, only: nil, except: nil)
- if only.nil? && except.nil?
- @default = layout
- else
- layouts << { layout: layout, only: only, except: except }
- end
- end
-
- # Parameters set for the story method
- def for_story(story_name)
- story_layout = default
- layouts.each do |opts|
- story_layout = opts[:layout] if valid_for_story?(story_name, **opts.slice(:only, :except))
- end
- story_layout
- end
-
- private
-
- attr_reader :default, :layouts
-
- def valid_for_story?(story_name, only:, except:)
- (only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
- end
- end
- end
-end
diff --git a/lib/view_component/storybook/parameters_collection.rb b/lib/view_component/storybook/parameters_collection.rb
deleted file mode 100644
index ba404d0..0000000
--- a/lib/view_component/storybook/parameters_collection.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- class ParametersCollection
- def initialize
- @all_paramsters = {}
- @parameters = []
- end
-
- def add(params, only: nil, except: nil)
- if only.nil? && except.nil?
- all_paramsters.merge!(params)
- else
- parameters << { params: params, only: only, except: except }
- end
- end
-
- # Parameters set for all stories
- def for_all
- all_paramsters
- end
-
- # Parameters set for the story method
- def for_story(story_name)
- parameters.each_with_object({}) do |opts, accum|
- accum.merge!(opts[:params]) if valid_for_story?(story_name, **opts.slice(:only, :except))
- end
- end
-
- private
-
- attr_reader :all_paramsters, :parameters
-
- def valid_for_story?(story_name, only:, except:)
- (only.nil? || Array.wrap(only).include?(story_name)) && Array.wrap(except).exclude?(story_name)
- end
- end
- end
-end
diff --git a/lib/view_component/storybook/stories.rb b/lib/view_component/storybook/stories.rb
index 93b173c..3383cf4 100644
--- a/lib/view_component/storybook/stories.rb
+++ b/lib/view_component/storybook/stories.rb
@@ -92,7 +92,7 @@ def code_object=(object)
private
def controls
- @controls ||= ControlsCollection.new
+ @controls ||= Collections::ControlsCollection.new
end
def stories_title
@@ -100,11 +100,11 @@ def stories_title
end
def parameters_collection
- @parameters_collection ||= ParametersCollection.new
+ @parameters_collection ||= Collections::ParametersCollection.new
end
def layout_collection
- @layout_collection ||= LayoutCollection.new
+ @layout_collection ||= Collections::LayoutCollection.new
end
def story_names
diff --git a/lib/view_component/storybook/stories_collection.rb b/lib/view_component/storybook/stories_collection.rb
deleted file mode 100644
index ee475b4..0000000
--- a/lib/view_component/storybook/stories_collection.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-module ViewComponent
- module Storybook
- class StoriesCollection
- include Enumerable
-
- delegate_missing_to :stories
-
- attr_reader :stories
-
- def load(code_objects)
- @stories = Array(code_objects).map { |obj| StoriesCollection.stories_from_code_object(obj) }.compact
- end
-
- def self.stories_from_code_object(code_object)
- klass = code_object.path.constantize
- klass.code_object = code_object
- klass
- end
-
- def self.stories_class?(klass)
- return unless klass.ancestors.include?(ViewComponent::Storybook::Stories)
-
- !klass.respond_to?(:abstract_class) || klass.abstract_class != true
- end
- end
- end
-end
diff --git a/spec/view_component/storybook/controls_collection_spec.rb b/spec/view_component/storybook/collections/controls_collection_spec.rb
similarity index 99%
rename from spec/view_component/storybook/controls_collection_spec.rb
rename to spec/view_component/storybook/collections/controls_collection_spec.rb
index 023c5fc..f28cdca 100644
--- a/spec/view_component/storybook/controls_collection_spec.rb
+++ b/spec/view_component/storybook/collections/controls_collection_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe ViewComponent::Storybook::ControlsCollection do
+RSpec.describe ViewComponent::Storybook::Collections::ControlsCollection do
subject do
collection = described_class.new
# borromw the code_object from Demo::ButtonComponentStories as an example
From a0f920db304fa042c4b9fab30a799b5e19a275b1 Mon Sep 17 00:00:00 2001
From: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
Date: Sat, 7 Jan 2023 15:18:09 -0500
Subject: [PATCH 35/35] Update Docs
---
docs/guide/getting-started.md | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md
index a9764b4..061c490 100644
--- a/docs/guide/getting-started.md
+++ b/docs/guide/getting-started.md
@@ -13,19 +13,12 @@ nav_order: 1
1. In `Gemfile`, add:
```ruby
- gem "view_component"
gem "view_component_storybook"
```
2. In`.gitignore`, add:
```text
**/*.stories.json
```
-3. In `config/application.rb`, add:
- ```ruby
- require 'view_component'
- require 'view_component/storybook'
- ```
-
### Storybook Installation
@@ -59,7 +52,7 @@ nav_order: 1
```javascript
export const parameters = {
server: {
- url: `http://localhost:3000/rails/stories`,
+ url: `http://localhost:3000/rails/view_components`,
},
};
```