diff options
| author | kj_sh604 | 2026-03-15 16:19:35 -0400 |
|---|---|---|
| committer | kj_sh604 | 2026-03-15 16:19:35 -0400 |
| commit | 6ec259a0e71174651bae95d4628138bf6fd68742 (patch) | |
| tree | 5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/components/FontPicker/FontPicker.tsx | |
| parent | 16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff) | |
refactor: packages/
Diffstat (limited to 'packages/excalidraw/components/FontPicker/FontPicker.tsx')
| -rw-r--r-- | packages/excalidraw/components/FontPicker/FontPicker.tsx | 110 |
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, +); |
