Rails 5.1+のシンプルなビューコンポーネント、Elemental_styleguideとうまく合うように設計されています。二人は一緒になって、ブラッド・フロストの作品と、ロンリー・プラネットのスタイルガイドリッツォの背後にある考えに触発されています。
この行をアプリケーションのGemfileに追加します。
gem "elemental_components"そして実行してください:
$ bundleここで提供される例は、BEMの命名規則を使用します。
コンポーネントはapp/componentsに住んでいます。実行してコンポーネントを生成します。
$ bin/rails g elemental_components:component alertこれにより、次のファイルが作成されます。
app/
components/
alert/
_alert.html.erb
alert.css
alert.js
alert_component.rb
ジェネレーターには--skip-cssおよび--skip-jsオプションも必要です。
マークアップとCSSを追加しましょう。
<% # app/components/alert/_alert.html.erb %>
< div class =" alert alert--primary " role =" alert " >
Message
</ div > /* app/components/alert/alert.css */
. alert {
padding : 1 rem ;
}
. alert--primary {
background : blue;
}
. alert--success {
background : green;
}
. alert--danger {
background : red;
}このコンポーネントは、 componentヘルパーを使用してレンダリングできるようになりました。
<%= component "alert" %> CSSなどの資産を要求するために、マニフェストで手動でそれらを必要とします。例: application.css :
/*
*= require alert/alert
*/または、すべてのコンポーネントの資産が必要になるcomponentsが必要です。
/*
*= require elemental_components
*/コンポーネントにデータを渡すには、属性とコンテンツブロックの2つの方法があります。属性は、ID、修飾子、データ構造(モデルなど)などのデータに役立ちます。コンテンツブロックは、HTMLコンテンツをコンポーネントに注入する必要がある場合に役立ちます。
作成したコンポーネントの属性を定義しましょう。
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :context
attribute :message
end <% # app/components/alert/_alert.html.erb %>
< div class =" alert alert-- <%= alert.context %> " role =" alert " >
<%= alert.message %>
</ div > <%= component "alert", message: "Something went right!", context: "success" %>
<%= component "alert", message: "Something went wrong!", context: "danger" %> コンポーネントにテキストまたはHTMLコンテンツを挿入するために、コンポーネントのコンテンツメソッドをテンプレートに印刷し、コンテンツブロックをコンポーネントヘルパーに渡すことで入力できます。
<% # app/components/alert/_alert.html.erb %>
< div class =" alert alert-- <%= alert.context %> " role =" alert " >
<%= alert.content %>
</ div > <%= component "alert", context: "success" do %>
< em > Something </ em > went right!
<% end %>属性のもう1つの良いユースケースは、モデルに裏付けられたコンポーネントがある場合です。
# app/components/comment_component.rb %>
class CommentComponent < ElementalComponents :: Component
attribute :comment
delegate :id ,
:author ,
:body , to : :comment
end <% # app/components/comment/_comment.html.erb %>
< div id =" comment- <%= comment.id %> " class =" comment " >
< div class =" comment__author " >
<%= link_to comment.author.name, author_path(comment.author) %>
</ div >
< div class =" comment__body " >
<%= comment.body %>
</ div >
</ div > <% comments.each do |comment| %>
<%= component "comment", comment: comment %>
<% end %> 属性にはデフォルト値を持つことができます。
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :message
attribute :context , default : "primary"
end追加のロジックで属性をオーバーライドするのは簡単です。
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :message
attribute :context , default : "primary"
def message
@message . upcase if context == "danger"
end
endコンポーネントが適切に初期化されるようにするにはActiveModel::Validationsを使用できます。
# app/components/alert_component.rb %>
class AlertComponent < ElementalComponents :: Component
attribute :label
validates :label , presence : true
end検証は、コンポーネントの初期化中に実行され、 ActiveModel::ValidationErrorが存在しない場合はRAPENが表示されます。
属性とブロックは、モデルなどのデータ構造に裏打ちされた単純なコンポーネントまたはコンポーネントに最適です。他のコンポーネントは本質的により一般的であり、さまざまなコンテキストで使用できます。多くの場合、それらは複数の部品または要素で構成され、時には繰り返され、時には独自の修飾子が必要になります。
カードコンポーネントを使用します。反応では、一般的なアプローチは、サブコンポーネントを作成することです。
< Card flush = { true } >
< CardHeader centered = { true } >
Header
</ CardHeader >
< CardSection size = "large" >
Section 1
</ CardSection >
< CardSection size = "small" >
Section 2
</ CardSection >
< CardFooter >
Footer
</ CardFooter >
</ Card >このアプローチには2つの問題があります。
CardHeader Cardの外側に配置できることを意味します。CardHeaderは、下に、またはCardFooter内に配置できます。この宝石を使用して、同じコンポーネントを次のように書くことができます。
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
attribute :flush , default : false
element :header do
attribute :centered , default : false
end
element :section , multiple : true do
attribute :size
end
element :footer
end <% # app/components/card/_card.html.erb %>
< div class =" card <%= "card--flush" if card.flush %> " >
<% if card.header.content? %>
< div class =" card__header <%= "card__header--centered" if card.header.centered %> " >
<%= card.header.content %>
</ div >
<% end %>
<% card.sections.each do |section| %>
< div class =" card__section <%= "card__section--#{section.size}" %> " >
<%= section.content %>
</ div >
<% end %>
<% if card.footer.content? %>
< div class =" card__footer " >
<%= card.footer.content %>
</ div >
<% end %>
</ div >要素は孤立したサブコンポーネントと考えることができ、コンポーネントで定義されています。 multiple: trueは繰り返し要素になり、ブロックを通過させると、コンポーネントで属性を宣言するのと同じように、要素の属性を宣言できます。
データを入力するために、コンポーネントヘルパーにブロックを渡します。コンポーネントはコンポーネントを生成します。コンポーネントは、コンポーネントの場合と同じ方法で要素に属性とコンテンツブロックを設定できます。
<%= component "card", flush: true do |c| %>
<% c.header centered: true do %>
Header
<% end %>
<% c.section size: "large" do %>
Section 1
<% end %>
<% c.section size: "large" do %>
Section 2
<% end %>
<% c.footer do %>
Footer
<% end %>
<% end %> 上記の例のsectionなど、繰り返し要素への複数の呼び出しは、各セクションを配列に追加します。
別の良いユースケースは、ナビゲーションコンポーネントです。
# app/components/navigation_component.rb %>
class NavigationComponent < ElementalComponents :: Component
element :items , multiple : true do
attribute :label
attribute :url
attribute :active , default : false
end
end <%= component "navigation" do |c| %>
<% c.item label: "Home", url: root_path, active: true %>
<% c.item label: "Explore" url: explore_path %>
<% end %> ここでの別の方法は、コンポーネントをレンダリングするときにHTMLを挿入する必要がない場合、属性としてデータ構造をコンポーネントに渡すことです。
<%= component "navigation", items: items %> 要素にも検証があります。
class NavigationComponent < ElementalComponents :: Component
element :items , multiple : true do
attribute :label
attribute :url
attribute :active , default : false
validates :label , presence : true
validates :url , presence : true
end
end要素もネストすることができますが、最小限に抑え続けることをお勧めします。
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
...
element :section , multiple : true do
attribute :size
element :header
element :footer
end
end属性と要素を宣言することに加えて、ヘルパーの方法を宣言することもできます。これは、テンプレートからロジックを排除したい場合に役立ちます。カードコンポーネントテンプレートから修飾子ロジックを抽出しましょう。
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
...
def css_classes
css_classes = [ "card" ]
css_classes << "card--flush" if flush
css_classes . join ( " " )
end
end <% # app/components/card/_card.html.erb %>
<%= content_tag :div, class: card.css_classes do %>
...
<% end %>要素でヘルパーを宣言することさえ可能です:
# app/components/card_component.rb %>
class CardComponent < ElementalComponents :: Component
...
element :section , multiple : true do
attribute :size
def css_classes
css_classes = [ "card__section" ]
css_classes << "card__section-- #{ size } " if size
css_classes . join ( " " )
end
end
end <% # app/components/card/_card.html.erb %>
<%= content_tag :div, class: card.css_classes do %>
...
<%= content_tag :div, class: section.css_classes do %>
<%= section %>
<% end %>
...
<% end %>ヘルパーメソッドは、 @viewインスタンス変数を使用して、 link_toやcontent_tagなどのレールヘルパーを呼び出すこともできます。
ボタンなどのいくつかの小さなコンポーネントの場合、レンダリングをスピードアップするために、部分的なスキップを完全にスキップすることが理にかなっているかもしれません。これは、コンポーネントのrenderをオーバーライドすることで実行できます。
# app/components/button_component.rb %>
class ButtonComponent < ElementalComponents :: Component
attribute :label
attribute :url
attribute :context
def render
@view . link_to label , url , class : css_classes
end
def css_classes
css_classes = "button"
css_classes << "button-- #{ context } " if context
css_classes . join ( " " )
end
end <%= component "button", label: "Sign up", url: sign_up_path, context: "primary" %>
<%= component "button", label: "Sign in", url: sign_in_path %> コンポーネントは、名前空間の下にネストできます。これは、アトミックデザイン、BEMIT、その他のコンポーネント分類スキームなどを実践したい場合に役立ちます。 NameSpacedコンポーネントを作成するには、フォルダーに貼り付けて、クラスをモジュールにラップします。
module Objects
class MediaObject < ElementalComponents :: Component ; end
end次に、次のようなテンプレートからそれを呼び出します:
<%= component "objects/media_object" %> このライブラリは、Elemental_styleguideとともに、Atomic Design and Living Styleガイドに関するBrad Frostの著作と、Lonely Planet Style GuideのRizzoに触発されました。他のインスピレーションは次のとおりです。
Real World Style Guidesのリストについては、http://styleguides.ioをご覧ください。