Packages
moon
2.79.7
2.90.5
retired
2.90.4
2.90.3
2.90.2
2.90.1
2.90.0
2.89.4
2.89.1
2.89.0
2.88.0
2.87.11
2.87.10
2.87.9
2.87.8
2.87.7
2.87.6
2.87.5
2.87.4
2.87.3
2.87.2
2.87.1
2.87.0
2.86.1
2.86.0
2.85.1
2.85.0
2.84.0
2.83.0
2.82.0
2.81.4
2.81.3
2.81.2
2.81.1
2.81.0
2.80.2
2.80.1
2.80.0
2.79.13
2.79.12
2.79.11
2.79.10
2.79.9
2.79.8
2.79.7
2.79.6
2.79.5
2.79.4
2.79.3
2.79.2
2.79.1
2.79.0
2.78.4
2.78.3
2.78.2
2.78.1
2.78.0
2.77.0
2.76.5
2.76.4
2.76.3
2.76.2
2.76.1
2.76.0
2.75.0
2.74.1
2.74.0
2.73.8
2.73.7
2.73.6
2.73.5
2.73.4
2.73.3
2.73.2
2.73.1
2.73.0
2.72.5
2.72.4
2.72.3
2.72.2
2.72.1
2.72.0
2.71.1
2.71.0
2.70.0
2.69.2
2.69.1
2.69.0
2.68.11
2.68.10
Components-based design system written in elixir
Current section
Files
Jump to
Current section
Files
lib/moon/design/table.ex
defmodule Moon.Design.Table do
@moduledoc false
use Moon.StatelessComponent
alias Moon.Icon
@doc "List of selected ids, or just id, or [], or nil"
prop(selected, :any, default: [])
@doc "Sorting of the table, format [field:, \"ASC\"|\"DESC\"]. If given, component will sort given items before displaying"
prop(sort, :keyword, default: [])
@doc "The list of items to be rendered. If item does not have id - than index is used instead. Able to work with streams"
prop(items, :generator, required: true)
@doc "Event that firset on row click"
prop(row_click, :event)
@doc "Callback for generating on_click per row. row and row_id will bi given as parameters"
prop(row_click_cb, :any)
@doc "Sorting stuff"
prop(sorting_click, :event)
@doc "Can be used to add any class to the table"
prop(row_gap, :css_class, default: "border-spacing-y-1")
@doc "Size of the row. not a css class!"
prop(row_size, :string, values!: ~w(xs sm md lg xl 2xl), default: "md")
@doc "If cell has border"
prop(is_cell_border, :boolean, default: false)
@doc "If table has column headers or not"
prop(is_headless, :boolean, default: false)
@doc "If table is styled to present its rows in automatically alternating colours"
prop(is_zebra_style, :boolean, default: false)
@doc "Can be used as an additional class for all the rows"
prop(row_bg, :css_class, default: "bg-goku")
@doc "Can be used as an additional class for selected rows"
prop(selected_bg, :css_class, default: "bg-beerus")
@doc "Can be used as an additional class for header row"
prop(header_row_class, :css_class)
@doc "Can be used as an additional class for even rows in zebra-style table"
prop(even_row_bg, :css_class, default: "bg-transparent")
@doc "Can be used as an additional class for all rows. please use hover:... tailwind's format"
prop(hover_bg, :css_class)
@doc "The list of columns defining the Grid"
slot(cols, generator_prop: :items)
@doc "Just an id for a table tag"
prop(id, :string)
@doc "Data-testid attribute for a table tag"
prop(testid, :string)
@doc "Additional classes for a table tag"
prop(class, :css_class)
@doc "Additional attributes for tbody tag"
prop(body_attrs, :map, default: %{})
def render(assigns) do
import Moon.Light.Table.Helper
~F"""
<table
class={merge([
[
"text-sm border-spacing-x-0 border-beerus min-w-full bg-gohan rounded-moon-s-sm border-separate",
@row_gap,
"border-spacing-y-0": @is_zebra_style
],
@class
])}
{=@id}
data-testid={@testid}
>
<thead :if={!@is_headless}>
<tr class={@header_row_class}>
{#for {col, col_index} <- Enum.with_index(@cols)}
<th
class={merge([
"text-left font-medium whitespace-nowrap",
text_size_classes(@row_size),
[
"#{inter_cell_border()}": @is_cell_border && col_index < Enum.count(@cols) - 1,
"cursor-pointer": col[:sortable] && @sorting_click
],
col[:width]
])}
:on-click={(col[:sortable] && col[:name] && @sorting_click) || nil}
:values={"sort-key": col[:name], "sort-dir": toggle_sort_dir(@sort[:"#{col[:name]}"])}
data-testid={"sort-column-#{col[:name]}"}
>
{col[:label]}
<Icon
:if={col[:name] && col[:sortable]}
class={
"text-[1.5em] transition-transform transition-200",
"rotate-180": @sort[:"#{col[:name]}"] != "ASC",
"opacity-0": !@sort[:"#{col[:name]}"]
}
name="arrows_up"
/>
</th>
{/for}
</tr>
</thead>
<tbody {...@body_attrs}>
{#for {row_index, item} <- stream_data(assigns)}
<tr
class={merge([
(is_selected_item(item, @selected) && @selected_bg) || @row_bg,
@hover_bg,
"#{@even_row_bg}":
@is_zebra_style && !is_selected_item(item, @selected) && rem(row_index, 2) == 1,
"cursor-pointer": @row_click
])}
:on-click={(@row_click_cb && @row_click_cb.(item, row_index)) || @row_click}
:values={selected: "#{item.id}", domid: dom_id(row_index, @id)}
data-testid={"row-#{row_index}"}
id={dom_id(row_index, @id)}
>
{#for {col, col_index} <- Enum.with_index(@cols)}
<td
class={merge([
"first:rounded-l-moon-s-sm last:rounded-r-moon-s-sm",
col[:width],
text_size_classes(@row_size),
["#{inter_cell_border()}": @is_cell_border && col_index < Enum.count(@cols) - 1],
col[:class]
])}
data-testid={"row-#{row_index}-col-#{col_index}"}
>
<#slot {col} generator_value={item} />
</td>
{/for}
</tr>
{/for}
</tbody>
</table>
"""
end
@doc "Sorts items by sort given"
def sort_items(items, sort) do
Moon.Light.Table.Helper.sort_items(items, sort)
end
end