@atlaskit/app-provider
Version:
A top level provider for the Design System.
207 lines (205 loc) • 11.1 kB
JavaScript
/* index.tsx generated by @compiled/babel-plugin v3.0.2 */
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ThemeProvider = ThemeProvider;
require("./index.compiled.css");
var _runtime = require("@compiled/react/runtime");
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _bindEventListener = require("bind-event-listener");
var _constants = require("@atlaskit/tokens/constants");
var _getThemeHtmlAttrs = require("@atlaskit/tokens/get-theme-html-attrs");
var _setGlobalTheme = require("@atlaskit/tokens/set-global-theme");
var _useIsAppProviderThemingEnabled = require("../use-is-app-provider-theming-enabled");
var _useIsInsideAppProvider = require("../use-is-inside-app-provider");
var _colorMode = require("./context/color-mode");
var _insideThemeProvider = require("./context/inside-theme-provider");
var _setColorModeContext = require("./context/set-color-mode-context");
var _theme = require("./context/theme");
var _useIsInsideThemeProvider = require("./hooks/use-is-inside-theme-provider");
var _loadAndMountThemes = require("./utils/load-and-mount-themes");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var defaultThemeSettings = {
dark: 'dark',
light: 'light',
shape: 'shape',
spacing: 'spacing',
typography: 'typography'
};
var isMatchMediaAvailable = typeof window !== 'undefined' && 'matchMedia' in window;
var prefersDarkModeMql = isMatchMediaAvailable ? window.matchMedia('(prefers-color-scheme: dark)') : undefined;
// TODO: currently 'auto' color mode will always return 'light' in SSR.
// Additional work required: https://product-fabric.atlassian.net/browse/DSP-9781
function getReconciledColorMode(colorMode) {
if (colorMode === 'auto') {
return prefersDarkModeMql !== null && prefersDarkModeMql !== void 0 && prefersDarkModeMql.matches ? 'dark' : 'light';
}
return colorMode;
}
var contentStyles = {
body: "_1e0c1bgi"
};
/**
* __Theme provider__
*
* Provides global theming configuration.
*/
function ThemeProvider(_ref) {
var children = _ref.children,
_ref$defaultColorMode = _ref.defaultColorMode,
defaultColorMode = _ref$defaultColorMode === void 0 ? 'auto' : _ref$defaultColorMode,
defaultTheme = _ref.defaultTheme;
var _useState = (0, _react.useState)(defaultColorMode),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
chosenColorMode = _useState2[0],
setChosenColorMode = _useState2[1];
var _useState3 = (0, _react.useState)(getReconciledColorMode(defaultColorMode)),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
reconciledColorMode = _useState4[0],
setReconciledColorMode = _useState4[1];
var _useState5 = (0, _react.useState)(function () {
return _objectSpread(_objectSpread({}, defaultThemeSettings), defaultTheme);
}),
_useState6 = (0, _slicedToArray2.default)(_useState5, 2),
theme = _useState6[0],
setTheme = _useState6[1];
var setColorMode = (0, _react.useCallback)(function (colorMode) {
setChosenColorMode(colorMode);
setReconciledColorMode(getReconciledColorMode(colorMode));
}, []);
var setPartialTheme = (0, _react.useCallback)(function (nextTheme) {
setTheme(function (theme) {
return _objectSpread(_objectSpread({}, theme), nextTheme);
});
}, []);
var lastSetGlobalThemePromiseRef = (0, _react.useRef)(null);
var isInsideAppProvider = (0, _useIsInsideAppProvider.useIsInsideAppProvider)();
var isAppProviderThemingEnabled = (0, _useIsAppProviderThemingEnabled.useIsAppProviderThemingEnabled)();
var isInsideThemeProvider = (0, _useIsInsideThemeProvider.useIsInsideThemeProvider)();
/**
* A top-level ThemeProvider is detected by being the first ThemeProvider inside an AppProvider.
*
* This will not use sub-tree theming but instead set the global theme state using the
* `@atlaskit/tokens` APIs, as it's required for styling root `html` and `body` elements
* for compatibility with `@atlaskit/css-reset`.
*
* In the future we could consider moving away from DOM mutations and require AppProvider to wrap
* `html` in order to apply global theme state, which would allow a more consistent approach to
* theme loading.
*/
var isRootThemeProvider = isInsideAppProvider && !isInsideThemeProvider && isAppProviderThemingEnabled;
(0, _react.useEffect)(function () {
if (isRootThemeProvider) {
/**
* We need to wait for any previous `setGlobalTheme` calls to finish before calling it again.
* This is to prevent race conditions as `setGlobalTheme` is async and mutates the DOM (e.g. sets the
* `data-color-mode` attribute on the root element).
*
* Since we can't safely abort the `setGlobalTheme` execution, we need to wait for it to properly finish before
* applying the new theme.
*
* Without this, we can end up in the following scenario:
* 1. app loads with the default 'light' theme, kicking off `setGlobalTheme`
* 2. app switches to 'dark' theme after retrieving value persisted in local storage, calling `setGlobalTheme` again
* 3. `setGlobalTheme` function execution for `dark` finishes before the initial `light` execution
* 4. `setGlobalTheme` function execution for `light` then finishes, resulting in the 'light' theme being applied.
*/
var cleanupLastFnCall = /*#__PURE__*/function () {
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
var unbindFn;
return _regenerator.default.wrap(function (_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
if (!lastSetGlobalThemePromiseRef.current) {
_context.next = 2;
break;
}
_context.next = 1;
return lastSetGlobalThemePromiseRef.current;
case 1:
unbindFn = _context.sent;
unbindFn();
lastSetGlobalThemePromiseRef.current = null;
case 2:
case "end":
return _context.stop();
}
}, _callee);
}));
return function cleanupLastFnCall() {
return _ref2.apply(this, arguments);
};
}();
var safelySetGlobalTheme = /*#__PURE__*/function () {
var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
var promise;
return _regenerator.default.wrap(function (_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 1;
return cleanupLastFnCall();
case 1:
promise = (0, _setGlobalTheme.setGlobalTheme)(_objectSpread(_objectSpread({}, theme), {}, {
colorMode: reconciledColorMode
}));
lastSetGlobalThemePromiseRef.current = promise;
case 2:
case "end":
return _context2.stop();
}
}, _callee2);
}));
return function safelySetGlobalTheme() {
return _ref3.apply(this, arguments);
};
}();
safelySetGlobalTheme();
return function cleanup() {
cleanupLastFnCall();
};
}
// For other theme providers (whether outside AppProvider or nested inside a ThemeProvider),
// we treat them as sub-tree themes that do not load global theme state.
(0, _loadAndMountThemes.loadAndMountThemes)(theme);
}, [isInsideAppProvider, isInsideThemeProvider, isRootThemeProvider, reconciledColorMode, theme]);
(0, _react.useEffect)(function () {
if (!prefersDarkModeMql) {
return;
}
var unbindListener = (0, _bindEventListener.bind)(prefersDarkModeMql, {
type: 'change',
listener: function listener(event) {
if (chosenColorMode === 'auto') {
setReconciledColorMode(event.matches ? 'dark' : 'light');
}
}
});
return unbindListener;
}, [chosenColorMode]);
var attrs = _objectSpread(_objectSpread({}, (0, _getThemeHtmlAttrs.getThemeHtmlAttrs)(_objectSpread(_objectSpread({}, theme), {}, {
colorMode: reconciledColorMode
}))), {}, (0, _defineProperty2.default)({}, _constants.SUBTREE_THEME_ATTRIBUTE, true));
return /*#__PURE__*/_react.default.createElement(_insideThemeProvider.InsideThemeProviderContext.Provider, {
value: true
}, /*#__PURE__*/_react.default.createElement(_colorMode.ColorModeContext.Provider, {
value: reconciledColorMode
}, /*#__PURE__*/_react.default.createElement(_setColorModeContext.SetColorModeContext.Provider, {
value: setColorMode
}, /*#__PURE__*/_react.default.createElement(_theme.ThemeContext.Provider, {
value: theme
}, /*#__PURE__*/_react.default.createElement(_theme.SetThemeContext.Provider, {
value: setPartialTheme
}, !isRootThemeProvider ? /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({}, attrs, {
className: (0, _runtime.ax)([contentStyles.body])
}), children) : children)))));
}