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,17 @@
'use client';
import * as React from 'react';
import { useMenuList_unstable } from './useMenuList';
import { renderMenuList_unstable } from './renderMenuList';
import { useMenuListContextValues_unstable } from './useMenuListContextValues';
import { useMenuListStyles_unstable } from './useMenuListStyles.styles';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';
/**
* Define a styled MenuList, using the `useMenuList_unstable` hook.
*/ export const MenuList = /*#__PURE__*/ React.forwardRef((props, ref)=>{
const state = useMenuList_unstable(props, ref);
const contextValues = useMenuListContextValues_unstable(state);
useMenuListStyles_unstable(state);
useCustomStyleHook_unstable('useMenuListStyles_unstable')(state);
return renderMenuList_unstable(state, contextValues);
});
MenuList.displayName = 'MenuList';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/MenuList/MenuList.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useMenuList_unstable } from './useMenuList';\nimport { renderMenuList_unstable } from './renderMenuList';\nimport { useMenuListContextValues_unstable } from './useMenuListContextValues';\nimport { useMenuListStyles_unstable } from './useMenuListStyles.styles';\nimport type { MenuListProps } from './MenuList.types';\nimport type { ForwardRefComponent } from '@fluentui/react-utilities';\nimport { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';\n\n/**\n * Define a styled MenuList, using the `useMenuList_unstable` hook.\n */\nexport const MenuList: ForwardRefComponent<MenuListProps> = React.forwardRef((props, ref) => {\n const state = useMenuList_unstable(props, ref);\n const contextValues = useMenuListContextValues_unstable(state);\n\n useMenuListStyles_unstable(state);\n\n useCustomStyleHook_unstable('useMenuListStyles_unstable')(state);\n\n return renderMenuList_unstable(state, contextValues);\n});\n\nMenuList.displayName = 'MenuList';\n"],"names":["React","useMenuList_unstable","renderMenuList_unstable","useMenuListContextValues_unstable","useMenuListStyles_unstable","useCustomStyleHook_unstable","MenuList","forwardRef","props","ref","state","contextValues","displayName"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,oBAAoB,QAAQ,gBAAgB;AACrD,SAASC,uBAAuB,QAAQ,mBAAmB;AAC3D,SAASC,iCAAiC,QAAQ,6BAA6B;AAC/E,SAASC,0BAA0B,QAAQ,6BAA6B;AAGxE,SAASC,2BAA2B,QAAQ,kCAAkC;AAE9E;;CAEC,GACD,OAAO,MAAMC,yBAA+CN,MAAMO,UAAU,CAAC,CAACC,OAAOC;IACnF,MAAMC,QAAQT,qBAAqBO,OAAOC;IAC1C,MAAME,gBAAgBR,kCAAkCO;IAExDN,2BAA2BM;IAE3BL,4BAA4B,8BAA8BK;IAE1D,OAAOR,wBAAwBQ,OAAOC;AACxC,GAAG;AAEHL,SAASM,WAAW,GAAG"}

View File

@@ -0,0 +1 @@
import * as React from 'react';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/MenuList/MenuList.types.ts"],"sourcesContent":["import * as React from 'react';\nimport type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport type { MenuListContextValue } from '../../contexts/menuListContext';\nimport type { SelectableHandler } from '../../selectable/index';\n\nexport type MenuCheckedValueChangeEvent = React.MouseEvent | React.KeyboardEvent;\n\nexport type MenuCheckedValueChangeData = {\n /** The items for this value that are checked */\n checkedItems: string[];\n /** The name of the value */\n name: string;\n};\n\nexport type MenuListSlots = {\n root: Slot<'div'>;\n};\n\nexport type MenuListProps = ComponentProps<MenuListSlots> & {\n /**\n * Map of all checked values\n */\n checkedValues?: Record<string, string[]>;\n\n /**\n * Default values to be checked on mount\n */\n defaultCheckedValues?: Record<string, string[]>;\n\n /**\n * States that menu items can contain selectable items and reserve slots for item alignment\n */\n hasCheckmarks?: boolean;\n\n /**\n * States that menu items can contain icons and reserve slots for item alignment\n */\n hasIcons?: boolean;\n\n /**\n * Callback when checked items change for value with a name\n *\n * @param event - React's original SyntheticEvent\n * @param data - A data object with relevant information\n */\n // eslint-disable-next-line @nx/workspace-consistent-callback-type -- can't change type of existing callback\n onCheckedValueChange?: (e: MenuCheckedValueChangeEvent, data: MenuCheckedValueChangeData) => void;\n};\n\nexport type MenuListState = ComponentState<MenuListSlots> &\n Required<Pick<MenuListProps, 'checkedValues' | 'hasCheckmarks' | 'hasIcons'>> &\n Pick<MenuListProps, 'defaultCheckedValues' | 'onCheckedValueChange'> & {\n /**\n * Selects a radio item, will de-select the currently selected ratio item\n */\n selectRadio: SelectableHandler;\n\n /**\n * Callback to set focus on the next menu item by first character\n */\n setFocusByFirstCharacter: NonNullable<MenuListContextValue['setFocusByFirstCharacter']>;\n\n /*\n * Toggles the state of a checkbox item\n */\n toggleCheckbox: SelectableHandler;\n\n /**\n * States if the MenuList is inside MenuContext\n */\n hasMenuContext?: boolean;\n };\n\nexport type MenuListContextValues = {\n menuList: MenuListContextValue;\n};\n\n/**\n * @deprecated this type is not being used internally anymore\n */\nexport type UninitializedMenuListState = Omit<\n MenuListState,\n 'checkedValues' | 'selectRadio' | 'setFocusByFirstCharacter' | 'toggleCheckbox'\n> &\n Partial<Pick<MenuListState, 'checkedValues'>>;\n"],"names":["React"],"mappings":"AAAA,YAAYA,WAAW,QAAQ"}

View File

@@ -0,0 +1,5 @@
export { MenuList } from './MenuList';
export { renderMenuList_unstable } from './renderMenuList';
export { useMenuList_unstable } from './useMenuList';
export { menuListClassNames, useMenuListStyles_unstable } from './useMenuListStyles.styles';
export { useMenuListContextValues_unstable } from './useMenuListContextValues';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/MenuList/index.ts"],"sourcesContent":["export { MenuList } from './MenuList';\nexport type {\n MenuCheckedValueChangeData,\n MenuCheckedValueChangeEvent,\n MenuListContextValues,\n MenuListProps,\n MenuListSlots,\n MenuListState,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n UninitializedMenuListState,\n} from './MenuList.types';\nexport { renderMenuList_unstable } from './renderMenuList';\nexport { useMenuList_unstable } from './useMenuList';\nexport { menuListClassNames, useMenuListStyles_unstable } from './useMenuListStyles.styles';\nexport { useMenuListContextValues_unstable } from './useMenuListContextValues';\n"],"names":["MenuList","renderMenuList_unstable","useMenuList_unstable","menuListClassNames","useMenuListStyles_unstable","useMenuListContextValues_unstable"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,aAAa;AAWtC,SAASC,uBAAuB,QAAQ,mBAAmB;AAC3D,SAASC,oBAAoB,QAAQ,gBAAgB;AACrD,SAASC,kBAAkB,EAAEC,0BAA0B,QAAQ,6BAA6B;AAC5F,SAASC,iCAAiC,QAAQ,6BAA6B"}

View File

@@ -0,0 +1,12 @@
import { jsx as _jsx } from "@fluentui/react-jsx-runtime/jsx-runtime";
import { assertSlots } from '@fluentui/react-utilities';
import { MenuListProvider } from '../../contexts/menuListContext';
/**
* Function that renders the final JSX of the component
*/ export const renderMenuList_unstable = (state, contextValues)=>{
assertSlots(state);
return /*#__PURE__*/ _jsx(MenuListProvider, {
value: contextValues.menuList,
children: /*#__PURE__*/ _jsx(state.root, {})
});
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/MenuList/renderMenuList.tsx"],"sourcesContent":["/** @jsxRuntime automatic */\n/** @jsxImportSource @fluentui/react-jsx-runtime */\nimport { assertSlots } from '@fluentui/react-utilities';\nimport type { JSXElement } from '@fluentui/react-utilities';\nimport { MenuListContextValues, MenuListSlots, MenuListState } from './MenuList.types';\nimport { MenuListProvider } from '../../contexts/menuListContext';\n\n/**\n * Function that renders the final JSX of the component\n */\nexport const renderMenuList_unstable = (state: MenuListState, contextValues: MenuListContextValues): JSXElement => {\n assertSlots<MenuListSlots>(state);\n\n return (\n <MenuListProvider value={contextValues.menuList}>\n <state.root />\n </MenuListProvider>\n );\n};\n"],"names":["assertSlots","MenuListProvider","renderMenuList_unstable","state","contextValues","value","menuList","root"],"mappings":"AAAA,0BAA0B,GAC1B,iDAAiD;AACjD,SAASA,WAAW,QAAQ,4BAA4B;AAGxD,SAASC,gBAAgB,QAAQ,iCAAiC;AAElE;;CAEC,GACD,OAAO,MAAMC,0BAA0B,CAACC,OAAsBC;IAC5DJ,YAA2BG;IAE3B,qBACE,KAACF;QAAiBI,OAAOD,cAAcE,QAAQ;kBAC7C,cAAA,KAACH,MAAMI,IAAI;;AAGjB,EAAE"}

View File

@@ -0,0 +1,179 @@
'use client';
import * as React from 'react';
import { useMergedRefs, useEventCallback, useControllableState, getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import { useArrowNavigationGroup, useFocusFinders, TabsterMoveFocusEventName } from '@fluentui/react-tabster';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { useHasParentContext } from '@fluentui/react-context-selector';
import { useMenuContext_unstable } from '../../contexts/menuContext';
import { MenuContext } from '../../contexts/menuContext';
import { useValidateNesting } from '../../utils/useValidateNesting';
/**
* Returns the props and state required to render the component
*/ export const useMenuList_unstable = (props, ref)=>{
const { findAllFocusable } = useFocusFinders();
const { targetDocument } = useFluent();
const menuContext = useMenuContextSelectors();
const hasMenuContext = useHasParentContext(MenuContext);
const focusAttributes = useArrowNavigationGroup({
circular: true
});
if (usingPropsAndMenuContext(props, menuContext, hasMenuContext)) {
// TODO throw warnings in development safely
// eslint-disable-next-line no-console
console.warn('You are using both MenuList and Menu props, we recommend you to use Menu props when available');
}
const innerRef = React.useRef(null);
const validateNestingRef = useValidateNesting('MenuList');
React.useEffect(()=>{
const element = innerRef.current;
if (hasMenuContext && targetDocument && element) {
const onTabsterMoveFocus = (e)=>{
const nextElement = e.detail.next;
if (nextElement && element.contains(targetDocument.activeElement) && !element.contains(nextElement)) {
// Preventing Tabster from handling Tab press, useMenuPopover will handle it.
e.preventDefault();
}
};
targetDocument.addEventListener(TabsterMoveFocusEventName, onTabsterMoveFocus);
return ()=>{
targetDocument.removeEventListener(TabsterMoveFocusEventName, onTabsterMoveFocus);
};
}
}, [
innerRef,
targetDocument,
hasMenuContext
]);
const setFocusByFirstCharacter = React.useCallback((e, itemEl)=>{
// TODO use some kind of children registration to reduce dependency on DOM roles
const acceptedRoles = [
'menuitem',
'menuitemcheckbox',
'menuitemradio'
];
if (!innerRef.current) {
return;
}
const menuItems = findAllFocusable(innerRef.current, (el)=>el.hasAttribute('role') && acceptedRoles.indexOf(el.getAttribute('role')) !== -1);
let startIndex = menuItems.indexOf(itemEl) + 1;
if (startIndex === menuItems.length) {
startIndex = 0;
}
const firstChars = menuItems.map((menuItem)=>{
var _menuItem_textContent;
return (_menuItem_textContent = menuItem.textContent) === null || _menuItem_textContent === void 0 ? void 0 : _menuItem_textContent.charAt(0).toLowerCase();
});
const char = e.key.toLowerCase();
const getIndexFirstChars = (start, firstChar)=>{
for(let i = start; i < firstChars.length; i++){
if (char === firstChars[i]) {
return i;
}
}
return -1;
};
// Check remaining slots in the menu
let index = getIndexFirstChars(startIndex, char);
// If not found in remaining slots, check from beginning
if (index === -1) {
index = getIndexFirstChars(0, char);
}
// If match was found...
if (index > -1) {
menuItems[index].focus();
}
}, [
findAllFocusable
]);
var _props_checkedValues;
const [checkedValues, setCheckedValues] = useControllableState({
state: (_props_checkedValues = props.checkedValues) !== null && _props_checkedValues !== void 0 ? _props_checkedValues : hasMenuContext ? menuContext.checkedValues : undefined,
defaultState: props.defaultCheckedValues,
initialState: {}
});
var _props_onCheckedValueChange;
const handleCheckedValueChange = (_props_onCheckedValueChange = props.onCheckedValueChange) !== null && _props_onCheckedValueChange !== void 0 ? _props_onCheckedValueChange : hasMenuContext ? menuContext.onCheckedValueChange : undefined;
const toggleCheckbox = useEventCallback((e, name, value, checked)=>{
const checkedItems = (checkedValues === null || checkedValues === void 0 ? void 0 : checkedValues[name]) || [];
const newCheckedItems = [
...checkedItems
];
if (checked) {
newCheckedItems.splice(newCheckedItems.indexOf(value), 1);
} else {
newCheckedItems.push(value);
}
handleCheckedValueChange === null || handleCheckedValueChange === void 0 ? void 0 : handleCheckedValueChange(e, {
name,
checkedItems: newCheckedItems
});
setCheckedValues((s)=>({
...s,
[name]: newCheckedItems
}));
});
const selectRadio = useEventCallback((e, name, value)=>{
const newCheckedItems = [
value
];
setCheckedValues((s)=>({
...s,
[name]: newCheckedItems
}));
handleCheckedValueChange === null || handleCheckedValueChange === void 0 ? void 0 : handleCheckedValueChange(e, {
name,
checkedItems: newCheckedItems
});
});
return {
components: {
root: '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: useMergedRefs(ref, innerRef, validateNestingRef),
role: 'menu',
'aria-labelledby': menuContext.triggerId,
...focusAttributes,
...props
}), {
elementType: 'div'
}),
hasIcons: menuContext.hasIcons || false,
hasCheckmarks: menuContext.hasCheckmarks || false,
checkedValues,
hasMenuContext,
setFocusByFirstCharacter,
selectRadio,
toggleCheckbox
};
};
/**
* Adds some sugar to fetching multiple context selector values
*/ const useMenuContextSelectors = ()=>{
const checkedValues = useMenuContext_unstable((context)=>context.checkedValues);
const onCheckedValueChange = useMenuContext_unstable((context)=>context.onCheckedValueChange);
const triggerId = useMenuContext_unstable((context)=>context.triggerId);
const hasIcons = useMenuContext_unstable((context)=>context.hasIcons);
const hasCheckmarks = useMenuContext_unstable((context)=>context.hasCheckmarks);
return {
checkedValues,
onCheckedValueChange,
triggerId,
hasIcons,
hasCheckmarks
};
};
/**
* Helper function to detect if props and MenuContext values are both used
*/ const usingPropsAndMenuContext = (props, contextValue, hasMenuContext)=>{
let isUsingPropsAndContext = false;
for(const val in contextValue){
if (props[val]) {
isUsingPropsAndContext = true;
}
}
return hasMenuContext && isUsingPropsAndContext;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,15 @@
export function useMenuListContextValues_unstable(state) {
const { checkedValues, hasCheckmarks, hasIcons, selectRadio, setFocusByFirstCharacter, toggleCheckbox } = state;
// This context is created with "@fluentui/react-context-selector", these is no sense to memoize it
const menuList = {
checkedValues,
hasCheckmarks,
hasIcons,
selectRadio,
setFocusByFirstCharacter,
toggleCheckbox
};
return {
menuList
};
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/MenuList/useMenuListContextValues.ts"],"sourcesContent":["import type { MenuListContextValues, MenuListState } from './MenuList.types';\n\nexport function useMenuListContextValues_unstable(state: MenuListState): MenuListContextValues {\n const { checkedValues, hasCheckmarks, hasIcons, selectRadio, setFocusByFirstCharacter, toggleCheckbox } = state;\n\n // This context is created with \"@fluentui/react-context-selector\", these is no sense to memoize it\n const menuList = {\n checkedValues,\n hasCheckmarks,\n hasIcons,\n selectRadio,\n setFocusByFirstCharacter,\n toggleCheckbox,\n };\n\n return { menuList };\n}\n"],"names":["useMenuListContextValues_unstable","state","checkedValues","hasCheckmarks","hasIcons","selectRadio","setFocusByFirstCharacter","toggleCheckbox","menuList"],"mappings":"AAEA,OAAO,SAASA,kCAAkCC,KAAoB;IACpE,MAAM,EAAEC,aAAa,EAAEC,aAAa,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,wBAAwB,EAAEC,cAAc,EAAE,GAAGN;IAE1G,mGAAmG;IACnG,MAAMO,WAAW;QACfN;QACAC;QACAC;QACAC;QACAC;QACAC;IACF;IAEA,OAAO;QAAEC;IAAS;AACpB"}

View File

@@ -0,0 +1,32 @@
'use client';
import { mergeClasses, __styles } from '@griffel/react';
export const menuListClassNames = {
root: 'fui-MenuList'
};
const useStyles = /*#__PURE__*/__styles({
root: {
mc9l5x: "f22iagw",
Beiy3e4: "f1vx9l62",
i8kkvl: 0,
Belr9w4: 0,
rmohyg: "f1t6b6ee"
},
hasMenuContext: {
Bqenvij: "f1l02sjl"
}
}, {
d: [".f22iagw{display:flex;}", ".f1vx9l62{flex-direction:column;}", [".f1t6b6ee{gap:2px;}", {
p: -1
}], ".f1l02sjl{height:100%;}"]
});
/**
* Apply styling to the Menu slots based on the state
*/
export const useMenuListStyles_unstable = state => {
'use no memo';
const styles = useStyles();
state.root.className = mergeClasses(menuListClassNames.root, styles.root, state.hasMenuContext && styles.hasMenuContext, state.root.className);
return state;
};

View File

@@ -0,0 +1 @@
{"version":3,"names":["mergeClasses","__styles","menuListClassNames","root","useStyles","mc9l5x","Beiy3e4","i8kkvl","Belr9w4","rmohyg","hasMenuContext","Bqenvij","d","p","useMenuListStyles_unstable","state","styles","className"],"sources":["useMenuListStyles.styles.js"],"sourcesContent":["'use client';\nimport { mergeClasses, makeStyles } from '@griffel/react';\nexport const menuListClassNames = {\n root: 'fui-MenuList'\n};\nconst useStyles = makeStyles({\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: '2px'\n },\n hasMenuContext: {\n height: '100%'\n }\n});\n/**\n * Apply styling to the Menu slots based on the state\n */ export const useMenuListStyles_unstable = (state)=>{\n 'use no memo';\n const styles = useStyles();\n state.root.className = mergeClasses(menuListClassNames.root, styles.root, state.hasMenuContext && styles.hasMenuContext, state.root.className);\n return state;\n};\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,YAAY,EAAAC,QAAA,QAAoB,gBAAgB;AACzD,OAAO,MAAMC,kBAAkB,GAAG;EAC9BC,IAAI,EAAE;AACV,CAAC;AACD,MAAMC,SAAS,gBAAGH,QAAA;EAAAE,IAAA;IAAAE,MAAA;IAAAC,OAAA;IAAAC,MAAA;IAAAC,OAAA;IAAAC,MAAA;EAAA;EAAAC,cAAA;IAAAC,OAAA;EAAA;AAAA;EAAAC,CAAA;IAAAC,CAAA;EAAA;AAAA,CASjB,CAAC;AACF;AACA;AACA;AAAI,OAAO,MAAMC,0BAA0B,GAAIC,KAAK,IAAG;EACnD,aAAa;;EACb,MAAMC,MAAM,GAAGZ,SAAS,CAAC,CAAC;EAC1BW,KAAK,CAACZ,IAAI,CAACc,SAAS,GAAGjB,YAAY,CAACE,kBAAkB,CAACC,IAAI,EAAEa,MAAM,CAACb,IAAI,EAAEY,KAAK,CAACL,cAAc,IAAIM,MAAM,CAACN,cAAc,EAAEK,KAAK,CAACZ,IAAI,CAACc,SAAS,CAAC;EAC9I,OAAOF,KAAK;AAChB,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,23 @@
'use client';
import { mergeClasses, makeStyles } from '@griffel/react';
export const menuListClassNames = {
root: 'fui-MenuList'
};
const useStyles = makeStyles({
root: {
display: 'flex',
flexDirection: 'column',
gap: '2px'
},
hasMenuContext: {
height: '100%'
}
});
/**
* Apply styling to the Menu slots based on the state
*/ export const useMenuListStyles_unstable = (state)=>{
'use no memo';
const styles = useStyles();
state.root.className = mergeClasses(menuListClassNames.root, styles.root, state.hasMenuContext && styles.hasMenuContext, state.root.className);
return state;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/MenuList/useMenuListStyles.styles.ts"],"sourcesContent":["'use client';\n\nimport type { SlotClassNames } from '@fluentui/react-utilities';\nimport { mergeClasses, makeStyles } from '@griffel/react';\nimport type { MenuListSlots, MenuListState } from './MenuList.types';\n\nexport const menuListClassNames: SlotClassNames<MenuListSlots> = {\n root: 'fui-MenuList',\n};\n\nconst useStyles = makeStyles({\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: '2px',\n },\n hasMenuContext: {\n height: '100%',\n },\n});\n\n/**\n * Apply styling to the Menu slots based on the state\n */\nexport const useMenuListStyles_unstable = (state: MenuListState): MenuListState => {\n 'use no memo';\n\n const styles = useStyles();\n state.root.className = mergeClasses(\n menuListClassNames.root,\n styles.root,\n state.hasMenuContext && styles.hasMenuContext,\n state.root.className,\n );\n return state;\n};\n"],"names":["mergeClasses","makeStyles","menuListClassNames","root","useStyles","display","flexDirection","gap","hasMenuContext","height","useMenuListStyles_unstable","state","styles","className"],"mappings":"AAAA;AAGA,SAASA,YAAY,EAAEC,UAAU,QAAQ,iBAAiB;AAG1D,OAAO,MAAMC,qBAAoD;IAC/DC,MAAM;AACR,EAAE;AAEF,MAAMC,YAAYH,WAAW;IAC3BE,MAAM;QACJE,SAAS;QACTC,eAAe;QACfC,KAAK;IACP;IACAC,gBAAgB;QACdC,QAAQ;IACV;AACF;AAEA;;CAEC,GACD,OAAO,MAAMC,6BAA6B,CAACC;IACzC;IAEA,MAAMC,SAASR;IACfO,MAAMR,IAAI,CAACU,SAAS,GAAGb,aACrBE,mBAAmBC,IAAI,EACvBS,OAAOT,IAAI,EACXQ,MAAMH,cAAc,IAAII,OAAOJ,cAAc,EAC7CG,MAAMR,IAAI,CAACU,SAAS;IAEtB,OAAOF;AACT,EAAE"}