Skip to content
Merged
Show file tree
Hide file tree
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
6 changes: 6 additions & 0 deletions .changeset/sweet-geese-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@asgardeo/javascript': patch
'@asgardeo/react': patch
---

Add component-specific overrides.
35 changes: 35 additions & 0 deletions packages/javascript/src/theme/createTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,12 +449,43 @@ const toCssVariables = (theme: ThemeConfig): Record<string, string> => {
});
}

/* |---------------------------------------------------------------| */
/* | Components | */
/* |---------------------------------------------------------------| */

// Button Overrides
if (theme.components?.Button?.styleOverrides?.root?.borderRadius) {
cssVars[`--${prefix}-component-button-root-borderRadius`] =
theme.components.Button.styleOverrides.root.borderRadius;
}

// Field Overrides (Parent of `TextField`, `DatePicker`, `OtpField`, `Select`, etc.)
if (theme.components?.Field?.styleOverrides?.root?.borderRadius) {
cssVars[`--${prefix}-component-field-root-borderRadius`] = theme.components.Field.styleOverrides.root.borderRadius;
}

return cssVars;
};

const toThemeVars = (theme: ThemeConfig): ThemeVars => {
const prefix = theme.cssVarPrefix || VendorConstants.VENDOR_PREFIX;

const componentVars: ThemeVars['components'] = {};
if (theme.components?.Button?.styleOverrides?.root?.borderRadius) {
componentVars.Button = {
root: {
borderRadius: `var(--${prefix}-component-button-root-borderRadius)`,
},
};
}
if (theme.components?.Field?.styleOverrides?.root?.borderRadius) {
componentVars.Field = {
root: {
borderRadius: `var(--${prefix}-component-field-root-borderRadius)`,
},
};
}

const themeVars: ThemeVars = {
colors: {
action: {
Expand Down Expand Up @@ -558,6 +589,10 @@ const toThemeVars = (theme: ThemeConfig): ThemeVars => {
});
}

if (Object.keys(componentVars).length > 0) {
themeVars.components = componentVars;
}

return themeVars;
};

Expand Down
71 changes: 71 additions & 0 deletions packages/javascript/src/theme/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,47 @@ export interface ThemeColors {
};
}

export interface ThemeComponentStyleOverrides {
/**
* Style overrides for the root element or slots.
* Example: { root: { borderRadius: '8px' } }
*/
root?: Record<string, any>;
[slot: string]: Record<string, any> | undefined;
}

export interface ThemeComponents {
Button?: {
styleOverrides?: {
root?: {
borderRadius?: string;
[key: string]: any;
};
[slot: string]: Record<string, any> | undefined;
};
defaultProps?: Record<string, any>;
variants?: Array<Record<string, any>>;
};
Field?: {
styleOverrides?: {
root?: {
borderRadius?: string;
[key: string]: any;
};
[slot: string]: Record<string, any> | undefined;
};
defaultProps?: Record<string, any>;
variants?: Array<Record<string, any>>;
};
[componentName: string]:
| {
styleOverrides?: ThemeComponentStyleOverrides;
defaultProps?: Record<string, any>;
variants?: Array<Record<string, any>>;
}
| undefined;
}

export interface ThemeConfig {
borderRadius: {
large: string;
Expand Down Expand Up @@ -148,6 +189,32 @@ export interface ThemeConfig {
* @default 'asgardeo' (from VendorConstants.VENDOR_PREFIX)
*/
cssVarPrefix?: string;
/**
* Component style overrides
*/
components?: ThemeComponents;
}

export interface ThemeComponentVars {
Button?: {
root?: {
borderRadius?: string;
[key: string]: any;
};
[slot: string]: Record<string, any> | undefined;
};
Field?: {
root?: {
borderRadius?: string;
[key: string]: any;
};
[slot: string]: Record<string, any> | undefined;
};
[componentName: string]:
| {
[slot: string]: Record<string, any> | undefined;
}
| undefined;
}

export interface ThemeVars {
Expand Down Expand Up @@ -266,6 +333,10 @@ export interface ThemeVars {
}
| undefined;
};
/**
* Component CSS variable references (e.g., for overrides)
*/
components?: ThemeComponentVars;
}

export interface Theme extends ThemeConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const transformThemeVariant = (themeVariant: ThemeVariant, isDark = false): Part
const inputs = themeVariant.inputs;
const images = themeVariant.images;

return {
const config: Partial<ThemeConfig> = {
colors: {
action: {
active: isDark ? 'rgba(255, 255, 255, 0.70)' : 'rgba(0, 0, 0, 0.54)',
Expand Down Expand Up @@ -111,13 +111,6 @@ const transformThemeVariant = (themeVariant: ThemeVariant, isDark = false): Part
dark: (colors?.alerts?.warning as ColorVariant)?.dark || (colors?.alerts?.warning as ColorVariant)?.main,
},
},
// Extract border radius from buttons or inputs
borderRadius: {
small: buttons?.primary?.base?.border?.borderRadius || inputs?.base?.border?.borderRadius,
medium: buttons?.secondary?.base?.border?.borderRadius,
large: buttons?.externalConnection?.base?.border?.borderRadius,
},
// Extract and transform images
images: {
favicon: images?.favicon
? {
Expand All @@ -135,6 +128,38 @@ const transformThemeVariant = (themeVariant: ThemeVariant, isDark = false): Part
: undefined,
},
};

/* |---------------------------------------------------------------| */
/* | Components | */
/* |---------------------------------------------------------------| */

const buttonBorderRadius = buttons?.primary?.base?.border?.borderRadius;
const fieldBorderRadius = inputs?.base?.border?.borderRadius;

if (buttonBorderRadius || fieldBorderRadius) {
config.components = {
...(buttonBorderRadius && {
Button: {
styleOverrides: {
root: {
borderRadius: buttonBorderRadius,
},
},
},
}),
...(fieldBorderRadius && {
Field: {
styleOverrides: {
root: {
borderRadius: fieldBorderRadius,
},
},
},
}),
};
}

return config;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ const useStyles = (
align-items: center;
justify-content: center;
gap: calc(${theme.vars.spacing.unit} * 1);
border-radius: ${shape === 'round' ? '50%' : theme.vars.borderRadius.medium};
border-radius: ${shape === 'round'
? '50%'
: theme.vars.components?.Button?.root?.borderRadius || theme.vars.borderRadius.medium};
font-weight: 500;
cursor: ${disabled || loading ? 'not-allowed' : 'pointer'};
outline: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const useStyles = (theme: Theme, colorScheme: string, hasError: boolean, disable
width: 100%;
padding: ${theme.vars.spacing.unit} calc(${theme.vars.spacing.unit} * 1.5);
border: 1px solid ${theme.vars.colors.border};
border-radius: ${theme.vars.borderRadius.medium};
border-radius: ${theme.vars.components?.Field?.root?.borderRadius || theme.vars.borderRadius.medium};
font-size: 1rem;
color: ${theme.vars.colors.text.primary};
background-color: ${theme.vars.colors.background.surface};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const useStyles = (
font-size: ${theme.vars.typography.fontSizes.xl};
font-weight: 500;
border: 2px solid ${hasError ? theme.vars.colors.error.main : theme.vars.colors.border};
border-radius: ${theme.vars.borderRadius.medium};
border-radius: ${theme.vars.components?.Field?.root?.borderRadius || theme.vars.borderRadius.medium};
color: ${theme.vars.colors.text.primary};
background-color: ${disabled ? theme.vars.colors.background.disabled : theme.vars.colors.background.surface};
outline: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const useStyles = (theme: Theme, colorScheme: string, disabled: boolean, hasErro
width: 100%;
padding: ${theme.vars.spacing.unit} calc(${theme.vars.spacing.unit} * 1.5);
border: 1px solid ${hasError ? theme.vars.colors.error.main : theme.vars.colors.border};
border-radius: ${theme.vars.borderRadius.medium};
border-radius: ${theme.vars.components?.Field?.root?.borderRadius || theme.vars.borderRadius.medium};
font-size: ${theme.vars.typography.fontSizes.md};
color: ${theme.vars.colors.text.primary};
background-color: ${disabled ? theme.vars.colors.background.disabled : theme.vars.colors.background.surface};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const useStyles = (
width: 100%;
padding: ${theme.vars.spacing.unit} ${rightPadding} ${theme.vars.spacing.unit} ${leftPadding};
border: 1px solid ${hasError ? theme.vars.colors.error.main : theme.vars.colors.border};
border-radius: ${theme.vars.borderRadius.medium};
border-radius: ${theme.vars.components?.Field?.root?.borderRadius || theme.vars.borderRadius.medium};
font-size: ${theme.vars.typography.fontSizes.md};
color: ${theme.vars.colors.text.primary};
background-color: ${disabled ? theme.vars.colors.background.disabled : theme.vars.colors.background.surface};
Expand Down
5 changes: 5 additions & 0 deletions packages/react/src/contexts/Theme/ThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ const ThemeProvider: FC<PropsWithChildren<ThemeProviderProps>> = ({
shadows: brandingTheme.shadows,
spacing: brandingTheme.spacing,
images: brandingTheme.images,
components: brandingTheme.components,
};

// Merge branding theme with user-provided theme config
Expand Down Expand Up @@ -202,6 +203,10 @@ const ThemeProvider: FC<PropsWithChildren<ThemeProviderProps>> = ({
...brandingThemeConfig.images,
...themeConfig?.images,
},
components: {
...brandingThemeConfig.components,
...themeConfig?.components,
},
};
}, [inheritFromBranding, brandingTheme, themeConfig]);

Expand Down
Loading