* feat(design-system): add DS::SearchInput + migrate 2 broken-focus callsites
Resolves#1715 §3.
Two standalone search-field callsites — `/settings/preferences`
currency filter and `/settings/providers` filter row — had a hand-
rolled markup that ended in `focus:ring-gray-500`. That utility has
no backing token in the design system (`ring-gray-500` isn't in
Tailwind's default + Sure doesn't register a gray ring color), so
the input rendered with zero focus indicator on a bordered
bg-container surface. Keyboard users couldn't tell when the field
was focused.
Introduce `DS::SearchInput` — icon-on-left, bordered, token-backed
focus ring matching the DS::Button pattern landing in #1840
(`outline-2 outline-offset-2 outline-gray-900` with the dark-mode
override). API:
DS::SearchInput.new(
name: "...",
placeholder: "...",
value: ...,
aria_label: "...", # defaults to placeholder
class: "...", # passed to the wrapper
**opts # spread onto the <input>, e.g. data-*
)
Migrate the two broken callsites. Three other "search" patterns
stay as-is (out of scope for this PR):
- `form.search_field :search` inside `styled_form_with` blocks
(accounts/show/_activity.html.erb, UI::Account::ActivityFeed) —
already routes through StyledFormBuilder's form-field CSS.
- Embedded-dropdown search input inside DS::Select, DS::Menu, and
the splits/category-select panels — uses a different shape
(no border, no ring) because the parent panel provides the chrome.
- Category dropdown's combobox search input
(app/views/category/dropdowns/show.html.erb) — has a custom
`role=combobox` flow and stays intentionally distinct.
* feat(design-system): add embedded variant to DS::SearchInput, migrate 2 more callsites
Adds `variant: :embedded` to `DS::SearchInput` for search inputs that
live *inside* another DS panel (DS::Select dropdown, splits category
filter, future DS::Popover-hosted filters). No own border / no own
focus ring — the parent panel provides the chrome, so adding ring
+ outline competes with its `focus-within` state.
API:
DS::SearchInput.new(variant: :embedded, placeholder: "...", data: {...})
The `:standalone` default (from the previous commit) stays unchanged
and remains the right choice for top-of-list filter inputs.
Migrated:
- `app/components/DS/select.html.erb` — the in-dropdown search input
for `DS::Select.new(searchable: true)`. Was the only remaining
internal raw <input type="search"> markup in the component.
- `app/views/splits/_category_select.html.erb` — split-transaction
category picker filter. Same shape as DS::Select's search but
hand-rolled because the picker isn't a vanilla DS::Select.
Three other search patterns stay out of scope (intentionally, per
the previous commit):
- `form.search_field :search` inside `styled_form_with` — uses
form-field CSS, different visual contract.
- `app/views/category/dropdowns/show.html.erb` — bespoke
`role="combobox"` flow with `aria-expanded` / `aria-autocomplete`
semantics that don't belong in this primitive.
* fix(review): mobile font + embedded variant focus-within ring
- DS::SearchInput: switch text-sm -> text-base sm:text-sm on both
variants so the input keeps its 16px base size on mobile. iOS
Safari zooms the viewport when a focused input is below 16px,
which the unconditional text-sm was triggering on the Settings
Preferences currency search and Settings Bank Sync provider
search.
- DS::Select (searchable variant) + splits/_category_select:
add focus-within:ring-4 focus-within:ring-alpha-black-200
(with theme-dark variant) on the wrapper around the embedded
search input. The embedded variant intentionally has no own
focus ring so it inherits chrome from its parent panel — but
the two current parent panels were not providing one, so
keyboard focus on the dropdown search box rendered with no
visible indicator. Ring matches the .form-field token used
across the design system.
* fix(merge): repair DS::Select search input merge resolution
The previous merge of main left invalid Ruby inside the DS::SearchInput
`data:` hash:
aria-label="<%= t("helpers.select.search_placeholder") %>"
This is an ERB string assignment masquerading as a hash entry — it does
not parse and would have raised SyntaxError at render. Two follow-ups:
- Drop the `aria-label` entry entirely. `DS::SearchInput` already
defaults `aria_label` to `placeholder`, and `placeholder` is set
on the call, so the resulting <input> already carries
`aria-label="<%= t(...) %>"`.
- Restore the `input->select#syncTabindex` action that main #1848
added on the embedded search input. It keeps the roving tabindex
on the listbox in sync as filtered results change. Original PR
branch had only `list-filter#filter`; reintegrate both with
explicit `input->` event prefixes for parity with main.
---------
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
* Initial split transaction support
* Add support to unsplit and edit split
* Update show.html.erb
* FIX address reviews
* Improve UX
* Update show.html.erb
* Reviews
* Update edit.html.erb
* Add parent category to dialog
* Update en.yml
* Add UI indication to totals
* FIX ui update
* Add category select like rest of app
---------
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>