@instructure/ui-heading 10.21.0 → 10.21.1-snapshot-1

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,6 +3,17 @@
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
+ ## [10.21.1-snapshot-1](https://github.com/instructure/instructure-ui/compare/v10.21.0...v10.21.1-snapshot-1) (2025-07-03)
7
+
8
+
9
+ ### Features
10
+
11
+ * **ui-heading,shared-types:** add new aiHeading prop and design. Also add h6 level to heading ([a74236a](https://github.com/instructure/instructure-ui/commit/a74236a4e245b8738e6fa7785806a9586666d33c))
12
+
13
+
14
+
15
+
16
+
6
17
  # [10.21.0](https://github.com/instructure/instructure-ui/compare/v10.20.1...v10.21.0) (2025-06-27)
7
18
 
8
19
 
@@ -1,6 +1,6 @@
1
1
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
2
2
  const _excluded = ["border", "children", "color", "level", "margin", "elementRef", "makeStyles", "variant"];
3
- var _dec, _dec2, _class, _Heading;
3
+ var _dec, _dec2, _class, _Heading, _IconAiColoredSolid, _IconAiColoredSolid2, _IconAiColoredSolid3;
4
4
  /*
5
5
  * The MIT License (MIT)
6
6
  *
@@ -29,11 +29,12 @@ import { Component } from 'react';
29
29
  import { View } from '@instructure/ui-view';
30
30
  import { getElementType, passthroughProps, callRenderProp } from '@instructure/ui-react-utils';
31
31
  import { testable } from '@instructure/ui-testable';
32
+ import { IconAiColoredSolid } from '@instructure/ui-icons';
32
33
  import { withStyle } from '@instructure/emotion';
33
34
  import generateStyle from './styles';
34
35
  import generateComponentTheme from './theme';
35
36
  import { propTypes, allowedProps } from './props';
36
- import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "@emotion/react/jsx-runtime";
37
+ import { jsxs as _jsxs, jsx as _jsx } from "@emotion/react/jsx-runtime";
37
38
  const variantLevels = {
38
39
  titlePageDesktop: 'h1',
39
40
  titlePageMobile: 'h1',
@@ -85,26 +86,78 @@ let Heading = (_dec = withStyle(generateStyle, generateComponentTheme), _dec2 =
85
86
  renderContent() {
86
87
  const _this$props4 = this.props,
87
88
  children = _this$props4.children,
88
- renderIcon = _this$props4.renderIcon;
89
- if (renderIcon) {
90
- return _jsxs(_Fragment, {
89
+ renderIcon = _this$props4.renderIcon,
90
+ aiVariant = _this$props4.aiVariant;
91
+ if (renderIcon && !aiVariant) {
92
+ var _this$props$styles;
93
+ return _jsxs("span", {
94
+ css: [(_this$props$styles = this.props.styles) === null || _this$props$styles === void 0 ? void 0 : _this$props$styles.withIcon],
95
+ "aria-hidden": "true",
91
96
  children: [callRenderProp(renderIcon), "\xA0", children]
92
97
  });
93
98
  }
99
+ if (aiVariant === 'stacked') {
100
+ var _this$props$styles2, _this$props$styles3, _this$props$styles4;
101
+ return _jsxs("span", {
102
+ css: [(_this$props$styles2 = this.props.styles) === null || _this$props$styles2 === void 0 ? void 0 : _this$props$styles2.withIcon],
103
+ "aria-hidden": "true",
104
+ children: [_jsxs("span", {
105
+ css: (_this$props$styles3 = this.props.styles) === null || _this$props$styles3 === void 0 ? void 0 : _this$props$styles3.igniteAIStacked,
106
+ children: [_IconAiColoredSolid || (_IconAiColoredSolid = _jsx(IconAiColoredSolid, {})), _jsx("span", {
107
+ css: (_this$props$styles4 = this.props.styles) === null || _this$props$styles4 === void 0 ? void 0 : _this$props$styles4.igniteAI,
108
+ children: "IgniteAI"
109
+ })]
110
+ }), children]
111
+ });
112
+ }
113
+ if (aiVariant === 'horizontal') {
114
+ var _this$props$styles5, _this$props$styles6;
115
+ return _jsxs("span", {
116
+ css: (_this$props$styles5 = this.props.styles) === null || _this$props$styles5 === void 0 ? void 0 : _this$props$styles5.withIcon,
117
+ "aria-hidden": "true",
118
+ children: [_IconAiColoredSolid2 || (_IconAiColoredSolid2 = _jsx(IconAiColoredSolid, {})), _jsx("span", {
119
+ css: (_this$props$styles6 = this.props.styles) === null || _this$props$styles6 === void 0 ? void 0 : _this$props$styles6.igniteAI,
120
+ children: "IgniteAI"
121
+ }), children]
122
+ });
123
+ }
124
+ if (aiVariant === 'iconOnly') {
125
+ var _this$props$styles7;
126
+ return _jsxs("span", {
127
+ css: (_this$props$styles7 = this.props.styles) === null || _this$props$styles7 === void 0 ? void 0 : _this$props$styles7.withIcon,
128
+ "aria-hidden": "true",
129
+ children: [_IconAiColoredSolid3 || (_IconAiColoredSolid3 = _jsx(IconAiColoredSolid, {})), "\xA0", children]
130
+ });
131
+ }
94
132
  return children;
95
133
  }
96
- render() {
97
- var _this$props$styles;
134
+
135
+ //overriding default screen reader functionality is needed to read spans in h tags correctly
136
+ getAriaLabel() {
98
137
  const _this$props5 = this.props,
99
- border = _this$props5.border,
138
+ aiVariant = _this$props5.aiVariant,
100
139
  children = _this$props5.children,
101
- color = _this$props5.color,
102
- level = _this$props5.level,
103
- margin = _this$props5.margin,
104
- elementRef = _this$props5.elementRef,
105
- makeStyles = _this$props5.makeStyles,
106
- variant = _this$props5.variant,
107
- props = _objectWithoutProperties(_this$props5, _excluded);
140
+ renderIcon = _this$props5.renderIcon;
141
+ if (aiVariant === 'stacked' || aiVariant === 'horizontal') {
142
+ return `IgniteAI, ${children}`;
143
+ }
144
+ if (aiVariant === 'iconOnly' || renderIcon) {
145
+ return `${children}`;
146
+ }
147
+ return void 0;
148
+ }
149
+ render() {
150
+ var _this$props$styles8;
151
+ const _this$props6 = this.props,
152
+ border = _this$props6.border,
153
+ children = _this$props6.children,
154
+ color = _this$props6.color,
155
+ level = _this$props6.level,
156
+ margin = _this$props6.margin,
157
+ elementRef = _this$props6.elementRef,
158
+ makeStyles = _this$props6.makeStyles,
159
+ variant = _this$props6.variant,
160
+ props = _objectWithoutProperties(_this$props6, _excluded);
108
161
  const propsForGetElementType = variant ? {} : this.props;
109
162
  const ElementType = getElementType(Heading, propsForGetElementType, () => {
110
163
  if (level === 'reset') {
@@ -120,10 +173,11 @@ let Heading = (_dec = withStyle(generateStyle, generateComponentTheme), _dec2 =
120
173
  });
121
174
  return _jsx(View, {
122
175
  ...passthroughProps(props),
123
- css: (_this$props$styles = this.props.styles) === null || _this$props$styles === void 0 ? void 0 : _this$props$styles.heading,
176
+ css: (_this$props$styles8 = this.props.styles) === null || _this$props$styles8 === void 0 ? void 0 : _this$props$styles8.heading,
124
177
  as: ElementType,
125
178
  elementRef: this.handleRef,
126
179
  margin: margin,
180
+ "aria-label": this.getAriaLabel(),
127
181
  children: this.renderContent()
128
182
  });
129
183
  }
@@ -25,6 +25,7 @@
25
25
  import PropTypes from 'prop-types';
26
26
  import { childrenOrValue } from '@instructure/ui-prop-types';
27
27
  const propTypes = {
28
+ aiVariant: PropTypes.oneOf(['stacked', 'horizontal', 'iconOnly']),
28
29
  border: PropTypes.oneOf(['none', 'top', 'bottom']),
29
30
  children: childrenOrValue,
30
31
  color: PropTypes.oneOf(['primary', 'secondary', 'primary-inverse', 'secondary-inverse', 'inherit', 'ai']),
@@ -35,5 +36,5 @@ const propTypes = {
35
36
  renderIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
36
37
  variant: PropTypes.oneOf(['titlePageDesktop', 'titlePageMobile', 'titleSection', 'titleCardSection', 'titleModule', 'titleCardLarge', 'titleCardRegular', 'titleCardMini', 'label', 'labelInline'])
37
38
  };
38
- const allowedProps = ['border', 'children', 'color', 'level', 'as', 'margin', 'elementRef', 'variant'];
39
+ const allowedProps = ['aiVariant', 'border', 'children', 'color', 'level', 'as', 'margin', 'elementRef', 'variant'];
39
40
  export { propTypes, allowedProps };
@@ -37,7 +37,7 @@ const generateStyle = (componentTheme, props) => {
37
37
  color = props.color,
38
38
  border = props.border,
39
39
  variant = props.variant,
40
- renderIcon = props.renderIcon;
40
+ aiVariant = props.aiVariant;
41
41
  const variants = {
42
42
  titlePageDesktop: {
43
43
  fontStyle: 'normal',
@@ -126,6 +126,11 @@ const generateStyle = (componentTheme, props) => {
126
126
  fontSize: componentTheme.h5FontSize,
127
127
  fontWeight: componentTheme.h5FontWeight
128
128
  },
129
+ h6: {
130
+ fontFamily: componentTheme.h6FontFamily,
131
+ fontSize: componentTheme.h6FontSize,
132
+ fontWeight: componentTheme.h6FontWeight
133
+ },
129
134
  reset: {
130
135
  margin: 0,
131
136
  fontSize: 'inherit',
@@ -192,11 +197,6 @@ const generateStyle = (componentTheme, props) => {
192
197
  label: 'heading',
193
198
  lineHeight: componentTheme.lineHeight,
194
199
  margin: 0,
195
- //need this for icons to render them vertically centered
196
- ...(renderIcon ? {
197
- display: 'flex',
198
- alignItems: 'center'
199
- } : {}),
200
200
  // NOTE: the input styles exist to accommodate the InPlaceEdit component
201
201
  // NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping)
202
202
  '&:is(input)[type]': inputStyles,
@@ -204,6 +204,31 @@ const generateStyle = (componentTheme, props) => {
204
204
  ...(variant ? variants[variant] : levelStyles[level]),
205
205
  ...colorStyles[color],
206
206
  ...borderStyles[border]
207
+ },
208
+ igniteAI: {
209
+ label: 'heading__ignite-ai',
210
+ background: `
211
+ linear-gradient(to bottom, ${componentTheme.aiTextTopGradientColor} 0%, ${componentTheme.aiTextBottomGradientColor} 100%) text`,
212
+ border: 'solid transparent',
213
+ WebkitTextFillColor: 'transparent',
214
+ paddingRight: '.25rem'
215
+ },
216
+ igniteAIStacked: {
217
+ label: 'heading__ignite-ai-stacked',
218
+ fontSize: '1rem',
219
+ lineHeight: '1.25rem',
220
+ display: 'flex',
221
+ alignItems: 'center'
222
+ },
223
+ withIcon: {
224
+ label: 'heading__with-icon',
225
+ display: 'flex',
226
+ alignItems: 'center',
227
+ ...(aiVariant === 'stacked' ? {
228
+ display: 'flex',
229
+ flexDirection: 'column',
230
+ alignItems: 'flex-start'
231
+ } : {})
207
232
  }
208
233
  };
209
234
  };
@@ -37,16 +37,6 @@ const generateComponentTheme = theme => {
37
37
  const themeSpecificStyle = {
38
38
  canvas: {
39
39
  primaryColor: theme['ic-brand-font-color-dark']
40
- },
41
- instructure: {
42
- h1FontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamilyHeading,
43
- h2FontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamilyHeading,
44
- h3FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightBold,
45
- h3FontSize: '2.125rem',
46
- h4FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightBold,
47
- h4FontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeLarge,
48
- h5FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightBold,
49
- h5FontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeMedium
50
40
  }
51
41
  };
52
42
  const componentVariables = {
@@ -67,6 +57,9 @@ const generateComponentTheme = theme => {
67
57
  h5FontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeSmall,
68
58
  h5FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightNormal,
69
59
  h5FontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamily,
60
+ h6FontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeXSmall,
61
+ h6FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightNormal,
62
+ h6FontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamily,
70
63
  primaryInverseColor: colors === null || colors === void 0 ? void 0 : (_colors$contrasts = colors.contrasts) === null || _colors$contrasts === void 0 ? void 0 : _colors$contrasts.white1010,
71
64
  primaryColor: colors === null || colors === void 0 ? void 0 : (_colors$contrasts2 = colors.contrasts) === null || _colors$contrasts2 === void 0 ? void 0 : _colors$contrasts2.grey125125,
72
65
  secondaryColor: colors === null || colors === void 0 ? void 0 : (_colors$contrasts3 = colors.contrasts) === null || _colors$contrasts3 === void 0 ? void 0 : _colors$contrasts3.grey4570,
@@ -12,13 +12,14 @@ var _getElementType = require("@instructure/ui-react-utils/lib/getElementType.js
12
12
  var _passthroughProps = require("@instructure/ui-react-utils/lib/passthroughProps.js");
13
13
  var _callRenderProp = require("@instructure/ui-react-utils/lib/callRenderProp.js");
14
14
  var _testable = require("@instructure/ui-testable/lib/testable.js");
15
+ var _IconAiColoredSolid4 = require("@instructure/ui-icons/lib/IconAiColoredSolid.js");
15
16
  var _emotion = require("@instructure/emotion");
16
17
  var _styles = _interopRequireDefault(require("./styles"));
17
18
  var _theme = _interopRequireDefault(require("./theme"));
18
19
  var _props = require("./props");
19
20
  var _jsxRuntime = require("@emotion/react/jsx-runtime");
20
21
  const _excluded = ["border", "children", "color", "level", "margin", "elementRef", "makeStyles", "variant"];
21
- var _dec, _dec2, _class, _Heading;
22
+ var _dec, _dec2, _class, _Heading, _IconAiColoredSolid, _IconAiColoredSolid2, _IconAiColoredSolid3;
22
23
  /*
23
24
  * The MIT License (MIT)
24
25
  *
@@ -93,26 +94,78 @@ let Heading = exports.Heading = (_dec = (0, _emotion.withStyle)(_styles.default,
93
94
  renderContent() {
94
95
  const _this$props4 = this.props,
95
96
  children = _this$props4.children,
96
- renderIcon = _this$props4.renderIcon;
97
- if (renderIcon) {
98
- return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
97
+ renderIcon = _this$props4.renderIcon,
98
+ aiVariant = _this$props4.aiVariant;
99
+ if (renderIcon && !aiVariant) {
100
+ var _this$props$styles;
101
+ return (0, _jsxRuntime.jsxs)("span", {
102
+ css: [(_this$props$styles = this.props.styles) === null || _this$props$styles === void 0 ? void 0 : _this$props$styles.withIcon],
103
+ "aria-hidden": "true",
99
104
  children: [(0, _callRenderProp.callRenderProp)(renderIcon), "\xA0", children]
100
105
  });
101
106
  }
107
+ if (aiVariant === 'stacked') {
108
+ var _this$props$styles2, _this$props$styles3, _this$props$styles4;
109
+ return (0, _jsxRuntime.jsxs)("span", {
110
+ css: [(_this$props$styles2 = this.props.styles) === null || _this$props$styles2 === void 0 ? void 0 : _this$props$styles2.withIcon],
111
+ "aria-hidden": "true",
112
+ children: [(0, _jsxRuntime.jsxs)("span", {
113
+ css: (_this$props$styles3 = this.props.styles) === null || _this$props$styles3 === void 0 ? void 0 : _this$props$styles3.igniteAIStacked,
114
+ children: [_IconAiColoredSolid || (_IconAiColoredSolid = (0, _jsxRuntime.jsx)(_IconAiColoredSolid4.IconAiColoredSolid, {})), (0, _jsxRuntime.jsx)("span", {
115
+ css: (_this$props$styles4 = this.props.styles) === null || _this$props$styles4 === void 0 ? void 0 : _this$props$styles4.igniteAI,
116
+ children: "IgniteAI"
117
+ })]
118
+ }), children]
119
+ });
120
+ }
121
+ if (aiVariant === 'horizontal') {
122
+ var _this$props$styles5, _this$props$styles6;
123
+ return (0, _jsxRuntime.jsxs)("span", {
124
+ css: (_this$props$styles5 = this.props.styles) === null || _this$props$styles5 === void 0 ? void 0 : _this$props$styles5.withIcon,
125
+ "aria-hidden": "true",
126
+ children: [_IconAiColoredSolid2 || (_IconAiColoredSolid2 = (0, _jsxRuntime.jsx)(_IconAiColoredSolid4.IconAiColoredSolid, {})), (0, _jsxRuntime.jsx)("span", {
127
+ css: (_this$props$styles6 = this.props.styles) === null || _this$props$styles6 === void 0 ? void 0 : _this$props$styles6.igniteAI,
128
+ children: "IgniteAI"
129
+ }), children]
130
+ });
131
+ }
132
+ if (aiVariant === 'iconOnly') {
133
+ var _this$props$styles7;
134
+ return (0, _jsxRuntime.jsxs)("span", {
135
+ css: (_this$props$styles7 = this.props.styles) === null || _this$props$styles7 === void 0 ? void 0 : _this$props$styles7.withIcon,
136
+ "aria-hidden": "true",
137
+ children: [_IconAiColoredSolid3 || (_IconAiColoredSolid3 = (0, _jsxRuntime.jsx)(_IconAiColoredSolid4.IconAiColoredSolid, {})), "\xA0", children]
138
+ });
139
+ }
102
140
  return children;
103
141
  }
104
- render() {
105
- var _this$props$styles;
142
+
143
+ //overriding default screen reader functionality is needed to read spans in h tags correctly
144
+ getAriaLabel() {
106
145
  const _this$props5 = this.props,
107
- border = _this$props5.border,
146
+ aiVariant = _this$props5.aiVariant,
108
147
  children = _this$props5.children,
109
- color = _this$props5.color,
110
- level = _this$props5.level,
111
- margin = _this$props5.margin,
112
- elementRef = _this$props5.elementRef,
113
- makeStyles = _this$props5.makeStyles,
114
- variant = _this$props5.variant,
115
- props = (0, _objectWithoutProperties2.default)(_this$props5, _excluded);
148
+ renderIcon = _this$props5.renderIcon;
149
+ if (aiVariant === 'stacked' || aiVariant === 'horizontal') {
150
+ return `IgniteAI, ${children}`;
151
+ }
152
+ if (aiVariant === 'iconOnly' || renderIcon) {
153
+ return `${children}`;
154
+ }
155
+ return void 0;
156
+ }
157
+ render() {
158
+ var _this$props$styles8;
159
+ const _this$props6 = this.props,
160
+ border = _this$props6.border,
161
+ children = _this$props6.children,
162
+ color = _this$props6.color,
163
+ level = _this$props6.level,
164
+ margin = _this$props6.margin,
165
+ elementRef = _this$props6.elementRef,
166
+ makeStyles = _this$props6.makeStyles,
167
+ variant = _this$props6.variant,
168
+ props = (0, _objectWithoutProperties2.default)(_this$props6, _excluded);
116
169
  const propsForGetElementType = variant ? {} : this.props;
117
170
  const ElementType = (0, _getElementType.getElementType)(Heading, propsForGetElementType, () => {
118
171
  if (level === 'reset') {
@@ -128,10 +181,11 @@ let Heading = exports.Heading = (_dec = (0, _emotion.withStyle)(_styles.default,
128
181
  });
129
182
  return (0, _jsxRuntime.jsx)(_View.View, {
130
183
  ...(0, _passthroughProps.passthroughProps)(props),
131
- css: (_this$props$styles = this.props.styles) === null || _this$props$styles === void 0 ? void 0 : _this$props$styles.heading,
184
+ css: (_this$props$styles8 = this.props.styles) === null || _this$props$styles8 === void 0 ? void 0 : _this$props$styles8.heading,
132
185
  as: ElementType,
133
186
  elementRef: this.handleRef,
134
187
  margin: margin,
188
+ "aria-label": this.getAriaLabel(),
135
189
  children: this.renderContent()
136
190
  });
137
191
  }
@@ -32,6 +32,7 @@ var _childrenOrValue = require("@instructure/ui-prop-types/lib/childrenOrValue.j
32
32
  */
33
33
 
34
34
  const propTypes = exports.propTypes = {
35
+ aiVariant: _propTypes.default.oneOf(['stacked', 'horizontal', 'iconOnly']),
35
36
  border: _propTypes.default.oneOf(['none', 'top', 'bottom']),
36
37
  children: _childrenOrValue.childrenOrValue,
37
38
  color: _propTypes.default.oneOf(['primary', 'secondary', 'primary-inverse', 'secondary-inverse', 'inherit', 'ai']),
@@ -42,4 +43,4 @@ const propTypes = exports.propTypes = {
42
43
  renderIcon: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
43
44
  variant: _propTypes.default.oneOf(['titlePageDesktop', 'titlePageMobile', 'titleSection', 'titleCardSection', 'titleModule', 'titleCardLarge', 'titleCardRegular', 'titleCardMini', 'label', 'labelInline'])
44
45
  };
45
- const allowedProps = exports.allowedProps = ['border', 'children', 'color', 'level', 'as', 'margin', 'elementRef', 'variant'];
46
+ const allowedProps = exports.allowedProps = ['aiVariant', 'border', 'children', 'color', 'level', 'as', 'margin', 'elementRef', 'variant'];
@@ -43,7 +43,7 @@ const generateStyle = (componentTheme, props) => {
43
43
  color = props.color,
44
44
  border = props.border,
45
45
  variant = props.variant,
46
- renderIcon = props.renderIcon;
46
+ aiVariant = props.aiVariant;
47
47
  const variants = {
48
48
  titlePageDesktop: {
49
49
  fontStyle: 'normal',
@@ -132,6 +132,11 @@ const generateStyle = (componentTheme, props) => {
132
132
  fontSize: componentTheme.h5FontSize,
133
133
  fontWeight: componentTheme.h5FontWeight
134
134
  },
135
+ h6: {
136
+ fontFamily: componentTheme.h6FontFamily,
137
+ fontSize: componentTheme.h6FontSize,
138
+ fontWeight: componentTheme.h6FontWeight
139
+ },
135
140
  reset: {
136
141
  margin: 0,
137
142
  fontSize: 'inherit',
@@ -198,11 +203,6 @@ const generateStyle = (componentTheme, props) => {
198
203
  label: 'heading',
199
204
  lineHeight: componentTheme.lineHeight,
200
205
  margin: 0,
201
- //need this for icons to render them vertically centered
202
- ...(renderIcon ? {
203
- display: 'flex',
204
- alignItems: 'center'
205
- } : {}),
206
206
  // NOTE: the input styles exist to accommodate the InPlaceEdit component
207
207
  // NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping)
208
208
  '&:is(input)[type]': inputStyles,
@@ -210,6 +210,31 @@ const generateStyle = (componentTheme, props) => {
210
210
  ...(variant ? variants[variant] : levelStyles[level]),
211
211
  ...colorStyles[color],
212
212
  ...borderStyles[border]
213
+ },
214
+ igniteAI: {
215
+ label: 'heading__ignite-ai',
216
+ background: `
217
+ linear-gradient(to bottom, ${componentTheme.aiTextTopGradientColor} 0%, ${componentTheme.aiTextBottomGradientColor} 100%) text`,
218
+ border: 'solid transparent',
219
+ WebkitTextFillColor: 'transparent',
220
+ paddingRight: '.25rem'
221
+ },
222
+ igniteAIStacked: {
223
+ label: 'heading__ignite-ai-stacked',
224
+ fontSize: '1rem',
225
+ lineHeight: '1.25rem',
226
+ display: 'flex',
227
+ alignItems: 'center'
228
+ },
229
+ withIcon: {
230
+ label: 'heading__with-icon',
231
+ display: 'flex',
232
+ alignItems: 'center',
233
+ ...(aiVariant === 'stacked' ? {
234
+ display: 'flex',
235
+ flexDirection: 'column',
236
+ alignItems: 'flex-start'
237
+ } : {})
213
238
  }
214
239
  };
215
240
  };
@@ -43,16 +43,6 @@ const generateComponentTheme = theme => {
43
43
  const themeSpecificStyle = {
44
44
  canvas: {
45
45
  primaryColor: theme['ic-brand-font-color-dark']
46
- },
47
- instructure: {
48
- h1FontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamilyHeading,
49
- h2FontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamilyHeading,
50
- h3FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightBold,
51
- h3FontSize: '2.125rem',
52
- h4FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightBold,
53
- h4FontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeLarge,
54
- h5FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightBold,
55
- h5FontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeMedium
56
46
  }
57
47
  };
58
48
  const componentVariables = {
@@ -73,6 +63,9 @@ const generateComponentTheme = theme => {
73
63
  h5FontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeSmall,
74
64
  h5FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightNormal,
75
65
  h5FontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamily,
66
+ h6FontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeXSmall,
67
+ h6FontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightNormal,
68
+ h6FontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamily,
76
69
  primaryInverseColor: colors === null || colors === void 0 ? void 0 : (_colors$contrasts = colors.contrasts) === null || _colors$contrasts === void 0 ? void 0 : _colors$contrasts.white1010,
77
70
  primaryColor: colors === null || colors === void 0 ? void 0 : (_colors$contrasts2 = colors.contrasts) === null || _colors$contrasts2 === void 0 ? void 0 : _colors$contrasts2.grey125125,
78
71
  secondaryColor: colors === null || colors === void 0 ? void 0 : (_colors$contrasts3 = colors.contrasts) === null || _colors$contrasts3 === void 0 ? void 0 : _colors$contrasts3.grey4570,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/ui-heading",
3
- "version": "10.21.0",
3
+ "version": "10.21.1-snapshot-1",
4
4
  "description": "A component for creating typographic headings",
5
5
  "author": "Instructure, Inc. Engineering and Product Design",
6
6
  "module": "./es/index.js",
@@ -24,19 +24,20 @@
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
26
  "@babel/runtime": "^7.27.6",
27
- "@instructure/console": "10.21.0",
28
- "@instructure/emotion": "10.21.0",
29
- "@instructure/shared-types": "10.21.0",
30
- "@instructure/ui-prop-types": "10.21.0",
31
- "@instructure/ui-react-utils": "10.21.0",
32
- "@instructure/ui-testable": "10.21.0",
33
- "@instructure/ui-view": "10.21.0",
27
+ "@instructure/console": "10.21.1-snapshot-1",
28
+ "@instructure/emotion": "10.21.1-snapshot-1",
29
+ "@instructure/shared-types": "10.21.1-snapshot-1",
30
+ "@instructure/ui-icons": "10.21.1-snapshot-1",
31
+ "@instructure/ui-prop-types": "10.21.1-snapshot-1",
32
+ "@instructure/ui-react-utils": "10.21.1-snapshot-1",
33
+ "@instructure/ui-testable": "10.21.1-snapshot-1",
34
+ "@instructure/ui-view": "10.21.1-snapshot-1",
34
35
  "prop-types": "^15.8.1"
35
36
  },
36
37
  "devDependencies": {
37
- "@instructure/ui-axe-check": "10.21.0",
38
- "@instructure/ui-babel-preset": "10.21.0",
39
- "@instructure/ui-themes": "10.21.0",
38
+ "@instructure/ui-axe-check": "10.21.1-snapshot-1",
39
+ "@instructure/ui-babel-preset": "10.21.1-snapshot-1",
40
+ "@instructure/ui-themes": "10.21.1-snapshot-1",
40
41
  "@testing-library/jest-dom": "^6.6.3",
41
42
  "@testing-library/react": "^16.0.1",
42
43
  "vitest": "^3.2.2"
@@ -34,11 +34,19 @@ type: example
34
34
  </div>
35
35
  ```
36
36
 
37
+ ### AI Heading
38
+
39
+ Pre-configured and with unique styles, the `ai-headings` are used for standardized, ai-related components.
40
+
37
41
  ```js
38
42
  ---
39
43
  type: example
40
44
  ---
41
- <Heading>Default Heading</Heading>
45
+ <div style={{display: 'flex', flexDirection: 'column', gap: '24px'}}>
46
+ <Heading aiVariant="stacked">Nutrition Facts</Heading>
47
+ <Heading aiVariant="horizontal">Nutrition Facts</Heading>
48
+ <Heading aiVariant="iconOnly">Nutrition Facts</Heading>
49
+ </div>
42
50
  ```
43
51
 
44
52
  ### Heading level
@@ -70,20 +78,19 @@ type: example
70
78
  <Heading>I inherit my color via the CSS cascade (default)</Heading>
71
79
  <Heading color="primary">I am primary color</Heading>
72
80
  <Heading color="secondary">I am secondary color</Heading>
73
- <Heading color="ai">I am AI color</Heading>
74
81
  </div>
75
82
  ```
76
83
 
77
84
  ### Icons
78
85
 
79
- With the `renderIcon` prop, an icon can be rendered before the text. Only current use-case is for the `ai heading`
86
+ With the `renderIcon` prop, an icon can be rendered before the text.
80
87
 
81
88
  ```js
82
89
  ---
83
90
  type: example
84
91
  ---
85
92
  <div>
86
- <Heading color="ai" renderIcon={<IconAiColoredSolid/>}>I am AI color with icon</Heading>
93
+ <Heading renderIcon={<IconAdminSolid/>}>I am heading with icon</Heading>
87
94
  </div>
88
95
  ```
89
96
 
@@ -31,6 +31,7 @@ import {
31
31
  callRenderProp
32
32
  } from '@instructure/ui-react-utils'
33
33
  import { testable } from '@instructure/ui-testable'
34
+ import { IconAiColoredSolid } from '@instructure/ui-icons'
34
35
 
35
36
  import { withStyle } from '@instructure/emotion'
36
37
 
@@ -107,18 +108,58 @@ class Heading extends Component<HeadingProps> {
107
108
  }
108
109
 
109
110
  renderContent() {
110
- const { children, renderIcon } = this.props
111
+ const { children, renderIcon, aiVariant } = this.props
111
112
 
112
- if (renderIcon) {
113
+ if (renderIcon && !aiVariant) {
113
114
  return (
114
- <>
115
+ <span css={[this.props.styles?.withIcon]} aria-hidden="true">
115
116
  {callRenderProp(renderIcon)}&nbsp;{children}
116
- </>
117
+ </span>
118
+ )
119
+ }
120
+ if (aiVariant === 'stacked') {
121
+ return (
122
+ <span css={[this.props.styles?.withIcon]} aria-hidden="true">
123
+ <span css={this.props.styles?.igniteAIStacked}>
124
+ <IconAiColoredSolid />
125
+ <span css={this.props.styles?.igniteAI}>IgniteAI</span>
126
+ </span>
127
+ {children}
128
+ </span>
129
+ )
130
+ }
131
+ if (aiVariant === 'horizontal') {
132
+ return (
133
+ <span css={this.props.styles?.withIcon} aria-hidden="true">
134
+ <IconAiColoredSolid />
135
+ <span css={this.props.styles?.igniteAI}>IgniteAI</span>
136
+ {children}
137
+ </span>
138
+ )
139
+ }
140
+ if (aiVariant === 'iconOnly') {
141
+ return (
142
+ <span css={this.props.styles?.withIcon} aria-hidden="true">
143
+ <IconAiColoredSolid />
144
+ &nbsp;{children}
145
+ </span>
117
146
  )
118
147
  }
119
148
  return children
120
149
  }
121
150
 
151
+ //overriding default screen reader functionality is needed to read spans in h tags correctly
152
+ getAriaLabel() {
153
+ const { aiVariant, children, renderIcon } = this.props
154
+ if (aiVariant === 'stacked' || aiVariant === 'horizontal') {
155
+ return `IgniteAI, ${children}`
156
+ }
157
+ if (aiVariant === 'iconOnly' || renderIcon) {
158
+ return `${children}`
159
+ }
160
+ return undefined
161
+ }
162
+
122
163
  render() {
123
164
  const {
124
165
  border,
@@ -155,6 +196,7 @@ class Heading extends Component<HeadingProps> {
155
196
  as={ElementType}
156
197
  elementRef={this.handleRef}
157
198
  margin={margin}
199
+ aria-label={this.getAriaLabel()}
158
200
  >
159
201
  {this.renderContent()}
160
202
  </View>