PhoenixKitCatalogue.Web.Components.ItemPicker
(PhoenixKitCatalogue v0.1.14)
Copy Markdown
View Source
Combobox LiveComponent for picking a single item from the catalogue via server-side search.
Drop one into any LiveView — typically many, one per row in a picker table. Each instance owns its own search state; the parent LV only reacts to two messages:
{:item_picker_select, id, %Item{}} # user chose an item
{:item_picker_clear, id} # user cleared the selectionAPI
<.item_picker
id="row-42-picker"
category_uuids={[category.uuid]}
selected_item={@chosen_item}
excluded_uuids={@already_used_uuids}
locale="en"
/>Attrs:
:id(required) — unique DOM/component id. The:item_picker_*messages echo this back so a parent with N pickers knows which fired.:category_uuids— scope search to these categories.nilor[]means "all categories + uncategorized" (matchesCatalogue.search_items/2).:catalogue_uuids— scope search to these catalogues. Composes with:category_uuids(AND).:include_descendants— whentrue(default),:category_uuidsis expanded through the V103 tree; passfalsefor literal set semantics.:only—:uncategorized_onlyrestricts results to items without a category;:categorized_onlyrestricts to items in some category;nil(default) is unrestricted. Forwards toCatalogue.search_items/2's:onlyopt.:selected_item— the%Item{}currently chosen (ornil). Drives the input text and thearia-selected/ primary-border styling in the dropdown.:excluded_uuids— items in this list are rendered dim +aria-disabledand cannot be clicked. Use for "already picked in another row" state.:locale(required) — locale string for translated display names ("en","es", etc.). Resolved viaCatalogue.get_translation/2.:placeholder— input placeholder. Defaults to "Search items…".:empty_query_limit— how many items to show when the query is empty (the "just focused" state). Defaults to10.:page_size— max results fetched per query. Defaults to20. When the unbounded count exceeds this the dropdown shows a "Type to refine…" sentinel row so the user knows there's more.:disabled— disables the input and hides the clear button.:format_price— 1-arity function taking an%Item{}(with:cataloguepreloaded — the search always does this) and returning a display string ornil. Defaults to a Decimal stringifier ofitem_pricing(item).final_price. Returnnilto omit the price column entirely.
Keyboard / a11y
Handled client-side by the colocated ItemPicker hook:
- ArrowDown / ArrowUp cycle through enabled options (announced via
aria-activedescendant; DOM focus stays on the input). - Home / End jump to first / last enabled option.
- Enter activates the focused option (simulates a click so the
normal
selectevent fires). - Escape closes the dropdown and keeps focus on the input.
- Clicking outside the picker closes it (
phx-click-away).
The dropdown is absolutely positioned and elevated with z-50; the
parent container must allow overflow (overflow: visible or just
don't set overflow: hidden on an ancestor that clips it).