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/CalendarCompat 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/CalendarCompat.multiDayView - High Contrast.default.chromium.png 1236 Changed
vr-tests-react-components/CalendarCompat.multiDayView.default.chromium.png 495 Changed
vr-tests-react-components/CalendarCompat.multiDayView.default.chromium_1.png 403 Changed
vr-tests-react-components/CalendarCompat.multiDayView - Dark Mode.default.chromium.png 1107 Changed
vr-tests-react-components/Charts-DonutChart 2 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/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 723 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 505 Changed
vr-tests-react-components/Skeleton converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Skeleton converged.Translucent Skeleton with circle - High Contrast.default.chromium.png 1 Changed
vr-tests-react-components/TagPicker 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - Dark Mode.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 4 duplicate changes discarded. Check the build logs for more information.

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

/**
* Card selected event type
Expand Down Expand Up @@ -135,6 +135,8 @@ export type CardProps = ComponentProps<CardSlots> & {
disabled?: boolean;
};

export type CardBaseProps = DistributiveOmit<CardProps, 'appearance' | 'orientation' | 'size'>;

/**
* State used in rendering Card.
*/
Expand Down Expand Up @@ -178,3 +180,5 @@ export type CardState = ComponentState<CardSlots> &
disabled: boolean;
}
>;

export type CardBaseState = DistributiveOmit<CardState, 'appearance' | 'orientation' | 'size'>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export { Card } from './Card';
export type {
CardBaseProps,
CardBaseState,
CardContextValue,
CardOnSelectData,
CardOnSelectionChangeEvent,
Expand All @@ -9,5 +11,5 @@ export type {
} from './Card.types';
export { CardProvider, cardContextDefaultValue, useCardContext_unstable } from './CardContext';
export { renderCard_unstable } from './renderCard';
export { useCard_unstable } from './useCard';
export { useCard_unstable, useCardBase_unstable } from './useCard';
export { cardCSSVars, cardClassNames, useCardStyles_unstable } from './useCardStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as React from 'react';
import { getIntrinsicElementProps, useMergedRefs, slot } from '@fluentui/react-utilities';
import { useFocusableGroup, useFocusWithin } from '@fluentui/react-tabster';

import type { CardProps, CardState } from './Card.types';
import type { CardBaseProps, CardBaseState, CardProps, CardState } from './Card.types';
import { useCardSelectable } from './useCardSelectable';
import { cardContextDefaultValue } from './CardContext';

Expand Down Expand Up @@ -79,7 +79,26 @@ const useCardInteractive = ({ focusMode: initialFocusMode, disabled = false, ...
* @param ref - reference to the root element of Card
*/
export const useCard_unstable = (props: CardProps, ref: React.Ref<HTMLDivElement>): CardState => {
const { appearance = 'filled', orientation = 'vertical', size = 'medium', disabled = false, ...restProps } = props;
const { appearance = 'filled', orientation = 'vertical', size = 'medium', ...cardProps } = props;
const state = useCardBase_unstable(cardProps, ref);

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

/**
* Base hook for Card component, which manages state related to interactivity, selection,
* focus management, ARIA attributes, and slot structure without design props.
*
* @param props - props from this instance of Card
* @param ref - reference to the root element of Card
*/
export const useCardBase_unstable = (props: CardBaseProps, ref: React.Ref<HTMLDivElement>): CardBaseState => {
const { disabled = false, ...restProps } = props;

const [referenceId, setReferenceId] = React.useState(cardContextDefaultValue.selectableA11yProps.referenceId);
const [referenceLabel, setReferenceLabel] = React.useState(cardContextDefaultValue.selectableA11yProps.referenceId);
Expand Down Expand Up @@ -107,9 +126,6 @@ export const useCard_unstable = (props: CardProps, ref: React.Ref<HTMLDivElement
}

return {
appearance,
orientation,
size,
interactive,
selectable,
selectFocused,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@ export type CardFooterSlots = {
*/
export type CardFooterProps = ComponentProps<CardFooterSlots>;

/**
* CardFooter base props (same as CardFooterProps since CardFooter has no design props)
*/
export type CardFooterBaseProps = CardFooterProps;

/**
* State used in rendering CardFooter.
*/
export type CardFooterState = ComponentState<CardFooterSlots>;

/**
* CardFooter base state (same as CardFooterState since CardFooter has no design props)
*/
export type CardFooterBaseState = CardFooterState;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { CardFooter } from './CardFooter';
export type { CardFooterProps, CardFooterSlots, CardFooterState } from './CardFooter.types';
export type {
CardFooterBaseProps,
CardFooterBaseState,
CardFooterProps,
CardFooterSlots,
CardFooterState,
} from './CardFooter.types';
export { renderCardFooter_unstable } from './renderCardFooter';
export { useCardFooter_unstable } from './useCardFooter';
export { useCardFooter_unstable, useCardFooterBase_unstable } from './useCardFooter';
export { cardFooterClassNames, useCardFooterStyles_unstable } from './useCardFooterStyles.styles';
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use client';

import * as React from 'react';
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import type { CardFooterProps, CardFooterState } from './CardFooter.types';
import type { CardFooterBaseProps, CardFooterBaseState, CardFooterProps, CardFooterState } from './CardFooter.types';

/**
* Create the state required to render CardFooter.
Expand All @@ -12,6 +14,20 @@ import type { CardFooterProps, CardFooterState } from './CardFooter.types';
* @param ref - reference to root HTMLElement of CardFooter
*/
export const useCardFooter_unstable = (props: CardFooterProps, ref: React.Ref<HTMLElement>): CardFooterState => {
return useCardFooterBase_unstable(props, ref);
};

/**
* Base hook for CardFooter component, which manages state related to slots structure.
* Note: CardFooter has no design props, so this is equivalent to useCardFooter_unstable.
*
* @param props - props from this instance of CardFooter
* @param ref - reference to root HTMLElement of CardFooter
*/
export const useCardFooterBase_unstable = (
props: CardFooterBaseProps,
ref: React.Ref<HTMLElement>,
): CardFooterBaseState => {
const { action } = props;

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,17 @@ export type CardHeaderSlots = {
*/
export type CardHeaderProps = ComponentProps<Partial<CardHeaderSlots>>;

/**
* CardHeader base props (same as CardHeaderProps since CardHeader has no design props)
*/
export type CardHeaderBaseProps = CardHeaderProps;

/**
* State used in rendering CardHeader.
*/
export type CardHeaderState = ComponentState<CardHeaderSlots>;

/**
* CardHeader base state (same as CardHeaderState since CardHeader has no design props)
*/
export type CardHeaderBaseState = CardHeaderState;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { CardHeader } from './CardHeader';
export type { CardHeaderProps, CardHeaderSlots, CardHeaderState } from './CardHeader.types';
export type {
CardHeaderBaseProps,
CardHeaderBaseState,
CardHeaderProps,
CardHeaderSlots,
CardHeaderState,
} from './CardHeader.types';
export { renderCardHeader_unstable } from './renderCardHeader';
export { useCardHeader_unstable } from './useCardHeader';
export { useCardHeader_unstable, useCardHeaderBase_unstable } from './useCardHeader';
export { cardHeaderCSSVars, cardHeaderClassNames, useCardHeaderStyles_unstable } from './useCardHeaderStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import * as React from 'react';
import { getIntrinsicElementProps, useId, slot } from '@fluentui/react-utilities';
import type { CardHeaderProps, CardHeaderState } from './CardHeader.types';
import type { CardHeaderBaseProps, CardHeaderBaseState, CardHeaderProps, CardHeaderState } from './CardHeader.types';
import { useCardContext_unstable } from '../Card/CardContext';
import { cardHeaderClassNames } from './useCardHeaderStyles.styles';

Expand Down Expand Up @@ -54,6 +54,21 @@ function getReferenceId(
* @param ref - reference to root HTMLElement of CardHeader
*/
export const useCardHeader_unstable = (props: CardHeaderProps, ref: React.Ref<HTMLElement>): CardHeaderState => {
return useCardHeaderBase_unstable(props, ref);
};

/**
* Base hook for CardHeader component, which manages state related to slots structure
* and the card's selectable accessibility properties.
* Note: CardHeader has no design props, so this is equivalent to useCardHeader_unstable.
*
* @param props - props from this instance of CardHeader
* @param ref - reference to root HTMLElement of CardHeader
*/
export const useCardHeaderBase_unstable = (
props: CardHeaderBaseProps,
ref: React.Ref<HTMLElement>,
): CardHeaderBaseState => {
const { image, header, description, action } = props;

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@ export type CardPreviewSlots = {
*/
export type CardPreviewProps = ComponentProps<CardPreviewSlots>;

/**
* CardPreview base props (same as CardPreviewProps since CardPreview has no design props)
*/
export type CardPreviewBaseProps = CardPreviewProps;

/**
* State used in rendering CardPreview.
*/
export type CardPreviewState = ComponentState<CardPreviewSlots>;

/**
* CardPreview base state (same as CardPreviewState since CardPreview has no design props)
*/
export type CardPreviewBaseState = CardPreviewState;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { CardPreview } from './CardPreview';
export type { CardPreviewProps, CardPreviewSlots, CardPreviewState } from './CardPreview.types';
export type {
CardPreviewBaseProps,
CardPreviewBaseState,
CardPreviewProps,
CardPreviewSlots,
CardPreviewState,
} from './CardPreview.types';
export { renderCardPreview_unstable } from './renderCardPreview';
export { useCardPreview_unstable } from './useCardPreview';
export { useCardPreview_unstable, useCardPreviewBase_unstable } from './useCardPreview';
export { cardPreviewClassNames, useCardPreviewStyles_unstable } from './useCardPreviewStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import * as React from 'react';
import { getIntrinsicElementProps, useMergedRefs, slot } from '@fluentui/react-utilities';
import type { CardPreviewProps, CardPreviewState } from './CardPreview.types';
import type {
CardPreviewBaseProps,
CardPreviewBaseState,
CardPreviewProps,
CardPreviewState,
} from './CardPreview.types';
import { useCardContext_unstable } from '../Card/CardContext';
import { cardPreviewClassNames } from './useCardPreviewStyles.styles';

Expand All @@ -16,6 +21,21 @@ import { cardPreviewClassNames } from './useCardPreviewStyles.styles';
* @param ref - reference to root HTMLElement of CardPreview
*/
export const useCardPreview_unstable = (props: CardPreviewProps, ref: React.Ref<HTMLElement>): CardPreviewState => {
return useCardPreviewBase_unstable(props, ref);
};

/**
* Base hook for CardPreview component, which manages state related to slots structure
* and the card's selectable accessibility label.
* Note: CardPreview has no design props, so this is equivalent to useCardPreview_unstable.
*
* @param props - props from this instance of CardPreview
* @param ref - reference to root HTMLElement of CardPreview
*/
export const useCardPreviewBase_unstable = (
props: CardPreviewBaseProps,
ref: React.Ref<HTMLElement>,
): CardPreviewBaseState => {
const { logo } = props;

const {
Expand Down
10 changes: 10 additions & 0 deletions packages/react-components/react-card/library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,13 @@ export {
export type { CardPreviewProps, CardPreviewSlots, CardPreviewState } from './CardPreview';
export { CardProvider, useCardContext_unstable } from './Card';
export type { CardContextValue } from './Card';

// Experimental APIs - will be uncommented in the experimental release branch
// export { useCardBase_unstable } from './Card';
// export type { CardBaseProps, CardBaseState } from './Card';
// export { useCardFooterBase_unstable } from './CardFooter';
// export type { CardFooterBaseProps, CardFooterBaseState } from './CardFooter';
// export { useCardHeaderBase_unstable } from './CardHeader';
// export type { CardHeaderBaseProps, CardHeaderBaseState } from './CardHeader';
// export { useCardPreviewBase_unstable } from './CardPreview';
// export type { CardPreviewBaseProps, CardPreviewBaseState } from './CardPreview';