Skip to content

Commit

Permalink
Carousel: Separate draggable area from controls (#33155)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mitch-At-Work authored Nov 1, 2024
1 parent 49e6794 commit 69dc72a
Show file tree
Hide file tree
Showing 46 changed files with 544 additions and 196 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: Add CarouselViewport to correctly define CarouselSlider within a static container",
"packageName": "@fluentui/react-carousel",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: Add CarouselViewport and deprecate CarouselSlider",
"packageName": "@fluentui/react-components",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: Add Carousel CustomStyleHook definitions",
"packageName": "@fluentui/react-provider",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: Add custom style hooks for Carousel components",
"packageName": "@fluentui/react-shared-contexts",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export type CarouselContextValue = {
enableAutoplay: (autoplay: boolean) => void;
resetAutoplay: () => void;
containerRef?: React_2.RefObject<HTMLDivElement>;
viewportRef?: React_2.RefObject<HTMLDivElement>;
};

// @public
Expand Down Expand Up @@ -246,6 +247,23 @@ export type CarouselSlots = {
// @public
export type CarouselState = ComponentState<CarouselSlots> & CarouselContextValue;

// @public
export const CarouselViewport: ForwardRefComponent<CarouselViewportProps>;

// @public (undocumented)
export const carouselViewportClassNames: SlotClassNames<CarouselViewportSlots>;

// @public
export type CarouselViewportProps = ComponentProps<CarouselViewportSlots>;

// @public (undocumented)
export type CarouselViewportSlots = {
root: Slot<'div'>;
};

// @public
export type CarouselViewportState = ComponentState<Required<CarouselViewportSlots>> & CarouselSliderContextValue;

// @public (undocumented)
export type NavButtonRenderFunction = (index: number) => React_2.ReactNode;

Expand Down Expand Up @@ -276,6 +294,9 @@ export const renderCarouselNavImageButton_unstable: (state: CarouselNavImageButt
// @public
export const renderCarouselSlider_unstable: (state: CarouselSliderState, contextValues: CarouselSliderContextValues) => JSX.Element;

// @public
export const renderCarouselViewport_unstable: (state: CarouselViewportState, contextValues: CarouselSliderContextValues) => JSX.Element;

// @public
export function useCarousel_unstable(props: CarouselProps, ref: React_2.Ref<HTMLDivElement>): CarouselState;

Expand Down Expand Up @@ -333,6 +354,12 @@ export const useCarouselSliderStyles_unstable: (state: CarouselSliderState) => C
// @public
export const useCarouselStyles_unstable: (state: CarouselState) => CarouselState;

// @public
export const useCarouselViewport_unstable: (props: CarouselViewportProps, ref: React_2.Ref<HTMLDivElement>) => CarouselViewportState;

// @public
export const useCarouselViewportStyles_unstable: (state: CarouselViewportState) => CarouselViewportState;

// (No @packageDocumentation comment for this package)

```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/CarouselViewport/index';
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { renderCarousel_unstable } from './renderCarousel';
import { useCarouselStyles_unstable } from './useCarouselStyles.styles';
import type { CarouselProps } from './Carousel.types';
import { useCarouselContextValues_unstable } from './useCarouselContextValues';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';

/**
* Carousel is the context wrapper and container for all carousel content/controls,
Expand All @@ -16,11 +17,10 @@ export const Carousel: ForwardRefComponent<CarouselProps> = React.forwardRef((pr
const state = useCarousel_unstable(props, ref);

useCarouselStyles_unstable(state);
useCustomStyleHook_unstable('useCarouselStyles_unstable')(state);

const contextValues = useCarouselContextValues_unstable(state);
// TODO update types in packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts
// https://github.com/microsoft/fluentui/blob/master/rfcs/react-components/convergence/custom-styling.md
// useCustomStyleHook_unstable('useCarouselStyles_unstable')(state);

return renderCarousel_unstable(state, contextValues);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function useCarousel_unstable(props: CarouselProps, ref: React.Ref<HTMLDi
} = props;

const { dir } = useFluent();
const { activeIndex, carouselApi, containerRef, subscribeForValues, enableAutoplay, resetAutoplay } =
const { activeIndex, carouselApi, containerRef, viewportRef, subscribeForValues, enableAutoplay, resetAutoplay } =
useEmblaCarousel({
align,
direction: dir,
Expand Down Expand Up @@ -71,7 +71,7 @@ export function useCarousel_unstable(props: CarouselProps, ref: React.Ref<HTMLDi
return nextPageIndex;
});

const mergedRefs = useMergedRefs(ref, containerRef);
const mergedContainerRef = useMergedRefs(ref, containerRef);

// Announce carousel updates
const announcementTextRef = React.useRef<string>('');
Expand Down Expand Up @@ -118,7 +118,7 @@ export function useCarousel_unstable(props: CarouselProps, ref: React.Ref<HTMLDi
},
root: slot.always(
getIntrinsicElementProps('div', {
ref: mergedRefs,
ref: mergedContainerRef,
role: 'region',
...props,
}),
Expand All @@ -127,7 +127,8 @@ export function useCarousel_unstable(props: CarouselProps, ref: React.Ref<HTMLDi

activeIndex,
circular,
containerRef: mergedRefs,
containerRef: mergedContainerRef,
viewportRef,
selectPageByElement,
selectPageByDirection,
selectPageByIndex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function useCarouselContextValues_unstable(state: CarouselState): Carouse
resetAutoplay,
circular,
containerRef,
viewportRef,
} = state;

const carousel = React.useMemo(
Expand All @@ -27,6 +28,7 @@ export function useCarouselContextValues_unstable(state: CarouselState): Carouse
resetAutoplay,
circular,
containerRef,
viewportRef,
}),
[
activeIndex,
Expand All @@ -38,6 +40,7 @@ export function useCarouselContextValues_unstable(state: CarouselState): Carouse
resetAutoplay,
circular,
containerRef,
viewportRef,
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { makeStyles, mergeClasses } from '@griffel/react';
import type { SlotClassNames } from '@fluentui/react-utilities';

import type { CarouselSlots, CarouselState } from './Carousel.types';
import { tokens } from '@fluentui/react-theme';

export const carouselClassNames: SlotClassNames<CarouselSlots> = {
root: 'fui-Carousel',
Expand All @@ -13,8 +12,8 @@ export const carouselClassNames: SlotClassNames<CarouselSlots> = {
*/
const useStyles = makeStyles({
root: {
paddingTop: tokens.strokeWidthThick, // Leave room for focus border & overflow hidden
overflow: 'hidden',
// Only hide horizontal overflow to enable focus border to bleed bounds vertically
overflowX: 'hidden',
overflowAnchor: 'none',
position: 'relative',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useCarouselAutoplayButton_unstable } from './useCarouselAutoplayButton'
import { renderCarouselAutoplayButton_unstable } from './renderCarouselAutoplayButton';
import { useCarouselAutoplayButtonStyles_unstable } from './useCarouselAutoplayButtonStyles.styles';
import type { CarouselAutoplayButtonProps } from './CarouselAutoplayButton.types';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';

/**
* If the Carousel is on auto-play, the user may opt into pausing the auto-play feature via the
Expand All @@ -16,9 +17,8 @@ export const CarouselAutoplayButton: ForwardRefComponent<CarouselAutoplayButtonP
const state = useCarouselAutoplayButton_unstable(props, ref);

useCarouselAutoplayButtonStyles_unstable(state);
// TODO update types in packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts
// https://github.com/microsoft/fluentui/blob/master/rfcs/react-components/convergence/custom-styling.md
// useCustomStyleHook_unstable('useCarouselAutoplayButtonStyles_unstable')(state);
useCustomStyleHook_unstable('useCarouselAutoplayButtonStyles_unstable')(state);

return renderCarouselAutoplayButton_unstable(state);
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useCarouselButton_unstable } from './useCarouselButton';
import { renderCarouselButton_unstable } from './renderCarouselButton';
import { useCarouselButtonStyles_unstable } from './useCarouselButtonStyles.styles';
import type { CarouselButtonProps } from './CarouselButton.types';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';

/**
* A default navigation button that will set value to the next/previous page,
Expand All @@ -13,9 +14,7 @@ export const CarouselButton: ForwardRefComponent<CarouselButtonProps> = React.fo
const state = useCarouselButton_unstable(props, ref);

useCarouselButtonStyles_unstable(state);
// TODO update types in packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts
// https://github.com/microsoft/fluentui/blob/master/rfcs/react-components/convergence/custom-styling.md
// useCustomStyleHook_unstable('useCarouselButtonStyles_unstable')(state);
useCustomStyleHook_unstable('useCarouselButtonStyles_unstable')(state);

return renderCarouselButton_unstable(state);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useCarouselCard_unstable } from './useCarouselCard';
import { renderCarouselCard_unstable } from './renderCarouselCard';
import { useCarouselCardStyles_unstable } from './useCarouselCardStyles.styles';
import type { CarouselCardProps } from './CarouselCard.types';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';

/**
* The defining wrapper of a carousel's indexed content, they will take up the full
Expand All @@ -17,9 +18,8 @@ export const CarouselCard: ForwardRefComponent<CarouselCardProps> = React.forwar
const state = useCarouselCard_unstable(props, ref);

useCarouselCardStyles_unstable(state);
// TODO update types in packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts
// https://github.com/microsoft/fluentui/blob/master/rfcs/react-components/convergence/custom-styling.md
// useCustomStyleHook_unstable('useCarouselCardStyles_unstable')(state);
useCustomStyleHook_unstable('useCarouselCardStyles_unstable')(state);

return renderCarouselCard_unstable(state);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const useCarouselCard_unstable = (
}
}, [cardFocus]);

const handleFocusCapture = React.useCallback(
const handleFocus = React.useCallback(
(e: React.FocusEvent) => {
if (!e.defaultPrevented && isHTMLElement(e.currentTarget) && !isMouseEvent.current) {
// We want to prevent any browser scroll intervention for 'offscreen' focus
Expand All @@ -88,7 +88,7 @@ export const useCarouselCard_unstable = (
}
};

const onFocusCapture = mergeCallbacks(props.onFocusCapture, handleFocusCapture);
const onFocus = mergeCallbacks(props.onFocus, handleFocus);
const onMouseUp = mergeCallbacks(props.onMouseUp, handleMouseUp);
const onMouseDown = mergeCallbacks(props.onMouseDown, handleMouseDown);
const state: CarouselCardState = {
Expand All @@ -103,7 +103,7 @@ export const useCarouselCard_unstable = (
tabIndex: cardFocus ? 0 : undefined,
...props,
id,
onFocusCapture,
onFocus,
onMouseDown,
onMouseUp,
...focusAttrProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const carouselContextDefaultValue: CarouselContextValue = {
},
circular: false,
containerRef: undefined,
viewportRef: undefined,
};

const CarouselContext = createContext<CarouselContextValue | undefined>(undefined);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ export type CarouselContextValue = {
subscribeForValues: (listener: (data: CarouselUpdateData) => void) => () => void;
enableAutoplay: (autoplay: boolean) => void;
resetAutoplay: () => void;
// Container with controls passed to carousel engine
containerRef?: React.RefObject<HTMLDivElement>;
// Viewport without controls used for interactive functionality (draggable, pause autoplay etc.)
viewportRef?: React.RefObject<HTMLDivElement>;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useCarouselNavContextValues_unstable } from './CarouselNavContext';
import { renderCarouselNav_unstable } from './renderCarouselNav';
import { useCarouselNav_unstable } from './useCarouselNav';
import { useCarouselNavStyles_unstable } from './useCarouselNavStyles.styles';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';

/**
* Used to jump to a card based on index, using arrow navigation via Tabster.
Expand All @@ -18,9 +19,7 @@ export const CarouselNav: ForwardRefComponent<CarouselNavProps> = React.forwardR
const contextValues = useCarouselNavContextValues_unstable(state);

useCarouselNavStyles_unstable(state);
// TODO update types in packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts
// https://github.com/microsoft/fluentui/blob/master/rfcs/react-components/convergence/custom-styling.md
// useCustomStyleHook_unstable('useCarouselNavStyles_unstable')(state);
useCustomStyleHook_unstable('useCarouselNavStyles_unstable')(state);

return renderCarouselNav_unstable(state, contextValues);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useCarouselNavButton_unstable } from './useCarouselNavButton';
import { renderCarouselNavButton_unstable } from './renderCarouselNavButton';
import { useCarouselNavButtonStyles_unstable } from './useCarouselNavButtonStyles.styles';
import type { CarouselNavButtonProps } from './CarouselNavButton.types';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';

/**
* The child element of CarouselNav, a singular button that will set the carousels active value on click.
Expand All @@ -12,9 +13,8 @@ export const CarouselNavButton: ForwardRefComponent<CarouselNavButtonProps> = Re
const state = useCarouselNavButton_unstable(props, ref);

useCarouselNavButtonStyles_unstable(state);
// TODO update types in packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts
// https://github.com/microsoft/fluentui/blob/master/rfcs/react-components/convergence/custom-styling.md
// useCustomStyleHook_unstable('useCarouselNavButtonStyles_unstable')(state);
useCustomStyleHook_unstable('useCarouselNavButtonStyles_unstable')(state);

return renderCarouselNavButton_unstable(state);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useCarouselNavContainer_unstable } from './useCarouselNavContainer';
import { renderCarouselNavContainer_unstable } from './renderCarouselNavContainer';
import { useCarouselNavContainerStyles_unstable } from './useCarouselNavContainerStyles.styles';
import type { CarouselNavContainerProps } from './CarouselNavContainer.types';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';

/**
* CarouselNavContainer component - This container will provide multiple valid layout options for the underlying carousel controls
Expand All @@ -12,16 +13,7 @@ export const CarouselNavContainer: ForwardRefComponent<CarouselNavContainerProps
const state = useCarouselNavContainer_unstable(props, ref);

useCarouselNavContainerStyles_unstable(state);

/**
* @see https://github.com/microsoft/fluentui/blob/master/docs/react-v9/contributing/rfcs/react-components/convergence/custom-styling.md
*
* TODO: 💡 once package will become stable (PR which will be part of promoting PREVIEW package to STABLE),
* - uncomment this line
* - update types {@link file://./../../../../../../../packages/react-components/react-shared-contexts/library/src/CustomStyleHooksContext/CustomStyleHooksContext.ts#CustomStyleHooksContextValue}
* - verify that custom global style override works for your component
*/
// useCustomStyleHook_unstable('useCarouselNavContainerStyles_unstable')(state);
useCustomStyleHook_unstable('useCarouselNavContainerStyles_unstable')(state);

return renderCarouselNavContainer_unstable(state);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useCarouselNavImageButton_unstable } from './useCarouselNavImageButton'
import { renderCarouselNavImageButton_unstable } from './renderCarouselNavImageButton';
import { useCarouselNavImageButtonStyles_unstable } from './useCarouselNavImageButtonStyles.styles';
import type { CarouselNavImageButtonProps } from './CarouselNavImageButton.types';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';

/**
* A variant child element of CarouselNav, a singular image button that displays a
Expand All @@ -14,9 +15,8 @@ export const CarouselNavImageButton: ForwardRefComponent<CarouselNavImageButtonP
const state = useCarouselNavImageButton_unstable(props, ref);

useCarouselNavImageButtonStyles_unstable(state);
// TODO update types in packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts
// https://github.com/microsoft/fluentui/blob/master/rfcs/react-components/convergence/custom-styling.md
// useCustomStyleHook_unstable('useCarouselNavImageButtonStyles_unstable')(state);
useCustomStyleHook_unstable('useCarouselNavImageButtonStyles_unstable')(state);

return renderCarouselNavImageButton_unstable(state);
},
);
Expand Down
Loading

0 comments on commit 69dc72a

Please sign in to comment.