App dialog primitives #
These React-owned components define reusable app chrome, not content or integration behavior.
ModalShellowns the centered overlay, dismissal, focus trap, and focus return.SectionedDialogowns the Settings-style title, vertical section navigation, icon-strip mobile layout, and scrolling content panel. Settings and Feedback supply section definitions and content.focusableprovides DOM-ordered keyboard targets and resolves the foreground dialog from its overlay layer; the Settings folder picker and account popup use it without adopting the sectioned layout.ActionButtonis the app-wide action control. Settings, the header update action, and edition panels share its neutral and primary styles; placement-specific spacing stays with the consumer.FormControlGrouppairs a single-line input, select, or read-only code value with adjacentActionButtons. Choose density once on the group; do not size each child separately.
Form sizing #
Use FormControlGroup for a field with utility actions such as Copy or Reset:
<FormControlGroup>
<SettingTextInput {...fieldProps} />
<ActionButton onClick={reset}>Reset</ActionButton>
</FormControlGroup>
The default compact density uses --ui-form-control-height (36px). regular
uses --ui-touch-target (44px). Coarse-pointer devices promote compact groups
to 44px so inputs and buttons remain equally touchable. The 25px
--ui-control-height token belongs to dense editor controls, not settings forms.
The field fills available width; actions use their label width plus shared horizontal padding. Use short utility action labels in these inline groups; long actions belong in a separate row. Buttons retain a minimum height rather than a fixed height so wrapping text can grow. Input colors, borders, focus styling, and behavior remain owned by the input. The group normalizes single-line control geometry.
Keep labels, validation messages, and outer spacing outside the group. Put labels
above the group when the available form width is narrow (use a container query),
and avoid fixed-width action columns or
button-specific height overrides. A standalone ActionButton retains its 44px
default. Verify paired heights, usable field width, focus, and overflow in a
desktop browser and a touch viewport when migrating a form.
The search and command palettes use their own shared ../palette-dialog/PaletteDialog; they have a search-input/list interaction model instead of sections. The Obsidian-compatible Modal in src/plugin/obsidian-stubs.ts is an imperative plugin API. The ATProto account popup remains a separate auth flow. Sharing their layout would conflate different interactions.