@instructure/ui-options 8.19.1-snapshot.8 → 8.20.0
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 +7 -0
- package/es/Options/Item/__examples__/Item.examples.js +5 -0
- package/es/Options/Item/index.js +16 -9
- package/es/Options/Item/props.js +3 -2
- package/es/Options/Item/styles.js +18 -1
- package/es/Options/Item/theme.js +1 -1
- package/es/Options/index.js +2 -2
- package/lib/Options/Item/__examples__/Item.examples.js +5 -0
- package/lib/Options/Item/index.js +15 -8
- package/lib/Options/Item/props.js +3 -2
- package/lib/Options/Item/styles.js +18 -1
- package/lib/Options/Item/theme.js +1 -1
- package/lib/Options/index.js +2 -2
- package/package.json +14 -15
- package/src/Options/Item/__examples__/Item.examples.ts +10 -0
- package/src/Options/Item/index.tsx +31 -4
- package/src/Options/Item/props.ts +22 -3
- package/src/Options/Item/styles.ts +17 -1
- package/src/Options/Item/theme.ts +1 -1
- package/src/Options/README.md +61 -0
- package/src/Options/index.tsx +8 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/Options/Item/__examples__/Item.examples.d.ts.map +1 -1
- package/types/Options/Item/index.d.ts +6 -4
- package/types/Options/Item/index.d.ts.map +1 -1
- package/types/Options/Item/props.d.ts +8 -3
- package/types/Options/Item/props.d.ts.map +1 -1
- package/types/Options/Item/styles.d.ts.map +1 -1
- package/types/Options/index.d.ts.map +1 -1
- package/LICENSE.md +0 -27
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
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
|
+
# [8.20.0](https://github.com/instructure/instructure-ui/compare/v8.19.0...v8.20.0) (2022-03-22)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- **ui-options:** add `href` prop to Options.Item ([49bf28c](https://github.com/instructure/instructure-ui/commit/49bf28c637f395f7ae5d23c0f676d83a15c2ee43))
|
|
11
|
+
- **ui-options:** modify default nested Options padding to have no extra padding ([bfc4f7c](https://github.com/instructure/instructure-ui/commit/bfc4f7cb094d91d25b58a87a24a473363c90796b))
|
|
12
|
+
|
|
6
13
|
# [8.19.0](https://github.com/instructure/instructure-ui/compare/v8.18.0...v8.19.0) (2022-03-16)
|
|
7
14
|
|
|
8
15
|
### Bug Fixes
|
|
@@ -27,6 +27,7 @@ export default {
|
|
|
27
27
|
propValues: {
|
|
28
28
|
renderAfterLabel: [null, IconArrowOpenEndSolid],
|
|
29
29
|
renderBeforeLabel: [null, IconCheckSolid],
|
|
30
|
+
href: [void 0, '/hello'],
|
|
30
31
|
description: [null, 'Curabitur fringilla, urna ut efficitur molestie, nibh lacus tincidunt elit, ut tempor ipsum nunc sit amet massa. Integer sit amet ante vitae lectus gravida pulvinar.']
|
|
31
32
|
},
|
|
32
33
|
getComponentProps: props => {
|
|
@@ -60,6 +61,10 @@ export default {
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
if (props.href && (props.beforeLabelContentVAlign !== 'center' || props.afterLabelContentVAlign !== 'center' || props.description)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
63
68
|
return false;
|
|
64
69
|
}
|
|
65
70
|
};
|
package/es/Options/Item/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var _dec, _dec2, _class, _class2, _temp;
|
|
1
|
+
var _dec, _dec2, _dec3, _class, _class2, _temp;
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* The MIT License (MIT)
|
|
@@ -26,7 +26,7 @@ var _dec, _dec2, _class, _class2, _temp;
|
|
|
26
26
|
|
|
27
27
|
/** @jsx jsx */
|
|
28
28
|
import { Component } from 'react';
|
|
29
|
-
import { omitProps, getElementType, callRenderProp } from '@instructure/ui-react-utils';
|
|
29
|
+
import { omitProps, getElementType, callRenderProp, withDeterministicId } from '@instructure/ui-react-utils';
|
|
30
30
|
import { testable } from '@instructure/ui-testable';
|
|
31
31
|
import { withStyle, jsx } from '@instructure/emotion';
|
|
32
32
|
import generateStyles from './styles';
|
|
@@ -40,10 +40,12 @@ id: Options.Item
|
|
|
40
40
|
@tsProps
|
|
41
41
|
**/
|
|
42
42
|
|
|
43
|
-
let Item = (_dec = withStyle(generateStyles, generateComponentTheme),
|
|
44
|
-
constructor() {
|
|
45
|
-
super(
|
|
43
|
+
let Item = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyles, generateComponentTheme), _dec3 = testable(), _dec(_class = _dec2(_class = _dec3(_class = (_temp = _class2 = class Item extends Component {
|
|
44
|
+
constructor(props) {
|
|
45
|
+
super(props);
|
|
46
46
|
this.ref = null;
|
|
47
|
+
this._descriptionId = void 0;
|
|
48
|
+
this._descriptionId = props.deterministicId('OptionsItem-description');
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
componentDidMount() {
|
|
@@ -80,6 +82,7 @@ let Item = (_dec = withStyle(generateStyles, generateComponentTheme), _dec2 = te
|
|
|
80
82
|
render() {
|
|
81
83
|
const _this$props4 = this.props,
|
|
82
84
|
as = _this$props4.as,
|
|
85
|
+
href = _this$props4.href,
|
|
83
86
|
role = _this$props4.role,
|
|
84
87
|
styles = _this$props4.styles,
|
|
85
88
|
description = _this$props4.description,
|
|
@@ -89,6 +92,7 @@ let Item = (_dec = withStyle(generateStyles, generateComponentTheme), _dec2 = te
|
|
|
89
92
|
elementRef = _this$props4.elementRef,
|
|
90
93
|
children = _this$props4.children;
|
|
91
94
|
const ElementType = getElementType(Item, this.props, () => as);
|
|
95
|
+
const InnerElementType = href ? 'a' : 'span';
|
|
92
96
|
const passthroughProps = omitProps(this.props, Item.allowedProps);
|
|
93
97
|
const childrenContent = callRenderProp(children);
|
|
94
98
|
const descriptionContent = callRenderProp(description);
|
|
@@ -102,12 +106,15 @@ let Item = (_dec = withStyle(generateStyles, generateComponentTheme), _dec2 = te
|
|
|
102
106
|
elementRef(element);
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
|
-
}, jsx(
|
|
109
|
+
}, jsx(InnerElementType, Object.assign({}, passthroughProps, {
|
|
106
110
|
css: styles === null || styles === void 0 ? void 0 : styles.container,
|
|
107
|
-
role: role
|
|
111
|
+
role: href ? void 0 : role,
|
|
112
|
+
href: href,
|
|
113
|
+
"aria-describedby": this.props['aria-describedby'] || (descriptionContent ? this._descriptionId : void 0)
|
|
108
114
|
}), childrenContent, descriptionContent && jsx("span", {
|
|
109
115
|
css: styles === null || styles === void 0 ? void 0 : styles.description,
|
|
110
|
-
role: descriptionRole
|
|
116
|
+
role: descriptionRole,
|
|
117
|
+
id: this._descriptionId
|
|
111
118
|
}, descriptionContent)), renderBeforeLabel && this.renderContent(renderBeforeLabel, styles === null || styles === void 0 ? void 0 : styles.contentBefore), renderAfterLabel && this.renderContent(renderAfterLabel, styles === null || styles === void 0 ? void 0 : styles.contentAfter));
|
|
112
119
|
}
|
|
113
120
|
|
|
@@ -118,6 +125,6 @@ let Item = (_dec = withStyle(generateStyles, generateComponentTheme), _dec2 = te
|
|
|
118
125
|
descriptionRole: 'note',
|
|
119
126
|
beforeLabelContentVAlign: 'center',
|
|
120
127
|
afterLabelContentVAlign: 'center'
|
|
121
|
-
}, _temp)) || _class) || _class);
|
|
128
|
+
}, _temp)) || _class) || _class) || _class);
|
|
122
129
|
export default Item;
|
|
123
130
|
export { Item };
|
package/es/Options/Item/props.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
import PropTypes from 'prop-types';
|
|
25
25
|
const propTypes = {
|
|
26
26
|
as: PropTypes.elementType,
|
|
27
|
-
variant: PropTypes.oneOf(['default', 'highlighted', 'selected', 'disabled']),
|
|
27
|
+
variant: PropTypes.oneOf(['default', 'highlighted', 'selected', 'disabled', 'highlighted-disabled']),
|
|
28
28
|
role: PropTypes.string,
|
|
29
29
|
renderBeforeLabel: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
30
30
|
renderAfterLabel: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
@@ -32,8 +32,9 @@ const propTypes = {
|
|
|
32
32
|
afterLabelContentVAlign: PropTypes.oneOf(['start', 'center', 'end']),
|
|
33
33
|
description: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
34
34
|
descriptionRole: PropTypes.string,
|
|
35
|
+
href: PropTypes.string,
|
|
35
36
|
elementRef: PropTypes.func,
|
|
36
37
|
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func])
|
|
37
38
|
};
|
|
38
|
-
const allowedProps = ['as', 'variant', 'role', 'renderBeforeLabel', 'renderAfterLabel', 'beforeLabelContentVAlign', 'afterLabelContentVAlign', 'description', 'descriptionRole', 'elementRef', 'children'];
|
|
39
|
+
const allowedProps = ['as', 'variant', 'role', 'renderBeforeLabel', 'renderAfterLabel', 'beforeLabelContentVAlign', 'afterLabelContentVAlign', 'description', 'descriptionRole', 'href', 'elementRef', 'children'];
|
|
39
40
|
export { propTypes, allowedProps };
|
|
@@ -55,6 +55,12 @@ const generateStyle = (componentTheme, props) => {
|
|
|
55
55
|
cursor: 'not-allowed',
|
|
56
56
|
opacity: 0.5
|
|
57
57
|
},
|
|
58
|
+
['highlighted-disabled']: {
|
|
59
|
+
background: componentTheme.highlightedBackground,
|
|
60
|
+
color: componentTheme.highlightedLabelColor,
|
|
61
|
+
cursor: 'not-allowed',
|
|
62
|
+
opacity: 0.5
|
|
63
|
+
},
|
|
58
64
|
default: {}
|
|
59
65
|
};
|
|
60
66
|
|
|
@@ -78,6 +84,10 @@ const generateStyle = (componentTheme, props) => {
|
|
|
78
84
|
}[vAlign];
|
|
79
85
|
};
|
|
80
86
|
|
|
87
|
+
const linkStyles = {
|
|
88
|
+
textDecoration: 'none',
|
|
89
|
+
color: 'currentColor'
|
|
90
|
+
};
|
|
81
91
|
const transition = 'background 200ms';
|
|
82
92
|
return {
|
|
83
93
|
item: {
|
|
@@ -129,7 +139,14 @@ const generateStyle = (componentTheme, props) => {
|
|
|
129
139
|
...(hasContentBeforeLabel && hasContentAfterLabel && {
|
|
130
140
|
paddingInlineEnd: `calc(${componentTheme.iconPadding} * 2 + 1em)`,
|
|
131
141
|
paddingInlineStart: `calc(${componentTheme.iconPadding} * 2 + 1em)`
|
|
132
|
-
})
|
|
142
|
+
}),
|
|
143
|
+
// NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping)
|
|
144
|
+
'&:is(a)': {
|
|
145
|
+
'&, &:link, &:visited, &:active, &:hover, &:focus': linkStyles
|
|
146
|
+
},
|
|
147
|
+
'&:-webkit-any(a)': {
|
|
148
|
+
'&, &:link, &:visited, &:active, &:hover, &:focus': linkStyles
|
|
149
|
+
}
|
|
133
150
|
},
|
|
134
151
|
content: {
|
|
135
152
|
label: 'optionItem__content',
|
package/es/Options/Item/theme.js
CHANGED
|
@@ -51,7 +51,7 @@ const generateComponentTheme = theme => {
|
|
|
51
51
|
selectedBackground: colors === null || colors === void 0 ? void 0 : colors.backgroundDark,
|
|
52
52
|
padding: `${spacing === null || spacing === void 0 ? void 0 : spacing.xSmall} ${spacing === null || spacing === void 0 ? void 0 : spacing.small}`,
|
|
53
53
|
iconPadding: spacing === null || spacing === void 0 ? void 0 : spacing.small,
|
|
54
|
-
nestedPadding: spacing === null || spacing === void 0 ? void 0 : spacing.
|
|
54
|
+
nestedPadding: spacing === null || spacing === void 0 ? void 0 : spacing.small,
|
|
55
55
|
beforeLabelContentVOffset: '0.625rem',
|
|
56
56
|
afterLabelContentVOffset: '0.625rem',
|
|
57
57
|
descriptionFontSize: typography.fontSizeSmall,
|
package/es/Options/index.js
CHANGED
|
@@ -106,7 +106,7 @@ let Options = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyles, g
|
|
|
106
106
|
|
|
107
107
|
if (matchComponentTypes(child, ['Item', 'Separator'])) {
|
|
108
108
|
return safeCloneElement(child, {
|
|
109
|
-
as: this.childAs
|
|
109
|
+
as: this.childAs || child.props.as
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -135,7 +135,7 @@ let Options = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyles, g
|
|
|
135
135
|
margin: "none",
|
|
136
136
|
padding: "none",
|
|
137
137
|
background: "primary",
|
|
138
|
-
"aria-labelledby": renderLabel ? this._labelId : void 0
|
|
138
|
+
"aria-labelledby": renderLabel ? this._labelId : this.props['aria-labelledby'] ? this.props['aria-labelledby'] : void 0
|
|
139
139
|
}), this.renderChildren()));
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -35,6 +35,7 @@ var _default = {
|
|
|
35
35
|
propValues: {
|
|
36
36
|
renderAfterLabel: [null, _uiIcons.IconArrowOpenEndSolid],
|
|
37
37
|
renderBeforeLabel: [null, _uiIcons.IconCheckSolid],
|
|
38
|
+
href: [void 0, '/hello'],
|
|
38
39
|
description: [null, 'Curabitur fringilla, urna ut efficitur molestie, nibh lacus tincidunt elit, ut tempor ipsum nunc sit amet massa. Integer sit amet ante vitae lectus gravida pulvinar.']
|
|
39
40
|
},
|
|
40
41
|
getComponentProps: props => {
|
|
@@ -68,6 +69,10 @@ var _default = {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
if (props.href && (props.beforeLabelContentVAlign !== 'center' || props.afterLabelContentVAlign !== 'center' || props.description)) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
71
76
|
return false;
|
|
72
77
|
}
|
|
73
78
|
};
|
|
@@ -21,7 +21,7 @@ var _theme = _interopRequireDefault(require("./theme"));
|
|
|
21
21
|
|
|
22
22
|
var _props = require("./props");
|
|
23
23
|
|
|
24
|
-
var _dec, _dec2, _class, _class2, _temp;
|
|
24
|
+
var _dec, _dec2, _dec3, _class, _class2, _temp;
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
---
|
|
@@ -30,10 +30,12 @@ id: Options.Item
|
|
|
30
30
|
---
|
|
31
31
|
@tsProps
|
|
32
32
|
**/
|
|
33
|
-
let Item = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default),
|
|
34
|
-
constructor() {
|
|
35
|
-
super(
|
|
33
|
+
let Item = (_dec = (0, _uiReactUtils.withDeterministicId)(), _dec2 = (0, _emotion.withStyle)(_styles.default, _theme.default), _dec3 = (0, _uiTestable.testable)(), _dec(_class = _dec2(_class = _dec3(_class = (_temp = _class2 = class Item extends _react.Component {
|
|
34
|
+
constructor(props) {
|
|
35
|
+
super(props);
|
|
36
36
|
this.ref = null;
|
|
37
|
+
this._descriptionId = void 0;
|
|
38
|
+
this._descriptionId = props.deterministicId('OptionsItem-description');
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
componentDidMount() {
|
|
@@ -70,6 +72,7 @@ let Item = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default), _de
|
|
|
70
72
|
render() {
|
|
71
73
|
const _this$props4 = this.props,
|
|
72
74
|
as = _this$props4.as,
|
|
75
|
+
href = _this$props4.href,
|
|
73
76
|
role = _this$props4.role,
|
|
74
77
|
styles = _this$props4.styles,
|
|
75
78
|
description = _this$props4.description,
|
|
@@ -79,6 +82,7 @@ let Item = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default), _de
|
|
|
79
82
|
elementRef = _this$props4.elementRef,
|
|
80
83
|
children = _this$props4.children;
|
|
81
84
|
const ElementType = (0, _uiReactUtils.getElementType)(Item, this.props, () => as);
|
|
85
|
+
const InnerElementType = href ? 'a' : 'span';
|
|
82
86
|
const passthroughProps = (0, _uiReactUtils.omitProps)(this.props, Item.allowedProps);
|
|
83
87
|
const childrenContent = (0, _uiReactUtils.callRenderProp)(children);
|
|
84
88
|
const descriptionContent = (0, _uiReactUtils.callRenderProp)(description);
|
|
@@ -92,12 +96,15 @@ let Item = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default), _de
|
|
|
92
96
|
elementRef(element);
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
|
-
}, (0, _emotion.jsx)(
|
|
99
|
+
}, (0, _emotion.jsx)(InnerElementType, Object.assign({}, passthroughProps, {
|
|
96
100
|
css: styles === null || styles === void 0 ? void 0 : styles.container,
|
|
97
|
-
role: role
|
|
101
|
+
role: href ? void 0 : role,
|
|
102
|
+
href: href,
|
|
103
|
+
"aria-describedby": this.props['aria-describedby'] || (descriptionContent ? this._descriptionId : void 0)
|
|
98
104
|
}), childrenContent, descriptionContent && (0, _emotion.jsx)("span", {
|
|
99
105
|
css: styles === null || styles === void 0 ? void 0 : styles.description,
|
|
100
|
-
role: descriptionRole
|
|
106
|
+
role: descriptionRole,
|
|
107
|
+
id: this._descriptionId
|
|
101
108
|
}, descriptionContent)), renderBeforeLabel && this.renderContent(renderBeforeLabel, styles === null || styles === void 0 ? void 0 : styles.contentBefore), renderAfterLabel && this.renderContent(renderAfterLabel, styles === null || styles === void 0 ? void 0 : styles.contentAfter));
|
|
102
109
|
}
|
|
103
110
|
|
|
@@ -108,7 +115,7 @@ let Item = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default), _de
|
|
|
108
115
|
descriptionRole: 'note',
|
|
109
116
|
beforeLabelContentVAlign: 'center',
|
|
110
117
|
afterLabelContentVAlign: 'center'
|
|
111
|
-
}, _temp)) || _class) || _class);
|
|
118
|
+
}, _temp)) || _class) || _class) || _class);
|
|
112
119
|
exports.Item = Item;
|
|
113
120
|
var _default = Item;
|
|
114
121
|
exports.default = _default;
|
|
@@ -34,7 +34,7 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
|
34
34
|
*/
|
|
35
35
|
const propTypes = {
|
|
36
36
|
as: _propTypes.default.elementType,
|
|
37
|
-
variant: _propTypes.default.oneOf(['default', 'highlighted', 'selected', 'disabled']),
|
|
37
|
+
variant: _propTypes.default.oneOf(['default', 'highlighted', 'selected', 'disabled', 'highlighted-disabled']),
|
|
38
38
|
role: _propTypes.default.string,
|
|
39
39
|
renderBeforeLabel: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
|
|
40
40
|
renderAfterLabel: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
|
|
@@ -42,9 +42,10 @@ const propTypes = {
|
|
|
42
42
|
afterLabelContentVAlign: _propTypes.default.oneOf(['start', 'center', 'end']),
|
|
43
43
|
description: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
|
|
44
44
|
descriptionRole: _propTypes.default.string,
|
|
45
|
+
href: _propTypes.default.string,
|
|
45
46
|
elementRef: _propTypes.default.func,
|
|
46
47
|
children: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func])
|
|
47
48
|
};
|
|
48
49
|
exports.propTypes = propTypes;
|
|
49
|
-
const allowedProps = ['as', 'variant', 'role', 'renderBeforeLabel', 'renderAfterLabel', 'beforeLabelContentVAlign', 'afterLabelContentVAlign', 'description', 'descriptionRole', 'elementRef', 'children'];
|
|
50
|
+
const allowedProps = ['as', 'variant', 'role', 'renderBeforeLabel', 'renderAfterLabel', 'beforeLabelContentVAlign', 'afterLabelContentVAlign', 'description', 'descriptionRole', 'href', 'elementRef', 'children'];
|
|
50
51
|
exports.allowedProps = allowedProps;
|
|
@@ -63,6 +63,12 @@ const generateStyle = (componentTheme, props) => {
|
|
|
63
63
|
cursor: 'not-allowed',
|
|
64
64
|
opacity: 0.5
|
|
65
65
|
},
|
|
66
|
+
['highlighted-disabled']: {
|
|
67
|
+
background: componentTheme.highlightedBackground,
|
|
68
|
+
color: componentTheme.highlightedLabelColor,
|
|
69
|
+
cursor: 'not-allowed',
|
|
70
|
+
opacity: 0.5
|
|
71
|
+
},
|
|
66
72
|
default: {}
|
|
67
73
|
};
|
|
68
74
|
|
|
@@ -86,6 +92,10 @@ const generateStyle = (componentTheme, props) => {
|
|
|
86
92
|
}[vAlign];
|
|
87
93
|
};
|
|
88
94
|
|
|
95
|
+
const linkStyles = {
|
|
96
|
+
textDecoration: 'none',
|
|
97
|
+
color: 'currentColor'
|
|
98
|
+
};
|
|
89
99
|
const transition = 'background 200ms';
|
|
90
100
|
return {
|
|
91
101
|
item: {
|
|
@@ -137,7 +147,14 @@ const generateStyle = (componentTheme, props) => {
|
|
|
137
147
|
...(hasContentBeforeLabel && hasContentAfterLabel && {
|
|
138
148
|
paddingInlineEnd: `calc(${componentTheme.iconPadding} * 2 + 1em)`,
|
|
139
149
|
paddingInlineStart: `calc(${componentTheme.iconPadding} * 2 + 1em)`
|
|
140
|
-
})
|
|
150
|
+
}),
|
|
151
|
+
// NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping)
|
|
152
|
+
'&:is(a)': {
|
|
153
|
+
'&, &:link, &:visited, &:active, &:hover, &:focus': linkStyles
|
|
154
|
+
},
|
|
155
|
+
'&:-webkit-any(a)': {
|
|
156
|
+
'&, &:link, &:visited, &:active, &:hover, &:focus': linkStyles
|
|
157
|
+
}
|
|
141
158
|
},
|
|
142
159
|
content: {
|
|
143
160
|
label: 'optionItem__content',
|
|
@@ -58,7 +58,7 @@ const generateComponentTheme = theme => {
|
|
|
58
58
|
selectedBackground: colors === null || colors === void 0 ? void 0 : colors.backgroundDark,
|
|
59
59
|
padding: `${spacing === null || spacing === void 0 ? void 0 : spacing.xSmall} ${spacing === null || spacing === void 0 ? void 0 : spacing.small}`,
|
|
60
60
|
iconPadding: spacing === null || spacing === void 0 ? void 0 : spacing.small,
|
|
61
|
-
nestedPadding: spacing === null || spacing === void 0 ? void 0 : spacing.
|
|
61
|
+
nestedPadding: spacing === null || spacing === void 0 ? void 0 : spacing.small,
|
|
62
62
|
beforeLabelContentVOffset: '0.625rem',
|
|
63
63
|
afterLabelContentVOffset: '0.625rem',
|
|
64
64
|
descriptionFontSize: typography.fontSizeSmall,
|
package/lib/Options/index.js
CHANGED
|
@@ -101,7 +101,7 @@ let Options = (_dec = (0, _uiReactUtils.withDeterministicId)(), _dec2 = (0, _emo
|
|
|
101
101
|
|
|
102
102
|
if ((0, _uiReactUtils.matchComponentTypes)(child, ['Item', 'Separator'])) {
|
|
103
103
|
return (0, _uiReactUtils.safeCloneElement)(child, {
|
|
104
|
-
as: this.childAs
|
|
104
|
+
as: this.childAs || child.props.as
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -131,7 +131,7 @@ let Options = (_dec = (0, _uiReactUtils.withDeterministicId)(), _dec2 = (0, _emo
|
|
|
131
131
|
margin: "none",
|
|
132
132
|
padding: "none",
|
|
133
133
|
background: "primary",
|
|
134
|
-
"aria-labelledby": renderLabel ? this._labelId : void 0
|
|
134
|
+
"aria-labelledby": renderLabel ? this._labelId : this.props['aria-labelledby'] ? this.props['aria-labelledby'] : void 0
|
|
135
135
|
}), this.renderChildren()));
|
|
136
136
|
}
|
|
137
137
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instructure/ui-options",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.20.0",
|
|
4
4
|
"description": "A view-only component for composing interactive lists and menus.",
|
|
5
5
|
"author": "Instructure, Inc. Engineering and Product Design",
|
|
6
6
|
"module": "./es/index.js",
|
|
@@ -23,21 +23,21 @@
|
|
|
23
23
|
},
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@instructure/ui-babel-preset": "8.
|
|
27
|
-
"@instructure/ui-color-utils": "8.
|
|
28
|
-
"@instructure/ui-test-locator": "8.
|
|
29
|
-
"@instructure/ui-test-utils": "8.
|
|
30
|
-
"@instructure/ui-themes": "8.
|
|
26
|
+
"@instructure/ui-babel-preset": "8.20.0",
|
|
27
|
+
"@instructure/ui-color-utils": "8.20.0",
|
|
28
|
+
"@instructure/ui-test-locator": "8.20.0",
|
|
29
|
+
"@instructure/ui-test-utils": "8.20.0",
|
|
30
|
+
"@instructure/ui-themes": "8.20.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@babel/runtime": "^7.13.10",
|
|
34
|
-
"@instructure/emotion": "8.
|
|
35
|
-
"@instructure/shared-types": "8.
|
|
36
|
-
"@instructure/ui-icons": "8.
|
|
37
|
-
"@instructure/ui-prop-types": "8.
|
|
38
|
-
"@instructure/ui-react-utils": "8.
|
|
39
|
-
"@instructure/ui-testable": "8.
|
|
40
|
-
"@instructure/ui-view": "8.
|
|
34
|
+
"@instructure/emotion": "8.20.0",
|
|
35
|
+
"@instructure/shared-types": "8.20.0",
|
|
36
|
+
"@instructure/ui-icons": "8.20.0",
|
|
37
|
+
"@instructure/ui-prop-types": "8.20.0",
|
|
38
|
+
"@instructure/ui-react-utils": "8.20.0",
|
|
39
|
+
"@instructure/ui-testable": "8.20.0",
|
|
40
|
+
"@instructure/ui-view": "8.20.0",
|
|
41
41
|
"prop-types": "^15"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
@@ -46,6 +46,5 @@
|
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
|
-
"sideEffects": false
|
|
50
|
-
"gitHead": "8648faa3b9f006a729a4d13195dd9c28e23d1335"
|
|
49
|
+
"sideEffects": false
|
|
51
50
|
}
|
|
@@ -31,6 +31,7 @@ export default {
|
|
|
31
31
|
propValues: {
|
|
32
32
|
renderAfterLabel: [null, IconArrowOpenEndSolid],
|
|
33
33
|
renderBeforeLabel: [null, IconCheckSolid],
|
|
34
|
+
href: [undefined, '/hello'],
|
|
34
35
|
description: [
|
|
35
36
|
null,
|
|
36
37
|
'Curabitur fringilla, urna ut efficitur molestie, nibh lacus tincidunt elit, ut tempor ipsum nunc sit amet massa. Integer sit amet ante vitae lectus gravida pulvinar.'
|
|
@@ -76,6 +77,15 @@ export default {
|
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
if (
|
|
81
|
+
props.href &&
|
|
82
|
+
(props.beforeLabelContentVAlign !== 'center' ||
|
|
83
|
+
props.afterLabelContentVAlign !== 'center' ||
|
|
84
|
+
props.description)
|
|
85
|
+
) {
|
|
86
|
+
return true
|
|
87
|
+
}
|
|
88
|
+
|
|
79
89
|
return false
|
|
80
90
|
}
|
|
81
91
|
} as StoryConfig<OptionsItemProps>
|
|
@@ -28,7 +28,8 @@ import { Component } from 'react'
|
|
|
28
28
|
import {
|
|
29
29
|
omitProps,
|
|
30
30
|
getElementType,
|
|
31
|
-
callRenderProp
|
|
31
|
+
callRenderProp,
|
|
32
|
+
withDeterministicId
|
|
32
33
|
} from '@instructure/ui-react-utils'
|
|
33
34
|
import { testable } from '@instructure/ui-testable'
|
|
34
35
|
|
|
@@ -46,6 +47,7 @@ id: Options.Item
|
|
|
46
47
|
---
|
|
47
48
|
@tsProps
|
|
48
49
|
**/
|
|
50
|
+
@withDeterministicId()
|
|
49
51
|
@withStyle(generateStyles, generateComponentTheme)
|
|
50
52
|
@testable()
|
|
51
53
|
class Item extends Component<OptionsItemProps> {
|
|
@@ -65,6 +67,14 @@ class Item extends Component<OptionsItemProps> {
|
|
|
65
67
|
|
|
66
68
|
ref: Element | null = null
|
|
67
69
|
|
|
70
|
+
private readonly _descriptionId: string
|
|
71
|
+
|
|
72
|
+
constructor(props: OptionsItemProps) {
|
|
73
|
+
super(props)
|
|
74
|
+
|
|
75
|
+
this._descriptionId = props.deterministicId!('OptionsItem-description')
|
|
76
|
+
}
|
|
77
|
+
|
|
68
78
|
componentDidMount() {
|
|
69
79
|
this.props.makeStyles?.()
|
|
70
80
|
}
|
|
@@ -102,6 +112,7 @@ class Item extends Component<OptionsItemProps> {
|
|
|
102
112
|
render() {
|
|
103
113
|
const {
|
|
104
114
|
as,
|
|
115
|
+
href,
|
|
105
116
|
role,
|
|
106
117
|
styles,
|
|
107
118
|
description,
|
|
@@ -113,6 +124,9 @@ class Item extends Component<OptionsItemProps> {
|
|
|
113
124
|
} = this.props
|
|
114
125
|
|
|
115
126
|
const ElementType = getElementType(Item, this.props, () => as!)
|
|
127
|
+
|
|
128
|
+
const InnerElementType = href ? 'a' : 'span'
|
|
129
|
+
|
|
116
130
|
const passthroughProps = omitProps(this.props, Item.allowedProps)
|
|
117
131
|
|
|
118
132
|
const childrenContent = callRenderProp(children)
|
|
@@ -131,14 +145,27 @@ class Item extends Component<OptionsItemProps> {
|
|
|
131
145
|
}
|
|
132
146
|
}}
|
|
133
147
|
>
|
|
134
|
-
<
|
|
148
|
+
<InnerElementType
|
|
149
|
+
{...passthroughProps}
|
|
150
|
+
css={styles?.container}
|
|
151
|
+
role={href ? undefined : role}
|
|
152
|
+
href={href}
|
|
153
|
+
aria-describedby={
|
|
154
|
+
this.props['aria-describedby'] ||
|
|
155
|
+
(descriptionContent ? this._descriptionId : undefined)
|
|
156
|
+
}
|
|
157
|
+
>
|
|
135
158
|
{childrenContent}
|
|
136
159
|
{descriptionContent && (
|
|
137
|
-
<span
|
|
160
|
+
<span
|
|
161
|
+
css={styles?.description}
|
|
162
|
+
role={descriptionRole}
|
|
163
|
+
id={this._descriptionId}
|
|
164
|
+
>
|
|
138
165
|
{descriptionContent}
|
|
139
166
|
</span>
|
|
140
167
|
)}
|
|
141
|
-
</
|
|
168
|
+
</InnerElementType>
|
|
142
169
|
{renderBeforeLabel &&
|
|
143
170
|
this.renderContent(renderBeforeLabel, styles?.contentBefore)}
|
|
144
171
|
{renderAfterLabel &&
|
|
@@ -31,18 +31,24 @@ import type {
|
|
|
31
31
|
OptionsItemTheme,
|
|
32
32
|
OtherHTMLAttributes
|
|
33
33
|
} from '@instructure/shared-types'
|
|
34
|
+
import type { WithDeterministicIdProps } from '@instructure/ui-react-utils'
|
|
34
35
|
import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
|
|
35
36
|
|
|
36
37
|
type ItemProps = {
|
|
37
38
|
children?: React.ReactNode | (() => React.ReactNode)
|
|
38
39
|
/**
|
|
39
|
-
* Element type to render as
|
|
40
|
+
* Element type to render as. Will be set to `<a>` if href is provided.
|
|
40
41
|
*/
|
|
41
42
|
as?: AsElementType
|
|
42
43
|
/**
|
|
43
44
|
* The style variant of the item
|
|
44
45
|
*/
|
|
45
|
-
variant?:
|
|
46
|
+
variant?:
|
|
47
|
+
| 'default'
|
|
48
|
+
| 'highlighted'
|
|
49
|
+
| 'selected'
|
|
50
|
+
| 'disabled'
|
|
51
|
+
| 'highlighted-disabled'
|
|
46
52
|
/**
|
|
47
53
|
* The ARIA role of the element
|
|
48
54
|
*/
|
|
@@ -76,6 +82,10 @@ type OptionsItemOwnProps = ItemProps & {
|
|
|
76
82
|
* The ARIA role of the description element
|
|
77
83
|
*/
|
|
78
84
|
descriptionRole?: string
|
|
85
|
+
/**
|
|
86
|
+
* Providing href will render the option as `<a>`.
|
|
87
|
+
*/
|
|
88
|
+
href?: string
|
|
79
89
|
/**
|
|
80
90
|
* provides a reference to the underlying html root element
|
|
81
91
|
*/
|
|
@@ -88,6 +98,7 @@ type AllowedPropKeys = Readonly<Array<PropKeys>>
|
|
|
88
98
|
|
|
89
99
|
type OptionsItemProps = OptionsItemOwnProps &
|
|
90
100
|
WithStyleProps<OptionsItemTheme, OptionsItemStyle> &
|
|
101
|
+
WithDeterministicIdProps &
|
|
91
102
|
OtherHTMLAttributes<OptionsItemOwnProps>
|
|
92
103
|
|
|
93
104
|
type OptionsItemStyle = ComponentStyle<
|
|
@@ -101,7 +112,13 @@ type OptionsItemStyle = ComponentStyle<
|
|
|
101
112
|
|
|
102
113
|
const propTypes: PropValidators<PropKeys> = {
|
|
103
114
|
as: PropTypes.elementType,
|
|
104
|
-
variant: PropTypes.oneOf([
|
|
115
|
+
variant: PropTypes.oneOf([
|
|
116
|
+
'default',
|
|
117
|
+
'highlighted',
|
|
118
|
+
'selected',
|
|
119
|
+
'disabled',
|
|
120
|
+
'highlighted-disabled'
|
|
121
|
+
]),
|
|
105
122
|
role: PropTypes.string,
|
|
106
123
|
renderBeforeLabel: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
107
124
|
renderAfterLabel: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
@@ -109,6 +126,7 @@ const propTypes: PropValidators<PropKeys> = {
|
|
|
109
126
|
afterLabelContentVAlign: PropTypes.oneOf(['start', 'center', 'end']),
|
|
110
127
|
description: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
111
128
|
descriptionRole: PropTypes.string,
|
|
129
|
+
href: PropTypes.string,
|
|
112
130
|
elementRef: PropTypes.func,
|
|
113
131
|
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func])
|
|
114
132
|
}
|
|
@@ -123,6 +141,7 @@ const allowedProps: AllowedPropKeys = [
|
|
|
123
141
|
'afterLabelContentVAlign',
|
|
124
142
|
'description',
|
|
125
143
|
'descriptionRole',
|
|
144
|
+
'href',
|
|
126
145
|
'elementRef',
|
|
127
146
|
'children'
|
|
128
147
|
]
|
|
@@ -63,6 +63,12 @@ const generateStyle = (
|
|
|
63
63
|
color: componentTheme.highlightedLabelColor
|
|
64
64
|
},
|
|
65
65
|
disabled: { cursor: 'not-allowed', opacity: 0.5 },
|
|
66
|
+
['highlighted-disabled']: {
|
|
67
|
+
background: componentTheme.highlightedBackground,
|
|
68
|
+
color: componentTheme.highlightedLabelColor,
|
|
69
|
+
cursor: 'not-allowed',
|
|
70
|
+
opacity: 0.5
|
|
71
|
+
},
|
|
66
72
|
default: {}
|
|
67
73
|
}
|
|
68
74
|
|
|
@@ -92,6 +98,8 @@ const generateStyle = (
|
|
|
92
98
|
}[vAlign!]
|
|
93
99
|
}
|
|
94
100
|
|
|
101
|
+
const linkStyles = { textDecoration: 'none', color: 'currentColor' }
|
|
102
|
+
|
|
95
103
|
const transition = 'background 200ms'
|
|
96
104
|
|
|
97
105
|
return {
|
|
@@ -143,7 +151,15 @@ const generateStyle = (
|
|
|
143
151
|
hasContentAfterLabel && {
|
|
144
152
|
paddingInlineEnd: `calc(${componentTheme.iconPadding} * 2 + 1em)`,
|
|
145
153
|
paddingInlineStart: `calc(${componentTheme.iconPadding} * 2 + 1em)`
|
|
146
|
-
})
|
|
154
|
+
}),
|
|
155
|
+
|
|
156
|
+
// NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping)
|
|
157
|
+
'&:is(a)': {
|
|
158
|
+
'&, &:link, &:visited, &:active, &:hover, &:focus': linkStyles
|
|
159
|
+
},
|
|
160
|
+
'&:-webkit-any(a)': {
|
|
161
|
+
'&, &:link, &:visited, &:active, &:hover, &:focus': linkStyles
|
|
162
|
+
}
|
|
147
163
|
},
|
|
148
164
|
content: {
|
|
149
165
|
label: 'optionItem__content',
|
|
@@ -55,7 +55,7 @@ const generateComponentTheme = (theme: Theme): OptionsItemTheme => {
|
|
|
55
55
|
|
|
56
56
|
padding: `${spacing?.xSmall} ${spacing?.small}`,
|
|
57
57
|
iconPadding: spacing?.small,
|
|
58
|
-
nestedPadding: spacing?.
|
|
58
|
+
nestedPadding: spacing?.small,
|
|
59
59
|
|
|
60
60
|
beforeLabelContentVOffset: '0.625rem',
|
|
61
61
|
afterLabelContentVOffset: '0.625rem',
|