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 { useListbox_unstable } from './useListbox';
import { renderListbox_unstable } from './renderListbox';
import { useListboxStyles_unstable } from './useListboxStyles.styles';
import { useListboxContextValues } from '../../contexts/useListboxContextValues';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';
/**
* Listbox component: a standalone selection control, or the popup in a Combobox
*/ export const Listbox = /*#__PURE__*/ React.forwardRef((props, ref)=>{
const state = useListbox_unstable(props, ref);
const contextValues = useListboxContextValues(state);
useListboxStyles_unstable(state);
useCustomStyleHook_unstable('useListboxStyles_unstable')(state);
return renderListbox_unstable(state, contextValues);
});
Listbox.displayName = 'Listbox';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Listbox/Listbox.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useListbox_unstable } from './useListbox';\nimport { renderListbox_unstable } from './renderListbox';\nimport { useListboxStyles_unstable } from './useListboxStyles.styles';\nimport type { ListboxProps } from './Listbox.types';\nimport { useListboxContextValues } from '../../contexts/useListboxContextValues';\nimport type { ForwardRefComponent } from '@fluentui/react-utilities';\nimport { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';\n\n/**\n * Listbox component: a standalone selection control, or the popup in a Combobox\n */\nexport const Listbox: ForwardRefComponent<ListboxProps> = React.forwardRef((props, ref) => {\n const state = useListbox_unstable(props, ref);\n const contextValues = useListboxContextValues(state);\n\n useListboxStyles_unstable(state);\n\n useCustomStyleHook_unstable('useListboxStyles_unstable')(state);\n\n return renderListbox_unstable(state, contextValues);\n});\n\nListbox.displayName = 'Listbox';\n"],"names":["React","useListbox_unstable","renderListbox_unstable","useListboxStyles_unstable","useListboxContextValues","useCustomStyleHook_unstable","Listbox","forwardRef","props","ref","state","contextValues","displayName"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,mBAAmB,QAAQ,eAAe;AACnD,SAASC,sBAAsB,QAAQ,kBAAkB;AACzD,SAASC,yBAAyB,QAAQ,4BAA4B;AAEtE,SAASC,uBAAuB,QAAQ,yCAAyC;AAEjF,SAASC,2BAA2B,QAAQ,kCAAkC;AAE9E;;CAEC,GACD,OAAO,MAAMC,wBAA6CN,MAAMO,UAAU,CAAC,CAACC,OAAOC;IACjF,MAAMC,QAAQT,oBAAoBO,OAAOC;IACzC,MAAME,gBAAgBP,wBAAwBM;IAE9CP,0BAA0BO;IAE1BL,4BAA4B,6BAA6BK;IAEzD,OAAOR,uBAAuBQ,OAAOC;AACvC,GAAG;AAEHL,QAAQM,WAAW,GAAG"}

View File

@@ -0,0 +1 @@
export { };

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Listbox/Listbox.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport type {\n ActiveDescendantChangeEvent,\n ActiveDescendantContextValue,\n ActiveDescendantImperativeRef,\n} from '@fluentui/react-aria';\nimport { OptionValue, OptionCollectionState } from '../../utils/OptionCollection.types';\nimport { SelectionEvents, SelectionProps, SelectionState } from '../../utils/Selection.types';\nimport type { ListboxContextValue } from '../../contexts/ListboxContext';\n\nexport type ListboxSlots = {\n /** The root slot, a `<div>` with `role=\"listbox\"` */\n root: Slot<'div'>;\n};\n\n/**\n * Listbox Props\n */\nexport type ListboxProps = ComponentProps<ListboxSlots> &\n SelectionProps & {\n /**\n * Disable auto-focusing on the first item when mounting.\n *\n * @default false\n */\n disableAutoFocus?: boolean;\n };\n\n/**\n * State used in rendering Listbox\n */\nexport type ListboxState = ComponentState<ListboxSlots> &\n OptionCollectionState &\n Pick<SelectionProps, 'multiselect'> &\n SelectionState & {\n /**\n * @deprecated - no longer used internally\n * @see activeDescendantController.active()\n */\n activeOption?: OptionValue;\n\n /**\n * @deprecated - no longer used internally\n */\n focusVisible: boolean;\n\n /**\n * @deprecated - no longer used internally\n * @see activeDescendantController.focus(id)\n */\n setActiveOption(option?: OptionValue): void;\n\n // Whether the Listbox renders within a Combobox, Dropdown, or picker, or as a standalone widget\n standalone: boolean;\n\n selectOption(event: SelectionEvents, option: OptionValue): void;\n\n activeDescendantController: ActiveDescendantImperativeRef;\n\n onActiveDescendantChange?: (event: ActiveDescendantChangeEvent) => void;\n };\n\nexport type ListboxContextValues = {\n listbox: ListboxContextValue;\n activeDescendant: ActiveDescendantContextValue;\n};\n"],"names":[],"mappings":"AA8DA,WAGE"}

View File

@@ -0,0 +1,4 @@
export { Listbox } from './Listbox';
export { renderListbox_unstable } from './renderListbox';
export { useListbox_unstable } from './useListbox';
export { listboxClassNames, useListboxStyles_unstable } from './useListboxStyles.styles';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Listbox/index.ts"],"sourcesContent":["export { Listbox } from './Listbox';\nexport type { ListboxContextValues, ListboxProps, ListboxSlots, ListboxState } from './Listbox.types';\nexport { renderListbox_unstable } from './renderListbox';\nexport { useListbox_unstable } from './useListbox';\nexport { listboxClassNames, useListboxStyles_unstable } from './useListboxStyles.styles';\n"],"names":["Listbox","renderListbox_unstable","useListbox_unstable","listboxClassNames","useListboxStyles_unstable"],"mappings":"AAAA,SAASA,OAAO,QAAQ,YAAY;AAEpC,SAASC,sBAAsB,QAAQ,kBAAkB;AACzD,SAASC,mBAAmB,QAAQ,eAAe;AACnD,SAASC,iBAAiB,EAAEC,yBAAyB,QAAQ,4BAA4B"}

View File

@@ -0,0 +1,16 @@
import { jsx as _jsx } from "@fluentui/react-jsx-runtime/jsx-runtime";
import { assertSlots } from '@fluentui/react-utilities';
import { ActiveDescendantContextProvider } from '@fluentui/react-aria';
import { ListboxContext } from '../../contexts/ListboxContext';
/**
* Render the final JSX of Listbox
*/ export const renderListbox_unstable = (state, contextValues)=>{
assertSlots(state);
return /*#__PURE__*/ _jsx(ActiveDescendantContextProvider, {
value: contextValues.activeDescendant,
children: /*#__PURE__*/ _jsx(ListboxContext.Provider, {
value: contextValues.listbox,
children: /*#__PURE__*/ _jsx(state.root, {})
})
});
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Listbox/renderListbox.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 { ActiveDescendantContextProvider } from '@fluentui/react-aria';\nimport type { ListboxContextValues, ListboxState, ListboxSlots } from './Listbox.types';\nimport { ListboxContext } from '../../contexts/ListboxContext';\n\n/**\n * Render the final JSX of Listbox\n */\nexport const renderListbox_unstable = (state: ListboxState, contextValues: ListboxContextValues): JSXElement => {\n assertSlots<ListboxSlots>(state);\n\n return (\n <ActiveDescendantContextProvider value={contextValues.activeDescendant}>\n <ListboxContext.Provider value={contextValues.listbox}>\n <state.root />\n </ListboxContext.Provider>\n </ActiveDescendantContextProvider>\n );\n};\n"],"names":["assertSlots","ActiveDescendantContextProvider","ListboxContext","renderListbox_unstable","state","contextValues","value","activeDescendant","Provider","listbox","root"],"mappings":"AAAA,0BAA0B,GAC1B,iDAAiD;AAEjD,SAASA,WAAW,QAAQ,4BAA4B;AAExD,SAASC,+BAA+B,QAAQ,uBAAuB;AAEvE,SAASC,cAAc,QAAQ,gCAAgC;AAE/D;;CAEC,GACD,OAAO,MAAMC,yBAAyB,CAACC,OAAqBC;IAC1DL,YAA0BI;IAE1B,qBACE,KAACH;QAAgCK,OAAOD,cAAcE,gBAAgB;kBACpE,cAAA,KAACL,eAAeM,QAAQ;YAACF,OAAOD,cAAcI,OAAO;sBACnD,cAAA,KAACL,MAAMM,IAAI;;;AAInB,EAAE"}

View File

@@ -0,0 +1,196 @@
'use client';
import * as React from 'react';
import { getIntrinsicElementProps, mergeCallbacks, useEventCallback, slot, useMergedRefs } from '@fluentui/react-utilities';
import { useHasParentContext } from '@fluentui/react-context-selector';
import { useActiveDescendant, useActiveDescendantContext, useHasParentActiveDescendantContext } from '@fluentui/react-aria';
import { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';
import { useOptionCollection } from '../../utils/useOptionCollection';
import { useSelection } from '../../utils/useSelection';
import { optionClassNames } from '../Option/useOptionStyles.styles';
import { ListboxContext, useListboxContext_unstable } from '../../contexts/ListboxContext';
import { useOnKeyboardNavigationChange } from '@fluentui/react-tabster';
// eslint-disable-next-line @typescript-eslint/naming-convention
const UNSAFE_noLongerUsed = {
activeOption: undefined,
focusVisible: false,
setActiveOption: ()=>null
};
/**
* Create the state required to render Listbox.
*
* The returned state can be modified with hooks such as useListboxStyles_unstable,
* before being passed to renderListbox_unstable.
*
* @param props - props from this instance of Listbox
* @param ref - reference to root HTMLElement of Listbox
*/ export const useListbox_unstable = (props, ref)=>{
'use no memo';
const { multiselect, disableAutoFocus = false } = props;
const optionCollection = useOptionCollection();
const { listboxRef: activeDescendantListboxRef, activeParentRef, controller } = useActiveDescendant({
matchOption: (el)=>el.classList.contains(optionClassNames.root)
});
const hasListboxContext = useHasParentContext(ListboxContext);
const onActiveDescendantChange = useListboxContext_unstable((ctx)=>ctx.onActiveDescendantChange);
const contextGetOptionById = useListboxContext_unstable((ctx)=>ctx.getOptionById);
const contextGetOptionsMatchingValue = useListboxContext_unstable((ctx)=>ctx.getOptionsMatchingValue);
const getOptionById = hasListboxContext ? contextGetOptionById : optionCollection.getOptionById;
const getOptionsMatchingValue = hasListboxContext ? contextGetOptionsMatchingValue : optionCollection.getOptionsMatchingValue;
const listenerRef = React.useMemo(()=>{
let element = null;
const listener = (untypedEvent)=>{
// Typescript doesn't support custom event types on handler
const event = untypedEvent;
onActiveDescendantChange === null || onActiveDescendantChange === void 0 ? void 0 : onActiveDescendantChange(event);
};
return (el)=>{
if (!el) {
element === null || element === void 0 ? void 0 : element.removeEventListener('activedescendantchange', listener);
return;
}
element = el;
element.addEventListener('activedescendantchange', listener);
};
}, [
onActiveDescendantChange
]);
const [isNavigatingWithKeyboard, setIsNavigatingWithKeyboard] = React.useState(false);
useOnKeyboardNavigationChange(setIsNavigatingWithKeyboard);
const activeDescendantContext = useActiveDescendantContext();
const hasParentActiveDescendantContext = useHasParentActiveDescendantContext();
const activeDescendantController = hasParentActiveDescendantContext ? activeDescendantContext.controller : controller;
const { clearSelection, selectedOptions, selectOption } = useSelection(props);
const onKeyDown = (event)=>{
const action = getDropdownActionFromKey(event, {
open: true
});
const activeOptionId = activeDescendantController.active();
const activeOption = activeOptionId ? getOptionById(activeOptionId) : null;
switch(action){
case 'First':
case 'Last':
case 'Next':
case 'Previous':
case 'PageDown':
case 'PageUp':
case 'CloseSelect':
case 'Select':
event.preventDefault();
break;
}
switch(action){
case 'Next':
if (activeOption) {
activeDescendantController.next();
} else {
activeDescendantController.first();
}
break;
case 'Previous':
if (activeOption) {
activeDescendantController.prev();
} else {
activeDescendantController.first();
}
break;
case 'PageUp':
case 'First':
activeDescendantController.first();
break;
case 'PageDown':
case 'Last':
activeDescendantController.last();
break;
case 'Select':
case 'CloseSelect':
activeOption && selectOption(event, activeOption);
break;
}
};
// get state from parent combobox, if it exists
const contextSelectedOptions = useListboxContext_unstable((ctx)=>ctx.selectedOptions);
const contextSelectOption = useListboxContext_unstable((ctx)=>ctx.selectOption);
// without a parent combobox context, provide values directly from Listbox
const optionContextValues = hasListboxContext ? {
selectedOptions: contextSelectedOptions,
selectOption: contextSelectOption,
...UNSAFE_noLongerUsed
} : {
selectedOptions,
selectOption,
...UNSAFE_noLongerUsed
};
React.useEffect(()=>{
// if the listbox has a parent context, that parent context should handle the activedescendant
if (hasParentActiveDescendantContext) {
return;
}
// disable focus-visible attributes until focus is received
activeDescendantController.hideFocusVisibleAttributes();
if (!disableAutoFocus) {
// if it is single-select and there is a selected option, start at the selected option
if (!multiselect && optionContextValues.selectedOptions.length > 0) {
const selectedOption = getOptionsMatchingValue((v)=>v === optionContextValues.selectedOptions[0]).pop();
if (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.id) {
activeDescendantController.focus(selectedOption.id);
}
} else {
activeDescendantController.first();
}
}
return ()=>{
activeDescendantController.blur();
};
// this should only be run once in the lifecycle of the Listbox
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const onFocus = React.useCallback(()=>{
if (hasParentActiveDescendantContext) {
return;
}
activeDescendantController.showFocusVisibleAttributes();
if (isNavigatingWithKeyboard) {
activeDescendantController.scrollActiveIntoView();
}
}, [
activeDescendantController,
hasParentActiveDescendantContext,
isNavigatingWithKeyboard
]);
const onBlur = React.useCallback(()=>{
if (hasParentActiveDescendantContext) {
return;
}
activeDescendantController.hideFocusVisibleAttributes();
}, [
activeDescendantController,
hasParentActiveDescendantContext
]);
const state = {
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, activeParentRef, activeDescendantListboxRef, listenerRef),
role: multiselect ? 'menu' : 'listbox',
tabIndex: 0,
...props
}), {
elementType: 'div'
}),
standalone: !hasListboxContext,
multiselect,
clearSelection,
activeDescendantController,
onActiveDescendantChange,
...optionCollection,
...optionContextValues
};
state.root.onKeyDown = useEventCallback(mergeCallbacks(state.root.onKeyDown, onKeyDown));
state.root.onFocus = useEventCallback(mergeCallbacks(state.root.onFocus, onFocus));
state.root.onBlur = useEventCallback(mergeCallbacks(state.root.onBlur, onBlur));
return state;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,46 @@
'use client';
import { tokens } from '@fluentui/react-theme';
import { __styles, mergeClasses } from '@griffel/react';
export const listboxClassNames = {
root: 'fui-Listbox'
};
/**
* Styles for the root slot
*/
const useStyles = /*#__PURE__*/__styles({
root: {
De3pzq: "fxugw4r",
B7ck84d: "f1ewtqcl",
mc9l5x: "f22iagw",
Beiy3e4: "f1vx9l62",
Bf4jedk: "f3hsy1e",
Bmxbyg5: "f5zp4f",
Bw0xxkn: 0,
oeaueh: 0,
Bpd4iqm: 0,
Befb4lg: "f1iepc6i",
Byoj8tv: 0,
uwmqm3: 0,
z189sj: 0,
z8tnut: 0,
B0ocmuz: "f1t35pdg",
Belr9w4: "fiut8dr"
}
}, {
d: [".fxugw4r{background-color:var(--colorNeutralBackground1);}", ".f1ewtqcl{box-sizing:border-box;}", ".f22iagw{display:flex;}", ".f1vx9l62{flex-direction:column;}", ".f3hsy1e{min-width:160px;}", ".f5zp4f{overflow-y:auto;}", [".f1iepc6i{outline:1px solid var(--colorTransparentStroke);}", {
p: -1
}], [".f1t35pdg{padding:var(--spacingHorizontalXS);}", {
p: -1
}], ".fiut8dr{row-gap:var(--spacingHorizontalXXS);}"]
});
/**
* Apply styling to the Listbox slots based on the state
*/
export const useListboxStyles_unstable = state => {
'use no memo';
const styles = useStyles();
state.root.className = mergeClasses(listboxClassNames.root, styles.root, state.root.className);
return state;
};

View File

@@ -0,0 +1 @@
{"version":3,"names":["tokens","__styles","mergeClasses","listboxClassNames","root","useStyles","De3pzq","B7ck84d","mc9l5x","Beiy3e4","Bf4jedk","Bmxbyg5","Bw0xxkn","oeaueh","Bpd4iqm","Befb4lg","Byoj8tv","uwmqm3","z189sj","z8tnut","B0ocmuz","Belr9w4","d","p","useListboxStyles_unstable","state","styles","className"],"sources":["useListboxStyles.styles.js"],"sourcesContent":["'use client';\nimport { tokens } from '@fluentui/react-theme';\nimport { makeStyles, mergeClasses } from '@griffel/react';\nexport const listboxClassNames = {\n root: 'fui-Listbox'\n};\n/**\n * Styles for the root slot\n */ const useStyles = makeStyles({\n root: {\n backgroundColor: tokens.colorNeutralBackground1,\n boxSizing: 'border-box',\n display: 'flex',\n flexDirection: 'column',\n minWidth: '160px',\n overflowY: 'auto',\n outline: `1px solid ${tokens.colorTransparentStroke}`,\n padding: tokens.spacingHorizontalXS,\n rowGap: tokens.spacingHorizontalXXS\n }\n});\n/**\n * Apply styling to the Listbox slots based on the state\n */ export const useListboxStyles_unstable = (state)=>{\n 'use no memo';\n const styles = useStyles();\n state.root.className = mergeClasses(listboxClassNames.root, styles.root, state.root.className);\n return state;\n};\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,MAAM,QAAQ,uBAAuB;AAC9C,SAAAC,QAAA,EAAqBC,YAAY,QAAQ,gBAAgB;AACzD,OAAO,MAAMC,iBAAiB,GAAG;EAC7BC,IAAI,EAAE;AACV,CAAC;AACD;AACA;AACA;AAAI,MAAMC,SAAS,gBAAGJ,QAAA;EAAAG,IAAA;IAAAE,MAAA;IAAAC,OAAA;IAAAC,MAAA;IAAAC,OAAA;IAAAC,OAAA;IAAAC,OAAA;IAAAC,OAAA;IAAAC,MAAA;IAAAC,OAAA;IAAAC,OAAA;IAAAC,OAAA;IAAAC,MAAA;IAAAC,MAAA;IAAAC,MAAA;IAAAC,OAAA;IAAAC,OAAA;EAAA;AAAA;EAAAC,CAAA;IAAAC,CAAA;EAAA;IAAAA,CAAA;EAAA;AAAA,CAYrB,CAAC;AACF;AACA;AACA;AAAI,OAAO,MAAMC,yBAAyB,GAAIC,KAAK,IAAG;EAClD,aAAa;;EACb,MAAMC,MAAM,GAAGrB,SAAS,CAAC,CAAC;EAC1BoB,KAAK,CAACrB,IAAI,CAACuB,SAAS,GAAGzB,YAAY,CAACC,iBAAiB,CAACC,IAAI,EAAEsB,MAAM,CAACtB,IAAI,EAAEqB,KAAK,CAACrB,IAAI,CAACuB,SAAS,CAAC;EAC9F,OAAOF,KAAK;AAChB,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,29 @@
'use client';
import { tokens } from '@fluentui/react-theme';
import { makeStyles, mergeClasses } from '@griffel/react';
export const listboxClassNames = {
root: 'fui-Listbox'
};
/**
* Styles for the root slot
*/ const useStyles = makeStyles({
root: {
backgroundColor: tokens.colorNeutralBackground1,
boxSizing: 'border-box',
display: 'flex',
flexDirection: 'column',
minWidth: '160px',
overflowY: 'auto',
outline: `1px solid ${tokens.colorTransparentStroke}`,
padding: tokens.spacingHorizontalXS,
rowGap: tokens.spacingHorizontalXXS
}
});
/**
* Apply styling to the Listbox slots based on the state
*/ export const useListboxStyles_unstable = (state)=>{
'use no memo';
const styles = useStyles();
state.root.className = mergeClasses(listboxClassNames.root, styles.root, state.root.className);
return state;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Listbox/useListboxStyles.styles.ts"],"sourcesContent":["'use client';\n\nimport { tokens } from '@fluentui/react-theme';\nimport { SlotClassNames } from '@fluentui/react-utilities';\nimport { makeStyles, mergeClasses } from '@griffel/react';\nimport type { ListboxSlots, ListboxState } from './Listbox.types';\n\nexport const listboxClassNames: SlotClassNames<ListboxSlots> = {\n root: 'fui-Listbox',\n};\n\n/**\n * Styles for the root slot\n */\nconst useStyles = makeStyles({\n root: {\n backgroundColor: tokens.colorNeutralBackground1,\n boxSizing: 'border-box',\n display: 'flex',\n flexDirection: 'column',\n minWidth: '160px',\n overflowY: 'auto',\n outline: `1px solid ${tokens.colorTransparentStroke}`,\n padding: tokens.spacingHorizontalXS,\n rowGap: tokens.spacingHorizontalXXS,\n },\n});\n\n/**\n * Apply styling to the Listbox slots based on the state\n */\nexport const useListboxStyles_unstable = (state: ListboxState): ListboxState => {\n 'use no memo';\n\n const styles = useStyles();\n state.root.className = mergeClasses(listboxClassNames.root, styles.root, state.root.className);\n\n return state;\n};\n"],"names":["tokens","makeStyles","mergeClasses","listboxClassNames","root","useStyles","backgroundColor","colorNeutralBackground1","boxSizing","display","flexDirection","minWidth","overflowY","outline","colorTransparentStroke","padding","spacingHorizontalXS","rowGap","spacingHorizontalXXS","useListboxStyles_unstable","state","styles","className"],"mappings":"AAAA;AAEA,SAASA,MAAM,QAAQ,wBAAwB;AAE/C,SAASC,UAAU,EAAEC,YAAY,QAAQ,iBAAiB;AAG1D,OAAO,MAAMC,oBAAkD;IAC7DC,MAAM;AACR,EAAE;AAEF;;CAEC,GACD,MAAMC,YAAYJ,WAAW;IAC3BG,MAAM;QACJE,iBAAiBN,OAAOO,uBAAuB;QAC/CC,WAAW;QACXC,SAAS;QACTC,eAAe;QACfC,UAAU;QACVC,WAAW;QACXC,SAAS,CAAC,UAAU,EAAEb,OAAOc,sBAAsB,EAAE;QACrDC,SAASf,OAAOgB,mBAAmB;QACnCC,QAAQjB,OAAOkB,oBAAoB;IACrC;AACF;AAEA;;CAEC,GACD,OAAO,MAAMC,4BAA4B,CAACC;IACxC;IAEA,MAAMC,SAAShB;IACfe,MAAMhB,IAAI,CAACkB,SAAS,GAAGpB,aAAaC,kBAAkBC,IAAI,EAAEiB,OAAOjB,IAAI,EAAEgB,MAAMhB,IAAI,CAACkB,SAAS;IAE7F,OAAOF;AACT,EAAE"}