Skip to content

Commit 18c0359

Browse files
committed
Merge branch 'main' of https://github.com/microsoft/fluentui-react-native into user/jasonvmo/style-cache
2 parents 95da1bc + 4727334 commit 18c0359

181 files changed

Lines changed: 12234 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/pages/Theming/Tokens/Basics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export const defaultNotificationTokens: TokenSettings<NotificationTokens, Theme>
7474

7575
Notes about alias color tokens:
7676

77-
- 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.
77+
- 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.
7878
- 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.
7979

8080
Special case: if accessing a specific color, you can find it in the `globalTokens.color` property.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
name: accordion
3+
platform: react-native (Windows, macOS)
4+
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.
5+
argument-hint: "[variant axis or behavior question, e.g. 'chevron end layout' or 'focus ring tokens']"
6+
tokens: tokens.yaml
7+
accessibility: accessibility.md
8+
interaction: interaction.md
9+
usage: usage.md
10+
---
11+
12+
## Metadata
13+
14+
| Field | Value |
15+
| --------- | --------- |
16+
| Type | atomic |
17+
| Component | Accordion |
18+
19+
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.
20+
21+
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.
22+
23+
---
24+
25+
# Accordion
26+
27+
## Spec
28+
29+
### Anatomy
30+
31+
1. **Container** — root auto-layout wrapper; owns the full component width.
32+
2. **Header** — interactive row; owns padding, gap, border radius, and the focus ring. The only interactive surface on the component.
33+
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.
34+
4. **Leading icon** — optional 16px Fluent Iconography instance before the title. Shown by default.
35+
5. **Title** — section label text; always Semibold (`body-small-strong`). Fills remaining header width in Chevron start layout; natural width in Chevron end layout.
36+
6. **Body** — content panel visible only when Expanded=True. Accepts any child component via the `Body content` slot.
37+
7. **Content placeholder** — default body content shown when no child is provided. Swap with your component.
38+
39+
| Slot | Required | Default |
40+
| ------------ | -------- | ------------------- |
41+
| Title | Yes | "Section title" |
42+
| Leading icon | No | Shown |
43+
| Body content | No | Content placeholder |
44+
45+
---
46+
47+
### Variants
48+
49+
Variant properties are ordered in the design tool: **Layout → Size → State → Expanded**.
50+
51+
#### Layout
52+
53+
| Value | When to Use |
54+
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
55+
| **Chevron start** | Default. Anchors the expand affordance to the leading edge; title fills remaining width. |
56+
| **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. |
57+
58+
#### Expanded
59+
60+
| Value | Visual |
61+
| --------- | ------------------------------------------------ |
62+
| **False** | Body hidden; chevron points right (ChevronRight) |
63+
| **True** | Body visible; chevron points down (ChevronDown) |
64+
65+
**Expanded is a variant axis, not a State.** It runs in parallel with State — a Rest+Expanded=True accordion is valid.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
component: Accordion
3+
platform: react-native (Windows, macOS)
4+
---
5+
6+
# Accordion Accessibility (React Native — Windows & macOS)
7+
8+
## Spec
9+
10+
- **ARIA role:** The Header should render as a `<button>` (or `role="button"`).
11+
- **Required attributes:**
12+
- `aria-expanded="true|false"` — on the Header button; reflects the Expanded variant state.
13+
- `aria-controls="{bodyId}"` — points to the Body panel element.
14+
- `id` on the Body panel — referenced by `aria-controls`.
15+
- `aria-label` or visible title text — the Header must have an accessible name.
16+
- **WCAG:**
17+
- **4.1.2 — Name, Role, Value:** The expanded/collapsed state must be programmatically determinable via `aria-expanded`.
18+
- **1.4.3 — Contrast (Minimum):** Title and icon foreground must meet 4.5:1 at rest and hover.
19+
- **2.1.1 — Keyboard:** Enter and Space must toggle the expanded state.
20+
- **2.4.7 — Focus Visible:** Focus ring must be visible on the Header.
21+
- **2.3.3 — Animation from Interactions:** Chevron rotation and body expand animation must be suppressed under reduce-motion.
22+
- **Screen reader:** On activation, should announce the new `aria-expanded` state ("expanded" or "collapsed").
23+
24+
---
25+
26+
## Usage
27+
28+
- **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.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
component: Accordion
3+
platform: react-native (Windows, macOS)
4+
---
5+
6+
# Accordion Interaction (React Native — Windows & macOS)
7+
8+
## Keyboard navigation
9+
10+
- **Tab / Shift+Tab** — moves focus to and from the Header.
11+
- **Enter / Space** — toggles the Expanded state.
12+
- No arrow key navigation within a single accordion item. Arrow navigation between items in a group is the responsibility of the parent container.
13+
14+
## Focus management
15+
16+
Focus is scoped to the Header only. Body content manages its own focus independently.
17+
18+
## Open / close
19+
20+
Single vs. multi-expand behavior (whether multiple items can be open simultaneously) is managed at the accordion group level, not by this component.
21+
22+
## Animation
23+
24+
The chevron rotates between Expanded states (right → down). The body panel height transition references motion tokens once defined.
25+
26+
> **Reduced motion:** When the OS reduce-motion setting is set, both the chevron rotation and body height transition should be instant.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
component: Accordion
2+
type: atomic
3+
4+
variants:
5+
Layout:
6+
values: [Chevron start, Chevron end]
7+
Size:
8+
values: [Small]
9+
notes: Only size currently defined.
10+
State:
11+
values: [Rest, Hover, Pressed]
12+
notes: Hover and Pressed are resolved as nested token state values. Disabled not present in current component set.
13+
Expanded:
14+
values: [false, true]
15+
default: false
16+
notes: Parallel axis — runs independently of State. Not a State value.
17+
18+
tokens:
19+
background:
20+
header:
21+
rest:
22+
value: colorBackgroundNeutralTransparent
23+
hover: hover.colorBackgroundNeutralTransparent
24+
pressed: pressed.colorBackgroundNeutralTransparent
25+
header-notes: Transparent at rest; gains visible fill through the inline hover/pressed state values.
26+
27+
foreground:
28+
rest:
29+
value: colorForegroundNeutralPrimary
30+
hover: hover.colorForegroundNeutralPrimary
31+
pressed: pressed.colorForegroundNeutralPrimary
32+
applies-to: Title, chevron, and leading icon.
33+
34+
stroke:
35+
container: no-stroke
36+
focus: See flex-system:styling — universal dual-outline focus ring.
37+
38+
radius:
39+
header: borderRadiusBase200
40+
41+
typography:
42+
title: textstyle-functional-body-small-strong
43+
notes: Title is always Semibold — no weight swap pattern. Consistent weight provides persistent visual hierarchy regardless of state.
44+
font-family: fontFamilyFunctional
45+
46+
spacing:
47+
header:
48+
horizontal: spacingComponentBase200
49+
vertical: spacingComponentBase100
50+
header-gap: spacingComponentBase100
51+
body: spacingComponentBase200
52+
53+
elevation: n/a
54+
55+
motion:
56+
status: pending
57+
guidance: Chevron rotation and body height transition should use fast duration with ease-in-out. Reduced motion — instant, no animation.
58+
sizes:
59+
Small:
60+
chevron-icon: 16px
61+
leading-icon: 16px
62+
63+
properties:
64+
component:
65+
Title string:
66+
type: TEXT
67+
default: 'Section title'
68+
notes: Bound to the title text node in the Header.
69+
Icon:
70+
type: BOOLEAN
71+
default: true
72+
notes: Shows/hides the leading icon slot.
73+
Icon (swap):
74+
type: INSTANCE_SWAP
75+
default: Image icon (16px Regular)
76+
notes: Leading icon slot.
77+
Body content:
78+
type: INSTANCE_SWAP
79+
default: Content placeholder
80+
notes: The body slot; swap with any component.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
component: Accordion
3+
---
4+
5+
# Accordion Usage
6+
7+
## When to Use
8+
9+
- To progressively disclose content in sections — FAQs, settings categories, reference details.
10+
- When a surface has multiple content sections and screen space is limited.
11+
- When most users will only need a subset of the available sections.
12+
13+
### When NOT to Use
14+
15+
- Never place content that is required to complete the current task inside an accordion.
16+
- Do not use as a navigation pattern; use a nav component or tree instead.
17+
- If only one section exists, use a plain content block — the expand/collapse affordance implies multiplicity.
18+
19+
---
20+
21+
## Behavior
22+
23+
- **Never place required content inside an accordion.** If completing the current task depends on the content, it must be visible by default.
24+
- **Never use the Expanded axis to simulate a Selected state.** Expanded communicates content visibility, not persistent selection.
25+
- **Never hardcode body content dimensions.** The Body panel must grow to fit its child component.
26+
27+
---
28+
29+
## Content
30+
31+
- **Always provide a meaningful title.** Generic labels like "More" or "Details" are insufficient for users to decide whether to expand.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
name: avatar
3+
platform: react-native (Windows, macOS)
4+
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.
5+
argument-hint: "[display mode or token question, e.g. 'icon avatar background token' or 'initials accessibility']"
6+
tokens: tokens.yaml
7+
accessibility: accessibility.md
8+
interaction: interaction.md
9+
usage: usage.md
10+
---
11+
12+
## Metadata
13+
14+
| Field | Value |
15+
| --------- | ------ |
16+
| Type | atomic |
17+
| Component | Avatar |
18+
19+
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.
20+
21+
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.
22+
23+
---
24+
25+
# Avatar
26+
27+
## Spec
28+
29+
### Anatomy
30+
31+
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.
32+
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.
33+
3. **Icon slot** — centered Fluent Iconography instance representing the entity type. Active only in the Icon display mode.
34+
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.
35+
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`).
36+
37+
| Slot | Required | Default |
38+
| ------------- | --------------------------------- | ----------- |
39+
| Image | No — active in Image mode only ||
40+
| Icon | No — active in Icon mode only | Person icon |
41+
| Initials | No — active in Initials mode only | "AB" |
42+
| Activity ring | No | Hidden |
43+
44+
---
45+
46+
### Variants
47+
48+
Variant properties are ordered in the design tool: **Content → Size → State**.
49+
50+
#### Content
51+
52+
| Value | Description | When to Use |
53+
| ------------ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
54+
| **Image** | Photo or entity image fills the container | When a real user photo or entity brand image is available |
55+
| **Icon** | Fluent Iconography icon centered in a filled container | When no photo is available and entity type can be represented by an icon |
56+
| **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 |
57+
58+
**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.
59+
60+
---
61+
62+
#### Size
63+
64+
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.
65+
66+
| Value | Diameter | When to Use |
67+
| ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
68+
| **16** | 16px | Dense surfaces: inline mentions, compact participant lists, chat bubbles. Initials are constrained to a single character at this size. |
69+
| **20** | 20px | Dense rows where 16 reads too small but 28 reads too heavy: compact toolbars, tight list cells, status strips. |
70+
| **24** | 24px | Dense rows where 20 reads too small but 28 reads too heavy: compact toolbars, tight list cells, status strips. |
71+
| **28** | 28px | Compact list rows and inline person chips that need slightly more identity weight than 16 |
72+
| **32** | 32px | Tight rows where text and avatar share a single line: input chips, condensed participant rosters |
73+
| **40** | 40px | Default. Comment threads, assignment fields, profile headers |
74+
| **56** | 56px | High-emphasis identity moments: profile cards, people pickers, detail views |
75+
| **120** | 120px | Hero moments: large profile views, about pages, onboarding flows |
76+
77+
**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.
78+
79+
---
80+
81+
#### State
82+
83+
| Value | Description |
84+
| -------- | --------------- |
85+
| **Rest** | Default display |
86+
87+
Avatar is non-interactive — no Hover, Pressed, Focus, or Disabled states apply.

0 commit comments

Comments
 (0)