@instructure/emotion 11.6.0 → 11.6.1-snapshot-129

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 (69) hide show
  1. package/CHANGELOG.md +51 -303
  2. package/es/InstUISettingsProvider/index.js +1 -1
  3. package/es/getComponentThemeOverride.js +5 -4
  4. package/es/getTheme.js +2 -2
  5. package/es/index.js +4 -1
  6. package/es/styleUtils/calcFocusOutlineStyles.js +71 -0
  7. package/es/styleUtils/calcSpacingFromShorthand.js +112 -0
  8. package/es/styleUtils/index.js +2 -1
  9. package/es/useStyle.js +27 -6
  10. package/es/useStyleLegacy.js +49 -0
  11. package/es/useTheme.js +1 -1
  12. package/es/withStyle.js +13 -31
  13. package/es/withStyleLegacy.js +116 -0
  14. package/lib/InstUISettingsProvider/index.js +1 -1
  15. package/lib/getComponentThemeOverride.js +5 -4
  16. package/lib/getTheme.js +2 -2
  17. package/lib/index.js +38 -7
  18. package/lib/styleUtils/calcFocusOutlineStyles.js +78 -0
  19. package/lib/styleUtils/calcSpacingFromShorthand.js +118 -0
  20. package/lib/styleUtils/index.js +14 -7
  21. package/lib/useStyle.js +28 -6
  22. package/lib/useStyleLegacy.js +59 -0
  23. package/lib/useTheme.js +1 -1
  24. package/lib/withStyle.js +13 -31
  25. package/lib/withStyleLegacy.js +125 -0
  26. package/package.json +11 -9
  27. package/src/EmotionTypes.ts +10 -1
  28. package/src/InstUISettingsProvider/index.tsx +5 -1
  29. package/src/getComponentThemeOverride.ts +9 -8
  30. package/src/getTheme.ts +8 -2
  31. package/src/index.ts +7 -2
  32. package/src/styleUtils/calcFocusOutlineStyles.ts +106 -0
  33. package/src/styleUtils/calcSpacingFromShorthand.ts +127 -0
  34. package/src/styleUtils/index.ts +2 -1
  35. package/src/useStyle.ts +63 -32
  36. package/src/useStyleLegacy.ts +92 -0
  37. package/src/useTheme.ts +4 -1
  38. package/src/withStyle.tsx +29 -39
  39. package/src/withStyleLegacy.tsx +212 -0
  40. package/tsconfig.build.json +3 -0
  41. package/tsconfig.build.tsbuildinfo +1 -1
  42. package/types/EmotionTypes.d.ts +4 -2
  43. package/types/EmotionTypes.d.ts.map +1 -1
  44. package/types/InstUISettingsProvider/index.d.ts.map +1 -1
  45. package/types/getComponentThemeOverride.d.ts +4 -5
  46. package/types/getComponentThemeOverride.d.ts.map +1 -1
  47. package/types/getTheme.d.ts.map +1 -1
  48. package/types/index.d.ts +6 -2
  49. package/types/index.d.ts.map +1 -1
  50. package/types/styleUtils/calcFocusOutlineStyles.d.ts +51 -0
  51. package/types/styleUtils/calcFocusOutlineStyles.d.ts.map +1 -0
  52. package/types/styleUtils/calcSpacingFromShorthand.d.ts +33 -0
  53. package/types/styleUtils/calcSpacingFromShorthand.d.ts.map +1 -0
  54. package/types/styleUtils/index.d.ts +2 -1
  55. package/types/styleUtils/index.d.ts.map +1 -1
  56. package/types/useStyle.d.ts +15 -13
  57. package/types/useStyle.d.ts.map +1 -1
  58. package/types/useStyleLegacy.d.ts +22 -0
  59. package/types/useStyleLegacy.d.ts.map +1 -0
  60. package/types/useTheme.d.ts.map +1 -1
  61. package/types/withStyle.d.ts +2 -22
  62. package/types/withStyle.d.ts.map +1 -1
  63. package/types/withStyleLegacy.d.ts +22 -0
  64. package/types/withStyleLegacy.d.ts.map +1 -0
  65. package/es/styleUtils/mapSpacingToShorthand.js +0 -29
  66. package/lib/styleUtils/mapSpacingToShorthand.js +0 -35
  67. package/src/styleUtils/mapSpacingToShorthand.ts +0 -35
  68. package/types/styleUtils/mapSpacingToShorthand.d.ts +0 -5
  69. package/types/styleUtils/mapSpacingToShorthand.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/emotion",
3
- "version": "11.6.0",
3
+ "version": "11.6.1-snapshot-129",
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,13 +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.6.0",
21
- "@instructure/shared-types": "11.6.0",
22
- "@instructure/ui-decorator": "11.6.0",
23
- "@instructure/ui-i18n": "11.6.0",
24
- "@instructure/ui-react-utils": "11.6.0",
25
- "@instructure/ui-themes": "11.6.0",
26
- "@instructure/ui-utils": "11.6.0"
20
+ "@instructure/ui-decorator": "11.6.1-snapshot-129",
21
+ "@instructure/shared-types": "11.6.1-snapshot-129",
22
+ "@instructure/ui-color-utils": "11.6.1-snapshot-129",
23
+ "@instructure/ui-i18n": "11.6.1-snapshot-129",
24
+ "@instructure/console": "11.6.1-snapshot-129",
25
+ "@instructure/ui-react-utils": "11.6.1-snapshot-129",
26
+ "@instructure/ui-themes": "11.6.1-snapshot-129",
27
+ "@instructure/ui-utils": "11.6.1-snapshot-129"
27
28
  },
28
29
  "devDependencies": {
29
30
  "@testing-library/jest-dom": "^6.6.3",
@@ -31,7 +32,7 @@
31
32
  "@testing-library/user-event": "^14.6.1",
32
33
  "react-dom": "18.3.1",
33
34
  "vitest": "^3.2.2",
34
- "@instructure/ui-babel-preset": "11.6.0"
35
+ "@instructure/ui-babel-preset": "11.6.1-snapshot-129"
35
36
  },
36
37
  "peerDependencies": {
37
38
  "react": ">=18 <=19"
@@ -42,6 +43,7 @@
42
43
  "sideEffects": false,
43
44
  "exports": {
44
45
  ".": {
46
+ "src": "./src/index.ts",
45
47
  "types": "./types/index.d.ts",
46
48
  "import": "./es/index.js",
47
49
  "require": "./lib/index.js",
@@ -28,6 +28,7 @@ import type {
28
28
  ComponentThemeMap,
29
29
  DeepPartial
30
30
  } from '@instructure/shared-types'
31
+ import type { Theme, SharedTokens } from '@instructure/ui-themes'
31
32
 
32
33
  /**
33
34
  * A theme object where every prop is optional
@@ -101,7 +102,7 @@ type Overrides = {
101
102
  componentOverrides?: ComponentOverride
102
103
  }
103
104
 
104
- type BaseThemeOrOverride = BaseTheme | PartialTheme | Overrides
105
+ type BaseThemeOrOverride = Theme | PartialTheme | Overrides
105
106
 
106
107
  type ThemeOrOverride =
107
108
  | BaseThemeOrOverride
@@ -120,6 +121,13 @@ type GenerateStyle = (
120
121
  state?: State
121
122
  ) => StyleObject
122
123
 
124
+ type GenerateStyleRework = (
125
+ componentTheme: ComponentTheme,
126
+ props: Props,
127
+ sharedTokens: SharedTokens,
128
+ state?: State
129
+ ) => StyleObject
130
+
123
131
  type GenerateStyleFunctional = (
124
132
  componentTheme: ComponentTheme,
125
133
  params: Record<string, unknown>
@@ -149,6 +157,7 @@ export type {
149
157
  State,
150
158
  GenerateComponentTheme,
151
159
  GenerateStyle,
160
+ GenerateStyleRework,
152
161
  GenerateStyleFunctional,
153
162
  ComponentStyle
154
163
  }
@@ -73,7 +73,11 @@ function InstUISettingsProvider({
73
73
  }: InstUIProviderProps) {
74
74
  const finalDir = dir || useContext(TextDirectionContext)
75
75
 
76
- if (process.env.NODE_ENV !== 'production' && finalDir === 'auto') {
76
+ if (
77
+ (process.env.NODE_ENV !== 'production' ||
78
+ process.env.GITHUB_PULL_REQUEST_PREVIEW === 'true') &&
79
+ finalDir === 'auto'
80
+ ) {
77
81
  console.warn(
78
82
  "'auto' is not an supported value for the 'dir' prop. Please pass 'ltr' or 'rtl'"
79
83
  )
@@ -27,8 +27,9 @@ import type {
27
27
  Overrides,
28
28
  ComponentOverride
29
29
  } from './EmotionTypes'
30
- import type { BaseTheme, ComponentTheme } from '@instructure/shared-types'
31
- import type { WithStyleProps } from './withStyle'
30
+ import type { ComponentTheme } from '@instructure/shared-types'
31
+ import { ThemeOverrideProp } from './withStyle'
32
+ import { ThemeOverrideValue } from './useStyle'
32
33
 
33
34
  type ComponentName = keyof ComponentOverride | undefined
34
35
 
@@ -42,7 +43,7 @@ type ComponentName = keyof ComponentOverride | undefined
42
43
  * @param theme - Theme object
43
44
  * @param displayName - Name of the component
44
45
  * @param componentId - componentId of the component
45
- * @param props - The component's props object
46
+ * @param themeOverride - The theme override object
46
47
  * @param componentTheme - The component's default theme
47
48
  * @returns The calculated theme override object
48
49
  */
@@ -50,14 +51,13 @@ const getComponentThemeOverride = (
50
51
  theme: ThemeOrOverride,
51
52
  displayName: string,
52
53
  componentId?: string,
53
- props?: { [k: string]: unknown } & WithStyleProps,
54
+ // ThemeOverrideProp is the old type, ThemeOverrideValue is the new one
55
+ themeOverride?: ThemeOverrideProp['themeOverride'] | ThemeOverrideValue,
54
56
  componentTheme?: ComponentTheme
55
57
  ): Partial<ComponentTheme> => {
56
58
  const name = displayName as ComponentName
57
59
  const id = componentId as ComponentName
58
60
 
59
- const themeOverride = props ? props.themeOverride : undefined
60
-
61
61
  const { componentOverrides } = theme as Overrides
62
62
 
63
63
  let overridesFromTheme: Partial<ComponentTheme> = {}
@@ -71,10 +71,11 @@ const getComponentThemeOverride = (
71
71
  if (themeOverride) {
72
72
  if (typeof themeOverride === 'function') {
73
73
  overrideFromComponent = themeOverride(
74
- componentTheme || {},
74
+ //TODO type properly when the old theme is gone
75
+ componentTheme || ({} as any),
75
76
  // the `theme` technically could be a partial theme / override object too,
76
77
  // but we want to display all possible options
77
- theme as BaseTheme
78
+ theme as any
78
79
  )
79
80
  } else {
80
81
  overrideFromComponent = themeOverride
package/src/getTheme.ts CHANGED
@@ -54,7 +54,10 @@ const getTheme =
54
54
  // we need to clone the ancestor theme not to override it
55
55
  let currentTheme
56
56
  if (Object.keys(ancestorTheme).length === 0) {
57
- if (process.env.NODE_ENV !== 'production') {
57
+ if (
58
+ process.env.NODE_ENV !== 'production' ||
59
+ process.env.GITHUB_PULL_REQUEST_PREVIEW === 'true'
60
+ ) {
58
61
  console.warn(
59
62
  'No theme provided for [InstUISettingsProvider], using default `canvas` theme.'
60
63
  )
@@ -78,7 +81,10 @@ const getTheme =
78
81
  // If the prop passed is not an Object, it will throw an error.
79
82
  // We are using this fail-safe here for the non-TS users,
80
83
  // because the whole page can break without a theme.
81
- if (process.env.NODE_ENV !== 'production') {
84
+ if (
85
+ process.env.NODE_ENV !== 'production' ||
86
+ process.env.GITHUB_PULL_REQUEST_PREVIEW === 'true'
87
+ ) {
82
88
  console.warn(
83
89
  'The `theme` property provided to InstUISettingsProvider is not a valid InstUI theme object.\ntheme: ',
84
90
  resolvedThemeOrOverride
package/src/index.ts CHANGED
@@ -26,6 +26,8 @@
26
26
  export * from '@emotion/react'
27
27
 
28
28
  export { InstUISettingsProvider } from './InstUISettingsProvider'
29
+ export { withStyleLegacy } from './withStyleLegacy'
30
+ export { getComponentThemeOverride } from './getComponentThemeOverride'
29
31
  export { withStyle } from './withStyle'
30
32
  export {
31
33
  ThemeablePropValues,
@@ -33,14 +35,17 @@ export {
33
35
  getShorthandPropValue,
34
36
  mirrorShorthandCorners,
35
37
  mirrorShorthandEdges,
36
- mapSpacingToShorthand
38
+ calcSpacingFromShorthand,
39
+ calcFocusOutlineStyles
37
40
  } from './styleUtils'
38
41
 
42
+ export { useStyleLegacy } from './useStyleLegacy'
39
43
  export { useStyle } from './useStyle'
40
44
  export { useTheme } from './useTheme'
41
45
 
42
46
  export type { ComponentStyle, StyleObject, Overrides } from './EmotionTypes'
43
- export type { WithStyleProps } from './withStyle'
47
+ export type { WithStyleProps } from './withStyleLegacy'
48
+ export type { ThemeOverrideValue } from './useStyle'
44
49
  export type {
45
50
  SpacingValues,
46
51
  Spacing,
@@ -0,0 +1,106 @@
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
+ import { alpha } from '@instructure/ui-color-utils'
25
+ import type { SharedTokens } from '@instructure/ui-themes'
26
+
27
+ /**
28
+ * This function creates CSS-in-JS styles for focus indicators.
29
+ *
30
+ * @returns CSS-in-JS style object containing focus outline styles ready for use with emotion or similar libraries.
31
+ */
32
+ const calcFocusOutlineStyles = (
33
+ /**
34
+ * The focus outline theme configuration object containing color and sizing tokens.
35
+ */
36
+ theme: SharedTokens['focusOutline'],
37
+ params?: {
38
+ /**
39
+ * The color variant to use for the focus outline
40
+ */
41
+ focusColor?: 'info' | 'inverse' | 'success' | 'danger'
42
+ /**
43
+ * Whether to position the outline outside ('offset') or inside ('inset') the element.
44
+ */
45
+ focusPosition?: 'offset' | 'inset'
46
+ /**
47
+ * Whether to include smooth transition animations for focus changes.
48
+ */
49
+ shouldAnimateFocus?: boolean
50
+ /**
51
+ * Whether to apply focus styles to :focus-within pseudo-class for container elements.
52
+ */
53
+ focusWithin?: boolean
54
+ /**
55
+ * Whether to force showing the focus outline.
56
+ */
57
+ withFocusOutline?: boolean
58
+ /**
59
+ * What CSS selector to use to display the focus ring, `:focus` by default.
60
+ */
61
+ customCSSSelector?: string
62
+ }
63
+ ) => {
64
+ const focusColor = params?.focusColor ?? 'info'
65
+ const focusPosition = params?.focusPosition ?? 'offset'
66
+ const shouldAnimateFocus = params?.shouldAnimateFocus ?? true
67
+ const focusWithin = params?.focusWithin ?? false
68
+ const withFocusOutline = params?.withFocusOutline ?? false
69
+ const selector = params?.customCSSSelector ?? '&:focus'
70
+
71
+ const focusColorVariants = {
72
+ info: theme.infoColor,
73
+ inverse: theme.onColor,
74
+ success: theme.successColor,
75
+ danger: theme.dangerColor
76
+ }
77
+
78
+ const outlineStyle = {
79
+ outlineColor: focusColorVariants[focusColor!],
80
+ outlineStyle: 'solid',
81
+ outlineWidth: theme.width,
82
+ outlineOffset: theme[focusPosition]
83
+ }
84
+ return {
85
+ ...(shouldAnimateFocus && {
86
+ transition: 'outline-color 0.2s, outline-offset 0.25s'
87
+ }),
88
+ outlineOffset: '-0.8rem',
89
+ outlineStyle: 'solid',
90
+ outlineColor: alpha(outlineStyle.outlineColor, 0),
91
+ ...(withFocusOutline && outlineStyle),
92
+ [selector]: {
93
+ ...outlineStyle,
94
+ '&:hover, &:active': {
95
+ // apply the same style so it's not overridden by some global style
96
+ ...outlineStyle
97
+ }
98
+ },
99
+ ...(focusWithin && {
100
+ '&:focus-within': outlineStyle
101
+ })
102
+ }
103
+ }
104
+
105
+ export default calcFocusOutlineStyles
106
+ export { calcFocusOutlineStyles }
@@ -0,0 +1,127 @@
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
+ import type { Spacing } from './ThemeablePropValues'
25
+
26
+ type DeepStringRecord = {
27
+ [key: string]: string | DeepStringRecord
28
+ }
29
+
30
+ /**
31
+ * Converts hyphen-case strings to camelCase
32
+ * Example: 'medium-small' -> 'mediumSmall'
33
+ */
34
+ function camelize(str: string): string {
35
+ return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase())
36
+ }
37
+
38
+ /**
39
+ * Converts shorthand spacing values into CSS strings using theme spacing tokens.
40
+ *
41
+ * This function parses space-separated spacing values (margin, padding) and resolves theme
42
+ * tokens to their actual CSS values. It supports CSS shorthand syntax (1-4 values), nested
43
+ * theme token paths using dot notation, and automatically converts hyphen-case tokens to camelCase.
44
+ *
45
+ * @param {Spacing | undefined} value - The shorthand spacing value string containing space-separated tokens or CSS values.
46
+ * Tokens can be in camelCase (mediumSmall) or hyphen-case (medium-small).
47
+ * Can be undefined, in which case '0' is returned.
48
+ * @param {Record<string, string>} spacingMap - The spacing theme object containing spacing tokens and nested values.
49
+ * Typically comes from `sharedTokens.margin.spacing` or `sharedTokens.padding.spacing` in the component theme.
50
+ *
51
+ * @returns {string} The resolved CSS spacing string ready to be used in styles.
52
+ *
53
+ * @example
54
+ * // Hyphen-case tokens are converted to camelCase
55
+ * calcSpacingFromShorthand('medium-small', spacingMap) // resolves to spacingMap.mediumSmall
56
+ * calcSpacingFromShorthand('x-large small', spacingMap) // resolves to spacingMap.xLarge + spacingMap.small
57
+ *
58
+ * // Dot notation paths are NOT converted
59
+ * calcSpacingFromShorthand('gap.nested-value', spacingMap) // resolves to spacingMap.gap['nested-value']
60
+ *
61
+ * // CSS values like 'none', 'auto', '10px' are returned as-is
62
+ * calcSpacingFromShorthand('none', spacingMap) // returns 'none'
63
+ */
64
+ export function calcSpacingFromShorthand(
65
+ value: Spacing | undefined,
66
+ spacingMap: DeepStringRecord
67
+ ) {
68
+ // return undefined when there is no value -> this is important when a component (like View)
69
+ // doesn't have a prop like `padding` but has inline css for padding
70
+ // this makes sure to not overwrite the inline style
71
+ if (!value) return
72
+
73
+ const tokens = value.trim().split(' ')
74
+
75
+ // Handle whitespace-only strings
76
+ if (tokens.length === 1 && tokens[0] === '') return ''
77
+
78
+ // Map each token to its resolved CSS value
79
+ const resolvedValues = tokens.map((token) => {
80
+ // Handle special CSS value 'none' - convert to 0 for valid CSS
81
+ if (token === 'none') {
82
+ return '0'
83
+ }
84
+
85
+ // Handle valid CSS numeric and keyword values
86
+ if (token === '0' || token === 'auto') {
87
+ return token
88
+ }
89
+
90
+ // Handle dot notation for nested theme token paths (no camelization)
91
+ if (token.includes('.')) {
92
+ const path = token.split('.')
93
+ let currentLevel: string | DeepStringRecord = spacingMap
94
+
95
+ for (const key of path) {
96
+ if (
97
+ currentLevel &&
98
+ typeof currentLevel === 'object' &&
99
+ key in currentLevel
100
+ ) {
101
+ currentLevel = currentLevel[key]
102
+ } else {
103
+ console.warn(`Theme token path "${token}" not found in theme.`)
104
+ // If path doesn't resolve, return the original token as fallback
105
+ return token
106
+ }
107
+ }
108
+ if (typeof currentLevel === 'string') {
109
+ return currentLevel
110
+ }
111
+ }
112
+
113
+ // For direct tokens, try camelized version
114
+ const camelizedToken = camelize(token)
115
+ const directValue = spacingMap[camelizedToken]
116
+ if (typeof directValue === 'string') {
117
+ return directValue
118
+ }
119
+
120
+ // Return the original token if not found (could be a direct CSS value like 'auto', '10px', etc.)
121
+ console.warn(`Theme token path "${token}" not found in theme.`)
122
+ return token
123
+ })
124
+
125
+ // Return the space-separated resolved values
126
+ return resolvedValues.join(' ')
127
+ }
@@ -27,7 +27,8 @@ export { makeThemeVars } from './makeThemeVars'
27
27
  export { getShorthandPropValue } from './getShorthandPropValue'
28
28
  export { mirrorShorthandCorners } from './mirrorShorthandCorners'
29
29
  export { mirrorShorthandEdges } from './mirrorShorthandEdges'
30
- export { mapSpacingToShorthand } from './mapSpacingToShorthand'
30
+ export { calcSpacingFromShorthand } from './calcSpacingFromShorthand'
31
+ export { calcFocusOutlineStyles } from './calcFocusOutlineStyles'
31
32
 
32
33
  export type {
33
34
  SpacingValues,
package/src/useStyle.ts CHANGED
@@ -24,55 +24,86 @@
24
24
 
25
25
  import { useTheme } from './useTheme'
26
26
  import { getComponentThemeOverride } from './getComponentThemeOverride'
27
- import type { BaseTheme, ComponentTheme } from '@instructure/shared-types'
27
+ import type {
28
+ SharedTokens,
29
+ NewComponentTypes,
30
+ Theme
31
+ } from '@instructure/ui-themes'
32
+ import type { BaseThemeOrOverride } from './EmotionTypes'
28
33
 
29
34
  // returns the second parameter of a function
30
35
  type SecondParameter<T extends (...args: any) => any> =
31
36
  Parameters<T>[1] extends undefined ? never : Parameters<T>[1]
32
37
 
33
- type UseStyleParamsWithTheme<P extends (theme: any, params: any) => any> = {
34
- generateStyle: P
35
- params?: SecondParameter<P>
36
- generateComponentTheme: (theme: BaseTheme) => ComponentTheme
37
- componentId: string
38
- displayName?: string
38
+ type GenerateStyleParams =
39
+ | ((componentTheme: any, params: any, sharedTokens: SharedTokens) => any)
40
+ | ((componentTheme: any, params: any) => any)
41
+ | ((componentTheme: any) => any)
42
+
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
+
53
+ const isNewThemeObject = (obj: BaseThemeOrOverride): obj is Theme => {
54
+ return typeof (obj as any)?.newTheme === 'object'
39
55
  }
40
56
 
41
- type UseStyleParamsWithoutTheme<P extends (theme: any, params: any) => any> = {
57
+ /**
58
+ * new useStyle syntax, use this with v12 themes
59
+ */
60
+
61
+ // TODO: improve useStyle to handle generateStyle functions that don't
62
+ // have a theme.
63
+ const useStyle = <P extends GenerateStyleParams>(useStyleParams: {
42
64
  generateStyle: P
43
65
  params?: SecondParameter<P>
44
- generateComponentTheme?: undefined
45
- componentId?: undefined
46
- displayName?: undefined
47
- }
48
-
49
- const useStyle = <P extends (theme: any, params: any) => any>(
50
- useStyleParams: UseStyleParamsWithTheme<P> | UseStyleParamsWithoutTheme<P>
51
- ): ReturnType<P> => {
52
- const {
53
- generateStyle,
54
- generateComponentTheme,
55
- params,
56
- componentId,
57
- displayName
58
- } = useStyleParams
66
+ // needs to be a string too because it might be a child component
67
+ componentId: keyof NewComponentTypes | string
68
+ themeOverride: ThemeOverrideValue | undefined
69
+ displayName?: string
70
+ //in case of a child component needed to use it's parent's tokens, provide parent's name
71
+ useTokensFrom?: keyof NewComponentTypes
72
+ }): ReturnType<P> => {
73
+ const { generateStyle, params, componentId, displayName, themeOverride } =
74
+ useStyleParams
75
+ const useTokensFrom = useStyleParams.useTokensFrom
59
76
  const theme = useTheme()
60
- const baseComponentTheme = generateComponentTheme
61
- ? generateComponentTheme(theme as BaseTheme)
62
- : {}
63
77
 
64
- const themeOverride = getComponentThemeOverride(
78
+ let baseComponentTheme = {}
79
+ const componentWithTokensId = useTokensFrom ?? componentId
80
+
81
+ if (
82
+ isNewThemeObject(theme) && // TODO: is it possible not to have a theme object here?
83
+ theme.newTheme.components[componentWithTokensId as keyof NewComponentTypes]
84
+ ) {
85
+ baseComponentTheme =
86
+ theme.newTheme.components[
87
+ componentWithTokensId as keyof NewComponentTypes
88
+ ]
89
+ }
90
+ const finalOverride = getComponentThemeOverride(
65
91
  theme,
66
- displayName ? displayName : componentId || '',
67
- componentId,
68
- params,
92
+ useTokensFrom ?? displayName ?? componentId ?? '',
93
+ componentWithTokensId,
94
+ themeOverride,
69
95
  baseComponentTheme
70
96
  )
71
97
 
72
- const componentTheme = { ...baseComponentTheme, ...themeOverride }
98
+ const componentTheme = { ...baseComponentTheme, ...finalOverride }
73
99
 
74
- return generateStyle(componentTheme, params ? params : {})
100
+ return generateStyle(
101
+ componentTheme,
102
+ params,
103
+ (theme as Theme).newTheme.sharedTokens
104
+ )
75
105
  }
76
106
 
77
107
  export default useStyle
78
108
  export { useStyle }
109
+ export type { ThemeOverrideValue }
@@ -0,0 +1,92 @@
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 './useTheme'
26
+ import { getComponentThemeOverride } from './getComponentThemeOverride'
27
+ import type { ComponentTheme } from '@instructure/shared-types'
28
+ import type { Theme } from '@instructure/ui-themes'
29
+
30
+ // returns the second parameter of a function
31
+ type SecondParameter<T extends (...args: any) => any> =
32
+ Parameters<T>[1] extends undefined ? never : Parameters<T>[1]
33
+
34
+ type GenerateComponentTheme = (theme: Theme) => ComponentTheme
35
+
36
+ type UseStyleParamsWithTheme<
37
+ P extends (componentTheme: any, params: any, theme: any) => any
38
+ > = {
39
+ generateStyle: P
40
+ params?: SecondParameter<P>
41
+ generateComponentTheme: GenerateComponentTheme
42
+ componentId: string
43
+ displayName?: string
44
+ }
45
+
46
+ // TODO this is only used by the old themes, remove when everything uses the new
47
+ // theming system
48
+ type UseStyleParamsWithoutTheme<
49
+ P extends (componentTheme: any, params: any, theme: any) => any
50
+ > = {
51
+ generateStyle: P
52
+ params?: SecondParameter<P>
53
+ generateComponentTheme?: undefined
54
+ componentId?: undefined
55
+ displayName?: undefined
56
+ }
57
+
58
+ /*
59
+ * This is only used by the **old themes**, remove when everything uses the new
60
+ * theming system (InstUI v12)
61
+ */
62
+ const useStyleLegacy = <
63
+ P extends (componentTheme: any, params: any, theme: any) => any
64
+ >(
65
+ useStyleParams: UseStyleParamsWithTheme<P> | UseStyleParamsWithoutTheme<P>
66
+ ): ReturnType<P> => {
67
+ const { generateStyle, params, componentId, displayName } = useStyleParams
68
+ const generateComponentTheme: GenerateComponentTheme = (
69
+ useStyleParams as UseStyleParamsWithTheme<P>
70
+ )?.generateComponentTheme
71
+ const theme = useTheme()
72
+
73
+ const baseComponentTheme =
74
+ typeof generateComponentTheme === 'function'
75
+ ? generateComponentTheme(theme as Theme)
76
+ : {}
77
+
78
+ const themeOverride = getComponentThemeOverride(
79
+ theme,
80
+ displayName ?? componentId ?? '',
81
+ componentId,
82
+ params?.themeOverride,
83
+ baseComponentTheme
84
+ )
85
+
86
+ const componentTheme = { ...baseComponentTheme, ...themeOverride }
87
+
88
+ return generateStyle(componentTheme, params ? params : {}, theme)
89
+ }
90
+
91
+ export default useStyleLegacy
92
+ export { useStyleLegacy }
package/src/useTheme.ts CHANGED
@@ -40,7 +40,10 @@ const useTheme = () => {
40
40
  // This reads the theme from Emotion's ThemeContext
41
41
  let theme = useEmotionTheme() as BaseThemeOrOverride
42
42
  if (isEmpty(theme)) {
43
- if (process.env.NODE_ENV !== 'production') {
43
+ if (
44
+ process.env.NODE_ENV !== 'production' ||
45
+ process.env.GITHUB_PULL_REQUEST_PREVIEW === 'true'
46
+ ) {
44
47
  console.warn(
45
48
  `No theme provided for [InstUISettingsProvider], using default <canvas> theme.`
46
49
  )