Block rendering outside of component template? #368
-
I am trying to render a simple badge with some content inside. This is from an ERB file: <%= render Elements::BadgeComponent.new(size: :large, color: :emerald) do %>
Today <%= content_tag(:span, "🥳", class: "ml-2 text-base") %>
<% end %>
and the def template(&content)
div(class: div_class) do
yield_content(&content) if content.present?
@text.presence
end
end However, the text from the block I pass is rendered OUTSIDE the DIV. Like such: Here's the resulting HTML: Today <span class="ml-2 text-base">🥳</span>
<div class="text-sm inline-flex font-medium rounded-full text-center px-2.5 py-1 bg-emerald-100 text-emerald-600">
</div> Is this a bug? Am I doing something wrong? |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 9 replies
-
Hey @cmer can you share your whole |
Beta Was this translation helpful? Give feedback.
-
# frozen_string_literal: true
class Elements::BadgeComponent < Phlex::HTML
STYLES = %i[default icon].freeze
VARIANTS = %i[default text_white].freeze
SIZES = %i[mini small large].freeze
# Variant / Color
CSS_COLORS = {
default: {
gray: "bg-slate-100 text-slate-500",
indigo: "bg-indigo-100 text-indigo-600",
sky: "bg-sky-100 text-sky-600",
emerald: "bg-emerald-100 text-emerald-600",
amber: "bg-amber-100 text-amber-600",
yellow: "bg-yellow-50 text-yellow-600",
rose: "bg-rose-100 text-rose-600",
purple: "bg-purple-100 text-purple-600",
blue: "bg-blue-100 text-blue-600",
slate_light: "bg-slate-100 text-slate-500",
slate_dark: "bg-slate-700 text-slate-100"
},
text_white: {
gray: "bg-slate-500 text-white",
indigo: "bg-indigo-500 text-white",
sky: "bg-sky-500 text-white",
emerald: "bg-emerald-500 text-white",
amber: "bg-amber-500 text-white",
yellow: "bg-yellow-500 text-white",
rose: "bg-rose-500 text-white",
purple: "bg-purple-500 text-white",
blue: "bg-blue-500 text-white",
slate: "bg-slate-500 text-white"
}
}
# Style / Size
CSS_STYLE_SIZES = {
default: {
mini: "text-[0.55rem] inline-flex font-semibold text-center tracking-widest uppercase px-2 py-0.5 mx-1 relative -top-[0.0625rem]",
small: "text-xs inline-flex font-medium rounded-full text-center px-2.5 py-1",
large: "text-sm inline-flex font-medium rounded-full text-center px-2.5 py-1"
},
icon: {
mini: proc { raise "Icon style does not support mini size" },
small: "text-xs inline-flex font-medium rounded-full text-center px-2 py-0.5 items-center",
large: "text-sm inline-flex font-medium rounded-full text-center px-2 py-0.5 items-center"
}
}
def initialize(color: :gray, style: :default, size: :small, variant: :default, text: nil)
raise ArgumentError, "Invalid style: #{style}. Use one of: #{STYLES.join(", ")}." unless STYLES.include?(style)
raise ArgumentError, "Invalid size: #{size}. Use one of: #{SIZES.join(", ")}." unless SIZES.include?(size)
raise ArgumentError, "Invalid variant: #{variant}. Use one of: #{VARIANTS.join(", ")}." unless VARIANTS.include?(variant)
raise ArgumentError, "Invalid color: #{color}. Use one of: #{CSS_COLORS[variant]&.keys.join(", ")}." unless CSS_COLORS[variant]&.key?(color)
@text = text
@size = size
@style = style
@color = color
@variant = variant
end
def template(&content)
div(class: div_class) do
yield_content(&content) if content.present?
@text.presence
end
end
private
def div_class
[CSS_STYLE_SIZES[@style][@size], CSS_COLORS[@variant][@color]].map do |value|
value.is_a?(Proc) ? value.call : value
end.join(" ")
end
end |
Beta Was this translation helpful? Give feedback.
-
@cmer my guy, you look like you could benefit from https://github.com/avo-hq/class_variants. It won't help with this problem, but it could help with these plentiful variations of components. |
Beta Was this translation helpful? Give feedback.
-
I was able to reproduce the issue and I have put together an example Rails app. It happens when I try to generate a Phlex component from a View Component. |
Beta Was this translation helpful? Give feedback.
-
So, you have two separate problems here. And thankfully we have @joeldrapper's attention so I can find out if this is the right way to go about dealing with them or not.
In order to allow for both arguments and blocks, you'll need to test the argument rather than the block. if @text.present?
text @text
else
yield
end 2). I have solved your positional error by means of the same magic I've employed thus far using Phlex. There have been HUNDREDS of occasions where I've had trouble with nesting like that, and threw Anyhow (and this is with Phlex 1.0.0-rc1, which still had the faulty behavior, so if you're testing make sure to update your Phlex): Change: yield_content(&content) to: unsafe_raw { capture(&content) } and everything will display how you would expect. |
Beta Was this translation helpful? Give feedback.
-
I finally have a fix! phlex-ruby/phlex-rails#25 If you upgrade to |
Beta Was this translation helpful? Give feedback.
I finally have a fix! phlex-ruby/phlex-rails#25
If you upgrade to
phlex-rails
version0.4.2
, it should work correctly with ViewComponent.