Skip to content

Commit

Permalink
Allow setting a custom stories title lambda (#107)
Browse files Browse the repository at this point in the history
Allow setting a custom story_title_generator lambda

Co-authored-by: Jon Palmer <328224+jonspalmer@users.noreply.github.com>
  • Loading branch information
simonrand and jonspalmer committed Jul 30, 2022
1 parent 66d60b6 commit 62f4599
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 19 deletions.
15 changes: 14 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const parameters = {
};
```

Other environements, such as production, require equivalent configuration.
Other environments, such as production, require equivalent configuration.

## Stories Path

Expand All @@ -41,6 +41,19 @@ config.view_component_storybook.stories_route = "/stories"

This example will make the previews available from <http://localhost:3000/stories>.

## 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:

```ruby
# config/application.rb
config.view_component_storybook.stories_title_generator = lambda { |stories|
stories.stories_name.humanize.delete_prefix('Namespace/').titlecase
}
```

This example will result in a title of `Example Component` instead of `Namespace/Example Component` for a stories file located at `namespace/example_component_stories.rb` (in your stories directory).

## Configuring Asset Hosts

Storybook typically runs on a different port or url from the Rails application. To use Javascript, CSS or other assets served by the Rails application in ViewComponents configure `asset_hosts`
Expand Down
9 changes: 9 additions & 0 deletions lib/view_component/storybook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ module Storybook
end
# :nocov:

# Define how component stories titles are generated:
#
# config.view_component_storybook.stories_title_generator = lambda { |stories|
# stories.stories_name.humanize.upcase
# }
#
mattr_accessor :stories_title_generator, instance_writer: false,
default: ->(stories) { stories.stories_name.humanize.titlecase }

ActiveSupport.run_load_hooks(:view_component_storybook, self)
end
end
2 changes: 2 additions & 0 deletions lib/view_component/storybook/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class Engine < Rails::Engine
options.stories_path ||= defined?(Rails.root) ? Rails.root.join("test/components/stories") : nil
end

options.stories_title_generator ||= ViewComponent::Storybook.stories_title_generator

ActiveSupport.on_load(:view_component_storybook) do
options.each { |k, v| send("#{k}=", v) }
end
Expand Down
2 changes: 1 addition & 1 deletion lib/view_component/storybook/stories.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def validate!
def inherited(other)
super(other)
# setup class defaults
other.stories_title = other.stories_name.humanize.titlecase
other.stories_title = Storybook.stories_title_generator.call(other)
other.story_configs = []
end

Expand Down
78 changes: 61 additions & 17 deletions spec/view_component/storybook/stories_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -298,24 +298,68 @@
)
end

it "converts Stories with customer Stories title" do
expect(Demo::HeadingComponentStories.to_csf_params).to eq(
title: "Heading Component",
stories: [
{
name: :default,
parameters: {
server: { id: "demo/heading_component/default" }
},
args: {
heading_text: "Heading"
},
argTypes: {
heading_text: { control: { type: :text }, name: "Heading Text" }
context "with a custom story title defined" do
it "converts Stories" do
expect(Demo::HeadingComponentStories.to_csf_params).to eq(
title: "Heading Component",
stories: [
{
name: :default,
parameters: {
server: { id: "demo/heading_component/default" }
},
args: {
heading_text: "Heading"
},
argTypes: {
heading_text: { control: { type: :text }, name: "Heading Text" }
}
}
}
]
)
]
)
end
end

context "with a custom story title generator defined" do
let(:custom_story_title) { "CustomStoryTitle" }

around do |example|
original_generator = ViewComponent::Storybook.stories_title_generator
ViewComponent::Storybook.stories_title_generator = ->(_stories) { custom_story_title }
example.run
ViewComponent::Storybook.stories_title_generator = original_generator
end

before do
# stories_title_generator is triggered when a class is declared.
# To test this behavior we have to create a new class dynamically onew we've
# configured the stories_title_generator in the around block above

# Descendant tracking appends our dynamic class to the list of
# descendants which (logically) causes failures on the .all example
# below
allow(ActiveSupport::DescendantsTracker).to receive(:store_inherited).once

component_class = Class.new(described_class) do
class << self
def name
"Demo::MoreButtonComponentStories"
end
end
end
stub_const("Demo::MoreButtonComponentStories", component_class)
end

it "converts Stories" do
expect(Demo::MoreButtonComponentStories.to_csf_params).to eq(
title: custom_story_title,
stories: []
)
end

it "allows compoents to override the title" do
expect(Demo::HeadingComponentStories.to_csf_params[:title]).to eq("Heading Component")
end
end

it "converts Stories with parameters" do
Expand Down

0 comments on commit 62f4599

Please sign in to comment.