From 72c61247282467bd820b614374f819e74078da39 Mon Sep 17 00:00:00 2001 From: sanjayrohith Date: Sun, 15 Mar 2026 14:47:30 +0530 Subject: [PATCH 1/2] fix: centralize toSnakeCase into web_core to eliminate renderer duplication --- renderers/angular/src/lib/catalog/icon.ts | 6 +++++- renderers/lit/src/0.8/ui/icon.ts | 4 ++-- renderers/react/src/components/content/Icon.tsx | 10 +--------- renderers/web_core/src/v0_8/styles/icons.ts | 15 +++++++++++++++ 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/renderers/angular/src/lib/catalog/icon.ts b/renderers/angular/src/lib/catalog/icon.ts index 770420d31..86148357b 100644 --- a/renderers/angular/src/lib/catalog/icon.ts +++ b/renderers/angular/src/lib/catalog/icon.ts @@ -17,6 +17,7 @@ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core'; import { DynamicComponent } from '../rendering/dynamic-component'; import * as Primitives from '@a2ui/web_core/types/primitives'; +import { toSnakeCase } from '@a2ui/web_core/styles/icons'; @Component({ selector: 'a2ui-icon', @@ -45,5 +46,8 @@ import * as Primitives from '@a2ui/web_core/types/primitives'; }) export class Icon extends DynamicComponent { readonly name = input.required(); - protected readonly resolvedName = computed(() => this.resolvePrimitive(this.name())); + protected readonly resolvedName = computed(() => { + const name = this.resolvePrimitive(this.name()); + return name ? toSnakeCase(name) : name; + }); } diff --git a/renderers/lit/src/0.8/ui/icon.ts b/renderers/lit/src/0.8/ui/icon.ts index aec35da79..1aa4d88ba 100644 --- a/renderers/lit/src/0.8/ui/icon.ts +++ b/renderers/lit/src/0.8/ui/icon.ts @@ -22,6 +22,7 @@ import * as Primitives from "@a2ui/web_core/types/primitives"; import { classMap } from "lit/directives/class-map.js"; import { styleMap } from "lit/directives/style-map.js"; import { structuralStyles } from "./styles.js"; +import { toSnakeCase } from "@a2ui/web_core/styles/icons"; @customElement("a2ui-icon") export class Icon extends Root { @@ -68,8 +69,7 @@ export class Icon extends Root { } const render = (url: string) => { - url = url.replace(/([A-Z])/gm, "_$1").toLocaleLowerCase(); - return html`${url}`; + return html`${toSnakeCase(url)}`; }; if (this.name && typeof this.name === "object") { diff --git a/renderers/react/src/components/content/Icon.tsx b/renderers/react/src/components/content/Icon.tsx index be8a607ee..bf486410a 100644 --- a/renderers/react/src/components/content/Icon.tsx +++ b/renderers/react/src/components/content/Icon.tsx @@ -19,15 +19,7 @@ import type * as Types from '@a2ui/web_core/types/types'; import type {A2UIComponentProps} from '../../types'; import {useA2UIComponent} from '../../hooks/useA2UIComponent'; import {classMapToString, stylesToObject} from '../../lib/utils'; - -/** - * Convert camelCase to snake_case for Material Symbols font. - * e.g., "shoppingCart" -> "shopping_cart" - * This matches the Lit renderer's approach. - */ -function toSnakeCase(str: string): string { - return str.replace(/([A-Z])/g, '_$1').toLowerCase(); -} +import {toSnakeCase} from '@a2ui/web_core/styles/icons'; /** * Icon component - renders an icon using Material Symbols Outlined font. diff --git a/renderers/web_core/src/v0_8/styles/icons.ts b/renderers/web_core/src/v0_8/styles/icons.ts index e62d7f509..0533e7903 100644 --- a/renderers/web_core/src/v0_8/styles/icons.ts +++ b/renderers/web_core/src/v0_8/styles/icons.ts @@ -14,6 +14,21 @@ * limitations under the License. */ +/** + * Converts a camelCase icon name to snake_case for use with Material Symbols. + * + * The Material Symbols font uses snake_case names (e.g., "shopping_cart"), + * but A2UI icon names may be provided in camelCase (e.g., "shoppingCart"). + * This utility normalizes them so all renderers behave consistently. + * + * @example + * toSnakeCase('shoppingCart') // -> 'shopping_cart' + * toSnakeCase('home') // -> 'home' + */ +export function toSnakeCase(str: string): string { + return str.replace(/([A-Z])/g, '_$1').toLowerCase(); +} + /** * CSS classes for Google Symbols. * From 54087adf4d18e8a906bf70269325d967b8879fe3 Mon Sep 17 00:00:00 2001 From: SANJAY ROHITH L Date: Sun, 15 Mar 2026 14:51:11 +0530 Subject: [PATCH 2/2] Update renderers/web_core/src/v0_8/styles/icons.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- renderers/web_core/src/v0_8/styles/icons.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderers/web_core/src/v0_8/styles/icons.ts b/renderers/web_core/src/v0_8/styles/icons.ts index 0533e7903..404a86309 100644 --- a/renderers/web_core/src/v0_8/styles/icons.ts +++ b/renderers/web_core/src/v0_8/styles/icons.ts @@ -26,7 +26,7 @@ * toSnakeCase('home') // -> 'home' */ export function toSnakeCase(str: string): string { - return str.replace(/([A-Z])/g, '_$1').toLowerCase(); + return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, ''); } /**