Skip to content

Commit b2c8395

Browse files
committed
feat(ui-color-picker): add new labelLevel prop to set heading level in ColorContrast
INSTUI-4874
1 parent 73af976 commit b2c8395

File tree

4 files changed

+74
-6
lines changed

4 files changed

+74
-6
lines changed

packages/ui-color-picker/src/ColorContrast/__tests__/ColorContrast.test.tsx

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* SOFTWARE.
2323
*/
2424

25-
import { render } from '@testing-library/react'
25+
import { render, screen } from '@testing-library/react'
2626
import { vi } from 'vitest'
2727
import '@testing-library/jest-dom'
2828
import { runAxeCheck } from '@instructure/ui-axe-check'
@@ -76,6 +76,53 @@ describe('<ColorContrast />', () => {
7676
})
7777
})
7878

79+
describe('labelLevel prop', () => {
80+
it('should render label as div when labelLevel is not provided', async () => {
81+
render(<ColorContrast {...testColors} {...testLabels} />)
82+
83+
const heading = screen.queryByRole('heading', {
84+
name: testLabels.label
85+
})
86+
expect(heading).not.toBeInTheDocument()
87+
88+
const labelText = screen.getByText(testLabels.label)
89+
expect(labelText).toBeInTheDocument()
90+
expect(labelText.tagName.toLowerCase()).toBe('div')
91+
})
92+
93+
it('should render label as Heading when labelLevel is provided', async () => {
94+
render(<ColorContrast {...testColors} {...testLabels} labelLevel="h2" />)
95+
96+
const heading = screen.getByRole('heading', {
97+
name: testLabels.label,
98+
level: 2
99+
})
100+
expect(heading).toBeInTheDocument()
101+
})
102+
103+
it('should render correct heading level', async () => {
104+
const { rerender } = render(
105+
<ColorContrast {...testColors} {...testLabels} labelLevel="h3" />
106+
)
107+
108+
let heading = screen.getByRole('heading', {
109+
name: testLabels.label,
110+
level: 3
111+
})
112+
expect(heading).toBeInTheDocument()
113+
114+
rerender(
115+
<ColorContrast {...testColors} {...testLabels} labelLevel="h1" />
116+
)
117+
118+
heading = screen.getByRole('heading', {
119+
name: testLabels.label,
120+
level: 1
121+
})
122+
expect(heading).toBeInTheDocument()
123+
})
124+
})
125+
79126
describe('should calculate contrast correctly', () => {
80127
it('on opaque colors', async () => {
81128
const color1 = '#fff'

packages/ui-color-picker/src/ColorContrast/index.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
import { withStyle } from '@instructure/emotion'
3434

3535
import { Text } from '@instructure/ui-text'
36+
import { Heading } from '@instructure/ui-heading'
3637
import { Pill } from '@instructure/ui-pill'
3738

3839
import ColorIndicator from '../ColorIndicator'
@@ -191,6 +192,7 @@ class ColorContrast extends Component<ColorContrastProps, ColorContrastState> {
191192
const {
192193
styles,
193194
label,
195+
labelLevel,
194196
normalTextLabel,
195197
largeTextLabel,
196198
graphicsTextLabel
@@ -211,9 +213,15 @@ class ColorContrast extends Component<ColorContrastProps, ColorContrastState> {
211213
data-cid="ColorContrast"
212214
>
213215
<div css={styles?.label}>
214-
<Text weight="bold" as="div">
215-
{label}
216-
</Text>
216+
{labelLevel ? (
217+
<Heading as={labelLevel} level="reset">
218+
{label}
219+
</Heading>
220+
) : (
221+
<Text weight="bold" as="div">
222+
{label}
223+
</Text>
224+
)}
217225
</div>
218226
<Text size="x-large">{contrast}:1</Text>
219227
{this.renderPreview()}

packages/ui-color-picker/src/ColorContrast/props.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,15 @@
2222
* SOFTWARE.
2323
*/
2424

25+
import React from 'react'
2526
import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
2627
import type {
2728
OtherHTMLAttributes,
2829
ColorContrastTheme
2930
} from '@instructure/shared-types'
3031

32+
type HeadingLevel<U extends keyof React.JSX.IntrinsicElements> = U
33+
3134
type ColorContrastOwnProps = {
3235
/**
3336
* Provides a reference to the component's underlying html element.
@@ -53,6 +56,10 @@ type ColorContrastOwnProps = {
5356
* Label of the component
5457
*/
5558
label: string
59+
/**
60+
* The heading level for the label. If provided, the label will be rendered as a `<Heading />` instead of `<Text />`.
61+
*/
62+
labelLevel?: HeadingLevel<'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'>
5663
/**
5764
* Text of the second check (Suggested english text: Large text)
5865
*/
@@ -154,6 +161,7 @@ const allowedProps: AllowedPropKeys = [
154161
'graphicsTextLabel',
155162
'withoutColorPreview',
156163
'label',
164+
'labelLevel',
157165
'largeTextLabel',
158166
'normalTextLabel',
159167
'secondColor',

packages/ui-color-picker/src/ColorContrast/styles.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
import type { ColorContrastTheme } from '@instructure/shared-types'
26+
import type { ColorContrastProps } from './props'
2627
/**
2728
* ---
2829
* private: true
@@ -33,7 +34,10 @@ import type { ColorContrastTheme } from '@instructure/shared-types'
3334
* @param {Object} state the state of the component, the style is applied to
3435
* @return {Object} The final style object, which will be used in the component
3536
*/
36-
const generateStyle = (componentTheme: ColorContrastTheme) => {
37+
const generateStyle = (
38+
componentTheme: ColorContrastTheme,
39+
props: ColorContrastProps
40+
) => {
3741
const statusDescriptionStyle = (pass: boolean) => ({
3842
label: pass
3943
? 'colorContrast__successDescription'
@@ -94,7 +98,8 @@ const generateStyle = (componentTheme: ColorContrastTheme) => {
9498
},
9599
label: {
96100
label: 'colorContrast__label',
97-
marginBottom: componentTheme.labelBottomMargin
101+
marginBottom: componentTheme.labelBottomMargin,
102+
...(props.labelLevel && { fontWeight: 'bold' })
98103
}
99104
}
100105
}

0 commit comments

Comments
 (0)