Skip to content

Commit bc47f4c

Browse files
committed
refactor(ui-themes,shared-types,emotion): type the new themeOverride object correctly
1 parent ffda8ca commit bc47f4c

41 files changed

Lines changed: 252 additions & 200 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/__docs__/src/withStyleForDocs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ const withStyleForDocs = decorator(
234234
theme,
235235
displayName,
236236
ComposedComponent.componentId,
237-
componentProps,
237+
(componentProps as ThemeOverrideProp).themeOverride,
238238
componentTheme
239239
)
240240

packages/emotion/src/InstUISettingsProvider/index.tsx

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,61 @@ import { getTheme } from '../getTheme'
3232

3333
import type { ThemeOrLegacyOverride } from '../EmotionTypes'
3434
import type { DeterministicIdProviderValue } from '@instructure/ui-react-utils'
35+
import type { NewThemeOverrideObject, Theme } from '@instructure/ui-themes'
3536
declare const process: Record<string, any> | undefined
3637

3738
type InstUIProviderProps = {
3839
children?: React.ReactNode
3940

4041
/**
41-
* A full theme or an override object
42+
* A full theme or an override object. The override only works for legacy
43+
* (v11.6 or earlier) themes, for newer ones use the `themeOverride` prop.
4244
*/
4345
theme?: ThemeOrLegacyOverride
4446

45-
// TODO-theme-types: fix override typing
46-
// TODO explain the usage of this override object. It will be deep merged into theme.themeOverride and the shape has to be a partial of the "newTheme" object
4747
/**
48-
* An override object for the new theming system.
48+
* An override object for the new theming system. It will be deep merged into
49+
* the theme. One can override primitives, semantics and individual component's
50+
* themes, for example:
51+
* ```js
52+
* themeOverride={{
53+
* semantics: {
54+
* color: {
55+
* stroke: {
56+
* error: 'purple'
57+
* }
58+
* }
59+
* },
60+
* primitives: {
61+
* color: {
62+
* blue: {
63+
* blue100: 'yellow'
64+
* }
65+
* }
66+
* },
67+
* components: {
68+
* Alert: {
69+
* background: 'brown',
70+
* infoIconBackground: 'darkblue',
71+
* borderWidth: '0.5rem'
72+
* },
73+
* Pill: {
74+
* baseTextColor: 'purple',
75+
* baseBorderColor: 'purple'
76+
* }
77+
* },
78+
* sharedTokens: {
79+
* focusOutline: {
80+
* width: '0.55rem',
81+
* infoColor: 'deeppink'
82+
* }
83+
* }
84+
* }}
85+
* ```
4986
*/
50-
themeOverride?: any
87+
themeOverride?:
88+
| NewThemeOverrideObject
89+
| ((theme: Theme) => NewThemeOverrideObject)
5190

5291
/**
5392
* @deprecated the `instanceCounterMap` prop is deprecated. You don't need to supply the
@@ -100,7 +139,6 @@ function InstUISettingsProvider({
100139
* For backward compatibility reasons, the old way of passing a partial theme to the theme prop is still supported, however only for
101140
* legacy (pre v11_7) components. Overriding the newTheme this way could break the system.
102141
*/
103-
104142
let providers = (
105143
<DeterministicIdContextProvider instanceCounterMap={instanceCounterMap}>
106144
<ThemeProvider theme={getTheme(theme, themeOverride)}>
@@ -120,3 +158,4 @@ function InstUISettingsProvider({
120158

121159
export default InstUISettingsProvider
122160
export { InstUISettingsProvider }
161+
export type { InstUIProviderProps }

packages/emotion/src/getComponentThemeOverride.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import type {
2929
} from './EmotionTypes'
3030
import type { ComponentTheme } from '@instructure/shared-types'
3131
import { ThemeOverrideProp } from './withStyle'
32-
import { ThemeOverrideValue } from './useStyle'
32+
import type { NewComponentTypes } from '@instructure/ui-themes'
3333

3434
type ComponentName = keyof ComponentOverride | undefined
3535

@@ -51,8 +51,10 @@ const getComponentThemeOverride = (
5151
theme: ThemeOverride,
5252
displayName: string,
5353
componentId?: string,
54-
// ThemeOverrideProp is the old type, ThemeOverrideValue is the new one
55-
themeOverride?: ThemeOverrideProp['themeOverride'] | ThemeOverrideValue,
54+
// ThemeOverrideProp['themeOverride'] is the old type
55+
themeOverride?:
56+
| ThemeOverrideProp['themeOverride']
57+
| ReturnType<NewComponentTypes[keyof NewComponentTypes]>,
5658
componentTheme?: ComponentTheme
5759
): Partial<ComponentTheme> => {
5860
const name = displayName as ComponentName

packages/emotion/src/getTheme.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@
2424
import canvas from '@instructure/ui-themes'
2525
import { isBaseTheme, mergeDeep } from '@instructure/ui-utils'
2626

27-
import type { BaseTheme } from '@instructure/shared-types'
27+
import type { Theme } from '@instructure/ui-themes'
2828

2929
import type {
3030
Overrides,
3131
ThemeOrLegacyOverride,
3232
SpecificThemeOverride
3333
} from './EmotionTypes'
34+
import { InstUIProviderProps } from './InstUISettingsProvider'
3435
declare const process: Record<string, any> | undefined
3536

3637
/**
@@ -45,14 +46,20 @@ declare const process: Record<string, any> | undefined
4546
* the overrides merged together.
4647
*
4748
* @param themeOrLegacyOverride - A full theme or an override object
48-
* @param themeOverride - if provided, it means it's a new theming-system override. This will be merged into theme.themeOverride and will be treated separately from the old way of applying overrides. This override will be applied in the withStyle.ts decorator
49+
* @param themeOverride - if provided, it means it's a new theming-system override.
50+
* This will be merged into theme.themeOverride and will be treated separately
51+
* from the old way of applying overrides. This override will be applied in the
52+
* `withStyle.ts` decorator
4953
* @returns A function that returns with the theme object for the [ThemeProvider](https://emotion.sh/docs/theming#themeprovider-reactcomponenttype)
5054
* This function is called by Emotion on theme provider creation, where
5155
* `ancestorTheme` is a theme object from an ancestor `ThemeProvider`
5256
*/
5357
const getTheme =
54-
(themeOrLegacyOverride: ThemeOrLegacyOverride, themeOverride?: any) =>
55-
(ancestorTheme = {} as BaseTheme) => {
58+
(
59+
themeOrLegacyOverride: ThemeOrLegacyOverride,
60+
themeOverride?: InstUIProviderProps['themeOverride']
61+
) =>
62+
(ancestorTheme = {} as Theme) => {
5663
// we need to clone the ancestor theme not to override it
5764
let currentTheme
5865
if (Object.keys(ancestorTheme).length === 0) {

packages/emotion/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ export { useStyleLegacy } from './useStyleLegacy'
4444
export { useStyle } from './useStyle'
4545
export { useTheme } from './useTheme'
4646

47+
export type { InstUIProviderProps } from './InstUISettingsProvider'
4748
export type { ComponentStyle, StyleObject, Overrides } from './EmotionTypes'
4849
export type { WithStyleProps } from './withStyle'
49-
export type { ThemeOverrideValue } from './useStyle'
50+
export type { NewThemeOverrideProp } from './useStyle'
5051
export type {
5152
SpacingValues,
5253
Spacing,

packages/emotion/src/useStyle.ts

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -25,98 +25,93 @@
2525
import { useTheme } from './useTheme'
2626
import { mergeDeep } from '@instructure/ui-utils'
2727
import type {
28-
SharedTokens,
2928
NewComponentTypes,
29+
SharedTokens,
3030
Theme
3131
} from '@instructure/ui-themes'
3232

3333
// returns the second parameter of a function
3434
type SecondParameter<T extends (...args: any) => any> =
3535
Parameters<T>[1] extends undefined ? never : Parameters<T>[1]
3636

37-
type GenerateStyleParams =
38-
| ((componentTheme: any, params: any, sharedTokens: SharedTokens) => any)
39-
| ((componentTheme: any, params: any) => any)
40-
| ((componentTheme: any) => any)
37+
type NewThemeOverrideProp<
38+
ComponentTheme extends ReturnType<NewComponentTypes[keyof NewComponentTypes]>
39+
> = {
40+
themeOverride?:
41+
| Partial<ComponentTheme>
42+
| ((compTheme: ComponentTheme, theme: Theme) => Partial<ComponentTheme>)
43+
}
4144

42-
/**
43-
* Type for a theme override
44-
*/
45-
type ThemeOverrideValue =
46-
| Partial<Theme>
45+
type GenerateStyleFn<ComponentTheme> =
4746
| ((
48-
componentTheme: Theme,
49-
currentTheme: NewComponentTypes[keyof NewComponentTypes]
50-
) => Partial<Theme>)
47+
componentTheme: ComponentTheme,
48+
params: any,
49+
sharedTokens: SharedTokens
50+
) => any)
51+
| ((componentTheme: ComponentTheme, params: any) => any)
52+
| ((componentTheme: ComponentTheme) => any)
5153

5254
/**
53-
* new useStyle syntax, use this with v12 themes
55+
* new useStyle syntax, use this with v11.7+ themes
5456
*/
55-
5657
// TODO: improve useStyle to handle generateStyle functions that don't
5758
// have a theme.
58-
const useStyle = <P extends GenerateStyleParams>(useStyleParams: {
59-
generateStyle: P
60-
params?: SecondParameter<P>
59+
const useStyle = <
60+
ComponentTheme extends ReturnType<NewComponentTypes[keyof NewComponentTypes]>,
61+
GenerateStyle extends GenerateStyleFn<ComponentTheme>
62+
>(useStyleParams: {
63+
generateStyle: GenerateStyle
64+
params?: SecondParameter<GenerateStyle>
6165
// needs to be a string too because it might be a child component
6266
componentId: keyof NewComponentTypes | string
63-
themeOverride: ThemeOverrideValue | undefined
67+
themeOverride?: NewThemeOverrideProp<ComponentTheme>['themeOverride']
6468
displayName?: string
65-
//in case of a child component needed to use it's parent's tokens, provide parent's name
69+
//in case of a child component needed to use its parent's tokens, provide parent's name
6670
useTokensFrom?: keyof NewComponentTypes
67-
}): ReturnType<P> => {
71+
}): ReturnType<GenerateStyle> => {
6872
const { generateStyle, params, componentId, themeOverride } = useStyleParams
6973
const useTokensFrom = useStyleParams.useTokensFrom
7074
const themeInContext = useTheme() as Theme
7175

7276
const themeOverrideFromProvider = themeInContext.themeOverride
73-
const componentWithTokensId = useTokensFrom ?? componentId
77+
const componentWithTokensId =
78+
useTokensFrom ?? (componentId as keyof NewComponentTypes)
7479

7580
// resolving the theming functions and applying the overrides
7681
const primitiveOverrides = themeOverrideFromProvider?.primitives
7782
const semanticsOverrides = themeOverrideFromProvider?.semantics
78-
// @ts-ignore TODO-theme-types: fix typing
7983
const sharedTokensOverrides = themeOverrideFromProvider?.sharedTokens
8084
const componentOverridesFromSettingsProvider =
81-
// @ts-ignore TODO-theme-types: fix typing
82-
themeOverrideFromProvider?.components?.[
83-
componentWithTokensId as keyof NewComponentTypes
84-
]
85+
themeOverrideFromProvider?.components?.[componentWithTokensId]
8586

8687
const primitives = mergeDeep(
8788
themeInContext.newTheme.primitives,
88-
primitiveOverrides
89+
primitiveOverrides!
8990
)
9091

9192
const semantics = mergeDeep(
9293
themeInContext.newTheme.semantics?.(primitives),
93-
semanticsOverrides
94+
semanticsOverrides!
9495
)
9596

9697
const sharedTokens = mergeDeep(
9798
themeInContext.newTheme.sharedTokens?.(semantics),
98-
sharedTokensOverrides
99+
sharedTokensOverrides as Record<string, unknown>
99100
)
100101

101102
const baseComponentTheme =
102-
themeInContext.newTheme.components[
103-
componentWithTokensId as keyof NewComponentTypes
104-
]?.(semantics)
103+
themeInContext.newTheme.components[componentWithTokensId]?.(semantics)
105104

106105
const componentThemeFromSettingsProvider = mergeDeep(
107106
baseComponentTheme,
108-
componentOverridesFromSettingsProvider
109-
)
107+
componentOverridesFromSettingsProvider as Record<string, unknown>
108+
) as ComponentTheme
110109

111110
const componentTheme = mergeDeep(
112111
componentThemeFromSettingsProvider,
113-
// @ts-ignore TODO-theme-types: fix typing
114112
typeof themeOverride === 'function'
115-
? themeOverride(
116-
componentThemeFromSettingsProvider as Theme,
117-
themeInContext as any
118-
)
119-
: themeOverride
113+
? themeOverride(componentThemeFromSettingsProvider, themeInContext)
114+
: themeOverride!
120115
)
121116

122117
// @ts-ignore TODO-theme-types: fix typing
@@ -125,4 +120,4 @@ const useStyle = <P extends GenerateStyleParams>(useStyleParams: {
125120

126121
export default useStyle
127122
export { useStyle }
128-
export type { ThemeOverrideValue }
123+
export type { NewThemeOverrideProp }

0 commit comments

Comments
 (0)