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,15 @@
'use client';
import * as React from 'react';
import { useCardHeader_unstable } from './useCardHeader';
import { renderCardHeader_unstable } from './renderCardHeader';
import { useCardHeaderStyles_unstable } from './useCardHeaderStyles.styles';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';
/**
* Component to render an image, text and an action in a Card component.
*/ export const CardHeader = /*#__PURE__*/ React.forwardRef((props, ref)=>{
const state = useCardHeader_unstable(props, ref);
useCardHeaderStyles_unstable(state);
useCustomStyleHook_unstable('useCardHeaderStyles_unstable')(state);
return renderCardHeader_unstable(state);
});
CardHeader.displayName = 'CardHeader';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CardHeader/CardHeader.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useCardHeader_unstable } from './useCardHeader';\nimport { renderCardHeader_unstable } from './renderCardHeader';\nimport { useCardHeaderStyles_unstable } from './useCardHeaderStyles.styles';\nimport type { CardHeaderProps } from './CardHeader.types';\nimport type { ForwardRefComponent } from '@fluentui/react-utilities';\nimport { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';\n\n/**\n * Component to render an image, text and an action in a Card component.\n */\nexport const CardHeader: ForwardRefComponent<CardHeaderProps> = React.forwardRef((props, ref) => {\n const state = useCardHeader_unstable(props, ref);\n\n useCardHeaderStyles_unstable(state);\n\n useCustomStyleHook_unstable('useCardHeaderStyles_unstable')(state);\n\n return renderCardHeader_unstable(state);\n});\n\nCardHeader.displayName = 'CardHeader';\n"],"names":["React","useCardHeader_unstable","renderCardHeader_unstable","useCardHeaderStyles_unstable","useCustomStyleHook_unstable","CardHeader","forwardRef","props","ref","state","displayName"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsB,QAAQ,kBAAkB;AACzD,SAASC,yBAAyB,QAAQ,qBAAqB;AAC/D,SAASC,4BAA4B,QAAQ,+BAA+B;AAG5E,SAASC,2BAA2B,QAAQ,kCAAkC;AAE9E;;CAEC,GACD,OAAO,MAAMC,2BAAmDL,MAAMM,UAAU,CAAC,CAACC,OAAOC;IACvF,MAAMC,QAAQR,uBAAuBM,OAAOC;IAE5CL,6BAA6BM;IAE7BL,4BAA4B,gCAAgCK;IAE5D,OAAOP,0BAA0BO;AACnC,GAAG;AAEHJ,WAAWK,WAAW,GAAG"}

View File

@@ -0,0 +1,3 @@
/**
* CardHeader base state (same as CardHeaderState since CardHeader has no design props)
*/ export { };

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CardHeader/CardHeader.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\n\n/**\n * Slots available in the CardHeader component.\n */\nexport type CardHeaderSlots = {\n /**\n * Root element of the component.\n */\n root: Slot<'div'>;\n\n /**\n * Element used to render an image or avatar related to the card.\n */\n image: Slot<'div', 'img'>;\n\n /**\n * Element used to render the main header title.\n */\n header: Slot<'div'>;\n\n /**\n * Element used to render short descriptions related to the title.\n */\n description: Slot<'div'>;\n\n /**\n * Container that renders on the far end of the footer, used for action buttons.\n */\n action?: Slot<'div'>;\n};\n\n/**\n * CardHeader component props.\n */\nexport type CardHeaderProps = ComponentProps<Partial<CardHeaderSlots>>;\n\n/**\n * CardHeader base props (same as CardHeaderProps since CardHeader has no design props)\n */\nexport type CardHeaderBaseProps = CardHeaderProps;\n\n/**\n * State used in rendering CardHeader.\n */\nexport type CardHeaderState = ComponentState<CardHeaderSlots>;\n\n/**\n * CardHeader base state (same as CardHeaderState since CardHeader has no design props)\n */\nexport type CardHeaderBaseState = CardHeaderState;\n"],"names":[],"mappings":"AA+CA;;CAEC,GACD,WAAkD"}

View File

@@ -0,0 +1,4 @@
export { CardHeader } from './CardHeader';
export { renderCardHeader_unstable } from './renderCardHeader';
export { useCardHeader_unstable, useCardHeaderBase_unstable } from './useCardHeader';
export { cardHeaderCSSVars, cardHeaderClassNames, useCardHeaderStyles_unstable } from './useCardHeaderStyles.styles';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CardHeader/index.ts"],"sourcesContent":["export { CardHeader } from './CardHeader';\nexport type {\n CardHeaderBaseProps,\n CardHeaderBaseState,\n CardHeaderProps,\n CardHeaderSlots,\n CardHeaderState,\n} from './CardHeader.types';\nexport { renderCardHeader_unstable } from './renderCardHeader';\nexport { useCardHeader_unstable, useCardHeaderBase_unstable } from './useCardHeader';\nexport { cardHeaderCSSVars, cardHeaderClassNames, useCardHeaderStyles_unstable } from './useCardHeaderStyles.styles';\n"],"names":["CardHeader","renderCardHeader_unstable","useCardHeader_unstable","useCardHeaderBase_unstable","cardHeaderCSSVars","cardHeaderClassNames","useCardHeaderStyles_unstable"],"mappings":"AAAA,SAASA,UAAU,QAAQ,eAAe;AAQ1C,SAASC,yBAAyB,QAAQ,qBAAqB;AAC/D,SAASC,sBAAsB,EAAEC,0BAA0B,QAAQ,kBAAkB;AACrF,SAASC,iBAAiB,EAAEC,oBAAoB,EAAEC,4BAA4B,QAAQ,+BAA+B"}

View File

@@ -0,0 +1,15 @@
import { jsx as _jsx, jsxs as _jsxs } from "@fluentui/react-jsx-runtime/jsx-runtime";
import { assertSlots } from '@fluentui/react-utilities';
/**
* Render the final JSX of CardHeader.
*/ export const renderCardHeader_unstable = (state)=>{
assertSlots(state);
return /*#__PURE__*/ _jsxs(state.root, {
children: [
state.image && /*#__PURE__*/ _jsx(state.image, {}),
state.header && /*#__PURE__*/ _jsx(state.header, {}),
state.description && /*#__PURE__*/ _jsx(state.description, {}),
state.action && /*#__PURE__*/ _jsx(state.action, {})
]
});
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/CardHeader/renderCardHeader.tsx"],"sourcesContent":["/** @jsxRuntime automatic */\n/** @jsxImportSource @fluentui/react-jsx-runtime */\n\nimport { assertSlots } from '@fluentui/react-utilities';\nimport type { JSXElement } from '@fluentui/react-utilities';\nimport type { CardHeaderSlots, CardHeaderBaseState } from './CardHeader.types';\n\n/**\n * Render the final JSX of CardHeader.\n */\nexport const renderCardHeader_unstable = (state: CardHeaderBaseState): JSXElement => {\n assertSlots<CardHeaderSlots>(state);\n\n return (\n <state.root>\n {state.image && <state.image />}\n {state.header && <state.header />}\n {state.description && <state.description />}\n {state.action && <state.action />}\n </state.root>\n );\n};\n"],"names":["assertSlots","renderCardHeader_unstable","state","root","image","header","description","action"],"mappings":"AAAA,0BAA0B,GAC1B,iDAAiD;AAEjD,SAASA,WAAW,QAAQ,4BAA4B;AAIxD;;CAEC,GACD,OAAO,MAAMC,4BAA4B,CAACC;IACxCF,YAA6BE;IAE7B,qBACE,MAACA,MAAMC,IAAI;;YACRD,MAAME,KAAK,kBAAI,KAACF,MAAME,KAAK;YAC3BF,MAAMG,MAAM,kBAAI,KAACH,MAAMG,MAAM;YAC7BH,MAAMI,WAAW,kBAAI,KAACJ,MAAMI,WAAW;YACvCJ,MAAMK,MAAM,kBAAI,KAACL,MAAMK,MAAM;;;AAGpC,EAAE"}

View File

@@ -0,0 +1,105 @@
'use client';
import * as React from 'react';
import { getIntrinsicElementProps, useId, slot } from '@fluentui/react-utilities';
import { useCardContext_unstable } from '../Card/CardContext';
import { cardHeaderClassNames } from './useCardHeaderStyles.styles';
/**
* Finds the first child of CardHeader with an id prop.
*
* @param header - the header prop of CardHeader
*/ function getChildWithId(header) {
function isReactElementWithIdProp(element) {
return React.isValidElement(element) && Boolean(element.props.id);
}
return React.Children.toArray(header).find(isReactElementWithIdProp);
}
/**
* Returns the id to use for the CardHeader root element.
*
* @param headerId - the id prop of the CardHeader component
* @param childWithId - the first child of the CardHeader component with an id prop
* @param generatedId - a generated id
*
* @returns the id to use for the CardHeader root element
*/ function getReferenceId(headerId, childWithId, generatedId) {
if (headerId) {
return headerId;
}
if (childWithId === null || childWithId === void 0 ? void 0 : childWithId.props.id) {
return childWithId.props.id;
}
return generatedId;
}
/**
* Create the state required to render CardHeader.
*
* The returned state can be modified with hooks such as useCardHeaderStyles_unstable,
* before being passed to renderCardHeader_unstable.
*
* @param props - props from this instance of CardHeader
* @param ref - reference to root HTMLElement of CardHeader
*/ export const useCardHeader_unstable = (props, ref)=>{
return useCardHeaderBase_unstable(props, ref);
};
/**
* Base hook for CardHeader component, which manages state related to slots structure
* and the card's selectable accessibility properties.
* Note: CardHeader has no design props, so this is equivalent to useCardHeader_unstable.
*
* @param props - props from this instance of CardHeader
* @param ref - reference to root HTMLElement of CardHeader
*/ export const useCardHeaderBase_unstable = (props, ref)=>{
const { image, header, description, action } = props;
const { selectableA11yProps: { referenceId, setReferenceId } } = useCardContext_unstable();
const headerRef = React.useRef(null);
const hasChildId = React.useRef(false);
const generatedId = useId(cardHeaderClassNames.header, referenceId);
const headerSlot = slot.optional(header, {
renderByDefault: true,
defaultProps: {
ref: headerRef,
id: !hasChildId.current ? referenceId : undefined
},
elementType: 'div'
});
React.useEffect(()=>{
var _headerRef_current;
const headerId = !hasChildId.current ? (_headerRef_current = headerRef.current) === null || _headerRef_current === void 0 ? void 0 : _headerRef_current.id : undefined;
const childWithId = getChildWithId(headerSlot === null || headerSlot === void 0 ? void 0 : headerSlot.children);
hasChildId.current = Boolean(childWithId);
setReferenceId(getReferenceId(headerId, childWithId, generatedId));
}, [
generatedId,
header,
headerSlot,
setReferenceId
]);
return {
components: {
root: 'div',
image: 'div',
header: 'div',
description: 'div',
action: 'div'
},
root: slot.always(getIntrinsicElementProps('div', {
// FIXME:
// `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement`
// but since it would be a breaking change to fix it, we are casting ref to it's proper type
ref: ref,
...props
}), {
elementType: 'div'
}),
image: slot.optional(image, {
elementType: 'div'
}),
header: headerSlot,
description: slot.optional(description, {
elementType: 'div'
}),
action: slot.optional(action, {
elementType: 'div'
})
};
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,123 @@
'use client';
import { __styles, mergeClasses, shorthands } from '@griffel/react';
/**
* Static CSS class names used internally for the component slots.
*/
export const cardHeaderClassNames = {
root: 'fui-CardHeader',
image: 'fui-CardHeader__image',
header: 'fui-CardHeader__header',
description: 'fui-CardHeader__description',
action: 'fui-CardHeader__action'
};
/**
* CSS variable names used internally for uniform styling in CardHeader.
*/
export const cardHeaderCSSVars = {
cardHeaderGapVar: '--fui-CardHeader--gap'
};
const useStyles = /*#__PURE__*/__styles({
root: {
Bkc6ea2: "fkufhic",
Bt984gj: "f122n59"
},
image: {
mc9l5x: "ftuwxu6",
t21cq0: ["fql5097", "f6yss9k"]
},
header: {
mc9l5x: "f22iagw"
},
description: {
mc9l5x: "f22iagw"
},
action: {
Frg6f3: ["f6yss9k", "fql5097"],
rjrqlh: "fs9eatd",
Boue1pl: ["fxoo9ru", "f1g0ekvh"],
Bhz1vi0: "f1m6zfxz",
etxrgc: ["f1g0ekvh", "fxoo9ru"],
Bdua9ef: "f1sret3r",
cbfxhg: "fs4gbcv"
}
}, {
d: [".fkufhic{--fui-CardHeader--gap:12px;}", ".f122n59{align-items:center;}", ".ftuwxu6{display:inline-flex;}", ".fql5097{margin-right:var(--fui-CardHeader--gap);}", ".f6yss9k{margin-left:var(--fui-CardHeader--gap);}", ".f22iagw{display:flex;}"],
m: [["@media (forced-colors: active){.fs9eatd .fui-Button,.fs9eatd .fui-Link{border-top-color:currentColor;}}", {
m: "(forced-colors: active)"
}], ["@media (forced-colors: active){.f1g0ekvh .fui-Button,.f1g0ekvh .fui-Link{border-left-color:currentColor;}.fxoo9ru .fui-Button,.fxoo9ru .fui-Link{border-right-color:currentColor;}}", {
m: "(forced-colors: active)"
}], ["@media (forced-colors: active){.f1m6zfxz .fui-Button,.f1m6zfxz .fui-Link{border-bottom-color:currentColor;}}", {
m: "(forced-colors: active)"
}], ["@media (forced-colors: active){.f1sret3r .fui-Button,.f1sret3r .fui-Link{color:currentColor;}}", {
m: "(forced-colors: active)"
}], ["@media (forced-colors: active){.fs4gbcv .fui-Button,.fs4gbcv .fui-Link{outline-color:currentColor;}}", {
m: "(forced-colors: active)"
}]]
});
const useStylesGrid = /*#__PURE__*/__styles({
root: {
mc9l5x: "f13qh94s",
t4k1zu: "f8a668j"
},
image: {
Br312pm: "fwpfdsa",
Ijaq50: "fldnz9j"
},
header: {
Br312pm: "fd46tj4",
Ijaq50: "f16hsg94"
},
description: {
Br312pm: "fd46tj4",
Ijaq50: "faunodf"
},
action: {
Br312pm: "fis13di",
Ijaq50: "fldnz9j"
}
}, {
d: [".f13qh94s{display:grid;}", ".f8a668j{grid-auto-columns:min-content 1fr min-content;}", ".fwpfdsa{grid-column-start:1;}", ".fldnz9j{grid-row-start:span 2;}", ".fd46tj4{grid-column-start:2;}", ".f16hsg94{grid-row-start:1;}", ".faunodf{grid-row-start:2;}", ".fis13di{grid-column-start:3;}"]
});
const useStylesFlex = /*#__PURE__*/__styles({
root: {
mc9l5x: "f22iagw"
},
header: {
Bh6795r: "fqerorx"
},
image: {},
description: {},
action: {}
}, {
d: [".f22iagw{display:flex;}", ".fqerorx{flex-grow:1;}"]
});
/**
* Apply styling to the CardHeader slots based on the state.
*/
export const useCardHeaderStyles_unstable = state => {
'use no memo';
const styles = useStyles();
const stylesGrid = useStylesGrid();
const stylesFlex = useStylesFlex();
const boxModelStyles = state.description ? stylesGrid : stylesFlex;
const getSlotStyles = slotName => {
var _state_slotName;
return mergeClasses(cardHeaderClassNames[slotName], styles[slotName], boxModelStyles[slotName], (_state_slotName = state[slotName]) === null || _state_slotName === void 0 ? void 0 : _state_slotName.className);
};
state.root.className = getSlotStyles('root');
if (state.image) {
state.image.className = getSlotStyles('image');
}
if (state.header) {
state.header.className = getSlotStyles('header');
}
if (state.description) {
state.description.className = getSlotStyles('description');
}
if (state.action) {
state.action.className = getSlotStyles('action');
}
return state;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,104 @@
'use client';
import { makeStyles, mergeClasses, shorthands } from '@griffel/react';
/**
* Static CSS class names used internally for the component slots.
*/ export const cardHeaderClassNames = {
root: 'fui-CardHeader',
image: 'fui-CardHeader__image',
header: 'fui-CardHeader__header',
description: 'fui-CardHeader__description',
action: 'fui-CardHeader__action'
};
/**
* CSS variable names used internally for uniform styling in CardHeader.
*/ export const cardHeaderCSSVars = {
cardHeaderGapVar: '--fui-CardHeader--gap'
};
const useStyles = makeStyles({
root: {
[cardHeaderCSSVars.cardHeaderGapVar]: '12px',
alignItems: 'center'
},
image: {
display: 'inline-flex',
marginRight: `var(${cardHeaderCSSVars.cardHeaderGapVar})`
},
header: {
display: 'flex'
},
description: {
display: 'flex'
},
action: {
marginLeft: `var(${cardHeaderCSSVars.cardHeaderGapVar})`,
// when the card is selected or hovered, it has custom high contrast color and background styles
// setting this ensures action buttons adopt those colors and are still visible in forced-colors mode
'@media (forced-colors: active)': {
'& .fui-Button, & .fui-Link': {
...shorthands.borderColor('currentColor'),
color: 'currentColor',
outlineColor: 'currentColor'
}
}
}
});
const useStylesGrid = makeStyles({
root: {
display: 'grid',
gridAutoColumns: 'min-content 1fr min-content'
},
image: {
gridColumnStart: '1',
gridRowStart: 'span 2'
},
header: {
gridColumnStart: '2',
gridRowStart: '1'
},
description: {
gridColumnStart: '2',
gridRowStart: '2'
},
action: {
gridColumnStart: '3',
gridRowStart: 'span 2'
}
});
const useStylesFlex = makeStyles({
root: {
display: 'flex'
},
header: {
flexGrow: 1
},
image: {},
description: {},
action: {}
});
/**
* Apply styling to the CardHeader slots based on the state.
*/ export const useCardHeaderStyles_unstable = (state)=>{
'use no memo';
const styles = useStyles();
const stylesGrid = useStylesGrid();
const stylesFlex = useStylesFlex();
const boxModelStyles = state.description ? stylesGrid : stylesFlex;
const getSlotStyles = (slotName)=>{
var _state_slotName;
return mergeClasses(cardHeaderClassNames[slotName], styles[slotName], boxModelStyles[slotName], (_state_slotName = state[slotName]) === null || _state_slotName === void 0 ? void 0 : _state_slotName.className);
};
state.root.className = getSlotStyles('root');
if (state.image) {
state.image.className = getSlotStyles('image');
}
if (state.header) {
state.header.className = getSlotStyles('header');
}
if (state.description) {
state.description.className = getSlotStyles('description');
}
if (state.action) {
state.action.className = getSlotStyles('action');
}
return state;
};

File diff suppressed because one or more lines are too long