@itwin/itwinui-react 3.4.1 → 3.5.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 +24 -0
- package/cjs/core/ProgressIndicators/ProgressLinear.js +6 -1
- package/cjs/core/ProgressIndicators/ProgressRadial.js +8 -3
- package/cjs/core/Select/Select.d.ts +3 -1
- package/cjs/core/Select/Select.js +1 -1
- package/cjs/core/ToggleSwitch/ToggleSwitch.d.ts +4 -2
- package/cjs/core/ToggleSwitch/ToggleSwitch.js +5 -11
- package/cjs/core/Typography/Anchor.d.ts +21 -1
- package/cjs/core/Typography/Anchor.js +38 -3
- package/cjs/core/VisuallyHidden/VisuallyHidden.js +19 -3
- package/cjs/core/utils/components/ShadowRoot.d.ts +2 -1
- package/cjs/core/utils/components/ShadowRoot.js +19 -4
- package/cjs/core/utils/functions/polymorphic.d.ts +5 -3
- package/cjs/core/utils/functions/polymorphic.js +20 -5
- package/cjs/core/utils/icons/Svg.js +5 -1
- package/esm/core/ProgressIndicators/ProgressLinear.js +7 -2
- package/esm/core/ProgressIndicators/ProgressRadial.js +9 -4
- package/esm/core/Select/Select.d.ts +3 -1
- package/esm/core/Select/Select.js +1 -1
- package/esm/core/ToggleSwitch/ToggleSwitch.d.ts +4 -2
- package/esm/core/ToggleSwitch/ToggleSwitch.js +6 -12
- package/esm/core/Typography/Anchor.d.ts +21 -1
- package/esm/core/Typography/Anchor.js +11 -2
- package/esm/core/VisuallyHidden/VisuallyHidden.js +19 -3
- package/esm/core/utils/components/ShadowRoot.d.ts +2 -1
- package/esm/core/utils/components/ShadowRoot.js +19 -4
- package/esm/core/utils/functions/polymorphic.d.ts +5 -3
- package/esm/core/utils/functions/polymorphic.js +20 -5
- package/esm/core/utils/icons/Svg.js +5 -1
- package/package.json +4 -4
- package/styles.css +34 -33
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1844](https://github.com/iTwin/iTwinUI/pull/1844): Interactive elements will now be correctly focused on Safari 17+.
|
|
8
|
+
- [#1860](https://github.com/iTwin/iTwinUI/pull/1860): `ThemeProvider` will now automatically specify an `accent-color` to match the current theme.
|
|
9
|
+
- [#1856](https://github.com/iTwin/iTwinUI/pull/1856): Added new `isExternal` prop to `Anchor`. When true, displays an icon at the end of link text.
|
|
10
|
+
- [#1858](https://github.com/iTwin/iTwinUI/pull/1858): `ToggleSwitch` will now show a checkmark icon by default in the checked state. `SvgCheckmark` no longer needs to be manually passed into the `icon` prop.
|
|
11
|
+
- [#1862](https://github.com/iTwin/iTwinUI/pull/1862): `Select` will now correctly reset its `value` if `null` is passed.
|
|
12
|
+
- [#1864](https://github.com/iTwin/iTwinUI/pull/1864): Added a new `underline` prop to `Anchor`. When true, anchors will be underlined by default instead of only on hover.
|
|
13
|
+
- [#1856](https://github.com/iTwin/iTwinUI/pull/1856): `Anchor` links that open in a new tab will now add a visually-hidden warning for screen-reader users. This can be combined with the `isExternal` prop, which adds a visual indication for sighted users.
|
|
14
|
+
- [#1859](https://github.com/iTwin/iTwinUI/pull/1859): `ProgressRadial` and `ProgressLinear` will now include a visually hidden "Loading" text alternative for non-sighted users.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- [#1845](https://github.com/iTwin/iTwinUI/pull/1845): Removed `:focus-visible` fallback styles for older browsers.
|
|
19
|
+
- [#1861](https://github.com/iTwin/iTwinUI/pull/1861): Added `width`/`height` attributes to inlined svgs, to make them more resilient in case CSS fails.
|
|
20
|
+
|
|
21
|
+
## 3.4.2
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- [#1848](https://github.com/iTwin/iTwinUI/pull/1848): Removed `jsdom` from direct dependencies.
|
|
26
|
+
|
|
3
27
|
## 3.4.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
|
@@ -34,6 +34,7 @@ exports.ProgressLinear = void 0;
|
|
|
34
34
|
const React = __importStar(require("react"));
|
|
35
35
|
const classnames_1 = __importDefault(require("classnames"));
|
|
36
36
|
const index_js_1 = require("../utils/index.js");
|
|
37
|
+
const VisuallyHidden_js_1 = require("../VisuallyHidden/VisuallyHidden.js");
|
|
37
38
|
/**
|
|
38
39
|
* Shows progress on a linear bar
|
|
39
40
|
* @example
|
|
@@ -62,5 +63,9 @@ exports.ProgressLinear = React.forwardRef((props, forwardedRef) => {
|
|
|
62
63
|
const boundedValue = (0, index_js_1.getBoundedValue)(value ?? 100, 0, 100);
|
|
63
64
|
return (React.createElement(index_js_1.Box, { className: (0, classnames_1.default)('iui-progress-indicator-linear', className), ref: forwardedRef, "data-iui-status": status, "data-iui-indeterminate": indeterminate ? 'true' : undefined, "data-iui-animated": isAnimated ? 'true' : undefined, style: {
|
|
64
65
|
'--iui-progress-percentage': `${boundedValue}%`,
|
|
65
|
-
}, ...rest },
|
|
66
|
+
}, ...rest },
|
|
67
|
+
React.createElement(index_js_1.ShadowRoot, null,
|
|
68
|
+
value !== 100 && React.createElement(VisuallyHidden_js_1.VisuallyHidden, null, "Loading."),
|
|
69
|
+
React.createElement("slot", null)),
|
|
70
|
+
labels.length > 0 && (React.createElement(index_js_1.Box, { as: 'div', ...labelGroupProps, className: (0, classnames_1.default)('iui-progress-indicator-linear-label', labelGroupProps?.className) }, labels.map((label, index) => (React.createElement("span", { key: index }, label)))))));
|
|
66
71
|
});
|
|
@@ -34,6 +34,7 @@ exports.ProgressRadial = void 0;
|
|
|
34
34
|
const classnames_1 = __importDefault(require("classnames"));
|
|
35
35
|
const React = __importStar(require("react"));
|
|
36
36
|
const index_js_1 = require("../utils/index.js");
|
|
37
|
+
const VisuallyHidden_js_1 = require("../VisuallyHidden/VisuallyHidden.js");
|
|
37
38
|
/**
|
|
38
39
|
* Circular Progress Indicator
|
|
39
40
|
* @example
|
|
@@ -62,7 +63,11 @@ exports.ProgressRadial = React.forwardRef((props, forwardedRef) => {
|
|
|
62
63
|
'--iui-progress-percentage': `${(0, index_js_1.getBoundedValue)(value, 0, 100)}%`,
|
|
63
64
|
}),
|
|
64
65
|
...style,
|
|
65
|
-
}, ...rest },
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
}, ...rest },
|
|
67
|
+
React.createElement(index_js_1.ShadowRoot, null,
|
|
68
|
+
value !== 100 && React.createElement(VisuallyHidden_js_1.VisuallyHidden, null, "Loading."),
|
|
69
|
+
React.createElement("slot", null)),
|
|
70
|
+
size !== 'x-small'
|
|
71
|
+
? children ?? (!!status ? statusMap[status] : null)
|
|
72
|
+
: null));
|
|
68
73
|
});
|
|
@@ -64,8 +64,10 @@ export type SelectMultipleTypeProps<T> = {
|
|
|
64
64
|
/**
|
|
65
65
|
* Selected option value.
|
|
66
66
|
* If `multiple` is enabled, it is an array of values.
|
|
67
|
+
*
|
|
68
|
+
* Pass `null` to reset the value.
|
|
67
69
|
*/
|
|
68
|
-
value?: T;
|
|
70
|
+
value?: T | null;
|
|
69
71
|
/**
|
|
70
72
|
* Callback function handling change event on select.
|
|
71
73
|
*/
|
|
@@ -102,7 +102,7 @@ exports.Select = React.forwardRef((props, forwardedRef) => {
|
|
|
102
102
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
103
103
|
const [liveRegionSelection, setLiveRegionSelection] = React.useState('');
|
|
104
104
|
const [uncontrolledValue, setUncontrolledValue] = React.useState();
|
|
105
|
-
const value = valueProp
|
|
105
|
+
const value = valueProp !== undefined ? valueProp : uncontrolledValue;
|
|
106
106
|
const onChangeRef = (0, index_js_1.useLatestRef)(onChangeProp);
|
|
107
107
|
const selectRef = React.useRef(null);
|
|
108
108
|
const show = React.useCallback(() => {
|
|
@@ -17,9 +17,11 @@ type ToggleSwitchProps = {
|
|
|
17
17
|
*/
|
|
18
18
|
size?: 'default';
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Custom icon inside the toggle switch. Shown only when toggle is checked and size is not small.
|
|
21
|
+
*
|
|
22
|
+
* Will override the default checkmark icon.
|
|
21
23
|
*/
|
|
22
|
-
icon?: JSX.Element;
|
|
24
|
+
icon?: JSX.Element | null;
|
|
23
25
|
} | {
|
|
24
26
|
size: 'small';
|
|
25
27
|
icon?: never;
|
|
@@ -53,21 +53,15 @@ const index_js_1 = require("../utils/index.js");
|
|
|
53
53
|
* <ToggleSwitch label='With icon toggle' icon={<svg viewBox='0 0 16 16'><path d='M1 1v14h14V1H1zm13 1.7v10.6L8.7 8 14 2.7zM8 7.3L2.7 2h10.6L8 7.3zm-.7.7L2 13.3V2.7L7.3 8zm.7.7l5.3 5.3H2.7L8 8.7z' /></svg>} />
|
|
54
54
|
*/
|
|
55
55
|
exports.ToggleSwitch = React.forwardRef((props, ref) => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
props = { ...props };
|
|
60
|
-
delete props.icon;
|
|
61
|
-
}
|
|
62
|
-
const { disabled = false, labelPosition = 'right', label, className, style, size = 'default', ...rest } = props;
|
|
63
|
-
const inputElementRef = React.useRef(null);
|
|
64
|
-
const refs = (0, index_js_1.useMergedRefs)(inputElementRef, ref);
|
|
56
|
+
const { disabled = false, labelPosition = 'right', label, className, style, size = 'default', icon: iconProp, ...rest } = props;
|
|
57
|
+
// Disallow custom icon for small size, but keep the default checkmark when prop is not passed.
|
|
58
|
+
const shouldShowIcon = iconProp === undefined || (iconProp !== null && size !== 'small');
|
|
65
59
|
return (React.createElement(index_js_1.Box, { as: label ? 'label' : 'div', className: (0, classnames_1.default)('iui-toggle-switch-wrapper', {
|
|
66
60
|
'iui-disabled': disabled,
|
|
67
61
|
'iui-label-on-right': label && labelPosition === 'right',
|
|
68
62
|
'iui-label-on-left': label && labelPosition === 'left',
|
|
69
63
|
}, className), "data-iui-size": size, style: style },
|
|
70
|
-
React.createElement(index_js_1.Box, { as: 'input', className: 'iui-toggle-switch', type: 'checkbox', role: 'switch', disabled: disabled, ref:
|
|
71
|
-
|
|
64
|
+
React.createElement(index_js_1.Box, { as: 'input', className: 'iui-toggle-switch', type: 'checkbox', role: 'switch', disabled: disabled, ref: ref, ...rest }),
|
|
65
|
+
shouldShowIcon && (React.createElement(index_js_1.Box, { as: 'span', className: 'iui-toggle-switch-icon', "aria-hidden": true }, iconProp || React.createElement(index_js_1.SvgCheckmark, null))),
|
|
72
66
|
label && (React.createElement(index_js_1.Box, { as: 'span', className: 'iui-toggle-switch-label' }, label))));
|
|
73
67
|
});
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
import type { PolymorphicForwardRefComponent } from '../utils/index.js';
|
|
2
|
+
type AnchorProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the anchor links to an external site.
|
|
5
|
+
*
|
|
6
|
+
* When true, there will be an icon added at the end of the anchor text. This is useful
|
|
7
|
+
* to indicate that the link will open in a new tab.
|
|
8
|
+
*
|
|
9
|
+
* Not all external links should open in a new tab, so this prop should be used with caution.
|
|
10
|
+
*/
|
|
11
|
+
isExternal?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the anchor should be underlined in its idle state.
|
|
14
|
+
*
|
|
15
|
+
* By default, the anchor is underlined only on hover, or when using a high-contrast theme.
|
|
16
|
+
*/
|
|
17
|
+
underline?: boolean;
|
|
18
|
+
};
|
|
1
19
|
/**
|
|
2
20
|
* A consistently styled anchor component.
|
|
3
21
|
*
|
|
@@ -7,9 +25,11 @@
|
|
|
7
25
|
* @example
|
|
8
26
|
* <Anchor href='/'>Home</Anchor>
|
|
9
27
|
* <Anchor href='/projects'>Projects</Anchor>
|
|
28
|
+
* <Anchor href='/help' underline>Help</Anchor>
|
|
10
29
|
*
|
|
11
30
|
* @example
|
|
12
31
|
* <Anchor as={Link} to='/'>Home</Anchor>
|
|
13
32
|
* <Anchor as='button' onClick={() => {}}>click me</Anchor>
|
|
14
33
|
*/
|
|
15
|
-
export declare const Anchor:
|
|
34
|
+
export declare const Anchor: PolymorphicForwardRefComponent<"a", AnchorProps>;
|
|
35
|
+
export {};
|
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Anchor = void 0;
|
|
4
2
|
/*---------------------------------------------------------------------------------------------
|
|
5
3
|
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
6
4
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
7
5
|
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
23
|
+
if (mod && mod.__esModule) return mod;
|
|
24
|
+
var result = {};
|
|
25
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
26
|
+
__setModuleDefault(result, mod);
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
30
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
31
|
+
};
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.Anchor = void 0;
|
|
34
|
+
const React = __importStar(require("react"));
|
|
35
|
+
const classnames_1 = __importDefault(require("classnames"));
|
|
8
36
|
const index_js_1 = require("../utils/index.js");
|
|
37
|
+
const VisuallyHidden_js_1 = require("../VisuallyHidden/VisuallyHidden.js");
|
|
9
38
|
/**
|
|
10
39
|
* A consistently styled anchor component.
|
|
11
40
|
*
|
|
@@ -15,9 +44,15 @@ const index_js_1 = require("../utils/index.js");
|
|
|
15
44
|
* @example
|
|
16
45
|
* <Anchor href='/'>Home</Anchor>
|
|
17
46
|
* <Anchor href='/projects'>Projects</Anchor>
|
|
47
|
+
* <Anchor href='/help' underline>Help</Anchor>
|
|
18
48
|
*
|
|
19
49
|
* @example
|
|
20
50
|
* <Anchor as={Link} to='/'>Home</Anchor>
|
|
21
51
|
* <Anchor as='button' onClick={() => {}}>click me</Anchor>
|
|
22
52
|
*/
|
|
23
|
-
exports.Anchor =
|
|
53
|
+
exports.Anchor = React.forwardRef((props, forwardedRef) => {
|
|
54
|
+
const { isExternal, underline, children, ...rest } = props;
|
|
55
|
+
return (React.createElement(index_js_1.Box, { as: 'a', "data-iui-underline": underline ? 'true' : undefined, ...rest, ref: forwardedRef, className: (0, classnames_1.default)('iui-anchor', { 'iui-anchor-external': isExternal }, props.className) },
|
|
56
|
+
children,
|
|
57
|
+
props.target === '_blank' && (React.createElement(VisuallyHidden_js_1.VisuallyHidden, null, " (opens in new tab)"))));
|
|
58
|
+
});
|
|
@@ -33,7 +33,7 @@ exports.VisuallyHidden = void 0;
|
|
|
33
33
|
*--------------------------------------------------------------------------------------------*/
|
|
34
34
|
const React = __importStar(require("react"));
|
|
35
35
|
const classnames_1 = __importDefault(require("classnames"));
|
|
36
|
-
const
|
|
36
|
+
const index_js_1 = require("../utils/index.js");
|
|
37
37
|
/**
|
|
38
38
|
* Hides content visually but keeps it still accessible to screen readers
|
|
39
39
|
* and other assistive technologies.
|
|
@@ -45,6 +45,22 @@ const Box_js_1 = require("../utils/components/Box.js");
|
|
|
45
45
|
* @see https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html
|
|
46
46
|
*/
|
|
47
47
|
exports.VisuallyHidden = React.forwardRef((props, ref) => {
|
|
48
|
-
const { className, unhideOnFocus = true, ...rest } = props;
|
|
49
|
-
|
|
48
|
+
const { as: asProp = 'span', className, unhideOnFocus = true, children: childrenProp, ...rest } = props;
|
|
49
|
+
// ShadowRoot is not supported on all elements, so we only use it for few common ones.
|
|
50
|
+
const children = !['div', 'span', 'p'].includes(asProp) ? (childrenProp) : (React.createElement(React.Fragment, null,
|
|
51
|
+
React.createElement(index_js_1.ShadowRoot, { css: css },
|
|
52
|
+
React.createElement("slot", null)),
|
|
53
|
+
childrenProp));
|
|
54
|
+
return (React.createElement(index_js_1.Box, { as: asProp, className: (0, classnames_1.default)('iui-visually-hidden', className), "data-iui-unhide-on-focus": unhideOnFocus ? true : undefined, ref: ref, ...rest }, children));
|
|
50
55
|
});
|
|
56
|
+
// ----------------------------------------------------------------------------
|
|
57
|
+
const css = /* css */ `
|
|
58
|
+
:host(:where(:not([data-iui-unhide-on-focus]:is(:focus-within, :active)))) {
|
|
59
|
+
clip-path: inset(50%) !important;
|
|
60
|
+
overflow: hidden !important;
|
|
61
|
+
position: absolute !important;
|
|
62
|
+
white-space: nowrap !important;
|
|
63
|
+
block-size: 1px !important;
|
|
64
|
+
inline-size: 1px !important;
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
@@ -32,24 +32,39 @@ const React = __importStar(require("react"));
|
|
|
32
32
|
const ReactDOM = __importStar(require("react-dom"));
|
|
33
33
|
const isBrowser = typeof document !== 'undefined';
|
|
34
34
|
const supportsDSD = isBrowser && 'shadowRootMode' in HTMLTemplateElement.prototype;
|
|
35
|
+
const supportsAdoptedStylesheets = isBrowser && 'adoptedStyleSheets' in Document.prototype;
|
|
35
36
|
/**
|
|
36
37
|
* Wrapper around `<template>` element that attaches shadow root to its parent
|
|
37
38
|
* and moves its children into the shadow root.
|
|
38
39
|
*
|
|
39
40
|
* @private
|
|
40
41
|
*/
|
|
41
|
-
const ShadowRoot = ({ children }) => {
|
|
42
|
+
const ShadowRoot = ({ children, css, }) => {
|
|
42
43
|
const [shadowRoot, setShadowRoot] = React.useState();
|
|
43
44
|
const isFirstRender = useIsFirstRender();
|
|
45
|
+
const styleSheet = React.useRef();
|
|
44
46
|
const attachShadowRef = React.useCallback((template) => {
|
|
45
47
|
const parent = template?.parentElement;
|
|
46
48
|
if (!template || !parent) {
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
if (parent.shadowRoot) {
|
|
52
|
+
parent.shadowRoot.replaceChildren(); // Remove previous shadowroot content
|
|
53
|
+
}
|
|
54
|
+
queueMicrotask(() => {
|
|
55
|
+
const shadow = parent.shadowRoot || parent.attachShadow({ mode: 'open' });
|
|
56
|
+
if (css && supportsAdoptedStylesheets) {
|
|
57
|
+
styleSheet.current || (styleSheet.current = new CSSStyleSheet());
|
|
58
|
+
styleSheet.current.replaceSync(css);
|
|
59
|
+
shadow.adoptedStyleSheets = [styleSheet.current];
|
|
60
|
+
}
|
|
61
|
+
ReactDOM.flushSync(() => setShadowRoot(shadow));
|
|
62
|
+
});
|
|
63
|
+
}, [css]);
|
|
51
64
|
if (!isBrowser) {
|
|
52
|
-
return React.createElement("template", { shadowrootmode: 'open' },
|
|
65
|
+
return (React.createElement("template", { shadowrootmode: 'open' },
|
|
66
|
+
css && React.createElement("style", null, css),
|
|
67
|
+
children));
|
|
53
68
|
}
|
|
54
69
|
// In browsers that support DSD, the template will be automatically removed as soon as it's parsed.
|
|
55
70
|
// To pass hydration, the first client render needs to emulate this browser behavior and return null.
|
|
@@ -3,11 +3,13 @@ import type { PolymorphicForwardRefComponent } from '../props.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Utility to create a type-safe polymorphic component with a simple class.
|
|
5
5
|
*
|
|
6
|
-
* Can be called directly or as a property of the `
|
|
6
|
+
* Can be called directly or as a property of the `polymorphic` object.
|
|
7
7
|
* In both cases, returns a component that:
|
|
8
|
+
* - uses CSS-modules scoped classes
|
|
8
9
|
* - supports `as` prop with default element
|
|
9
|
-
* - forwards ref and rest props
|
|
10
|
-
* - adds and merges
|
|
10
|
+
* - forwards ref and spreads rest props
|
|
11
|
+
* - adds and merges CSS classes
|
|
12
|
+
* - adds tabIndex to interactive elements (Safari workaround)
|
|
11
13
|
*
|
|
12
14
|
* @example
|
|
13
15
|
* const MyPolyDiv = polymorphic('my-poly-div');
|
|
@@ -31,6 +31,7 @@ exports.polymorphic = void 0;
|
|
|
31
31
|
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
32
32
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
33
33
|
*--------------------------------------------------------------------------------------------*/
|
|
34
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
34
35
|
const React = __importStar(require("react"));
|
|
35
36
|
const classnames_1 = __importDefault(require("classnames"));
|
|
36
37
|
const useGlobals_js_1 = require("../hooks/useGlobals.js");
|
|
@@ -38,9 +39,21 @@ const styles_js_1 = __importDefault(require("../../../styles.js"));
|
|
|
38
39
|
const _base = (defaultElement) => {
|
|
39
40
|
return (className, attrs) => {
|
|
40
41
|
const Comp = React.forwardRef(({ as = defaultElement, ...props }, ref) => {
|
|
41
|
-
|
|
42
|
+
props = {
|
|
43
|
+
...attrs,
|
|
44
|
+
...props,
|
|
45
|
+
className: getScopedClassName((0, classnames_1.default)(className, attrs?.className, props.className)),
|
|
46
|
+
};
|
|
47
|
+
const Element = as || 'div';
|
|
48
|
+
// Add tabIndex to interactive elements if not already set.
|
|
49
|
+
// Workaround for Safari refusing to focus links/buttons/non-text inputs.
|
|
50
|
+
if (Element === 'button' ||
|
|
51
|
+
Element === 'a' ||
|
|
52
|
+
(Element === 'input' && props.type === 'checkbox')) {
|
|
53
|
+
props.tabIndex ?? (props.tabIndex = 0);
|
|
54
|
+
}
|
|
42
55
|
(0, useGlobals_js_1.useGlobals)();
|
|
43
|
-
return
|
|
56
|
+
return React.createElement(Element, { ref: ref, ...props });
|
|
44
57
|
});
|
|
45
58
|
Comp.displayName = getDisplayNameFromClass(className);
|
|
46
59
|
return Comp;
|
|
@@ -49,11 +62,13 @@ const _base = (defaultElement) => {
|
|
|
49
62
|
/**
|
|
50
63
|
* Utility to create a type-safe polymorphic component with a simple class.
|
|
51
64
|
*
|
|
52
|
-
* Can be called directly or as a property of the `
|
|
65
|
+
* Can be called directly or as a property of the `polymorphic` object.
|
|
53
66
|
* In both cases, returns a component that:
|
|
67
|
+
* - uses CSS-modules scoped classes
|
|
54
68
|
* - supports `as` prop with default element
|
|
55
|
-
* - forwards ref and rest props
|
|
56
|
-
* - adds and merges
|
|
69
|
+
* - forwards ref and spreads rest props
|
|
70
|
+
* - adds and merges CSS classes
|
|
71
|
+
* - adds tabIndex to interactive elements (Safari workaround)
|
|
57
72
|
*
|
|
58
73
|
* @example
|
|
59
74
|
* const MyPolyDiv = polymorphic('my-poly-div');
|
|
@@ -6,4 +6,8 @@ exports.Svg = void 0;
|
|
|
6
6
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
7
7
|
*--------------------------------------------------------------------------------------------*/
|
|
8
8
|
const polymorphic_js_1 = require("../functions/polymorphic.js");
|
|
9
|
-
exports.Svg = polymorphic_js_1.polymorphic.svg('', {
|
|
9
|
+
exports.Svg = polymorphic_js_1.polymorphic.svg('', {
|
|
10
|
+
viewBox: '0 0 16 16',
|
|
11
|
+
width: 16,
|
|
12
|
+
height: 16,
|
|
13
|
+
});
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
|
-
import { Box, getBoundedValue } from '../utils/index.js';
|
|
7
|
+
import { Box, ShadowRoot, getBoundedValue } from '../utils/index.js';
|
|
8
|
+
import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden.js';
|
|
8
9
|
/**
|
|
9
10
|
* Shows progress on a linear bar
|
|
10
11
|
* @example
|
|
@@ -33,5 +34,9 @@ export const ProgressLinear = React.forwardRef((props, forwardedRef) => {
|
|
|
33
34
|
const boundedValue = getBoundedValue(value ?? 100, 0, 100);
|
|
34
35
|
return (React.createElement(Box, { className: cx('iui-progress-indicator-linear', className), ref: forwardedRef, "data-iui-status": status, "data-iui-indeterminate": indeterminate ? 'true' : undefined, "data-iui-animated": isAnimated ? 'true' : undefined, style: {
|
|
35
36
|
'--iui-progress-percentage': `${boundedValue}%`,
|
|
36
|
-
}, ...rest },
|
|
37
|
+
}, ...rest },
|
|
38
|
+
React.createElement(ShadowRoot, null,
|
|
39
|
+
value !== 100 && React.createElement(VisuallyHidden, null, "Loading."),
|
|
40
|
+
React.createElement("slot", null)),
|
|
41
|
+
labels.length > 0 && (React.createElement(Box, { as: 'div', ...labelGroupProps, className: cx('iui-progress-indicator-linear-label', labelGroupProps?.className) }, labels.map((label, index) => (React.createElement("span", { key: index }, label)))))));
|
|
37
42
|
});
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import cx from 'classnames';
|
|
6
6
|
import * as React from 'react';
|
|
7
|
-
import { SvgCheckmarkSmall, SvgImportantSmall, Box, getBoundedValue, } from '../utils/index.js';
|
|
7
|
+
import { SvgCheckmarkSmall, SvgImportantSmall, Box, getBoundedValue, ShadowRoot, } from '../utils/index.js';
|
|
8
|
+
import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden.js';
|
|
8
9
|
/**
|
|
9
10
|
* Circular Progress Indicator
|
|
10
11
|
* @example
|
|
@@ -33,7 +34,11 @@ export const ProgressRadial = React.forwardRef((props, forwardedRef) => {
|
|
|
33
34
|
'--iui-progress-percentage': `${getBoundedValue(value, 0, 100)}%`,
|
|
34
35
|
}),
|
|
35
36
|
...style,
|
|
36
|
-
}, ...rest },
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
}, ...rest },
|
|
38
|
+
React.createElement(ShadowRoot, null,
|
|
39
|
+
value !== 100 && React.createElement(VisuallyHidden, null, "Loading."),
|
|
40
|
+
React.createElement("slot", null)),
|
|
41
|
+
size !== 'x-small'
|
|
42
|
+
? children ?? (!!status ? statusMap[status] : null)
|
|
43
|
+
: null));
|
|
39
44
|
});
|
|
@@ -64,8 +64,10 @@ export type SelectMultipleTypeProps<T> = {
|
|
|
64
64
|
/**
|
|
65
65
|
* Selected option value.
|
|
66
66
|
* If `multiple` is enabled, it is an array of values.
|
|
67
|
+
*
|
|
68
|
+
* Pass `null` to reset the value.
|
|
67
69
|
*/
|
|
68
|
-
value?: T;
|
|
70
|
+
value?: T | null;
|
|
69
71
|
/**
|
|
70
72
|
* Callback function handling change event on select.
|
|
71
73
|
*/
|
|
@@ -73,7 +73,7 @@ export const Select = React.forwardRef((props, forwardedRef) => {
|
|
|
73
73
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
74
74
|
const [liveRegionSelection, setLiveRegionSelection] = React.useState('');
|
|
75
75
|
const [uncontrolledValue, setUncontrolledValue] = React.useState();
|
|
76
|
-
const value = valueProp
|
|
76
|
+
const value = valueProp !== undefined ? valueProp : uncontrolledValue;
|
|
77
77
|
const onChangeRef = useLatestRef(onChangeProp);
|
|
78
78
|
const selectRef = React.useRef(null);
|
|
79
79
|
const show = React.useCallback(() => {
|
|
@@ -17,9 +17,11 @@ type ToggleSwitchProps = {
|
|
|
17
17
|
*/
|
|
18
18
|
size?: 'default';
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Custom icon inside the toggle switch. Shown only when toggle is checked and size is not small.
|
|
21
|
+
*
|
|
22
|
+
* Will override the default checkmark icon.
|
|
21
23
|
*/
|
|
22
|
-
icon?: JSX.Element;
|
|
24
|
+
icon?: JSX.Element | null;
|
|
23
25
|
} | {
|
|
24
26
|
size: 'small';
|
|
25
27
|
icon?: never;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
|
-
import {
|
|
7
|
+
import { Box, SvgCheckmark } from '../utils/index.js';
|
|
8
8
|
/**
|
|
9
9
|
* A switch for turning on and off.
|
|
10
10
|
* @example
|
|
@@ -24,21 +24,15 @@ import { useMergedRefs, Box } from '../utils/index.js';
|
|
|
24
24
|
* <ToggleSwitch label='With icon toggle' icon={<svg viewBox='0 0 16 16'><path d='M1 1v14h14V1H1zm13 1.7v10.6L8.7 8 14 2.7zM8 7.3L2.7 2h10.6L8 7.3zm-.7.7L2 13.3V2.7L7.3 8zm.7.7l5.3 5.3H2.7L8 8.7z' /></svg>} />
|
|
25
25
|
*/
|
|
26
26
|
export const ToggleSwitch = React.forwardRef((props, ref) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
props = { ...props };
|
|
31
|
-
delete props.icon;
|
|
32
|
-
}
|
|
33
|
-
const { disabled = false, labelPosition = 'right', label, className, style, size = 'default', ...rest } = props;
|
|
34
|
-
const inputElementRef = React.useRef(null);
|
|
35
|
-
const refs = useMergedRefs(inputElementRef, ref);
|
|
27
|
+
const { disabled = false, labelPosition = 'right', label, className, style, size = 'default', icon: iconProp, ...rest } = props;
|
|
28
|
+
// Disallow custom icon for small size, but keep the default checkmark when prop is not passed.
|
|
29
|
+
const shouldShowIcon = iconProp === undefined || (iconProp !== null && size !== 'small');
|
|
36
30
|
return (React.createElement(Box, { as: label ? 'label' : 'div', className: cx('iui-toggle-switch-wrapper', {
|
|
37
31
|
'iui-disabled': disabled,
|
|
38
32
|
'iui-label-on-right': label && labelPosition === 'right',
|
|
39
33
|
'iui-label-on-left': label && labelPosition === 'left',
|
|
40
34
|
}, className), "data-iui-size": size, style: style },
|
|
41
|
-
React.createElement(Box, { as: 'input', className: 'iui-toggle-switch', type: 'checkbox', role: 'switch', disabled: disabled, ref:
|
|
42
|
-
|
|
35
|
+
React.createElement(Box, { as: 'input', className: 'iui-toggle-switch', type: 'checkbox', role: 'switch', disabled: disabled, ref: ref, ...rest }),
|
|
36
|
+
shouldShowIcon && (React.createElement(Box, { as: 'span', className: 'iui-toggle-switch-icon', "aria-hidden": true }, iconProp || React.createElement(SvgCheckmark, null))),
|
|
43
37
|
label && (React.createElement(Box, { as: 'span', className: 'iui-toggle-switch-label' }, label))));
|
|
44
38
|
});
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
import type { PolymorphicForwardRefComponent } from '../utils/index.js';
|
|
2
|
+
type AnchorProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the anchor links to an external site.
|
|
5
|
+
*
|
|
6
|
+
* When true, there will be an icon added at the end of the anchor text. This is useful
|
|
7
|
+
* to indicate that the link will open in a new tab.
|
|
8
|
+
*
|
|
9
|
+
* Not all external links should open in a new tab, so this prop should be used with caution.
|
|
10
|
+
*/
|
|
11
|
+
isExternal?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the anchor should be underlined in its idle state.
|
|
14
|
+
*
|
|
15
|
+
* By default, the anchor is underlined only on hover, or when using a high-contrast theme.
|
|
16
|
+
*/
|
|
17
|
+
underline?: boolean;
|
|
18
|
+
};
|
|
1
19
|
/**
|
|
2
20
|
* A consistently styled anchor component.
|
|
3
21
|
*
|
|
@@ -7,9 +25,11 @@
|
|
|
7
25
|
* @example
|
|
8
26
|
* <Anchor href='/'>Home</Anchor>
|
|
9
27
|
* <Anchor href='/projects'>Projects</Anchor>
|
|
28
|
+
* <Anchor href='/help' underline>Help</Anchor>
|
|
10
29
|
*
|
|
11
30
|
* @example
|
|
12
31
|
* <Anchor as={Link} to='/'>Home</Anchor>
|
|
13
32
|
* <Anchor as='button' onClick={() => {}}>click me</Anchor>
|
|
14
33
|
*/
|
|
15
|
-
export declare const Anchor:
|
|
34
|
+
export declare const Anchor: PolymorphicForwardRefComponent<"a", AnchorProps>;
|
|
35
|
+
export {};
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
3
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
import
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import cx from 'classnames';
|
|
7
|
+
import { Box } from '../utils/index.js';
|
|
8
|
+
import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden.js';
|
|
6
9
|
/**
|
|
7
10
|
* A consistently styled anchor component.
|
|
8
11
|
*
|
|
@@ -12,9 +15,15 @@ import { polymorphic } from '../utils/index.js';
|
|
|
12
15
|
* @example
|
|
13
16
|
* <Anchor href='/'>Home</Anchor>
|
|
14
17
|
* <Anchor href='/projects'>Projects</Anchor>
|
|
18
|
+
* <Anchor href='/help' underline>Help</Anchor>
|
|
15
19
|
*
|
|
16
20
|
* @example
|
|
17
21
|
* <Anchor as={Link} to='/'>Home</Anchor>
|
|
18
22
|
* <Anchor as='button' onClick={() => {}}>click me</Anchor>
|
|
19
23
|
*/
|
|
20
|
-
export const Anchor =
|
|
24
|
+
export const Anchor = React.forwardRef((props, forwardedRef) => {
|
|
25
|
+
const { isExternal, underline, children, ...rest } = props;
|
|
26
|
+
return (React.createElement(Box, { as: 'a', "data-iui-underline": underline ? 'true' : undefined, ...rest, ref: forwardedRef, className: cx('iui-anchor', { 'iui-anchor-external': isExternal }, props.className) },
|
|
27
|
+
children,
|
|
28
|
+
props.target === '_blank' && (React.createElement(VisuallyHidden, null, " (opens in new tab)"))));
|
|
29
|
+
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
|
-
import { Box } from '../utils/
|
|
7
|
+
import { Box, ShadowRoot } from '../utils/index.js';
|
|
8
8
|
/**
|
|
9
9
|
* Hides content visually but keeps it still accessible to screen readers
|
|
10
10
|
* and other assistive technologies.
|
|
@@ -16,6 +16,22 @@ import { Box } from '../utils/components/Box.js';
|
|
|
16
16
|
* @see https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html
|
|
17
17
|
*/
|
|
18
18
|
export const VisuallyHidden = React.forwardRef((props, ref) => {
|
|
19
|
-
const { className, unhideOnFocus = true, ...rest } = props;
|
|
20
|
-
|
|
19
|
+
const { as: asProp = 'span', className, unhideOnFocus = true, children: childrenProp, ...rest } = props;
|
|
20
|
+
// ShadowRoot is not supported on all elements, so we only use it for few common ones.
|
|
21
|
+
const children = !['div', 'span', 'p'].includes(asProp) ? (childrenProp) : (React.createElement(React.Fragment, null,
|
|
22
|
+
React.createElement(ShadowRoot, { css: css },
|
|
23
|
+
React.createElement("slot", null)),
|
|
24
|
+
childrenProp));
|
|
25
|
+
return (React.createElement(Box, { as: asProp, className: cx('iui-visually-hidden', className), "data-iui-unhide-on-focus": unhideOnFocus ? true : undefined, ref: ref, ...rest }, children));
|
|
21
26
|
});
|
|
27
|
+
// ----------------------------------------------------------------------------
|
|
28
|
+
const css = /* css */ `
|
|
29
|
+
:host(:where(:not([data-iui-unhide-on-focus]:is(:focus-within, :active)))) {
|
|
30
|
+
clip-path: inset(50%) !important;
|
|
31
|
+
overflow: hidden !important;
|
|
32
|
+
position: absolute !important;
|
|
33
|
+
white-space: nowrap !important;
|
|
34
|
+
block-size: 1px !important;
|
|
35
|
+
inline-size: 1px !important;
|
|
36
|
+
}
|
|
37
|
+
`;
|