Hello,
I have been working with Surface for a little while and have been pretty thrilled with the experience and its ease of use, however, I have recently run across a use case whose implementation is unclear to me.
I have grabbed the example Table component from the Surface-UI docs to work with in my side project and its worked great.
However, I’d like to render a bunch of tables which all share the same formatting but can continue accept a <:cols>
slot, so that I can individually specify the content for each, using the same <Col>
component as the original table.
So here is my first attempt which does not work, but I’m hoping that someone could help me understand how this could work:
defmodule OOTPUtilityWeb.Components.Player.Attributes.Table do
use Surface.Component
alias OOTPUtilityWeb.Components.Shared.Table
slot cols, args: [item: ^data], required: true
prop attributes, :keyword, required: true
prop id, :string, required: true
def render(assigns) do
~F"""
<Table id={@id} data={{name, ratings} <- @attributes} header_class={&header_class/2} column_class={&column_class/2}>
<:cols>
<#cols />
</:cols>
</Table>
"""
end
def header_class(_standing, 0) do
do_header_class(["text-left"])
end
def header_class(_col, _index),
do: do_header_class([])
def do_header_class(extra_classes \\ []) do
extra_classes ++ [
"p-1",
"md:p-2",
"uppercase",
"font-small",
"md:font-medium",
"text-left"
]
end
def column_class(_standing, 0) do
do_column_class(["text-left"])
end
def column_class(_standing, _index) do
do_column_class([])
end
defp do_column_class(extra_classes) do
Enum.join(extra_classes ++ [ "p-px", "md:p-1", "whitespace-nowrap" ], " ")
end
end
and then try to use it in a way like this:
defmodule OOTPUtilityWeb.Components.Player.Attributes.Pitches do
use Surface.Component
alias OOTPUtilityWeb.Components.Player.Attributes.Table
alias OOTPUtilityWeb.Components.Shared.Table.Column
prop pitches, :keyword, required: true
def render(assigns) do
~F"""
<Table id={"player-pitch-ratings"} attributes={@pitches}>
<Column label={"Pitches"}>
{attribute_name(name)}
</Column>
<Column label="Ability">
{as_number(Keyword.get(ratings, :ability))}
</Column>
<Column label="Talent">
{as_number(Keyword.get(ratings, :talent))}
</Column>
</Table>
"""
end
def attribute_name(attribute) do
OOTPUtilityWeb.Helpers.capitalize_all(attribute)
end
def as_number(rating) do
assigns = %{rating: rating}
~F"""
<span class={"text-rating-#{@rating * 2}"}>{@rating}</span>
"""
end
end
But I see the following compilation error:
== Compilation error in file lib/ootp_utility_web/components/player/attributes/table.ex ==
** (FunctionClauseError) no function clause matching in Code.ensure_compiled/1
The following arguments were given to Code.ensure_compiled/1:
# 1
{:cols, [line: 1], nil}
Attempted function clauses (showing 1 out of 1):
def ensure_compiled(module) when is_atom(module)
(elixir 1.13.2) lib/code.ex:1519: Code.ensure_compiled/1
(surface 0.7.0) lib/surface/compiler/helpers.ex:236: Surface.Compiler.Helpers.check_module_loaded/2
(surface 0.7.0) lib/surface/compiler/helpers.ex:260: Surface.Compiler.Helpers.validate_component_module/2
(surface 0.7.0) lib/surface/compiler.ex:677: Surface.Compiler.convert_node_to_ast/3
(surface 0.7.0) lib/surface/compiler.ex:198: anonymous fn/3 in Surface.Compiler.to_ast/2
(elixir 1.13.2) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
(surface 0.7.0) lib/surface/compiler.ex:197: Surface.Compiler.to_ast/2
(surface 0.7.0) lib/surface/compiler.ex:433: Surface.Compiler.convert_node_to_ast/3
since this is a compiler error, I’m wondering if this is why Surface.quote_surface/2
exists, but TBH I’m still struggling to understand how it might help me if it did.
If anyone could help me to at least understand why Surface seems to hate this so much or how I might leverage Surface.quote_surface/2
to fix this I’d be grateful.
Thank you,
Joe