Skip to content

Commit e69f4ae

Browse files
committed
fix(ui-heading): add renderIcon prop to fix layout issues
INSTUI-4554
1 parent 342dc80 commit e69f4ae

File tree

4 files changed

+48
-8
lines changed

4 files changed

+48
-8
lines changed

packages/ui-heading/src/Heading/README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,20 @@ type: example
6565
<Heading>I inherit my color via the CSS cascade (default)</Heading>
6666
<Heading color="primary">I am primary color</Heading>
6767
<Heading color="secondary">I am secondary color</Heading>
68-
<Heading color="ai"><IconAiColoredSolid/>&nbsp; I am AI color</Heading>
68+
<Heading color="ai">I am AI color</Heading>
69+
</div>
70+
```
71+
72+
### Icons
73+
74+
With the `renderIcon` prop, an icon can be rendered before the text. Only current use-case is for the `ai heading`
75+
76+
```js
77+
---
78+
type: example
79+
---
80+
<div>
81+
<Heading color="ai" renderIcon={<IconAiColoredSolid/>}>I am AI color with icon</Heading>
6982
</div>
7083
```
7184

packages/ui-heading/src/Heading/index.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
import { Component } from 'react'
2626

2727
import { View } from '@instructure/ui-view'
28-
import { getElementType, passthroughProps } from '@instructure/ui-react-utils'
28+
import {
29+
getElementType,
30+
passthroughProps,
31+
callRenderProp
32+
} from '@instructure/ui-react-utils'
2933
import { testable } from '@instructure/ui-testable'
3034

3135
import { withStyle } from '@instructure/emotion'
@@ -105,6 +109,19 @@ class Heading extends Component<HeadingProps> {
105109
this.checkProps()
106110
}
107111

112+
renderContent() {
113+
const { children, renderIcon } = this.props
114+
115+
if (renderIcon) {
116+
return (
117+
<>
118+
{callRenderProp(renderIcon)}&nbsp;{children}
119+
</>
120+
)
121+
}
122+
return children
123+
}
124+
108125
render() {
109126
const {
110127
border,
@@ -139,7 +156,7 @@ class Heading extends Component<HeadingProps> {
139156
elementRef={this.handleRef}
140157
margin={margin}
141158
>
142-
{children}
159+
{this.renderContent()}
143160
</View>
144161
)
145162
}

packages/ui-heading/src/Heading/props.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ import type {
3030
AsElementType,
3131
PropValidators,
3232
HeadingTheme,
33-
OtherHTMLAttributes
33+
OtherHTMLAttributes,
34+
Renderable
3435
} from '@instructure/shared-types'
3536
import type {
3637
Spacing,
@@ -78,6 +79,10 @@ type HeadingOwnProps = {
7879
* Provides a ref to the underlying HTML element
7980
*/
8081
elementRef?: (element: Element | null) => void
82+
/**
83+
* An icon, or function that returns an icon that gets displayed before the text.
84+
*/
85+
renderIcon?: Renderable
8186
/**
8287
* Sets style and level at once. The as property will be the same as the level.
8388
* NOTE: this is the recommended way of setting the appearance, instead of level
@@ -120,6 +125,7 @@ const propTypes: PropValidators<PropKeys> = {
120125
as: PropTypes.elementType,
121126
margin: PropTypes.string,
122127
elementRef: PropTypes.func,
128+
renderIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
123129
variant: PropTypes.oneOf([
124130
'titlePageDesktop',
125131
'titlePageMobile',

packages/ui-heading/src/Heading/styles.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const generateStyle = (
3939
componentTheme: HeadingTheme,
4040
props: HeadingProps
4141
): HeadingStyle => {
42-
const { level, color, border, variant } = props
42+
const { level, color, border, variant, renderIcon } = props
4343

4444
const variants: Record<NonNullable<HeadingProps['variant']>, object> = {
4545
titlePageDesktop: {
@@ -188,9 +188,13 @@ const generateStyle = (
188188
label: 'heading',
189189
lineHeight: componentTheme.lineHeight,
190190
margin: 0,
191-
display: 'flex',
192-
alignItems: 'center',
193-
191+
//need this for icons to render them vertically centered
192+
...(renderIcon
193+
? {
194+
display: 'flex',
195+
alignItems: 'center'
196+
}
197+
: {}),
194198
// NOTE: the input styles exist to accommodate the InPlaceEdit component
195199
// NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping)
196200
'&:is(input)[type]': inputStyles,

0 commit comments

Comments
 (0)