Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/pages/Theming/Tokens/Basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const defaultNotificationTokens: TokenSettings<NotificationTokens, Theme>

Notes about alias color tokens:

- Different platforms can have different sets of alias tokens; however, the entire set of alias tokens are all defined in the same interface. See (Color.types.ts)[https://github.com/microsoft/fluentui-react-native/blob/main/packages/theming/theme-types/src/Color.types.ts#L453] for this interface and which platforms define which alias tokens.
- Different platforms can have different sets of alias tokens; however, the entire set of alias tokens are all defined in the same interface. See [Color.types.ts](https://github.com/microsoft/fluentui-react-native/blob/main/packages/agentic-design/src/theming/Color.types.ts#L861) for this interface and which platforms define which alias tokens.
- As a result, if an alias token is referenced that does not exist for that platform, there won't be any compile-time or run-time errors. Instead, the color shown will default to black.

Special case: if accessing a specific color, you can find it in the `globalTokens.color` property.
Expand Down
65 changes: 65 additions & 0 deletions packages/agentic-components/specs/accordion/SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
name: accordion
platform: react-native (Windows, macOS)
description: Atomic collapsible panel with an interactive header and a free body content slot. Covers chevron layout (start/end), expand/collapse state, optional leading icon, focus ring behavior, and body content slot conventions.
argument-hint: "[variant axis or behavior question, e.g. 'chevron end layout' or 'focus ring tokens']"
tokens: tokens.yaml
accessibility: accessibility.md
interaction: interaction.md
usage: usage.md
---

## Metadata

| Field | Value |
| --------- | --------- |
| Type | atomic |
| Component | Accordion |

This spec covers the Accordion component for React Native (Windows & macOS). React Native tokens are in `tokens.yaml`, React Native interaction guidance (keyboard, focus, animation) is in `interaction.md`, React Native accessibility guidance (ARIA, WCAG, screen reader) is in `accessibility.md`, and shared usage guidance is in `usage.md` — read the relevant companion file before answering.

Answer design questions directly — lead with rationale, then tokens. The most important principle: the body slot is a free content area — never put information required for the current task inside an accordion. The Expanded axis is a variant property (not a State), and Focused is a boolean component prop — do not conflate these with the State axis.

---

# Accordion

## Spec

### Anatomy

1. **Container** — root auto-layout wrapper; owns the full component width.
2. **Header** — interactive row; owns padding, gap, border radius, and the focus ring. The only interactive surface on the component.
3. **Chevron** — 16px Fluent Iconography instance. ChevronRight at rest (Expanded=False), rotates to ChevronDown when Expanded=True. Position determined by Layout variant: at the leading edge in Chevron start, pushed to the far trailing edge in Chevron end.
4. **Leading icon** — optional 16px Fluent Iconography instance before the title. Shown by default.
5. **Title** — section label text; always Semibold (`body-small-strong`). Fills remaining header width in Chevron start layout; natural width in Chevron end layout.
6. **Body** — content panel visible only when Expanded=True. Accepts any child component via the `Body content` slot.
7. **Content placeholder** — default body content shown when no child is provided. Swap with your component.

| Slot | Required | Default |
| ------------ | -------- | ------------------- |
| Title | Yes | "Section title" |
| Leading icon | No | Shown |
| Body content | No | Content placeholder |

---

### Variants

Variant properties are ordered in the design tool: **Layout → Size → State → Expanded**.

#### Layout

| Value | When to Use |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Chevron start** | Default. Anchors the expand affordance to the leading edge; title fills remaining width. |
| **Chevron end** | When the leading icon is the primary anchor; chevron is pushed to the far end of the header (opposite edge from the title). Title at natural width. |

#### Expanded

| Value | Visual |
| --------- | ------------------------------------------------ |
| **False** | Body hidden; chevron points right (ChevronRight) |
| **True** | Body visible; chevron points down (ChevronDown) |

**Expanded is a variant axis, not a State.** It runs in parallel with State — a Rest+Expanded=True accordion is valid.
28 changes: 28 additions & 0 deletions packages/agentic-components/specs/accordion/accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
component: Accordion
platform: react-native (Windows, macOS)
---

# Accordion Accessibility (React Native — Windows & macOS)

## Spec

- **ARIA role:** The Header should render as a `<button>` (or `role="button"`).
- **Required attributes:**
- `aria-expanded="true|false"` — on the Header button; reflects the Expanded variant state.
- `aria-controls="{bodyId}"` — points to the Body panel element.
- `id` on the Body panel — referenced by `aria-controls`.
- `aria-label` or visible title text — the Header must have an accessible name.
- **WCAG:**
- **4.1.2 — Name, Role, Value:** The expanded/collapsed state must be programmatically determinable via `aria-expanded`.
- **1.4.3 — Contrast (Minimum):** Title and icon foreground must meet 4.5:1 at rest and hover.
- **2.1.1 — Keyboard:** Enter and Space must toggle the expanded state.
- **2.4.7 — Focus Visible:** Focus ring must be visible on the Header.
- **2.3.3 — Animation from Interactions:** Chevron rotation and body expand animation must be suppressed under reduce-motion.
- **Screen reader:** On activation, should announce the new `aria-expanded` state ("expanded" or "collapsed").

---

## Usage

- **Required ARIA attributes for state:** Set `aria-expanded` and `aria-controls` on the Header button. Without them, keyboard and screen reader users cannot determine the expanded state.
26 changes: 26 additions & 0 deletions packages/agentic-components/specs/accordion/interaction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
component: Accordion
platform: react-native (Windows, macOS)
---

# Accordion Interaction (React Native — Windows & macOS)

## Keyboard navigation

- **Tab / Shift+Tab** — moves focus to and from the Header.
- **Enter / Space** — toggles the Expanded state.
- No arrow key navigation within a single accordion item. Arrow navigation between items in a group is the responsibility of the parent container.

## Focus management

Focus is scoped to the Header only. Body content manages its own focus independently.

## Open / close

Single vs. multi-expand behavior (whether multiple items can be open simultaneously) is managed at the accordion group level, not by this component.

## Animation

The chevron rotates between Expanded states (right → down). The body panel height transition references motion tokens once defined.

> **Reduced motion:** When the OS reduce-motion setting is set, both the chevron rotation and body height transition should be instant.
80 changes: 80 additions & 0 deletions packages/agentic-components/specs/accordion/tokens.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
component: Accordion
type: atomic

variants:
Layout:
values: [Chevron start, Chevron end]
Size:
values: [Small]
notes: Only size currently defined.
State:
values: [Rest, Hover, Pressed]
notes: Hover and Pressed are resolved as nested token state values. Disabled not present in current component set.
Expanded:
values: [false, true]
default: false
notes: Parallel axis — runs independently of State. Not a State value.

tokens:
background:
header:
rest:
value: colorBackgroundNeutralTransparent
hover: hover.colorBackgroundNeutralTransparent
pressed: pressed.colorBackgroundNeutralTransparent
header-notes: Transparent at rest; gains visible fill through the inline hover/pressed state values.

foreground:
rest:
value: colorForegroundNeutralPrimary
hover: hover.colorForegroundNeutralPrimary
pressed: pressed.colorForegroundNeutralPrimary
applies-to: Title, chevron, and leading icon.

stroke:
container: no-stroke
focus: See flex-system:styling — universal dual-outline focus ring.

radius:
header: borderRadiusBase200

typography:
title: textstyle-functional-body-small-strong
notes: Title is always Semibold — no weight swap pattern. Consistent weight provides persistent visual hierarchy regardless of state.
font-family: fontFamilyFunctional

spacing:
header:
horizontal: spacingComponentBase200
vertical: spacingComponentBase100
header-gap: spacingComponentBase100
body: spacingComponentBase200

elevation: n/a

motion:
status: pending
guidance: Chevron rotation and body height transition should use fast duration with ease-in-out. Reduced motion — instant, no animation.
sizes:
Small:
chevron-icon: 16px
leading-icon: 16px

properties:
component:
Title string:
type: TEXT
default: 'Section title'
notes: Bound to the title text node in the Header.
Icon:
type: BOOLEAN
default: true
notes: Shows/hides the leading icon slot.
Icon (swap):
type: INSTANCE_SWAP
default: Image icon (16px Regular)
notes: Leading icon slot.
Body content:
type: INSTANCE_SWAP
default: Content placeholder
notes: The body slot; swap with any component.
31 changes: 31 additions & 0 deletions packages/agentic-components/specs/accordion/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
component: Accordion
---

# Accordion Usage

## When to Use

- To progressively disclose content in sections — FAQs, settings categories, reference details.
- When a surface has multiple content sections and screen space is limited.
- When most users will only need a subset of the available sections.

### When NOT to Use

- Never place content that is required to complete the current task inside an accordion.
- Do not use as a navigation pattern; use a nav component or tree instead.
- If only one section exists, use a plain content block — the expand/collapse affordance implies multiplicity.

---

## Behavior

- **Never place required content inside an accordion.** If completing the current task depends on the content, it must be visible by default.
- **Never use the Expanded axis to simulate a Selected state.** Expanded communicates content visibility, not persistent selection.
- **Never hardcode body content dimensions.** The Body panel must grow to fit its child component.

---

## Content

- **Always provide a meaningful title.** Generic labels like "More" or "Details" are insufficient for users to decide whether to expand.
87 changes: 87 additions & 0 deletions packages/agentic-components/specs/avatar/SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
name: avatar
platform: react-native (Windows, macOS)
description: Atomic identity element representing a person, group, or entity. Covers three mutually exclusive display modes (Image, Icon, Initials), eight numeric sizes (16 / 20 / 24 / 28 / 32 / 40 / 56 / 120 px diameter), and non-interactive state handling.
argument-hint: "[display mode or token question, e.g. 'icon avatar background token' or 'initials accessibility']"
tokens: tokens.yaml
accessibility: accessibility.md
interaction: interaction.md
usage: usage.md
---

## Metadata

| Field | Value |
| --------- | ------ |
| Type | atomic |
| Component | Avatar |

This spec covers the Avatar component for React Native (Windows & macOS). React Native tokens are in `tokens.yaml`, React Native interaction guidance (keyboard, focus, animation) is in `interaction.md`, React Native accessibility guidance (ARIA, WCAG, screen reader) is in `accessibility.md`, and shared usage guidance is in `usage.md` — read the relevant companion file before answering.

Answer design questions directly — lead with rationale, then tokens. Image, Icon, and Initials are mutually exclusive display modes — never show more than one simultaneously. Avatar is non-interactive; the component carries no focus ring, hover, or pressed states.

---

# Avatar

## Spec

### Anatomy

1. **Container** — circular frame; owns the fixed diameter per size, border radius, and background fill. Avatar has no container stroke — the fill defines the circle across all three content modes.
2. **Image slot** — a user photo or entity image that covers the **entire** container edge-to-edge (full-bleed). The image spans the full diameter and is clipped to the circular radius — the per-size padding (see `tokens.yaml` `spacing`) applies to the Icon and Initials slots only, **never** to Image; an image inset by padding would render as a square that never reaches the circular clip. Active only in the Image display mode.
3. **Icon slot** — centered Fluent Iconography instance representing the entity type. Active only in the Icon display mode.
4. **Initials slot** — centered text node showing 1–2 characters (1 character at size 16). Active only in the Initials display mode. Uses `line-height: 1` override at all sizes for optical centering — see `tokens.yaml` (`typography.initials-line-height-override`) for rationale.
5. **Activity ring** — a brand outline offset from the avatar container, indicating the person is active or collaborating in a shared space. The offset creates a true transparent gap that reveals the surface beneath. Both offset and stroke width scale with avatar size so the ring stays proportional at every diameter. Controlled by a boolean property. Does not affect layout dimensions (rendered as `outline` + `outline-offset`).

| Slot | Required | Default |
| ------------- | --------------------------------- | ----------- |
| Image | No — active in Image mode only | — |
| Icon | No — active in Icon mode only | Person icon |
| Initials | No — active in Initials mode only | "AB" |
| Activity ring | No | Hidden |

---

### Variants

Variant properties are ordered in the design tool: **Content → Size → State**.

#### Content

| Value | Description | When to Use |
| ------------ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| **Image** | Photo or entity image fills the container | When a real user photo or entity brand image is available |
| **Icon** | Fluent Iconography icon centered in a filled container | When no photo is available and entity type can be represented by an icon |
| **Initials** | 1–2 character text centered in a filled container (1 character at size 16) | When no photo is available and entity type is best represented by initials |

**Why three modes share the same component:** Image, Icon, and Initials all resolve to the same circular container with identical sizing, padding, and accessibility surface — they differ only in which inner slot is rendered. A Content variant keeps the three fallback paths consistent so callers can swap between them based on data availability without reflowing layout.

---

#### Size

Size is a numeric scale — the variant value is the container's pixel diameter. Eight sizes are valid: **16, 20, 24, 28, 32, 40, 56, 120**. The numeric scale lets the component grow new stops without naming churn while still capturing the full set of valid sizes the design system supports.

| Value | Diameter | When to Use |
| ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **16** | 16px | Dense surfaces: inline mentions, compact participant lists, chat bubbles. Initials are constrained to a single character at this size. |
| **20** | 20px | Dense rows where 16 reads too small but 28 reads too heavy: compact toolbars, tight list cells, status strips. |
| **24** | 24px | Dense rows where 20 reads too small but 28 reads too heavy: compact toolbars, tight list cells, status strips. |
| **28** | 28px | Compact list rows and inline person chips that need slightly more identity weight than 16 |
| **32** | 32px | Tight rows where text and avatar share a single line: input chips, condensed participant rosters |
| **40** | 40px | Default. Comment threads, assignment fields, profile headers |
| **56** | 56px | High-emphasis identity moments: profile cards, people pickers, detail views |
| **120** | 120px | Hero moments: large profile views, about pages, onboarding flows |

**Why sizes share the same content treatment:** Size changes only the container diameter, icon size, and typography scale — not semantic meaning. **Why a numeric scale rather than named buckets:** Once a system carries more than ~4 sizes, names like Small / Medium / Large / XL run out fast. A pixel-named scale keeps the contract honest while still constraining consumers to the documented set.

---

#### State

| Value | Description |
| -------- | --------------- |
| **Rest** | Default display |

Avatar is non-interactive — no Hover, Pressed, Focus, or Disabled states apply.
Loading
Loading