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;
