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,
  selectedItemIndex = 1, // optional
  onItemSelected = { }
)

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
)

Charts #

Line Chart #

  1. Categorical Line Chart
LineChart(
    xAxisValues = getSampleCategoricalXAxisValues(),
    yAxisValues = getSampleCategoricalYAxisValues(),
    datasets = getSampleCategoricalDatasets(),
    shouldShadeArea = true,
    modifier = Modifier.padding(YassirTheme.spacing.spacing1), //optional
    shouldRotateXAxisLabels = true, //optional
)

private fun getSampleCategoricalXAxisValues() = listOf("January", "February", "March", "April", "May", "June", "July").map { AxisValue.Categorical(it) }

private fun getSampleCategoricalYAxisValues() = listOf("V. Low", "Low", "Low M.", "Medium", "Medium H.", "High", "V. High").map { AxisValue.Categorical(it) }

private fun getSampleCategoricalDatasets(): List<Dataset> {
    val xCategories = listOf("January", "February", "March", "April", "May", "June", "July")

    val staticYValues = listOf(
        listOf("Low", "Medium", "High", "Medium H.", "Medium", "Low M.", "V. Low"),
        listOf("Medium", "Medium H.", "High", "V. High", "High", "Medium H.", "Medium"),
        listOf("V. Low", "Low", "Low M.", "Medium", "Medium H.", "High", "V. High"),
        listOf("High", "High", "Medium H.", "Medium", "Low M.", "Low", "V. Low"),
        listOf("Medium H.", "High", "V. High", "High", "Medium H.", "Medium", "Low M."),
        listOf("Low M.", "Medium", "Medium H.", "High", "V. High", "High", "Medium H."),
        listOf("V. HighF", "High", "Medium H.", "Medium", "Low M.F", "Low", "V. Low"),//V. HighF & Low M. are intentionally added to represent wrong data
        listOf("Low", "Low M.", "Medium", "Medium H.", "High", "V. High", "High")
    )

    return staticYValues.mapIndexed { index, yValues ->
        val points = xCategories.zip(yValues).map { (x, y) ->
            DataPoint(AxisValue.Categorical(x), AxisValue.Categorical(y))
        }
        val label = "Dataset ${index + 1}"
        Dataset(points = points, label = label)
    }
}
  1. Numerical Line Chart
LineChart(
    xAxisValues = getSampleNumericXAxisValues(),
    yAxisValues = getSampleNumericYAxisValues(),
    datasets = getSampleNumericDatasets(),
    shouldShadeArea = false,
    modifier = Modifier.padding(YassirTheme.spacing.spacing1), //optional
    shouldRotateXAxisLabels = false, //optional
)


private fun getSampleNumericXAxisValues() =
    (1..7).map { 
        x -> AxisValue.Numeric(
            value = x.toFloat(),
            showAsInteger = true) //optional
    }

private fun getSampleNumericYAxisValues() =
    (1..7).map { y -> 
        AxisValue.Numeric(
            value = (y * 10f), 
            suffix = "k",  //optional
            showAsInteger = true) //optional
    }

private fun getSampleNumericDatasets(): List<Dataset> {
    val staticYValues = listOf(
        listOf(10f, 2f, 30f, 40f, 50f, 60f, 78f),  //78 is intentionally added to represent data outside the grid
        listOf(12f, 28f, 20f, 33f, 35f, 44f, 51f),
        listOf(-25f, 2f, 5f, 43f, 55f, 57f, 65f),  //-25 is intentionally added to represent data outside the grid
        listOf(10f, 20f, 15f, 25f, 30f, 35f, 45f),
        listOf(30f, 45f, 35f, 50f, 40f, 55f, 65f),
        listOf(20f, 30f, 25f, 35f, 40f, 50f, 60f),
        listOf(25f, 35f, 30f, 40f, 45f, 55f, 65f),
        listOf(15f, 25f, 20f, 30f, 35f, 45f, 55f)
    )

    val xValues = (1..7).map { it.toFloat() }

    return staticYValues.mapIndexed { index, yValues ->
        val points = xValues.zip(yValues).map { (x, y) ->
            DataPoint(AxisValue.Numeric(x), AxisValue.Numeric(y))
        }
        val label = "Dataset ${index + 1}"
        Dataset(points = points, label = label)
    }
}

For more details visit Line Chart documentation

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
)

Date & Time Pickers #

Date Picker #

  1. Single Selection
val selectedDates = remember { mutableStateListOf<Date>() }

val datePickerProperties = DatePickerProperties(
    primaryAction = ButtonAction(
        text = "Primary Action",
        onClick = {
            Toast.makeText(context,"Primary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    secondaryAction = ButtonAction(
        text = "Secondary Action",
        onClick = {
            Toast.makeText(context,"Secondary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    startDayOfWeek = Weekday.SUNDAY,
    startDayOfWeekend = Weekday.FRIDAY,
    calendarStart = CalendarMonth(month = Calendar.FEBRUARY, year = 2023),
    calendarEnd = CalendarMonth(month = Calendar.NOVEMBER, year = 2035),
    selectCalendarMonth = CalendarMonth(month = Calendar.OCTOBER, year = 2024), // optional
    yearDialogTitle = ¨Year¨, // optional
    monthDialogTitle = ¨Month¨, // optional
)
DatePicker(
    modifier = Modifier,
    selectionMode = DateSelectionMode.Single(
        isScrollable = false, 
        isTodayMarked = true,
        timeSelectionProperties = TimePickerProperties() // optional if you want time picker to pop up as well after date selection
    ),
    properties = datePickerProperties,
    selectedDates = selectedDates, // optional
    updateDateSelection = {
        selectedDates.clear()
        selectedDates.addAll(it)
    },
    onDismissRequest = {}
)
  1. Single Selection - Scrollable
val selectedDates = remember { mutableStateListOf<Date>() }

val datePickerProperties = DatePickerProperties(
    primaryAction = ButtonAction(
        text = "Primary Action",
        onClick = {
            Toast.makeText(context,"Primary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    secondaryAction = ButtonAction(
        text = "Secondary Action",
        onClick = {
            Toast.makeText(context,"Secondary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    startDayOfWeek = Weekday.SUNDAY,
    startDayOfWeekend = Weekday.FRIDAY,
    calendarStart = CalendarMonth(month = Calendar.FEBRUARY, year = 2023),
    calendarEnd = CalendarMonth(month = Calendar.NOVEMBER, year = 2035),
    selectCalendarMonth = CalendarMonth(month = Calendar.OCTOBER, year = 2024), // optional
    yearDialogTitle = ¨Year¨, // optional
    monthDialogTitle = ¨Month¨, // optional
)
DatePicker(
    modifier = Modifier,
    selectionMode = DateSelectionMode.Single(
        isScrollable = true, 
        isTodayMarked = true,
        timeSelectionProperties = TimePickerProperties() // optional if you want time picker to pop up as well after date selection
    ),
    properties = datePickerProperties,
    selectedDates = selectedDates // optional,
    updateDateSelection = {
        selectedDates.clear()
        selectedDates.addAll(it)
    },
    onDismissRequest = {}
)
  1. Range Seclection
val selectedDates = remember { mutableStateListOf<Date>() }

val datePickerProperties = DatePickerProperties(
    primaryAction = ButtonAction(
        text = "Primary Action",
        onClick = {
            Toast.makeText(context,"Primary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    secondaryAction = ButtonAction(
        text = "Secondary Action",
        onClick = {
            Toast.makeText(context,"Secondary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    startDayOfWeek = Weekday.SUNDAY,
    startDayOfWeekend = Weekday.FRIDAY,
    calendarStart = CalendarMonth(month = Calendar.FEBRUARY, year = 2023),
    calendarEnd = CalendarMonth(month = Calendar.NOVEMBER, year = 2035),
    selectCalendarMonth = CalendarMonth(month = Calendar.OCTOBER, year = 2024), // optional
    yearDialogTitle = ¨Year¨, // optional
    monthDialogTitle = ¨Month¨, // optional
)
DatePicker(
    modifier = Modifier,
    selectionMode = DateSelectionMode.Range(isScrollable = false, isTodayMarked = false),
    properties = datePickerProperties,
    selectedDates = selectedDates, // optional
    updateDateSelection = {
        selectedDates.clear()
        selectedDates.addAll(it)
    },
    onDismissRequest = {}
)
  1. Range Seclection - Scrollable
val selectedDates = remember { mutableStateListOf<Date>() }

val datePickerProperties = DatePickerProperties(
    primaryAction = ButtonAction(
        text = "Primary Action",
        onClick = {
            Toast.makeText(context,"Primary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    secondaryAction = ButtonAction(
        text = "Secondary Action",
        onClick = {
            Toast.makeText(context,"Secondary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    startDayOfWeek = Weekday.SUNDAY,
    startDayOfWeekend = Weekday.FRIDAY,
    calendarStart = CalendarMonth(month = Calendar.FEBRUARY, year = 2023),
    calendarEnd = CalendarMonth(month = Calendar.NOVEMBER, year = 2035),
    selectCalendarMonth = CalendarMonth(month = Calendar.OCTOBER, year = 2024), // optional
    yearDialogTitle = ¨Year¨, // optional
    monthDialogTitle = ¨Month¨, // optional
)
DatePicker(
    modifier = Modifier,
    selectionMode = DateSelectionMode.Range(isScrollable = true, isTodayMarked = false),
    properties = datePickerProperties,
    selectedDates = selectedDates, // optional
    updateDateSelection = {
        selectedDates.clear()
        selectedDates.addAll(it)
    },
    onDismissRequest = {}
)
  1. Multiple Dates Seclection
val selectedDates = remember { mutableStateListOf<Date>() }

val datePickerProperties = DatePickerProperties(
    primaryAction = ButtonAction(
        text = "Primary Action",
        onClick = {
            Toast.makeText(context,"Primary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    secondaryAction = ButtonAction(
        text = "Secondary Action",
        onClick = {
            Toast.makeText(context,"Secondary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    startDayOfWeek = Weekday.SUNDAY,
    startDayOfWeekend = Weekday.FRIDAY,
    calendarStart = CalendarMonth(month = Calendar.FEBRUARY, year = 2023),
    calendarEnd = CalendarMonth(month = Calendar.NOVEMBER, year = 2035),
    selectCalendarMonth = CalendarMonth(month = Calendar.OCTOBER, year = 2024), // optional
    yearDialogTitle = ¨Year¨, // optional
    monthDialogTitle = ¨Month¨, // optional
)
DatePicker(
    modifier = Modifier,
    selectionMode = DateSelectionMode.Multiple(isTodayMarked = false, showSelectionChips = false),
    properties = datePickerProperties,
    selectedDates = selectedDates, // optional
    updateDateSelection = {
        selectedDates.clear()
        selectedDates.addAll(it)
    },
    onDismissRequest = {}
)
  1. Multiple Dates Seclection - With Selection Chips
val selectedDates = remember { mutableStateListOf<Date>() }

val datePickerProperties = DatePickerProperties(
    primaryAction = ButtonAction(
        text = "Primary Action",
        onClick = {
            Toast.makeText(context,"Primary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    secondaryAction = ButtonAction(
        text = "Secondary Action",
        onClick = {
            Toast.makeText(context,"Secondary Action Clicked",Toast.LENGTH_SHORT).show()
        }
    ),
    startDayOfWeek = Weekday.SUNDAY,
    startDayOfWeekend = Weekday.FRIDAY,
    calendarStart = CalendarMonth(month = Calendar.FEBRUARY, year = 2023),
    calendarEnd = CalendarMonth(month = Calendar.NOVEMBER, year = 2035),
    selectCalendarMonth = CalendarMonth(month = Calendar.OCTOBER, year = 2024), // optional
    yearDialogTitle = ¨Year¨, // optional
    monthDialogTitle = ¨Month¨, // optional
)
DatePicker(
    modifier = Modifier,
    selectionMode = DateSelectionMode.Multiple(isTodayMarked = true, showSelectionChips = true),
    properties = datePickerProperties,
    selectedDates = selectedDates, // optional
    updateDateSelection = {
        selectedDates.clear()
        selectedDates.addAll(it)
    },
    onDismissRequest = {}
)

Month Picker #

MonthPicker(
    modifier = Modifier, // optional
    startMonth = 4, // optional
    endMonth = 11,
    onDismissRequest = { },
    selectedMonth = 10, // optional
    onMonthSelected = { }
)

For more details visit Month Picker documentation

Time Picker #

TimePicker(
    timePickerProperties = TimePickerProperties(
        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
        onChevronIconClick = { /* Handle chevron icon click here */ }, // optional, default is an empty function
    ),
    onDismissRequest = { /* Handle dismiss request here */ }, // required, no default
    onApply = { selectedTime -> /* Handle apply action here */ }, // required, no default
    onCancel = { /* Handle cancel action here */ } // required, no default
)

For more details visit Time Picker documentation

Year Picker #

YearPicker(
    modifier = Modifier,// optional
    startYear = 2000, // optional
    endYear = 2066,
    onDismissRequest = { },
    selectedYear = 2024, // optional
    onYearSelected = { }
)

For more details visit Year Picker documentation

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
)

Image PlaceHolder #

  1. Portrait
    Box {
    ImagePlaceholder(
        aspectRatio = AspectRatio.Square,
        orientation = Orientation.Portrait,
        resId = R.drawable.ic_avatar, // optional
        url = null,  // optional,
        contentDescription = null // optional
    )
}
  1. Landscape
    Box {
    ImagePlaceholder(
        aspectRatio = AspectRatio.Landscape,
        orientation = Orientation.Portrait,
        resId = R.drawable.ic_avatar, // optional
        url = null,  // optional,
        contentDescription = null // 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.PinCode,
  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.OtpCode(
    initialCode = "456757" //optional
  ),
  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 an supported countries list and supported initial 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
  initialSelectedCountryRegionCode: String = SupportedCountry.Algeria.regionCode // optional
  countriesBackDropList: CountryCodeListType = CountryCodeListType.SupportedCounties // optional
  countryBackdropTitle: String = "", // optional
  backdropHintText: Int? = R.string.country_backdrop_hint, // optional
  searchBackdropPlaceholder: String? = null,
  onHintClick = { /* action */ } // optional,
  onImeAction = { /* action */ } // optional,
)
  1. with an Mixed countries list and unsupported initial country
val countryGermany = SimpleCountry(regionCode = "DE", countryName = "Germany")

val listOfCountries =  listOf(
    SupportedCountry.Algeria,
    SupportedCountry.Egypt,
    countryGermany
)

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
  initialSelectedCountryRegionCode: String = countryGermany.regionCode // optional
  countriesBackDropList: CountryCodeListType = CountryCodeListType.MixedCountries(listOfCountries) // optional
  countryBackdropTitle: String = "", // optional
  backdropHintText: Int? = R.string.country_backdrop_hint, // optional
  searchBackdropPlaceholder: String? = null,
  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
MapPin(
    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
        painter = painterResource(id = R.drawable.ic_user) // 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
val modalType = ModalType.EmptyState(
        illustrationResIds = listOf(
          IllustrationInfo(
            resId = DrawableR.system_verified,
            message = "Title",
            description = "This Is description"
          ),
        ),
        isSecondaryButtonNegative = false, // optional - add as true for a negative or destructive secondary button
    )
    
Modal(
    modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
    modalType = modalType,
    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
val modalType = ModalType.Slot(
        slot =  /* @Composable  */,
        isSecondaryButtonNegative = false, // optional - add as true for a negative or destructive secondary button
    )

Modal(
    modifier = Modifier.padding(YassirTheme.spacing.spacing3), // optional
    modalType = modalType,
    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 #

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)
            )
        }
    }
}

VerticalScrollbar #

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

LazyListScrollbar - Horizontal #

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

LazyListScrollbar - Vertical #

@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)
            )
        }
    }
}

Shadow - 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
        )
) {}

Test Prefix #

Use the modifier extension method kotlin withTextPrefix to add your unique identifier prefix to the test tag of the component itself and all its subcomponents

Price(
    modifier = Modifier.withTestPrefix("checkout_screen") // optional
    regularPriceText = "6000 DZD",
    discountPriceText = "7000 DZD", // optional
    priceLayoutDirection = PriceLayoutDirection.Vertical, // optional
    priceSize = PriceSize.Large // optional
)

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
)
  1. Positive ProgressBar
ProgressBar(
    progress = 25f,
    label = "25%",//optional
    style = ProgressBarStyle.Positive,//optional
    type = ProgressBarType.Linear,//optional
    size = ProgressBarSize.Large,//optional
)
  1. Negative ProgressBar
ProgressBar(
    progress = 25f,
    label = "25%",//optional
    style = ProgressBarStyle.Negative,//optional
    type = ProgressBarType.Linear,//optional
    size = ProgressBarSize.Large,//optional
)
  1. Dynamic ProgressBar
ProgressBar(
    progress = 25f,
    label = "25%",//optional
    style = ProgressBarStyle.Dynamic,//optional
    type = ProgressBarType.Linear,//optional
    size = ProgressBarSize.Large,//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
)

Steppers #

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

Progress Stepper #

ProgressStepper(
    modifier = Modifier,
    numberOfCompletedSteps = 3,
    totalSteps = 5,
    stepSize = ProgressStepperSize.Medium,
    showCompletedLabel = true,
)

For more details visit Progress 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
)

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
  )