| name | fantasia-select-input |
| description | Reusable FaSelectInput QSelect chips wrapper and src/scripts/faSelectInput helpers: modes simple / document / otherType / tags (media stub), filter highlight, create-new, clearIsNewFlags. Use when adding select/chip fields or wiring document/template options. |
Fantasia Archive — FaSelectInput
When to use
Reusable q-select with chips, filter input, whole-word label highlight, optional create-new → FaSelectInput from src/components/elements/FaSelectInput/. No one-off chip menus that reimplement this contract.
Do not use mode="media" yet — typed stub; options always normalize to [].
Live smoke only (not persisted document field): DocumentWorkspacePageSelectSmoke under dead toggle on DocumentWorkspacePage.
App Settings enum q-select stays in DialogAppSettingsSettingBlock unless product wants this chip UX.
Public API (SFC)
<FaSelectInput
v-model="model"
mode="document"
:options="options"
test-locator="myFeature-select"
allow-create-new
@request-options="reloadOptions"
@new-value="onCreated"
@change="onChange"
/>
| Prop | Role |
|---|
mode | Required — simple | document | otherType | tags | media (stub) |
modelValue | String(s) or object item(s) / null per mode |
options | Strings or I_faSelectInputObjectItem list |
testLocator | Root data-test-locator; chip / option / separator-alt attrs |
allowCreateNew | Opt-in Enter create-new (default false) |
clearInputOnSelect | Opt-in clear filter text after select/create (default false; chip stays) |
activateOnly | Opt-in: option click/Enter emit option-activate only — no Quasar model select / menu close (Quick Search stay-open) |
chipRemovable | Chip X remove control (default true); set false for mandatory single (chip stays, no X) |
filterFn | Optional override of default filter |
multiple, label, loading, disable, Quasar chrome | Standard defaults: dense filled dark, color primary-bright |
Emits: update:modelValue, change ({ action, value }), new-value, request-options (focus + popup-show), option-activate (option click or Enter on focused option, including single reselect).
Expose: clearIsNewFlags(ids), openPopup(), getFilterNeedle().
Test hooks: {testLocator}, -filter, -chip, -selected (inline), -option-{index}, data-test-locator-separator-alt on option (index ≥ 1).
UX behavior
- Default presentation chips;
selectionPresentation="inline" for icon+label closed field (no chips)
chipRemovable default true; mandatory single parents set false (chip, no X)
- Optional object
color tints icons via fa-color-glyph (object icons always get that class + glyph CSS vars; flat = solid color; fantasy = shading; missing color uses workspace-row default base)
- Hide empty single selection chip;
isNew → teal-3 chip else accent; text dark
- Object
icon on chip/option/inline when non-empty
- Filter = FA 1.0 multi-token match: space-split query words AND-matched against distinct label words (equality and/or includes); highlight claimed words only (not letter-only wash); results sorted exact → full-word → partial
- Default: keyboard-highlight first option on popup-show and after every filter update (model unchanged)
- Focus opens menu: Tab / Shift+Tab via
keyup Tab (not @focus showPopup — that races Quasar click toggle; QSelect inheritAttrs: false drops wrapper @mousedown); parents may still call openPopup() (Quick Add template)
- Menu fixed 600px, center under field (
bottom middle / top middle); optional popupContentClass
- separatorAlt via CSS border on option item (single virtual-scroll root);
virtual-scroll-slice-size 80 fills tall menus on first open; selected = side bars on ::before + idle non-match text; filter optionMatch gold on selected too; fantasy hover/keyboard = menu bottom-edge glow (faMenuItemGlow on ::after); label/icon stay idle color (no hover wash tint)
- Create-new: trim; simple string or object
{ id: crypto.randomUUID(), name, isNew: true }
File map
| Area | Path |
|---|
| SFC + styles | FaSelectInput.vue, styles/_variables.scss, styles/FaSelectInput.unscoped.scss |
| Composable | scripts/faSelectInput_manager.ts, scripts/functions/createUseFaSelectInput.ts |
| Domain | src/scripts/faSelectInput/functions/ + faSelectInput_manager.ts barrel |
| Types | types/I_faSelectInput.ts |
| Storybook | _tests/FaSelectInput.stories.ts |
| Smoke | DocumentWorkspacePageSelectSmoke.vue + mapDocumentWorkspacePageSelectSmokeOptions.ts |
Modes
| Mode | Options | Empty single |
|---|
simple | strings | '' |
document / otherType / tags | objects | null |
media | always [] | stub |
Smoke today: simple + otherType templates + document docs via projectContent IPC on request-options.
Adding to a new screen
- Import
FaSelectInput; pick mode
- Parent owns
options + reload on @request-options
- Unique
test-locator
- Persist create-new: listen
@new-value / @change; call clearIsNewFlags when ids saved
- Stub in parent Vitest when testing layout only
Two-level layout
- Level 1:
src/scripts/faSelectInput/functions/*.ts + element createUseFaSelectInput
- Level 2: element
faSelectInput_manager.ts wires Vue + domain barrel
See fantasia-two-level-architecture.
Tests
| Suite | Location |
|---|
| Vitest (SFC) | FaSelectInput/_tests/FaSelectInput.vitest.test.ts |
| Vitest (composable) | scripts/_tests/createUseFaSelectInput.vitest.test.ts |
| Vitest (domain) | src/scripts/faSelectInput/functions/_tests/faSelectInputDomain.vitest.test.ts |
| Smoke | DocumentWorkspacePageSelectSmoke.vitest.test.ts |
| Playwright component | FaSelectInput/_tests/FaSelectInput.playwright.test.ts — Tab open, reopen click, filter type, separator-alt, tall menu fill, selected-option close |
Quick Add dialog PW/E2E also exercise FaSelectInput world/template fields.
Related