76 lines
3.0 KiB
JavaScript
76 lines
3.0 KiB
JavaScript
import * as React from 'react';
|
|
import { TABSTER_ATTRIBUTE_NAME } from 'tabster';
|
|
/**
|
|
* Merges a collection of tabster attributes.
|
|
*
|
|
* ⚠️The attributes passed as arguments to this hook cannot change at runtime.
|
|
* @internal
|
|
* @param attributes - collection of tabster attributes from other react-tabster hooks
|
|
* @returns single merged tabster attribute
|
|
*/ export const useMergedTabsterAttributes_unstable = (...attributes)=>{
|
|
'use no memo';
|
|
const stringAttributes = attributes.reduce((acc, curr)=>{
|
|
if (curr === null || curr === void 0 ? void 0 : curr[TABSTER_ATTRIBUTE_NAME]) {
|
|
acc.push(curr[TABSTER_ATTRIBUTE_NAME]);
|
|
}
|
|
return acc;
|
|
}, []);
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
// ignoring rules of hooks because this is a condition based on the environment
|
|
// it's safe to ignore the rule
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
useWarnIfUnstableAttributes(stringAttributes);
|
|
}
|
|
return React.useMemo(()=>({
|
|
[TABSTER_ATTRIBUTE_NAME]: stringAttributes.length > 0 ? stringAttributes.reduce(mergeJSONStrings) : undefined
|
|
}), // disable exhaustive-deps because we want to memoize the result of the reduction
|
|
// this is safe because the collection of attributes is not expected to change at runtime
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
stringAttributes);
|
|
};
|
|
/**
|
|
* Merges two JSON strings into one.
|
|
*/ const mergeJSONStrings = (a, b)=>JSON.stringify(Object.assign(safelyParseJSON(a), safelyParseJSON(b)));
|
|
/**
|
|
* Tries to parse a JSON string and returns an object.
|
|
* If the JSON string is invalid, an empty object is returned.
|
|
*/ const safelyParseJSON = (json)=>{
|
|
try {
|
|
return JSON.parse(json);
|
|
} catch {
|
|
return {};
|
|
}
|
|
};
|
|
/**
|
|
* Helper hook that ensures that the attributes passed to the hook are stable.
|
|
* This is necessary because the attributes are expected to not change at runtime.
|
|
*
|
|
* This hook will console.warn if the attributes change at runtime.
|
|
*/ const useWarnIfUnstableAttributes = (attributes)=>{
|
|
'use no memo';
|
|
const initialAttributesRef = React.useRef(attributes);
|
|
let isStable = initialAttributesRef.current.length === attributes.length;
|
|
if (initialAttributesRef.current !== attributes && isStable) {
|
|
for(let i = 0; i < attributes.length; i++){
|
|
if (initialAttributesRef.current[i] !== attributes[i]) {
|
|
isStable = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
React.useEffect(()=>{
|
|
if (!isStable) {
|
|
const error = new Error();
|
|
// eslint-disable-next-line no-console
|
|
console.warn(/** #__DE-INDENT__ */ `
|
|
@fluentui/react-tabster [useMergedTabsterAttributes]:
|
|
The attributes passed to the hook changed at runtime.
|
|
This might lead to unexpected behavior, please ensure that the attributes are stable.
|
|
${error.stack}
|
|
`);
|
|
}
|
|
}, [
|
|
isStable
|
|
]);
|
|
};
|