Skip to content

Add nine agentic components and shared policies - #4308

Open
Jason Morse (JasonVMo) wants to merge 23 commits into
mainfrom
user/jasonvmo/components-next
Open

Add nine agentic components and shared policies#4308
Jason Morse (JasonVMo) wants to merge 23 commits into
mainfrom
user/jasonvmo/components-next

Conversation

@JasonVMo

Copy link
Copy Markdown
Contributor

Platforms Impacted

  • iOS
  • macOS
  • win32 (Office)
  • windows
  • android

Description of changes

Adds the nine X3/Flex components that are ready now that Callout and FocusZone are available:

  • AvatarGroup
  • DestructiveButton
  • InteractionTag
  • Label
  • Link
  • NavItem
  • Popover
  • SearchBox
  • Tooltip

Each component includes its reviewed React Native contract, source provenance, token styling, runtime and type coverage, Storybook stories, and package exports.

This also:

  • keeps native Popover and Tooltip surfaces readable with bounded widths;
  • keeps Input and SearchBox text vertically centered after clearing a focused value;
  • shares accessible-name detection, disabled focusability, native focus-ring suppression, development warnings, and numeric style narrowing;
  • migrates component semantics, public types, tests, contracts, stories, and authoring guidance from accessibilityRole to React Native's ARIA-aligned role prop.

Closes #4218
Closes #4221
Closes #4227
Closes #4228
Closes #4229
Closes #4234
Closes #4236
Closes #4239
Closes #4249

Verification

  • yarn workspace @fluentui-react-native/framework-base format
  • yarn workspace @fluentui-react-native/framework-base lint
  • yarn workspace @fluentui-react-native/framework-base test (137 tests)
  • yarn workspace @fluentui-react-native/design format
  • yarn workspace @fluentui-react-native/design lint
  • yarn workspace @fluentui-react-native/design test (263 tests)
  • yarn workspace @fluentui-react-native/components format
  • yarn workspace @fluentui-react-native/components lint
  • yarn workspace @fluentui-react-native/components test (72 test files)
  • yarn change:check
  • yarn build
  • macOS and Windows Storybook bundles
Before After
The nine tracked components were unavailable in the agentic package. Native callout-backed text could collapse into a narrow column, and clearing a focused SearchBox could shift text vertically. The components are exported with reviewed contracts and stories. Floating surfaces keep readable bounds, SearchBox alignment remains stable, and shared interaction/accessibility policies are consistently applied.

Pull request checklist

This PR has considered (when applicable):

  • Automated Tests
  • Documentation and examples
  • Keyboard Accessibility
  • Voiceover
  • Internationalization and Right-to-left Layouts

Jason Morse (JasonVMo) and others added 23 commits September 2, 2026 16:58
AvatarGroup lays a small set of Avatar children out as one cohort and
optionally appends a trailing `+N` indicator for the members it does not
show. It supports the spread and stack layouts and the eight Avatar
sizes, and it resolves the spread gap, stack overlap, separation ring,
item box, and indicator scale from its own declared size.

React Native has no sibling-relative sizing and no mask compositing, so
the contract records five accepted divergences: size is declared on the
group for geometry only, the stack separation ring is a filled circular
box rather than a mask, the indicator is its own view and text rather
than an Avatar, the five-item maximum is advisory, and a labelled group
uses the image role because React Native has no group role.

Adds the reviewed contract and companions, the implementation, public
exports, runtime and type tests, Storybook stories with a static desktop
driver plan, and a changeset.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add DestructiveButton as a distinct component for irreversible and
high-consequence actions rather than widening Button with a danger
appearance. Keeping it separate lets the destructive surface drop the
axes that do not apply to it: there is no selection model, no square
shape, and no neutral emphasis level, so a destructive action can never
be authored as a toggle or mistaken for a neutral square Button.

The contract was authored and explicitly reviewed against the pinned
Flex source (flex-1.5.0-206c4996) before any code, and records three
divergences: the icon-only default shape, the mobile-only Secondary
style, and FURN's single icon slot with iconPosition. Only icon sizing
is reused from Button, since the source states it inherits; structural
padding and radius are restated locally because Button's style factory
is keyed by a square shape and a selection-bearing state shape that
DestructiveButton does not have.

The default token set maps no distinct hover or pressed value onto the
loud danger background, so the primary appearance currently shows no
background change on interaction. That gap is recorded in
spec/tokens.yaml and spec/interaction.md rather than papered over.

Resolves #4221

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the InteractionTag component under packages/agentic/components with a
reviewed, implemented contract for #4227.

The component renders two independently pressable regions inside one
non-interactive container: a primary action that names the tag and a
dismiss action that removes it. Each region is its own button, its own tab
stop, and its own focus visual, so nothing bubbles between them. Leading
content is typed as an exclusive icon-or-avatar union, the divider is a
private state slot, and dismissal stays caller owned.

Includes the contract and companions with generated Flex provenance,
runtime tests, compile-time type tests, stories with a static desktop
driver plan, explicit package exports, and a changeset.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Label names an associated form control. It builds on the agentic Text
component, offers regular and strong weights across three sizes, renders an
optional decorative required indicator, and applies a disabled foreground
that mirrors the control it names.

Browser label activation forwarding has no React Native equivalent, so
association is programmatic: a caller gives the label a nativeID and points
the control at it with accessibilityLabelledBy. The root owns the accessible
name so the label reports one text element on Windows UI Automation and macOS
AX; the name is read from string content unless the caller supplies an
explicit accessibilityLabel.

The contract was authored from pinned Flex evidence and reviewed before
implementation. Both divergences from the source are recorded as
not-applicable in SPEC.md and spec/source.json.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add Link to @fluentui-react-native/components for #4229,
contract first. SPEC.md and the spec/ companions were authored and reviewed
before any code, and spec/source.json records the two sources that govern the
requirements LNK-001 through LNK-012.

The root is a native Text so the component participates in a surrounding text
run and keeps React 19 ref-as-prop without forwardRef. The content slot is also
a native Text rather than the agentic Text, which is what lets an inline link
inherit the typography around it instead of imposing its own.

Navigation is adapted to React Native Linking. onPress runs first on every
activation and a supplied url is then opened, deliberately diverging from the
V1 FURN Link where url supersedes onPress. When onNavigationError is supplied
the rejection is routed to it; when it is not, no catch is attached at all, so
the rejection is left untouched rather than silently absorbed.

Nine divergences from the Flex source are recorded rather than faked. The most
consequential are that CSS underline geometry and the dotted content underline
have no React Native equivalent on Windows or macOS, that there is no hover
state because core TextProps has no hover events, and that the focus visual is
a single border on the root Text because FocusVisual composes Views that cannot
nest inside a text run.

Provenance caveat: report:spec-source-drift could not reach the origin
repositories from this environment, so the origin digests in spec/source.json
mirror the locally verified Marketplace digests and the report entry records
candidateStatus "unchecked". Re-run --update-sources with credentials to
confirm the origin lineage. This is also disclosed at the bottom of SPEC.md.

Validated with package format, lint, build, check:spec-contracts, the package
test suite (54 suites, 299 tests), and the root unified build.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add NavItem, a single pressable navigation row shared by a future Nav and
Simple Nav. The contract is authored locally from the pinned Flex nav-item
skill and reviewed before implementation.

- Comfortable and compact density, top-level and sub-item nesting
- Externally driven selection and category disclosure so a parent
  navigation can own which destination is current and which category is open
- Item rows publish link semantics with selected state; category rows
  publish button semantics with expanded state and an optional controls id
- Collapsed icon rail mode that requires an accessible name
- Persistent selected indicator and focus visual so state never reflows
- Trailing string content and always-visible trailing actions

Fixes #4234

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Popover pairs a trigger with an anchored floating surface built on the native
@fluentui-react-native/callout component. It owns controlled and uncontrolled
open state, trigger accessibility and interaction, the anchor relationship,
tokenized surface styling, and the mount lifetime of the surface content.

The contract is authored from pinned Flex evidence plus the pinned Callout
native sources, and it records the verified per-platform limits rather than
assuming parity: macOS collapses every directional hint onto four screen edges,
initial focus differs on each platform, focus return and anchor gap are not
implemented anywhere, and viewport containment is native best effort. Eleven
divergences capture those gaps explicitly.

The visible surface boundary is drawn on the React Native content host inside
the popup, which is the node both platforms render and size from.

Also allows @fluentui-react-native/callout in the component source boundary and
removes the now-obsolete knip ignore.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add SearchBox to the agentic components package for issue #4239. The
component delegates all field chrome to the reviewed Input pipeline and
owns only the search-specific surface: a leading search icon, a clear
button that renders only while a query is present, and search semantics
for submitting, clearing, and abandoning a query.

Behavior owned by SearchBox:

- controllable value with `value`, `defaultValue`, and `onChangeText`
- `onSearch` on submit and `onClear` from the clear button or Escape
- clear-button press returns focus to the text input
- `disabled` and `readOnly` both suppress edits, clearing, and submit
- a forwarded ref that resolves to the underlying text input
- an accessible name required on the field and on the clear button

Includes the reviewed contract and companions under `spec/`, runtime and
type tests, stories with a static desktop-driver plan, and a changeset.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tooltip pairs a trigger with a short descriptive label that appears on
pointer entry after showDelay and immediately on keyboard focus. It is a
specialization of the reviewed Popover pipeline rather than a second
floating-surface implementation: Popover keeps the wrapper, anchor ref,
surface mount lifetime, and native dismissal channel, and Tooltip drives
it as a controlled surface while replacing the decisions a tooltip owns.

Behavior:
- Visibility is controllable (visible / defaultVisible / onVisibleChange)
  and driven independently by pointer and focus, so either interaction
  keeps the label up. Opposite interactions cancel pending timers, and
  pending timers are cleared on unmount.
- The trigger describes itself with the label text and reports disabled
  state without reporting expanded state, because a tooltip is not a
  disclosure. Consumer trigger handlers run after Tooltip's own handling
  and the consumer ref composes with the anchor ref.
- A disabled trigger never reveals the tooltip and never schedules a
  timer, but never blocks a hide. Close requests from trigger activation
  or native dismissal are always adopted, including while disabled;
  open requests from trigger activation are ignored.
- The surface requests no initial focus and its label node carries the
  tooltip role; the surface and label mount only while visible.
- Label styling comes from the pinned Flex tooltip tokens, with the
  consumer content style applied last.

The reviewed contract, provenance, and companion specs are ratified to
implemented against flex-1.5.0-206c4996. The component-scoped live source
refresh confirmed the pinned tooltip source identities are unchanged; the
only upstream edit is a refinement of the still-pending motion guidance,
which does not affect the already-deferred tooltip-motion divergence.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The pointer reveal is gated on disabled when the pointer enters, but the
trigger can be disabled while the showDelay timer is still pending. The
timer then fired against the stale decision and revealed the tooltip from
a disabled trigger, violating TIP-004.

The delayed callback now re-checks the current disabled value before it
reports a change. Only reveals are gated, so a pending hide still runs
after the trigger is disabled and native dismissal is still adopted,
matching the contract that disabled never blocks a hide.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Inline desktop-driver selectors in the new Popover and SearchBox stories, and constrain the representative-plan harness to the three stories it is designed to execute as the catalog grows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Bundle size report

Tree-shaken production Metro bundles. Component costs are relative to their platform shell; shell costs are absolute.

Platform Scenario Baseline cost Current cost Cost delta Change Gzip delta Module delta
macos shell 801.3 KiB 801.3 KiB 0.0 KiB 0.00% 0.0 KiB +0
macos components-button 50.1 KiB 51.6 KiB +1.6 KiB +3.14% +0.5 KiB +9
macos components-catalog 267.3 KiB 327.0 KiB +59.6 KiB +22.31% +15.7 KiB +66
macos design-theme-state 33.3 KiB 33.5 KiB +0.2 KiB +0.52% +0.0 KiB +3
macos design-color-lib 7.1 KiB 7.1 KiB 0.0 KiB 0.00% 0.0 KiB +0
macos design-theme-state-legacy-source 35.3 KiB 35.5 KiB +0.2 KiB +0.49% +0.0 KiB +3
macos design-legacy-theme-from-flex 100.2 KiB 100.4 KiB +0.2 KiB +0.17% +0.1 KiB +3
windows shell 810.2 KiB 810.2 KiB 0.0 KiB 0.00% 0.0 KiB +0
windows components-button 50.0 KiB 51.6 KiB +1.6 KiB +3.15% +0.5 KiB +9
windows components-catalog 267.0 KiB 326.7 KiB +59.6 KiB +22.33% +15.7 KiB +66
windows design-theme-state 33.2 KiB 33.4 KiB +0.2 KiB +0.53% +0.1 KiB +3
windows design-color-lib 7.1 KiB 7.1 KiB 0.0 KiB 0.00% 0.0 KiB +0
windows design-theme-state-legacy-source 35.3 KiB 35.4 KiB +0.2 KiB +0.50% +0.0 KiB +3
windows design-legacy-theme-from-flex 100.0 KiB 100.2 KiB +0.2 KiB +0.17% +0.1 KiB +3

The job is advisory: size changes are reported but do not fail the pull request. Bundle or analysis errors still fail.


View bundle-size workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant