Private
Public Access
1
0

feat: Fluent UI Outlook Lite + connections mockup

This commit is contained in:
2026-04-14 18:52:25 +00:00
parent 1199eff6c3
commit dfa4010406
34820 changed files with 1003813 additions and 205 deletions

View File

@@ -0,0 +1,16 @@
'use client';
import * as React from 'react';
import { useCarouselButton_unstable } from './useCarouselButton';
import { renderCarouselButton_unstable } from './renderCarouselButton';
import { useCarouselButtonStyles_unstable } from './useCarouselButtonStyles.styles';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';
/**
* A default navigation button that will set value to the next/previous page,
* driven by it's type 'next' or 'previous'.
*/ export const CarouselButton = /*#__PURE__*/ React.forwardRef((props, ref)=>{
const state = useCarouselButton_unstable(props, ref);
useCarouselButtonStyles_unstable(state);
useCustomStyleHook_unstable('useCarouselButtonStyles_unstable')(state);
return renderCarouselButton_unstable(state);
});
CarouselButton.displayName = 'CarouselButton';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CarouselButton/CarouselButton.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { ForwardRefComponent } from '@fluentui/react-utilities';\nimport { useCarouselButton_unstable } from './useCarouselButton';\nimport { renderCarouselButton_unstable } from './renderCarouselButton';\nimport { useCarouselButtonStyles_unstable } from './useCarouselButtonStyles.styles';\nimport type { CarouselButtonProps } from './CarouselButton.types';\nimport { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';\n\n/**\n * A default navigation button that will set value to the next/previous page,\n * driven by it's type 'next' or 'previous'.\n */\nexport const CarouselButton: ForwardRefComponent<CarouselButtonProps> = React.forwardRef((props, ref) => {\n const state = useCarouselButton_unstable(props, ref);\n\n useCarouselButtonStyles_unstable(state);\n useCustomStyleHook_unstable('useCarouselButtonStyles_unstable')(state);\n\n return renderCarouselButton_unstable(state);\n});\n\nCarouselButton.displayName = 'CarouselButton';\n"],"names":["React","useCarouselButton_unstable","renderCarouselButton_unstable","useCarouselButtonStyles_unstable","useCustomStyleHook_unstable","CarouselButton","forwardRef","props","ref","state","displayName"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAE/B,SAASC,0BAA0B,QAAQ,sBAAsB;AACjE,SAASC,6BAA6B,QAAQ,yBAAyB;AACvE,SAASC,gCAAgC,QAAQ,mCAAmC;AAEpF,SAASC,2BAA2B,QAAQ,kCAAkC;AAE9E;;;CAGC,GACD,OAAO,MAAMC,+BAA2DL,MAAMM,UAAU,CAAC,CAACC,OAAOC;IAC/F,MAAMC,QAAQR,2BAA2BM,OAAOC;IAEhDL,iCAAiCM;IACjCL,4BAA4B,oCAAoCK;IAEhE,OAAOP,8BAA8BO;AACvC,GAAG;AAEHJ,eAAeK,WAAW,GAAG"}

View File

@@ -0,0 +1,3 @@
/**
* State used in rendering CarouselButton
*/ export { };

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CarouselButton/CarouselButton.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport { ARIAButtonSlotProps } from '@fluentui/react-aria';\nimport { ButtonProps, ButtonSlots, ButtonState } from '@fluentui/react-button';\n\nexport type CarouselButtonSlots = ButtonSlots & {\n root: NonNullable<Slot<ARIAButtonSlotProps>>;\n};\n\n/**\n * CarouselButton Props\n */\nexport type CarouselButtonProps = Partial<ButtonProps> &\n ComponentProps<CarouselButtonSlots> & {\n /**\n * Dictates whether button will be of type go next or go previous\n * Default: 'next'\n */\n navType?: 'prev' | 'next';\n };\n\n/**\n * State used in rendering CarouselButton\n */\nexport type CarouselButtonState = ButtonState &\n ComponentState<CarouselButtonSlots> &\n Required<Pick<CarouselButtonProps, 'navType'>>;\n"],"names":[],"mappings":"AAoBA;;CAEC,GACD,WAEiD"}

View File

@@ -0,0 +1,4 @@
export { CarouselButton } from './CarouselButton';
export { renderCarouselButton_unstable } from './renderCarouselButton';
export { useCarouselButton_unstable } from './useCarouselButton';
export { carouselButtonClassNames, useCarouselButtonStyles_unstable } from './useCarouselButtonStyles.styles';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CarouselButton/index.ts"],"sourcesContent":["export { CarouselButton } from './CarouselButton';\nexport type { CarouselButtonProps, CarouselButtonSlots, CarouselButtonState } from './CarouselButton.types';\nexport { renderCarouselButton_unstable } from './renderCarouselButton';\nexport { useCarouselButton_unstable } from './useCarouselButton';\nexport { carouselButtonClassNames, useCarouselButtonStyles_unstable } from './useCarouselButtonStyles.styles';\n"],"names":["CarouselButton","renderCarouselButton_unstable","useCarouselButton_unstable","carouselButtonClassNames","useCarouselButtonStyles_unstable"],"mappings":"AAAA,SAASA,cAAc,QAAQ,mBAAmB;AAElD,SAASC,6BAA6B,QAAQ,yBAAyB;AACvE,SAASC,0BAA0B,QAAQ,sBAAsB;AACjE,SAASC,wBAAwB,EAAEC,gCAAgC,QAAQ,mCAAmC"}

View File

@@ -0,0 +1,9 @@
import { assertSlots } from '@fluentui/react-utilities';
import { renderButton_unstable } from '@fluentui/react-button';
/**
* Render the final JSX of CarouselButton
*/ export const renderCarouselButton_unstable = (state)=>{
assertSlots(state);
// We render the underlying react-button with injected carousel functionality
return renderButton_unstable(state);
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CarouselButton/renderCarouselButton.tsx"],"sourcesContent":["import { assertSlots } from '@fluentui/react-utilities';\nimport type { JSXElement } from '@fluentui/react-utilities';\nimport type { CarouselButtonState, CarouselButtonSlots } from './CarouselButton.types';\nimport { renderButton_unstable } from '@fluentui/react-button';\n\n/**\n * Render the final JSX of CarouselButton\n */\nexport const renderCarouselButton_unstable = (state: CarouselButtonState): JSXElement => {\n assertSlots<CarouselButtonSlots>(state);\n\n // We render the underlying react-button with injected carousel functionality\n return renderButton_unstable(state);\n};\n"],"names":["assertSlots","renderButton_unstable","renderCarouselButton_unstable","state"],"mappings":"AAAA,SAASA,WAAW,QAAQ,4BAA4B;AAGxD,SAASC,qBAAqB,QAAQ,yBAAyB;AAE/D;;CAEC,GACD,OAAO,MAAMC,gCAAgC,CAACC;IAC5CH,YAAiCG;IAEjC,6EAA6E;IAC7E,OAAOF,sBAAsBE;AAC/B,EAAE"}

View File

@@ -0,0 +1,92 @@
'use client';
import { useButton_unstable } from '@fluentui/react-button';
import { ChevronLeftRegular, ChevronRightRegular } from '@fluentui/react-icons';
import { mergeCallbacks, useEventCallback, slot, useIsomorphicLayoutEffect, useMergedRefs } from '@fluentui/react-utilities';
import * as React from 'react';
import { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';
import { carouselButtonClassNames } from './useCarouselButtonStyles.styles';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
/**
* Create the state required to render CarouselButton.
*
* The returned state can be modified with hooks such as useCarouselButtonStyles_unstable,
* before being passed to renderCarouselButton_unstable.
*
* @param props - props from this instance of CarouselButton
* @param ref - reference to root HTMLDivElement of CarouselButton
*/ export const useCarouselButton_unstable = (props, ref)=>{
const { navType = 'next', ...buttonProps } = props;
// Locally tracks the total number of slides, will only update if this changes.
const [totalSlides, setTotalSlides] = React.useState(0);
const { dir } = useFluent();
const buttonRef = React.useRef(undefined);
const circular = useCarouselContext((ctx)=>ctx.circular);
const [canLoop, setCanLoop] = React.useState(circular);
const containerRef = useCarouselContext((ctx)=>ctx.containerRef);
const selectPageByDirection = useCarouselContext((ctx)=>ctx.selectPageByDirection);
const subscribeForValues = useCarouselContext((ctx)=>ctx.subscribeForValues);
const resetAutoplay = useCarouselContext((ctx)=>ctx.resetAutoplay);
const isTrailing = useCarouselContext((ctx)=>{
if (circular && canLoop) {
return false;
}
if (navType === 'prev') {
return ctx.activeIndex === 0;
}
return ctx.activeIndex === totalSlides - 1;
});
const handleClick = (event)=>{
if (event.isDefaultPrevented()) {
return;
}
const nextIndex = selectPageByDirection(event, navType);
let _trailing = false;
if (navType === 'prev') {
_trailing = nextIndex === 0;
} else {
_trailing = nextIndex === totalSlides - 1;
}
if (!circular && _trailing && (containerRef === null || containerRef === void 0 ? void 0 : containerRef.current)) {
// Focus non-disabled element
const buttonRefs = containerRef.current.querySelectorAll(`.${carouselButtonClassNames.root}`);
buttonRefs.forEach((_buttonRef)=>{
if (_buttonRef !== buttonRef.current) {
_buttonRef.focus();
}
});
}
resetAutoplay();
};
useIsomorphicLayoutEffect(()=>{
return subscribeForValues((data)=>{
if (data.canLoop !== undefined) {
// Only update canLoop if it has been defined by the carousel engine
setCanLoop(data.canLoop);
}
setTotalSlides(data.navItemsCount);
});
}, [
subscribeForValues
]);
const nextArrowIcon = dir === 'ltr' ? /*#__PURE__*/ React.createElement(ChevronRightRegular, null) : /*#__PURE__*/ React.createElement(ChevronLeftRegular, null);
const prevArrowIcon = dir === 'ltr' ? /*#__PURE__*/ React.createElement(ChevronLeftRegular, null) : /*#__PURE__*/ React.createElement(ChevronRightRegular, null);
return {
navType,
// We lean on react-button class to handle styling and icon enhancements
...useButton_unstable({
icon: slot.optional(props.icon, {
defaultProps: {
children: navType === 'next' ? nextArrowIcon : prevArrowIcon
},
renderByDefault: true,
elementType: 'span'
}),
disabled: isTrailing,
tabIndex: isTrailing ? -1 : 0,
'aria-disabled': isTrailing,
appearance: 'subtle',
...buttonProps,
onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick))
}, useMergedRefs(ref, buttonRef))
};
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,42 @@
'use client';
import { __styles, mergeClasses } from '@griffel/react';
import { useButtonStyles_unstable } from '@fluentui/react-button';
import { tokens } from '@fluentui/react-theme';
export const carouselButtonClassNames = {
root: 'fui-CarouselButton',
icon: 'fui-CarouselButton__icon'
};
/**
* Styles for the root slot
*/
const useStyles = /*#__PURE__*/__styles({
root: {
B6of3ja: "fgr6219",
jrapky: "f10jk5vf",
sj55zd: "fkfq4zb",
De3pzq: "fkfdr9r",
Bkecrkj: "fc5wo7j",
eoavqd: "f8491dx"
}
}, {
d: [".fgr6219{margin-top:auto;}", ".f10jk5vf{margin-bottom:auto;}", ".fkfq4zb{color:var(--colorNeutralForeground2);}", ".fkfdr9r{background-color:var(--colorNeutralBackgroundAlpha);}", ".fc5wo7j{pointer-events:all;}"],
h: [".f8491dx:hover{cursor:pointer;}"]
});
/**
* Apply styling to the CarouselButton slots based on the state
*/
export const useCarouselButtonStyles_unstable = state => {
'use no memo';
const styles = useStyles();
state = {
...state,
...useButtonStyles_unstable(state)
};
state.root.className = mergeClasses(carouselButtonClassNames.root, styles.root, state.root.className);
if (state.icon) {
state.icon.className = mergeClasses(carouselButtonClassNames.icon, state.icon.className);
}
return state;
};

View File

@@ -0,0 +1 @@
{"version":3,"names":["__styles","mergeClasses","useButtonStyles_unstable","tokens","carouselButtonClassNames","root","icon","useStyles","B6of3ja","jrapky","sj55zd","De3pzq","Bkecrkj","eoavqd","d","h","useCarouselButtonStyles_unstable","state","styles","className"],"sources":["useCarouselButtonStyles.styles.js"],"sourcesContent":["'use client';\nimport { makeStyles, mergeClasses } from '@griffel/react';\nimport { useButtonStyles_unstable } from '@fluentui/react-button';\nimport { tokens } from '@fluentui/react-theme';\nexport const carouselButtonClassNames = {\n root: 'fui-CarouselButton',\n icon: 'fui-CarouselButton__icon'\n};\n/**\n * Styles for the root slot\n */ const useStyles = makeStyles({\n root: {\n marginTop: 'auto',\n marginBottom: 'auto',\n color: tokens.colorNeutralForeground2,\n backgroundColor: tokens.colorNeutralBackgroundAlpha,\n pointerEvents: 'all',\n ':hover': {\n cursor: 'pointer'\n }\n }\n});\n/**\n * Apply styling to the CarouselButton slots based on the state\n */ export const useCarouselButtonStyles_unstable = (state)=>{\n 'use no memo';\n const styles = useStyles();\n state = {\n ...state,\n ...useButtonStyles_unstable(state)\n };\n state.root.className = mergeClasses(carouselButtonClassNames.root, styles.root, state.root.className);\n if (state.icon) {\n state.icon.className = mergeClasses(carouselButtonClassNames.icon, state.icon.className);\n }\n return state;\n};\n"],"mappings":"AAAA,YAAY;;AACZ,SAAAA,QAAA,EAAqBC,YAAY,QAAQ,gBAAgB;AACzD,SAASC,wBAAwB,QAAQ,wBAAwB;AACjE,SAASC,MAAM,QAAQ,uBAAuB;AAC9C,OAAO,MAAMC,wBAAwB,GAAG;EACpCC,IAAI,EAAE,oBAAoB;EAC1BC,IAAI,EAAE;AACV,CAAC;AACD;AACA;AACA;AAAI,MAAMC,SAAS,gBAAGP,QAAA;EAAAK,IAAA;IAAAG,OAAA;IAAAC,MAAA;IAAAC,MAAA;IAAAC,MAAA;IAAAC,OAAA;IAAAC,MAAA;EAAA;AAAA;EAAAC,CAAA;EAAAC,CAAA;AAAA,CAWrB,CAAC;AACF;AACA;AACA;AAAI,OAAO,MAAMC,gCAAgC,GAAIC,KAAK,IAAG;EACzD,aAAa;;EACb,MAAMC,MAAM,GAAGX,SAAS,CAAC,CAAC;EAC1BU,KAAK,GAAG;IACJ,GAAGA,KAAK;IACR,GAAGf,wBAAwB,CAACe,KAAK;EACrC,CAAC;EACDA,KAAK,CAACZ,IAAI,CAACc,SAAS,GAAGlB,YAAY,CAACG,wBAAwB,CAACC,IAAI,EAAEa,MAAM,CAACb,IAAI,EAAEY,KAAK,CAACZ,IAAI,CAACc,SAAS,CAAC;EACrG,IAAIF,KAAK,CAACX,IAAI,EAAE;IACZW,KAAK,CAACX,IAAI,CAACa,SAAS,GAAGlB,YAAY,CAACG,wBAAwB,CAACE,IAAI,EAAEW,KAAK,CAACX,IAAI,CAACa,SAAS,CAAC;EAC5F;EACA,OAAOF,KAAK;AAChB,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,37 @@
'use client';
import { makeStyles, mergeClasses } from '@griffel/react';
import { useButtonStyles_unstable } from '@fluentui/react-button';
import { tokens } from '@fluentui/react-theme';
export const carouselButtonClassNames = {
root: 'fui-CarouselButton',
icon: 'fui-CarouselButton__icon'
};
/**
* Styles for the root slot
*/ const useStyles = makeStyles({
root: {
marginTop: 'auto',
marginBottom: 'auto',
color: tokens.colorNeutralForeground2,
backgroundColor: tokens.colorNeutralBackgroundAlpha,
pointerEvents: 'all',
':hover': {
cursor: 'pointer'
}
}
});
/**
* Apply styling to the CarouselButton slots based on the state
*/ export const useCarouselButtonStyles_unstable = (state)=>{
'use no memo';
const styles = useStyles();
state = {
...state,
...useButtonStyles_unstable(state)
};
state.root.className = mergeClasses(carouselButtonClassNames.root, styles.root, state.root.className);
if (state.icon) {
state.icon.className = mergeClasses(carouselButtonClassNames.icon, state.icon.className);
}
return state;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CarouselButton/useCarouselButtonStyles.styles.ts"],"sourcesContent":["'use client';\n\nimport { makeStyles, mergeClasses } from '@griffel/react';\nimport type { SlotClassNames } from '@fluentui/react-utilities';\nimport type { CarouselButtonSlots, CarouselButtonState } from './CarouselButton.types';\nimport { useButtonStyles_unstable } from '@fluentui/react-button';\nimport { tokens } from '@fluentui/react-theme';\n\nexport const carouselButtonClassNames: SlotClassNames<CarouselButtonSlots> = {\n root: 'fui-CarouselButton',\n icon: 'fui-CarouselButton__icon',\n};\n\n/**\n * Styles for the root slot\n */\nconst useStyles = makeStyles({\n root: {\n marginTop: 'auto',\n marginBottom: 'auto',\n color: tokens.colorNeutralForeground2,\n backgroundColor: tokens.colorNeutralBackgroundAlpha,\n pointerEvents: 'all',\n ':hover': {\n cursor: 'pointer',\n },\n },\n});\n\n/**\n * Apply styling to the CarouselButton slots based on the state\n */\nexport const useCarouselButtonStyles_unstable = (state: CarouselButtonState): CarouselButtonState => {\n 'use no memo';\n\n const styles = useStyles();\n\n state = {\n ...state,\n ...useButtonStyles_unstable(state),\n };\n\n state.root.className = mergeClasses(carouselButtonClassNames.root, styles.root, state.root.className);\n\n if (state.icon) {\n state.icon.className = mergeClasses(carouselButtonClassNames.icon, state.icon.className);\n }\n\n return state;\n};\n"],"names":["makeStyles","mergeClasses","useButtonStyles_unstable","tokens","carouselButtonClassNames","root","icon","useStyles","marginTop","marginBottom","color","colorNeutralForeground2","backgroundColor","colorNeutralBackgroundAlpha","pointerEvents","cursor","useCarouselButtonStyles_unstable","state","styles","className"],"mappings":"AAAA;AAEA,SAASA,UAAU,EAAEC,YAAY,QAAQ,iBAAiB;AAG1D,SAASC,wBAAwB,QAAQ,yBAAyB;AAClE,SAASC,MAAM,QAAQ,wBAAwB;AAE/C,OAAO,MAAMC,2BAAgE;IAC3EC,MAAM;IACNC,MAAM;AACR,EAAE;AAEF;;CAEC,GACD,MAAMC,YAAYP,WAAW;IAC3BK,MAAM;QACJG,WAAW;QACXC,cAAc;QACdC,OAAOP,OAAOQ,uBAAuB;QACrCC,iBAAiBT,OAAOU,2BAA2B;QACnDC,eAAe;QACf,UAAU;YACRC,QAAQ;QACV;IACF;AACF;AAEA;;CAEC,GACD,OAAO,MAAMC,mCAAmC,CAACC;IAC/C;IAEA,MAAMC,SAASX;IAEfU,QAAQ;QACN,GAAGA,KAAK;QACR,GAAGf,yBAAyBe,MAAM;IACpC;IAEAA,MAAMZ,IAAI,CAACc,SAAS,GAAGlB,aAAaG,yBAAyBC,IAAI,EAAEa,OAAOb,IAAI,EAAEY,MAAMZ,IAAI,CAACc,SAAS;IAEpG,IAAIF,MAAMX,IAAI,EAAE;QACdW,MAAMX,IAAI,CAACa,SAAS,GAAGlB,aAAaG,yBAAyBE,IAAI,EAAEW,MAAMX,IAAI,CAACa,SAAS;IACzF;IAEA,OAAOF;AACT,EAAE"}