diff --git a/packages/shared-types/src/Colors.ts b/packages/shared-types/src/Colors.ts
index 1e916366a1..337ebbb8e1 100644
--- a/packages/shared-types/src/Colors.ts
+++ b/packages/shared-types/src/Colors.ts
@@ -63,6 +63,28 @@ type Primitives = {
red57: string
red70: string
red82: string
+
+ sea12: string
+ sea30: string
+ sea45: string
+ sea70: string
+ sea110: string
+ sea35: string
+ sea40: string
+ sea50: string
+ sea57: string
+ sea90: string
+
+ violet12: string
+ violet30: string
+ violet45: string
+ violet70: string
+ violet110: string
+ violet35: string
+ violet40: string
+ violet50: string
+ violet57: string
+ violet90: string
}
type AdditionalPrimitives = {
@@ -219,6 +241,12 @@ type Contrasts = {
red1212: Primitives['red12']
red4570: Primitives['red45'] | Primitives['red70']
red5782: Primitives['red57'] | Primitives['red82']
+
+ violet1212: Primitives['violet12']
+ violet4570: Primitives['violet45'] | Primitives['violet70']
+ violet5790: Primitives['violet57'] | Primitives['violet90']
+ sea4570: Primitives['sea45'] | Primitives['sea70']
+ sea5790: Primitives['sea57'] | Primitives['sea90']
}
type UI = {
diff --git a/packages/shared-types/src/ComponentThemeVariables.ts b/packages/shared-types/src/ComponentThemeVariables.ts
index 1ebafa179d..8a225cd590 100644
--- a/packages/shared-types/src/ComponentThemeVariables.ts
+++ b/packages/shared-types/src/ComponentThemeVariables.ts
@@ -66,21 +66,24 @@ export type AlertTheme = {
}
export type AvatarTheme = {
- background: Colors['contrasts']['white1010']
+ background: string
borderWidthSmall: Border['widthSmall']
borderWidthMedium: Border['widthMedium']
- borderColor: Colors['contrasts']['grey1214']
+ borderColor: string
boxShadowColor: string
boxShadowBlur: string
fontFamily: Typography['fontFamily']
fontWeight: Typography['fontWeightBold']
- color: Colors['contrasts']['blue4570']
- colorShamrock: Colors['contrasts']['green4570']
- colorBarney: Colors['contrasts']['blue4570']
- colorCrimson: Colors['contrasts']['orange4570']
- colorFire: Colors['contrasts']['red4570']
- colorLicorice: Colors['contrasts']['grey125125']
- colorAsh: Colors['contrasts']['grey4570']
+ color: string
+ colorShamrock: string
+ colorBarney: string
+ colorCrimson: string
+ colorFire: string
+ colorLicorice: string
+ colorAsh: string
+
+ aiTopGradientColor: string
+ aiBottomGradientColor: string
}
export type BadgeTheme = {
@@ -1386,15 +1389,18 @@ export type TagTheme = {
}
export type TextTheme = Typography & {
- primaryInverseColor: Colors['contrasts']['white1010']
- primaryColor: Colors['contrasts']['grey125125']
- secondaryColor: Colors['contrasts']['grey4570']
- secondaryInverseColor: Colors['contrasts']['grey1111']
- brandColor: Colors['contrasts']['blue4570']
- dangerColor: Colors['contrasts']['red4570']
- successColor: Colors['contrasts']['green4570']
- alertColor: Colors['contrasts']['blue4570']
- warningColor: Colors['contrasts']['orange5782']
+ primaryInverseColor: string
+ primaryColor: string
+ secondaryColor: string
+ secondaryInverseColor: string
+ brandColor: string
+ dangerColor: string
+ successColor: string
+ alertColor: string
+ warningColor: string
+ aiColor: string
+
+ aiBackgroundColor: string
paragraphMargin: string | 0
}
diff --git a/packages/ui-avatar/src/Avatar/README.md b/packages/ui-avatar/src/Avatar/README.md
index a030d951c7..32a4ca84e4 100644
--- a/packages/ui-avatar/src/Avatar/README.md
+++ b/packages/ui-avatar/src/Avatar/README.md
@@ -4,6 +4,34 @@ describes: Avatar
The avatar component can be used to display a user's avatar. When an image src is not supplied the user's initials will display.
+## Variant
+
+Avatar has a variant prop, which currently only toggles it between `ai` and `default` behavior. `ai` is a preset where you can only change the `size` and `margin` visual props, all others are preset. In the following example, there are the `ai` variants.
+
+### ai
+
+```js
+---
+type: example
+readonly: true
+---
+
+```
+
+### default
+
+Most avatar's features are accessible through the `default` variant
+
Instead of the initials, an SVG icon can be displayed with the `renderIcon` property.
The avatar can be `circle` _(default)_ or `rectangle`. Use the `margin` prop to add space between Avatar and other content.
diff --git a/packages/ui-avatar/src/Avatar/index.tsx b/packages/ui-avatar/src/Avatar/index.tsx
index 1dc7a969f1..8dff95f36d 100644
--- a/packages/ui-avatar/src/Avatar/index.tsx
+++ b/packages/ui-avatar/src/Avatar/index.tsx
@@ -32,6 +32,7 @@ import {
} from 'react'
import { View } from '@instructure/ui-view'
+import { IconAiSolid } from '@instructure/ui-icons'
import { callRenderProp, passthroughProps } from '@instructure/ui-react-utils'
import type { AvatarProps } from './props'
@@ -52,7 +53,8 @@ const Avatar = forwardRef(
showBorder = 'auto',
shape = 'circle',
display = 'inline-block',
- onImageLoaded = (_event: SyntheticEvent) => {},
+ variant = 'default',
+ onImageLoaded = (_event: SyntheticEvent) => { },
src,
name,
renderIcon,
@@ -78,7 +80,8 @@ const Avatar = forwardRef(
shape,
src,
showBorder,
- themeOverride
+ themeOverride,
+ variant
},
componentId: 'Avatar',
displayName: 'Avatar'
@@ -122,11 +125,13 @@ const Avatar = forwardRef(
}
const renderContent = () => {
- if (!renderIcon) {
+ const calcedRenderIcon = variant === 'ai' ? : renderIcon
+
+ if (!calcedRenderIcon) {
return renderInitials()
}
- return {callRenderProp(renderIcon)}
+ return {callRenderProp(calcedRenderIcon)}
}
return (
diff --git a/packages/ui-avatar/src/Avatar/props.ts b/packages/ui-avatar/src/Avatar/props.ts
index 2029bf44d9..6510ba5770 100644
--- a/packages/ui-avatar/src/Avatar/props.ts
+++ b/packages/ui-avatar/src/Avatar/props.ts
@@ -100,6 +100,11 @@ type AvatarOwnProps = {
* An icon, or function that returns an icon that gets displayed. If the `src` prop is provided, `src` will have priority.
*/
renderIcon?: Renderable
+
+ /**
+ * if "ai", it will ignore most props (e.g.: shape, showBorder, onImageLoaded, hasInverseColor, color, name) and render an "ai avatar"
+ */
+ variant?: 'default' | 'ai'
}
export type AvatarState = {
@@ -149,7 +154,8 @@ const propTypes: PropValidators = {
onImageLoaded: PropTypes.func,
as: PropTypes.elementType,
elementRef: PropTypes.func,
- renderIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func])
+ renderIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
+ variant: PropTypes.oneOf(['default', 'ai'])
}
const allowedProps: AllowedPropKeys = [
diff --git a/packages/ui-avatar/src/Avatar/styles.ts b/packages/ui-avatar/src/Avatar/styles.ts
index bad4f54386..f5f162c616 100644
--- a/packages/ui-avatar/src/Avatar/styles.ts
+++ b/packages/ui-avatar/src/Avatar/styles.ts
@@ -34,6 +34,7 @@ type StyleParams = {
src: AvatarProps['src']
showBorder: AvatarProps['showBorder']
themeOverride: AvatarProps['themeOverride']
+ variant: AvatarProps['variant']
}
/**
* ---
@@ -48,47 +49,108 @@ const generateStyle = (
componentTheme: AvatarTheme,
params: StyleParams
): AvatarStyle => {
- const { loaded, size, color, hasInverseColor, shape, src, showBorder } =
- params
+ const {
+ loaded,
+ size,
+ color,
+ hasInverseColor,
+ shape,
+ src,
+ showBorder,
+ variant
+ } = params
+
+ // NOTE: this is needed due to design changes. The size of the component is calculated from "em" which means it is
+ // tied to the fontSize. The font sizes changed for the icons, which meant that the container (component) size would've
+ // changed too without additional calculations
+ const calcNewScaler = (
+ originalFontSize: number,
+ newFontSize: number,
+ originalScaler: number
+ ) => {
+ return `${(originalFontSize * originalScaler) / newFontSize}em`
+ }
const sizeStyles = {
auto: {
fontSize: 'inherit',
- borderWidth: componentTheme.borderWidthSmall
+ borderWidth: componentTheme.borderWidthSmall,
+ width: '2.5em',
+ height: '2.5em'
},
'xx-small': {
- fontSize: '0.5rem',
- borderWidth: componentTheme.borderWidthSmall
+ fontSize: '0.625rem',
+ borderWidth: componentTheme.borderWidthSmall,
+ width: calcNewScaler(0.5, 0.625, shape === 'circle' ? 2.5 : 3),
+ height: calcNewScaler(0.5, 0.625, 2.5)
},
'x-small': {
- fontSize: '0.75rem',
- borderWidth: componentTheme.borderWidthSmall
+ fontSize: '0.875rem',
+ borderWidth: componentTheme.borderWidthSmall,
+ width: calcNewScaler(0.75, 0.875, shape === 'circle' ? 2.5 : 3),
+ height: calcNewScaler(0.75, 0.875, 2.5)
},
small: {
- fontSize: '1rem',
- borderWidth: componentTheme.borderWidthSmall
+ fontSize: '1.25rem',
+ borderWidth: componentTheme.borderWidthSmall,
+ width: calcNewScaler(1, 1.25, shape === 'circle' ? 2.5 : 3),
+ height: calcNewScaler(1, 1.25, 2.5)
},
medium: {
- fontSize: '1.25rem',
- borderWidth: componentTheme.borderWidthMedium
+ fontSize: '1.5rem',
+ borderWidth: componentTheme.borderWidthMedium,
+ width: calcNewScaler(1.25, 1.5, shape === 'circle' ? 2.5 : 3),
+ height: calcNewScaler(1.25, 1.5, 2.5)
},
large: {
- fontSize: '1.5rem',
- borderWidth: componentTheme.borderWidthMedium
+ fontSize: '1.75rem',
+ borderWidth: componentTheme.borderWidthMedium,
+ width: calcNewScaler(1.5, 1.75, shape === 'circle' ? 2.5 : 3),
+ height: calcNewScaler(1.5, 1.75, 2.5)
},
'x-large': {
- fontSize: '1.75rem',
- borderWidth: componentTheme.borderWidthMedium
+ fontSize: '2rem',
+ borderWidth: componentTheme.borderWidthMedium,
+ width: calcNewScaler(1.75, 2, shape === 'circle' ? 2.5 : 3),
+ height: calcNewScaler(1.75, 2, 2.5)
},
'xx-large': {
- fontSize: '2rem',
- borderWidth: componentTheme.borderWidthMedium
+ fontSize: '2.25rem',
+ borderWidth: componentTheme.borderWidthMedium,
+ width: calcNewScaler(2, 2.25, shape === 'circle' ? 2.5 : 3),
+ height: calcNewScaler(2, 2.25, 2.5)
}
}
- const variantStyles = {
+ const initialSizeStyles = {
+ auto: {
+ fontSize: 'inherit'
+ },
+ 'xx-small': {
+ fontSize: '0.5rem'
+ },
+ 'x-small': {
+ fontSize: '0.75rem'
+ },
+ small: {
+ fontSize: '1rem'
+ },
+ medium: {
+ fontSize: '1.25rem'
+ },
+ large: {
+ fontSize: '1.5rem'
+ },
+ 'x-large': {
+ fontSize: '1.75rem'
+ },
+ 'xx-large': {
+ fontSize: '2rem'
+ }
+ }
+
+ const shapeStyles = {
circle: {
- width: '2.5em',
position: 'relative',
borderRadius: '100%',
overflow: 'hidden'
@@ -112,27 +174,23 @@ const generateStyle = (
? colorVariants[color!]
: componentTheme.background
- const contentColor = hasInverseColor
- ? componentTheme.background
- : colorVariants[color!]
+ const contentColor =
+ variant === 'ai'
+ ? 'white'
+ : hasInverseColor
+ ? componentTheme.background
+ : colorVariants[color!]
- return {
- avatar: {
- label: 'avatar',
- height: '2.5em',
- boxSizing: 'border-box',
- backgroundColor: backgroundColor,
- backgroundPosition: 'center',
- backgroundSize: 'cover',
- backgroundClip: 'content-box',
- backgroundRepeat: 'no-repeat',
- overflow: 'hidden',
- lineHeight: 0,
- textAlign: 'center',
- borderStyle: 'solid',
- borderColor: componentTheme.borderColor,
- ...sizeStyles[size!],
- ...variantStyles[shape!],
+ const variantStyles = {
+ ai: {
+ background: `
+ linear-gradient(to bottom, ${componentTheme.aiTopGradientColor} 0%, ${componentTheme.aiBottomGradientColor} 100%) padding-box,
+ linear-gradient(to bottom right, ${componentTheme.aiTopGradientColor} 0%, ${componentTheme.aiBottomGradientColor} 100%) border-box`,
+ border: 'solid transparent',
+ ...shapeStyles['circle']
+ },
+ default: {
+ ...shapeStyles[shape!],
...(loaded
? {
backgroundImage: `url('${src}')`,
@@ -152,6 +210,25 @@ const generateStyle = (
...(showBorder === 'never' && {
border: 0
})
+ }
+ }
+
+ return {
+ avatar: {
+ label: 'avatar',
+ boxSizing: 'border-box',
+ backgroundColor: backgroundColor,
+ backgroundPosition: 'center',
+ backgroundSize: 'cover',
+ backgroundClip: 'content-box',
+ backgroundRepeat: 'no-repeat',
+ overflow: 'hidden',
+ lineHeight: 0,
+ textAlign: 'center',
+ borderStyle: 'solid',
+ borderColor: componentTheme.borderColor,
+ ...sizeStyles[size!],
+ ...variantStyles[variant!]
},
initials: {
label: 'avatar__initials',
@@ -159,7 +236,8 @@ const generateStyle = (
lineHeight: '2.375em',
fontFamily: componentTheme.fontFamily,
fontWeight: componentTheme.fontWeight,
- letterSpacing: '0.0313em'
+ letterSpacing: '0.0313em',
+ ...initialSizeStyles[size!]
},
loadImage: {
label: 'avatar__loadImage',
diff --git a/packages/ui-avatar/src/Avatar/theme.ts b/packages/ui-avatar/src/Avatar/theme.ts
index 8bef04e26b..0f06c61239 100644
--- a/packages/ui-avatar/src/Avatar/theme.ts
+++ b/packages/ui-avatar/src/Avatar/theme.ts
@@ -52,7 +52,10 @@ const generateComponentTheme = (theme: Theme): AvatarTheme => {
colorCrimson: colors?.contrasts?.red4570,
colorFire: colors?.contrasts?.orange4570,
colorLicorice: colors?.contrasts?.grey125125,
- colorAsh: colors?.contrasts?.grey4570
+ colorAsh: colors?.contrasts?.grey4570,
+
+ aiTopGradientColor: colors?.contrasts?.violet4570,
+ aiBottomGradientColor: colors?.contrasts?.sea4570
}
return {
diff --git a/packages/ui-text/src/Text/README.md b/packages/ui-text/src/Text/README.md
index f6efd45167..9adf3adf25 100644
--- a/packages/ui-text/src/Text/README.md
+++ b/packages/ui-text/src/Text/README.md
@@ -26,6 +26,24 @@ type: example
```
+### Text colors
+
+```js
+---
+type: example
+---
+
+ I'm primary text
+ I'm secondary text
+ I'm brand text
+ I'm success text
+ I'm warning text
+ I'm danger text
+ I'm a highlighted text (by AI)
+ I'm alert text - DEPRECATED - DO NOT USE
+
+```
+
### Font sizes
```js
@@ -134,23 +152,6 @@ type: example
```
-### Text colors
-
-```js
----
-type: example
----
-
- I'm primary text
- I'm secondary text
- I'm brand text
- I'm success text
- I'm warning text
- I'm danger text
- I'm alert text - DEPRECATED - DO NOT USE
-
-```
-
```js
---
type: example
diff --git a/packages/ui-text/src/Text/props.ts b/packages/ui-text/src/Text/props.ts
index 426028ca4c..547ea36df2 100644
--- a/packages/ui-text/src/Text/props.ts
+++ b/packages/ui-text/src/Text/props.ts
@@ -52,6 +52,7 @@ type TextOwnProps = {
| 'warning'
| 'primary-inverse'
| 'secondary-inverse'
+ | 'ai-highlight'
/**
* Provides a reference to the underlying HTML element
*/
@@ -119,7 +120,8 @@ const propTypes: PropValidators = {
'warning',
'alert',
'primary-inverse',
- 'secondary-inverse'
+ 'secondary-inverse',
+ 'ai-highlight'
]),
elementRef: PropTypes.func,
fontStyle: PropTypes.oneOf(['italic', 'normal']),
diff --git a/packages/ui-text/src/Text/styles.ts b/packages/ui-text/src/Text/styles.ts
index dc40fbacd9..4d19aa8c37 100644
--- a/packages/ui-text/src/Text/styles.ts
+++ b/packages/ui-text/src/Text/styles.ts
@@ -105,7 +105,11 @@ const generateStyle = (
brand: { color: componentTheme.brandColor },
danger: { color: componentTheme.dangerColor },
alert: { color: componentTheme.alertColor },
- warning: { color: componentTheme.warningColor }
+ warning: { color: componentTheme.warningColor },
+ 'ai-highlight': {
+ color: componentTheme.aiColor,
+ background: componentTheme.aiBackgroundColor
+ }
}
const wrapStyle = {
diff --git a/packages/ui-text/src/Text/theme.ts b/packages/ui-text/src/Text/theme.ts
index 370627df47..40364070c1 100644
--- a/packages/ui-text/src/Text/theme.ts
+++ b/packages/ui-text/src/Text/theme.ts
@@ -54,6 +54,9 @@ const generateComponentTheme = (theme: Theme): TextTheme => {
successColor: colors?.contrasts?.green5782,
alertColor: colors?.contrasts?.blue5782,
warningColor: colors?.contrasts?.orange5782,
+ aiColor: colors.contrasts?.violet5790,
+
+ aiBackgroundColor: colors.contrasts?.violet1212,
paragraphMargin: `${spacing.medium} 0`
}
diff --git a/packages/ui-themes/src/sharedThemeTokens/colors/primitives.ts b/packages/ui-themes/src/sharedThemeTokens/colors/primitives.ts
index 6476cd9a4b..b7e30d5311 100644
--- a/packages/ui-themes/src/sharedThemeTokens/colors/primitives.ts
+++ b/packages/ui-themes/src/sharedThemeTokens/colors/primitives.ts
@@ -64,7 +64,29 @@ export const primitives: Primitives = {
red45: '#E62429',
red57: '#C71F23',
red70: '#AE1B1F',
- red82: '#9B181C'
+ red82: '#9B181C',
+
+ sea12: '#DAEEEF',
+ sea30: '#37A1AA',
+ sea35: '#1E95A0',
+ sea40: '#0A8C97',
+ sea45: '#00828E',
+ sea50: '#007B86',
+ sea57: '#00717B',
+ sea70: '#00626B',
+ sea90: '#005158',
+ sea110: '#004349',
+
+ violet12: '#F1E6F5',
+ violet30: '#B57FCC',
+ violet35: '#AC6FC6',
+ violet40: '#A564C2',
+ violet45: '#9E58BD',
+ violet50: '#994FB9',
+ violet57: '#9242B4',
+ violet70: '#7F399E',
+ violet90: '#682F82',
+ violet110: '#56276B'
}
export const additionalPrimitives: AdditionalPrimitives = {
diff --git a/packages/ui-themes/src/themes/canvas/colors.ts b/packages/ui-themes/src/themes/canvas/colors.ts
index 713bb71cca..26da842d21 100644
--- a/packages/ui-themes/src/themes/canvas/colors.ts
+++ b/packages/ui-themes/src/themes/canvas/colors.ts
@@ -61,7 +61,13 @@ const contrasts: Contrasts = {
red1212: primitives.red12,
red4570: primitives.red45,
- red5782: primitives.red57
+ red5782: primitives.red57,
+
+ violet1212: primitives.violet12,
+ violet4570: primitives.violet45,
+ violet5790: primitives.violet57,
+ sea4570: primitives.sea45,
+ sea5790: primitives.sea57
}
const ui: UI = getUIColors(contrasts)
diff --git a/packages/ui-themes/src/themes/canvasHighContrast/colors.ts b/packages/ui-themes/src/themes/canvasHighContrast/colors.ts
index f27b18220a..a678f458e2 100644
--- a/packages/ui-themes/src/themes/canvasHighContrast/colors.ts
+++ b/packages/ui-themes/src/themes/canvasHighContrast/colors.ts
@@ -61,7 +61,13 @@ const contrasts: Contrasts = {
red1212: primitives.red12,
red4570: primitives.red70,
- red5782: primitives.red82
+ red5782: primitives.red82,
+
+ violet1212: primitives.violet12,
+ violet4570: primitives.violet70,
+ violet5790: primitives.violet90,
+ sea4570: primitives.sea70,
+ sea5790: primitives.sea90
}
const ui: UI = getUIColors(contrasts)