@fluentui/react-northstar
Version:
A themable React component library.
223 lines (217 loc) • 9.95 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.providerClassName = exports.Provider = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _noop2 = _interopRequireDefault(require("lodash/noop"));
var _isBoolean2 = _interopRequireDefault(require("lodash/isBoolean"));
var _isFunction2 = _interopRequireDefault(require("lodash/isFunction"));
var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
var _isPlainObject2 = _interopRequireDefault(require("lodash/isPlainObject"));
var _reactBindings = require("@fluentui/react-bindings");
var _styles = require("@fluentui/styles");
var PropTypes = _interopRequireWildcard(require("prop-types"));
var React = _interopRequireWildcard(require("react"));
var _utils = require("../../utils");
var _mergeProviderContexts = require("../../utils/mergeProviderContexts");
var _ProviderConsumer = require("./ProviderConsumer");
var _portalContext = require("./portalContext");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
var renderFontFaces = function renderFontFaces(renderer, theme) {
if (!theme.fontFaces) {
return;
}
var renderFontObject = function renderFontObject(font) {
if (!(0, _isPlainObject2.default)(font)) {
throw new Error("fontFaces must be objects, got: " + typeof font);
}
renderer.renderFont(font);
};
theme.fontFaces.forEach(function (font) {
renderFontObject(font);
});
};
var renderStaticStyles = function renderStaticStyles(renderer, theme, siteVariables) {
if (!theme.staticStyles) {
return;
}
var renderObject = function renderObject(object) {
(0, _forEach2.default)(object, function (style, selector) {
renderer.renderGlobal(style, selector);
});
};
theme.staticStyles.forEach(function (staticStyle) {
if (typeof staticStyle === 'string') {
renderer.renderGlobal(staticStyle);
} else if ((0, _isPlainObject2.default)(staticStyle)) {
renderObject(staticStyle);
} else if ((0, _isFunction2.default)(staticStyle)) {
var preparedSiteVariables = (0, _styles.mergeSiteVariables)(undefined, siteVariables);
renderObject(staticStyle(preparedSiteVariables));
} else {
throw new Error("staticStyles array must contain CSS strings, style objects, or style functions, got: " + typeof staticStyle);
}
});
};
var providerClassName = 'ui-provider';
/**
* The Provider passes the CSS-in-JS renderer, theme styles and other settings to Fluent UI components.
*/
exports.providerClassName = providerClassName;
var Provider = function Provider(props) {
var children = props.children,
className = props.className,
design = props.design,
overwrite = props.overwrite,
styles = props.styles,
variables = props.variables,
telemetryRef = props.telemetryRef;
var ElementType = (0, _reactBindings.getElementType)(props);
var unhandledProps = (0, _reactBindings.useUnhandledProps)(Provider.handledProps, props);
var rendersReactFragment = ElementType === React.Fragment;
var telemetry = React.useMemo(function () {
if (!telemetryRef) {
return undefined;
}
if (!telemetryRef.current) {
telemetryRef.current = new _reactBindings.Telemetry();
}
return telemetryRef.current;
}, [telemetryRef]);
var consumedContext = (0, _reactBindings.useFluentContext)();
var incomingContext = overwrite ? _reactBindings.defaultContextValue : consumedContext;
var createRenderer = React.useContext(_reactBindings.RendererContext);
// Memoization of `inputContext` & `outgoingContext` is required to avoid useless notifications of components that
// consume `useFluentContext()` on each render
// @see https://reactjs.org/docs/context.html#caveats
var inputContext = React.useMemo(function () {
return {
disableAnimations: props.disableAnimations,
performance: props.performance,
rtl: props.rtl,
target: props.target,
telemetry: telemetry,
theme: props.theme
};
}, [props.disableAnimations, props.performance, props.rtl, props.target, telemetry, props.theme]);
var outgoingContext = React.useMemo(function () {
return (0, _mergeProviderContexts.mergeProviderContexts)(createRenderer, incomingContext, inputContext);
}, [createRenderer, incomingContext, inputContext]);
var rtlProps = {};
// only add dir attribute for top level provider or when direction changes from parent to child
if (consumedContext.rtl !== outgoingContext.rtl && (0, _isBoolean2.default)(outgoingContext.rtl)) {
rtlProps.dir = outgoingContext.rtl ? 'rtl' : 'ltr';
}
// Perf optimisation
// Do not invoke styling layer is there is no need
var _ref = rendersReactFragment ? {
classes: {
root: ''
}
} : (0, _reactBindings.unstable_getStyles)({
allDisplayNames: [Provider.displayName],
className: providerClassName,
primaryDisplayName: Provider.displayName,
componentProps: {},
inlineStylesProps: {
className: className,
design: design,
styles: styles,
variables: variables
},
disableAnimations: outgoingContext.disableAnimations,
performance: outgoingContext.performance,
renderer: outgoingContext.renderer,
rtl: outgoingContext.rtl,
theme: outgoingContext.theme,
saveDebug: _noop2.default,
telemetry: undefined
}),
classes = _ref.classes;
var portalContextValue = React.useMemo(function () {
return {
className: classes.root
};
}, [classes.root]);
var RenderProvider = outgoingContext.renderer.Provider;
(0, _reactBindings.useIsomorphicLayoutEffect)(function () {
renderFontFaces(outgoingContext.renderer, props.theme);
renderStaticStyles(outgoingContext.renderer, props.theme, outgoingContext.theme.siteVariables);
if (props.target) {
(0, _utils.setUpWhatInput)(props.target);
}
outgoingContext.renderer.registerUsage();
return function () {
if (props.target) {
(0, _utils.tryCleanupWhatInput)(props.target);
}
outgoingContext.renderer.unregisterUsage();
};
}, []);
// If a Fragment is rendered:
// - do not spread anything to an element - React.Fragment can only have `key` and `children` props
// - as we don't apply styles "PortalContext.Provider" should not be rendered
if (rendersReactFragment) {
return /*#__PURE__*/React.createElement(RenderProvider, {
target: outgoingContext.target
}, /*#__PURE__*/React.createElement(_reactBindings.Unstable_FluentContextProvider, {
value: outgoingContext
}, /*#__PURE__*/React.createElement(React.Fragment, null, children)));
}
return /*#__PURE__*/React.createElement(RenderProvider, {
target: outgoingContext.target
}, /*#__PURE__*/React.createElement(_reactBindings.Unstable_FluentContextProvider, {
value: outgoingContext
}, /*#__PURE__*/React.createElement(_portalContext.PortalContext.Provider, {
value: portalContextValue
}, /*#__PURE__*/React.createElement(ElementType, (0, _extends2.default)({
className: classes.root
}, rtlProps, unhandledProps), children))));
};
exports.Provider = Provider;
Provider.displayName = 'Provider';
Provider.defaultProps = {
theme: {}
};
Provider.propTypes = {
as: PropTypes.elementType,
design: PropTypes.object,
variables: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
styles: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
theme: PropTypes.shape({
siteVariables: PropTypes.object,
componentVariables: PropTypes.object,
componentStyles: PropTypes.objectOf(PropTypes.any),
fontFaces: PropTypes.arrayOf(PropTypes.exact({
name: PropTypes.string.isRequired,
paths: PropTypes.arrayOf(PropTypes.string),
props: PropTypes.shape({
fontStretch: PropTypes.string,
fontStyle: PropTypes.string,
fontVariant: PropTypes.string,
fontWeight: PropTypes.number,
localAlias: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
unicodeRange: PropTypes.string
})
})),
staticStyles: PropTypes.array,
animations: PropTypes.objectOf(PropTypes.any)
}),
rtl: PropTypes.bool,
disableAnimations: PropTypes.bool,
// Heads Up!
// Keep in sync with packages/react-bindings/src/styles/types.ts
performance: PropTypes.shape({
enableSanitizeCssPlugin: PropTypes.bool,
enableStylesCaching: PropTypes.bool,
enableVariablesCaching: PropTypes.bool
}),
children: PropTypes.node.isRequired,
overwrite: PropTypes.bool,
target: PropTypes.object,
telemetryRef: PropTypes.object
};
Provider.handledProps = Object.keys(Provider.propTypes);
Provider.Consumer = _ProviderConsumer.ProviderConsumer;
//# sourceMappingURL=Provider.js.map