Pantrix UI

Command Palette

Every command of the app, found by its name and run from the keyboard: what Cmd+K or Ctrl+K opens.

import com.pantrixui.components.overlay.commandpalette.PantrixCommandPalette

Examples

Groups, shortcuts and keywords

A file editor's commands, with their groups. A button opens it; typing narrows the list, the arrows walk it, and Enter runs the highlighted command and closes the palette. "Delete" cannot be run now: it is listed, but the arrows pass it by. "Appearance settings" is found by "theme" or "dark" too: those are its keywords. Two commands have a second line under their label that says what they do (supportingText); the search reads it too: type "address".

var open by rememberSaveable { mutableStateOf(false) }
var ran by rememberSaveable { mutableStateOf<String?>(null) }
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)) {
    PantrixButton(text = "Open the command palette", onClick = { open = true }, tagKey = "open_editor")
    PantrixText(
        text = "Last run: ${ran ?: "none"}",
        color = PantrixTheme.colors.textSecondary,
        tagKey = "ran_editor"
    )
}
PantrixCommandPalette(
    visible = open,
    onDismissRequest = { open = false },
    commands = EDITOR_COMMANDS,
    onRun = { command ->
        open = false
        ran = command.label
    },
    tagKey = "editor"
)

private val EDITOR_COMMANDS = listOf(
    PantrixCommand(
        key = "new",
        label = "New file",
        group = "File",
        icon = PantrixIcons.Plus,
        shortcut = PantrixShortcut(Key.N, command = true)
    ),
    PantrixCommand(
        key = "open",
        label = "Open file",
        group = "File",
        icon = PantrixIcons.Folder,
        shortcut = PantrixShortcut(Key.O, command = true)
    ),
    PantrixCommand(
        key = "rename",
        label = "Rename",
        group = "File",
        shortcut = PantrixShortcut(Key.R, command = true, shift = true)
    ),
    PantrixCommand(key = "delete", label = "Delete", group = "File", enabled = false),
    PantrixCommand(
        key = "copy",
        label = "Copy the link",
        group = "File",
        icon = PantrixIcons.Copy,
        keywords = listOf("link", "share"),
        supportingText = "An address for those who can see the file"
    ),
    PantrixCommand(
        key = "zoom_in",
        label = "Zoom in",
        group = "View",
        icon = PantrixIcons.ZoomIn,
        shortcut = PantrixShortcut(Key.Equals, command = true)
    ),
    PantrixCommand(
        key = "zoom_out",
        label = "Zoom out",
        group = "View",
        icon = PantrixIcons.ZoomOut,
        shortcut = PantrixShortcut(Key.Minus, command = true)
    ),
    PantrixCommand(
        key = "appearance",
        label = "Appearance settings",
        group = "View",
        icon = PantrixIcons.Eye,
        keywords = listOf("theme", "dark", "light"),
        supportingText = "Theme, text size, line spacing"
    ),
    PantrixCommand(
        key = "search",
        label = "Search the files",
        icon = PantrixIcons.Search,
        shortcut = PantrixShortcut(Key.F, command = true, shift = true)
    )
)

The commands' own shortcuts

The commands' own shortcuts: one list is what the palette shows and what the keyboard runs. While typing in the field, ⌘B or Ctrl+B runs "Bold" and ⌘I or Ctrl+I "Italic"; the letter is not typed in the field. They are heard while the focus is inside this card: for the whole window they belong on its root.

var open by rememberSaveable { mutableStateOf(false) }
var ran by rememberSaveable { mutableStateOf<String?>(null) }
val note = rememberTextFieldState()
val run = { command: PantrixCommand -> ran = command.label }
Column(
    modifier = Modifier.fillMaxWidth().commandShortcuts(TEXT_COMMANDS, onRun = run),
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)
) {
    PantrixTextField(
        state = note,
        modifier = Modifier.fillMaxWidth(),
        label = "Note",
        placeholder = "Type here, then ⌘B or Ctrl+B",
        tagKey = "note"
    )
    PantrixButton(
        text = "Formatting commands",
        onClick = { open = true },
        variant = ButtonVariant.Outline,
        tagKey = "open_text"
    )
    PantrixText(
        text = "Last run: ${ran ?: "none"}",
        color = PantrixTheme.colors.textSecondary,
        tagKey = "ran_text"
    )
}
PantrixCommandPalette(
    visible = open,
    onDismissRequest = { open = false },
    commands = TEXT_COMMANDS,
    onRun = { command ->
        open = false
        run(command)
    },
    tagKey = "text"
)

private val TEXT_COMMANDS = listOf(
    PantrixCommand(
        key = "bold",
        label = "Bold",
        group = "Format",
        shortcut = PantrixShortcut(Key.B, command = true)
    ),
    PantrixCommand(
        key = "italic",
        label = "Italic",
        group = "Format",
        shortcut = PantrixShortcut(Key.I, command = true)
    ),
    PantrixCommand(
        key = "clear",
        label = "Clear the formatting",
        group = "Format",
        shortcut = PantrixShortcut(Key.Backslash, command = true)
    )
)

Words of its own and colours of its own

The palette's own words and colours: the field's placeholder and what is written when nothing matches are the caller's, and the highlighted row is in the app's own violet. Type "zzz" to see the words for an empty list.

var open by rememberSaveable { mutableStateOf(false) }
val own = ownColors()
PantrixButton(text = "Go somewhere", onClick = { open = true }, variant = ButtonVariant.Outline, tagKey = "open_go")
PantrixCommandPalette(
    visible = open,
    onDismissRequest = { open = false },
    commands = PLACES,
    onRun = { open = false },
    placeholder = "Type the name of a page…",
    emptyText = "No page has that name",
    colors = CommandPaletteColors(highlightedContainer = own.container, highlightedContent = own.onContainer),
    tagKey = "go"
)

private val PLACES = listOf(
    PantrixCommand(key = "home", label = "Home", icon = PantrixIcons.Inbox),
    PantrixCommand(key = "profile", label = "Profile", icon = PantrixIcons.Person),
    PantrixCommand(key = "favourites", label = "Favourites", icon = PantrixIcons.Star),
    PantrixCommand(key = "calendar", label = "Calendar", icon = PantrixIcons.Calendar)
)

In its own style

In its own style: CommandPaletteStyle changes the palette's width, its corners and its rows. Here the palette is at most 420dp wide, its corners are medium round and its rows 40dp high; every field not given is the platform's preset.

var open by rememberSaveable { mutableStateOf(false) }
PantrixButton(text = "Open the narrow palette", onClick = { open = true }, tagKey = "open_narrow")
PantrixCommandPalette(
    visible = open,
    onDismissRequest = { open = false },
    commands = EDITOR_COMMANDS,
    onRun = { open = false },
    style = CommandPaletteStyle(maxWidth = 420.dp, shape = ShapeRole.Medium, itemHeight = 40.dp, iconGap = 12.dp),
    tagKey = "narrow"
)

private val EDITOR_COMMANDS = listOf(
    PantrixCommand(
        key = "new",
        label = "New file",
        group = "File",
        icon = PantrixIcons.Plus,
        shortcut = PantrixShortcut(Key.N, command = true)
    ),
    PantrixCommand(
        key = "open",
        label = "Open file",
        group = "File",
        icon = PantrixIcons.Folder,
        shortcut = PantrixShortcut(Key.O, command = true)
    ),
    PantrixCommand(
        key = "rename",
        label = "Rename",
        group = "File",
        shortcut = PantrixShortcut(Key.R, command = true, shift = true)
    ),
    PantrixCommand(key = "delete", label = "Delete", group = "File", enabled = false),
    PantrixCommand(
        key = "copy",
        label = "Copy the link",
        group = "File",
        icon = PantrixIcons.Copy,
        keywords = listOf("link", "share"),
        supportingText = "An address for those who can see the file"
    ),
    PantrixCommand(
        key = "zoom_in",
        label = "Zoom in",
        group = "View",
        icon = PantrixIcons.ZoomIn,
        shortcut = PantrixShortcut(Key.Equals, command = true)
    ),
    PantrixCommand(
        key = "zoom_out",
        label = "Zoom out",
        group = "View",
        icon = PantrixIcons.ZoomOut,
        shortcut = PantrixShortcut(Key.Minus, command = true)
    ),
    PantrixCommand(
        key = "appearance",
        label = "Appearance settings",
        group = "View",
        icon = PantrixIcons.Eye,
        keywords = listOf("theme", "dark", "light"),
        supportingText = "Theme, text size, line spacing"
    ),
    PantrixCommand(
        key = "search",
        label = "Search the files",
        icon = PantrixIcons.Search,
        shortcut = PantrixShortcut(Key.F, command = true, shift = true)
    )
)

API

visible

Every command of the app, found by its name and run from the keyboard: what Cmd+K or Ctrl+K opens.

ParameterTypeDefaultWhat it is
visibleBooleanwhether the palette is shown. It never hides itself.
onDismissRequest() -> Unitcalled for back, Escape and a click on the scrim.
commandsList<PantrixCommand>every command, in the order they are listed under their groups. No two have one key.
onRun(PantrixCommand) -> Unitcalled with the command run, by Enter, the keyboard's action or a press. Close the palette here.
modifierModifierModifierthe panel's modifier.
placeholderString?nullwhat the empty field shows, or null for the theme's words for searching commands.
emptyTextString?nullwhat stands in the list's place while nothing matches, or null for the theme's words for it.
styleCommandPaletteStyle?nullthis call's own style: over every enclosing one and under the density. Only the fields it sets change, on every platform.
colorsCommandPaletteColors?nullthis palette's own colours, where they are not the theme's: the ones set here, with the theme's for the rest.
tagKeyString?nullthe palette's automation key: the panel is CommandPalette_<tagKey>, its field CommandPalette_<tagKey>.TextField_query and a command's row CommandPalette_<tagKey>.Command_<key>. What is done is reported as a CommandPalette event: open, dismiss with via (back or scrim), and run with the command's key and via (key or click). What is typed is never reported.

CommandPaletteStyle

PantrixCommandPalette's geometry: the panel, where it stands, and the rows of its list.

ParameterTypeDefaultWhat it is
shapeShapeSpecShapeSpec.UnspecifiedThe panel's corners: a step of the brand's shape scale, or a fixed shape.
maxWidthDpDp.UnspecifiedThe widest the panel grows in a wide window.
maxHeightDpDp.UnspecifiedThe tallest the panel grows in a tall window. A narrower window, and the keyboard, make it less.
elevationDpDp.UnspecifiedThe panel's shadow. iOS sets a panel apart by the dimming alone.
marginDpDp.UnspecifiedThe least room between the panel and the window's safe area.
topSpaceDpDp.UnspecifiedThe room above the panel, past margin.
itemHeightDpDp.UnspecifiedThe least height of a command's row. A larger type makes it taller.
itemHorizontalPaddingDpDp.UnspecifiedThe room between a row's sides and what it holds, and a heading's.
iconSizeDpDp.UnspecifiedThe width and height of a command's icon.
iconGapDpDp.UnspecifiedBetween a command's icon, its label and its shortcut.

CommandPaletteColors

What a PantrixCommandPalette is painted with, in place of the theme's colours: a colour that is set is used, and one that is left out stays the theme's.

ParameterTypeDefaultWhat it is
containerColorColor.UnspecifiedThe panel's fill. The theme's surface.
contentColorColor.UnspecifiedA command's label and its icon, and what is typed. The theme's textPrimary, or the colour a role's fill given as container gives what stands on it.
highlightedContainerColorColor.UnspecifiedThe fill behind the command Enter runs. The primary role's container.
highlightedContentColorColor.UnspecifiedThat command's label, icon and shortcut: the colour that reads on highlightedContainer. The primary role's onContainer.
headingColorColor.UnspecifiedA group's heading, a shortcut and what stands in the list's place when nothing matches. The theme's textSecondary on the theme's own grounds, and content on another fill.
scrimColorColor.UnspecifiedThe dimming laid over the app behind the palette, with its own alpha. The theme's scrim.

Accessibility