diff --git a/packages/react-components/semantic-style-hooks-preview/library/etc/semantic-style-hooks-preview.api.md b/packages/react-components/semantic-style-hooks-preview/library/etc/semantic-style-hooks-preview.api.md index 6c569ea3aa9ba..cef2854629e34 100644 --- a/packages/react-components/semantic-style-hooks-preview/library/etc/semantic-style-hooks-preview.api.md +++ b/packages/react-components/semantic-style-hooks-preview/library/etc/semantic-style-hooks-preview.api.md @@ -76,6 +76,18 @@ import { TableSelectionCellState } from '@fluentui/react-table'; import { TableState } from '@fluentui/react-table'; import { TabListState } from '@fluentui/react-tabs'; import { TabState } from '@fluentui/react-tabs'; +import { TeachingPopoverBodyState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverCarouselCardState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverCarouselFooterButtonState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverCarouselFooterState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverCarouselNavButtonState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverCarouselNavState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverCarouselPageCountState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverCarouselState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverFooterState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverHeaderState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverSurfaceState } from '@fluentui/react-teaching-popover'; +import { TeachingPopoverTitleState } from '@fluentui/react-teaching-popover'; import { TextareaState } from '@fluentui/react-textarea'; import { TextState } from '@fluentui/react-text'; import { ToastBodyState } from '@fluentui/react-toast'; @@ -321,6 +333,42 @@ export const useSemanticTabListStyles: (_state: unknown) => TabListState; // @public export const useSemanticTabStyles: (_state: unknown) => TabState; +// @public +export const useSemanticTeachingPopoverBodyStyles: (_state: unknown) => TeachingPopoverBodyState; + +// @public +export const useSemanticTeachingPopoverCarouselCardStyles: (_state: unknown) => TeachingPopoverCarouselCardState; + +// @public +export const useSemanticTeachingPopoverCarouselFooterButtonStyles: (_state: unknown) => TeachingPopoverCarouselFooterButtonState; + +// @public +export const useSemanticTeachingPopoverCarouselFooterStyles: (_state: unknown) => TeachingPopoverCarouselFooterState; + +// @public +export const useSemanticTeachingPopoverCarouselNavButtonStyles: (_state: unknown) => TeachingPopoverCarouselNavButtonState; + +// @public +export const useSemanticTeachingPopoverCarouselNavStyles: (_state: unknown) => TeachingPopoverCarouselNavState; + +// @public +export const useSemanticTeachingPopoverCarouselPageCountStyles: (_state: unknown) => TeachingPopoverCarouselPageCountState; + +// @public +export const useSemanticTeachingPopoverCarouselStyles: (_state: unknown) => TeachingPopoverCarouselState; + +// @public +export const useSemanticTeachingPopoverFooterStyles: (_state: unknown) => TeachingPopoverFooterState; + +// @public +export const useSemanticTeachingPopoverHeaderStyles: (_state: unknown) => TeachingPopoverHeaderState; + +// @public +export const useSemanticTeachingPopoverSurfaceStyles: (_state: unknown) => TeachingPopoverSurfaceState; + +// @public +export const useSemanticTeachingPopoverTitleStyles: (_state: unknown) => TeachingPopoverTitleState; + // @public export const useSemanticTextareaStyles: (_state: unknown) => TextareaState; diff --git a/packages/react-components/semantic-style-hooks-preview/library/package.json b/packages/react-components/semantic-style-hooks-preview/library/package.json index 3832885c5b102..46da5050ba4d6 100644 --- a/packages/react-components/semantic-style-hooks-preview/library/package.json +++ b/packages/react-components/semantic-style-hooks-preview/library/package.json @@ -47,6 +47,7 @@ "@fluentui/react-message-bar": "^9.4.7", "@fluentui/react-positioning": "^9.16.7", "@fluentui/react-persona": "^9.3.6", + "@fluentui/react-popover": "^9.10.6", "@fluentui/react-progress": "^9.2.6", "@fluentui/react-provider": "^9.20.6", "@fluentui/react-radio": "^9.3.6", @@ -60,6 +61,7 @@ "@fluentui/react-table": "^9.16.6", "@fluentui/react-tabs": "^9.7.6", "@fluentui/react-tabster": "^9.24.6", + "@fluentui/react-teaching-popover": "^9.4.5", "@fluentui/react-text": "^9.4.36", "@fluentui/react-textarea": "^9.4.6", "@fluentui/react-theme": "^9.1.24", diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/index.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/index.ts new file mode 100644 index 0000000000000..333b4345df99d --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/index.ts @@ -0,0 +1,12 @@ +export { useSemanticTeachingPopoverBodyStyles } from './useSemanticTeachingPopoverBodyStyles.styles'; +export { useSemanticTeachingPopoverCarouselCardStyles } from './useSemanticTeachingPopoverCarouselCardStyles.styles'; +export { useSemanticTeachingPopoverCarouselFooterButtonStyles } from './useSemanticTeachingPopoverCarouselFooterButtonStyles.styles'; +export { useSemanticTeachingPopoverCarouselFooterStyles } from './useSemanticTeachingPopoverCarouselFooterStyles.styles'; +export { useSemanticTeachingPopoverCarouselNavButtonStyles } from './useSemanticTeachingPopoverCarouselNavButtonStyles.styles'; +export { useSemanticTeachingPopoverCarouselNavStyles } from './useSemanticTeachingPopoverCarouselNavStyles.styles'; +export { useSemanticTeachingPopoverCarouselPageCountStyles } from './useSemanticTeachingPopoverCarouselPageCountStyles.styles'; +export { useSemanticTeachingPopoverCarouselStyles } from './useSemanticTeachingPopoverCarouselStyles.styles'; +export { useSemanticTeachingPopoverFooterStyles } from './useSemanticTeachingPopoverFooterStyles.styles'; +export { useSemanticTeachingPopoverHeaderStyles } from './useSemanticTeachingPopoverHeaderStyles.styles'; +export { useSemanticTeachingPopoverSurfaceStyles } from './useSemanticTeachingPopoverSurfaceStyles.styles'; +export { useSemanticTeachingPopoverTitleStyles } from './useSemanticTeachingPopoverTitleStyles.styles'; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverBodyStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverBodyStyles.styles.ts new file mode 100644 index 0000000000000..a997611b36869 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverBodyStyles.styles.ts @@ -0,0 +1,73 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import { teachingPopoverBodyClassNames, type TeachingPopoverBodyState } from '@fluentui/react-teaching-popover'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; + +const popoverBodyDimension = 288; + +export const useMediaStyles = makeStyles({ + base: { + gridArea: 'media', + overflow: 'hidden', + width: 'auto', + marginBottom: '12px', + verticalAlign: 'middle', + justifyContent: 'center', + display: 'flex', + }, + short: { + aspectRatio: popoverBodyDimension / 117, + '@supports not (aspect-ratio)': { + height: '117px', + }, + }, + medium: { + aspectRatio: popoverBodyDimension / 176, + '@supports not (aspect-ratio)': { + height: '176px', + }, + }, + tall: { + aspectRatio: 1, + '@supports not (aspect-ratio)': { + height: `${popoverBodyDimension}px`, + }, + }, +}); + +const useStyles = makeStyles({ + root: { + display: 'flex', + flexDirection: 'column', + paddingBottom: '12px', + }, +}); + +/** Applies style classnames to slots */ +export const useSemanticTeachingPopoverBodyStyles = (_state: unknown) => { + 'use no memo'; + + const state = _state as TeachingPopoverBodyState; + + const { mediaLength } = state; + const styles = useStyles(); + const mediaStyles = useMediaStyles(); + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverBodyClassNames.root, + styles.root, + getSlotClassNameProp_unstable(state.root), + ); + + if (state.media) { + state.media.className = mergeClasses( + state.media.className, + teachingPopoverBodyClassNames.media, + mediaStyles.base, + mediaStyles[mediaLength], + getSlotClassNameProp_unstable(state.media), + ); + } + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselCardStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselCardStyles.styles.ts new file mode 100644 index 0000000000000..cb1af6c68b059 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselCardStyles.styles.ts @@ -0,0 +1,28 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import { + teachingPopoverCarouselCardClassNames, + type TeachingPopoverCarouselCardState, +} from '@fluentui/react-teaching-popover'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; + +const useStyles = makeStyles({ + root: {}, +}); + +/** Applies style classnames to slots */ +export const useSemanticTeachingPopoverCarouselCardStyles = (_state: unknown) => { + 'use no memo'; + + const state = _state as TeachingPopoverCarouselCardState; + + const styles = useStyles(); + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverCarouselCardClassNames.root, + styles.root, + getSlotClassNameProp_unstable(state.root), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselFooterButtonStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselFooterButtonStyles.styles.ts new file mode 100644 index 0000000000000..5bd275cfbbadf --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselFooterButtonStyles.styles.ts @@ -0,0 +1,74 @@ +import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import { + teachingPopoverCarouselFooterButtonClassNames, + type TeachingPopoverCarouselFooterButtonState, +} from '@fluentui/react-teaching-popover'; +import { useSemanticButtonStyles } from '../Button'; +import * as semanticTokens from '@fluentui/semantic-tokens'; + +const useStyles = makeStyles({ + root: { + minWidth: '96px', + }, + brandNext: { + color: semanticTokens.foregroundContentBrandPrimary, + backgroundColor: semanticTokens.foregroundCtrlOnBrandRest, + ...shorthands.borderColor(semanticTokens.nullColor), + ':hover': { + color: semanticTokens.foregroundCtrlActiveBrandHover, + backgroundColor: semanticTokens.foregroundCtrlOnBrandHover, + }, + ':hover:active': { + color: semanticTokens.foregroundCtrlActiveBrandPressed, + backgroundColor: semanticTokens.foregroundCtrlOnBrandPressed, + }, + }, + brandPrevious: { + // In brand, this is always 'NeutralForegroundOnBrand' + color: semanticTokens.foregroundCtrlOnBrandRest, + backgroundColor: semanticTokens.backgroundCtrlBrandRest, + ...shorthands.borderColor(semanticTokens.strokeCtrlOnActiveBrandRest), + ':hover': { + color: semanticTokens.foregroundCtrlOnBrandHover, + ...shorthands.borderColor(semanticTokens.strokeCtrlOnActiveBrandRest), + backgroundColor: semanticTokens.backgroundCtrlBrandHover, + }, + ':hover:active': { + color: semanticTokens.foregroundCtrlOnBrandPressed, + ...shorthands.borderColor(semanticTokens.strokeCtrlOnActiveBrandRest), + backgroundColor: semanticTokens.backgroundCtrlBrandPressed, + }, + }, +}); + +/** + * Apply styling to the TeachingPopoverCarouselFooterButton slots based on the state + */ +export const useSemanticTeachingPopoverCarouselFooterButtonStyles = ( + _state: unknown, +): TeachingPopoverCarouselFooterButtonState => { + 'use no memo'; + + let state = _state as TeachingPopoverCarouselFooterButtonState; + + const styles = useStyles(); + const { navType, popoverAppearance } = state; + + // Apply underlying fluent Button styles + state = { + ...state, + ...useSemanticButtonStyles(state), + }; + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverCarouselFooterButtonClassNames.root, + styles.root, + navType === 'prev' && popoverAppearance === 'brand' && styles.brandPrevious, + navType === 'next' && popoverAppearance === 'brand' && styles.brandNext, + getSlotClassNameProp_unstable(state.root), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselFooterStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselFooterStyles.styles.ts new file mode 100644 index 0000000000000..ddbd51bf90bd8 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselFooterStyles.styles.ts @@ -0,0 +1,58 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import { + teachingPopoverCarouselFooterClassNames, + type TeachingPopoverCarouselFooterState, +} from '@fluentui/react-teaching-popover'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; + +// Todo: Page change animation & styles +const useStyles = makeStyles({ + root: { + display: 'flex', + flexDirection: 'row', + }, + rootCentered: { + justifyContent: 'space-between', + gap: '8px', + }, + rootRightAligned: { + gap: '8px', + '& :first-child': { + marginInlineEnd: 'auto', + }, + }, +}); + +/** Applies style classnames to slots */ +export const useSemanticTeachingPopoverCarouselFooterStyles = (_state: unknown) => { + 'use no memo'; + + const state = _state as TeachingPopoverCarouselFooterState; + + const styles = useStyles(); + const { layout } = state; + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverCarouselFooterClassNames.root, + styles.root, + layout === 'centered' ? styles.rootCentered : styles.rootRightAligned, + getSlotClassNameProp_unstable(state.root), + ); + + if (state.previous) { + state.previous.className = mergeClasses( + state.previous.className, + teachingPopoverCarouselFooterClassNames.previous, + getSlotClassNameProp_unstable(state.previous), + ); + } + + state.next.className = mergeClasses( + state.next.className, + teachingPopoverCarouselFooterClassNames.next, + getSlotClassNameProp_unstable(state.next), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselNavButtonStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselNavButtonStyles.styles.ts new file mode 100644 index 0000000000000..5dacc073f0e5d --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselNavButtonStyles.styles.ts @@ -0,0 +1,92 @@ +import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import { + teachingPopoverCarouselNavButtonClassNames, + type TeachingPopoverCarouselNavButtonState, +} from '@fluentui/react-teaching-popover'; +import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster'; +import * as semanticTokens from '@fluentui/semantic-tokens'; + +/** + * Styles for the root slot + */ +const useStyles = makeStyles({ + root: { + display: 'flex', + cursor: 'pointer', + boxSizing: 'border-box', + height: '8px', + width: '8px', + backgroundColor: semanticTokens.backgroundCtrlBrandRest, + }, + rootUnselected: { + border: 'none', + borderRadius: semanticTokens.cornerCircular, + padding: '0px', + outline: `${semanticTokens.strokeWidthDefault} solid ${semanticTokens.nullColor}`, // For high contrast + ...createCustomFocusIndicatorStyle({ + outline: `${semanticTokens.ctrlFocusOuterStrokeWidth} solid ${semanticTokens.ctrlFocusInnerStroke}`, + borderRadius: semanticTokens.cornerCtrlRest, + ...shorthands.borderColor(semanticTokens.nullColor), + }), + backgroundColor: `color-mix(in srgb, ${semanticTokens.backgroundCtrlBrandRest} 30%, transparent)`, + '@supports not (color: color-mix(in lch, white, black))': { + // This will also affect the focus border, but only in older unsupported browsers + opacity: 0.3, + backgroundColor: semanticTokens.backgroundCtrlBrandRest, + }, + }, + rootSelected: { + outline: `${semanticTokens.strokeWidthCtrlOutlinePressed} solid ${semanticTokens.nullColor}`, // For high contrast + width: '16px', + border: 'none', + borderRadius: semanticTokens.cornerCtrlRest, + padding: '0px', + ...createCustomFocusIndicatorStyle({ + outline: `${semanticTokens.ctrlFocusOuterStrokeWidth} solid ${semanticTokens.ctrlFocusInnerStroke}`, + borderRadius: semanticTokens.cornerCtrlPressed, + ...shorthands.borderColor(semanticTokens.nullColor), + }), + '@media (forced-colors: active)': { + backgroundColor: 'CanvasText', + }, + }, + rootBrand: { + backgroundColor: semanticTokens.foregroundCtrlOnBrandRest, + }, + rootBrandUnselected: { + backgroundColor: `color-mix(in srgb, ${semanticTokens.foregroundCtrlOnBrandRest} 30%, transparent)`, + '@supports not (color: color-mix(in lch, white, black))': { + // This will also affect the focus border, but only in older unsupported browsers + opacity: 0.3, + backgroundColor: semanticTokens.backgroundCtrlBrandRest, + }, + }, +}); + +/** + * Apply styling to the TeachingPopoverCarouselNavButton slots based on the state + */ +export const useSemanticTeachingPopoverCarouselNavButtonStyles = ( + _state: unknown, +): TeachingPopoverCarouselNavButtonState => { + 'use no memo'; + + const state = _state as TeachingPopoverCarouselNavButtonState; + + const styles = useStyles(); + const { appearance, isSelected } = state; + + const brandStyles = isSelected ? styles.rootBrand : styles.rootBrandUnselected; + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverCarouselNavButtonClassNames.root, + styles.root, + isSelected ? styles.rootSelected : styles.rootUnselected, + appearance === 'brand' && brandStyles, + getSlotClassNameProp_unstable(state.root), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselNavStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselNavStyles.styles.ts new file mode 100644 index 0000000000000..eb9ed952d8412 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselNavStyles.styles.ts @@ -0,0 +1,41 @@ +import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import { + teachingPopoverCarouselNavClassNames, + type TeachingPopoverCarouselNavState, +} from '@fluentui/react-teaching-popover'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster'; +import * as semanticTokens from '@fluentui/semantic-tokens'; + +const useStyles = makeStyles({ + root: { + display: 'flex', + flexDirection: 'row', + columnGap: semanticTokens.gapInsideCtrlSmDefault, + alignItems: 'center', + justifyContent: 'center', + ...createCustomFocusIndicatorStyle({ + outline: `${semanticTokens.ctrlFocusOuterStrokeWidth} solid ${semanticTokens.ctrlFocusInnerStroke}`, + borderRadius: semanticTokens.cornerCtrlRest, + ...shorthands.borderColor(semanticTokens.nullColor), + }), + }, +}); + +/** Applies style classnames to slots */ +export const useSemanticTeachingPopoverCarouselNavStyles = (_state: unknown) => { + 'use no memo'; + + const state = _state as TeachingPopoverCarouselNavState; + + const styles = useStyles(); + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverCarouselNavClassNames.root, + styles.root, + getSlotClassNameProp_unstable(state.root), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselPageCountStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselPageCountStyles.styles.ts new file mode 100644 index 0000000000000..cd3b9d11f40c8 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselPageCountStyles.styles.ts @@ -0,0 +1,38 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import { + teachingPopoverCarouselPageCountClassNames, + type TeachingPopoverCarouselPageCountState, +} from '@fluentui/react-teaching-popover'; + +/** + * Styles for the root slot + */ +const useStyles = makeStyles({ + root: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, +}); + +/** + * Apply styling to the TeachingPopoverCarouselPageCount slots based on the state + */ +export const useSemanticTeachingPopoverCarouselPageCountStyles = ( + _state: unknown, +): TeachingPopoverCarouselPageCountState => { + 'use no memo'; + + const state = _state as TeachingPopoverCarouselPageCountState; + + const styles = useStyles(); + state.root.className = mergeClasses( + state.root.className, + teachingPopoverCarouselPageCountClassNames.root, + styles.root, + getSlotClassNameProp_unstable(state.root), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselStyles.styles.ts new file mode 100644 index 0000000000000..edd184e0fdde3 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverCarouselStyles.styles.ts @@ -0,0 +1,26 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import { teachingPopoverCarouselClassNames, type TeachingPopoverCarouselState } from '@fluentui/react-teaching-popover'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; + +// Todo: Page change animation & styles +const useStyles = makeStyles({ + root: {}, +}); + +/** Applies style classnames to slots */ +export const useSemanticTeachingPopoverCarouselStyles = (_state: unknown) => { + 'use no memo'; + + const state = _state as TeachingPopoverCarouselState; + + const styles = useStyles(); + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverCarouselClassNames.root, + styles.root, + getSlotClassNameProp_unstable(state.root), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverFooterStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverFooterStyles.styles.ts new file mode 100644 index 0000000000000..0b1179a2a097e --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverFooterStyles.styles.ts @@ -0,0 +1,78 @@ +import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import { teachingPopoverFooterClassNames, type TeachingPopoverFooterState } from '@fluentui/react-teaching-popover'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import * as semanticTokens from '@fluentui/semantic-tokens'; + +const useStyles = makeStyles({ + root: { + display: 'flex', + gap: semanticTokens.gapBetweenCtrlDefault, + paddingTop: semanticTokens.paddingCtrlHorizontalDefault, + }, + rootVertical: { + flexDirection: 'column', + }, + rootHorizontal: { + flexDirection: 'row', + justifyContent: 'flex-end', + }, + buttonRootVertical: { + width: 'auto', + borderRadius: semanticTokens.cornerCtrlRest, + }, + buttonRootHorizontal: { + minWidth: '96px', + borderRadius: semanticTokens.cornerCtrlRest, + }, + brandSecondary: { + ...shorthands.borderColor(semanticTokens.foregroundCtrlOnBrandRest), + }, + brandPrimary: { + color: semanticTokens.foregroundContentBrandPrimary, + backgroundColor: semanticTokens.foregroundCtrlOnBrandRest, + ':hover': { + color: semanticTokens.foregroundCtrlActiveBrandHover, + backgroundColor: semanticTokens.foregroundCtrlOnBrandHover, + }, + ':hover:active': { + color: semanticTokens.foregroundCtrlActiveBrandPressed, + backgroundColor: semanticTokens.foregroundCtrlOnBrandPressed, + }, + }, +}); + +/** Applies style classnames to slots */ +export const useSemanticTeachingPopoverFooterStyles = (_state: unknown) => { + 'use no memo'; + + const state = _state as TeachingPopoverFooterState; + + const styles = useStyles(); + const { appearance, footerLayout } = state; + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverFooterClassNames.root, + styles.root, + footerLayout === 'horizontal' ? styles.rootHorizontal : styles.rootVertical, + getSlotClassNameProp_unstable(state.root), + ); + if (state.secondary) { + state.secondary.className = mergeClasses( + state.secondary.className, + teachingPopoverFooterClassNames.secondary, + footerLayout === 'horizontal' ? styles.buttonRootHorizontal : styles.buttonRootVertical, + appearance === 'brand' ? styles.brandSecondary : undefined, + getSlotClassNameProp_unstable(state.secondary), + ); + } + state.primary.className = mergeClasses( + state.primary.className, + teachingPopoverFooterClassNames.primary, + footerLayout === 'horizontal' ? styles.buttonRootHorizontal : styles.buttonRootVertical, + appearance === 'brand' ? styles.brandPrimary : undefined, + getSlotClassNameProp_unstable(state.primary), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverHeaderStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverHeaderStyles.styles.ts new file mode 100644 index 0000000000000..0ebcab914e8f1 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverHeaderStyles.styles.ts @@ -0,0 +1,100 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import { tokens } from '@fluentui/react-theme'; +import { teachingPopoverHeaderClassNames, type TeachingPopoverHeaderState } from '@fluentui/react-teaching-popover'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import * as semanticTokens from '@fluentui/semantic-tokens'; + +const useStyles = makeStyles({ + root: { + display: 'flex', + flexDirection: 'row', + color: tokens.colorNeutralForeground3, + fontWeight: semanticTokens.textStyleDefaultHeaderWeight, + fontSize: semanticTokens.textRampSmItemBodyFontSize, + lineHeight: semanticTokens.textRampSmItemBodyLineHeight, + paddingBottom: tokens.spacingVerticalXS, + alignItems: 'center', + marginTop: semanticTokens.paddingContentNone, + marginBottom: semanticTokens.paddingContentNone, + }, + rootBrand: { + color: semanticTokens.foregroundCtrlOnBrandRest, + }, + dismissButton: { + color: semanticTokens.foregroundContentNeutralSecondary, + position: 'relative', + display: 'flex', + alignItems: 'center', + cursor: 'pointer', + fontFamily: semanticTokens.textStyleDefaultRegularFontFamily, + fontSize: semanticTokens.textRampItemBodyFontSize, + fontWeight: semanticTokens.textStyleDefaultRegularWeight, + lineHeight: semanticTokens.textRampItemBodyLineHeight, + backgroundColor: semanticTokens.nullColor, + boxSizing: 'border-box', + marginInlineStart: 'auto', + padding: `${tokens.spacingVerticalXS} ${tokens.spacingHorizontalXS}`, + border: `${semanticTokens.strokeWidthDefault} solid ${semanticTokens.strokeLayer}`, + }, + dismissBrand: { + color: semanticTokens.foregroundCtrlOnBrandRest, + }, + icon: { + height: semanticTokens.textGlobalCaption1FontSize, + width: semanticTokens.textGlobalCaption1FontSize, + lineHeight: semanticTokens.textGlobalCaption1LineHeight, + fontSize: semanticTokens.textGlobalCaption1FontSize, + alignItems: 'center', + boxSizing: 'content-box', + display: 'inline-flex', + justifyContent: 'center', + textDecorationLine: 'none', + verticalAlign: 'middle', + position: 'relative', + backgroundColor: semanticTokens.nullColor, + color: semanticTokens.foregroundContentNeutralSecondary, + marginInlineEnd: semanticTokens.gapBetweenTextSmall, + }, + iconBrand: { + color: semanticTokens.foregroundCtrlOnBrandRest, + }, +}); + +/** Applies style classnames to slots */ +export const useSemanticTeachingPopoverHeaderStyles = (_state: unknown) => { + 'use no memo'; + + const state = _state as TeachingPopoverHeaderState; + + const styles = useStyles(); + const { appearance } = state; + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverHeaderClassNames.root, + styles.root, + appearance === 'brand' && styles.rootBrand, + getSlotClassNameProp_unstable(state.root), + ); + + if (state.dismissButton) { + state.dismissButton.className = mergeClasses( + state.dismissButton.className, + teachingPopoverHeaderClassNames.dismissButton, + styles.dismissButton, + appearance === 'brand' ? styles.dismissBrand : undefined, + getSlotClassNameProp_unstable(state.dismissButton), + ); + } + + if (state.icon) { + state.icon.className = mergeClasses( + state.icon.className, + teachingPopoverHeaderClassNames.icon, + styles.icon, + appearance === 'brand' ? styles.iconBrand : undefined, + getSlotClassNameProp_unstable(state.icon), + ); + } + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverSurfaceStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverSurfaceStyles.styles.ts new file mode 100644 index 0000000000000..e48d75c7426a9 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverSurfaceStyles.styles.ts @@ -0,0 +1,39 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import { teachingPopoverSurfaceClassNames, type TeachingPopoverSurfaceState } from '@fluentui/react-teaching-popover'; +import { usePopoverSurfaceStyles_unstable } from '@fluentui/react-popover'; +// import { useSemanticPopoverSurfaceStyles } from '../Popover'; +import * as semanticTokens from '@fluentui/semantic-tokens'; + +const useStyles = makeStyles({ + root: { + padding: `${semanticTokens.paddingCtrlLgHorizontalDefault} ${semanticTokens.paddingCtrlLgHorizontalDefault}`, + borderRadius: semanticTokens._ctrlTeachingPopoverSurfaceCorner, + minWidth: '320px', + boxSizing: 'border-box', + }, +}); + +/** + * Apply styling to the TeachingPopoverSurface slots based on the state + */ +export const useSemanticTeachingPopoverSurfaceStyles = (_state: unknown): TeachingPopoverSurfaceState => { + 'use no memo'; + + const state = _state as TeachingPopoverSurfaceState; + + const styles = useStyles(); + + // Make sure to merge teaching bubble surface prior to popover styles + state.root.className = mergeClasses( + state.root.className, + teachingPopoverSurfaceClassNames.root, + styles.root, + getSlotClassNameProp_unstable(state.root), + ); + + const updatedState = usePopoverSurfaceStyles_unstable(state); + // const updatedState = useSemanticPopoverSurfaceStyles(state); + + return updatedState; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverTitleStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverTitleStyles.styles.ts new file mode 100644 index 0000000000000..fa953b7aed620 --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/TeachingPopover/useSemanticTeachingPopoverTitleStyles.styles.ts @@ -0,0 +1,78 @@ +import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import { teachingPopoverTitleClassNames, type TeachingPopoverTitleState } from '@fluentui/react-teaching-popover'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster'; +import * as semanticTokens from '@fluentui/semantic-tokens'; + +const useStyles = makeStyles({ + root: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + fontSize: semanticTokens.textRampLgItemBodyFontSize, + fontWeight: semanticTokens.textStyleDefaultHeaderWeight, + color: semanticTokens.foregroundContentNeutralPrimary, + lineHeight: semanticTokens.textRampLgItemBodyLineHeight, + paddingBottom: semanticTokens.ctrlChoicePaddingVertical, + marginTop: semanticTokens.paddingContentNone, + marginBottom: semanticTokens.paddingContentNone, + }, + rootBrand: { + color: semanticTokens.foregroundCtrlOnBrandRest, + }, + dismissButton: { + position: 'relative', + border: `${semanticTokens.strokeWidthDefault} solid ${semanticTokens.strokeLayer}`, + display: 'flex', + alignItems: 'center', + cursor: 'pointer', + fontFamily: semanticTokens.textStyleDefaultRegularFontFamily, + fontSize: semanticTokens.textRampItemBodyFontSize, + fontWeight: semanticTokens.textStyleDefaultRegularWeight, + lineHeight: semanticTokens.textRampItemBodyLineHeight, + backgroundColor: semanticTokens.nullColor, + boxSizing: 'border-box', + borderTopRightRadius: semanticTokens.cornerZero, + borderBottomRightRadius: semanticTokens.cornerZero, + borderRightStyle: 'none', + ...createCustomFocusIndicatorStyle({ + outline: `${semanticTokens.ctrlFocusOuterStrokeWidth} solid ${semanticTokens.ctrlFocusInnerStroke}`, + borderRadius: semanticTokens.cornerCtrlRest, + ...shorthands.borderColor(semanticTokens.nullColor), + }), + marginInlineStart: 'auto', + }, + dismissBrand: { + color: semanticTokens.foregroundCtrlOnBrandRest, + }, +}); + +/** Applies style classnames to slots */ +export const useSemanticTeachingPopoverTitleStyles = (_state: unknown) => { + 'use no memo'; + + const state = _state as TeachingPopoverTitleState; + + const styles = useStyles(); + const { appearance } = state; + + state.root.className = mergeClasses( + state.root.className, + teachingPopoverTitleClassNames.root, + styles.root, + appearance === 'brand' && styles.rootBrand, + getSlotClassNameProp_unstable(state.root), + ); + + if (state.dismissButton) { + state.dismissButton.className = mergeClasses( + state.dismissButton.className, + teachingPopoverTitleClassNames.dismissButton, + styles.dismissButton, + appearance === 'brand' ? styles.dismissBrand : undefined, + getSlotClassNameProp_unstable(state.dismissButton), + ); + } + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/semanticStyleHooks.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/semanticStyleHooks.ts index 185d5fcf373ce..1a966a1480927 100644 --- a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/semanticStyleHooks.ts +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/semanticStyleHooks.ts @@ -108,6 +108,20 @@ import { useSemanticToastTitleStyles, } from './Toast'; import { useSemanticSearchBoxStyles } from './Search'; +import { + useSemanticTeachingPopoverBodyStyles, + useSemanticTeachingPopoverCarouselCardStyles, + useSemanticTeachingPopoverCarouselFooterButtonStyles, + useSemanticTeachingPopoverCarouselFooterStyles, + useSemanticTeachingPopoverCarouselNavButtonStyles, + useSemanticTeachingPopoverCarouselNavStyles, + useSemanticTeachingPopoverCarouselPageCountStyles, + useSemanticTeachingPopoverCarouselStyles, + useSemanticTeachingPopoverFooterStyles, + useSemanticTeachingPopoverHeaderStyles, + useSemanticTeachingPopoverSurfaceStyles, + useSemanticTeachingPopoverTitleStyles, +} from './TeachingPopover'; export const SEMANTIC_STYLE_HOOKS: FluentProviderCustomStyleHooks = { // Accordion styles @@ -236,4 +250,17 @@ export const SEMANTIC_STYLE_HOOKS: FluentProviderCustomStyleHooks = { useToastFooterStyles_unstable: useSemanticToastFooterStyles, useToastStyles_unstable: useSemanticToastStyles, useToastTitleStyles_unstable: useSemanticToastTitleStyles, + // TeachingPopover styles + useTeachingPopoverBodyStyles_unstable: useSemanticTeachingPopoverBodyStyles, + useTeachingPopoverCarouselCardStyles_unstable: useSemanticTeachingPopoverCarouselCardStyles, + useTeachingPopoverCarouselFooterButtonStyles_unstable: useSemanticTeachingPopoverCarouselFooterButtonStyles, + useTeachingPopoverCarouselFooterStyles_unstable: useSemanticTeachingPopoverCarouselFooterStyles, + useTeachingPopoverCarouselNavButtonStyles_unstable: useSemanticTeachingPopoverCarouselNavButtonStyles, + useTeachingPopoverCarouselNavStyles_unstable: useSemanticTeachingPopoverCarouselNavStyles, + useTeachingPopoverCarouselPageCountStyles_unstable: useSemanticTeachingPopoverCarouselPageCountStyles, + useTeachingPopoverCarouselStyles_unstable: useSemanticTeachingPopoverCarouselStyles, + useTeachingPopoverFooterStyles_unstable: useSemanticTeachingPopoverFooterStyles, + useTeachingPopoverHeaderStyles_unstable: useSemanticTeachingPopoverHeaderStyles, + useTeachingPopoverSurfaceStyles_unstable: useSemanticTeachingPopoverSurfaceStyles, + useTeachingPopoverTitleStyles_unstable: useSemanticTeachingPopoverTitleStyles, }; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/index.ts b/packages/react-components/semantic-style-hooks-preview/library/src/index.ts index ea730ec73cfed..d6f8d1d2786c1 100644 --- a/packages/react-components/semantic-style-hooks-preview/library/src/index.ts +++ b/packages/react-components/semantic-style-hooks-preview/library/src/index.ts @@ -111,3 +111,17 @@ export { useSemanticToastTitleStyles, } from './component-styles/Toast'; export { useSemanticSearchBoxStyles } from './component-styles/Search'; +export { + useSemanticTeachingPopoverBodyStyles, + useSemanticTeachingPopoverCarouselCardStyles, + useSemanticTeachingPopoverCarouselFooterButtonStyles, + useSemanticTeachingPopoverCarouselFooterStyles, + useSemanticTeachingPopoverCarouselNavButtonStyles, + useSemanticTeachingPopoverCarouselNavStyles, + useSemanticTeachingPopoverCarouselPageCountStyles, + useSemanticTeachingPopoverCarouselStyles, + useSemanticTeachingPopoverFooterStyles, + useSemanticTeachingPopoverHeaderStyles, + useSemanticTeachingPopoverSurfaceStyles, + useSemanticTeachingPopoverTitleStyles, +} from './component-styles/TeachingPopover'; diff --git a/packages/semantic-tokens/etc/semantic-tokens.api.md b/packages/semantic-tokens/etc/semantic-tokens.api.md index 26e5a5a9ff84c..b552a0b965676 100644 --- a/packages/semantic-tokens/etc/semantic-tokens.api.md +++ b/packages/semantic-tokens/etc/semantic-tokens.api.md @@ -3226,6 +3226,9 @@ export const _ctrlTabSmGapInsideDefault = "var(--smtc-gap-inside-ctrl-default, v // @public export const _ctrlTabSmPaddingHorizontalDefault = "var(--smtc-padding-ctrl-horizontal-default, var(--spacingHorizontalSNudge))"; +// @public +export const _ctrlTeachingPopoverSurfaceCorner = "var(--smtc-corner-flyout-rest, var(--borderRadiusXLarge))"; + // @public export const _ctrlToastBackgroundFlyoutLumBlend = "var(--smtc-background-flyout-lum-blend, var(--colorNeutralBackgroundInverted))"; diff --git a/packages/semantic-tokens/src/fluentLegacyVariants.ts b/packages/semantic-tokens/src/fluentLegacyVariants.ts index 99e30e8cbc0d8..8edd767babc5f 100644 --- a/packages/semantic-tokens/src/fluentLegacyVariants.ts +++ b/packages/semantic-tokens/src/fluentLegacyVariants.ts @@ -717,6 +717,10 @@ export const legacyFluentVariantsValues: LegacyFluentVariants = { f2Token: 'spacingHorizontalSNudge', originalToken: 'paddingCtrlHorizontalDefault', }, + _ctrlTeachingPopoverSurfaceCorner: { + f2Token: 'borderRadiusXLarge', + originalToken: 'cornerFlyoutRest', + }, _ctrlToastBackgroundFlyoutLumBlend: { f2Token: 'colorNeutralBackgroundInverted', originalToken: 'backgroundFlyoutLumBlend', diff --git a/packages/semantic-tokens/src/index.ts b/packages/semantic-tokens/src/index.ts index 2f8d8773a3ca5..a52e0b9fed6f7 100644 --- a/packages/semantic-tokens/src/index.ts +++ b/packages/semantic-tokens/src/index.ts @@ -1958,6 +1958,7 @@ export { _ctrlTabSizeDefault, _ctrlTabSmGapInsideDefault, _ctrlTabSmPaddingHorizontalDefault, + _ctrlTeachingPopoverSurfaceCorner, _ctrlToastBackgroundFlyoutLumBlend, _ctrlToastBodyForegroundContentNeutralPrimary, _ctrlToastBodyForegroundContentNeutralSecondary, diff --git a/packages/semantic-tokens/src/legacyVariant/tokens.ts b/packages/semantic-tokens/src/legacyVariant/tokens.ts index b529a6ba789ab..772361b4758da 100644 --- a/packages/semantic-tokens/src/legacyVariant/tokens.ts +++ b/packages/semantic-tokens/src/legacyVariant/tokens.ts @@ -1455,6 +1455,13 @@ export const _ctrlTabSmGapInsideDefault = `var(${gapInsideCtrlDefaultRaw}, ${spa * please use paddingCtrlHorizontalDefault instead. */ export const _ctrlTabSmPaddingHorizontalDefault = `var(${paddingCtrlHorizontalDefaultRaw}, ${spacingHorizontalSNudge})`; +/** + * This is a legacy variant for cornerFlyoutRest to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use cornerFlyoutRest instead. + */ +export const _ctrlTeachingPopoverSurfaceCorner = `var(${cornerFlyoutRestRaw}, ${borderRadiusXLarge})`; /** * This is a legacy variant for backgroundFlyoutLumBlend to enable backwards compatibility. * It's purpose is to support Fluent UI legacy fallback variants only.