'use client'; import { useRenderer_unstable } from '@griffel/react'; import { useFocusVisible } from '@fluentui/react-tabster'; import { ThemeContext_unstable as ThemeContext, useFluent_unstable as useFluent, useOverrides_unstable as useOverrides, CustomStyleHooksContext_unstable as CustomStyleHooksContext } from '@fluentui/react-shared-contexts'; import { getIntrinsicElementProps, useMergedRefs, slot } from '@fluentui/react-utilities'; import * as React from 'react'; import { useFluentProviderThemeStyleTag } from './useFluentProviderThemeStyleTag'; // Meomizing empty objects to avoid unnecessary rerenders. const DEFAULT_STYLE_HOOKS = {}; const DEFAULT_RENDERER_ATTRIBUTES = {}; /** * Create the state required to render FluentProvider. * * The returned state can be modified with hooks such as useFluentProviderStyles_unstable, * before being passed to renderFluentProvider_unstable. * * @param props - props from this instance of FluentProvider * @param ref - reference to root HTMLElement of FluentProvider */ export const useFluentProvider_unstable = (props, ref)=>{ 'use no memo'; const parentContext = useFluent(); const parentTheme = useTheme(); const parentOverrides = useOverrides(); const parentCustomStyleHooks = React.useContext(CustomStyleHooksContext) || DEFAULT_STYLE_HOOKS; /** * TODO: add merge functions to "dir" merge, * nesting providers with the same "dir" should not add additional attributes to DOM * see https://github.com/microsoft/fluentui/blob/0dc74a19f3aa5a058224c20505016fbdb84db172/packages/fluentui/react-northstar/src/utils/mergeProviderContexts.ts#L89-L93 */ const { applyStylesToPortals = true, // eslint-disable-next-line @typescript-eslint/naming-convention customStyleHooks_unstable, dir = parentContext.dir, targetDocument = parentContext.targetDocument, theme, overrides_unstable: overrides = {} } = props; const mergedTheme = shallowMerge(parentTheme, theme); const mergedOverrides = shallowMerge(parentOverrides, overrides); const mergedCustomStyleHooks = shallowMerge(parentCustomStyleHooks, customStyleHooks_unstable); const renderer = useRenderer_unstable(); var _renderer_styleElementAttributes; const { styleTagId, rule } = useFluentProviderThemeStyleTag({ theme: mergedTheme, targetDocument, rendererAttributes: (_renderer_styleElementAttributes = renderer.styleElementAttributes) !== null && _renderer_styleElementAttributes !== void 0 ? _renderer_styleElementAttributes : DEFAULT_RENDERER_ATTRIBUTES }); if (process.env.NODE_ENV !== 'production') { // eslint-disable-next-line react-hooks/rules-of-hooks React.useEffect(()=>{ if (mergedTheme === undefined) { // eslint-disable-next-line no-console console.warn([ '@fluentui/react-provider: FluentProvider does not have your "theme" defined.', "Make sure that your top-level FluentProvider has set a `theme` prop or you're setting the theme in your child FluentProvider." ].join(' ')); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); } return { applyStylesToPortals, // eslint-disable-next-line @typescript-eslint/naming-convention customStyleHooks_unstable: mergedCustomStyleHooks, dir, targetDocument, theme: mergedTheme, // eslint-disable-next-line @typescript-eslint/naming-convention overrides_unstable: mergedOverrides, themeClassName: styleTagId, components: { root: 'div' }, root: slot.always(getIntrinsicElementProps('div', { ...props, dir, // FIXME: // `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement` // but since it would be a breaking change to fix it, we are casting ref to it's proper type ref: useMergedRefs(ref, useFocusVisible({ targetDocument })) }), { elementType: 'div' }), serverStyleProps: { cssRule: rule, attributes: { ...renderer.styleElementAttributes, id: styleTagId } } }; }; function shallowMerge(a, b) { // Merge impacts perf: we should like to avoid it if it's possible if (a && b) { return { ...a, ...b }; } if (a) { return a; } return b; } function useTheme() { return React.useContext(ThemeContext); }