This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch fix/ace-emoji-token-classes
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 0f51c61370f287d517adf5d7cd8972ad7887d616
Author: Evan Rusackas <[email protected]>
AuthorDate: Mon Jul 6 11:58:17 2026 -0700

    fix(ace-editor): carry token classes onto emoji boxes
    
    Follow-up to #41697: the emoji spans were appended outside the
    token-class wrapper ace puts around non-text tokens, so token styling
    that isn't glyph color (comment italics, invalid-token backgrounds)
    stopped applying to emoji segments. Mirror ace's text_util token-class
    handling directly on the emoji box.
    
    Co-Authored-By: Claude Fable 5 <[email protected]>
---
 .../AsyncAceEditor/emojiWidthPatch.test.ts         | 29 ++++++++++++++++++++++
 .../components/AsyncAceEditor/emojiWidthPatch.ts   | 14 ++++++++++-
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/emojiWidthPatch.test.ts
 
b/superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/emojiWidthPatch.test.ts
index 2da3e2bdd9e..36c1a5d4af3 100644
--- 
a/superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/emojiWidthPatch.test.ts
+++ 
b/superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/emojiWidthPatch.test.ts
@@ -132,6 +132,35 @@ test('renderer leaves emoji-free tokens entirely to the 
original path', () => {
   expect(screenColumn).toBe(8);
 });
 
+test('emoji boxes carry the token-class styling of their token', () => {
+  const container = document.createElement('div');
+  const layer = new TextLayer(container);
+  layer.config = { characterWidth: 10 };
+
+  const parent = document.createElement('div');
+  layer.$renderToken(
+    parent,
+    0,
+    { type: 'constant.language', value: '✨' },
+    '✨',
+  );
+
+  const box = parent.querySelector<HTMLElement>('.ace_cjk');
+  expect(box?.className).toBe('ace_cjk ace_constant ace_language');
+});
+
+test('emoji boxes in plain text tokens carry no extra classes', () => {
+  const container = document.createElement('div');
+  const layer = new TextLayer(container);
+  layer.config = { characterWidth: 10 };
+
+  const parent = document.createElement('div');
+  layer.$renderToken(parent, 0, { type: 'text', value: '✨' }, '✨');
+
+  const box = parent.querySelector<HTMLElement>('.ace_cjk');
+  expect(box?.className).toBe('ace_cjk');
+});
+
 test('patch is idempotent', () => {
   const before = EditSession.prototype.$getStringScreenWidth;
   patchAceEmojiWidths(EditSession, TextLayer);
diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/emojiWidthPatch.ts
 
b/superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/emojiWidthPatch.ts
index 816ce06e631..55a0c5c889a 100644
--- 
a/superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/emojiWidthPatch.ts
+++ 
b/superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/emojiWidthPatch.ts
@@ -49,6 +49,10 @@
 
 const VS16 = 0xfe0f;
 
+// Tokens ace renders as bare text nodes with no token-class span; mirrors
+// ace/layer/text_util's textTokens set.
+const TEXT_TOKENS = new Set(['text', 'rparen', 'lparen']);
+
 // Emoji_Presentation covers exactly the codepoints browsers render as color
 // emoji without a variation selector. Lone surrogates never match it (the
 // astral path is already consistent), so only BMP emoji change behavior.
@@ -243,6 +247,14 @@ export function patchAceEmojiWidths(
     if (!EMOJI_RUN_TEST_RE.test(value)) {
       return origRenderToken.call(this, parent, screenColumn, token, value);
     }
+    // Non-text tokens normally have their whole fragment wrapped in a
+    // token-class span ("ace_" + dotted type); carry those classes on the
+    // emoji box itself so syntax styling that isn't glyph color (comment
+    // italics, invalid-token backgrounds, …) still applies to emoji.
+    // Mirrors ace's text_util.isTextToken and $renderToken class handling.
+    const tokenClasses = TEXT_TOKENS.has(token.type)
+      ? ''
+      : ` ace_${token.type.replace(/\./g, ' ace_')}`;
     let column = screenColumn;
     value.split(EMOJI_RUN_SPLIT_RE).forEach((part, index) => {
       if (!part) {
@@ -256,7 +268,7 @@ export function patchAceEmojiWidths(
           cluster => {
             const span = this.dom.createElement('span');
             span.style.width = `${this.config.characterWidth * 2}px`;
-            span.className = 'ace_cjk';
+            span.className = `ace_cjk${tokenClasses}`;
             span.textContent = cluster;
             parent.appendChild(span);
             column += 2;

Reply via email to