- Add PWA infrastructure: vite-plugin-pwa, manifest, service worker, SW update prompt component, placeholder icons, Apple meta tags - Harden API client: 401 auto-logout, AbortController timeouts (30s standard, 120s uploads), onUnauthorized callback - Fix memory leaks: clear voice user status on leave, clean up all Maps (channelToSpaceMap, permissions, etc.) on removeSpace - Upgrade error boundary to Aether Drift design with Try Again button, collapsible stack trace, and componentDidCatch logging - Configure desktop icon paths in electron-builder.yml - Remove sticker feature (server routes, schema, types, UI components) - Fix Docker build: use **/node_modules in .dockerignore to prevent COPY from clobbering pnpm-installed workspace dependencies - Add vite-env.d.ts declarations for noise suppressor wasm imports - Exclude test files from tsc build via tsconfig
40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import React, { useRef, useEffect } from 'react';
|
|
import Picker from '@emoji-mart/react';
|
|
import data from '@emoji-mart/data';
|
|
|
|
interface EmojiPickerProps {
|
|
onEmojiSelect: (emoji: { native: string }) => void;
|
|
}
|
|
|
|
export function EmojiPicker({ onEmojiSelect }: EmojiPickerProps) {
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
|
|
// Prevent keyboard events from bubbling out (e.g. Enter submitting the chat input)
|
|
useEffect(() => {
|
|
const el = containerRef.current;
|
|
if (!el) return;
|
|
const stop = (e: KeyboardEvent) => e.stopPropagation();
|
|
el.addEventListener('keydown', stop);
|
|
return () => el.removeEventListener('keydown', stop);
|
|
}, []);
|
|
|
|
return (
|
|
<div ref={containerRef} className="emoji-picker-wrapper">
|
|
<Picker
|
|
data={data}
|
|
onEmojiSelect={onEmojiSelect}
|
|
theme="dark"
|
|
set="native"
|
|
skinTonePosition="search"
|
|
previewPosition="none"
|
|
navPosition="bottom"
|
|
perLine={10}
|
|
maxFrequentRows={2}
|
|
emojiSize={24}
|
|
emojiButtonSize={32}
|
|
categories={['frequent', 'people', 'nature', 'foods', 'activity', 'places', 'objects', 'symbols', 'flags']}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|