Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion renderers/react/src/v0_9/catalog/basic/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,18 @@ import {createReactComponent} from '../../../adapter';
import {IconApi} from '@a2ui/web_core/v0_9/basic_catalog';
import {getBaseLeafStyle} from '../utils';

/**
* Convert camelCase to snake_case for Material Symbols font.
* e.g., "shoppingCart" -> "shopping_cart", "skipPrevious" -> "skip_previous"
*/
function toSnakeCase(str: string): string {
return str.replace(/([A-Z])/g, '_$1').toLowerCase();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation of toSnakeCase will produce a leading underscore for strings that start with an uppercase letter (e.g., 'ShoppingCart' becomes '_shopping_cart'). This is likely not the intended behavior for Material Symbols font ligatures.

A more robust implementation would handle this case correctly. Using a negative lookbehind (?<!^) can prevent matching an uppercase letter at the beginning of the string.

Suggested change
return str.replace(/([A-Z])/g, '_$1').toLowerCase();
return str.replace(/(?<!^)([A-Z])/g, '_$1').toLowerCase();

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The A2UI schema enforces camelCase icon names via a Zod enum (ICON_NAMES in basic_components.ts), so PascalCase input is never valid. This regex is also identical to Angular v0.9 (icon.component.ts:98) and React v0.8 (Icon.tsx:29). Changing it here would break consistency across renderers.

}

export const Icon = createReactComponent(IconApi, ({props}) => {
const iconName =
const rawName =
typeof props.name === 'string' ? props.name : (props.name as {path?: string})?.path;
const iconName = rawName ? toSnakeCase(rawName) : undefined;
const style: React.CSSProperties = {
...getBaseLeafStyle(),
fontSize: '24px',
Expand Down