Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
73 lines
2.4 KiB
TypeScript
73 lines
2.4 KiB
TypeScript
import React, { useMemo, useSyncExternalStore } from 'react';
|
|
import {
|
|
extractPrimaryFamily,
|
|
getFontAvailabilityVersion,
|
|
hasAuthoritativeData,
|
|
isFontInstalled,
|
|
subscribeFontAvailability,
|
|
} from '../../lib/fontAvailability';
|
|
import type { TerminalFont } from '../../infrastructure/config/fonts';
|
|
import { FontSelect } from './FontSelect';
|
|
|
|
interface TerminalFontSelectProps {
|
|
value: string;
|
|
fonts: TerminalFont[];
|
|
onChange: (value: string) => void;
|
|
className?: string;
|
|
disabled?: boolean;
|
|
ariaLabel: string;
|
|
}
|
|
|
|
export const TerminalFontSelect: React.FC<TerminalFontSelectProps> = ({
|
|
value,
|
|
fonts,
|
|
onChange,
|
|
className,
|
|
disabled,
|
|
ariaLabel,
|
|
}) => {
|
|
// Subscribe to font availability so the filter re-evaluates after the
|
|
// Local Font Access API populates the authoritative install set
|
|
// asynchronously, even if the `fonts` prop ref hasn't changed.
|
|
const availabilityVersion = useSyncExternalStore(
|
|
subscribeFontAvailability,
|
|
getFontAvailabilityVersion,
|
|
getFontAvailabilityVersion,
|
|
);
|
|
|
|
// Hide fonts that aren't actually rendered on this machine so users
|
|
// don't pick a font and then see no visible change. The currently
|
|
// selected font is always shown so the user can read their setting.
|
|
//
|
|
// When the Local Font Access API has populated authoritative data,
|
|
// trust it: an empty or near-empty result means the user really has
|
|
// few monospace fonts (Layer 3 still gives at least one option via
|
|
// bundled Sarasa Mono SC). When canvas-only fallback is in play,
|
|
// we keep a safety net at length>=1 to avoid an empty dropdown if
|
|
// detection misfires.
|
|
const visibleFonts = useMemo(() => {
|
|
// Referenced so eslint-react-hooks sees the dep used; the real
|
|
// purpose is to invalidate this memo when setSystemFamilies bumps
|
|
// the version (isFontInstalled reads module state).
|
|
void availabilityVersion;
|
|
const filtered = fonts.filter(
|
|
(font) => font.id === "" || font.id === value || isFontInstalled(extractPrimaryFamily(font.family)),
|
|
);
|
|
if (hasAuthoritativeData()) return filtered;
|
|
return filtered.length >= 1 ? filtered : fonts;
|
|
}, [fonts, value, availabilityVersion]);
|
|
|
|
return (
|
|
<FontSelect
|
|
fonts={visibleFonts}
|
|
value={value}
|
|
onChange={onChange}
|
|
className={className}
|
|
disabled={disabled}
|
|
ariaLabel={ariaLabel}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default TerminalFontSelect;
|