Skip to content

Instantly share code, notes, and snippets.

@bradparker
Last active June 7, 2020 01:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bradparker/494a8d5c6f8f8e8f4098326ffc6b146a to your computer and use it in GitHub Desktop.
Save bradparker/494a8d5c6f8f8e8f4098326ffc6b146a to your computer and use it in GitHub Desktop.
Sketch of ViewComponent::Styled API
module ViewComponent
module Styled
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def styled(static = [], &block)
@static_styles = static
@dynamic_styles = block
end
def styled_like(components = [], static = [], &block)
@static_styles = components.flat_map(&:static_styles) + static
@dynamic_styles = Proc.new do
component_styles = components.flat_map do |component|
instance_eval(&component.dynamic_styles)
end
component_styles + instance_eval(&block)
end
end
def static_styles
@static_styles
end
def dynamic_styles
@dynamic_styles
end
end
def styles
self.class.static_styles + instance_eval(&self.class.dynamic_styles)
end
class Base
include ViewComponent::Styled
styled [] do
props.styles.to_a
end
def self.default_props
{ styles: [], element: :div }
end
attr_reader :props
def initialize(props = {})
@props = Struct.new(
*props.keys, keyword_init: true
).new(
self.class.default_props.merge(props)
)
end
def element
props.element
end
def call
{ element: element, styles: styles }
end
end
end
end
# Not sure about this. Don't know if to override `styled` and `styled_like` in subclasses
puts ViewComponent::Styled::Base.new(styles: [:foo], element: :section).call.inspect
# {:element=>:section, :styles=>[:foo]}
class ExampleA
include ViewComponent::Styled
styled [:base] do
if active?
[:active]
else
[]
end
end
def initialize(active:)
@active = active
end
def active?
@active
end
end
puts ExampleA.new(active: true).styles.inspect
# [:base, :active]
puts ExampleA.new(active: false).styles.inspect
# [:base]
class ExampleB
include ViewComponent::Styled
styled [:a_different_base] do
if good?
[:good]
else
[]
end
end
def initialize(good:)
@good = good
end
def good?
@good
end
end
puts ExampleB.new(good: true).styles.inspect
# [:a_different_base, :good]
puts ExampleB.new(good: false).styles.inspect
# [:a_different_base]
class ExampleC
include ViewComponent::Styled
styled_like [ExampleA, ExampleB] do
if really_good?
[:really_good]
else
[]
end
end
def good?
true
end
def active?
true
end
def really_good?
true
end
end
puts ExampleC.new.styles.inspect
# [:base, :a_different_base, :active, :good, :really_good]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment