@instructure/emotion 11.7.2-snapshot-54 → 11.7.2-snapshot-62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/es/InstUISettingsProvider/index.js +12 -2
  3. package/es/getTheme.js +20 -13
  4. package/es/index.js +1 -0
  5. package/es/useComputedTheme.js +61 -0
  6. package/es/useStyle.js +26 -19
  7. package/es/withStyle.js +41 -19
  8. package/lib/InstUISettingsProvider/index.js +12 -2
  9. package/lib/getTheme.js +20 -13
  10. package/lib/index.js +8 -0
  11. package/lib/useComputedTheme.js +67 -0
  12. package/lib/useStyle.js +23 -20
  13. package/lib/withStyle.js +41 -18
  14. package/package.json +10 -10
  15. package/src/EmotionTypes.ts +2 -2
  16. package/src/InstUISettingsProvider/index.tsx +20 -4
  17. package/src/getComponentThemeOverride.ts +2 -2
  18. package/src/getTheme.ts +30 -15
  19. package/src/index.ts +1 -0
  20. package/src/useComputedTheme.ts +62 -0
  21. package/src/useStyle.ts +52 -33
  22. package/src/useTheme.ts +1 -0
  23. package/src/withStyle.tsx +78 -35
  24. package/tsconfig.build.tsbuildinfo +1 -1
  25. package/types/EmotionTypes.d.ts +2 -2
  26. package/types/EmotionTypes.d.ts.map +1 -1
  27. package/types/InstUISettingsProvider/index.d.ts +7 -3
  28. package/types/InstUISettingsProvider/index.d.ts.map +1 -1
  29. package/types/getComponentThemeOverride.d.ts +2 -2
  30. package/types/getComponentThemeOverride.d.ts.map +1 -1
  31. package/types/getTheme.d.ts +4 -3
  32. package/types/getTheme.d.ts.map +1 -1
  33. package/types/index.d.ts +1 -0
  34. package/types/index.d.ts.map +1 -1
  35. package/types/useComputedTheme.d.ts +22 -0
  36. package/types/useComputedTheme.d.ts.map +1 -0
  37. package/types/useStyle.d.ts.map +1 -1
  38. package/types/useTheme.d.ts.map +1 -1
  39. package/types/withStyle.d.ts.map +1 -1
package/CHANGELOG.md CHANGED
@@ -3,13 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [11.7.2-snapshot-54](https://github.com/instructure/instructure-ui/compare/v11.7.1...v11.7.2-snapshot-54) (2026-04-23)
6
+ ## [11.7.2-snapshot-62](https://github.com/instructure/instructure-ui/compare/v11.7.1...v11.7.2-snapshot-62) (2026-04-23)
7
7
 
8
8
 
9
9
  ### Bug Fixes
10
10
 
11
11
  * **emotion:** fix getShortHandValue not trimming input string ([75eac6f](https://github.com/instructure/instructure-ui/commit/75eac6f122623fe4c7d750fde8739864402ecaaf))
12
12
  * **many:** fix doc component previews, update dark theme text and code block styles, and replace old icons ([d4e48d3](https://github.com/instructure/instructure-ui/commit/d4e48d3f739decb13b76c863c8f01685f0788dd6))
13
+ * **ui-scripts,emotion:** fix primitives and semantics override functionality ([d72df52](https://github.com/instructure/instructure-ui/commit/d72df52242fdf5ecd13fa38e19f254da1be9a8dc))
14
+
15
+
16
+ ### Features
17
+
18
+ * **emotion:** add helper for accessing computed theme (useComputedTheme.ts in the emotion package) ([6d3c649](https://github.com/instructure/instructure-ui/commit/6d3c64912304bf863e3bc720cdb29c88165bfe81))
19
+ * **many:** fix issues ([9d623ed](https://github.com/instructure/instructure-ui/commit/9d623ed9ba2be49549b625d1e436edc230a4df41))
20
+ * **ui-themes,ui-alerts,emotion:** fix primitives and semantics overrides and add freeze functionlionality to old components ([336fde9](https://github.com/instructure/instructure-ui/commit/336fde9952698eda020db4916f276e8532ed1669))
13
21
 
14
22
 
15
23
 
@@ -38,15 +38,25 @@ function InstUISettingsProvider({
38
38
  children,
39
39
  theme = {},
40
40
  dir,
41
- instanceCounterMap
41
+ instanceCounterMap,
42
+ themeOverride
42
43
  }) {
43
44
  var _process, _process$env, _process2, _process2$env;
44
45
  const finalDir = dir || useContext(TextDirectionContext);
45
46
  if (typeof process !== 'undefined' && (((_process = process) === null || _process === void 0 ? void 0 : (_process$env = _process.env) === null || _process$env === void 0 ? void 0 : _process$env.NODE_ENV) !== 'production' || ((_process2 = process) === null || _process2 === void 0 ? void 0 : (_process2$env = _process2.env) === null || _process2$env === void 0 ? void 0 : _process2$env.GITHUB_PULL_REQUEST_PREVIEW) === 'true') && finalDir === 'auto') {}
47
+
48
+ /**
49
+ * new pattern: if you want to replace a theme inside an InstUISettingsProvider, provide it via the theme prop. It'll
50
+ * override everything, replacing the otherwise used theme.
51
+ * if you want to apply an override, use the themeOverride prop.
52
+ * For backward compatibility reasons, the old way of passing a partial theme to the theme prop is still supported, however only for
53
+ * legacy (pre v11_7) components. Overriding the newTheme this way could break the system.
54
+ */
55
+
46
56
  let providers = _jsx(DeterministicIdContextProvider, {
47
57
  instanceCounterMap: instanceCounterMap,
48
58
  children: _jsx(ThemeProvider, {
49
- theme: getTheme(theme),
59
+ theme: getTheme(theme, themeOverride),
50
60
  children: _jsx(TextDirectionContext.Provider, {
51
61
  value: finalDir,
52
62
  children: children
package/es/getTheme.js CHANGED
@@ -34,13 +34,14 @@ import { isBaseTheme, mergeDeep } from '@instructure/ui-utils';
34
34
  * If an override object is given, it returns the ancestor theme and
35
35
  * the overrides merged together.
36
36
  *
37
- * @param themeOrOverride - A full theme or an override object
37
+ * @param themeOrLegacyOverride - A full theme or an override object
38
+ * @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
38
39
  * @returns A function that returns with the theme object for the [ThemeProvider](https://emotion.sh/docs/theming#themeprovider-reactcomponenttype)
39
40
  * This function is called by Emotion on theme provider creation, where
40
41
  * `ancestorTheme` is a theme object from an ancestor `ThemeProvider`
41
42
  */
42
- const getTheme = themeOrOverride => (ancestorTheme = {}) => {
43
- var _resolvedThemeOrOverr;
43
+ const getTheme = (themeOrLegacyOverride, themeOverride) => (ancestorTheme = {}) => {
44
+ var _resolvedLegacyThemeO;
44
45
  // we need to clone the ancestor theme not to override it
45
46
  let currentTheme;
46
47
  if (Object.keys(ancestorTheme).length === 0) {
@@ -50,14 +51,18 @@ const getTheme = themeOrOverride => (ancestorTheme = {}) => {
50
51
  } else {
51
52
  currentTheme = ancestorTheme;
52
53
  }
53
- let resolvedThemeOrOverride = themeOrOverride;
54
- if (typeof resolvedThemeOrOverride === 'function') {
55
- resolvedThemeOrOverride = resolvedThemeOrOverride(currentTheme);
56
- }
54
+ const resolvedThemeOverride = typeof themeOverride === 'function' ? themeOverride(currentTheme) : themeOverride;
55
+ let resolvedLegacyThemeOrOverride = typeof themeOrLegacyOverride === 'function' ? themeOrLegacyOverride(currentTheme) : themeOrLegacyOverride;
57
56
  try {
58
57
  // If a valid InstUI theme is given, it just returns the theme.
59
- if (isBaseTheme(resolvedThemeOrOverride)) {
60
- return resolvedThemeOrOverride;
58
+ // in case of the legacy pattern, it's just a simple replacement, in the new system, overrides should be merged into the new theme. Old overrides will be removed because they may make no sense for a different theme
59
+ if (isBaseTheme(resolvedLegacyThemeOrOverride)) {
60
+ return {
61
+ ...resolvedLegacyThemeOrOverride,
62
+ ...(resolvedThemeOverride ? {
63
+ themeOverride: resolvedThemeOverride
64
+ } : {})
65
+ };
61
66
  }
62
67
  } catch {
63
68
  var _process3, _process3$env, _process4, _process4$env;
@@ -65,14 +70,16 @@ const getTheme = themeOrOverride => (ancestorTheme = {}) => {
65
70
  // We are using this fail-safe here for the non-TS users,
66
71
  // because the whole page can break without a theme.
67
72
  if (typeof process !== 'undefined' && (((_process3 = process) === null || _process3 === void 0 ? void 0 : (_process3$env = _process3.env) === null || _process3$env === void 0 ? void 0 : _process3$env.NODE_ENV) !== 'production' || ((_process4 = process) === null || _process4 === void 0 ? void 0 : (_process4$env = _process4.env) === null || _process4$env === void 0 ? void 0 : _process4$env.GITHUB_PULL_REQUEST_PREVIEW) === 'true')) {}
68
- resolvedThemeOrOverride = {};
73
+ resolvedLegacyThemeOrOverride = {};
69
74
  }
70
75
  const themeName = currentTheme.key;
71
76
 
72
- // we pick the overrides for the current theme from the override object
73
- const specificOverrides = (_resolvedThemeOrOverr = resolvedThemeOrOverride) === null || _resolvedThemeOrOverr === void 0 ? void 0 : _resolvedThemeOrOverr.themeOverrides;
77
+ // legacy: we pick the overrides for the current theme from the override object
78
+ const specificOverrides = (_resolvedLegacyThemeO = resolvedLegacyThemeOrOverride) === null || _resolvedLegacyThemeO === void 0 ? void 0 : _resolvedLegacyThemeO.themeOverrides;
74
79
  const currentThemeOverrides = (specificOverrides === null || specificOverrides === void 0 ? void 0 : specificOverrides[themeName]) || specificOverrides || {};
75
- return mergeDeep(currentTheme, resolvedThemeOrOverride, currentThemeOverrides);
80
+ return mergeDeep(currentTheme, resolvedLegacyThemeOrOverride, currentThemeOverrides, ...(resolvedThemeOverride ? [{
81
+ themeOverride: resolvedThemeOverride
82
+ }] : []));
76
83
  };
77
84
  export default getTheme;
78
85
  export { getTheme };
package/es/index.js CHANGED
@@ -24,6 +24,7 @@
24
24
  /// <reference types="@emotion/react/types/css-prop" />
25
25
 
26
26
  export * from '@emotion/react';
27
+ export { useComputedTheme } from "./useComputedTheme.js";
27
28
  export { InstUISettingsProvider } from "./InstUISettingsProvider/index.js";
28
29
  export { withStyleLegacy } from "./withStyleLegacy.js";
29
30
  export { getComponentThemeOverride } from "./getComponentThemeOverride.js";
@@ -0,0 +1,61 @@
1
+ /*
2
+ * The MIT License (MIT)
3
+ *
4
+ * Copyright (c) 2015 - present Instructure, Inc.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import { useTheme } from '@emotion/react';
26
+
27
+ /**
28
+ * ---
29
+ * category: utilities/themes
30
+ * ---
31
+ * A hook that returns the fully resolved theme object from the context, with all token layers evaluated.
32
+ *
33
+ * The raw `newTheme` stored on the context exposes its layers as functions
34
+ * that depend on the previous layer (`semantics` takes `primitives`,
35
+ * `components` and `sharedTokens` take `semantics`). This hook runs those
36
+ * functions for you and returns the computed values, so you can read
37
+ * tokens directly without having to know the evaluation order.
38
+ *
39
+ * @returns An object containing the computed `primitives`, `semantics`,
40
+ * `components` and `sharedTokens` of the current theme.
41
+ */
42
+ export const useComputedTheme = () => {
43
+ var _rawTheme$semantics, _rawTheme$sharedToken;
44
+ const rawTheme = useTheme().newTheme;
45
+ const primitives = rawTheme === null || rawTheme === void 0 ? void 0 : rawTheme.primitives;
46
+ const semantics = rawTheme === null || rawTheme === void 0 ? void 0 : (_rawTheme$semantics = rawTheme.semantics) === null || _rawTheme$semantics === void 0 ? void 0 : _rawTheme$semantics.call(rawTheme, primitives);
47
+ const components = Object.keys(rawTheme === null || rawTheme === void 0 ? void 0 : rawTheme.components).reduce((acc, component) => {
48
+ var _rawTheme$components$, _rawTheme$components;
49
+ return {
50
+ ...acc,
51
+ [component]: (_rawTheme$components$ = (_rawTheme$components = rawTheme.components)[component]) === null || _rawTheme$components$ === void 0 ? void 0 : _rawTheme$components$.call(_rawTheme$components, semantics)
52
+ };
53
+ }, {});
54
+ const sharedTokens = rawTheme === null || rawTheme === void 0 ? void 0 : (_rawTheme$sharedToken = rawTheme.sharedTokens) === null || _rawTheme$sharedToken === void 0 ? void 0 : _rawTheme$sharedToken.call(rawTheme, semantics);
55
+ return {
56
+ primitives,
57
+ semantics,
58
+ components,
59
+ sharedTokens
60
+ };
61
+ };
package/es/useStyle.js CHANGED
@@ -22,13 +22,13 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
  import { useTheme } from "./useTheme.js";
25
- import { getComponentThemeOverride } from "./getComponentThemeOverride.js"; // returns the second parameter of a function
25
+ import { mergeDeep } from '@instructure/ui-utils';
26
+
27
+ // returns the second parameter of a function
28
+
26
29
  /**
27
30
  * Type for a theme override
28
31
  */
29
- const isNewThemeObject = obj => {
30
- return typeof (obj === null || obj === void 0 ? void 0 : obj.newTheme) === 'object';
31
- };
32
32
 
33
33
  /**
34
34
  * new useStyle syntax, use this with v12 themes
@@ -37,27 +37,34 @@ const isNewThemeObject = obj => {
37
37
  // TODO: improve useStyle to handle generateStyle functions that don't
38
38
  // have a theme.
39
39
  const useStyle = useStyleParams => {
40
- var _ref, _ref2;
40
+ var _themeOverrideFromPro, _themeInContext$newTh, _themeInContext$newTh2, _themeInContext$newTh3, _themeInContext$newTh4, _themeInContext$newTh5, _themeInContext$newTh6;
41
41
  const generateStyle = useStyleParams.generateStyle,
42
42
  params = useStyleParams.params,
43
43
  componentId = useStyleParams.componentId,
44
- displayName = useStyleParams.displayName,
45
44
  themeOverride = useStyleParams.themeOverride;
46
45
  const useTokensFrom = useStyleParams.useTokensFrom;
47
- const theme = useTheme();
48
- let baseComponentTheme = {};
46
+ const themeInContext = useTheme();
47
+ const themeOverrideFromProvider = themeInContext.themeOverride;
49
48
  const componentWithTokensId = useTokensFrom !== null && useTokensFrom !== void 0 ? useTokensFrom : componentId;
50
- if (isNewThemeObject(theme) &&
51
- // TODO: is it possible not to have a theme object here?
52
- theme.newTheme.components[componentWithTokensId]) {
53
- baseComponentTheme = theme.newTheme.components[componentWithTokensId];
54
- }
55
- const finalOverride = getComponentThemeOverride(theme, (_ref = (_ref2 = useTokensFrom !== null && useTokensFrom !== void 0 ? useTokensFrom : displayName) !== null && _ref2 !== void 0 ? _ref2 : componentId) !== null && _ref !== void 0 ? _ref : '', componentWithTokensId, themeOverride, baseComponentTheme);
56
- const componentTheme = {
57
- ...baseComponentTheme,
58
- ...finalOverride
59
- };
60
- return generateStyle(componentTheme, params, theme.newTheme.sharedTokens);
49
+
50
+ // resolving the theming functions and applying the overrides
51
+ const primitiveOverrides = themeOverrideFromProvider === null || themeOverrideFromProvider === void 0 ? void 0 : themeOverrideFromProvider.primitives;
52
+ const semanticsOverrides = themeOverrideFromProvider === null || themeOverrideFromProvider === void 0 ? void 0 : themeOverrideFromProvider.semantics;
53
+ // @ts-ignore TODO-theme-types: fix typing
54
+ const sharedTokensOverrides = themeOverrideFromProvider === null || themeOverrideFromProvider === void 0 ? void 0 : themeOverrideFromProvider.sharedTokens;
55
+ const componentOverridesFromSettingsProvider = // @ts-ignore TODO-theme-types: fix typing
56
+ themeOverrideFromProvider === null || themeOverrideFromProvider === void 0 ? void 0 : (_themeOverrideFromPro = themeOverrideFromProvider.components) === null || _themeOverrideFromPro === void 0 ? void 0 : _themeOverrideFromPro[componentWithTokensId];
57
+ const primitives = mergeDeep(themeInContext.newTheme.primitives, primitiveOverrides);
58
+ const semantics = mergeDeep((_themeInContext$newTh = (_themeInContext$newTh2 = themeInContext.newTheme).semantics) === null || _themeInContext$newTh === void 0 ? void 0 : _themeInContext$newTh.call(_themeInContext$newTh2, primitives), semanticsOverrides);
59
+ const sharedTokens = mergeDeep((_themeInContext$newTh3 = (_themeInContext$newTh4 = themeInContext.newTheme).sharedTokens) === null || _themeInContext$newTh3 === void 0 ? void 0 : _themeInContext$newTh3.call(_themeInContext$newTh4, semantics), sharedTokensOverrides);
60
+ const baseComponentTheme = (_themeInContext$newTh5 = (_themeInContext$newTh6 = themeInContext.newTheme.components)[componentWithTokensId]) === null || _themeInContext$newTh5 === void 0 ? void 0 : _themeInContext$newTh5.call(_themeInContext$newTh6, semantics);
61
+ const componentThemeFromSettingsProvider = mergeDeep(baseComponentTheme, componentOverridesFromSettingsProvider);
62
+ const componentTheme = mergeDeep(componentThemeFromSettingsProvider,
63
+ // @ts-ignore TODO-theme-types: fix typing
64
+ typeof themeOverride === 'function' ? themeOverride(componentThemeFromSettingsProvider, themeInContext) : themeOverride);
65
+
66
+ // @ts-ignore TODO-theme-types: fix typing
67
+ return generateStyle(componentTheme, params, sharedTokens);
61
68
  };
62
69
  export default useStyle;
63
70
  export { useStyle };
package/es/withStyle.js CHANGED
@@ -25,10 +25,9 @@ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
25
25
 
26
26
  import { forwardRef, useState } from 'react';
27
27
  import hoistNonReactStatics from 'hoist-non-react-statics';
28
- import { deepEqual as isEqual } from '@instructure/ui-utils';
28
+ import { deepEqual as isEqual, mergeDeep } from '@instructure/ui-utils';
29
29
  import { warn } from '@instructure/console';
30
30
  import { decorator } from '@instructure/ui-decorator';
31
- import { getComponentThemeOverride } from "./getComponentThemeOverride.js";
32
31
  import { useTheme } from "./useTheme.js"; // Extract is needed because it would allow number otherwise
33
32
  // https://stackoverflow.com/a/51808262/319473
34
33
  // Unique name of an InstUI component
@@ -93,12 +92,27 @@ const defaultValues = {
93
92
  * @param {function} generateStyle - The function that returns the component's style object
94
93
  * @returns {ReactElement} The decorated WithStyle Component
95
94
  */
96
- const withStyle = decorator((ComposedComponent, generateStyle, useTokensFrom) => {
95
+ const withStyle = decorator((ComposedComponent, generateStyle, useTokensFrom, frozenTheme) => {
97
96
  var _ComposedComponent$co, _process, _process$env;
98
97
  const displayName = ComposedComponent.displayName || ComposedComponent.name;
99
- const componentId = (_ComposedComponent$co = ComposedComponent.componentId) === null || _ComposedComponent$co === void 0 ? void 0 : _ComposedComponent$co.replace('.', '');
98
+ const componentId = useTokensFrom !== null && useTokensFrom !== void 0 ? useTokensFrom : (_ComposedComponent$co = ComposedComponent.componentId) === null || _ComposedComponent$co === void 0 ? void 0 : _ComposedComponent$co.replace('.', '');
100
99
  const WithStyle = /*#__PURE__*/forwardRef((props, ref) => {
101
- const theme = useTheme();
100
+ var _themeOverride$compon, _theme$newTheme$seman, _theme$newTheme, _theme$newTheme$share, _theme$newTheme2, _theme$newTheme$compo, _theme$newTheme$compo2;
101
+ const themeInContext = useTheme();
102
+ const themeKey = themeInContext.key;
103
+
104
+ // this is for the new overrides. theme.themeOverride has all the overrides
105
+ const themeOverride = themeInContext.themeOverride;
106
+
107
+ // if a new theme has been added to the lib since this component version has been frozen, it can't be used with this
108
+ // theme, so we throw an error. Solution: upgrade to the latest version, it will support it
109
+ if (frozenTheme && !frozenTheme[themeKey]) {}
110
+
111
+ // if this component is an older component version but still uses the new theming system, it'll have a frozenTheme
112
+ // object passed to it. We use that instead of the current theme so backward compatibility stays intact
113
+ const theme = frozenTheme ? {
114
+ newTheme: frozenTheme[themeKey]
115
+ } : themeInContext;
102
116
  if (props.styles) {
103
117
  warn(false, `Manually passing the "styles" property is not allowed on the ${displayName} component. Using the default styles calculated by the @withStyle decorator instead.\n`, props.styles);
104
118
  }
@@ -110,21 +124,34 @@ const withStyle = decorator((ComposedComponent, generateStyle, useTokensFrom) =>
110
124
  ...props,
111
125
  ...defaultValues
112
126
  };
113
- const componentWithTokensId = useTokensFrom !== null && useTokensFrom !== void 0 ? useTokensFrom : componentId;
114
- const baseComponentTheme = theme.newTheme.components[componentWithTokensId];
115
- const themeOverride = getComponentThemeOverride(theme, displayName, ComposedComponent.componentId, componentProps.themeOverride, baseComponentTheme);
116
- const componentTheme = {
117
- ...baseComponentTheme,
118
- ...themeOverride
119
- };
127
+ // resolving the theming functions and applying the overrides
128
+ const primitiveOverrides = themeOverride === null || themeOverride === void 0 ? void 0 : themeOverride.primitives;
129
+ const semanticsOverrides = themeOverride === null || themeOverride === void 0 ? void 0 : themeOverride.semantics;
130
+ // @ts-ignore TODO-theme-types: fix typing
131
+ const sharedTokensOverrides = themeOverride === null || themeOverride === void 0 ? void 0 : themeOverride.sharedTokens;
132
+ const componentOverridesFromSettingsProvider = // @ts-ignore TODO-theme-types: fix typing
133
+ themeOverride === null || themeOverride === void 0 ? void 0 : (_themeOverride$compon = themeOverride.components) === null || _themeOverride$compon === void 0 ? void 0 : _themeOverride$compon[componentId];
134
+ const componentOverridesFromThemeOverrideProp = componentProps.themeOverride;
135
+ const primitives = mergeDeep(theme.newTheme.primitives, primitiveOverrides);
136
+ const semantics = mergeDeep((_theme$newTheme$seman = (_theme$newTheme = theme.newTheme).semantics) === null || _theme$newTheme$seman === void 0 ? void 0 : _theme$newTheme$seman.call(_theme$newTheme, primitives), semanticsOverrides);
137
+ const sharedTokens = mergeDeep((_theme$newTheme$share = (_theme$newTheme2 = theme.newTheme).sharedTokens) === null || _theme$newTheme$share === void 0 ? void 0 : _theme$newTheme$share.call(_theme$newTheme2, semantics), sharedTokensOverrides);
138
+ const baseComponentTheme = (_theme$newTheme$compo = (_theme$newTheme$compo2 = theme.newTheme.components)[componentId]) === null || _theme$newTheme$compo === void 0 ? void 0 : _theme$newTheme$compo.call(_theme$newTheme$compo2, semantics);
139
+ const componentThemeFromSettingsProvider = mergeDeep(baseComponentTheme, componentOverridesFromSettingsProvider);
140
+ const componentTheme = mergeDeep(componentThemeFromSettingsProvider,
141
+ // @ts-ignore TODO-theme-types: fix typing
142
+ typeof componentOverridesFromThemeOverrideProp === 'function' ? componentOverridesFromThemeOverrideProp(componentThemeFromSettingsProvider, themeInContext) : componentOverridesFromThemeOverrideProp);
120
143
 
121
144
  // TODO do not call here generateStyle, it does not receive the extraArgs
122
- const _useState = useState(generateStyle ? generateStyle(componentTheme, componentProps, theme.newTheme.sharedTokens, {}) : {}),
145
+ const _useState = useState(generateStyle ?
146
+ // @ts-ignore TODO-theme-types: fix typing
147
+ generateStyle(componentTheme, componentProps, sharedTokens, {}) : {}),
123
148
  _useState2 = _slicedToArray(_useState, 2),
124
149
  styles = _useState2[0],
125
150
  setStyles = _useState2[1];
126
151
  const makeStyleHandler = extraArgs => {
127
- const calculatedStyles = generateStyle(componentTheme, componentProps, theme.newTheme.sharedTokens, extraArgs);
152
+ const calculatedStyles = generateStyle(componentTheme, componentProps,
153
+ // @ts-ignore TODO-theme-types: fix typing
154
+ sharedTokens, extraArgs);
128
155
  if (!isEqual(calculatedStyles, styles)) {
129
156
  setStyles(calculatedStyles);
130
157
  }
@@ -134,11 +161,6 @@ const withStyle = decorator((ComposedComponent, generateStyle, useTokensFrom) =>
134
161
  ...props,
135
162
  makeStyles: makeStyleHandler,
136
163
  styles: styles
137
- // passing themeOverrides is needed for components like Button
138
- // that have no makeStyles of their own and only pass themeOverrides
139
- // to the underlying component (e.g.: BaseButton)
140
- ,
141
- themeOverride: themeOverride
142
164
  });
143
165
  });
144
166
  hoistNonReactStatics(WithStyle, ComposedComponent);
@@ -45,15 +45,25 @@ function InstUISettingsProvider({
45
45
  children,
46
46
  theme = {},
47
47
  dir,
48
- instanceCounterMap
48
+ instanceCounterMap,
49
+ themeOverride
49
50
  }) {
50
51
  var _process, _process$env, _process2, _process2$env;
51
52
  const finalDir = dir || (0, _react.useContext)(_TextDirectionContext.TextDirectionContext);
52
53
  if (typeof process !== 'undefined' && (((_process = process) === null || _process === void 0 ? void 0 : (_process$env = _process.env) === null || _process$env === void 0 ? void 0 : _process$env.NODE_ENV) !== 'production' || ((_process2 = process) === null || _process2 === void 0 ? void 0 : (_process2$env = _process2.env) === null || _process2$env === void 0 ? void 0 : _process2$env.GITHUB_PULL_REQUEST_PREVIEW) === 'true') && finalDir === 'auto') {}
54
+
55
+ /**
56
+ * new pattern: if you want to replace a theme inside an InstUISettingsProvider, provide it via the theme prop. It'll
57
+ * override everything, replacing the otherwise used theme.
58
+ * if you want to apply an override, use the themeOverride prop.
59
+ * For backward compatibility reasons, the old way of passing a partial theme to the theme prop is still supported, however only for
60
+ * legacy (pre v11_7) components. Overriding the newTheme this way could break the system.
61
+ */
62
+
53
63
  let providers = (0, _jsxRuntime.jsx)(_DeterministicIdContextProvider.DeterministicIdContextProvider, {
54
64
  instanceCounterMap: instanceCounterMap,
55
65
  children: (0, _jsxRuntime.jsx)(_react2.ThemeProvider, {
56
- theme: (0, _getTheme.getTheme)(theme),
66
+ theme: (0, _getTheme.getTheme)(theme, themeOverride),
57
67
  children: (0, _jsxRuntime.jsx)(_TextDirectionContext.TextDirectionContext.Provider, {
58
68
  value: finalDir,
59
69
  children: children
package/lib/getTheme.js CHANGED
@@ -43,13 +43,14 @@ var _mergeDeep = require("@instructure/ui-utils/lib/mergeDeep.js");
43
43
  * If an override object is given, it returns the ancestor theme and
44
44
  * the overrides merged together.
45
45
  *
46
- * @param themeOrOverride - A full theme or an override object
46
+ * @param themeOrLegacyOverride - A full theme or an override object
47
+ * @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
47
48
  * @returns A function that returns with the theme object for the [ThemeProvider](https://emotion.sh/docs/theming#themeprovider-reactcomponenttype)
48
49
  * This function is called by Emotion on theme provider creation, where
49
50
  * `ancestorTheme` is a theme object from an ancestor `ThemeProvider`
50
51
  */
51
- const getTheme = themeOrOverride => (ancestorTheme = {}) => {
52
- var _resolvedThemeOrOverr;
52
+ const getTheme = (themeOrLegacyOverride, themeOverride) => (ancestorTheme = {}) => {
53
+ var _resolvedLegacyThemeO;
53
54
  // we need to clone the ancestor theme not to override it
54
55
  let currentTheme;
55
56
  if (Object.keys(ancestorTheme).length === 0) {
@@ -59,14 +60,18 @@ const getTheme = themeOrOverride => (ancestorTheme = {}) => {
59
60
  } else {
60
61
  currentTheme = ancestorTheme;
61
62
  }
62
- let resolvedThemeOrOverride = themeOrOverride;
63
- if (typeof resolvedThemeOrOverride === 'function') {
64
- resolvedThemeOrOverride = resolvedThemeOrOverride(currentTheme);
65
- }
63
+ const resolvedThemeOverride = typeof themeOverride === 'function' ? themeOverride(currentTheme) : themeOverride;
64
+ let resolvedLegacyThemeOrOverride = typeof themeOrLegacyOverride === 'function' ? themeOrLegacyOverride(currentTheme) : themeOrLegacyOverride;
66
65
  try {
67
66
  // If a valid InstUI theme is given, it just returns the theme.
68
- if ((0, _isBaseTheme.isBaseTheme)(resolvedThemeOrOverride)) {
69
- return resolvedThemeOrOverride;
67
+ // in case of the legacy pattern, it's just a simple replacement, in the new system, overrides should be merged into the new theme. Old overrides will be removed because they may make no sense for a different theme
68
+ if ((0, _isBaseTheme.isBaseTheme)(resolvedLegacyThemeOrOverride)) {
69
+ return {
70
+ ...resolvedLegacyThemeOrOverride,
71
+ ...(resolvedThemeOverride ? {
72
+ themeOverride: resolvedThemeOverride
73
+ } : {})
74
+ };
70
75
  }
71
76
  } catch {
72
77
  var _process3, _process3$env, _process4, _process4$env;
@@ -74,14 +79,16 @@ const getTheme = themeOrOverride => (ancestorTheme = {}) => {
74
79
  // We are using this fail-safe here for the non-TS users,
75
80
  // because the whole page can break without a theme.
76
81
  if (typeof process !== 'undefined' && (((_process3 = process) === null || _process3 === void 0 ? void 0 : (_process3$env = _process3.env) === null || _process3$env === void 0 ? void 0 : _process3$env.NODE_ENV) !== 'production' || ((_process4 = process) === null || _process4 === void 0 ? void 0 : (_process4$env = _process4.env) === null || _process4$env === void 0 ? void 0 : _process4$env.GITHUB_PULL_REQUEST_PREVIEW) === 'true')) {}
77
- resolvedThemeOrOverride = {};
82
+ resolvedLegacyThemeOrOverride = {};
78
83
  }
79
84
  const themeName = currentTheme.key;
80
85
 
81
- // we pick the overrides for the current theme from the override object
82
- const specificOverrides = (_resolvedThemeOrOverr = resolvedThemeOrOverride) === null || _resolvedThemeOrOverr === void 0 ? void 0 : _resolvedThemeOrOverr.themeOverrides;
86
+ // legacy: we pick the overrides for the current theme from the override object
87
+ const specificOverrides = (_resolvedLegacyThemeO = resolvedLegacyThemeOrOverride) === null || _resolvedLegacyThemeO === void 0 ? void 0 : _resolvedLegacyThemeO.themeOverrides;
83
88
  const currentThemeOverrides = (specificOverrides === null || specificOverrides === void 0 ? void 0 : specificOverrides[themeName]) || specificOverrides || {};
84
- return (0, _mergeDeep.mergeDeep)(currentTheme, resolvedThemeOrOverride, currentThemeOverrides);
89
+ return (0, _mergeDeep.mergeDeep)(currentTheme, resolvedLegacyThemeOrOverride, currentThemeOverrides, ...(resolvedThemeOverride ? [{
90
+ themeOverride: resolvedThemeOverride
91
+ }] : []));
85
92
  };
86
93
  exports.getTheme = getTheme;
87
94
  var _default = exports.default = getTheme;
package/lib/index.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  var _exportNames = {
7
+ useComputedTheme: true,
7
8
  InstUISettingsProvider: true,
8
9
  withStyleLegacy: true,
9
10
  getComponentThemeOverride: true,
@@ -73,6 +74,12 @@ Object.defineProperty(exports, "mirrorShorthandEdges", {
73
74
  return _styleUtils.mirrorShorthandEdges;
74
75
  }
75
76
  });
77
+ Object.defineProperty(exports, "useComputedTheme", {
78
+ enumerable: true,
79
+ get: function () {
80
+ return _useComputedTheme.useComputedTheme;
81
+ }
82
+ });
76
83
  Object.defineProperty(exports, "useStyle", {
77
84
  enumerable: true,
78
85
  get: function () {
@@ -115,6 +122,7 @@ Object.keys(_react).forEach(function (key) {
115
122
  }
116
123
  });
117
124
  });
125
+ var _useComputedTheme = require("./useComputedTheme");
118
126
  var _InstUISettingsProvider = require("./InstUISettingsProvider");
119
127
  var _withStyleLegacy = require("./withStyleLegacy");
120
128
  var _getComponentThemeOverride = require("./getComponentThemeOverride");
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useComputedTheme = void 0;
7
+ var _react = require("@emotion/react");
8
+ /*
9
+ * The MIT License (MIT)
10
+ *
11
+ * Copyright (c) 2015 - present Instructure, Inc.
12
+ *
13
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ * of this software and associated documentation files (the "Software"), to deal
15
+ * in the Software without restriction, including without limitation the rights
16
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ * copies of the Software, and to permit persons to whom the Software is
18
+ * furnished to do so, subject to the following conditions:
19
+ *
20
+ * The above copyright notice and this permission notice shall be included in all
21
+ * copies or substantial portions of the Software.
22
+ *
23
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ * SOFTWARE.
30
+ */
31
+
32
+ /**
33
+ * ---
34
+ * category: utilities/themes
35
+ * ---
36
+ * A hook that returns the fully resolved theme object from the context, with all token layers evaluated.
37
+ *
38
+ * The raw `newTheme` stored on the context exposes its layers as functions
39
+ * that depend on the previous layer (`semantics` takes `primitives`,
40
+ * `components` and `sharedTokens` take `semantics`). This hook runs those
41
+ * functions for you and returns the computed values, so you can read
42
+ * tokens directly without having to know the evaluation order.
43
+ *
44
+ * @returns An object containing the computed `primitives`, `semantics`,
45
+ * `components` and `sharedTokens` of the current theme.
46
+ */
47
+ const useComputedTheme = () => {
48
+ var _rawTheme$semantics, _rawTheme$sharedToken;
49
+ const rawTheme = (0, _react.useTheme)().newTheme;
50
+ const primitives = rawTheme === null || rawTheme === void 0 ? void 0 : rawTheme.primitives;
51
+ const semantics = rawTheme === null || rawTheme === void 0 ? void 0 : (_rawTheme$semantics = rawTheme.semantics) === null || _rawTheme$semantics === void 0 ? void 0 : _rawTheme$semantics.call(rawTheme, primitives);
52
+ const components = Object.keys(rawTheme === null || rawTheme === void 0 ? void 0 : rawTheme.components).reduce((acc, component) => {
53
+ var _rawTheme$components$, _rawTheme$components;
54
+ return {
55
+ ...acc,
56
+ [component]: (_rawTheme$components$ = (_rawTheme$components = rawTheme.components)[component]) === null || _rawTheme$components$ === void 0 ? void 0 : _rawTheme$components$.call(_rawTheme$components, semantics)
57
+ };
58
+ }, {});
59
+ const sharedTokens = rawTheme === null || rawTheme === void 0 ? void 0 : (_rawTheme$sharedToken = rawTheme.sharedTokens) === null || _rawTheme$sharedToken === void 0 ? void 0 : _rawTheme$sharedToken.call(rawTheme, semantics);
60
+ return {
61
+ primitives,
62
+ semantics,
63
+ components,
64
+ sharedTokens
65
+ };
66
+ };
67
+ exports.useComputedTheme = useComputedTheme;
package/lib/useStyle.js CHANGED
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.useStyle = exports.default = void 0;
7
7
  var _useTheme = require("./useTheme");
8
- var _getComponentThemeOverride = require("./getComponentThemeOverride");
8
+ var _mergeDeep = require("@instructure/ui-utils/lib/mergeDeep.js");
9
9
  /*
10
10
  * The MIT License (MIT)
11
11
  *
@@ -36,10 +36,6 @@ var _getComponentThemeOverride = require("./getComponentThemeOverride");
36
36
  * Type for a theme override
37
37
  */
38
38
 
39
- const isNewThemeObject = obj => {
40
- return typeof (obj === null || obj === void 0 ? void 0 : obj.newTheme) === 'object';
41
- };
42
-
43
39
  /**
44
40
  * new useStyle syntax, use this with v12 themes
45
41
  */
@@ -47,27 +43,34 @@ const isNewThemeObject = obj => {
47
43
  // TODO: improve useStyle to handle generateStyle functions that don't
48
44
  // have a theme.
49
45
  const useStyle = useStyleParams => {
50
- var _ref, _ref2;
46
+ var _themeOverrideFromPro, _themeInContext$newTh, _themeInContext$newTh2, _themeInContext$newTh3, _themeInContext$newTh4, _themeInContext$newTh5, _themeInContext$newTh6;
51
47
  const generateStyle = useStyleParams.generateStyle,
52
48
  params = useStyleParams.params,
53
49
  componentId = useStyleParams.componentId,
54
- displayName = useStyleParams.displayName,
55
50
  themeOverride = useStyleParams.themeOverride;
56
51
  const useTokensFrom = useStyleParams.useTokensFrom;
57
- const theme = (0, _useTheme.useTheme)();
58
- let baseComponentTheme = {};
52
+ const themeInContext = (0, _useTheme.useTheme)();
53
+ const themeOverrideFromProvider = themeInContext.themeOverride;
59
54
  const componentWithTokensId = useTokensFrom !== null && useTokensFrom !== void 0 ? useTokensFrom : componentId;
60
- if (isNewThemeObject(theme) &&
61
- // TODO: is it possible not to have a theme object here?
62
- theme.newTheme.components[componentWithTokensId]) {
63
- baseComponentTheme = theme.newTheme.components[componentWithTokensId];
64
- }
65
- const finalOverride = (0, _getComponentThemeOverride.getComponentThemeOverride)(theme, (_ref = (_ref2 = useTokensFrom !== null && useTokensFrom !== void 0 ? useTokensFrom : displayName) !== null && _ref2 !== void 0 ? _ref2 : componentId) !== null && _ref !== void 0 ? _ref : '', componentWithTokensId, themeOverride, baseComponentTheme);
66
- const componentTheme = {
67
- ...baseComponentTheme,
68
- ...finalOverride
69
- };
70
- return generateStyle(componentTheme, params, theme.newTheme.sharedTokens);
55
+
56
+ // resolving the theming functions and applying the overrides
57
+ const primitiveOverrides = themeOverrideFromProvider === null || themeOverrideFromProvider === void 0 ? void 0 : themeOverrideFromProvider.primitives;
58
+ const semanticsOverrides = themeOverrideFromProvider === null || themeOverrideFromProvider === void 0 ? void 0 : themeOverrideFromProvider.semantics;
59
+ // @ts-ignore TODO-theme-types: fix typing
60
+ const sharedTokensOverrides = themeOverrideFromProvider === null || themeOverrideFromProvider === void 0 ? void 0 : themeOverrideFromProvider.sharedTokens;
61
+ const componentOverridesFromSettingsProvider = // @ts-ignore TODO-theme-types: fix typing
62
+ themeOverrideFromProvider === null || themeOverrideFromProvider === void 0 ? void 0 : (_themeOverrideFromPro = themeOverrideFromProvider.components) === null || _themeOverrideFromPro === void 0 ? void 0 : _themeOverrideFromPro[componentWithTokensId];
63
+ const primitives = (0, _mergeDeep.mergeDeep)(themeInContext.newTheme.primitives, primitiveOverrides);
64
+ const semantics = (0, _mergeDeep.mergeDeep)((_themeInContext$newTh = (_themeInContext$newTh2 = themeInContext.newTheme).semantics) === null || _themeInContext$newTh === void 0 ? void 0 : _themeInContext$newTh.call(_themeInContext$newTh2, primitives), semanticsOverrides);
65
+ const sharedTokens = (0, _mergeDeep.mergeDeep)((_themeInContext$newTh3 = (_themeInContext$newTh4 = themeInContext.newTheme).sharedTokens) === null || _themeInContext$newTh3 === void 0 ? void 0 : _themeInContext$newTh3.call(_themeInContext$newTh4, semantics), sharedTokensOverrides);
66
+ const baseComponentTheme = (_themeInContext$newTh5 = (_themeInContext$newTh6 = themeInContext.newTheme.components)[componentWithTokensId]) === null || _themeInContext$newTh5 === void 0 ? void 0 : _themeInContext$newTh5.call(_themeInContext$newTh6, semantics);
67
+ const componentThemeFromSettingsProvider = (0, _mergeDeep.mergeDeep)(baseComponentTheme, componentOverridesFromSettingsProvider);
68
+ const componentTheme = (0, _mergeDeep.mergeDeep)(componentThemeFromSettingsProvider,
69
+ // @ts-ignore TODO-theme-types: fix typing
70
+ typeof themeOverride === 'function' ? themeOverride(componentThemeFromSettingsProvider, themeInContext) : themeOverride);
71
+
72
+ // @ts-ignore TODO-theme-types: fix typing
73
+ return generateStyle(componentTheme, params, sharedTokens);
71
74
  };
72
75
  exports.useStyle = useStyle;
73
76
  var _default = exports.default = useStyle;