# `Cinder.Collection`
[🔗](https://github.com/sevenseacat/cinder/blob/v0.12.1/lib/cinder/collection.ex#L1)

Unified collection component for displaying data in table, list, or grid layouts.

This component provides a single API for all collection displays, with the `layout`
attribute selecting how items are rendered. All layouts share the same filtering,
sorting, pagination, and URL sync capabilities.

## Layouts

- `:table` (default) - Traditional HTML table with sortable headers
- `:list` - Vertical list with sort button group
- `:grid` - Responsive card grid with sort button group

## Basic Usage

### Table Layout (default)

```heex
<Cinder.collection resource={MyApp.User} actor={@current_user}>
  <:col :let={user} field="name" filter sort>{user.name}</:col>
  <:col :let={user} field="email" filter>{user.email}</:col>
</Cinder.collection>
```

### List Layout

```heex
<Cinder.collection resource={MyApp.User} actor={@current_user} layout={:list}>
  <:col field="name" filter sort />
  <:col field="status" filter={:select} />

  <:item :let={user}>
    <div class="flex justify-between">
      <span class="font-bold">{user.name}</span>
      <span>{user.status}</span>
    </div>
  </:item>
</Cinder.collection>
```

### Grid Layout

```heex
<Cinder.collection resource={MyApp.Product} actor={@current_user} layout={:grid}>
  <:col field="name" filter sort search />
  <:col field="category" filter={:select} />

  <:item :let={product}>
    <h3 class="font-bold">{product.name}</h3>
    <p class="text-gray-600">{product.category}</p>
    <p class="text-lg font-semibold">${product.price}</p>
  </:item>
</Cinder.collection>
```

## Grid Columns

Control the number of grid columns with the `grid_columns` attribute:

```heex
<!-- Fixed 4 columns -->
<Cinder.collection resource={MyApp.Product} layout={:grid} grid_columns={4}>
  ...
</Cinder.collection>

<!-- Responsive columns -->
<Cinder.collection resource={MyApp.Product} layout={:grid} grid_columns={[xs: 1, md: 2, lg: 3, xl: 4]}>
  ...
</Cinder.collection>
```

## Layout-Specific Attributes

| Attribute | Table | List | Grid | Description |
|-----------|-------|------|------|-------------|
| `<:col>` content | ✅ Rendered | ❌ Ignored | ❌ Ignored | Cell content for table rows |
| `<:item>` slot | ❌ Ignored | ✅ Required | ✅ Required | Template for each item |
| `sort_label` | ❌ N/A | ✅ Button label | ✅ Button label | Label for sort button group |
| `container_class` | ❌ N/A | ✅ Override | ✅ Override | Custom container CSS |
| `grid_columns` | ❌ N/A | ❌ N/A | ✅ Column count | Number of grid columns |
| `click` | ✅ Row click | ✅ Item click | ✅ Item click | Click handler |

## Custom Controls Layout

Use the `:controls` slot to customize how filters and search are rendered while
keeping Cinder's state management, URL sync, and query building intact:

```heex
<Cinder.collection resource={MyApp.User} actor={@current_user}>
  <:col :let={user} field="name" filter sort search>{user.name}</:col>
  <:col :let={user} field="status" filter={:select}>{user.status}</:col>

  <:controls :let={controls}>
    <Cinder.Controls.render_header {controls} />
    <div class="grid grid-cols-2 gap-4">
      <Cinder.Controls.render_filter
        :for={filter <- controls.filters}
        filter={filter}
      />
    </div>
  </:controls>
</Cinder.collection>
```

See `Cinder.Controls` for the full API and more examples.

# `build_query_columns`

Builds the list of columns used for query operations (filtering AND searching).

This function combines:
- **Filterable columns**: needed for filter application
- **Searchable columns**: needed for search even if not filterable
- **Filter-only slots**: dedicated filter controls not tied to display columns

NOTE: Sortable-only columns are NOT included here - sorting uses display_columns
because sort controls are tied to column headers.

Raises `ArgumentError` if the same field is defined in both a filterable column
and a filter-only slot.

# `collection`

## Attributes

* `resource` (`:atom`) - The Ash resource to query (use either resource or query, not both). Defaults to `nil`.
* `query` (`:any`) - The Ash query to execute (use either resource or query, not both). Defaults to `nil`.
* `action` (`:atom`) - The read action to use. Defaults to the primary read action. Defaults to `nil`.
* `actor` (`:any`) - Actor for authorization. Defaults to `nil`.
* `tenant` (`:any`) - Tenant for multi-tenant resources. Defaults to `nil`.
* `scope` (`:any`) - Ash scope containing actor and tenant. Defaults to `nil`.
* `layout` (`:any`) - Layout type: :table, :list, or :grid (also accepts strings). Defaults to `:table`.
* `id` (`:string`) - Unique identifier for the collection. Defaults to `"cinder-collection"`.
* `page_size` (`:any`) - Number of items per page or [default: 25, options: [10, 25, 50]]. See `Cinder.PageSize` for global configuration. Defaults to `nil`.
* `theme` (`:any`) - Theme name or theme map. Defaults to `"default"`.
* `url_state` (`:any`) - URL state object from UrlSync.handle_params, or false to disable. Defaults to `false`.
* `query_opts` (`:list`) - Additional Ash query options. Defaults to `[]`.
* `on_state_change` (`:any`) - Custom state change handler. Defaults to `nil`.
* `show_pagination` (`:boolean`) - Whether to show pagination controls. Defaults to `true`.
* `pagination` (`:any`) - Pagination mode: :offset (default) or :keyset. Keyset pagination is faster for large datasets but only supports prev/next navigation. Defaults to `:offset`.
* `show_filters` (`:any`) - Controls filter visibility. true = always visible, false = hidden, nil = auto-detect, :toggle/"toggle" = collapsible starting collapsed, :toggle_open/"toggle_open" = collapsible starting expanded. Can also be set globally via `config :cinder, show_filters: :toggle`. Defaults to `nil`.
* `show_sort` (`:boolean`) - Whether to show sort controls (auto-detected if nil, list/grid only). Defaults to `nil`.
* `loading_message` (`:string`) - Message to show while loading. Defaults to `"Loading..."`.
* `filters_label` (`:string`) - Label for the filters component (defaults to translated "Filters"). Defaults to `nil`.
* `sort_label` (`:string`) - Label for sort button group (defaults to translated "Sort by:"). Defaults to `nil`.
* `search` (`:any`) - Search configuration. Auto-enables when searchable columns exist. Defaults to `nil`.
* `empty_message` (`:string`) - Message to show when no results. Defaults to `nil`.
* `error_message` (`:string`) - Message to show on error. Defaults to `nil`.
* `class` (`:string`) - Additional CSS classes for the outer container. Defaults to `""`.
* `container_class` (`:string`) - Override the item container CSS class (list/grid only). Defaults to `nil`.
* `grid_columns` (`:any`) - Number of grid columns. Integer (e.g., 4) or keyword list (e.g., [xs: 1, md: 2, lg: 3]). Defaults to `[xs: 1, md: 2, lg: 3]`.
* `click` (`:any`) - Function to call when a row/item is clicked. Receives the item as argument. Defaults to `nil`.
* `id_field` (`:atom`) - Field to use as ID for update_if_visible operations (defaults to :id). Defaults to `:id`.
* `selectable` (`:boolean`) - Enable row/item selection via checkboxes. Defaults to `false`.
* `on_selection_change` (`:any`) - Event name (atom or string) sent to parent when selection changes. Parent receives {event_name, %{selected_ids: MapSet.t(), selected_count: integer(), component_id: string(), action: atom()}}. Defaults to `nil`.
## Slots

* `col` - Accepts attributes:

  * `field` (`:string`) - Field name (supports dot notation for relationships or `__` for embedded attributes).
  * `filter` (`:any`) - Enable filtering (true, false, filter type atom, or unified config).
  * `filter_options` (`:list`) - Custom filter options - DEPRECATED: Use filter={[type: :select, options: [...]]} instead.
  * `sort` (`:any`) - Enable sorting (true, false, or unified config [cycle: [nil, :asc, :desc]]).
  * `search` (`:boolean`) - Enable global search on this column.
  * `label` (`:string`) - Custom column label (auto-generated if not provided).
  * `class` (`:string`) - CSS classes for table column (table layout only).
* `item` - Template for rendering each item (required for list/grid layouts).
* `filter` - Filter-only slots for filtering without display columns. Accepts attributes:

  * `field` (`:string`) (required) - Field name to filter on.
  * `type` (`:atom`) - Filter type (:text, :select, :boolean, :date_range, etc.).
  * `label` (`:string`) - Custom filter label.
  * `options` (`:list`) - Options for select/multi_select filters.
  * `value` (`:any`) - Default or fixed value for checkbox filters.
  * `operator` (`:atom`) - Filter operator (:eq, :contains, :gt, etc.).
  * `case_sensitive` (`:boolean`) - Whether text filtering is case-sensitive.
  * `placeholder` (`:string`) - Placeholder text for filter input.
  * `labels` (`:map`) - Custom labels for boolean filter options.
  * `prompt` (`:string`) - Prompt text for select filters.
  * `match_mode` (`:atom`) - Match mode for multi-value filters (:any or :all).
  * `format` (`:string`) - Date format for date filters.
  * `include_time` (`:boolean`) - Whether to include time in date filters.
  * `step` (`:any`) - Step value for number range filters.
  * `min` (`:any`) - Minimum value for range filters.
  * `max` (`:any`) - Maximum value for range filters.
  * `fn` (`:fun`) - Custom filter function (fn query, filter_config -> query).
* `bulk_action` - Accepts attributes:

  * `action` (`:any`) (required) - Ash action atom or function/2 receiving (query, opts) like code interface functions.
  * `label` (`:string`) - Button label text. Supports {count} interpolation. If provided, renders a themed button.
  * `variant` (`:atom`) - Button style: :primary (solid), :secondary (outline), :danger (destructive). Default: :primary. Must be one of `:primary`, `:secondary`, or `:danger`.
  * `action_opts` (`:list`) - Additional options passed to the Ash action (e.g., [return_records?: true, notify?: true]).
  * `confirm` (`:string`) - Confirmation message. Supports {count} interpolation for selected count.
  * `on_success` (`:atom`) - Message name sent to parent via handle_info on success. Payload: %{component_id, action, count, result}.
  * `on_error` (`:atom`) - Message name sent to parent via handle_info on error. Payload: %{component_id, action, reason}.
* `controls` - Custom layout for the filter/search controls area. Receives a controls data map via :let with filters, search, and metadata. Use Cinder.Controls helpers to render individual filters, search, and headers.
* `loading` - Custom loading state content.
* `empty` - Custom empty state content.
* `error` - Custom error state content.

# `process_columns`

Process column definitions into the format expected by the underlying component.

# `process_filter_slots`

Process filter-only slot definitions into the format expected by the filter system.

# `process_search_config`

Process unified search configuration into individual components.
Returns {label, placeholder, enabled, search_fn}.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
