aboutsummaryrefslogtreecommitdiffstats
path: root/packages/excalidraw/components/FontPicker/FontPicker.tsx
diff options
context:
space:
mode:
authorkj_sh6042026-03-15 16:19:35 -0400
committerkj_sh6042026-03-15 16:19:35 -0400
commit6ec259a0e71174651bae95d4628138bf6fd68742 (patch)
tree5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/components/FontPicker/FontPicker.tsx
parent16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff)
refactor: packages/
Diffstat (limited to 'packages/excalidraw/components/FontPicker/FontPicker.tsx')
-rw-r--r--packages/excalidraw/components/FontPicker/FontPicker.tsx110
1 files changed, 110 insertions, 0 deletions
diff --git a/packages/excalidraw/components/FontPicker/FontPicker.tsx b/packages/excalidraw/components/FontPicker/FontPicker.tsx
new file mode 100644
index 0000000..4585c58
--- /dev/null
+++ b/packages/excalidraw/components/FontPicker/FontPicker.tsx
@@ -0,0 +1,110 @@
+import React, { useCallback, useMemo } from "react";
+import * as Popover from "@radix-ui/react-popover";
+
+import { FontPickerList } from "./FontPickerList";
+import { FontPickerTrigger } from "./FontPickerTrigger";
+import { ButtonIconSelect } from "../ButtonIconSelect";
+import {
+ FontFamilyCodeIcon,
+ FontFamilyNormalIcon,
+ FreedrawIcon,
+} from "../icons";
+import { ButtonSeparator } from "../ButtonSeparator";
+import type { FontFamilyValues } from "../../element/types";
+import { FONT_FAMILY } from "../../constants";
+import { t } from "../../i18n";
+
+import "./FontPicker.scss";
+
+export const DEFAULT_FONTS = [
+ {
+ value: FONT_FAMILY.Excalifont,
+ icon: FreedrawIcon,
+ text: t("labels.handDrawn"),
+ testId: "font-family-hand-drawn",
+ },
+ {
+ value: FONT_FAMILY.Nunito,
+ icon: FontFamilyNormalIcon,
+ text: t("labels.normal"),
+ testId: "font-family-normal",
+ },
+ {
+ value: FONT_FAMILY["Comic Shanns"],
+ icon: FontFamilyCodeIcon,
+ text: t("labels.code"),
+ testId: "font-family-code",
+ },
+];
+
+const defaultFontFamilies = new Set(DEFAULT_FONTS.map((x) => x.value));
+
+export const isDefaultFont = (fontFamily: number | null) => {
+ if (!fontFamily) {
+ return false;
+ }
+
+ return defaultFontFamilies.has(fontFamily);
+};
+
+interface FontPickerProps {
+ isOpened: boolean;
+ selectedFontFamily: FontFamilyValues | null;
+ hoveredFontFamily: FontFamilyValues | null;
+ onSelect: (fontFamily: FontFamilyValues) => void;
+ onHover: (fontFamily: FontFamilyValues) => void;
+ onLeave: () => void;
+ onPopupChange: (open: boolean) => void;
+}
+
+export const FontPicker = React.memo(
+ ({
+ isOpened,
+ selectedFontFamily,
+ hoveredFontFamily,
+ onSelect,
+ onHover,
+ onLeave,
+ onPopupChange,
+ }: FontPickerProps) => {
+ const defaultFonts = useMemo(() => DEFAULT_FONTS, []);
+ const onSelectCallback = useCallback(
+ (value: number | false) => {
+ if (value) {
+ onSelect(value);
+ }
+ },
+ [onSelect],
+ );
+
+ return (
+ <div role="dialog" aria-modal="true" className="FontPicker__container">
+ <ButtonIconSelect<FontFamilyValues | false>
+ type="button"
+ options={defaultFonts}
+ value={selectedFontFamily}
+ onClick={onSelectCallback}
+ />
+ <ButtonSeparator />
+ <Popover.Root open={isOpened} onOpenChange={onPopupChange}>
+ <FontPickerTrigger selectedFontFamily={selectedFontFamily} />
+ {isOpened && (
+ <FontPickerList
+ selectedFontFamily={selectedFontFamily}
+ hoveredFontFamily={hoveredFontFamily}
+ onSelect={onSelectCallback}
+ onHover={onHover}
+ onLeave={onLeave}
+ onOpen={() => onPopupChange(true)}
+ onClose={() => onPopupChange(false)}
+ />
+ )}
+ </Popover.Root>
+ </div>
+ );
+ },
+ (prev, next) =>
+ prev.isOpened === next.isOpened &&
+ prev.selectedFontFamily === next.selectedFontFamily &&
+ prev.hoveredFontFamily === next.hoveredFontFamily,
+);