codeant-ai-for-open-source[bot] commented on code in PR #36417:
URL: https://github.com/apache/superset/pull/36417#discussion_r2587288670


##########
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/EmojiTextArea.test.tsx:
##########
@@ -0,0 +1,170 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { render, screen, userEvent } from '@superset-ui/core/spec';
+import { EmojiTextArea } from '.';
+import { filterEmojis, EMOJI_DATA } from './emojiData';
+
+test('renders EmojiTextArea with placeholder', () => {
+  render(<EmojiTextArea placeholder="Type something..." />);
+  expect(screen.getByPlaceholderText('Type something...')).toBeInTheDocument();
+});
+
+test('renders EmojiTextArea as textarea element', () => {
+  render(<EmojiTextArea placeholder="Type here" />);
+  const textarea = screen.getByPlaceholderText('Type here');
+  expect(textarea.tagName.toLowerCase()).toBe('textarea');
+});
+
+test('allows typing in the textarea', async () => {
+  render(<EmojiTextArea placeholder="Type here" />);
+  const textarea = screen.getByPlaceholderText('Type here');
+  await userEvent.type(textarea, 'Hello world');
+  expect(textarea).toHaveValue('Hello world');
+});
+
+test('calls onChange when typing', async () => {
+  const onChange = jest.fn();
+  render(<EmojiTextArea placeholder="Type here" onChange={onChange} />);
+  const textarea = screen.getByPlaceholderText('Type here');
+  await userEvent.type(textarea, 'Hi');
+  expect(onChange).toHaveBeenCalled();
+});
+
+test('passes through rows prop', () => {
+  render(<EmojiTextArea placeholder="Type here" rows={5} />);
+  const textarea = screen.getByPlaceholderText('Type here');
+  expect(textarea).toHaveAttribute('rows', '5');
+});
+
+test('forwards ref to underlying component', () => {
+  const ref = { current: null };
+  render(<EmojiTextArea ref={ref} placeholder="Type here" />);
+  expect(ref.current).not.toBeNull();
+});
+
+test('renders controlled component with value prop', () => {
+  render(<EmojiTextArea value="Hello" onChange={() => {}} />);
+  expect(screen.getByDisplayValue('Hello')).toBeInTheDocument();
+});
+
+// ============================================
+// Unit tests for filterEmojis utility function
+// ============================================
+
+test('filterEmojis returns matching emojis by shortcode', () => {
+  const results = filterEmojis('smile');
+  expect(results.length).toBeGreaterThan(0);
+  expect(results[0].shortcode).toBe('smile');
+});
+
+test('filterEmojis returns matching emojis by partial shortcode', () => {
+  const results = filterEmojis('sm');
+  expect(results.length).toBeGreaterThan(0);
+  // Should include smile, smirk, etc.
+  expect(results.some(e => e.shortcode.includes('sm'))).toBe(true);
+});
+
+test('filterEmojis returns matching emojis by keyword', () => {
+  const results = filterEmojis('happy');
+  expect(results.length).toBeGreaterThan(0);
+  // Should include emojis with 'happy' keyword
+  expect(results.some(e => e.keywords?.includes('happy'))).toBe(true);
+});
+
+test('filterEmojis is case insensitive', () => {
+  const results1 = filterEmojis('SMILE');
+  const results2 = filterEmojis('smile');
+  expect(results1.length).toBe(results2.length);
+  expect(results1[0].shortcode).toBe(results2[0].shortcode);

Review Comment:
   **Suggestion:** Fragile case-insensitivity test: the test compares lengths 
and the first element of the two result arrays, which can fail if order differs 
even when the sets are the same. Compare the sets of shortcodes in a 
deterministic way (sort them) to assert case-insensitive behavior robustly. 
[possible bug]
   
   **Severity Level:** Critical ๐Ÿšจ
   ```suggestion
     // Compare shortcode sets in a deterministic way rather than relying on 
array order
     const sc1 = results1.map(r => r.shortcode).sort();
     const sc2 = results2.map(r => r.shortcode).sort();
     expect(sc1).toEqual(sc2);
   ```
   <details>
   <summary><b>Why it matters? โญ </b></summary>
   
   Comparing lengths and the first element is brittle because arrays can be the 
same
   set but in different order. Comparing deterministic sets (e.g., sorted 
shortcodes)
   accurately verifies case-insensitivity and is a small, meaningful 
improvement.
   </details>
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/EmojiTextArea.test.tsx
   **Line:** 93:94
   **Comment:**
        *Possible Bug: Fragile case-insensitivity test: the test compares 
lengths and the first element of the two result arrays, which can fail if order 
differs even when the sets are the same. Compare the sets of shortcodes in a 
deterministic way (sort them) to assert case-insensitive behavior robustly.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>



##########
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/EmojiTextArea.stories.tsx:
##########
@@ -0,0 +1,331 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { useState } from 'react';

Review Comment:
   **Suggestion:** The file references `React.FormEvent` in the `handleSubmit` 
parameter but only imports `useState` from 'react' (no `React` namespace). This 
will cause a TypeScript "React is not defined" type error (or require a 
separate import) because the `React` identifier is used in a type position 
without being imported. Import the React namespace alongside `useState` so the 
`React` type is available. [type error]
   
   **Severity Level:** Minor โš ๏ธ
   ```suggestion
   import React, { useState } from 'react';
   ```
   <details>
   <summary><b>Why it matters? โญ </b></summary>
   
   The story uses the `React` namespace in a type position: `handleSubmit = (e: 
React.FormEvent) => { ... }`.
   Without importing `React` (or importing the FormEvent type directly), 
TypeScript will complain that `React` is not defined.
   This is a real type error, not a style nit. Adding `import React, { useState 
} from 'react';` or `import type { FormEvent } from 'react'` and adjusting the 
signature fixes it.
   </details>
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/EmojiTextArea.stories.tsx
   **Line:** 19:19
   **Comment:**
        *Type Error: The file references `React.FormEvent` in the 
`handleSubmit` parameter but only imports `useState` from 'react' (no `React` 
namespace). This will cause a TypeScript "React is not defined" type error (or 
require a separate import) because the `React` identifier is used in a type 
position without being imported. Import the React namespace alongside 
`useState` so the `React` type is available.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>



##########
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/EmojiTextArea.test.tsx:
##########
@@ -0,0 +1,170 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { render, screen, userEvent } from '@superset-ui/core/spec';
+import { EmojiTextArea } from '.';
+import { filterEmojis, EMOJI_DATA } from './emojiData';
+
+test('renders EmojiTextArea with placeholder', () => {
+  render(<EmojiTextArea placeholder="Type something..." />);
+  expect(screen.getByPlaceholderText('Type something...')).toBeInTheDocument();
+});
+
+test('renders EmojiTextArea as textarea element', () => {
+  render(<EmojiTextArea placeholder="Type here" />);
+  const textarea = screen.getByPlaceholderText('Type here');
+  expect(textarea.tagName.toLowerCase()).toBe('textarea');
+});
+
+test('allows typing in the textarea', async () => {
+  render(<EmojiTextArea placeholder="Type here" />);
+  const textarea = screen.getByPlaceholderText('Type here');
+  await userEvent.type(textarea, 'Hello world');
+  expect(textarea).toHaveValue('Hello world');
+});
+
+test('calls onChange when typing', async () => {
+  const onChange = jest.fn();
+  render(<EmojiTextArea placeholder="Type here" onChange={onChange} />);
+  const textarea = screen.getByPlaceholderText('Type here');
+  await userEvent.type(textarea, 'Hi');
+  expect(onChange).toHaveBeenCalled();
+});
+
+test('passes through rows prop', () => {
+  render(<EmojiTextArea placeholder="Type here" rows={5} />);
+  const textarea = screen.getByPlaceholderText('Type here');
+  expect(textarea).toHaveAttribute('rows', '5');
+});
+
+test('forwards ref to underlying component', () => {
+  const ref = { current: null };
+  render(<EmojiTextArea ref={ref} placeholder="Type here" />);
+  expect(ref.current).not.toBeNull();
+});
+
+test('renders controlled component with value prop', () => {
+  render(<EmojiTextArea value="Hello" onChange={() => {}} />);
+  expect(screen.getByDisplayValue('Hello')).toBeInTheDocument();
+});
+
+// ============================================
+// Unit tests for filterEmojis utility function
+// ============================================
+
+test('filterEmojis returns matching emojis by shortcode', () => {
+  const results = filterEmojis('smile');
+  expect(results.length).toBeGreaterThan(0);
+  expect(results[0].shortcode).toBe('smile');

Review Comment:
   **Suggestion:** Fragile assertion: the test assumes the first returned match 
for "smile" will always be the exact `smile` shortcode. If ordering changes (or 
other shortcodes that include "smile" appear earlier), this assertion will be 
flaky or fail. Replace the strict index-based check with an existence check 
that the results include an item with shortcode `smile`. [possible bug]
   
   **Severity Level:** Critical ๐Ÿšจ
   ```suggestion
     // Ensure the results include the exact 'smile' shortcode (don't rely on 
ordering)
     expect(results.some(e => e.shortcode === 'smile')).toBe(true);
   ```
   <details>
   <summary><b>Why it matters? โญ </b></summary>
   
   The current assertion relies on ordering (results[0]) which can be flaky if 
the
   filter implementation or emoji ordering changes. The proposed change 
(asserting
   that some result has shortcode 'smile') correctly preserves the intent of 
the test
   without depending on order, and it fixes a real brittleness in the test.
   </details>
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/EmojiTextArea.test.tsx
   **Line:** 73:73
   **Comment:**
        *Possible Bug: Fragile assertion: the test assumes the first returned 
match for "smile" will always be the exact `smile` shortcode. If ordering 
changes (or other shortcodes that include "smile" appear earlier), this 
assertion will be flaky or fail. Replace the strict index-based check with an 
existence check that the results include an item with shortcode `smile`.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>



##########
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/index.tsx:
##########
@@ -0,0 +1,247 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { forwardRef, useCallback, useMemo, useState, useRef } from 'react';
+import { Mentions } from 'antd';
+import type { MentionsRef, MentionsProps } from 'antd/es/mentions';
+import { filterEmojis, type EmojiItem } from './emojiData';
+
+const MIN_CHARS_BEFORE_POPUP = 2;
+
+// Regex to match emoji characters (simplified, covers most common emojis)
+const EMOJI_REGEX =
+  
/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]/u;
+
+export interface EmojiTextAreaProps
+  extends Omit<MentionsProps, 'prefix' | 'options' | 'onSelect'> {
+  /**
+   * Minimum characters after colon before showing popup.
+   * @default 2 (Slack-like behavior)
+   */
+  minCharsBeforePopup?: number;
+  /**
+   * Maximum number of emoji suggestions to show.
+   * @default 10
+   */
+  maxSuggestions?: number;
+  /**
+   * Called when an emoji is selected from the popup.
+   */
+  onEmojiSelect?: (emoji: EmojiItem) => void;
+}
+
+/**
+ * A TextArea component with Slack-like emoji autocomplete.
+ *
+ * Features:
+ * - Triggers on `:` prefix (like Slack)
+ * - Only shows popup after 2+ characters are typed (configurable)
+ * - Colon must be preceded by a space, start of line, or another emoji
+ * - Prevents accidental Enter key selection when typing quickly
+ *
+ * @example
+ * ```tsx
+ * <EmojiTextArea
+ *   placeholder="Type :sm to see emoji suggestions..."
+ *   onChange={(text) => console.log(text)}
+ * />
+ * ```
+ */
+export const EmojiTextArea = forwardRef<MentionsRef, EmojiTextAreaProps>(
+  (
+    {
+      minCharsBeforePopup = MIN_CHARS_BEFORE_POPUP,
+      maxSuggestions = 10,
+      onEmojiSelect,
+      onChange,
+      onKeyDown,
+      ...restProps
+    },
+    ref,
+  ) => {
+    const [options, setOptions] = useState<
+      Array<{ value: string; label: React.ReactNode }>
+    >([]);
+    const [isPopupVisible, setIsPopupVisible] = useState(false);
+    const lastSearchRef = useRef<string>('');
+    const lastKeyPressTimeRef = useRef<number>(0);
+
+    /**
+     * Validates whether the colon trigger should activate the popup.
+     * Implements Slack-like behavior:
+     * - Colon must be preceded by whitespace, start of text, or emoji
+     * - At least minCharsBeforePopup characters must be typed after colon
+     */
+    const validateSearch = useCallback(
+      (text: string, props: MentionsProps): boolean => {
+        // Get the full value to check what precedes the colon
+        const fullValue = (props.value as string) || '';
+
+        // Find where this search text starts in the full value
+        // The search text is what comes after the `:` prefix
+        const colonIndex = fullValue.lastIndexOf(`:${text}`);
+
+        if (colonIndex === -1) {
+          setIsPopupVisible(false);
+          return false;
+        }
+
+        // Check what precedes the colon
+        if (colonIndex > 0) {
+          const charBefore = fullValue[colonIndex - 1];
+
+          // Must be preceded by whitespace, newline, or emoji
+          const isWhitespace = /\s/.test(charBefore);
+          const isEmoji = EMOJI_REGEX.test(charBefore);
+
+          if (!isWhitespace && !isEmoji) {
+            setIsPopupVisible(false);
+            return false;
+          }
+        }
+
+        // Check minimum character requirement
+        if (text.length < minCharsBeforePopup) {
+          setIsPopupVisible(false);
+          return false;
+        }
+
+        setIsPopupVisible(true);
+        return true;
+      },
+      [minCharsBeforePopup],
+    );
+
+    /**
+     * Handles search and filters emoji suggestions.
+     */
+    const handleSearch = useCallback(
+      (searchText: string) => {
+        lastSearchRef.current = searchText;
+
+        if (searchText.length < minCharsBeforePopup) {
+          setOptions([]);
+          return;
+        }
+
+        const filteredEmojis = filterEmojis(searchText, maxSuggestions);
+
+        const newOptions = filteredEmojis.map(item => ({
+          value: item.emoji,
+          label: (
+            <span>
+              <span style={{ marginRight: 8 }}>{item.emoji}</span>
+              <span style={{ color: 'var(--ant-color-text-secondary)' }}>
+                :{item.shortcode}:
+              </span>
+            </span>
+          ),
+          // Store the full item for onSelect callback
+          data: item,
+        }));
+
+        setOptions(newOptions);
+      },
+      [minCharsBeforePopup, maxSuggestions],
+    );
+
+    /**
+     * Handles emoji selection from the popup.
+     */
+    const handleSelect = useCallback(
+      (option: { value: string; data?: EmojiItem }) => {
+        if (option.data && onEmojiSelect) {
+          onEmojiSelect(option.data);
+        }
+        setIsPopupVisible(false);
+      },
+      [onEmojiSelect],
+    );
+
+    /**
+     * Handles key down events to prevent accidental selection on Enter.
+     * If the user presses Enter very quickly after typing (< 100ms),
+     * we treat it as a newline intent rather than selection.
+     */
+    const handleKeyDown = useCallback(
+      (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
+        const now = Date.now();
+        const timeSinceLastKey = now - lastKeyPressTimeRef.current;
+
+        // If Enter is pressed and popup is visible
+        if (e.key === 'Enter' && isPopupVisible) {
+          // If typed very quickly (< 100ms since last keypress) and
+          // there's meaningful search text, allow the Enter to create newline
+          // This prevents accidental selection when typing something like:
+          // "let me show you an example:[Enter]"
+          if (timeSinceLastKey < 100 && lastSearchRef.current.length === 0) {

Review Comment:
   **Suggestion:** The Enter-key timing check is inverted: the code intends to 
treat a quick Enter after typing a meaningful emoji search as a newline (not a 
selection), but it checks for an empty search (length === 0) instead of a 
non-empty search. This will allow newline only when there's no search text and 
prevent the intended newline behavior when there actually is search text, 
causing accidental emoji selection or wrong newline handling. Change the 
condition to check for a non-empty search string. [logic error]
   
   **Severity Level:** Minor โš ๏ธ
   ```suggestion
             if (timeSinceLastKey < 100 && lastSearchRef.current.length > 0) {
   ```
   <details>
   <summary><b>Why it matters? โญ </b></summary>
   
   The comment and intent in the surrounding code say we should treat a very 
quick Enter after typing a meaningful search as a newline (to avoid accidental 
selection). The current condition checks for length === 0 (empty search), which 
is the opposite of the described intent. This is a real logic bug that can 
cause accidental emoji selection or wrong newline handling. Flipping to length 
> 0 aligns code with the documented intent and fixes the runtime behavior.
   </details>
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/index.tsx
   **Line:** 192:192
   **Comment:**
        *Logic Error: The Enter-key timing check is inverted: the code intends 
to treat a quick Enter after typing a meaningful emoji search as a newline (not 
a selection), but it checks for an empty search (length === 0) instead of a 
non-empty search. This will allow newline only when there's no search text and 
prevent the intended newline behavior when there actually is search text, 
causing accidental emoji selection or wrong newline handling. Change the 
condition to check for a non-empty search string.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>



##########
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/index.tsx:
##########
@@ -0,0 +1,247 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { forwardRef, useCallback, useMemo, useState, useRef } from 'react';
+import { Mentions } from 'antd';
+import type { MentionsRef, MentionsProps } from 'antd/es/mentions';
+import { filterEmojis, type EmojiItem } from './emojiData';
+
+const MIN_CHARS_BEFORE_POPUP = 2;
+
+// Regex to match emoji characters (simplified, covers most common emojis)
+const EMOJI_REGEX =
+  
/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]/u;
+
+export interface EmojiTextAreaProps
+  extends Omit<MentionsProps, 'prefix' | 'options' | 'onSelect'> {
+  /**
+   * Minimum characters after colon before showing popup.
+   * @default 2 (Slack-like behavior)
+   */
+  minCharsBeforePopup?: number;
+  /**
+   * Maximum number of emoji suggestions to show.
+   * @default 10
+   */
+  maxSuggestions?: number;
+  /**
+   * Called when an emoji is selected from the popup.
+   */
+  onEmojiSelect?: (emoji: EmojiItem) => void;
+}
+
+/**
+ * A TextArea component with Slack-like emoji autocomplete.
+ *
+ * Features:
+ * - Triggers on `:` prefix (like Slack)
+ * - Only shows popup after 2+ characters are typed (configurable)
+ * - Colon must be preceded by a space, start of line, or another emoji
+ * - Prevents accidental Enter key selection when typing quickly
+ *
+ * @example
+ * ```tsx
+ * <EmojiTextArea
+ *   placeholder="Type :sm to see emoji suggestions..."
+ *   onChange={(text) => console.log(text)}
+ * />
+ * ```
+ */
+export const EmojiTextArea = forwardRef<MentionsRef, EmojiTextAreaProps>(
+  (
+    {
+      minCharsBeforePopup = MIN_CHARS_BEFORE_POPUP,
+      maxSuggestions = 10,
+      onEmojiSelect,
+      onChange,
+      onKeyDown,
+      ...restProps
+    },
+    ref,
+  ) => {
+    const [options, setOptions] = useState<
+      Array<{ value: string; label: React.ReactNode }>

Review Comment:
   **Suggestion:** The `options` state is typed as objects with only `value` 
and `label`, but the code stores a `data` property on each option for later 
retrieval. This type mismatch can cause type-checking issues and makes the 
intended shape unclear; extend the state type to include an optional `data?: 
EmojiItem` property so the stored emoji item is typed and available. [type 
error]
   
   **Severity Level:** Minor โš ๏ธ
   ```suggestion
         Array<{ value: string; label: React.ReactNode; data?: EmojiItem }>
   ```
   <details>
   <summary><b>Why it matters? โญ </b></summary>
   
   The code stores a `data` field on each option object (used on select), but 
the useState type only declares value and label. That mismatch can cause 
TypeScript excess-property or type confusion. Extending the state type to 
include an optional `data?: EmojiItem` accurately models the stored shape and 
prevents type errors while making intent explicit.
   </details>
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/index.tsx
   **Line:** 78:78
   **Comment:**
        *Type Error: The `options` state is typed as objects with only `value` 
and `label`, but the code stores a `data` property on each option for later 
retrieval. This type mismatch can cause type-checking issues and makes the 
intended shape unclear; extend the state type to include an optional `data?: 
EmojiItem` property so the stored emoji item is typed and available.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>



##########
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/emojiData.ts:
##########
@@ -0,0 +1,569 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export interface EmojiItem {
+  shortcode: string;
+  emoji: string;
+  keywords?: string[];
+}
+
+/**
+ * Common emoji data with shortcodes.
+ * This is a curated subset of emojis commonly used in Slack-like applications.
+ * Can be extended or replaced with a more comprehensive emoji library.
+ */
+export const EMOJI_DATA: EmojiItem[] = [
+  // Smileys & Emotion
+  { shortcode: 'smile', emoji: '๐Ÿ˜„', keywords: ['happy', 'joy', 'glad'] },
+  { shortcode: 'smiley', emoji: '๐Ÿ˜ƒ', keywords: ['happy', 'joy'] },
+  { shortcode: 'grinning', emoji: '๐Ÿ˜€', keywords: ['happy', 'smile'] },
+  { shortcode: 'blush', emoji: '๐Ÿ˜Š', keywords: ['happy', 'shy', 'smile'] },
+  { shortcode: 'wink', emoji: '๐Ÿ˜‰', keywords: ['flirt'] },
+  {
+    shortcode: 'heart_eyes',
+    emoji: '๐Ÿ˜',
+    keywords: ['love', 'crush', 'adore'],
+  },
+  { shortcode: 'kissing_heart', emoji: '๐Ÿ˜˜', keywords: ['love', 'kiss'] },
+  { shortcode: 'laughing', emoji: '๐Ÿ˜†', keywords: ['happy', 'haha', 'lol'] },
+  { shortcode: 'sweat_smile', emoji: '๐Ÿ˜…', keywords: ['nervous', 'phew'] },
+  { shortcode: 'joy', emoji: '๐Ÿ˜‚', keywords: ['tears', 'laugh', 'lol', 'lmao'] 
},
+  {
+    shortcode: 'rofl',
+    emoji: '๐Ÿคฃ',
+    keywords: ['rolling', 'laugh', 'lol', 'lmao'],
+  },
+  { shortcode: 'relaxed', emoji: 'โ˜บ๏ธ', keywords: ['calm', 'peace'] },
+  { shortcode: 'yum', emoji: '๐Ÿ˜‹', keywords: ['tasty', 'delicious'] },
+  { shortcode: 'relieved', emoji: '๐Ÿ˜Œ', keywords: ['calm', 'peaceful'] },
+  { shortcode: 'sunglasses', emoji: '๐Ÿ˜Ž', keywords: ['cool', 'awesome'] },
+  { shortcode: 'smirk', emoji: '๐Ÿ˜', keywords: ['sly', 'confident'] },
+  { shortcode: 'neutral_face', emoji: '๐Ÿ˜', keywords: ['meh', 'blank'] },
+  { shortcode: 'expressionless', emoji: '๐Ÿ˜‘', keywords: ['blank', 'meh'] },
+  { shortcode: 'unamused', emoji: '๐Ÿ˜’', keywords: ['bored', 'meh'] },
+  { shortcode: 'sweat', emoji: '๐Ÿ˜“', keywords: ['nervous', 'worried'] },
+  { shortcode: 'pensive', emoji: '๐Ÿ˜”', keywords: ['sad', 'thoughtful'] },
+  { shortcode: 'confused', emoji: '๐Ÿ˜•', keywords: ['puzzled', 'unsure'] },
+  { shortcode: 'upside_down', emoji: '๐Ÿ™ƒ', keywords: ['silly', 'sarcasm'] },
+  { shortcode: 'thinking', emoji: '๐Ÿค”', keywords: ['ponder', 'hmm'] },
+  { shortcode: 'zipper_mouth', emoji: '๐Ÿค', keywords: ['secret', 'quiet'] },
+  { shortcode: 'raised_eyebrow', emoji: '๐Ÿคจ', keywords: ['skeptical', 'doubt'] 
},
+  { shortcode: 'rolling_eyes', emoji: '๐Ÿ™„', keywords: ['annoyed', 'whatever'] },
+  { shortcode: 'grimacing', emoji: '๐Ÿ˜ฌ', keywords: ['awkward', 'nervous'] },
+  { shortcode: 'lying_face', emoji: '๐Ÿคฅ', keywords: ['liar', 'pinocchio'] },
+  { shortcode: 'shushing', emoji: '๐Ÿคซ', keywords: ['quiet', 'secret'] },
+  { shortcode: 'hand_over_mouth', emoji: '๐Ÿคญ', keywords: ['oops', 'giggle'] },
+  { shortcode: 'face_vomiting', emoji: '๐Ÿคฎ', keywords: ['sick', 'gross'] },
+  { shortcode: 'exploding_head', emoji: '๐Ÿคฏ', keywords: ['mind', 'blown'] },
+  { shortcode: 'cowboy', emoji: '๐Ÿค ', keywords: ['western', 'yeehaw'] },
+  { shortcode: 'partying', emoji: '๐Ÿฅณ', keywords: ['party', 'celebration'] },
+  { shortcode: 'star_struck', emoji: '๐Ÿคฉ', keywords: ['excited', 'amazed'] },
+  { shortcode: 'sleeping', emoji: '๐Ÿ˜ด', keywords: ['zzz', 'tired'] },
+  { shortcode: 'drooling', emoji: '๐Ÿคค', keywords: ['hungry', 'want'] },
+  { shortcode: 'sleepy', emoji: '๐Ÿ˜ช', keywords: ['tired', 'zzz'] },
+  { shortcode: 'mask', emoji: '๐Ÿ˜ท', keywords: ['sick', 'covid'] },
+  { shortcode: 'nerd', emoji: '๐Ÿค“', keywords: ['geek', 'smart'] },
+  { shortcode: 'monocle', emoji: '๐Ÿง', keywords: ['curious', 'inspect'] },
+  { shortcode: 'worried', emoji: '๐Ÿ˜Ÿ', keywords: ['concerned', 'anxious'] },
+  { shortcode: 'frowning', emoji: '๐Ÿ™', keywords: ['sad', 'unhappy'] },
+  { shortcode: 'open_mouth', emoji: '๐Ÿ˜ฎ', keywords: ['surprised', 'wow'] },
+  { shortcode: 'hushed', emoji: '๐Ÿ˜ฏ', keywords: ['surprised', 'quiet'] },
+  { shortcode: 'astonished', emoji: '๐Ÿ˜ฒ', keywords: ['shocked', 'wow'] },
+  { shortcode: 'flushed', emoji: '๐Ÿ˜ณ', keywords: ['embarrassed', 'shy'] },
+  { shortcode: 'pleading', emoji: '๐Ÿฅบ', keywords: ['puppy', 'please'] },
+  { shortcode: 'cry', emoji: '๐Ÿ˜ข', keywords: ['sad', 'tear'] },
+  { shortcode: 'sob', emoji: '๐Ÿ˜ญ', keywords: ['crying', 'sad', 'tears'] },
+  { shortcode: 'scream', emoji: '๐Ÿ˜ฑ', keywords: ['scared', 'horror'] },
+  { shortcode: 'confounded', emoji: '๐Ÿ˜–', keywords: ['frustrated'] },
+  { shortcode: 'persevere', emoji: '๐Ÿ˜ฃ', keywords: ['struggling'] },
+  { shortcode: 'disappointed', emoji: '๐Ÿ˜ž', keywords: ['sad', 'let down'] },
+  { shortcode: 'fearful', emoji: '๐Ÿ˜จ', keywords: ['scared', 'afraid'] },
+  { shortcode: 'cold_sweat', emoji: '๐Ÿ˜ฐ', keywords: ['nervous', 'anxious'] },
+  { shortcode: 'weary', emoji: '๐Ÿ˜ฉ', keywords: ['tired', 'exhausted'] },
+  { shortcode: 'tired_face', emoji: '๐Ÿ˜ซ', keywords: ['exhausted'] },
+  { shortcode: 'angry', emoji: '๐Ÿ˜ ', keywords: ['mad', 'grumpy'] },
+  { shortcode: 'rage', emoji: '๐Ÿ˜ก', keywords: ['angry', 'furious'] },
+  { shortcode: 'triumph', emoji: '๐Ÿ˜ค', keywords: ['proud', 'huffing'] },
+  { shortcode: 'skull', emoji: '๐Ÿ’€', keywords: ['dead', 'death'] },
+  { shortcode: 'poop', emoji: '๐Ÿ’ฉ', keywords: ['crap', 'shit'] },
+  { shortcode: 'clown', emoji: '๐Ÿคก', keywords: ['funny', 'circus'] },
+  { shortcode: 'imp', emoji: '๐Ÿ‘ฟ', keywords: ['devil', 'evil'] },
+  { shortcode: 'ghost', emoji: '๐Ÿ‘ป', keywords: ['boo', 'spooky'] },
+  { shortcode: 'alien', emoji: '๐Ÿ‘ฝ', keywords: ['ufo', 'space'] },
+  { shortcode: 'robot', emoji: '๐Ÿค–', keywords: ['bot', 'machine'] },
+  { shortcode: 'cat', emoji: '๐Ÿ˜บ', keywords: ['kitty', 'meow'] },
+  { shortcode: 'heart_eyes_cat', emoji: '๐Ÿ˜ป', keywords: ['love', 'cat'] },
+  { shortcode: 'joy_cat', emoji: '๐Ÿ˜น', keywords: ['laugh', 'cat'] },
+  { shortcode: 'crying_cat', emoji: '๐Ÿ˜ฟ', keywords: ['sad', 'cat'] },
+  { shortcode: 'pouting_cat', emoji: '๐Ÿ˜พ', keywords: ['angry', 'cat'] },
+  { shortcode: 'see_no_evil', emoji: '๐Ÿ™ˆ', keywords: ['monkey', 'shy'] },
+  { shortcode: 'hear_no_evil', emoji: '๐Ÿ™‰', keywords: ['monkey'] },
+  { shortcode: 'speak_no_evil', emoji: '๐Ÿ™Š', keywords: ['monkey', 'secret'] },
+
+  // Gestures & Body
+  { shortcode: 'wave', emoji: '๐Ÿ‘‹', keywords: ['hello', 'bye', 'hi'] },
+  { shortcode: 'raised_hand', emoji: 'โœ‹', keywords: ['stop', 'high five'] },
+  { shortcode: 'ok_hand', emoji: '๐Ÿ‘Œ', keywords: ['perfect', 'nice'] },
+  { shortcode: 'pinching_hand', emoji: '๐Ÿค', keywords: ['small', 'tiny'] },
+  { shortcode: 'v', emoji: 'โœŒ๏ธ', keywords: ['peace', 'victory'] },
+  { shortcode: 'crossed_fingers', emoji: '๐Ÿคž', keywords: ['luck', 'hope'] },
+  { shortcode: 'love_you', emoji: '๐ŸคŸ', keywords: ['ily', 'sign'] },
+  { shortcode: 'metal', emoji: '๐Ÿค˜', keywords: ['rock', 'horns'] },
+  { shortcode: 'call_me', emoji: '๐Ÿค™', keywords: ['phone', 'shaka'] },
+  { shortcode: 'point_left', emoji: '๐Ÿ‘ˆ', keywords: ['direction'] },
+  { shortcode: 'point_right', emoji: '๐Ÿ‘‰', keywords: ['direction'] },
+  { shortcode: 'point_up', emoji: '๐Ÿ‘†', keywords: ['direction'] },
+  { shortcode: 'point_down', emoji: '๐Ÿ‘‡', keywords: ['direction'] },
+  { shortcode: 'middle_finger', emoji: '๐Ÿ–•', keywords: ['flip', 'rude'] },
+  { shortcode: 'thumbsup', emoji: '๐Ÿ‘', keywords: ['yes', 'good', '+1'] },
+  { shortcode: 'thumbsdown', emoji: '๐Ÿ‘Ž', keywords: ['no', 'bad', '-1'] },
+  { shortcode: 'fist', emoji: 'โœŠ', keywords: ['power', 'punch'] },
+  { shortcode: 'punch', emoji: '๐Ÿ‘Š', keywords: ['fist', 'bump'] },
+  { shortcode: 'clap', emoji: '๐Ÿ‘', keywords: ['applause', 'bravo'] },
+  { shortcode: 'raised_hands', emoji: '๐Ÿ™Œ', keywords: ['celebration', 'yay'] },
+  { shortcode: 'open_hands', emoji: '๐Ÿ‘', keywords: ['hug', 'open'] },
+  { shortcode: 'palms_up', emoji: '๐Ÿคฒ', keywords: ['prayer', 'request'] },
+  { shortcode: 'handshake', emoji: '๐Ÿค', keywords: ['deal', 'agreement'] },
+  { shortcode: 'pray', emoji: '๐Ÿ™', keywords: ['please', 'thanks', 'namaste'] },
+  { shortcode: 'writing', emoji: 'โœ๏ธ', keywords: ['write', 'pen'] },
+  { shortcode: 'nail_care', emoji: '๐Ÿ’…', keywords: ['nails', 'fabulous'] },
+  { shortcode: 'selfie', emoji: '๐Ÿคณ', keywords: ['photo', 'camera'] },
+  { shortcode: 'muscle', emoji: '๐Ÿ’ช', keywords: ['strong', 'flex', 'bicep'] },
+  { shortcode: 'leg', emoji: '๐Ÿฆต', keywords: ['kick'] },
+  { shortcode: 'foot', emoji: '๐Ÿฆถ', keywords: ['kick', 'step'] },
+  { shortcode: 'ear', emoji: '๐Ÿ‘‚', keywords: ['listen', 'hear'] },
+  { shortcode: 'nose', emoji: '๐Ÿ‘ƒ', keywords: ['smell', 'sniff'] },
+  { shortcode: 'brain', emoji: '๐Ÿง ', keywords: ['think', 'smart'] },
+  { shortcode: 'eyes', emoji: '๐Ÿ‘€', keywords: ['look', 'see', 'watch'] },
+  { shortcode: 'eye', emoji: '๐Ÿ‘๏ธ', keywords: ['look', 'see'] },
+  { shortcode: 'tongue', emoji: '๐Ÿ‘…', keywords: ['taste', 'lick'] },
+  { shortcode: 'lips', emoji: '๐Ÿ‘„', keywords: ['mouth', 'kiss'] },
+  { shortcode: 'baby', emoji: '๐Ÿ‘ถ', keywords: ['child', 'infant'] },
+  { shortcode: 'person', emoji: '๐Ÿง‘', keywords: ['human', 'adult'] },
+  { shortcode: 'man', emoji: '๐Ÿ‘จ', keywords: ['male', 'guy'] },
+  { shortcode: 'woman', emoji: '๐Ÿ‘ฉ', keywords: ['female', 'lady'] },
+  { shortcode: 'older_person', emoji: '๐Ÿง“', keywords: ['senior', 'elderly'] },
+
+  // Hearts & Love
+  { shortcode: 'heart', emoji: 'โค๏ธ', keywords: ['love', 'red'] },
+  { shortcode: 'orange_heart', emoji: '๐Ÿงก', keywords: ['love'] },
+  { shortcode: 'yellow_heart', emoji: '๐Ÿ’›', keywords: ['love'] },
+  { shortcode: 'green_heart', emoji: '๐Ÿ’š', keywords: ['love'] },
+  { shortcode: 'blue_heart', emoji: '๐Ÿ’™', keywords: ['love'] },
+  { shortcode: 'purple_heart', emoji: '๐Ÿ’œ', keywords: ['love'] },
+  { shortcode: 'black_heart', emoji: '๐Ÿ–ค', keywords: ['love', 'dark'] },
+  { shortcode: 'white_heart', emoji: '๐Ÿค', keywords: ['love', 'pure'] },
+  { shortcode: 'brown_heart', emoji: '๐ŸคŽ', keywords: ['love'] },
+  { shortcode: 'broken_heart', emoji: '๐Ÿ’”', keywords: ['sad', 'heartbreak'] },
+  { shortcode: 'heartbeat', emoji: '๐Ÿ’“', keywords: ['love', 'pulse'] },
+  { shortcode: 'heartpulse', emoji: '๐Ÿ’—', keywords: ['love', 'growing'] },
+  { shortcode: 'two_hearts', emoji: '๐Ÿ’•', keywords: ['love', 'romance'] },
+  { shortcode: 'revolving_hearts', emoji: '๐Ÿ’ž', keywords: ['love'] },
+  { shortcode: 'cupid', emoji: '๐Ÿ’˜', keywords: ['love', 'arrow'] },
+  { shortcode: 'sparkling_heart', emoji: '๐Ÿ’–', keywords: ['love', 'sparkle'] },
+  { shortcode: 'gift_heart', emoji: '๐Ÿ’', keywords: ['love', 'valentine'] },
+  { shortcode: 'heart_decoration', emoji: '๐Ÿ’Ÿ', keywords: ['love'] },
+  { shortcode: 'kiss', emoji: '๐Ÿ’‹', keywords: ['love', 'lips'] },
+  { shortcode: 'love_letter', emoji: '๐Ÿ’Œ', keywords: ['email', 'message'] },
+
+  // Symbols & Objects
+  { shortcode: 'fire', emoji: '๐Ÿ”ฅ', keywords: ['hot', 'lit', 'flame'] },
+  { shortcode: 'star', emoji: 'โญ', keywords: ['favorite', 'rating'] },
+  { shortcode: 'sparkles', emoji: 'โœจ', keywords: ['shiny', 'new', 'magic'] },
+  { shortcode: 'zap', emoji: 'โšก', keywords: ['lightning', 'power'] },
+  { shortcode: 'boom', emoji: '๐Ÿ’ฅ', keywords: ['explosion', 'collision'] },
+  { shortcode: 'dizzy', emoji: '๐Ÿ’ซ', keywords: ['star', 'dazed'] },
+  { shortcode: 'speech_balloon', emoji: '๐Ÿ’ฌ', keywords: ['talk', 'chat'] },
+  { shortcode: 'thought_balloon', emoji: '๐Ÿ’ญ', keywords: ['think', 'idea'] },
+  { shortcode: 'zzz', emoji: '๐Ÿ’ค', keywords: ['sleep', 'tired'] },
+  { shortcode: 'wave_emoji', emoji: '๐ŸŒŠ', keywords: ['ocean', 'water'] },
+  { shortcode: 'droplet', emoji: '๐Ÿ’ง', keywords: ['water', 'sweat'] },
+  { shortcode: 'sweat_drops', emoji: '๐Ÿ’ฆ', keywords: ['water', 'splash'] },
+  { shortcode: 'dash', emoji: '๐Ÿ’จ', keywords: ['wind', 'running'] },
+  { shortcode: 'hole', emoji: '๐Ÿ•ณ๏ธ', keywords: ['empty', 'void'] },
+  { shortcode: 'bomb', emoji: '๐Ÿ’ฃ', keywords: ['explosive', 'danger'] },
+  { shortcode: 'money', emoji: '๐Ÿ’ฐ', keywords: ['bag', 'cash', 'dollar'] },
+  { shortcode: 'dollar', emoji: '๐Ÿ’ต', keywords: ['money', 'cash'] },
+  { shortcode: 'gem', emoji: '๐Ÿ’Ž', keywords: ['diamond', 'jewel'] },
+  { shortcode: 'bulb', emoji: '๐Ÿ’ก', keywords: ['idea', 'light'] },
+  { shortcode: 'bell', emoji: '๐Ÿ””', keywords: ['notification', 'alert'] },
+  { shortcode: 'loudspeaker', emoji: '๐Ÿ“ข', keywords: ['announce'] },
+  { shortcode: 'mega', emoji: '๐Ÿ“ฃ', keywords: ['megaphone', 'announce'] },
+  { shortcode: 'lock', emoji: '๐Ÿ”’', keywords: ['secure', 'closed'] },
+  { shortcode: 'unlock', emoji: '๐Ÿ”“', keywords: ['open', 'access'] },
+  { shortcode: 'key', emoji: '๐Ÿ”‘', keywords: ['password', 'access'] },
+  { shortcode: 'magnifying_glass', emoji: '๐Ÿ”', keywords: ['search', 'find'] },
+  { shortcode: 'link', emoji: '๐Ÿ”—', keywords: ['chain', 'url'] },
+  { shortcode: 'paperclip', emoji: '๐Ÿ“Ž', keywords: ['attach'] },
+  { shortcode: 'scissors', emoji: 'โœ‚๏ธ', keywords: ['cut', 'snip'] },
+  { shortcode: 'hammer', emoji: '๐Ÿ”จ', keywords: ['tool', 'build'] },
+  { shortcode: 'wrench', emoji: '๐Ÿ”ง', keywords: ['tool', 'fix'] },
+  { shortcode: 'gear', emoji: 'โš™๏ธ', keywords: ['settings', 'cog'] },
+  { shortcode: 'shield', emoji: '๐Ÿ›ก๏ธ', keywords: ['protect', 'security'] },
+  { shortcode: 'trophy', emoji: '๐Ÿ†', keywords: ['win', 'first', 'award'] },
+  { shortcode: 'medal', emoji: '๐Ÿ…', keywords: ['award', 'sports'] },
+  { shortcode: 'first_place', emoji: '๐Ÿฅ‡', keywords: ['gold', 'winner'] },
+  { shortcode: 'second_place', emoji: '๐Ÿฅˆ', keywords: ['silver'] },
+  { shortcode: 'third_place', emoji: '๐Ÿฅ‰', keywords: ['bronze'] },
+  { shortcode: 'soccer', emoji: 'โšฝ', keywords: ['football', 'sports'] },
+  { shortcode: 'basketball', emoji: '๐Ÿ€', keywords: ['sports', 'ball'] },
+  { shortcode: 'football', emoji: '๐Ÿˆ', keywords: ['sports', 'american'] },
+  { shortcode: 'baseball', emoji: 'โšพ', keywords: ['sports', 'ball'] },
+  { shortcode: 'tennis', emoji: '๐ŸŽพ', keywords: ['sports', 'ball'] },
+  { shortcode: 'dart', emoji: '๐ŸŽฏ', keywords: ['target', 'bullseye'] },
+  { shortcode: 'video_game', emoji: '๐ŸŽฎ', keywords: ['gaming', 'controller'] },
+  { shortcode: 'slot_machine', emoji: '๐ŸŽฐ', keywords: ['gambling', 'casino'] },
+  { shortcode: 'game_die', emoji: '๐ŸŽฒ', keywords: ['dice', 'random'] },
+  { shortcode: 'jigsaw', emoji: '๐Ÿงฉ', keywords: ['puzzle', 'piece'] },
+  { shortcode: 'art', emoji: '๐ŸŽจ', keywords: ['palette', 'paint'] },
+  { shortcode: 'performing_arts', emoji: '๐ŸŽญ', keywords: ['theater', 'drama'] },
+  { shortcode: 'microphone', emoji: '๐ŸŽค', keywords: ['sing', 'karaoke'] },
+  { shortcode: 'headphones', emoji: '๐ŸŽง', keywords: ['music', 'audio'] },
+  { shortcode: 'musical_note', emoji: '๐ŸŽต', keywords: ['music', 'song'] },
+  { shortcode: 'notes', emoji: '๐ŸŽถ', keywords: ['music', 'melody'] },
+  { shortcode: 'guitar', emoji: '๐ŸŽธ', keywords: ['music', 'rock'] },
+  { shortcode: 'piano', emoji: '๐ŸŽน', keywords: ['music', 'keys'] },
+  { shortcode: 'drum', emoji: '๐Ÿฅ', keywords: ['music', 'beat'] },
+  { shortcode: 'trumpet', emoji: '๐ŸŽบ', keywords: ['music', 'brass'] },
+  { shortcode: 'violin', emoji: '๐ŸŽป', keywords: ['music', 'string'] },
+  { shortcode: 'movie_camera', emoji: '๐ŸŽฅ', keywords: ['film', 'video'] },
+  { shortcode: 'camera', emoji: '๐Ÿ“ท', keywords: ['photo', 'picture'] },
+  { shortcode: 'tv', emoji: '๐Ÿ“บ', keywords: ['television', 'watch'] },
+  { shortcode: 'computer', emoji: '๐Ÿ’ป', keywords: ['laptop', 'pc'] },
+  { shortcode: 'keyboard', emoji: 'โŒจ๏ธ', keywords: ['type', 'computer'] },
+  { shortcode: 'phone', emoji: '๐Ÿ“ฑ', keywords: ['mobile', 'cell'] },
+  { shortcode: 'email', emoji: '๐Ÿ“ง', keywords: ['mail', 'message'] },
+  { shortcode: 'inbox', emoji: '๐Ÿ“ฅ', keywords: ['mail', 'receive'] },
+  { shortcode: 'outbox', emoji: '๐Ÿ“ค', keywords: ['mail', 'send'] },
+  { shortcode: 'package', emoji: '๐Ÿ“ฆ', keywords: ['box', 'delivery'] },
+  { shortcode: 'memo', emoji: '๐Ÿ“', keywords: ['note', 'write'] },
+  { shortcode: 'page', emoji: '๐Ÿ“„', keywords: ['document', 'file'] },
+  { shortcode: 'bookmark', emoji: '๐Ÿ”–', keywords: ['save', 'tag'] },
+  { shortcode: 'book', emoji: '๐Ÿ“–', keywords: ['read', 'open'] },
+  { shortcode: 'books', emoji: '๐Ÿ“š', keywords: ['library', 'study'] },
+  { shortcode: 'newspaper', emoji: '๐Ÿ“ฐ', keywords: ['news', 'article'] },
+  { shortcode: 'calendar', emoji: '๐Ÿ“…', keywords: ['date', 'schedule'] },
+  { shortcode: 'chart', emoji: '๐Ÿ“ˆ', keywords: ['graph', 'increase'] },
+  { shortcode: 'chart_down', emoji: '๐Ÿ“‰', keywords: ['graph', 'decrease'] },
+  { shortcode: 'bar_chart', emoji: '๐Ÿ“Š', keywords: ['graph', 'stats'] },
+  { shortcode: 'clipboard', emoji: '๐Ÿ“‹', keywords: ['list', 'todo'] },
+  { shortcode: 'pushpin', emoji: '๐Ÿ“Œ', keywords: ['pin', 'location'] },
+  { shortcode: 'round_pushpin', emoji: '๐Ÿ“', keywords: ['pin', 'location'] },
+  { shortcode: 'triangular_ruler', emoji: '๐Ÿ“', keywords: ['math', 'measure'] },
+  { shortcode: 'straight_ruler', emoji: '๐Ÿ“', keywords: ['math', 'measure'] },
+  { shortcode: 'pencil', emoji: 'โœ๏ธ', keywords: ['write', 'draw'] },
+  { shortcode: 'pen', emoji: '๐Ÿ–Š๏ธ', keywords: ['write', 'sign'] },
+  { shortcode: 'crayon', emoji: '๐Ÿ–๏ธ', keywords: ['draw', 'color'] },
+  { shortcode: 'paintbrush', emoji: '๐Ÿ–Œ๏ธ', keywords: ['art', 'paint'] },
+  { shortcode: 'folder', emoji: '๐Ÿ“', keywords: ['file', 'directory'] },
+  { shortcode: 'open_folder', emoji: '๐Ÿ“‚', keywords: ['file', 'directory'] },
+
+  // Nature & Animals
+  { shortcode: 'dog', emoji: '๐Ÿถ', keywords: ['puppy', 'pet', 'woof'] },
+  { shortcode: 'cat_face', emoji: '๐Ÿฑ', keywords: ['kitty', 'pet', 'meow'] },
+  { shortcode: 'mouse', emoji: '๐Ÿญ', keywords: ['rodent'] },
+  { shortcode: 'hamster', emoji: '๐Ÿน', keywords: ['pet', 'rodent'] },
+  { shortcode: 'rabbit', emoji: '๐Ÿฐ', keywords: ['bunny', 'pet'] },
+  { shortcode: 'fox', emoji: '๐ŸฆŠ', keywords: ['animal'] },
+  { shortcode: 'bear', emoji: '๐Ÿป', keywords: ['animal'] },
+  { shortcode: 'panda', emoji: '๐Ÿผ', keywords: ['animal', 'cute'] },
+  { shortcode: 'koala', emoji: '๐Ÿจ', keywords: ['animal', 'australia'] },
+  { shortcode: 'tiger', emoji: '๐Ÿฏ', keywords: ['animal', 'cat'] },
+  { shortcode: 'lion', emoji: '๐Ÿฆ', keywords: ['animal', 'king'] },
+  { shortcode: 'cow', emoji: '๐Ÿฎ', keywords: ['animal', 'farm'] },
+  { shortcode: 'pig', emoji: '๐Ÿท', keywords: ['animal', 'farm'] },
+  { shortcode: 'frog', emoji: '๐Ÿธ', keywords: ['animal', 'toad'] },
+  { shortcode: 'monkey_face', emoji: '๐Ÿต', keywords: ['animal', 'ape'] },
+  { shortcode: 'chicken', emoji: '๐Ÿ”', keywords: ['animal', 'farm', 'hen'] },
+  { shortcode: 'penguin', emoji: '๐Ÿง', keywords: ['animal', 'bird'] },
+  { shortcode: 'bird', emoji: '๐Ÿฆ', keywords: ['animal', 'fly'] },
+  { shortcode: 'eagle', emoji: '๐Ÿฆ…', keywords: ['animal', 'bird'] },
+  { shortcode: 'duck', emoji: '๐Ÿฆ†', keywords: ['animal', 'bird', 'quack'] },
+  { shortcode: 'owl', emoji: '๐Ÿฆ‰', keywords: ['animal', 'bird', 'night'] },
+  { shortcode: 'bat', emoji: '๐Ÿฆ‡', keywords: ['animal', 'night', 'vampire'] },
+  { shortcode: 'wolf', emoji: '๐Ÿบ', keywords: ['animal'] },
+  { shortcode: 'horse', emoji: '๐Ÿด', keywords: ['animal'] },
+  { shortcode: 'unicorn', emoji: '๐Ÿฆ„', keywords: ['animal', 'magic'] },
+  { shortcode: 'bee', emoji: '๐Ÿ', keywords: ['insect', 'honey'] },
+  { shortcode: 'bug', emoji: '๐Ÿ›', keywords: ['insect', 'caterpillar'] },
+  { shortcode: 'butterfly', emoji: '๐Ÿฆ‹', keywords: ['insect', 'pretty'] },
+  { shortcode: 'snail', emoji: '๐ŸŒ', keywords: ['slow'] },
+  { shortcode: 'lady_beetle', emoji: '๐Ÿž', keywords: ['insect', 'bug'] },
+  { shortcode: 'ant', emoji: '๐Ÿœ', keywords: ['insect', 'bug'] },
+  { shortcode: 'spider', emoji: '๐Ÿ•ท๏ธ', keywords: ['insect', 'scary'] },
+  { shortcode: 'turtle', emoji: '๐Ÿข', keywords: ['animal', 'slow'] },
+  { shortcode: 'snake', emoji: '๐Ÿ', keywords: ['animal', 'reptile'] },
+  { shortcode: 'dragon', emoji: '๐Ÿฒ', keywords: ['animal', 'mythical'] },
+  { shortcode: 'dinosaur', emoji: '๐Ÿฆ•', keywords: ['animal', 'extinct'] },
+  { shortcode: 't_rex', emoji: '๐Ÿฆ–', keywords: ['animal', 'dinosaur'] },
+  { shortcode: 'whale', emoji: '๐Ÿณ', keywords: ['animal', 'ocean'] },
+  { shortcode: 'dolphin', emoji: '๐Ÿฌ', keywords: ['animal', 'ocean'] },
+  { shortcode: 'fish', emoji: '๐ŸŸ', keywords: ['animal', 'ocean'] },
+  { shortcode: 'tropical_fish', emoji: '๐Ÿ ', keywords: ['animal', 'ocean'] },
+  { shortcode: 'shark', emoji: '๐Ÿฆˆ', keywords: ['animal', 'ocean'] },
+  { shortcode: 'octopus', emoji: '๐Ÿ™', keywords: ['animal', 'ocean'] },
+  { shortcode: 'crab', emoji: '๐Ÿฆ€', keywords: ['animal', 'ocean'] },
+  { shortcode: 'lobster', emoji: '๐Ÿฆž', keywords: ['animal', 'ocean'] },
+  { shortcode: 'shrimp', emoji: '๐Ÿฆ', keywords: ['animal', 'ocean'] },
+
+  // Plants & Nature
+  { shortcode: 'bouquet', emoji: '๐Ÿ’', keywords: ['flowers', 'gift'] },
+  { shortcode: 'cherry_blossom', emoji: '๐ŸŒธ', keywords: ['flower', 'spring'] },
+  { shortcode: 'rose', emoji: '๐ŸŒน', keywords: ['flower', 'love'] },
+  { shortcode: 'tulip', emoji: '๐ŸŒท', keywords: ['flower', 'spring'] },
+  { shortcode: 'sunflower', emoji: '๐ŸŒป', keywords: ['flower', 'summer'] },
+  { shortcode: 'hibiscus', emoji: '๐ŸŒบ', keywords: ['flower', 'tropical'] },
+  { shortcode: 'seedling', emoji: '๐ŸŒฑ', keywords: ['plant', 'grow'] },
+  { shortcode: 'evergreen_tree', emoji: '๐ŸŒฒ', keywords: ['tree', 'pine'] },
+  { shortcode: 'deciduous_tree', emoji: '๐ŸŒณ', keywords: ['tree'] },
+  { shortcode: 'palm_tree', emoji: '๐ŸŒด', keywords: ['tree', 'tropical'] },
+  { shortcode: 'cactus', emoji: '๐ŸŒต', keywords: ['plant', 'desert'] },
+  { shortcode: 'herb', emoji: '๐ŸŒฟ', keywords: ['plant', 'leaf'] },
+  { shortcode: 'shamrock', emoji: 'โ˜˜๏ธ', keywords: ['clover', 'irish'] },
+  { shortcode: 'four_leaf_clover', emoji: '๐Ÿ€', keywords: ['luck', 'irish'] },
+  { shortcode: 'maple_leaf', emoji: '๐Ÿ', keywords: ['fall', 'autumn'] },
+  { shortcode: 'fallen_leaf', emoji: '๐Ÿ‚', keywords: ['fall', 'autumn'] },
+  { shortcode: 'leaves', emoji: '๐Ÿƒ', keywords: ['leaf', 'wind'] },
+  { shortcode: 'mushroom', emoji: '๐Ÿ„', keywords: ['fungus'] },
+
+  // Food & Drink
+  { shortcode: 'apple', emoji: '๐ŸŽ', keywords: ['fruit', 'red'] },
+  { shortcode: 'green_apple', emoji: '๐Ÿ', keywords: ['fruit'] },
+  { shortcode: 'pear', emoji: '๐Ÿ', keywords: ['fruit'] },
+  { shortcode: 'orange', emoji: '๐ŸŠ', keywords: ['fruit', 'citrus'] },
+  { shortcode: 'lemon', emoji: '๐Ÿ‹', keywords: ['fruit', 'citrus'] },
+  { shortcode: 'banana', emoji: '๐ŸŒ', keywords: ['fruit'] },
+  { shortcode: 'watermelon', emoji: '๐Ÿ‰', keywords: ['fruit', 'summer'] },
+  { shortcode: 'grapes', emoji: '๐Ÿ‡', keywords: ['fruit', 'wine'] },
+  { shortcode: 'strawberry', emoji: '๐Ÿ“', keywords: ['fruit', 'berry'] },
+  { shortcode: 'cherries', emoji: '๐Ÿ’', keywords: ['fruit'] },
+  { shortcode: 'peach', emoji: '๐Ÿ‘', keywords: ['fruit'] },
+  { shortcode: 'mango', emoji: '๐Ÿฅญ', keywords: ['fruit', 'tropical'] },
+  { shortcode: 'pineapple', emoji: '๐Ÿ', keywords: ['fruit', 'tropical'] },
+  { shortcode: 'coconut', emoji: '๐Ÿฅฅ', keywords: ['fruit', 'tropical'] },
+  { shortcode: 'avocado', emoji: '๐Ÿฅ‘', keywords: ['fruit', 'guacamole'] },
+  { shortcode: 'tomato', emoji: '๐Ÿ…', keywords: ['vegetable', 'red'] },
+  { shortcode: 'eggplant', emoji: '๐Ÿ†', keywords: ['vegetable', 'purple'] },
+  { shortcode: 'potato', emoji: '๐Ÿฅ”', keywords: ['vegetable', 'spud'] },
+  { shortcode: 'carrot', emoji: '๐Ÿฅ•', keywords: ['vegetable', 'orange'] },
+  { shortcode: 'corn', emoji: '๐ŸŒฝ', keywords: ['vegetable', 'maize'] },
+  { shortcode: 'hot_pepper', emoji: '๐ŸŒถ๏ธ', keywords: ['spicy', 'chili'] },
+  { shortcode: 'broccoli', emoji: '๐Ÿฅฆ', keywords: ['vegetable', 'green'] },
+  { shortcode: 'bread', emoji: '๐Ÿž', keywords: ['food', 'toast'] },
+  { shortcode: 'croissant', emoji: '๐Ÿฅ', keywords: ['food', 'french'] },
+  { shortcode: 'pretzel', emoji: '๐Ÿฅจ', keywords: ['food', 'snack'] },
+  { shortcode: 'bagel', emoji: '๐Ÿฅฏ', keywords: ['food', 'breakfast'] },
+  { shortcode: 'cheese', emoji: '๐Ÿง€', keywords: ['food', 'dairy'] },
+  { shortcode: 'egg', emoji: '๐Ÿฅš', keywords: ['food', 'breakfast'] },
+  { shortcode: 'bacon', emoji: '๐Ÿฅ“', keywords: ['food', 'breakfast'] },
+  { shortcode: 'pancakes', emoji: '๐Ÿฅž', keywords: ['food', 'breakfast'] },
+  { shortcode: 'waffle', emoji: '๐Ÿง‡', keywords: ['food', 'breakfast'] },
+  { shortcode: 'steak', emoji: '๐Ÿฅฉ', keywords: ['food', 'meat'] },
+  { shortcode: 'poultry_leg', emoji: '๐Ÿ—', keywords: ['food', 'chicken'] },
+  { shortcode: 'hamburger', emoji: '๐Ÿ”', keywords: ['food', 'burger'] },
+  { shortcode: 'fries', emoji: '๐ŸŸ', keywords: ['food', 'fast'] },
+  { shortcode: 'pizza', emoji: '๐Ÿ•', keywords: ['food', 'italian'] },
+  { shortcode: 'hot_dog', emoji: '๐ŸŒญ', keywords: ['food', 'fast'] },
+  { shortcode: 'sandwich', emoji: '๐Ÿฅช', keywords: ['food', 'lunch'] },
+  { shortcode: 'taco', emoji: '๐ŸŒฎ', keywords: ['food', 'mexican'] },
+  { shortcode: 'burrito', emoji: '๐ŸŒฏ', keywords: ['food', 'mexican'] },
+  { shortcode: 'sushi', emoji: '๐Ÿฃ', keywords: ['food', 'japanese'] },
+  { shortcode: 'ramen', emoji: '๐Ÿœ', keywords: ['food', 'noodles'] },
+  { shortcode: 'spaghetti', emoji: '๐Ÿ', keywords: ['food', 'pasta'] },
+  { shortcode: 'curry', emoji: '๐Ÿ›', keywords: ['food', 'rice'] },
+  { shortcode: 'rice', emoji: '๐Ÿš', keywords: ['food', 'white'] },
+  { shortcode: 'salad', emoji: '๐Ÿฅ—', keywords: ['food', 'healthy'] },
+  { shortcode: 'popcorn', emoji: '๐Ÿฟ', keywords: ['food', 'movie'] },
+  { shortcode: 'cake', emoji: '๐ŸŽ‚', keywords: ['food', 'birthday'] },
+  { shortcode: 'cupcake', emoji: '๐Ÿง', keywords: ['food', 'sweet'] },
+  { shortcode: 'pie', emoji: '๐Ÿฅง', keywords: ['food', 'dessert'] },
+  { shortcode: 'cookie', emoji: '๐Ÿช', keywords: ['food', 'sweet'] },
+  { shortcode: 'chocolate', emoji: '๐Ÿซ', keywords: ['food', 'sweet'] },
+  { shortcode: 'candy', emoji: '๐Ÿฌ', keywords: ['food', 'sweet'] },
+  { shortcode: 'lollipop', emoji: '๐Ÿญ', keywords: ['food', 'sweet'] },
+  { shortcode: 'donut', emoji: '๐Ÿฉ', keywords: ['food', 'sweet'] },
+  { shortcode: 'ice_cream', emoji: '๐Ÿจ', keywords: ['food', 'dessert'] },
+  { shortcode: 'icecream', emoji: '๐Ÿฆ', keywords: ['food', 'dessert', 'cone'] },
+  { shortcode: 'coffee', emoji: 'โ˜•', keywords: ['drink', 'caffeine'] },
+  { shortcode: 'tea', emoji: '๐Ÿต', keywords: ['drink', 'green'] },
+  { shortcode: 'beer', emoji: '๐Ÿบ', keywords: ['drink', 'alcohol'] },
+  { shortcode: 'beers', emoji: '๐Ÿป', keywords: ['drink', 'cheers'] },
+  { shortcode: 'wine_glass', emoji: '๐Ÿท', keywords: ['drink', 'alcohol'] },
+  { shortcode: 'cocktail', emoji: '๐Ÿธ', keywords: ['drink', 'alcohol'] },
+  { shortcode: 'tropical_drink', emoji: '๐Ÿน', keywords: ['drink', 'vacation'] },
+  { shortcode: 'champagne', emoji: '๐Ÿพ', keywords: ['drink', 'celebrate'] },
+  { shortcode: 'milk', emoji: '๐Ÿฅ›', keywords: ['drink', 'dairy'] },
+  { shortcode: 'baby_bottle', emoji: '๐Ÿผ', keywords: ['drink', 'infant'] },
+  { shortcode: 'juice', emoji: '๐Ÿงƒ', keywords: ['drink', 'box'] },
+  { shortcode: 'cup_with_straw', emoji: '๐Ÿฅค', keywords: ['drink', 'soda'] },
+
+  // Weather & Nature
+  { shortcode: 'sun', emoji: 'โ˜€๏ธ', keywords: ['weather', 'sunny', 'bright'] },
+  { shortcode: 'moon', emoji: '๐ŸŒ™', keywords: ['night', 'sleep'] },
+  { shortcode: 'full_moon', emoji: '๐ŸŒ•', keywords: ['night', 'lunar'] },
+  { shortcode: 'new_moon', emoji: '๐ŸŒ‘', keywords: ['night', 'dark'] },
+  { shortcode: 'star2', emoji: '๐ŸŒŸ', keywords: ['glow', 'sparkle'] },
+  { shortcode: 'milky_way', emoji: '๐ŸŒŒ', keywords: ['galaxy', 'space'] },
+  { shortcode: 'cloud', emoji: 'โ˜๏ธ', keywords: ['weather', 'sky'] },
+  { shortcode: 'sun_behind_cloud', emoji: 'โ›…', keywords: ['weather'] },
+  { shortcode: 'cloud_with_rain', emoji: '๐ŸŒง๏ธ', keywords: ['weather', 'rainy'] 
},
+  { shortcode: 'thunder', emoji: 'โ›ˆ๏ธ', keywords: ['weather', 'storm'] },
+  { shortcode: 'snowflake', emoji: 'โ„๏ธ', keywords: ['weather', 'cold'] },
+  { shortcode: 'snowman', emoji: 'โ˜ƒ๏ธ', keywords: ['winter', 'snow'] },
+  { shortcode: 'wind_blowing', emoji: '๐ŸŒฌ๏ธ', keywords: ['weather', 'air'] },
+  { shortcode: 'tornado', emoji: '๐ŸŒช๏ธ', keywords: ['weather', 'storm'] },
+  { shortcode: 'fog', emoji: '๐ŸŒซ๏ธ', keywords: ['weather', 'mist'] },
+  { shortcode: 'umbrella', emoji: 'โ˜‚๏ธ', keywords: ['rain', 'weather'] },
+  { shortcode: 'rainbow', emoji: '๐ŸŒˆ', keywords: ['weather', 'pride'] },
+  { shortcode: 'earth', emoji: '๐ŸŒ', keywords: ['world', 'planet'] },
+  { shortcode: 'earth_americas', emoji: '๐ŸŒŽ', keywords: ['world', 'planet'] },
+  { shortcode: 'earth_asia', emoji: '๐ŸŒ', keywords: ['world', 'planet'] },
+  { shortcode: 'rocket', emoji: '๐Ÿš€', keywords: ['space', 'launch'] },
+  { shortcode: 'satellite', emoji: '๐Ÿ›ฐ๏ธ', keywords: ['space', 'orbit'] },
+  { shortcode: 'ufo', emoji: '๐Ÿ›ธ', keywords: ['alien', 'space'] },
+
+  // Checkmarks & Common Symbols
+  { shortcode: 'white_check_mark', emoji: 'โœ…', keywords: ['done', 'yes', 'ok'] 
},
+  { shortcode: 'check', emoji: 'โœ”๏ธ', keywords: ['done', 'yes'] },
+  { shortcode: 'x', emoji: 'โŒ', keywords: ['no', 'wrong', 'cancel'] },
+  { shortcode: 'cross_mark', emoji: 'โŽ', keywords: ['no', 'wrong'] },
+  { shortcode: 'plus', emoji: 'โž•', keywords: ['add', 'math'] },
+  { shortcode: 'minus', emoji: 'โž–', keywords: ['subtract', 'math'] },
+  { shortcode: 'divide', emoji: 'โž—', keywords: ['math', 'division'] },
+  { shortcode: 'multiply', emoji: 'โœ–๏ธ', keywords: ['math', 'times'] },
+  { shortcode: 'infinity', emoji: 'โ™พ๏ธ', keywords: ['forever', 'endless'] },
+  { shortcode: 'question', emoji: 'โ“', keywords: ['ask', 'what'] },
+  { shortcode: 'grey_question', emoji: 'โ”', keywords: ['ask', 'what'] },
+  { shortcode: 'exclamation', emoji: 'โ—', keywords: ['alert', 'important'] },
+  { shortcode: 'grey_exclamation', emoji: 'โ•', keywords: ['alert'] },
+  { shortcode: 'warning', emoji: 'โš ๏ธ', keywords: ['alert', 'caution'] },
+  { shortcode: 'no_entry', emoji: 'โ›”', keywords: ['stop', 'forbidden'] },
+  { shortcode: 'prohibited', emoji: '๐Ÿšซ', keywords: ['stop', 'banned'] },
+  { shortcode: 'recycle', emoji: 'โ™ป๏ธ', keywords: ['environment', 'green'] },
+  { shortcode: 'arrow_up', emoji: 'โฌ†๏ธ', keywords: ['direction', 'north'] },
+  { shortcode: 'arrow_down', emoji: 'โฌ‡๏ธ', keywords: ['direction', 'south'] },
+  { shortcode: 'arrow_left', emoji: 'โฌ…๏ธ', keywords: ['direction', 'west'] },
+  { shortcode: 'arrow_right', emoji: 'โžก๏ธ', keywords: ['direction', 'east'] },
+  {
+    shortcode: 'arrow_upper_right',
+    emoji: 'โ†—๏ธ',
+    keywords: ['direction', 'northeast'],
+  },
+  {
+    shortcode: 'arrow_lower_right',
+    emoji: 'โ†˜๏ธ',
+    keywords: ['direction', 'southeast'],
+  },
+  {
+    shortcode: 'arrow_lower_left',
+    emoji: 'โ†™๏ธ',
+    keywords: ['direction', 'southwest'],
+  },
+  {
+    shortcode: 'arrow_upper_left',
+    emoji: 'โ†–๏ธ',
+    keywords: ['direction', 'northwest'],
+  },
+  {
+    shortcode: 'left_right_arrow',
+    emoji: 'โ†”๏ธ',
+    keywords: ['direction', 'horizontal'],
+  },
+  {
+    shortcode: 'up_down_arrow',
+    emoji: 'โ†•๏ธ',
+    keywords: ['direction', 'vertical'],
+  },
+  { shortcode: 'arrows_clockwise', emoji: '๐Ÿ”ƒ', keywords: ['refresh', 'sync'] },
+  {
+    shortcode: 'arrows_counterclockwise',
+    emoji: '๐Ÿ”„',
+    keywords: ['refresh', 'sync'],
+  },
+  { shortcode: 'back', emoji: '๐Ÿ”™', keywords: ['return', 'previous'] },
+  { shortcode: 'end', emoji: '๐Ÿ”š', keywords: ['finish', 'last'] },
+  { shortcode: 'on', emoji: '๐Ÿ”›', keywords: ['active'] },
+  { shortcode: 'soon', emoji: '๐Ÿ”œ', keywords: ['coming', 'future'] },
+  { shortcode: 'top', emoji: '๐Ÿ”', keywords: ['best', 'first'] },
+  { shortcode: 'new', emoji: '๐Ÿ†•', keywords: ['fresh', 'latest'] },
+  { shortcode: 'free', emoji: '๐Ÿ†“', keywords: ['gratis', 'cost'] },
+  { shortcode: 'up', emoji: '๐Ÿ†™', keywords: ['increase', 'level'] },
+  { shortcode: 'cool', emoji: '๐Ÿ†’', keywords: ['nice', 'awesome'] },
+  { shortcode: 'ok', emoji: '๐Ÿ†—', keywords: ['yes', 'approve'] },
+  { shortcode: 'sos', emoji: '๐Ÿ†˜', keywords: ['help', 'emergency'] },
+  { shortcode: 'stop_sign', emoji: '๐Ÿ›‘', keywords: ['halt', 'cease'] },
+  { shortcode: 'a', emoji: '๐Ÿ…ฐ๏ธ', keywords: ['letter', 'blood'] },
+  { shortcode: 'b', emoji: '๐Ÿ…ฑ๏ธ', keywords: ['letter', 'blood'] },
+  { shortcode: 'o', emoji: '๐Ÿ…พ๏ธ', keywords: ['letter', 'blood'] },
+  { shortcode: 'information', emoji: 'โ„น๏ธ', keywords: ['info', 'help'] },
+  { shortcode: 'copyright', emoji: 'ยฉ๏ธ', keywords: ['legal', 'ip'] },
+  { shortcode: 'registered', emoji: 'ยฎ๏ธ', keywords: ['legal', 'brand'] },
+  { shortcode: 'tm', emoji: 'โ„ข๏ธ', keywords: ['legal', 'trademark'] },
+  { shortcode: 'one', emoji: '1๏ธโƒฃ', keywords: ['number', 'first'] },
+  { shortcode: 'two', emoji: '2๏ธโƒฃ', keywords: ['number', 'second'] },
+  { shortcode: 'three', emoji: '3๏ธโƒฃ', keywords: ['number', 'third'] },
+  { shortcode: 'four', emoji: '4๏ธโƒฃ', keywords: ['number'] },
+  { shortcode: 'five', emoji: '5๏ธโƒฃ', keywords: ['number'] },
+  { shortcode: 'six', emoji: '6๏ธโƒฃ', keywords: ['number'] },
+  { shortcode: 'seven', emoji: '7๏ธโƒฃ', keywords: ['number'] },
+  { shortcode: 'eight', emoji: '8๏ธโƒฃ', keywords: ['number'] },
+  { shortcode: 'nine', emoji: '9๏ธโƒฃ', keywords: ['number'] },
+  { shortcode: 'zero', emoji: '0๏ธโƒฃ', keywords: ['number'] },
+  { shortcode: 'keycap_ten', emoji: '๐Ÿ”Ÿ', keywords: ['number', 'ten'] },
+  { shortcode: 'hash', emoji: '#๏ธโƒฃ', keywords: ['number', 'pound', 'hashtag'] 
},
+  { shortcode: 'asterisk', emoji: '*๏ธโƒฃ', keywords: ['star', 'symbol'] },
+  { shortcode: 'eject', emoji: 'โ๏ธ', keywords: ['media', 'remove'] },
+  { shortcode: 'play', emoji: 'โ–ถ๏ธ', keywords: ['media', 'start'] },
+  { shortcode: 'pause', emoji: 'โธ๏ธ', keywords: ['media', 'wait'] },
+  { shortcode: 'stop', emoji: 'โน๏ธ', keywords: ['media', 'end'] },
+  { shortcode: 'record', emoji: 'โบ๏ธ', keywords: ['media', 'red'] },
+  { shortcode: 'fast_forward', emoji: 'โฉ', keywords: ['media', 'skip'] },
+  { shortcode: 'rewind', emoji: 'โช', keywords: ['media', 'back'] },
+  { shortcode: 'next_track', emoji: 'โญ๏ธ', keywords: ['media', 'skip'] },
+  { shortcode: 'previous_track', emoji: 'โฎ๏ธ', keywords: ['media', 'back'] },
+  { shortcode: 'cinema', emoji: '๐ŸŽฆ', keywords: ['movie', 'film'] },
+  { shortcode: 'low_brightness', emoji: '๐Ÿ”…', keywords: ['dim', 'light'] },
+  { shortcode: 'high_brightness', emoji: '๐Ÿ”†', keywords: ['bright', 'light'] },
+  { shortcode: 'signal_strength', emoji: '๐Ÿ“ถ', keywords: ['wifi', 'bars'] },
+  { shortcode: 'vibration', emoji: '๐Ÿ“ณ', keywords: ['phone', 'mode'] },
+  { shortcode: 'mobile_off', emoji: '๐Ÿ“ด', keywords: ['phone', 'silent'] },
+  { shortcode: 'female', emoji: 'โ™€๏ธ', keywords: ['woman', 'gender'] },
+  { shortcode: 'male', emoji: 'โ™‚๏ธ', keywords: ['man', 'gender'] },
+  { shortcode: 'medical', emoji: 'โš•๏ธ', keywords: ['health', 'doctor'] },
+  { shortcode: 'atom', emoji: 'โš›๏ธ', keywords: ['science', 'physics'] },
+];
+
+/**
+ * Filter emojis by search text (checks shortcode and keywords)
+ */
+export function filterEmojis(
+  searchText: string,
+  limit: number = 10,
+): EmojiItem[] {
+  if (!searchText) return [];
+
+  const lowerSearch = searchText.toLowerCase();

Review Comment:
   **Suggestion:** Normalization bug: the function does not trim input or 
remove leading colon(s) (e.g. ":smile") which is commonly provided by 
Slack-like autocomplete triggers, so searches with a leading ':' or surrounding 
whitespace will not match any shortcodes; normalize the input (trim and strip 
leading colons) before searching. [logic error]
   
   **Severity Level:** Minor โš ๏ธ
   ```suggestion
     const normalized = searchText?.trim().replace(/^:+/, '');
     if (!normalized) return [];
   
     const lowerSearch = normalized.toLowerCase();
   ```
   <details>
   <summary><b>Why it matters? โญ </b></summary>
   
   This is a real usability bug: users commonly type ":smile" (leading colon) 
or add surrounding whitespace when using Slack-like autocompletes. As 
shortcodes in EMOJI_DATA don't include the colon, the current code won't match 
those inputs. Normalizing (trim + strip leading colons) directly fixes the 
behavior with a small, low-risk change.
   </details>
   <details>
   <summary><b>Prompt for AI Agent ๐Ÿค– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/packages/superset-ui-core/src/components/EmojiTextArea/emojiData.ts
   **Line:** 559:561
   **Comment:**
        *Logic Error: Normalization bug: the function does not trim input or 
remove leading colon(s) (e.g. ":smile") which is commonly provided by 
Slack-like autocomplete triggers, so searches with a leading ':' or surrounding 
whitespace will not match any shortcodes; normalize the input (trim and strip 
leading colons) before searching.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to