toolbarItemSemantics

The single accessibility contract for every toolbar item (A11Y-1 / P1-6).

Applied at the leaf composable of each item by NutrientToolbarLayout; producers never call it directly. Centralizing it means a11y review is a one-time design exercise instead of per-PR vigilance, and it matches or exceeds the View toolbar's AppCompatImageButton baseline.

It sets, from item and its state:

  • Role — Role.Switch for a ToolbarItem.Toggle, Role.Button otherwise.

  • contentDescription — item.contentDescription (the label TalkBack reads).

  • State via framework properties, never literal strings — a toggle exposes toggleableState (localized on/off announcement), everything else exposes selected when selected. Accessibility services derive their announcements from these in the device locale; a hand-rolled stateDescription would be English-only in an SDK shipping 32 languages.

  • testTag — derived from item.id via toToolbarTestTag (closes P1-12: customers map per-button R.id Espresso matchers to onNodeWithTag mechanically).

  • disabled() when not enabled (localized "disabled" announcement comes from the property); hidden from accessibility when not visible. The visual disabled treatment is the render leaf's tint (MainToolbarColors.iconDisabledColor) — no alpha layer here, or the two would stack and disabled icons render twice as dim as the View toolbar's single DISABLED_ITEM_ALPHA pass.

  • The click action itself comes from the host composable's clickable and merges in; its default "double-tap to activate" hint is localized by the accessibility service, so no custom click label is set.

It's @Composable because the test tag is resolved from the R.id resource name, which needs a Context (LocalContext).

Note: ToolbarItem.Submenu expanded/collapsed announcement is deferred to the popup layer (it depends on transient expansion state not held by ToolbarItem).