Pantrix UI

Card Skeleton

A PantrixCard whose content has not arrived: the card's own surface, with bars where its header, its body and its actions will be.

import com.pantrixui.components.container.card.PantrixCardSkeleton

Examples

Until the data arrives: the skeleton

Press "Refresh": for two seconds the two cards are replaced by their skeletons. PantrixCardSkeleton is not drawn to look like a card: it is built from the card's own shape, fill, shadow, padding and spacing. Its bars take the room of what they stand in for: when the data arrives the card's height does not change, and nothing below it moves.

The skeleton cannot know what is in the card: showHeader, lines, footerButtons and mediaHeight are given to match the card it stands in for. The first card has a header, one line and two buttons: lines = 1, footerButtons = 2.

The fill and the content colour of the "Campaign" card were given by the caller. Its skeleton takes the card's colours with colors too; its bars are drawn in the colour given with skeletonColors.

val own = ownColors()
val campaign = CardColors(container = own.container, content = own.onContainer)
var loading by remember { mutableStateOf(false) }
LaunchedEffect(loading) {
    if (loading) {
        delay(2_000)
        loading = false
    }
}
if (loading) {
    PantrixCardSkeleton(modifier = Modifier.fillMaxWidth(), lines = 1, footerButtons = 2)
} else {
    PantrixCard(
        modifier = Modifier.fillMaxWidth(),
        header = {
            PantrixText(
                text = "Order #1042",
                style = PantrixTheme.typography.title,
                role = TextRole.Heading(level = 3)
            )
        },
        footer = {
            PantrixButton(
                text = "Refresh",
                onClick = { loading = true },
                variant = ButtonVariant.Text,
                tagKey = "reload"
            )
            PantrixButton(text = "Track", onClick = {}, tagKey = "track")
        }
    ) {
        PantrixText(text = "Two items, delivery on Thursday")
    }
}
if (loading) {
    PantrixCardSkeleton(
        modifier = Modifier.fillMaxWidth(),
        variant = CardVariant.Filled,
        colors = campaign,
        skeletonColors = SkeletonColors(base = own.onContainer.copy(alpha = 0.3f), highlight = own.container),
        lines = 1
    )
} else {
    PantrixCard(
        modifier = Modifier.fillMaxWidth(),
        variant = CardVariant.Filled,
        colors = campaign,
        tagKey = "campaign"
    ) {
        PantrixText(text = "Campaign", style = PantrixTheme.typography.title)
        PantrixText(text = "Its fill and content colour were given by the caller")
    }
}

A loading list

A loading list: the skeletons of two outlined cards. mediaHeight stands in for the media the card will show, lines for the lines of the body, and footerButtons for the actions.

A skeleton that stands alone is announced to a screen reader once, for the whole card: with the theme's word, "Loading". Inside something that already says it is loading, this announcement is turned off: here the list says once that it is loading, and the skeletons were given contentDescription = null.

val loading = PantrixTheme.strings.loading
Column(
    modifier = Modifier.widthIn(max = 360.dp).semantics { contentDescription = loading },
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)
) {
    repeat(2) {
        PantrixCardSkeleton(
            modifier = Modifier.fillMaxWidth(),
            variant = CardVariant.Outlined,
            lines = 2,
            footerButtons = 1,
            mediaHeight = 96.dp,
            contentDescription = null
        )
    }
}

API

modifier

A PantrixCard whose content has not arrived: the card's own surface, with bars where its header, its body and its actions will be.

ParameterTypeDefaultWhat it is
modifierModifierModifierthe skeleton's modifier.
variantCardVariantCardVariant.Elevatedthe variant of the card it replaces: the same fill, shadow and edge.
styleCardStyle?nullthis call's own CardStyle: over every enclosing one and under the density. The footer's bars keep the theme's button shape.
shapeShapePantrixTheme.style(CardStyle, style).shape.toShape()the card's corners: by default the resolved style's. Given here, it wins over style's.
colorsCardColors?nullthe colours of the card it replaces, where that card has its own: the same fill and edge.
skeletonColorsSkeletonColors?nullthe bars' own colours, where they are not the theme's.
contentPaddingPaddingValuesPaddingValues(PantrixTheme.spacing.lg)the room around the bars, as around a card's content.
showHeaderBooleantruewhether a bar stands in for the header: a line of the theme's title.
linesInt3how many lines of text the bars stand in for, in the type a PantrixText has by itself.
footerButtonsInt0how many buttons the footer's bars stand in for.
mediaHeightDp?nullthe height of the media the card will show above its content, or null for a card without any.
contentDescriptionString?PantrixTheme.strings.loadingwhat a screen reader says for the whole skeleton, or null inside something that already says it is loading.
tagKeyString?nullthe skeleton's automation key: it is CardSkeleton_<tagKey>, and its bars have no tags of their own. Without one it has no tag.

CardStyle

PantrixCard's geometry: its corners, and the shadow of its elevated variant.

ParameterTypeDefaultWhat it is
shapeShapeSpecShapeSpec.UnspecifiedThe card's corners: medium on Android, large on iOS, small on desktop and the web.
elevationDpDp.UnspecifiedThe shadow under CardVariant.Elevated: 2dp on Android, none on iOS, 1dp on desktop and the web. The other variants draw none.

CardColors

What PantrixCard is painted with, for a card that does not take its variant's colours: a colour that is set is used, and one that is left out stays the variant's.

ParameterTypeDefaultWhat it is
containerColorColor.UnspecifiedThe card's fill. The theme's surface, or the neutral role's container in a CardVariant.Filled card.
contentColorColor.UnspecifiedWhat the card holds is drawn in, unless a child sets a colour of its own: the colour that reads on container. None on the theme's surface, where each child draws in its own default, a text in textPrimary; the neutral role's onContainer in a filled card.
borderColorColor.UnspecifiedThe hairline around the card. The theme's divider on a CardVariant.Outlined card, and where that card is given a fill that is no ground of the theme's, on which that line would not read, a share of what is written there: the edge a subtle button has. The other variants have none unless one is given here.