From 115992d6bb3f091323acef5278f7852f8df1143e Mon Sep 17 00:00:00 2001 From: Dmytro Kirpa Date: Tue, 3 Mar 2026 08:14:46 +0100 Subject: [PATCH 1/4] feat(react-badge): add useBadgeBase_unstable, useCounterBadgeBase_unstable, and usePresenceBadgeBase_unstable hooks Implements base state hooks for Badge, CounterBadge, and PresenceBadge components. Each base hook extracts pure component logic (slot structure, ARIA attributes, functional state) while omitting design props (appearance, color, shape, size). - BadgeBaseProps/BadgeBaseState: omits appearance, color, shape, size - CounterBadgeBaseProps/CounterBadgeBaseState: omits appearance, color, shape, size - PresenceBadgeBaseProps/PresenceBadgeBaseState: omits size (appearance/color/shape are not exposed) - useBadge_unstable now calls useBadgeBase_unstable internally - useCounterBadge_unstable now calls useCounterBadgeBase_unstable internally - All new types and hooks exported from package index.ts Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/Badge/Badge.types.ts | 6 ++- .../library/src/components/Badge/index.ts | 4 +- .../library/src/components/Badge/useBadge.ts | 26 ++++++--- .../CounterBadge/CounterBadge.types.ts | 5 ++ .../src/components/CounterBadge/index.ts | 9 +++- .../CounterBadge/useCounterBadge.ts | 43 ++++++++++++--- .../PresenceBadge/PresenceBadge.types.ts | 6 ++- .../src/components/PresenceBadge/index.ts | 10 +++- .../PresenceBadge/usePresenceBadge.tsx | 53 ++++++++++++++++++- .../react-badge/library/src/index.ts | 27 ++++++++-- 10 files changed, 164 insertions(+), 25 deletions(-) diff --git a/packages/react-components/react-badge/library/src/components/Badge/Badge.types.ts b/packages/react-components/react-badge/library/src/components/Badge/Badge.types.ts index d9e325415df1e..483f689ae5a9b 100644 --- a/packages/react-components/react-badge/library/src/components/Badge/Badge.types.ts +++ b/packages/react-components/react-badge/library/src/components/Badge/Badge.types.ts @@ -1,4 +1,4 @@ -import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; +import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities'; export type BadgeSlots = { root: Slot<'div'>; @@ -41,3 +41,7 @@ export type BadgeProps = Omit, 'color'> & { export type BadgeState = ComponentState & Required>; + +export type BadgeBaseProps = DistributiveOmit; + +export type BadgeBaseState = DistributiveOmit; diff --git a/packages/react-components/react-badge/library/src/components/Badge/index.ts b/packages/react-components/react-badge/library/src/components/Badge/index.ts index 94552cb73b051..03545bbfacb0a 100644 --- a/packages/react-components/react-badge/library/src/components/Badge/index.ts +++ b/packages/react-components/react-badge/library/src/components/Badge/index.ts @@ -1,6 +1,6 @@ export { Badge } from './Badge'; // Explicit exports to omit BadgeCommons -export type { BadgeProps, BadgeSlots, BadgeState } from './Badge.types'; +export type { BadgeBaseProps, BadgeBaseState, BadgeProps, BadgeSlots, BadgeState } from './Badge.types'; export { renderBadge_unstable } from './renderBadge'; -export { useBadge_unstable } from './useBadge'; +export { useBadge_unstable, useBadgeBase_unstable } from './useBadge'; export { badgeClassNames, useBadgeStyles_unstable } from './useBadgeStyles.styles'; diff --git a/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts b/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts index 2159c9679333d..5fbe14ca34e18 100644 --- a/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts +++ b/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities'; -import type { BadgeProps, BadgeState } from './Badge.types'; +import type { BadgeBaseProps, BadgeBaseState, BadgeProps, BadgeState } from './Badge.types'; /** * Returns the props and state required to render the component @@ -9,17 +9,33 @@ export const useBadge_unstable = (props: BadgeProps, ref: React.Ref const { shape = 'circular', size = 'medium', - iconPosition = 'before', appearance = 'filled', color = 'brand', + ...badgeProps } = props; - const state: BadgeState = { + const state = useBadgeBase_unstable(badgeProps, ref); + + return { + ...state, shape, size, - iconPosition, appearance, color, + }; +}; + +/** + * Base hook for Badge component, which manages state related to slots structure and ARIA attributes. + * + * @param props - User provided props to the Badge component. + * @param ref - User provided ref to be passed to the Badge component. + */ +export const useBadgeBase_unstable = (props: BadgeBaseProps, ref: React.Ref): BadgeBaseState => { + const { iconPosition = 'before' } = props; + + return { + iconPosition, components: { root: 'div', icon: 'span', @@ -36,6 +52,4 @@ export const useBadge_unstable = (props: BadgeProps, ref: React.Ref ), icon: slot.optional(props.icon, { elementType: 'span' }), }; - - return state; }; diff --git a/packages/react-components/react-badge/library/src/components/CounterBadge/CounterBadge.types.ts b/packages/react-components/react-badge/library/src/components/CounterBadge/CounterBadge.types.ts index 03b0bf0967083..18d7b8702b68f 100644 --- a/packages/react-components/react-badge/library/src/components/CounterBadge/CounterBadge.types.ts +++ b/packages/react-components/react-badge/library/src/components/CounterBadge/CounterBadge.types.ts @@ -1,3 +1,4 @@ +import type { DistributiveOmit } from '@fluentui/react-utilities'; import type { BadgeProps, BadgeState } from '../Badge/index'; export type CounterBadgeProps = Omit & { @@ -49,3 +50,7 @@ export type CounterBadgeProps = Omit & Required>; + +export type CounterBadgeBaseProps = DistributiveOmit; + +export type CounterBadgeBaseState = DistributiveOmit; diff --git a/packages/react-components/react-badge/library/src/components/CounterBadge/index.ts b/packages/react-components/react-badge/library/src/components/CounterBadge/index.ts index 2c149ed8d8fbd..16620efaf677f 100644 --- a/packages/react-components/react-badge/library/src/components/CounterBadge/index.ts +++ b/packages/react-components/react-badge/library/src/components/CounterBadge/index.ts @@ -1,4 +1,9 @@ export { CounterBadge } from './CounterBadge'; -export type { CounterBadgeProps, CounterBadgeState } from './CounterBadge.types'; -export { useCounterBadge_unstable } from './useCounterBadge'; +export type { + CounterBadgeBaseProps, + CounterBadgeBaseState, + CounterBadgeProps, + CounterBadgeState, +} from './CounterBadge.types'; +export { useCounterBadge_unstable, useCounterBadgeBase_unstable } from './useCounterBadge'; export { counterBadgeClassNames, useCounterBadgeStyles_unstable } from './useCounterBadgeStyles.styles'; diff --git a/packages/react-components/react-badge/library/src/components/CounterBadge/useCounterBadge.ts b/packages/react-components/react-badge/library/src/components/CounterBadge/useCounterBadge.ts index a4132f5031134..fcba1d5cd489f 100644 --- a/packages/react-components/react-badge/library/src/components/CounterBadge/useCounterBadge.ts +++ b/packages/react-components/react-badge/library/src/components/CounterBadge/useCounterBadge.ts @@ -2,8 +2,13 @@ import * as React from 'react'; import type { BadgeState } from '../Badge/index'; -import { useBadge_unstable } from '../Badge/index'; -import type { CounterBadgeProps, CounterBadgeState } from './CounterBadge.types'; +import { useBadgeBase_unstable } from '../Badge/index'; +import type { + CounterBadgeBaseProps, + CounterBadgeBaseState, + CounterBadgeProps, + CounterBadgeState, +} from './CounterBadge.types'; /** * Returns the props and state required to render the component @@ -12,16 +17,42 @@ export const useCounterBadge_unstable = (props: CounterBadgeProps, ref: React.Re const { shape = 'circular', appearance = 'filled', + color = 'brand', + size = 'medium', + ...counterBadgeProps + } = props; + + const state = useCounterBadgeBase_unstable(counterBadgeProps, ref); + + return { + ...state, + shape, + appearance, + color, + size, + }; +}; + +/** + * Base hook for CounterBadge component, which manages state related to slots structure and counter logic. + * + * @param props - User provided props to the CounterBadge component. + * @param ref - User provided ref to be passed to the CounterBadge component. + */ +export const useCounterBadgeBase_unstable = ( + props: CounterBadgeBaseProps, + ref: React.Ref, +): CounterBadgeBaseState => { + const { showZero = false, overflowCount = 99, count = 0, dot = false, + ...badgeProps } = props; - const state: CounterBadgeState = { - ...(useBadge_unstable(props, ref) as Pick), - shape, - appearance, + const state: CounterBadgeBaseState = { + ...(useBadgeBase_unstable(badgeProps, ref) as Pick>), showZero, count, dot, diff --git a/packages/react-components/react-badge/library/src/components/PresenceBadge/PresenceBadge.types.ts b/packages/react-components/react-badge/library/src/components/PresenceBadge/PresenceBadge.types.ts index 176e3e7e8ce89..1fb6a821497ca 100644 --- a/packages/react-components/react-badge/library/src/components/PresenceBadge/PresenceBadge.types.ts +++ b/packages/react-components/react-badge/library/src/components/PresenceBadge/PresenceBadge.types.ts @@ -1,4 +1,4 @@ -import type { ComponentProps, ComponentState } from '@fluentui/react-utilities'; +import type { ComponentProps, ComponentState, DistributiveOmit } from '@fluentui/react-utilities'; import type { BadgeProps, BadgeState, BadgeSlots } from '../Badge/Badge.types'; export type PresenceBadgeStatus = @@ -30,3 +30,7 @@ export type PresenceBadgeProps = Omit & BadgeState & Required>; + +export type PresenceBadgeBaseProps = DistributiveOmit; + +export type PresenceBadgeBaseState = DistributiveOmit; diff --git a/packages/react-components/react-badge/library/src/components/PresenceBadge/index.ts b/packages/react-components/react-badge/library/src/components/PresenceBadge/index.ts index ca264ac9288d3..b4776ce4fc758 100644 --- a/packages/react-components/react-badge/library/src/components/PresenceBadge/index.ts +++ b/packages/react-components/react-badge/library/src/components/PresenceBadge/index.ts @@ -1,6 +1,12 @@ export { PresenceBadge } from './PresenceBadge'; -export type { PresenceBadgeProps, PresenceBadgeState, PresenceBadgeStatus } from './PresenceBadge.types'; -export { usePresenceBadge_unstable } from './usePresenceBadge'; +export type { + PresenceBadgeBaseProps, + PresenceBadgeBaseState, + PresenceBadgeProps, + PresenceBadgeState, + PresenceBadgeStatus, +} from './PresenceBadge.types'; +export { usePresenceBadge_unstable, usePresenceBadgeBase_unstable } from './usePresenceBadge'; export { presenceBadgeClassNames, usePresenceBadgeStyles_unstable } from './usePresenceBadgeStyles.styles'; export { presenceAvailableFilled, diff --git a/packages/react-components/react-badge/library/src/components/PresenceBadge/usePresenceBadge.tsx b/packages/react-components/react-badge/library/src/components/PresenceBadge/usePresenceBadge.tsx index c23befefd56b3..9769552679f43 100644 --- a/packages/react-components/react-badge/library/src/components/PresenceBadge/usePresenceBadge.tsx +++ b/packages/react-components/react-badge/library/src/components/PresenceBadge/usePresenceBadge.tsx @@ -14,8 +14,13 @@ import { presenceOofRegular, presenceUnknownRegular, } from './presenceIcons'; -import { useBadge_unstable } from '../Badge/index'; -import type { PresenceBadgeProps, PresenceBadgeState } from './PresenceBadge.types'; +import { useBadge_unstable, useBadgeBase_unstable } from '../Badge/index'; +import type { + PresenceBadgeBaseProps, + PresenceBadgeBaseState, + PresenceBadgeProps, + PresenceBadgeState, +} from './PresenceBadge.types'; const iconMap = (status: PresenceBadgeState['status'], outOfOffice: boolean, size: PresenceBadgeState['size']) => { switch (status) { @@ -86,3 +91,47 @@ export const usePresenceBadge_unstable = ( return state; }; + +/** + * Base hook for PresenceBadge component, which manages state related to presence status and ARIA attributes. + * Note: size is excluded from BaseProps as it is a design prop; icon selection uses the 'medium' size default. + * To render size-specific icons, use the full usePresenceBadge_unstable hook. + * + * @param props - User provided props to the PresenceBadge component. + * @param ref - User provided ref to be passed to the PresenceBadge component. + */ +export const usePresenceBadgeBase_unstable = ( + props: PresenceBadgeBaseProps, + ref: React.Ref, +): PresenceBadgeBaseState => { + const { status = 'available', outOfOffice = false } = props; + + const statusText = DEFAULT_STRINGS[status]; + const oofText = props.outOfOffice && props.status !== 'out-of-office' ? ` ${DEFAULT_STRINGS['out-of-office']}` : ''; + + // Default to 'medium' size for icon selection when no size design prop is available + const iconSize = 'medium'; + const IconElement = iconMap(status, outOfOffice, iconSize); + + const state: PresenceBadgeBaseState = { + ...useBadgeBase_unstable( + { + 'aria-label': statusText + oofText, + role: 'img', + ...props, + icon: slot.optional(props.icon, { + defaultProps: { + children: IconElement ? : null, + }, + renderByDefault: true, + elementType: 'span', + }), + }, + ref, + ), + status, + outOfOffice, + }; + + return state; +}; diff --git a/packages/react-components/react-badge/library/src/index.ts b/packages/react-components/react-badge/library/src/index.ts index a7ebb34ef0c59..0d4ac444d125b 100644 --- a/packages/react-components/react-badge/library/src/index.ts +++ b/packages/react-components/react-badge/library/src/index.ts @@ -1,4 +1,10 @@ -export { Badge, badgeClassNames, renderBadge_unstable, useBadgeStyles_unstable, useBadge_unstable } from './Badge'; +export { + Badge, + badgeClassNames, + renderBadge_unstable, + useBadgeStyles_unstable, + useBadge_unstable, +} from './Badge'; export type { BadgeProps, BadgeSlots, BadgeState } from './Badge'; export { PresenceBadge, @@ -17,11 +23,26 @@ export { presenceOfflineRegular, presenceUnknownRegular, } from './PresenceBadge'; -export type { PresenceBadgeProps, PresenceBadgeState, PresenceBadgeStatus } from './PresenceBadge'; +export type { + PresenceBadgeProps, + PresenceBadgeState, + PresenceBadgeStatus, +} from './PresenceBadge'; export { CounterBadge, counterBadgeClassNames, useCounterBadgeStyles_unstable, useCounterBadge_unstable, } from './CounterBadge'; -export type { CounterBadgeProps, CounterBadgeState } from './CounterBadge'; +export type { + CounterBadgeProps, + CounterBadgeState, +} from './CounterBadge'; + +// Experimental APIs - will be uncommented in the experimental release branch +// export { useBadgeBase_unstable } from './Badge'; +// export type { BadgeBaseProps, BadgeBaseState } from './Badge'; +// export { usePresenceBadgeBase_unstable } from './PresenceBadge'; +// export type { PresenceBadgeBaseProps, PresenceBadgeBaseState } from './PresenceBadge'; +// export { useCounterBadgeBase_unstable } from './CounterBadge'; +// export type { CounterBadgeBaseProps, CounterBadgeBaseState } from './CounterBadge'; From beb6fb457a4b177b9224a09301612a720743cc61 Mon Sep 17 00:00:00 2001 From: Dmytro Kirpa Date: Tue, 3 Mar 2026 11:57:18 +0100 Subject: [PATCH 2/4] change file --- ...i-react-badge-eff39565-e2dd-45e9-93f5-ed2afdd31651.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-react-badge-eff39565-e2dd-45e9-93f5-ed2afdd31651.json diff --git a/change/@fluentui-react-badge-eff39565-e2dd-45e9-93f5-ed2afdd31651.json b/change/@fluentui-react-badge-eff39565-e2dd-45e9-93f5-ed2afdd31651.json new file mode 100644 index 0000000000000..0af378b18fa96 --- /dev/null +++ b/change/@fluentui-react-badge-eff39565-e2dd-45e9-93f5-ed2afdd31651.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add base hooks for Badge", + "packageName": "@fluentui/react-badge", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} From 4f3a0a33388dcb60327224c0efae125b3f8f3535 Mon Sep 17 00:00:00 2001 From: Dmytro Kirpa Date: Thu, 5 Mar 2026 13:16:28 +0100 Subject: [PATCH 3/4] chore: fix lint errors in react-badge base hooks Co-Authored-By: Claude Sonnet 4.6 --- .../react-badge/library/src/components/Badge/useBadge.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts b/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts index 5fbe14ca34e18..e81bc2ce9172c 100644 --- a/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts +++ b/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts @@ -1,3 +1,5 @@ +"use client"; + import * as React from 'react'; import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities'; import type { BadgeBaseProps, BadgeBaseState, BadgeProps, BadgeState } from './Badge.types'; From a998ad3b18228bdfd45d651bdcbe7eca7783a3f0 Mon Sep 17 00:00:00 2001 From: Dmytro Kirpa Date: Thu, 5 Mar 2026 13:27:42 +0100 Subject: [PATCH 4/4] chore: fix formatting and lint in react-badge Co-Authored-By: Claude Sonnet 4.6 --- .../library/etc/react-badge.api.md | 29 ++++++++++++- .../react-badge/library/src/Badge.ts | 3 +- .../react-badge/library/src/CounterBadge.ts | 8 +++- .../react-badge/library/src/PresenceBadge.ts | 9 +++- .../src/components/Badge/Badge.types.ts | 6 +-- .../src/components/Badge/renderBadge.tsx | 4 +- .../library/src/components/Badge/useBadge.ts | 19 +++------ .../CounterBadge/CounterBadge.types.ts | 5 +-- .../CounterBadge/useCounterBadge.ts | 19 ++------- .../PresenceBadge/PresenceBadge.types.ts | 6 +-- .../PresenceBadge/usePresenceBadge.tsx | 41 ++++++------------- .../react-badge/library/src/index.ts | 17 ++++---- 12 files changed, 83 insertions(+), 83 deletions(-) diff --git a/packages/react-components/react-badge/library/etc/react-badge.api.md b/packages/react-components/react-badge/library/etc/react-badge.api.md index cc6b4b8cc3321..a10cbf9a2d43b 100644 --- a/packages/react-components/react-badge/library/etc/react-badge.api.md +++ b/packages/react-components/react-badge/library/etc/react-badge.api.md @@ -15,6 +15,12 @@ import type { SlotClassNames } from '@fluentui/react-utilities'; // @public export const Badge: ForwardRefComponent; +// @public (undocumented) +export type BadgeBaseProps = Omit; + +// @public (undocumented) +export type BadgeBaseState = Omit; + // @public (undocumented) export const badgeClassNames: SlotClassNames; @@ -39,6 +45,12 @@ export type BadgeState = ComponentState & Required; +// @public (undocumented) +export type CounterBadgeBaseProps = Omit; + +// @public (undocumented) +export type CounterBadgeBaseState = Omit; + // @public (undocumented) export const counterBadgeClassNames: SlotClassNames; @@ -71,6 +83,12 @@ export const presenceAwayRegular: Record; +// @public (undocumented) +export type PresenceBadgeBaseProps = Omit; + +// @public (undocumented) +export type PresenceBadgeBaseState = Omit; + // @public (undocumented) export const presenceBadgeClassNames: SlotClassNames; @@ -108,23 +126,32 @@ export const presenceOofRegular: Record; // @public (undocumented) -export const renderBadge_unstable: (state: BadgeState) => JSXElement; +export const renderBadge_unstable: (state: BadgeBaseState) => JSXElement; // @public export const useBadge_unstable: (props: BadgeProps, ref: React_2.Ref) => BadgeState; +// @public +export const useBadgeBase_unstable: (props: BadgeBaseProps, ref: React_2.Ref) => BadgeBaseState; + // @public export const useBadgeStyles_unstable: (state: BadgeState) => BadgeState; // @public export const useCounterBadge_unstable: (props: CounterBadgeProps, ref: React_2.Ref) => CounterBadgeState; +// @public +export const useCounterBadgeBase_unstable: (props: CounterBadgeBaseProps, ref: React_2.Ref) => CounterBadgeBaseState; + // @public export const useCounterBadgeStyles_unstable: (state: CounterBadgeState) => CounterBadgeState; // @public export const usePresenceBadge_unstable: (props: PresenceBadgeProps, ref: React_2.Ref) => PresenceBadgeState; +// @public +export const usePresenceBadgeBase_unstable: (props: PresenceBadgeBaseProps, ref: React_2.Ref) => PresenceBadgeBaseState; + // @public export const usePresenceBadgeStyles_unstable: (state: PresenceBadgeState) => PresenceBadgeState; diff --git a/packages/react-components/react-badge/library/src/Badge.ts b/packages/react-components/react-badge/library/src/Badge.ts index 56de48b1a2b87..9e98c07346146 100644 --- a/packages/react-components/react-badge/library/src/Badge.ts +++ b/packages/react-components/react-badge/library/src/Badge.ts @@ -1,8 +1,9 @@ -export type { BadgeProps, BadgeSlots, BadgeState } from './components/Badge/index'; +export type { BadgeBaseProps, BadgeProps, BadgeSlots, BadgeBaseState, BadgeState } from './components/Badge/index'; export { Badge, badgeClassNames, renderBadge_unstable, useBadgeStyles_unstable, useBadge_unstable, + useBadgeBase_unstable, } from './components/Badge/index'; diff --git a/packages/react-components/react-badge/library/src/CounterBadge.ts b/packages/react-components/react-badge/library/src/CounterBadge.ts index 7fad9f1447d63..612489b253c0e 100644 --- a/packages/react-components/react-badge/library/src/CounterBadge.ts +++ b/packages/react-components/react-badge/library/src/CounterBadge.ts @@ -1,7 +1,13 @@ -export type { CounterBadgeProps, CounterBadgeState } from './components/CounterBadge/index'; +export type { + CounterBadgeProps, + CounterBadgeState, + CounterBadgeBaseProps, + CounterBadgeBaseState, +} from './components/CounterBadge/index'; export { CounterBadge, counterBadgeClassNames, useCounterBadgeStyles_unstable, useCounterBadge_unstable, + useCounterBadgeBase_unstable, } from './components/CounterBadge/index'; diff --git a/packages/react-components/react-badge/library/src/PresenceBadge.ts b/packages/react-components/react-badge/library/src/PresenceBadge.ts index 84d192cfde495..1a35068413ace 100644 --- a/packages/react-components/react-badge/library/src/PresenceBadge.ts +++ b/packages/react-components/react-badge/library/src/PresenceBadge.ts @@ -1,4 +1,10 @@ -export type { PresenceBadgeProps, PresenceBadgeState, PresenceBadgeStatus } from './components/PresenceBadge/index'; +export type { + PresenceBadgeProps, + PresenceBadgeState, + PresenceBadgeStatus, + PresenceBadgeBaseProps, + PresenceBadgeBaseState, +} from './components/PresenceBadge/index'; export { PresenceBadge, presenceAvailableFilled, @@ -15,4 +21,5 @@ export { presenceUnknownRegular, usePresenceBadgeStyles_unstable, usePresenceBadge_unstable, + usePresenceBadgeBase_unstable, } from './components/PresenceBadge/index'; diff --git a/packages/react-components/react-badge/library/src/components/Badge/Badge.types.ts b/packages/react-components/react-badge/library/src/components/Badge/Badge.types.ts index 483f689ae5a9b..6cb555497ad5e 100644 --- a/packages/react-components/react-badge/library/src/components/Badge/Badge.types.ts +++ b/packages/react-components/react-badge/library/src/components/Badge/Badge.types.ts @@ -1,4 +1,4 @@ -import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities'; +import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; export type BadgeSlots = { root: Slot<'div'>; @@ -42,6 +42,6 @@ export type BadgeProps = Omit, 'color'> & { export type BadgeState = ComponentState & Required>; -export type BadgeBaseProps = DistributiveOmit; +export type BadgeBaseProps = Omit; -export type BadgeBaseState = DistributiveOmit; +export type BadgeBaseState = Omit; diff --git a/packages/react-components/react-badge/library/src/components/Badge/renderBadge.tsx b/packages/react-components/react-badge/library/src/components/Badge/renderBadge.tsx index f19feddefa98f..9f4a5b077b892 100644 --- a/packages/react-components/react-badge/library/src/components/Badge/renderBadge.tsx +++ b/packages/react-components/react-badge/library/src/components/Badge/renderBadge.tsx @@ -4,9 +4,9 @@ import { assertSlots } from '@fluentui/react-utilities'; import type { JSXElement } from '@fluentui/react-utilities'; -import type { BadgeState, BadgeSlots } from './Badge.types'; +import type { BadgeBaseState, BadgeSlots } from './Badge.types'; -export const renderBadge_unstable = (state: BadgeState): JSXElement => { +export const renderBadge_unstable = (state: BadgeBaseState): JSXElement => { assertSlots(state); return ( diff --git a/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts b/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts index e81bc2ce9172c..53727729a233b 100644 --- a/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts +++ b/packages/react-components/react-badge/library/src/components/Badge/useBadge.ts @@ -1,4 +1,4 @@ -"use client"; +'use client'; import * as React from 'react'; import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities'; @@ -8,15 +8,9 @@ import type { BadgeBaseProps, BadgeBaseState, BadgeProps, BadgeState } from './B * Returns the props and state required to render the component */ export const useBadge_unstable = (props: BadgeProps, ref: React.Ref): BadgeState => { - const { - shape = 'circular', - size = 'medium', - appearance = 'filled', - color = 'brand', - ...badgeProps - } = props; + const { shape = 'circular', size = 'medium', appearance = 'filled', color = 'brand', ...badgeProps } = props; - const state = useBadgeBase_unstable(badgeProps, ref); + const state = useBadgeBase_unstable(badgeProps, ref as React.Ref); return { ...state, @@ -33,7 +27,7 @@ export const useBadge_unstable = (props: BadgeProps, ref: React.Ref * @param props - User provided props to the Badge component. * @param ref - User provided ref to be passed to the Badge component. */ -export const useBadgeBase_unstable = (props: BadgeBaseProps, ref: React.Ref): BadgeBaseState => { +export const useBadgeBase_unstable = (props: BadgeBaseProps, ref: React.Ref): BadgeBaseState => { const { iconPosition = 'before' } = props; return { @@ -44,10 +38,7 @@ export const useBadgeBase_unstable = (props: BadgeBaseProps, ref: React.Ref, + ref, ...props, }), { elementType: 'div' }, diff --git a/packages/react-components/react-badge/library/src/components/CounterBadge/CounterBadge.types.ts b/packages/react-components/react-badge/library/src/components/CounterBadge/CounterBadge.types.ts index 18d7b8702b68f..f3b64187b30bd 100644 --- a/packages/react-components/react-badge/library/src/components/CounterBadge/CounterBadge.types.ts +++ b/packages/react-components/react-badge/library/src/components/CounterBadge/CounterBadge.types.ts @@ -1,4 +1,3 @@ -import type { DistributiveOmit } from '@fluentui/react-utilities'; import type { BadgeProps, BadgeState } from '../Badge/index'; export type CounterBadgeProps = Omit & { @@ -51,6 +50,6 @@ export type CounterBadgeProps = Omit & Required>; -export type CounterBadgeBaseProps = DistributiveOmit; +export type CounterBadgeBaseProps = Omit; -export type CounterBadgeBaseState = DistributiveOmit; +export type CounterBadgeBaseState = Omit; diff --git a/packages/react-components/react-badge/library/src/components/CounterBadge/useCounterBadge.ts b/packages/react-components/react-badge/library/src/components/CounterBadge/useCounterBadge.ts index fcba1d5cd489f..bd2dc2180ed14 100644 --- a/packages/react-components/react-badge/library/src/components/CounterBadge/useCounterBadge.ts +++ b/packages/react-components/react-badge/library/src/components/CounterBadge/useCounterBadge.ts @@ -1,7 +1,6 @@ 'use client'; import * as React from 'react'; -import type { BadgeState } from '../Badge/index'; import { useBadgeBase_unstable } from '../Badge/index'; import type { CounterBadgeBaseProps, @@ -14,13 +13,7 @@ import type { * Returns the props and state required to render the component */ export const useCounterBadge_unstable = (props: CounterBadgeProps, ref: React.Ref): CounterBadgeState => { - const { - shape = 'circular', - appearance = 'filled', - color = 'brand', - size = 'medium', - ...counterBadgeProps - } = props; + const { shape = 'circular', appearance = 'filled', color = 'brand', size = 'medium', ...counterBadgeProps } = props; const state = useCounterBadgeBase_unstable(counterBadgeProps, ref); @@ -43,16 +36,10 @@ export const useCounterBadgeBase_unstable = ( props: CounterBadgeBaseProps, ref: React.Ref, ): CounterBadgeBaseState => { - const { - showZero = false, - overflowCount = 99, - count = 0, - dot = false, - ...badgeProps - } = props; + const { showZero = false, overflowCount = 99, count = 0, dot = false, ...badgeProps } = props; const state: CounterBadgeBaseState = { - ...(useBadgeBase_unstable(badgeProps, ref) as Pick>), + ...useBadgeBase_unstable(badgeProps, ref as React.Ref), showZero, count, dot, diff --git a/packages/react-components/react-badge/library/src/components/PresenceBadge/PresenceBadge.types.ts b/packages/react-components/react-badge/library/src/components/PresenceBadge/PresenceBadge.types.ts index 1fb6a821497ca..501d0a9064d00 100644 --- a/packages/react-components/react-badge/library/src/components/PresenceBadge/PresenceBadge.types.ts +++ b/packages/react-components/react-badge/library/src/components/PresenceBadge/PresenceBadge.types.ts @@ -1,4 +1,4 @@ -import type { ComponentProps, ComponentState, DistributiveOmit } from '@fluentui/react-utilities'; +import type { ComponentProps, ComponentState } from '@fluentui/react-utilities'; import type { BadgeProps, BadgeState, BadgeSlots } from '../Badge/Badge.types'; export type PresenceBadgeStatus = @@ -31,6 +31,6 @@ export type PresenceBadgeState = ComponentState & BadgeState & Required>; -export type PresenceBadgeBaseProps = DistributiveOmit; +export type PresenceBadgeBaseProps = Omit; -export type PresenceBadgeBaseState = DistributiveOmit; +export type PresenceBadgeBaseState = Omit; diff --git a/packages/react-components/react-badge/library/src/components/PresenceBadge/usePresenceBadge.tsx b/packages/react-components/react-badge/library/src/components/PresenceBadge/usePresenceBadge.tsx index 9769552679f43..60e27cef7b3b3 100644 --- a/packages/react-components/react-badge/library/src/components/PresenceBadge/usePresenceBadge.tsx +++ b/packages/react-components/react-badge/library/src/components/PresenceBadge/usePresenceBadge.tsx @@ -14,7 +14,7 @@ import { presenceOofRegular, presenceUnknownRegular, } from './presenceIcons'; -import { useBadge_unstable, useBadgeBase_unstable } from '../Badge/index'; +import { useBadgeBase_unstable } from '../Badge/index'; import type { PresenceBadgeBaseProps, PresenceBadgeBaseState, @@ -61,34 +61,24 @@ export const usePresenceBadge_unstable = ( props: PresenceBadgeProps, ref: React.Ref, ): PresenceBadgeState => { - const { size = 'medium', status = 'available', outOfOffice = false } = props; - - const statusText = DEFAULT_STRINGS[status]; - const oofText = props.outOfOffice && props.status !== 'out-of-office' ? ` ${DEFAULT_STRINGS['out-of-office']}` : ''; + const { size = 'medium', status = 'available', outOfOffice = false, ...baseProps } = props; const IconElement = iconMap(status, outOfOffice, size); const state: PresenceBadgeState = { - ...useBadge_unstable( - { - 'aria-label': statusText + oofText, - role: 'img', - ...props, - size, - icon: slot.optional(props.icon, { - defaultProps: { - children: IconElement ? : null, - }, - renderByDefault: true, - elementType: 'span', - }), - }, - ref, - ), + ...usePresenceBadgeBase_unstable(baseProps, ref), + appearance: 'filled', + color: 'brand', + shape: 'circular', + size, status, outOfOffice, }; + if (state.icon) { + state.icon.children ??= ; + } + return state; }; @@ -109,10 +99,6 @@ export const usePresenceBadgeBase_unstable = ( const statusText = DEFAULT_STRINGS[status]; const oofText = props.outOfOffice && props.status !== 'out-of-office' ? ` ${DEFAULT_STRINGS['out-of-office']}` : ''; - // Default to 'medium' size for icon selection when no size design prop is available - const iconSize = 'medium'; - const IconElement = iconMap(status, outOfOffice, iconSize); - const state: PresenceBadgeBaseState = { ...useBadgeBase_unstable( { @@ -120,14 +106,11 @@ export const usePresenceBadgeBase_unstable = ( role: 'img', ...props, icon: slot.optional(props.icon, { - defaultProps: { - children: IconElement ? : null, - }, renderByDefault: true, elementType: 'span', }), }, - ref, + ref as React.Ref, ), status, outOfOffice, diff --git a/packages/react-components/react-badge/library/src/index.ts b/packages/react-components/react-badge/library/src/index.ts index 0d4ac444d125b..58c118a9f8d7f 100644 --- a/packages/react-components/react-badge/library/src/index.ts +++ b/packages/react-components/react-badge/library/src/index.ts @@ -4,13 +4,15 @@ export { renderBadge_unstable, useBadgeStyles_unstable, useBadge_unstable, + useBadgeBase_unstable, } from './Badge'; -export type { BadgeProps, BadgeSlots, BadgeState } from './Badge'; +export type { BadgeProps, BadgeSlots, BadgeState, BadgeBaseProps, BadgeBaseState } from './Badge'; export { PresenceBadge, presenceBadgeClassNames, usePresenceBadgeStyles_unstable, usePresenceBadge_unstable, + usePresenceBadgeBase_unstable, presenceAwayRegular, presenceAwayFilled, presenceAvailableRegular, @@ -27,22 +29,19 @@ export type { PresenceBadgeProps, PresenceBadgeState, PresenceBadgeStatus, + PresenceBadgeBaseProps, + PresenceBadgeBaseState, } from './PresenceBadge'; export { CounterBadge, counterBadgeClassNames, useCounterBadgeStyles_unstable, useCounterBadge_unstable, + useCounterBadgeBase_unstable, } from './CounterBadge'; export type { CounterBadgeProps, CounterBadgeState, + CounterBadgeBaseProps, + CounterBadgeBaseState, } from './CounterBadge'; - -// Experimental APIs - will be uncommented in the experimental release branch -// export { useBadgeBase_unstable } from './Badge'; -// export type { BadgeBaseProps, BadgeBaseState } from './Badge'; -// export { usePresenceBadgeBase_unstable } from './PresenceBadge'; -// export type { PresenceBadgeBaseProps, PresenceBadgeBaseState } from './PresenceBadge'; -// export { useCounterBadgeBase_unstable } from './CounterBadge'; -// export type { CounterBadgeBaseProps, CounterBadgeBaseState } from './CounterBadge';