A search field that turns what you type into filter chips.
import { QueryField } from '@oztix/roadie-components/query-field'
Pass the chips you hold and a suggest function. Suggestions come back in
groups, and onAccept hands you the one taken: add a chip for a filter, or
search for the text when Enter sends kind: 'search'. The row Enter takes
leads the list, with its group above the rest, and is highlighted, so Down
Arrow moves to the next row. A suggestion's icon, a bold Phosphor icon,
shows before its label. Chips never show one.
Inside Field, the label names the input, and the field
takes invalid, disabled, and required from it.
Picking a field, such as Venue, starts the value step. Show a pendingChip
and swap what suggest returns for that field's values. What you type sits
inside the pending chip, after its label. Taking a value adds
the chip and ends the step. Each of these calls onPendingChipCancel to go
back:
Focus going nowhere, as when a phone's keyboard is put away, keeps the step.
Give the pending chip two or more operators, and the chosen one as
operator, to show a toggle above the values. Pressing an operator, or Tab in
the field, calls onPendingOperatorChange. Update operator and the chip's
label, such as "Venue is not", and the field asks suggest again. Give an
operator that's a symbol, such as ≠, an aria-label. The list is as wide as
the field, so operators that don't fit scroll sideways, and long values
truncate.
Once something is typed, Enter takes the first value. When the highlighted
value's label starts with the typed text, the rest shows faintly after the
caret, such as "n sale" after "O". Only Enter takes it. When the step has one
answer, such as "Location is empty" under is empty, mark it exact, and
Enter takes it before anything is typed.
Give the pending chip a hint, such as "Type a number.", to say what to type.
It shows in place of No suggestions while no value is listed, and below the
values while Enter has none to take for the typed text, such as when the only
match is already ticked. Screen readers announce it.
Give the pending chip content to show it under the values, such as a
calendar to pick a date from. Focus stays in the field as you press it, so
typing and Tab carry on there. A press that ends the step, such as picking a
day, closes the list, as taking a value does.
The list is as wide as the field, and a calendar fits from about 300px, as on a phone. Keep the content to pointer and touch, and offer the same values as suggestions, so typing reaches them too.
A chip the page sets, such as the event a list is scoped to, is locked. It
shows first, explains itself with a "Set by this page" tooltip, and nothing in
the field removes it: not its own keys, not Backspace, not Clear.
Pass onSelectChip, and a click, Enter, or Space on an unlocked chip selects
it. Answer with a value step for the chip's field, with pendingChip.chipId
naming the chip. The list opens, and the pending chip takes the chip's place.
To edit a value typed in full, such as a date or a number, set inputValue to
it as the step starts. The field selects it, so typing replaces it.
Mark the values the chip holds selected to tick them, and toggle them in
onAccept. Taking a value keeps the list open, so several can be ticked and
unticked. For a chip that holds one value, such as typed text or a date, end the step in
onAccept, and the list closes. Enter on typed text takes the first value that isn't ticked, so only
an arrow or a click unticks one.
Backspace in the empty field removes the chip. Pass onPendingChipBackspace
to do something else, such as bring back text the step set aside. Escape,
Enter on the text the step started with or with no new value to take, or focus
leaving the field ends the step and keeps the chip.
Enter keeps the step while typed text matches no value, so the hint stays.
Enter searches the free text. When the text names one record exactly, such as
an order number, mark that suggestion exact and Enter takes it instead.
A suggestion that reads only part of the text, such as the location in "melb
this weekend", gives the rest as remainder. Taking it leaves those words in
the field, with the list open, so the next suggestion can read them.
parseRecordQuery from @oztix/roadie-core/records fills remainder for you.
A chip's description, such as the dates a relative range stands for, shows
in a tooltip and is read after the chip's label.
Set focusShortcut to let a key focus the field from anywhere on the page. It
takes one KeyboardEvent.key value, such as / or s, pressed without Cmd,
Ctrl, or Alt. The field ignores it while you type in another field. When
several fields ask for the same key, the first one on the page takes it and
shows the hint. recent lists earlier searches above the fields while the
field is empty.
Do
Return filters first, then fields. The field adds "Search for …", and Enter takes it unless a suggestion is an exact match. Whichever Enter takes leads the list.
Don’t
Outside a value step, don't mark a filter exact to make Enter take it.
People expect Enter to search what they typed, and pick a filter with the
arrows or a click. A value step's one answer, such as "Location is empty",
is the exception.
{ id: 'venue', label: 'Venue is Iguana Teapot Hall' }
Do
Label a chip with field, operator, and value, so it reads on its own.
{ id: 'venue', label: 'Iguana Teapot Hall' }
Don’t
Don't show the value alone. "Iguana Teapot Hall" could be a venue, a promoter, or a search.
Do
Lock a chip the page sets, such as the event a ticket list belongs to. Clear leaves it alone.
Don’t
Don't lock a filter someone added themselves. They need a way to remove it.
aria-label, or put the field in
Field and use Field.Label.aria-activedescendant points at the highlighted row, so screen
readers read each row the highlight moves to.data-keyboard-hints='always' keeps key hints,
as on a tablet with a keyboard.onSelectChip,
Enter or Space selects it and moves focus to the input, and the list
opens once a value step edits the chip. Locked chips ignore all four keys.selected suggestion is aria-selected. Its check stays out of its name.operators, while the values show, Tab and
Shift+Tab move to the next and previous operator. Tab from the last
operator, or Shift+Tab from the first, leaves the input and ends the step,
even when focus lands on Clear. The input's aria-keyshortcuts names each
key only while it moves to an operator. Focus stays in the input, even when
you press an operator. Without operators, or with the list closed, Tab
leaves the input as usual and ends the step.content, except
on a native control such as a select, which takes focus to open and gives
it back once its value changes. The
content is for pointer and touch, so offer what it picks as suggestions
too, and a keyboard can type it.description is read after its label too. A pending chip describes the
input, so the value step is announced. It's a live region, so a change of
operator is announced too. While a step edits a chip, the chip is hidden,
and the pending chip in its place describes the input. The pending chip
shows where the chip was, but screen readers reach it after the other
chips, as moving the input would lose focus.required is announced but never blocks a form: an empty search is valid.focusShortcut adds aria-keyshortcuts to the input. The key hint beside the
field is visual only, and hides once the field has focus.The conditions applied, each read as one chip. Locked chips show first.
Defaults to [].
A chip's remove button, Backspace on a selected chip, or Clear asks to remove it. Clear calls it once per chip, so update state functionally.
A click, Enter, or Space on an unlocked chip, which moves focus to the input. Start a value step with `pendingChip.chipId` naming the chip to list its values, or open an editor of your own.
Clear calls it in place of clearing the text through `onInputValueChange` and removing each unlocked chip, so one update can clear both.
The field being given a value, such as "Venue is", shown after the chips with the input inside it. With `chipId`, it stands in that chip's place, the text the step starts with is selected, taking a value keeps the list open unless `onAccept` ends the step, and Backspace in the empty field removes the chip. Focus moving outside the field and its list, or a press outside them, ends the step.
An operator was pressed, or Tab moved to one, while a chip is pending.
While a chip is pending: Backspace on an empty field, Escape, Tab out of the input, or, while a chip is edited, Enter on the text the step started with or with no new value to take.
Backspace on an empty field while a chip is pending, in place of removing the edited chip and `onPendingChipCancel`, such as to bring back text the step set aside.
The typed text, searched as it changes. Controlled.
The typed text to start with. Uncontrolled.
Defaults to .
Typing changed the text, or taking a suggestion cleared it.
Suggestions for the text, in the order shown: filters first, then fields.
A suggestion was taken, or Enter searched the free text (`kind: 'search'`).
Shown above the fields while the field is empty.
Defaults to Search and filter.
A key that focuses the field from anywhere on the page: one `KeyboardEvent.key` value, such as `/` or `s`, pressed without Cmd, Ctrl or Alt. Ignored while typing in another field. Unlike `Menu.Item`'s display-only `shortcut`, this binds the key. When several fields on a page ask for the same key, the first one mounted takes it.
The input, for focusing it after an editor closes. Pass a stable ref.
Defaults to 'md'.
Defaults to 'normal'.
Inherits from `Field` when omitted.
Inherits from `Field` when omitted.
Announced as required; the field never blocks a form. Inherits from `Field` when omitted.
Names the field when it isn't inside `Field`.