Sefar by Yassir

Usage

📝 Usage #

All the components are ready to use out-of-the-box.

Yassir Theme #

YassirTheme {
  Box(
    modifier = Modifier
      .fillMaxSize()
      .padding(YassirTheme.spacing.m)
  ) {
    Text(
      text = "Hello from Yassir Theme!",
      style = YassirTheme.typography.heading4,
      color = YassirTheme.colors.labelNeutralDefault,
    )
  }
}

Accordion #

Accordion(
  modifier = Modifier // optional
  headingText = "Heading",
  bodyText = "Body Text ".repeat(50), // optional
  headerIconResId = ContentIcons.Document, // optional
  customContent =  { Text("Change me!") }  // optional
)

Avatar #

  1. Initials Avatar
InitialsAvatar(
  modifier = Modifier, // optional
  name = "Foo Bar",
  size = AvatarSize.Large,
  isFocused = true, // optional
  badge = {} // optional
)
  1. Image Avatar
ImageAvatar(
  modifier = Modifier, // optional
  imageUrl = null, // optional
  resourceId = R.drawable.ic_avatar, // optional
  size = AvatarSize.Medium,
  isFocused = false, // optional
  badge = {} // optional
)
  1. Icon Avatar
IconAvatar(
  size = AvatarSize.Small,
  modifier = Modifier, // optional
  iconRes = DrawableR.ic_user, // optional
  isFocused = false, // optional
  badge = {} // optional
)

Avatar Group #

val listOfAvatars = listOf(
    AvatarGroupItem(
        avatarType = AvatarType.Initials, //Icon, Image, Initials variants
        name = "John Doe", // optional (for Initials variant)
        imageUrl = null, // optional (for Image variant)
        iconRes = R.drawable.ic_avatar, // optional (for Icon variant)
        imageRes = R.drawable.ic_avatar, // optional (for Image variant)
    )
)
AvatarGroup (
    modifier = Modifier,
    avatars= listOfAvatars,
    size = AvatarSize.Large
)

Backdrop #

  1. Carousel Dot State
Backdrop(
    modifier = Modifier.padding(YassirTheme.spacing.spacing0_5), // optional
    backDropType =  BackdropType.EmptyState(
        illustrationResIds = listOf(
            IllustrationInfo(
                R.drawable.flag_algeria_rect,
                message = "Top up 1",
                description = "check 1"
            ), IllustrationInfo(
                R.drawable.flag_uae_rect,
                message = "Top up 2",
                description = "check 2"
            ), IllustrationInfo(
                R.drawable.flag_south_africa_rect,
                message = "Top up 3",
                description = "check 3",
            )
        ),
        carouselIndicatorType = CarouselIndicatorType.Black, // optional
        carouselIndicatorStyle = CarouselIndicatorStyle.Dot,  // optional
    ),
    backdropHeaderItem = BackdropHeaderItem(
      title = "Title",
      subtitle = "Subtitle",
      tabsList = tabsList,
      onBackClick = {},
    ), // optional
    primaryAction = Action(
        text = "Primary Action",
        onClick = {}
    ), // optional
    secondaryAction = Action(
        text = "Secondary Action",
        onClick = {}
    ), // optional
    tertiaryAction = Action(
        text = "Teritary Action",
        onClick = {}
    ), // optional
    isVisible = true, // optional
    screenState = ScreenState.FullScreen, // optional
    windowInsets = WindowInsets(0, 0, 0, 0), // optional
    containerColor = YassirTheme.colors.surfaceNeutralHigh, // optional
    sheetState = SheetState(
        skipPartiallyExpanded = true,
        density = LocalDensity.current,
        initialValue = SheetValue.Expanded
    ), // optional
    onDismissRequest = {},
)
  1. Carousel Line State
Backdrop(
    modiefier = Modifier.padding(YassirTheme.spacing.spacing0_5), // optional
    backDropType =  BackdropType.EmptyState(
        illustrationResIds = listOf(
            IllustrationInfo(
                R.drawable.flag_algeria_rect,
                message = "Top up 1",
                description = "check 1"
            ), IllustrationInfo(
                R.drawable.flag_uae_rect,
                message = "Top up 2",
                description = "check 2"
            ),  IllustrationInfo(
                R.drawable.flag_south_africa_rect,
                message = "Top up 3",
                description = "check 3",
            )
        ),
        carouselIndicatorType = CarouselIndicatorType.White, // optional
        carouselIndicatorStyle = CarouselIndicatorStyle.Line, // optional
    ),
    backdropHeaderItem = BackdropHeaderItem(
      title = "Title",
      subtitle = "Subtitle",
      tabsList = tabsList,
      onBackClick = {},
    ), // optional
    primaryAction = Action(
        text = "Primary Action",
        onClick = {}
    ), // optional
    secondaryAction = Action(
        text = "Secondary Action",
        onClick = {}
    ), // optional
    tertiaryAction = Action(
        text = "Teritary Action",
        onClick = {}
    ), // optional
    isVisible = true, // optional
    screenState = ScreenState.FullScreen, // optional
    windowInsets = WindowInsets(0, 0, 0, 0), // optional
    containerColor = YassirTheme.colors.surfaceNeutralHigh, // optional
    sheetState = SheetState(
        skipPartiallyExpanded = true,
        density = LocalDensity.current,
        initialValue = SheetValue.Expanded
    ), // optional
    onDismissRequest = {  }
)
  1. Single Illustration State
Backdrop(
    modiefier = Modifier.padding(YassirTheme.spacing.spacing0_5), // optional
    backDropType =  BackdropType.EmptyState(
        illustrationResIds =  IllustrationInfo(
            R.drawable.flag_algeria_rect,
            message = "Top up 1",
            description = "check 1"
        )
    ),
    backdropHeaderItem = BackdropHeaderItem(
      title = "Title",
      subtitle = "Subtitle",
      tabsList = tabsList,
      onBackClick = {},
    ), // optional
    primaryAction = Action(
        text = "Primary Action",
        onClick = {}
    ), // optional
    secondaryAction = Action(
        text = "Secondary Action",
        onClick = {}
    ), // optional
    tertiaryAction = Action(
        text = "Teritary Action",
        onClick = {}
    ), // optional
    isVisible = true, // optional
    screenState = ScreenState.FullScreen, // optional
    windowInsets = WindowInsets(0, 0, 0, 0), // optional
    containerColor = YassirTheme.colors.surfaceNeutralHigh, // optional
    sheetState = SheetState(
        skipPartiallyExpanded = true,
        density = LocalDensity.current,
        initialValue = SheetValue.Expanded
    ), // optional
    onDismissRequest = {  }
)
  1. CustomState State
Backdrop(
    modiefier = Modifier.padding(YassirTheme.spacing.spacing0_5), // optional
    backDropType =  BackdropType.CustomState(
        customContent = {
            // create custom component
        }
    ),
    backdropHeaderItem = BackdropHeaderItem(
      title = "Title",
      subtitle = "Subtitle",
      tabsList = tabsList,
      onBackClick = {},
    ), // optional
    primaryAction = Action(
        text = "Primary Action",
        onClick = {}
    ), // optional
    secondaryAction = Action(
        text = "Secondary Action",
        onClick = {}
    ), // optional
    tertiaryAction = Action(
        text = "Teritary Action",
        onClick = {}
    ), // optional
    isVisible = true, // optional
    screenState = ScreenState.FullScreen, // optional
    windowInsets = WindowInsets(0, 0, 0, 0), // optional
    containerColor = YassirTheme.colors.surfaceNeutralHigh, // optional
    sheetState = SheetState(
        skipPartiallyExpanded = true,
        density = LocalDensity.current,
        initialValue = SheetValue.Expanded
    ), // optional
    onDismissRequest = {  }
)
  1. ListItem State
Backdrop(
    modiefier = Modifier.padding(YassirTheme.spacing.spacing0_5), // optional
    backDropType = BackdropType.ListItemState(
        items = List(50) { index ->
           Element(
                title = "Item Title $index",
                description = "description",
                formattedAmount = "1000$",
                onClick = {}
            )
        },
        showScrollbar = true  // optional
    ),
    backdropHeaderItem = BackdropHeaderItem(
      title = "Title",
      subtitle = "Subtitle",
      tabsList = tabsList,
      onBackClick = {},
    ), // optional
    primaryAction = Action(
        text = "Primary Action",
        onClick = {}
    ), // optional
    secondaryAction = Action(
        text = "Secondary Action",
        onClick = {}
    ), // optional
    tertiaryAction = Action(
        text = "Teritary Action",
        onClick = {}
    ), // optional
    isVisible = true, // optional
    screenState = ScreenState.FullScreen, // optional
    windowInsets = WindowInsets(0, 0, 0, 0), // optional
    containerColor = YassirTheme.colors.surfaceNeutralHigh, // optional
    sheetState = SheetState(
        skipPartiallyExpanded = true,
        density = LocalDensity.current,
        initialValue = SheetValue.Expanded
    ), // optional
    onDismissRequest = {  }
)

Badge #

Badge(
  style = BadgeStyleType.Primary,
  badgeText = "1", // optional
  colors: YassirColorScheme = YassirTheme.colors, // optional
  typography: YassirTypography = YassirTheme.typography, // optional
)
  1. Boxed Banner
Banner(
   bannerType = BannerType.Boxed(
      label = "Label", // optional
      bodyText = "This is the subtitle text of banner.", // optional
      style = BannerState.Default,
      captionText = "This is the caption text of banner", // optional
      captionIconRes = R.drawable.ic_alert_circle, // optional
      leadingIconRes = R.drawable.ic_alert_circle, // optional
      trailingIconRes = R.drawable.ic_small_x, // optional
      isElevated = false, // optional
      primaryBannerAction =
          BannerAction(
              text = "Primary Action",
              isEnabled = false,  // optional
              onClick = { /* action */  }
           ),  // optional
      secondaryBannerAction =
          BannerAction(
              text = "Secondary action",
              isEnabled = false,  // optional
              onClick = {  /* action */  },
            )
        ),  // optional
      trailingIconOnClick = {  /* action */ }
)
  1. FulWidth Banner
Banner(
    bannerType = BannerType.FullWidth(
        text = "This is the text of banner",
        style = BannerState.Positive,
        iconRes = R.drawable.ic_alert_circle,  // optional
        isElevated = true  // optional
    )
)

Bottom Navigation Bar #

val bottomNavigationBarList = listOf(
        BottomNavigationBarItem(
            text = "Tab",
            iconRes = R.drawable.ic_alert_circle,
            onClick = { /* action */ }
        ),
        BottomNavigationBarItem(
            text = "Tabs",
            iconRes = R.drawable.ic_lock,
            onClick = { /* action */ }
        ),
        BottomNavigationBarItem(
            text = "Tab",
            iconRes = R.drawable.ic_coins_hand,
            onClick = { /* action */ },
            badgeText = "2"
            onClick = { /* action */ },
        )
    )

BottomNavigationBar(
  list = bottomNavigationBarList,
  initialSelectedItemIndex = 1, // optional
  colors = YassirColorScheme.colors // optional
)

Buttons #

  1. Floating Action Button
PrimaryFloatingActionButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle,
  enabled = true, // optional
  label = "label", // optional
  loading = true, // optional
  elevationStyle = null, // optional
  shadowPosition = ShadowPosition.Top, // optional
  contentDescription = "content_description", // optional
)
SecondaryFloatingActionButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle,
  enabled = true, // optional
  label = "label", // optional
  loading = true, // optional
  elevationStyle = null, // optional
  shadowPosition = ShadowPosition.Bottom, // optional
  contentDescription = "content_description", // optional
)
TextualFloatingActionButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle,
  enabled = true, // optional
  label = "label", // optional
  loading = true, // optional
  elevationStyle = null, // optional
  shadowPosition = ShadowPosition.Top, // optional
  contentDescription = "content_description", // optional
)
BrandedFloatingActionButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle,
  enabled = true, // optional
  label = "label", // optional
  loading = true, // optional
  elevationStyle = null, // optional
  shadowPosition = ShadowPosition.Top, // optional
  contentDescription = "content_description", // optional
)
NegativeFloatingActionButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle,
  enabled = true, // optional
  label = "label", // optional
  loading = true, // optional
  elevationStyle = null, // optional
  shadowPosition = ShadowPosition.Bottom, // optional
  contentDescription = "content_description", // optional
)

For more details visit Floating Action Buttons documentation

  1. Icon Buttons
PrimaryIconButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  clickable = true,  // optional
  isShadowOnTop = false, // optional
  elevationStyle = null, // optional
  size = YassirButtonSize.Small, // optional
  contentDescription = "content_description", // optional
  iconSize = 5.dp // optional
)
SecondaryIconButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  clickable = true,  // optional
  isShadowOnTop = false, // optional
  elevationStyle = null, // optional
  size = YassirButtonSize.Medium, // optional
  contentDescription = "content_description", // optional
  iconSize = 5.dp // optional
)
TextualIconButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  clickable = true,  // optional
  isShadowOnTop = false, // optional
  elevationStyle = null, // optional
  size = YassirButtonSize.Large, // optional
  contentDescription = "content_description", // optional
  iconSize = 5.dp // optional
)
BrandedIconButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  clickable = true,  // optional
  isShadowOnTop = false, // optional
  elevationStyle = null, // optional
  size = YassirButtonSize.ExtraLarge, // optional
  contentDescription = "content_description", // optional
  iconSize = 5.dp // optional
)
NegativeIconButton(
  modifier = modifier, // optional
  onClick = {},
  iconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  clickable = true,  // optional
  isShadowOnTop = false, // optional
  elevationStyle = null, // optional
  size = YassirButtonSize.Small, // optional
  contentDescription = "content_description", // optional
  iconSize = 5.dp // optional
)

For more details visit Icon Buttons documentation

  1. Increment Button
var showProgressIndicator by rememberSaveable { mutableStateOf(false) }
DefaultIncrementButton(
  modifier = modifier, // optional
  enabled = areButtonsEnabled, // optional
  loading = showProgressIndicator, // optional
  trashState = true, // optional
  minValue = 1, // optional
  maxValue = 5, // optional
  defaultValue = 1, // optional
  elevationStyle = ElevationStyle.Light1, // optional
  shadowPosition = ShadowPosition.Top, // optional
  onTrashClicked = { Toast.makeText(context, "Trash Clicked", Toast.LENGTH_SHORT).show() } // optional
)

For more details visit Increment Buttons documentation

  1. Text Button
PrimaryButton(
  modifier = modifier, // optional
  onClick = {},
  text = "text",
  loading = true, // optional
  expanded = true, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  endIconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  size = YassirButtonSize.Small, // optional
)
BrandedButton(
  modifier = modifier, // optional
  onClick = {},
  text = "text",
  loading = true, // optional
  expanded = true, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  endIconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  size = YassirButtonSize.ExtraLarge, // optional
)
SecondaryButton(
  modifier = modifier, // optional
  onClick = {},
  text = "text",
  isElevated = true, // optional
  loading = true, // optional
  expanded = true, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  endIconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  size = YassirButtonSize.Large, // optional
)
TextualButton(
  modifier = modifier, // optional
  onClick = {},
  text = "text",
  loading = true, // optional
  expanded = true, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  endIconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  size = YassirButtonSize.Medium, // optional
)
NegativeButton(
  modifier = modifier, // optional
  onClick = {},
  text = "text",
  loading = true, // optional
  expanded = true, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  endIconResId = DrawableR.ic_alert_circle, // optional
  enabled = true, // optional
  size = YassirButtonSize.Small, // optional
)

For more details visit Text Buttons documentation

Cards #

Activity Card #

  1. Activity Card with Body = Text and Actions = single button
 SefarActivityCard(
        modifier = Modifier, //optional
        listItem = ActivityCardListItem(
            title = "Title",
            iconRes = DrawableR.ic_user, //optional
            transactionStatus = TransactionStatus.Pending, //optional
            transactionDateTime = Date(), //optional
            balance = "1000 DZD" //optional
        ),
        body = ActivityCardBody.Text("Some Text for Preview"),
        actions = ActivityCardActions.Buttons(
            firstAction = ActivityAction(
              label = "Action",
              onClick = {},
               isEnabled = true
               ),
        ) //optional
    )
  1. Activity Card with Body = Address List and Actions = two buttons
 SefarActivityCard(
        modifier = Modifier, //optional
        listItem = ActivityCardListItem(
            title = "Title",
            iconRes = DrawableR.ic_user, //optional
            transactionStatus = TransactionStatus.Pending, //optional
            transactionDateTime = Date(), //optional
            balance = "1000 DZD" //optional
        ),
        body =  ActivityCardBody.AddressList(
            locationsList = listOf(
                Location(name = "Location Name", address = "Location Address"),
                Location(name = "Location Name", address = "Location Address"),
                Location(name = "Location Name", address = "Location Address"),
                Location(name = "Location Name", address = "Location Address"),
            )
        ),
        actions = ActivityCardActions.Buttons(
            firstAction = ActivityAction(
              label = "Action",
              onClick = {},
               isEnabled = true
               ),
            secondaryAction = ActivityAction(
              label = "Action 2",
              onClick = {},
               isEnabled = true
            ),
        ) //optional
    )
  1. Activity Card with Body = Address List and Actions = tag and label
 SefarActivityCard(
        modifier = Modifier, //optional
        listItem = ActivityCardListItem(
            title = "Title",
            iconRes = DrawableR.ic_user, //optional
            transactionStatus = TransactionStatus.Pending, //optional
            transactionDateTime = Date(), //optional
            balance = "1000 DZD" //optional
        ),
        body =  ActivityCardBody.AddressList(
            locationsList = listOf(
                Location(name = "Location Name", address = "Location Address"),
                Location(name = "Location Name", address = "Location Address"),
                Location(name = "Location Name", address = "Location Address"),
                Location(name = "Location Name", address = "Location Address"),
            )
        ),
        actions = ActivityCardActions.Tag(
          labelText = "Label", //optional
            tagText = "Tag Text", //optional
            iconRes = DrawableR.ic_coins_hand //optional
        ) //optional
    )

For more details visit Activity Card documentation

Horizontal Card #

  1. Image Aligned
HorizontalCard(
    modifier = Modifier, // optional
    element = HorizontalCardElement(
        image = Image(
            resId = R.drawable.flag_algeria_rect,
            size = ImageSize.Large
        ), // optional
        titled = Titled(
            variant = TitledSectionVariant.Level4,
            title = CARD_TITLE,
            subtitle = CARD_SUBTITLE,
            description = TEXT_ALIGNED_LAYOUT,
            caption = CAPTION_TEXT
        ),
        subElement = SubElement.PriceElement(regularPriceText = REGULAR_PRICE_TEXT), // optional
        primary = ActionButton(text = BUY_NOW, onClick = {}), // optional
        secondary = SecondaryAction.Button(text = ADD_TO_CART, onClick = {}) // optional
    ),
    layoutCardType = LayoutCardType.ImageAligned // optional
)
  1. Text Aligned
HorizontalCard(
    modifier = Modifier, // optional
    element = HorizontalCardElement(
        image = Image(
            resId = R.drawable.flag_algeria_rect,
            size = ImageSize.Large
        ), // optional
        titled = Titled(
            variant = TitledSectionVariant.Level4,
            title = CARD_TITLE,
            subtitle = CARD_SUBTITLE,
            description = TEXT_ALIGNED_LAYOUT,
            caption = CAPTION_TEXT
        ),
        subElement = SubElement.PriceElement(regularPriceText = REGULAR_PRICE_TEXT), // optional
        primary = ActionButton(text = BUY_NOW, onClick = {}), // optional
        secondary = SecondaryAction.Button(text = ADD_TO_CART, onClick = {}) // optional
    ),
    layoutCardType = LayoutCardType.TextAligned // optional
)

Shop Card #

@Composable
fun ShopCardExample() { 
    ShopCard(
        shopCardDetails = shopCardDetails,
        isEnabled = true
    )
}
fun getShopCardDetails() {
    val hasYassirSideElement = false
    val shopCardDetails = ShopCardDetails(
        text = "Title",
        sideElement = if (hasYassirSideElement) {
            SideElement.YassirLogo(isDirectlyAdjacent = hasSnugSideElement)
        } else {
            SideElement.IconWithLabel(
                isDirectlyAdjacent = hasSnugSideElement,
                iconResId = DrawableR.ic_plus_circle,
                iconLabel = "1"
            )
        },
        imageUrl = null, // optional
        imageResId = DrawableR.flag_morocco_rect, // optional
        leadingElementType = LeadingElementType.ImageAvatar(resourceId = R.drawable.ic_avatar), // optional
        desc = "Body", // optional
        primaryTag = TagDetails(
            text = "New",
            startIconResId = R.drawable.ic_map_mark
        ), // optional
        secondaryTag = TagDetails(
            text = "Discount",
            startIconResId = R.drawable.ic_map_mark
        ), // optional
        disabledTag = TagDetails(
            text = "Coming Soon",
            startIconResId = R.drawable.ic_map_mark
        ), // optional
        iconButton = IconButtonDetails(
            iconResId = MapsIcons.Bus,
            contentDescription = null,
        ) // optional
    )
}

For more details visit Shop Card documentation

Vertical Card #

  1. Large Card
VerticalCard(
    element = VerticalCardElement(
        title = CARD_TITLE,
        image = Image(
            resId = R.drawable.ic_avatar,
            isEnable = isImageEnable == ImageInput.Enable
        ),
        priceElement = priceElement, // optional
        tagElement = tagElement, // optional
        action = SecondaryAction.IncrementButton(type = IncrementButtonType.Animated()) // optional
    ),
    size = VerticalCardSize.Large
)
  1. Small Card
VerticalCard(
    element = VerticalCardElement(
        title = CARD_TITLE,
        image = Image(
            resId = R.drawable.ic_avatar,
            isEnable = isImageEnable == ImageInput.Enable
        ),
        priceElement = priceElement,// optional
        tagElement = tagElement,// optional
        action = SecondaryAction.IncrementButton(type = IncrementButtonType.Animated())// optional
    ),
    size = VerticalCardSize.Small
)

Chips #

  1. Plain Single Chip with no Leading Element
SingleChip(
    modifier = Modifier.align(Alignment.CenterHorizontally), // optional
    size = YassirChipSize.Large,
    chipItem = ChipItem.Plain(
        text = text,
        counterValue = 50, // optional
        isEnabled = isEnabled, // optional
        isSelected = isSelected, // optional
    ),
    onClick = { isSelected = isSelected.not() }, // optional
    onClearIconClick = if (hasClearIcon) {
        null
    } else {
        { isCleared = true }
    }, // optional
    shape = RoundedCornerShape(size = SizeConstants.size6) // optional
)
  1. Single Chip with Icon as Leading Element
SingleChip(
    modifier = Modifier.align(Alignment.CenterHorizontally), // optional
    size = YassirChipSize.Small,
    chipItem = ChipItem.Icon(
        text = text,
        iconResourceId = DrawableR.ic_coins_hand,
        counterValue = null, // optional
        isEnabled = isEnabled, // optional
        isSelected = isSelected, // optional
    ),
    onClick = { isSelected = isSelected.not() }, // optional
    onClearIconClick = if (hasClearIcon) {
        null
    } else {
        { isCleared = true }
    }, // optional
    shape = RoundedCornerShape(size = SizeConstants.size6) // optional
)
  1. Single Chip with Image Avatar as Leading Element
SingleChip(
    modifier = Modifier.align(Alignment.CenterHorizontally), // optional
    size = YassirChipSize.Small,
    chipItem = ChipItem.ImageAvatar(
        text = text,
        imageUrl = "", // optional
        counterValue = 50, // optional
        isEnabled = isEnabled, // optional
        isSelected = isSelected, // optional
    ),
    onClick = { isSelected = isSelected.not() }, // optional
    onClearIconClick = if (hasClearIcon) {
        null
    } else {
        { isCleared = true }
    }, // optional
    shape = RoundedCornerShape(size = SizeConstants.size6) // optional
)
  1. Chip Filter
val listOfChips = (1..7).forEach {
    add(
        ChipItem.ImageAvatar(
            text = text,
                imageUrl = "", // optional
            counterValue = 50, // optional
            isEnabled = isEnabled, // optional
            isSelected = isSelected, // optional
        )
    )
}
ChipFilter(
    modifier = Modifier.align(Alignment.CenterHorizontally), // optional
    chipElements = listOfChips,
    size = chipSelectedSize,
    allowMultipleSelection = allowMultipleSelection, // optional
    allowHorizontalScrolling = allowHorizontalScrolling, // optional,
    shape = RoundedCornerShape(size = SizeConstants.size6), // optional
    onElementClick = { chipItem -> } // optional
)
  1. Chip Group
val listOfChips = (1..7).forEach {
    add(
        ChipItem.Plain(
            text = text,
            counterValue = 50, // optional
            isEnabled = isEnabled, // optional
            isSelected = isSelected, // optional
        )
    )
}
ChipGroup(
    modifier = Modifier.align(Alignment.CenterHorizontally), // optional
    chipElements = listOfChips,
    size = YassirChipSize.Small,
    onElementClick = { chipItem -> } // optional
)

Divider #

  1. Simple Default
Divider(
    modifier = Modifier.background(color = YassirTheme.colors.outlineLowAlternative), // optional
    dividerType = DividerType.Simple.Default,
    orientation = Orientation.Horizontal,
)
  1. Simple Left Aligned
Divider(
    modifier = Modifier.background(color = YassirTheme.colors.outlineLowAlternative), // optional
    dividerType = DividerType.Simple.LeftAligned,
    orientation = Orientation.Horizontal
)
  1. Simple Right Aligned
Divider(
    modifier = Modifier.background(color = YassirTheme.colors.outlineLowAlternative), // optional
    dividerType = DividerType.Simple.RightAligned,
    orientation = Orientation.Horizontal
)
  1. Simple Horizontally Aligned
Divider(
    modifier = Modifier.background(color = YassirTheme.colors.outlineLowAlternative), // optional
    dividerType = DividerType.Simple.HorizontalAligned,
    orientation = Orientation.Horizontal
)
  1. Doubled
Divider(
    modifier = Modifier.background(color = YassirTheme.colors.outlineLowAlternative), // optional
    dividerType = DividerType.Doubled,
    orientation = Orientation.Horizontal
)
  1. Thick
Divider(
    modifier = Modifier.background(color = YassirTheme.colors.outlineLowAlternative), // optional
    dividerType = DividerType.Thick,
    orientation = Orientation.Horizontal
)
  1. Dotted
 Divider(
    modifier = Modifier.background(color = YassirTheme.colors.outlineLowAlternative), // optional
    dividerType = DividerType.Dotted,
    orientation = Orientation.Horizontal
)

Flags #

  1. Circular Flag
CircularFlag(
  countryCode = "TN",
  modifier = modifier, // optional
  size = FlagSize.Small, // optional
  contentDescription = "" // optional
)
  1. Rectangular Flag
RectangularFlag(
  countryCode = "SA",
  modifier = Modifier, // optional
  size = FlagSize.Medium, // optional
  contentDescription = "" // optional
)

Input Fields #

Address Field #

  1. Departure Address Field
var value by remember { mutableStateOf("") }
AddressField(
    modifier = Modifier.padding(top = YassirTheme.spacing.spacing1),  // optional
    addressFieldType = AddressFieldType.Departure(
        leadingIcon = leadingAddressFieldLeadingIcon.Flag, // optional
        label = "label",  // optional
        hint = "hint", // optional
    ),
    enabled = true,
    value = value,
    errorMessage = "Field can't be empty", // optional
    onValueChange = { value = it },
)
  1. Stop Address Field
var value by remember { mutableStateOf("") }
AddressField(
    modifier = Modifier.padding(top = YassirTheme.spacing.spacing1),  // optional
    addressFieldType = AddressFieldType.Stop(
        leadingIcon = AddressFieldLeadingIcon.MarkerPin, // optional
        label = "label", // optional
        hint = "hint", // optional
        hasTrailingDragIcon = true, // optional
        onDragStart = {}, // optional
        onDrag = {}, // optional
        onDragEnd = {}, // optional
        onDragReposition = {}, // optional
        onAddActionClick = {} // optional
    ),
    enabled = true,
    value = "",
    errorMessage = "Field can't be empty", // optional
    onValueChange = { value = it },
)
  1. Destination Address Field
var value by remember { mutableStateOf("") }
AddressField(
    modifier = Modifier.padding(top = YassirTheme.spacing.spacing1), // optional
    addressFieldType = AddressFieldType.Destination(
        leadingIcon = AddressFieldLeadingIcon.DoubleLocationPins, // optional
        label = "label", // optional
        hint = "hint", // optional
        hasTrailingDragIcon = true, // optional
        onDragStart = {}, // optional
        onDrag = {}, // optional
        onDragEnd = {}, // optional
        onDragReposition = {}, // optional
        onAddActionClick = {} // optional
    ),
    enabled = true,
    value = "",
    errorMessage = "Field can't be empty", // optional
    onValueChange = { value = it },
)

Currency Input Field #

CurrencyInput(
  modifier = Modifier.padding(horizontal = YassirTheme.spacing.spacing1_5), // optional
  value = "text",
  onValueChange = { },
  regionCode = "DZ",
  currencyCode = "DZD",
  formattedBalance = "3000 DZD",
  enabled = true, // optional
  hasError = false, // optional
  hint = AnnotatedString("This is an example hint"), // optional
  onImeAction = { /* action */ }, // optional
  placeholder = "0", // optional
  clickableHint = "HyperLink", // optional
  onHintClick = {}, // optional
  imeAction = ImeAction.Default, // optional
)

For more details visit Currency Input documentation

DropdownInput(
    modifier = Modifier.fillMaxWidth(), // optional, default is Modifier
    items = listOf(
        DropdownInputItem(text = "Option 1", iconResourceId = R.drawable.ic_option1_icon),
        DropdownInputItem(text = "Option 2", avatarResourceId = R.drawable.avatar_option2),
        DropdownInputItem(text = "Option 3") // No icon or avatar
    ),
    selectedItems = mutableListOf(
        // Empty list for standard behavior, prefilled list for already pre-selected items being displayed
    ),
    multiSelect = true,
    onItemSelect = { selectedItem ->
        // Handle item select logic here
    },
    onItemDeselect = { deselectedItem ->
        // Handle item deselect logic here
    },
    onApply = {
        // Handle apply button logic here
    },
    onClear = {
        // Handle clear button logic here
    },
    labelText = "Select Items", // optional, default is null
    dropDownText = "Choose from options", // optional, default is null
    hintText = "Select one or more options from the dropdown", // optional, default is null
    leadingIcon = R.drawable.ic_dropdown_icon, // optional, default is null
    isError = false, // optional, default is false
    errorText = "An error occurred", // optional, default is null
    disabled = false, // optional, default is false
    applyButtonText = "Apply Selection", // optional, default is "Apply"
    clearButtonText = "Clear All" // optional, default is "Clear filter"
)

Generic Input Field #

GenericInput(
  label = "Email Label", // optional
  value = "text",
  onValueChange = { text = it },
  modifier = Modifier, // optional
  enabled = enabled, // optional
  hasError = hasError, // optional
  showIconOnError = true, // optional
  leading = GenericInputDefaults.Empty, // optional
  trailing = GenericInputDefaults.Empty, // optional
  placeholder = "Placeholder text", // optional
  hint = "Hint text", // optional
  showScrollBars = true, // optional
  shiftTrailingComponent = false,  // optional
  onHintClick = {}, // optional
  forceLtr = true, // optional
  cursorAtEnd = false, // optional
  textAlign = TextAlign.Start, // optional
  maxLines = 1, // optional
  fixedHeight = null, // optional
  minHeight = 30.dp, // optional
  maxHeight = 60.dp, // optional
  innerFieldStaticLeadingText = "Test", // optional
  keyboardOptions = KeyboardOptions(
    keyboardType = keyboardType,
    imeAction = imeAction
  ), // optional
  keyboardActions = KeyboardActions(
    onAny = { /* action */ }
  ), // optional
  labelTextStyle = YassirTheme.typography.bodyLargeBold, // optional
  visualTransformation = VisualTransformation.None
)

For more details visit Generic Input documentation

(PIN/OTP) Code Input Fields #

//PIN Code
CodeInput(
  modifier = Modifier, // optional
  codeType = CodeType.PIN_CODE,
  label = "PIN Code", // optional
  isError = false, // optional
  isEnabled = true, // optional
  clearCode = false, // optional
  autoFocus = true, // optional
  codeLength = CodeInputDefaults.LENGTH, // optional
  spaceBetweenCodeCells = YassirTheme.spacing.spacing2, // optional
  hint = AnnotatedString(hintText), // optional
  onHintClick = {}, // optional
  resetErrorState = {}, // optional
  onCodeFilled = { code ->
    /* handle entered PIN code */
  },
  colors = YassirTheme.colors // optional
)
//OTP Code
CodeInput(
  modifier = Modifier
    .align(Alignment.CenterHorizontally)
    .padding(top = YassirTheme.spacing.spacing4), // optional
  codeType = CodeType.OTP_CODE,
  isError = false, // optional
  isEnabled = true, // optional
  clearCode = false, // optional
  autoFocus = true, // optional
  codeLength = 6, // optional
  spaceBetweenCodeCells = YassirTheme.spacing.spacing1_5, // optional
  hint = AnnotatedString(hintText), // optional
  onHintClick = {}, // optional
  resetErrorState = { isError = false }, // optional
  onCodeFilled = { code ->
    /* handle entered OTP code */
  },
  colors = YassirTheme.colors, // optional
  label = "OTP Code" // optional
)

Phone Input Field #

  1. with a supported initially selected Country
PhoneInput(
  modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
  hint = "Phone Number can't be empty!", // optional
  hasError = true, // optional
  hasLabel = true, // optional
  enabled = true, // optional
  phoneNumber = "", // optional
  isCountrySelectionEnabled = true, // optional
  countriesList = SupportedCountries.entries, // optional
  onPhoneNumberChange = { phoneNumber, isValid -> }, // optional
  initialSelectedCountry = SupportedCountry.ALgeria, // optional
  onHintClick = { /* action */ } // optional,
  onImeAction = { /* action */ } // optional,
)
  1. with an unsupported initially selected country
val listOfCountries = buildList {
    add(SupportedCountry.Algeria)
    add(SupportedCountry.Canada)
    add(SupportedCountry.Egypt)
    add(getCountryFromRegionCode("JP"))
    add(getCountryFromRegionCode("MA"))
    add(getCountryFromInternationalPrefix("+34"))
    add(getCountryFromInternationalPrefix("+971"))
}
PhoneInput(
  modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
  hint = "Phone Number can't be empty!", // optional
  hasError = true, // optional
  hasLabel = true, // optional
  enabled = true, // optional
  isCountrySelectionEnabled = true, // optional
  phoneNumber = "", // optional
  countriesList = listOfCountries, // optional
  onPhoneNumberChange = { phoneNumber, isValid -> }, // optional
  initialSelectedCountry = getCountryFromRegionCode("JP"), // or getCountryFromInternationalPrefix("+81")  - optional
  onHintClick = { /* action */ } // optional,
  onImeAction = { /* action */ } // optional,
)

For more details visit Phone Input documentation

Search Input Field #

SearchInput(
  label = "Search", // optional
  value = "text",
  onValueChange = { newValue -> },
  enabled = false, // optional
  modifier = modifier, // optional
  placeholder = "Search", // optional
  hint = "This is a hint text to help user.", // optional
)

Text Area Field #

TextAreaInput(
    text = "text",
    onValueChange = { },
    enabled = true,
    hasError = false,
    showScrollBars = false, // optional
    placeholder = stringResource(R.string.placeholder_text), // optional
    hint = if (hasHint) stringResource(R.string.hint_text) // optional
)

For more details visit Text Area Input documentation

Lists & List Items #

Address List #

val locationsList = repeat((0 until 5).count()) {
    add(
        Location(
            name = "Location Name",
            address = "Address"
        )
    )
}
AddressList(
    modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
    locationsList = locationsList,
    notesHint = "Enter your notes to the driver here", // optional
    onNotesFieldChange = { newNotes -> } // optional
)

Checkout List Item #

CheckoutListItem(
    countNumber = 2,
    label = "Label",
    description = "Description" // optional,
    regularPriceText = "7000" // optional,
    discountPriceText = "8000" // optional,
    regularPriceCurrency = "DZD" // optional,
    discountPriceCurrency = "DZD" // optional,
    chipElements = listOf(
        ChipItem(text = "Item 1", iconResourceId = DrawableR.ic_coins_hand),
        ChipItem(text = "Sample Item 2",  isSelected = true),
        ChipItem(text = "Item 3", DrawableR.ic_coins_hand),
        ChipItem(text = "Sample Item 4"),
    ) // optional,
)

For more details visit Checkout List Item documentation

List Item #

  1. List item
ListItem(
  modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
  title = "Sample Title",
  description = "description",
    leading = LeadingElementType.Icon(
      iconRes = DrawableR.ic_coins_hand,
      tint = YassirTheme.colors.labelNeutralDefault,
    ), // optional
    trailing = TrailingElementType.CheckBox(
      selectionState = trailingCheckBoxState,
      onClick = {},
    ), // optional
    description = "description", // optional
    upperDescription = "upperDescription", // optional
    locale = currentLocale(), // optional
    onClickLabel = "", // optional
    isSelected = true, // optional
    isEnabled = true, // optional
    onClick = {
        Toast.makeText(context, "List Item was clicked", Toast.LENGTH_SHORT).show()
    } // optional
)
  1. Item with a transaction data
ListItem(
    modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
    title = "Item Title",
    description = "description", // optional
    formattedAmount = "1000$",
    transactionStatus = TransactionStatus.None, // optional
    transactionDateTime = Date(), // optional
    transactionType = TransactionType.Pending, // optional
    leading = LeadingElementType.Icon(
      iconRes = DrawableR.ic_coins_hand,
      tint = YassirTheme.colors.labelNeutralDefault,
    ), // optional
    trailing = TrailingElementType.CheckBox(
      selectionState = trailingCheckBoxState,
      onClick = {},
    ), // optional
    locale = currentLocale(), // optional
    currencyHidden = true, // optional
    size = ListItemSize.Medium, // optional
    upperDescription = "upperDescription", // optional
    onClickLabel = "", // optional
    isSelected = true, // optional
    isEnabled = true, // optional
    onClick = {
        Toast.makeText(context, "List Item was clicked", Toast.LENGTH_SHORT).show()
    } // optional
)

Price List #

  1. Primary Price List with Total Element
 PriceList(
    modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
    listItems = listOf(
      PriceListElement(
        label = "Label",
        price = "10",
       currency = "DZD",
      )
    ),
    totalElement = TotalPriceListElement(
      label = "Total",
      price = "4000",
      currency = "DZD"
    ), // optional
    type = PriceListType.Primary,
    onClick = { value ->   /* action */  },
)
  1. Icon Price List
 PriceList(
    modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
    modifier = Modifier,
    listItems = listOf(
      PriceListElement(
        label = "Label",
        price = "10",
       currency = "DZD",
       iconRes = R.drawable.image
      )
    ),
    totalElement = null, // optional
    type = PriceListType.Icon,
    onClick = { value ->   /* action */  },
)

Selectors List #

  1. Selectors List with RadioButton
SelectorsList(
    selectorsListLeadingElementType = SelectorsListRadioButton(
        modifier = Modifier, // optional
        selectedItemIndex = 0, // optional
        items = listOf(
            SelectorsListItemElement(
                label = "Label",
                priceText = "10",
                currencyText = "DZD",
                iconRes = R.drawable.image,
                isEnabled = true // optional
            isPreselected = true // optional
            )
        ),
        isGroupEnabled = isEnabled,
        onItemSelection = { value ->   /* action */ },
    ),
)
  1. Selectors List with Checkbox
SelectorsList(
    selectorsListLeadingElementType = SelectorsListCheckBox(
    modifier = Modifier, // optional
    items = listOf(
       SelectorsListItemElement(
            label = "Label",
            priceText = "10",
            currencyText = "DZD",
            iconRes = R.drawable.image,
            isEnabled = true, // optional
            isPreselected = true // optional
        )
    ),
    isGroupEnabled = isEnabled,
    onStateChange = { checkBoxGroupState -> /* action */},  // optional
  ),
)

Map Pin #

  1. Label type
YassirMapPin(
    mapPinType =  MapPinType.Label(
        caption = "caption text",
        body = "body",
        subtitle = "subtitle",
        showIcon = true
    ),
    mapPinDirection = MapPinDirection.Up, // optional
    mapPinCardColor = MapPinCardColor.Primary // optional
)
  1. Avatar type
YassirMapPin(
    mapPinType =  MapPinType.Avatar(
        imageUrl = "",  // optional
        resourceId = R.drawable.ic_avatar // optional
    ),
    mapPinDirection = MapPinDirection.Up, // optional
    mapPinCardColor = MapPinCardColor.Primary // optional
)
  1. Dot type
YassirMapPin(
    mapPinType =  MapPinType.Dot,
    mapPinDirection = MapPinDirection.Up, // optional
    mapPinCardColor = MapPinCardColor.Primary // optional
)
  1. Icon type
YassirMapPin(
    mapPinType =  MapPinType.Icon.Loading,
    mapPinDirection = MapPinDirection.Up, // optional
    mapPinCardColor = MapPinCardColor.Primary // optional
)
  1. Empty State Modal
Modal(
    modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
    modalType = ModalType.EmptyState(
        illustrationResIds = listOf(
          IllustrationInfo(
            resId = DrawableR.system_verified,
            message = "Title",
            description = "This Is description"
          ),
        ),
    ),
    onDismiss = { /* action */ },
    colors = YassirTheme.colors, // optional
    primaryAction = Action(
        text = "Primary Action",
        onClick = { /* action */ }
    ), // optional
    secondaryAction = Action(
        text = "Secondary Action",
        onClick = { /* action */ }
    ), // optional
    tertiaryAction = Action(
        text = "Terniary Action",
        onClick = { /* action */ }
    ) // optional
)
  1. Slot Modal
Modal(
    modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
    modalType = ModalType.Slot(  /* @Composable  */),
    onDismiss = { /* action */ },
    colors = YassirTheme.colors, // optional
    primaryAction = Action(
        text = "Primary Action",
        onClick = { /* action */ }
    ), // optional
    secondaryAction = Action(
        text = "Secondary Action",
        onClick = { /* action */ }
    ), // optional
    tertiaryAction = Action(
        text = "Terniary Action",
        onClick = { /* action */ }
    ) // optional
)

Modifiers #

1.HorizontalScrollbar

@Composable
internal fun HorizontalScrollbarPreview() {
    val state = rememberScrollState()
    Row(
        modifier = Modifier
            .drawHorizontalScrollbar(state)
    ) {
        repeat(50) {
            Text(
                text = (it + 1).toString(),
                modifier = Modifier
                    .padding(YassirTheme.spacing.spacing1, vertical = YassirTheme.spacing.spacing2)
            )
        }
    }
}

2.LazyListScrollbar

@Composable
internal fun LazyListScrollbarPreview() {
    val state = rememberLazyListState()
    LazyColumn(
        modifier = Modifier.drawVerticalScrollbar(state),
        state = state
    ) {
        items(50) {
            Text(
                text = "Item ${it + 1}",
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(YassirTheme.spacing.spacing2)
            )
        }
    }
}

3.elevation

Column(
    modifier = Modifier
        .elevation(ElevationStyle.Light2,
            shape = RoundedCornerShape(YassirTheme.spacing.spacing1),
            shadowPosition = ShadowPosition.Bottom)
        .background(
            colors.fromToken(style.backgroundColorKey),
            shape = RoundedCornerShape(YassirTheme.spacing.spacing1)
        )
        .padding(
            horizontal = YassirTheme.spacing.spacing1_5,
            vertical = YassirTheme.spacing.spacing1
        )
) {}

Price #

  1. Vertical Large Price
Price(
    regularPriceText = "6000 DZD",
    discountPriceText = "7000 DZD", // optional
    priceLayoutDirection = PriceLayoutDirection.Vertical, // optional
    priceSize = PriceSize.Large // optional
)
  1. Horizontal Small Price
Price(
    regularPriceText = "6000 DZD",
    discountPriceText = "7000 DZD", // optional
    priceLayoutDirection = PriceLayoutDirection.Horizontal, // optional
    priceSize = PriceSize.Small // optional
)
  1. Horizontal Large Price with no discount price
Price(
    regularPriceText = "6000 DZD",
    priceLayoutDirection = PriceLayoutDirection.Horizontal, // optional
    priceSize = PriceSize.Large // optional
)

Profile Photo #

  1. Image Profile
ImageProfile(
    modifier = Modifier, // optional
    imageUrl = "", // optional
    resourceId = R.drawable.ic_avatar, // optional
    size = ProfileSize.Small,
    withBorder = false, // optional
    badge = { } // optional
)
  1. Icon Profile
IconProfile(
    modifier = Modifier, // optional
    size = ProfileSize.Medium,
    withBorder = false, // optional
    badge = { } // optional
)
  1. Initials Profile
InitialsProfile(
    name = "Foo Bar",
    modifier = Modifier, // optional
    size = ProfileSize.Large,
    withBorder = false, // optional
    badge = { } // optional
)

Badge is a lambda that returns a composable that will be displayed on the bottom right corner of the profile photo.

Verified Badge

VerifiedBadge()

Edit Badge Has onEditBadgeClick parameter that is a lambda that will be called when the edit badge is clicked.

EditBadge(onEditBadgeClick = null)

Progress Bar #

  1. Large ProgressBar
ProgressBar(
    progress = 25f,
    label = "2/5",//optional
    style = ProgressBarStyle.Default,//optional
    type = ProgressBarType.Linear,//optional
    size = ProgressBarSize.Large,//optional
)
  1. Small ProgressBar
ProgressBar(
    progress = 25f,
    label = "25%",//optional
    style = ProgressBarStyle.Default,//optional
    type = ProgressBarType.Linear,//optional
    size = ProgressBarSize.Small,//optional
)

Scrollbar #

  1. LazyListState Fast Scrolling component
val numbers = (1..100).toList()
val scrollableState: LazyListState = rememberLazyListState()
val scrollbarState: ScrollbarState =
    scrollableState.scrollbarState(itemsAvailable = numbers.size)

Box(modifier = Modifier.fillMaxSize()) {
    LazyColumn(
        modifier = Modifier.fillMaxWidth(),
        state = scrollableState,
    ) {
        items(items = numbers) { number ->
            //any item
        }
    }
    scrollableState.DraggableScrollbar(
        modifier = Modifier
            .windowInsetsPadding(WindowInsets.systemBars)
            .padding(horizontal = 2.dp)
            .align(Alignment.CenterEnd),
        state = scrollbarState,
        orientation = Orientation.Vertical,
        onThumbMoved = scrollableState.rememberDraggableScroller(itemsAvailable = numbers.size)
    )
}
  1. LazyListState Regular Scrolling component
val numbers = (1..100).toList()
val scrollableState: LazyListState = rememberLazyListState()
val scrollbarState: ScrollbarState =
    scrollableState.scrollbarState(itemsAvailable = numbers.size)

Box(modifier = Modifier.fillMaxSize()) {
    LazyColumn(
        modifier = Modifier.fillMaxWidth(),
        state = scrollableState,
    ) {
        items(items = numbers) { number ->
            //any item
        }
    }
    scrollableState.DecorativeScrollbar(
        modifier = Modifier
            .windowInsetsPadding(WindowInsets.systemBars)
            .padding(horizontal = 2.dp)
            .align(Alignment.CenterEnd),
        state = scrollbarState,
        orientation = Orientation.Vertical
    )
}
  1. LazyListState Modifier Scrolling
val state = rememberLazyListState()
LazyColumn(
    modifier = Modifier.drawVerticalScrollbar(state),
    state = state
) {
    items(50) {
        Text(
            text = "Item ${it + 1}",
            modifier = Modifier
                .fillMaxWidth()
                .padding(YassirTheme.spacing.spacing2)
        )
    }
}
  1. ScrollState Regular Scrolling component
val state: ScrollState = rememberScrollState()
val scrollbarState: ScrollbarState = state.scrollbarState()

Box(modifier = Modifier.fillMaxSize()) {
    Column(
        modifier = Modifier
            .verticalScroll(state)
            .fillMaxSize()
    ) {
        repeat(100) { index ->
            Text(text = "Item $index", style = YassirTheme.typography.heading1)
            Spacer(modifier = Modifier.height(YassirTheme.spacing.spacing2))
        }
    }

    state.DecorativeScrollbar(
        modifier = Modifier
            .windowInsetsPadding(WindowInsets.systemBars)
            .padding(horizontal = 2.dp)
            .align(Alignment.CenterEnd),
        state = scrollbarState,
        orientation = Orientation.Vertical
    )
}
  1. ScrollState Modifier Scrolling
val state = rememberScrollState()
Column(
    modifier = Modifier
        .drawVerticalScrollbar(state)
) {
    repeat(50) {
        Text(
            text = (it + 1).toString(),
            modifier = Modifier
                .padding(YassirTheme.spacing.spacing1, vertical = YassirTheme.spacing.spacing2)
        )
    }
}

Selectors #

  1. Checkbox and ChecboxGroup
Checkbox(
  modifier = Modifier.padding(top = YassirTheme.spacing.spacing1_5), // optional
  onSelectedChange = {},
  title = "title", // optional
  description = "description", // optional
  isSelected = false, // optional
  isEnabled = false // optional
)
CheckboxGroup(
  modifier = Modifier, // optional
  onStateChange = {checkBoxGroupState -> },
  topLevelCheckbox = IndeterminateCheckboxItem(
    title = "Toppings",
    description = "All the toppings"
  ),
  checkboxes = listOf(
    CheckboxItem(title = "Pepperoni", description = "spicy salami seasoned with paprika"),
    CheckboxItem(title = "Extra cheese", description = "extra cheese on your pizza!"),
    CheckboxItem(title = "Olives", description = "delicious black olives")
  ),
  isGroupEnabled = true // optional
)
  1. Radio Group
RadioGroup(
  modifier = Modifier, // optional
  onItemSelection = { intValue ->  },
  items = leadingRadioGroupList,
  selectedItemIndex = 0, // optional
  isGroupEnabled = true // optional
)

Skeleton (Shimmer Layout) #

  1. Circular
var isLoading by remember { mutableStateOf(false) }
val customSize = Size(width = 50F, height = 50F)
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl

Text(
    modifier = Modifier.shimmerEffect(
        isLoading = isLoading,
        skeletonShape = SkeletonShape.Circular(
            size = customSize // optional
        ), // optional
        isRtl = isRtl
    ),
    text = "genericText"
)
  1. Rectangular
var isLoading by remember { mutableStateOf(false) }
val customSize = Size(width = 50F, height = 50F)
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl

Text(
    modifier = Modifier.shimmerEffect(
        isLoading = isLoading,
        skeletonShape = SkeletonShape.Rectangular(
            rounderCornerSize = 4.dp, // optional
            size = customSize // optional
        ), // optional
        isRtl = isRtl
    ),
    text = "genericText"
)
  1. List Item
var isLoading by remember { mutableStateOf(false) }
val customSize = Size(width = 350F, height = 100F)
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl

Text(
    modifier = Modifier.shimmerEffect(
        isLoading = isLoading,
        skeletonShape = SkeletonShape.ListItem(
            hasImagePlaceholder = false, // optional
            size = customSize // optional
        ), // optional
        isRtl = isRtl
    ),
    text = "genericText"
)

Slider #

  1. Simple Slider without label
Slider(
    modifier = Modifier.padding(vertical = YassirTheme.spacing.spacing2) // optional
    value = sliderValue,
    onValueChange = { newValue -> sliderValue = newValue },
    valueRange = 0f..10f, // optional
    step = 1, // optional
    enabled = isEnabled, // optional
)
  1. Simple Slider with label - has a value sign
Slider(
    modifier = Modifier.padding(vertical = YassirTheme.spacing.spacing2) // optional
    value = sliderValue,
    onValueChange = { newValue -> sliderValue = newValue },
    valueRange = 0f..10f, // optional
    step = 1, // optional
    enabled = true, // optional
    labelData = SliderLabelData(
        text = "GenericText",
        symbol = "\$" // optional
    ), // optional
)
  1. Simple Slider with label - has no value sign
Slider(
    modifier = Modifier.padding(vertical = YassirTheme.spacing.spacing2) // optional
    value = sliderValue,
    onValueChange = { newValue -> sliderValue = newValue },
    valueRange = 0f..10f, // optional
    step = 1, // optional
    enabled = true, // optional
    labelData = SliderLabelData(
        text = "GenericText",
    ), // optional
)
  1. Dashed Slider with ticks
Slider(
    modifier = Modifier.padding(vertical = YassirTheme.spacing.spacing2) // optional
    value = sliderValue,
    onValueChange = { newValue -> sliderValue = newValue },
    valueRange = 0f..10f, // optional
    step = 1, // optional
    enabled = true, // optional
    labelData = SliderLabelData(
        text = "GenericText",
        symbol = "\$" // optional
    ), // optional
    isDashed = true, // optional
)
  1. Dashed Slider with ticks and indicator labels
Slider(
    modifier = Modifier.padding(vertical = YassirTheme.spacing.spacing2) // optional
    value = sliderValue,
    onValueChange = { newValue -> sliderValue = newValue },
    valueRange = 0f..10f, // optional
    step = 1, // optional
    enabled = true, // optional
    labelData = SliderLabelData(
        text = "GenericText",
        symbol = "\$" // optional
    ), // optional
    isDashed = true, // optional
    showDashedLabels = hasDashLabels, // optional
)

Snackbar #

Snackbar(
    message = "This is a snackbar message",
    actionLabel = "Retry", // optional, displays an action button if provided
    onActionClick = { /* Handle retry action */ }, // optional, called when the action button is clicked
    iconResId = R.drawable.ic_alert_circle, // optional, displays an icon if a drawable resource ID is provided
    size = SnackbarSize.Medium, // optional, default is SnackbarSize.Medium, can be set to SnackbarSize.Large
    displayDuration = 5000L, // optional, default is 5000 milliseconds (5 seconds)
    onDismiss = { /* Handle snackbar dismiss */ } // optional, called when the snackbar is dismissed
)

Stepper #

  1. Vertical Stepper
@Composable
fun StepperExample() {
    val currentStepIsError = false
    val stepsAreNumbered = false
    val includeDescription = true

    Stepper(
        modifier = Modifier, // optional
        steps = getStepsList(
            currentStepIsError, 
            stepsAreNumbered, 
            includeDescription
        ),
        isHorizontal = false
    )
}

private fun getStepsList(
    currentStepIsError: Boolean,
    stepsAreNumbered: Boolean,
    includeDescription: Boolean,
    noOfSteps: Int = defaultNoOfSteps,
) = buildList {
    (1..noOfSteps).forEach {
        val status = when (it) {
            noOfSteps -> StepStatus.Remaining
            noOfSteps - 1 -> if (currentStepIsError) StepStatus.Error else StepStatus.Current
            else -> StepStatus.Completed
        }
        add(
            Step(
                text = "Step $it",
                description = if (includeDescription) "Desc" else null, // optional
                status = status,
                number = it, // optional
                iconResId = if (!stepsAreNumbered) R.drawable.ic_map_mark else null, // optional
                iconContentDesc = "Step $it" // optional
            )
        )
    }
}
  1. Horizontal Stepper
@Composable
fun StepperExample() {
    val currentStepIsError = true
    val stepsAreNumbered = true
    val includeDescription = false

    Stepper(
        modifier = Modifier, // optional
        steps = getStepsList(
            currentStepIsError, 
            stepsAreNumbered, 
            includeDescription
        ),
        isHorizontal = true
    )
}

private fun getStepsList(
    currentStepIsError: Boolean,
    stepsAreNumbered: Boolean,
    includeDescription: Boolean,
    noOfSteps: Int = defaultNoOfSteps,
) = buildList {
    (1..noOfSteps).forEach {
        val status = when (it) {
            noOfSteps -> StepStatus.Remaining
            noOfSteps - 1 -> if (currentStepIsError) StepStatus.Error else StepStatus.Current
            else -> StepStatus.Completed
        }
        add(
            Step(
                text = "Step $it",
                description = if (includeDescription) "Desc" else null, // optional
                status = status,
                number = it, // optional
                iconResId = if (!stepsAreNumbered) R.drawable.ic_map_mark else null, // optional
                iconContentDesc = "Step $it" // optional
            )
        )
    }
}

For more details visit Stepper documentation

Switches (Toggle) #

  1. Large Switch
Switch(
    modifier = Modifier.padding(vertical = YassirTheme.spacing.spacing1),
    enabled = true,
    checked = true,
    type = ToggleType.LargeSwitch(title = "on", isIconVisible = true),
    onToggle = { checked = checked.not() },
)
  1. Small Switch
Switch(
    modifier = Modifier.padding(vertical = YassirTheme.spacing.spacing1),
    enabled = true,
    checked = true,
    type = ToggleType.SmallSwitch,
    onToggle = {},
)

Tabs #

Tabs(
    modifier = Modifier, // optional
    selectedTabIndex = 0,
    tabsList = listOf(
      TabElement(
        isEnabled = true,
        text = "Tab Text",
        isBadgePresent = true,
        badgeText = "1",
        onClick = { /* action */ }
      ),
      TabElement(
        isEnabled = true,
        text = "Tab Text",
        isBadgePresent = false,
        onClick = { /* action */ }
      )
    ),
    type = TabType.Default(isScrollable = true),
    colors = YassirTheme.colors, // optional
    badgeStyleType = BadgeStyleType.Primary // optional
)

Tag #

  1. Neutral Tag
NeutralTag (
  modifier = Modifier, // optional
  text = text, // optional
  isAlternativeStyle = false, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  isElevated = true, // optional
  size = YassirTagSize.Small // optional
)
  1. Positive Tag
PositiveTag (
  modifier = Modifier, // optional
  text = text, // optional
  isAlternativeStyle = false, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  isElevated = true, // optional
  size = YassirTagSize.Medium // optional
)
  1. Negative Tag
NegativelTag (
  modifier = Modifier, // optional
  text = text, // optional
  isAlternativeStyle = false, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  isElevated = true, // optional
  size = YassirTagSize.Large // optional
)
  1. Warning Tag
WarningTag (
  modifier = Modifier, // optional
  text = text, // optional
  isAlternativeStyle = false, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  isElevated = true, // optional
  size = YassirTagSize.ExtraLarge // optional
)
  1. Informative Tag
InformativeTag (
  modifier = Modifier, // optional
  text = text, // optional
  isAlternativeStyle = false, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  isElevated = true, // optional
  size = YassirTagSize.Medium // optional
)
  1. Primary Tag
PrimaryTag (
  modifier = Modifier, // optional
  text = text, // optional
  isAlternativeStyle = false, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  isElevated = true, // optional
  size = YassirTagSize.Large // optional
)
  1. Secondary Tag
SecondaryTag (
  modifier = Modifier, // optional
  text = text, // optional
  isAlternativeStyle = false, // optional
  startIconResId = DrawableR.ic_alert_circle, // optional
  isElevated = true, // optional
  size = YassirTagSize.Small // optional
)

Time Picker #

TimePicker(
    timeFormat = TimeFormat.HOUR_24, // optional, default is TimeFormat.HOUR_24
    minutesIncrement = TimeMinutesIncrement.ONE, // optional, default is TimeMinutesIncrement.ONE
    startTime = Calendar.getInstance(), // optional, default is the current time
    minTime = Calendar.getInstance().apply { // optional, default is start of the day (00:00)
        set(Calendar.HOUR_OF_DAY, 0)
        set(Calendar.MINUTE, 0)
        set(Calendar.SECOND, 0)
        set(Calendar.MILLISECOND, 0)
    },
    maxTime = Calendar.getInstance().apply { // optional, default is end of the day (23:59:59.999)
        set(Calendar.HOUR_OF_DAY, 23)
        set(Calendar.MINUTE, 59)
        set(Calendar.SECOND, 59)
        set(Calendar.MILLISECOND, 999)
    },
    titleText = "Time", // optional, default is "Time"
    applyButtonText = "Apply", // optional, default is "Apply"
    cancelButtonText = "Cancel", // optional, default is "Cancel"
    onSnappedTime = { snappedTime, timeFormat -> /* Handle snapped time here */ }, // optional, default is an empty function
    onDismissRequest = { /* Handle dismiss request here */ }, // required, no default
    onChevronIconClick = { /* Handle chevron icon click here */ }, // optional, default is an empty function
    onApply = { selectedTime -> /* Handle apply action here */ }, // required, no default
    onCancel = { /* Handle cancel action here */ } // required, no default
)

For more details visit Time Picker documentation

Titled Section #

TitledSection(
    title = "title",
    modifier = Modifier, // optional
    subtitle = "subtitle", // optional
    caption = "caption", // optional
    description = "description", // optional
    horizontalAlignment = Alignment.Start, // optional
    variant = TitledSectionVariant.Level1, // optional
)

Tooltip #

Tooltip(
    text = "Tooltip text",
    supportingText = "Supporting text goes here.", // optional
    arrowDirection = ArrowDirection.Top, // optional
    dotColor = YassirTheme.colors.labelNeutralDefault, // optional
    invertedColors = false // optional
)

Top Bar #

  1. Top Bar with Textual Button Action and Title Content
TopBar(
    contentType = TopBarContentType.Title(
        title = "Title",
        subtitle = "Subtitle",
        ratingText = "4.5"
    ),
    actionType = TopBarActionType.Button(
        text = "Button",
        onClick = { /* action */ }
    ),
    showBackground = true, // optional
    leadingIconClick = { /* action */ } // optional
  )
  1. Top Bar With Actions Bar Action and Address Content
TopBar(
    contentType = TopBarContentType.Address(
        title = "Title",
        subtitle = "Subtitle",
    ),
    actionType = TopBarActionType.Actions(
        firstAction = TopBarAction(
            iconRes = DrawableR.ic_plus,
            onClick = { /* action */ }
        ),
        secondAction = TopBarAction(
            iconRes = DrawableR.ic_lock,
            onClick = { /* action */ }
        ),
        thirdAction = TopBarAction(
            iconRes = DrawableR.ic_coins_hand,
            onClick = { /* action */ }
        )
    ),
    showBackground = true, // optional
    leadingIconClick = { /* action */ } // optional
  )
  1. Top Bar with Avatar Action and Search Input Content
TopBar(
    contentType = TopBarContentType.Search(
        value = "",
        placeholder = "Search",
        onValueChange = { /* action */ },
    ),
    actionType = TopBarActionType.Avatar(
        imageUrl = "",
        onClick = {/* action */}
    ),
    showBackground = true, // optional
    leadingIconClick = { /* action */ } // optional
)
  1. Top Bar with Switch Action and Dropdown Input Content
TopBar(
    contentType = TopBarContentType.DropDown(
        label = "Button",
        onClick = { /* action */ }
    ),
    actionType = TopBarActionType.Switch(
        checked = true,
        enabled = true,
        title = "ON",
        onToggle = { /* action */  }
    ),
    showBackground = true, // optional
    leadingIconClick = { /* action */ } // optional
  )
  1. Top Bar with Slot Action and Title Content
TopBar(
    contentType = TopBarContentType.Title(
        title = "Title",
        subtitle = "Subtitle",
        ratingText = "4.5"
    ),
    actionType = TopBarActionType.Slot(
        slot = { TopBarSlot() }
    ),
    showBackground = true, // optional
    leadingIconClick = { /* action */ } // optional
  )