Skip to content

Commit

Permalink
OKTA-645490 theming api (#3385)
Browse files Browse the repository at this point in the history
OKTA-645490 feat: add support for theming using design tokens
  • Loading branch information
lesterchoi-okta authored Oct 3, 2023
1 parent b4d79f0 commit 84fe733
Show file tree
Hide file tree
Showing 95 changed files with 50,792 additions and 49,702 deletions.
131 changes: 33 additions & 98 deletions src/v3/src/components/Widget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// We need to emit a CSS file, even if it's empty, to prevent a 404 on the Okta-hosted login page.
import './style.css';

import { ScopedCssBaseline } from '@mui/material';
import { MuiThemeProvider } from '@okta/odyssey-react-mui';
import {
AuthApiError,
Expand All @@ -37,8 +38,10 @@ import Bundles from '../../../../util/Bundles';
import { IDX_STEP } from '../../constants';
import { WidgetContextProvider } from '../../contexts';
import {
useInteractionCodeFlow, useOnce,
usePolling, useStateHandle,
useInteractionCodeFlow,
useOnce,
usePolling,
useStateHandle,
} from '../../hooks';
import { transformIdxTransaction } from '../../transformer';
import {
Expand Down Expand Up @@ -71,7 +74,7 @@ import {
triggerEmailVerifyCallback,
} from '../../util';
import { getEventContext } from '../../util/getEventContext';
import { mapMuiThemeFromBrand } from '../../util/theme';
import { createTheme } from '../../util/theme';
import AuthContainer from '../AuthContainer/AuthContainer';
import AuthContent from '../AuthContent/AuthContent';
import AuthHeader from '../AuthHeader/AuthHeader';
Expand All @@ -92,7 +95,7 @@ export const Widget: FunctionComponent<WidgetProps> = (widgetProps) => {
brandColors,
brandName,
cspNonce,
muiThemeOverrides,
theme: customTheme,
logo,
logoText,
globalSuccessFn,
Expand Down Expand Up @@ -133,81 +136,10 @@ export const Widget: FunctionComponent<WidgetProps> = (widgetProps) => {
const { stateHandle, unsetStateHandle } = useStateHandle(widgetProps);

// merge themes
const mergedTheme = useMemo(() => mergeThemes(
mapMuiThemeFromBrand(brandColors, languageDirection, muiThemeOverrides),
{
components: {
MuiAlert: {
styleOverrides: {
root: {
gap: 0,
},
icon: ({ theme }) => ({
paddingInlineEnd: theme.spacing(4),
flexShrink: 0,
}),
},
},
MuiInputBase: {
styleOverrides: {
input: {
'::-ms-reveal': {
display: 'none',
},
},
},
},
MuiInputLabel: {
styleOverrides: {
root: {
wordBreak: 'break-word',
whiteSpace: 'normal',
},
},
},
// ruleset with :focus-visible pseudo-selector break entire ruleset in
// ie11 because its not supported. re-define the :hover rule separately
// again so the ruleset is applied in ie11
MuiButton: {
styleOverrides: {
root: ({ ownerState, theme }) => ({
...(ownerState.variant === 'primary' && {
'&:hover': {
backgroundColor: theme.palette.primary.dark,
},
}),
...(ownerState.variant === 'secondary' && {
'&:hover': {
backgroundColor: theme.palette.primary.lighter,
borderColor: theme.palette.primary.light,
color: theme.palette.primary.main,
},
}),
...(ownerState.variant === 'floating' && {
'&:hover': {
backgroundColor: 'rgba(29, 29, 33, 0.1)',
borderColor: 'transparent',
},
}),
}),
},
},
// ruleset with :focus-visible pseudo-selector break entire ruleset in
// ie11 because its not supported. re-define the :hover rule separately
// again so the ruleset is applied in ie11
MuiIconButton: {
styleOverrides: {
root: () => ({
'&:hover': {
backgroundColor: 'rgba(29, 29, 33, 0.1)',
borderColor: 'transparent',
},
}),
},
},
},
},
), [brandColors, languageDirection, muiThemeOverrides]);
const theme = useMemo(() => mergeThemes(
createTheme(brandColors, customTheme?.tokens ?? {}),
{ direction: languageDirection },
), [brandColors, customTheme, languageDirection]);

// on unmount, remove the language
useEffect(() => () => {
Expand All @@ -234,7 +166,7 @@ export const Widget: FunctionComponent<WidgetProps> = (widgetProps) => {
return null;
};

const shouldRedirectToEnrollFlow = (transaction: IdxTransaction) : boolean => {
const shouldRedirectToEnrollFlow = (transaction: IdxTransaction): boolean => {
const { nextStep, neededToProceed } = transaction;
if (!isConfigRegisterFlow(flow) || nextStep?.name !== IDX_STEP.IDENTIFY) {
return false;
Expand Down Expand Up @@ -560,25 +492,28 @@ export const Widget: FunctionComponent<WidgetProps> = (widgetProps) => {
}}
>
<CustomPluginsOdysseyCacheProvider nonce={cspNonce}>
<MuiThemeProvider theme={mergedTheme}>
<MuiThemeProvider theme={theme}>
<GlobalStyles />
<AuthContainer hide={hide}>
<AuthHeader
logo={logo}
logoText={logoText}
brandName={brandName}
authCoinProps={buildAuthCoinProps(idxTransaction)}
/>
<AuthContent>
{isConsentStep(idxTransaction) && <ConsentHeader />}
<IdentifierContainer />
{
uischema.elements.length > 0
? <Form uischema={uischema as UISchemaLayout} />
: <Spinner />
}
</AuthContent>
</AuthContainer>
{/* the style is to allow the widget to inherit the parent's bg color */}
<ScopedCssBaseline sx={{ backgroundColor: 'inherit' }}>
<AuthContainer hide={hide}>
<AuthHeader
logo={logo}
logoText={logoText}
brandName={brandName}
authCoinProps={buildAuthCoinProps(idxTransaction)}
/>
<AuthContent>
{isConsentStep(idxTransaction) && <ConsentHeader />}
<IdentifierContainer />
{
uischema.elements.length > 0
? <Form uischema={uischema as UISchemaLayout} />
: <Spinner />
}
</AuthContent>
</AuthContainer>
</ScopedCssBaseline>
</MuiThemeProvider>
</CustomPluginsOdysseyCacheProvider>
</WidgetContextProvider>
Expand Down
14 changes: 14 additions & 0 deletions src/v3/src/components/Widget/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,17 @@
filter: unset !important;
}
}

/*
* NOTE: widget styles below, login page styles above. Take care when moving CSS
* from SIW to loginpage (okta-ui) in OKTA-602545
*
* TODO: OKTA-654405
*/
span.strong {
font-weight: 600;
word-break: break-all;
}
.no-translate {
white-space: nowrap;
}
15 changes: 5 additions & 10 deletions src/v3/src/types/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

import type { ThemeOptions as MuiThemeOptions } from '@mui/material';
import {
FlowIdentifier,
IdxActionParams,
Expand All @@ -35,6 +34,7 @@ import {
UserOperation,
} from '../../../types';
import { InterstitialRedirectView } from '../constants';
import { DesignTokensType } from '../util/designTokens';
import { WidgetHooks } from '../util/widgetHooks';
import { OktaSignInAPI } from './api';
import { JsonObject } from './json';
Expand Down Expand Up @@ -115,15 +115,11 @@ export type WidgetProps = Partial<WidgetOptions> & {
};

export type WidgetOptions = {
// // ui customizations
// renderers?: JsonFormsRendererRegistryEntry[];
// cells?: JsonFormsCellRendererRegistryEntry[];
// components?: Record<string, Component>;
// brand colors
brandColors?: BrandColors;

// theming
theme?: ThemeOptions;
// Override MUI Theming
muiThemeOverrides?: MuiThemeOptions;
// theme
theme?: { tokens: DesignTokensType }; // & ThemeOptions;

// hooks
hooks?: HooksOptions; // object in options
Expand Down Expand Up @@ -165,7 +161,6 @@ export type WidgetOptions = {
otp?: string;
baseUrl?: string;
brandName?: string;
brandColors?: BrandColors;
logo?: string;
logoText?: string;
stateToken?: string;
Expand Down
Loading

0 comments on commit 84fe733

Please sign in to comment.