diff --git a/change/@fluentui-react-spinbutton-f8f2fa27-5ed8-4c63-bdce-802fafb5946c.json b/change/@fluentui-react-spinbutton-f8f2fa27-5ed8-4c63-bdce-802fafb5946c.json new file mode 100644 index 0000000000000..3c389e916ff0b --- /dev/null +++ b/change/@fluentui-react-spinbutton-f8f2fa27-5ed8-4c63-bdce-802fafb5946c.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat(react-spinbutton): add useSpinButtonBase_unstable hook", + "packageName": "@fluentui/react-spinbutton", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-spinbutton/library/etc/react-spinbutton.api.md b/packages/react-components/react-spinbutton/library/etc/react-spinbutton.api.md index 28f6a67473675..d528da198b5a1 100644 --- a/packages/react-components/react-spinbutton/library/etc/react-spinbutton.api.md +++ b/packages/react-components/react-spinbutton/library/etc/react-spinbutton.api.md @@ -6,6 +6,7 @@ import type { ComponentProps } from '@fluentui/react-utilities'; import type { ComponentState } from '@fluentui/react-utilities'; +import type { DistributiveOmit } from '@fluentui/react-utilities'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; import type { JSXElement } from '@fluentui/react-utilities'; import * as React_2 from 'react'; @@ -13,11 +14,17 @@ import type { Slot } from '@fluentui/react-utilities'; import { SlotClassNames } from '@fluentui/react-utilities'; // @public -export const renderSpinButton_unstable: (state: SpinButtonState) => JSXElement; +export const renderSpinButton_unstable: (state: SpinButtonBaseState) => JSXElement; // @public export const SpinButton: ForwardRefComponent; +// @public (undocumented) +export type SpinButtonBaseProps = DistributiveOmit; + +// @public (undocumented) +export type SpinButtonBaseState = DistributiveOmit; + // @public (undocumented) export type SpinButtonBounds = 'none' | 'min' | 'max' | 'both'; @@ -68,6 +75,9 @@ export type SpinButtonState = ComponentState & Required) => SpinButtonState; +// @public +export const useSpinButtonBase_unstable: (props: SpinButtonBaseProps, ref: React_2.Ref) => SpinButtonBaseState; + // @public export const useSpinButtonStyles_unstable: (state: SpinButtonState) => SpinButtonState; diff --git a/packages/react-components/react-spinbutton/library/src/SpinButton.ts b/packages/react-components/react-spinbutton/library/src/SpinButton.ts index 2740bab85fc2d..3888f45d96638 100644 --- a/packages/react-components/react-spinbutton/library/src/SpinButton.ts +++ b/packages/react-components/react-spinbutton/library/src/SpinButton.ts @@ -1,4 +1,6 @@ export type { + SpinButtonBaseProps, + SpinButtonBaseState, SpinButtonBounds, SpinButtonChangeEvent, SpinButtonOnChangeData, @@ -12,5 +14,6 @@ export { renderSpinButton_unstable, spinButtonClassNames, useSpinButtonStyles_unstable, + useSpinButtonBase_unstable, useSpinButton_unstable, } from './components/SpinButton/index'; diff --git a/packages/react-components/react-spinbutton/library/src/components/SpinButton/SpinButton.types.ts b/packages/react-components/react-spinbutton/library/src/components/SpinButton/SpinButton.types.ts index 7f48f7835dba8..b33aeb670b007 100644 --- a/packages/react-components/react-spinbutton/library/src/components/SpinButton/SpinButton.types.ts +++ b/packages/react-components/react-spinbutton/library/src/components/SpinButton/SpinButton.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'; import * as React from 'react'; export type SpinButtonSlots = { @@ -157,3 +157,6 @@ export type SpinButtonOnChangeData = { export type SpinButtonSpinState = 'rest' | 'up' | 'down'; export type SpinButtonBounds = 'none' | 'min' | 'max' | 'both'; + +export type SpinButtonBaseProps = DistributiveOmit; +export type SpinButtonBaseState = DistributiveOmit; diff --git a/packages/react-components/react-spinbutton/library/src/components/SpinButton/index.ts b/packages/react-components/react-spinbutton/library/src/components/SpinButton/index.ts index 38cab436c1b28..676191994313b 100644 --- a/packages/react-components/react-spinbutton/library/src/components/SpinButton/index.ts +++ b/packages/react-components/react-spinbutton/library/src/components/SpinButton/index.ts @@ -1,5 +1,7 @@ export { SpinButton } from './SpinButton'; export type { + SpinButtonBaseProps, + SpinButtonBaseState, SpinButtonBounds, SpinButtonChangeEvent, SpinButtonOnChangeData, @@ -9,5 +11,5 @@ export type { SpinButtonState, } from './SpinButton.types'; export { renderSpinButton_unstable } from './renderSpinButton'; -export { useSpinButton_unstable } from './useSpinButton'; +export { useSpinButtonBase_unstable, useSpinButton_unstable } from './useSpinButton'; export { spinButtonClassNames, useSpinButtonStyles_unstable } from './useSpinButtonStyles.styles'; diff --git a/packages/react-components/react-spinbutton/library/src/components/SpinButton/renderSpinButton.tsx b/packages/react-components/react-spinbutton/library/src/components/SpinButton/renderSpinButton.tsx index 4cac6735bbd98..734982287319c 100644 --- a/packages/react-components/react-spinbutton/library/src/components/SpinButton/renderSpinButton.tsx +++ b/packages/react-components/react-spinbutton/library/src/components/SpinButton/renderSpinButton.tsx @@ -3,12 +3,12 @@ import { assertSlots } from '@fluentui/react-utilities'; import type { JSXElement } from '@fluentui/react-utilities'; -import type { SpinButtonState, SpinButtonSlots } from './SpinButton.types'; +import type { SpinButtonBaseState, SpinButtonSlots } from './SpinButton.types'; /** * Render the final JSX of SpinButton */ -export const renderSpinButton_unstable = (state: SpinButtonState): JSXElement => { +export const renderSpinButton_unstable = (state: SpinButtonBaseState): JSXElement => { assertSlots(state); return ( diff --git a/packages/react-components/react-spinbutton/library/src/components/SpinButton/useSpinButton.tsx b/packages/react-components/react-spinbutton/library/src/components/SpinButton/useSpinButton.tsx index 13235927900a0..0e6e30fb8407c 100644 --- a/packages/react-components/react-spinbutton/library/src/components/SpinButton/useSpinButton.tsx +++ b/packages/react-components/react-spinbutton/library/src/components/SpinButton/useSpinButton.tsx @@ -12,6 +12,8 @@ import { } from '@fluentui/react-utilities'; import { ArrowUp, ArrowDown, End, Enter, Escape, Home, PageDown, PageUp } from '@fluentui/keyboard-keys'; import { + SpinButtonBaseProps, + SpinButtonBaseState, SpinButtonProps, SpinButtonState, SpinButtonSpinState, @@ -41,26 +43,21 @@ const MAX_SPIN_TIME_MS = 1000; const lerp = (start: number, end: number, percent: number): number => start + (end - start) * percent; /** - * Create the state required to render SpinButton. - * - * The returned state can be modified with hooks such as useSpinButtonStyles_unstable, - * before being passed to renderSpinButton_unstable. + * Create the base state required to render SpinButton without design-specific props. * - * @param props - props from this instance of SpinButton + * @param props - props from this instance of SpinButton (without appearance/size) * @param ref - reference to root HTMLElement of SpinButton */ -export const useSpinButton_unstable = (props: SpinButtonProps, ref: React.Ref): SpinButtonState => { - // Merge props from surrounding , if any - props = useFieldControlProps_unstable(props, { supportsLabelFor: true, supportsRequired: true }); - +export const useSpinButtonBase_unstable = ( + props: SpinButtonBaseProps, + ref: React.Ref, +): SpinButtonBaseState => { const nativeProps = getPartitionedNativeProps({ props, primarySlotTagName: 'input', - excludedPropNames: ['defaultValue', 'max', 'min', 'onChange', 'size', 'value'], + excludedPropNames: ['defaultValue', 'max', 'min', 'onChange', 'value'], }); - const overrides = useOverrides(); - const { value, displayValue, @@ -71,8 +68,6 @@ export const useSpinButton_unstable = (props: SpinButtonProps, ref: React.Ref, disabled: nativeProps.primary.readOnly || nativeProps.primary.disabled || @@ -324,7 +316,6 @@ export const useSpinButton_unstable = (props: SpinButtonProps, ref: React.Ref, disabled: nativeProps.primary.readOnly || nativeProps.primary.disabled || @@ -359,3 +350,28 @@ export const useSpinButton_unstable = (props: SpinButtonProps, ref: React.Ref): SpinButtonState => { + // Merge props from surrounding , if any + props = useFieldControlProps_unstable(props, { supportsLabelFor: true, supportsRequired: true }); + + const overrides = useOverrides(); + + const { appearance = overrides.inputDefaultAppearance ?? 'outline', size = 'medium', ...baseProps } = props; + + const state = useSpinButtonBase_unstable(baseProps, ref); + + state.incrementButton.children ??= ; + state.decrementButton.children ??= ; + + return { ...state, appearance, size }; +}; diff --git a/packages/react-components/react-spinbutton/library/src/index.ts b/packages/react-components/react-spinbutton/library/src/index.ts index 3f33ebd3d253b..7dd32276de261 100644 --- a/packages/react-components/react-spinbutton/library/src/index.ts +++ b/packages/react-components/react-spinbutton/library/src/index.ts @@ -3,9 +3,12 @@ export { renderSpinButton_unstable, spinButtonClassNames, useSpinButtonStyles_unstable, + useSpinButtonBase_unstable, useSpinButton_unstable, } from './SpinButton'; export type { + SpinButtonBaseProps, + SpinButtonBaseState, SpinButtonOnChangeData, SpinButtonChangeEvent, SpinButtonProps,