Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
import * as React from 'react';
import { SLOT_ELEMENT_TYPE_SYMBOL } from './constants';
import { isSlot } from './isSlot';
import * as slot from './slot';
/**
* @internal
* Assertion method to ensure state slots properties are properly declared.
* A properly declared slot must be declared by using the `slot` method.
*
* @example
* ```tsx
* export const renderInput_unstable = (state: InputState) => {
assertSlots<InputSlots>(state);
return (
<state.root>
{state.contentBefore && <state.contentBefore />}
<state.input />
{state.contentAfter && <state.contentAfter />}
</state.root>
);
};
* ```
*/ export function assertSlots(state) {
/**
* This verification is not necessary in production
* as we're verifying static properties that will not change between environments
*/ if (process.env.NODE_ENV !== 'production') {
const typedState = state;
for (const slotName of Object.keys(typedState.components)){
const slotElement = typedState[slotName];
if (slotElement === undefined) {
continue;
}
// this means a slot is being declared without using, slot.always or slot.optional or even resolveShorthand on the state hook,
// but the render method is using the new `assertSlots` method. That scenario can be solved by simply updating the slot element with the proper element type
// FIXME: this slot will still fail to support child render function scenario
if (!isSlot(slotElement)) {
typedState[slotName] = slot.always(slotElement, {
elementType: typedState.components[slotName]
});
// eslint-disable-next-line no-console
console.warn(`@fluentui/react-utilities [${assertSlots.name}]:
"state.${slotName}" is not a slot!
Be sure to create slots properly by using "slot.always" or "slot.optional".`);
} else {
// This means a slot is being declared by using resolveShorthand on the state hook,
// but the render method is using the new `assertSlots` method. That scenario can be solved by simply updating the slot element with the proper element type
const { [SLOT_ELEMENT_TYPE_SYMBOL]: elementType } = slotElement;
if (elementType !== typedState.components[slotName]) {
slotElement[SLOT_ELEMENT_TYPE_SYMBOL] = typedState.components[slotName];
// eslint-disable-next-line no-console
console.warn(`@fluentui/react-utilities [${assertSlots.name}]:
"state.${slotName}" element type differs from "state.components.${slotName}",
${elementType} !== ${typedState.components[slotName]}.
Be sure to create slots properly by using "slot.always" or "slot.optional" with the correct elementType.`);
}
}
}
}
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/compose/assertSlots.ts"],"sourcesContent":["import * as React from 'react';\nimport { SLOT_ELEMENT_TYPE_SYMBOL } from './constants';\nimport { isSlot } from './isSlot';\nimport { ComponentState, ExtractSlotProps, SlotComponentType, SlotPropsRecord } from './types';\nimport * as slot from './slot';\n\ntype SlotComponents<Slots extends SlotPropsRecord> = {\n [K in keyof Slots]: SlotComponentType<ExtractSlotProps<Slots[K]>> | (null extends Slots[K] ? undefined : never);\n};\n\n/**\n * @internal\n * Assertion method to ensure state slots properties are properly declared.\n * A properly declared slot must be declared by using the `slot` method.\n *\n * @example\n * ```tsx\n * export const renderInput_unstable = (state: InputState) => {\n assertSlots<InputSlots>(state);\n return (\n <state.root>\n {state.contentBefore && <state.contentBefore />}\n <state.input />\n {state.contentAfter && <state.contentAfter />}\n </state.root>\n );\n };\n * ```\n */\nexport function assertSlots<Slots extends SlotPropsRecord>(state: unknown): asserts state is SlotComponents<Slots> {\n /**\n * This verification is not necessary in production\n * as we're verifying static properties that will not change between environments\n */\n if (process.env.NODE_ENV !== 'production') {\n const typedState = state as ComponentState<Slots>;\n for (const slotName of Object.keys(typedState.components)) {\n const slotElement = typedState[slotName];\n if (slotElement === undefined) {\n continue;\n }\n // this means a slot is being declared without using, slot.always or slot.optional or even resolveShorthand on the state hook,\n // but the render method is using the new `assertSlots` method. That scenario can be solved by simply updating the slot element with the proper element type\n // FIXME: this slot will still fail to support child render function scenario\n if (!isSlot(slotElement)) {\n typedState[slotName as keyof ComponentState<Slots>] = slot.always(slotElement, {\n elementType: typedState.components[slotName] as React.ComponentType<{}>,\n }) as ComponentState<Slots>[keyof ComponentState<Slots>];\n // eslint-disable-next-line no-console\n console.warn(/** #__DE-INDENT__ */ `\n @fluentui/react-utilities [${assertSlots.name}]:\n \"state.${slotName}\" is not a slot!\n Be sure to create slots properly by using \"slot.always\" or \"slot.optional\".\n `);\n } else {\n // This means a slot is being declared by using resolveShorthand on the state hook,\n // but the render method is using the new `assertSlots` method. That scenario can be solved by simply updating the slot element with the proper element type\n const { [SLOT_ELEMENT_TYPE_SYMBOL]: elementType } = slotElement;\n if (elementType !== typedState.components[slotName]) {\n slotElement[SLOT_ELEMENT_TYPE_SYMBOL] = typedState.components[slotName] as React.ComponentType<{}>;\n // eslint-disable-next-line no-console\n console.warn(/** #__DE-INDENT__ */ `\n @fluentui/react-utilities [${assertSlots.name}]:\n \"state.${slotName}\" element type differs from \"state.components.${slotName}\",\n ${elementType} !== ${typedState.components[slotName]}.\n Be sure to create slots properly by using \"slot.always\" or \"slot.optional\" with the correct elementType.\n `);\n }\n }\n }\n }\n}\n"],"names":["React","SLOT_ELEMENT_TYPE_SYMBOL","isSlot","slot","assertSlots","state","process","env","NODE_ENV","typedState","slotName","Object","keys","components","slotElement","undefined","always","elementType","console","warn","name"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,wBAAwB,QAAQ,cAAc;AACvD,SAASC,MAAM,QAAQ,WAAW;AAElC,YAAYC,UAAU,SAAS;AAM/B;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASC,YAA2CC,KAAc;IACvE;;;GAGC,GACD,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,cAAc;QACzC,MAAMC,aAAaJ;QACnB,KAAK,MAAMK,YAAYC,OAAOC,IAAI,CAACH,WAAWI,UAAU,EAAG;YACzD,MAAMC,cAAcL,UAAU,CAACC,SAAS;YACxC,IAAII,gBAAgBC,WAAW;gBAC7B;YACF;YACA,8HAA8H;YAC9H,4JAA4J;YAC5J,6EAA6E;YAC7E,IAAI,CAACb,OAAOY,cAAc;gBACxBL,UAAU,CAACC,SAAwC,GAAGP,KAAKa,MAAM,CAACF,aAAa;oBAC7EG,aAAaR,WAAWI,UAAU,CAACH,SAAS;gBAC9C;gBACA,sCAAsC;gBACtCQ,QAAQC,IAAI,CAAuB,CAAC,2BACP,EAAEf,YAAYgB,IAAI,CAAC;OACvC,EAAEV,SAAS;2EAEpB,CAAC;YACH,OAAO;gBACL,mFAAmF;gBACnF,4JAA4J;gBAC5J,MAAM,EAAE,CAACT,yBAAyB,EAAEgB,WAAW,EAAE,GAAGH;gBACpD,IAAIG,gBAAgBR,WAAWI,UAAU,CAACH,SAAS,EAAE;oBACnDI,WAAW,CAACb,yBAAyB,GAAGQ,WAAWI,UAAU,CAACH,SAAS;oBACvE,sCAAsC;oBACtCQ,QAAQC,IAAI,CAAuB,CAAC,2BACP,EAAEf,YAAYgB,IAAI,CAAC;OACvC,EAAEV,SAAS,8CAA8C,EAAEA,SAAS;AAC3E,EAAEO,YAAY,KAAK,EAAER,WAAWI,UAAU,CAACH,SAAS,CAAC;wGAEvD,CAAC;gBACH;YACF;QACF;IACF;AACF"}
+8
View File
@@ -0,0 +1,8 @@
/**
* @internal
* Internal reference for the render function
*/ export const SLOT_RENDER_FUNCTION_SYMBOL = Symbol.for('fui.slotRenderFunction');
/**
* @internal
* Internal reference for the render function
*/ export const SLOT_ELEMENT_TYPE_SYMBOL = Symbol.for('fui.slotElementType');
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/compose/constants.ts"],"sourcesContent":["/**\n * @internal\n * Internal reference for the render function\n */\nexport const SLOT_RENDER_FUNCTION_SYMBOL = Symbol.for('fui.slotRenderFunction');\n/**\n * @internal\n * Internal reference for the render function\n */\nexport const SLOT_ELEMENT_TYPE_SYMBOL = Symbol.for('fui.slotElementType');\n"],"names":["SLOT_RENDER_FUNCTION_SYMBOL","Symbol","for","SLOT_ELEMENT_TYPE_SYMBOL"],"rangeMappings":";;;;;;;","mappings":"AAAA;;;CAGC,GACD,OAAO,MAAMA,8BAA8BC,OAAOC,GAAG,CAAC,0BAA0B;AAChF;;;CAGC,GACD,OAAO,MAAMC,2BAA2BF,OAAOC,GAAG,CAAC,uBAAuB"}
@@ -0,0 +1,70 @@
import * as React from 'react';
import { omit } from '../../utils/omit';
import { isSlot } from '../isSlot';
import { SLOT_RENDER_FUNCTION_SYMBOL } from '../constants';
/**
* Given the state and an array of slot names, will break out `slots` and `slotProps`
* collections.
*
* The root is derived from a mix of `components` props and `as` prop.
*
* Slots will render as null if they are rendered as primitives with undefined children.
*
* The slotProps will always omit the `as` prop within them, and for slots that are string
* primitives, the props will be filtered according to the slot type by the type system.
* For example, if the slot is rendered `as: 'a'`, the props will be filtered for acceptable
* anchor props. Note that this is only enforced at build time by Typescript -- there is no
* runtime code filtering props in this function.
*
* @deprecated use slot.always or slot.optional combined with assertSlots instead
*
* @param state - State including slot definitions
* @returns An object containing the `slots` map and `slotProps` map.
*/ export function getSlots(state) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
const slots = {};
const slotProps = {};
const slotNames = Object.keys(state.components);
for (const slotName of slotNames){
const [slot, props] = getSlot(state, slotName);
// eslint-disable-next-line @typescript-eslint/no-deprecated
slots[slotName] = slot;
slotProps[slotName] = props;
}
// eslint-disable-next-line @typescript-eslint/no-deprecated
return {
slots,
slotProps: slotProps
};
}
function getSlot(state, slotName) {
var _state_components, _state_components1;
const props = state[slotName];
if (props === undefined) {
return [
null,
undefined
];
}
// TS Error: Property 'as' does not exist on type 'UnknownSlotProps | undefined'.ts(2339)
const { as: asProp, children, ...rest } = props;
const renderFunction = isSlot(props) ? props[SLOT_RENDER_FUNCTION_SYMBOL] : undefined;
const slot = ((_state_components = state.components) === null || _state_components === void 0 ? void 0 : _state_components[slotName]) === undefined || typeof state.components[slotName] === 'string' ? asProp || ((_state_components1 = state.components) === null || _state_components1 === void 0 ? void 0 : _state_components1[slotName]) || 'div' : state.components[slotName];
if (renderFunction || typeof children === 'function') {
const render = renderFunction || children;
return [
React.Fragment,
{
children: render(slot, rest)
}
];
}
const shouldOmitAsProp = typeof slot === 'string' && asProp;
const slotProps = shouldOmitAsProp ? omit(props, [
'as'
]) : props;
return [
slot,
slotProps
];
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,49 @@
import * as React from 'react';
/**
* Similar to `getSlots`, main difference is that it's compatible with new custom jsx pragma
*
* @internal
* This is an internal temporary method, this method will cease to exist eventually!
*
* * ❗️❗️ **DO NOT USE IT EXTERNALLY** ❗️❗️
*
* @deprecated use slot.always or slot.optional combined with assertSlots instead
*/ export function getSlotsNext(state) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
const slots = {};
const slotProps = {};
const slotNames = Object.keys(state.components);
for (const slotName of slotNames){
// eslint-disable-next-line @typescript-eslint/no-deprecated
const [slot, props] = getSlotNext(state, slotName);
// eslint-disable-next-line @typescript-eslint/no-deprecated
slots[slotName] = slot;
slotProps[slotName] = props;
}
// eslint-disable-next-line @typescript-eslint/no-deprecated
return {
slots,
slotProps: slotProps
};
}
/**
* @deprecated use slot.always or slot.optional combined with assertSlots instead
*/ function getSlotNext(state, slotName) {
var _state_components, _state_components1;
const props = state[slotName];
if (props === undefined) {
return [
null,
undefined
];
}
// TS Error: Property 'as' does not exist on type 'UnknownSlotProps | undefined'.ts(2339)
const { as: asProp, ...propsWithoutAs } = props;
const slot = ((_state_components = state.components) === null || _state_components === void 0 ? void 0 : _state_components[slotName]) === undefined || typeof state.components[slotName] === 'string' ? asProp || ((_state_components1 = state.components) === null || _state_components1 === void 0 ? void 0 : _state_components1[slotName]) || 'div' : state.components[slotName];
const shouldOmitAsProp = typeof slot === 'string' && asProp;
const slotProps = shouldOmitAsProp ? propsWithoutAs : props;
return [
slot,
slotProps
];
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/compose/deprecated/getSlotsNext.ts"],"sourcesContent":["import * as React from 'react';\nimport type { ComponentState, SlotPropsRecord, UnknownSlotProps } from '../types';\nimport { ObjectSlotProps, Slots } from './getSlots';\n\n/**\n * Similar to `getSlots`, main difference is that it's compatible with new custom jsx pragma\n *\n * @internal\n * This is an internal temporary method, this method will cease to exist eventually!\n *\n * * ❗️❗️ **DO NOT USE IT EXTERNALLY** ❗️❗️\n *\n * @deprecated use slot.always or slot.optional combined with assertSlots instead\n */\nexport function getSlotsNext<R extends SlotPropsRecord>(\n state: ComponentState<R>,\n): {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n slots: Slots<R>;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n slotProps: ObjectSlotProps<R>;\n} {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const slots = {} as Slots<R>;\n const slotProps = {} as R;\n\n const slotNames: (keyof R)[] = Object.keys(state.components);\n for (const slotName of slotNames) {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const [slot, props] = getSlotNext(state, slotName);\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n slots[slotName] = slot as Slots<R>[typeof slotName];\n slotProps[slotName] = props;\n }\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n return { slots, slotProps: slotProps as unknown as ObjectSlotProps<R> };\n}\n\n/**\n * @deprecated use slot.always or slot.optional combined with assertSlots instead\n */\nfunction getSlotNext<R extends SlotPropsRecord, K extends keyof R>(\n state: ComponentState<R>,\n slotName: K,\n): readonly [React.ElementType<R[K]> | null, R[K]] {\n const props = state[slotName];\n\n if (props === undefined) {\n return [null, undefined as R[K]];\n }\n\n type NonUndefined<T> = T extends undefined ? never : T;\n // TS Error: Property 'as' does not exist on type 'UnknownSlotProps | undefined'.ts(2339)\n const { as: asProp, ...propsWithoutAs } = props as NonUndefined<typeof props>;\n\n const slot = (\n state.components?.[slotName] === undefined || typeof state.components[slotName] === 'string'\n ? asProp || state.components?.[slotName] || 'div'\n : state.components[slotName]\n ) as React.ElementType<R[K]>;\n\n const shouldOmitAsProp = typeof slot === 'string' && asProp;\n const slotProps: UnknownSlotProps = shouldOmitAsProp ? propsWithoutAs : props;\n\n return [slot, slotProps as R[K]];\n}\n"],"names":["React","getSlotsNext","state","slots","slotProps","slotNames","Object","keys","components","slotName","slot","props","getSlotNext","undefined","as","asProp","propsWithoutAs","shouldOmitAsProp"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAI/B;;;;;;;;;CASC,GACD,OAAO,SAASC,aACdC,KAAwB;IAOxB,4DAA4D;IAC5D,MAAMC,QAAQ,CAAC;IACf,MAAMC,YAAY,CAAC;IAEnB,MAAMC,YAAyBC,OAAOC,IAAI,CAACL,MAAMM,UAAU;IAC3D,KAAK,MAAMC,YAAYJ,UAAW;QAChC,4DAA4D;QAC5D,MAAM,CAACK,MAAMC,MAAM,GAAGC,YAAYV,OAAOO;QACzC,4DAA4D;QAC5DN,KAAK,CAACM,SAAS,GAAGC;QAClBN,SAAS,CAACK,SAAS,GAAGE;IACxB;IACA,4DAA4D;IAC5D,OAAO;QAAER;QAAOC,WAAWA;IAA2C;AACxE;AAEA;;CAEC,GACD,SAASQ,YACPV,KAAwB,EACxBO,QAAW;QAaTP,mBACcA;IAZhB,MAAMS,QAAQT,KAAK,CAACO,SAAS;IAE7B,IAAIE,UAAUE,WAAW;QACvB,OAAO;YAAC;YAAMA;SAAkB;IAClC;IAGA,yFAAyF;IACzF,MAAM,EAAEC,IAAIC,MAAM,EAAE,GAAGC,gBAAgB,GAAGL;IAE1C,MAAMD,OACJR,EAAAA,oBAAAA,MAAMM,UAAU,cAAhBN,wCAAAA,iBAAkB,CAACO,SAAS,MAAKI,aAAa,OAAOX,MAAMM,UAAU,CAACC,SAAS,KAAK,WAChFM,YAAUb,qBAAAA,MAAMM,UAAU,cAAhBN,yCAAAA,kBAAkB,CAACO,SAAS,KAAI,QAC1CP,MAAMM,UAAU,CAACC,SAAS;IAGhC,MAAMQ,mBAAmB,OAAOP,SAAS,YAAYK;IACrD,MAAMX,YAA8Ba,mBAAmBD,iBAAiBL;IAExE,OAAO;QAACD;QAAMN;KAAkB;AAClC"}
@@ -0,0 +1,17 @@
import * as slot from '../slot';
/**
*
* Resolves shorthands into slot props, to ensure normalization of the signature
* being passed down to getSlots method
* @param value - the base shorthand props
* @param options - options to resolve shorthand props
*
* @deprecated use slot.always or slot.optional combined with assertSlots instead
*/ // eslint-disable-next-line @typescript-eslint/no-deprecated
export const resolveShorthand = (value, options)=>slot.optional(value, {
...options,
renderByDefault: options === null || options === void 0 ? void 0 : options.required,
// elementType as undefined is the way to identify between a slot and a resolveShorthand call
// in the case elementType is undefined assertSlots will fail, ensuring it'll only work with slot method.
elementType: undefined
});
@@ -0,0 +1 @@
{"version":3,"sources":["../src/compose/deprecated/resolveShorthand.ts"],"sourcesContent":["import * as slot from '../slot';\nimport type { SlotShorthandValue, UnknownSlotProps } from '../types';\n\n/**\n * @deprecated - use slot.always or slot.optional combined with assertSlots instead\n */\nexport type ResolveShorthandOptions<Props, Required extends boolean = false> = Required extends true\n ? { required: true; defaultProps?: Props }\n : { required?: Required; defaultProps?: Props };\n\n/**\n * @deprecated use slot.always or slot.optional combined with assertSlots instead\n */\nexport type ResolveShorthandFunction<Props extends UnknownSlotProps = UnknownSlotProps> = {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n <P extends Props>(value: P | SlotShorthandValue | undefined, options: ResolveShorthandOptions<P, true>): P;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n <P extends Props>(value: P | SlotShorthandValue | null | undefined, options?: ResolveShorthandOptions<P, boolean>):\n | P\n | undefined;\n};\n\n/**\n *\n * Resolves shorthands into slot props, to ensure normalization of the signature\n * being passed down to getSlots method\n * @param value - the base shorthand props\n * @param options - options to resolve shorthand props\n *\n * @deprecated use slot.always or slot.optional combined with assertSlots instead\n */\n// eslint-disable-next-line @typescript-eslint/no-deprecated\nexport const resolveShorthand: ResolveShorthandFunction<UnknownSlotProps> = (value, options) =>\n slot.optional<UnknownSlotProps>(value, {\n ...options,\n renderByDefault: options?.required,\n // elementType as undefined is the way to identify between a slot and a resolveShorthand call\n // in the case elementType is undefined assertSlots will fail, ensuring it'll only work with slot method.\n elementType: undefined!,\n });\n"],"names":["slot","resolveShorthand","value","options","optional","renderByDefault","required","elementType","undefined"],"rangeMappings":";;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,UAAU,UAAU;AAsBhC;;;;;;;;CAQC,GACD,4DAA4D;AAC5D,OAAO,MAAMC,mBAA+D,CAACC,OAAOC,UAClFH,KAAKI,QAAQ,CAAmBF,OAAO;QACrC,GAAGC,OAAO;QACVE,eAAe,EAAEF,oBAAAA,8BAAAA,QAASG,QAAQ;QAClC,6FAA6F;QAC7F,yGAAyG;QACzGC,aAAaC;IACf,GAAG"}
@@ -0,0 +1,12 @@
import * as React from 'react';
import { getNativeElementProps } from '../utils/getNativeElementProps';
/**
* Given an element tagname and user props, filters the props to only allowed props for the given
* element type.
*
* Equivalent to {@link getNativeElementProps}, but more type-safe.
*/ export const getIntrinsicElementProps = (/** The slot's default element type (e.g. 'div') */ tagName, /** The component's props object */ props, /** List of native props to exclude from the returned value */ excludedPropNames)=>{
var _props_as;
// eslint-disable-next-line @typescript-eslint/no-deprecated
return getNativeElementProps((_props_as = props.as) !== null && _props_as !== void 0 ? _props_as : tagName, props, excludedPropNames);
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/compose/getIntrinsicElementProps.ts"],"sourcesContent":["import * as React from 'react';\nimport { getNativeElementProps } from '../utils/getNativeElementProps';\nimport type { InferredElementRefType, UnknownSlotProps } from './types';\nimport type { DistributiveOmit } from '../utils/types';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype HTMLAttributes = React.HTMLAttributes<any>;\n\n/**\n * Given an element tagname and user props, filters the props to only allowed props for the given\n * element type.\n *\n * Equivalent to {@link getNativeElementProps}, but more type-safe.\n */\nexport const getIntrinsicElementProps = <\n Props extends UnknownSlotProps,\n ExcludedPropKeys extends Extract<keyof Props, string> = never,\n>(\n /** The slot's default element type (e.g. 'div') */\n tagName: NonNullable<Props['as']>,\n /** The component's props object */\n props: Props & React.RefAttributes<InferredElementRefType<Props>>,\n /** List of native props to exclude from the returned value */\n excludedPropNames?: ExcludedPropKeys[],\n) => {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n return getNativeElementProps<\n DistributiveOmit<Props, Exclude<keyof Props, keyof HTMLAttributes | keyof UnknownSlotProps> | ExcludedPropKeys>\n >(props.as ?? tagName, props, excludedPropNames);\n};\n"],"names":["React","getNativeElementProps","getIntrinsicElementProps","tagName","props","excludedPropNames","as"],"rangeMappings":";;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,qBAAqB,QAAQ,iCAAiC;AAOvE;;;;;CAKC,GACD,OAAO,MAAMC,2BAA2B,CAItC,iDAAiD,GACjDC,SACA,iCAAiC,GACjCC,OACA,4DAA4D,GAC5DC;QAKED;IAHF,4DAA4D;IAC5D,OAAOH,sBAELG,CAAAA,YAAAA,MAAME,EAAE,cAARF,uBAAAA,YAAYD,SAASC,OAAOC;AAChC,EAAE"}
+13
View File
@@ -0,0 +1,13 @@
import * as slot from './slot';
export { isResolvedShorthand } from './isResolvedShorthand';
export { SLOT_ELEMENT_TYPE_SYMBOL, SLOT_RENDER_FUNCTION_SYMBOL } from './constants';
export { isSlot } from './isSlot';
export { assertSlots } from './assertSlots';
export { getIntrinsicElementProps } from './getIntrinsicElementProps';
// eslint-disable-next-line @typescript-eslint/no-deprecated
export { getSlots } from './deprecated/getSlots';
// eslint-disable-next-line @typescript-eslint/no-deprecated
export { resolveShorthand } from './deprecated/resolveShorthand';
// eslint-disable-next-line @typescript-eslint/no-deprecated
export { getSlotsNext } from './deprecated/getSlotsNext';
export { slot };
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/compose/index.ts"],"sourcesContent":["import * as slot from './slot';\n\nexport type {\n AsIntrinsicElement,\n ComponentProps,\n ComponentState,\n EventData,\n EventHandler,\n ExtractSlotProps,\n ForwardRefComponent,\n InferredElementRefType,\n IsSingleton,\n PropsWithoutChildren,\n PropsWithoutRef,\n Slot,\n SlotClassNames,\n SlotComponentType,\n SlotPropsRecord,\n SlotRenderFunction,\n SlotShorthandValue,\n UnknownSlotProps,\n} from './types';\nexport { isResolvedShorthand } from './isResolvedShorthand';\nexport { SLOT_ELEMENT_TYPE_SYMBOL, SLOT_RENDER_FUNCTION_SYMBOL } from './constants';\nexport { isSlot } from './isSlot';\nexport { assertSlots } from './assertSlots';\nexport { getIntrinsicElementProps } from './getIntrinsicElementProps';\n\n// eslint-disable-next-line @typescript-eslint/no-deprecated\nexport type { ObjectSlotProps, Slots } from './deprecated/getSlots';\n// eslint-disable-next-line @typescript-eslint/no-deprecated\nexport { getSlots } from './deprecated/getSlots';\n// eslint-disable-next-line @typescript-eslint/no-deprecated\nexport type { ResolveShorthandFunction, ResolveShorthandOptions } from './deprecated/resolveShorthand';\n// eslint-disable-next-line @typescript-eslint/no-deprecated\nexport { resolveShorthand } from './deprecated/resolveShorthand';\n// eslint-disable-next-line @typescript-eslint/no-deprecated\nexport { getSlotsNext } from './deprecated/getSlotsNext';\n\nexport { slot };\nexport type { SlotOptions } from './slot';\n"],"names":["slot","isResolvedShorthand","SLOT_ELEMENT_TYPE_SYMBOL","SLOT_RENDER_FUNCTION_SYMBOL","isSlot","assertSlots","getIntrinsicElementProps","getSlots","resolveShorthand","getSlotsNext"],"rangeMappings":";;;;;;;;;;;;","mappings":"AAAA,YAAYA,UAAU,SAAS;AAsB/B,SAASC,mBAAmB,QAAQ,wBAAwB;AAC5D,SAASC,wBAAwB,EAAEC,2BAA2B,QAAQ,cAAc;AACpF,SAASC,MAAM,QAAQ,WAAW;AAClC,SAASC,WAAW,QAAQ,gBAAgB;AAC5C,SAASC,wBAAwB,QAAQ,6BAA6B;AAItE,4DAA4D;AAC5D,SAASC,QAAQ,QAAQ,wBAAwB;AAGjD,4DAA4D;AAC5D,SAASC,gBAAgB,QAAQ,gCAAgC;AACjE,4DAA4D;AAC5D,SAASC,YAAY,QAAQ,4BAA4B;AAEzD,SAAST,IAAI,GAAG"}
@@ -0,0 +1,33 @@
import * as React from 'react';
/**
* Guard method that validates if a shorthand is a slot
* can be used to extends properties provided by a slot
*
* @example
* ```
* const backdropSlot = resolveShorthand(backdrop, {
* defaultProps: {
* onClick: useEventCallback(event => {
* if (isResolvedShorthand(backdrop)) {
* backdrop.onClick?.(event)
* }
* // do something after passing click down the line
* }),
* },
* })
* ```
* @example
* ```
* const handleBackDropClick = (event) => {
* // do your thing
* }
* const backdropSlot = resolveShorthand(backdrop, {
* defaultProps: {
* onClick: useEventCallback(
* mergeCallbacks(isResolvedShorthand(backdrop) ? backdrop.onClick : undefined, handleBackdropClick)
* )
* })
* ```
*/ export function isResolvedShorthand(shorthand) {
return shorthand !== null && typeof shorthand === 'object' && !Array.isArray(shorthand) && !React.isValidElement(shorthand);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/compose/isResolvedShorthand.ts"],"sourcesContent":["import * as React from 'react';\nimport type { ExtractSlotProps, Slot, UnknownSlotProps } from './types';\n\n/**\n * Guard method that validates if a shorthand is a slot\n * can be used to extends properties provided by a slot\n *\n * @example\n * ```\n * const backdropSlot = resolveShorthand(backdrop, {\n * defaultProps: {\n * onClick: useEventCallback(event => {\n * if (isResolvedShorthand(backdrop)) {\n * backdrop.onClick?.(event)\n * }\n * // do something after passing click down the line\n * }),\n * },\n * })\n * ```\n * @example\n * ```\n * const handleBackDropClick = (event) => {\n * // do your thing\n * }\n * const backdropSlot = resolveShorthand(backdrop, {\n * defaultProps: {\n * onClick: useEventCallback(\n * mergeCallbacks(isResolvedShorthand(backdrop) ? backdrop.onClick : undefined, handleBackdropClick)\n * )\n * })\n * ```\n */\nexport function isResolvedShorthand<Shorthand extends Slot<UnknownSlotProps>>(\n shorthand?: Shorthand,\n): shorthand is ExtractSlotProps<Shorthand> {\n return (\n shorthand !== null && typeof shorthand === 'object' && !Array.isArray(shorthand) && !React.isValidElement(shorthand)\n );\n}\n"],"names":["React","isResolvedShorthand","shorthand","Array","isArray","isValidElement"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAG/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BC,GACD,OAAO,SAASC,oBACdC,SAAqB;IAErB,OACEA,cAAc,QAAQ,OAAOA,cAAc,YAAY,CAACC,MAAMC,OAAO,CAACF,cAAc,CAACF,MAAMK,cAAc,CAACH;AAE9G"}
+7
View File
@@ -0,0 +1,7 @@
import { SLOT_ELEMENT_TYPE_SYMBOL } from './constants';
/**
* Guard method to ensure a given element is a slot.
* This is mainly used internally to ensure a slot is being used as a component.
*/ export function isSlot(element) {
return Boolean(element === null || element === void 0 ? void 0 : element.hasOwnProperty(SLOT_ELEMENT_TYPE_SYMBOL));
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/compose/isSlot.ts"],"sourcesContent":["import { SLOT_ELEMENT_TYPE_SYMBOL } from './constants';\nimport { SlotComponentType } from './types';\n\n/**\n * Guard method to ensure a given element is a slot.\n * This is mainly used internally to ensure a slot is being used as a component.\n */\nexport function isSlot<Props extends {}>(element: unknown): element is SlotComponentType<Props> {\n return Boolean((element as {} | undefined)?.hasOwnProperty(SLOT_ELEMENT_TYPE_SYMBOL));\n}\n"],"names":["SLOT_ELEMENT_TYPE_SYMBOL","isSlot","element","Boolean","hasOwnProperty"],"rangeMappings":";;;;;;","mappings":"AAAA,SAASA,wBAAwB,QAAQ,cAAc;AAGvD;;;CAGC,GACD,OAAO,SAASC,OAAyBC,OAAgB;IACvD,OAAOC,QAASD,oBAAAA,8BAAD,AAACA,QAA4BE,cAAc,CAACJ;AAC7D"}
+67
View File
@@ -0,0 +1,67 @@
import * as React from 'react';
import { SLOT_ELEMENT_TYPE_SYMBOL, SLOT_RENDER_FUNCTION_SYMBOL } from './constants';
/**
* Creates a slot from a slot shorthand or properties (`props.SLOT_NAME` or `props` itself)
* @param value - the value of the slot, it can be a slot shorthand, a slot component or a slot properties
* @param options - values you can pass to alter the signature of a slot, those values are:
*
* * `elementType` - the base element type of a slot, defaults to `'div'`
* * `defaultProps` - similar to a React component declaration, you can provide a slot default properties to be merged with the shorthand/properties provided.
*/ export function always(value, options) {
const { defaultProps, elementType } = options;
const props = resolveShorthand(value);
/**
* Casting is required here as SlotComponentType is a function, not an object.
* Although SlotComponentType has a function signature, it is still just an object.
* This is required to make a slot callable (JSX compatible), this is the exact same approach
* that is used on `@types/react` components
*/ const propsWithMetadata = {
...defaultProps,
...props,
[SLOT_ELEMENT_TYPE_SYMBOL]: elementType
};
if (props && typeof props.children === 'function') {
propsWithMetadata[SLOT_RENDER_FUNCTION_SYMBOL] = props.children;
propsWithMetadata.children = defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.children;
}
return propsWithMetadata;
}
/**
* Creates a slot from a slot shorthand or properties (`props.SLOT_NAME` or `props` itself)
* @param value - the value of the slot, it can be a slot shorthand, a slot component or a slot properties
* @param options - values you can pass to alter the signature of a slot, those values are:
*
* * `elementType` - the base element type of a slot, defaults to `'div'`
* * `defaultProps` - similar to a React component declaration, you can provide a slot default properties to be merged with the shorthand/properties provided
* * `renderByDefault` - a boolean that indicates if a slot will be rendered even if it's base value is `undefined`.
* By default if `props.SLOT_NAME` is `undefined` then `state.SLOT_NAME` becomes `undefined`
* and nothing will be rendered, but if `renderByDefault = true` then `state.SLOT_NAME` becomes an object
* with the values provided by `options.defaultProps` (or `{}`). This is useful for cases such as providing a default content
* in case no shorthand is provided, like the case of the `expandIcon` slot for the `AccordionHeader`
*/ export function optional(value, options) {
if (value === null || value === undefined && !options.renderByDefault) {
return undefined;
}
return always(value, options);
}
/**
* Helper function that converts a slot shorthand or properties to a slot properties object
* The main difference between this function and `slot` is that this function does not return the metadata required for a slot to be considered a properly renderable slot, it only converts the value to a slot properties object
* @param value - the value of the slot, it can be a slot shorthand or a slot properties object
*/ export function resolveShorthand(value) {
if (typeof value === 'string' || typeof value === 'number' || Array.isArray(value) || // eslint-disable-next-line @typescript-eslint/no-explicit-any
React.isValidElement(value)) {
return {
children: value
};
}
if (value && typeof value !== 'object' && process.env.NODE_ENV !== 'production') {
// TODO: would be nice to have a link to slot documentation in this error message
// eslint-disable-next-line no-console
console.error(`@fluentui/react-utilities [slot.${resolveShorthand.name}]:
A slot got an invalid value "${value}" (${typeof value}).
A valid value for a slot is a slot shorthand or slot properties object.
Slot shorthands can be strings, numbers, arrays or JSX elements`);
}
return value;
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import * as React from 'react';
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export { getEventClientCoords, isMouseEvent, isTouchEvent } from './mouseTouchHelpers';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/events/index.ts"],"sourcesContent":["export type { NativeTouchOrMouseEvent, ReactTouchOrMouseEvent, TouchOrMouseEvent } from './mouseTouchHelpers';\nexport { getEventClientCoords, isMouseEvent, isTouchEvent } from './mouseTouchHelpers';\n"],"names":["getEventClientCoords","isMouseEvent","isTouchEvent"],"rangeMappings":"","mappings":"AACA,SAASA,oBAAoB,EAAEC,YAAY,EAAEC,YAAY,QAAQ,sBAAsB"}
+39
View File
@@ -0,0 +1,39 @@
import * as React from 'react';
/**
* Returns true if event is a touch event. Useful when sharing logic between touch and mouse interactions.
*/ export function isTouchEvent(event) {
return event.type.startsWith('touch');
}
/**
* Returns true if event is a mouse event. Useful when sharing logic between touch and mouse interactions.
*/ export function isMouseEvent(event) {
return event.type.startsWith('mouse') || [
'click',
'contextmenu',
'dblclick'
].indexOf(event.type) > -1;
}
/**
* Returns an object with clientX, clientY for TouchOrMouseEvent.
* Returns zeros in case the event is not a mouse or a touch event.
*/ export function getEventClientCoords(event) {
if (isMouseEvent(event)) {
return {
clientX: event.clientX,
clientY: event.clientY
};
} else if (isTouchEvent(event)) {
return {
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY
};
} else {
if (process.env.NODE_ENV !== 'production') {
throw new Error('@fluentui/react-utilities]: Unable to get clientX. Unknown event type.');
}
return {
clientX: 0,
clientY: 0
};
}
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/events/mouseTouchHelpers.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type NativeTouchOrMouseEvent = MouseEvent | TouchEvent;\n\nexport type ReactTouchOrMouseEvent = React.MouseEvent | React.TouchEvent;\n\nexport type TouchOrMouseEvent = NativeTouchOrMouseEvent | ReactTouchOrMouseEvent;\n\n/**\n * Returns true if event is a touch event. Useful when sharing logic between touch and mouse interactions.\n */\nexport function isTouchEvent(event: TouchOrMouseEvent): event is TouchEvent | React.TouchEvent {\n return event.type.startsWith('touch');\n}\n\n/**\n * Returns true if event is a mouse event. Useful when sharing logic between touch and mouse interactions.\n */\nexport function isMouseEvent(event: TouchOrMouseEvent): event is MouseEvent | React.MouseEvent {\n return event.type.startsWith('mouse') || ['click', 'contextmenu', 'dblclick'].indexOf(event.type) > -1;\n}\n\n/**\n * Returns an object with clientX, clientY for TouchOrMouseEvent.\n * Returns zeros in case the event is not a mouse or a touch event.\n */\nexport function getEventClientCoords(event: TouchOrMouseEvent): { clientX: number; clientY: number } {\n if (isMouseEvent(event)) {\n return { clientX: event.clientX, clientY: event.clientY };\n } else if (isTouchEvent(event)) {\n return { clientX: event.touches[0].clientX, clientY: event.touches[0].clientY };\n } else {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('@fluentui/react-utilities]: Unable to get clientX. Unknown event type.');\n }\n return { clientX: 0, clientY: 0 };\n }\n}\n"],"names":["React","isTouchEvent","event","type","startsWith","isMouseEvent","indexOf","getEventClientCoords","clientX","clientY","touches","process","env","NODE_ENV","Error"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAQ/B;;CAEC,GACD,OAAO,SAASC,aAAaC,KAAwB;IACnD,OAAOA,MAAMC,IAAI,CAACC,UAAU,CAAC;AAC/B;AAEA;;CAEC,GACD,OAAO,SAASC,aAAaH,KAAwB;IACnD,OAAOA,MAAMC,IAAI,CAACC,UAAU,CAAC,YAAY;QAAC;QAAS;QAAe;KAAW,CAACE,OAAO,CAACJ,MAAMC,IAAI,IAAI,CAAC;AACvG;AAEA;;;CAGC,GACD,OAAO,SAASI,qBAAqBL,KAAwB;IAC3D,IAAIG,aAAaH,QAAQ;QACvB,OAAO;YAAEM,SAASN,MAAMM,OAAO;YAAEC,SAASP,MAAMO,OAAO;QAAC;IAC1D,OAAO,IAAIR,aAAaC,QAAQ;QAC9B,OAAO;YAAEM,SAASN,MAAMQ,OAAO,CAAC,EAAE,CAACF,OAAO;YAAEC,SAASP,MAAMQ,OAAO,CAAC,EAAE,CAACD,OAAO;QAAC;IAChF,OAAO;QACL,IAAIE,QAAQC,GAAG,CAACC,QAAQ,KAAK,cAAc;YACzC,MAAM,IAAIC,MAAM;QAClB;QACA,OAAO;YAAEN,SAAS;YAAGC,SAAS;QAAE;IAClC;AACF"}
+13
View File
@@ -0,0 +1,13 @@
export { useAnimationFrame } from './useAnimationFrame';
export { useControllableState } from './useControllableState';
export { useEventCallback } from './useEventCallback';
export { useFirstMount } from './useFirstMount';
export { useForceUpdate } from './useForceUpdate';
export { IdPrefixProvider, resetIdsForTests, useId } from './useId';
export { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
export { useMergedRefs } from './useMergedRefs';
export { useOnClickOutside } from './useOnClickOutside';
export { useOnScrollOutside } from './useOnScrollOutside';
export { usePrevious } from './usePrevious';
export { useScrollbarWidth } from './useScrollbarWidth';
export { useTimeout } from './useTimeout';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/index.ts"],"sourcesContent":["export { useAnimationFrame } from './useAnimationFrame';\nexport type { UseControllableStateOptions } from './useControllableState';\nexport { useControllableState } from './useControllableState';\nexport { useEventCallback } from './useEventCallback';\nexport { useFirstMount } from './useFirstMount';\nexport { useForceUpdate } from './useForceUpdate';\nexport { IdPrefixProvider, resetIdsForTests, useId } from './useId';\nexport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';\nexport type { RefObjectFunction } from './useMergedRefs';\nexport { useMergedRefs } from './useMergedRefs';\nexport type { UseOnClickOrScrollOutsideOptions } from './useOnClickOutside';\nexport { useOnClickOutside } from './useOnClickOutside';\nexport { useOnScrollOutside } from './useOnScrollOutside';\nexport { usePrevious } from './usePrevious';\nexport { useScrollbarWidth } from './useScrollbarWidth';\nexport { useTimeout } from './useTimeout';\n"],"names":["useAnimationFrame","useControllableState","useEventCallback","useFirstMount","useForceUpdate","IdPrefixProvider","resetIdsForTests","useId","useIsomorphicLayoutEffect","useMergedRefs","useOnClickOutside","useOnScrollOutside","usePrevious","useScrollbarWidth","useTimeout"],"rangeMappings":";;;;;;;;;;;;","mappings":"AAAA,SAASA,iBAAiB,QAAQ,sBAAsB;AAExD,SAASC,oBAAoB,QAAQ,yBAAyB;AAC9D,SAASC,gBAAgB,QAAQ,qBAAqB;AACtD,SAASC,aAAa,QAAQ,kBAAkB;AAChD,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,gBAAgB,EAAEC,gBAAgB,EAAEC,KAAK,QAAQ,UAAU;AACpE,SAASC,yBAAyB,QAAQ,8BAA8B;AAExE,SAASC,aAAa,QAAQ,kBAAkB;AAEhD,SAASC,iBAAiB,QAAQ,sBAAsB;AACxD,SAASC,kBAAkB,QAAQ,uBAAuB;AAC1D,SAASC,WAAW,QAAQ,gBAAgB;AAC5C,SAASC,iBAAiB,QAAQ,sBAAsB;AACxD,SAASC,UAAU,QAAQ,eAAe"}
+21
View File
@@ -0,0 +1,21 @@
import { useBrowserTimer } from './useBrowserTimer';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
const setAnimationFrameNoop = (callback)=>{
callback(0);
return 0;
};
const cancelAnimationFrameNoop = (handle)=>handle;
/**
* @internal
* Helper to manage a browser requestAnimationFrame.
* Ensures that the requestAnimationFrame isn't set multiple times at once and is cleaned up
* when the component is unloaded.
*
* @returns A pair of [requestAnimationFrame, cancelAnimationFrame] that are stable between renders.
*/ export function useAnimationFrame() {
const { targetDocument } = useFluent();
const win = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView;
const setAnimationFrame = win ? win.requestAnimationFrame : setAnimationFrameNoop;
const clearAnimationFrame = win ? win.cancelAnimationFrame : cancelAnimationFrameNoop;
return useBrowserTimer(setAnimationFrame, clearAnimationFrame);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useAnimationFrame.ts"],"sourcesContent":["import { useBrowserTimer } from './useBrowserTimer';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\n\nconst setAnimationFrameNoop = (callback: FrameRequestCallback) => {\n callback(0);\n return 0;\n};\nconst cancelAnimationFrameNoop = (handle: number) => handle;\n\n/**\n * @internal\n * Helper to manage a browser requestAnimationFrame.\n * Ensures that the requestAnimationFrame isn't set multiple times at once and is cleaned up\n * when the component is unloaded.\n *\n * @returns A pair of [requestAnimationFrame, cancelAnimationFrame] that are stable between renders.\n */\nexport function useAnimationFrame() {\n const { targetDocument } = useFluent();\n const win = targetDocument?.defaultView;\n\n const setAnimationFrame = win ? win.requestAnimationFrame : setAnimationFrameNoop;\n const clearAnimationFrame = win ? win.cancelAnimationFrame : cancelAnimationFrameNoop;\n\n return useBrowserTimer(setAnimationFrame, clearAnimationFrame);\n}\n"],"names":["useBrowserTimer","useFluent_unstable","useFluent","setAnimationFrameNoop","callback","cancelAnimationFrameNoop","handle","useAnimationFrame","targetDocument","win","defaultView","setAnimationFrame","requestAnimationFrame","clearAnimationFrame","cancelAnimationFrame"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,eAAe,QAAQ,oBAAoB;AACpD,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF,MAAMC,wBAAwB,CAACC;IAC7BA,SAAS;IACT,OAAO;AACT;AACA,MAAMC,2BAA2B,CAACC,SAAmBA;AAErD;;;;;;;CAOC,GACD,OAAO,SAASC;IACd,MAAM,EAAEC,cAAc,EAAE,GAAGN;IAC3B,MAAMO,MAAMD,2BAAAA,qCAAAA,eAAgBE,WAAW;IAEvC,MAAMC,oBAAoBF,MAAMA,IAAIG,qBAAqB,GAAGT;IAC5D,MAAMU,sBAAsBJ,MAAMA,IAAIK,oBAAoB,GAAGT;IAE7D,OAAOL,gBAAgBW,mBAAmBE;AAC5C"}
+45
View File
@@ -0,0 +1,45 @@
import * as React from 'react';
/**
* @internal
* Helper to manage a browser timer.
* Ensures that the timer isn't set multiple times at once,
* and is cleaned up when the component is unloaded.
*
* @param setTimer - The timer setter function
* @param cancelTimer - The timer cancel function
* @returns A pair of [setTimer, cancelTimer] that are stable between renders.
*
* @example
* const [setTimer, cancelTimer] = useBrowserTimer(setTimeout, cancelTimeout);
*
* setTimer(() => console.log('Hello world!'), 1000);
* cancelTimer();
*/ export function useBrowserTimer(setTimer, cancelTimer) {
const id = React.useRef(undefined);
const set = React.useCallback((fn, delay)=>{
if (id.current !== undefined) {
cancelTimer(id.current);
}
id.current = setTimer(fn, delay);
return id.current;
}, [
cancelTimer,
setTimer
]);
const cancel = React.useCallback(()=>{
if (id.current !== undefined) {
cancelTimer(id.current);
id.current = undefined;
}
}, [
cancelTimer
]);
// Clean up the timeout when the component is unloaded
React.useEffect(()=>cancel, [
cancel
]);
return [
set,
cancel
];
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useBrowserTimer.ts"],"sourcesContent":["import * as React from 'react';\n\ntype BrowserTimerSetter =\n | ((fn: () => void, duration?: number, ...args: Record<string, unknown>[]) => number)\n | ((fn: () => void) => number);\n\n/**\n * @internal\n * Helper to manage a browser timer.\n * Ensures that the timer isn't set multiple times at once,\n * and is cleaned up when the component is unloaded.\n *\n * @param setTimer - The timer setter function\n * @param cancelTimer - The timer cancel function\n * @returns A pair of [setTimer, cancelTimer] that are stable between renders.\n *\n * @example\n * const [setTimer, cancelTimer] = useBrowserTimer(setTimeout, cancelTimeout);\n *\n * setTimer(() => console.log('Hello world!'), 1000);\n * cancelTimer();\n */\nexport function useBrowserTimer(setTimer: BrowserTimerSetter, cancelTimer: (id: number) => void) {\n const id = React.useRef<number | undefined>(undefined);\n\n const set = React.useCallback(\n (fn: () => void, delay?: number) => {\n if (id.current !== undefined) {\n cancelTimer(id.current);\n }\n\n id.current = setTimer(fn, delay);\n return id.current;\n },\n [cancelTimer, setTimer],\n );\n\n const cancel = React.useCallback(() => {\n if (id.current !== undefined) {\n cancelTimer(id.current);\n id.current = undefined;\n }\n }, [cancelTimer]);\n\n // Clean up the timeout when the component is unloaded\n React.useEffect(() => cancel, [cancel]);\n\n return [set, cancel] as const;\n}\n"],"names":["React","useBrowserTimer","setTimer","cancelTimer","id","useRef","undefined","set","useCallback","fn","delay","current","cancel","useEffect"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAM/B;;;;;;;;;;;;;;;CAeC,GACD,OAAO,SAASC,gBAAgBC,QAA4B,EAAEC,WAAiC;IAC7F,MAAMC,KAAKJ,MAAMK,MAAM,CAAqBC;IAE5C,MAAMC,MAAMP,MAAMQ,WAAW,CAC3B,CAACC,IAAgBC;QACf,IAAIN,GAAGO,OAAO,KAAKL,WAAW;YAC5BH,YAAYC,GAAGO,OAAO;QACxB;QAEAP,GAAGO,OAAO,GAAGT,SAASO,IAAIC;QAC1B,OAAON,GAAGO,OAAO;IACnB,GACA;QAACR;QAAaD;KAAS;IAGzB,MAAMU,SAASZ,MAAMQ,WAAW,CAAC;QAC/B,IAAIJ,GAAGO,OAAO,KAAKL,WAAW;YAC5BH,YAAYC,GAAGO,OAAO;YACtBP,GAAGO,OAAO,GAAGL;QACf;IACF,GAAG;QAACH;KAAY;IAEhB,sDAAsD;IACtDH,MAAMa,SAAS,CAAC,IAAMD,QAAQ;QAACA;KAAO;IAEtC,OAAO;QAACL;QAAKK;KAAO;AACtB"}
@@ -0,0 +1,91 @@
import * as React from 'react';
function isFactoryDispatch(newState) {
return typeof newState === 'function';
}
/**
* @internal
*
* A [`useState`](https://reactjs.org/docs/hooks-reference.html#usestate)-like hook
* to manage a value that could be either `controlled` or `uncontrolled`,
* such as a checked state or text input string.
*
* @see https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components for more details on `controlled`/`uncontrolled`
*
* @returns an array of the current value and an updater (dispatcher) function.
* The updater function is referentially stable (won't change during the component's lifecycle).
* It can take either a new value, or a function which is passed the previous value and returns the new value.
*
* ❗️❗️ Calls to the dispatcher will only modify the state if the state is `uncontrolled`.
* Meaning that if a state is `controlled`, calls to the dispatcher do not modify the state.
*
*/ export const useControllableState = (options)=>{
'use no memo';
if (process.env.NODE_ENV !== 'production') {
if (options.state !== undefined && options.defaultState !== undefined) {
// eslint-disable-next-line no-console
console.error(`@fluentui/react-utilities [useControllableState]:
A component must be either controlled or uncontrolled (specify either the state or the defaultState, but not both).
Decide between using a controlled or uncontrolled component and remove one of this props.
More info: https://reactjs.org/link/controlled-components
${new Error().stack}`);
}
}
const [internalState, setInternalState] = React.useState(()=>{
if (options.defaultState === undefined) {
return options.initialState;
}
return isInitializer(options.defaultState) ? options.defaultState() : options.defaultState;
});
// Heads up!
// This part is specific for controlled mode and mocks behavior of React dispatcher function.
const stateValueRef = React.useRef(options.state);
React.useEffect(()=>{
stateValueRef.current = options.state;
}, [
options.state
]);
const setControlledState = React.useCallback((newState)=>{
if (isFactoryDispatch(newState)) {
newState(stateValueRef.current);
}
}, []);
return useIsControlled(options.state) ? [
options.state,
setControlledState
] : [
internalState,
setInternalState
];
};
function isInitializer(value) {
return typeof value === 'function';
}
/**
* Helper hook to handle previous comparison of controlled/uncontrolled
* Prints an error when isControlled value switches between subsequent renders
* @returns - whether the value is controlled
*/ const useIsControlled = (controlledValue)=>{
'use no memo';
const [isControlled] = React.useState(()=>controlledValue !== undefined);
if (process.env.NODE_ENV !== 'production') {
// We don't want these warnings in production even though it is against native behaviour
// eslint-disable-next-line react-hooks/rules-of-hooks
React.useEffect(()=>{
if (isControlled !== (controlledValue !== undefined)) {
const error = new Error();
const controlWarning = isControlled ? 'a controlled value to be uncontrolled' : 'an uncontrolled value to be controlled';
const undefinedWarning = isControlled ? 'defined to an undefined' : 'undefined to a defined';
// eslint-disable-next-line no-console
console.error(`@fluentui/react-utilities [useControllableState]:
A component is changing ${controlWarning}. This is likely caused by the value changing from ${undefinedWarning} value, which should not happen.
Decide between using a controlled or uncontrolled input element for the lifetime of the component.
More info: https://reactjs.org/link/controlled-components
${error.stack}`);
}
}, [
isControlled,
controlledValue
]);
}
return isControlled;
};
File diff suppressed because one or more lines are too long
+30
View File
@@ -0,0 +1,30 @@
import * as React from 'react';
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
/**
* @internal
* https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback
*
* Modified `useCallback` that can be used when dependencies change too frequently. Can occur when
* e.g. user props are dependencies which could change on every render
* e.g. volatile values (i.e. useState/useDispatch) are dependencies which could change frequently
*
* This should not be used often, but can be a useful re-render optimization since the callback is a ref and
* will not be invalidated between re-renders
*
* @param fn - The callback function that will be used
*/ export const useEventCallback = (fn)=>{
const callbackRef = React.useRef(()=>{
throw new Error('Cannot call an event handler while rendering');
});
useIsomorphicLayoutEffect(()=>{
callbackRef.current = fn;
}, [
fn
]);
return React.useCallback((...args)=>{
const callback = callbackRef.current;
return callback(...args);
}, [
callbackRef
]);
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useEventCallback.ts"],"sourcesContent":["import * as React from 'react';\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';\n\n/**\n * @internal\n * https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback\n *\n * Modified `useCallback` that can be used when dependencies change too frequently. Can occur when\n * e.g. user props are dependencies which could change on every render\n * e.g. volatile values (i.e. useState/useDispatch) are dependencies which could change frequently\n *\n * This should not be used often, but can be a useful re-render optimization since the callback is a ref and\n * will not be invalidated between re-renders\n *\n * @param fn - The callback function that will be used\n */\nexport const useEventCallback = <Args extends unknown[], Return>(fn: (...args: Args) => Return) => {\n const callbackRef = React.useRef<typeof fn>(() => {\n throw new Error('Cannot call an event handler while rendering');\n });\n\n useIsomorphicLayoutEffect(() => {\n callbackRef.current = fn;\n }, [fn]);\n\n return React.useCallback(\n (...args: Args) => {\n const callback = callbackRef.current;\n return callback(...args);\n },\n [callbackRef],\n );\n};\n"],"names":["React","useIsomorphicLayoutEffect","useEventCallback","fn","callbackRef","useRef","Error","current","useCallback","args","callback"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,yBAAyB,QAAQ,8BAA8B;AAExE;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMC,mBAAmB,CAAiCC;IAC/D,MAAMC,cAAcJ,MAAMK,MAAM,CAAY;QAC1C,MAAM,IAAIC,MAAM;IAClB;IAEAL,0BAA0B;QACxBG,YAAYG,OAAO,GAAGJ;IACxB,GAAG;QAACA;KAAG;IAEP,OAAOH,MAAMQ,WAAW,CACtB,CAAC,GAAGC;QACF,MAAMC,WAAWN,YAAYG,OAAO;QACpC,OAAOG,YAAYD;IACrB,GACA;QAACL;KAAY;AAEjB,EAAE"}
+19
View File
@@ -0,0 +1,19 @@
import * as React from 'react';
/**
* @internal
* Checks if components was mounted the first time.
* Since concurrent mode will be released in the future this needs to be verified
* Currently (React 17) will always render the initial mount once
* https://codesandbox.io/s/heuristic-brook-s4w0q?file=/src/App.jsx
* https://codesandbox.io/s/holy-grass-8nieu?file=/src/App.jsx
*
* @example
* const isFirstMount = useFirstMount();
*/ export function useFirstMount() {
const isFirst = React.useRef(true);
if (isFirst.current) {
isFirst.current = false;
return true;
}
return isFirst.current;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useFirstMount.ts"],"sourcesContent":["import * as React from 'react';\n\n/**\n * @internal\n * Checks if components was mounted the first time.\n * Since concurrent mode will be released in the future this needs to be verified\n * Currently (React 17) will always render the initial mount once\n * https://codesandbox.io/s/heuristic-brook-s4w0q?file=/src/App.jsx\n * https://codesandbox.io/s/holy-grass-8nieu?file=/src/App.jsx\n *\n * @example\n * const isFirstMount = useFirstMount();\n */\nexport function useFirstMount(): boolean {\n const isFirst = React.useRef(true);\n\n if (isFirst.current) {\n isFirst.current = false;\n return true;\n }\n\n return isFirst.current;\n}\n"],"names":["React","useFirstMount","isFirst","useRef","current"],"rangeMappings":";;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAE/B;;;;;;;;;;CAUC,GACD,OAAO,SAASC;IACd,MAAMC,UAAUF,MAAMG,MAAM,CAAC;IAE7B,IAAID,QAAQE,OAAO,EAAE;QACnBF,QAAQE,OAAO,GAAG;QAClB,OAAO;IACT;IAEA,OAAOF,QAAQE,OAAO;AACxB"}
+7
View File
@@ -0,0 +1,7 @@
import * as React from 'react';
/**
* @internal
* Forces a re-render, similar to `forceUpdate` in class components.
*/ export function useForceUpdate() {
return React.useReducer((x)=>x + 1, 0)[1];
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useForceUpdate.ts"],"sourcesContent":["import * as React from 'react';\n/**\n * @internal\n * Forces a re-render, similar to `forceUpdate` in class components.\n */\nexport function useForceUpdate() {\n return React.useReducer(x => x + 1, 0)[1];\n}\n"],"names":["React","useForceUpdate","useReducer","x"],"rangeMappings":";;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B;;;CAGC,GACD,OAAO,SAASC;IACd,OAAOD,MAAME,UAAU,CAACC,CAAAA,IAAKA,IAAI,GAAG,EAAE,CAAC,EAAE;AAC3C"}
+52
View File
@@ -0,0 +1,52 @@
import * as React from 'react';
import { defaultSSRContextValue, useSSRContext } from '../ssr/index';
const IdPrefixContext = React.createContext(undefined);
/**
* Allows to define a prefix that will be used for all IDs generated by useId() hook. It's useful to avoid collisions
* between different bundles.
*/ export const IdPrefixProvider = IdPrefixContext.Provider;
function useIdPrefix() {
return React.useContext(IdPrefixContext) || '';
}
/**
* Resets generated IDs, should be used only in tests.
*/ export function resetIdsForTests() {
defaultSSRContextValue.current = 0;
}
/**
* Hook to generate a unique ID.
*
* @param prefix - Optional prefix for the ID. Defaults to 'fui-'.
* @param providedId - Optional id provided by a parent component. Defaults to the provided value if present,
* without conditioning the hook call
* @returns The ID
*/ export function useId(prefix = 'fui-', providedId) {
'use no memo';
const contextValue = useSSRContext();
const idPrefix = useIdPrefix();
// Checking if useId is available on React, if it is, we use it to generate the id. String concatenation is used to
// prevent bundlers from complaining with older versions of React.
const _useId = React['use' + 'Id'];
if (_useId) {
const generatedId = _useId();
// eslint-disable-next-line react-hooks/rules-of-hooks
const escapedId = React.useMemo(()=>generatedId.replace(/:/g, ''), [
generatedId
]);
return providedId || `${idPrefix}${prefix}${escapedId}`;
}
// Hooks appear to be running conditionally, but they will always run in the same order since it's based on
// the version of React being used. This is safe to ignore.
// eslint-disable-next-line react-hooks/rules-of-hooks
return React.useMemo(()=>{
if (providedId) {
return providedId;
}
return `${idPrefix}${prefix}${++contextValue.current}`;
}, [
idPrefix,
prefix,
providedId,
contextValue
]);
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useId.ts"],"sourcesContent":["import * as React from 'react';\nimport { defaultSSRContextValue, useSSRContext } from '../ssr/index';\n\nconst IdPrefixContext = React.createContext<string | undefined>(undefined);\n\n/**\n * Allows to define a prefix that will be used for all IDs generated by useId() hook. It's useful to avoid collisions\n * between different bundles.\n */\nexport const IdPrefixProvider = IdPrefixContext.Provider;\n\nfunction useIdPrefix(): string {\n return React.useContext(IdPrefixContext) || '';\n}\n\n/**\n * Resets generated IDs, should be used only in tests.\n */\nexport function resetIdsForTests(): void {\n defaultSSRContextValue.current = 0;\n}\n\n/**\n * Hook to generate a unique ID.\n *\n * @param prefix - Optional prefix for the ID. Defaults to 'fui-'.\n * @param providedId - Optional id provided by a parent component. Defaults to the provided value if present,\n * without conditioning the hook call\n * @returns The ID\n */\nexport function useId(prefix: string = 'fui-', providedId?: string): string {\n 'use no memo';\n\n const contextValue = useSSRContext();\n const idPrefix = useIdPrefix();\n\n // Checking if useId is available on React, if it is, we use it to generate the id. String concatenation is used to\n // prevent bundlers from complaining with older versions of React.\n const _useId = (React as never)['use' + 'Id'] as (() => string) | undefined;\n\n if (_useId) {\n const generatedId = _useId();\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const escapedId = React.useMemo(() => generatedId.replace(/:/g, ''), [generatedId]);\n\n return providedId || `${idPrefix}${prefix}${escapedId}`;\n }\n\n // Hooks appear to be running conditionally, but they will always run in the same order since it's based on\n // the version of React being used. This is safe to ignore.\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return React.useMemo(() => {\n if (providedId) {\n return providedId;\n }\n\n return `${idPrefix}${prefix}${++contextValue.current}`;\n }, [idPrefix, prefix, providedId, contextValue]);\n}\n"],"names":["React","defaultSSRContextValue","useSSRContext","IdPrefixContext","createContext","undefined","IdPrefixProvider","Provider","useIdPrefix","useContext","resetIdsForTests","current","useId","prefix","providedId","contextValue","idPrefix","_useId","generatedId","escapedId","useMemo","replace"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsB,EAAEC,aAAa,QAAQ,eAAe;AAErE,MAAMC,kBAAkBH,MAAMI,aAAa,CAAqBC;AAEhE;;;CAGC,GACD,OAAO,MAAMC,mBAAmBH,gBAAgBI,QAAQ,CAAC;AAEzD,SAASC;IACP,OAAOR,MAAMS,UAAU,CAACN,oBAAoB;AAC9C;AAEA;;CAEC,GACD,OAAO,SAASO;IACdT,uBAAuBU,OAAO,GAAG;AACnC;AAEA;;;;;;;CAOC,GACD,OAAO,SAASC,MAAMC,SAAiB,MAAM,EAAEC,UAAmB;IAChE;IAEA,MAAMC,eAAeb;IACrB,MAAMc,WAAWR;IAEjB,mHAAmH;IACnH,kEAAkE;IAClE,MAAMS,SAAS,AAACjB,KAAe,CAAC,QAAQ,KAAK;IAE7C,IAAIiB,QAAQ;QACV,MAAMC,cAAcD;QAEpB,sDAAsD;QACtD,MAAME,YAAYnB,MAAMoB,OAAO,CAAC,IAAMF,YAAYG,OAAO,CAAC,MAAM,KAAK;YAACH;SAAY;QAElF,OAAOJ,cAAc,CAAC,EAAEE,SAAS,EAAEH,OAAO,EAAEM,UAAU,CAAC;IACzD;IAEA,2GAA2G;IAC3G,2DAA2D;IAC3D,sDAAsD;IACtD,OAAOnB,MAAMoB,OAAO,CAAC;QACnB,IAAIN,YAAY;YACd,OAAOA;QACT;QAEA,OAAO,CAAC,EAAEE,SAAS,EAAEH,OAAO,EAAE,EAAEE,aAAaJ,OAAO,CAAC,CAAC;IACxD,GAAG;QAACK;QAAUH;QAAQC;QAAYC;KAAa;AACjD"}
@@ -0,0 +1,12 @@
import * as React from 'react';
import { canUseDOM } from '../ssr/index';
/**
* React currently throws a warning when using useLayoutEffect on the server. To get around it, we can conditionally
* useEffect on the server (no-op) and useLayoutEffect in the browser. We occasionally need useLayoutEffect to
* ensure we don't get a render flash for certain operations, but we may also need affected components to render on
* the server.
*
* https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
* https://github.com/reduxjs/react-redux/blob/master/src/utils/useIsomorphicLayoutEffect.js
*/ // eslint-disable-next-line no-restricted-properties
export const useIsomorphicLayoutEffect = canUseDOM() ? React.useLayoutEffect : React.useEffect;
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useIsomorphicLayoutEffect.ts"],"sourcesContent":["import * as React from 'react';\nimport { canUseDOM } from '../ssr/index';\n\n/**\n * React currently throws a warning when using useLayoutEffect on the server. To get around it, we can conditionally\n * useEffect on the server (no-op) and useLayoutEffect in the browser. We occasionally need useLayoutEffect to\n * ensure we don't get a render flash for certain operations, but we may also need affected components to render on\n * the server.\n *\n * https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85\n * https://github.com/reduxjs/react-redux/blob/master/src/utils/useIsomorphicLayoutEffect.js\n */\n// eslint-disable-next-line no-restricted-properties\nexport const useIsomorphicLayoutEffect: typeof React.useEffect = canUseDOM() ? React.useLayoutEffect : React.useEffect;\n"],"names":["React","canUseDOM","useIsomorphicLayoutEffect","useLayoutEffect","useEffect"],"rangeMappings":";;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,SAAS,QAAQ,eAAe;AAEzC;;;;;;;;CAQC,GACD,oDAAoD;AACpD,OAAO,MAAMC,4BAAoDD,cAAcD,MAAMG,eAAe,GAAGH,MAAMI,SAAS,CAAC"}
+25
View File
@@ -0,0 +1,25 @@
import * as React from 'react';
/**
* React hook to merge multiple React refs (either MutableRefObjects or ref callbacks) into a single ref callback that
* updates all provided refs
* @param refs - Refs to collectively update with one ref value.
* @returns A function with an attached "current" prop, so that it can be treated like a RefObject.
*/ export function useMergedRefs(...refs) {
'use no memo';
const mergedCallback = React.useCallback((value)=>{
// Update the "current" prop hanging on the function.
mergedCallback.current = value;
for (const ref of refs){
if (typeof ref === 'function') {
ref(value);
} else if (ref) {
// work around the immutability of the React.Ref type
ref.current = value;
}
}
}, // eslint-disable-next-line react-hooks/exhaustive-deps -- already exhaustive
[
...refs
]);
return mergedCallback;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useMergedRefs.ts"],"sourcesContent":["import * as React from 'react';\n\n/**\n * A Ref function which can be treated like a ref object in that it has an attached\n * current property, which will be updated as the ref is evaluated.\n */\nexport type RefObjectFunction<T> = React.RefObject<T> & ((value: T | null) => void);\n\n/**\n * React hook to merge multiple React refs (either MutableRefObjects or ref callbacks) into a single ref callback that\n * updates all provided refs\n * @param refs - Refs to collectively update with one ref value.\n * @returns A function with an attached \"current\" prop, so that it can be treated like a RefObject.\n */\nexport function useMergedRefs<T>(...refs: (React.Ref<T> | undefined)[]): RefObjectFunction<T> {\n 'use no memo';\n\n const mergedCallback: RefObjectFunction<T> = React.useCallback(\n (value: T | null) => {\n // Update the \"current\" prop hanging on the function.\n (mergedCallback as React.MutableRefObject<T | null>).current = value;\n\n for (const ref of refs) {\n if (typeof ref === 'function') {\n ref(value);\n } else if (ref) {\n // work around the immutability of the React.Ref type\n (ref as React.MutableRefObject<T | null>).current = value;\n }\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps -- already exhaustive\n [...refs],\n ) as RefObjectFunction<T>;\n\n return mergedCallback;\n}\n"],"names":["React","useMergedRefs","refs","mergedCallback","useCallback","value","current","ref"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAQ/B;;;;;CAKC,GACD,OAAO,SAASC,cAAiB,GAAGC,IAAkC;IACpE;IAEA,MAAMC,iBAAuCH,MAAMI,WAAW,CAC5D,CAACC;QACC,qDAAqD;QACpDF,eAAoDG,OAAO,GAAGD;QAE/D,KAAK,MAAME,OAAOL,KAAM;YACtB,IAAI,OAAOK,QAAQ,YAAY;gBAC7BA,IAAIF;YACN,OAAO,IAAIE,KAAK;gBACd,qDAAqD;gBACpDA,IAAyCD,OAAO,GAAGD;YACtD;QACF;IACF,GACA,6EAA6E;IAC7E;WAAIH;KAAK;IAGX,OAAOC;AACT"}
+149
View File
@@ -0,0 +1,149 @@
import * as React from 'react';
import { useEventCallback } from './useEventCallback';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
const DEFAULT_CONTAINS = (parent, child)=>!!(parent === null || parent === void 0 ? void 0 : parent.contains(child));
/**
* @internal
* Utility to perform checks where a click/touch event was made outside a component
*/ export const useOnClickOutside = (options)=>{
const { targetDocument } = useFluent();
const win = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView;
const { refs, callback, element, disabled, disabledFocusOnIframe, contains = DEFAULT_CONTAINS } = options;
const timeoutId = React.useRef(undefined);
useIFrameFocus({
element,
disabled: disabledFocusOnIframe || disabled,
callback,
refs,
contains
});
const isMouseDownInsideRef = React.useRef(false);
const listener = useEventCallback((ev)=>{
if (isMouseDownInsideRef.current) {
isMouseDownInsideRef.current = false;
return;
}
const target = ev.composedPath()[0];
const isOutside = refs.every((ref)=>!contains(ref.current || null, target));
if (isOutside && !disabled) {
callback(ev);
}
});
const handleMouseDown = useEventCallback((ev)=>{
// Selecting text from inside to outside will rigger click event.
// In this case click event target is outside but mouse down event target is inside.
// And this click event should be considered as inside click.
isMouseDownInsideRef.current = refs.some((ref)=>contains(ref.current || null, ev.target));
});
React.useEffect(()=>{
if (disabled) {
return;
}
// Store the current event to avoid triggering handlers immediately
// Note this depends on a deprecated but extremely well supported quirk of the web platform
// https://github.com/facebook/react/issues/20074
let currentEvent = getWindowEvent(win);
const conditionalHandler = (event)=>{
// Skip if this event is the same as the one running when we added the handlers
if (event === currentEvent) {
currentEvent = undefined;
return;
}
listener(event);
};
// use capture phase because React can update DOM before the event bubbles to the document
element === null || element === void 0 ? void 0 : element.addEventListener('click', conditionalHandler, true);
element === null || element === void 0 ? void 0 : element.addEventListener('touchstart', conditionalHandler, true);
element === null || element === void 0 ? void 0 : element.addEventListener('contextmenu', conditionalHandler, true);
element === null || element === void 0 ? void 0 : element.addEventListener('mousedown', handleMouseDown, true);
// Garbage collect this event after it's no longer useful to avoid memory leaks
timeoutId.current = win === null || win === void 0 ? void 0 : win.setTimeout(()=>{
currentEvent = undefined;
}, 1);
return ()=>{
element === null || element === void 0 ? void 0 : element.removeEventListener('click', conditionalHandler, true);
element === null || element === void 0 ? void 0 : element.removeEventListener('touchstart', conditionalHandler, true);
element === null || element === void 0 ? void 0 : element.removeEventListener('contextmenu', conditionalHandler, true);
element === null || element === void 0 ? void 0 : element.removeEventListener('mousedown', handleMouseDown, true);
win === null || win === void 0 ? void 0 : win.clearTimeout(timeoutId.current);
currentEvent = undefined;
};
}, [
listener,
element,
disabled,
handleMouseDown,
win
]);
};
const getWindowEvent = (target)=>{
if (target) {
var _target_ownerDocument_defaultView, _target_ownerDocument;
if (typeof target.window === 'object' && target.window === target) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
return target.event;
}
var _target_ownerDocument_defaultView_event;
// eslint-disable-next-line @typescript-eslint/no-deprecated
return (_target_ownerDocument_defaultView_event = (_target_ownerDocument = target.ownerDocument) === null || _target_ownerDocument === void 0 ? void 0 : (_target_ownerDocument_defaultView = _target_ownerDocument.defaultView) === null || _target_ownerDocument_defaultView === void 0 ? void 0 : _target_ownerDocument_defaultView.event) !== null && _target_ownerDocument_defaultView_event !== void 0 ? _target_ownerDocument_defaultView_event : undefined;
}
return undefined;
};
const FUI_FRAME_EVENT = 'fuiframefocus';
/**
* Since click events do not propagate past iframes, we use focus to detect if a
* click has happened inside an iframe, since the only ways of focusing inside an
* iframe are:
* - clicking inside
* - tabbing inside
*
* Polls the value of `document.activeElement`. If it is an iframe, then dispatch
* a custom DOM event. When the custom event is received call the provided callback
*/ const useIFrameFocus = (options)=>{
const { disabled, element: targetDocument, callback, contains = DEFAULT_CONTAINS, pollDuration = 1000, refs } = options;
const timeoutRef = React.useRef();
const listener = useEventCallback((e)=>{
const isOutside = refs.every((ref)=>!contains(ref.current || null, e.target));
if (isOutside && !disabled) {
callback(e);
}
});
// Adds listener to the custom iframe focus event
React.useEffect(()=>{
if (disabled) {
return;
}
targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.addEventListener(FUI_FRAME_EVENT, listener, true);
return ()=>{
targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.removeEventListener(FUI_FRAME_EVENT, listener, true);
};
}, [
targetDocument,
disabled,
listener
]);
// Starts polling for the active element
React.useEffect(()=>{
var _targetDocument_defaultView;
if (disabled) {
return;
}
timeoutRef.current = targetDocument === null || targetDocument === void 0 ? void 0 : (_targetDocument_defaultView = targetDocument.defaultView) === null || _targetDocument_defaultView === void 0 ? void 0 : _targetDocument_defaultView.setInterval(()=>{
const activeElement = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.activeElement;
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.tagName) === 'IFRAME' || (activeElement === null || activeElement === void 0 ? void 0 : activeElement.tagName) === 'WEBVIEW') {
const event = new CustomEvent(FUI_FRAME_EVENT, {
bubbles: true
});
activeElement.dispatchEvent(event);
}
}, pollDuration);
return ()=>{
var _targetDocument_defaultView;
targetDocument === null || targetDocument === void 0 ? void 0 : (_targetDocument_defaultView = targetDocument.defaultView) === null || _targetDocument_defaultView === void 0 ? void 0 : _targetDocument_defaultView.clearTimeout(timeoutRef.current);
};
}, [
targetDocument,
disabled,
pollDuration
]);
};
File diff suppressed because one or more lines are too long
+31
View File
@@ -0,0 +1,31 @@
import * as React from 'react';
import { useEventCallback } from './useEventCallback';
/**
* @internal
* Utility to perform checks where a click/touch event was made outside a component
*/ export const useOnScrollOutside = (options)=>{
const { refs, callback, element, disabled, contains: containsProp } = options;
const listener = useEventCallback((ev)=>{
const contains = containsProp || ((parent, child)=>!!(parent === null || parent === void 0 ? void 0 : parent.contains(child)));
const target = ev.composedPath()[0];
const isOutside = refs.every((ref)=>!contains(ref.current || null, target));
if (isOutside && !disabled) {
callback(ev);
}
});
React.useEffect(()=>{
if (disabled) {
return;
}
element === null || element === void 0 ? void 0 : element.addEventListener('wheel', listener);
element === null || element === void 0 ? void 0 : element.addEventListener('touchmove', listener);
return ()=>{
element === null || element === void 0 ? void 0 : element.removeEventListener('wheel', listener);
element === null || element === void 0 ? void 0 : element.removeEventListener('touchmove', listener);
};
}, [
listener,
element,
disabled
]);
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useOnScrollOutside.ts"],"sourcesContent":["import * as React from 'react';\nimport { useEventCallback } from './useEventCallback';\nimport type { UseOnClickOrScrollOutsideOptions } from './useOnClickOutside';\n\n/**\n * @internal\n * Utility to perform checks where a click/touch event was made outside a component\n */\nexport const useOnScrollOutside = (options: UseOnClickOrScrollOutsideOptions) => {\n const { refs, callback, element, disabled, contains: containsProp } = options;\n\n const listener = useEventCallback((ev: MouseEvent | TouchEvent) => {\n const contains: UseOnClickOrScrollOutsideOptions['contains'] =\n containsProp || ((parent, child) => !!parent?.contains(child));\n\n const target = ev.composedPath()[0] as HTMLElement;\n const isOutside = refs.every(ref => !contains(ref.current || null, target));\n\n if (isOutside && !disabled) {\n callback(ev);\n }\n });\n\n React.useEffect(() => {\n if (disabled) {\n return;\n }\n\n element?.addEventListener('wheel', listener);\n element?.addEventListener('touchmove', listener);\n\n return () => {\n element?.removeEventListener('wheel', listener);\n element?.removeEventListener('touchmove', listener);\n };\n }, [listener, element, disabled]);\n};\n"],"names":["React","useEventCallback","useOnScrollOutside","options","refs","callback","element","disabled","contains","containsProp","listener","ev","parent","child","target","composedPath","isOutside","every","ref","current","useEffect","addEventListener","removeEventListener"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,gBAAgB,QAAQ,qBAAqB;AAGtD;;;CAGC,GACD,OAAO,MAAMC,qBAAqB,CAACC;IACjC,MAAM,EAAEC,IAAI,EAAEC,QAAQ,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,UAAUC,YAAY,EAAE,GAAGN;IAEtE,MAAMO,WAAWT,iBAAiB,CAACU;QACjC,MAAMH,WACJC,gBAAiB,CAAA,CAACG,QAAQC,QAAU,CAAC,EAACD,mBAAAA,6BAAAA,OAAQJ,QAAQ,CAACK,OAAK;QAE9D,MAAMC,SAASH,GAAGI,YAAY,EAAE,CAAC,EAAE;QACnC,MAAMC,YAAYZ,KAAKa,KAAK,CAACC,CAAAA,MAAO,CAACV,SAASU,IAAIC,OAAO,IAAI,MAAML;QAEnE,IAAIE,aAAa,CAACT,UAAU;YAC1BF,SAASM;QACX;IACF;IAEAX,MAAMoB,SAAS,CAAC;QACd,IAAIb,UAAU;YACZ;QACF;QAEAD,oBAAAA,8BAAAA,QAASe,gBAAgB,CAAC,SAASX;QACnCJ,oBAAAA,8BAAAA,QAASe,gBAAgB,CAAC,aAAaX;QAEvC,OAAO;YACLJ,oBAAAA,8BAAAA,QAASgB,mBAAmB,CAAC,SAASZ;YACtCJ,oBAAAA,8BAAAA,QAASgB,mBAAmB,CAAC,aAAaZ;QAC5C;IACF,GAAG;QAACA;QAAUJ;QAASC;KAAS;AAClC,EAAE"}
+12
View File
@@ -0,0 +1,12 @@
import * as React from 'react';
/**
* @internal
*/ export const usePrevious = (value)=>{
const ref = React.useRef(null);
React.useEffect(()=>{
ref.current = value;
}, [
value
]);
return ref.current;
};
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/usePrevious.ts"],"sourcesContent":["import * as React from 'react';\n\n/**\n * @internal\n */\nexport const usePrevious = <ValueType = unknown>(value: ValueType) => {\n const ref = React.useRef<ValueType | null>(null);\n React.useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref.current;\n};\n"],"names":["React","usePrevious","value","ref","useRef","useEffect","current"],"rangeMappings":";;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAE/B;;CAEC,GACD,OAAO,MAAMC,cAAc,CAAsBC;IAC/C,MAAMC,MAAMH,MAAMI,MAAM,CAAmB;IAC3CJ,MAAMK,SAAS,CAAC;QACdF,IAAIG,OAAO,GAAGJ;IAChB,GAAG;QAACA;KAAM;IACV,OAAOC,IAAIG,OAAO;AACpB,EAAE"}
+28
View File
@@ -0,0 +1,28 @@
import * as React from 'react';
const cache = new WeakMap();
/**
* @returns The width in pixels of the scrollbar in the user agent
*/ export function useScrollbarWidth(options) {
const { targetDocument, force } = options;
return React.useMemo(()=>{
if (!targetDocument) {
return 0;
}
if (!force && cache.has(targetDocument)) {
return cache.get(targetDocument);
}
const outer = targetDocument.createElement('div');
outer.style.visibility = 'hidden';
outer.style.overflow = 'scroll';
const inner = targetDocument.createElement('div');
outer.appendChild(inner);
targetDocument.body.appendChild(outer);
const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
outer.remove();
cache.set(targetDocument, scrollbarWidth);
return scrollbarWidth;
}, [
targetDocument,
force
]);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useScrollbarWidth.ts"],"sourcesContent":["import * as React from 'react';\n\nconst cache = new WeakMap<Document, number>();\n\ninterface UseScrollbarWidthOptions {\n /**\n * Reference document to measure the scrollbar width\n */\n targetDocument: Document | null | undefined;\n\n /**\n * Does not use the cache and recalculates the scrollbar width\n */\n force?: boolean;\n}\n\n/**\n * @returns The width in pixels of the scrollbar in the user agent\n */\nexport function useScrollbarWidth(options: UseScrollbarWidthOptions) {\n const { targetDocument, force } = options;\n return React.useMemo(() => {\n if (!targetDocument) {\n return 0;\n }\n\n if (!force && cache.has(targetDocument)) {\n return cache.get(targetDocument);\n }\n\n const outer = targetDocument.createElement('div');\n outer.style.visibility = 'hidden';\n outer.style.overflow = 'scroll';\n\n const inner = targetDocument.createElement('div');\n outer.appendChild(inner);\n\n targetDocument.body.appendChild(outer);\n const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;\n outer.remove();\n cache.set(targetDocument, scrollbarWidth);\n return scrollbarWidth;\n }, [targetDocument, force]);\n}\n"],"names":["React","cache","WeakMap","useScrollbarWidth","options","targetDocument","force","useMemo","has","get","outer","createElement","style","visibility","overflow","inner","appendChild","body","scrollbarWidth","offsetWidth","remove","set"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAE/B,MAAMC,QAAQ,IAAIC;AAclB;;CAEC,GACD,OAAO,SAASC,kBAAkBC,OAAiC;IACjE,MAAM,EAAEC,cAAc,EAAEC,KAAK,EAAE,GAAGF;IAClC,OAAOJ,MAAMO,OAAO,CAAC;QACnB,IAAI,CAACF,gBAAgB;YACnB,OAAO;QACT;QAEA,IAAI,CAACC,SAASL,MAAMO,GAAG,CAACH,iBAAiB;YACvC,OAAOJ,MAAMQ,GAAG,CAACJ;QACnB;QAEA,MAAMK,QAAQL,eAAeM,aAAa,CAAC;QAC3CD,MAAME,KAAK,CAACC,UAAU,GAAG;QACzBH,MAAME,KAAK,CAACE,QAAQ,GAAG;QAEvB,MAAMC,QAAQV,eAAeM,aAAa,CAAC;QAC3CD,MAAMM,WAAW,CAACD;QAElBV,eAAeY,IAAI,CAACD,WAAW,CAACN;QAChC,MAAMQ,iBAAiBR,MAAMS,WAAW,GAAGJ,MAAMI,WAAW;QAC5DT,MAAMU,MAAM;QACZnB,MAAMoB,GAAG,CAAChB,gBAAgBa;QAC1B,OAAOA;IACT,GAAG;QAACb;QAAgBC;KAAM;AAC5B"}
+18
View File
@@ -0,0 +1,18 @@
import { useBrowserTimer } from './useBrowserTimer';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
const setTimeoutNoop = (_callback)=>-1;
const clearTimeoutNoop = (_handle)=>undefined;
/**
* @internal
* Helper to manage a browser timeout.
* Ensures that the timeout isn't set multiple times at once and is cleaned up
* when the component is unloaded.
*
* @returns A pair of [setTimeout, clearTimeout] that are stable between renders.
*/ export function useTimeout() {
const { targetDocument } = useFluent();
const win = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView;
const setTimerFn = win ? win.setTimeout : setTimeoutNoop;
const clearTimerFn = win ? win.clearTimeout : clearTimeoutNoop;
return useBrowserTimer(setTimerFn, clearTimerFn);
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/hooks/useTimeout.ts"],"sourcesContent":["import { useBrowserTimer } from './useBrowserTimer';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\n\nconst setTimeoutNoop = (_callback: Function) => -1;\nconst clearTimeoutNoop = (_handle: number) => undefined;\n\n/**\n * @internal\n * Helper to manage a browser timeout.\n * Ensures that the timeout isn't set multiple times at once and is cleaned up\n * when the component is unloaded.\n *\n * @returns A pair of [setTimeout, clearTimeout] that are stable between renders.\n */\nexport function useTimeout() {\n const { targetDocument } = useFluent();\n const win = targetDocument?.defaultView;\n\n const setTimerFn = win ? win.setTimeout : setTimeoutNoop;\n const clearTimerFn = win ? win.clearTimeout : clearTimeoutNoop;\n\n return useBrowserTimer(setTimerFn, clearTimerFn);\n}\n"],"names":["useBrowserTimer","useFluent_unstable","useFluent","setTimeoutNoop","_callback","clearTimeoutNoop","_handle","undefined","useTimeout","targetDocument","win","defaultView","setTimerFn","setTimeout","clearTimerFn","clearTimeout"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,eAAe,QAAQ,oBAAoB;AACpD,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF,MAAMC,iBAAiB,CAACC,YAAwB,CAAC;AACjD,MAAMC,mBAAmB,CAACC,UAAoBC;AAE9C;;;;;;;CAOC,GACD,OAAO,SAASC;IACd,MAAM,EAAEC,cAAc,EAAE,GAAGP;IAC3B,MAAMQ,MAAMD,2BAAAA,qCAAAA,eAAgBE,WAAW;IAEvC,MAAMC,aAAaF,MAAMA,IAAIG,UAAU,GAAGV;IAC1C,MAAMW,eAAeJ,MAAMA,IAAIK,YAAY,GAAGV;IAE9C,OAAOL,gBAAgBY,YAAYE;AACrC"}
+12
View File
@@ -0,0 +1,12 @@
export { slot, isSlot, // eslint-disable-next-line @typescript-eslint/no-deprecated
getSlots, // eslint-disable-next-line @typescript-eslint/no-deprecated
getSlotsNext, assertSlots, // eslint-disable-next-line @typescript-eslint/no-deprecated
resolveShorthand, isResolvedShorthand, getIntrinsicElementProps, SLOT_ELEMENT_TYPE_SYMBOL, SLOT_RENDER_FUNCTION_SYMBOL } from './compose/index';
export { IdPrefixProvider, resetIdsForTests, useAnimationFrame, useControllableState, useEventCallback, useFirstMount, useForceUpdate, useId, useIsomorphicLayoutEffect, useMergedRefs, useOnClickOutside, useOnScrollOutside, usePrevious, useScrollbarWidth, useTimeout } from './hooks/index';
export { canUseDOM, useIsSSR, SSRProvider } from './ssr/index';
export { clamp, // eslint-disable-next-line @typescript-eslint/no-deprecated
getNativeElementProps, getPartitionedNativeProps, getRTLSafeKey, mergeCallbacks, isHTMLElement, isInteractiveHTMLElement, omit, createPriorityQueue } from './utils/index';
export { applyTriggerPropsToChildren, getTriggerChild, isFluentTrigger } from './trigger/index';
export { isTouchEvent, isMouseEvent, getEventClientCoords } from './events/index';
export { useSelection } from './selection/index';
export { elementContains, setVirtualParent, getParent } from './virtualParent/index';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n slot,\n isSlot,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n getSlots,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n getSlotsNext,\n assertSlots,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n resolveShorthand,\n isResolvedShorthand,\n getIntrinsicElementProps,\n SLOT_ELEMENT_TYPE_SYMBOL,\n SLOT_RENDER_FUNCTION_SYMBOL,\n} from './compose/index';\nexport type {\n ExtractSlotProps,\n ComponentProps,\n ComponentState,\n ForwardRefComponent,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n ResolveShorthandFunction,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n ResolveShorthandOptions,\n Slot,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n Slots,\n SlotClassNames,\n SlotPropsRecord,\n SlotRenderFunction,\n SlotShorthandValue,\n UnknownSlotProps,\n SlotComponentType,\n SlotOptions,\n InferredElementRefType,\n EventData,\n EventHandler,\n} from './compose/index';\n\nexport {\n IdPrefixProvider,\n resetIdsForTests,\n useAnimationFrame,\n useControllableState,\n useEventCallback,\n useFirstMount,\n useForceUpdate,\n useId,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n useOnClickOutside,\n useOnScrollOutside,\n usePrevious,\n useScrollbarWidth,\n useTimeout,\n} from './hooks/index';\nexport type { RefObjectFunction, UseControllableStateOptions, UseOnClickOrScrollOutsideOptions } from './hooks/index';\n\nexport { canUseDOM, useIsSSR, SSRProvider } from './ssr/index';\n\nexport {\n clamp,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n getNativeElementProps,\n getPartitionedNativeProps,\n getRTLSafeKey,\n mergeCallbacks,\n isHTMLElement,\n isInteractiveHTMLElement,\n omit,\n createPriorityQueue,\n} from './utils/index';\n\nexport type { DistributiveOmit, UnionToIntersection } from './utils/types';\n\nexport type { PriorityQueue } from './utils/priorityQueue';\n\nexport { applyTriggerPropsToChildren, getTriggerChild, isFluentTrigger } from './trigger/index';\n\nexport type { FluentTriggerComponent, TriggerProps } from './trigger/index';\n\n/**\n * Event utils\n */\nexport type { NativeTouchOrMouseEvent, ReactTouchOrMouseEvent, TouchOrMouseEvent } from './events/index';\nexport { isTouchEvent, isMouseEvent, getEventClientCoords } from './events/index';\n\nexport type {\n SelectionMode,\n OnSelectionChangeCallback,\n OnSelectionChangeData,\n SelectionItemId,\n SelectionHookParams,\n SelectionMethods,\n} from './selection/index';\nexport { useSelection } from './selection/index';\n\nexport { elementContains, setVirtualParent, getParent } from './virtualParent/index';\n"],"names":["slot","isSlot","getSlots","getSlotsNext","assertSlots","resolveShorthand","isResolvedShorthand","getIntrinsicElementProps","SLOT_ELEMENT_TYPE_SYMBOL","SLOT_RENDER_FUNCTION_SYMBOL","IdPrefixProvider","resetIdsForTests","useAnimationFrame","useControllableState","useEventCallback","useFirstMount","useForceUpdate","useId","useIsomorphicLayoutEffect","useMergedRefs","useOnClickOutside","useOnScrollOutside","usePrevious","useScrollbarWidth","useTimeout","canUseDOM","useIsSSR","SSRProvider","clamp","getNativeElementProps","getPartitionedNativeProps","getRTLSafeKey","mergeCallbacks","isHTMLElement","isInteractiveHTMLElement","omit","createPriorityQueue","applyTriggerPropsToChildren","getTriggerChild","isFluentTrigger","isTouchEvent","isMouseEvent","getEventClientCoords","useSelection","elementContains","setVirtualParent","getParent"],"rangeMappings":";;;;;;;;;;;","mappings":"AAAA,SACEA,IAAI,EACJC,MAAM,EACN,4DAA4D;AAC5DC,QAAQ,EACR,4DAA4D;AAC5DC,YAAY,EACZC,WAAW,EACX,4DAA4D;AAC5DC,gBAAgB,EAChBC,mBAAmB,EACnBC,wBAAwB,EACxBC,wBAAwB,EACxBC,2BAA2B,QACtB,kBAAkB;AAyBzB,SACEC,gBAAgB,EAChBC,gBAAgB,EAChBC,iBAAiB,EACjBC,oBAAoB,EACpBC,gBAAgB,EAChBC,aAAa,EACbC,cAAc,EACdC,KAAK,EACLC,yBAAyB,EACzBC,aAAa,EACbC,iBAAiB,EACjBC,kBAAkB,EAClBC,WAAW,EACXC,iBAAiB,EACjBC,UAAU,QACL,gBAAgB;AAGvB,SAASC,SAAS,EAAEC,QAAQ,EAAEC,WAAW,QAAQ,cAAc;AAE/D,SACEC,KAAK,EACL,4DAA4D;AAC5DC,qBAAqB,EACrBC,yBAAyB,EACzBC,aAAa,EACbC,cAAc,EACdC,aAAa,EACbC,wBAAwB,EACxBC,IAAI,EACJC,mBAAmB,QACd,gBAAgB;AAMvB,SAASC,2BAA2B,EAAEC,eAAe,EAAEC,eAAe,QAAQ,kBAAkB;AAQhG,SAASC,YAAY,EAAEC,YAAY,EAAEC,oBAAoB,QAAQ,iBAAiB;AAUlF,SAASC,YAAY,QAAQ,oBAAoB;AAEjD,SAASC,eAAe,EAAEC,gBAAgB,EAAEC,SAAS,QAAQ,wBAAwB"}
+1
View File
@@ -0,0 +1 @@
export { useSelection } from './useSelection';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/selection/index.ts"],"sourcesContent":["export type {\n OnSelectionChangeCallback,\n OnSelectionChangeData,\n SelectionHookParams,\n SelectionItemId,\n SelectionMethods,\n SelectionMode,\n} from './types';\nexport { useSelection } from './useSelection';\n"],"names":["useSelection"],"rangeMappings":"","mappings":"AAQA,SAASA,YAAY,QAAQ,iBAAiB"}
+1
View File
@@ -0,0 +1 @@
import * as React from 'react';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/selection/types.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type SelectionMode = 'single' | 'multiselect';\n\nexport interface SelectionMethods {\n toggleItem(event: React.SyntheticEvent, id: SelectionItemId): void;\n selectItem(event: React.SyntheticEvent, id: SelectionItemId): void;\n deselectItem(event: React.SyntheticEvent, id: SelectionItemId): void;\n clearItems(event: React.SyntheticEvent): void;\n isSelected(id: SelectionItemId): boolean;\n toggleAllItems(event: React.SyntheticEvent, itemIds: SelectionItemId[]): void;\n}\n\nexport type SelectionItemId = string | number;\n\nexport type OnSelectionChangeCallback = (event: React.SyntheticEvent, selectedItems: Set<SelectionItemId>) => void;\n\nexport type OnSelectionChangeData = {\n selectedItems: Set<SelectionItemId>;\n};\n\nexport type SelectionHookParams = {\n selectionMode: SelectionMode;\n /**\n * Used in uncontrolled mode to set initial selected items on mount\n */\n defaultSelectedItems?: Iterable<SelectionItemId>;\n /**\n * Used to control selected items\n */\n selectedItems?: Iterable<SelectionItemId>;\n /**\n * Called when selection changes\n */\n onSelectionChange?(event: React.SyntheticEvent, data: OnSelectionChangeData): void;\n};\n"],"names":["React"],"rangeMappings":"","mappings":"AAAA,YAAYA,WAAW,QAAQ"}
+104
View File
@@ -0,0 +1,104 @@
import * as React from 'react';
import { useControllableState } from '../hooks/useControllableState';
import { createSetFromIterable } from '../utils/createSetFromIterable';
function useSelectionState(params) {
const [selected, setSelected] = useControllableState({
initialState: new Set(),
defaultState: React.useMemo(()=>params.defaultSelectedItems && createSetFromIterable(params.defaultSelectedItems), [
params.defaultSelectedItems
]),
state: React.useMemo(()=>params.selectedItems && createSetFromIterable(params.selectedItems), [
params.selectedItems
])
});
const changeSelection = (event, nextSelectedItems)=>{
var _params_onSelectionChange;
(_params_onSelectionChange = params.onSelectionChange) === null || _params_onSelectionChange === void 0 ? void 0 : _params_onSelectionChange.call(params, event, {
selectedItems: nextSelectedItems
});
setSelected(nextSelectedItems);
};
return [
selected,
changeSelection
];
}
function useSingleSelection(params) {
const [selected, changeSelection] = useSelectionState(params);
const methods = {
deselectItem: (event)=>changeSelection(event, new Set()),
selectItem: (event, itemId)=>changeSelection(event, new Set([
itemId
])),
toggleAllItems: ()=>{
if (process.env.NODE_ENV !== 'production') {
throw new Error('[react-utilities]: `toggleAllItems` should not be used in single selection mode');
}
},
toggleItem: (event, itemId)=>changeSelection(event, new Set([
itemId
])),
clearItems: (event)=>changeSelection(event, new Set()),
isSelected: (itemId)=>{
var _selected_has;
return (_selected_has = selected.has(itemId)) !== null && _selected_has !== void 0 ? _selected_has : false;
}
};
return [
selected,
methods
];
}
function useMultipleSelection(params) {
const [selected, changeSelection] = useSelectionState(params);
const methods = {
toggleItem: (event, itemId)=>{
const nextSelectedItems = new Set(selected);
if (selected.has(itemId)) {
nextSelectedItems.delete(itemId);
} else {
nextSelectedItems.add(itemId);
}
changeSelection(event, nextSelectedItems);
},
selectItem: (event, itemId)=>{
const nextSelectedItems = new Set(selected);
nextSelectedItems.add(itemId);
changeSelection(event, nextSelectedItems);
},
deselectItem: (event, itemId)=>{
const nextSelectedItems = new Set(selected);
nextSelectedItems.delete(itemId);
changeSelection(event, nextSelectedItems);
},
clearItems: (event)=>{
changeSelection(event, new Set());
},
isSelected: (itemId)=>selected.has(itemId),
toggleAllItems: (event, itemIds)=>{
const allItemsSelected = itemIds.every((itemId)=>selected.has(itemId));
const nextSelectedItems = new Set(selected);
if (allItemsSelected) {
nextSelectedItems.clear();
} else {
itemIds.forEach((itemId)=>nextSelectedItems.add(itemId));
}
changeSelection(event, nextSelectedItems);
}
};
return [
selected,
methods
];
}
export function useSelection(params) {
'use no memo';
if (params.selectionMode === 'multiselect') {
// selectionMode is a static value, so we can safely ignore rules-of-hooks
// eslint-disable-next-line react-hooks/rules-of-hooks
return useMultipleSelection(params);
}
// selectionMode is a static value, so we can safely ignore rules-of-hooks
// eslint-disable-next-line react-hooks/rules-of-hooks
return useSingleSelection(params);
}
File diff suppressed because one or more lines are too long
+59
View File
@@ -0,0 +1,59 @@
import * as React from 'react';
import { canUseDOM } from './canUseDOM';
/**
* Default context value to use in case there is no SSRProvider. This is fine for client-only apps.
*
* @internal
*/ export const defaultSSRContextValue = {
current: 0
};
export const SSRContext = /*#__PURE__*/ React.createContext(undefined);
/**
* @internal
*/ export function useSSRContext() {
var _React_useContext;
return (_React_useContext = React.useContext(SSRContext)) !== null && _React_useContext !== void 0 ? _React_useContext : defaultSSRContextValue;
}
/**
* When using SSR with Fluent UI, applications must be wrapped in an SSRProvider. This ensures that auto generated ids
* are consistent between the client and server.
*
* @public
*/ export const SSRProvider = (props)=>{
const [value] = React.useState(()=>({
current: 0
}));
return /*#__PURE__*/ React.createElement(SSRContext.Provider, {
value: value
}, props.children);
};
/**
* Returns whether the component is currently being server side rendered or hydrated on the client. Can be used to delay
* browser-specific rendering until after hydration. May cause re-renders on a client when is used within SSRProvider.
*/ export function useIsSSR() {
const isInSSRContext = useSSRContext() !== defaultSSRContextValue;
const [isSSR, setIsSSR] = React.useState(isInSSRContext);
// If we are rendering in a non-DOM environment, and there's no SSRProvider, provide a warning to hint to the
// developer to add one.
if (process.env.NODE_ENV !== 'production') {
if (!isInSSRContext && !canUseDOM()) {
// eslint-disable-next-line no-console
console.error(`@fluentui/react-components [${useIsSSR.name}]:
When server rendering, you must wrap your application in an <SSRProvider> to ensure consistent ids are generated between the client and server.
Check documentation at https://aka.ms/fluentui-ssr.`);
}
}
// If on the client, and the component was initially server rendered, then schedule a layout effect to update the
// component after hydration.
if (canUseDOM() && isInSSRContext) {
// This if statement technically breaks the rules of hooks, but is safe because the condition never changes after
// mounting.
// eslint-disable-next-line
React.useLayoutEffect(()=>{
setIsSSR(false);
}, []);
}
return isSSR;
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/ssr/SSRContext.tsx"],"sourcesContent":["import * as React from 'react';\nimport { canUseDOM } from './canUseDOM';\n\n/**\n * To support SSR, the auto incrementing id counter is stored in a context. This allows it to be reset on every request\n * to ensure the client and server are consistent.\n *\n * @internal\n */\nexport type SSRContextValue = {\n current: number;\n};\n\n/**\n * Default context value to use in case there is no SSRProvider. This is fine for client-only apps.\n *\n * @internal\n */\nexport const defaultSSRContextValue: SSRContextValue = {\n current: 0,\n};\n\nexport const SSRContext = React.createContext<SSRContextValue | undefined>(undefined) as React.Context<SSRContextValue>;\n\n/**\n * @internal\n */\nexport function useSSRContext(): SSRContextValue {\n return React.useContext(SSRContext) ?? defaultSSRContextValue;\n}\n\n/**\n * When using SSR with Fluent UI, applications must be wrapped in an SSRProvider. This ensures that auto generated ids\n * are consistent between the client and server.\n *\n * @public\n */\nexport const SSRProvider: React.FC<{ children: React.ReactNode }> = props => {\n const [value] = React.useState<SSRContextValue>(() => ({ current: 0 }));\n\n return <SSRContext.Provider value={value}>{props.children}</SSRContext.Provider>;\n};\n\n/**\n * Returns whether the component is currently being server side rendered or hydrated on the client. Can be used to delay\n * browser-specific rendering until after hydration. May cause re-renders on a client when is used within SSRProvider.\n */\nexport function useIsSSR(): boolean {\n const isInSSRContext = useSSRContext() !== defaultSSRContextValue;\n const [isSSR, setIsSSR] = React.useState(isInSSRContext);\n\n // If we are rendering in a non-DOM environment, and there's no SSRProvider, provide a warning to hint to the\n // developer to add one.\n if (process.env.NODE_ENV !== 'production') {\n if (!isInSSRContext && !canUseDOM()) {\n // eslint-disable-next-line no-console\n console.error(/** #__DE-INDENT__ */ `\n @fluentui/react-components [${useIsSSR.name}]:\n When server rendering, you must wrap your application in an <SSRProvider> to ensure consistent ids are generated between the client and server.\n\n\n Check documentation at https://aka.ms/fluentui-ssr.\n `);\n }\n }\n\n // If on the client, and the component was initially server rendered, then schedule a layout effect to update the\n // component after hydration.\n if (canUseDOM() && isInSSRContext) {\n // This if statement technically breaks the rules of hooks, but is safe because the condition never changes after\n // mounting.\n // eslint-disable-next-line\n React.useLayoutEffect(() => {\n setIsSSR(false);\n }, []);\n }\n\n return isSSR;\n}\n"],"names":["React","canUseDOM","defaultSSRContextValue","current","SSRContext","createContext","undefined","useSSRContext","useContext","SSRProvider","props","value","useState","Provider","children","useIsSSR","isInSSRContext","isSSR","setIsSSR","process","env","NODE_ENV","console","error","name","useLayoutEffect"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,SAAS,QAAQ,cAAc;AAYxC;;;;CAIC,GACD,OAAO,MAAMC,yBAA0C;IACrDC,SAAS;AACX,EAAE;AAEF,OAAO,MAAMC,2BAAaJ,MAAMK,aAAa,CAA8BC,WAA6C;AAExH;;CAEC,GACD,OAAO,SAASC;QACPP;IAAP,OAAOA,CAAAA,oBAAAA,MAAMQ,UAAU,CAACJ,yBAAjBJ,+BAAAA,oBAAgCE;AACzC;AAEA;;;;;CAKC,GACD,OAAO,MAAMO,cAAuDC,CAAAA;IAClE,MAAM,CAACC,MAAM,GAAGX,MAAMY,QAAQ,CAAkB,IAAO,CAAA;YAAET,SAAS;QAAE,CAAA;IAEpE,qBAAO,oBAACC,WAAWS,QAAQ;QAACF,OAAOA;OAAQD,MAAMI,QAAQ;AAC3D,EAAE;AAEF;;;CAGC,GACD,OAAO,SAASC;IACd,MAAMC,iBAAiBT,oBAAoBL;IAC3C,MAAM,CAACe,OAAOC,SAAS,GAAGlB,MAAMY,QAAQ,CAACI;IAEzC,6GAA6G;IAC7G,wBAAwB;IACxB,IAAIG,QAAQC,GAAG,CAACC,QAAQ,KAAK,cAAc;QACzC,IAAI,CAACL,kBAAkB,CAACf,aAAa;YACnC,sCAAsC;YACtCqB,QAAQC,KAAK,CAAuB,CAAC,4BACP,EAAER,SAASS,IAAI,CAAC;;;;mDAK9C,CAAC;QACH;IACF;IAEA,iHAAiH;IACjH,6BAA6B;IAC7B,IAAIvB,eAAee,gBAAgB;QACjC,iHAAiH;QACjH,YAAY;QACZ,2BAA2B;QAC3BhB,MAAMyB,eAAe,CAAC;YACpBP,SAAS;QACX,GAAG,EAAE;IACP;IAEA,OAAOD;AACT"}
+6
View File
@@ -0,0 +1,6 @@
/**
* Verifies if an application can use DOM.
*/ export function canUseDOM() {
return /* eslint-disable @nx/workspace-no-restricted-globals -- expected ignore ( SSR friendly acquisition of globals )*/ typeof window !== 'undefined' && !!(window.document && // eslint-disable-next-line @typescript-eslint/no-deprecated
window.document.createElement);
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/ssr/canUseDOM.ts"],"sourcesContent":["/**\n * Verifies if an application can use DOM.\n */\nexport function canUseDOM(): boolean {\n return (\n /* eslint-disable @nx/workspace-no-restricted-globals -- expected ignore ( SSR friendly acquisition of globals )*/\n typeof window !== 'undefined' &&\n !!(\n window.document &&\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n window.document.createElement\n )\n /* eslint-enable @nx/workspace-no-restricted-globals */\n );\n}\n"],"names":["canUseDOM","window","document","createElement"],"rangeMappings":";;;;;","mappings":"AAAA;;CAEC,GACD,OAAO,SAASA;IACd,OACE,gHAAgH,GAChH,OAAOC,WAAW,eAClB,CAAC,CACCA,CAAAA,OAAOC,QAAQ,IACf,4DAA4D;IAC5DD,OAAOC,QAAQ,CAACC,aAAa,AAAD;AAIlC"}
+2
View File
@@ -0,0 +1,2 @@
export { canUseDOM } from './canUseDOM';
export { SSRContext, SSRProvider, defaultSSRContextValue, useIsSSR, useSSRContext } from './SSRContext';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/ssr/index.ts"],"sourcesContent":["export { canUseDOM } from './canUseDOM';\nexport type { SSRContextValue } from './SSRContext';\nexport { SSRContext, SSRProvider, defaultSSRContextValue, useIsSSR, useSSRContext } from './SSRContext';\n"],"names":["canUseDOM","SSRContext","SSRProvider","defaultSSRContextValue","useIsSSR","useSSRContext"],"rangeMappings":";","mappings":"AAAA,SAASA,SAAS,QAAQ,cAAc;AAExC,SAASC,UAAU,EAAEC,WAAW,EAAEC,sBAAsB,EAAEC,QAAQ,EAAEC,aAAa,QAAQ,eAAe"}
@@ -0,0 +1,30 @@
import * as React from 'react';
import { isFluentTrigger } from './isFluentTrigger';
/**
* @internal
* resolve the trigger props to the children, either by calling the render function, or cloning with the new props.
*/ export function applyTriggerPropsToChildren(children, triggerChildProps) {
if (typeof children === 'function') {
return children(triggerChildProps);
} else if (children) {
return cloneTriggerTree(children, triggerChildProps);
}
// Components in React should return either JSX elements or "null", otherwise React will throw:
// Nothing was returned from render.
// This usually means a return statement is missing. Or, to render nothing, return null.
return children || null;
}
/**
* Clones a React element tree, and applies the given props to the first grandchild that is not
* a FluentTriggerComponent or React Fragment (the same element returned by {@link getTriggerChild}).
*/ function cloneTriggerTree(child, triggerProps) {
if (!React.isValidElement(child) || child.type === React.Fragment) {
throw new Error('A trigger element must be a single element for this component. ' + "Please ensure that you're not using React Fragments.");
}
if (isFluentTrigger(child)) {
const grandchild = cloneTriggerTree(child.props.children, triggerProps);
return React.cloneElement(child, undefined, grandchild);
} else {
return React.cloneElement(child, triggerProps);
}
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/applyTriggerPropsToChildren.ts"],"sourcesContent":["import * as React from 'react';\nimport { isFluentTrigger } from './isFluentTrigger';\nimport type { TriggerProps } from './types';\n\n/**\n * @internal\n * resolve the trigger props to the children, either by calling the render function, or cloning with the new props.\n */\nexport function applyTriggerPropsToChildren<TriggerChildProps>(\n children: TriggerProps<TriggerChildProps>['children'],\n triggerChildProps: TriggerChildProps,\n): React.ReactElement | null {\n if (typeof children === 'function') {\n return children(triggerChildProps);\n } else if (children) {\n return cloneTriggerTree(children, triggerChildProps);\n }\n\n // Components in React should return either JSX elements or \"null\", otherwise React will throw:\n // Nothing was returned from render.\n // This usually means a return statement is missing. Or, to render nothing, return null.\n return children || null;\n}\n\n/**\n * Clones a React element tree, and applies the given props to the first grandchild that is not\n * a FluentTriggerComponent or React Fragment (the same element returned by {@link getTriggerChild}).\n */\nfunction cloneTriggerTree<TriggerChildProps>(\n child: React.ReactNode,\n triggerProps: TriggerChildProps,\n): React.ReactElement {\n if (!React.isValidElement(child) || child.type === React.Fragment) {\n throw new Error(\n 'A trigger element must be a single element for this component. ' +\n \"Please ensure that you're not using React Fragments.\",\n );\n }\n\n if (isFluentTrigger(child)) {\n const grandchild = cloneTriggerTree(child.props.children, triggerProps);\n return React.cloneElement(child, undefined, grandchild);\n } else {\n return React.cloneElement(child, triggerProps as TriggerChildProps & React.Attributes);\n }\n}\n"],"names":["React","isFluentTrigger","applyTriggerPropsToChildren","children","triggerChildProps","cloneTriggerTree","child","triggerProps","isValidElement","type","Fragment","Error","grandchild","props","cloneElement","undefined"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,eAAe,QAAQ,oBAAoB;AAGpD;;;CAGC,GACD,OAAO,SAASC,4BACdC,QAAqD,EACrDC,iBAAoC;IAEpC,IAAI,OAAOD,aAAa,YAAY;QAClC,OAAOA,SAASC;IAClB,OAAO,IAAID,UAAU;QACnB,OAAOE,iBAAiBF,UAAUC;IACpC;IAEA,+FAA+F;IAC/F,sCAAsC;IACtC,0FAA0F;IAC1F,OAAOD,YAAY;AACrB;AAEA;;;CAGC,GACD,SAASE,iBACPC,KAAsB,EACtBC,YAA+B;IAE/B,IAAI,CAACP,MAAMQ,cAAc,CAACF,UAAUA,MAAMG,IAAI,KAAKT,MAAMU,QAAQ,EAAE;QACjE,MAAM,IAAIC,MACR,oEACE;IAEN;IAEA,IAAIV,gBAAgBK,QAAQ;QAC1B,MAAMM,aAAaP,iBAAiBC,MAAMO,KAAK,CAACV,QAAQ,EAAEI;QAC1D,OAAOP,MAAMc,YAAY,CAACR,OAAOS,WAAWH;IAC9C,OAAO;QACL,OAAOZ,MAAMc,YAAY,CAACR,OAAOC;IACnC;AACF"}
+31
View File
@@ -0,0 +1,31 @@
import * as React from 'react';
import { isFluentTrigger } from './isFluentTrigger';
/**
* @internal
* Gets the trigger element of a FluentTriggerComponent (such as Tooltip or MenuTrigger).
*
* In the case where the immediate child is itself a FluentTriggerComponent and/or React Fragment,
* it returns the first descendant that is _not_ a FluentTriggerComponent or Fragment.
* This allows multiple triggers to be stacked, and still apply their props to the actual trigger element.
*
* For example, the following returns `<div id="child" />`:
* ```jsx
* getTriggerChild(
* <Tooltip>
* <MenuTrigger>
* <div id="child" />
* </MenuTrigger>
* </Tooltip>
* );
* ```
*
* In the case where the immediate child is not a valid element,
* null is returned
*/ export function getTriggerChild(children) {
if (!React.isValidElement(children)) {
return null;
}
return isFluentTrigger(children) ? getTriggerChild(// FIXME: This casting should be unnecessary as isFluentTrigger is a guard type method,
// but for some reason it's failing on build
children.props.children) : children;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/getTriggerChild.ts"],"sourcesContent":["import * as React from 'react';\nimport { isFluentTrigger } from './isFluentTrigger';\nimport type { TriggerProps } from './types';\n\n/**\n * @internal\n * Gets the trigger element of a FluentTriggerComponent (such as Tooltip or MenuTrigger).\n *\n * In the case where the immediate child is itself a FluentTriggerComponent and/or React Fragment,\n * it returns the first descendant that is _not_ a FluentTriggerComponent or Fragment.\n * This allows multiple triggers to be stacked, and still apply their props to the actual trigger element.\n *\n * For example, the following returns `<div id=\"child\" />`:\n * ```jsx\n * getTriggerChild(\n * <Tooltip>\n * <MenuTrigger>\n * <div id=\"child\" />\n * </MenuTrigger>\n * </Tooltip>\n * );\n * ```\n *\n * In the case where the immediate child is not a valid element,\n * null is returned\n */\nexport function getTriggerChild<TriggerChildProps>(\n children: TriggerProps<TriggerChildProps>['children'],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): (React.ReactElement<Partial<TriggerChildProps>> & { ref?: React.Ref<any> }) | null {\n if (!React.isValidElement<TriggerChildProps>(children)) {\n return null;\n }\n return isFluentTrigger(children)\n ? getTriggerChild(\n // FIXME: This casting should be unnecessary as isFluentTrigger is a guard type method,\n // but for some reason it's failing on build\n (children.props as TriggerProps).children,\n )\n : children;\n}\n"],"names":["React","isFluentTrigger","getTriggerChild","children","isValidElement","props"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,eAAe,QAAQ,oBAAoB;AAGpD;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,SAASC,gBACdC,QAAqD;IAGrD,IAAI,CAACH,MAAMI,cAAc,CAAoBD,WAAW;QACtD,OAAO;IACT;IACA,OAAOF,gBAAgBE,YACnBD,gBAGE,AAFA,uFAAuF;IACvF,4CAA4C;IAC3CC,SAASE,KAAK,CAAkBF,QAAQ,IAE3CA;AACN"}
+3
View File
@@ -0,0 +1,3 @@
export { applyTriggerPropsToChildren } from './applyTriggerPropsToChildren';
export { getTriggerChild } from './getTriggerChild';
export { isFluentTrigger } from './isFluentTrigger';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/index.ts"],"sourcesContent":["export { applyTriggerPropsToChildren } from './applyTriggerPropsToChildren';\nexport { getTriggerChild } from './getTriggerChild';\nexport { isFluentTrigger } from './isFluentTrigger';\nexport type { FluentTriggerComponent, TriggerProps } from './types';\n"],"names":["applyTriggerPropsToChildren","getTriggerChild","isFluentTrigger"],"rangeMappings":";;","mappings":"AAAA,SAASA,2BAA2B,QAAQ,gCAAgC;AAC5E,SAASC,eAAe,QAAQ,oBAAoB;AACpD,SAASC,eAAe,QAAQ,oBAAoB"}
@@ -0,0 +1,8 @@
import * as React from 'react';
/**
* @internal
* Checks if a given element is a FluentUI trigger (e.g. `MenuTrigger` or `Tooltip`).
* See the {@link FluentTriggerComponent} type for more info.
*/ export function isFluentTrigger(element) {
return Boolean(element.type.isFluentTriggerComponent);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/isFluentTrigger.ts"],"sourcesContent":["import * as React from 'react';\nimport type { FluentTriggerComponent, TriggerProps } from './types';\n\n/**\n * @internal\n * Checks if a given element is a FluentUI trigger (e.g. `MenuTrigger` or `Tooltip`).\n * See the {@link FluentTriggerComponent} type for more info.\n */\nexport function isFluentTrigger(element: React.ReactElement): element is React.ReactElement<TriggerProps> {\n return Boolean((element.type as FluentTriggerComponent).isFluentTriggerComponent);\n}\n"],"names":["React","isFluentTrigger","element","Boolean","type","isFluentTriggerComponent"],"rangeMappings":";;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAG/B;;;;CAIC,GACD,OAAO,SAASC,gBAAgBC,OAA2B;IACzD,OAAOC,QAAQ,AAACD,QAAQE,IAAI,CAA4BC,wBAAwB;AAClF"}
+1
View File
@@ -0,0 +1 @@
import * as React from 'react';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/trigger/types.ts"],"sourcesContent":["import * as React from 'react';\n\n/**\n * @internal\n * Allows a component to be tagged as a FluentUI trigger component.\n *\n * Triggers are special-case components: they attach event listeners and other props on their child,\n * and use them to trigger another component to show. Examples include `MenuTrigger` and `Tooltip`.\n *\n * A component can be tagged as a trigger as follows:\n * ```ts\n * const MyComponent: React.FC<MyComponentProps> & FluentTriggerComponent = ...;\n *\n * MyComponent.isFluentTriggerComponent = true; // MUST also set this to true\n * ```\n */\nexport type FluentTriggerComponent = {\n isFluentTriggerComponent?: boolean;\n};\n\n/**\n * A trigger may have a children that could be either:\n * 1. A single element\n * 2. A render function that will receive properties and must return a valid element or null\n * 3. null or undefined\n */\nexport type TriggerProps<TriggerChildProps = unknown> = {\n children?: React.ReactElement | ((props: TriggerChildProps) => React.ReactElement | null) | null;\n};\n"],"names":["React"],"rangeMappings":"","mappings":"AAAA,YAAYA,WAAW,QAAQ"}
+8
View File
@@ -0,0 +1,8 @@
/**
* @internal
* Clamps `value` to a number between the min and max.
*
* @param value - the value to be clamped
* @param min - the lowest valid value
* @param max - the highest valid value
*/ export const clamp = (value, min, max)=>Math.max(min, Math.min(max, value || 0));
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/clamp.ts"],"sourcesContent":["/**\n * @internal\n * Clamps `value` to a number between the min and max.\n *\n * @param value - the value to be clamped\n * @param min - the lowest valid value\n * @param max - the highest valid value\n */\nexport const clamp = (value: number, min: number, max: number): number => Math.max(min, Math.min(max, value || 0));\n"],"names":["clamp","value","min","max","Math"],"rangeMappings":";;;;;;;","mappings":"AAAA;;;;;;;CAOC,GACD,OAAO,MAAMA,QAAQ,CAACC,OAAeC,KAAaC,MAAwBC,KAAKD,GAAG,CAACD,KAAKE,KAAKF,GAAG,CAACC,KAAKF,SAAS,IAAI"}
@@ -0,0 +1,5 @@
/**
* Creates a set from a given iterable, in case the iterable is a set itself, returns the given set instead.
*/ export function createSetFromIterable(iterable) {
return iterable instanceof Set ? iterable : new Set(iterable);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/createSetFromIterable.ts"],"sourcesContent":["/**\n * Creates a set from a given iterable, in case the iterable is a set itself, returns the given set instead.\n */\nexport function createSetFromIterable<V>(iterable: Iterable<V>): Set<V> {\n return iterable instanceof Set ? iterable : new Set(iterable);\n}\n"],"names":["createSetFromIterable","iterable","Set"],"rangeMappings":";;;;","mappings":"AAAA;;CAEC,GACD,OAAO,SAASA,sBAAyBC,QAAqB;IAC5D,OAAOA,oBAAoBC,MAAMD,WAAW,IAAIC,IAAID;AACtD"}
@@ -0,0 +1,62 @@
import * as React from 'react';
import { labelProperties, audioProperties, videoProperties, olProperties, liProperties, anchorProperties, buttonProperties, inputProperties, textAreaProperties, selectProperties, optionProperties, tableProperties, trProperties, thProperties, tdProperties, colGroupProperties, colProperties, fieldsetProperties, formProperties, iframeProperties, imgProperties, htmlElementProperties, getNativeProps, timeProperties, dialogProperties } from './properties';
const nativeElementMap = {
label: labelProperties,
audio: audioProperties,
video: videoProperties,
ol: olProperties,
li: liProperties,
a: anchorProperties,
button: buttonProperties,
input: inputProperties,
textarea: textAreaProperties,
select: selectProperties,
option: optionProperties,
table: tableProperties,
tr: trProperties,
th: thProperties,
td: tdProperties,
colGroup: colGroupProperties,
col: colProperties,
fieldset: fieldsetProperties,
form: formProperties,
iframe: iframeProperties,
img: imgProperties,
time: timeProperties,
dialog: dialogProperties
};
/**
* Given an element tagname and user props, filters the props to only allowed props for the given
* element type.
* @param tagName - Tag name (e.g. "div")
* @param props - Props object
* @param excludedPropNames - List of props to disallow
*
* @deprecated use getIntrinsicElementProps instead, it is a type-safe version of this method
*/ // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getNativeElementProps(tagName, props, excludedPropNames) {
const allowedPropNames = tagName && nativeElementMap[tagName] || htmlElementProperties;
allowedPropNames.as = 1;
return getNativeProps(props, allowedPropNames, excludedPropNames);
}
/**
* Splits the native props into ones that go to the `root` slot, and ones that go to the primary slot.
*
* This function is only for use with components that have a primary slot other than `root`.
* Most components should use {@link getNativeElementProps} for their root slot if it is the primary slot.
*
* @returns An object containing the native props for the `root` and primary slots.
*/ export const getPartitionedNativeProps = ({ primarySlotTagName, props, excludedPropNames })=>{
return {
root: {
style: props.style,
className: props.className
},
// eslint-disable-next-line @typescript-eslint/no-deprecated
primary: getNativeElementProps(primarySlotTagName, props, [
...excludedPropNames || [],
'style',
'className'
])
};
};
File diff suppressed because one or more lines are too long
+18
View File
@@ -0,0 +1,18 @@
/**
* @internal
* Finds and swaps a provided key for it's right to left format.
*/ export const getRTLSafeKey = (key, dir)=>{
if (dir === 'rtl') {
switch(key){
case 'ArrowLeft':
{
return 'ArrowRight';
}
case 'ArrowRight':
{
return 'ArrowLeft';
}
}
}
return key;
};
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/getRTLSafeKey.ts"],"sourcesContent":["/**\n * @internal\n * Finds and swaps a provided key for it's right to left format.\n */\nexport const getRTLSafeKey = (key: string, dir: 'ltr' | 'rtl') => {\n if (dir === 'rtl') {\n switch (key) {\n case 'ArrowLeft': {\n return 'ArrowRight';\n }\n\n case 'ArrowRight': {\n return 'ArrowLeft';\n }\n }\n }\n\n return key;\n};\n"],"names":["getRTLSafeKey","key","dir"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AAAA;;;CAGC,GACD,OAAO,MAAMA,gBAAgB,CAACC,KAAaC;IACzC,IAAIA,QAAQ,OAAO;QACjB,OAAQD;YACN,KAAK;gBAAa;oBAChB,OAAO;gBACT;YAEA,KAAK;gBAAc;oBACjB,OAAO;gBACT;QACF;IACF;IAEA,OAAOA;AACT,EAAE"}
@@ -0,0 +1,23 @@
import * as React from 'react';
/**
* React.SyntheticEvent contains name of a callback that should be fired, this function returns it.
*
* Ideally, it should also distinguish regular and "capture" callbacks, but it's possible only with React 17 as
* ".eventPhase" there has proper value, see https://github.com/facebook/react/pull/19244. In React 16 all events
* are handled in bubble phase.
*/ export function getReactCallbackName(event) {
if (event._reactName) {
return event._reactName;
}
if (event.dispatchConfig) {
if (event.dispatchConfig.registrationName) {
return event.dispatchConfig.registrationName;
}
return event.dispatchConfig.phasedRegistrationNames.bubbled;
}
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.error(`@fluentui/react-utilities [${getReactCallbackName.name}]:
Passed React.SyntheticEvent does not contain ".dispatchConfig" or "._reactName". This should not happen, please report it to https://github.com/microsoft/fluentui.`);
}
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/getReactCallbackName.ts"],"sourcesContent":["import * as React from 'react';\n\ninterface ReactSyntheticEvent extends React.SyntheticEvent<unknown> {\n // React 17/18\n // See https://github.com/facebook/react/pull/19236\n _reactName?: string;\n\n // React 16\n dispatchConfig?: {\n registrationName: string;\n phasedRegistrationNames: {\n bubbled: string;\n captured: string;\n };\n };\n}\n\ntype NonUndefined<A> = A extends undefined ? never : A;\ntype FunctionKeys<T extends object> = {\n [K in keyof T]-?: NonUndefined<T[K]> extends Function ? K : never;\n}[keyof T];\n\nexport type ReactCallbackName = FunctionKeys<React.DOMAttributes<unknown>>;\n\n/**\n * React.SyntheticEvent contains name of a callback that should be fired, this function returns it.\n *\n * Ideally, it should also distinguish regular and \"capture\" callbacks, but it's possible only with React 17 as\n * \".eventPhase\" there has proper value, see https://github.com/facebook/react/pull/19244. In React 16 all events\n * are handled in bubble phase.\n */\nexport function getReactCallbackName(event: ReactSyntheticEvent): ReactCallbackName | undefined {\n if (event._reactName) {\n return event._reactName as ReactCallbackName;\n }\n\n if (event.dispatchConfig) {\n if (event.dispatchConfig.registrationName) {\n return event.dispatchConfig.registrationName as ReactCallbackName;\n }\n\n return event.dispatchConfig.phasedRegistrationNames.bubbled as ReactCallbackName;\n }\n\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line no-console\n console.error(/** #__DE-INDENT__ */ `\n @fluentui/react-utilities [${getReactCallbackName.name}]:\n Passed React.SyntheticEvent does not contain \".dispatchConfig\" or \"._reactName\". This should not happen, please report it to https://github.com/microsoft/fluentui.\n `);\n }\n}\n"],"names":["React","getReactCallbackName","event","_reactName","dispatchConfig","registrationName","phasedRegistrationNames","bubbled","process","env","NODE_ENV","console","error","name"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAwB/B;;;;;;CAMC,GACD,OAAO,SAASC,qBAAqBC,KAA0B;IAC7D,IAAIA,MAAMC,UAAU,EAAE;QACpB,OAAOD,MAAMC,UAAU;IACzB;IAEA,IAAID,MAAME,cAAc,EAAE;QACxB,IAAIF,MAAME,cAAc,CAACC,gBAAgB,EAAE;YACzC,OAAOH,MAAME,cAAc,CAACC,gBAAgB;QAC9C;QAEA,OAAOH,MAAME,cAAc,CAACE,uBAAuB,CAACC,OAAO;IAC7D;IAEA,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,cAAc;QACzC,sCAAsC;QACtCC,QAAQC,KAAK,CAAuB,CAAC,2BACR,EAAEX,qBAAqBY,IAAI,CAAC;mKAEzD,CAAC;IACH;AACF"}
+10
View File
@@ -0,0 +1,10 @@
export { clamp } from './clamp';
export { // eslint-disable-next-line @typescript-eslint/no-deprecated
getNativeElementProps, getPartitionedNativeProps } from './getNativeElementProps';
export { getRTLSafeKey } from './getRTLSafeKey';
export { mergeCallbacks } from './mergeCallbacks';
export { omit } from './omit';
export { anchorProperties, audioProperties, baseElementEvents, baseElementProperties, buttonProperties, colGroupProperties, colProperties, dialogProperties, divProperties, fieldsetProperties, formProperties, getNativeProps, htmlElementProperties, iframeProperties, imgProperties, inputProperties, labelProperties, liProperties, microdataProperties, olProperties, optionProperties, selectProperties, tableProperties, tdProperties, textAreaProperties, thProperties, timeProperties, trProperties, videoProperties } from './properties';
export { isHTMLElement } from './isHTMLElement';
export { isInteractiveHTMLElement } from './isInteractiveHTMLElement';
export { createPriorityQueue } from './priorityQueue';
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/index.ts"],"sourcesContent":["export { clamp } from './clamp';\nexport {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n getNativeElementProps,\n getPartitionedNativeProps,\n} from './getNativeElementProps';\nexport { getRTLSafeKey } from './getRTLSafeKey';\nexport { mergeCallbacks } from './mergeCallbacks';\nexport { omit } from './omit';\nexport {\n anchorProperties,\n audioProperties,\n baseElementEvents,\n baseElementProperties,\n buttonProperties,\n colGroupProperties,\n colProperties,\n dialogProperties,\n divProperties,\n fieldsetProperties,\n formProperties,\n getNativeProps,\n htmlElementProperties,\n iframeProperties,\n imgProperties,\n inputProperties,\n labelProperties,\n liProperties,\n microdataProperties,\n olProperties,\n optionProperties,\n selectProperties,\n tableProperties,\n tdProperties,\n textAreaProperties,\n thProperties,\n timeProperties,\n trProperties,\n videoProperties,\n} from './properties';\nexport { isHTMLElement } from './isHTMLElement';\nexport { isInteractiveHTMLElement } from './isInteractiveHTMLElement';\nexport type { PriorityQueue, PriorityQueueCompareFn } from './priorityQueue';\nexport { createPriorityQueue } from './priorityQueue';\n"],"names":["clamp","getNativeElementProps","getPartitionedNativeProps","getRTLSafeKey","mergeCallbacks","omit","anchorProperties","audioProperties","baseElementEvents","baseElementProperties","buttonProperties","colGroupProperties","colProperties","dialogProperties","divProperties","fieldsetProperties","formProperties","getNativeProps","htmlElementProperties","iframeProperties","imgProperties","inputProperties","labelProperties","liProperties","microdataProperties","olProperties","optionProperties","selectProperties","tableProperties","tdProperties","textAreaProperties","thProperties","timeProperties","trProperties","videoProperties","isHTMLElement","isInteractiveHTMLElement","createPriorityQueue"],"rangeMappings":";;;;;;;;;","mappings":"AAAA,SAASA,KAAK,QAAQ,UAAU;AAChC,SACE,4DAA4D;AAC5DC,qBAAqB,EACrBC,yBAAyB,QACpB,0BAA0B;AACjC,SAASC,aAAa,QAAQ,kBAAkB;AAChD,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,IAAI,QAAQ,SAAS;AAC9B,SACEC,gBAAgB,EAChBC,eAAe,EACfC,iBAAiB,EACjBC,qBAAqB,EACrBC,gBAAgB,EAChBC,kBAAkB,EAClBC,aAAa,EACbC,gBAAgB,EAChBC,aAAa,EACbC,kBAAkB,EAClBC,cAAc,EACdC,cAAc,EACdC,qBAAqB,EACrBC,gBAAgB,EAChBC,aAAa,EACbC,eAAe,EACfC,eAAe,EACfC,YAAY,EACZC,mBAAmB,EACnBC,YAAY,EACZC,gBAAgB,EAChBC,gBAAgB,EAChBC,eAAe,EACfC,YAAY,EACZC,kBAAkB,EAClBC,YAAY,EACZC,cAAc,EACdC,YAAY,EACZC,eAAe,QACV,eAAe;AACtB,SAASC,aAAa,QAAQ,kBAAkB;AAChD,SAASC,wBAAwB,QAAQ,6BAA6B;AAEtE,SAASC,mBAAmB,QAAQ,kBAAkB"}
+19
View File
@@ -0,0 +1,19 @@
/**
* Verifies if a given node is an HTMLElement,
* this method works seamlessly with frames and elements from different documents
*
* This is preferred over simply using `instanceof`.
* Since `instanceof` might be problematic while operating with [multiple realms](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof#instanceof_and_multiple_realms)
*
* @example
* ```ts
* isHTMLElement(event.target) && event.target.focus()
* isHTMLElement(event.target, {constructorName: 'HTMLInputElement'}) && event.target.value // some value
* ```
*
*/ export function isHTMLElement(element, options) {
var _typedElement_ownerDocument;
const typedElement = element;
var _options_constructorName;
return Boolean((typedElement === null || typedElement === void 0 ? void 0 : (_typedElement_ownerDocument = typedElement.ownerDocument) === null || _typedElement_ownerDocument === void 0 ? void 0 : _typedElement_ownerDocument.defaultView) && typedElement instanceof typedElement.ownerDocument.defaultView[(_options_constructorName = options === null || options === void 0 ? void 0 : options.constructorName) !== null && _options_constructorName !== void 0 ? _options_constructorName : 'HTMLElement']);
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/isHTMLElement.ts"],"sourcesContent":["/**\n * Verifies if a given node is an HTMLElement,\n * this method works seamlessly with frames and elements from different documents\n *\n * This is preferred over simply using `instanceof`.\n * Since `instanceof` might be problematic while operating with [multiple realms](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof#instanceof_and_multiple_realms)\n *\n * @example\n * ```ts\n * isHTMLElement(event.target) && event.target.focus()\n * isHTMLElement(event.target, {constructorName: 'HTMLInputElement'}) && event.target.value // some value\n * ```\n *\n */\nexport function isHTMLElement<ConstructorName extends HTMLElementConstructorName = 'HTMLElement'>(\n element?: unknown,\n options?: {\n /**\n * Can be used to provide a custom constructor instead of `HTMLElement`,\n * Like `HTMLInputElement` for example.\n */\n constructorName?: ConstructorName;\n },\n): element is InstanceType<(typeof globalThis)[ConstructorName]> {\n const typedElement = element as Node | null | undefined;\n return Boolean(\n typedElement?.ownerDocument?.defaultView &&\n typedElement instanceof typedElement.ownerDocument.defaultView[options?.constructorName ?? 'HTMLElement'],\n );\n}\n\ntype HTMLElementConstructorName =\n | 'HTMLElement'\n | 'HTMLAnchorElement'\n | 'HTMLAreaElement'\n | 'HTMLAudioElement'\n | 'HTMLBaseElement'\n | 'HTMLBodyElement'\n | 'HTMLBRElement'\n | 'HTMLButtonElement'\n | 'HTMLCanvasElement'\n | 'HTMLDataElement'\n | 'HTMLDataListElement'\n | 'HTMLDetailsElement'\n // NOTE: dialog is not supported in safari 14, also it was removed from lib-dom starting typescript 4.4\n // | 'HTMLDialogElement'\n | 'HTMLDivElement'\n | 'HTMLDListElement'\n | 'HTMLEmbedElement'\n | 'HTMLFieldSetElement'\n | 'HTMLFormElement'\n | 'HTMLHeadingElement'\n | 'HTMLHeadElement'\n | 'HTMLHRElement'\n | 'HTMLHtmlElement'\n | 'HTMLIFrameElement'\n | 'HTMLImageElement'\n | 'HTMLInputElement'\n | 'HTMLModElement'\n | 'HTMLLabelElement'\n | 'HTMLLegendElement'\n | 'HTMLLIElement'\n | 'HTMLLinkElement'\n | 'HTMLMapElement'\n | 'HTMLMetaElement'\n | 'HTMLMeterElement'\n | 'HTMLObjectElement'\n | 'HTMLOListElement'\n | 'HTMLOptGroupElement'\n | 'HTMLOptionElement'\n | 'HTMLOutputElement'\n | 'HTMLParagraphElement'\n | 'HTMLParamElement'\n | 'HTMLPreElement'\n | 'HTMLProgressElement'\n | 'HTMLQuoteElement'\n | 'HTMLSlotElement'\n | 'HTMLScriptElement'\n | 'HTMLSelectElement'\n | 'HTMLSourceElement'\n | 'HTMLSpanElement'\n | 'HTMLStyleElement'\n | 'HTMLTableElement'\n | 'HTMLTableColElement'\n | 'HTMLTableRowElement'\n | 'HTMLTableSectionElement'\n | 'HTMLTemplateElement'\n | 'HTMLTextAreaElement'\n | 'HTMLTimeElement'\n | 'HTMLTitleElement'\n | 'HTMLTrackElement'\n | 'HTMLUListElement'\n | 'HTMLVideoElement';\n"],"names":["isHTMLElement","element","options","typedElement","Boolean","ownerDocument","defaultView","constructorName"],"rangeMappings":";;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASA,cACdC,OAAiB,EACjBC,OAMC;QAICC;IAFF,MAAMA,eAAeF;QAG8CC;IAFnE,OAAOE,QACLD,CAAAA,yBAAAA,oCAAAA,8BAAAA,aAAcE,aAAa,cAA3BF,kDAAAA,4BAA6BG,WAAW,KACtCH,wBAAwBA,aAAaE,aAAa,CAACC,WAAW,CAACJ,CAAAA,2BAAAA,oBAAAA,8BAAAA,QAASK,eAAe,cAAxBL,sCAAAA,2BAA4B,cAAc;AAE/G"}
@@ -0,0 +1,18 @@
import { isHTMLElement } from './isHTMLElement';
/**
* @internal
* Checks that the element has default behaviour from user input on click or 'Enter'/'Space' keys
*/ export function isInteractiveHTMLElement(element) {
if (!isHTMLElement(element)) {
return false;
}
const { tagName } = element;
switch(tagName){
case 'BUTTON':
case 'A':
case 'INPUT':
case 'TEXTAREA':
return true;
}
return element.isContentEditable;
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/isInteractiveHTMLElement.ts"],"sourcesContent":["import { isHTMLElement } from './isHTMLElement';\n\n/**\n * @internal\n * Checks that the element has default behaviour from user input on click or 'Enter'/'Space' keys\n */\nexport function isInteractiveHTMLElement(element: unknown) {\n if (!isHTMLElement(element)) {\n return false;\n }\n\n const { tagName } = element;\n switch (tagName) {\n case 'BUTTON':\n case 'A':\n case 'INPUT':\n case 'TEXTAREA':\n return true;\n }\n\n return element.isContentEditable;\n}\n"],"names":["isHTMLElement","isInteractiveHTMLElement","element","tagName","isContentEditable"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,aAAa,QAAQ,kBAAkB;AAEhD;;;CAGC,GACD,OAAO,SAASC,yBAAyBC,OAAgB;IACvD,IAAI,CAACF,cAAcE,UAAU;QAC3B,OAAO;IACT;IAEA,MAAM,EAAEC,OAAO,EAAE,GAAGD;IACpB,OAAQC;QACN,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;YACH,OAAO;IACX;IAEA,OAAOD,QAAQE,iBAAiB;AAClC"}
+28
View File
@@ -0,0 +1,28 @@
/**
* @internal
* Combine two event callbacks into a single callback function that calls each one in order.
*
* Usage example:
* ```ts
* state.slot.onChange = mergeCallbacks(state.slot.onChange, ev => {
* // Handle onChange
* });
* ```
*
* The primary use is to avoid the need to capture an existing callback (`state.slot.onChange` in the example) to a
* local variable before replacing with a new listener that calls the existing one. This helps avoid bugs like:
* * Infinite recursion by calling the re-assigned state.slot.onChange if it's not captured to a local variable.
* * Missing a call to the original onChange due to an early return or other conditional.
*
* If you need a callback that is stable between renders, wrap the result in {@link useEventCallback}.
*
* @param callback1 - The first callback to be called, or undefined
* @param callback2 - The second callback to be called, or undefined
*
* @returns A function that that calls the provided functions in order
*/ export function mergeCallbacks(callback1, callback2) {
return (...args)=>{
callback1 === null || callback1 === void 0 ? void 0 : callback1(...args);
callback2 === null || callback2 === void 0 ? void 0 : callback2(...args);
};
}
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/mergeCallbacks.ts"],"sourcesContent":["/**\n * @internal\n * Combine two event callbacks into a single callback function that calls each one in order.\n *\n * Usage example:\n * ```ts\n * state.slot.onChange = mergeCallbacks(state.slot.onChange, ev => {\n * // Handle onChange\n * });\n * ```\n *\n * The primary use is to avoid the need to capture an existing callback (`state.slot.onChange` in the example) to a\n * local variable before replacing with a new listener that calls the existing one. This helps avoid bugs like:\n * * Infinite recursion by calling the re-assigned state.slot.onChange if it's not captured to a local variable.\n * * Missing a call to the original onChange due to an early return or other conditional.\n *\n * If you need a callback that is stable between renders, wrap the result in {@link useEventCallback}.\n *\n * @param callback1 - The first callback to be called, or undefined\n * @param callback2 - The second callback to be called, or undefined\n *\n * @returns A function that that calls the provided functions in order\n */\nexport function mergeCallbacks<Args extends unknown[]>(\n callback1: ((...args: Args) => void) | undefined,\n callback2: ((...args: Args) => void) | undefined,\n) {\n return (...args: Args) => {\n callback1?.(...args);\n callback2?.(...args);\n };\n}\n"],"names":["mergeCallbacks","callback1","callback2","args"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,OAAO,SAASA,eACdC,SAAgD,EAChDC,SAAgD;IAEhD,OAAO,CAAC,GAAGC;QACTF,sBAAAA,gCAAAA,aAAeE;QACfD,sBAAAA,gCAAAA,aAAeC;IACjB;AACF"}
+23
View File
@@ -0,0 +1,23 @@
/**
* Tiny helper to do the minimal amount of work in duplicating an object but omitting some
* props. This ends up faster than using object ...rest or reduce to filter.
*
* This behaves very much like filteredAssign, but does not merge many objects together,
* uses an exclusion object map, and avoids spreads all for optimal performance.
*
* See perf test for background:
* https://jsperf.com/omit-vs-rest-vs-reduce/1
*
* @param obj - The object to clone
* @param exclusions - The array of keys to exclude
*/ // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function omit(obj, exclusions) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = {};
for(const key in obj){
if (exclusions.indexOf(key) === -1 && obj.hasOwnProperty(key)) {
result[key] = obj[key];
}
}
return result;
}
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils/omit.ts"],"sourcesContent":["/**\n * Tiny helper to do the minimal amount of work in duplicating an object but omitting some\n * props. This ends up faster than using object ...rest or reduce to filter.\n *\n * This behaves very much like filteredAssign, but does not merge many objects together,\n * uses an exclusion object map, and avoids spreads all for optimal performance.\n *\n * See perf test for background:\n * https://jsperf.com/omit-vs-rest-vs-reduce/1\n *\n * @param obj - The object to clone\n * @param exclusions - The array of keys to exclude\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function omit<TObj extends Record<string, any>, Exclusions extends (keyof TObj)[]>(\n obj: TObj,\n exclusions: Exclusions,\n): Omit<TObj, Exclusions[number]> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result: Record<string, any> = {};\n\n for (const key in obj) {\n if (exclusions.indexOf(key) === -1 && obj.hasOwnProperty(key)) {\n result[key] = obj[key];\n }\n }\n\n return result as TObj;\n}\n"],"names":["omit","obj","exclusions","result","key","indexOf","hasOwnProperty"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;;;;;;;;CAYC,GACD,8DAA8D;AAC9D,OAAO,SAASA,KACdC,GAAS,EACTC,UAAsB;IAEtB,8DAA8D;IAC9D,MAAMC,SAA8B,CAAC;IAErC,IAAK,MAAMC,OAAOH,IAAK;QACrB,IAAIC,WAAWG,OAAO,CAACD,SAAS,CAAC,KAAKH,IAAIK,cAAc,CAACF,MAAM;YAC7DD,MAAM,CAACC,IAAI,GAAGH,GAAG,CAACG,IAAI;QACxB;IACF;IAEA,OAAOD;AACT"}

Some files were not shown because too many files have changed in this diff Show More