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,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
FOCUS_VISIBLE_ATTR: function() {
return FOCUS_VISIBLE_ATTR;
},
FOCUS_WITHIN_ATTR: function() {
return FOCUS_WITHIN_ATTR;
},
KEYBOARD_NAV_ATTRIBUTE: function() {
return KEYBOARD_NAV_ATTRIBUTE;
},
KEYBOARD_NAV_SELECTOR: function() {
return KEYBOARD_NAV_SELECTOR;
},
defaultOptions: function() {
return defaultOptions;
}
});
const KEYBOARD_NAV_ATTRIBUTE = 'data-keyboard-nav';
const KEYBOARD_NAV_SELECTOR = `:global([${KEYBOARD_NAV_ATTRIBUTE}])`;
const FOCUS_VISIBLE_ATTR = 'data-fui-focus-visible';
const FOCUS_WITHIN_ATTR = 'data-fui-focus-within';
const defaultOptions = {
style: {},
selector: 'focus',
customizeSelector: (selector)=>selector
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/focus/constants.ts"],"sourcesContent":["export const KEYBOARD_NAV_ATTRIBUTE = 'data-keyboard-nav' as const;\nexport const KEYBOARD_NAV_SELECTOR = `:global([${KEYBOARD_NAV_ATTRIBUTE}])` as const;\n\n/**\n * @internal\n */\nexport const FOCUS_VISIBLE_ATTR = 'data-fui-focus-visible';\n\n/**\n * @internal\n */\nexport const FOCUS_WITHIN_ATTR = 'data-fui-focus-within';\nexport const defaultOptions = {\n style: {},\n selector: 'focus',\n customizeSelector: (selector: string) => selector,\n} as const;\n"],"names":["FOCUS_VISIBLE_ATTR","FOCUS_WITHIN_ATTR","KEYBOARD_NAV_ATTRIBUTE","KEYBOARD_NAV_SELECTOR","defaultOptions","style","selector","customizeSelector"],"mappings":";;;;;;;;;;;IAMaA,kBAAkB;eAAlBA;;IAKAC,iBAAiB;eAAjBA;;IAXAC,sBAAsB;eAAtBA;;IACAC,qBAAqB;eAArBA;;IAWAC,cAAc;eAAdA;;;AAZN,MAAMF,yBAAyB;AAC/B,MAAMC,wBAAwB,CAAC,SAAS,EAAED,uBAAuB,EAAE,CAAC;AAKpE,MAAMF,qBAAqB;AAK3B,MAAMC,oBAAoB;AAC1B,MAAMG,iBAAiB;IAC5BC,OAAO,CAAC;IACRC,UAAU;IACVC,mBAAmB,CAACD,WAAqBA;AAC3C"}

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "createCustomFocusIndicatorStyle", {
enumerable: true,
get: function() {
return createCustomFocusIndicatorStyle;
}
});
const _constants = require("./constants");
function createCustomFocusIndicatorStyle(style, { selector: selectorType = _constants.defaultOptions.selector, customizeSelector = _constants.defaultOptions.customizeSelector } = _constants.defaultOptions) {
return {
[customizeSelector(createBaseSelector(selectorType))]: style
};
}
function createBaseSelector(selectorType) {
switch(selectorType){
case 'focus':
return `&[${_constants.FOCUS_VISIBLE_ATTR}]`;
case 'focus-within':
return `&[${_constants.FOCUS_WITHIN_ATTR}]:focus-within`;
}
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/focus/createCustomFocusIndicatorStyle.ts"],"sourcesContent":["import { defaultOptions, FOCUS_VISIBLE_ATTR, FOCUS_WITHIN_ATTR } from './constants';\nimport { makeResetStyles } from '@griffel/react';\nimport type { GriffelStyle } from '@griffel/react';\n\n// TODO: Use the type directly from @griffel/react\n// https://github.com/microsoft/griffel/pull/278\ntype GriffelResetStyle = Parameters<typeof makeResetStyles>[0];\n\nexport interface CreateCustomFocusIndicatorStyleOptions {\n /**\n * Control if the indicator appears when the corresponding element is focused,\n * or any child is focused within the corresponding element.\n * @default 'focus'\n * @alias selectorType\n */\n selector?: 'focus' | 'focus-within';\n /**\n * Customizes the selector provided based on the selector type.\n */\n customizeSelector?: (selector: string) => string;\n /**\n * Enables the browser default outline style\n * @deprecated The custom focus indicator no longer affects outline styles. Outline is overridden\n * in the default focus indicator function, `createFocusOutlineStyle`.\n */\n enableOutline?: boolean;\n}\n\n/**\n * Creates a style for @see makeStyles that includes the necessary selectors for focus.\n * Should be used only when @see createFocusOutlineStyle does not fit requirements\n *\n * If you're using `createCustomFocusIndicatorStyle` instead of `createFocusOutlineStyle`\n * keep in mind that the default outline style is not going to be removed\n * (as it is in `createFocusOutlineStyle`),\n * and is your responsibility to manually remove it from your styles.\n *\n * @example\n * ```ts\n * // Link styles\n * const useStyles = makeStyles({\n focusIndicator: createCustomFocusIndicatorStyle({\n textDecorationColor: tokens.colorStrokeFocus2,\n textDecorationLine: 'underline',\n textDecorationStyle: 'double',\n outlineStyle: 'none',\n }),\n // Common styles.\n root: {\n // ❗️ DO NOT FORGET TO REMOVE THE DEFAULT OUTLINE STYLE\n ':focus-visible': {\n outlineStyle: 'none',\n },\n * ```\n *\n * @param style - styling applied on focus, defaults to @see getDefaultFocusOutlineStyles\n * @param options - Configure the style of the focus outline\n */\nexport function createCustomFocusIndicatorStyle<TStyle extends GriffelStyle | GriffelResetStyle>(\n style: TStyle,\n {\n selector: selectorType = defaultOptions.selector,\n customizeSelector = defaultOptions.customizeSelector,\n }: CreateCustomFocusIndicatorStyleOptions = defaultOptions,\n): TStyle extends GriffelStyle ? GriffelStyle : GriffelResetStyle {\n return { [customizeSelector(createBaseSelector(selectorType))]: style };\n}\n\nfunction createBaseSelector(selectorType: 'focus' | 'focus-within'): string {\n switch (selectorType) {\n case 'focus':\n return `&[${FOCUS_VISIBLE_ATTR}]`;\n case 'focus-within':\n return `&[${FOCUS_WITHIN_ATTR}]:focus-within`;\n }\n}\n"],"names":["createCustomFocusIndicatorStyle","style","selector","selectorType","defaultOptions","customizeSelector","createBaseSelector","FOCUS_VISIBLE_ATTR","FOCUS_WITHIN_ATTR"],"mappings":";;;;+BA0DgBA;;;eAAAA;;;2BA1DsD;AA0D/D,SAASA,gCACdC,KAAa,EACb,EACEC,UAAUC,eAAeC,yBAAc,CAACF,QAAQ,EAChDG,oBAAoBD,yBAAc,CAACC,iBAAiB,EACb,GAAGD,yBAAc;IAE1D,OAAO;QAAE,CAACC,kBAAkBC,mBAAmBH,eAAe,EAAEF;IAAM;AACxE;AAEA,SAASK,mBAAmBH,YAAsC;IAChE,OAAQA;QACN,KAAK;YACH,OAAO,CAAC,EAAE,EAAEI,6BAAkB,CAAC,CAAC,CAAC;QACnC,KAAK;YACH,OAAO,CAAC,EAAE,EAAEC,4BAAiB,CAAC,cAAc,CAAC;IACjD;AACF"}

View File

@@ -0,0 +1,74 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "createFocusOutlineStyle", {
enumerable: true,
get: function() {
return createFocusOutlineStyle;
}
});
const _reacttheme = require("@fluentui/react-theme");
const _react = require("@griffel/react");
const _createCustomFocusIndicatorStyle = require("./createCustomFocusIndicatorStyle");
const _constants = require("./constants");
/**
* Get the position of the focus outline
*
* @param options - Configures the style of the focus outline
* @param position - The position of the focus outline
* @returns CSS value for the position of the focus outline
*/ function getOutlinePosition({ outlineWidth, outlineOffset }, position) {
const offsetValue = (outlineOffset === null || outlineOffset === void 0 ? void 0 : outlineOffset[position]) || outlineOffset;
if (!outlineOffset) {
return `calc(${outlineWidth} * -1)`;
}
return `calc(0px - ${outlineWidth} - ${offsetValue})`;
}
/**
* NOTE: the element with the focus outline needs to have `position: relative` so that the
* pseudo element can be properly positioned.
*
* @param options - Configures the style of the focus outline
* @returns focus outline styles object
*/ const getFocusOutlineStyles = (options)=>{
const { outlineRadius, outlineColor, outlineWidth } = options;
return {
..._react.shorthands.borderColor('transparent'),
'@media (forced-colors: active)': {
'::after': {
..._react.shorthands.borderColor('Highlight')
}
},
'::after': {
content: '""',
position: 'absolute',
pointerEvents: 'none',
zIndex: 1,
border: `${outlineWidth} solid ${outlineColor}`,
borderRadius: outlineRadius,
top: getOutlinePosition(options, 'top'),
right: getOutlinePosition(options, 'right'),
bottom: getOutlinePosition(options, 'bottom'),
left: getOutlinePosition(options, 'left')
}
};
};
const createFocusOutlineStyle = ({ enableOutline = false, selector = _constants.defaultOptions.selector, customizeSelector, style = _constants.defaultOptions.style } = _constants.defaultOptions)=>({
':focus': {
outlineStyle: enableOutline ? undefined : 'none'
},
':focus-visible': {
outlineStyle: enableOutline ? undefined : 'none'
},
...(0, _createCustomFocusIndicatorStyle.createCustomFocusIndicatorStyle)(getFocusOutlineStyles({
outlineColor: _reacttheme.tokens.colorStrokeFocus2,
outlineRadius: _reacttheme.tokens.borderRadiusMedium,
// FIXME: tokens.strokeWidthThick causes some weird bugs
outlineWidth: '2px',
...style
}), {
selector,
customizeSelector
})
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,79 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "applyFocusVisiblePolyfill", {
enumerable: true,
get: function() {
return applyFocusVisiblePolyfill;
}
});
const _reactutilities = require("@fluentui/react-utilities");
const _keyborg = require("keyborg");
const _constants = require("./constants");
function applyFocusVisiblePolyfill(scope, targetWindow) {
if (alreadyInScope(scope)) {
// Focus visible polyfill already applied at this scope
return ()=>undefined;
}
const state = {
current: undefined
};
const keyborg = (0, _keyborg.createKeyborg)(targetWindow);
function registerElementIfNavigating(el) {
if (keyborg.isNavigatingWithKeyboard() && (0, _reactutilities.isHTMLElement)(el)) {
state.current = el;
el.setAttribute(_constants.FOCUS_VISIBLE_ATTR, '');
}
}
function disposeCurrentElement() {
if (state.current) {
state.current.removeAttribute(_constants.FOCUS_VISIBLE_ATTR);
state.current = undefined;
}
}
// When navigation mode changes remove the focus-visible selector
keyborg.subscribe((isNavigatingWithKeyboard)=>{
if (!isNavigatingWithKeyboard) {
disposeCurrentElement();
} else {
registerElementIfNavigating(targetWindow.document.activeElement);
}
});
// Keyborg's focusin event is delegated so it's only registered once on the window
// and contains metadata about the focus event
const keyborgListener = (e)=>{
disposeCurrentElement();
const target = e.composedPath()[0];
registerElementIfNavigating(target);
};
// Make sure that when focus leaves the scope, the focus visible class is removed
const blurListener = (e)=>{
if (!e.relatedTarget || (0, _reactutilities.isHTMLElement)(e.relatedTarget) && !scope.contains(e.relatedTarget)) {
disposeCurrentElement();
}
};
scope.addEventListener(_keyborg.KEYBORG_FOCUSIN, keyborgListener);
scope.addEventListener('focusout', blurListener);
scope.focusVisible = true;
if (scope.contains(targetWindow.document.activeElement)) {
registerElementIfNavigating(targetWindow.document.activeElement);
}
// Return disposer
return ()=>{
disposeCurrentElement();
scope.removeEventListener(_keyborg.KEYBORG_FOCUSIN, keyborgListener);
scope.removeEventListener('focusout', blurListener);
scope.focusVisible = undefined;
(0, _keyborg.disposeKeyborg)(keyborg);
};
}
function alreadyInScope(el) {
if (!el) {
return false;
}
if (el.focusVisible) {
return true;
}
return alreadyInScope(el === null || el === void 0 ? void 0 : el.parentElement);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "applyFocusWithinPolyfill", {
enumerable: true,
get: function() {
return applyFocusWithinPolyfill;
}
});
const _keyborg = require("keyborg");
const _constants = require("./constants");
function applyFocusWithinPolyfill(element, win) {
const keyborg = (0, _keyborg.createKeyborg)(win);
// When navigation mode changes to mouse, remove the focus-within selector
keyborg.subscribe((isNavigatingWithKeyboard)=>{
if (!isNavigatingWithKeyboard) {
removeFocusWithinClass(element);
}
});
// Keyborg's focusin event is delegated so it's only registered once on the window
// and contains metadata about the focus event
const keyborgListener = (e)=>{
if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(e.target)) {
// Griffel can't create chained global styles so use the parent element for now
applyFocusWithinClass(element);
}
};
// Make sure that when focus leaves the scope, the focus within class is removed
const blurListener = (e)=>{
if (!e.relatedTarget || isHTMLElement(e.relatedTarget) && !element.contains(e.relatedTarget)) {
removeFocusWithinClass(element);
}
};
element.addEventListener(_keyborg.KEYBORG_FOCUSIN, keyborgListener);
element.addEventListener('focusout', blurListener);
// Return disposer
return ()=>{
element.removeEventListener(_keyborg.KEYBORG_FOCUSIN, keyborgListener);
element.removeEventListener('focusout', blurListener);
(0, _keyborg.disposeKeyborg)(keyborg);
};
}
function applyFocusWithinClass(el) {
el.setAttribute(_constants.FOCUS_WITHIN_ATTR, '');
}
function removeFocusWithinClass(el) {
el.removeAttribute(_constants.FOCUS_WITHIN_ATTR);
}
function isHTMLElement(target) {
if (!target) {
return false;
}
return Boolean(target && typeof target === 'object' && 'classList' in target && 'contains' in target);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/focus/focusWithinPolyfill.ts"],"sourcesContent":["import { KEYBORG_FOCUSIN, KeyborgFocusInEvent, createKeyborg, disposeKeyborg } from 'keyborg';\nimport { FOCUS_WITHIN_ATTR } from './constants';\n\n/**\n * Because `addEventListener` type override falls back to 2nd definition (evt name is unknown string literal)\n * evt is being typed as a base class of MouseEvent -> `Event`.\n * This type is used to override `listener` calls to make TS happy\n */\ntype ListenerOverride = (evt: Event) => void;\n\n/**\n * A ponyfill that allows `:focus-within` to support visibility based on keyboard/mouse navigation\n * like `:focus-visible` https://github.com/WICG/focus-visible/issues/151\n * @returns ref to the element that uses `:focus-within` styles\n */\nexport function applyFocusWithinPolyfill(element: HTMLElement, win: Window): () => void {\n const keyborg = createKeyborg(win);\n\n // When navigation mode changes to mouse, remove the focus-within selector\n keyborg.subscribe(isNavigatingWithKeyboard => {\n if (!isNavigatingWithKeyboard) {\n removeFocusWithinClass(element);\n }\n });\n\n // Keyborg's focusin event is delegated so it's only registered once on the window\n // and contains metadata about the focus event\n const keyborgListener = (e: KeyborgFocusInEvent) => {\n if (keyborg.isNavigatingWithKeyboard() && isHTMLElement(e.target)) {\n // Griffel can't create chained global styles so use the parent element for now\n applyFocusWithinClass(element);\n }\n };\n\n // Make sure that when focus leaves the scope, the focus within class is removed\n const blurListener = (e: FocusEvent) => {\n if (!e.relatedTarget || (isHTMLElement(e.relatedTarget) && !element.contains(e.relatedTarget))) {\n removeFocusWithinClass(element);\n }\n };\n\n element.addEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n element.addEventListener('focusout', blurListener);\n\n // Return disposer\n return () => {\n element.removeEventListener(KEYBORG_FOCUSIN, keyborgListener as ListenerOverride);\n element.removeEventListener('focusout', blurListener);\n disposeKeyborg(keyborg);\n };\n}\n\nfunction applyFocusWithinClass(el: HTMLElement) {\n el.setAttribute(FOCUS_WITHIN_ATTR, '');\n}\n\nfunction removeFocusWithinClass(el: HTMLElement) {\n el.removeAttribute(FOCUS_WITHIN_ATTR);\n}\n\nfunction isHTMLElement(target: EventTarget | null): target is HTMLElement {\n if (!target) {\n return false;\n }\n return Boolean(target && typeof target === 'object' && 'classList' in target && 'contains' in target);\n}\n"],"names":["applyFocusWithinPolyfill","element","win","keyborg","createKeyborg","subscribe","isNavigatingWithKeyboard","removeFocusWithinClass","keyborgListener","e","isHTMLElement","target","applyFocusWithinClass","blurListener","relatedTarget","contains","addEventListener","KEYBORG_FOCUSIN","removeEventListener","disposeKeyborg","el","setAttribute","FOCUS_WITHIN_ATTR","removeAttribute","Boolean"],"mappings":";;;;+BAegBA;;;eAAAA;;;yBAfoE;2BAClD;AAc3B,SAASA,yBAAyBC,OAAoB,EAAEC,GAAW;IACxE,MAAMC,UAAUC,IAAAA,sBAAa,EAACF;IAE9B,0EAA0E;IAC1EC,QAAQE,SAAS,CAACC,CAAAA;QAChB,IAAI,CAACA,0BAA0B;YAC7BC,uBAAuBN;QACzB;IACF;IAEA,kFAAkF;IAClF,8CAA8C;IAC9C,MAAMO,kBAAkB,CAACC;QACvB,IAAIN,QAAQG,wBAAwB,MAAMI,cAAcD,EAAEE,MAAM,GAAG;YACjE,+EAA+E;YAC/EC,sBAAsBX;QACxB;IACF;IAEA,gFAAgF;IAChF,MAAMY,eAAe,CAACJ;QACpB,IAAI,CAACA,EAAEK,aAAa,IAAKJ,cAAcD,EAAEK,aAAa,KAAK,CAACb,QAAQc,QAAQ,CAACN,EAAEK,aAAa,GAAI;YAC9FP,uBAAuBN;QACzB;IACF;IAEAA,QAAQe,gBAAgB,CAACC,wBAAe,EAAET;IAC1CP,QAAQe,gBAAgB,CAAC,YAAYH;IAErC,kBAAkB;IAClB,OAAO;QACLZ,QAAQiB,mBAAmB,CAACD,wBAAe,EAAET;QAC7CP,QAAQiB,mBAAmB,CAAC,YAAYL;QACxCM,IAAAA,uBAAc,EAAChB;IACjB;AACF;AAEA,SAASS,sBAAsBQ,EAAe;IAC5CA,GAAGC,YAAY,CAACC,4BAAiB,EAAE;AACrC;AAEA,SAASf,uBAAuBa,EAAe;IAC7CA,GAAGG,eAAe,CAACD,4BAAiB;AACtC;AAEA,SAASZ,cAAcC,MAA0B;IAC/C,IAAI,CAACA,QAAQ;QACX,OAAO;IACT;IACA,OAAOa,QAAQb,UAAU,OAAOA,WAAW,YAAY,eAAeA,UAAU,cAAcA;AAChG"}

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
applyFocusVisiblePolyfill: function() {
return _focusVisiblePolyfill.applyFocusVisiblePolyfill;
},
applyFocusWithinPolyfill: function() {
return _focusWithinPolyfill.applyFocusWithinPolyfill;
},
createCustomFocusIndicatorStyle: function() {
return _createCustomFocusIndicatorStyle.createCustomFocusIndicatorStyle;
},
createFocusOutlineStyle: function() {
return _createFocusOutlineStyle.createFocusOutlineStyle;
}
});
const _createCustomFocusIndicatorStyle = require("./createCustomFocusIndicatorStyle");
const _createFocusOutlineStyle = require("./createFocusOutlineStyle");
const _focusVisiblePolyfill = require("./focusVisiblePolyfill");
const _focusWithinPolyfill = require("./focusWithinPolyfill");

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/focus/index.ts"],"sourcesContent":["export type { CreateCustomFocusIndicatorStyleOptions } from './createCustomFocusIndicatorStyle';\nexport { createCustomFocusIndicatorStyle } from './createCustomFocusIndicatorStyle';\nexport type {\n CreateFocusOutlineStyleOptions,\n FocusOutlineOffset,\n FocusOutlineStyleOptions,\n} from './createFocusOutlineStyle';\nexport { createFocusOutlineStyle } from './createFocusOutlineStyle';\nexport { applyFocusVisiblePolyfill } from './focusVisiblePolyfill';\nexport { applyFocusWithinPolyfill } from './focusWithinPolyfill';\n"],"names":["applyFocusVisiblePolyfill","applyFocusWithinPolyfill","createCustomFocusIndicatorStyle","createFocusOutlineStyle"],"mappings":";;;;;;;;;;;IAQSA,yBAAyB;eAAzBA,+CAAyB;;IACzBC,wBAAwB;eAAxBA,6CAAwB;;IARxBC,+BAA+B;eAA/BA,gEAA+B;;IAM/BC,uBAAuB;eAAvBA,gDAAuB;;;iDANgB;yCAMR;sCACE;qCACD"}