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

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.
package/CHANGELOG.md CHANGED
@@ -3,13 +3,20 @@
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-60](https://github.com/instructure/instructure-ui/compare/v11.7.1...v11.7.2-snapshot-60) (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
+ * **many:** fix issues ([9d623ed](https://github.com/instructure/instructure-ui/commit/9d623ed9ba2be49549b625d1e436edc230a4df41))
19
+ * **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
20
 
14
21
 
15
22
 
@@ -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/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/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;
package/lib/withStyle.js CHANGED
@@ -9,9 +9,9 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
9
9
  var _react = require("react");
10
10
  var _hoistNonReactStatics = _interopRequireDefault(require("hoist-non-react-statics"));
11
11
  var _deepEqual = require("@instructure/ui-utils/lib/deepEqual.js");
12
+ var _mergeDeep = require("@instructure/ui-utils/lib/mergeDeep.js");
12
13
  var _console = require("@instructure/console");
13
14
  var _decorator = require("@instructure/ui-decorator/lib/decorator.js");
14
- var _getComponentThemeOverride = require("./getComponentThemeOverride");
15
15
  var _useTheme = require("./useTheme");
16
16
  var _jsxRuntime = require("@emotion/react/jsx-runtime");
17
17
  /*
@@ -103,12 +103,27 @@ const defaultValues = {
103
103
  * @param {function} generateStyle - The function that returns the component's style object
104
104
  * @returns {ReactElement} The decorated WithStyle Component
105
105
  */
106
- const withStyle = exports.withStyle = (0, _decorator.decorator)((ComposedComponent, generateStyle, useTokensFrom) => {
106
+ const withStyle = exports.withStyle = (0, _decorator.decorator)((ComposedComponent, generateStyle, useTokensFrom, frozenTheme) => {
107
107
  var _ComposedComponent$co, _process, _process$env;
108
108
  const displayName = ComposedComponent.displayName || ComposedComponent.name;
109
- const componentId = (_ComposedComponent$co = ComposedComponent.componentId) === null || _ComposedComponent$co === void 0 ? void 0 : _ComposedComponent$co.replace('.', '');
109
+ const componentId = useTokensFrom !== null && useTokensFrom !== void 0 ? useTokensFrom : (_ComposedComponent$co = ComposedComponent.componentId) === null || _ComposedComponent$co === void 0 ? void 0 : _ComposedComponent$co.replace('.', '');
110
110
  const WithStyle = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
111
- const theme = (0, _useTheme.useTheme)();
111
+ var _themeOverride$compon, _theme$newTheme$seman, _theme$newTheme, _theme$newTheme$share, _theme$newTheme2, _theme$newTheme$compo, _theme$newTheme$compo2;
112
+ const themeInContext = (0, _useTheme.useTheme)();
113
+ const themeKey = themeInContext.key;
114
+
115
+ // this is for the new overrides. theme.themeOverride has all the overrides
116
+ const themeOverride = themeInContext.themeOverride;
117
+
118
+ // if a new theme has been added to the lib since this component version has been frozen, it can't be used with this
119
+ // theme, so we throw an error. Solution: upgrade to the latest version, it will support it
120
+ if (frozenTheme && !frozenTheme[themeKey]) {}
121
+
122
+ // if this component is an older component version but still uses the new theming system, it'll have a frozenTheme
123
+ // object passed to it. We use that instead of the current theme so backward compatibility stays intact
124
+ const theme = frozenTheme ? {
125
+ newTheme: frozenTheme[themeKey]
126
+ } : themeInContext;
112
127
  if (props.styles) {
113
128
  (0, _console.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);
114
129
  }
@@ -120,21 +135,34 @@ const withStyle = exports.withStyle = (0, _decorator.decorator)((ComposedCompone
120
135
  ...props,
121
136
  ...defaultValues
122
137
  };
123
- const componentWithTokensId = useTokensFrom !== null && useTokensFrom !== void 0 ? useTokensFrom : componentId;
124
- const baseComponentTheme = theme.newTheme.components[componentWithTokensId];
125
- const themeOverride = (0, _getComponentThemeOverride.getComponentThemeOverride)(theme, displayName, ComposedComponent.componentId, componentProps.themeOverride, baseComponentTheme);
126
- const componentTheme = {
127
- ...baseComponentTheme,
128
- ...themeOverride
129
- };
138
+ // resolving the theming functions and applying the overrides
139
+ const primitiveOverrides = themeOverride === null || themeOverride === void 0 ? void 0 : themeOverride.primitives;
140
+ const semanticsOverrides = themeOverride === null || themeOverride === void 0 ? void 0 : themeOverride.semantics;
141
+ // @ts-ignore TODO-theme-types: fix typing
142
+ const sharedTokensOverrides = themeOverride === null || themeOverride === void 0 ? void 0 : themeOverride.sharedTokens;
143
+ const componentOverridesFromSettingsProvider = // @ts-ignore TODO-theme-types: fix typing
144
+ themeOverride === null || themeOverride === void 0 ? void 0 : (_themeOverride$compon = themeOverride.components) === null || _themeOverride$compon === void 0 ? void 0 : _themeOverride$compon[componentId];
145
+ const componentOverridesFromThemeOverrideProp = componentProps.themeOverride;
146
+ const primitives = (0, _mergeDeep.mergeDeep)(theme.newTheme.primitives, primitiveOverrides);
147
+ const semantics = (0, _mergeDeep.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);
148
+ const sharedTokens = (0, _mergeDeep.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);
149
+ 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);
150
+ const componentThemeFromSettingsProvider = (0, _mergeDeep.mergeDeep)(baseComponentTheme, componentOverridesFromSettingsProvider);
151
+ const componentTheme = (0, _mergeDeep.mergeDeep)(componentThemeFromSettingsProvider,
152
+ // @ts-ignore TODO-theme-types: fix typing
153
+ typeof componentOverridesFromThemeOverrideProp === 'function' ? componentOverridesFromThemeOverrideProp(componentThemeFromSettingsProvider, themeInContext) : componentOverridesFromThemeOverrideProp);
130
154
 
131
155
  // TODO do not call here generateStyle, it does not receive the extraArgs
132
- const _useState = (0, _react.useState)(generateStyle ? generateStyle(componentTheme, componentProps, theme.newTheme.sharedTokens, {}) : {}),
156
+ const _useState = (0, _react.useState)(generateStyle ?
157
+ // @ts-ignore TODO-theme-types: fix typing
158
+ generateStyle(componentTheme, componentProps, sharedTokens, {}) : {}),
133
159
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
134
160
  styles = _useState2[0],
135
161
  setStyles = _useState2[1];
136
162
  const makeStyleHandler = extraArgs => {
137
- const calculatedStyles = generateStyle(componentTheme, componentProps, theme.newTheme.sharedTokens, extraArgs);
163
+ const calculatedStyles = generateStyle(componentTheme, componentProps,
164
+ // @ts-ignore TODO-theme-types: fix typing
165
+ sharedTokens, extraArgs);
138
166
  if (!(0, _deepEqual.deepEqual)(calculatedStyles, styles)) {
139
167
  setStyles(calculatedStyles);
140
168
  }
@@ -144,11 +172,6 @@ const withStyle = exports.withStyle = (0, _decorator.decorator)((ComposedCompone
144
172
  ...props,
145
173
  makeStyles: makeStyleHandler,
146
174
  styles: styles
147
- // passing themeOverrides is needed for components like Button
148
- // that have no makeStyles of their own and only pass themeOverrides
149
- // to the underlying component (e.g.: BaseButton)
150
- ,
151
- themeOverride: themeOverride
152
175
  });
153
176
  });
154
177
  (0, _hoistNonReactStatics.default)(WithStyle, ComposedComponent);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/emotion",
3
- "version": "11.7.2-snapshot-54",
3
+ "version": "11.7.2-snapshot-60",
4
4
  "description": "A UI component library made by Instructure Inc.",
5
5
  "author": "Instructure, Inc. Engineering and Product Design",
6
6
  "module": "./es/index.js",
@@ -17,14 +17,14 @@
17
17
  "@babel/runtime": "^7.27.6",
18
18
  "@emotion/react": "^11",
19
19
  "hoist-non-react-statics": "^3.3.2",
20
- "@instructure/console": "11.7.2-snapshot-54",
21
- "@instructure/ui-color-utils": "11.7.2-snapshot-54",
22
- "@instructure/shared-types": "11.7.2-snapshot-54",
23
- "@instructure/ui-i18n": "11.7.2-snapshot-54",
24
- "@instructure/ui-decorator": "11.7.2-snapshot-54",
25
- "@instructure/ui-react-utils": "11.7.2-snapshot-54",
26
- "@instructure/ui-themes": "11.7.2-snapshot-54",
27
- "@instructure/ui-utils": "11.7.2-snapshot-54"
20
+ "@instructure/console": "11.7.2-snapshot-60",
21
+ "@instructure/shared-types": "11.7.2-snapshot-60",
22
+ "@instructure/ui-decorator": "11.7.2-snapshot-60",
23
+ "@instructure/ui-color-utils": "11.7.2-snapshot-60",
24
+ "@instructure/ui-i18n": "11.7.2-snapshot-60",
25
+ "@instructure/ui-react-utils": "11.7.2-snapshot-60",
26
+ "@instructure/ui-themes": "11.7.2-snapshot-60",
27
+ "@instructure/ui-utils": "11.7.2-snapshot-60"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@testing-library/jest-dom": "^6.6.3",
@@ -32,7 +32,7 @@
32
32
  "@testing-library/user-event": "^14.6.1",
33
33
  "react-dom": "18.3.1",
34
34
  "vitest": "^3.2.2",
35
- "@instructure/ui-babel-preset": "11.7.2-snapshot-54"
35
+ "@instructure/ui-babel-preset": "11.7.2-snapshot-60"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": ">=18 <=19"
@@ -104,7 +104,7 @@ type Overrides = {
104
104
 
105
105
  type BaseThemeOrOverride = Theme | PartialTheme | Overrides
106
106
 
107
- type ThemeOrOverride =
107
+ type ThemeOrLegacyOverride =
108
108
  | BaseThemeOrOverride
109
109
  | ((theme: BaseTheme) => BaseThemeOrOverride)
110
110
 
@@ -147,7 +147,7 @@ export interface StyleObject {
147
147
 
148
148
  export type {
149
149
  BaseThemeOrOverride,
150
- ThemeOrOverride,
150
+ ThemeOrLegacyOverride,
151
151
  Overrides,
152
152
  ComponentOverride,
153
153
  SpecificThemeOverride,