From 0c804a8dc44347c0558b564aa151072e3408b123 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Lapersonne Date: Tue, 14 Jul 2026 11:30:43 +0200 Subject: [PATCH 1/9] feat: add agentic AI skills (#1388) Vibe-coded generations of skills and references files to allow users to embed and use OUDS Android library. Closes #1388 Suggested-by: Slim Namouchi Suggested-by: Thierry Tassaint Assisted-by: Claude Sonnet 4.6 (OpenCode, LLMProxy) Reviewed-by: Pierre-Yves Lapersonne Signed-off-by: Pierre-Yves Lapersonne --- .agents | 1 + .claude | 1 + .opencode | 1 + AGENTS.md | 23 + skills/ouds-android-framework-usage/SKILL.md | 240 ++++++ .../references/components.md | 721 ++++++++++++++++++ skills/ouds-android-vocabulary/SKILL.md | 65 ++ 7 files changed, 1052 insertions(+) create mode 120000 .agents create mode 120000 .claude create mode 120000 .opencode create mode 100644 skills/ouds-android-framework-usage/SKILL.md create mode 100644 skills/ouds-android-framework-usage/references/components.md create mode 100644 skills/ouds-android-vocabulary/SKILL.md diff --git a/.agents b/.agents new file mode 120000 index 0000000000..5a74acc44d --- /dev/null +++ b/.agents @@ -0,0 +1 @@ +skills \ No newline at end of file diff --git a/.claude b/.claude new file mode 120000 index 0000000000..5a74acc44d --- /dev/null +++ b/.claude @@ -0,0 +1 @@ +skills \ No newline at end of file diff --git a/.opencode b/.opencode new file mode 120000 index 0000000000..5a74acc44d --- /dev/null +++ b/.opencode @@ -0,0 +1 @@ +skills \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 8b175a2874..eac73e0050 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -206,6 +206,29 @@ Always consider that changes affect multiple brands. Test components with: See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed contribution guidelines. +## AI Skills + +Agent skills are located in the `skills/` directory at the repository root. The `.agents/`, `.claude/`, and `.opencode/` directories are symlinks to `skills/`, ensuring compatibility across all major AI agent tools. + +### Available skills + +| Skill | When to load | +|---|---| +| `ouds-android-vocabulary` | User asks about OUDS-specific terms: tokenator, raw token, semantic token, component token, theme, OudsThemeContract, OudsColoredBox, tinted, OudsError, etc. | +| `ouds-android-framework-usage` | User needs to write or review Kotlin/Compose code using OUDS components, configure the theme, access tokens, or set up Gradle dependencies | + +### Skill structure + +``` +skills/ +├── ouds-android-vocabulary/ +│ └── SKILL.md ← vocabulary definitions and token hierarchy +└── ouds-android-framework-usage/ + ├── SKILL.md ← setup, themes, token access, common patterns, checklist + └── references/ + └── components.md ← full component signatures and usage examples +``` + ## Resources - **Documentation**: https://android.unified-design-system.orange.com/ diff --git a/skills/ouds-android-framework-usage/SKILL.md b/skills/ouds-android-framework-usage/SKILL.md new file mode 100644 index 0000000000..b4503d456f --- /dev/null +++ b/skills/ouds-android-framework-usage/SKILL.md @@ -0,0 +1,240 @@ +--- +name: ouds-android-framework-usage +description: How to set up and use the OUDS Android library with Gradle dependencies, OudsTheme setup, token access, and components with Kotlin/Compose code examples +license: MIT +--- + +# OUDS Android Framework Usage + +## 1. Gradle setup + +Add the OUDS dependencies to your module's `build.gradle.kts`. Choose the theme modules you need: + +```kotlin +dependencies { + // Core components — always required + implementation("com.orange.ouds.android:core:") + + // Choose one or more theme modules: + implementation("com.orange.ouds.android:theme-orange:") // Orange brand + implementation("com.orange.ouds.android:theme-orange-compact:") // Orange Compact variant + implementation("com.orange.ouds.android:theme-sosh:") // Sosh brand + implementation("com.orange.ouds.android:theme-wireframe:") // Wireframe (dev/prototyping) +} +``` + +Latest version available on Maven Central under group `com.orange.ouds.android`. + +--- + +## 2. OudsTheme setup + +Wrap your root composable with `OudsTheme`, passing a theme object: + +```kotlin +import com.orange.ouds.core.theme.OudsTheme +import com.orange.ouds.theme.orange.OrangeTheme +import com.orange.ouds.theme.orange.OrangeFontFamily +import com.orange.ouds.theme.orange.OrangeHelveticaNeueLatin + +@Composable +fun App() { + OudsTheme( + theme = OrangeTheme( + orangeFontFamily = OrangeFontFamily( + latin = OrangeHelveticaNeueLatin.Bundled( + R.font.helvetica_neue_latin_roman, + R.font.helvetica_neue_latin_medium, + R.font.helvetica_neue_latin_bold + ) + ) + ) + ) { + // Your app UI here + } +} +``` + +### Available themes + +| Theme class | Brand | Notes | +|---|---|---| +| `OrangeTheme` | Orange | Requires Helvetica Neue font (bundled or downloadable) | +| `OrangeCompactTheme` | Orange Compact | Compact size variant of Orange | +| `SoshTheme` | Sosh | — | +| `WireframeTheme` | Wireframe | For development and prototyping only | + +### OrangeTheme — font options + +**Bundled font** (copy `.ttf` files to `res/font/`): +```kotlin +OrangeTheme( + orangeFontFamily = OrangeFontFamily( + latin = OrangeHelveticaNeueLatin.Bundled( + R.font.helvetica_neue_latin_roman, + R.font.helvetica_neue_latin_medium, + R.font.helvetica_neue_latin_bold + ) + ) +) +``` + +**Downloadable font** (via Android Downloadable Fonts — requires `INTERNET` permission and a `` in the manifest): +```kotlin +OrangeTheme( + orangeFontFamily = OrangeFontFamily( + latin = OrangeHelveticaNeueLatin.Downloadable + ) +) +// Call once at startup: +OrangeFontFamily.preloadDownloadableFontFamilies(context, listOf(OrangeHelveticaNeueLatin.Downloadable)) { + // Update UI state when ready +} +``` + +### OrangeTheme — optional rounded corner settings + +```kotlin +OrangeTheme( + orangeFontFamily = ..., + roundedCornerButtons = true, + roundedCornerTextInputs = true, + roundedCornerAlertMessages = true, + roundedCornerProgressIndicators = true +) +``` + +--- + +## 3. Accessing tokens inside composables + +Tokens are accessed via the `OudsTheme` static object inside any composable wrapped by `OudsTheme { }`: + +```kotlin +import com.orange.ouds.core.theme.OudsTheme + +@Composable +fun MyView() { + Box( + modifier = Modifier + .background(OudsTheme.colorScheme.background.primary) + .padding(OudsTheme.spaces.fixed.medium) + ) { + Text( + text = stringResource(R.string.my_text), + color = OudsTheme.colorScheme.content.default, + style = OudsTheme.fonts.bodyDefaultMedium + ) + } +} +``` + +### Token namespaces + +| Accessor | Content | +|---|---| +| `OudsTheme.colorScheme` | Color tokens (`.content.*`, `.background.*`, `.border.*`, `.action.*`, `.surface.*`, `.overlay.*`) | +| `OudsTheme.borders` | Border radius (`.radius.*`), style (`.style.*`), width (`.width.*`) | +| `OudsTheme.spaces` | Spacing tokens (`.fixed.*`, `.scaled.*`) | +| `OudsTheme.sizes` | Size tokens | +| `OudsTheme.fonts` | Typography / font tokens | +| `OudsTheme.elevations` | Elevation / shadow tokens | +| `OudsTheme.grids` | Grid tokens | +| `OudsTheme.opacities` | Opacity tokens | +| `OudsTheme.effects` | Visual effect tokens | +| `OudsTheme.componentsTokens.*` | Per-component tokens (`.button`, `.tag`, `.textInput`, etc.) | + +--- + +## 4. OudsColoredBox — colored surfaces + +`OudsColoredBox` creates a semantically colored surface. All OUDS child components inside automatically switch to their **monochrome** variant for maximum contrast: + +```kotlin +OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { + // OudsButton inside uses monochrome colors automatically + OudsButton(label = stringResource(R.string.action), onClick = { }) + Text( + text = stringResource(R.string.description), + color = OudsTheme.colorScheme.content.default // automatically inverted + ) +} +``` + +--- + +## 5. Common patterns + +### Tinted vs. untinted icons + +By default, icons passed to OUDS components are **tinted** (color driven by tokens). Pass `tinted = false` to preserve the painter's own colors (brand/multi-color icons): + +```kotlin +// Tinted icon (default) +OudsButtonIcon(imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Favorite") + +// Untinted icon — painter colors preserved +OudsButtonIcon(painter = myMultiColorPainter, contentDescription = "Brand", tinted = false) +``` + +The same `tinted` flag is available on `OudsControlItemIcon`, `OudsLinkIcon`, `OudsTagAsset.Icon`, `OudsAlertIcon`, `OudsBadgeIcon`, etc. + +### Error and helper text + +Input components accept both plain strings and rich `AnnotatedString` for error and helper text: + +```kotlin +// Plain error +error = OudsError(message = "This field cannot be empty.") + +// Rich annotated error +error = OudsError( + annotatedMessage = buildOudsAnnotatedErrorMessage { + append("This field ") + withStrong { append("cannot") } + append(" be empty.") + } +) + +// Plain helper text +helperText = "Minimum 8 characters." + +// Rich annotated helper text +helperText = buildOudsAnnotatedHelperText { + append("Password must be ") + withStrong { append("at least 8 characters") } + append(" long.") +} +``` + +### Hardcoded strings — forbidden + +Never use hardcoded strings in OUDS components or any composable: + +```kotlin +// Wrong +OudsButton(label = "Submit", onClick = { }) + +// Correct +OudsButton(label = stringResource(R.string.submit), onClick = { }) +``` + +--- + +## 6. Checklist before writing components + +- `OudsTheme { }` wraps the UI at the root +- All user-visible strings use `stringResource(R.string.*)` +- Icons that should preserve their original colors have `tinted = false` +- Content descriptions are provided for all icon-only elements +- Components inside `OudsColoredBox` do **not** need manual color adjustment +- `OudsButtonAppearance.Negative` must **not** be used inside `OudsColoredBox` +- A disabled component must **not** have a loader simultaneously + +--- + +## 7. Components reference + +See [`references/components.md`](references/components.md) for the full list of components with signatures and usage examples. + +**Index:** [Button](#button) · [SmallButton](#smallbutton) · [Tag](#tag) · [Badge](#badge) · [AlertMessage](#alertmessage) · [InlineAlert](#inlinealert) · [BulletList](#bulletlist) · [CheckboxItem](#checkboxitem) · [RadioButtonItem](#radiobuttonitem) · [SwitchItem](#switchitem) · [TextInput](#textinput) · [TextArea](#textarea) · [PasswordInput](#passwordinput) · [PinCodeInput](#pincodeinput) · [FilterChip / SuggestionChip](#filterchip--suggestionchip) · [Link](#link) · [Divider](#divider) · [NavigationBar](#navigationbar) · [TopAppBar](#topappbar) · [ColoredBox](#coloredbox) diff --git a/skills/ouds-android-framework-usage/references/components.md b/skills/ouds-android-framework-usage/references/components.md new file mode 100644 index 0000000000..23b6b04559 --- /dev/null +++ b/skills/ouds-android-framework-usage/references/components.md @@ -0,0 +1,721 @@ +# OUDS Android — Components Reference + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +--- + +## Button + +**Layouts:** text only · icon only · text + icon +**Sizes:** default (`OudsButton`) · small (`OudsSmallButton`) +**Appearances:** `OudsButtonAppearance` — `Default`, `Strong`, `Brand`, `Minimal`, `Negative` +**Note:** `Negative` appearance is forbidden inside `OudsColoredBox`. +Inside `OudsColoredBox`, the button automatically adopts its monochrome variant. + +```kotlin +// Text only +OudsButton( + label = stringResource(R.string.action), + onClick = { } +) + +// Icon only — contentDescription required +OudsButton( + icon = OudsButtonIcon( + imageVector = Icons.Filled.FavoriteBorder, + contentDescription = stringResource(R.string.favorite_desc) + ), + onClick = { } +) + +// Text + icon +OudsButton( + icon = OudsButtonIcon(imageVector = Icons.Filled.FavoriteBorder, contentDescription = ""), + label = stringResource(R.string.action), + onClick = { } +) + +// Untinted icon (multi-color / brand icon) +OudsButton( + icon = OudsButtonIcon(painter = myPainter, contentDescription = "", tinted = false), + onClick = { } +) + +// With loading state +OudsButton( + label = stringResource(R.string.action), + loader = OudsButtonLoader(progress = null), // indeterminate + onClick = { } +) + +// On colored background — colors adjusted automatically +OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { + OudsButton(label = stringResource(R.string.action), onClick = { }) +} +``` + +--- + +## SmallButton + +Same API as `OudsButton` but uses the small size variant. + +```kotlin +OudsSmallButton(label = stringResource(R.string.action), onClick = { }) + +OudsSmallButton( + icon = OudsButtonIcon(imageVector = Icons.Filled.FavoriteBorder, contentDescription = ""), + label = stringResource(R.string.action), + onClick = { } +) +``` + +--- + +## Tag + +**Statuses:** `OudsTagStatus` — `Neutral`, `Accent`, `Positive`, `Warning`, `Negative`, `Info` +**Assets:** `OudsTagAsset.Bullet` · `OudsTagAsset.Icon(…)` · `OudsTagAsset.Icon.Default` (functional icon per status) +**Appearances:** `OudsTagAppearance` — `Emphasized` (default), `Muted` +**Sizes:** `OudsTagSize` — `Default`, `Small` + +```kotlin +// Text only +OudsTag(label = stringResource(R.string.label)) + +// With bullet +OudsTag( + label = stringResource(R.string.label), + status = OudsTagStatus.Positive(asset = OudsTagAsset.Bullet) +) + +// With default functional icon (icon per status) +OudsTag( + label = stringResource(R.string.label), + status = OudsTagStatus.Positive(asset = OudsTagAsset.Icon.Default) +) + +// With custom icon (Neutral or Accent only) +OudsTag( + label = stringResource(R.string.label), + status = OudsTagStatus.Neutral(asset = OudsTagAsset.Icon(imageVector = Icons.Filled.FavoriteBorder)) +) + +// With untinted icon +OudsTag( + label = stringResource(R.string.label), + status = OudsTagStatus.Neutral(asset = OudsTagAsset.Icon(painter = myPainter, tinted = false)) +) + +// Small size +OudsTag(label = stringResource(R.string.label), size = OudsTagSize.Small) + +// With loader (indeterminate) +OudsTag(label = stringResource(R.string.label), loader = OudsTagLoader(progress = null)) +``` + +--- + +## Badge + +**Statuses (plain/count):** `OudsBadgeStatus` — `Neutral`, `Accent`, `Positive`, `Warning`, `Negative`, `Info` +**Statuses (icon):** `OudsIconBadgeStatus` — `Neutral(icon?)`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` +**Sizes:** `OudsBadgeSize` — `ExtraSmall`, `Small`, `Medium`, `Large` +**Note:** Always provide a `contentDescription` via `Modifier.semantics { contentDescription = "…" }`. + +```kotlin +// Standard dot badge +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.info_desc) }, + status = OudsBadgeStatus.Info, + size = OudsBadgeSize.Small +) + +// Badge with count +val count = 10 +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.unread_count, count) }, + status = OudsBadgeStatus.Accent, + count = count +) + +// Badge with default functional icon +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.info_desc) }, + status = OudsIconBadgeStatus.Info, + size = OudsBadgeSize.Large +) + +// Badge with custom icon +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.favorite_desc) }, + status = OudsIconBadgeStatus.Accent(OudsBadgeIcon(imageVector = Icons.Filled.FavoriteBorder)), + size = OudsBadgeSize.Large +) + +// Badge with untinted custom icon +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.brand_desc) }, + status = OudsIconBadgeStatus.Neutral(OudsBadgeIcon(painter = myPainter, tinted = false)), + size = OudsBadgeSize.Large +) + +// Typical use: badged navigation item +BadgedBox( + badge = { + OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.unread_count, 8) }, + count = 8, + status = OudsBadgeStatus.Accent + ) + } +) { + Icon(imageVector = Icons.Filled.Notifications, contentDescription = null) +} +``` + +--- + +## AlertMessage + +**Statuses:** `OudsAlertMessageStatus` — `Neutral`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` +**Action link positions:** `OudsAlertMessageActionLinkPosition` — `Bottom` (default), `TopEnd` + +```kotlin +// Minimal +OudsAlertMessage(label = stringResource(R.string.title)) + +// With functional status (no icon param) +OudsAlertMessage( + label = stringResource(R.string.title), + description = stringResource(R.string.description), + status = OudsAlertMessageStatus.Positive, + onClose = { /* dismiss */ } +) + +// With non-functional status and custom icon +OudsAlertMessage( + label = stringResource(R.string.title), + description = stringResource(R.string.description), + status = OudsAlertMessageStatus.Accent(OudsAlertIcon(imageVector = Icons.Filled.FavoriteBorder)), + onClose = { /* dismiss */ }, + actionLink = OudsAlertMessageActionLink( + label = stringResource(R.string.learn_more), + onClick = { /* navigate */ } + ), + bulletList = listOf( + stringResource(R.string.point_1), + stringResource(R.string.point_2) + ) +) + +// With untinted icon +OudsAlertMessage( + label = stringResource(R.string.title), + status = OudsAlertMessageStatus.Accent(OudsAlertIcon(painter = myPainter, tinted = false)), + onClose = { } +) + +// Action link at top end +OudsAlertMessage( + label = stringResource(R.string.title), + status = OudsAlertMessageStatus.Positive, + onClose = { }, + actionLink = OudsAlertMessageActionLink( + label = stringResource(R.string.details), + onClick = { }, + position = OudsAlertMessageActionLinkPosition.TopEnd + ) +) +``` + +--- + +## InlineAlert + +**Statuses:** `OudsInlineAlertStatus` — `Neutral`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` +Functional statuses (`Positive`, `Warning`, `Negative`, `Info`) display a default icon automatically; no icon param. + +```kotlin +// Functional status — icon automatic +OudsInlineAlert( + label = stringResource(R.string.label), + status = OudsInlineAlertStatus.Positive +) + +// Non-functional with default icon +OudsInlineAlert( + label = stringResource(R.string.label), + status = OudsInlineAlertStatus.Accent(OudsAlertIcon.Default) +) + +// Non-functional with custom icon +OudsInlineAlert( + label = stringResource(R.string.label), + status = OudsInlineAlertStatus.Accent(OudsAlertIcon(imageVector = Icons.Filled.FavoriteBorder)) +) + +// Non-functional with untinted icon +OudsInlineAlert( + label = stringResource(R.string.label), + status = OudsInlineAlertStatus.Accent(OudsAlertIcon(painter = myPainter, tinted = false)) +) +``` + +--- + +## BulletList + +**Types:** `OudsBulletListType` — `Unordered` (default, `brandColor: Boolean`), `Ordered`, `Bare` + +```kotlin +// Unordered (brand color) +OudsBulletList { + item(label = stringResource(R.string.item_1)) + item(label = stringResource(R.string.item_2), subListType = OudsBulletListType.Unordered(brandColor = false)) { + item(label = stringResource(R.string.sub_item_1)) + } +} + +// Ordered +OudsBulletList(type = OudsBulletListType.Ordered) { + item(label = stringResource(R.string.step_1)) + item(label = stringResource(R.string.step_2)) { + item(label = stringResource(R.string.sub_step_1)) + } +} + +// Bare (no bullet) +OudsBulletList(type = OudsBulletListType.Bare) { + item(label = stringResource(R.string.item_1)) +} +``` + +--- + +## CheckboxItem + +Signature: `OudsCheckboxItem(checked, label, onCheckedChange, modifier, description?, icon?, divider?, enabled?, error?)` +Tri-state variant: `OudsTriStateCheckboxItem(state: ToggleableState, label, onClick, …)` + +```kotlin +// Basic +var checked by remember { mutableStateOf(false) } +OudsCheckboxItem( + checked = checked, + label = stringResource(R.string.terms), + onCheckedChange = { checked = it } +) + +// With description and icon +OudsCheckboxItem( + checked = checked, + label = stringResource(R.string.terms), + description = stringResource(R.string.terms_desc), + icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + onCheckedChange = { checked = it } +) + +// With untinted icon +OudsCheckboxItem( + checked = checked, + label = stringResource(R.string.terms), + icon = OudsControlItemIcon(painter = myPainter, tinted = false), + onCheckedChange = { checked = it } +) + +// With error +OudsCheckboxItem( + checked = checked, + label = stringResource(R.string.terms), + onCheckedChange = { checked = it }, + error = OudsError(message = stringResource(R.string.error_required)) +) + +// Tri-state +var state by remember { mutableStateOf(ToggleableState.Off) } +OudsTriStateCheckboxItem( + state = state, + label = stringResource(R.string.select_all), + onClick = { + state = when (state) { + ToggleableState.On -> ToggleableState.Off + ToggleableState.Off -> ToggleableState.Indeterminate + ToggleableState.Indeterminate -> ToggleableState.On + } + } +) +``` + +--- + +## RadioButtonItem + +Signature: `OudsRadioButtonItem(selected, label, onClick, modifier, description?, icon?, divider?, enabled?, error?)` +**Always** wrap a group of radio items in `Modifier.selectableGroup()`. + +```kotlin +val options = listOf( + stringResource(R.string.option_a), + stringResource(R.string.option_b) +) +var selected by rememberSaveable { mutableStateOf(options.first()) } + +Column(modifier = Modifier.selectableGroup()) { + options.forEach { option -> + OudsRadioButtonItem( + selected = option == selected, + label = option, + onClick = { selected = option }, + divider = true + ) + } +} + +// With icon +OudsRadioButtonItem( + selected = selected == option, + label = option, + icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + onClick = { selected = option } +) + +// With error (typically on the last item) +OudsRadioButtonItem( + selected = selected == option, + label = option, + onClick = { selected = option }, + error = OudsError(message = stringResource(R.string.selection_required)) +) +``` + +--- + +## SwitchItem + +Signature: `OudsSwitchItem(checked, label, onCheckedChange, modifier, description?, icon?, divider?, enabled?, error?)` + +```kotlin +var checked by remember { mutableStateOf(true) } + +OudsSwitchItem( + checked = checked, + label = stringResource(R.string.notifications), + description = stringResource(R.string.notifications_desc), + icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + onCheckedChange = { checked = it } +) + +// With untinted icon +OudsSwitchItem( + checked = checked, + label = stringResource(R.string.notifications), + icon = OudsControlItemIcon(painter = myPainter, tinted = false), + onCheckedChange = { checked = it } +) + +// With error +OudsSwitchItem( + checked = checked, + label = stringResource(R.string.notifications), + onCheckedChange = { checked = it }, + error = OudsError(message = stringResource(R.string.notifications_required)) +) +``` + +--- + +## TextInput + +Two API variants: **state-based** (`textFieldState`) and **value-based** (`value` + `onValueChange`). +Prefer the state-based API for new code. + +```kotlin +// State-based — basic +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.label) +) + +// State-based — full featured +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.label), + placeholder = stringResource(R.string.placeholder), + leadingIcon = OudsTextInputLeadingIcon(imageVector = Icons.Filled.Search, contentDescription = ""), + prefix = stringResource(R.string.prefix), + suffix = stringResource(R.string.suffix), + helperText = stringResource(R.string.helper), + helperLink = OudsTextInputHelperLink(text = stringResource(R.string.more), onClick = { }) +) + +// With trailing action button +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.date), + trailingIconButton = OudsTextInputTrailingIconButton( + imageVector = Icons.Filled.DateRange, + contentDescription = stringResource(R.string.open_calendar), + onClick = { } + ), + outlined = true +) + +// With error +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.label), + error = OudsError(message = stringResource(R.string.field_required)) +) + +// Value-based +var value by remember { mutableStateOf("") } +OudsTextInput( + value = value, + onValueChange = { value = it }, + label = stringResource(R.string.label) +) + +// Untinted leading icon +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.label), + leadingIcon = OudsTextInputLeadingIcon(painter = myPainter, contentDescription = "", tinted = false) +) +``` + +--- + +## TextArea + +Same two API variants as `TextInput` (state-based / value-based). + +```kotlin +// State-based +OudsTextArea( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.feedback), + placeholder = stringResource(R.string.feedback_placeholder), + helperText = stringResource(R.string.feedback_helper) +) + +// With error +OudsTextArea( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.comment), + outlined = true, + error = OudsError(message = stringResource(R.string.min_chars_error)) +) + +// Value-based +var value by remember { mutableStateOf("") } +OudsTextArea( + value = value, + onValueChange = { value = it }, + label = stringResource(R.string.description) +) +``` + +--- + +## PasswordInput + +Uses `OudsPasswordInputState` to manage visibility toggle. Create the state with `rememberOudsPasswordInputState()`. + +```kotlin +OudsPasswordInput( + state = rememberOudsPasswordInputState(), + label = stringResource(R.string.password), + lockIcon = true, + helperText = stringResource(R.string.password_helper) +) + +// With error +OudsPasswordInput( + state = rememberOudsPasswordInputState(), + label = stringResource(R.string.password), + error = OudsError(message = stringResource(R.string.password_error)) +) +``` + +--- + +## PinCodeInput + +**Lengths:** `OudsPinCodeInputLength` — `Four`, `Six` + +```kotlin +var value by remember { mutableStateOf("") } + +OudsPinCodeInput( + value = value, + onValueChange = { value = it }, + length = OudsPinCodeInputLength.Four, + helperText = stringResource(R.string.pin_helper) +) + +// With error +OudsPinCodeInput( + value = value, + onValueChange = { value = it }, + length = OudsPinCodeInputLength.Four, + error = OudsError(message = stringResource(R.string.pin_error)) +) +``` + +--- + +## FilterChip / SuggestionChip + +```kotlin +// Filter chip — text +OudsFilterChip(text = stringResource(R.string.label), onClick = { }) + +// Filter chip — with icon +OudsFilterChip( + icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), + text = stringResource(R.string.label), + onClick = { } +) + +// Filter chip — icon only +OudsFilterChip( + icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), + contentDescription = stringResource(R.string.label_desc), + onClick = { } +) + +// Suggestion chip +OudsSuggestionChip(text = stringResource(R.string.label), onClick = { }) + +// Suggestion chip — with icon +OudsSuggestionChip( + icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), + text = stringResource(R.string.label), + onClick = { } +) +``` + +--- + +## Link + +**Chevrons:** `OudsLinkChevron` — `Next`, `Back` + +```kotlin +// Text only +OudsLink( + label = stringResource(R.string.link_label), + onClick = { } +) + +// With icon +OudsLink( + label = stringResource(R.string.link_label), + icon = OudsLinkIcon(imageVector = Icons.Filled.FavoriteBorder), + onClick = { } +) + +// With chevron +OudsLink( + label = stringResource(R.string.link_label), + chevron = OudsLinkChevron.Next, + onClick = { } +) + +// With untinted icon +OudsLink( + label = stringResource(R.string.link_label), + icon = OudsLinkIcon(painter = myPainter, tinted = false), + onClick = { } +) +``` + +--- + +## Divider + +```kotlin +// Horizontal +OudsHorizontalDivider(modifier = Modifier.fillMaxWidth()) + +// Vertical +OudsVerticalDivider(modifier = Modifier.height(50.dp)) +``` + +--- + +## NavigationBar + +```kotlin +var selectedIndex by rememberSaveable { mutableIntStateOf(0) } + +OudsNavigationBar( + items = listOf( + OudsNavigationBarItem( + selected = selectedIndex == 0, + onClick = { selectedIndex = 0 }, + icon = OudsNavigationBarItemIcon(imageVector = Icons.Default.Home), + label = stringResource(R.string.home) + ), + OudsNavigationBarItem( + selected = selectedIndex == 1, + onClick = { selectedIndex = 1 }, + icon = OudsNavigationBarItemIcon(imageVector = Icons.Default.Email), + label = stringResource(R.string.messages), + badge = OudsNavigationBarItemBadge( + contentDescription = stringResource(R.string.unread_count, 5), + count = 5 + ) + ) + ) +) +``` + +--- + +## TopAppBar + +Four variants: `OudsTopAppBar`, `OudsCenterAlignedTopAppBar`, `OudsMediumTopAppBar`, `OudsLargeTopAppBar`. +**Navigation icons:** `OudsTopAppBarNavigationIcon.Back { }` · `OudsTopAppBarNavigationIcon.Menu { }` +**Actions:** `OudsTopAppBarAction.Icon(…)` · `OudsTopAppBarAction.Avatar(…)` + +```kotlin +@OptIn(ExperimentalMaterial3Api::class) +OudsTopAppBar( + title = stringResource(R.string.screen_title), + navigationIcon = OudsTopAppBarNavigationIcon.Back { /* navigate back */ }, + actions = listOf( + OudsTopAppBarAction.Icon( + imageVector = Icons.Outlined.Settings, + contentDescription = stringResource(R.string.settings_desc) + ) { /* open settings */ } + ) +) + +// Large top app bar +@OptIn(ExperimentalMaterial3Api::class) +OudsLargeTopAppBar( + title = stringResource(R.string.screen_title), + navigationIcon = OudsTopAppBarNavigationIcon.Back { } +) +``` + +--- + +## ColoredBox + +Creates a colored surface where child OUDS components automatically switch to their monochrome variant. +**Colors:** `OudsColoredBoxColor` — `BrandPrimary`, `StatusNeutralEmphasized`, `StatusAccentEmphasized`, `StatusPositiveEmphasized`, `StatusInfoEmphasized`, `StatusWarningEmphasized`, `StatusNegativeEmphasized`, and more. + +```kotlin +OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { + // Child OUDS components adopt monochrome colors automatically + OudsButton(label = stringResource(R.string.action), onClick = { }) + Text( + text = stringResource(R.string.description), + color = OudsTheme.colorScheme.content.default + ) +} +``` diff --git a/skills/ouds-android-vocabulary/SKILL.md b/skills/ouds-android-vocabulary/SKILL.md new file mode 100644 index 0000000000..e0887f57e7 --- /dev/null +++ b/skills/ouds-android-vocabulary/SKILL.md @@ -0,0 +1,65 @@ +--- +name: ouds-android-vocabulary +description: Use when the user asks about OUDS-specific terms such as tokenator, token, raw token, semantic token, component token, theme, OudsThemeContract, OudsTheme, component, OudsColoredBox, Tokenator +license: MIT +--- + +# OUDS Android Vocabulary + +| Term | Definition | +|---|---| +| **Tokenator** | Internal tool that converts Figma-exported JSON token specs into Kotlin source files and submits them via pull requests; generates files in `:global-raw-tokens` and `:theme-contract` | +| **token** | Named variable holding a design value (color, size, spacing, border…); most tokens are produced by Tokenator | +| **raw token** | Token whose value is a primitive Kotlin/Compose type (`Color`, `Dp`, `Int`…); grouped in the `:global-raw-tokens` module (e.g. `OudsColorRawTokens`, `OudsBorderRawTokens`) | +| **semantic token** | Token that references a raw token and carries semantic meaning (e.g. `actionColorTokens.enabled`); used directly inside components via `OudsTheme.*` | +| **component token** | Token scoped to a specific component, referencing semantic tokens for per-component styling overrides (e.g. `OudsButtonTokens`, `OudsTagTokens`); accessed via `OudsTheme.componentsTokens.*` | +| **OudsThemeContract** | Kotlin interface that every theme must implement; centralises all semantic token groups (`colorTokens`, `borderTokens`, `fontTokens`, `spaceTokens`, `componentsTokens`, etc.) and drawable resources | +| **theme** | Cohesive set of tokens and assets (fonts, drawables) controlling the look and feel of an app; available themes: `OrangeTheme`, `OrangeCompactTheme`, `SoshTheme`, `WireframeTheme` | +| **OudsTheme** | The Jetpack Compose entry-point composable that wraps your UI with a given theme; it also exposes static accessors (`OudsTheme.colorScheme`, `OudsTheme.spaces`, `OudsTheme.borders`, etc.) for reading token values inside composables | +| **component** | Jetpack Compose composable shipped by OUDS, always prefixed with `Ouds` (e.g. `OudsButton`, `OudsTag`, `OudsCheckboxItem`); token-driven, accessible, multi-brand | +| **OudsColoredBox** | Special OUDS container composable that creates a semantically colored surface; child OUDS components automatically switch to their monochrome variant to maximise contrast | +| **OudsButtonIcon** | Wrapper class used to pass an icon to `OudsButton` or `OudsSmallButton`; accepts `ImageVector`, `Painter`, or `ImageBitmap`, plus a `tinted` flag | +| **OudsControlItemIcon** | Wrapper class used to pass an optional icon to item-type controls (`OudsCheckboxItem`, `OudsRadioButtonItem`, `OudsSwitchItem`); accepts `ImageVector`, `Painter`, or `ImageBitmap`, plus a `tinted` flag | +| **OudsError** | Data class wrapping an error message (plain `String` or `AnnotatedString`) to display in input components (`OudsTextInput`, `OudsTextArea`, `OudsPasswordInput`, `OudsPinCodeInput`, `OudsCheckboxItem`, etc.) | +| **tinted** | Boolean flag on icon wrapper classes (`OudsButtonIcon`, `OudsControlItemIcon`, `OudsLinkIcon`, etc.) — when `true` (default) the icon color is driven by tokens; when `false` the painter's own colors are preserved (useful for brand/multi-color icons) | + +## Token access inside composables + +Tokens are accessed via the `OudsTheme` static object inside any composable wrapped by `OudsTheme { }`: + +| Accessor | Content | +|---|---| +| `OudsTheme.colorScheme` | Color semantic tokens (content, background, border, action, surface…) | +| `OudsTheme.borders` | Border radius, style and width tokens | +| `OudsTheme.spaces` | Spacing tokens (`fixed.*`, `scaled.*`) | +| `OudsTheme.sizes` | Size tokens | +| `OudsTheme.fonts` | Typography / font tokens | +| `OudsTheme.elevations` | Elevation / shadow tokens | +| `OudsTheme.grids` | Grid tokens | +| `OudsTheme.opacities` | Opacity tokens | +| `OudsTheme.effects` | Visual effect tokens | +| `OudsTheme.componentsTokens.*` | Per-component tokens (button, tag, textInput, etc.) | + +## Token hierarchy + +``` +Figma design tokens + │ + Tokenator (generates Kotlin) + │ + ├── :global-raw-tokens ← raw values (OudsColorRawTokens, OudsDimensionRawTokens…) + │ + └── :theme-contract ← semantic interfaces + component token interfaces + │ + └── :theme-orange / :theme-sosh / :theme-wireframe / :theme-orange-compact + └── concrete token values per brand + │ + └── :core ← Ouds* composables read tokens via OudsTheme.* +``` + +## When to load which skill + +| Task | Skill to load | +|---|---| +| Write or review Kotlin/Compose code using OUDS components or tokens | `ouds-android-framework-usage` | +| Ask about OUDS-specific terminology | `ouds-android-vocabulary` (this skill) | From c3584743bba99fb892bc6550ea1047415fd9739e Mon Sep 17 00:00:00 2001 From: Pierre-Yves Lapersonne Date: Tue, 14 Jul 2026 15:11:19 +0200 Subject: [PATCH 2/9] refactor: apply review comments (#1388) Reviewed-by: Copilot <198982749+Copilot@users.noreply.github.com> Signed-off-by: Pierre-Yves Lapersonne --- skills/ouds-android-framework-usage/SKILL.md | 6 +++--- skills/ouds-android-vocabulary/SKILL.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/skills/ouds-android-framework-usage/SKILL.md b/skills/ouds-android-framework-usage/SKILL.md index b4503d456f..3079ecdea4 100644 --- a/skills/ouds-android-framework-usage/SKILL.md +++ b/skills/ouds-android-framework-usage/SKILL.md @@ -123,7 +123,7 @@ fun MyView() { Text( text = stringResource(R.string.my_text), color = OudsTheme.colorScheme.content.default, - style = OudsTheme.fonts.bodyDefaultMedium + style = OudsTheme.typography.body.medium.default ) } } @@ -137,12 +137,12 @@ fun MyView() { | `OudsTheme.borders` | Border radius (`.radius.*`), style (`.style.*`), width (`.width.*`) | | `OudsTheme.spaces` | Spacing tokens (`.fixed.*`, `.scaled.*`) | | `OudsTheme.sizes` | Size tokens | -| `OudsTheme.fonts` | Typography / font tokens | +| `OudsTheme.typography` | Typography / font tokens | | `OudsTheme.elevations` | Elevation / shadow tokens | | `OudsTheme.grids` | Grid tokens | | `OudsTheme.opacities` | Opacity tokens | | `OudsTheme.effects` | Visual effect tokens | -| `OudsTheme.componentsTokens.*` | Per-component tokens (`.button`, `.tag`, `.textInput`, etc.) | +| `OudsTheme.components` | Component-level tokens for advanced customization (requires `@OptIn(RestrictedOudsApi::class)`) | --- diff --git a/skills/ouds-android-vocabulary/SKILL.md b/skills/ouds-android-vocabulary/SKILL.md index e0887f57e7..661136e2ed 100644 --- a/skills/ouds-android-vocabulary/SKILL.md +++ b/skills/ouds-android-vocabulary/SKILL.md @@ -12,7 +12,7 @@ license: MIT | **token** | Named variable holding a design value (color, size, spacing, border…); most tokens are produced by Tokenator | | **raw token** | Token whose value is a primitive Kotlin/Compose type (`Color`, `Dp`, `Int`…); grouped in the `:global-raw-tokens` module (e.g. `OudsColorRawTokens`, `OudsBorderRawTokens`) | | **semantic token** | Token that references a raw token and carries semantic meaning (e.g. `actionColorTokens.enabled`); used directly inside components via `OudsTheme.*` | -| **component token** | Token scoped to a specific component, referencing semantic tokens for per-component styling overrides (e.g. `OudsButtonTokens`, `OudsTagTokens`); accessed via `OudsTheme.componentsTokens.*` | + | **component token** | Token scoped to a specific component, referencing semantic tokens for per-component styling overrides (e.g. `OudsButtonTokens`, `OudsTagTokens`); exposed to consumers via `@OptIn(RestrictedOudsApi::class) OudsTheme.components` | | **OudsThemeContract** | Kotlin interface that every theme must implement; centralises all semantic token groups (`colorTokens`, `borderTokens`, `fontTokens`, `spaceTokens`, `componentsTokens`, etc.) and drawable resources | | **theme** | Cohesive set of tokens and assets (fonts, drawables) controlling the look and feel of an app; available themes: `OrangeTheme`, `OrangeCompactTheme`, `SoshTheme`, `WireframeTheme` | | **OudsTheme** | The Jetpack Compose entry-point composable that wraps your UI with a given theme; it also exposes static accessors (`OudsTheme.colorScheme`, `OudsTheme.spaces`, `OudsTheme.borders`, etc.) for reading token values inside composables | @@ -33,12 +33,12 @@ Tokens are accessed via the `OudsTheme` static object inside any composable wrap | `OudsTheme.borders` | Border radius, style and width tokens | | `OudsTheme.spaces` | Spacing tokens (`fixed.*`, `scaled.*`) | | `OudsTheme.sizes` | Size tokens | -| `OudsTheme.fonts` | Typography / font tokens | +| `OudsTheme.typography` | Typography / font tokens | | `OudsTheme.elevations` | Elevation / shadow tokens | | `OudsTheme.grids` | Grid tokens | | `OudsTheme.opacities` | Opacity tokens | | `OudsTheme.effects` | Visual effect tokens | -| `OudsTheme.componentsTokens.*` | Per-component tokens (button, tag, textInput, etc.) | +| `OudsTheme.components` | Component-level tokens for advanced customization (requires `@OptIn(RestrictedOudsApi::class)`) | ## Token hierarchy From 8dc4c316f81813178058eaac2f16713def771721 Mon Sep 17 00:00:00 2001 From: Pauline Auvray Date: Thu, 30 Jul 2026 14:37:00 +0200 Subject: [PATCH 3/9] Optimize skill descriptions for improved triggering --- AGENTS.md | 4 ++-- skills/ouds-android-framework-usage/SKILL.md | 2 +- skills/ouds-android-vocabulary/SKILL.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index eac73e0050..38b3e68c9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -214,8 +214,8 @@ Agent skills are located in the `skills/` directory at the repository root. The | Skill | When to load | |---|---| -| `ouds-android-vocabulary` | User asks about OUDS-specific terms: tokenator, raw token, semantic token, component token, theme, OudsThemeContract, OudsColoredBox, tinted, OudsError, etc. | -| `ouds-android-framework-usage` | User needs to write or review Kotlin/Compose code using OUDS components, configure the theme, access tokens, or set up Gradle dependencies | +| `ouds-android-vocabulary` | User asks to explain, define, or understand OUDS-specific terminology and concepts (tokens, Tokenator, OudsThemeContract, tinted, OudsError, etc.) or relationships between OUDS architecture elements | +| `ouds-android-framework-usage` | User needs to write code, create components, set up OUDS, configure themes, access tokens, or use any Ouds* component in Kotlin/Compose | ### Skill structure diff --git a/skills/ouds-android-framework-usage/SKILL.md b/skills/ouds-android-framework-usage/SKILL.md index 3079ecdea4..7f9ec90e76 100644 --- a/skills/ouds-android-framework-usage/SKILL.md +++ b/skills/ouds-android-framework-usage/SKILL.md @@ -1,6 +1,6 @@ --- name: ouds-android-framework-usage -description: How to set up and use the OUDS Android library with Gradle dependencies, OudsTheme setup, token access, and components with Kotlin/Compose code examples +description: Use this skill whenever the user needs to write code using OUDS Android components, set up the library, configure themes, or access design tokens in Kotlin/Compose. This includes adding dependencies, wrapping UI with OudsTheme, creating any Ouds* component (OudsButton, OudsTextInput, OudsNavigationBar, etc.), accessing tokens via OudsTheme.colorScheme/spaces/typography, configuring fonts, handling tinted/untinted icons, using OudsColoredBox, showing error messages, or switching themes dynamically. ALWAYS trigger when the user asks to 'create', 'show me how', 'write a composable', 'set up', or 'access' anything related to OUDS components or tokens, even if they don't explicitly mention 'OUDS framework'. license: MIT --- diff --git a/skills/ouds-android-vocabulary/SKILL.md b/skills/ouds-android-vocabulary/SKILL.md index 661136e2ed..3909ed0277 100644 --- a/skills/ouds-android-vocabulary/SKILL.md +++ b/skills/ouds-android-vocabulary/SKILL.md @@ -1,6 +1,6 @@ --- name: ouds-android-vocabulary -description: Use when the user asks about OUDS-specific terms such as tokenator, token, raw token, semantic token, component token, theme, OudsThemeContract, OudsTheme, component, OudsColoredBox, Tokenator +description: Use this skill whenever the user asks about OUDS-specific terminology, concepts, or vocabulary. This includes questions about tokens (raw, semantic, component), Tokenator, OudsThemeContract, OudsTheme, OudsColoredBox, tinted parameters, OudsError, or any OUDS-specific classes and patterns. ALWAYS trigger when the user asks to explain, define, clarify, or understand the difference between OUDS concepts, even if they don't explicitly say 'what is' or 'define'. Also trigger when they ask about relationships between OUDS architecture elements (e.g., how tokens relate to each other, theme hierarchy). license: MIT --- From 8c7d91a45ded4c92679b85c9685a42f6b51018c7 Mon Sep 17 00:00:00 2001 From: Pauline Auvray Date: Thu, 30 Jul 2026 15:41:33 +0200 Subject: [PATCH 4/9] Add TOC and missing components --- .../references/components.md | 518 +++++++++++++++++- 1 file changed, 510 insertions(+), 8 deletions(-) diff --git a/skills/ouds-android-framework-usage/references/components.md b/skills/ouds-android-framework-usage/references/components.md index 23b6b04559..fd8ed1ac90 100644 --- a/skills/ouds-android-framework-usage/references/components.md +++ b/skills/ouds-android-framework-usage/references/components.md @@ -3,6 +3,57 @@ All components are in the `com.orange.ouds.core.component` package. All user-visible strings must use `stringResource(R.string.*)` — never hardcode. +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +**Action** +- [Button](#button) — Default and small buttons +- [FloatingActionButton](#floatingactionbutton) — Floating action button (FAB) +- [NavigationButton](#navigationbutton) — Navigation button with chevron +- [SmallButton](#smallbutton) — Small size button variant + +**Alerts & Messages** +- [AlertMessage](#alertmessage) — Full-featured alert with actions +- [InlineAlert](#inlinealert) — Compact inline alert + +**Content Display** +- [BulletList](#bulletlist) — Ordered, unordered, and bare lists + +**Control** +- [Checkbox](#checkbox) — Standalone checkbox +- [CheckboxItem](#checkboxitem) — Checkbox with label and description +- [RadioButton](#radiobutton) — Standalone radio button +- [RadioButtonItem](#radiobuttonitem) — Radio button with label and description +- [Switch](#switch) — Standalone switch +- [SwitchItem](#switchitem) — Toggle switch with label and description + - **Chip** + - [FilterChip](#filterchip) — Selectable filter chip + - [SuggestionChip](#suggestionchip) — Suggestion and action chip + +**Indicator** +- [Badge](#badge) — Count and status badges +- [CircularProgressIndicator](#circularprogressindicator) — Circular loading indicator +- [LinearProgressIndicator](#linearprogressindicator) — Linear loading indicator +- [Tag](#tag) — Status and category tags + +**Layout** +- [BottomSheetScaffold](#bottomsheetscaffold) — Standard bottom sheet scaffold +- [ColoredBox](#coloredbox) — Colored surface container +- [Divider](#divider) — Horizontal and vertical dividers +- [ModalBottomSheet](#modalbottomsheet) — Modal bottom sheet + +**Navigation** +- [Link](#link) — Text link with optional icon/chevron +- [NavigationBar](#navigationbar) — Bottom navigation bar +- [TopAppBar](#topappbar) — Top app bar with variants + +**Text Inputs** +- [TextInput](#textinput) — Single-line text field +- [TextArea](#textarea) — Multi-line text field +- [PasswordInput](#passwordinput) — Password field with visibility toggle +- [PinCodeInput](#pincodeinput) — PIN code input (4 or 6 digits) + --- ## Button @@ -73,6 +124,125 @@ OudsSmallButton( --- +## FloatingActionButton + +**Sizes:** `OudsFloatingActionButton` (default) · `OudsSmallFloatingActionButton` · `OudsLargeFloatingActionButton` · `OudsExtendedFloatingActionButton` (with text) +**Appearances:** `OudsFloatingActionButtonAppearance` — `Primary`, `Secondary` + +```kotlin +// Icon only (default size) +OudsFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + imageVector = Icons.Filled.Add, + contentDescription = stringResource(R.string.add) + ), + onClick = { } +) + +// Small size +OudsSmallFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + imageVector = Icons.Filled.Edit, + contentDescription = stringResource(R.string.edit) + ), + onClick = { } +) + +// Large size +OudsLargeFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + imageVector = Icons.Filled.FavoriteBorder, + contentDescription = stringResource(R.string.favorite) + ), + onClick = { } +) + +// Extended (with text) +OudsExtendedFloatingActionButton( + text = stringResource(R.string.create), + icon = OudsFloatingActionButtonIcon(imageVector = Icons.Filled.Add, contentDescription = ""), + onClick = { } +) + +// With secondary appearance +OudsFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + imageVector = Icons.Filled.Settings, + contentDescription = stringResource(R.string.settings) + ), + appearance = OudsFloatingActionButtonAppearance.Secondary, + onClick = { } +) + +// With untinted icon (multi-color) +OudsFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + painter = myBrandPainter, + contentDescription = stringResource(R.string.brand_action), + tinted = false + ), + onClick = { } +) +``` + +--- + +## NavigationButton + +**Chevrons:** `OudsNavigationButtonChevron` — `Next`, `Previous` +**Appearances:** `OudsNavigationButtonAppearance` — `Default`, `Strong`, `Brand`, `Minimal` +**Note:** `Brand` appearance is forbidden inside `OudsColoredBox`. +Inside `OudsColoredBox`, the button automatically adopts its monochrome variant. + +```kotlin +// Icon only (chevron) +OudsNavigationButton( + chevron = OudsNavigationButtonChevron.Next, + onClick = { } +) + +// With label +OudsNavigationButton( + label = stringResource(R.string.next), + chevron = OudsNavigationButtonChevron.Next, + onClick = { } +) + +// Previous chevron +OudsNavigationButton( + label = stringResource(R.string.previous), + chevron = OudsNavigationButtonChevron.Previous, + onClick = { } +) + +// With appearance +OudsNavigationButton( + label = stringResource(R.string.next), + chevron = OudsNavigationButtonChevron.Next, + appearance = OudsNavigationButtonAppearance.Strong, + onClick = { } +) + +// With loader +OudsNavigationButton( + label = stringResource(R.string.next), + chevron = OudsNavigationButtonChevron.Next, + loader = OudsButtonLoader(progress = null), // indeterminate + onClick = { } +) + +// On colored background — colors adjusted automatically +OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { + OudsNavigationButton( + label = stringResource(R.string.next), + chevron = OudsNavigationButtonChevron.Next, + onClick = { } + ) +} +``` + +--- + ## Tag **Statuses:** `OudsTagStatus` — `Neutral`, `Accent`, `Positive`, `Warning`, `Negative`, `Info` @@ -177,6 +347,89 @@ BadgedBox( --- +## CircularProgressIndicator + +**Statuses:** `OudsProgressIndicatorStatus` — `Accent` (default), `Neutral` +**Variants:** Determinate (with progress value) · Indeterminate (loading animation) +**Track:** Optional background track for better visibility + +```kotlin +// Indeterminate (loading) +OudsCircularProgressIndicator() + +// Determinate (with progress) +OudsCircularProgressIndicator(progress = { 0.75f }) + +// With status +OudsCircularProgressIndicator( + progress = { 0.5f }, + status = OudsProgressIndicatorStatus.Neutral +) + +// Without track (minimal) +OudsCircularProgressIndicator( + progress = { 0.75f }, + track = false +) + +// Custom size +OudsCircularProgressIndicator( + modifier = Modifier.size(64.dp), + progress = { 0.75f } +) +``` + +--- + +## LinearProgressIndicator + +**Statuses:** `OudsProgressIndicatorStatus` — `Accent` (default), `Neutral` +**Variants:** Determinate (with progress value) · Indeterminate (loading animation) +**Track:** Optional background track for better visibility +**Stop Indicator:** Optional end marker for accessibility (required if contrast < 3:1) + +```kotlin +// Indeterminate (loading) +OudsLinearProgressIndicator( + helperText = stringResource(R.string.loading) +) + +// Determinate (with progress) +OudsLinearProgressIndicator( + progress = { 0.75f }, + helperText = stringResource(R.string.loading_percent, 75) +) + +// With status +OudsLinearProgressIndicator( + progress = { 0.5f }, + status = OudsProgressIndicatorStatus.Neutral, + helperText = stringResource(R.string.uploading) +) + +// Without track (minimal) +OudsLinearProgressIndicator( + progress = { 0.75f }, + track = false +) + +// With stop indicator (for accessibility) +OudsLinearProgressIndicator( + progress = { 0.75f }, + stopIndicator = true, + helperText = stringResource(R.string.processing) +) + +// Full width with helper text +OudsLinearProgressIndicator( + modifier = Modifier.fillMaxWidth(), + progress = { 0.75f }, + helperText = "Uploading file: document.pdf" +) +``` + +--- + ## AlertMessage **Statuses:** `OudsAlertMessageStatus` — `Neutral`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` @@ -426,6 +679,109 @@ OudsSwitchItem( --- +## Checkbox + +**Standalone checkbox** without label — use when checkbox is nested within another component with an alternative label. +**See also:** [CheckboxItem](#checkboxitem) for checkbox with label and description. + +```kotlin +var checked by remember { mutableStateOf(false) } + +// Basic checkbox +OudsCheckbox( + checked = checked, + onCheckedChange = { checked = it } +) + +// Disabled +OudsCheckbox( + checked = checked, + onCheckedChange = { checked = it }, + enabled = false +) + +// Tri-state checkbox +var state by remember { mutableStateOf(ToggleableState.Off) } +OudsTriStateCheckbox( + state = state, + onClick = { + state = when (state) { + ToggleableState.On -> ToggleableState.Off + ToggleableState.Off -> ToggleableState.Indeterminate + ToggleableState.Indeterminate -> ToggleableState.On + } + } +) +``` + +--- + +## RadioButton + +**Standalone radio button** without label — use when radio button is nested within another component with an alternative label. +**See also:** [RadioButtonItem](#radiobuttonitem) for radio button with label and description. +**Always** wrap a group of radio buttons in `Modifier.selectableGroup()`. + +```kotlin +val options = listOf("Option A", "Option B", "Option C") +var selected by remember { mutableStateOf(options[0]) } + +Column(modifier = Modifier.selectableGroup()) { + options.forEach { option -> + OudsRadioButton( + selected = option == selected, + onClick = { selected = option } + ) + } +} + +// Disabled +OudsRadioButton( + selected = true, + onClick = null, + enabled = false +) +``` + +--- + +## Switch + +**Standalone switch** without label — use when switch is nested within another component with an alternative label. +**See also:** [SwitchItem](#switchitem) for switch with label and description. + +```kotlin +var checked by remember { mutableStateOf(true) } + +// Basic switch +OudsSwitch( + checked = checked, + onCheckedChange = { checked = it } +) + +// Disabled +OudsSwitch( + checked = checked, + onCheckedChange = { checked = it }, + enabled = false +) + +// With icon (when checked) +OudsSwitch( + checked = checked, + onCheckedChange = { checked = it }, + thumbContent = { + Icon( + imageVector = Icons.Filled.Check, + contentDescription = null, + modifier = Modifier.size(16.dp) + ) + } +) +``` + +--- + ## TextInput Two API variants: **state-based** (`textFieldState`) and **value-based** (`value` + `onValueChange`). @@ -566,35 +922,60 @@ OudsPinCodeInput( --- -## FilterChip / SuggestionChip +## FilterChip + +**Selectable chip** used for filtering content. ```kotlin -// Filter chip — text +// Text only OudsFilterChip(text = stringResource(R.string.label), onClick = { }) -// Filter chip — with icon +// With icon OudsFilterChip( icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), text = stringResource(R.string.label), onClick = { } ) -// Filter chip — icon only +// Icon only OudsFilterChip( icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), contentDescription = stringResource(R.string.label_desc), onClick = { } ) -// Suggestion chip +// Selected state +var selected by remember { mutableStateOf(false) } +OudsFilterChip( + text = stringResource(R.string.label), + selected = selected, + onClick = { selected = !selected } +) +``` + +--- + +## SuggestionChip + +**Action chip** used for suggestions and quick actions. + +```kotlin +// Text only OudsSuggestionChip(text = stringResource(R.string.label), onClick = { }) -// Suggestion chip — with icon +// With icon OudsSuggestionChip( icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), text = stringResource(R.string.label), onClick = { } ) + +// Icon only +OudsSuggestionChip( + icon = OudsChipIcon(imageVector = Icons.Filled.Add), + contentDescription = stringResource(R.string.add_desc), + onClick = { } +) ``` --- @@ -706,10 +1087,19 @@ OudsLargeTopAppBar( ## ColoredBox -Creates a colored surface where child OUDS components automatically switch to their monochrome variant. -**Colors:** `OudsColoredBoxColor` — `BrandPrimary`, `StatusNeutralEmphasized`, `StatusAccentEmphasized`, `StatusPositiveEmphasized`, `StatusInfoEmphasized`, `StatusWarningEmphasized`, `StatusNegativeEmphasized`, and more. +Creates a colored surface where child OUDS components automatically switch to their monochrome variant. + +**Colors:** 24 values organized by category: +- **Background** (5): `BackgroundInverseHigh`, `BackgroundInverseLow`, `BackgroundPrimary`, `BackgroundSecondary`, `BackgroundTertiary` +- **Brand** (3): `BrandPrimary`, `BrandSecondary`, `BrandTertiary` +- **Overlay** (3): `OverlayDropdown`, `OverlayModal`, `OverlayTooltip` +- **Status** (8): `StatusAccentEmphasized`, `StatusAccentMuted`, `StatusInfoEmphasized`, `StatusInfoMuted`, `StatusNegativeEmphasized`, `StatusNegativeMuted`, `StatusPositiveEmphasized`, `StatusPositiveMuted`, `StatusWarningEmphasized`, `StatusWarningMuted` +- **Surface** (5): `SurfaceInverseHigh`, `SurfaceInverseLow`, `SurfacePrimary`, `SurfaceSecondary`, `SurfaceTertiary` + +> **Note:** Not all colors are supported by all themes. Check `color.isSupported` before using a color in production code. ```kotlin +// Basic usage OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { // Child OUDS components adopt monochrome colors automatically OudsButton(label = stringResource(R.string.action), onClick = { }) @@ -718,4 +1108,116 @@ OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { color = OudsTheme.colorScheme.content.default ) } + +// Check if color is supported by current theme +val color = OudsColoredBoxColor.BrandPrimary +if (color.isSupported) { + OudsColoredBox(color = color) { + // Content + } +} + +// Different color categories +OudsColoredBox(color = OudsColoredBoxColor.BrandPrimary) { /* Brand colors */ } +OudsColoredBox(color = OudsColoredBoxColor.StatusPositiveEmphasized) { /* Status colors */ } +OudsColoredBox(color = OudsColoredBoxColor.SurfacePrimary) { /* Surface colors */ } +``` + +--- + +## BottomSheetScaffold + +**Standard bottom sheet** that co-exists with main screen content, allowing simultaneous interaction. +**See also:** [ModalBottomSheet](#modalbottomsheet) for modal behavior that blocks main content. + +```kotlin +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MyScreen() { + val scaffoldState = rememberBottomSheetScaffoldState() + + OudsBottomSheetScaffold( + sheetContent = { + Column(modifier = Modifier.padding(16.dp)) { + Text(stringResource(R.string.sheet_title)) + Text(stringResource(R.string.sheet_content)) + } + }, + sheetPeekHeight = 128.dp, + content = { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + ) { + Text(stringResource(R.string.main_content)) + } + } + ) +} + +// Without drag handle +OudsBottomSheetScaffold( + sheetContent = { /* content */ }, + sheetDragHandle = false, + content = { /* main content */ } +) + +// With custom peek height +OudsBottomSheetScaffold( + sheetContent = { /* content */ }, + sheetPeekHeight = 200.dp, + content = { /* main content */ } +) +``` + +--- + +## ModalBottomSheet + +**Modal bottom sheet** that appears in front of app content and blocks interaction until dismissed. +**See also:** [BottomSheetScaffold](#bottomsheetscaffold) for non-modal variant. + +```kotlin +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MyScreen() { + var showBottomSheet by remember { mutableStateOf(false) } + val sheetState = rememberModalBottomSheetState() + + Button(onClick = { showBottomSheet = true }) { + Text(stringResource(R.string.show_sheet)) + } + + if (showBottomSheet) { + OudsModalBottomSheet( + onDismissRequest = { showBottomSheet = false }, + sheetState = sheetState + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text(stringResource(R.string.sheet_title)) + Text(stringResource(R.string.sheet_content)) + Button(onClick = { showBottomSheet = false }) { + Text(stringResource(R.string.close)) + } + } + } + } +} + +// Without drag handle +OudsModalBottomSheet( + onDismissRequest = { /* dismiss */ }, + dragHandle = false +) { + // Content +} + +// With gestures disabled +OudsModalBottomSheet( + onDismissRequest = { /* dismiss */ }, + sheetGesturesEnabled = false +) { + // Content +} ``` From 4cd452fb95aaf4d1c1fc04b9b1927ed6bcc9804a Mon Sep 17 00:00:00 2001 From: Pauline Auvray Date: Thu, 30 Jul 2026 16:28:08 +0200 Subject: [PATCH 5/9] Add information about tokens use --- skills/ouds-android-framework-usage/SKILL.md | 11 +- .../references/component-tokens.md | 617 +++++++++++++ .../references/tokens.md | 847 ++++++++++++++++++ 3 files changed, 1473 insertions(+), 2 deletions(-) create mode 100644 skills/ouds-android-framework-usage/references/component-tokens.md create mode 100644 skills/ouds-android-framework-usage/references/tokens.md diff --git a/skills/ouds-android-framework-usage/SKILL.md b/skills/ouds-android-framework-usage/SKILL.md index 7f9ec90e76..ef767fd9e0 100644 --- a/skills/ouds-android-framework-usage/SKILL.md +++ b/skills/ouds-android-framework-usage/SKILL.md @@ -233,8 +233,15 @@ OudsButton(label = stringResource(R.string.submit), onClick = { }) --- -## 7. Components reference +## 7. Reference documentation + +### Components reference See [`references/components.md`](references/components.md) for the full list of components with signatures and usage examples. -**Index:** [Button](#button) · [SmallButton](#smallbutton) · [Tag](#tag) · [Badge](#badge) · [AlertMessage](#alertmessage) · [InlineAlert](#inlinealert) · [BulletList](#bulletlist) · [CheckboxItem](#checkboxitem) · [RadioButtonItem](#radiobuttonitem) · [SwitchItem](#switchitem) · [TextInput](#textinput) · [TextArea](#textarea) · [PasswordInput](#passwordinput) · [PinCodeInput](#pincodeinput) · [FilterChip / SuggestionChip](#filterchip--suggestionchip) · [Link](#link) · [Divider](#divider) · [NavigationBar](#navigationbar) · [TopAppBar](#topappbar) · [ColoredBox](#coloredbox) +**Component Index:** [Button](#button) · [SmallButton](#smallbutton) · [Tag](#tag) · [Badge](#badge) · [AlertMessage](#alertmessage) · [InlineAlert](#inlinealert) · [BulletList](#bulletlist) · [CheckboxItem](#checkboxitem) · [RadioButtonItem](#radiobuttonitem) · [SwitchItem](#switchitem) · [TextInput](#textinput) · [TextArea](#textarea) · [PasswordInput](#passwordinput) · [PinCodeInput](#pincodeinput) · [FilterChip / SuggestionChip](#filterchip--suggestionchip) · [Link](#link) · [Divider](#divider) · [NavigationBar](#navigationbar) · [TopAppBar](#topappbar) · [ColoredBox](#coloredbox) + +### Tokens reference + +- **Semantic tokens:** See [`references/tokens.md`](references/tokens.md) for color scheme, typography, spacing, sizes, borders, elevations, opacities, effects, and grids +- **Component tokens:** See [`references/component-tokens.md`](references/component-tokens.md) for advanced component-level tokens (`@RestrictedOudsApi`) diff --git a/skills/ouds-android-framework-usage/references/component-tokens.md b/skills/ouds-android-framework-usage/references/component-tokens.md new file mode 100644 index 0000000000..e707987781 --- /dev/null +++ b/skills/ouds-android-framework-usage/references/component-tokens.md @@ -0,0 +1,617 @@ +# OUDS Android — Component Tokens Reference + +**Restricted API** (`@RestrictedOudsApi`) — For advanced component customization. + +Component tokens provide granular control over the appearance of OUDS components. These tokens are designed for building custom components or extending existing OUDS components with precise design specifications. + +> **Important:** Most developers should use [semantic tokens](tokens.md) and standard OUDS components. Only use component tokens when you have specific customization needs that cannot be met with the standard API. + +--- + +## When to Use Component Tokens + +**Use component tokens when:** +- Building custom components that need to align with OUDS design language +- Extending existing OUDS components with additional functionality +- Implementing precise design specifications that require component-level token values +- Creating reusable component patterns within your design system + +**Do NOT use component tokens when:** +- Standard OUDS components (e.g., `OudsButton`, `OudsChip`, `OudsTextInput`) meet your needs +- Building typical UI layouts — use [semantic tokens](tokens.md) instead +- You're unsure whether component tokens are needed — start with semantic tokens first + +--- + +## Accessing Component Tokens + +Component tokens are accessed via `OudsTheme.components` and require opt-in to the restricted API: + +```kotlin +import com.orange.ouds.core.theme.OudsTheme +import com.orange.ouds.theme.tokens.utils.RestrictedOudsApi + +@OptIn(RestrictedOudsApi::class) +@Composable +fun MyCustomComponent() { + val buttonPadding = OudsTheme.components.button.space.paddingInline.medium + val buttonRadius = OudsTheme.components.button.border.radius.default + + // Use component tokens for precise customization +} +``` + +--- + +## Available Component Token Categories + +### Action Components + +```kotlin +// Button tokens +OudsTheme.components.button.border.radius.default +OudsTheme.components.button.border.radius.rounded +OudsTheme.components.button.border.width +OudsTheme.components.button.color.background.* +OudsTheme.components.button.color.border.* +OudsTheme.components.button.color.content.* +OudsTheme.components.button.elevation.* +OudsTheme.components.button.opacity.* +OudsTheme.components.button.size.height.* +OudsTheme.components.button.size.icon.* +OudsTheme.components.button.size.minWidth.* +OudsTheme.components.button.space.columnGap.* +OudsTheme.components.button.space.paddingInline.* +OudsTheme.components.button.typography.* + +// Monochrome button variant +OudsTheme.components.buttonMonochrome.color.background.* +OudsTheme.components.buttonMonochrome.color.border.* +OudsTheme.components.buttonMonochrome.color.content.* + +// Link tokens +OudsTheme.components.link.color.content.* +OudsTheme.components.link.size.icon.* +OudsTheme.components.link.space.columnGap.* +OudsTheme.components.link.typography.* + +// Monochrome link variant +OudsTheme.components.linkMonochrome.color.content.* +``` + +### Indicator Components + +```kotlin +// Badge tokens +OudsTheme.components.badge.border.radius +OudsTheme.components.badge.color.background.* +OudsTheme.components.badge.color.content.* +OudsTheme.components.badge.size.height.* +OudsTheme.components.badge.size.icon.* +OudsTheme.components.badge.size.minWidth.* +OudsTheme.components.badge.size.width.* +OudsTheme.components.badge.space.paddingInline.* +OudsTheme.components.badge.typography.* + +// Tag tokens +OudsTheme.components.tag.border.radius.default +OudsTheme.components.tag.border.radius.rounded +OudsTheme.components.tag.border.width +OudsTheme.components.tag.color.background.* +OudsTheme.components.tag.color.border.* +OudsTheme.components.tag.color.content.* +OudsTheme.components.tag.size.height.* +OudsTheme.components.tag.size.icon.* +OudsTheme.components.tag.space.columnGap.* +OudsTheme.components.tag.space.paddingInline.* +OudsTheme.components.tag.typography.* + +// Progress indicator tokens +OudsTheme.components.progressIndicator.border.radius.default +OudsTheme.components.progressIndicator.border.radius.rounded +OudsTheme.components.progressIndicator.color.background.* +OudsTheme.components.progressIndicator.color.content.* +OudsTheme.components.progressIndicator.size.height.* +OudsTheme.components.progressIndicator.size.width.* +OudsTheme.components.progressIndicator.space.rowGap.* +``` + +### Alert Components + +```kotlin +// Alert message tokens +OudsTheme.components.alert.border.radius.default +OudsTheme.components.alert.border.radius.rounded +OudsTheme.components.alert.border.width +OudsTheme.components.alert.color.background.* +OudsTheme.components.alert.color.border.* +OudsTheme.components.alert.color.content.* +OudsTheme.components.alert.size.icon +OudsTheme.components.alert.size.minHeight +OudsTheme.components.alert.size.minHeightBottomActionPlacement +OudsTheme.components.alert.size.minWidth +OudsTheme.components.alert.space.columnGap +OudsTheme.components.alert.space.columnGapAction +OudsTheme.components.alert.space.paddingBlock +OudsTheme.components.alert.space.paddingInline +OudsTheme.components.alert.space.rowGap +OudsTheme.components.alert.space.rowGapAction +OudsTheme.components.alert.space.rowGapBullet +``` + +### Control Components + +```kotlin +// Checkbox tokens +OudsTheme.components.checkbox.border.radius +OudsTheme.components.checkbox.border.width.* +OudsTheme.components.checkbox.color.background.* +OudsTheme.components.checkbox.color.border.* +OudsTheme.components.checkbox.color.content.* +OudsTheme.components.checkbox.elevation.* +OudsTheme.components.checkbox.size.* + +// Radio button tokens +OudsTheme.components.radioButton.border.width.* +OudsTheme.components.radioButton.color.background.* +OudsTheme.components.radioButton.color.border.* +OudsTheme.components.radioButton.color.content.* +OudsTheme.components.radioButton.elevation.* +OudsTheme.components.radioButton.size.* + +// Switch tokens +OudsTheme.components.switch.border.width.* +OudsTheme.components.switch.color.background.* +OudsTheme.components.switch.color.border.* +OudsTheme.components.switch.color.content.* +OudsTheme.components.switch.elevation.* +OudsTheme.components.switch.size.* + +// Control item tokens (CheckboxItem, RadioButtonItem, SwitchItem) +OudsTheme.components.controlItem.color.background.* +OudsTheme.components.controlItem.color.content.* +OudsTheme.components.controlItem.size.icon +OudsTheme.components.controlItem.space.columnGap +OudsTheme.components.controlItem.space.paddingBlock +OudsTheme.components.controlItem.space.paddingInline +OudsTheme.components.controlItem.space.rowGap +OudsTheme.components.controlItem.typography.* + +// Chip tokens +OudsTheme.components.chip.border.radius +OudsTheme.components.chip.border.width +OudsTheme.components.chip.color.background.* +OudsTheme.components.chip.color.border.* +OudsTheme.components.chip.color.content.* +OudsTheme.components.chip.size.height.* +OudsTheme.components.chip.size.icon.* +OudsTheme.components.chip.space.columnGap.* +OudsTheme.components.chip.space.paddingInline.* +OudsTheme.components.chip.typography.* +``` + +### Input Components + +```kotlin +// Text input tokens +OudsTheme.components.textInput.border.radius.default +OudsTheme.components.textInput.border.radius.rounded +OudsTheme.components.textInput.border.width +OudsTheme.components.textInput.color.background.* +OudsTheme.components.textInput.color.border.* +OudsTheme.components.textInput.color.content.* +OudsTheme.components.textInput.opacity.* +OudsTheme.components.textInput.size.height +OudsTheme.components.textInput.size.icon +OudsTheme.components.textInput.space.columnGap +OudsTheme.components.textInput.space.paddingBlock +OudsTheme.components.textInput.space.paddingInline +OudsTheme.components.textInput.space.rowGap +OudsTheme.components.textInput.typography.* + +// Text area tokens +OudsTheme.components.textArea.border.radius.default +OudsTheme.components.textArea.border.radius.rounded +OudsTheme.components.textArea.border.width +OudsTheme.components.textArea.color.background.* +OudsTheme.components.textArea.color.border.* +OudsTheme.components.textArea.color.content.* +OudsTheme.components.textArea.opacity.* +OudsTheme.components.textArea.size.minHeight +OudsTheme.components.textArea.space.paddingBlock +OudsTheme.components.textArea.space.paddingInline +OudsTheme.components.textArea.space.rowGap +OudsTheme.components.textArea.typography.* + +// PIN code input tokens +OudsTheme.components.pinCodeInput.border.radius.default +OudsTheme.components.pinCodeInput.border.radius.rounded +OudsTheme.components.pinCodeInput.border.width +OudsTheme.components.pinCodeInput.color.background.* +OudsTheme.components.pinCodeInput.color.border.* +OudsTheme.components.pinCodeInput.color.content.* +OudsTheme.components.pinCodeInput.opacity.* +OudsTheme.components.pinCodeInput.size.digitWidth +OudsTheme.components.pinCodeInput.size.height +OudsTheme.components.pinCodeInput.space.columnGap +OudsTheme.components.pinCodeInput.space.rowGap +OudsTheme.components.pinCodeInput.typography.* + +// Input tag tokens +OudsTheme.components.inputTag.color.background.* +OudsTheme.components.inputTag.color.border.* +OudsTheme.components.inputTag.color.content.* +``` + +### Layout Components + +```kotlin +// Divider tokens +OudsTheme.components.divider.color.background +OudsTheme.components.divider.size.height + +// Top app bar tokens +OudsTheme.components.bar.topAppBar.color.background +OudsTheme.components.bar.topAppBar.color.content +OudsTheme.components.bar.topAppBar.elevation.* +OudsTheme.components.bar.topAppBar.size.actionIcon +OudsTheme.components.bar.topAppBar.size.height.* +OudsTheme.components.bar.topAppBar.size.navigationIcon +OudsTheme.components.bar.topAppBar.space.columnGap +OudsTheme.components.bar.topAppBar.space.paddingBlock +OudsTheme.components.bar.topAppBar.space.paddingInline +OudsTheme.components.bar.topAppBar.typography.* + +// Navigation bar tokens +OudsTheme.components.bar.navigationBar.color.background +OudsTheme.components.bar.navigationBar.color.content.* +OudsTheme.components.bar.navigationBar.elevation +OudsTheme.components.bar.navigationBar.size.height +OudsTheme.components.bar.navigationBar.size.icon +OudsTheme.components.bar.navigationBar.space.rowGap +OudsTheme.components.bar.navigationBar.typography.* +``` + +### Content Components + +```kotlin +// Bullet list tokens +OudsTheme.components.bulletList.color.content.* +OudsTheme.components.bulletList.size.bullet.* +OudsTheme.components.bulletList.size.icon +OudsTheme.components.bulletList.space.columnGap +OudsTheme.components.bulletList.space.indent +OudsTheme.components.bulletList.space.rowGap + +// Icon tokens +OudsTheme.components.icon.color.content +``` + +--- + +## Component Token Examples + +### Example 1: Custom Button with Component Tokens + +```kotlin +@OptIn(RestrictedOudsApi::class) +@Composable +fun CustomBrandButton( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Button( + onClick = onClick, + modifier = modifier, + shape = RoundedCornerShape(OudsTheme.components.button.border.radius.rounded), + colors = ButtonDefaults.buttonColors( + containerColor = OudsTheme.components.button.color.background.brand.enabled, + contentColor = OudsTheme.components.button.color.content.brand.enabled + ), + elevation = ButtonDefaults.buttonElevation( + defaultElevation = OudsTheme.components.button.elevation.default + ), + contentPadding = PaddingValues( + horizontal = OudsTheme.components.button.space.paddingInline.medium, + vertical = 0.dp + ) + ) { + Text( + text = text, + style = OudsTheme.components.button.typography.medium.strong + ) + } +} +``` + +### Example 2: Custom Chip with Component Tokens + +```kotlin +@OptIn(RestrictedOudsApi::class) +@Composable +fun CustomChip( + text: String, + icon: ImageVector? = null, + selected: Boolean = false, + onClick: () -> Unit +) { + val backgroundColor = if (selected) { + OudsTheme.components.chip.color.background.outlined.selected + } else { + OudsTheme.components.chip.color.background.outlined.enabled + } + + val contentColor = if (selected) { + OudsTheme.components.chip.color.content.outlined.selected + } else { + OudsTheme.components.chip.color.content.outlined.enabled + } + + Surface( + onClick = onClick, + shape = RoundedCornerShape(OudsTheme.components.chip.border.radius), + color = backgroundColor, + border = BorderStroke( + width = OudsTheme.components.chip.border.width, + color = OudsTheme.components.chip.color.border.outlined.enabled + ) + ) { + Row( + modifier = Modifier + .height(OudsTheme.components.chip.size.height.medium) + .padding(horizontal = OudsTheme.components.chip.space.paddingInline.medium), + horizontalArrangement = Arrangement.spacedBy(OudsTheme.components.chip.space.columnGap.icon), + verticalAlignment = Alignment.CenterVertically + ) { + icon?.let { + Icon( + imageVector = it, + contentDescription = null, + modifier = Modifier.size(OudsTheme.components.chip.size.icon.outlined.medium), + tint = contentColor + ) + } + Text( + text = text, + style = OudsTheme.components.chip.typography.medium.default, + color = contentColor + ) + } + } +} +``` + +### Example 3: Custom Text Input with Component Tokens + +```kotlin +@OptIn(RestrictedOudsApi::class, ExperimentalMaterial3Api::class) +@Composable +fun CustomTextInput( + value: String, + onValueChange: (String) -> Unit, + label: String, + modifier: Modifier = Modifier, + isError: Boolean = false +) { + val borderColor = if (isError) { + OudsTheme.components.textInput.color.border.error + } else { + OudsTheme.components.textInput.color.border.default + } + + TextField( + value = value, + onValueChange = onValueChange, + modifier = modifier, + label = { + Text( + text = label, + style = OudsTheme.components.textInput.typography.label + ) + }, + textStyle = OudsTheme.components.textInput.typography.content, + shape = RoundedCornerShape(OudsTheme.components.textInput.border.radius.default), + colors = TextFieldDefaults.colors( + focusedContainerColor = OudsTheme.components.textInput.color.background.default, + unfocusedContainerColor = OudsTheme.components.textInput.color.background.default, + focusedIndicatorColor = OudsTheme.components.textInput.color.border.focus, + unfocusedIndicatorColor = borderColor, + errorIndicatorColor = OudsTheme.components.textInput.color.border.error, + focusedTextColor = OudsTheme.components.textInput.color.content.default, + unfocusedTextColor = OudsTheme.components.textInput.color.content.default + ), + isError = isError + ) +} +``` + +### Example 4: Custom Alert Banner with Component Tokens + +```kotlin +@OptIn(RestrictedOudsApi::class) +@Composable +fun CustomAlertBanner( + title: String, + message: String, + icon: ImageVector, + onDismiss: () -> Unit, + modifier: Modifier = Modifier +) { + Surface( + modifier = modifier, + shape = RoundedCornerShape(OudsTheme.components.alert.border.radius.default), + color = OudsTheme.components.alert.color.background.info.emphasized, + border = BorderStroke( + width = OudsTheme.components.alert.border.width, + color = OudsTheme.components.alert.color.border.info.emphasized + ) + ) { + Row( + modifier = Modifier + .padding( + horizontal = OudsTheme.components.alert.space.paddingInline, + vertical = OudsTheme.components.alert.space.paddingBlock + ), + horizontalArrangement = Arrangement.spacedBy(OudsTheme.components.alert.space.columnGap) + ) { + Icon( + imageVector = icon, + contentDescription = null, + modifier = Modifier.size(OudsTheme.components.alert.size.icon), + tint = OudsTheme.components.alert.color.content.info.emphasized + ) + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(OudsTheme.components.alert.space.rowGap) + ) { + Text( + text = title, + color = OudsTheme.components.alert.color.content.info.emphasized + ) + Text( + text = message, + color = OudsTheme.components.alert.color.content.info.emphasized + ) + } + IconButton(onClick = onDismiss) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = "Close", + tint = OudsTheme.components.alert.color.content.info.emphasized + ) + } + } + } +} +``` + +--- + +## Best Practices + +### 1. Prefer Semantic Tokens When Possible + +Before using component tokens, check if semantic tokens can achieve your goal: + +```kotlin +// ❌ Avoid if unnecessary +@OptIn(RestrictedOudsApi::class) +val spacing = OudsTheme.components.button.space.paddingInline.medium + +// ✅ Prefer semantic tokens +val spacing = OudsTheme.spaces.fixed.medium +``` + +### 2. Use Component Tokens for Component-Specific Values + +Component tokens are ideal when you need values specific to a component's design: + +```kotlin +@OptIn(RestrictedOudsApi::class) +// ✅ Good use case: component-specific height +val chipHeight = OudsTheme.components.chip.size.height.medium + +// ✅ Good use case: component-specific color states +val chipBackground = OudsTheme.components.chip.color.background.outlined.selected +``` + +### 3. Document Your Custom Components + +When creating custom components with component tokens, document your decisions: + +```kotlin +/** + * Custom branded chip component. + * + * Uses component tokens for: + * - Precise height matching OUDS chip specs + * - Brand-specific color states + * - Consistent padding and spacing + * + * @param text Chip label text + * @param selected Whether the chip is selected + * @param onClick Callback when chip is clicked + */ +@OptIn(RestrictedOudsApi::class) +@Composable +fun BrandChip( + text: String, + selected: Boolean, + onClick: () -> Unit +) { + // Implementation +} +``` + +### 4. Keep Component Token Usage Localized + +Limit component token access to component files: + +```kotlin +// ✅ Good: Component token usage in a dedicated component file +// file: CustomChip.kt +@OptIn(RestrictedOudsApi::class) +@Composable +fun CustomChip(...) { + val chipHeight = OudsTheme.components.chip.size.height.medium + // ... +} + +// ❌ Avoid: Spreading component tokens across screen/page files +// file: HomeScreen.kt +@OptIn(RestrictedOudsApi::class) +@Composable +fun HomeScreen() { + val chipHeight = OudsTheme.components.chip.size.height.medium // Prefer CustomChip component + // ... +} +``` + +--- + +## Migration from Semantic to Component Tokens + +If you find yourself needing more control than semantic tokens provide, migrate gradually: + +```kotlin +// Step 1: Start with semantic tokens +@Composable +fun MyButton(text: String, onClick: () -> Unit) { + Button( + onClick = onClick, + colors = ButtonDefaults.buttonColors( + containerColor = OudsTheme.colorScheme.action.enabled + ) + ) { + Text(text, style = OudsTheme.typography.label.large.strong) + } +} + +// Step 2: Identify specific needs (e.g., precise padding) +@OptIn(RestrictedOudsApi::class) +@Composable +fun MyButton(text: String, onClick: () -> Unit) { + Button( + onClick = onClick, + colors = ButtonDefaults.buttonColors( + containerColor = OudsTheme.colorScheme.action.enabled + ), + contentPadding = PaddingValues( + horizontal = OudsTheme.components.button.space.paddingInline.medium // Component token + ) + ) { + Text(text, style = OudsTheme.typography.label.large.strong) // Semantic token + } +} +``` + +--- + +## References + +- **Semantic Tokens:** See [`tokens.md`](tokens.md) for standard design tokens +- **Components:** See [`components.md`](components.md) for standard OUDS components +- **Documentation:** https://android.unified-design-system.orange.com/ +- **Repository:** https://github.com/Orange-OpenSource/ouds-android +- **Design System:** https://unified-design-system.orange.com/ diff --git a/skills/ouds-android-framework-usage/references/tokens.md b/skills/ouds-android-framework-usage/references/tokens.md new file mode 100644 index 0000000000..44db57c506 --- /dev/null +++ b/skills/ouds-android-framework-usage/references/tokens.md @@ -0,0 +1,847 @@ +# OUDS Android — Semantic Tokens Reference + +All OUDS semantic tokens are accessed via `OudsTheme` in composable functions. +**Never hardcode values** — always use token references for consistency and theme support. + +> **Golden Rule:** Always use `OudsTheme.*` tokens instead of hardcoded values. +> ```kotlin +> // ✅ CORRECT +> Text( +> text = "Title", +> color = OudsTheme.colorScheme.content.default, +> style = OudsTheme.typography.heading.large +> ) +> Box( +> modifier = Modifier +> .padding(OudsTheme.spaces.fixed.medium) +> .border( +> width = OudsTheme.borders.width.default, +> color = OudsTheme.colorScheme.border.default +> ) +> ) +> +> // ❌ INCORRECT +> Text(text = "Title", color = Color.Black, fontSize = 16.sp) +> Box(modifier = Modifier.padding(16.dp)) +> ``` + +## Table of Contents + +- [Color Scheme](#color-scheme-oudsthemecolorscheme) +- [Typography](#typography-oudsthemetypography) +- [Spacing](#spacing-oudsthemespaces) +- [Sizes](#sizes-oudsthemesizes) +- [Borders](#borders-oudsthemeborders) +- [Elevations](#elevations-oudsthemeelevations) +- [Opacities](#opacities-oudsthemeopacities) +- [Effects](#effects-oudsthemeeffects) +- [Grids](#grids-oudsthemegrids) +- [Usage Examples](#usage-examples) + +> **Advanced Usage:** For component-level tokens (`@RestrictedOudsApi`), see [`component-tokens.md`](component-tokens.md). + +--- + +## Color Scheme (`OudsTheme.colorScheme`) + +**Design guidelines:** [Color tokens documentation](https://r.orange.fr/r/S-ouds-doc-token-color) + +> Color tokens are **auto-adaptive**: they automatically adjust between Light and Dark modes. + +### Actions + +Interactive element colors for buttons, links, and actionable items. + +| Token | Usage | +|-------|-------| +| `OudsTheme.colorScheme.action.enabled` | Primary action color (enabled button, active link) | +| `OudsTheme.colorScheme.action.disabled` | Disabled action state | +| `OudsTheme.colorScheme.action.hover` | Hover state | +| `OudsTheme.colorScheme.action.pressed` | Pressed/tap state | +| `OudsTheme.colorScheme.action.focus` | Focus state | +| `OudsTheme.colorScheme.action.loading` | Loading state | +| `OudsTheme.colorScheme.action.highlighted` | Highlighted state | +| `OudsTheme.colorScheme.action.selected` | Selected state | +| `OudsTheme.colorScheme.action.visited` | Visited link state | +| `OudsTheme.colorScheme.action.readOnlyPrimary` | Read-only primary | +| `OudsTheme.colorScheme.action.readOnlySecondary` | Read-only secondary | +| `OudsTheme.colorScheme.action.negative.enabled` | Destructive action enabled | +| `OudsTheme.colorScheme.action.negative.hover` | Destructive action hover | +| `OudsTheme.colorScheme.action.negative.pressed` | Destructive action pressed | +| `OudsTheme.colorScheme.action.negative.loading` | Destructive action loading | +| `OudsTheme.colorScheme.action.negative.focus` | Destructive action focus | +| `OudsTheme.colorScheme.action.support.enabled` | Support/secondary action enabled | +| `OudsTheme.colorScheme.action.support.disabled` | Support/secondary action disabled | +| `OudsTheme.colorScheme.action.support.hover` | Support action hover | +| `OudsTheme.colorScheme.action.support.pressed` | Support action pressed | +| `OudsTheme.colorScheme.action.support.focus` | Support action focus | +| `OudsTheme.colorScheme.action.support.loading` | Support action loading | + +```kotlin +// Action colors in use +Button( + onClick = { }, + colors = ButtonDefaults.buttonColors( + containerColor = OudsTheme.colorScheme.action.enabled, + contentColor = OudsTheme.colorScheme.content.onAction.enabled, + disabledContainerColor = OudsTheme.colorScheme.action.disabled + ) +) { + Text("Action") +} +``` + +### Always + +Colors that remain constant regardless of Light/Dark mode. + +| Token | Usage | +|-------|-------| +| `OudsTheme.colorScheme.always.black` | Absolute black (mode-independent) | +| `OudsTheme.colorScheme.always.white` | Absolute white (mode-independent) | +| `OudsTheme.colorScheme.always.onBlack` | Content on absolute black | +| `OudsTheme.colorScheme.always.onWhite` | Content on absolute white | + +```kotlin +// Always colors for mode-independent elements +Surface(color = OudsTheme.colorScheme.always.black) { + Text( + text = "Always visible", + color = OudsTheme.colorScheme.always.onBlack + ) +} +``` + +### Background + +Page and screen background colors. + +| Token | Usage | +|-------|-------| +| `OudsTheme.colorScheme.background.primary` | Primary page background | +| `OudsTheme.colorScheme.background.secondary` | Secondary background (sections) | +| `OudsTheme.colorScheme.background.tertiary` | Tertiary background | +| `OudsTheme.colorScheme.background.inverseHigh` | High contrast inverse background | +| `OudsTheme.colorScheme.background.inverseLow` | Low contrast inverse background | + +### Border + +Border and divider colors. + +| Token | Usage | +|-------|-------| +| `OudsTheme.colorScheme.border.default` | Standard border | +| `OudsTheme.colorScheme.border.muted` | Subtle border | +| `OudsTheme.colorScheme.border.emphasized` | Strong border | +| `OudsTheme.colorScheme.border.minimal` | Minimal border | +| `OudsTheme.colorScheme.border.focus` | Focus ring (outer) | +| `OudsTheme.colorScheme.border.focusInset` | Focus ring (inner/inset) | +| `OudsTheme.colorScheme.border.brandPrimary` | Brand-colored border | +| `OudsTheme.colorScheme.border.brandSecondary` | Brand secondary border | +| `OudsTheme.colorScheme.border.brandTertiary` | Brand tertiary border | +| `OudsTheme.colorScheme.border.onBrand.primary` | Border on brand primary background | +| `OudsTheme.colorScheme.border.onBrand.secondary` | Border on brand secondary background | +| `OudsTheme.colorScheme.border.onBrand.tertiary` | Border on brand tertiary background | +| `OudsTheme.colorScheme.border.status.accent` | Accent status border | +| `OudsTheme.colorScheme.border.status.negative` | Error/negative border | +| `OudsTheme.colorScheme.border.status.positive` | Success/positive border | +| `OudsTheme.colorScheme.border.status.warning` | Warning border | +| `OudsTheme.colorScheme.border.status.info` | Info border | + +```kotlin +// Border colors +Box( + modifier = Modifier.border( + width = OudsTheme.borders.width.default, + color = OudsTheme.colorScheme.border.default, + shape = RoundedCornerShape(OudsTheme.borders.radius.medium) + ) +) +``` + +### Content + +Text, icon, and foreground element colors. + +| Token | Usage | +|-------|-------| +| `OudsTheme.colorScheme.content.default` | Primary text/icon color | +| `OudsTheme.colorScheme.content.muted` | Secondary text, hints, captions | +| `OudsTheme.colorScheme.content.disabled` | Disabled text/icon | +| `OudsTheme.colorScheme.content.inverse` | Text on inverse background | +| `OudsTheme.colorScheme.content.brandPrimary` | Brand primary colored text | +| `OudsTheme.colorScheme.content.brandSecondary` | Brand secondary colored text | +| `OudsTheme.colorScheme.content.brandTertiary` | Brand tertiary colored text | +| `OudsTheme.colorScheme.content.onAction.enabled` | Content on enabled action background | +| `OudsTheme.colorScheme.content.onAction.disabled` | Content on disabled action background | +| `OudsTheme.colorScheme.content.onAction.focus` | Content on focused action | +| `OudsTheme.colorScheme.content.onAction.highlighted` | Content on highlighted action | +| `OudsTheme.colorScheme.content.onAction.hover` | Content on hovered action | +| `OudsTheme.colorScheme.content.onAction.loading` | Content on loading action | +| `OudsTheme.colorScheme.content.onAction.pressed` | Content on pressed action | +| `OudsTheme.colorScheme.content.onAction.selected` | Content on selected action | +| `OudsTheme.colorScheme.content.onBrand.primary` | Text on brand primary background | +| `OudsTheme.colorScheme.content.onBrand.secondary` | Text on brand secondary background | +| `OudsTheme.colorScheme.content.onBrand.tertiary` | Text on brand tertiary background | +| `OudsTheme.colorScheme.content.onStatus.accent.emphasized` | Text on accent emphasized background | +| `OudsTheme.colorScheme.content.onStatus.accent.muted` | Text on accent muted background | +| `OudsTheme.colorScheme.content.onStatus.info.emphasized` | Text on info emphasized background | +| `OudsTheme.colorScheme.content.onStatus.info.muted` | Text on info muted background | +| `OudsTheme.colorScheme.content.onStatus.negative.emphasized` | Text on error emphasized background | +| `OudsTheme.colorScheme.content.onStatus.negative.muted` | Text on error muted background | +| `OudsTheme.colorScheme.content.onStatus.positive.emphasized` | Text on success emphasized background | +| `OudsTheme.colorScheme.content.onStatus.positive.muted` | Text on success muted background | +| `OudsTheme.colorScheme.content.onStatus.warning.emphasized` | Text on warning emphasized background | +| `OudsTheme.colorScheme.content.onStatus.warning.muted` | Text on warning muted background | +| `OudsTheme.colorScheme.content.status.accent` | Accent colored text | +| `OudsTheme.colorScheme.content.status.info` | Info colored text | +| `OudsTheme.colorScheme.content.status.negative` | Error colored text | +| `OudsTheme.colorScheme.content.status.positive` | Success colored text | +| `OudsTheme.colorScheme.content.status.warning` | Warning colored text | + +```kotlin +// Content colors for text hierarchy +Column { + Text( + text = stringResource(R.string.title), + color = OudsTheme.colorScheme.content.default, + style = OudsTheme.typography.heading.large + ) + Text( + text = stringResource(R.string.subtitle), + color = OudsTheme.colorScheme.content.muted, + style = OudsTheme.typography.body.medium.default + ) +} +``` + +### Opacity + +Transparency colors. + +| Token | Usage | +|-------|-------| +| `OudsTheme.colorScheme.opacity.transparent` | Fully transparent | +| `OudsTheme.colorScheme.opacity.lowest` | Very high transparency | +| `OudsTheme.colorScheme.opacity.lower` | High transparency | + +### Overlay + +Overlay, modal, and tooltip background colors. + +| Token | Usage | +|-------|-------| +| `OudsTheme.colorScheme.overlay.backdrop` | Modal backdrop/scrim | +| `OudsTheme.colorScheme.overlay.modalSheet` | Bottom sheet background | +| `OudsTheme.colorScheme.overlay.dropdown` | Dropdown background | +| `OudsTheme.colorScheme.overlay.tooltip` | Tooltip background | +| `OudsTheme.colorScheme.overlay.drag` | Drag overlay | + +### Surface + +Surface colors for cards, dialogs, and elevated components. + +| Token | Usage | +|-------|-------| +| `OudsTheme.colorScheme.surface.primary` | Primary surface (cards, modals) | +| `OudsTheme.colorScheme.surface.secondary` | Secondary surface | +| `OudsTheme.colorScheme.surface.tertiary` | Tertiary surface | +| `OudsTheme.colorScheme.surface.inverseHigh` | High contrast inverse surface | +| `OudsTheme.colorScheme.surface.inverseLow` | Low contrast inverse surface | +| `OudsTheme.colorScheme.surface.brand.primary` | Brand primary surface | +| `OudsTheme.colorScheme.surface.brand.secondary` | Brand secondary surface | +| `OudsTheme.colorScheme.surface.brand.tertiary` | Brand tertiary surface | +| `OudsTheme.colorScheme.surface.status.accent.emphasized` | Accent emphasized surface | +| `OudsTheme.colorScheme.surface.status.accent.muted` | Accent muted surface | +| `OudsTheme.colorScheme.surface.status.info.emphasized` | Info emphasized surface | +| `OudsTheme.colorScheme.surface.status.info.muted` | Info muted surface | +| `OudsTheme.colorScheme.surface.status.negative.emphasized` | Error emphasized surface | +| `OudsTheme.colorScheme.surface.status.negative.muted` | Error muted surface | +| `OudsTheme.colorScheme.surface.status.positive.emphasized` | Success emphasized surface | +| `OudsTheme.colorScheme.surface.status.positive.muted` | Success muted surface | +| `OudsTheme.colorScheme.surface.status.warning.emphasized` | Warning emphasized surface | +| `OudsTheme.colorScheme.surface.status.warning.muted` | Warning muted surface | + +--- + +## Typography (`OudsTheme.typography`) + +**Design guidelines:** [Typography tokens documentation](https://r.orange.fr/r/S-ouds-doc-token-typography) + +> Text styles that automatically adapt to screen size (mobile/tablet). + +| Token | Recommended Usage | +|-------|-------------------| +| `OudsTheme.typography.display.large` | Hero title, splash screens | +| `OudsTheme.typography.display.medium` | Large display title | +| `OudsTheme.typography.display.small` | Medium display title | +| `OudsTheme.typography.heading.extraLarge` | H0 — Main page title | +| `OudsTheme.typography.heading.large` | H1 — Primary section title | +| `OudsTheme.typography.heading.medium` | H2 — Subsection title | +| `OudsTheme.typography.heading.small` | H3 — Group title | +| `OudsTheme.typography.body.large.default` | Large body text (regular weight) | +| `OudsTheme.typography.body.large.moderate` | Large body text (medium weight) | +| `OudsTheme.typography.body.large.strong` | Large body text (bold weight) | +| `OudsTheme.typography.body.medium.default` | Standard body text (regular) | +| `OudsTheme.typography.body.medium.moderate` | Standard body text (medium) | +| `OudsTheme.typography.body.medium.strong` | Standard body text (bold) | +| `OudsTheme.typography.body.small.default` | Compact body text (regular) | +| `OudsTheme.typography.body.small.moderate` | Compact body text (medium) | +| `OudsTheme.typography.body.small.strong` | Compact body text (bold) | +| `OudsTheme.typography.label.extraLarge.default` | XL label (regular) | +| `OudsTheme.typography.label.extraLarge.moderate` | XL label (medium) | +| `OudsTheme.typography.label.extraLarge.strong` | XL label (bold, for buttons) | +| `OudsTheme.typography.label.large.default` | Large label (regular) | +| `OudsTheme.typography.label.large.moderate` | Large label (medium) | +| `OudsTheme.typography.label.large.strong` | Large label (bold) | +| `OudsTheme.typography.label.medium.default` | Medium label (regular) | +| `OudsTheme.typography.label.medium.moderate` | Medium label (medium) | +| `OudsTheme.typography.label.medium.strong` | Medium label (bold) | +| `OudsTheme.typography.label.small.default` | Small label (regular) | +| `OudsTheme.typography.label.small.moderate` | Small label (medium) | +| `OudsTheme.typography.label.small.strong` | Small label (bold) | + +```kotlin +// Typography hierarchy +Column(verticalArrangement = Arrangement.spacedBy(OudsTheme.spaces.fixed.small)) { + Text( + text = stringResource(R.string.page_title), + style = OudsTheme.typography.heading.large + ) + Text( + text = stringResource(R.string.section_title), + style = OudsTheme.typography.heading.medium + ) + Text( + text = stringResource(R.string.body), + style = OudsTheme.typography.body.medium.default + ) + Text( + text = stringResource(R.string.caption), + style = OudsTheme.typography.label.small.default, + color = OudsTheme.colorScheme.content.muted + ) +} +``` + +--- + +## Spacing (`OudsTheme.spaces`) + +**Design guidelines:** [Space tokens documentation](https://r.orange.fr/r/S-ouds-doc-token-space) + +### Fixed Spaces + +Fixed spacing values that remain constant regardless of screen size. + +| Token | Approximate Size | +|-------|-----------------| +| `OudsTheme.spaces.fixed.none` | 0 dp | +| `OudsTheme.spaces.fixed.threeExtraSmall` | ~2 dp | +| `OudsTheme.spaces.fixed.twoExtraSmall` | ~4 dp | +| `OudsTheme.spaces.fixed.extraSmall` | ~8 dp | +| `OudsTheme.spaces.fixed.small` | ~12 dp | +| `OudsTheme.spaces.fixed.medium` | ~16 dp | +| `OudsTheme.spaces.fixed.large` | ~24 dp | +| `OudsTheme.spaces.fixed.extraLarge` | ~32 dp | +| `OudsTheme.spaces.fixed.twoExtraLarge` | ~40 dp | +| `OudsTheme.spaces.fixed.threeExtraLarge` | ~48 dp | +| `OudsTheme.spaces.fixed.fourExtraLarge` | ~64 dp | +| `OudsTheme.spaces.fixed.fiveExtraLarge` | ~80 dp | + +### Scaled Spaces + +Adaptive spacing values that adjust based on screen size (mobile vs tablet). + +| Token | Usage | +|-------|-------| +| `OudsTheme.spaces.scaled.none` | 0 dp | +| `OudsTheme.spaces.scaled.threeExtraSmall` | Very compact spacing | +| `OudsTheme.spaces.scaled.twoExtraSmall` | Very compact spacing | +| `OudsTheme.spaces.scaled.extraSmall` | Compact spacing | +| `OudsTheme.spaces.scaled.small` | Small spacing | +| `OudsTheme.spaces.scaled.medium` | Medium spacing | +| `OudsTheme.spaces.scaled.large` | Large spacing | +| `OudsTheme.spaces.scaled.extraLarge` | Very large spacing | +| `OudsTheme.spaces.scaled.twoExtraLarge` | 2XL spacing | +| `OudsTheme.spaces.scaled.threeExtraLarge` | 3XL spacing | + +```kotlin +// Fixed spacing for consistent layouts +Card( + modifier = Modifier.padding(OudsTheme.spaces.fixed.medium) +) { + Column( + modifier = Modifier.padding(OudsTheme.spaces.fixed.large), + verticalArrangement = Arrangement.spacedBy(OudsTheme.spaces.fixed.small) + ) { + Text(stringResource(R.string.title)) + Text(stringResource(R.string.content)) + } +} + +// Scaled spacing for responsive layouts +Column( + modifier = Modifier.padding(OudsTheme.spaces.scaled.medium), + verticalArrangement = Arrangement.spacedBy(OudsTheme.spaces.scaled.small) +) { + // Content adapts spacing to screen size +} +``` + +--- + +## Sizes (`OudsTheme.sizes`) + +**Design guidelines:** [Size tokens documentation](https://r.orange.fr/r/S-ouds-doc-token-size) + +### Icon Sizes — Decorative + +General-purpose icon sizes for standalone icons without textual context. + +| Token | Usage | +|-------|-------| +| `OudsTheme.sizes.icon.decorative.fourExtraSmall` | Tiny icon | +| `OudsTheme.sizes.icon.decorative.threeExtraSmall` | Very small icon | +| `OudsTheme.sizes.icon.decorative.twoExtraSmall` | Extra small icon | +| `OudsTheme.sizes.icon.decorative.extraSmall` | Small icon | +| `OudsTheme.sizes.icon.decorative.small` | Small-standard icon | +| `OudsTheme.sizes.icon.decorative.medium` | Standard icon (common use) | +| `OudsTheme.sizes.icon.decorative.large` | Large icon | +| `OudsTheme.sizes.icon.decorative.extraLarge` | Very large icon | +| `OudsTheme.sizes.icon.decorative.twoExtraLarge` | 2XL icon | + +### Icon Sizes — Contextual + +Icon sizes paired with text elements for proper alignment. + +```kotlin +// Icon with label +OudsTheme.sizes.icon.withLabel.small.sizeExtraSmall +OudsTheme.sizes.icon.withLabel.small.sizeSmall +OudsTheme.sizes.icon.withLabel.small.sizeMedium +OudsTheme.sizes.icon.withLabel.small.sizeLarge +OudsTheme.sizes.icon.withLabel.medium.sizeExtraSmall +OudsTheme.sizes.icon.withLabel.medium.sizeSmall +OudsTheme.sizes.icon.withLabel.medium.sizeMedium +OudsTheme.sizes.icon.withLabel.medium.sizeLarge +OudsTheme.sizes.icon.withLabel.large.sizeExtraSmall +OudsTheme.sizes.icon.withLabel.large.sizeSmall +OudsTheme.sizes.icon.withLabel.large.sizeMedium +OudsTheme.sizes.icon.withLabel.large.sizeLarge +OudsTheme.sizes.icon.withLabel.large.sizeExtraLarge +OudsTheme.sizes.icon.withLabel.extraLarge.sizeExtraSmall +OudsTheme.sizes.icon.withLabel.extraLarge.sizeSmall +OudsTheme.sizes.icon.withLabel.extraLarge.sizeMedium +OudsTheme.sizes.icon.withLabel.extraLarge.sizeLarge + +// Icon with body text +OudsTheme.sizes.icon.withBody.small.sizeSmall +OudsTheme.sizes.icon.withBody.small.sizeMedium +OudsTheme.sizes.icon.withBody.small.sizeLarge +OudsTheme.sizes.icon.withBody.medium.sizeSmall +OudsTheme.sizes.icon.withBody.medium.sizeMedium +OudsTheme.sizes.icon.withBody.medium.sizeLarge +OudsTheme.sizes.icon.withBody.large.sizeSmall +OudsTheme.sizes.icon.withBody.large.sizeMedium +OudsTheme.sizes.icon.withBody.large.sizeLarge + +// Icon with heading +OudsTheme.sizes.icon.withHeading.small.sizeSmall +OudsTheme.sizes.icon.withHeading.small.sizeMedium +OudsTheme.sizes.icon.withHeading.small.sizeLarge +OudsTheme.sizes.icon.withHeading.medium.sizeSmall +OudsTheme.sizes.icon.withHeading.medium.sizeMedium +OudsTheme.sizes.icon.withHeading.medium.sizeLarge +OudsTheme.sizes.icon.withHeading.large.sizeSmall +OudsTheme.sizes.icon.withHeading.large.sizeMedium +OudsTheme.sizes.icon.withHeading.large.sizeLarge +OudsTheme.sizes.icon.withHeading.extraLarge.sizeSmall +OudsTheme.sizes.icon.withHeading.extraLarge.sizeMedium +OudsTheme.sizes.icon.withHeading.extraLarge.sizeLarge +``` + +### Max Width Constraints + +Maximum width constraints for readable text blocks. + +```kotlin +// Body text +OudsTheme.sizes.maxWidth.body.small +OudsTheme.sizes.maxWidth.body.medium +OudsTheme.sizes.maxWidth.body.large + +// Display text +OudsTheme.sizes.maxWidth.display.small +OudsTheme.sizes.maxWidth.display.medium +OudsTheme.sizes.maxWidth.display.large + +// Heading text +OudsTheme.sizes.maxWidth.heading.small +OudsTheme.sizes.maxWidth.heading.medium +OudsTheme.sizes.maxWidth.heading.large +OudsTheme.sizes.maxWidth.heading.extraLarge + +// Label text +OudsTheme.sizes.maxWidth.label.small +OudsTheme.sizes.maxWidth.label.medium +OudsTheme.sizes.maxWidth.label.large +OudsTheme.sizes.maxWidth.label.extraLarge +``` + +### Minimum Interactive Area + +Minimum touch target size for accessibility. + +```kotlin +OudsTheme.sizes.minInteractiveArea // General minimum touch target +``` + +```kotlin +// Using icon sizes +Icon( + imageVector = Icons.Default.Settings, + contentDescription = stringResource(R.string.settings), + modifier = Modifier.size(OudsTheme.sizes.icon.decorative.medium) +) + +// Using max width for readable text +Text( + text = stringResource(R.string.long_content), + style = OudsTheme.typography.body.medium.default, + modifier = Modifier.widthIn(max = OudsTheme.sizes.maxWidth.body.medium) +) +``` + +--- + +## Borders (`OudsTheme.borders`) + +**Design guidelines:** [Border tokens documentation](https://r.orange.fr/r/S-ouds-doc-token-border) + +### Width + +Border stroke widths. + +| Token | Usage | +|-------|-------| +| `OudsTheme.borders.width.none` | No border (0 dp) | +| `OudsTheme.borders.width.default` | Standard border width | +| `OudsTheme.borders.width.thin` | Thin border | +| `OudsTheme.borders.width.medium` | Medium border | +| `OudsTheme.borders.width.thick` | Thick border | +| `OudsTheme.borders.width.thicker` | Very thick border | +| `OudsTheme.borders.width.focus` | Focus ring (outer) | +| `OudsTheme.borders.width.focusInset` | Focus ring (inner/inset) | + +### Radius + +Corner rounding radii. + +| Token | Usage | +|-------|-------| +| `OudsTheme.borders.radius.none` | Square corners (0 dp) | +| `OudsTheme.borders.radius.default` | Standard rounding | +| `OudsTheme.borders.radius.small` | Slight rounding | +| `OudsTheme.borders.radius.medium` | Medium rounding (cards, chips) | +| `OudsTheme.borders.radius.large` | Large rounding | +| `OudsTheme.borders.radius.pill` | Pill/capsule shape (buttons, badges) | + +### Style + +Border stroke styles. + +| Token | Usage | +|-------|-------| +| `OudsTheme.borders.style.default` | Solid border | +| `OudsTheme.borders.style.drag` | Dashed border (drag & drop) | + +```kotlin +// Using border tokens +Box( + modifier = Modifier + .size(100.dp) + .border( + width = OudsTheme.borders.width.default, + color = OudsTheme.colorScheme.border.default, + shape = RoundedCornerShape(OudsTheme.borders.radius.medium) + ) +) + +// Card with border +Card( + shape = RoundedCornerShape(OudsTheme.borders.radius.large), + border = BorderStroke( + width = OudsTheme.borders.width.thin, + color = OudsTheme.colorScheme.border.muted + ) +) { + // Content +} +``` + +--- + +## Elevations (`OudsTheme.elevations`) + +**Design guidelines:** [Elevation tokens documentation](https://r.orange.fr/r/S-ouds-doc-token-elevation) + +Shadow and z-axis elevation values. + +| Token | Usage | +|-------|-------| +| `OudsTheme.elevations.none` | No shadow (0 dp) | +| `OudsTheme.elevations.default` | Default elevation | +| `OudsTheme.elevations.raised` | Raised card elevation | +| `OudsTheme.elevations.sticky` | Sticky/floating bar elevation | +| `OudsTheme.elevations.drag` | Drag & drop elevation | +| `OudsTheme.elevations.emphasized` | Modal/dialog elevation | + +```kotlin +// Using elevations +Card( + elevation = CardDefaults.cardElevation( + defaultElevation = OudsTheme.elevations.raised + ) +) { + // Content +} + +Surface( + shadowElevation = OudsTheme.elevations.emphasized, + shape = RoundedCornerShape(OudsTheme.borders.radius.medium) +) { + // Modal content +} +``` + +--- + +## Opacities (`OudsTheme.opacities`) + +**Design guidelines:** [Opacity tokens documentation](https://r.orange.fr/r/S-ouds-doc-token-opacity) + +Transparency alpha values (Float, 0.0 to 1.0). + +| Token | Value Range | Usage | +|-------|------------|-------| +| `OudsTheme.opacities.invisible` | 0.0 | Fully transparent | +| `OudsTheme.opacities.weakest` | Very low | Very subtle overlay | +| `OudsTheme.opacities.weaker` | Low | Subtle overlay | +| `OudsTheme.opacities.weak` | Medium-low | Light overlay | +| `OudsTheme.opacities.medium` | Medium | Standard overlay | +| `OudsTheme.opacities.strong` | Medium-high | Strong overlay | +| `OudsTheme.opacities.disabled` | Variable | Disabled state opacity | +| `OudsTheme.opacities.opaque` | 1.0 | Fully opaque | + +```kotlin +// Using opacity +Box( + modifier = Modifier + .fillMaxSize() + .background( + OudsTheme.colorScheme.always.black.copy( + alpha = OudsTheme.opacities.medium + ) + ) +) +``` + +--- + +## Effects (`OudsTheme.effects`) + +Visual effect values. + +| Token | Usage | +|-------|-------| +| `OudsTheme.effects.blurDrag` | Blur radius for drag effects (Int) | + +--- + +## Grids (`OudsTheme.grids`) + +**Design guidelines:** [Grid tokens documentation](https://r.orange.fr/r/S-ouds-doc-token-grid) + +Grid layout properties that adapt to screen size. + +| Token | Usage | +|-------|-------| +| `OudsTheme.grids.minWidth` | Minimum grid column width | +| `OudsTheme.grids.maxWidth` | Maximum grid column width | +| `OudsTheme.grids.margin` | Grid outer margin | +| `OudsTheme.grids.columnGap` | Gap between grid columns | + +```kotlin +// Using grid tokens +LazyVerticalGrid( + columns = GridCells.Adaptive(minSize = OudsTheme.grids.minWidth), + contentPadding = PaddingValues(OudsTheme.grids.margin), + horizontalArrangement = Arrangement.spacedBy(OudsTheme.grids.columnGap) +) { + // Grid items +} +``` + +--- + +## Usage Examples + +### Complete Card Layout + +```kotlin +@Composable +fun ProductCard() { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(OudsTheme.spaces.fixed.medium), + shape = RoundedCornerShape(OudsTheme.borders.radius.large), + elevation = CardDefaults.cardElevation( + defaultElevation = OudsTheme.elevations.raised + ), + border = BorderStroke( + width = OudsTheme.borders.width.thin, + color = OudsTheme.colorScheme.border.muted + ) + ) { + Column( + modifier = Modifier.padding(OudsTheme.spaces.fixed.large), + verticalArrangement = Arrangement.spacedBy(OudsTheme.spaces.fixed.small) + ) { + Text( + text = stringResource(R.string.product_name), + style = OudsTheme.typography.heading.medium, + color = OudsTheme.colorScheme.content.default + ) + Text( + text = stringResource(R.string.product_description), + style = OudsTheme.typography.body.medium.default, + color = OudsTheme.colorScheme.content.muted, + modifier = Modifier.widthIn(max = OudsTheme.sizes.maxWidth.body.medium) + ) + Row( + horizontalArrangement = Arrangement.spacedBy(OudsTheme.spaces.fixed.small) + ) { + Icon( + imageVector = Icons.Default.Star, + contentDescription = null, + modifier = Modifier.size(OudsTheme.sizes.icon.decorative.small), + tint = OudsTheme.colorScheme.content.status.positive + ) + Text( + text = "4.5", + style = OudsTheme.typography.label.medium.strong + ) + } + } + } +} +``` + +### Styled Button + +```kotlin +@Composable +fun CustomStyledButton() { + Button( + onClick = { }, + colors = ButtonDefaults.buttonColors( + containerColor = OudsTheme.colorScheme.action.enabled, + contentColor = OudsTheme.colorScheme.content.onAction.enabled + ), + shape = RoundedCornerShape(OudsTheme.borders.radius.pill), + elevation = ButtonDefaults.buttonElevation( + defaultElevation = OudsTheme.elevations.raised + ), + contentPadding = PaddingValues( + horizontal = OudsTheme.spaces.fixed.large, + vertical = OudsTheme.spaces.fixed.medium + ) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(OudsTheme.spaces.fixed.small), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Default.Add, + contentDescription = null, + modifier = Modifier.size(OudsTheme.sizes.icon.decorative.small) + ) + Text( + text = stringResource(R.string.add_to_cart), + style = OudsTheme.typography.label.large.strong + ) + } + } +} +``` + +### Text Hierarchy + +```kotlin +@Composable +fun ArticleContent() { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(OudsTheme.spaces.fixed.large), + verticalArrangement = Arrangement.spacedBy(OudsTheme.spaces.fixed.medium) + ) { + Text( + text = stringResource(R.string.article_title), + style = OudsTheme.typography.heading.large, + color = OudsTheme.colorScheme.content.default + ) + Text( + text = stringResource(R.string.article_subtitle), + style = OudsTheme.typography.heading.small, + color = OudsTheme.colorScheme.content.muted + ) + HorizontalDivider( + thickness = OudsTheme.borders.width.thin, + color = OudsTheme.colorScheme.border.muted + ) + Text( + text = stringResource(R.string.article_body), + style = OudsTheme.typography.body.medium.default, + color = OudsTheme.colorScheme.content.default, + modifier = Modifier.widthIn(max = OudsTheme.sizes.maxWidth.body.medium) + ) + Text( + text = stringResource(R.string.article_caption), + style = OudsTheme.typography.label.small.default, + color = OudsTheme.colorScheme.content.muted + ) + } +} +``` + +--- + +## Token Generation + +All OUDS tokens are **generated by Tokenator**, a tool that converts Figma design tokens to Kotlin code. Generated files include comments like: + +```kotlin +// Orange brand tokens version 2.5.0 +// Generated by Tokenator +``` + +**Do not manually edit generated token files.** All token modifications must be made in Figma and regenerated through Tokenator. + +--- + +## References + +- **Documentation:** https://android.unified-design-system.orange.com/ +- **Repository:** https://github.com/Orange-OpenSource/ouds-android +- **Design System:** https://unified-design-system.orange.com/ +- **Color Guidelines:** https://r.orange.fr/r/S-ouds-doc-token-color +- **Typography Guidelines:** https://r.orange.fr/r/S-ouds-doc-token-typography +- **Space Guidelines:** https://r.orange.fr/r/S-ouds-doc-token-space +- **Size Guidelines:** https://r.orange.fr/r/S-ouds-doc-token-size +- **Border Guidelines:** https://r.orange.fr/r/S-ouds-doc-token-border +- **Elevation Guidelines:** https://r.orange.fr/r/S-ouds-doc-token-elevation +- **Opacity Guidelines:** https://r.orange.fr/r/S-ouds-doc-token-opacity +- **Grid Guidelines:** https://r.orange.fr/r/S-ouds-doc-token-grid From 48b8bc4371ae0da2d453ffcb9d5c5f19f92a1a79 Mon Sep 17 00:00:00 2001 From: Pauline Auvray Date: Thu, 30 Jul 2026 16:37:26 +0200 Subject: [PATCH 6/9] Rename skills using gerund --- AGENTS.md | 8 ++++---- .../SKILL.md | 6 +++--- .../SKILL.md | 2 +- .../references/component-tokens.md | 0 .../references/components.md | 0 .../references/tokens.md | 0 6 files changed, 8 insertions(+), 8 deletions(-) rename skills/{ouds-android-vocabulary => understanding-ouds-android-vocabulary}/SKILL.md (96%) rename skills/{ouds-android-framework-usage => using-ouds-android}/SKILL.md (99%) rename skills/{ouds-android-framework-usage => using-ouds-android}/references/component-tokens.md (100%) rename skills/{ouds-android-framework-usage => using-ouds-android}/references/components.md (100%) rename skills/{ouds-android-framework-usage => using-ouds-android}/references/tokens.md (100%) diff --git a/AGENTS.md b/AGENTS.md index 38b3e68c9a..a2efdeacf7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -214,16 +214,16 @@ Agent skills are located in the `skills/` directory at the repository root. The | Skill | When to load | |---|---| -| `ouds-android-vocabulary` | User asks to explain, define, or understand OUDS-specific terminology and concepts (tokens, Tokenator, OudsThemeContract, tinted, OudsError, etc.) or relationships between OUDS architecture elements | -| `ouds-android-framework-usage` | User needs to write code, create components, set up OUDS, configure themes, access tokens, or use any Ouds* component in Kotlin/Compose | +| `understanding-ouds-android-vocabulary` | User asks to explain, define, or understand OUDS-specific terminology and concepts (tokens, Tokenator, OudsThemeContract, tinted, OudsError, etc.) or relationships between OUDS architecture elements | +| `using-ouds-android` | User needs to write code, create components, set up OUDS, configure themes, access tokens, or use any Ouds* component in Kotlin/Compose | ### Skill structure ``` skills/ -├── ouds-android-vocabulary/ +├── understanding-ouds-android-vocabulary/ │ └── SKILL.md ← vocabulary definitions and token hierarchy -└── ouds-android-framework-usage/ +└── using-ouds-android/ ├── SKILL.md ← setup, themes, token access, common patterns, checklist └── references/ └── components.md ← full component signatures and usage examples diff --git a/skills/ouds-android-vocabulary/SKILL.md b/skills/understanding-ouds-android-vocabulary/SKILL.md similarity index 96% rename from skills/ouds-android-vocabulary/SKILL.md rename to skills/understanding-ouds-android-vocabulary/SKILL.md index 3909ed0277..870f8e78d8 100644 --- a/skills/ouds-android-vocabulary/SKILL.md +++ b/skills/understanding-ouds-android-vocabulary/SKILL.md @@ -1,5 +1,5 @@ --- -name: ouds-android-vocabulary +name: understanding-ouds-android-vocabulary description: Use this skill whenever the user asks about OUDS-specific terminology, concepts, or vocabulary. This includes questions about tokens (raw, semantic, component), Tokenator, OudsThemeContract, OudsTheme, OudsColoredBox, tinted parameters, OudsError, or any OUDS-specific classes and patterns. ALWAYS trigger when the user asks to explain, define, clarify, or understand the difference between OUDS concepts, even if they don't explicitly say 'what is' or 'define'. Also trigger when they ask about relationships between OUDS architecture elements (e.g., how tokens relate to each other, theme hierarchy). license: MIT --- @@ -61,5 +61,5 @@ Figma design tokens | Task | Skill to load | |---|---| -| Write or review Kotlin/Compose code using OUDS components or tokens | `ouds-android-framework-usage` | -| Ask about OUDS-specific terminology | `ouds-android-vocabulary` (this skill) | +| Write or review Kotlin/Compose code using OUDS components or tokens | `using-ouds-android` | +| Ask about OUDS-specific terminology | `understanding-ouds-android-vocabulary` (this skill) | diff --git a/skills/ouds-android-framework-usage/SKILL.md b/skills/using-ouds-android/SKILL.md similarity index 99% rename from skills/ouds-android-framework-usage/SKILL.md rename to skills/using-ouds-android/SKILL.md index ef767fd9e0..fe54f06fc1 100644 --- a/skills/ouds-android-framework-usage/SKILL.md +++ b/skills/using-ouds-android/SKILL.md @@ -1,5 +1,5 @@ --- -name: ouds-android-framework-usage +name: using-ouds-android description: Use this skill whenever the user needs to write code using OUDS Android components, set up the library, configure themes, or access design tokens in Kotlin/Compose. This includes adding dependencies, wrapping UI with OudsTheme, creating any Ouds* component (OudsButton, OudsTextInput, OudsNavigationBar, etc.), accessing tokens via OudsTheme.colorScheme/spaces/typography, configuring fonts, handling tinted/untinted icons, using OudsColoredBox, showing error messages, or switching themes dynamically. ALWAYS trigger when the user asks to 'create', 'show me how', 'write a composable', 'set up', or 'access' anything related to OUDS components or tokens, even if they don't explicitly mention 'OUDS framework'. license: MIT --- diff --git a/skills/ouds-android-framework-usage/references/component-tokens.md b/skills/using-ouds-android/references/component-tokens.md similarity index 100% rename from skills/ouds-android-framework-usage/references/component-tokens.md rename to skills/using-ouds-android/references/component-tokens.md diff --git a/skills/ouds-android-framework-usage/references/components.md b/skills/using-ouds-android/references/components.md similarity index 100% rename from skills/ouds-android-framework-usage/references/components.md rename to skills/using-ouds-android/references/components.md diff --git a/skills/ouds-android-framework-usage/references/tokens.md b/skills/using-ouds-android/references/tokens.md similarity index 100% rename from skills/ouds-android-framework-usage/references/tokens.md rename to skills/using-ouds-android/references/tokens.md From e32ea2671377a3eb19b976e5fa3846011fa8ee27 Mon Sep 17 00:00:00 2001 From: Pauline Auvray Date: Thu, 30 Jul 2026 17:54:38 +0200 Subject: [PATCH 7/9] Split components references by category and improve descriptions --- AGENTS.md | 14 +- .../SKILL.md | 2 +- skills/using-ouds-android/SKILL.md | 250 +++- .../references/action-components.md | 200 +++ .../references/alert-components.md | 99 ++ .../references/components-index.md | 71 + .../references/components.md | 1223 ----------------- .../references/content-components.md | 39 + .../references/control-components.md | 311 +++++ .../references/indicator-components.md | 200 +++ .../references/input-components.md | 153 +++ .../references/layout-components.md | 164 +++ .../references/navigation-components.md | 105 ++ 13 files changed, 1577 insertions(+), 1254 deletions(-) create mode 100644 skills/using-ouds-android/references/action-components.md create mode 100644 skills/using-ouds-android/references/alert-components.md create mode 100644 skills/using-ouds-android/references/components-index.md delete mode 100644 skills/using-ouds-android/references/components.md create mode 100644 skills/using-ouds-android/references/content-components.md create mode 100644 skills/using-ouds-android/references/control-components.md create mode 100644 skills/using-ouds-android/references/indicator-components.md create mode 100644 skills/using-ouds-android/references/input-components.md create mode 100644 skills/using-ouds-android/references/layout-components.md create mode 100644 skills/using-ouds-android/references/navigation-components.md diff --git a/AGENTS.md b/AGENTS.md index a2efdeacf7..6b6b160d5b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -224,9 +224,19 @@ skills/ ├── understanding-ouds-android-vocabulary/ │ └── SKILL.md ← vocabulary definitions and token hierarchy └── using-ouds-android/ - ├── SKILL.md ← setup, themes, token access, common patterns, checklist + ├── SKILL.md ← setup, themes, token access, common patterns, checklist, troubleshooting └── references/ - └── components.md ← full component signatures and usage examples + ├── components-index.md ← complete component cross-reference + ├── action-components.md ← Button, FloatingActionButton, NavigationButton, SmallButton + ├── alert-components.md ← AlertMessage, InlineAlert + ├── content-components.md ← BulletList + ├── control-components.md ← Checkbox, CheckboxItem, RadioButton, RadioButtonItem, Switch, SwitchItem, FilterChip, SuggestionChip + ├── indicator-components.md ← Badge, CircularProgressIndicator, LinearProgressIndicator, Tag + ├── input-components.md ← TextInput, TextArea, PasswordInput, PinCodeInput + ├── layout-components.md ← BottomSheetScaffold, ColoredBox, Divider, ModalBottomSheet + ├── navigation-components.md ← Link, NavigationBar, TopAppBar + ├── component-tokens.md ← advanced component-level tokens + └── tokens.md ← semantic tokens (color, typography, spacing, etc.) ``` ## Resources diff --git a/skills/understanding-ouds-android-vocabulary/SKILL.md b/skills/understanding-ouds-android-vocabulary/SKILL.md index 870f8e78d8..a5435f9131 100644 --- a/skills/understanding-ouds-android-vocabulary/SKILL.md +++ b/skills/understanding-ouds-android-vocabulary/SKILL.md @@ -1,6 +1,6 @@ --- name: understanding-ouds-android-vocabulary -description: Use this skill whenever the user asks about OUDS-specific terminology, concepts, or vocabulary. This includes questions about tokens (raw, semantic, component), Tokenator, OudsThemeContract, OudsTheme, OudsColoredBox, tinted parameters, OudsError, or any OUDS-specific classes and patterns. ALWAYS trigger when the user asks to explain, define, clarify, or understand the difference between OUDS concepts, even if they don't explicitly say 'what is' or 'define'. Also trigger when they ask about relationships between OUDS architecture elements (e.g., how tokens relate to each other, theme hierarchy). +description: Use this skill whenever the user asks about OUDS-specific terminology, concepts, or vocabulary. This includes questions about tokens (raw, semantic, component), Tokenator, OudsThemeContract, OudsTheme, OudsColoredBox, tinted parameters, OudsError, or any OUDS-specific classes and patterns. ALWAYS trigger when the user asks to explain, define, clarify, understand the difference, or asks 'what is', 'how does X work', 'why do we use', 'what's the purpose of', or any conceptual question about OUDS concepts, even if they don't use these exact phrases. Also trigger when they ask about relationships between OUDS architecture elements (e.g., how tokens relate to each other, theme hierarchy, how Tokenator generates code, where tokens are defined). Trigger even when they seem confused about OUDS terminology without explicitly asking for definitions, or when they use incorrect terminology that suggests they need clarification. license: MIT --- diff --git a/skills/using-ouds-android/SKILL.md b/skills/using-ouds-android/SKILL.md index fe54f06fc1..9beb08b6bb 100644 --- a/skills/using-ouds-android/SKILL.md +++ b/skills/using-ouds-android/SKILL.md @@ -1,6 +1,6 @@ --- name: using-ouds-android -description: Use this skill whenever the user needs to write code using OUDS Android components, set up the library, configure themes, or access design tokens in Kotlin/Compose. This includes adding dependencies, wrapping UI with OudsTheme, creating any Ouds* component (OudsButton, OudsTextInput, OudsNavigationBar, etc.), accessing tokens via OudsTheme.colorScheme/spaces/typography, configuring fonts, handling tinted/untinted icons, using OudsColoredBox, showing error messages, or switching themes dynamically. ALWAYS trigger when the user asks to 'create', 'show me how', 'write a composable', 'set up', or 'access' anything related to OUDS components or tokens, even if they don't explicitly mention 'OUDS framework'. +description: Use this skill whenever the user needs to write code using OUDS Android components, set up the library, configure themes, access design tokens, debug OUDS code, or fix OUDS-related issues in Kotlin/Compose. This includes adding dependencies, wrapping UI with OudsTheme, creating any Ouds* component (OudsButton, OudsTextInput, OudsNavigationBar, OudsTag, OudsCheckbox, etc.), accessing tokens via OudsTheme.colorScheme/spaces/typography/borders, configuring fonts, handling tinted/untinted icons, using OudsColoredBox, showing error messages with OudsError, switching themes dynamically, troubleshooting component behavior, styling with component tokens, or migrating from Material 3 to OUDS. ALWAYS trigger when the user asks to 'create', 'show me how', 'write a composable', 'set up', 'access', 'fix', 'debug', 'implement', 'migrate', 'add', 'use', 'build', or 'style' anything related to OUDS components or tokens, even if they don't explicitly mention 'OUDS framework' or 'design system'. Also trigger when they want examples, code samples, or ask how to do something UI-related in the context of an OUDS-based Android app. license: MIT --- @@ -57,16 +57,17 @@ fun App() { ### Available themes -| Theme class | Brand | Notes | -|---|---|---| -| `OrangeTheme` | Orange | Requires Helvetica Neue font (bundled or downloadable) | -| `OrangeCompactTheme` | Orange Compact | Compact size variant of Orange | -| `SoshTheme` | Sosh | — | -| `WireframeTheme` | Wireframe | For development and prototyping only | +| Theme class | Brand | Notes | +|----------------------|----------------|--------------------------------------------------------| +| `OrangeTheme` | Orange | Requires Helvetica Neue font (bundled or downloadable) | +| `OrangeCompactTheme` | Orange Compact | Compact size variant of Orange | +| `SoshTheme` | Sosh | — | +| `WireframeTheme` | Wireframe | For development and prototyping only | ### OrangeTheme — font options **Bundled font** (copy `.ttf` files to `res/font/`): + ```kotlin OrangeTheme( orangeFontFamily = OrangeFontFamily( @@ -80,6 +81,7 @@ OrangeTheme( ``` **Downloadable font** (via Android Downloadable Fonts — requires `INTERNET` permission and a `` in the manifest): + ```kotlin OrangeTheme( orangeFontFamily = OrangeFontFamily( @@ -97,10 +99,10 @@ OrangeFontFamily.preloadDownloadableFontFamilies(context, listOf(OrangeHelvetica ```kotlin OrangeTheme( orangeFontFamily = ..., - roundedCornerButtons = true, - roundedCornerTextInputs = true, - roundedCornerAlertMessages = true, - roundedCornerProgressIndicators = true +roundedCornerButtons = true, +roundedCornerTextInputs = true, +roundedCornerAlertMessages = true, +roundedCornerProgressIndicators = true ) ``` @@ -131,24 +133,25 @@ fun MyView() { ### Token namespaces -| Accessor | Content | -|---|---| +| Accessor | Content | +|-------------------------|----------------------------------------------------------------------------------------------------| | `OudsTheme.colorScheme` | Color tokens (`.content.*`, `.background.*`, `.border.*`, `.action.*`, `.surface.*`, `.overlay.*`) | -| `OudsTheme.borders` | Border radius (`.radius.*`), style (`.style.*`), width (`.width.*`) | -| `OudsTheme.spaces` | Spacing tokens (`.fixed.*`, `.scaled.*`) | -| `OudsTheme.sizes` | Size tokens | -| `OudsTheme.typography` | Typography / font tokens | -| `OudsTheme.elevations` | Elevation / shadow tokens | -| `OudsTheme.grids` | Grid tokens | -| `OudsTheme.opacities` | Opacity tokens | -| `OudsTheme.effects` | Visual effect tokens | -| `OudsTheme.components` | Component-level tokens for advanced customization (requires `@OptIn(RestrictedOudsApi::class)`) | +| `OudsTheme.borders` | Border radius (`.radius.*`), style (`.style.*`), width (`.width.*`) | +| `OudsTheme.spaces` | Spacing tokens (`.fixed.*`, `.scaled.*`) | +| `OudsTheme.sizes` | Size tokens | +| `OudsTheme.typography` | Typography / font tokens | +| `OudsTheme.elevations` | Elevation / shadow tokens | +| `OudsTheme.grids` | Grid tokens | +| `OudsTheme.opacities` | Opacity tokens | +| `OudsTheme.effects` | Visual effect tokens | +| `OudsTheme.components` | Component-level tokens for advanced customization (requires `@OptIn(RestrictedOudsApi::class)`) | --- ## 4. OudsColoredBox — colored surfaces -`OudsColoredBox` creates a semantically colored surface. All OUDS child components inside automatically switch to their **monochrome** variant for maximum contrast: +`OudsColoredBox` creates a semantically colored surface. All OUDS child components inside automatically switch to their **monochrome** variant for maximum +contrast: ```kotlin OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { @@ -167,7 +170,8 @@ OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { ### Tinted vs. untinted icons -By default, icons passed to OUDS components are **tinted** (color driven by tokens). Pass `tinted = false` to preserve the painter's own colors (brand/multi-color icons): +By default, icons passed to OUDS components are **tinted** (color driven by tokens). Pass `tinted = false` to preserve the painter's own colors ( +brand/multi-color icons): ```kotlin // Tinted icon (default) @@ -233,15 +237,205 @@ OudsButton(label = stringResource(R.string.submit), onClick = { }) --- -## 7. Reference documentation +## 7. Common mistakes and troubleshooting + +### Missing OudsTheme wrapper + +**Problem:** Components don't display correctly, colors are wrong, or app crashes with "CompositionLocal LocalOudsTheme not present" + +**Solution:** Ensure your UI is wrapped with `OudsTheme { }` at the root: + +```kotlin +@Composable +fun App() { + OudsTheme(theme = OrangeTheme(...)) { + // Your composables here + } +} +``` + +### Hardcoded strings + +**Problem:** Strings appear directly in code instead of using resources + +**Solution:** Always use `stringResource(R.string.*)`: + +```kotlin +// Wrong +OudsButton(label = "Submit", onClick = { }) + +// Correct +OudsButton(label = stringResource(R.string.submit), onClick = { }) +``` + +### OudsButtonAppearance.Negative inside OudsColoredBox + +**Problem:** App crashes or displays incorrectly when using `OudsButtonAppearance.Negative` inside `OudsColoredBox` + +**Solution:** The `Negative` appearance is forbidden inside `OudsColoredBox`. Use `Default`, `Strong`, `Brand`, or `Minimal` instead. The button will +automatically adopt its monochrome variant inside `OudsColoredBox`. + +### Disabled component with loader + +**Problem:** A component is both disabled and showing a loader simultaneously + +**Solution:** A disabled component must not have a loader. Choose one state: + +```kotlin +// Wrong +OudsButton( + label = stringResource(R.string.action), + enabled = false, + loader = OudsButtonLoader(progress = null), + onClick = { } +) + +// Correct - either disabled OR loading +OudsButton( + label = stringResource(R.string.action), + loader = OudsButtonLoader(progress = null), + onClick = { } +) +``` + +### Icon not tinted correctly + +**Problem:** Icon appears in wrong color or doesn't match theme + +**Solution:** By default, icons are tinted (color driven by tokens). For brand/multi-color icons, set `tinted = false`: + +```kotlin +// Tinted icon (default) - color from tokens +OudsButtonIcon(imageVector = Icons.Filled.Star, contentDescription = "") + +// Untinted icon - preserves painter's colors +OudsButtonIcon(painter = myBrandIcon, contentDescription = "", tinted = false) +``` + +### Missing content description + +**Problem:** Accessibility warnings or icon-only components without descriptions + +**Solution:** Always provide `contentDescription` for icon-only elements: + +```kotlin +// Wrong +OudsButton( + icon = OudsButtonIcon(imageVector = Icons.Filled.Star, contentDescription = ""), + onClick = { } +) + +// Correct +OudsButton( + icon = OudsButtonIcon( + imageVector = Icons.Filled.Star, + contentDescription = stringResource(R.string.favorite_desc) + ), + onClick = { } +) +``` + +### Font not loaded for OrangeTheme + +**Problem:** Text doesn't display in Helvetica Neue, falls back to system font + +**Solution:** For `OrangeTheme`, you must provide the Helvetica Neue font either as bundled (`.ttf` files in `res/font/`) or downloadable: + +```kotlin +// Bundled font (recommended) +OrangeTheme( + orangeFontFamily = OrangeFontFamily( + latin = OrangeHelveticaNeueLatin.Bundled( + R.font.helvetica_neue_latin_roman, + R.font.helvetica_neue_latin_medium, + R.font.helvetica_neue_latin_bold + ) + ) +) + +// Downloadable font (requires INTERNET permission) +OrangeTheme( + orangeFontFamily = OrangeFontFamily( + latin = OrangeHelveticaNeueLatin.Downloadable + ) +) +``` + +### Token access outside OudsTheme + +**Problem:** `OudsTheme.colorScheme` or other token accessors return unexpected values or crash + +**Solution:** Token accessors only work inside composables wrapped by `OudsTheme { }`. Move token access inside the theme wrapper: + +```kotlin +// Wrong - outside OudsTheme +val color = OudsTheme.colorScheme.background.primary +OudsTheme(theme = OrangeTheme(...)) { + Box(modifier = Modifier.background(color)) +} + +// Correct - inside OudsTheme +OudsTheme(theme = OrangeTheme(...)) { + val color = OudsTheme.colorScheme.background.primary + Box(modifier = Modifier.background(color)) +} +``` + +### Error message not displaying + +**Problem:** Error passed to input component but not showing + +**Solution:** Ensure you're using `OudsError` wrapper with either `message` or `annotatedMessage`: + +```kotlin +// Correct - plain error +error = OudsError(message = stringResource(R.string.error_required)) + +// Correct - rich annotated error +error = OudsError( + annotatedMessage = buildOudsAnnotatedErrorMessage { + append(stringResource(R.string.error_prefix)) + withStrong { append(stringResource(R.string.error_highlight)) } + } +) +``` + +--- + +## 8. Reference documentation ### Components reference -See [`references/components.md`](references/components.md) for the full list of components with signatures and usage examples. +Component documentation is organized by category. When the user asks about specific components, consult the relevant reference file: + +- **Action components** (buttons, FAB): [`references/action-components.md`](references/action-components.md) + - Button, FloatingActionButton, NavigationButton, SmallButton + +- **Alert components** (alerts, messages): [`references/alert-components.md`](references/alert-components.md) + - AlertMessage, InlineAlert + +- **Content components** (lists): [`references/content-components.md`](references/content-components.md) + - BulletList + +- **Control components** (checkboxes, switches, chips): [`references/control-components.md`](references/control-components.md) + - Checkbox, CheckboxItem, RadioButton, RadioButtonItem, Switch, SwitchItem, FilterChip, SuggestionChip + +- **Indicator components** (badges, progress, tags): [`references/indicator-components.md`](references/indicator-components.md) + - Badge, CircularProgressIndicator, LinearProgressIndicator, Tag + +- **Input components** (text fields): [`references/input-components.md`](references/input-components.md) + - TextInput, TextArea, PasswordInput, PinCodeInput + +- **Layout components** (containers, dividers): [`references/layout-components.md`](references/layout-components.md) + - BottomSheetScaffold, ColoredBox, Divider, ModalBottomSheet + +- **Navigation components** (links, bars): [`references/navigation-components.md`](references/navigation-components.md) + - Link, NavigationBar, TopAppBar -**Component Index:** [Button](#button) · [SmallButton](#smallbutton) · [Tag](#tag) · [Badge](#badge) · [AlertMessage](#alertmessage) · [InlineAlert](#inlinealert) · [BulletList](#bulletlist) · [CheckboxItem](#checkboxitem) · [RadioButtonItem](#radiobuttonitem) · [SwitchItem](#switchitem) · [TextInput](#textinput) · [TextArea](#textarea) · [PasswordInput](#passwordinput) · [PinCodeInput](#pincodeinput) · [FilterChip / SuggestionChip](#filterchip--suggestionchip) · [Link](#link) · [Divider](#divider) · [NavigationBar](#navigationbar) · [TopAppBar](#topappbar) · [ColoredBox](#coloredbox) +**Complete component index:** See [`references/components-index.md`](references/components-index.md) for a full cross-reference of all components. ### Tokens reference -- **Semantic tokens:** See [`references/tokens.md`](references/tokens.md) for color scheme, typography, spacing, sizes, borders, elevations, opacities, effects, and grids +- **Semantic tokens:** See [`references/tokens.md`](references/tokens.md) for color scheme, typography, spacing, sizes, borders, elevations, opacities, effects, + and grids - **Component tokens:** See [`references/component-tokens.md`](references/component-tokens.md) for advanced component-level tokens (`@RestrictedOudsApi`) diff --git a/skills/using-ouds-android/references/action-components.md b/skills/using-ouds-android/references/action-components.md new file mode 100644 index 0000000000..23cce26be4 --- /dev/null +++ b/skills/using-ouds-android/references/action-components.md @@ -0,0 +1,200 @@ +# OUDS Android — Action Components + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +- [Button](#button) — Default and small buttons +- [FloatingActionButton](#floatingactionbutton) — Floating action button (FAB) +- [NavigationButton](#navigationbutton) — Navigation button with chevron +- [SmallButton](#smallbutton) — Small size button variant + +--- + +## Button + +**Layouts:** text only · icon only · text + icon +**Sizes:** default (`OudsButton`) · small (`OudsSmallButton`) +**Appearances:** `OudsButtonAppearance` — `Default`, `Strong`, `Brand`, `Minimal`, `Negative` +**Note:** `Negative` appearance is forbidden inside `OudsColoredBox`. +Inside `OudsColoredBox`, the button automatically adopts its monochrome variant. + +```kotlin +// Text only +OudsButton( + label = stringResource(R.string.action), + onClick = { } +) + +// Icon only — contentDescription required +OudsButton( + icon = OudsButtonIcon( + imageVector = Icons.Filled.FavoriteBorder, + contentDescription = stringResource(R.string.favorite_desc) + ), + onClick = { } +) + +// Text + icon +OudsButton( + icon = OudsButtonIcon(imageVector = Icons.Filled.FavoriteBorder, contentDescription = ""), + label = stringResource(R.string.action), + onClick = { } +) + +// Untinted icon (multi-color / brand icon) +OudsButton( + icon = OudsButtonIcon(painter = myPainter, contentDescription = "", tinted = false), + onClick = { } +) + +// With loading state +OudsButton( + label = stringResource(R.string.action), + loader = OudsButtonLoader(progress = null), // indeterminate + onClick = { } +) + +// On colored background — colors adjusted automatically +OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { + OudsButton(label = stringResource(R.string.action), onClick = { }) +} +``` + +--- + +## SmallButton + +Same API as `OudsButton` but uses the small size variant. + +```kotlin +OudsSmallButton(label = stringResource(R.string.action), onClick = { }) + +OudsSmallButton( + icon = OudsButtonIcon(imageVector = Icons.Filled.FavoriteBorder, contentDescription = ""), + label = stringResource(R.string.action), + onClick = { } +) +``` + +--- + +## FloatingActionButton + +**Sizes:** `OudsFloatingActionButton` (default) · `OudsSmallFloatingActionButton` · `OudsLargeFloatingActionButton` · `OudsExtendedFloatingActionButton` (with text) +**Appearances:** `OudsFloatingActionButtonAppearance` — `Primary`, `Secondary` + +```kotlin +// Icon only (default size) +OudsFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + imageVector = Icons.Filled.Add, + contentDescription = stringResource(R.string.add) + ), + onClick = { } +) + +// Small size +OudsSmallFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + imageVector = Icons.Filled.Edit, + contentDescription = stringResource(R.string.edit) + ), + onClick = { } +) + +// Large size +OudsLargeFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + imageVector = Icons.Filled.FavoriteBorder, + contentDescription = stringResource(R.string.favorite) + ), + onClick = { } +) + +// Extended (with text) +OudsExtendedFloatingActionButton( + text = stringResource(R.string.create), + icon = OudsFloatingActionButtonIcon(imageVector = Icons.Filled.Add, contentDescription = ""), + onClick = { } +) + +// With secondary appearance +OudsFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + imageVector = Icons.Filled.Settings, + contentDescription = stringResource(R.string.settings) + ), + appearance = OudsFloatingActionButtonAppearance.Secondary, + onClick = { } +) + +// With untinted icon (multi-color) +OudsFloatingActionButton( + icon = OudsFloatingActionButtonIcon( + painter = myBrandPainter, + contentDescription = stringResource(R.string.brand_action), + tinted = false + ), + onClick = { } +) +``` + +--- + +## NavigationButton + +**Chevrons:** `OudsNavigationButtonChevron` — `Next`, `Previous` +**Appearances:** `OudsNavigationButtonAppearance` — `Default`, `Strong`, `Brand`, `Minimal` +**Note:** `Brand` appearance is forbidden inside `OudsColoredBox`. +Inside `OudsColoredBox`, the button automatically adopts its monochrome variant. + +```kotlin +// Icon only (chevron) +OudsNavigationButton( + chevron = OudsNavigationButtonChevron.Next, + onClick = { } +) + +// With label +OudsNavigationButton( + label = stringResource(R.string.next), + chevron = OudsNavigationButtonChevron.Next, + onClick = { } +) + +// Previous chevron +OudsNavigationButton( + label = stringResource(R.string.previous), + chevron = OudsNavigationButtonChevron.Previous, + onClick = { } +) + +// With appearance +OudsNavigationButton( + label = stringResource(R.string.next), + chevron = OudsNavigationButtonChevron.Next, + appearance = OudsNavigationButtonAppearance.Strong, + onClick = { } +) + +// With loader +OudsNavigationButton( + label = stringResource(R.string.next), + chevron = OudsNavigationButtonChevron.Next, + loader = OudsButtonLoader(progress = null), // indeterminate + onClick = { } +) + +// On colored background — colors adjusted automatically +OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { + OudsNavigationButton( + label = stringResource(R.string.next), + chevron = OudsNavigationButtonChevron.Next, + onClick = { } + ) +} +``` diff --git a/skills/using-ouds-android/references/alert-components.md b/skills/using-ouds-android/references/alert-components.md new file mode 100644 index 0000000000..cac94ed253 --- /dev/null +++ b/skills/using-ouds-android/references/alert-components.md @@ -0,0 +1,99 @@ +# OUDS Android — Alert Components + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +- [AlertMessage](#alertmessage) — Full-featured alert with actions +- [InlineAlert](#inlinealert) — Compact inline alert + +--- + +## AlertMessage + +**Statuses:** `OudsAlertMessageStatus` — `Neutral`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` +**Action link positions:** `OudsAlertMessageActionLinkPosition` — `Bottom` (default), `TopEnd` + +```kotlin +// Minimal +OudsAlertMessage(label = stringResource(R.string.title)) + +// With functional status (no icon param) +OudsAlertMessage( + label = stringResource(R.string.title), + description = stringResource(R.string.description), + status = OudsAlertMessageStatus.Positive, + onClose = { /* dismiss */ } +) + +// With non-functional status and custom icon +OudsAlertMessage( + label = stringResource(R.string.title), + description = stringResource(R.string.description), + status = OudsAlertMessageStatus.Accent(OudsAlertIcon(imageVector = Icons.Filled.FavoriteBorder)), + onClose = { /* dismiss */ }, + actionLink = OudsAlertMessageActionLink( + label = stringResource(R.string.learn_more), + onClick = { /* navigate */ } + ), + bulletList = listOf( + stringResource(R.string.point_1), + stringResource(R.string.point_2) + ) +) + +// With untinted icon +OudsAlertMessage( + label = stringResource(R.string.title), + status = OudsAlertMessageStatus.Accent(OudsAlertIcon(painter = myPainter, tinted = false)), + onClose = { } +) + +// Action link at top end +OudsAlertMessage( + label = stringResource(R.string.title), + status = OudsAlertMessageStatus.Positive, + onClose = { }, + actionLink = OudsAlertMessageActionLink( + label = stringResource(R.string.details), + onClick = { }, + position = OudsAlertMessageActionLinkPosition.TopEnd + ) +) +``` + +--- + +## InlineAlert + +**Statuses:** `OudsInlineAlertStatus` — `Neutral`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` +Functional statuses (`Positive`, `Warning`, `Negative`, `Info`) display a default icon automatically; no icon param. + +```kotlin +// Functional status — icon automatic +OudsInlineAlert( + label = stringResource(R.string.label), + status = OudsInlineAlertStatus.Positive +) + +// Non-functional with default icon +OudsInlineAlert( + label = stringResource(R.string.label), + status = OudsInlineAlertStatus.Accent(OudsAlertIcon.Default) +) + +// Non-functional with custom icon +OudsInlineAlert( + label = stringResource(R.string.label), + status = OudsInlineAlertStatus.Accent(OudsAlertIcon(imageVector = Icons.Filled.FavoriteBorder)) +) + +// Non-functional with untinted icon +OudsInlineAlert( + label = stringResource(R.string.label), + status = OudsInlineAlertStatus.Accent(OudsAlertIcon(painter = myPainter, tinted = false)) +) +``` diff --git a/skills/using-ouds-android/references/components-index.md b/skills/using-ouds-android/references/components-index.md new file mode 100644 index 0000000000..65ecc44b70 --- /dev/null +++ b/skills/using-ouds-android/references/components-index.md @@ -0,0 +1,71 @@ +# OUDS Android — Components Reference Index + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents by Category + +### Action Components +[→ See full documentation](action-components.md) + +- [Button](action-components.md#button) — Default and small buttons +- [FloatingActionButton](action-components.md#floatingactionbutton) — Floating action button (FAB) +- [NavigationButton](action-components.md#navigationbutton) — Navigation button with chevron +- [SmallButton](action-components.md#smallbutton) — Small size button variant + +### Alert Components +[→ See full documentation](alert-components.md) + +- [AlertMessage](alert-components.md#alertmessage) — Full-featured alert with actions +- [InlineAlert](alert-components.md#inlinealert) — Compact inline alert + +### Content Components +[→ See full documentation](content-components.md) + +- [BulletList](content-components.md#bulletlist) — Ordered, unordered, and bare lists + +### Control Components +[→ See full documentation](control-components.md) + +- [Checkbox](control-components.md#checkbox) — Standalone checkbox +- [CheckboxItem](control-components.md#checkboxitem) — Checkbox with label and description +- [RadioButton](control-components.md#radiobutton) — Standalone radio button +- [RadioButtonItem](control-components.md#radiobuttonitem) — Radio button with label and description +- [Switch](control-components.md#switch) — Standalone switch +- [SwitchItem](control-components.md#switchitem) — Toggle switch with label and description + - **Chip** + - [FilterChip](control-components.md#filterchip) — Selectable filter chip + - [SuggestionChip](control-components.md#suggestionchip) — Suggestion and action chip + +### Indicator Components +[→ See full documentation](indicator-components.md) + +- [Badge](indicator-components.md#badge) — Count and status badges +- [CircularProgressIndicator](indicator-components.md#circularprogressindicator) — Circular loading indicator +- [LinearProgressIndicator](indicator-components.md#linearprogressindicator) — Linear loading indicator +- [Tag](indicator-components.md#tag) — Status and category tags + +### Input Components +[→ See full documentation](input-components.md) + +- [TextInput](input-components.md#textinput) — Single-line text field +- [TextArea](input-components.md#textarea) — Multi-line text field +- [PasswordInput](input-components.md#passwordinput) — Password field with visibility toggle +- [PinCodeInput](input-components.md#pincodeinput) — PIN code input (4 or 6 digits) + +### Layout Components +[→ See full documentation](layout-components.md) + +- [BottomSheetScaffold](layout-components.md#bottomsheetscaffold) — Standard bottom sheet scaffold +- [ColoredBox](layout-components.md#coloredbox) — Colored surface container +- [Divider](layout-components.md#divider) — Horizontal and vertical dividers +- [ModalBottomSheet](layout-components.md#modalbottomsheet) — Modal bottom sheet + +### Navigation Components +[→ See full documentation](navigation-components.md) + +- [Link](navigation-components.md#link) — Text link with optional icon/chevron +- [NavigationBar](navigation-components.md#navigationbar) — Bottom navigation bar +- [TopAppBar](navigation-components.md#topappbar) — Top app bar with variants diff --git a/skills/using-ouds-android/references/components.md b/skills/using-ouds-android/references/components.md deleted file mode 100644 index fd8ed1ac90..0000000000 --- a/skills/using-ouds-android/references/components.md +++ /dev/null @@ -1,1223 +0,0 @@ -# OUDS Android — Components Reference - -All components are in the `com.orange.ouds.core.component` package. -All user-visible strings must use `stringResource(R.string.*)` — never hardcode. - -> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). - -## Table of Contents - -**Action** -- [Button](#button) — Default and small buttons -- [FloatingActionButton](#floatingactionbutton) — Floating action button (FAB) -- [NavigationButton](#navigationbutton) — Navigation button with chevron -- [SmallButton](#smallbutton) — Small size button variant - -**Alerts & Messages** -- [AlertMessage](#alertmessage) — Full-featured alert with actions -- [InlineAlert](#inlinealert) — Compact inline alert - -**Content Display** -- [BulletList](#bulletlist) — Ordered, unordered, and bare lists - -**Control** -- [Checkbox](#checkbox) — Standalone checkbox -- [CheckboxItem](#checkboxitem) — Checkbox with label and description -- [RadioButton](#radiobutton) — Standalone radio button -- [RadioButtonItem](#radiobuttonitem) — Radio button with label and description -- [Switch](#switch) — Standalone switch -- [SwitchItem](#switchitem) — Toggle switch with label and description - - **Chip** - - [FilterChip](#filterchip) — Selectable filter chip - - [SuggestionChip](#suggestionchip) — Suggestion and action chip - -**Indicator** -- [Badge](#badge) — Count and status badges -- [CircularProgressIndicator](#circularprogressindicator) — Circular loading indicator -- [LinearProgressIndicator](#linearprogressindicator) — Linear loading indicator -- [Tag](#tag) — Status and category tags - -**Layout** -- [BottomSheetScaffold](#bottomsheetscaffold) — Standard bottom sheet scaffold -- [ColoredBox](#coloredbox) — Colored surface container -- [Divider](#divider) — Horizontal and vertical dividers -- [ModalBottomSheet](#modalbottomsheet) — Modal bottom sheet - -**Navigation** -- [Link](#link) — Text link with optional icon/chevron -- [NavigationBar](#navigationbar) — Bottom navigation bar -- [TopAppBar](#topappbar) — Top app bar with variants - -**Text Inputs** -- [TextInput](#textinput) — Single-line text field -- [TextArea](#textarea) — Multi-line text field -- [PasswordInput](#passwordinput) — Password field with visibility toggle -- [PinCodeInput](#pincodeinput) — PIN code input (4 or 6 digits) - ---- - -## Button - -**Layouts:** text only · icon only · text + icon -**Sizes:** default (`OudsButton`) · small (`OudsSmallButton`) -**Appearances:** `OudsButtonAppearance` — `Default`, `Strong`, `Brand`, `Minimal`, `Negative` -**Note:** `Negative` appearance is forbidden inside `OudsColoredBox`. -Inside `OudsColoredBox`, the button automatically adopts its monochrome variant. - -```kotlin -// Text only -OudsButton( - label = stringResource(R.string.action), - onClick = { } -) - -// Icon only — contentDescription required -OudsButton( - icon = OudsButtonIcon( - imageVector = Icons.Filled.FavoriteBorder, - contentDescription = stringResource(R.string.favorite_desc) - ), - onClick = { } -) - -// Text + icon -OudsButton( - icon = OudsButtonIcon(imageVector = Icons.Filled.FavoriteBorder, contentDescription = ""), - label = stringResource(R.string.action), - onClick = { } -) - -// Untinted icon (multi-color / brand icon) -OudsButton( - icon = OudsButtonIcon(painter = myPainter, contentDescription = "", tinted = false), - onClick = { } -) - -// With loading state -OudsButton( - label = stringResource(R.string.action), - loader = OudsButtonLoader(progress = null), // indeterminate - onClick = { } -) - -// On colored background — colors adjusted automatically -OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { - OudsButton(label = stringResource(R.string.action), onClick = { }) -} -``` - ---- - -## SmallButton - -Same API as `OudsButton` but uses the small size variant. - -```kotlin -OudsSmallButton(label = stringResource(R.string.action), onClick = { }) - -OudsSmallButton( - icon = OudsButtonIcon(imageVector = Icons.Filled.FavoriteBorder, contentDescription = ""), - label = stringResource(R.string.action), - onClick = { } -) -``` - ---- - -## FloatingActionButton - -**Sizes:** `OudsFloatingActionButton` (default) · `OudsSmallFloatingActionButton` · `OudsLargeFloatingActionButton` · `OudsExtendedFloatingActionButton` (with text) -**Appearances:** `OudsFloatingActionButtonAppearance` — `Primary`, `Secondary` - -```kotlin -// Icon only (default size) -OudsFloatingActionButton( - icon = OudsFloatingActionButtonIcon( - imageVector = Icons.Filled.Add, - contentDescription = stringResource(R.string.add) - ), - onClick = { } -) - -// Small size -OudsSmallFloatingActionButton( - icon = OudsFloatingActionButtonIcon( - imageVector = Icons.Filled.Edit, - contentDescription = stringResource(R.string.edit) - ), - onClick = { } -) - -// Large size -OudsLargeFloatingActionButton( - icon = OudsFloatingActionButtonIcon( - imageVector = Icons.Filled.FavoriteBorder, - contentDescription = stringResource(R.string.favorite) - ), - onClick = { } -) - -// Extended (with text) -OudsExtendedFloatingActionButton( - text = stringResource(R.string.create), - icon = OudsFloatingActionButtonIcon(imageVector = Icons.Filled.Add, contentDescription = ""), - onClick = { } -) - -// With secondary appearance -OudsFloatingActionButton( - icon = OudsFloatingActionButtonIcon( - imageVector = Icons.Filled.Settings, - contentDescription = stringResource(R.string.settings) - ), - appearance = OudsFloatingActionButtonAppearance.Secondary, - onClick = { } -) - -// With untinted icon (multi-color) -OudsFloatingActionButton( - icon = OudsFloatingActionButtonIcon( - painter = myBrandPainter, - contentDescription = stringResource(R.string.brand_action), - tinted = false - ), - onClick = { } -) -``` - ---- - -## NavigationButton - -**Chevrons:** `OudsNavigationButtonChevron` — `Next`, `Previous` -**Appearances:** `OudsNavigationButtonAppearance` — `Default`, `Strong`, `Brand`, `Minimal` -**Note:** `Brand` appearance is forbidden inside `OudsColoredBox`. -Inside `OudsColoredBox`, the button automatically adopts its monochrome variant. - -```kotlin -// Icon only (chevron) -OudsNavigationButton( - chevron = OudsNavigationButtonChevron.Next, - onClick = { } -) - -// With label -OudsNavigationButton( - label = stringResource(R.string.next), - chevron = OudsNavigationButtonChevron.Next, - onClick = { } -) - -// Previous chevron -OudsNavigationButton( - label = stringResource(R.string.previous), - chevron = OudsNavigationButtonChevron.Previous, - onClick = { } -) - -// With appearance -OudsNavigationButton( - label = stringResource(R.string.next), - chevron = OudsNavigationButtonChevron.Next, - appearance = OudsNavigationButtonAppearance.Strong, - onClick = { } -) - -// With loader -OudsNavigationButton( - label = stringResource(R.string.next), - chevron = OudsNavigationButtonChevron.Next, - loader = OudsButtonLoader(progress = null), // indeterminate - onClick = { } -) - -// On colored background — colors adjusted automatically -OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { - OudsNavigationButton( - label = stringResource(R.string.next), - chevron = OudsNavigationButtonChevron.Next, - onClick = { } - ) -} -``` - ---- - -## Tag - -**Statuses:** `OudsTagStatus` — `Neutral`, `Accent`, `Positive`, `Warning`, `Negative`, `Info` -**Assets:** `OudsTagAsset.Bullet` · `OudsTagAsset.Icon(…)` · `OudsTagAsset.Icon.Default` (functional icon per status) -**Appearances:** `OudsTagAppearance` — `Emphasized` (default), `Muted` -**Sizes:** `OudsTagSize` — `Default`, `Small` - -```kotlin -// Text only -OudsTag(label = stringResource(R.string.label)) - -// With bullet -OudsTag( - label = stringResource(R.string.label), - status = OudsTagStatus.Positive(asset = OudsTagAsset.Bullet) -) - -// With default functional icon (icon per status) -OudsTag( - label = stringResource(R.string.label), - status = OudsTagStatus.Positive(asset = OudsTagAsset.Icon.Default) -) - -// With custom icon (Neutral or Accent only) -OudsTag( - label = stringResource(R.string.label), - status = OudsTagStatus.Neutral(asset = OudsTagAsset.Icon(imageVector = Icons.Filled.FavoriteBorder)) -) - -// With untinted icon -OudsTag( - label = stringResource(R.string.label), - status = OudsTagStatus.Neutral(asset = OudsTagAsset.Icon(painter = myPainter, tinted = false)) -) - -// Small size -OudsTag(label = stringResource(R.string.label), size = OudsTagSize.Small) - -// With loader (indeterminate) -OudsTag(label = stringResource(R.string.label), loader = OudsTagLoader(progress = null)) -``` - ---- - -## Badge - -**Statuses (plain/count):** `OudsBadgeStatus` — `Neutral`, `Accent`, `Positive`, `Warning`, `Negative`, `Info` -**Statuses (icon):** `OudsIconBadgeStatus` — `Neutral(icon?)`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` -**Sizes:** `OudsBadgeSize` — `ExtraSmall`, `Small`, `Medium`, `Large` -**Note:** Always provide a `contentDescription` via `Modifier.semantics { contentDescription = "…" }`. - -```kotlin -// Standard dot badge -OudsBadge( - modifier = Modifier.semantics { contentDescription = stringResource(R.string.info_desc) }, - status = OudsBadgeStatus.Info, - size = OudsBadgeSize.Small -) - -// Badge with count -val count = 10 -OudsBadge( - modifier = Modifier.semantics { contentDescription = stringResource(R.string.unread_count, count) }, - status = OudsBadgeStatus.Accent, - count = count -) - -// Badge with default functional icon -OudsBadge( - modifier = Modifier.semantics { contentDescription = stringResource(R.string.info_desc) }, - status = OudsIconBadgeStatus.Info, - size = OudsBadgeSize.Large -) - -// Badge with custom icon -OudsBadge( - modifier = Modifier.semantics { contentDescription = stringResource(R.string.favorite_desc) }, - status = OudsIconBadgeStatus.Accent(OudsBadgeIcon(imageVector = Icons.Filled.FavoriteBorder)), - size = OudsBadgeSize.Large -) - -// Badge with untinted custom icon -OudsBadge( - modifier = Modifier.semantics { contentDescription = stringResource(R.string.brand_desc) }, - status = OudsIconBadgeStatus.Neutral(OudsBadgeIcon(painter = myPainter, tinted = false)), - size = OudsBadgeSize.Large -) - -// Typical use: badged navigation item -BadgedBox( - badge = { - OudsBadge( - modifier = Modifier.semantics { contentDescription = stringResource(R.string.unread_count, 8) }, - count = 8, - status = OudsBadgeStatus.Accent - ) - } -) { - Icon(imageVector = Icons.Filled.Notifications, contentDescription = null) -} -``` - ---- - -## CircularProgressIndicator - -**Statuses:** `OudsProgressIndicatorStatus` — `Accent` (default), `Neutral` -**Variants:** Determinate (with progress value) · Indeterminate (loading animation) -**Track:** Optional background track for better visibility - -```kotlin -// Indeterminate (loading) -OudsCircularProgressIndicator() - -// Determinate (with progress) -OudsCircularProgressIndicator(progress = { 0.75f }) - -// With status -OudsCircularProgressIndicator( - progress = { 0.5f }, - status = OudsProgressIndicatorStatus.Neutral -) - -// Without track (minimal) -OudsCircularProgressIndicator( - progress = { 0.75f }, - track = false -) - -// Custom size -OudsCircularProgressIndicator( - modifier = Modifier.size(64.dp), - progress = { 0.75f } -) -``` - ---- - -## LinearProgressIndicator - -**Statuses:** `OudsProgressIndicatorStatus` — `Accent` (default), `Neutral` -**Variants:** Determinate (with progress value) · Indeterminate (loading animation) -**Track:** Optional background track for better visibility -**Stop Indicator:** Optional end marker for accessibility (required if contrast < 3:1) - -```kotlin -// Indeterminate (loading) -OudsLinearProgressIndicator( - helperText = stringResource(R.string.loading) -) - -// Determinate (with progress) -OudsLinearProgressIndicator( - progress = { 0.75f }, - helperText = stringResource(R.string.loading_percent, 75) -) - -// With status -OudsLinearProgressIndicator( - progress = { 0.5f }, - status = OudsProgressIndicatorStatus.Neutral, - helperText = stringResource(R.string.uploading) -) - -// Without track (minimal) -OudsLinearProgressIndicator( - progress = { 0.75f }, - track = false -) - -// With stop indicator (for accessibility) -OudsLinearProgressIndicator( - progress = { 0.75f }, - stopIndicator = true, - helperText = stringResource(R.string.processing) -) - -// Full width with helper text -OudsLinearProgressIndicator( - modifier = Modifier.fillMaxWidth(), - progress = { 0.75f }, - helperText = "Uploading file: document.pdf" -) -``` - ---- - -## AlertMessage - -**Statuses:** `OudsAlertMessageStatus` — `Neutral`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` -**Action link positions:** `OudsAlertMessageActionLinkPosition` — `Bottom` (default), `TopEnd` - -```kotlin -// Minimal -OudsAlertMessage(label = stringResource(R.string.title)) - -// With functional status (no icon param) -OudsAlertMessage( - label = stringResource(R.string.title), - description = stringResource(R.string.description), - status = OudsAlertMessageStatus.Positive, - onClose = { /* dismiss */ } -) - -// With non-functional status and custom icon -OudsAlertMessage( - label = stringResource(R.string.title), - description = stringResource(R.string.description), - status = OudsAlertMessageStatus.Accent(OudsAlertIcon(imageVector = Icons.Filled.FavoriteBorder)), - onClose = { /* dismiss */ }, - actionLink = OudsAlertMessageActionLink( - label = stringResource(R.string.learn_more), - onClick = { /* navigate */ } - ), - bulletList = listOf( - stringResource(R.string.point_1), - stringResource(R.string.point_2) - ) -) - -// With untinted icon -OudsAlertMessage( - label = stringResource(R.string.title), - status = OudsAlertMessageStatus.Accent(OudsAlertIcon(painter = myPainter, tinted = false)), - onClose = { } -) - -// Action link at top end -OudsAlertMessage( - label = stringResource(R.string.title), - status = OudsAlertMessageStatus.Positive, - onClose = { }, - actionLink = OudsAlertMessageActionLink( - label = stringResource(R.string.details), - onClick = { }, - position = OudsAlertMessageActionLinkPosition.TopEnd - ) -) -``` - ---- - -## InlineAlert - -**Statuses:** `OudsInlineAlertStatus` — `Neutral`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` -Functional statuses (`Positive`, `Warning`, `Negative`, `Info`) display a default icon automatically; no icon param. - -```kotlin -// Functional status — icon automatic -OudsInlineAlert( - label = stringResource(R.string.label), - status = OudsInlineAlertStatus.Positive -) - -// Non-functional with default icon -OudsInlineAlert( - label = stringResource(R.string.label), - status = OudsInlineAlertStatus.Accent(OudsAlertIcon.Default) -) - -// Non-functional with custom icon -OudsInlineAlert( - label = stringResource(R.string.label), - status = OudsInlineAlertStatus.Accent(OudsAlertIcon(imageVector = Icons.Filled.FavoriteBorder)) -) - -// Non-functional with untinted icon -OudsInlineAlert( - label = stringResource(R.string.label), - status = OudsInlineAlertStatus.Accent(OudsAlertIcon(painter = myPainter, tinted = false)) -) -``` - ---- - -## BulletList - -**Types:** `OudsBulletListType` — `Unordered` (default, `brandColor: Boolean`), `Ordered`, `Bare` - -```kotlin -// Unordered (brand color) -OudsBulletList { - item(label = stringResource(R.string.item_1)) - item(label = stringResource(R.string.item_2), subListType = OudsBulletListType.Unordered(brandColor = false)) { - item(label = stringResource(R.string.sub_item_1)) - } -} - -// Ordered -OudsBulletList(type = OudsBulletListType.Ordered) { - item(label = stringResource(R.string.step_1)) - item(label = stringResource(R.string.step_2)) { - item(label = stringResource(R.string.sub_step_1)) - } -} - -// Bare (no bullet) -OudsBulletList(type = OudsBulletListType.Bare) { - item(label = stringResource(R.string.item_1)) -} -``` - ---- - -## CheckboxItem - -Signature: `OudsCheckboxItem(checked, label, onCheckedChange, modifier, description?, icon?, divider?, enabled?, error?)` -Tri-state variant: `OudsTriStateCheckboxItem(state: ToggleableState, label, onClick, …)` - -```kotlin -// Basic -var checked by remember { mutableStateOf(false) } -OudsCheckboxItem( - checked = checked, - label = stringResource(R.string.terms), - onCheckedChange = { checked = it } -) - -// With description and icon -OudsCheckboxItem( - checked = checked, - label = stringResource(R.string.terms), - description = stringResource(R.string.terms_desc), - icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), - onCheckedChange = { checked = it } -) - -// With untinted icon -OudsCheckboxItem( - checked = checked, - label = stringResource(R.string.terms), - icon = OudsControlItemIcon(painter = myPainter, tinted = false), - onCheckedChange = { checked = it } -) - -// With error -OudsCheckboxItem( - checked = checked, - label = stringResource(R.string.terms), - onCheckedChange = { checked = it }, - error = OudsError(message = stringResource(R.string.error_required)) -) - -// Tri-state -var state by remember { mutableStateOf(ToggleableState.Off) } -OudsTriStateCheckboxItem( - state = state, - label = stringResource(R.string.select_all), - onClick = { - state = when (state) { - ToggleableState.On -> ToggleableState.Off - ToggleableState.Off -> ToggleableState.Indeterminate - ToggleableState.Indeterminate -> ToggleableState.On - } - } -) -``` - ---- - -## RadioButtonItem - -Signature: `OudsRadioButtonItem(selected, label, onClick, modifier, description?, icon?, divider?, enabled?, error?)` -**Always** wrap a group of radio items in `Modifier.selectableGroup()`. - -```kotlin -val options = listOf( - stringResource(R.string.option_a), - stringResource(R.string.option_b) -) -var selected by rememberSaveable { mutableStateOf(options.first()) } - -Column(modifier = Modifier.selectableGroup()) { - options.forEach { option -> - OudsRadioButtonItem( - selected = option == selected, - label = option, - onClick = { selected = option }, - divider = true - ) - } -} - -// With icon -OudsRadioButtonItem( - selected = selected == option, - label = option, - icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), - onClick = { selected = option } -) - -// With error (typically on the last item) -OudsRadioButtonItem( - selected = selected == option, - label = option, - onClick = { selected = option }, - error = OudsError(message = stringResource(R.string.selection_required)) -) -``` - ---- - -## SwitchItem - -Signature: `OudsSwitchItem(checked, label, onCheckedChange, modifier, description?, icon?, divider?, enabled?, error?)` - -```kotlin -var checked by remember { mutableStateOf(true) } - -OudsSwitchItem( - checked = checked, - label = stringResource(R.string.notifications), - description = stringResource(R.string.notifications_desc), - icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), - onCheckedChange = { checked = it } -) - -// With untinted icon -OudsSwitchItem( - checked = checked, - label = stringResource(R.string.notifications), - icon = OudsControlItemIcon(painter = myPainter, tinted = false), - onCheckedChange = { checked = it } -) - -// With error -OudsSwitchItem( - checked = checked, - label = stringResource(R.string.notifications), - onCheckedChange = { checked = it }, - error = OudsError(message = stringResource(R.string.notifications_required)) -) -``` - ---- - -## Checkbox - -**Standalone checkbox** without label — use when checkbox is nested within another component with an alternative label. -**See also:** [CheckboxItem](#checkboxitem) for checkbox with label and description. - -```kotlin -var checked by remember { mutableStateOf(false) } - -// Basic checkbox -OudsCheckbox( - checked = checked, - onCheckedChange = { checked = it } -) - -// Disabled -OudsCheckbox( - checked = checked, - onCheckedChange = { checked = it }, - enabled = false -) - -// Tri-state checkbox -var state by remember { mutableStateOf(ToggleableState.Off) } -OudsTriStateCheckbox( - state = state, - onClick = { - state = when (state) { - ToggleableState.On -> ToggleableState.Off - ToggleableState.Off -> ToggleableState.Indeterminate - ToggleableState.Indeterminate -> ToggleableState.On - } - } -) -``` - ---- - -## RadioButton - -**Standalone radio button** without label — use when radio button is nested within another component with an alternative label. -**See also:** [RadioButtonItem](#radiobuttonitem) for radio button with label and description. -**Always** wrap a group of radio buttons in `Modifier.selectableGroup()`. - -```kotlin -val options = listOf("Option A", "Option B", "Option C") -var selected by remember { mutableStateOf(options[0]) } - -Column(modifier = Modifier.selectableGroup()) { - options.forEach { option -> - OudsRadioButton( - selected = option == selected, - onClick = { selected = option } - ) - } -} - -// Disabled -OudsRadioButton( - selected = true, - onClick = null, - enabled = false -) -``` - ---- - -## Switch - -**Standalone switch** without label — use when switch is nested within another component with an alternative label. -**See also:** [SwitchItem](#switchitem) for switch with label and description. - -```kotlin -var checked by remember { mutableStateOf(true) } - -// Basic switch -OudsSwitch( - checked = checked, - onCheckedChange = { checked = it } -) - -// Disabled -OudsSwitch( - checked = checked, - onCheckedChange = { checked = it }, - enabled = false -) - -// With icon (when checked) -OudsSwitch( - checked = checked, - onCheckedChange = { checked = it }, - thumbContent = { - Icon( - imageVector = Icons.Filled.Check, - contentDescription = null, - modifier = Modifier.size(16.dp) - ) - } -) -``` - ---- - -## TextInput - -Two API variants: **state-based** (`textFieldState`) and **value-based** (`value` + `onValueChange`). -Prefer the state-based API for new code. - -```kotlin -// State-based — basic -OudsTextInput( - textFieldState = rememberTextFieldState(), - label = stringResource(R.string.label) -) - -// State-based — full featured -OudsTextInput( - textFieldState = rememberTextFieldState(), - label = stringResource(R.string.label), - placeholder = stringResource(R.string.placeholder), - leadingIcon = OudsTextInputLeadingIcon(imageVector = Icons.Filled.Search, contentDescription = ""), - prefix = stringResource(R.string.prefix), - suffix = stringResource(R.string.suffix), - helperText = stringResource(R.string.helper), - helperLink = OudsTextInputHelperLink(text = stringResource(R.string.more), onClick = { }) -) - -// With trailing action button -OudsTextInput( - textFieldState = rememberTextFieldState(), - label = stringResource(R.string.date), - trailingIconButton = OudsTextInputTrailingIconButton( - imageVector = Icons.Filled.DateRange, - contentDescription = stringResource(R.string.open_calendar), - onClick = { } - ), - outlined = true -) - -// With error -OudsTextInput( - textFieldState = rememberTextFieldState(), - label = stringResource(R.string.label), - error = OudsError(message = stringResource(R.string.field_required)) -) - -// Value-based -var value by remember { mutableStateOf("") } -OudsTextInput( - value = value, - onValueChange = { value = it }, - label = stringResource(R.string.label) -) - -// Untinted leading icon -OudsTextInput( - textFieldState = rememberTextFieldState(), - label = stringResource(R.string.label), - leadingIcon = OudsTextInputLeadingIcon(painter = myPainter, contentDescription = "", tinted = false) -) -``` - ---- - -## TextArea - -Same two API variants as `TextInput` (state-based / value-based). - -```kotlin -// State-based -OudsTextArea( - textFieldState = rememberTextFieldState(), - label = stringResource(R.string.feedback), - placeholder = stringResource(R.string.feedback_placeholder), - helperText = stringResource(R.string.feedback_helper) -) - -// With error -OudsTextArea( - textFieldState = rememberTextFieldState(), - label = stringResource(R.string.comment), - outlined = true, - error = OudsError(message = stringResource(R.string.min_chars_error)) -) - -// Value-based -var value by remember { mutableStateOf("") } -OudsTextArea( - value = value, - onValueChange = { value = it }, - label = stringResource(R.string.description) -) -``` - ---- - -## PasswordInput - -Uses `OudsPasswordInputState` to manage visibility toggle. Create the state with `rememberOudsPasswordInputState()`. - -```kotlin -OudsPasswordInput( - state = rememberOudsPasswordInputState(), - label = stringResource(R.string.password), - lockIcon = true, - helperText = stringResource(R.string.password_helper) -) - -// With error -OudsPasswordInput( - state = rememberOudsPasswordInputState(), - label = stringResource(R.string.password), - error = OudsError(message = stringResource(R.string.password_error)) -) -``` - ---- - -## PinCodeInput - -**Lengths:** `OudsPinCodeInputLength` — `Four`, `Six` - -```kotlin -var value by remember { mutableStateOf("") } - -OudsPinCodeInput( - value = value, - onValueChange = { value = it }, - length = OudsPinCodeInputLength.Four, - helperText = stringResource(R.string.pin_helper) -) - -// With error -OudsPinCodeInput( - value = value, - onValueChange = { value = it }, - length = OudsPinCodeInputLength.Four, - error = OudsError(message = stringResource(R.string.pin_error)) -) -``` - ---- - -## FilterChip - -**Selectable chip** used for filtering content. - -```kotlin -// Text only -OudsFilterChip(text = stringResource(R.string.label), onClick = { }) - -// With icon -OudsFilterChip( - icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), - text = stringResource(R.string.label), - onClick = { } -) - -// Icon only -OudsFilterChip( - icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), - contentDescription = stringResource(R.string.label_desc), - onClick = { } -) - -// Selected state -var selected by remember { mutableStateOf(false) } -OudsFilterChip( - text = stringResource(R.string.label), - selected = selected, - onClick = { selected = !selected } -) -``` - ---- - -## SuggestionChip - -**Action chip** used for suggestions and quick actions. - -```kotlin -// Text only -OudsSuggestionChip(text = stringResource(R.string.label), onClick = { }) - -// With icon -OudsSuggestionChip( - icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), - text = stringResource(R.string.label), - onClick = { } -) - -// Icon only -OudsSuggestionChip( - icon = OudsChipIcon(imageVector = Icons.Filled.Add), - contentDescription = stringResource(R.string.add_desc), - onClick = { } -) -``` - ---- - -## Link - -**Chevrons:** `OudsLinkChevron` — `Next`, `Back` - -```kotlin -// Text only -OudsLink( - label = stringResource(R.string.link_label), - onClick = { } -) - -// With icon -OudsLink( - label = stringResource(R.string.link_label), - icon = OudsLinkIcon(imageVector = Icons.Filled.FavoriteBorder), - onClick = { } -) - -// With chevron -OudsLink( - label = stringResource(R.string.link_label), - chevron = OudsLinkChevron.Next, - onClick = { } -) - -// With untinted icon -OudsLink( - label = stringResource(R.string.link_label), - icon = OudsLinkIcon(painter = myPainter, tinted = false), - onClick = { } -) -``` - ---- - -## Divider - -```kotlin -// Horizontal -OudsHorizontalDivider(modifier = Modifier.fillMaxWidth()) - -// Vertical -OudsVerticalDivider(modifier = Modifier.height(50.dp)) -``` - ---- - -## NavigationBar - -```kotlin -var selectedIndex by rememberSaveable { mutableIntStateOf(0) } - -OudsNavigationBar( - items = listOf( - OudsNavigationBarItem( - selected = selectedIndex == 0, - onClick = { selectedIndex = 0 }, - icon = OudsNavigationBarItemIcon(imageVector = Icons.Default.Home), - label = stringResource(R.string.home) - ), - OudsNavigationBarItem( - selected = selectedIndex == 1, - onClick = { selectedIndex = 1 }, - icon = OudsNavigationBarItemIcon(imageVector = Icons.Default.Email), - label = stringResource(R.string.messages), - badge = OudsNavigationBarItemBadge( - contentDescription = stringResource(R.string.unread_count, 5), - count = 5 - ) - ) - ) -) -``` - ---- - -## TopAppBar - -Four variants: `OudsTopAppBar`, `OudsCenterAlignedTopAppBar`, `OudsMediumTopAppBar`, `OudsLargeTopAppBar`. -**Navigation icons:** `OudsTopAppBarNavigationIcon.Back { }` · `OudsTopAppBarNavigationIcon.Menu { }` -**Actions:** `OudsTopAppBarAction.Icon(…)` · `OudsTopAppBarAction.Avatar(…)` - -```kotlin -@OptIn(ExperimentalMaterial3Api::class) -OudsTopAppBar( - title = stringResource(R.string.screen_title), - navigationIcon = OudsTopAppBarNavigationIcon.Back { /* navigate back */ }, - actions = listOf( - OudsTopAppBarAction.Icon( - imageVector = Icons.Outlined.Settings, - contentDescription = stringResource(R.string.settings_desc) - ) { /* open settings */ } - ) -) - -// Large top app bar -@OptIn(ExperimentalMaterial3Api::class) -OudsLargeTopAppBar( - title = stringResource(R.string.screen_title), - navigationIcon = OudsTopAppBarNavigationIcon.Back { } -) -``` - ---- - -## ColoredBox - -Creates a colored surface where child OUDS components automatically switch to their monochrome variant. - -**Colors:** 24 values organized by category: -- **Background** (5): `BackgroundInverseHigh`, `BackgroundInverseLow`, `BackgroundPrimary`, `BackgroundSecondary`, `BackgroundTertiary` -- **Brand** (3): `BrandPrimary`, `BrandSecondary`, `BrandTertiary` -- **Overlay** (3): `OverlayDropdown`, `OverlayModal`, `OverlayTooltip` -- **Status** (8): `StatusAccentEmphasized`, `StatusAccentMuted`, `StatusInfoEmphasized`, `StatusInfoMuted`, `StatusNegativeEmphasized`, `StatusNegativeMuted`, `StatusPositiveEmphasized`, `StatusPositiveMuted`, `StatusWarningEmphasized`, `StatusWarningMuted` -- **Surface** (5): `SurfaceInverseHigh`, `SurfaceInverseLow`, `SurfacePrimary`, `SurfaceSecondary`, `SurfaceTertiary` - -> **Note:** Not all colors are supported by all themes. Check `color.isSupported` before using a color in production code. - -```kotlin -// Basic usage -OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { - // Child OUDS components adopt monochrome colors automatically - OudsButton(label = stringResource(R.string.action), onClick = { }) - Text( - text = stringResource(R.string.description), - color = OudsTheme.colorScheme.content.default - ) -} - -// Check if color is supported by current theme -val color = OudsColoredBoxColor.BrandPrimary -if (color.isSupported) { - OudsColoredBox(color = color) { - // Content - } -} - -// Different color categories -OudsColoredBox(color = OudsColoredBoxColor.BrandPrimary) { /* Brand colors */ } -OudsColoredBox(color = OudsColoredBoxColor.StatusPositiveEmphasized) { /* Status colors */ } -OudsColoredBox(color = OudsColoredBoxColor.SurfacePrimary) { /* Surface colors */ } -``` - ---- - -## BottomSheetScaffold - -**Standard bottom sheet** that co-exists with main screen content, allowing simultaneous interaction. -**See also:** [ModalBottomSheet](#modalbottomsheet) for modal behavior that blocks main content. - -```kotlin -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun MyScreen() { - val scaffoldState = rememberBottomSheetScaffoldState() - - OudsBottomSheetScaffold( - sheetContent = { - Column(modifier = Modifier.padding(16.dp)) { - Text(stringResource(R.string.sheet_title)) - Text(stringResource(R.string.sheet_content)) - } - }, - sheetPeekHeight = 128.dp, - content = { paddingValues -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(paddingValues) - ) { - Text(stringResource(R.string.main_content)) - } - } - ) -} - -// Without drag handle -OudsBottomSheetScaffold( - sheetContent = { /* content */ }, - sheetDragHandle = false, - content = { /* main content */ } -) - -// With custom peek height -OudsBottomSheetScaffold( - sheetContent = { /* content */ }, - sheetPeekHeight = 200.dp, - content = { /* main content */ } -) -``` - ---- - -## ModalBottomSheet - -**Modal bottom sheet** that appears in front of app content and blocks interaction until dismissed. -**See also:** [BottomSheetScaffold](#bottomsheetscaffold) for non-modal variant. - -```kotlin -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun MyScreen() { - var showBottomSheet by remember { mutableStateOf(false) } - val sheetState = rememberModalBottomSheetState() - - Button(onClick = { showBottomSheet = true }) { - Text(stringResource(R.string.show_sheet)) - } - - if (showBottomSheet) { - OudsModalBottomSheet( - onDismissRequest = { showBottomSheet = false }, - sheetState = sheetState - ) { - Column(modifier = Modifier.padding(16.dp)) { - Text(stringResource(R.string.sheet_title)) - Text(stringResource(R.string.sheet_content)) - Button(onClick = { showBottomSheet = false }) { - Text(stringResource(R.string.close)) - } - } - } - } -} - -// Without drag handle -OudsModalBottomSheet( - onDismissRequest = { /* dismiss */ }, - dragHandle = false -) { - // Content -} - -// With gestures disabled -OudsModalBottomSheet( - onDismissRequest = { /* dismiss */ }, - sheetGesturesEnabled = false -) { - // Content -} -``` diff --git a/skills/using-ouds-android/references/content-components.md b/skills/using-ouds-android/references/content-components.md new file mode 100644 index 0000000000..b7b8e7109a --- /dev/null +++ b/skills/using-ouds-android/references/content-components.md @@ -0,0 +1,39 @@ +# OUDS Android — Content Components + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +- [BulletList](#bulletlist) — Ordered, unordered, and bare lists + +--- + +## BulletList + +**Types:** `OudsBulletListType` — `Unordered` (default, `brandColor: Boolean`), `Ordered`, `Bare` + +```kotlin +// Unordered (brand color) +OudsBulletList { + item(label = stringResource(R.string.item_1)) + item(label = stringResource(R.string.item_2), subListType = OudsBulletListType.Unordered(brandColor = false)) { + item(label = stringResource(R.string.sub_item_1)) + } +} + +// Ordered +OudsBulletList(type = OudsBulletListType.Ordered) { + item(label = stringResource(R.string.step_1)) + item(label = stringResource(R.string.step_2)) { + item(label = stringResource(R.string.sub_step_1)) + } +} + +// Bare (no bullet) +OudsBulletList(type = OudsBulletListType.Bare) { + item(label = stringResource(R.string.item_1)) +} +``` diff --git a/skills/using-ouds-android/references/control-components.md b/skills/using-ouds-android/references/control-components.md new file mode 100644 index 0000000000..5bd6a7b6c4 --- /dev/null +++ b/skills/using-ouds-android/references/control-components.md @@ -0,0 +1,311 @@ +# OUDS Android — Control Components + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +- [Checkbox](#checkbox) — Standalone checkbox +- [CheckboxItem](#checkboxitem) — Checkbox with label and description +- [RadioButton](#radiobutton) — Standalone radio button +- [RadioButtonItem](#radiobuttonitem) — Radio button with label and description +- [Switch](#switch) — Standalone switch +- [SwitchItem](#switchitem) — Toggle switch with label and description + - **Chip** + - [FilterChip](#filterchip) — Selectable filter chip + - [SuggestionChip](#suggestionchip) — Suggestion and action chip + +--- + +## CheckboxItem + +Signature: `OudsCheckboxItem(checked, label, onCheckedChange, modifier, description?, icon?, divider?, enabled?, error?)` +Tri-state variant: `OudsTriStateCheckboxItem(state: ToggleableState, label, onClick, …)` + +```kotlin +// Basic +var checked by remember { mutableStateOf(false) } +OudsCheckboxItem( + checked = checked, + label = stringResource(R.string.terms), + onCheckedChange = { checked = it } +) + +// With description and icon +OudsCheckboxItem( + checked = checked, + label = stringResource(R.string.terms), + description = stringResource(R.string.terms_desc), + icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + onCheckedChange = { checked = it } +) + +// With untinted icon +OudsCheckboxItem( + checked = checked, + label = stringResource(R.string.terms), + icon = OudsControlItemIcon(painter = myPainter, tinted = false), + onCheckedChange = { checked = it } +) + +// With error +OudsCheckboxItem( + checked = checked, + label = stringResource(R.string.terms), + onCheckedChange = { checked = it }, + error = OudsError(message = stringResource(R.string.error_required)) +) + +// Tri-state +var state by remember { mutableStateOf(ToggleableState.Off) } +OudsTriStateCheckboxItem( + state = state, + label = stringResource(R.string.select_all), + onClick = { + state = when (state) { + ToggleableState.On -> ToggleableState.Off + ToggleableState.Off -> ToggleableState.Indeterminate + ToggleableState.Indeterminate -> ToggleableState.On + } + } +) +``` + +--- + +## RadioButtonItem + +Signature: `OudsRadioButtonItem(selected, label, onClick, modifier, description?, icon?, divider?, enabled?, error?)` +**Always** wrap a group of radio items in `Modifier.selectableGroup()`. + +```kotlin +val options = listOf( + stringResource(R.string.option_a), + stringResource(R.string.option_b) +) +var selected by rememberSaveable { mutableStateOf(options.first()) } + +Column(modifier = Modifier.selectableGroup()) { + options.forEach { option -> + OudsRadioButtonItem( + selected = option == selected, + label = option, + onClick = { selected = option }, + divider = true + ) + } +} + +// With icon +OudsRadioButtonItem( + selected = selected == option, + label = option, + icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + onClick = { selected = option } +) + +// With error (typically on the last item) +OudsRadioButtonItem( + selected = selected == option, + label = option, + onClick = { selected = option }, + error = OudsError(message = stringResource(R.string.selection_required)) +) +``` + +--- + +## SwitchItem + +Signature: `OudsSwitchItem(checked, label, onCheckedChange, modifier, description?, icon?, divider?, enabled?, error?)` + +```kotlin +var checked by remember { mutableStateOf(true) } + +OudsSwitchItem( + checked = checked, + label = stringResource(R.string.notifications), + description = stringResource(R.string.notifications_desc), + icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + onCheckedChange = { checked = it } +) + +// With untinted icon +OudsSwitchItem( + checked = checked, + label = stringResource(R.string.notifications), + icon = OudsControlItemIcon(painter = myPainter, tinted = false), + onCheckedChange = { checked = it } +) + +// With error +OudsSwitchItem( + checked = checked, + label = stringResource(R.string.notifications), + onCheckedChange = { checked = it }, + error = OudsError(message = stringResource(R.string.notifications_required)) +) +``` + +--- + +## Checkbox + +**Standalone checkbox** without label — use when checkbox is nested within another component with an alternative label. +**See also:** [CheckboxItem](#checkboxitem) for checkbox with label and description. + +```kotlin +var checked by remember { mutableStateOf(false) } + +// Basic checkbox +OudsCheckbox( + checked = checked, + onCheckedChange = { checked = it } +) + +// Disabled +OudsCheckbox( + checked = checked, + onCheckedChange = { checked = it }, + enabled = false +) + +// Tri-state checkbox +var state by remember { mutableStateOf(ToggleableState.Off) } +OudsTriStateCheckbox( + state = state, + onClick = { + state = when (state) { + ToggleableState.On -> ToggleableState.Off + ToggleableState.Off -> ToggleableState.Indeterminate + ToggleableState.Indeterminate -> ToggleableState.On + } + } +) +``` + +--- + +## RadioButton + +**Standalone radio button** without label — use when radio button is nested within another component with an alternative label. +**See also:** [RadioButtonItem](#radiobuttonitem) for radio button with label and description. +**Always** wrap a group of radio buttons in `Modifier.selectableGroup()`. + +```kotlin +val options = listOf("Option A", "Option B", "Option C") +var selected by remember { mutableStateOf(options[0]) } + +Column(modifier = Modifier.selectableGroup()) { + options.forEach { option -> + OudsRadioButton( + selected = option == selected, + onClick = { selected = option } + ) + } +} + +// Disabled +OudsRadioButton( + selected = true, + onClick = null, + enabled = false +) +``` + +--- + +## Switch + +**Standalone switch** without label — use when switch is nested within another component with an alternative label. +**See also:** [SwitchItem](#switchitem) for switch with label and description. + +```kotlin +var checked by remember { mutableStateOf(true) } + +// Basic switch +OudsSwitch( + checked = checked, + onCheckedChange = { checked = it } +) + +// Disabled +OudsSwitch( + checked = checked, + onCheckedChange = { checked = it }, + enabled = false +) + +// With icon (when checked) +OudsSwitch( + checked = checked, + onCheckedChange = { checked = it }, + thumbContent = { + Icon( + imageVector = Icons.Filled.Check, + contentDescription = null, + modifier = Modifier.size(16.dp) + ) + } +) +``` + +--- + +## FilterChip + +**Selectable chip** used for filtering content. + +```kotlin +// Text only +OudsFilterChip(text = stringResource(R.string.label), onClick = { }) + +// With icon +OudsFilterChip( + icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), + text = stringResource(R.string.label), + onClick = { } +) + +// Icon only +OudsFilterChip( + icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), + contentDescription = stringResource(R.string.label_desc), + onClick = { } +) + +// Selected state +var selected by remember { mutableStateOf(false) } +OudsFilterChip( + text = stringResource(R.string.label), + selected = selected, + onClick = { selected = !selected } +) +``` + +--- + +## SuggestionChip + +**Action chip** used for suggestions and quick actions. + +```kotlin +// Text only +OudsSuggestionChip(text = stringResource(R.string.label), onClick = { }) + +// With icon +OudsSuggestionChip( + icon = OudsChipIcon(imageVector = Icons.Filled.FavoriteBorder), + text = stringResource(R.string.label), + onClick = { } +) + +// Icon only +OudsSuggestionChip( + icon = OudsChipIcon(imageVector = Icons.Filled.Add), + contentDescription = stringResource(R.string.add_desc), + onClick = { } +) +``` diff --git a/skills/using-ouds-android/references/indicator-components.md b/skills/using-ouds-android/references/indicator-components.md new file mode 100644 index 0000000000..8e5ec31894 --- /dev/null +++ b/skills/using-ouds-android/references/indicator-components.md @@ -0,0 +1,200 @@ +# OUDS Android — Indicator Components + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +- [Badge](#badge) — Count and status badges +- [CircularProgressIndicator](#circularprogressindicator) — Circular loading indicator +- [LinearProgressIndicator](#linearprogressindicator) — Linear loading indicator +- [Tag](#tag) — Status and category tags + +--- + +## Tag + +**Statuses:** `OudsTagStatus` — `Neutral`, `Accent`, `Positive`, `Warning`, `Negative`, `Info` +**Assets:** `OudsTagAsset.Bullet` · `OudsTagAsset.Icon(…)` · `OudsTagAsset.Icon.Default` (functional icon per status) +**Appearances:** `OudsTagAppearance` — `Emphasized` (default), `Muted` +**Sizes:** `OudsTagSize` — `Default`, `Small` + +```kotlin +// Text only +OudsTag(label = stringResource(R.string.label)) + +// With bullet +OudsTag( + label = stringResource(R.string.label), + status = OudsTagStatus.Positive(asset = OudsTagAsset.Bullet) +) + +// With default functional icon (icon per status) +OudsTag( + label = stringResource(R.string.label), + status = OudsTagStatus.Positive(asset = OudsTagAsset.Icon.Default) +) + +// With custom icon (Neutral or Accent only) +OudsTag( + label = stringResource(R.string.label), + status = OudsTagStatus.Neutral(asset = OudsTagAsset.Icon(imageVector = Icons.Filled.FavoriteBorder)) +) + +// With untinted icon +OudsTag( + label = stringResource(R.string.label), + status = OudsTagStatus.Neutral(asset = OudsTagAsset.Icon(painter = myPainter, tinted = false)) +) + +// Small size +OudsTag(label = stringResource(R.string.label), size = OudsTagSize.Small) + +// With loader (indeterminate) +OudsTag(label = stringResource(R.string.label), loader = OudsTagLoader(progress = null)) +``` + +--- + +## Badge + +**Statuses (plain/count):** `OudsBadgeStatus` — `Neutral`, `Accent`, `Positive`, `Warning`, `Negative`, `Info` +**Statuses (icon):** `OudsIconBadgeStatus` — `Neutral(icon?)`, `Accent(icon?)`, `Positive`, `Warning`, `Negative`, `Info` +**Sizes:** `OudsBadgeSize` — `ExtraSmall`, `Small`, `Medium`, `Large` +**Note:** Always provide a `contentDescription` via `Modifier.semantics { contentDescription = "…" }`. + +```kotlin +// Standard dot badge +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.info_desc) }, + status = OudsBadgeStatus.Info, + size = OudsBadgeSize.Small +) + +// Badge with count +val count = 10 +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.unread_count, count) }, + status = OudsBadgeStatus.Accent, + count = count +) + +// Badge with default functional icon +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.info_desc) }, + status = OudsIconBadgeStatus.Info, + size = OudsBadgeSize.Large +) + +// Badge with custom icon +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.favorite_desc) }, + status = OudsIconBadgeStatus.Accent(OudsBadgeIcon(imageVector = Icons.Filled.FavoriteBorder)), + size = OudsBadgeSize.Large +) + +// Badge with untinted custom icon +OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.brand_desc) }, + status = OudsIconBadgeStatus.Neutral(OudsBadgeIcon(painter = myPainter, tinted = false)), + size = OudsBadgeSize.Large +) + +// Typical use: badged navigation item +BadgedBox( + badge = { + OudsBadge( + modifier = Modifier.semantics { contentDescription = stringResource(R.string.unread_count, 8) }, + count = 8, + status = OudsBadgeStatus.Accent + ) + } +) { + Icon(imageVector = Icons.Filled.Notifications, contentDescription = null) +} +``` + +--- + +## CircularProgressIndicator + +**Statuses:** `OudsProgressIndicatorStatus` — `Accent` (default), `Neutral` +**Variants:** Determinate (with progress value) · Indeterminate (loading animation) +**Track:** Optional background track for better visibility + +```kotlin +// Indeterminate (loading) +OudsCircularProgressIndicator() + +// Determinate (with progress) +OudsCircularProgressIndicator(progress = { 0.75f }) + +// With status +OudsCircularProgressIndicator( + progress = { 0.5f }, + status = OudsProgressIndicatorStatus.Neutral +) + +// Without track (minimal) +OudsCircularProgressIndicator( + progress = { 0.75f }, + track = false +) + +// Custom size +OudsCircularProgressIndicator( + modifier = Modifier.size(64.dp), + progress = { 0.75f } +) +``` + +--- + +## LinearProgressIndicator + +**Statuses:** `OudsProgressIndicatorStatus` — `Accent` (default), `Neutral` +**Variants:** Determinate (with progress value) · Indeterminate (loading animation) +**Track:** Optional background track for better visibility +**Stop Indicator:** Optional end marker for accessibility (required if contrast < 3:1) + +```kotlin +// Indeterminate (loading) +OudsLinearProgressIndicator( + helperText = stringResource(R.string.loading) +) + +// Determinate (with progress) +OudsLinearProgressIndicator( + progress = { 0.75f }, + helperText = stringResource(R.string.loading_percent, 75) +) + +// With status +OudsLinearProgressIndicator( + progress = { 0.5f }, + status = OudsProgressIndicatorStatus.Neutral, + helperText = stringResource(R.string.uploading) +) + +// Without track (minimal) +OudsLinearProgressIndicator( + progress = { 0.75f }, + track = false +) + +// With stop indicator (for accessibility) +OudsLinearProgressIndicator( + progress = { 0.75f }, + stopIndicator = true, + helperText = stringResource(R.string.processing) +) + +// Full width with helper text +OudsLinearProgressIndicator( + modifier = Modifier.fillMaxWidth(), + progress = { 0.75f }, + helperText = "Uploading file: document.pdf" +) +``` diff --git a/skills/using-ouds-android/references/input-components.md b/skills/using-ouds-android/references/input-components.md new file mode 100644 index 0000000000..b6f596e0f8 --- /dev/null +++ b/skills/using-ouds-android/references/input-components.md @@ -0,0 +1,153 @@ +# OUDS Android — Input Components + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +- [TextInput](#textinput) — Single-line text field +- [TextArea](#textarea) — Multi-line text field +- [PasswordInput](#passwordinput) — Password field with visibility toggle +- [PinCodeInput](#pincodeinput) — PIN code input (4 or 6 digits) + +--- + +## TextInput + +Two API variants: **state-based** (`textFieldState`) and **value-based** (`value` + `onValueChange`). +Prefer the state-based API for new code. + +```kotlin +// State-based — basic +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.label) +) + +// State-based — full featured +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.label), + placeholder = stringResource(R.string.placeholder), + leadingIcon = OudsTextInputLeadingIcon(imageVector = Icons.Filled.Search, contentDescription = ""), + prefix = stringResource(R.string.prefix), + suffix = stringResource(R.string.suffix), + helperText = stringResource(R.string.helper), + helperLink = OudsTextInputHelperLink(text = stringResource(R.string.more), onClick = { }) +) + +// With trailing action button +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.date), + trailingIconButton = OudsTextInputTrailingIconButton( + imageVector = Icons.Filled.DateRange, + contentDescription = stringResource(R.string.open_calendar), + onClick = { } + ), + outlined = true +) + +// With error +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.label), + error = OudsError(message = stringResource(R.string.field_required)) +) + +// Value-based +var value by remember { mutableStateOf("") } +OudsTextInput( + value = value, + onValueChange = { value = it }, + label = stringResource(R.string.label) +) + +// Untinted leading icon +OudsTextInput( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.label), + leadingIcon = OudsTextInputLeadingIcon(painter = myPainter, contentDescription = "", tinted = false) +) +``` + +--- + +## TextArea + +Same two API variants as `TextInput` (state-based / value-based). + +```kotlin +// State-based +OudsTextArea( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.feedback), + placeholder = stringResource(R.string.feedback_placeholder), + helperText = stringResource(R.string.feedback_helper) +) + +// With error +OudsTextArea( + textFieldState = rememberTextFieldState(), + label = stringResource(R.string.comment), + outlined = true, + error = OudsError(message = stringResource(R.string.min_chars_error)) +) + +// Value-based +var value by remember { mutableStateOf("") } +OudsTextArea( + value = value, + onValueChange = { value = it }, + label = stringResource(R.string.description) +) +``` + +--- + +## PasswordInput + +Uses `OudsPasswordInputState` to manage visibility toggle. Create the state with `rememberOudsPasswordInputState()`. + +```kotlin +OudsPasswordInput( + state = rememberOudsPasswordInputState(), + label = stringResource(R.string.password), + lockIcon = true, + helperText = stringResource(R.string.password_helper) +) + +// With error +OudsPasswordInput( + state = rememberOudsPasswordInputState(), + label = stringResource(R.string.password), + error = OudsError(message = stringResource(R.string.password_error)) +) +``` + +--- + +## PinCodeInput + +**Lengths:** `OudsPinCodeInputLength` — `Four`, `Six` + +```kotlin +var value by remember { mutableStateOf("") } + +OudsPinCodeInput( + value = value, + onValueChange = { value = it }, + length = OudsPinCodeInputLength.Four, + helperText = stringResource(R.string.pin_helper) +) + +// With error +OudsPinCodeInput( + value = value, + onValueChange = { value = it }, + length = OudsPinCodeInputLength.Four, + error = OudsError(message = stringResource(R.string.pin_error)) +) +``` diff --git a/skills/using-ouds-android/references/layout-components.md b/skills/using-ouds-android/references/layout-components.md new file mode 100644 index 0000000000..a77bbef0c4 --- /dev/null +++ b/skills/using-ouds-android/references/layout-components.md @@ -0,0 +1,164 @@ +# OUDS Android — Layout Components + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +- [BottomSheetScaffold](#bottomsheetscaffold) — Standard bottom sheet scaffold +- [ColoredBox](#coloredbox) — Colored surface container +- [Divider](#divider) — Horizontal and vertical dividers +- [ModalBottomSheet](#modalbottomsheet) — Modal bottom sheet + +--- + +## ColoredBox + +Creates a colored surface where child OUDS components automatically switch to their monochrome variant. + +**Colors:** 24 values organized by category: +- **Background** (5): `BackgroundInverseHigh`, `BackgroundInverseLow`, `BackgroundPrimary`, `BackgroundSecondary`, `BackgroundTertiary` +- **Brand** (3): `BrandPrimary`, `BrandSecondary`, `BrandTertiary` +- **Overlay** (3): `OverlayDropdown`, `OverlayModal`, `OverlayTooltip` +- **Status** (8): `StatusAccentEmphasized`, `StatusAccentMuted`, `StatusInfoEmphasized`, `StatusInfoMuted`, `StatusNegativeEmphasized`, `StatusNegativeMuted`, `StatusPositiveEmphasized`, `StatusPositiveMuted`, `StatusWarningEmphasized`, `StatusWarningMuted` +- **Surface** (5): `SurfaceInverseHigh`, `SurfaceInverseLow`, `SurfacePrimary`, `SurfaceSecondary`, `SurfaceTertiary` + +> **Note:** Not all colors are supported by all themes. Check `color.isSupported` before using a color in production code. + +```kotlin +// Basic usage +OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { + // Child OUDS components adopt monochrome colors automatically + OudsButton(label = stringResource(R.string.action), onClick = { }) + Text( + text = stringResource(R.string.description), + color = OudsTheme.colorScheme.content.default + ) +} + +// Check if color is supported by current theme +val color = OudsColoredBoxColor.BrandPrimary +if (color.isSupported) { + OudsColoredBox(color = color) { + // Content + } +} + +// Different color categories +OudsColoredBox(color = OudsColoredBoxColor.BrandPrimary) { /* Brand colors */ } +OudsColoredBox(color = OudsColoredBoxColor.StatusPositiveEmphasized) { /* Status colors */ } +OudsColoredBox(color = OudsColoredBoxColor.SurfacePrimary) { /* Surface colors */ } +``` + +--- + +## Divider + +```kotlin +// Horizontal +OudsHorizontalDivider(modifier = Modifier.fillMaxWidth()) + +// Vertical +OudsVerticalDivider(modifier = Modifier.height(50.dp)) +``` + +--- + +## BottomSheetScaffold + +**Standard bottom sheet** that co-exists with main screen content, allowing simultaneous interaction. +**See also:** [ModalBottomSheet](#modalbottomsheet) for modal behavior that blocks main content. + +```kotlin +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MyScreen() { + val scaffoldState = rememberBottomSheetScaffoldState() + + OudsBottomSheetScaffold( + sheetContent = { + Column(modifier = Modifier.padding(16.dp)) { + Text(stringResource(R.string.sheet_title)) + Text(stringResource(R.string.sheet_content)) + } + }, + sheetPeekHeight = 128.dp, + content = { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + ) { + Text(stringResource(R.string.main_content)) + } + } + ) +} + +// Without drag handle +OudsBottomSheetScaffold( + sheetContent = { /* content */ }, + sheetDragHandle = false, + content = { /* main content */ } +) + +// With custom peek height +OudsBottomSheetScaffold( + sheetContent = { /* content */ }, + sheetPeekHeight = 200.dp, + content = { /* main content */ } +) +``` + +--- + +## ModalBottomSheet + +**Modal bottom sheet** that appears in front of app content and blocks interaction until dismissed. +**See also:** [BottomSheetScaffold](#bottomsheetscaffold) for non-modal variant. + +```kotlin +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MyScreen() { + var showBottomSheet by remember { mutableStateOf(false) } + val sheetState = rememberModalBottomSheetState() + + Button(onClick = { showBottomSheet = true }) { + Text(stringResource(R.string.show_sheet)) + } + + if (showBottomSheet) { + OudsModalBottomSheet( + onDismissRequest = { showBottomSheet = false }, + sheetState = sheetState + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text(stringResource(R.string.sheet_title)) + Text(stringResource(R.string.sheet_content)) + Button(onClick = { showBottomSheet = false }) { + Text(stringResource(R.string.close)) + } + } + } + } +} + +// Without drag handle +OudsModalBottomSheet( + onDismissRequest = { /* dismiss */ }, + dragHandle = false +) { + // Content +} + +// With gestures disabled +OudsModalBottomSheet( + onDismissRequest = { /* dismiss */ }, + sheetGesturesEnabled = false +) { + // Content +} +``` diff --git a/skills/using-ouds-android/references/navigation-components.md b/skills/using-ouds-android/references/navigation-components.md new file mode 100644 index 0000000000..267fea1150 --- /dev/null +++ b/skills/using-ouds-android/references/navigation-components.md @@ -0,0 +1,105 @@ +# OUDS Android — Navigation Components + +All components are in the `com.orange.ouds.core.component` package. +All user-visible strings must use `stringResource(R.string.*)` — never hardcode. + +> **Naming Convention:** All OUDS components follow the `Ouds*` prefix naming pattern (e.g., `OudsButton`, `OudsTag`, `OudsTextInput`). + +## Table of Contents + +- [Link](#link) — Text link with optional icon/chevron +- [NavigationBar](#navigationbar) — Bottom navigation bar +- [TopAppBar](#topappbar) — Top app bar with variants + +--- + +## Link + +**Chevrons:** `OudsLinkChevron` — `Next`, `Back` + +```kotlin +// Text only +OudsLink( + label = stringResource(R.string.link_label), + onClick = { } +) + +// With icon +OudsLink( + label = stringResource(R.string.link_label), + icon = OudsLinkIcon(imageVector = Icons.Filled.FavoriteBorder), + onClick = { } +) + +// With chevron +OudsLink( + label = stringResource(R.string.link_label), + chevron = OudsLinkChevron.Next, + onClick = { } +) + +// With untinted icon +OudsLink( + label = stringResource(R.string.link_label), + icon = OudsLinkIcon(painter = myPainter, tinted = false), + onClick = { } +) +``` + +--- + +## NavigationBar + +```kotlin +var selectedIndex by rememberSaveable { mutableIntStateOf(0) } + +OudsNavigationBar( + items = listOf( + OudsNavigationBarItem( + selected = selectedIndex == 0, + onClick = { selectedIndex = 0 }, + icon = OudsNavigationBarItemIcon(imageVector = Icons.Default.Home), + label = stringResource(R.string.home) + ), + OudsNavigationBarItem( + selected = selectedIndex == 1, + onClick = { selectedIndex = 1 }, + icon = OudsNavigationBarItemIcon(imageVector = Icons.Default.Email), + label = stringResource(R.string.messages), + badge = OudsNavigationBarItemBadge( + contentDescription = stringResource(R.string.unread_count, 5), + count = 5 + ) + ) + ) +) +``` + +--- + +## TopAppBar + +Four variants: `OudsTopAppBar`, `OudsCenterAlignedTopAppBar`, `OudsMediumTopAppBar`, `OudsLargeTopAppBar`. +**Navigation icons:** `OudsTopAppBarNavigationIcon.Back { }` · `OudsTopAppBarNavigationIcon.Menu { }` +**Actions:** `OudsTopAppBarAction.Icon(…)` · `OudsTopAppBarAction.Avatar(…)` + +```kotlin +@OptIn(ExperimentalMaterial3Api::class) +OudsTopAppBar( + title = stringResource(R.string.screen_title), + navigationIcon = OudsTopAppBarNavigationIcon.Back { /* navigate back */ }, + actions = listOf( + OudsTopAppBarAction.Icon( + imageVector = Icons.Outlined.Settings, + contentDescription = stringResource(R.string.settings_desc) + ) { /* open settings */ } + ) +) + +// Large top app bar +@OptIn(ExperimentalMaterial3Api::class) +OudsLargeTopAppBar( + title = stringResource(R.string.screen_title), + navigationIcon = OudsTopAppBarNavigationIcon.Back { } +) +``` From b3a69a2dfe25665a6fce2902a39aa64944fc486e Mon Sep 17 00:00:00 2001 From: Pauline Auvray Date: Thu, 30 Jul 2026 18:07:58 +0200 Subject: [PATCH 8/9] Add "Ouds" prefix when it is an OUDS components --- AGENTS.md | 16 ++--- skills/using-ouds-android/SKILL.md | 16 ++--- .../references/action-components.md | 8 +-- .../references/alert-components.md | 4 +- .../references/components-index.md | 60 +++++++++---------- .../references/content-components.md | 2 +- .../references/control-components.md | 22 +++---- .../references/indicator-components.md | 8 +-- .../references/input-components.md | 12 ++-- .../references/layout-components.md | 12 ++-- .../references/navigation-components.md | 6 +- 11 files changed, 83 insertions(+), 83 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6b6b160d5b..daca313ea6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -227,14 +227,14 @@ skills/ ├── SKILL.md ← setup, themes, token access, common patterns, checklist, troubleshooting └── references/ ├── components-index.md ← complete component cross-reference - ├── action-components.md ← Button, FloatingActionButton, NavigationButton, SmallButton - ├── alert-components.md ← AlertMessage, InlineAlert - ├── content-components.md ← BulletList - ├── control-components.md ← Checkbox, CheckboxItem, RadioButton, RadioButtonItem, Switch, SwitchItem, FilterChip, SuggestionChip - ├── indicator-components.md ← Badge, CircularProgressIndicator, LinearProgressIndicator, Tag - ├── input-components.md ← TextInput, TextArea, PasswordInput, PinCodeInput - ├── layout-components.md ← BottomSheetScaffold, ColoredBox, Divider, ModalBottomSheet - ├── navigation-components.md ← Link, NavigationBar, TopAppBar + ├── action-components.md ← OudsButton, OudsFloatingActionButton, OudsNavigationButton, OudsSmallButton + ├── alert-components.md ← OudsAlertMessage, OudsInlineAlert + ├── content-components.md ← OudsBulletList + ├── control-components.md ← OudsCheckbox, OudsCheckboxItem, OudsRadioButton, OudsRadioButtonItem, OudsSwitch, OudsSwitchItem, OudsFilterChip, OudsSuggestionChip + ├── indicator-components.md ← OudsBadge, OudsCircularProgressIndicator, OudsLinearProgressIndicator, OudsTag + ├── input-components.md ← OudsTextInput, OudsTextArea, OudsPasswordInput, OudsPinCodeInput + ├── layout-components.md ← OudsBottomSheetScaffold, OudsColoredBox, OudsDivider, OudsModalBottomSheet + ├── navigation-components.md ← OudsLink, OudsNavigationBar, OudsTopAppBar ├── component-tokens.md ← advanced component-level tokens └── tokens.md ← semantic tokens (color, typography, spacing, etc.) ``` diff --git a/skills/using-ouds-android/SKILL.md b/skills/using-ouds-android/SKILL.md index 9beb08b6bb..db0558710a 100644 --- a/skills/using-ouds-android/SKILL.md +++ b/skills/using-ouds-android/SKILL.md @@ -409,28 +409,28 @@ error = OudsError( Component documentation is organized by category. When the user asks about specific components, consult the relevant reference file: - **Action components** (buttons, FAB): [`references/action-components.md`](references/action-components.md) - - Button, FloatingActionButton, NavigationButton, SmallButton + - OudsButton, OudsFloatingActionButton, OudsNavigationButton, OudsSmallButton - **Alert components** (alerts, messages): [`references/alert-components.md`](references/alert-components.md) - - AlertMessage, InlineAlert + - OudsAlertMessage, OudsInlineAlert - **Content components** (lists): [`references/content-components.md`](references/content-components.md) - - BulletList + - OudsBulletList - **Control components** (checkboxes, switches, chips): [`references/control-components.md`](references/control-components.md) - - Checkbox, CheckboxItem, RadioButton, RadioButtonItem, Switch, SwitchItem, FilterChip, SuggestionChip + - OudsCheckbox, OudsCheckboxItem, OudsRadioButton, OudsRadioButtonItem, OudsSwitch, OudsSwitchItem, OudsFilterChip, OudsSuggestionChip - **Indicator components** (badges, progress, tags): [`references/indicator-components.md`](references/indicator-components.md) - - Badge, CircularProgressIndicator, LinearProgressIndicator, Tag + - OudsBadge, OudsCircularProgressIndicator, OudsLinearProgressIndicator, OudsTag - **Input components** (text fields): [`references/input-components.md`](references/input-components.md) - - TextInput, TextArea, PasswordInput, PinCodeInput + - OudsTextInput, OudsTextArea, OudsPasswordInput, OudsPinCodeInput - **Layout components** (containers, dividers): [`references/layout-components.md`](references/layout-components.md) - - BottomSheetScaffold, ColoredBox, Divider, ModalBottomSheet + - OudsBottomSheetScaffold, OudsColoredBox, OudsDivider, OudsModalBottomSheet - **Navigation components** (links, bars): [`references/navigation-components.md`](references/navigation-components.md) - - Link, NavigationBar, TopAppBar + - OudsLink, OudsNavigationBar, OudsTopAppBar **Complete component index:** See [`references/components-index.md`](references/components-index.md) for a full cross-reference of all components. diff --git a/skills/using-ouds-android/references/action-components.md b/skills/using-ouds-android/references/action-components.md index 23cce26be4..16eae8bd7d 100644 --- a/skills/using-ouds-android/references/action-components.md +++ b/skills/using-ouds-android/references/action-components.md @@ -7,10 +7,10 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ## Table of Contents -- [Button](#button) — Default and small buttons -- [FloatingActionButton](#floatingactionbutton) — Floating action button (FAB) -- [NavigationButton](#navigationbutton) — Navigation button with chevron -- [SmallButton](#smallbutton) — Small size button variant +- [OudsButton](#button) — Default and small buttons +- [OudsFloatingActionButton](#floatingactionbutton) — Floating action button (FAB) +- [OudsNavigationButton](#navigationbutton) — Navigation button with chevron +- [OudsSmallButton](#smallbutton) — Small size button variant --- diff --git a/skills/using-ouds-android/references/alert-components.md b/skills/using-ouds-android/references/alert-components.md index cac94ed253..6c56fd75f9 100644 --- a/skills/using-ouds-android/references/alert-components.md +++ b/skills/using-ouds-android/references/alert-components.md @@ -7,8 +7,8 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ## Table of Contents -- [AlertMessage](#alertmessage) — Full-featured alert with actions -- [InlineAlert](#inlinealert) — Compact inline alert +- [OudsAlertMessage](#alertmessage) — Full-featured alert with actions +- [OudsInlineAlert](#inlinealert) — Compact inline alert --- diff --git a/skills/using-ouds-android/references/components-index.md b/skills/using-ouds-android/references/components-index.md index 65ecc44b70..11cb6e4d79 100644 --- a/skills/using-ouds-android/references/components-index.md +++ b/skills/using-ouds-android/references/components-index.md @@ -10,62 +10,62 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ### Action Components [→ See full documentation](action-components.md) -- [Button](action-components.md#button) — Default and small buttons -- [FloatingActionButton](action-components.md#floatingactionbutton) — Floating action button (FAB) -- [NavigationButton](action-components.md#navigationbutton) — Navigation button with chevron -- [SmallButton](action-components.md#smallbutton) — Small size button variant +- [OudsButton](action-components.md#button) — Default and small buttons +- [OudsFloatingActionButton](action-components.md#floatingactionbutton) — Floating action button (FAB) +- [OudsNavigationButton](action-components.md#navigationbutton) — Navigation button with chevron +- [OudsSmallButton](action-components.md#smallbutton) — Small size button variant ### Alert Components [→ See full documentation](alert-components.md) -- [AlertMessage](alert-components.md#alertmessage) — Full-featured alert with actions -- [InlineAlert](alert-components.md#inlinealert) — Compact inline alert +- [OudsAlertMessage](alert-components.md#alertmessage) — Full-featured alert with actions +- [OudsInlineAlert](alert-components.md#inlinealert) — Compact inline alert ### Content Components [→ See full documentation](content-components.md) -- [BulletList](content-components.md#bulletlist) — Ordered, unordered, and bare lists +- [OudsBulletList](content-components.md#bulletlist) — Ordered, unordered, and bare lists ### Control Components [→ See full documentation](control-components.md) -- [Checkbox](control-components.md#checkbox) — Standalone checkbox -- [CheckboxItem](control-components.md#checkboxitem) — Checkbox with label and description -- [RadioButton](control-components.md#radiobutton) — Standalone radio button -- [RadioButtonItem](control-components.md#radiobuttonitem) — Radio button with label and description -- [Switch](control-components.md#switch) — Standalone switch -- [SwitchItem](control-components.md#switchitem) — Toggle switch with label and description +- [OudsCheckbox](control-components.md#checkbox) — Standalone checkbox +- [OudsCheckboxItem](control-components.md#checkboxitem) — Checkbox with label and description +- [OudsRadioButton](control-components.md#radiobutton) — Standalone radio button +- [OudsRadioButtonItem](control-components.md#radiobuttonitem) — Radio button with label and description +- [OudsSwitch](control-components.md#switch) — Standalone switch +- [OudsSwitchItem](control-components.md#switchitem) — Toggle switch with label and description - **Chip** - - [FilterChip](control-components.md#filterchip) — Selectable filter chip - - [SuggestionChip](control-components.md#suggestionchip) — Suggestion and action chip + - [OudsFilterChip](control-components.md#filterchip) — Selectable filter chip + - [OudsSuggestionChip](control-components.md#suggestionchip) — Suggestion and action chip ### Indicator Components [→ See full documentation](indicator-components.md) -- [Badge](indicator-components.md#badge) — Count and status badges -- [CircularProgressIndicator](indicator-components.md#circularprogressindicator) — Circular loading indicator -- [LinearProgressIndicator](indicator-components.md#linearprogressindicator) — Linear loading indicator -- [Tag](indicator-components.md#tag) — Status and category tags +- [OudsBadge](indicator-components.md#badge) — Count and status badges +- [OudsCircularProgressIndicator](indicator-components.md#circularprogressindicator) — Circular loading indicator +- [OudsLinearProgressIndicator](indicator-components.md#linearprogressindicator) — Linear loading indicator +- [OudsTag](indicator-components.md#tag) — Status and category tags ### Input Components [→ See full documentation](input-components.md) -- [TextInput](input-components.md#textinput) — Single-line text field -- [TextArea](input-components.md#textarea) — Multi-line text field -- [PasswordInput](input-components.md#passwordinput) — Password field with visibility toggle -- [PinCodeInput](input-components.md#pincodeinput) — PIN code input (4 or 6 digits) +- [OudsTextInput](input-components.md#textinput) — Single-line text field +- [OudsTextArea](input-components.md#textarea) — Multi-line text field +- [OudsPasswordInput](input-components.md#passwordinput) — Password field with visibility toggle +- [OudsPinCodeInput](input-components.md#pincodeinput) — PIN code input (4 or 6 digits) ### Layout Components [→ See full documentation](layout-components.md) -- [BottomSheetScaffold](layout-components.md#bottomsheetscaffold) — Standard bottom sheet scaffold -- [ColoredBox](layout-components.md#coloredbox) — Colored surface container -- [Divider](layout-components.md#divider) — Horizontal and vertical dividers -- [ModalBottomSheet](layout-components.md#modalbottomsheet) — Modal bottom sheet +- [OudsBottomSheetScaffold](layout-components.md#bottomsheetscaffold) — Standard bottom sheet scaffold +- [OudsColoredBox](layout-components.md#coloredbox) — Colored surface container +- [OudsDivider](layout-components.md#divider) — Horizontal and vertical dividers +- [OudsModalBottomSheet](layout-components.md#modalbottomsheet) — Modal bottom sheet ### Navigation Components [→ See full documentation](navigation-components.md) -- [Link](navigation-components.md#link) — Text link with optional icon/chevron -- [NavigationBar](navigation-components.md#navigationbar) — Bottom navigation bar -- [TopAppBar](navigation-components.md#topappbar) — Top app bar with variants +- [OudsLink](navigation-components.md#link) — Text link with optional icon/chevron +- [OudsNavigationBar](navigation-components.md#navigationbar) — Bottom navigation bar +- [OudsTopAppBar](navigation-components.md#topappbar) — Top app bar with variants diff --git a/skills/using-ouds-android/references/content-components.md b/skills/using-ouds-android/references/content-components.md index b7b8e7109a..d06d444af8 100644 --- a/skills/using-ouds-android/references/content-components.md +++ b/skills/using-ouds-android/references/content-components.md @@ -7,7 +7,7 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ## Table of Contents -- [BulletList](#bulletlist) — Ordered, unordered, and bare lists +- [OudsBulletList](#bulletlist) — Ordered, unordered, and bare lists --- diff --git a/skills/using-ouds-android/references/control-components.md b/skills/using-ouds-android/references/control-components.md index 5bd6a7b6c4..8dbe1308c3 100644 --- a/skills/using-ouds-android/references/control-components.md +++ b/skills/using-ouds-android/references/control-components.md @@ -7,15 +7,15 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ## Table of Contents -- [Checkbox](#checkbox) — Standalone checkbox -- [CheckboxItem](#checkboxitem) — Checkbox with label and description -- [RadioButton](#radiobutton) — Standalone radio button -- [RadioButtonItem](#radiobuttonitem) — Radio button with label and description -- [Switch](#switch) — Standalone switch -- [SwitchItem](#switchitem) — Toggle switch with label and description +- [OudsCheckbox](#checkbox) — Standalone checkbox +- [OudsCheckboxItem](#checkboxitem) — Checkbox with label and description +- [OudsRadioButton](#radiobutton) — Standalone radio button +- [OudsRadioButtonItem](#radiobuttonitem) — Radio button with label and description +- [OudsSwitch](#switch) — Standalone switch +- [OudsSwitchItem](#switchitem) — Toggle switch with label and description - **Chip** - - [FilterChip](#filterchip) — Selectable filter chip - - [SuggestionChip](#suggestionchip) — Suggestion and action chip + - [OudsFilterChip](#filterchip) — Selectable filter chip + - [OudsSuggestionChip](#suggestionchip) — Suggestion and action chip --- @@ -154,7 +154,7 @@ OudsSwitchItem( ## Checkbox **Standalone checkbox** without label — use when checkbox is nested within another component with an alternative label. -**See also:** [CheckboxItem](#checkboxitem) for checkbox with label and description. +**See also:** [OudsCheckboxItem](#checkboxitem) for checkbox with label and description. ```kotlin var checked by remember { mutableStateOf(false) } @@ -191,7 +191,7 @@ OudsTriStateCheckbox( ## RadioButton **Standalone radio button** without label — use when radio button is nested within another component with an alternative label. -**See also:** [RadioButtonItem](#radiobuttonitem) for radio button with label and description. +**See also:** [OudsRadioButtonItem](#radiobuttonitem) for radio button with label and description. **Always** wrap a group of radio buttons in `Modifier.selectableGroup()`. ```kotlin @@ -220,7 +220,7 @@ OudsRadioButton( ## Switch **Standalone switch** without label — use when switch is nested within another component with an alternative label. -**See also:** [SwitchItem](#switchitem) for switch with label and description. +**See also:** [OudsSwitchItem](#switchitem) for switch with label and description. ```kotlin var checked by remember { mutableStateOf(true) } diff --git a/skills/using-ouds-android/references/indicator-components.md b/skills/using-ouds-android/references/indicator-components.md index 8e5ec31894..0acd72aff3 100644 --- a/skills/using-ouds-android/references/indicator-components.md +++ b/skills/using-ouds-android/references/indicator-components.md @@ -7,10 +7,10 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ## Table of Contents -- [Badge](#badge) — Count and status badges -- [CircularProgressIndicator](#circularprogressindicator) — Circular loading indicator -- [LinearProgressIndicator](#linearprogressindicator) — Linear loading indicator -- [Tag](#tag) — Status and category tags +- [OudsBadge](#badge) — Count and status badges +- [OudsCircularProgressIndicator](#circularprogressindicator) — Circular loading indicator +- [OudsLinearProgressIndicator](#linearprogressindicator) — Linear loading indicator +- [OudsTag](#tag) — Status and category tags --- diff --git a/skills/using-ouds-android/references/input-components.md b/skills/using-ouds-android/references/input-components.md index b6f596e0f8..6429319e6e 100644 --- a/skills/using-ouds-android/references/input-components.md +++ b/skills/using-ouds-android/references/input-components.md @@ -7,16 +7,16 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ## Table of Contents -- [TextInput](#textinput) — Single-line text field -- [TextArea](#textarea) — Multi-line text field -- [PasswordInput](#passwordinput) — Password field with visibility toggle -- [PinCodeInput](#pincodeinput) — PIN code input (4 or 6 digits) +- [OudsTextInput](#textinput) — Single-line text field +- [OudsTextArea](#textarea) — Multi-line text field +- [OudsPasswordInput](#passwordinput) — Password field with visibility toggle +- [OudsPinCodeInput](#pincodeinput) — PIN code input (4 or 6 digits) --- ## TextInput -Two API variants: **state-based** (`textFieldState`) and **value-based** (`value` + `onValueChange`). +Two API variants for OudsTextInput: **state-based** (`textFieldState`) and **value-based** (`value` + `onValueChange`). Prefer the state-based API for new code. ```kotlin @@ -77,7 +77,7 @@ OudsTextInput( ## TextArea -Same two API variants as `TextInput` (state-based / value-based). +Same two API variants as `OudsTextInput` (state-based / value-based). ```kotlin // State-based diff --git a/skills/using-ouds-android/references/layout-components.md b/skills/using-ouds-android/references/layout-components.md index a77bbef0c4..b70fb144da 100644 --- a/skills/using-ouds-android/references/layout-components.md +++ b/skills/using-ouds-android/references/layout-components.md @@ -7,10 +7,10 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ## Table of Contents -- [BottomSheetScaffold](#bottomsheetscaffold) — Standard bottom sheet scaffold -- [ColoredBox](#coloredbox) — Colored surface container -- [Divider](#divider) — Horizontal and vertical dividers -- [ModalBottomSheet](#modalbottomsheet) — Modal bottom sheet +- [OudsBottomSheetScaffold](#bottomsheetscaffold) — Standard bottom sheet scaffold +- [OudsColoredBox](#coloredbox) — Colored surface container +- [OudsDivider](#divider) — Horizontal and vertical dividers +- [OudsModalBottomSheet](#modalbottomsheet) — Modal bottom sheet --- @@ -69,7 +69,7 @@ OudsVerticalDivider(modifier = Modifier.height(50.dp)) ## BottomSheetScaffold **Standard bottom sheet** that co-exists with main screen content, allowing simultaneous interaction. -**See also:** [ModalBottomSheet](#modalbottomsheet) for modal behavior that blocks main content. +**See also:** [OudsModalBottomSheet](#modalbottomsheet) for modal behavior that blocks main content. ```kotlin @OptIn(ExperimentalMaterial3Api::class) @@ -117,7 +117,7 @@ OudsBottomSheetScaffold( ## ModalBottomSheet **Modal bottom sheet** that appears in front of app content and blocks interaction until dismissed. -**See also:** [BottomSheetScaffold](#bottomsheetscaffold) for non-modal variant. +**See also:** [OudsBottomSheetScaffold](#bottomsheetscaffold) for non-modal variant. ```kotlin @OptIn(ExperimentalMaterial3Api::class) diff --git a/skills/using-ouds-android/references/navigation-components.md b/skills/using-ouds-android/references/navigation-components.md index 267fea1150..b660dd7854 100644 --- a/skills/using-ouds-android/references/navigation-components.md +++ b/skills/using-ouds-android/references/navigation-components.md @@ -7,9 +7,9 @@ All user-visible strings must use `stringResource(R.string.*)` — never hardcod ## Table of Contents -- [Link](#link) — Text link with optional icon/chevron -- [NavigationBar](#navigationbar) — Bottom navigation bar -- [TopAppBar](#topappbar) — Top app bar with variants +- [OudsLink](#link) — Text link with optional icon/chevron +- [OudsNavigationBar](#navigationbar) — Bottom navigation bar +- [OudsTopAppBar](#topappbar) — Top app bar with variants --- From 6106572e6260651916351cd11546beb8d27ab6db Mon Sep 17 00:00:00 2001 From: Pauline Auvray Date: Fri, 31 Jul 2026 16:34:06 +0200 Subject: [PATCH 9/9] Apply corrections --- .../SKILL.md | 64 +++++++++---------- skills/using-ouds-android/SKILL.md | 6 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/skills/understanding-ouds-android-vocabulary/SKILL.md b/skills/understanding-ouds-android-vocabulary/SKILL.md index a5435f9131..38805fdabf 100644 --- a/skills/understanding-ouds-android-vocabulary/SKILL.md +++ b/skills/understanding-ouds-android-vocabulary/SKILL.md @@ -6,39 +6,39 @@ license: MIT # OUDS Android Vocabulary -| Term | Definition | -|---|---| -| **Tokenator** | Internal tool that converts Figma-exported JSON token specs into Kotlin source files and submits them via pull requests; generates files in `:global-raw-tokens` and `:theme-contract` | -| **token** | Named variable holding a design value (color, size, spacing, border…); most tokens are produced by Tokenator | -| **raw token** | Token whose value is a primitive Kotlin/Compose type (`Color`, `Dp`, `Int`…); grouped in the `:global-raw-tokens` module (e.g. `OudsColorRawTokens`, `OudsBorderRawTokens`) | -| **semantic token** | Token that references a raw token and carries semantic meaning (e.g. `actionColorTokens.enabled`); used directly inside components via `OudsTheme.*` | - | **component token** | Token scoped to a specific component, referencing semantic tokens for per-component styling overrides (e.g. `OudsButtonTokens`, `OudsTagTokens`); exposed to consumers via `@OptIn(RestrictedOudsApi::class) OudsTheme.components` | -| **OudsThemeContract** | Kotlin interface that every theme must implement; centralises all semantic token groups (`colorTokens`, `borderTokens`, `fontTokens`, `spaceTokens`, `componentsTokens`, etc.) and drawable resources | -| **theme** | Cohesive set of tokens and assets (fonts, drawables) controlling the look and feel of an app; available themes: `OrangeTheme`, `OrangeCompactTheme`, `SoshTheme`, `WireframeTheme` | -| **OudsTheme** | The Jetpack Compose entry-point composable that wraps your UI with a given theme; it also exposes static accessors (`OudsTheme.colorScheme`, `OudsTheme.spaces`, `OudsTheme.borders`, etc.) for reading token values inside composables | -| **component** | Jetpack Compose composable shipped by OUDS, always prefixed with `Ouds` (e.g. `OudsButton`, `OudsTag`, `OudsCheckboxItem`); token-driven, accessible, multi-brand | -| **OudsColoredBox** | Special OUDS container composable that creates a semantically colored surface; child OUDS components automatically switch to their monochrome variant to maximise contrast | -| **OudsButtonIcon** | Wrapper class used to pass an icon to `OudsButton` or `OudsSmallButton`; accepts `ImageVector`, `Painter`, or `ImageBitmap`, plus a `tinted` flag | -| **OudsControlItemIcon** | Wrapper class used to pass an optional icon to item-type controls (`OudsCheckboxItem`, `OudsRadioButtonItem`, `OudsSwitchItem`); accepts `ImageVector`, `Painter`, or `ImageBitmap`, plus a `tinted` flag | -| **OudsError** | Data class wrapping an error message (plain `String` or `AnnotatedString`) to display in input components (`OudsTextInput`, `OudsTextArea`, `OudsPasswordInput`, `OudsPinCodeInput`, `OudsCheckboxItem`, etc.) | -| **tinted** | Boolean flag on icon wrapper classes (`OudsButtonIcon`, `OudsControlItemIcon`, `OudsLinkIcon`, etc.) — when `true` (default) the icon color is driven by tokens; when `false` the painter's own colors are preserved (useful for brand/multi-color icons) | +| Term | Definition | +|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Tokenator** | Internal tool that converts Figma-exported JSON token specs into Kotlin source files and submits them via pull requests. | +| **token** | Named variable holding a design value (color, size, spacing, border…); most tokens are produced by Tokenator | +| **raw token** | Token whose value is a primitive Kotlin/Compose type (`Color`, `Dp`, `Int`…); grouped in the `:global-raw-tokens` module (e.g. `OudsColorRawTokens`, `OudsBorderRawTokens`) | +| **semantic token** | Token that references a raw token and carries semantic meaning (e.g. `colorScheme.action.enabled`); used directly inside components via `OudsTheme.*` | +| **component token** | Token scoped to a specific component, referencing semantic tokens for per-component styling overrides (e.g. `OudsButtonTokens`, `OudsTagTokens`); exposed to consumers via `@OptIn(RestrictedOudsApi::class) OudsTheme.components` | +| **OudsThemeContract** | Kotlin interface that every theme must implement; centralises all semantic token groups (`colorTokens`, `borderTokens`, `fontTokens`, `spaceTokens`, `componentsTokens`, etc.) and drawable resources | +| **theme** | Cohesive set of tokens and assets (fonts, drawables) controlling the look and feel of an app; available themes: `OrangeTheme`, `OrangeCompactTheme`, `SoshTheme`, `WireframeTheme` | +| **OudsTheme** | The Jetpack Compose entry-point composable that wraps your UI with a given theme; it also exposes static accessors (`OudsTheme.colorScheme`, `OudsTheme.spaces`, `OudsTheme.borders`, etc.) for reading token values inside composables | +| **component** | Jetpack Compose composable shipped by OUDS, always prefixed with `Ouds` (e.g. `OudsButton`, `OudsTag`, `OudsCheckboxItem`); token-driven, accessible, multi-brand | +| **OudsColoredBox** | Special OUDS container composable that creates a semantically colored surface; child OUDS components automatically switch to their monochrome variant to maximise contrast | +| **OudsButtonIcon** | Wrapper class used to pass an icon to `OudsButton` or `OudsSmallButton`; accepts `ImageVector`, `Painter`, or `ImageBitmap`, plus a `tinted` flag | +| **OudsControlItemIcon** | Wrapper class used to pass an optional icon to item-type controls (`OudsCheckboxItem`, `OudsRadioButtonItem`, `OudsSwitchItem`); accepts `ImageVector`, `Painter`, or `ImageBitmap`, plus a `tinted` flag | +| **OudsError** | Data class wrapping an error message (plain `String` or `AnnotatedString`) to display in input components (`OudsTextInput`, `OudsTextArea`, `OudsPasswordInput`, `OudsPinCodeInput`, `OudsCheckboxItem`, etc.) | +| **tinted** | Boolean flag on icon wrapper classes (`OudsButtonIcon`, `OudsControlItemIcon`, `OudsLinkIcon`, etc.) — when `true` (default) the icon color is driven by tokens; when `false` the painter's own colors are preserved (useful for brand/multi-color icons) | ## Token access inside composables Tokens are accessed via the `OudsTheme` static object inside any composable wrapped by `OudsTheme { }`: -| Accessor | Content | -|---|---| -| `OudsTheme.colorScheme` | Color semantic tokens (content, background, border, action, surface…) | -| `OudsTheme.borders` | Border radius, style and width tokens | -| `OudsTheme.spaces` | Spacing tokens (`fixed.*`, `scaled.*`) | -| `OudsTheme.sizes` | Size tokens | -| `OudsTheme.typography` | Typography / font tokens | -| `OudsTheme.elevations` | Elevation / shadow tokens | -| `OudsTheme.grids` | Grid tokens | -| `OudsTheme.opacities` | Opacity tokens | -| `OudsTheme.effects` | Visual effect tokens | -| `OudsTheme.components` | Component-level tokens for advanced customization (requires `@OptIn(RestrictedOudsApi::class)`) | +| Accessor | Content | +|-------------------------|-------------------------------------------------------------------------------------------------| +| `OudsTheme.colorScheme` | Color semantic tokens (content, background, border, action, surface…) | +| `OudsTheme.borders` | Border radius, style and width tokens | +| `OudsTheme.spaces` | Spacing tokens (`fixed.*`, `scaled.*`) | +| `OudsTheme.sizes` | Size tokens | +| `OudsTheme.typography` | Typography / font tokens | +| `OudsTheme.elevations` | Elevation / shadow tokens | +| `OudsTheme.grids` | Grid tokens | +| `OudsTheme.opacities` | Opacity tokens | +| `OudsTheme.effects` | Visual effect tokens | +| `OudsTheme.components` | Component-level tokens for advanced customization (requires `@OptIn(RestrictedOudsApi::class)`) | ## Token hierarchy @@ -59,7 +59,7 @@ Figma design tokens ## When to load which skill -| Task | Skill to load | -|---|---| -| Write or review Kotlin/Compose code using OUDS components or tokens | `using-ouds-android` | -| Ask about OUDS-specific terminology | `understanding-ouds-android-vocabulary` (this skill) | +| Task | Skill to load | +|---------------------------------------------------------------------|------------------------------------------------------| +| Write or review Kotlin/Compose code using OUDS components or tokens | `using-ouds-android` | +| Ask about OUDS-specific terminology | `understanding-ouds-android-vocabulary` (this skill) | diff --git a/skills/using-ouds-android/SKILL.md b/skills/using-ouds-android/SKILL.md index db0558710a..d0a733cb29 100644 --- a/skills/using-ouds-android/SKILL.md +++ b/skills/using-ouds-android/SKILL.md @@ -66,7 +66,7 @@ fun App() { ### OrangeTheme — font options -**Bundled font** (copy `.ttf` files to `res/font/`): +**Bundled font (recommended)** (copy `.ttf` files to `res/font/`): ```kotlin OrangeTheme( @@ -150,8 +150,8 @@ fun MyView() { ## 4. OudsColoredBox — colored surfaces -`OudsColoredBox` creates a semantically colored surface. All OUDS child components inside automatically switch to their **monochrome** variant for maximum -contrast: +`OudsColoredBox` creates a semantically colored surface. Some OUDS child components inside automatically switch to their **monochrome** variant for maximum +contrast (such as `OudsButton` or `OudsLink`): ```kotlin OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) {