@itwin/itwinui-react
Version:
A react component library for iTwinUI
339 lines (338 loc) • 11.3 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', {
value: true,
});
Object.defineProperty(exports, 'ThemeProvider', {
enumerable: true,
get: function () {
return ThemeProvider;
},
});
const _interop_require_default = require('@swc/helpers/_/_interop_require_default');
const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard');
const _react = /*#__PURE__*/ _interop_require_wildcard._(require('react'));
const _reactdom = /*#__PURE__*/ _interop_require_wildcard._(
require('react-dom'),
);
const _classnames = /*#__PURE__*/ _interop_require_default._(
require('classnames'),
);
const _index = require('../../utils/index.js');
const _ThemeContext = require('./ThemeContext.js');
const _Toaster = require('../Toast/Toaster.js');
const _meta = require('../../utils/meta.js');
const versionWithoutDots = _meta.meta.version.replace(/\./g, '');
const OwnerDocumentContext = _react.createContext(void 0);
const ThemeProvider = _react.forwardRef((props, forwardedRef) => {
var _themeOptions, _themeOptions1;
let {
theme: themeProp = 'inherit',
children,
themeOptions = {},
portalContainer: portalContainerProp,
includeCss = 'inherit' === themeProp,
future: futureProp = {},
...rest
} = props;
useInertPolyfill();
let [rootElement, setRootElement] = _react.useState(null);
let parent = useParentThemeAndContext(rootElement);
let theme = 'inherit' === themeProp ? parent.theme || 'light' : themeProp;
(_themeOptions = themeOptions).applyBackground ??
(_themeOptions.applyBackground = !parent.theme);
(_themeOptions1 = themeOptions).highContrast ??
(_themeOptions1.highContrast =
'inherit' === themeProp ? parent.highContrast : void 0);
let portalContainerFromParent = _react.useContext(
_index.PortalContainerContext,
);
let themeContextValue = _react.useMemo(
() => ({
theme,
themeOptions,
}),
[theme, JSON.stringify(themeOptions)],
);
let [portalContainer, setPortalContainer] = _react.useState(
portalContainerProp || null,
);
return _react.createElement(
_index.FutureFlagsProvider,
{
value: futureProp,
},
_react.createElement(
_index.PortalContainerContext.Provider,
{
value: portalContainer,
},
_react.createElement(
_index.HydrationProvider,
null,
_react.createElement(
_ThemeContext.ThemeContext.Provider,
{
value: themeContextValue,
},
_react.createElement(
_Toaster.ToastProvider,
{
inherit: 'inherit' === themeProp && !portalContainerProp,
},
includeCss && rootElement
? _react.createElement(FallbackStyles, {
root: rootElement,
})
: null,
_react.createElement(
MainRoot,
{
theme: theme,
themeOptions: themeOptions,
ref: (0, _index.useMergedRefs)(
forwardedRef,
setRootElement,
useIuiDebugRef,
),
...rest,
},
children,
_react.createElement(PortalContainer, {
theme: theme,
themeOptions: themeOptions,
portalContainerProp: portalContainerProp,
portalContainerFromParent: portalContainerFromParent,
setPortalContainer: setPortalContainer,
isInheritingTheme: 'inherit' === themeProp,
}),
),
),
),
),
),
);
});
if ('development' === process.env.NODE_ENV)
ThemeProvider.displayName = 'ThemeProvider';
const MainRoot = _react.forwardRef((props, forwardedRef) => {
let [ownerDocument, setOwnerDocument] = _react.useState(void 0);
let findOwnerDocumentFromRef = _react.useCallback(
(el) => {
if (el && el.ownerDocument !== ownerDocument)
setOwnerDocument(el.ownerDocument);
},
[ownerDocument, setOwnerDocument],
);
return _react.createElement(
OwnerDocumentContext.Provider,
{
value: ownerDocument,
},
_react.createElement(Root, {
...props,
ref: (0, _index.useMergedRefs)(findOwnerDocumentFromRef, forwardedRef),
}),
);
});
const Root = _react.forwardRef((props, forwardedRef) => {
let { theme, children, themeOptions, className, ...rest } = props;
let prefersDark = (0, _index.useMediaQuery)('(prefers-color-scheme: dark)');
let prefersHighContrast = (0, _index.useMediaQuery)(
'(prefers-contrast: more)',
);
let shouldApplyDark = 'dark' === theme || ('os' === theme && prefersDark);
let shouldApplyHC = themeOptions?.highContrast ?? prefersHighContrast;
let shouldApplyBackground = themeOptions?.applyBackground;
let themeBridge = (0, _index.useFutureFlag)('themeBridge');
return _react.createElement(
_index.Box,
{
className: (0, _classnames.default)(
'iui-root',
{
'iui-root-background': shouldApplyBackground,
},
className,
),
'data-iui-theme': shouldApplyDark ? 'dark' : 'light',
'data-iui-contrast': shouldApplyHC ? 'high' : 'default',
'data-iui-bridge': themeBridge ? 'true' : void 0,
ref: forwardedRef,
...rest,
},
children,
);
});
const useParentThemeAndContext = (rootElement) => {
let parentContext = _react.useContext(_ThemeContext.ThemeContext);
let [parentThemeState, setParentTheme] = _react.useState(
parentContext?.theme,
);
let [parentHighContrastState, setParentHighContrastState] = _react.useState(
parentContext?.themeOptions?.highContrast,
);
let parentThemeRef = (0, _index.useLatestRef)(parentContext?.theme);
(0, _index.useLayoutEffect)(() => {
if (parentThemeRef.current) return;
let closestRoot = rootElement?.parentElement?.closest('[data-iui-theme]');
if (!closestRoot) return;
let synchronizeTheme = () => {
setParentTheme(closestRoot?.getAttribute('data-iui-theme'));
setParentHighContrastState(
closestRoot?.getAttribute('data-iui-contrast') === 'high',
);
};
synchronizeTheme();
let observer = new MutationObserver(() => synchronizeTheme());
observer.observe(closestRoot, {
attributes: true,
attributeFilter: ['data-iui-theme', 'data-iui-contrast'],
});
return () => {
observer.disconnect();
};
}, [rootElement, parentThemeRef]);
return {
theme: parentContext?.theme ?? parentThemeState,
highContrast:
parentContext?.themeOptions?.highContrast ?? parentHighContrastState,
context: parentContext,
};
};
const PortalContainer = _react.memo(
({
portalContainerProp,
portalContainerFromParent,
setPortalContainer,
isInheritingTheme,
theme,
themeOptions,
}) => {
let ownerDocument = _react.useContext(OwnerDocumentContext);
let shouldSetupPortalContainer =
!portalContainerProp &&
(!isInheritingTheme ||
!portalContainerFromParent ||
(!!ownerDocument &&
portalContainerFromParent.ownerDocument !== ownerDocument));
let id = (0, _index.useId)();
_react.useEffect(() => {
if (shouldSetupPortalContainer) return;
let portalTarget = portalContainerProp || portalContainerFromParent;
if (portalTarget) setPortalContainer(portalTarget);
}, [
portalContainerProp,
portalContainerFromParent,
shouldSetupPortalContainer,
setPortalContainer,
]);
let isHydrated = 'hydrated' === (0, _index.useHydration)();
if (!isHydrated) return null;
if (shouldSetupPortalContainer && ownerDocument)
return _reactdom.createPortal(
_react.createElement(
Root,
{
theme: theme,
themeOptions: {
...themeOptions,
applyBackground: false,
},
'data-iui-portal': true,
style: {
display: 'contents',
},
ref: setPortalContainer,
id: id,
},
_react.createElement(_Toaster.Toaster, null),
),
ownerDocument.body,
);
if (portalContainerProp)
return _reactdom.createPortal(
_react.createElement(_Toaster.Toaster, null),
portalContainerProp,
);
return null;
},
);
const FallbackStyles = ({ root }) => {
(0, _index.useLayoutEffect)(() => {
if (
'yes' ===
getComputedStyle(root).getPropertyValue(`--_iui-v${versionWithoutDots}`)
)
return;
if (_index.isUnitTest) return;
(async () => {
try {
await Promise.resolve().then(() =>
/*#__PURE__*/ _interop_require_wildcard._(
require('../../../styles.css'),
),
);
} catch (error) {
console.log('Error loading styles.css locally', error);
let css = await (0, _index.importCss)(
`https://cdn.jsdelivr.net/npm/@itwin/itwinui-react@${_meta.meta.version}/styles.css`,
);
document.adoptedStyleSheets = [
...document.adoptedStyleSheets,
css.default,
];
}
})();
}, [root]);
return _react.createElement(_react.Fragment, null);
};
const useIuiDebugRef = () => {
var _globalThis;
let _globalThis1 = globalThis;
(_globalThis = _globalThis1).__iui ||
(_globalThis.__iui = {
versions: new Set(),
});
if ('development' === process.env.NODE_ENV && !_index.isUnitTest)
_globalThis1.__iui.versions.add = (version) => {
Set.prototype.add.call(_globalThis1.__iui.versions, version);
if (_globalThis1.__iui.versions.size > 1) {
_globalThis1.__iui._shouldWarn = true;
if (_globalThis1.__iui._warnTimeout)
clearTimeout(_globalThis1.__iui._warnTimeout);
_globalThis1.__iui._warnTimeout = setTimeout(() => {
if (_globalThis1.__iui._shouldWarn) {
console.warn(
"Multiple versions of iTwinUI were detected on this page. This can lead to unexpected behavior and duplicated code in the bundle. Make sure you're using a single iTwinUI instance across your app. https://github.com/iTwin/iTwinUI/wiki/Version-conflicts",
);
console.groupCollapsed('iTwinUI versions detected:');
let versionsTable = [];
_globalThis1.__iui.versions.forEach((version) => {
versionsTable.push(JSON.parse(version));
});
console.table(versionsTable);
console.groupEnd();
_globalThis1.__iui._shouldWarn = false;
}
}, 3000);
}
};
_globalThis1.__iui.versions.add(JSON.stringify(_meta.meta));
};
const useInertPolyfill = () => {
let loaded = _react.useRef(false);
let modulePath =
'https://cdn.jsdelivr.net/npm/wicg-inert@3.1.2/dist/inert.min.js';
_react.useEffect(() => {
(async () => {
if (
!HTMLElement.prototype.hasOwnProperty('inert') &&
!loaded.current &&
!_index.isUnitTest
) {
await new Function('url', 'return import(url)')(modulePath);
loaded.current = true;
}
})();
}, []);
};