@primer/react
Version:
An implementation of GitHub's Primer Design System using React
234 lines (220 loc) • 9.32 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var reactCompilerRuntime = require('react-compiler-runtime');
var React = require('react');
var ReactDOM = require('react-dom');
var styled = require('styled-components');
var theme = require('./theme.js');
var merge = require('deepmerge');
var useSyncedState = require('./hooks/useSyncedState.js');
var jsxRuntime = require('react/jsx-runtime');
var useId = require('./hooks/useId.js');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var React__default = /*#__PURE__*/_interopDefault(React);
var ReactDOM__default = /*#__PURE__*/_interopDefault(ReactDOM);
var merge__default = /*#__PURE__*/_interopDefault(merge);
const defaultColorMode = 'day';
const defaultDayScheme = 'light';
const defaultNightScheme = 'dark';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ThemeContext = /*#__PURE__*/React__default.default.createContext({
setColorMode: () => null,
setDayScheme: () => null,
setNightScheme: () => null
});
// inspired from __NEXT_DATA__, we use application/json to avoid CSRF policy with inline scripts
const getServerHandoff = id => {
try {
var _document$getElementB;
const serverData = (_document$getElementB = document.getElementById(`__PRIMER_DATA_${id}__`)) === null || _document$getElementB === void 0 ? void 0 : _document$getElementB.textContent;
if (serverData) return JSON.parse(serverData);
} catch (_error) {
// if document/element does not exist or JSON is invalid, supress error
}
return {};
};
const ThemeProvider = ({
children,
...props
}) => {
var _ref, _props$theme, _ref2, _props$colorMode, _ref3, _props$dayScheme, _ref4, _props$nightScheme;
// Get fallback values from parent ThemeProvider (if exists)
const {
theme: fallbackTheme,
colorMode: fallbackColorMode,
dayScheme: fallbackDayScheme,
nightScheme: fallbackNightScheme
} = useTheme();
// Initialize state
const theme$1 = (_ref = (_props$theme = props.theme) !== null && _props$theme !== void 0 ? _props$theme : fallbackTheme) !== null && _ref !== void 0 ? _ref : theme;
const uniqueDataId = useId.useId();
const {
resolvedServerColorMode
} = getServerHandoff(uniqueDataId);
const resolvedColorModePassthrough = React__default.default.useRef(resolvedServerColorMode);
const [colorMode, setColorMode] = useSyncedState.useSyncedState((_ref2 = (_props$colorMode = props.colorMode) !== null && _props$colorMode !== void 0 ? _props$colorMode : fallbackColorMode) !== null && _ref2 !== void 0 ? _ref2 : defaultColorMode);
const [dayScheme, setDayScheme] = useSyncedState.useSyncedState((_ref3 = (_props$dayScheme = props.dayScheme) !== null && _props$dayScheme !== void 0 ? _props$dayScheme : fallbackDayScheme) !== null && _ref3 !== void 0 ? _ref3 : defaultDayScheme);
const [nightScheme, setNightScheme] = useSyncedState.useSyncedState((_ref4 = (_props$nightScheme = props.nightScheme) !== null && _props$nightScheme !== void 0 ? _props$nightScheme : fallbackNightScheme) !== null && _ref4 !== void 0 ? _ref4 : defaultNightScheme);
const systemColorMode = useSystemColorMode();
const resolvedColorMode = resolvedColorModePassthrough.current || resolveColorMode(colorMode, systemColorMode);
const colorScheme = chooseColorScheme(resolvedColorMode, dayScheme, nightScheme);
const {
resolvedTheme,
resolvedColorScheme
} = React__default.default.useMemo(() => applyColorScheme(theme$1, colorScheme), [theme$1, colorScheme]);
// this effect will only run on client
React__default.default.useEffect(function updateColorModeAfterServerPassthrough() {
const resolvedColorModeOnClient = resolveColorMode(colorMode, systemColorMode);
if (resolvedColorModePassthrough.current) {
// if the resolved color mode passed on from the server is not the resolved color mode on client, change it!
if (resolvedColorModePassthrough.current !== resolvedColorModeOnClient) {
window.setTimeout(() => {
// use ReactDOM.flushSync to prevent automatic batching of state updates since React 18
// ref: https://github.com/reactwg/react-18/discussions/21
ReactDOM__default.default.flushSync(() => {
// override colorMode to whatever is resolved on the client to get a re-render
setColorMode(resolvedColorModeOnClient);
});
// immediately after that, set the colorMode to what the user passed to respond to system color mode changes
setColorMode(colorMode);
});
}
resolvedColorModePassthrough.current = null;
}
}, [colorMode, systemColorMode, setColorMode]);
return /*#__PURE__*/jsxRuntime.jsx(ThemeContext.Provider, {
value: {
theme: resolvedTheme,
colorScheme,
colorMode,
resolvedColorMode,
resolvedColorScheme,
dayScheme,
nightScheme,
setColorMode,
setDayScheme,
setNightScheme
},
children: /*#__PURE__*/jsxRuntime.jsxs(styled.ThemeProvider, {
theme: resolvedTheme,
children: [children, props.preventSSRMismatch ? /*#__PURE__*/jsxRuntime.jsx("script", {
type: "application/json",
id: `__PRIMER_DATA_${uniqueDataId}__`,
dangerouslySetInnerHTML: {
__html: JSON.stringify({
resolvedServerColorMode: resolvedColorMode
})
}
}) : null]
})
});
};
ThemeProvider.displayName = "ThemeProvider";
function useTheme() {
return React__default.default.useContext(ThemeContext);
}
function useColorSchemeVar(values, fallback) {
var _values$colorScheme;
const {
colorScheme: t0
} = useTheme();
const colorScheme = t0 === undefined ? "" : t0;
return (_values$colorScheme = values[colorScheme]) !== null && _values$colorScheme !== void 0 ? _values$colorScheme : fallback;
}
function useSystemColorMode() {
const $ = reactCompilerRuntime.c(2);
const [systemColorMode, setSystemColorMode] = React__default.default.useState(getSystemColorMode);
let t0;
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = () => {
var _window, _window$matchMedia;
const media = (_window = window) === null || _window === void 0 ? void 0 : (_window$matchMedia = _window.matchMedia) === null || _window$matchMedia === void 0 ? void 0 : _window$matchMedia.call(_window, "(prefers-color-scheme: dark)");
const matchesMediaToColorMode = function matchesMediaToColorMode(matches) {
return matches ? "night" : "day";
};
const handleChange = function handleChange(event) {
const isNight = event.matches;
setSystemColorMode(matchesMediaToColorMode(isNight));
};
if (media) {
const isNight_0 = media.matches;
setSystemColorMode(matchesMediaToColorMode(isNight_0));
if (media.addEventListener !== undefined) {
media.addEventListener("change", handleChange);
return function cleanup() {
media.removeEventListener("change", handleChange);
};
} else {
if (media.addListener !== undefined) {
media.addListener(handleChange);
return function cleanup() {
media.removeListener(handleChange);
};
}
}
}
};
t1 = [];
$[0] = t0;
$[1] = t1;
} else {
t0 = $[0];
t1 = $[1];
}
React__default.default.useEffect(t0, t1);
return systemColorMode;
}
function getSystemColorMode() {
var _window$matchMedia2, _window2, _window$matchMedia2$c;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (typeof window !== 'undefined' && (_window$matchMedia2 = (_window2 = window).matchMedia) !== null && _window$matchMedia2 !== void 0 && (_window$matchMedia2$c = _window$matchMedia2.call(_window2, '(prefers-color-scheme: dark)')) !== null && _window$matchMedia2$c !== void 0 && _window$matchMedia2$c.matches) {
return 'night';
}
return 'day';
}
function resolveColorMode(colorMode, systemColorMode) {
switch (colorMode) {
case 'auto':
return systemColorMode;
default:
return colorMode;
}
}
function chooseColorScheme(colorMode, dayScheme, nightScheme) {
switch (colorMode) {
case 'day':
case 'light':
return dayScheme;
case 'dark':
case 'night':
return nightScheme;
}
}
function applyColorScheme(theme, colorScheme) {
if (!theme.colorSchemes) {
return {
resolvedTheme: theme,
resolvedColorScheme: undefined
};
}
if (!theme.colorSchemes[colorScheme]) {
// eslint-disable-next-line no-console
console.error(`\`${colorScheme}\` scheme not defined in \`theme.colorSchemes\``);
// Apply the first defined color scheme
const defaultColorScheme = Object.keys(theme.colorSchemes)[0];
return {
resolvedTheme: merge__default.default(theme, theme.colorSchemes[defaultColorScheme]),
resolvedColorScheme: defaultColorScheme
};
}
return {
resolvedTheme: merge__default.default(theme, theme.colorSchemes[colorScheme]),
resolvedColorScheme: colorScheme
};
}
exports.ThemeProvider = ThemeProvider;
exports.default = ThemeProvider;
exports.defaultColorMode = defaultColorMode;
exports.useColorSchemeVar = useColorSchemeVar;
exports.useTheme = useTheme;