Module: ComponentHelper

Defined in:
app/helpers/component_helper.rb

Overview

The Registry of Names

All components available to views are declared here. There is no method_missing sorcery, no dynamic resolution, no convention-based guessing. If a component is not in the registry, it does not exist.

To create a new component: add one line to COMPONENT_MAP and create the class.

See: specs/the-holy-view-spec.md, Article 3

Constant Summary collapse

COMPONENT_MAP =
{
  # Layout Primitives
  VStack:      "VStackComponent",
  HStack:      "HStackComponent",
  Column:      "ColumnComponent",
  Row:         "RowComponent",
  Pusher:      "PusherComponent",
  Overlay:     "OverlayComponent",
  LinkTo:      "LinkToComponent",
  SubHeader:   "SubHeaderComponent",

  # Globals
  Reset:       "ResetComponent",
  Site:        "SiteComponent",
  Wrapper:     "WrapperComponent",
  Template:    "TemplateComponent",
  BackButton:  "BackButtonComponent",

  # Elements
  Button:      "ButtonComponent",
  Paragraph:   "ParagraphComponent",
  ButtonTo:    "ButtonToComponent",
  Container:   "ContainerComponent",
  Divider:     "DividerComponent",
  Emoji:       "EmojiComponent",
  Flag:        "FlagComponent",
  Header:      "HeaderComponent",
  Icon:        "IconComponent",
  Image:       "ImageComponent",
  Input:       "InputComponent",
  Label:       "LabelComponent",
  List:        "ListComponent",
  Loader:      "LoaderComponent",
  Placeholder: "PlaceholderComponent",
  Rail:        "RailComponent",
  Reveal:      "RevealComponent",
  Segment:      "SegmentComponent",
  SegmentGroup: "SegmentGroupComponent",
  Step:        "StepComponent",
  StepGroup:   "StepGroupComponent",

  Text:        "TextComponent",

  # Collections
  Breadcrumb:  "BreadcrumbComponent",
  Form:        "FormComponent",
  Grid:        "GridComponent",
  Menu:        "MenuComponent",
  MenuItem:    "MenuItemComponent",
  SubMenu:     "SubMenuComponent",
  Message:     "MessageComponent",
  Table:       "TableComponent",
  TableRow:    "TableRowComponent",
  TableCell:   "TableCellComponent",

  # Views
  Ad:          "AdComponent",
  ItemGroup:   "ItemGroupComponent",
  Card:        "CardComponent",
  Comment:     "CommentComponent",
  Feed:        "FeedComponent",
  Item:        "ItemComponent",
  Statistic:   "StatisticComponent",

  # Modules
  Accordion:   "AccordionComponent",
  Calendar:    "CalendarComponent",
  Checkbox:    "CheckboxComponent",
  Dimmer:      "DimmerComponent",
  Dropdown:    "DropdownComponent",
  Embed:       "EmbedComponent",
  Flyout:      "FlyoutComponent",
  Modal:       "ModalComponent",
  Nag:         "NagComponent",
  Popup:       "PopupComponent",
  Progress:    "ProgressComponent",
  Slider:      "SliderComponent",
  Rating:      "RatingComponent",
  Search:      "SearchComponent",
  Shape:       "ShapeComponent",
  Sidebar:     "SidebarComponent",
  Sticky:      "StickyComponent",
  Tab:         "TabComponent",
  Toast:       "ToastComponent",
  Transition:  "TransitionComponent",

  # Behaviors
  Api:         "ApiComponent",
  State:       "StateComponent",
  Visibility:  "VisibilityComponent",

  # Blocks
  ResourceListBlock: "ResourceListBlock"
}.freeze

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, **kwargs, &block) ⇒ Object

PascalCase method calls that aren’t in COMPONENT_MAP are forwarded to the current form builder as underscored method names. e.g. TextField(:label, placeholder: “Name”) -> f.text_field(:label, placeholder: “Name”)

EmojiField(:icon)                      -> f.emoji_field(:icon)
Select(:role, [["Admin","admin"]])      -> f.select(:role, [["Admin","admin"]])


158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'app/helpers/component_helper.rb', line 158

def method_missing(method_name, *args, **kwargs, &block)
  if method_name =~ /\A[A-Z]/ && @_form_builder
    underscored = method_name.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
    if @_form_builder.respond_to?(underscored)
      output_buffer << @_form_builder.public_send(underscored, *args, **kwargs, &block)
      return
    end
  end

  if method_name =~ /\A[A-Z]/
    tag_name = method_name.to_s.underscore.gsub("_", "-")
    output_buffer << tag.public_send(tag_name, *args, **kwargs, &block)
    return
  end

  super
end

Instance Method Details

#ContentFor(*args, &block) ⇒ Object



147
148
149
150
151
# File 'app/helpers/component_helper.rb', line 147

def ContentFor(*args, &block)
  value = content_for(*args, &block)
  output_buffer << value if value.present?
  value
end

#CspMetaTagObject



143
144
145
# File 'app/helpers/component_helper.rb', line 143

def CspMetaTag
  output_buffer << csp_meta_tag
end

#CsrfMetaTagsObject



139
140
141
# File 'app/helpers/component_helper.rb', line 139

def CsrfMetaTags
  output_buffer << csrf_meta_tags
end

#DocType(type = :html) ⇒ Object



127
128
129
# File 'app/helpers/component_helper.rb', line 127

def DocType(type = :html)
  output_buffer << "<!DOCTYPE #{type}>".html_safe
end

#JavascriptImportmapObject



135
136
137
# File 'app/helpers/component_helper.rb', line 135

def JavascriptImportmap
  output_buffer << javascript_importmap_tags
end

#Partial(*args, **kwargs, &block) ⇒ Object



123
124
125
# File 'app/helpers/component_helper.rb', line 123

def Partial(*args, **kwargs, &block)
  output_buffer << render(*args, **kwargs, &block)
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


176
177
178
179
180
181
182
183
184
185
# File 'app/helpers/component_helper.rb', line 176

def respond_to_missing?(method_name, include_private = false)
  if method_name =~ /\A[A-Z]/ && @_form_builder
    underscored = method_name.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
    return true if @_form_builder.respond_to?(underscored)
  end

  return true if method_name =~ /\A[A-Z]/

  super
end

#Style(css = nil, &block) ⇒ Object



115
116
117
# File 'app/helpers/component_helper.rb', line 115

def Style(css = nil, &block)
  output_buffer << render("StyleComponent".constantize.new(css), &block)
end


131
132
133
# File 'app/helpers/component_helper.rb', line 131

def StylesheetLink(*args)
  output_buffer << stylesheet_link_tag(*args)
end

#text(content) ⇒ Object



119
120
121
# File 'app/helpers/component_helper.rb', line 119

def text(content)
  output_buffer << content.to_s
end