fumadocs-ui
Version:
The Radix UI version of Fumadocs UI
74 lines (73 loc) • 2.49 kB
JavaScript
"use client";
import { I18nProvider } from "../contexts/i18n.js";
import { SearchProvider } from "../contexts/search.js";
import { jsx, jsxs } from "react/jsx-runtime";
import { useEffect, useEffectEvent } from "react";
import { ThemeProvider, useTheme, useTheme as useTheme$1 } from "next-themes";
import { flushSync } from "react-dom";
import { DirectionProvider } from "@radix-ui/react-direction";
//#region src/provider/base.tsx
/**
* Whether the event should be ignored because the user is interacting with an editable element,
* or an opened dialog (e.g. the search dialog).
*/
function isTypingTarget(target) {
if (!(target instanceof HTMLElement)) return false;
if (target.isContentEditable) return true;
if ([
"INPUT",
"TEXTAREA",
"SELECT"
].includes(target.tagName)) return true;
return target.closest("[role=\"dialog\"]") !== null;
}
/**
* Toggle between light/dark mode with a hotkey, must be placed under `next-themes` provider.
*/
function ThemeHotKey({ hotKey }) {
const { setTheme, resolvedTheme } = useTheme$1();
const onKeyDown = useEffectEvent((e) => {
if (e.defaultPrevented || e.isComposing) return;
if (isTypingTarget(e.target)) return;
if (!(typeof hotKey === "string" ? !e.metaKey && !e.ctrlKey && !e.altKey && e.key.toLowerCase() === hotKey.toLowerCase() : hotKey(e))) return;
e.preventDefault();
const next = resolvedTheme === "dark" ? "light" : "dark";
if (document?.startViewTransition) document.startViewTransition(() => flushSync(() => setTheme(next)));
else setTheme(next);
});
useEffect(() => {
window.addEventListener("keydown", onKeyDown);
return () => {
window.removeEventListener("keydown", onKeyDown);
};
}, []);
return null;
}
function RootProvider({ children, dir = "ltr", theme = {}, search, i18n }) {
let body = children;
if (search?.enabled !== false) body = /* @__PURE__ */ jsx(SearchProvider, {
...search,
children: body
});
if (theme?.enabled !== false) {
const { enabled: _, hotKey = "d", ...themeProps } = theme;
body = /* @__PURE__ */ jsxs(ThemeProvider, {
attribute: "class",
defaultTheme: "system",
enableSystem: true,
disableTransitionOnChange: true,
...themeProps,
children: [hotKey !== false && /* @__PURE__ */ jsx(ThemeHotKey, { hotKey }), body]
});
}
if (i18n) body = /* @__PURE__ */ jsx(I18nProvider, {
...i18n,
children: body
});
return /* @__PURE__ */ jsx(DirectionProvider, {
dir,
children: body
});
}
//#endregion
export { RootProvider, useTheme };