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,3 @@
export { useARIAButtonProps } from './useARIAButtonProps';
// eslint-disable-next-line @typescript-eslint/no-deprecated
export { useARIAButtonShorthand } from './useARIAButtonShorthand';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/button/index.ts"],"sourcesContent":["export { useARIAButtonProps } from './useARIAButtonProps';\n// eslint-disable-next-line @typescript-eslint/no-deprecated\nexport { useARIAButtonShorthand } from './useARIAButtonShorthand';\nexport type {\n ARIAButtonAlteredProps,\n ARIAButtonElement,\n ARIAButtonElementIntersection,\n ARIAButtonProps,\n ARIAButtonResultProps,\n ARIAButtonSlotProps,\n ARIAButtonType,\n} from './types';\n"],"names":["useARIAButtonProps","useARIAButtonShorthand"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,uBAAuB;AAC1D,4DAA4D;AAC5D,SAASC,sBAAsB,QAAQ,2BAA2B"}

View File

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

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/button/types.ts"],"sourcesContent":["import type {\n DistributiveOmit,\n ExtractSlotProps,\n Slot,\n UnionToIntersection,\n JSXIntrinsicElement,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nexport type ARIAButtonType = 'button' | 'a' | 'div';\n\nexport type ARIAButtonElement<AlternateAs extends 'a' | 'div' = 'a' | 'div'> =\n | HTMLButtonElement\n | (AlternateAs extends 'a' ? HTMLAnchorElement : never)\n | (AlternateAs extends 'div' ? HTMLDivElement : never);\n\n/**\n * @internal\n */\nexport type ARIAButtonElementIntersection<AlternateAs extends 'a' | 'div' = 'a' | 'div'> = UnionToIntersection<\n ARIAButtonElement<AlternateAs>\n>;\n\n/**\n * Props expected by `useARIAButtonProps` hooks\n */\nexport type ARIAButtonProps<Type extends ARIAButtonType = ARIAButtonType> = DistributiveOmit<\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n React.PropsWithRef<JSXIntrinsicElement<Type>>,\n 'children'\n> & {\n disabled?: boolean;\n /**\n * When set, allows the button to be focusable even when it has been disabled.\n * This is used in scenarios where it is important to keep a consistent tab order\n * for screen reader and keyboard users. The primary example of this\n * pattern is when the disabled button is in a menu or a commandbar and is seldom used for standalone buttons.\n *\n * @default false\n */\n disabledFocusable?: boolean;\n};\n\nexport type ARIAButtonSlotProps<AlternateAs extends 'a' | 'div' = 'a' | 'div'> = ExtractSlotProps<\n Slot<'button', AlternateAs>\n> &\n Pick<ARIAButtonProps<ARIAButtonType>, 'disabled' | 'disabledFocusable'>;\n\n/**\n * Props that will be modified internally by `useARIAButtonProps` by each case.\n * This typing is to ensure a well specified return value for `useARIAbButtonProps`\n */\nexport type ARIAButtonAlteredProps<Type extends ARIAButtonType> =\n | (Type extends 'button'\n ? Pick<\n JSXIntrinsicElement<'button'>,\n 'onClick' | 'onKeyDown' | 'onKeyUp' | 'disabled' | 'aria-disabled' | 'tabIndex'\n >\n : never)\n | (Type extends 'a'\n ? Pick<\n JSXIntrinsicElement<'a'>,\n 'onClick' | 'onKeyDown' | 'onKeyUp' | 'aria-disabled' | 'tabIndex' | 'role' | 'href'\n >\n : never)\n | (Type extends 'div'\n ? Pick<JSXIntrinsicElement<'div'>, 'onClick' | 'onKeyDown' | 'onKeyUp' | 'aria-disabled' | 'tabIndex' | 'role'>\n : never);\n\n/**\n * Merge of props provided by the user and props provided internally.\n */\nexport type ARIAButtonResultProps<Type extends ARIAButtonType, Props> = Props &\n UnionToIntersection<ARIAButtonAlteredProps<Type>>;\n"],"names":["React"],"mappings":"AAOA,YAAYA,WAAW,QAAQ"}

View File

@@ -0,0 +1,115 @@
'use client';
import { Enter, Space } from '@fluentui/keyboard-keys';
import { useEventCallback } from '@fluentui/react-utilities';
import * as React from 'react';
/**
* @internal
*
* Button keyboard handling, role, disabled and tabIndex implementation that ensures ARIA spec
* for multiple scenarios of non native button elements. Ensuring 1st rule of ARIA for cases
* where no attribute addition is required.
*
* @param type - the proper scenario to be interpreted by the hook.
* 1. `button` - Minimal interference from the hook, as semantic button already supports most of the states
* 2. `a` or `div` - Proper keyboard/mouse handling plus other support to ensure ARIA behavior
* @param props - the props to be passed down the line to the desired element.
* This hook will encapsulate proper properties, such as `onClick`, `onKeyDown`, `onKeyUp`, etc,.
*
* @example
* ```tsx
* const buttonProps = useARIAButtonProps('a', {
* href: './some-route'
* onClick: () => console.log('this should run both on click and Space and Enter')
* })
*
* // ...
*
* return (
* <a {...buttonProps}>This anchor will behave as a proper button</a>
* )
* ```
*/ export function useARIAButtonProps(type, props) {
const { disabled, disabledFocusable = false, ['aria-disabled']: ariaDisabled, onClick, onKeyDown, onKeyUp, ...rest } = props !== null && props !== void 0 ? props : {};
const normalizedARIADisabled = typeof ariaDisabled === 'string' ? ariaDisabled === 'true' : ariaDisabled;
const isDisabled = disabled || disabledFocusable || normalizedARIADisabled;
const handleClick = useEventCallback((ev)=>{
if (isDisabled) {
ev.preventDefault();
ev.stopPropagation();
} else {
onClick === null || onClick === void 0 ? void 0 : onClick(ev);
}
});
const handleKeyDown = useEventCallback((ev)=>{
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(ev);
if (ev.isDefaultPrevented()) {
return;
}
const key = ev.key;
if (isDisabled && (key === Enter || key === Space)) {
ev.preventDefault();
ev.stopPropagation();
return;
}
if (key === Space) {
ev.preventDefault();
return;
} else if (key === Enter) {
ev.preventDefault();
ev.currentTarget.click();
}
});
const handleKeyUp = useEventCallback((ev)=>{
onKeyUp === null || onKeyUp === void 0 ? void 0 : onKeyUp(ev);
if (ev.isDefaultPrevented()) {
return;
}
const key = ev.key;
if (isDisabled && (key === Enter || key === Space)) {
ev.preventDefault();
ev.stopPropagation();
return;
}
if (key === Space) {
ev.preventDefault();
ev.currentTarget.click();
}
});
// If a <button> tag is to be rendered we just need to set disabled and aria-disabled correctly
if (type === 'button' || type === undefined) {
return {
...rest,
disabled: disabled && !disabledFocusable,
'aria-disabled': disabledFocusable ? true : normalizedARIADisabled,
// onclick should still use internal handler to ensure prevention if disabled
// if disabledFocusable then there's no requirement for handlers as those events should not be propagated
onClick: disabledFocusable ? undefined : handleClick,
onKeyUp: disabledFocusable ? undefined : onKeyUp,
onKeyDown: disabledFocusable ? undefined : onKeyDown
};
} else {
// the role needs to be explicitly set if the href is undefined
const isLink = !!rest.href;
let roleOverride = isLink ? undefined : 'button';
if (!roleOverride && isDisabled) {
// need to set role=link explicitly for disabled links
roleOverride = 'link';
}
const resultProps = {
role: roleOverride,
tabIndex: disabledFocusable || !isLink && !disabled ? 0 : undefined,
...rest,
// If it's not a <button> than listeners are required even with disabledFocusable
// Since you cannot assure the default behavior of the element
// E.g: <a> will redirect on click
onClick: handleClick,
onKeyUp: handleKeyUp,
onKeyDown: handleKeyDown,
'aria-disabled': isDisabled
};
if (type === 'a' && isDisabled) {
resultProps.href = undefined;
}
return resultProps;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,21 @@
'use client';
import { resolveShorthand } from '@fluentui/react-utilities';
import { useARIAButtonProps } from './useARIAButtonProps';
/**
* @internal
*
* @deprecated use useARIAButtonProps instead
*
* This function expects to receive a slot, if `as` property is not desired use `useARIAButtonProps` instead
*
* Button keyboard handling, role, disabled and tabIndex implementation that ensures ARIA spec
* for multiple scenarios of shorthand properties. Ensuring 1st rule of ARIA for cases
* where no attribute addition is required.
*/ export const useARIAButtonShorthand = (value, options)=>{
// eslint-disable-next-line @typescript-eslint/no-deprecated
const shorthand = resolveShorthand(value, options);
var _shorthand_as;
const shorthandARIAButton = useARIAButtonProps((_shorthand_as = shorthand === null || shorthand === void 0 ? void 0 : shorthand.as) !== null && _shorthand_as !== void 0 ? _shorthand_as : 'button', shorthand);
return shorthand && shorthandARIAButton;
// eslint-disable-next-line @typescript-eslint/no-deprecated
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/button/useARIAButtonShorthand.ts"],"sourcesContent":["'use client';\n\nimport { resolveShorthand } from '@fluentui/react-utilities';\nimport { useARIAButtonProps } from './useARIAButtonProps';\nimport type { ResolveShorthandFunction } from '@fluentui/react-utilities';\nimport type { ARIAButtonProps, ARIAButtonSlotProps, ARIAButtonType } from './types';\n\n/**\n * @internal\n *\n * @deprecated use useARIAButtonProps instead\n *\n * This function expects to receive a slot, if `as` property is not desired use `useARIAButtonProps` instead\n *\n * Button keyboard handling, role, disabled and tabIndex implementation that ensures ARIA spec\n * for multiple scenarios of shorthand properties. Ensuring 1st rule of ARIA for cases\n * where no attribute addition is required.\n */\nexport const useARIAButtonShorthand = ((value, options) => {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const shorthand = resolveShorthand(value, options);\n const shorthandARIAButton = useARIAButtonProps<ARIAButtonType, ARIAButtonProps>(shorthand?.as ?? 'button', shorthand);\n return shorthand && shorthandARIAButton;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n}) as ResolveShorthandFunction<ARIAButtonSlotProps>;\n"],"names":["resolveShorthand","useARIAButtonProps","useARIAButtonShorthand","value","options","shorthand","shorthandARIAButton","as"],"mappings":"AAAA;AAEA,SAASA,gBAAgB,QAAQ,4BAA4B;AAC7D,SAASC,kBAAkB,QAAQ,uBAAuB;AAI1D;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,yBAA0B,CAACC,OAAOC;IAC7C,4DAA4D;IAC5D,MAAMC,YAAYL,iBAAiBG,OAAOC;QACsCC;IAAhF,MAAMC,sBAAsBL,mBAAoDI,CAAAA,gBAAAA,sBAAAA,gCAAAA,UAAWE,EAAE,cAAbF,2BAAAA,gBAAiB,UAAUA;IAC3G,OAAOA,aAAaC;AACpB,4DAA4D;AAC9D,EAAoD"}