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

1900
node_modules/@fluentui/react-aria/CHANGELOG.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

15
node_modules/@fluentui/react-aria/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,15 @@
@fluentui/react-aria
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Note: Usage of the fonts and icons referenced in Fluent UI React is subject to the terms listed at https://aka.ms/fluentui-assets-license

3
node_modules/@fluentui/react-aria/README.md generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# @fluentui/react-aria
**React Aria components for [Fluent UI React](https://react.fluentui.dev)**

215
node_modules/@fluentui/react-aria/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,215 @@
import type { AnnounceContextValue } from '@fluentui/react-shared-contexts';
import type { DistributiveOmit } from '@fluentui/react-utilities';
import type { ExtractSlotProps } from '@fluentui/react-utilities';
import type { JSXElement } from '@fluentui/react-utilities';
import type { JSXIntrinsicElement } from '@fluentui/react-utilities';
import * as React_2 from 'react';
import type { ResolveShorthandFunction } from '@fluentui/react-utilities';
import type { Slot } from '@fluentui/react-utilities';
import type { UnionToIntersection } from '@fluentui/react-utilities';
/**
* Applied to the active descendant when the user is navigating with keyboard
*/
export declare const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = "data-activedescendant-focusvisible";
export declare type ActiveDescendantChangeEvent = CustomEvent<ActiveDescendantChangeEventDetail>;
declare interface ActiveDescendantChangeEventDetail {
id: string;
previousId: string | null;
}
export declare const ActiveDescendantContextProvider: React_2.Provider<ActiveDescendantContextValue | undefined>;
export declare type ActiveDescendantContextValue = {
controller: ActiveDescendantImperativeRef;
};
export declare interface ActiveDescendantImperativeRef {
first: (options?: IteratorOptions) => string | undefined;
last: (options?: IteratorOptions) => string | undefined;
next: (options?: IteratorOptions) => string | undefined;
prev: (options?: IteratorOptions) => string | undefined;
find: (predicate: (id: string) => boolean, options?: IteratorOptions & FindOptions) => string | undefined;
blur: () => void;
active: () => string | undefined;
focus: (id: string) => void;
/**
* @deprecated This function is not used internally anymore and will be removed in the future
*/
focusLastActive: () => void;
/**
* Scrolls the active option into view, if it still exists
*/
scrollActiveIntoView: () => void;
hideAttributes: () => void;
showAttributes: () => void;
hideFocusVisibleAttributes: () => void;
showFocusVisibleAttributes: () => void;
}
export declare interface ActiveDescendantOptions {
/**
* @param el - HTML element to test
* @returns whether the element can be an active descendant
*/
matchOption: (el: HTMLElement) => boolean;
/**
* Forward imperative refs when exposing functionality from a React component
*/
imperativeRef?: React_2.RefObject<ActiveDescendantImperativeRef | null>;
}
/**
* Props that will be modified internally by `useARIAButtonProps` by each case.
* This typing is to ensure a well specified return value for `useARIAbButtonProps`
*/
export declare type ARIAButtonAlteredProps<Type extends ARIAButtonType> = (Type extends 'button' ? Pick<JSXIntrinsicElement<'button'>, 'onClick' | 'onKeyDown' | 'onKeyUp' | 'disabled' | 'aria-disabled' | 'tabIndex'> : never) | (Type extends 'a' ? Pick<JSXIntrinsicElement<'a'>, 'onClick' | 'onKeyDown' | 'onKeyUp' | 'aria-disabled' | 'tabIndex' | 'role' | 'href'> : never) | (Type extends 'div' ? Pick<JSXIntrinsicElement<'div'>, 'onClick' | 'onKeyDown' | 'onKeyUp' | 'aria-disabled' | 'tabIndex' | 'role'> : never);
export declare type ARIAButtonElement<AlternateAs extends 'a' | 'div' = 'a' | 'div'> = HTMLButtonElement | (AlternateAs extends 'a' ? HTMLAnchorElement : never) | (AlternateAs extends 'div' ? HTMLDivElement : never);
/**
* @internal
*/
export declare type ARIAButtonElementIntersection<AlternateAs extends 'a' | 'div' = 'a' | 'div'> = UnionToIntersection<ARIAButtonElement<AlternateAs>>;
/**
* Props expected by `useARIAButtonProps` hooks
*/
export declare type ARIAButtonProps<Type extends ARIAButtonType = ARIAButtonType> = DistributiveOmit<React_2.PropsWithRef<JSXIntrinsicElement<Type>>, 'children'> & {
disabled?: boolean;
/**
* When set, allows the button to be focusable even when it has been disabled.
* This is used in scenarios where it is important to keep a consistent tab order
* for screen reader and keyboard users. The primary example of this
* pattern is when the disabled button is in a menu or a commandbar and is seldom used for standalone buttons.
*
* @default false
*/
disabledFocusable?: boolean;
};
/**
* Merge of props provided by the user and props provided internally.
*/
export declare type ARIAButtonResultProps<Type extends ARIAButtonType, Props> = Props & UnionToIntersection<ARIAButtonAlteredProps<Type>>;
export declare type ARIAButtonSlotProps<AlternateAs extends 'a' | 'div' = 'a' | 'div'> = ExtractSlotProps<Slot<'button', AlternateAs>> & Pick<ARIAButtonProps<ARIAButtonType>, 'disabled' | 'disabledFocusable'>;
export declare type ARIAButtonType = 'button' | 'a' | 'div';
declare type AriaLiveAnnounceFn = AnnounceContextValue['announce'];
/**
* A sample implementation of a component that manages aria live announcements.
*/
export declare const AriaLiveAnnouncer: React_2.FC<AriaLiveAnnouncerProps>;
declare type AriaLiveAnnouncerContextValues = {
announce: {
announce: AriaLiveAnnounceFn;
};
};
export declare type AriaLiveAnnouncerProps = {
children?: React_2.ReactNode;
};
export declare type AriaLiveAnnouncerState = {
announce: AriaLiveAnnounceFn;
children?: React_2.ReactNode;
};
declare interface FindOptions {
/**
* Starts the search from a specific id
*/
startFrom?: string;
}
declare interface IteratorOptions {
/**
* When passive, the active descendant is changed
* @default false
*/
passive?: boolean;
}
export declare const renderAriaLiveAnnouncer_unstable: (state: AriaLiveAnnouncerState, contextValues: AriaLiveAnnouncerContextValues) => JSXElement;
declare interface TypingAnnounceReturn<TInputElement extends HTMLElement = HTMLElement> {
typingAnnounce: AriaLiveAnnounceFn;
inputRef: React_2.MutableRefObject<TInputElement | null>;
}
export declare function useActiveDescendant<TActiveParentElement extends HTMLElement, TListboxElement extends HTMLElement>(options: ActiveDescendantOptions): UseActiveDescendantReturn<TActiveParentElement, TListboxElement>;
export declare const useActiveDescendantContext: () => ActiveDescendantContextValue;
declare interface UseActiveDescendantReturn<TActiveParentElement extends HTMLElement = HTMLElement, TListboxElement extends HTMLElement = HTMLElement> {
/**
* Attach this to the element that contains all active descendants
*/
listboxRef: React_2.Ref<TListboxElement>;
/**
* Attach this to the element that has an active descendant
*/
activeParentRef: React_2.Ref<TActiveParentElement>;
/**
* Imperative functions to manage active descendants within the listboxRef
*/
controller: ActiveDescendantImperativeRef;
}
/**
* @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 declare function useARIAButtonProps<Type extends ARIAButtonType, Props extends ARIAButtonProps<Type>>(type?: Type, props?: Props): ARIAButtonResultProps<Type, Props>;
/**
* @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 declare const useARIAButtonShorthand: ResolveShorthandFunction<ARIAButtonSlotProps>;
export declare const useAriaLiveAnnouncer_unstable: (props: AriaLiveAnnouncerProps) => AriaLiveAnnouncerState;
export declare function useAriaLiveAnnouncerContextValues_unstable(state: AriaLiveAnnouncerState): AriaLiveAnnouncerContextValues;
export declare const useHasParentActiveDescendantContext: () => boolean;
export declare function useTypingAnnounce<TInputElement extends HTMLElement = HTMLElement>(): TypingAnnounceReturn<TInputElement>;
export { }

View File

@@ -0,0 +1,22 @@
'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "AriaLiveAnnouncer", {
enumerable: true,
get: function() {
return AriaLiveAnnouncer;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _renderAriaLiveAnnouncer = require("./renderAriaLiveAnnouncer");
const _useAriaLiveAnnouncer = require("./useAriaLiveAnnouncer");
const _useAriaLiveAnnouncerContextValues = require("./useAriaLiveAnnouncerContextValues");
const AriaLiveAnnouncer = (props)=>{
const state = (0, _useAriaLiveAnnouncer.useAriaLiveAnnouncer_unstable)(props);
const contextValues = (0, _useAriaLiveAnnouncerContextValues.useAriaLiveAnnouncerContextValues_unstable)(state);
return (0, _renderAriaLiveAnnouncer.renderAriaLiveAnnouncer_unstable)(state, contextValues);
};
AriaLiveAnnouncer.displayName = 'AriaLiveAnnouncer';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/AriaLiveAnnouncer.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport type { AriaLiveAnnouncerProps } from './AriaLiveAnnouncer.types';\nimport { renderAriaLiveAnnouncer_unstable } from './renderAriaLiveAnnouncer';\nimport { useAriaLiveAnnouncer_unstable } from './useAriaLiveAnnouncer';\nimport { useAriaLiveAnnouncerContextValues_unstable } from './useAriaLiveAnnouncerContextValues';\n\n/**\n * A sample implementation of a component that manages aria live announcements.\n */\nexport const AriaLiveAnnouncer: React.FC<AriaLiveAnnouncerProps> = props => {\n const state = useAriaLiveAnnouncer_unstable(props);\n const contextValues = useAriaLiveAnnouncerContextValues_unstable(state);\n\n return renderAriaLiveAnnouncer_unstable(state, contextValues);\n};\n\nAriaLiveAnnouncer.displayName = 'AriaLiveAnnouncer';\n"],"names":["AriaLiveAnnouncer","props","state","useAriaLiveAnnouncer_unstable","contextValues","useAriaLiveAnnouncerContextValues_unstable","renderAriaLiveAnnouncer_unstable","displayName"],"mappings":"AAAA;;;;;+BAYaA;;;eAAAA;;;;iEAVU;yCAG0B;sCACH;mDACa;AAKpD,MAAMA,oBAAsDC,CAAAA;IACjE,MAAMC,QAAQC,IAAAA,mDAA6B,EAACF;IAC5C,MAAMG,gBAAgBC,IAAAA,6EAA0C,EAACH;IAEjE,OAAOI,IAAAA,yDAAgC,EAACJ,OAAOE;AACjD;AAEAJ,kBAAkBO,WAAW,GAAG"}

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/AriaLiveAnnouncer.types.ts"],"sourcesContent":["import type { AnnounceContextValue } from '@fluentui/react-shared-contexts';\nimport * as React from 'react';\n\nexport type AriaLiveAnnounceFn = AnnounceContextValue['announce'];\n\nexport type AriaLiveMessage = {\n message: string;\n\n createdAt: number;\n\n priority: number;\n batchId?: string;\n};\n\nexport type AriaLiveAnnouncerProps = {\n children?: React.ReactNode;\n};\n\nexport type AriaLiveAnnouncerState = {\n announce: AriaLiveAnnounceFn;\n children?: React.ReactNode;\n};\n\nexport type AriaLiveAnnouncerContextValues = {\n announce: { announce: AriaLiveAnnounceFn };\n};\n"],"names":[],"mappings":";;;;;iEACuB"}

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, {
AriaLiveAnnouncer: function() {
return _AriaLiveAnnouncer.AriaLiveAnnouncer;
},
renderAriaLiveAnnouncer_unstable: function() {
return _renderAriaLiveAnnouncer.renderAriaLiveAnnouncer_unstable;
},
useAriaLiveAnnouncerContextValues_unstable: function() {
return _useAriaLiveAnnouncerContextValues.useAriaLiveAnnouncerContextValues_unstable;
},
useAriaLiveAnnouncer_unstable: function() {
return _useAriaLiveAnnouncer.useAriaLiveAnnouncer_unstable;
}
});
const _AriaLiveAnnouncer = require("./AriaLiveAnnouncer");
const _renderAriaLiveAnnouncer = require("./renderAriaLiveAnnouncer");
const _useAriaLiveAnnouncer = require("./useAriaLiveAnnouncer");
const _useAriaLiveAnnouncerContextValues = require("./useAriaLiveAnnouncerContextValues");

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/index.ts"],"sourcesContent":["export { AriaLiveAnnouncer } from './AriaLiveAnnouncer';\nexport type { AriaLiveAnnouncerProps, AriaLiveAnnouncerState } from './AriaLiveAnnouncer.types';\nexport { renderAriaLiveAnnouncer_unstable } from './renderAriaLiveAnnouncer';\nexport { useAriaLiveAnnouncer_unstable } from './useAriaLiveAnnouncer';\nexport { useAriaLiveAnnouncerContextValues_unstable } from './useAriaLiveAnnouncerContextValues';\n"],"names":["AriaLiveAnnouncer","renderAriaLiveAnnouncer_unstable","useAriaLiveAnnouncerContextValues_unstable","useAriaLiveAnnouncer_unstable"],"mappings":";;;;;;;;;;;IAASA,iBAAiB;eAAjBA,oCAAiB;;IAEjBC,gCAAgC;eAAhCA,yDAAgC;;IAEhCC,0CAA0C;eAA1CA,6EAA0C;;IAD1CC,6BAA6B;eAA7BA,mDAA6B;;;mCAHJ;yCAEe;sCACH;mDACa"}

View File

@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "renderAriaLiveAnnouncer_unstable", {
enumerable: true,
get: function() {
return renderAriaLiveAnnouncer_unstable;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
const renderAriaLiveAnnouncer_unstable = (state, contextValues)=>{
return /*#__PURE__*/ _react.createElement(_reactsharedcontexts.AnnounceProvider, {
value: contextValues.announce
}, state.children);
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/renderAriaLiveAnnouncer.tsx"],"sourcesContent":["import * as React from 'react';\nimport { AnnounceProvider } from '@fluentui/react-shared-contexts';\n\nimport type { AriaLiveAnnouncerContextValues, AriaLiveAnnouncerState } from './AriaLiveAnnouncer.types';\nimport type { JSXElement } from '@fluentui/react-utilities';\n\nexport const renderAriaLiveAnnouncer_unstable = (\n state: AriaLiveAnnouncerState,\n contextValues: AriaLiveAnnouncerContextValues,\n): JSXElement => {\n return <AnnounceProvider value={contextValues.announce}>{state.children}</AnnounceProvider>;\n};\n"],"names":["renderAriaLiveAnnouncer_unstable","state","contextValues","AnnounceProvider","value","announce","children"],"mappings":";;;;+BAMaA;;;eAAAA;;;;iEANU;qCACU;AAK1B,MAAMA,mCAAmC,CAC9CC,OACAC;IAEA,qBAAO,qBAACC,qCAAgB;QAACC,OAAOF,cAAcG,QAAQ;OAAGJ,MAAMK,QAAQ;AACzE"}

View File

@@ -0,0 +1,34 @@
'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useAriaLiveAnnouncer_unstable", {
enumerable: true,
get: function() {
return useAriaLiveAnnouncer_unstable;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
const _useDomAnnounce = require("./useDomAnnounce");
const _useAriaNotifyAnnounce = require("./useAriaNotifyAnnounce");
const useAriaLiveAnnouncer_unstable = (props)=>{
const { targetDocument } = (0, _reactsharedcontexts.useFluent_unstable)();
const domAnnounce = (0, _useDomAnnounce.useDomAnnounce_unstable)();
const ariaNotifyAnnounce = (0, _useAriaNotifyAnnounce.useAriaNotifyAnnounce_unstable)();
const announce = _react.useMemo(()=>{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const supportsAriaNotify = typeof (targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.ariaNotify) === 'function';
return supportsAriaNotify ? ariaNotifyAnnounce : domAnnounce;
}, [
targetDocument,
ariaNotifyAnnounce,
domAnnounce
]);
return {
announce,
children: props.children
};
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/useAriaLiveAnnouncer.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { useDomAnnounce_unstable } from './useDomAnnounce';\nimport { useAriaNotifyAnnounce_unstable } from './useAriaNotifyAnnounce';\n\nimport type { AriaLiveAnnouncerState, AriaLiveAnnouncerProps } from './AriaLiveAnnouncer.types';\n\nexport const useAriaLiveAnnouncer_unstable = (props: AriaLiveAnnouncerProps): AriaLiveAnnouncerState => {\n const { targetDocument } = useFluent();\n const domAnnounce = useDomAnnounce_unstable();\n const ariaNotifyAnnounce = useAriaNotifyAnnounce_unstable();\n\n const announce = React.useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const supportsAriaNotify = typeof (targetDocument as any)?.ariaNotify === 'function';\n return supportsAriaNotify ? ariaNotifyAnnounce : domAnnounce;\n }, [targetDocument, ariaNotifyAnnounce, domAnnounce]);\n\n return {\n announce,\n children: props.children,\n };\n};\n"],"names":["useAriaLiveAnnouncer_unstable","props","targetDocument","useFluent","domAnnounce","useDomAnnounce_unstable","ariaNotifyAnnounce","useAriaNotifyAnnounce_unstable","announce","React","useMemo","supportsAriaNotify","ariaNotify","children"],"mappings":"AAAA;;;;;+BASaA;;;eAAAA;;;;iEAPU;qCACyB;gCACR;uCACO;AAIxC,MAAMA,gCAAgC,CAACC;IAC5C,MAAM,EAAEC,cAAc,EAAE,GAAGC,IAAAA,uCAAS;IACpC,MAAMC,cAAcC,IAAAA,uCAAuB;IAC3C,MAAMC,qBAAqBC,IAAAA,qDAA8B;IAEzD,MAAMC,WAAWC,OAAMC,OAAO,CAAC;QAC7B,8DAA8D;QAC9D,MAAMC,qBAAqB,QAAQT,2BAAAA,qCAAD,AAACA,eAAwBU,UAAU,MAAK;QAC1E,OAAOD,qBAAqBL,qBAAqBF;IACnD,GAAG;QAACF;QAAgBI;QAAoBF;KAAY;IAEpD,OAAO;QACLI;QACAK,UAAUZ,MAAMY,QAAQ;IAC1B;AACF"}

View File

@@ -0,0 +1,23 @@
'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useAriaLiveAnnouncerContextValues_unstable", {
enumerable: true,
get: function() {
return useAriaLiveAnnouncerContextValues_unstable;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
function useAriaLiveAnnouncerContextValues_unstable(state) {
const { announce } = state;
return _react.useMemo(()=>({
announce: {
announce
}
}), [
announce
]);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/useAriaLiveAnnouncerContextValues.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { AriaLiveAnnouncerContextValues, AriaLiveAnnouncerState } from './AriaLiveAnnouncer.types';\n\nexport function useAriaLiveAnnouncerContextValues_unstable(\n state: AriaLiveAnnouncerState,\n): AriaLiveAnnouncerContextValues {\n const { announce } = state;\n\n return React.useMemo(() => ({ announce: { announce } }), [announce]);\n}\n"],"names":["useAriaLiveAnnouncerContextValues_unstable","state","announce","React","useMemo"],"mappings":"AAAA;;;;;+BAKgBA;;;eAAAA;;;;iEAHO;AAGhB,SAASA,2CACdC,KAA6B;IAE7B,MAAM,EAAEC,QAAQ,EAAE,GAAGD;IAErB,OAAOE,OAAMC,OAAO,CAAC,IAAO,CAAA;YAAEF,UAAU;gBAAEA;YAAS;QAAE,CAAA,GAAI;QAACA;KAAS;AACrE"}

View File

@@ -0,0 +1,36 @@
'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useAriaNotifyAnnounce_unstable", {
enumerable: true,
get: function() {
return useAriaNotifyAnnounce_unstable;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const useAriaNotifyAnnounce_unstable = ()=>{
const { targetDocument } = (0, _reactsharedcontexts.useFluent_unstable)();
const announce = _react.useCallback((message, options = {})=>{
if (!targetDocument) {
return;
}
const { alert = false, polite } = options;
// default priority to 0 if polite, 2 if alert, and 1 by default
// used to set both ariaNotify's priority and interrupt
const defaultPriority = polite ? 0 : alert ? 2 : 1;
var _options_priority;
const priority = (_options_priority = options.priority) !== null && _options_priority !== void 0 ? _options_priority : defaultPriority;
// map fluent announce options to ariaNotify options
const ariaNotifyOptions = {
priority: priority > 1 ? 'high' : 'normal'
};
targetDocument.ariaNotify(message, ariaNotifyOptions);
}, [
targetDocument
]);
return announce;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/useAriaNotifyAnnounce.ts"],"sourcesContent":["'use client';\n\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport type { AnnounceOptions } from '@fluentui/react-shared-contexts';\nimport * as React from 'react';\n\nimport type { AriaLiveAnnounceFn } from './AriaLiveAnnouncer.types';\n\ntype AriaNotifyOptions = {\n priority?: 'high' | 'normal';\n};\n\ntype DocumentWithAriaNotify = Document & {\n ariaNotify: (message: string, options: AriaNotifyOptions) => void;\n};\n\n/* INTERNAL: implementation of the announcer using the ariaNotify API */\nexport const useAriaNotifyAnnounce_unstable = (): AriaLiveAnnounceFn => {\n const { targetDocument } = useFluent();\n\n const announce: AriaLiveAnnounceFn = React.useCallback(\n (message: string, options: AnnounceOptions = {}) => {\n if (!targetDocument) {\n return;\n }\n\n const { alert = false, polite } = options;\n\n // default priority to 0 if polite, 2 if alert, and 1 by default\n // used to set both ariaNotify's priority and interrupt\n const defaultPriority = polite ? 0 : alert ? 2 : 1;\n const priority = options.priority ?? defaultPriority;\n\n // map fluent announce options to ariaNotify options\n const ariaNotifyOptions: AriaNotifyOptions = {\n priority: priority > 1 ? 'high' : 'normal',\n };\n\n (targetDocument as DocumentWithAriaNotify).ariaNotify(message, ariaNotifyOptions);\n },\n [targetDocument],\n );\n\n return announce;\n};\n"],"names":["useAriaNotifyAnnounce_unstable","targetDocument","useFluent","announce","React","useCallback","message","options","alert","polite","defaultPriority","priority","ariaNotifyOptions","ariaNotify"],"mappings":"AAAA;;;;;+BAiBaA;;;eAAAA;;;;qCAfmC;iEAEzB;AAahB,MAAMA,iCAAiC;IAC5C,MAAM,EAAEC,cAAc,EAAE,GAAGC,IAAAA,uCAAS;IAEpC,MAAMC,WAA+BC,OAAMC,WAAW,CACpD,CAACC,SAAiBC,UAA2B,CAAC,CAAC;QAC7C,IAAI,CAACN,gBAAgB;YACnB;QACF;QAEA,MAAM,EAAEO,QAAQ,KAAK,EAAEC,MAAM,EAAE,GAAGF;QAElC,gEAAgE;QAChE,uDAAuD;QACvD,MAAMG,kBAAkBD,SAAS,IAAID,QAAQ,IAAI;YAChCD;QAAjB,MAAMI,WAAWJ,CAAAA,oBAAAA,QAAQI,QAAQ,cAAhBJ,+BAAAA,oBAAoBG;QAErC,oDAAoD;QACpD,MAAME,oBAAuC;YAC3CD,UAAUA,WAAW,IAAI,SAAS;QACpC;QAECV,eAA0CY,UAAU,CAACP,SAASM;IACjE,GACA;QAACX;KAAe;IAGlB,OAAOE;AACT"}

View File

@@ -0,0 +1,145 @@
'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useDomAnnounce_unstable", {
enumerable: true,
get: function() {
return useDomAnnounce_unstable;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
const _reactutilities = require("@fluentui/react-utilities");
const _reacttabster = require("@fluentui/react-tabster");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
/** The duration the message needs to be in present in DOM for screen readers to register a change and announce */ const MESSAGE_DURATION = 500;
const VISUALLY_HIDDEN_STYLES = {
clip: 'rect(0px, 0px, 0px, 0px)',
height: '1px',
margin: '-1px',
width: '1px',
position: 'absolute',
overflow: 'hidden',
textWrap: 'nowrap'
};
const useDomAnnounce_unstable = ()=>{
const { targetDocument } = (0, _reactsharedcontexts.useFluent_unstable)();
const timeoutRef = _react.useRef(undefined);
const [setAnnounceTimeout, clearAnnounceTimeout] = (0, _reactutilities.useTimeout)();
const tabsterNeverHiddenAttributes = (0, _reacttabster.useDangerousNeverHidden_unstable)();
const elementRef = _react.useRef(null);
const order = _react.useRef(0);
// investigate alert implementation later
// const [alertList, setAlertList] = React.useState<string[]>([]);
const batchMessages = _react.useRef([]);
const [messageQueue] = _react.useState(()=>(0, _reactutilities.createPriorityQueue)((a, b)=>{
if (a.priority !== b.priority) {
return b.priority - a.priority;
}
return a.createdAt - b.createdAt;
}));
const queueMessage = _react.useCallback(()=>{
if (timeoutRef.current || !elementRef.current) {
return;
}
const runCycle = ()=>{
if (!elementRef.current) {
return;
}
if (targetDocument && messageQueue.peek()) {
// need a wrapping element for Narrator/Edge, which currently does not pick up text-only live region changes
// consistently
// if this is fixed, we can set textContent to the string directly
const wrappingEl = targetDocument.createElement('span');
wrappingEl.innerText = messageQueue.all().filter((msg)=>msg.message.trim().length > 0).reduce((prevText, currMsg)=>prevText + currMsg.message + '. ', '');
elementRef.current.innerText = '';
elementRef.current.appendChild(wrappingEl);
messageQueue.clear();
batchMessages.current = [];
// begin new cycle to clear (or update) messages
timeoutRef.current = setAnnounceTimeout(()=>{
runCycle();
}, MESSAGE_DURATION);
} else {
elementRef.current.textContent = '';
clearAnnounceTimeout();
timeoutRef.current = undefined;
}
};
// Run the first cycle with a 0 timeout to ensure multiple messages in the same tick are handled
timeoutRef.current = setAnnounceTimeout(()=>{
runCycle();
}, 0);
}, [
clearAnnounceTimeout,
messageQueue,
setAnnounceTimeout,
targetDocument
]);
const announce = _react.useCallback((message, options = {})=>{
const { alert = false, priority = 0, batchId } = options;
// check if message is an alert
if (alert) {
// TODO: alert implementation
// setAlertList([...alertList, message]);
}
const liveMessage = {
message,
createdAt: order.current++,
priority,
batchId
};
// check if batchId exists
if (batchId) {
// update associated msg if it does
const batchMessage = batchMessages.current.find((msg)=>msg.batchId === batchId);
if (batchMessage) {
// replace existing message in queue
messageQueue.remove(batchMessage.message);
// update list of existing batchIds w/ most recent message
batchMessage.message = liveMessage;
} else {
// update list of existing batchIds, add new if doesn't already exist
batchMessages.current = [
...batchMessages.current,
{
batchId,
message: liveMessage
}
];
}
}
// add new message
messageQueue.enqueue(liveMessage);
queueMessage();
}, [
messageQueue,
queueMessage
]);
_react.useEffect(()=>{
if (!targetDocument) {
return;
}
const element = targetDocument.createElement('div');
element.setAttribute('aria-live', 'assertive');
Object.entries(tabsterNeverHiddenAttributes).forEach(([key, value])=>{
element.setAttribute(key, value);
});
Object.assign(element.style, VISUALLY_HIDDEN_STYLES);
targetDocument.body.append(element);
elementRef.current = element;
return ()=>{
element.remove();
elementRef.current = null;
clearAnnounceTimeout();
timeoutRef.current = undefined;
};
}, [
clearAnnounceTimeout,
tabsterNeverHiddenAttributes,
targetDocument
]);
return announce;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,50 @@
'use client';
"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, {
ActiveDescendantContextProvider: function() {
return ActiveDescendantContextProvider;
},
useActiveDescendantContext: function() {
return useActiveDescendantContext;
},
useHasParentActiveDescendantContext: function() {
return useHasParentActiveDescendantContext;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const noop = ()=>undefined;
const activeDescendantContextDefaultValue = {
controller: {
active: noop,
blur: noop,
find: noop,
first: noop,
focus: noop,
focusLastActive: noop,
scrollActiveIntoView: noop,
last: noop,
next: noop,
prev: noop,
showAttributes: noop,
hideAttributes: noop,
showFocusVisibleAttributes: noop,
hideFocusVisibleAttributes: noop
}
};
const ActiveDescendantContext = _react.createContext(undefined);
const ActiveDescendantContextProvider = ActiveDescendantContext.Provider;
const useActiveDescendantContext = ()=>{
var _React_useContext;
return (_React_useContext = _react.useContext(ActiveDescendantContext)) !== null && _React_useContext !== void 0 ? _React_useContext : activeDescendantContextDefaultValue;
};
const useHasParentActiveDescendantContext = ()=>!!_react.useContext(ActiveDescendantContext);

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/ActiveDescendantContext.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { ActiveDescendantImperativeRef } from './types';\n\nexport type ActiveDescendantContextValue = {\n controller: ActiveDescendantImperativeRef;\n};\n\nconst noop = () => undefined;\n\nconst activeDescendantContextDefaultValue: ActiveDescendantContextValue = {\n controller: {\n active: noop,\n blur: noop,\n find: noop,\n first: noop,\n focus: noop,\n focusLastActive: noop,\n scrollActiveIntoView: noop,\n last: noop,\n next: noop,\n prev: noop,\n showAttributes: noop,\n hideAttributes: noop,\n showFocusVisibleAttributes: noop,\n hideFocusVisibleAttributes: noop,\n },\n};\n\nconst ActiveDescendantContext = React.createContext<ActiveDescendantContextValue | undefined>(undefined);\n\nexport const ActiveDescendantContextProvider = ActiveDescendantContext.Provider;\nexport const useActiveDescendantContext = (): ActiveDescendantContextValue =>\n React.useContext(ActiveDescendantContext) ?? activeDescendantContextDefaultValue;\nexport const useHasParentActiveDescendantContext = (): boolean => !!React.useContext(ActiveDescendantContext);\n"],"names":["ActiveDescendantContextProvider","useActiveDescendantContext","useHasParentActiveDescendantContext","noop","undefined","activeDescendantContextDefaultValue","controller","active","blur","find","first","focus","focusLastActive","scrollActiveIntoView","last","next","prev","showAttributes","hideAttributes","showFocusVisibleAttributes","hideFocusVisibleAttributes","ActiveDescendantContext","React","createContext","Provider","useContext"],"mappings":"AAAA;;;;;;;;;;;;IAgCaA,+BAA+B;eAA/BA;;IACAC,0BAA0B;eAA1BA;;IAEAC,mCAAmC;eAAnCA;;;;iEAjCU;AAOvB,MAAMC,OAAO,IAAMC;AAEnB,MAAMC,sCAAoE;IACxEC,YAAY;QACVC,QAAQJ;QACRK,MAAML;QACNM,MAAMN;QACNO,OAAOP;QACPQ,OAAOR;QACPS,iBAAiBT;QACjBU,sBAAsBV;QACtBW,MAAMX;QACNY,MAAMZ;QACNa,MAAMb;QACNc,gBAAgBd;QAChBe,gBAAgBf;QAChBgB,4BAA4BhB;QAC5BiB,4BAA4BjB;IAC9B;AACF;AAEA,MAAMkB,0BAA0BC,OAAMC,aAAa,CAA2CnB;AAEvF,MAAMJ,kCAAkCqB,wBAAwBG,QAAQ;AACxE,MAAMvB,6BAA6B;QACxCqB;WAAAA,CAAAA,oBAAAA,OAAMG,UAAU,CAACJ,sCAAjBC,+BAAAA,oBAA6CjB;;AACxC,MAAMH,sCAAsC,IAAe,CAAC,CAACoB,OAAMG,UAAU,CAACJ"}

View File

@@ -0,0 +1,22 @@
/**
* Applied to the element that is active descendant
*/ "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, {
ACTIVEDESCENDANT_ATTRIBUTE: function() {
return ACTIVEDESCENDANT_ATTRIBUTE;
},
ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE: function() {
return ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE;
}
});
const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';
const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = 'data-activedescendant-focusvisible';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/constants.ts"],"sourcesContent":["/**\n * Applied to the element that is active descendant\n */\nexport const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';\n\n/**\n * Applied to the active descendant when the user is navigating with keyboard\n */\nexport const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = 'data-activedescendant-focusvisible';\n"],"names":["ACTIVEDESCENDANT_ATTRIBUTE","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE"],"mappings":"AAAA;;CAEC;;;;;;;;;;;IACYA,0BAA0B;eAA1BA;;IAKAC,uCAAuC;eAAvCA;;;AALN,MAAMD,6BAA6B;AAKnC,MAAMC,0CAA0C"}

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, {
ACTIVEDESCENDANT_ATTRIBUTE: function() {
return _constants.ACTIVEDESCENDANT_ATTRIBUTE;
},
ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE: function() {
return _constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE;
},
ActiveDescendantContextProvider: function() {
return _ActiveDescendantContext.ActiveDescendantContextProvider;
},
createActiveDescendantChangeEvent: function() {
return _useActiveDescendant.createActiveDescendantChangeEvent;
},
useActiveDescendant: function() {
return _useActiveDescendant.useActiveDescendant;
},
useActiveDescendantContext: function() {
return _ActiveDescendantContext.useActiveDescendantContext;
},
useHasParentActiveDescendantContext: function() {
return _ActiveDescendantContext.useHasParentActiveDescendantContext;
}
});
const _ActiveDescendantContext = require("./ActiveDescendantContext");
const _useActiveDescendant = require("./useActiveDescendant");
const _constants = require("./constants");

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/index.ts"],"sourcesContent":["export type { ActiveDescendantContextValue } from './ActiveDescendantContext';\nexport {\n ActiveDescendantContextProvider,\n useActiveDescendantContext,\n useHasParentActiveDescendantContext,\n} from './ActiveDescendantContext';\nexport type { ActiveDescendantChangeEvent } from './useActiveDescendant';\nexport { createActiveDescendantChangeEvent, useActiveDescendant } from './useActiveDescendant';\nexport { ACTIVEDESCENDANT_ATTRIBUTE, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './constants';\nexport type {\n ActiveDescendantImperativeRef,\n ActiveDescendantOptions,\n FindOptions,\n IteratorOptions,\n UseActiveDescendantReturn,\n} from './types';\n"],"names":["ACTIVEDESCENDANT_ATTRIBUTE","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE","ActiveDescendantContextProvider","createActiveDescendantChangeEvent","useActiveDescendant","useActiveDescendantContext","useHasParentActiveDescendantContext"],"mappings":";;;;;;;;;;;IAQSA,0BAA0B;eAA1BA,qCAA0B;;IAAEC,uCAAuC;eAAvCA,kDAAuC;;IAN1EC,+BAA+B;eAA/BA,wDAA+B;;IAKxBC,iCAAiC;eAAjCA,sDAAiC;;IAAEC,mBAAmB;eAAnBA,wCAAmB;;IAJ7DC,0BAA0B;eAA1BA,mDAA0B;;IAC1BC,mCAAmC;eAAnCA,4DAAmC;;;yCAC9B;qCAEgE;2BACa"}

View File

@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "scrollIntoView", {
enumerable: true,
get: function() {
return scrollIntoView;
}
});
const scrollIntoView = (target)=>{
if (!target) {
return;
}
const scrollParent = findScrollableParent(target.parentElement);
if (!scrollParent) {
return;
}
const { offsetHeight } = target;
const offsetTop = getTotalOffsetTop(target, scrollParent);
const { scrollMarginTop, scrollMarginBottom } = getScrollMargins(target);
const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;
const isAbove = offsetTop - scrollMarginTop < scrollTop;
const isBelow = offsetTop + offsetHeight + scrollMarginBottom > scrollTop + parentOffsetHeight;
const buffer = 2;
if (isAbove) {
scrollParent.scrollTo(0, offsetTop - scrollMarginTop - buffer);
} else if (isBelow) {
scrollParent.scrollTo(0, offsetTop + offsetHeight + scrollMarginBottom - parentOffsetHeight + buffer);
}
};
const findScrollableParent = (element)=>{
if (!element) {
return null;
}
if (element.scrollHeight > element.offsetHeight) {
return element;
}
return findScrollableParent(element.parentElement);
};
const getTotalOffsetTop = (element, scrollParent)=>{
if (!element || element === scrollParent) {
return 0;
}
if (element.contains(scrollParent)) {
// subtract the scroll parent's offset top from the running total if the offsetParent is above it
return scrollParent.offsetTop * -1;
}
return element.offsetTop + getTotalOffsetTop(element.offsetParent, scrollParent);
};
const getScrollMargins = (element)=>{
var _element_ownerDocument;
const win = (_element_ownerDocument = element.ownerDocument) === null || _element_ownerDocument === void 0 ? void 0 : _element_ownerDocument.defaultView;
if (!win) {
return {
scrollMarginTop: 0,
scrollMarginBottom: 0
};
}
const computedStyles = win.getComputedStyle(element);
var _getIntValueOfComputedStyle;
const scrollMarginTop = (_getIntValueOfComputedStyle = getIntValueOfComputedStyle(computedStyles.scrollMarginTop)) !== null && _getIntValueOfComputedStyle !== void 0 ? _getIntValueOfComputedStyle : getIntValueOfComputedStyle(computedStyles.scrollMarginBlockStart);
var _getIntValueOfComputedStyle1;
const scrollMarginBottom = (_getIntValueOfComputedStyle1 = getIntValueOfComputedStyle(computedStyles.scrollMarginBottom)) !== null && _getIntValueOfComputedStyle1 !== void 0 ? _getIntValueOfComputedStyle1 : getIntValueOfComputedStyle(computedStyles.scrollMarginBlockEnd);
return {
scrollMarginTop,
scrollMarginBottom
};
};
const getIntValueOfComputedStyle = (computedStyle)=>{
return computedStyle ? parseInt(computedStyle, 10) : 0;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/scrollIntoView.ts"],"sourcesContent":["export const scrollIntoView = (target: HTMLElement | null | undefined): void => {\n if (!target) {\n return;\n }\n\n const scrollParent = findScrollableParent(target.parentElement as HTMLElement);\n if (!scrollParent) {\n return;\n }\n\n const { offsetHeight } = target;\n const offsetTop = getTotalOffsetTop(target, scrollParent);\n\n const { scrollMarginTop, scrollMarginBottom } = getScrollMargins(target);\n\n const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;\n\n const isAbove = offsetTop - scrollMarginTop < scrollTop;\n const isBelow = offsetTop + offsetHeight + scrollMarginBottom > scrollTop + parentOffsetHeight;\n\n const buffer = 2;\n\n if (isAbove) {\n scrollParent.scrollTo(0, offsetTop - scrollMarginTop - buffer);\n } else if (isBelow) {\n scrollParent.scrollTo(0, offsetTop + offsetHeight + scrollMarginBottom - parentOffsetHeight + buffer);\n }\n};\n\nconst findScrollableParent = (element: HTMLElement | null): HTMLElement | null => {\n if (!element) {\n return null;\n }\n\n if (element.scrollHeight > element.offsetHeight) {\n return element;\n }\n\n return findScrollableParent(element.parentElement);\n};\n\nconst getTotalOffsetTop = (element: HTMLElement, scrollParent: HTMLElement): number => {\n if (!element || element === scrollParent) {\n return 0;\n }\n\n if (element.contains(scrollParent)) {\n // subtract the scroll parent's offset top from the running total if the offsetParent is above it\n return scrollParent.offsetTop * -1;\n }\n\n return element.offsetTop + getTotalOffsetTop(element.offsetParent as HTMLElement, scrollParent);\n};\n\nconst getScrollMargins = (element: HTMLElement) => {\n const win = element.ownerDocument?.defaultView;\n if (!win) {\n return {\n scrollMarginTop: 0,\n scrollMarginBottom: 0,\n };\n }\n\n const computedStyles = win.getComputedStyle(element);\n const scrollMarginTop =\n getIntValueOfComputedStyle(computedStyles.scrollMarginTop) ??\n getIntValueOfComputedStyle(computedStyles.scrollMarginBlockStart);\n const scrollMarginBottom =\n getIntValueOfComputedStyle(computedStyles.scrollMarginBottom) ??\n getIntValueOfComputedStyle(computedStyles.scrollMarginBlockEnd);\n return {\n scrollMarginTop,\n scrollMarginBottom,\n };\n};\n\nconst getIntValueOfComputedStyle = (computedStyle: string) => {\n return computedStyle ? parseInt(computedStyle, 10) : 0;\n};\n"],"names":["scrollIntoView","target","scrollParent","findScrollableParent","parentElement","offsetHeight","offsetTop","getTotalOffsetTop","scrollMarginTop","scrollMarginBottom","getScrollMargins","parentOffsetHeight","scrollTop","isAbove","isBelow","buffer","scrollTo","element","scrollHeight","contains","offsetParent","win","ownerDocument","defaultView","computedStyles","getComputedStyle","getIntValueOfComputedStyle","scrollMarginBlockStart","scrollMarginBlockEnd","computedStyle","parseInt"],"mappings":";;;;+BAAaA;;;eAAAA;;;AAAN,MAAMA,iBAAiB,CAACC;IAC7B,IAAI,CAACA,QAAQ;QACX;IACF;IAEA,MAAMC,eAAeC,qBAAqBF,OAAOG,aAAa;IAC9D,IAAI,CAACF,cAAc;QACjB;IACF;IAEA,MAAM,EAAEG,YAAY,EAAE,GAAGJ;IACzB,MAAMK,YAAYC,kBAAkBN,QAAQC;IAE5C,MAAM,EAAEM,eAAe,EAAEC,kBAAkB,EAAE,GAAGC,iBAAiBT;IAEjE,MAAM,EAAEI,cAAcM,kBAAkB,EAAEC,SAAS,EAAE,GAAGV;IAExD,MAAMW,UAAUP,YAAYE,kBAAkBI;IAC9C,MAAME,UAAUR,YAAYD,eAAeI,qBAAqBG,YAAYD;IAE5E,MAAMI,SAAS;IAEf,IAAIF,SAAS;QACXX,aAAac,QAAQ,CAAC,GAAGV,YAAYE,kBAAkBO;IACzD,OAAO,IAAID,SAAS;QAClBZ,aAAac,QAAQ,CAAC,GAAGV,YAAYD,eAAeI,qBAAqBE,qBAAqBI;IAChG;AACF;AAEA,MAAMZ,uBAAuB,CAACc;IAC5B,IAAI,CAACA,SAAS;QACZ,OAAO;IACT;IAEA,IAAIA,QAAQC,YAAY,GAAGD,QAAQZ,YAAY,EAAE;QAC/C,OAAOY;IACT;IAEA,OAAOd,qBAAqBc,QAAQb,aAAa;AACnD;AAEA,MAAMG,oBAAoB,CAACU,SAAsBf;IAC/C,IAAI,CAACe,WAAWA,YAAYf,cAAc;QACxC,OAAO;IACT;IAEA,IAAIe,QAAQE,QAAQ,CAACjB,eAAe;QAClC,iGAAiG;QACjG,OAAOA,aAAaI,SAAS,GAAG,CAAC;IACnC;IAEA,OAAOW,QAAQX,SAAS,GAAGC,kBAAkBU,QAAQG,YAAY,EAAiBlB;AACpF;AAEA,MAAMQ,mBAAmB,CAACO;QACZA;IAAZ,MAAMI,OAAMJ,yBAAAA,QAAQK,aAAa,cAArBL,6CAAAA,uBAAuBM,WAAW;IAC9C,IAAI,CAACF,KAAK;QACR,OAAO;YACLb,iBAAiB;YACjBC,oBAAoB;QACtB;IACF;IAEA,MAAMe,iBAAiBH,IAAII,gBAAgB,CAACR;QAE1CS;IADF,MAAMlB,kBACJkB,CAAAA,8BAAAA,2BAA2BF,eAAehB,eAAe,eAAzDkB,yCAAAA,8BACAA,2BAA2BF,eAAeG,sBAAsB;QAEhED;IADF,MAAMjB,qBACJiB,CAAAA,+BAAAA,2BAA2BF,eAAef,kBAAkB,eAA5DiB,0CAAAA,+BACAA,2BAA2BF,eAAeI,oBAAoB;IAChE,OAAO;QACLpB;QACAC;IACF;AACF;AAEA,MAAMiB,6BAA6B,CAACG;IAClC,OAAOA,gBAAgBC,SAASD,eAAe,MAAM;AACvD"}

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/types.ts"],"sourcesContent":["import * as React from 'react';\n\nexport interface ActiveDescendantImperativeRef {\n first: (options?: IteratorOptions) => string | undefined;\n last: (options?: IteratorOptions) => string | undefined;\n next: (options?: IteratorOptions) => string | undefined;\n prev: (options?: IteratorOptions) => string | undefined;\n find: (predicate: (id: string) => boolean, options?: IteratorOptions & FindOptions) => string | undefined;\n blur: () => void;\n active: () => string | undefined;\n focus: (id: string) => void;\n /**\n * @deprecated This function is not used internally anymore and will be removed in the future\n */\n focusLastActive: () => void;\n /**\n * Scrolls the active option into view, if it still exists\n */\n scrollActiveIntoView: () => void;\n hideAttributes: () => void;\n showAttributes: () => void;\n hideFocusVisibleAttributes: () => void;\n showFocusVisibleAttributes: () => void;\n}\n\nexport interface ActiveDescendantOptions {\n /**\n * @param el - HTML element to test\n * @returns whether the element can be an active descendant\n */\n matchOption: (el: HTMLElement) => boolean;\n /**\n * Forward imperative refs when exposing functionality from a React component\n */\n imperativeRef?: React.RefObject<ActiveDescendantImperativeRef | null>;\n}\n\nexport interface FindOptions {\n /**\n * Starts the search from a specific id\n */\n startFrom?: string;\n}\n\nexport interface UseActiveDescendantReturn<\n TActiveParentElement extends HTMLElement = HTMLElement,\n TListboxElement extends HTMLElement = HTMLElement,\n> {\n /**\n * Attach this to the element that contains all active descendants\n */\n listboxRef: React.Ref<TListboxElement>;\n /**\n * Attach this to the element that has an active descendant\n */\n activeParentRef: React.Ref<TActiveParentElement>;\n /**\n * Imperative functions to manage active descendants within the listboxRef\n */\n controller: ActiveDescendantImperativeRef;\n}\n\nexport interface IteratorOptions {\n /**\n * When passive, the active descendant is changed\n * @default false\n */\n passive?: boolean;\n}\n"],"names":[],"mappings":";;;;;iEAAuB"}

View File

@@ -0,0 +1,238 @@
'use client';
"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, {
createActiveDescendantChangeEvent: function() {
return createActiveDescendantChangeEvent;
},
useActiveDescendant: function() {
return useActiveDescendant;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reactutilities = require("@fluentui/react-utilities");
const _reacttabster = require("@fluentui/react-tabster");
const _useOptionWalker = require("./useOptionWalker");
const _constants = require("./constants");
const _scrollIntoView = require("./scrollIntoView");
const createActiveDescendantChangeEvent = (detail)=>new CustomEvent('activedescendantchange', {
bubbles: true,
cancelable: false,
composed: true,
detail
});
function useActiveDescendant(options) {
const { imperativeRef, matchOption: matchOptionUnstable } = options;
const focusVisibleRef = _react.useRef(false);
const shouldShowFocusVisibleAttrRef = _react.useRef(true);
const activeIdRef = _react.useRef(null);
const lastActiveIdRef = _react.useRef(null);
const activeParentRef = _react.useRef(null);
const attributeVisibilityRef = _react.useRef(true);
const removeAttribute = _react.useCallback(()=>{
var _activeParentRef_current;
(_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.removeAttribute('aria-activedescendant');
}, []);
const setAttribute = _react.useCallback((id)=>{
if (id) {
activeIdRef.current = id;
}
if (attributeVisibilityRef.current && activeIdRef.current) {
var _activeParentRef_current;
(_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.setAttribute('aria-activedescendant', activeIdRef.current);
}
}, []);
(0, _reacttabster.useOnKeyboardNavigationChange)((isNavigatingWithKeyboard)=>{
focusVisibleRef.current = isNavigatingWithKeyboard;
const active = getActiveDescendant();
if (!active) {
return;
}
if (isNavigatingWithKeyboard && shouldShowFocusVisibleAttrRef.current) {
active.setAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
} else {
active.removeAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
}
});
const matchOption = (0, _reactutilities.useEventCallback)(matchOptionUnstable);
const listboxRef = _react.useRef(null);
const { optionWalker, listboxCallbackRef } = (0, _useOptionWalker.useOptionWalker)({
matchOption
});
const getActiveDescendant = _react.useCallback(()=>{
var _listboxRef_current;
return (_listboxRef_current = listboxRef.current) === null || _listboxRef_current === void 0 ? void 0 : _listboxRef_current.querySelector(`#${activeIdRef.current}`);
}, [
listboxRef
]);
const setShouldShowFocusVisibleAttribute = _react.useCallback((shouldShow)=>{
shouldShowFocusVisibleAttrRef.current = shouldShow;
const active = getActiveDescendant();
if (!active) {
return;
}
if (shouldShow && focusVisibleRef.current) {
active.setAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
} else {
active.removeAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
}
}, [
getActiveDescendant
]);
const blurActiveDescendant = _react.useCallback(()=>{
const active = getActiveDescendant();
if (active) {
active.removeAttribute(_constants.ACTIVEDESCENDANT_ATTRIBUTE);
active.removeAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
}
removeAttribute();
lastActiveIdRef.current = activeIdRef.current;
activeIdRef.current = null;
var _active_id;
return (_active_id = active === null || active === void 0 ? void 0 : active.id) !== null && _active_id !== void 0 ? _active_id : null;
}, [
getActiveDescendant,
removeAttribute
]);
const focusActiveDescendant = _react.useCallback((nextActive)=>{
if (!nextActive) {
return;
}
const previousActiveId = blurActiveDescendant();
(0, _scrollIntoView.scrollIntoView)(nextActive);
setAttribute(nextActive.id);
nextActive.setAttribute(_constants.ACTIVEDESCENDANT_ATTRIBUTE, '');
if (focusVisibleRef.current && shouldShowFocusVisibleAttrRef.current) {
nextActive.setAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
}
const event = createActiveDescendantChangeEvent({
id: nextActive.id,
previousId: previousActiveId
});
nextActive.dispatchEvent(event);
}, [
blurActiveDescendant,
setAttribute
]);
const controller = _react.useMemo(()=>({
first: ({ passive } = {})=>{
const first = optionWalker.first();
if (!passive) {
focusActiveDescendant(first);
}
return first === null || first === void 0 ? void 0 : first.id;
},
last: ({ passive } = {})=>{
const last = optionWalker.last();
if (!passive) {
focusActiveDescendant(last);
}
return last === null || last === void 0 ? void 0 : last.id;
},
next: ({ passive } = {})=>{
const active = getActiveDescendant();
if (!active) {
return;
}
optionWalker.setCurrent(active);
const next = optionWalker.next();
if (!passive) {
focusActiveDescendant(next);
}
return next === null || next === void 0 ? void 0 : next.id;
},
prev: ({ passive } = {})=>{
const active = getActiveDescendant();
if (!active) {
return;
}
optionWalker.setCurrent(active);
const next = optionWalker.prev();
if (!passive) {
focusActiveDescendant(next);
}
return next === null || next === void 0 ? void 0 : next.id;
},
blur: ()=>{
blurActiveDescendant();
},
active: ()=>{
var _getActiveDescendant;
return (_getActiveDescendant = getActiveDescendant()) === null || _getActiveDescendant === void 0 ? void 0 : _getActiveDescendant.id;
},
focus: (id)=>{
if (!listboxRef.current) {
return;
}
const target = listboxRef.current.querySelector(`#${id}`);
if (target) {
focusActiveDescendant(target);
}
},
focusLastActive: ()=>{
if (!listboxRef.current || !lastActiveIdRef.current) {
return;
}
const target = listboxRef.current.querySelector(`#${lastActiveIdRef.current}`);
if (target) {
focusActiveDescendant(target);
return true;
}
},
find (predicate, { passive, startFrom } = {}) {
const target = optionWalker.find(predicate, startFrom);
if (!passive) {
focusActiveDescendant(target);
}
return target === null || target === void 0 ? void 0 : target.id;
},
scrollActiveIntoView: ()=>{
if (!listboxRef.current) {
return;
}
const active = getActiveDescendant();
if (!active) {
return;
}
(0, _scrollIntoView.scrollIntoView)(active);
},
showAttributes () {
attributeVisibilityRef.current = true;
setAttribute();
},
hideAttributes () {
attributeVisibilityRef.current = false;
removeAttribute();
},
showFocusVisibleAttributes () {
setShouldShowFocusVisibleAttribute(true);
},
hideFocusVisibleAttributes () {
setShouldShowFocusVisibleAttribute(false);
}
}), [
optionWalker,
listboxRef,
setAttribute,
removeAttribute,
focusActiveDescendant,
blurActiveDescendant,
getActiveDescendant,
setShouldShowFocusVisibleAttribute
]);
_react.useImperativeHandle(imperativeRef, ()=>controller);
return {
listboxRef: (0, _reactutilities.useMergedRefs)(listboxRef, listboxCallbackRef),
activeParentRef,
controller
};
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,93 @@
'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useOptionWalker", {
enumerable: true,
get: function() {
return useOptionWalker;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
const _reactutilities = require("@fluentui/react-utilities");
function useOptionWalker(options) {
const { matchOption } = options;
const { targetDocument } = (0, _reactsharedcontexts.useFluent_unstable)();
const treeWalkerRef = _react.useRef(null);
const listboxRef = _react.useRef(null);
const optionFilter = _react.useCallback((node)=>{
if ((0, _reactutilities.isHTMLElement)(node) && matchOption(node)) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
}, [
matchOption
]);
const setListbox = _react.useCallback((el)=>{
if (el && targetDocument) {
listboxRef.current = el;
treeWalkerRef.current = targetDocument.createTreeWalker(el, NodeFilter.SHOW_ELEMENT, optionFilter);
} else {
listboxRef.current = null;
treeWalkerRef.current = null;
}
}, [
targetDocument,
optionFilter
]);
const optionWalker = _react.useMemo(()=>({
first: ()=>{
if (!treeWalkerRef.current || !listboxRef.current) {
return null;
}
treeWalkerRef.current.currentNode = listboxRef.current;
return treeWalkerRef.current.firstChild();
},
last: ()=>{
if (!treeWalkerRef.current || !listboxRef.current) {
return null;
}
treeWalkerRef.current.currentNode = listboxRef.current;
return treeWalkerRef.current.lastChild();
},
next: ()=>{
if (!treeWalkerRef.current) {
return null;
}
return treeWalkerRef.current.nextNode();
},
prev: ()=>{
if (!treeWalkerRef.current) {
return null;
}
return treeWalkerRef.current.previousNode();
},
find: (predicate, startFrom)=>{
if (!treeWalkerRef.current || !listboxRef.current) {
return null;
}
const start = startFrom ? targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.getElementById(startFrom) : null;
treeWalkerRef.current.currentNode = start !== null && start !== void 0 ? start : listboxRef.current;
let cur = treeWalkerRef.current.currentNode;
while(cur && !predicate(cur.id)){
cur = treeWalkerRef.current.nextNode();
}
return cur;
},
setCurrent: (el)=>{
if (!treeWalkerRef.current) {
return;
}
treeWalkerRef.current.currentNode = el;
}
}), [
targetDocument
]);
return {
optionWalker,
listboxCallbackRef: setListbox
};
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,20 @@
"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, {
useARIAButtonProps: function() {
return _useARIAButtonProps.useARIAButtonProps;
},
useARIAButtonShorthand: function() {
return _useARIAButtonShorthand.useARIAButtonShorthand;
}
});
const _useARIAButtonProps = require("./useARIAButtonProps");
const _useARIAButtonShorthand = require("./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":";;;;;;;;;;;IAASA,kBAAkB;eAAlBA,sCAAkB;;IAElBC,sBAAsB;eAAtBA,8CAAsB;;;oCAFI;wCAEI"}

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("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":[],"mappings":";;;;;iEAOuB"}

View File

@@ -0,0 +1,100 @@
'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useARIAButtonProps", {
enumerable: true,
get: function() {
return useARIAButtonProps;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _keyboardkeys = require("@fluentui/keyboard-keys");
const _reactutilities = require("@fluentui/react-utilities");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
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 = (0, _reactutilities.useEventCallback)((ev)=>{
if (isDisabled) {
ev.preventDefault();
ev.stopPropagation();
} else {
onClick === null || onClick === void 0 ? void 0 : onClick(ev);
}
});
const handleKeyDown = (0, _reactutilities.useEventCallback)((ev)=>{
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(ev);
if (ev.isDefaultPrevented()) {
return;
}
const key = ev.key;
if (isDisabled && (key === _keyboardkeys.Enter || key === _keyboardkeys.Space)) {
ev.preventDefault();
ev.stopPropagation();
return;
}
if (key === _keyboardkeys.Space) {
ev.preventDefault();
return;
} else if (key === _keyboardkeys.Enter) {
ev.preventDefault();
ev.currentTarget.click();
}
});
const handleKeyUp = (0, _reactutilities.useEventCallback)((ev)=>{
onKeyUp === null || onKeyUp === void 0 ? void 0 : onKeyUp(ev);
if (ev.isDefaultPrevented()) {
return;
}
const key = ev.key;
if (isDisabled && (key === _keyboardkeys.Enter || key === _keyboardkeys.Space)) {
ev.preventDefault();
ev.stopPropagation();
return;
}
if (key === _keyboardkeys.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';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useARIAButtonShorthand", {
enumerable: true,
get: function() {
return useARIAButtonShorthand;
}
});
const _reactutilities = require("@fluentui/react-utilities");
const _useARIAButtonProps = require("./useARIAButtonProps");
const useARIAButtonShorthand = (value, options)=>{
// eslint-disable-next-line @typescript-eslint/no-deprecated
const shorthand = (0, _reactutilities.resolveShorthand)(value, options);
var _shorthand_as;
const shorthandARIAButton = (0, _useARIAButtonProps.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":["useARIAButtonShorthand","value","options","shorthand","resolveShorthand","shorthandARIAButton","useARIAButtonProps","as"],"mappings":"AAAA;;;;;+BAkBaA;;;eAAAA;;;gCAhBoB;oCACE;AAe5B,MAAMA,yBAA0B,CAACC,OAAOC;IAC7C,4DAA4D;IAC5D,MAAMC,YAAYC,IAAAA,gCAAgB,EAACH,OAAOC;QACsCC;IAAhF,MAAME,sBAAsBC,IAAAA,sCAAkB,EAAkCH,CAAAA,gBAAAA,sBAAAA,gCAAAA,UAAWI,EAAE,cAAbJ,2BAAAA,gBAAiB,UAAUA;IAC3G,OAAOA,aAAaE;AACpB,4DAA4D;AAC9D"}

View File

@@ -0,0 +1,53 @@
"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, {
ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE: function() {
return _activedescendant.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE;
},
ActiveDescendantContextProvider: function() {
return _activedescendant.ActiveDescendantContextProvider;
},
AriaLiveAnnouncer: function() {
return _index1.AriaLiveAnnouncer;
},
renderAriaLiveAnnouncer_unstable: function() {
return _index1.renderAriaLiveAnnouncer_unstable;
},
useARIAButtonProps: function() {
return _index.useARIAButtonProps;
},
// eslint-disable-next-line @typescript-eslint/no-deprecated
useARIAButtonShorthand: function() {
return _index.useARIAButtonShorthand;
},
useActiveDescendant: function() {
return _activedescendant.useActiveDescendant;
},
useActiveDescendantContext: function() {
return _activedescendant.useActiveDescendantContext;
},
useAriaLiveAnnouncerContextValues_unstable: function() {
return _index1.useAriaLiveAnnouncerContextValues_unstable;
},
useAriaLiveAnnouncer_unstable: function() {
return _index1.useAriaLiveAnnouncer_unstable;
},
useHasParentActiveDescendantContext: function() {
return _activedescendant.useHasParentActiveDescendantContext;
},
useTypingAnnounce: function() {
return _index2.useTypingAnnounce;
}
});
const _index = require("./button/index");
const _activedescendant = require("./activedescendant");
const _index1 = require("./AriaLiveAnnouncer/index");
const _index2 = require("./useTypingAnnounce/index");

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n useARIAButtonShorthand,\n useARIAButtonProps,\n} from './button/index';\nexport {\n useActiveDescendant,\n ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE,\n ActiveDescendantContextProvider,\n useActiveDescendantContext,\n useHasParentActiveDescendantContext,\n} from './activedescendant';\nexport type {\n ActiveDescendantImperativeRef,\n ActiveDescendantOptions,\n ActiveDescendantContextValue,\n ActiveDescendantChangeEvent,\n} from './activedescendant';\nexport type {\n ARIAButtonSlotProps,\n ARIAButtonProps,\n ARIAButtonResultProps,\n ARIAButtonType,\n ARIAButtonElement,\n ARIAButtonElementIntersection,\n ARIAButtonAlteredProps,\n} from './button/index';\n\nexport {\n AriaLiveAnnouncer,\n renderAriaLiveAnnouncer_unstable,\n useAriaLiveAnnouncer_unstable,\n useAriaLiveAnnouncerContextValues_unstable,\n} from './AriaLiveAnnouncer/index';\nexport type { AriaLiveAnnouncerProps, AriaLiveAnnouncerState } from './AriaLiveAnnouncer/index';\n\nexport { useTypingAnnounce } from './useTypingAnnounce/index';\n"],"names":["ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE","ActiveDescendantContextProvider","AriaLiveAnnouncer","renderAriaLiveAnnouncer_unstable","useARIAButtonProps","useARIAButtonShorthand","useActiveDescendant","useActiveDescendantContext","useAriaLiveAnnouncerContextValues_unstable","useAriaLiveAnnouncer_unstable","useHasParentActiveDescendantContext","useTypingAnnounce"],"mappings":";;;;;;;;;;;IAOEA,uCAAuC;eAAvCA,yDAAuC;;IACvCC,+BAA+B;eAA/BA,iDAA+B;;IAqB/BC,iBAAiB;eAAjBA,yBAAiB;;IACjBC,gCAAgC;eAAhCA,wCAAgC;;IA3BhCC,kBAAkB;eAAlBA,yBAAkB;;IAFlB,4DAA4D;IAC5DC,sBAAsB;eAAtBA,6BAAsB;;IAItBC,mBAAmB;eAAnBA,qCAAmB;;IAGnBC,0BAA0B;eAA1BA,4CAA0B;;IAuB1BC,0CAA0C;eAA1CA,kDAA0C;;IAD1CC,6BAA6B;eAA7BA,qCAA6B;;IArB7BC,mCAAmC;eAAnCA,qDAAmC;;IA0B5BC,iBAAiB;eAAjBA,yBAAiB;;;uBAhCnB;kCAOA;wBAsBA;wBAG2B"}

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useTypingAnnounce", {
enumerable: true,
get: function() {
return _useTypingAnnounce.useTypingAnnounce;
}
});
const _useTypingAnnounce = require("./useTypingAnnounce");

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/useTypingAnnounce/index.ts"],"sourcesContent":["export { useTypingAnnounce } from './useTypingAnnounce';\n"],"names":["useTypingAnnounce"],"mappings":";;;;+BAASA;;;eAAAA,oCAAiB;;;mCAAQ"}

View File

@@ -0,0 +1,83 @@
'use client';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "useTypingAnnounce", {
enumerable: true,
get: function() {
return useTypingAnnounce;
}
});
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
const _reactutilities = require("@fluentui/react-utilities");
const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
const valueMutationOptions = {
attributes: true,
subtree: true,
characterData: true,
attributeFilter: [
'value'
]
};
function useTypingAnnounce() {
const { targetDocument } = (0, _reactsharedcontexts.useFluent_unstable)();
const { announce } = (0, _reactsharedcontexts.useAnnounce)();
const inputRef = _react.useRef(null);
const observer = _react.useRef(undefined);
const [setTypingTimeout, clearTypingTimeout] = (0, _reactutilities.useTimeout)();
const messageQueue = _react.useRef([]);
const callback = _react.useCallback((mutationList, mutationObserver)=>{
setTypingTimeout(()=>{
messageQueue.current.forEach(({ message, options })=>{
announce(message, options);
});
messageQueue.current.length = 0;
mutationObserver.disconnect();
}, 500);
}, [
announce,
setTypingTimeout
]);
const typingAnnounce = _react.useCallback((message, options = {})=>{
messageQueue.current.push({
message,
options
});
if (inputRef.current && observer.current) {
observer.current.observe(inputRef.current, valueMutationOptions);
}
setTypingTimeout(()=>{
observer.current && callback([], observer.current);
}, 500);
}, [
callback,
inputRef,
setTypingTimeout
]);
_react.useEffect(()=>{
const win = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView;
if (!win) {
return;
}
if (!observer.current) {
observer.current = new win.MutationObserver(callback);
}
return ()=>{
// Clean up the observer when the component unmounts
if (observer.current) {
observer.current.disconnect();
clearTypingTimeout();
}
};
}, [
callback,
clearTypingTimeout,
targetDocument
]);
return {
typingAnnounce,
inputRef
};
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/useTypingAnnounce/useTypingAnnounce.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useTimeout } from '@fluentui/react-utilities';\nimport { useAnnounce, useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport type { AnnounceOptions } from '@fluentui/react-shared-contexts';\nimport { AriaLiveAnnounceFn } from '../AriaLiveAnnouncer/AriaLiveAnnouncer.types';\n\ntype Message = {\n message: string;\n options: AnnounceOptions;\n};\n\nconst valueMutationOptions = {\n attributes: true,\n subtree: true,\n characterData: true,\n attributeFilter: ['value'],\n};\n\ninterface TypingAnnounceReturn<TInputElement extends HTMLElement = HTMLElement> {\n typingAnnounce: AriaLiveAnnounceFn;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n inputRef: React.MutableRefObject<TInputElement | null>;\n}\n\nexport function useTypingAnnounce<\n TInputElement extends HTMLElement = HTMLElement,\n>(): TypingAnnounceReturn<TInputElement> {\n const { targetDocument } = useFluent();\n const { announce } = useAnnounce();\n\n const inputRef = React.useRef<TInputElement | null>(null);\n const observer = React.useRef<MutationObserver>(undefined);\n const [setTypingTimeout, clearTypingTimeout] = useTimeout();\n const messageQueue = React.useRef<Message[]>([]);\n\n const callback: MutationCallback = React.useCallback(\n (mutationList, mutationObserver) => {\n setTypingTimeout(() => {\n messageQueue.current.forEach(({ message, options }) => {\n announce(message, options);\n });\n messageQueue.current.length = 0;\n mutationObserver.disconnect();\n }, 500);\n },\n [announce, setTypingTimeout],\n );\n\n const typingAnnounce: AriaLiveAnnounceFn = React.useCallback(\n (message: string, options: AnnounceOptions = {}) => {\n messageQueue.current.push({ message, options });\n\n if (inputRef.current && observer.current) {\n observer.current.observe(inputRef.current, valueMutationOptions);\n }\n\n setTypingTimeout(() => {\n observer.current && callback([], observer.current);\n }, 500);\n },\n [callback, inputRef, setTypingTimeout],\n );\n\n React.useEffect(() => {\n const win = targetDocument?.defaultView;\n if (!win) {\n return;\n }\n\n if (!observer.current) {\n observer.current = new win.MutationObserver(callback);\n }\n\n return () => {\n // Clean up the observer when the component unmounts\n if (observer.current) {\n observer.current.disconnect();\n clearTypingTimeout();\n }\n };\n }, [callback, clearTypingTimeout, targetDocument]);\n\n return { typingAnnounce, inputRef };\n}\n"],"names":["useTypingAnnounce","valueMutationOptions","attributes","subtree","characterData","attributeFilter","targetDocument","useFluent","announce","useAnnounce","inputRef","React","useRef","observer","undefined","setTypingTimeout","clearTypingTimeout","useTimeout","messageQueue","callback","useCallback","mutationList","mutationObserver","current","forEach","message","options","length","disconnect","typingAnnounce","push","observe","useEffect","win","defaultView","MutationObserver"],"mappings":"AAAA;;;;;+BA0BgBA;;;eAAAA;;;;iEAxBO;gCACI;qCACkC;AAS7D,MAAMC,uBAAuB;IAC3BC,YAAY;IACZC,SAAS;IACTC,eAAe;IACfC,iBAAiB;QAAC;KAAQ;AAC5B;AAQO,SAASL;IAGd,MAAM,EAAEM,cAAc,EAAE,GAAGC,IAAAA,uCAAS;IACpC,MAAM,EAAEC,QAAQ,EAAE,GAAGC,IAAAA,gCAAW;IAEhC,MAAMC,WAAWC,OAAMC,MAAM,CAAuB;IACpD,MAAMC,WAAWF,OAAMC,MAAM,CAAmBE;IAChD,MAAM,CAACC,kBAAkBC,mBAAmB,GAAGC,IAAAA,0BAAU;IACzD,MAAMC,eAAeP,OAAMC,MAAM,CAAY,EAAE;IAE/C,MAAMO,WAA6BR,OAAMS,WAAW,CAClD,CAACC,cAAcC;QACbP,iBAAiB;YACfG,aAAaK,OAAO,CAACC,OAAO,CAAC,CAAC,EAAEC,OAAO,EAAEC,OAAO,EAAE;gBAChDlB,SAASiB,SAASC;YACpB;YACAR,aAAaK,OAAO,CAACI,MAAM,GAAG;YAC9BL,iBAAiBM,UAAU;QAC7B,GAAG;IACL,GACA;QAACpB;QAAUO;KAAiB;IAG9B,MAAMc,iBAAqClB,OAAMS,WAAW,CAC1D,CAACK,SAAiBC,UAA2B,CAAC,CAAC;QAC7CR,aAAaK,OAAO,CAACO,IAAI,CAAC;YAAEL;YAASC;QAAQ;QAE7C,IAAIhB,SAASa,OAAO,IAAIV,SAASU,OAAO,EAAE;YACxCV,SAASU,OAAO,CAACQ,OAAO,CAACrB,SAASa,OAAO,EAAEtB;QAC7C;QAEAc,iBAAiB;YACfF,SAASU,OAAO,IAAIJ,SAAS,EAAE,EAAEN,SAASU,OAAO;QACnD,GAAG;IACL,GACA;QAACJ;QAAUT;QAAUK;KAAiB;IAGxCJ,OAAMqB,SAAS,CAAC;QACd,MAAMC,MAAM3B,2BAAAA,qCAAAA,eAAgB4B,WAAW;QACvC,IAAI,CAACD,KAAK;YACR;QACF;QAEA,IAAI,CAACpB,SAASU,OAAO,EAAE;YACrBV,SAASU,OAAO,GAAG,IAAIU,IAAIE,gBAAgB,CAAChB;QAC9C;QAEA,OAAO;YACL,oDAAoD;YACpD,IAAIN,SAASU,OAAO,EAAE;gBACpBV,SAASU,OAAO,CAACK,UAAU;gBAC3BZ;YACF;QACF;IACF,GAAG;QAACG;QAAUH;QAAoBV;KAAe;IAEjD,OAAO;QAAEuB;QAAgBnB;IAAS;AACpC"}

View File

@@ -0,0 +1,13 @@
'use client';
import * as React from 'react';
import { renderAriaLiveAnnouncer_unstable } from './renderAriaLiveAnnouncer';
import { useAriaLiveAnnouncer_unstable } from './useAriaLiveAnnouncer';
import { useAriaLiveAnnouncerContextValues_unstable } from './useAriaLiveAnnouncerContextValues';
/**
* A sample implementation of a component that manages aria live announcements.
*/ export const AriaLiveAnnouncer = (props)=>{
const state = useAriaLiveAnnouncer_unstable(props);
const contextValues = useAriaLiveAnnouncerContextValues_unstable(state);
return renderAriaLiveAnnouncer_unstable(state, contextValues);
};
AriaLiveAnnouncer.displayName = 'AriaLiveAnnouncer';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/AriaLiveAnnouncer.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport type { AriaLiveAnnouncerProps } from './AriaLiveAnnouncer.types';\nimport { renderAriaLiveAnnouncer_unstable } from './renderAriaLiveAnnouncer';\nimport { useAriaLiveAnnouncer_unstable } from './useAriaLiveAnnouncer';\nimport { useAriaLiveAnnouncerContextValues_unstable } from './useAriaLiveAnnouncerContextValues';\n\n/**\n * A sample implementation of a component that manages aria live announcements.\n */\nexport const AriaLiveAnnouncer: React.FC<AriaLiveAnnouncerProps> = props => {\n const state = useAriaLiveAnnouncer_unstable(props);\n const contextValues = useAriaLiveAnnouncerContextValues_unstable(state);\n\n return renderAriaLiveAnnouncer_unstable(state, contextValues);\n};\n\nAriaLiveAnnouncer.displayName = 'AriaLiveAnnouncer';\n"],"names":["React","renderAriaLiveAnnouncer_unstable","useAriaLiveAnnouncer_unstable","useAriaLiveAnnouncerContextValues_unstable","AriaLiveAnnouncer","props","state","contextValues","displayName"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAG/B,SAASC,gCAAgC,QAAQ,4BAA4B;AAC7E,SAASC,6BAA6B,QAAQ,yBAAyB;AACvE,SAASC,0CAA0C,QAAQ,sCAAsC;AAEjG;;CAEC,GACD,OAAO,MAAMC,oBAAsDC,CAAAA;IACjE,MAAMC,QAAQJ,8BAA8BG;IAC5C,MAAME,gBAAgBJ,2CAA2CG;IAEjE,OAAOL,iCAAiCK,OAAOC;AACjD,EAAE;AAEFH,kBAAkBI,WAAW,GAAG"}

View File

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

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/AriaLiveAnnouncer.types.ts"],"sourcesContent":["import type { AnnounceContextValue } from '@fluentui/react-shared-contexts';\nimport * as React from 'react';\n\nexport type AriaLiveAnnounceFn = AnnounceContextValue['announce'];\n\nexport type AriaLiveMessage = {\n message: string;\n\n createdAt: number;\n\n priority: number;\n batchId?: string;\n};\n\nexport type AriaLiveAnnouncerProps = {\n children?: React.ReactNode;\n};\n\nexport type AriaLiveAnnouncerState = {\n announce: AriaLiveAnnounceFn;\n children?: React.ReactNode;\n};\n\nexport type AriaLiveAnnouncerContextValues = {\n announce: { announce: AriaLiveAnnounceFn };\n};\n"],"names":["React"],"mappings":"AACA,YAAYA,WAAW,QAAQ"}

View File

@@ -0,0 +1,4 @@
export { AriaLiveAnnouncer } from './AriaLiveAnnouncer';
export { renderAriaLiveAnnouncer_unstable } from './renderAriaLiveAnnouncer';
export { useAriaLiveAnnouncer_unstable } from './useAriaLiveAnnouncer';
export { useAriaLiveAnnouncerContextValues_unstable } from './useAriaLiveAnnouncerContextValues';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/index.ts"],"sourcesContent":["export { AriaLiveAnnouncer } from './AriaLiveAnnouncer';\nexport type { AriaLiveAnnouncerProps, AriaLiveAnnouncerState } from './AriaLiveAnnouncer.types';\nexport { renderAriaLiveAnnouncer_unstable } from './renderAriaLiveAnnouncer';\nexport { useAriaLiveAnnouncer_unstable } from './useAriaLiveAnnouncer';\nexport { useAriaLiveAnnouncerContextValues_unstable } from './useAriaLiveAnnouncerContextValues';\n"],"names":["AriaLiveAnnouncer","renderAriaLiveAnnouncer_unstable","useAriaLiveAnnouncer_unstable","useAriaLiveAnnouncerContextValues_unstable"],"mappings":"AAAA,SAASA,iBAAiB,QAAQ,sBAAsB;AAExD,SAASC,gCAAgC,QAAQ,4BAA4B;AAC7E,SAASC,6BAA6B,QAAQ,yBAAyB;AACvE,SAASC,0CAA0C,QAAQ,sCAAsC"}

View File

@@ -0,0 +1,7 @@
import * as React from 'react';
import { AnnounceProvider } from '@fluentui/react-shared-contexts';
export const renderAriaLiveAnnouncer_unstable = (state, contextValues)=>{
return /*#__PURE__*/ React.createElement(AnnounceProvider, {
value: contextValues.announce
}, state.children);
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/renderAriaLiveAnnouncer.tsx"],"sourcesContent":["import * as React from 'react';\nimport { AnnounceProvider } from '@fluentui/react-shared-contexts';\n\nimport type { AriaLiveAnnouncerContextValues, AriaLiveAnnouncerState } from './AriaLiveAnnouncer.types';\nimport type { JSXElement } from '@fluentui/react-utilities';\n\nexport const renderAriaLiveAnnouncer_unstable = (\n state: AriaLiveAnnouncerState,\n contextValues: AriaLiveAnnouncerContextValues,\n): JSXElement => {\n return <AnnounceProvider value={contextValues.announce}>{state.children}</AnnounceProvider>;\n};\n"],"names":["React","AnnounceProvider","renderAriaLiveAnnouncer_unstable","state","contextValues","value","announce","children"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,gBAAgB,QAAQ,kCAAkC;AAKnE,OAAO,MAAMC,mCAAmC,CAC9CC,OACAC;IAEA,qBAAO,oBAACH;QAAiBI,OAAOD,cAAcE,QAAQ;OAAGH,MAAMI,QAAQ;AACzE,EAAE"}

View File

@@ -0,0 +1,23 @@
'use client';
import * as React from 'react';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { useDomAnnounce_unstable } from './useDomAnnounce';
import { useAriaNotifyAnnounce_unstable } from './useAriaNotifyAnnounce';
export const useAriaLiveAnnouncer_unstable = (props)=>{
const { targetDocument } = useFluent();
const domAnnounce = useDomAnnounce_unstable();
const ariaNotifyAnnounce = useAriaNotifyAnnounce_unstable();
const announce = React.useMemo(()=>{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const supportsAriaNotify = typeof (targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.ariaNotify) === 'function';
return supportsAriaNotify ? ariaNotifyAnnounce : domAnnounce;
}, [
targetDocument,
ariaNotifyAnnounce,
domAnnounce
]);
return {
announce,
children: props.children
};
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/useAriaLiveAnnouncer.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { useDomAnnounce_unstable } from './useDomAnnounce';\nimport { useAriaNotifyAnnounce_unstable } from './useAriaNotifyAnnounce';\n\nimport type { AriaLiveAnnouncerState, AriaLiveAnnouncerProps } from './AriaLiveAnnouncer.types';\n\nexport const useAriaLiveAnnouncer_unstable = (props: AriaLiveAnnouncerProps): AriaLiveAnnouncerState => {\n const { targetDocument } = useFluent();\n const domAnnounce = useDomAnnounce_unstable();\n const ariaNotifyAnnounce = useAriaNotifyAnnounce_unstable();\n\n const announce = React.useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const supportsAriaNotify = typeof (targetDocument as any)?.ariaNotify === 'function';\n return supportsAriaNotify ? ariaNotifyAnnounce : domAnnounce;\n }, [targetDocument, ariaNotifyAnnounce, domAnnounce]);\n\n return {\n announce,\n children: props.children,\n };\n};\n"],"names":["React","useFluent_unstable","useFluent","useDomAnnounce_unstable","useAriaNotifyAnnounce_unstable","useAriaLiveAnnouncer_unstable","props","targetDocument","domAnnounce","ariaNotifyAnnounce","announce","useMemo","supportsAriaNotify","ariaNotify","children"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,uBAAuB,QAAQ,mBAAmB;AAC3D,SAASC,8BAA8B,QAAQ,0BAA0B;AAIzE,OAAO,MAAMC,gCAAgC,CAACC;IAC5C,MAAM,EAAEC,cAAc,EAAE,GAAGL;IAC3B,MAAMM,cAAcL;IACpB,MAAMM,qBAAqBL;IAE3B,MAAMM,WAAWV,MAAMW,OAAO,CAAC;QAC7B,8DAA8D;QAC9D,MAAMC,qBAAqB,QAAQL,2BAAAA,qCAAD,AAACA,eAAwBM,UAAU,MAAK;QAC1E,OAAOD,qBAAqBH,qBAAqBD;IACnD,GAAG;QAACD;QAAgBE;QAAoBD;KAAY;IAEpD,OAAO;QACLE;QACAI,UAAUR,MAAMQ,QAAQ;IAC1B;AACF,EAAE"}

View File

@@ -0,0 +1,12 @@
'use client';
import * as React from 'react';
export function useAriaLiveAnnouncerContextValues_unstable(state) {
const { announce } = state;
return React.useMemo(()=>({
announce: {
announce
}
}), [
announce
]);
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/useAriaLiveAnnouncerContextValues.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { AriaLiveAnnouncerContextValues, AriaLiveAnnouncerState } from './AriaLiveAnnouncer.types';\n\nexport function useAriaLiveAnnouncerContextValues_unstable(\n state: AriaLiveAnnouncerState,\n): AriaLiveAnnouncerContextValues {\n const { announce } = state;\n\n return React.useMemo(() => ({ announce: { announce } }), [announce]);\n}\n"],"names":["React","useAriaLiveAnnouncerContextValues_unstable","state","announce","useMemo"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAG/B,OAAO,SAASC,2CACdC,KAA6B;IAE7B,MAAM,EAAEC,QAAQ,EAAE,GAAGD;IAErB,OAAOF,MAAMI,OAAO,CAAC,IAAO,CAAA;YAAED,UAAU;gBAAEA;YAAS;QAAE,CAAA,GAAI;QAACA;KAAS;AACrE"}

View File

@@ -0,0 +1,25 @@
'use client';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import * as React from 'react';
/* INTERNAL: implementation of the announcer using the ariaNotify API */ export const useAriaNotifyAnnounce_unstable = ()=>{
const { targetDocument } = useFluent();
const announce = React.useCallback((message, options = {})=>{
if (!targetDocument) {
return;
}
const { alert = false, polite } = options;
// default priority to 0 if polite, 2 if alert, and 1 by default
// used to set both ariaNotify's priority and interrupt
const defaultPriority = polite ? 0 : alert ? 2 : 1;
var _options_priority;
const priority = (_options_priority = options.priority) !== null && _options_priority !== void 0 ? _options_priority : defaultPriority;
// map fluent announce options to ariaNotify options
const ariaNotifyOptions = {
priority: priority > 1 ? 'high' : 'normal'
};
targetDocument.ariaNotify(message, ariaNotifyOptions);
}, [
targetDocument
]);
return announce;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/AriaLiveAnnouncer/useAriaNotifyAnnounce.ts"],"sourcesContent":["'use client';\n\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport type { AnnounceOptions } from '@fluentui/react-shared-contexts';\nimport * as React from 'react';\n\nimport type { AriaLiveAnnounceFn } from './AriaLiveAnnouncer.types';\n\ntype AriaNotifyOptions = {\n priority?: 'high' | 'normal';\n};\n\ntype DocumentWithAriaNotify = Document & {\n ariaNotify: (message: string, options: AriaNotifyOptions) => void;\n};\n\n/* INTERNAL: implementation of the announcer using the ariaNotify API */\nexport const useAriaNotifyAnnounce_unstable = (): AriaLiveAnnounceFn => {\n const { targetDocument } = useFluent();\n\n const announce: AriaLiveAnnounceFn = React.useCallback(\n (message: string, options: AnnounceOptions = {}) => {\n if (!targetDocument) {\n return;\n }\n\n const { alert = false, polite } = options;\n\n // default priority to 0 if polite, 2 if alert, and 1 by default\n // used to set both ariaNotify's priority and interrupt\n const defaultPriority = polite ? 0 : alert ? 2 : 1;\n const priority = options.priority ?? defaultPriority;\n\n // map fluent announce options to ariaNotify options\n const ariaNotifyOptions: AriaNotifyOptions = {\n priority: priority > 1 ? 'high' : 'normal',\n };\n\n (targetDocument as DocumentWithAriaNotify).ariaNotify(message, ariaNotifyOptions);\n },\n [targetDocument],\n );\n\n return announce;\n};\n"],"names":["useFluent_unstable","useFluent","React","useAriaNotifyAnnounce_unstable","targetDocument","announce","useCallback","message","options","alert","polite","defaultPriority","priority","ariaNotifyOptions","ariaNotify"],"mappings":"AAAA;AAEA,SAASA,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF,YAAYC,WAAW,QAAQ;AAY/B,sEAAsE,GACtE,OAAO,MAAMC,iCAAiC;IAC5C,MAAM,EAAEC,cAAc,EAAE,GAAGH;IAE3B,MAAMI,WAA+BH,MAAMI,WAAW,CACpD,CAACC,SAAiBC,UAA2B,CAAC,CAAC;QAC7C,IAAI,CAACJ,gBAAgB;YACnB;QACF;QAEA,MAAM,EAAEK,QAAQ,KAAK,EAAEC,MAAM,EAAE,GAAGF;QAElC,gEAAgE;QAChE,uDAAuD;QACvD,MAAMG,kBAAkBD,SAAS,IAAID,QAAQ,IAAI;YAChCD;QAAjB,MAAMI,WAAWJ,CAAAA,oBAAAA,QAAQI,QAAQ,cAAhBJ,+BAAAA,oBAAoBG;QAErC,oDAAoD;QACpD,MAAME,oBAAuC;YAC3CD,UAAUA,WAAW,IAAI,SAAS;QACpC;QAECR,eAA0CU,UAAU,CAACP,SAASM;IACjE,GACA;QAACT;KAAe;IAGlB,OAAOC;AACT,EAAE"}

View File

@@ -0,0 +1,134 @@
'use client';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { createPriorityQueue, useTimeout } from '@fluentui/react-utilities';
import { useDangerousNeverHidden_unstable as useDangerousNeverHidden } from '@fluentui/react-tabster';
import * as React from 'react';
/** The duration the message needs to be in present in DOM for screen readers to register a change and announce */ const MESSAGE_DURATION = 500;
const VISUALLY_HIDDEN_STYLES = {
clip: 'rect(0px, 0px, 0px, 0px)',
height: '1px',
margin: '-1px',
width: '1px',
position: 'absolute',
overflow: 'hidden',
textWrap: 'nowrap'
};
/* INTERNAL: implementation of the announcer using a live region element */ export const useDomAnnounce_unstable = ()=>{
const { targetDocument } = useFluent();
const timeoutRef = React.useRef(undefined);
const [setAnnounceTimeout, clearAnnounceTimeout] = useTimeout();
const tabsterNeverHiddenAttributes = useDangerousNeverHidden();
const elementRef = React.useRef(null);
const order = React.useRef(0);
// investigate alert implementation later
// const [alertList, setAlertList] = React.useState<string[]>([]);
const batchMessages = React.useRef([]);
const [messageQueue] = React.useState(()=>createPriorityQueue((a, b)=>{
if (a.priority !== b.priority) {
return b.priority - a.priority;
}
return a.createdAt - b.createdAt;
}));
const queueMessage = React.useCallback(()=>{
if (timeoutRef.current || !elementRef.current) {
return;
}
const runCycle = ()=>{
if (!elementRef.current) {
return;
}
if (targetDocument && messageQueue.peek()) {
// need a wrapping element for Narrator/Edge, which currently does not pick up text-only live region changes
// consistently
// if this is fixed, we can set textContent to the string directly
const wrappingEl = targetDocument.createElement('span');
wrappingEl.innerText = messageQueue.all().filter((msg)=>msg.message.trim().length > 0).reduce((prevText, currMsg)=>prevText + currMsg.message + '. ', '');
elementRef.current.innerText = '';
elementRef.current.appendChild(wrappingEl);
messageQueue.clear();
batchMessages.current = [];
// begin new cycle to clear (or update) messages
timeoutRef.current = setAnnounceTimeout(()=>{
runCycle();
}, MESSAGE_DURATION);
} else {
elementRef.current.textContent = '';
clearAnnounceTimeout();
timeoutRef.current = undefined;
}
};
// Run the first cycle with a 0 timeout to ensure multiple messages in the same tick are handled
timeoutRef.current = setAnnounceTimeout(()=>{
runCycle();
}, 0);
}, [
clearAnnounceTimeout,
messageQueue,
setAnnounceTimeout,
targetDocument
]);
const announce = React.useCallback((message, options = {})=>{
const { alert = false, priority = 0, batchId } = options;
// check if message is an alert
if (alert) {
// TODO: alert implementation
// setAlertList([...alertList, message]);
}
const liveMessage = {
message,
createdAt: order.current++,
priority,
batchId
};
// check if batchId exists
if (batchId) {
// update associated msg if it does
const batchMessage = batchMessages.current.find((msg)=>msg.batchId === batchId);
if (batchMessage) {
// replace existing message in queue
messageQueue.remove(batchMessage.message);
// update list of existing batchIds w/ most recent message
batchMessage.message = liveMessage;
} else {
// update list of existing batchIds, add new if doesn't already exist
batchMessages.current = [
...batchMessages.current,
{
batchId,
message: liveMessage
}
];
}
}
// add new message
messageQueue.enqueue(liveMessage);
queueMessage();
}, [
messageQueue,
queueMessage
]);
React.useEffect(()=>{
if (!targetDocument) {
return;
}
const element = targetDocument.createElement('div');
element.setAttribute('aria-live', 'assertive');
Object.entries(tabsterNeverHiddenAttributes).forEach(([key, value])=>{
element.setAttribute(key, value);
});
Object.assign(element.style, VISUALLY_HIDDEN_STYLES);
targetDocument.body.append(element);
elementRef.current = element;
return ()=>{
element.remove();
elementRef.current = null;
clearAnnounceTimeout();
timeoutRef.current = undefined;
};
}, [
clearAnnounceTimeout,
tabsterNeverHiddenAttributes,
targetDocument
]);
return announce;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
'use client';
import * as React from 'react';
const noop = ()=>undefined;
const activeDescendantContextDefaultValue = {
controller: {
active: noop,
blur: noop,
find: noop,
first: noop,
focus: noop,
focusLastActive: noop,
scrollActiveIntoView: noop,
last: noop,
next: noop,
prev: noop,
showAttributes: noop,
hideAttributes: noop,
showFocusVisibleAttributes: noop,
hideFocusVisibleAttributes: noop
}
};
const ActiveDescendantContext = React.createContext(undefined);
export const ActiveDescendantContextProvider = ActiveDescendantContext.Provider;
export const useActiveDescendantContext = ()=>{
var _React_useContext;
return (_React_useContext = React.useContext(ActiveDescendantContext)) !== null && _React_useContext !== void 0 ? _React_useContext : activeDescendantContextDefaultValue;
};
export const useHasParentActiveDescendantContext = ()=>!!React.useContext(ActiveDescendantContext);

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/ActiveDescendantContext.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { ActiveDescendantImperativeRef } from './types';\n\nexport type ActiveDescendantContextValue = {\n controller: ActiveDescendantImperativeRef;\n};\n\nconst noop = () => undefined;\n\nconst activeDescendantContextDefaultValue: ActiveDescendantContextValue = {\n controller: {\n active: noop,\n blur: noop,\n find: noop,\n first: noop,\n focus: noop,\n focusLastActive: noop,\n scrollActiveIntoView: noop,\n last: noop,\n next: noop,\n prev: noop,\n showAttributes: noop,\n hideAttributes: noop,\n showFocusVisibleAttributes: noop,\n hideFocusVisibleAttributes: noop,\n },\n};\n\nconst ActiveDescendantContext = React.createContext<ActiveDescendantContextValue | undefined>(undefined);\n\nexport const ActiveDescendantContextProvider = ActiveDescendantContext.Provider;\nexport const useActiveDescendantContext = (): ActiveDescendantContextValue =>\n React.useContext(ActiveDescendantContext) ?? activeDescendantContextDefaultValue;\nexport const useHasParentActiveDescendantContext = (): boolean => !!React.useContext(ActiveDescendantContext);\n"],"names":["React","noop","undefined","activeDescendantContextDefaultValue","controller","active","blur","find","first","focus","focusLastActive","scrollActiveIntoView","last","next","prev","showAttributes","hideAttributes","showFocusVisibleAttributes","hideFocusVisibleAttributes","ActiveDescendantContext","createContext","ActiveDescendantContextProvider","Provider","useActiveDescendantContext","useContext","useHasParentActiveDescendantContext"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAO/B,MAAMC,OAAO,IAAMC;AAEnB,MAAMC,sCAAoE;IACxEC,YAAY;QACVC,QAAQJ;QACRK,MAAML;QACNM,MAAMN;QACNO,OAAOP;QACPQ,OAAOR;QACPS,iBAAiBT;QACjBU,sBAAsBV;QACtBW,MAAMX;QACNY,MAAMZ;QACNa,MAAMb;QACNc,gBAAgBd;QAChBe,gBAAgBf;QAChBgB,4BAA4BhB;QAC5BiB,4BAA4BjB;IAC9B;AACF;AAEA,MAAMkB,0BAA0BnB,MAAMoB,aAAa,CAA2ClB;AAE9F,OAAO,MAAMmB,kCAAkCF,wBAAwBG,QAAQ,CAAC;AAChF,OAAO,MAAMC,6BAA6B;QACxCvB;WAAAA,CAAAA,oBAAAA,MAAMwB,UAAU,CAACL,sCAAjBnB,+BAAAA,oBAA6CG;EAAoC;AACnF,OAAO,MAAMsB,sCAAsC,IAAe,CAAC,CAACzB,MAAMwB,UAAU,CAACL,yBAAyB"}

View File

@@ -0,0 +1,6 @@
/**
* Applied to the element that is active descendant
*/ export const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';
/**
* Applied to the active descendant when the user is navigating with keyboard
*/ export const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = 'data-activedescendant-focusvisible';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/constants.ts"],"sourcesContent":["/**\n * Applied to the element that is active descendant\n */\nexport const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';\n\n/**\n * Applied to the active descendant when the user is navigating with keyboard\n */\nexport const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = 'data-activedescendant-focusvisible';\n"],"names":["ACTIVEDESCENDANT_ATTRIBUTE","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE"],"mappings":"AAAA;;CAEC,GACD,OAAO,MAAMA,6BAA6B,wBAAwB;AAElE;;CAEC,GACD,OAAO,MAAMC,0CAA0C,qCAAqC"}

View File

@@ -0,0 +1,3 @@
export { ActiveDescendantContextProvider, useActiveDescendantContext, useHasParentActiveDescendantContext } from './ActiveDescendantContext';
export { createActiveDescendantChangeEvent, useActiveDescendant } from './useActiveDescendant';
export { ACTIVEDESCENDANT_ATTRIBUTE, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './constants';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/index.ts"],"sourcesContent":["export type { ActiveDescendantContextValue } from './ActiveDescendantContext';\nexport {\n ActiveDescendantContextProvider,\n useActiveDescendantContext,\n useHasParentActiveDescendantContext,\n} from './ActiveDescendantContext';\nexport type { ActiveDescendantChangeEvent } from './useActiveDescendant';\nexport { createActiveDescendantChangeEvent, useActiveDescendant } from './useActiveDescendant';\nexport { ACTIVEDESCENDANT_ATTRIBUTE, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './constants';\nexport type {\n ActiveDescendantImperativeRef,\n ActiveDescendantOptions,\n FindOptions,\n IteratorOptions,\n UseActiveDescendantReturn,\n} from './types';\n"],"names":["ActiveDescendantContextProvider","useActiveDescendantContext","useHasParentActiveDescendantContext","createActiveDescendantChangeEvent","useActiveDescendant","ACTIVEDESCENDANT_ATTRIBUTE","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE"],"mappings":"AACA,SACEA,+BAA+B,EAC/BC,0BAA0B,EAC1BC,mCAAmC,QAC9B,4BAA4B;AAEnC,SAASC,iCAAiC,EAAEC,mBAAmB,QAAQ,wBAAwB;AAC/F,SAASC,0BAA0B,EAAEC,uCAAuC,QAAQ,cAAc"}

View File

@@ -0,0 +1,62 @@
export const scrollIntoView = (target)=>{
if (!target) {
return;
}
const scrollParent = findScrollableParent(target.parentElement);
if (!scrollParent) {
return;
}
const { offsetHeight } = target;
const offsetTop = getTotalOffsetTop(target, scrollParent);
const { scrollMarginTop, scrollMarginBottom } = getScrollMargins(target);
const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;
const isAbove = offsetTop - scrollMarginTop < scrollTop;
const isBelow = offsetTop + offsetHeight + scrollMarginBottom > scrollTop + parentOffsetHeight;
const buffer = 2;
if (isAbove) {
scrollParent.scrollTo(0, offsetTop - scrollMarginTop - buffer);
} else if (isBelow) {
scrollParent.scrollTo(0, offsetTop + offsetHeight + scrollMarginBottom - parentOffsetHeight + buffer);
}
};
const findScrollableParent = (element)=>{
if (!element) {
return null;
}
if (element.scrollHeight > element.offsetHeight) {
return element;
}
return findScrollableParent(element.parentElement);
};
const getTotalOffsetTop = (element, scrollParent)=>{
if (!element || element === scrollParent) {
return 0;
}
if (element.contains(scrollParent)) {
// subtract the scroll parent's offset top from the running total if the offsetParent is above it
return scrollParent.offsetTop * -1;
}
return element.offsetTop + getTotalOffsetTop(element.offsetParent, scrollParent);
};
const getScrollMargins = (element)=>{
var _element_ownerDocument;
const win = (_element_ownerDocument = element.ownerDocument) === null || _element_ownerDocument === void 0 ? void 0 : _element_ownerDocument.defaultView;
if (!win) {
return {
scrollMarginTop: 0,
scrollMarginBottom: 0
};
}
const computedStyles = win.getComputedStyle(element);
var _getIntValueOfComputedStyle;
const scrollMarginTop = (_getIntValueOfComputedStyle = getIntValueOfComputedStyle(computedStyles.scrollMarginTop)) !== null && _getIntValueOfComputedStyle !== void 0 ? _getIntValueOfComputedStyle : getIntValueOfComputedStyle(computedStyles.scrollMarginBlockStart);
var _getIntValueOfComputedStyle1;
const scrollMarginBottom = (_getIntValueOfComputedStyle1 = getIntValueOfComputedStyle(computedStyles.scrollMarginBottom)) !== null && _getIntValueOfComputedStyle1 !== void 0 ? _getIntValueOfComputedStyle1 : getIntValueOfComputedStyle(computedStyles.scrollMarginBlockEnd);
return {
scrollMarginTop,
scrollMarginBottom
};
};
const getIntValueOfComputedStyle = (computedStyle)=>{
return computedStyle ? parseInt(computedStyle, 10) : 0;
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/scrollIntoView.ts"],"sourcesContent":["export const scrollIntoView = (target: HTMLElement | null | undefined): void => {\n if (!target) {\n return;\n }\n\n const scrollParent = findScrollableParent(target.parentElement as HTMLElement);\n if (!scrollParent) {\n return;\n }\n\n const { offsetHeight } = target;\n const offsetTop = getTotalOffsetTop(target, scrollParent);\n\n const { scrollMarginTop, scrollMarginBottom } = getScrollMargins(target);\n\n const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;\n\n const isAbove = offsetTop - scrollMarginTop < scrollTop;\n const isBelow = offsetTop + offsetHeight + scrollMarginBottom > scrollTop + parentOffsetHeight;\n\n const buffer = 2;\n\n if (isAbove) {\n scrollParent.scrollTo(0, offsetTop - scrollMarginTop - buffer);\n } else if (isBelow) {\n scrollParent.scrollTo(0, offsetTop + offsetHeight + scrollMarginBottom - parentOffsetHeight + buffer);\n }\n};\n\nconst findScrollableParent = (element: HTMLElement | null): HTMLElement | null => {\n if (!element) {\n return null;\n }\n\n if (element.scrollHeight > element.offsetHeight) {\n return element;\n }\n\n return findScrollableParent(element.parentElement);\n};\n\nconst getTotalOffsetTop = (element: HTMLElement, scrollParent: HTMLElement): number => {\n if (!element || element === scrollParent) {\n return 0;\n }\n\n if (element.contains(scrollParent)) {\n // subtract the scroll parent's offset top from the running total if the offsetParent is above it\n return scrollParent.offsetTop * -1;\n }\n\n return element.offsetTop + getTotalOffsetTop(element.offsetParent as HTMLElement, scrollParent);\n};\n\nconst getScrollMargins = (element: HTMLElement) => {\n const win = element.ownerDocument?.defaultView;\n if (!win) {\n return {\n scrollMarginTop: 0,\n scrollMarginBottom: 0,\n };\n }\n\n const computedStyles = win.getComputedStyle(element);\n const scrollMarginTop =\n getIntValueOfComputedStyle(computedStyles.scrollMarginTop) ??\n getIntValueOfComputedStyle(computedStyles.scrollMarginBlockStart);\n const scrollMarginBottom =\n getIntValueOfComputedStyle(computedStyles.scrollMarginBottom) ??\n getIntValueOfComputedStyle(computedStyles.scrollMarginBlockEnd);\n return {\n scrollMarginTop,\n scrollMarginBottom,\n };\n};\n\nconst getIntValueOfComputedStyle = (computedStyle: string) => {\n return computedStyle ? parseInt(computedStyle, 10) : 0;\n};\n"],"names":["scrollIntoView","target","scrollParent","findScrollableParent","parentElement","offsetHeight","offsetTop","getTotalOffsetTop","scrollMarginTop","scrollMarginBottom","getScrollMargins","parentOffsetHeight","scrollTop","isAbove","isBelow","buffer","scrollTo","element","scrollHeight","contains","offsetParent","win","ownerDocument","defaultView","computedStyles","getComputedStyle","getIntValueOfComputedStyle","scrollMarginBlockStart","scrollMarginBlockEnd","computedStyle","parseInt"],"mappings":"AAAA,OAAO,MAAMA,iBAAiB,CAACC;IAC7B,IAAI,CAACA,QAAQ;QACX;IACF;IAEA,MAAMC,eAAeC,qBAAqBF,OAAOG,aAAa;IAC9D,IAAI,CAACF,cAAc;QACjB;IACF;IAEA,MAAM,EAAEG,YAAY,EAAE,GAAGJ;IACzB,MAAMK,YAAYC,kBAAkBN,QAAQC;IAE5C,MAAM,EAAEM,eAAe,EAAEC,kBAAkB,EAAE,GAAGC,iBAAiBT;IAEjE,MAAM,EAAEI,cAAcM,kBAAkB,EAAEC,SAAS,EAAE,GAAGV;IAExD,MAAMW,UAAUP,YAAYE,kBAAkBI;IAC9C,MAAME,UAAUR,YAAYD,eAAeI,qBAAqBG,YAAYD;IAE5E,MAAMI,SAAS;IAEf,IAAIF,SAAS;QACXX,aAAac,QAAQ,CAAC,GAAGV,YAAYE,kBAAkBO;IACzD,OAAO,IAAID,SAAS;QAClBZ,aAAac,QAAQ,CAAC,GAAGV,YAAYD,eAAeI,qBAAqBE,qBAAqBI;IAChG;AACF,EAAE;AAEF,MAAMZ,uBAAuB,CAACc;IAC5B,IAAI,CAACA,SAAS;QACZ,OAAO;IACT;IAEA,IAAIA,QAAQC,YAAY,GAAGD,QAAQZ,YAAY,EAAE;QAC/C,OAAOY;IACT;IAEA,OAAOd,qBAAqBc,QAAQb,aAAa;AACnD;AAEA,MAAMG,oBAAoB,CAACU,SAAsBf;IAC/C,IAAI,CAACe,WAAWA,YAAYf,cAAc;QACxC,OAAO;IACT;IAEA,IAAIe,QAAQE,QAAQ,CAACjB,eAAe;QAClC,iGAAiG;QACjG,OAAOA,aAAaI,SAAS,GAAG,CAAC;IACnC;IAEA,OAAOW,QAAQX,SAAS,GAAGC,kBAAkBU,QAAQG,YAAY,EAAiBlB;AACpF;AAEA,MAAMQ,mBAAmB,CAACO;QACZA;IAAZ,MAAMI,OAAMJ,yBAAAA,QAAQK,aAAa,cAArBL,6CAAAA,uBAAuBM,WAAW;IAC9C,IAAI,CAACF,KAAK;QACR,OAAO;YACLb,iBAAiB;YACjBC,oBAAoB;QACtB;IACF;IAEA,MAAMe,iBAAiBH,IAAII,gBAAgB,CAACR;QAE1CS;IADF,MAAMlB,kBACJkB,CAAAA,8BAAAA,2BAA2BF,eAAehB,eAAe,eAAzDkB,yCAAAA,8BACAA,2BAA2BF,eAAeG,sBAAsB;QAEhED;IADF,MAAMjB,qBACJiB,CAAAA,+BAAAA,2BAA2BF,eAAef,kBAAkB,eAA5DiB,0CAAAA,+BACAA,2BAA2BF,eAAeI,oBAAoB;IAChE,OAAO;QACLpB;QACAC;IACF;AACF;AAEA,MAAMiB,6BAA6B,CAACG;IAClC,OAAOA,gBAAgBC,SAASD,eAAe,MAAM;AACvD"}

View File

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

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/activedescendant/types.ts"],"sourcesContent":["import * as React from 'react';\n\nexport interface ActiveDescendantImperativeRef {\n first: (options?: IteratorOptions) => string | undefined;\n last: (options?: IteratorOptions) => string | undefined;\n next: (options?: IteratorOptions) => string | undefined;\n prev: (options?: IteratorOptions) => string | undefined;\n find: (predicate: (id: string) => boolean, options?: IteratorOptions & FindOptions) => string | undefined;\n blur: () => void;\n active: () => string | undefined;\n focus: (id: string) => void;\n /**\n * @deprecated This function is not used internally anymore and will be removed in the future\n */\n focusLastActive: () => void;\n /**\n * Scrolls the active option into view, if it still exists\n */\n scrollActiveIntoView: () => void;\n hideAttributes: () => void;\n showAttributes: () => void;\n hideFocusVisibleAttributes: () => void;\n showFocusVisibleAttributes: () => void;\n}\n\nexport interface ActiveDescendantOptions {\n /**\n * @param el - HTML element to test\n * @returns whether the element can be an active descendant\n */\n matchOption: (el: HTMLElement) => boolean;\n /**\n * Forward imperative refs when exposing functionality from a React component\n */\n imperativeRef?: React.RefObject<ActiveDescendantImperativeRef | null>;\n}\n\nexport interface FindOptions {\n /**\n * Starts the search from a specific id\n */\n startFrom?: string;\n}\n\nexport interface UseActiveDescendantReturn<\n TActiveParentElement extends HTMLElement = HTMLElement,\n TListboxElement extends HTMLElement = HTMLElement,\n> {\n /**\n * Attach this to the element that contains all active descendants\n */\n listboxRef: React.Ref<TListboxElement>;\n /**\n * Attach this to the element that has an active descendant\n */\n activeParentRef: React.Ref<TActiveParentElement>;\n /**\n * Imperative functions to manage active descendants within the listboxRef\n */\n controller: ActiveDescendantImperativeRef;\n}\n\nexport interface IteratorOptions {\n /**\n * When passive, the active descendant is changed\n * @default false\n */\n passive?: boolean;\n}\n"],"names":["React"],"mappings":"AAAA,YAAYA,WAAW,QAAQ"}

View File

@@ -0,0 +1,219 @@
'use client';
import * as React from 'react';
import { useEventCallback, useMergedRefs } from '@fluentui/react-utilities';
import { useOnKeyboardNavigationChange } from '@fluentui/react-tabster';
import { useOptionWalker } from './useOptionWalker';
import { ACTIVEDESCENDANT_ATTRIBUTE, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './constants';
import { scrollIntoView } from './scrollIntoView';
export const createActiveDescendantChangeEvent = (detail)=>new CustomEvent('activedescendantchange', {
bubbles: true,
cancelable: false,
composed: true,
detail
});
export function useActiveDescendant(options) {
const { imperativeRef, matchOption: matchOptionUnstable } = options;
const focusVisibleRef = React.useRef(false);
const shouldShowFocusVisibleAttrRef = React.useRef(true);
const activeIdRef = React.useRef(null);
const lastActiveIdRef = React.useRef(null);
const activeParentRef = React.useRef(null);
const attributeVisibilityRef = React.useRef(true);
const removeAttribute = React.useCallback(()=>{
var _activeParentRef_current;
(_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.removeAttribute('aria-activedescendant');
}, []);
const setAttribute = React.useCallback((id)=>{
if (id) {
activeIdRef.current = id;
}
if (attributeVisibilityRef.current && activeIdRef.current) {
var _activeParentRef_current;
(_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.setAttribute('aria-activedescendant', activeIdRef.current);
}
}, []);
useOnKeyboardNavigationChange((isNavigatingWithKeyboard)=>{
focusVisibleRef.current = isNavigatingWithKeyboard;
const active = getActiveDescendant();
if (!active) {
return;
}
if (isNavigatingWithKeyboard && shouldShowFocusVisibleAttrRef.current) {
active.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
} else {
active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
}
});
const matchOption = useEventCallback(matchOptionUnstable);
const listboxRef = React.useRef(null);
const { optionWalker, listboxCallbackRef } = useOptionWalker({
matchOption
});
const getActiveDescendant = React.useCallback(()=>{
var _listboxRef_current;
return (_listboxRef_current = listboxRef.current) === null || _listboxRef_current === void 0 ? void 0 : _listboxRef_current.querySelector(`#${activeIdRef.current}`);
}, [
listboxRef
]);
const setShouldShowFocusVisibleAttribute = React.useCallback((shouldShow)=>{
shouldShowFocusVisibleAttrRef.current = shouldShow;
const active = getActiveDescendant();
if (!active) {
return;
}
if (shouldShow && focusVisibleRef.current) {
active.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
} else {
active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
}
}, [
getActiveDescendant
]);
const blurActiveDescendant = React.useCallback(()=>{
const active = getActiveDescendant();
if (active) {
active.removeAttribute(ACTIVEDESCENDANT_ATTRIBUTE);
active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
}
removeAttribute();
lastActiveIdRef.current = activeIdRef.current;
activeIdRef.current = null;
var _active_id;
return (_active_id = active === null || active === void 0 ? void 0 : active.id) !== null && _active_id !== void 0 ? _active_id : null;
}, [
getActiveDescendant,
removeAttribute
]);
const focusActiveDescendant = React.useCallback((nextActive)=>{
if (!nextActive) {
return;
}
const previousActiveId = blurActiveDescendant();
scrollIntoView(nextActive);
setAttribute(nextActive.id);
nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');
if (focusVisibleRef.current && shouldShowFocusVisibleAttrRef.current) {
nextActive.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
}
const event = createActiveDescendantChangeEvent({
id: nextActive.id,
previousId: previousActiveId
});
nextActive.dispatchEvent(event);
}, [
blurActiveDescendant,
setAttribute
]);
const controller = React.useMemo(()=>({
first: ({ passive } = {})=>{
const first = optionWalker.first();
if (!passive) {
focusActiveDescendant(first);
}
return first === null || first === void 0 ? void 0 : first.id;
},
last: ({ passive } = {})=>{
const last = optionWalker.last();
if (!passive) {
focusActiveDescendant(last);
}
return last === null || last === void 0 ? void 0 : last.id;
},
next: ({ passive } = {})=>{
const active = getActiveDescendant();
if (!active) {
return;
}
optionWalker.setCurrent(active);
const next = optionWalker.next();
if (!passive) {
focusActiveDescendant(next);
}
return next === null || next === void 0 ? void 0 : next.id;
},
prev: ({ passive } = {})=>{
const active = getActiveDescendant();
if (!active) {
return;
}
optionWalker.setCurrent(active);
const next = optionWalker.prev();
if (!passive) {
focusActiveDescendant(next);
}
return next === null || next === void 0 ? void 0 : next.id;
},
blur: ()=>{
blurActiveDescendant();
},
active: ()=>{
var _getActiveDescendant;
return (_getActiveDescendant = getActiveDescendant()) === null || _getActiveDescendant === void 0 ? void 0 : _getActiveDescendant.id;
},
focus: (id)=>{
if (!listboxRef.current) {
return;
}
const target = listboxRef.current.querySelector(`#${id}`);
if (target) {
focusActiveDescendant(target);
}
},
focusLastActive: ()=>{
if (!listboxRef.current || !lastActiveIdRef.current) {
return;
}
const target = listboxRef.current.querySelector(`#${lastActiveIdRef.current}`);
if (target) {
focusActiveDescendant(target);
return true;
}
},
find (predicate, { passive, startFrom } = {}) {
const target = optionWalker.find(predicate, startFrom);
if (!passive) {
focusActiveDescendant(target);
}
return target === null || target === void 0 ? void 0 : target.id;
},
scrollActiveIntoView: ()=>{
if (!listboxRef.current) {
return;
}
const active = getActiveDescendant();
if (!active) {
return;
}
scrollIntoView(active);
},
showAttributes () {
attributeVisibilityRef.current = true;
setAttribute();
},
hideAttributes () {
attributeVisibilityRef.current = false;
removeAttribute();
},
showFocusVisibleAttributes () {
setShouldShowFocusVisibleAttribute(true);
},
hideFocusVisibleAttributes () {
setShouldShowFocusVisibleAttribute(false);
}
}), [
optionWalker,
listboxRef,
setAttribute,
removeAttribute,
focusActiveDescendant,
blurActiveDescendant,
getActiveDescendant,
setShouldShowFocusVisibleAttribute
]);
React.useImperativeHandle(imperativeRef, ()=>controller);
return {
listboxRef: useMergedRefs(listboxRef, listboxCallbackRef),
activeParentRef,
controller
};
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,82 @@
'use client';
import * as React from 'react';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { isHTMLElement } from '@fluentui/react-utilities';
export function useOptionWalker(options) {
const { matchOption } = options;
const { targetDocument } = useFluent();
const treeWalkerRef = React.useRef(null);
const listboxRef = React.useRef(null);
const optionFilter = React.useCallback((node)=>{
if (isHTMLElement(node) && matchOption(node)) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
}, [
matchOption
]);
const setListbox = React.useCallback((el)=>{
if (el && targetDocument) {
listboxRef.current = el;
treeWalkerRef.current = targetDocument.createTreeWalker(el, NodeFilter.SHOW_ELEMENT, optionFilter);
} else {
listboxRef.current = null;
treeWalkerRef.current = null;
}
}, [
targetDocument,
optionFilter
]);
const optionWalker = React.useMemo(()=>({
first: ()=>{
if (!treeWalkerRef.current || !listboxRef.current) {
return null;
}
treeWalkerRef.current.currentNode = listboxRef.current;
return treeWalkerRef.current.firstChild();
},
last: ()=>{
if (!treeWalkerRef.current || !listboxRef.current) {
return null;
}
treeWalkerRef.current.currentNode = listboxRef.current;
return treeWalkerRef.current.lastChild();
},
next: ()=>{
if (!treeWalkerRef.current) {
return null;
}
return treeWalkerRef.current.nextNode();
},
prev: ()=>{
if (!treeWalkerRef.current) {
return null;
}
return treeWalkerRef.current.previousNode();
},
find: (predicate, startFrom)=>{
if (!treeWalkerRef.current || !listboxRef.current) {
return null;
}
const start = startFrom ? targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.getElementById(startFrom) : null;
treeWalkerRef.current.currentNode = start !== null && start !== void 0 ? start : listboxRef.current;
let cur = treeWalkerRef.current.currentNode;
while(cur && !predicate(cur.id)){
cur = treeWalkerRef.current.nextNode();
}
return cur;
},
setCurrent: (el)=>{
if (!treeWalkerRef.current) {
return;
}
treeWalkerRef.current.currentNode = el;
}
}), [
targetDocument
]);
return {
optionWalker,
listboxCallbackRef: setListbox
};
}

File diff suppressed because one or more lines are too long

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"}

5
node_modules/@fluentui/react-aria/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export { // eslint-disable-next-line @typescript-eslint/no-deprecated
useARIAButtonShorthand, useARIAButtonProps } from './button/index';
export { useActiveDescendant, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, ActiveDescendantContextProvider, useActiveDescendantContext, useHasParentActiveDescendantContext } from './activedescendant';
export { AriaLiveAnnouncer, renderAriaLiveAnnouncer_unstable, useAriaLiveAnnouncer_unstable, useAriaLiveAnnouncerContextValues_unstable } from './AriaLiveAnnouncer/index';
export { useTypingAnnounce } from './useTypingAnnounce/index';

1
node_modules/@fluentui/react-aria/lib/index.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n useARIAButtonShorthand,\n useARIAButtonProps,\n} from './button/index';\nexport {\n useActiveDescendant,\n ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE,\n ActiveDescendantContextProvider,\n useActiveDescendantContext,\n useHasParentActiveDescendantContext,\n} from './activedescendant';\nexport type {\n ActiveDescendantImperativeRef,\n ActiveDescendantOptions,\n ActiveDescendantContextValue,\n ActiveDescendantChangeEvent,\n} from './activedescendant';\nexport type {\n ARIAButtonSlotProps,\n ARIAButtonProps,\n ARIAButtonResultProps,\n ARIAButtonType,\n ARIAButtonElement,\n ARIAButtonElementIntersection,\n ARIAButtonAlteredProps,\n} from './button/index';\n\nexport {\n AriaLiveAnnouncer,\n renderAriaLiveAnnouncer_unstable,\n useAriaLiveAnnouncer_unstable,\n useAriaLiveAnnouncerContextValues_unstable,\n} from './AriaLiveAnnouncer/index';\nexport type { AriaLiveAnnouncerProps, AriaLiveAnnouncerState } from './AriaLiveAnnouncer/index';\n\nexport { useTypingAnnounce } from './useTypingAnnounce/index';\n"],"names":["useARIAButtonShorthand","useARIAButtonProps","useActiveDescendant","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE","ActiveDescendantContextProvider","useActiveDescendantContext","useHasParentActiveDescendantContext","AriaLiveAnnouncer","renderAriaLiveAnnouncer_unstable","useAriaLiveAnnouncer_unstable","useAriaLiveAnnouncerContextValues_unstable","useTypingAnnounce"],"mappings":"AAAA,SACE,4DAA4D;AAC5DA,sBAAsB,EACtBC,kBAAkB,QACb,iBAAiB;AACxB,SACEC,mBAAmB,EACnBC,uCAAuC,EACvCC,+BAA+B,EAC/BC,0BAA0B,EAC1BC,mCAAmC,QAC9B,qBAAqB;AAiB5B,SACEC,iBAAiB,EACjBC,gCAAgC,EAChCC,6BAA6B,EAC7BC,0CAA0C,QACrC,4BAA4B;AAGnC,SAASC,iBAAiB,QAAQ,4BAA4B"}

View File

@@ -0,0 +1 @@
export { useTypingAnnounce } from './useTypingAnnounce';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/useTypingAnnounce/index.ts"],"sourcesContent":["export { useTypingAnnounce } from './useTypingAnnounce';\n"],"names":["useTypingAnnounce"],"mappings":"AAAA,SAASA,iBAAiB,QAAQ,sBAAsB"}

View File

@@ -0,0 +1,72 @@
'use client';
import * as React from 'react';
import { useTimeout } from '@fluentui/react-utilities';
import { useAnnounce, useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
const valueMutationOptions = {
attributes: true,
subtree: true,
characterData: true,
attributeFilter: [
'value'
]
};
export function useTypingAnnounce() {
const { targetDocument } = useFluent();
const { announce } = useAnnounce();
const inputRef = React.useRef(null);
const observer = React.useRef(undefined);
const [setTypingTimeout, clearTypingTimeout] = useTimeout();
const messageQueue = React.useRef([]);
const callback = React.useCallback((mutationList, mutationObserver)=>{
setTypingTimeout(()=>{
messageQueue.current.forEach(({ message, options })=>{
announce(message, options);
});
messageQueue.current.length = 0;
mutationObserver.disconnect();
}, 500);
}, [
announce,
setTypingTimeout
]);
const typingAnnounce = React.useCallback((message, options = {})=>{
messageQueue.current.push({
message,
options
});
if (inputRef.current && observer.current) {
observer.current.observe(inputRef.current, valueMutationOptions);
}
setTypingTimeout(()=>{
observer.current && callback([], observer.current);
}, 500);
}, [
callback,
inputRef,
setTypingTimeout
]);
React.useEffect(()=>{
const win = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView;
if (!win) {
return;
}
if (!observer.current) {
observer.current = new win.MutationObserver(callback);
}
return ()=>{
// Clean up the observer when the component unmounts
if (observer.current) {
observer.current.disconnect();
clearTypingTimeout();
}
};
}, [
callback,
clearTypingTimeout,
targetDocument
]);
return {
typingAnnounce,
inputRef
};
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/useTypingAnnounce/useTypingAnnounce.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useTimeout } from '@fluentui/react-utilities';\nimport { useAnnounce, useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport type { AnnounceOptions } from '@fluentui/react-shared-contexts';\nimport { AriaLiveAnnounceFn } from '../AriaLiveAnnouncer/AriaLiveAnnouncer.types';\n\ntype Message = {\n message: string;\n options: AnnounceOptions;\n};\n\nconst valueMutationOptions = {\n attributes: true,\n subtree: true,\n characterData: true,\n attributeFilter: ['value'],\n};\n\ninterface TypingAnnounceReturn<TInputElement extends HTMLElement = HTMLElement> {\n typingAnnounce: AriaLiveAnnounceFn;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n inputRef: React.MutableRefObject<TInputElement | null>;\n}\n\nexport function useTypingAnnounce<\n TInputElement extends HTMLElement = HTMLElement,\n>(): TypingAnnounceReturn<TInputElement> {\n const { targetDocument } = useFluent();\n const { announce } = useAnnounce();\n\n const inputRef = React.useRef<TInputElement | null>(null);\n const observer = React.useRef<MutationObserver>(undefined);\n const [setTypingTimeout, clearTypingTimeout] = useTimeout();\n const messageQueue = React.useRef<Message[]>([]);\n\n const callback: MutationCallback = React.useCallback(\n (mutationList, mutationObserver) => {\n setTypingTimeout(() => {\n messageQueue.current.forEach(({ message, options }) => {\n announce(message, options);\n });\n messageQueue.current.length = 0;\n mutationObserver.disconnect();\n }, 500);\n },\n [announce, setTypingTimeout],\n );\n\n const typingAnnounce: AriaLiveAnnounceFn = React.useCallback(\n (message: string, options: AnnounceOptions = {}) => {\n messageQueue.current.push({ message, options });\n\n if (inputRef.current && observer.current) {\n observer.current.observe(inputRef.current, valueMutationOptions);\n }\n\n setTypingTimeout(() => {\n observer.current && callback([], observer.current);\n }, 500);\n },\n [callback, inputRef, setTypingTimeout],\n );\n\n React.useEffect(() => {\n const win = targetDocument?.defaultView;\n if (!win) {\n return;\n }\n\n if (!observer.current) {\n observer.current = new win.MutationObserver(callback);\n }\n\n return () => {\n // Clean up the observer when the component unmounts\n if (observer.current) {\n observer.current.disconnect();\n clearTypingTimeout();\n }\n };\n }, [callback, clearTypingTimeout, targetDocument]);\n\n return { typingAnnounce, inputRef };\n}\n"],"names":["React","useTimeout","useAnnounce","useFluent_unstable","useFluent","valueMutationOptions","attributes","subtree","characterData","attributeFilter","useTypingAnnounce","targetDocument","announce","inputRef","useRef","observer","undefined","setTypingTimeout","clearTypingTimeout","messageQueue","callback","useCallback","mutationList","mutationObserver","current","forEach","message","options","length","disconnect","typingAnnounce","push","observe","useEffect","win","defaultView","MutationObserver"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,UAAU,QAAQ,4BAA4B;AACvD,SAASC,WAAW,EAAEC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAS/F,MAAMC,uBAAuB;IAC3BC,YAAY;IACZC,SAAS;IACTC,eAAe;IACfC,iBAAiB;QAAC;KAAQ;AAC5B;AAQA,OAAO,SAASC;IAGd,MAAM,EAAEC,cAAc,EAAE,GAAGP;IAC3B,MAAM,EAAEQ,QAAQ,EAAE,GAAGV;IAErB,MAAMW,WAAWb,MAAMc,MAAM,CAAuB;IACpD,MAAMC,WAAWf,MAAMc,MAAM,CAAmBE;IAChD,MAAM,CAACC,kBAAkBC,mBAAmB,GAAGjB;IAC/C,MAAMkB,eAAenB,MAAMc,MAAM,CAAY,EAAE;IAE/C,MAAMM,WAA6BpB,MAAMqB,WAAW,CAClD,CAACC,cAAcC;QACbN,iBAAiB;YACfE,aAAaK,OAAO,CAACC,OAAO,CAAC,CAAC,EAAEC,OAAO,EAAEC,OAAO,EAAE;gBAChDf,SAASc,SAASC;YACpB;YACAR,aAAaK,OAAO,CAACI,MAAM,GAAG;YAC9BL,iBAAiBM,UAAU;QAC7B,GAAG;IACL,GACA;QAACjB;QAAUK;KAAiB;IAG9B,MAAMa,iBAAqC9B,MAAMqB,WAAW,CAC1D,CAACK,SAAiBC,UAA2B,CAAC,CAAC;QAC7CR,aAAaK,OAAO,CAACO,IAAI,CAAC;YAAEL;YAASC;QAAQ;QAE7C,IAAId,SAASW,OAAO,IAAIT,SAASS,OAAO,EAAE;YACxCT,SAASS,OAAO,CAACQ,OAAO,CAACnB,SAASW,OAAO,EAAEnB;QAC7C;QAEAY,iBAAiB;YACfF,SAASS,OAAO,IAAIJ,SAAS,EAAE,EAAEL,SAASS,OAAO;QACnD,GAAG;IACL,GACA;QAACJ;QAAUP;QAAUI;KAAiB;IAGxCjB,MAAMiC,SAAS,CAAC;QACd,MAAMC,MAAMvB,2BAAAA,qCAAAA,eAAgBwB,WAAW;QACvC,IAAI,CAACD,KAAK;YACR;QACF;QAEA,IAAI,CAACnB,SAASS,OAAO,EAAE;YACrBT,SAASS,OAAO,GAAG,IAAIU,IAAIE,gBAAgB,CAAChB;QAC9C;QAEA,OAAO;YACL,oDAAoD;YACpD,IAAIL,SAASS,OAAO,EAAE;gBACpBT,SAASS,OAAO,CAACK,UAAU;gBAC3BX;YACF;QACF;IACF,GAAG;QAACE;QAAUF;QAAoBP;KAAe;IAEjD,OAAO;QAAEmB;QAAgBjB;IAAS;AACpC"}

49
node_modules/@fluentui/react-aria/package.json generated vendored Normal file
View File

@@ -0,0 +1,49 @@
{
"name": "@fluentui/react-aria",
"version": "9.17.10",
"description": "React helper to ensure ARIA",
"main": "lib-commonjs/index.js",
"module": "lib/index.js",
"typings": "./dist/index.d.ts",
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/microsoft/fluentui"
},
"license": "MIT",
"dependencies": {
"@fluentui/keyboard-keys": "^9.0.8",
"@fluentui/react-shared-contexts": "^9.26.2",
"@fluentui/react-jsx-runtime": "^9.4.1",
"@fluentui/react-tabster": "^9.26.13",
"@fluentui/react-utilities": "^9.26.2",
"@swc/helpers": "^0.5.1"
},
"peerDependencies": {
"@types/react": ">=16.14.0 <20.0.0",
"@types/react-dom": ">=16.9.0 <20.0.0",
"react": ">=16.14.0 <20.0.0",
"react-dom": ">=16.14.0 <20.0.0"
},
"beachball": {
"disallowedChangeTypes": [
"major",
"prerelease"
]
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"node": "./lib-commonjs/index.js",
"import": "./lib/index.js",
"require": "./lib-commonjs/index.js"
},
"./package.json": "./package.json"
},
"files": [
"*.md",
"dist/*.d.ts",
"lib",
"lib-commonjs"
]
}