MishkaGervaz.Table.Templates.Shared (MishkaGervaz v0.0.2)

Copy Markdown View Source

Shared rendering functions used by all templates.

These provide default implementations for common UI elements like filters, bulk actions, pagination, and template switcher.

Assigns

All functions expect two key assigns:

  • @static - Same reference always (columns, filters, ui_adapter, etc.)
  • @state - Changes trigger re-render (page, filter_values, etc.)

See MishkaGervaz.Table.Behaviours.Template, MishkaGervaz.Table.Templates.Table, MishkaGervaz.Table.Templates.MediaGallery, and MishkaGervaz.Table.Web.Renderer.

Summary

Functions

Checks if a filter group is visible and accessible for the current state.

Checks if a row action is visible for a given record and state.

The five "is this part on?" flags a card template's render/1 opens with.

Builds active filter chip data for custom templates.

The number of rows a bulk action runs on, or nil when the table cannot tell.

Checks all media gallery checkboxes.

Checks all table row checkboxes and adds selection highlighting.

The extra classes the resource asks this record's row to wear, if any.

Format a filter value for display in a chip.

Returns the Tailwind grid-cols class for a given column count.

Returns the column count from a filter group's UI config, or nil if not set. Pass the result to grid_cols/1 for the Tailwind class.

Returns the icon name for a filter group, falling back to "hero-funnel". Useful for custom templates rendering their own filter group UI.

Returns the resolved label for a filter group, falling back to humanized group name. Useful for custom templates rendering their own filter group UI.

Returns the CSS class for a collapsible filter group panel wrapper. Falls back to a default rounded panel style if not set in DSL.

Check if a filter value is meaningful (non-nil, non-empty).

Checks if any row actions or dropdowns are potentially visible for the current user.

Check if any bulk actions are visible for the given archive status.

Returns a CSS class for inline (non-collapsible) filters based on filter type. Text filters get a flexible width, relation filters a minimum width, others a smaller minimum. Only used when the group has no custom class (i.e., wrapper is "contents"). Custom templates can override this if they need different sizing.

Returns the CSS class for an inline (non-collapsible) group wrapper. If the group has ui do class "..." end, uses that. Otherwise defaults to "contents" which makes the wrapper transparent so filters participate directly in the parent flex layout.

Merges dynamic relation filter state (options, loading, etc.) into filter configs.

The row actions a template should draw as buttons — everything except an :accordion.

Which pager a resource asked for — numbered pages, a Load-more button, or infinite scroll.

Prepares all filter groups for rendering by custom templates.

The four class strings that put a page's :rail slot beside its records rather than above them.

Whether this record's tick is on, under either selection mode.

Renders the bulk-action bar shown once rows are selected.

Renders one cell the way the plain table does — format first, then the column's render if it has one, then its type module, then the bare value.

Renders the empty state with configurable message, icon, and action.

Renders the error state with configurable message, icon, and retry button.

One filter's input, resolved from its type — text, select, boolean, relation, date range — including the disabled state a depends_on filter wears until its parent has a value.

Renders the filter bar: the toolbar row, any collapsible filter groups, the active-filter chips and the archive toggle.

No header at all — the default for a template whose page already names itself.

Renders the loading state with spinner and configurable text.

Renders the pagination control — numbered pages, a load-more button or the infinite-scroll sentinel, whichever the resource configured.

Renders one row's action strip: the inline buttons, then any dropdown.

Renders the Table/Cards switcher for a resource that declared switchable_templates.

Resolve a filter chip's display value, using relation labels when available.

Sorts filter groups by their position attribute.

Unchecks all selection checkboxes and removes selection highlighting.

Functions

accessible_group?(group, state)

Checks if a filter group is visible and accessible for the current state.

action_visible?(arg1, record, state)

Checks if a row action is visible for a given record and state.

Used by templates to filter visible row actions.

assign_card_flags(assigns)

@spec assign_card_flags(map()) :: map()

The five "is this part on?" flags a card template's render/1 opens with.

Each is a feature flag crossed with whether there is anything to show — :paginate alone does not mean a pager, it means a pager if the count is known and non-zero.

Assigns show_checkboxes, show_filters, show_pagination, show_bulk_actions and show_switcher.

build_active_filter_chips(state, static)

@spec build_active_filter_chips(map(), map()) :: {[map()], boolean()}

Builds active filter chip data for custom templates.

Returns {visible_chips, has_any_active_filters} where:

  • visible_chips excludes visible: false filters (hidden from UI but still active in state)
  • has_any_active_filters is true if any filter has a value (including hidden ones)

Use has_any_active_filters for the "Clear all" button visibility so users can always clear hidden filters (e.g., id filter from URL).

bulk_selection_count(state)

@spec bulk_selection_count(map()) :: non_neg_integer() | nil

The number of rows a bulk action runs on, or nil when the table cannot tell.

Checked rows are counted. With select all, the count is the table's total minus the unchecked rows, and the table can tell only when it holds every row or counts its rows (:numbered pagination, or show_total true in the pagination ui block).

check_all_gallery(js \\ %JS{}, scope \\ nil)

@spec check_all_gallery(Phoenix.LiveView.JS.t(), String.t() | nil) ::
  Phoenix.LiveView.JS.t()

Checks all media gallery checkboxes.

check_all_table(js \\ %JS{}, scope \\ nil)

@spec check_all_table(Phoenix.LiveView.JS.t(), String.t() | nil) ::
  Phoenix.LiveView.JS.t()

Checks all table row checkboxes and adds selection highlighting.

custom_row_class(arg1, record)

@spec custom_row_class(map(), map()) :: list() | String.t() | nil

The extra classes the resource asks this record's row to wear, if any.

row do class do apply … end end is where a resource says which records look different. Callers compose the result — selection state usually has to win over it.

format_chip_value(value)

@spec format_chip_value(term()) :: String.t()

Format a filter value for display in a chip.

grid_cols(_)

Returns the Tailwind grid-cols class for a given column count.

group_columns(group)

@spec group_columns(map()) :: pos_integer() | nil

Returns the column count from a filter group's UI config, or nil if not set. Pass the result to grid_cols/1 for the Tailwind class.

group_icon(group)

@spec group_icon(map()) :: String.t()

Returns the icon name for a filter group, falling back to "hero-funnel". Useful for custom templates rendering their own filter group UI.

group_label(group)

@spec group_label(map()) :: String.t()

Returns the resolved label for a filter group, falling back to humanized group name. Useful for custom templates rendering their own filter group UI.

group_panel_class(group)

@spec group_panel_class(map()) :: String.t()

Returns the CSS class for a collapsible filter group panel wrapper. Falls back to a default rounded panel style if not set in DSL.

has_chip_value?(map)

@spec has_chip_value?(term()) :: boolean()

Check if a filter value is meaningful (non-nil, non-empty).

has_user_visible_actions?(row_actions, dropdowns, state)

@spec has_user_visible_actions?(list(), list() | nil, map()) :: boolean()

Checks if any row actions or dropdowns are potentially visible for the current user.

Used by templates to decide whether to render the Actions column header. Does not evaluate per-record visibility functions — only checks restricted and boolean/atom visible values.

has_visible_bulk_actions?(bulk_actions, archive_status)

@spec has_visible_bulk_actions?(list() | term(), atom()) :: boolean()

Check if any bulk actions are visible for the given archive status.

Returns true if there is at least one bulk action that should be shown for the current mode (active or archived).

inline_filter_class(_)

@spec inline_filter_class(map()) :: String.t()

Returns a CSS class for inline (non-collapsible) filters based on filter type. Text filters get a flexible width, relation filters a minimum width, others a smaller minimum. Only used when the group has no custom class (i.e., wrapper is "contents"). Custom templates can override this if they need different sizing.

inline_group_class(group)

@spec inline_group_class(map()) :: String.t()

Returns the CSS class for an inline (non-collapsible) group wrapper. If the group has ui do class "..." end, uses that. Otherwise defaults to "contents" which makes the wrapper transparent so filters participate directly in the parent flex layout.

merge_relation_filter_state(filters, relation_state)

@spec merge_relation_filter_state(list(), map()) :: list()

Merges dynamic relation filter state (options, loading, etc.) into filter configs.

non_accordion_actions(row_actions)

@spec non_accordion_actions([map()]) :: [map()]

The row actions a template should draw as buttons — everything except an :accordion.

An :accordion action is a declaration that the row expands, not a button: a template renders the caret itself, wherever its design puts it.

pagination_type(static)

@spec pagination_type(map()) :: atom()

Which pager a resource asked for — numbered pages, a Load-more button, or infinite scroll.

render_pagination/1 reads this itself when the caller has not already assigned it, so a template only passes pagination_type when it wants to override what the resource declared.

prepare_filter_groups(filters, groups, state)

@spec prepare_filter_groups(list(), list(), map()) :: map()

Prepares all filter groups for rendering by custom templates.

Resolves accessible filters, splits them into visible groups (sorted by position), and identifies ungrouped filters. Each group entry includes the resolved filter structs (not just names).

Returns a map:

%{
  all_filters: [filter_struct],
  visible_groups: [%{group | resolved_filters: [filter_struct]}],
  ungrouped_filters: [filter_struct],
  inline_groups: [group],      # non-collapsible
  collapsible_groups: [group]   # collapsible
}

rail_class(rail, arg2)

@spec rail_class(list() | nil, :grid | :top | :rail | :bottom) :: String.t() | nil

The four class strings that put a page's :rail slot beside its records rather than above them.

Returns nil for every region when the page passed no rail, and HEEx omits a nil attribute entirely, so a template can spread these across its markup unconditionally.

record_checked?(map, record_id)

@spec record_checked?(map(), term()) :: boolean()

Whether this record's tick is on, under either selection mode.

Normally selected_ids lists what is ticked; once "select all" is on it is excluded_ids that lists what has been un-ticked, so the same tick reads from a different set and with the opposite sense.

render_bulk_actions(assigns)

Renders the bulk-action bar shown once rows are selected.

Only the actions visible in the current archive scope are drawn — see has_visible_bulk_actions?/2 to decide whether to give it any room at all.

<div :if={@show_bulk_actions}>{Shared.render_bulk_actions(assigns)}</div>

render_cell(assigns)

Renders one cell the way the plain table does — format first, then the column's render if it has one, then its type module, then the bare value.

A custom template should call this rather than reading the value itself, or a column's render and ui do type … end stop working inside it.

<td :for={column <- @columns}>{Shared.render_cell(%{column: column, record: @record, static: @static, state: @state})}</td>

render_empty_state(assigns)

@spec render_empty_state(map()) :: Phoenix.LiveView.Rendered.t()

Renders the empty state with configurable message, icon, and action.

render_error_state(assigns)

@spec render_error_state(map()) :: Phoenix.LiveView.Rendered.t()

Renders the error state with configurable message, icon, and retry button.

render_filter(assigns)

One filter's input, resolved from its type — text, select, boolean, relation, date range — including the disabled state a depends_on filter wears until its parent has a value.

Call it from a custom template that lays the filters out itself, the same way render_cell/1 and render_row_actions/1 are called.

Expects :filter, :all_filters, :state, :static and :myself.

render_filters(assigns)

Renders the filter bar: the toolbar row, any collapsible filter groups, the active-filter chips and the archive toggle.

The default render_filters/1 of every template built with use MishkaGervaz.Table.Behaviours.Template. Call it from a custom template rather than rebuilding the bar.

def render_filters(assigns), do: Shared.render_filters(assigns)

Expects @static and @state.

render_header(assigns)

@spec render_header(map()) :: Phoenix.LiveView.Rendered.t()

No header at all — the default for a template whose page already names itself.

Returns an empty template.

render_loading(assigns)

@spec render_loading(map()) :: Phoenix.LiveView.Rendered.t()

Renders the loading state with spinner and configurable text.

render_pagination(assigns)

Renders the pagination control — numbered pages, a load-more button or the infinite-scroll sentinel, whichever the resource configured.

Reads its labels from static.pagination_ui, so pagination do ui do … end end on the resource is honoured without the template knowing about it.

render_row_actions(assigns)

Renders one row's action strip: the inline buttons, then any dropdown.

Honours actions_layout placement and each action's visible rule, and leaves :accordion actions out — the caret is the table's own, not a button. Expects @record, @static, @state and @myself.

render_template_switcher(assigns)

Renders the Table/Cards switcher for a resource that declared switchable_templates.

Reads @ui_adapter when given and falls back to the Tailwind adapter, so it can be called from a context that has not resolved one.

resolve_chip_value(name, value, state)

@spec resolve_chip_value(atom(), term(), map()) :: String.t()

Resolve a filter chip's display value, using relation labels when available.

sort_by_position(groups)

Sorts filter groups by their position attribute.

uncheck_all(js \\ %JS{}, scope \\ nil)

@spec uncheck_all(Phoenix.LiveView.JS.t(), String.t() | nil) ::
  Phoenix.LiveView.JS.t()

Unchecks all selection checkboxes and removes selection highlighting.