* fix(ui): make composer keyboard interactions consistent * docs(settings): refine description visibility guidance --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
4.4 KiB
Settings Controls
Load theme-system for button/icon/color contracts and locale-ui-patterns
for every visible or accessible string. All primitives/constants come from
packages/ui/src/components/sections/shared/SettingsSection.tsx (+
SettingsInfoHint.tsx).
Standard Sizes And Widths
One control size across Settings — h-8:
SelectTrigger:size={SETTINGS_SELECT_SIZE}('settings' → h-8, rounded-md, px-3).- Custom dropdown triggers (ModelSelector / AgentSelector):
SETTINGS_CUSTOM_TRIGGER_CLASS. - Text
Inputnext to dropdowns:h-8 rounded-md px-3(match the trigger footprint). - Icon action next to a control:
SETTINGS_ICON_BUTTON_CLASS.
Widths are capped — never let controls span the pane:
- Field-row control cluster / stacked-field default cap:
max-w-[24rem](built intoSettingsStackedField; useSETTINGS_CONTROL_CLUSTER_CLASSelsewhere). - Field-row selects:
SETTINGS_SELECT_ROW_TRIGGER_CLASS(full width narrow,@xl:w-56wide). - Stacked-field selects:
SETTINGS_SELECT_TRIGGER_CLASS(fills the capped container). - Genuinely full-width content (dialog textareas): opt out with
controlClassName="w-full max-w-none".
Field Rows
<SettingsFieldRow
label={t('...label')}
info={t('...hint')} // helper text behind the info icon
settingsItem="page.some-setting"
>
<Select …>
<SelectTrigger size={SETTINGS_SELECT_SIZE} className={SETTINGS_SELECT_ROW_TRIGGER_CLASS} aria-label={t('...aria')}>…
Use SettingsStackedField (label above control) inside SettingsTwoColumn
cells or when the control is wide; same info / settingsItem props.
Boolean
For a self-explanatory enable/disable setting, use only a checkbox and label; no separate group title or description is needed.
<SettingsCheckboxRow
checked={value}
onChange={setValue}
label={t('...label')}
ariaLabel={t('...aria')}
info={t('...explanation')} // optional; see Description Policy
settingsItem="page.some-setting"
/>
Row click + keyboard toggling are built in. A visible description is only
for text that must stay visible (warnings, dynamic status).
Mutually Exclusive Options
Use radios for mutually exclusive modes, not independent checkboxes. Keep self-explanatory choices compact; a title or description is not mandatory.
When the skill's Description Policy calls for a visible explanation, wrap
the controls in SettingsControlGroup: title, description, then options.
Explain the choice once at group level. Use checkbox rows for independent
choices and radio options for mutually exclusive choices. Group spacing is
defined in layout.md.
<SettingsControlGroup title={t('...group')} description={t('...description')}>
<SettingsRadioGroup aria-label={t('...group')}>
<SettingsRadioOption selected={…} onSelect={…} label={t('...')} ariaLabel={t('...')} />
</SettingsRadioGroup>
</SettingsControlGroup>
Skip per-option descriptions when labels are self-explanatory. For short
segmented choices use SettingsChipGroup (chips with aria-pressed).
Numeric Value / Override
NumberInput inside SETTINGS_NUMBER_STEPPER_ROW_CLASS, with
SETTINGS_NUMBER_UNIT_CLASS for the unit and an adjacent
SETTINGS_ICON_BUTTON_CLASS reset button. Never flex-grow the stepper.
Optional overrides: empty means "inherit"; provide fallbackValue,
onClear, emptyLabel="—".
Info Hints
SettingsInfoHint is the only info-icon implementation: it opens on hover
AND on click (touch devices have no hover), and closes on outside tap.
Prefer the info prop of the enclosing primitive; use the component
directly only next to raw labels/headings. Never build info icons from raw
<Tooltip> + <Icon name="information"> — those don't work on mobile.
Mobile Constraints
packages/ui/src/styles/mobile.cssmay force.overflow-hiddento scroll; use explicit x/y clipping only when required.- Touch CSS enforces minimum button height. Do not put custom segmented buttons in a container too short for them.
Picker Rows
- Place icon/color palettes beneath their label.
- Keep option dimensions and gaps consistent.
- Use stable border/ring/background selection; avoid scale transforms that shift layout.
Dialogs
Dialogs reuse the same primitives (SettingsCheckboxRow,
SETTINGS_FIELD_LABEL_CLASS, SettingsStackedField) and the same sizes.
Dividers between dialog form groups are acceptable; wizard step
instructions guiding an active flow stay visible (not behind info).