Facilities and components for writing desktop applications with the Compose Multiplatform framework.
Chords applications use a compact Material 3 desktop theme by default. It
provides neutral work surfaces, semantic light and dark color schemes,
restrained corner radii, regular-weight typography, and shared dimensions for common
controls, navigation, tables, dialogs, and supporting panes. The dark scheme is
selected from the operating system appearance observed at application startup.
Changes to the system appearance while the application is running are not
observed automatically; override ApplicationTheme when the application needs
a live theme switch.
The standard Material values are available through MaterialTheme. Desktop
values that Material does not define are available through
ChordsTheme:
val rowHeight = ChordsTheme.dimensions.tableRowHeight
val hoverAlpha = ChordsTheme.interaction.hoveredStateAlphaAn application can replace the theme in one place by overriding
Application.ApplicationTheme:
@Composable
override fun ApplicationTheme(content: @Composable () -> Unit) {
ChordsTheme(
colorScheme = myColorScheme,
typography = myTypography,
shapes = myShapes,
dimensions = ChordsDimensions(
controlHeight = 48.dp,
tableRowHeight = 44.dp
),
content = content
)
}Component properties take precedence over theme values. Class-based
components can also be customized application-wide with sharedDefaults.
The effective order is: instance properties, shared component defaults, Chords
desktop tokens, and finally Material theme values.
Menus, dialogs, and tooltips use ChordsTheme.overlayColor and a visible outline to separate
layers in dark themes. Custom popup panels can use
PopupSurface; Material
dropdown menus can apply Modifier.popupAppearance() from the same file.
Filled actions use
PrimaryButton;
outlined actions use
SecondaryButton.
For actions represented by a single icon, use
CircularIconButton.
These buttons provide hover and keyboard focus feedback in the active window.
EmptyState supplies the illustration,
caption, and alignment for empty work areas.
ScrollableColumn keeps long
details reachable within a bounded pane. Each component's KDoc includes usage examples.
Confirmation prompts share ChordsTheme.confirmationTextStyle.
Text inputs and selectors expose their text style, shape, modifier, and colors. Dropdowns expose popup shape, elevations, item height, padding, and selection colors. Tables expose content padding, container/header/row colors, and row heights. Dialogs, lightweight windows, and wizards expose their unique sizing, spacing, surface, shape, border, and elevation values.
Add a dependency to the library as follows:
dependencies {
implementation("io.spine.chords:spine-chords-core:$chordsVersion")
}Below is a high-level overview of what is included in the module for a quick start. You can also study the references for a more detailed documentation on respective topics.
Provides an API that simplifies creating Compose desktop applications that follow a multiview UI organization.
Although many components in Chords libraries do not depend on how the application is created on a high level, some components (particularly in the Spine Chords Client library) expect that the application is created using this Application Shell API.
See appshell/README.md for details.
As an alternative to writing components as @Composable functions, as is
typical in Compose, this library also adds a possibility to write components
as classes. This adds certain possibilities for writing and using Compose
components, while still maintaining an experience of using such components
that is very similar to using regular function-based ones.
This approach doesn't replace the function-based components, but adds a possibility to write components using an object-oriented paradigm whenever that appears more appropriate, while using such components interchangeably with the usual function-based ones. The syntax of using such components is similar that of function-based ones.
See the documentation for the Component class for details.
The library introduces its own notion of an input component that is represented by the InputComponent class. Having such a common basis for input components standardizes the API that is expected from all input components, and allows reusing it via class inheritance without having to repeat it for each implementation.
Such a standardized API is in particular useful for a polymorphic (uniform) usage of different input components in components like input forms, which have to be configured with arbitrary sets of input components.
See the InputComponent class, which includes such things as the property for edited value, validation support, etc.
This is a subclass of InputComponent, which simplifies creating input
components for entering arbitrary value types in text form. It includes support
for such aspects of entry as customizable parsing and formatting of respective
value types, input text validation, etc.
See the InputField documentation for details.
DropdownSelector is a base class for creating another type of input components, where item selection should be performed using a drop-down list.
In addition to components, the library includes such facilities:
-
A simple API to declare and detect key combinations, like this:
if (keyEvent matches 'x'.key.typed) { /*...*/ }
or
Modifier.on(Ctrl(Enter.key).up) { /*...*/ }
See the Keystroke class.
-
Extension functions to address common tasks or current shortcomings in Compose, like ensuring the usual focus traversal with the Tab key for text fields (see Modifier.moveFocusOnTab()).
-
Some simple components that address common needs like CheckboxWithText, RadioButtonWithText, or WithTooltip.
-
A blocking progress overlay for content that is busy with an asynchronous process (ProgressOverlay). It wraps arbitrary content, and, while it is active, covers that content with a semitransparent layer that displays a progress indicator and prevents the covered content from being operated with a pointing device:
ProgressOverlay(saving) { // The content that cannot be operated while it is being saved. }
The overlay doesn't change the way that the covered content is measured. While it is inactive, no overlay or interaction-intercepting layer is composed, and the wrapped content is composed and behaves exactly as it does without the wrapper. Its background and indicator can be customized with the respective parameters.
-
More complex components like Wizard.
-
Automatic submission progress in Dialog and Wizard. Both apply
ProgressOverlayto their content whenever theirsubmittingproperty istrue, which requires no changes at their usage sites. Such content additionally stops receiving key events, so it cannot be edited, navigated, or submitted again while the submission is in progress, while the dialog's Cancel button and the wizard's "Cancel" button keep working.