Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Copy link

@github-actions github-actions bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Breadcrumb Converged 5 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Breadcrumb Converged.appearance - High Contrast.pressed.chromium.png 466 Changed
vr-tests-react-components/Breadcrumb Converged.appearance - Dark Mode.focused.chromium.png 275 Changed
vr-tests-react-components/Breadcrumb Converged.appearance - RTL.pressed.chromium.png 186 Changed
vr-tests-react-components/Breadcrumb Converged.appearance.default.chromium.png 184 Changed
vr-tests-react-components/Breadcrumb Converged.size.pressed.chromium.png 577 Changed
vr-tests-react-components/CalendarCompat 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/CalendarCompat.multiDayView - Dark Mode.default.chromium.png 1107 Changed
vr-tests-react-components/CalendarCompat.multiDayView - High Contrast.default.chromium.png 1236 Changed
vr-tests-react-components/CalendarCompat.multiDayView - RTL.default.chromium.png 495 Changed
vr-tests-react-components/CalendarCompat.multiDayView.default.chromium_1.png 403 Changed
vr-tests-react-components/Charts-DonutChart 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic - Dark Mode.default.chromium.png 7530 Changed
vr-tests-react-components/Charts-DonutChart.Dynamic - RTL.default.chromium.png 5570 Changed
vr-tests-react-components/Charts-DonutChart.Dynamic.default.chromium.png 5581 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 413 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default - RTL.submenus open.chromium.png 404 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 605 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 510 Changed
vr-tests-react-components/TagPicker 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - Dark Mode.disabled input hover.chromium.png 658 Changed
vr-tests-react-components/TagPicker.disabled - High Contrast.disabled input hover.chromium.png 1319 Changed
vr-tests-react-components/TagPicker.disabled - RTL.disabled input hover.chromium.png 635 Changed

There were 19 duplicate changes discarded. Check the build logs for more information.

"type": "minor",
"comment": "feat: add base hooks for Breadcrumb",
"packageName": "@fluentui/react-breadcrumb",
"email": "dmytrokirpa@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities';

/**
* Data shared between breadcrumb components
Expand Down Expand Up @@ -46,3 +46,7 @@ export type BreadcrumbProps = ComponentProps<BreadcrumbSlots> & {
* State used in rendering Breadcrumb
*/
export type BreadcrumbState = ComponentState<BreadcrumbSlots> & Required<Pick<BreadcrumbProps, 'size'>>;

export type BreadcrumbBaseProps = DistributiveOmit<BreadcrumbProps, 'size'>;

export type BreadcrumbBaseState = DistributiveOmit<BreadcrumbState, 'size'>;
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
export { Breadcrumb } from './Breadcrumb';
export type { BreadcrumbContextValues, BreadcrumbProps, BreadcrumbSlots, BreadcrumbState } from './Breadcrumb.types';
export type {
BreadcrumbBaseProps,
BreadcrumbBaseState,
BreadcrumbContextValues,
BreadcrumbProps,
BreadcrumbSlots,
BreadcrumbState,
} from './Breadcrumb.types';
export { BreadcrumbProvider, breadcrumbDefaultValue, useBreadcrumbContext_unstable } from './BreadcrumbContext';
export { renderBreadcrumb_unstable } from './renderBreadcrumb';
export { useBreadcrumb_unstable } from './useBreadcrumb';
export { useBreadcrumb_unstable, useBreadcrumbBase_unstable } from './useBreadcrumb';
export { breadcrumbClassNames, useBreadcrumbStyles_unstable } from './useBreadcrumbStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import * as React from 'react';
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import type { BreadcrumbProps, BreadcrumbState } from './Breadcrumb.types';
import type { BreadcrumbBaseProps, BreadcrumbBaseState, BreadcrumbProps, BreadcrumbState } from './Breadcrumb.types';
import { useArrowNavigationGroup } from '@fluentui/react-tabster';

/**
Expand All @@ -15,7 +15,27 @@ import { useArrowNavigationGroup } from '@fluentui/react-tabster';
* @param ref - reference to root HTMLElement of Breadcrumb
*/
export const useBreadcrumb_unstable = (props: BreadcrumbProps, ref: React.Ref<HTMLElement>): BreadcrumbState => {
const { focusMode = 'tab', size = 'medium', list, ...rest } = props;
const { size = 'medium', ...breadcrumbProps } = props;
const state = useBreadcrumbBase_unstable(breadcrumbProps, ref);

return {
...state,
size,
};
};

/**
* Base hook for Breadcrumb component, which manages state related to slots structure, ARIA attributes,
* and keyboard navigation without design props.
*
* @param props - props from this instance of Breadcrumb
* @param ref - reference to root HTMLElement of Breadcrumb
*/
export const useBreadcrumbBase_unstable = (
props: BreadcrumbBaseProps,
ref: React.Ref<HTMLElement>,
): BreadcrumbBaseState => {
const { focusMode = 'tab', list, ...rest } = props;

const focusAttributes = useArrowNavigationGroup({
circular: true,
Expand All @@ -38,6 +58,5 @@ export const useBreadcrumb_unstable = (props: BreadcrumbProps, ref: React.Ref<HT
{ elementType: 'nav' },
),
list: slot.optional(list, { renderByDefault: true, defaultProps: { role: 'list' }, elementType: 'ol' }),
size,
};
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, ComponentState } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState, DistributiveOmit } from '@fluentui/react-utilities';
import { ButtonProps, ButtonSlots, ButtonState } from '@fluentui/react-button';
import { BreadcrumbProps } from '../Breadcrumb/Breadcrumb.types';

Expand All @@ -24,3 +24,7 @@ export type BreadcrumbButtonProps = ComponentProps<BreadcrumbButtonSlots> &
export type BreadcrumbButtonState = ComponentState<BreadcrumbButtonSlots> &
Omit<ButtonState, keyof ButtonSlots | 'components'> &
Required<Pick<BreadcrumbButtonProps, 'current' | 'size'>>;

export type BreadcrumbButtonBaseProps = DistributiveOmit<BreadcrumbButtonProps, 'size'>;

export type BreadcrumbButtonBaseState = DistributiveOmit<BreadcrumbButtonState, 'size'>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { BreadcrumbButton } from './BreadcrumbButton';
export type { BreadcrumbButtonProps, BreadcrumbButtonSlots, BreadcrumbButtonState } from './BreadcrumbButton.types';
export type {
BreadcrumbButtonBaseProps,
BreadcrumbButtonBaseState,
BreadcrumbButtonProps,
BreadcrumbButtonSlots,
BreadcrumbButtonState,
} from './BreadcrumbButton.types';
export { renderBreadcrumbButton_unstable } from './renderBreadcrumbButton';
export { useBreadcrumbButton_unstable } from './useBreadcrumbButton';
export { useBreadcrumbButton_unstable, useBreadcrumbButtonBase_unstable } from './useBreadcrumbButton';
export { breadcrumbButtonClassNames, useBreadcrumbButtonStyles_unstable } from './useBreadcrumbButtonStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import type { ARIAButtonProps } from '@fluentui/react-aria';
import { useButton_unstable } from '@fluentui/react-button';
import type { ButtonProps } from '@fluentui/react-button';
import { useBreadcrumbContext_unstable } from '../Breadcrumb/BreadcrumbContext';
import type { BreadcrumbButtonProps, BreadcrumbButtonState } from './BreadcrumbButton.types';
import type {
BreadcrumbButtonBaseProps,
BreadcrumbButtonBaseState,
BreadcrumbButtonProps,
BreadcrumbButtonState,
} from './BreadcrumbButton.types';

/**
* Create the state required to render BreadcrumbButton.
Expand All @@ -21,25 +26,44 @@ export const useBreadcrumbButton_unstable = (
ref: React.Ref<HTMLButtonElement | HTMLAnchorElement>,
): BreadcrumbButtonState => {
const { size } = useBreadcrumbContext_unstable();
const state = useBreadcrumbButtonBase_unstable(props, ref);

return {
...state,
size,
};
};

/**
* Base hook for BreadcrumbButton component, which manages state related to button behavior,
* ARIA attributes (aria-current, aria-disabled), and slot structure without design props.
*
* @param props - props from this instance of BreadcrumbButton
* @param ref - reference to root HTMLElement of BreadcrumbButton
*/
export const useBreadcrumbButtonBase_unstable = (
props: BreadcrumbButtonBaseProps,
ref: React.Ref<HTMLButtonElement | HTMLAnchorElement>,
): BreadcrumbButtonBaseState => {
const { current = false, as, ...rest } = props;

const controlType = as ?? (props as ARIAButtonProps<'a'>).href ? 'a' : 'button';

const { size: _size, ...buttonState } = useButton_unstable(
{
role: undefined,
type: undefined,
as: controlType,
iconPosition: 'before',
'aria-current': current ? props['aria-current'] ?? 'page' : undefined,
'aria-disabled': current ? props['aria-disabled'] ?? true : undefined,
...rest,
} as ButtonProps,
ref,
);

return {
...useButton_unstable(
{
appearance: 'subtle',
role: undefined,
type: undefined,
as: controlType,
iconPosition: 'before',
'aria-current': current ? props['aria-current'] ?? 'page' : undefined,
'aria-disabled': current ? props['aria-disabled'] ?? true : undefined,
...rest,
} as ButtonProps,
ref,
),
...buttonState,
current,
size,
};
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities';
import type { BreadcrumbProps } from '../Breadcrumb/Breadcrumb.types';

export type BreadcrumbDividerSlots = {
Expand All @@ -14,3 +14,13 @@ export type BreadcrumbDividerProps = ComponentProps<BreadcrumbDividerSlots> & {}
* State used in rendering BreadcrumbDivider
*/
export type BreadcrumbDividerState = ComponentState<BreadcrumbDividerSlots> & Pick<BreadcrumbProps, 'size'>;

/**
* BreadcrumbDivider base props (same as BreadcrumbDividerProps since BreadcrumbDivider has no design props of its own)
*/
export type BreadcrumbDividerBaseProps = BreadcrumbDividerProps;

/**
* BreadcrumbDivider base state (excludes size, which is a design prop injected from context)
*/
export type BreadcrumbDividerBaseState = DistributiveOmit<BreadcrumbDividerState, 'size'>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { BreadcrumbDivider } from './BreadcrumbDivider';
export type { BreadcrumbDividerProps, BreadcrumbDividerSlots, BreadcrumbDividerState } from './BreadcrumbDivider.types';
export type {
BreadcrumbDividerBaseProps,
BreadcrumbDividerBaseState,
BreadcrumbDividerProps,
BreadcrumbDividerSlots,
BreadcrumbDividerState,
} from './BreadcrumbDivider.types';
export { renderBreadcrumbDivider_unstable } from './renderBreadcrumbDivider';
export { useBreadcrumbDivider_unstable } from './useBreadcrumbDivider';
export { useBreadcrumbDivider_unstable, useBreadcrumbDividerBase_unstable } from './useBreadcrumbDivider';
export { breadcrumbDividerClassNames, useBreadcrumbDividerStyles_unstable } from './useBreadcrumbDividerStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import * as React from 'react';
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import type { BreadcrumbDividerProps, BreadcrumbDividerState } from './BreadcrumbDivider.types';
import type {
BreadcrumbDividerBaseProps,
BreadcrumbDividerBaseState,
BreadcrumbDividerProps,
BreadcrumbDividerState,
} from './BreadcrumbDivider.types';
import { ChevronRightRegular, ChevronLeftRegular } from '@fluentui/react-icons';
import { useBreadcrumbContext_unstable } from '../Breadcrumb/BreadcrumbContext';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
Expand All @@ -21,6 +26,25 @@ export const useBreadcrumbDivider_unstable = (
ref: React.Ref<HTMLLIElement>,
): BreadcrumbDividerState => {
const { size } = useBreadcrumbContext_unstable();
const state = useBreadcrumbDividerBase_unstable(props, ref);

return {
...state,
size,
};
};

/**
* Base hook for BreadcrumbDivider component, which manages state related to slots structure and ARIA attributes
* without design props. Note: size is provided via BreadcrumbContext in the full hook.
*
* @param props - props from this instance of BreadcrumbDivider
* @param ref - reference to root HTMLElement of BreadcrumbDivider
*/
export const useBreadcrumbDividerBase_unstable = (
props: BreadcrumbDividerBaseProps,
ref: React.Ref<HTMLLIElement>,
): BreadcrumbDividerBaseState => {
const { dir } = useFluent();
const icon = getDividerIcon(dir);

Expand All @@ -37,7 +61,6 @@ export const useBreadcrumbDivider_unstable = (
}),
{ elementType: 'li' },
),
size,
};
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities';
import type { BreadcrumbProps } from '../Breadcrumb';

export type BreadcrumbItemSlots = {
Expand All @@ -14,3 +14,13 @@ export type BreadcrumbItemProps = ComponentProps<BreadcrumbItemSlots> & Pick<Bre
* State used in rendering BreadcrumbItem
*/
export type BreadcrumbItemState = ComponentState<BreadcrumbItemSlots> & Required<Pick<BreadcrumbItemProps, 'size'>>;

/**
* BreadcrumbItem base props (same as BreadcrumbItemProps since size is passed through context, not as a design prop)
*/
export type BreadcrumbItemBaseProps = DistributiveOmit<BreadcrumbItemProps, 'size'>;

/**
* BreadcrumbItem base state (excludes size, which is a design prop injected from context)
*/
export type BreadcrumbItemBaseState = DistributiveOmit<BreadcrumbItemState, 'size'>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { BreadcrumbItem } from './BreadcrumbItem';
export type { BreadcrumbItemProps, BreadcrumbItemSlots, BreadcrumbItemState } from './BreadcrumbItem.types';
export type {
BreadcrumbItemBaseProps,
BreadcrumbItemBaseState,
BreadcrumbItemProps,
BreadcrumbItemSlots,
BreadcrumbItemState,
} from './BreadcrumbItem.types';
export { renderBreadcrumbItem_unstable } from './renderBreadcrumbItem';
export { useBreadcrumbItem_unstable } from './useBreadcrumbItem';
export { useBreadcrumbItem_unstable, useBreadcrumbItemBase_unstable } from './useBreadcrumbItem';
export { breadcrumbItemClassNames, useBreadcrumbItemStyles_unstable } from './useBreadcrumbItemStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import * as React from 'react';
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import type { BreadcrumbItemProps, BreadcrumbItemState } from './BreadcrumbItem.types';
import type {
BreadcrumbItemBaseProps,
BreadcrumbItemBaseState,
BreadcrumbItemProps,
BreadcrumbItemState,
} from './BreadcrumbItem.types';
import { useBreadcrumbContext_unstable } from '../Breadcrumb/BreadcrumbContext';

/**
Expand All @@ -19,7 +24,25 @@ export const useBreadcrumbItem_unstable = (
ref: React.Ref<HTMLLIElement>,
): BreadcrumbItemState => {
const { size } = useBreadcrumbContext_unstable();
const state = useBreadcrumbItemBase_unstable(props, ref);

return {
...state,
size,
};
};

/**
* Base hook for BreadcrumbItem component, which manages state related to slots structure
* without design props. Note: size is provided via BreadcrumbContext in the full hook.
*
* @param props - props from this instance of BreadcrumbItem
* @param ref - reference to root HTMLElement of BreadcrumbItem
*/
export const useBreadcrumbItemBase_unstable = (
props: BreadcrumbItemBaseProps,
ref: React.Ref<HTMLLIElement>,
): BreadcrumbItemBaseState => {
return {
components: { root: 'li' },
root: slot.always(
Expand All @@ -29,6 +52,5 @@ export const useBreadcrumbItem_unstable = (
}),
{ elementType: 'li' },
),
size,
};
};
10 changes: 10 additions & 0 deletions packages/react-components/react-breadcrumb/library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,13 @@ export {
export type { BreadcrumbButtonProps, BreadcrumbButtonSlots, BreadcrumbButtonState } from './BreadcrumbButton';
export { BreadcrumbProvider, useBreadcrumbContext_unstable } from './Breadcrumb';
export type { BreadcrumbContextValues } from './Breadcrumb';

// Experimental APIs - will be uncommented in the experimental release branch
// export { useBreadcrumbBase_unstable } from './Breadcrumb';
// export type { BreadcrumbBaseProps, BreadcrumbBaseState } from './Breadcrumb';
// export { useBreadcrumbDividerBase_unstable } from './BreadcrumbDivider';
// export type { BreadcrumbDividerBaseProps, BreadcrumbDividerBaseState } from './BreadcrumbDivider';
// export { useBreadcrumbItemBase_unstable } from './BreadcrumbItem';
// export type { BreadcrumbItemBaseProps, BreadcrumbItemBaseState } from './BreadcrumbItem';
// export { useBreadcrumbButtonBase_unstable } from './BreadcrumbButton';
// export type { BreadcrumbButtonBaseProps, BreadcrumbButtonBaseState } from './BreadcrumbButton';