Coder Social home page Coder Social logo

vc_shortcut's Introduction

VcShortcut

Gem Version Gem Total Downloads

VcShortcut simplifies the API for rendering ViewComponents and Phlex components in Ruby on Rails applications, reducing verbosity.

It also features caching for lookups, ensuring that it operates with minimal overhead and maximal speed.

<%# Instead of: %>
<%= render Admin::Dashboard::TabsComponent.new(style: :compact) do |tabs| %>
  ...
<% end %>

<%# You can now also do: %>
<%= vc.admin.dashboard.tabs(style: :compact) do |tabs| %>
  ...
<% end %>

It works out of the box with just a bundle add vc_shortcut, and is also highly customizable.

By default, two shortcuts are set up: vc for rendering and vci for instantiating components. You can change the shortcut prefix.

For more advanced use-cases, it also allows you to change the lookup logic as well as setup custom shortcuts.

Installation

Add vc_shortcut to your Gemfile:

bundle add vc_shortcut

Usage

If you're using ViewComponent or Phlex in your Rails app and your component class names end with Component or ::Component (which should be the standard), there's nothing else you need to do.

By default, two shortcuts are set up: vc for rendering and vci for instantiating components.

You can start using these helpers from any views or from your components.

Example:

### Instead of:
render Wysiwyg::UploadFieldComponent.new(limit: 50.megabytes) do |upload_field|
  upload_field.with_footer do
      render IconComponent.new('file')
  end
end
### You can now also do:
vc.wysiwyg.upload_field(limit: 50.megabytes) do |upload_field|
  upload_field.with_footer do
    vc.icon('file')
  end
end

### Instead of:
instance = ProgressBarComponent.new(progress: 75)
### You can now also do:
instance = vci.progress_bar(progress: 75)


Interested in a powerful Rails UI library?

I am working on a super-powerful Rails UI library - components as well as templates & patterns.

Please check this out if you're interested.


Advanced

You can customize things by creating an initializer file at config/initializers/vc_shortcut.rb.

Customize name of default shortcuts

You can rename the default shortcuts or disable them entirely:

# In config/initializers/vc_shortcut.rb:
VcShortcut.render_shortcut      = :vc  # Or whatever you prefer
VcShortcut.instantiate_shortcut = :vci # Or whatever you prefer

You can disable a shortcut by setting its value to false.

Custom Component Lookup

By default, we assume your component class names end with Component or ::Component, which is the standard and should cover the majority of cases.

However, if you're doing something non-standard, you can customize the logic that finds a component:

# In config/initializers/vc_shortcut.rb:
VcShortcut.find_component = ->(camelized_name) {
  "#{camelized_name}Component".safe_constantize || "#{camelized_name}::Component".safe_constantize
}

For example, if all your components are namespaced under Polaris and are suffixed with Primitive instead of Component, you can set:

# In config/initializers/vc_shortcut.rb:
VcShortcut.find_component = ->(camelized_name) {
  "Polaris::#{camelized_name}Primitive".safe_constantize
}
## So instead of:
#   `render Polaris::Admin::NavbarPrimitive.new`
#  You can now also do:
#   `vc.admin.navbar`

Super Advanced

You can take customization one level further if needed:

Registering Additional Custom Shortcuts

# In config/initializers/vc_shortcut.rb:
VcShortcut.register :admin,
  find_component: ->(camelized_name) {
    "Ui::Admin::#{camelized_name}::Component".safe_constantize
  },
  process: ->(context) {
    context.view_context.render(
      context.component.new(*context.call_args, **context.call_kwargs),
      &context.call_block
    )
  }
## So instead of:
#   `render Ui::Admin::Navbar::Component.new`
#  You can now also do:
#   `admin.navbar`

Taking Full Control

You can customize the find process even more by specifying find instead of find_component:

# In config/initializers/vc_shortcut.rb:
VcShortcut.register :admin,
  find: ->(context) {
    # If you return :has_more, we'll assume there's another component coming up in the chain.
    # If you return a non-nil value, we'll assume this is the leaf component and move on to call `process`.
    # If you return nil, we'll assume nothing was found for the given chain and raise an error.
    chain_camelized = context.chain_camelized
    component = "Ui::#{chain_camelized}::Component".safe_constantize
    next component if component
    :has_more if chain_camelized.safe_constantize
  },
  process: ->(context) {
    context.view_context.render(
      context.component.new(*context.call_args, **context.call_kwargs),
      &context.call_block
    )
  }
## So instead of:
#   `render Ui::Admin::Navbar::Component.new`
#  You can now also do:
#   `admin.navbar`

The return value of the register call is a module that you can include in places where you wish to make the helper available. It's, however, automatically included for all your views, view components, and phlex components.

What is context in the above examples?

context is provided to the find and process proc. It's an object that responds to the following methods:

1. context.chain:

Chain until now. E.g., if you call vc.admin.button:

  • When processing :admin, chain will be [:admin].
  • Then, when processing :button, chain will be [:admin, :button].
2. context.chain_camelized:

Just does context.chain.join('/').camelize. So, if chain was [:admin, :buttton], it'd return Admin::Button.

3. context.component:

Only set when called in the process proc. It is the component returned by the find or find_component proc.

4. context.call_args context.call_kwargs, context.call_block:

Only set when called in the process proc. These are the arguments used when calling the shortcut. E.g.:

vc.admin.navbar('Treact', size: :sm, style: :compact) do |navbar|
  navbar.with_menu_item(...)
end

Here, context.call_args will be ['Treact'], context.call_kwargs will be { size: :sm, style: :compact } and context.call_block will be the block above.

5. context.view_context:

The view context when the shortcut was called. You can use it to render the component. E.g.:

instance = context.component.new(*context.call_args, **context.call_kwargs)
html = context.view_context.render(instance, &context.call_block)

Contributing

Bug reports and pull requests are welcome on GitHub.

License

The gem is available as open-source under the terms of the MIT License.

vc_shortcut's People

Contributors

dependabot[bot] avatar owaiswiz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.