|
24 | 24 |
|
25 | 25 | import { useTheme } from './useTheme' |
26 | 26 | import { getComponentThemeOverride } from './getComponentThemeOverride' |
27 | | -import type { ComponentTheme } from '@instructure/shared-types' |
28 | 27 | import type { |
29 | 28 | SharedTokens, |
30 | 29 | NewComponentTypes, |
31 | 30 | Theme |
32 | 31 | } from '@instructure/ui-themes' |
33 | | -import { BaseThemeOrOverride } from './EmotionTypes' |
| 32 | +import type { BaseThemeOrOverride } from './EmotionTypes' |
34 | 33 |
|
35 | 34 | // returns the second parameter of a function |
36 | 35 | type SecondParameter<T extends (...args: any) => any> = |
37 | 36 | Parameters<T>[1] extends undefined ? never : Parameters<T>[1] |
38 | 37 |
|
39 | | -type GenerateComponentTheme = (theme: Theme) => ComponentTheme |
| 38 | +type GenerateStyleParams = |
| 39 | + | ((componentTheme: any, params: any, sharedTokens: SharedTokens) => any) |
| 40 | + | ((componentTheme: any, params: any) => any) |
| 41 | + | ((componentTheme: any) => any) |
40 | 42 |
|
41 | | -// TODO this is only used by the old themes, remove when everything uses the new |
42 | | -// theming system |
43 | | -type UseStyleParamsWithTheme< |
44 | | - P extends (componentTheme: any, params: any, theme: any) => any |
45 | | -> = { |
46 | | - generateStyle: P |
47 | | - params?: SecondParameter<P> |
48 | | - generateComponentTheme: GenerateComponentTheme |
49 | | - componentId: string |
50 | | - displayName?: string |
51 | | -} |
| 43 | +/** |
| 44 | + * Type for a theme override |
| 45 | + */ |
| 46 | +type ThemeOverrideValue = |
| 47 | + | Partial<Theme> |
| 48 | + | (( |
| 49 | + componentTheme: Theme, |
| 50 | + currentTheme: NewComponentTypes[keyof NewComponentTypes] |
| 51 | + ) => Partial<Theme>) |
52 | 52 |
|
53 | | -// TODO this is only used by the old themes, remove when everything uses the new |
54 | | -// theming system |
55 | | -type UseStyleParamsWithoutTheme< |
56 | | - P extends (componentTheme: any, params: any, theme: any) => any |
57 | | -> = { |
58 | | - generateStyle: P |
59 | | - params?: SecondParameter<P> |
60 | | - generateComponentTheme?: undefined |
61 | | - componentId?: undefined |
62 | | - displayName?: undefined |
| 53 | +const isNewThemeObject = (obj: BaseThemeOrOverride): obj is Theme => { |
| 54 | + return typeof (obj as any)?.newTheme === 'object' |
63 | 55 | } |
64 | 56 |
|
65 | | -// new useStyle syntax, use this with new themes |
66 | | -type UseStyleParamsNew< |
67 | | - P extends ( |
68 | | - componentTheme: any, |
69 | | - params: any, |
70 | | - sharedTokens: SharedTokens |
71 | | - ) => any |
72 | | -> = { |
| 57 | +/** |
| 58 | + * new useStyle syntax, use this with v12 themes |
| 59 | + */ |
| 60 | +const useStyle = <P extends GenerateStyleParams>(useStyleParams: { |
73 | 61 | generateStyle: P |
74 | 62 | params?: SecondParameter<P> |
75 | 63 | componentId: keyof NewComponentTypes |
| 64 | + themeOverride: ThemeOverrideValue | undefined |
76 | 65 | displayName?: string |
77 | 66 | //in case of a child component needed to use it's parent's tokens, provide parent's name |
78 | 67 | useTokensFrom?: keyof NewComponentTypes |
79 | | -} |
80 | | - |
81 | | -const isNewThemeObject = (obj: BaseThemeOrOverride): obj is Theme => { |
82 | | - return typeof (obj as any)?.newTheme === 'object' |
83 | | -} |
84 | | - |
85 | | -const useStyle = < |
86 | | - P extends (componentTheme: any, params: any, themeOrSharedTokens: any) => any |
87 | | ->( |
88 | | - useStyleParams: |
89 | | - | UseStyleParamsWithTheme<P> |
90 | | - | UseStyleParamsWithoutTheme<P> |
91 | | - | UseStyleParamsNew<P> |
92 | | -): ReturnType<P> => { |
93 | | - const { generateStyle, params, componentId, displayName } = useStyleParams |
94 | | - const useTokensFrom = (useStyleParams as UseStyleParamsNew<P>).useTokensFrom |
95 | | - const generateComponentTheme: GenerateComponentTheme = ( |
96 | | - useStyleParams as UseStyleParamsWithTheme<P> |
97 | | - )?.generateComponentTheme |
| 68 | +}): ReturnType<P> => { |
| 69 | + const { generateStyle, params, componentId, displayName, themeOverride } = |
| 70 | + useStyleParams |
| 71 | + const useTokensFrom = useStyleParams.useTokensFrom |
98 | 72 | const theme = useTheme() |
99 | 73 |
|
100 | | - let baseComponentTheme = |
101 | | - typeof generateComponentTheme === 'function' |
102 | | - ? generateComponentTheme(theme as Theme) |
103 | | - : {} |
| 74 | + let baseComponentTheme = {} |
104 | 75 | const componentWithTokensId = useTokensFrom ?? componentId |
105 | 76 |
|
106 | 77 | if ( |
107 | | - isNewThemeObject(theme) && |
| 78 | + isNewThemeObject(theme) && // TODO: is it possible not to have a theme object here? |
108 | 79 | theme.newTheme.components[componentWithTokensId as keyof NewComponentTypes] |
109 | 80 | ) { |
110 | 81 | baseComponentTheme = |
111 | 82 | theme.newTheme.components[ |
112 | 83 | componentWithTokensId as keyof NewComponentTypes |
113 | 84 | ] |
114 | 85 | } |
115 | | - const themeOverride = getComponentThemeOverride( |
| 86 | + const finalOverride = getComponentThemeOverride( |
116 | 87 | theme, |
117 | 88 | useTokensFrom ?? displayName ?? componentId ?? '', |
118 | 89 | componentWithTokensId, |
119 | | - params, |
| 90 | + themeOverride, |
120 | 91 | baseComponentTheme |
121 | 92 | ) |
122 | 93 |
|
123 | | - const componentTheme = { ...baseComponentTheme, ...themeOverride } |
| 94 | + const componentTheme = { ...baseComponentTheme, ...finalOverride } |
124 | 95 |
|
125 | 96 | return generateStyle( |
126 | 97 | componentTheme, |
127 | | - params ? params : {}, |
| 98 | + params, |
128 | 99 | (theme as Theme).newTheme.components.SharedTokens |
129 | 100 | ) |
130 | 101 | } |
131 | 102 |
|
132 | 103 | export default useStyle |
133 | 104 | export { useStyle } |
| 105 | +export type { ThemeOverrideValue } |
0 commit comments