@itwin/itwinui-react 2.7.0 → 2.8.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/cjs/core/Dialog/DialogMain.js +18 -23
  3. package/cjs/core/Surface/Surface.d.ts +24 -2
  4. package/cjs/core/Surface/Surface.js +38 -2
  5. package/cjs/core/Surface/index.d.ts +1 -1
  6. package/cjs/core/Tile/Tile.js +2 -4
  7. package/cjs/core/index.d.ts +3 -3
  8. package/cjs/core/index.js +3 -1
  9. package/cjs/core/utils/components/Divider.d.ts +14 -0
  10. package/cjs/core/utils/components/Divider.js +23 -0
  11. package/cjs/core/utils/components/Resizer.js +9 -9
  12. package/cjs/core/utils/components/VisuallyHidden.d.ts +20 -6
  13. package/cjs/core/utils/components/VisuallyHidden.js +10 -3
  14. package/cjs/core/utils/components/index.d.ts +1 -0
  15. package/cjs/core/utils/components/index.js +1 -0
  16. package/cjs/core/utils/functions/index.d.ts +1 -0
  17. package/cjs/core/utils/functions/index.js +1 -0
  18. package/cjs/core/utils/functions/supports.d.ts +4 -0
  19. package/cjs/core/utils/functions/supports.js +13 -0
  20. package/cjs/core/utils/hooks/useDragAndDrop.js +4 -3
  21. package/cjs/core/utils/hooks/useTheme.js +44 -0
  22. package/esm/core/Dialog/DialogMain.js +19 -24
  23. package/esm/core/Surface/Surface.d.ts +24 -2
  24. package/esm/core/Surface/Surface.js +39 -3
  25. package/esm/core/Surface/index.d.ts +1 -1
  26. package/esm/core/Tile/Tile.js +3 -5
  27. package/esm/core/index.d.ts +3 -3
  28. package/esm/core/index.js +1 -1
  29. package/esm/core/utils/components/Divider.d.ts +14 -0
  30. package/esm/core/utils/components/Divider.js +17 -0
  31. package/esm/core/utils/components/Resizer.js +9 -9
  32. package/esm/core/utils/components/VisuallyHidden.d.ts +20 -6
  33. package/esm/core/utils/components/VisuallyHidden.js +10 -3
  34. package/esm/core/utils/components/index.d.ts +1 -0
  35. package/esm/core/utils/components/index.js +1 -0
  36. package/esm/core/utils/functions/index.d.ts +1 -0
  37. package/esm/core/utils/functions/index.js +1 -0
  38. package/esm/core/utils/functions/supports.d.ts +4 -0
  39. package/esm/core/utils/functions/supports.js +9 -0
  40. package/esm/core/utils/hooks/useDragAndDrop.js +4 -3
  41. package/esm/core/utils/hooks/useTheme.js +21 -0
  42. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 861fcab3: The `Surface` component can now be broken down using the `Surface.Header` and `Surface.Body` subcomponents. Users can add padding to the body using `isPadded`.
8
+
9
+ ```jsx
10
+ <Surface>
11
+ <Surface.Header>Surface Header Content</Surface.Header>
12
+ <Surface.Body isPadded={true}>Surface Body Content</Surface.Body>
13
+ </Surface>
14
+ ```
15
+
16
+ - 861fcab3: A new `Divider` component has been created which can be used horizontally or vertically
17
+
18
+ ```jsx
19
+ <Divider orientation={'vertical'} />
20
+ ```
21
+
22
+ - 8c89441f: Added `VisuallyHidden`, a utility component for providing text to assistive technologies while hiding it visually.
23
+
24
+ ```jsx
25
+ <div aria-hidden='true'>★★★☆☆</div>
26
+ <VisuallyHidden>3 stars out of 5</VisuallyHidden>
27
+ ```
28
+
29
+ ### Patch Changes
30
+
31
+ - 3ad2dd90: Fixed an issue in draggable/resizable dialogs opened in popup windows, where pointermove event listeners were not being removed correctly.
32
+ - 521610a0: iTwinUI will now show a warning in development if it detects that the page overrides the root font size. For more details, see the [migration guide](https://github.com/iTwin/iTwinUI/wiki/iTwinUI-react-v2-migration-guide#relative-font-size).
33
+ - 6caccc8d: Fixes jumpy animation when opening full page dialog
34
+ - Updated dependencies
35
+ - @itwin/itwinui-css@1.9.0
36
+
3
37
  ## 2.7.0
4
38
 
5
39
  ### Minor Changes
@@ -44,28 +44,7 @@ exports.DialogMain = react_1.default.forwardRef((props, ref) => {
44
44
  const dialogRef = react_1.default.useRef(null);
45
45
  const refs = (0, utils_1.useMergedRefs)(dialogRef, ref);
46
46
  const hasBeenResized = react_1.default.useRef(false);
47
- // Focuses dialog when opened and brings back focus to the previously focused element when closed.
48
47
  const previousFocusedElement = react_1.default.useRef();
49
- const setFocusRef = (0, utils_1.useLatestRef)(setFocus);
50
- react_1.default.useEffect(() => {
51
- var _a, _b, _c;
52
- if (!setFocusRef.current) {
53
- return;
54
- }
55
- if (isOpen) {
56
- previousFocusedElement.current = (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.activeElement;
57
- (_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.focus();
58
- }
59
- else {
60
- (_c = previousFocusedElement.current) === null || _c === void 0 ? void 0 : _c.focus();
61
- }
62
- const ref = dialogRef.current;
63
- return () => {
64
- var _a;
65
- (ref === null || ref === void 0 ? void 0 : ref.contains(document.activeElement)) &&
66
- ((_a = previousFocusedElement.current) === null || _a === void 0 ? void 0 : _a.focus());
67
- };
68
- }, [isOpen, setFocusRef]);
69
48
  const originalBodyOverflow = react_1.default.useRef('');
70
49
  react_1.default.useEffect(() => {
71
50
  if (isOpen) {
@@ -136,7 +115,6 @@ exports.DialogMain = react_1.default.forwardRef((props, ref) => {
136
115
  const content = (react_1.default.createElement("div", { className: (0, classnames_1.default)('iui-dialog', {
137
116
  'iui-dialog-default': styleType === 'default',
138
117
  'iui-dialog-full-page': styleType === 'fullPage',
139
- 'iui-dialog-visible': isOpen,
140
118
  'iui-dialog-draggable': isDraggable,
141
119
  }, className), role: 'dialog', ref: refs, onKeyDown: handleKeyDown, tabIndex: -1, style: {
142
120
  transform,
@@ -151,7 +129,24 @@ exports.DialogMain = react_1.default.forwardRef((props, ref) => {
151
129
  }
152
130
  }, onResizeEnd: setResizeStyle })),
153
131
  children));
154
- return (react_1.default.createElement(react_transition_group_1.CSSTransition, { in: isOpen, classNames: 'iui-dialog-animation', timeout: { exit: 600 }, unmountOnExit: true, nodeRef: dialogRef },
132
+ return (react_1.default.createElement(react_transition_group_1.CSSTransition, { in: isOpen, classNames: {
133
+ enter: 'iui-dialog-animation-enter',
134
+ enterActive: 'iui-dialog-animation-enter-active',
135
+ enterDone: 'iui-dialog-visible',
136
+ }, timeout: { exit: 600 },
137
+ // Focuses dialog when opened
138
+ onEntered: () => {
139
+ var _a, _b;
140
+ previousFocusedElement.current = (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.activeElement;
141
+ setFocus && ((_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.focus({ preventScroll: true }));
142
+ },
143
+ // Brings back focus to the previously focused element when closed
144
+ onExit: () => {
145
+ var _a, _b, _c;
146
+ if ((_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.contains((_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.activeElement)) {
147
+ (_c = previousFocusedElement.current) === null || _c === void 0 ? void 0 : _c.focus();
148
+ }
149
+ }, unmountOnExit: true, nodeRef: dialogRef },
155
150
  react_1.default.createElement(DialogDragContext_1.DialogDragContext.Provider, { value: { onPointerDown: handlePointerDown } },
156
151
  trapFocus && react_1.default.createElement(utils_1.FocusTrap, null, content),
157
152
  !trapFocus && content)));
@@ -1,6 +1,15 @@
1
1
  import React from 'react';
2
- import { CommonProps } from '../utils';
2
+ import { CommonProps, PolymorphicComponentProps, PolymorphicForwardRefComponent } from '../utils';
3
3
  import '@itwin/itwinui-css/css/surface.css';
4
+ declare type SurfaceHeaderOwnProps = {};
5
+ export declare type SurfaceHeaderProps<T extends React.ElementType = 'div'> = PolymorphicComponentProps<T, SurfaceHeaderOwnProps>;
6
+ declare type SurfaceBodyOwnProps = {
7
+ /**
8
+ * Gives padding to the surface body
9
+ */
10
+ isPadded?: boolean;
11
+ };
12
+ export declare type SurfaceBodyProps<T extends React.ElementType = 'div'> = PolymorphicComponentProps<T, SurfaceBodyOwnProps>;
4
13
  export declare type SurfaceProps = {
5
14
  /**
6
15
  * Sets the elevation of the surface
@@ -16,6 +25,10 @@ export declare type SurfaceProps = {
16
25
  * @example
17
26
  * <Surface>Surface Content</Surface>
18
27
  * <Surface elevation={2}>Surface Content</Surface>
28
+ * <Surface>
29
+ * <Surface.Header>Surface Header Content</Surface.Header>
30
+ * <Surface.Body isPadded={true}>Surface Body Content</Surface.Body>
31
+ * </Surface>
19
32
  */
20
33
  export declare const Surface: React.ForwardRefExoticComponent<{
21
34
  /**
@@ -26,5 +39,14 @@ export declare const Surface: React.ForwardRefExoticComponent<{
26
39
  * Content in the surface.
27
40
  */
28
41
  children: React.ReactNode;
29
- } & Omit<CommonProps, "title"> & React.RefAttributes<HTMLDivElement>>;
42
+ } & Omit<CommonProps, "title"> & React.RefAttributes<HTMLDivElement>> & {
43
+ /**
44
+ * Surface header subcomponent
45
+ */
46
+ Header: PolymorphicForwardRefComponent<"div", SurfaceHeaderOwnProps>;
47
+ /**
48
+ * Surface body subcomponent. Additional padding can be added to the body through the 'isPadded' prop
49
+ */
50
+ Body: PolymorphicForwardRefComponent<"div", SurfaceBodyOwnProps>;
51
+ };
30
52
  export default Surface;
@@ -33,19 +33,55 @@ const getSurfaceElevationValue = (elevation) => {
33
33
  return '';
34
34
  }
35
35
  };
36
+ const SurfaceHeader = react_1.default.forwardRef((props, ref) => {
37
+ const { as: Element = 'div', children, className, ...rest } = props;
38
+ const { setHasLayout } = (0, utils_1.useSafeContext)(SurfaceContext);
39
+ react_1.default.useEffect(() => {
40
+ if (!(0, utils_1.supportsHas)()) {
41
+ setHasLayout(true);
42
+ }
43
+ }, [setHasLayout]);
44
+ return (react_1.default.createElement(Element, { className: (0, classnames_1.default)('iui-surface-header', className), ref: ref, ...rest }, children));
45
+ });
46
+ const SurfaceBody = react_1.default.forwardRef((props, ref) => {
47
+ const { as: Element = 'div', children, className, isPadded, ...rest } = props;
48
+ const { setHasLayout } = (0, utils_1.useSafeContext)(SurfaceContext);
49
+ react_1.default.useEffect(() => {
50
+ if (!(0, utils_1.supportsHas)()) {
51
+ setHasLayout(true);
52
+ }
53
+ }, [setHasLayout]);
54
+ return (react_1.default.createElement(Element, { className: (0, classnames_1.default)('iui-surface-body', className), ref: ref, "data-iui-padded": isPadded ? 'true' : undefined, ...rest }, children));
55
+ });
36
56
  /**
37
57
  * The Surface container allows content to appear elevated through the use of a drop shadow
38
58
  * @example
39
59
  * <Surface>Surface Content</Surface>
40
60
  * <Surface elevation={2}>Surface Content</Surface>
61
+ * <Surface>
62
+ * <Surface.Header>Surface Header Content</Surface.Header>
63
+ * <Surface.Body isPadded={true}>Surface Body Content</Surface.Body>
64
+ * </Surface>
41
65
  */
42
- exports.Surface = react_1.default.forwardRef((props, ref) => {
66
+ exports.Surface = Object.assign(react_1.default.forwardRef((props, ref) => {
43
67
  const { elevation, className, style, children, ...rest } = props;
44
68
  (0, utils_1.useTheme)();
69
+ const [hasLayout, setHasLayout] = react_1.default.useState(false);
45
70
  const _style = {
46
71
  '--iui-surface-elevation': getSurfaceElevationValue(elevation),
47
72
  ...style,
48
73
  };
49
- return (react_1.default.createElement("div", { className: (0, classnames_1.default)('iui-surface', className), style: _style, ref: ref, ...rest }, children));
74
+ return (react_1.default.createElement("div", { className: (0, classnames_1.default)('iui-surface', className), style: _style, ref: ref, "data-iui-layout": hasLayout ? 'true' : undefined, ...rest },
75
+ react_1.default.createElement(SurfaceContext.Provider, { value: { setHasLayout } }, children)));
76
+ }), {
77
+ /**
78
+ * Surface header subcomponent
79
+ */
80
+ Header: SurfaceHeader,
81
+ /**
82
+ * Surface body subcomponent. Additional padding can be added to the body through the 'isPadded' prop
83
+ */
84
+ Body: SurfaceBody,
50
85
  });
86
+ const SurfaceContext = react_1.default.createContext(undefined);
51
87
  exports.default = exports.Surface;
@@ -1,4 +1,4 @@
1
1
  export { Surface } from './Surface';
2
- export type { SurfaceProps } from './Surface';
2
+ export type { SurfaceProps, SurfaceHeaderProps, SurfaceBodyProps, } from './Surface';
3
3
  declare const _default: "./Surface";
4
4
  export default _default;
@@ -25,14 +25,12 @@ const TileContext = react_1.default.createContext(undefined);
25
25
  * />
26
26
  */
27
27
  const TileAction = (props) => {
28
- var _a, _b, _c;
29
28
  const tileContext = (0, utils_1.useSafeContext)(TileContext);
30
- const supportsHas = (_c = (_b = (_a = (0, utils_1.getWindow)()) === null || _a === void 0 ? void 0 : _a.CSS) === null || _b === void 0 ? void 0 : _b.supports) === null || _c === void 0 ? void 0 : _c.call(_b, 'selector(:has(+ *))');
31
29
  react_1.default.useEffect(() => {
32
- if (!supportsHas) {
30
+ if (!(0, utils_1.supportsHas)()) {
33
31
  tileContext.setActionable(true);
34
32
  }
35
- }, [supportsHas, tileContext]);
33
+ }, [tileContext]);
36
34
  return react_1.default.createElement(utils_1.LinkAction, { ...props });
37
35
  };
38
36
  exports.TileAction = TileAction;
@@ -79,7 +79,7 @@ export type { SliderProps } from './Slider';
79
79
  export { StatusMessage } from './StatusMessage';
80
80
  export type { StatusMessageProps } from './StatusMessage';
81
81
  export { Surface } from './Surface';
82
- export type { SurfaceProps } from './Surface';
82
+ export type { SurfaceProps, SurfaceHeaderProps, SurfaceBodyProps, } from './Surface';
83
83
  export { Table, tableFilters, BaseFilter, FilterButtonBar, DefaultCell, EditableCell, TablePaginator, ActionColumn, ExpanderColumn, SelectionColumn, } from './Table';
84
84
  export type { TableProps, TableFilterProps, TableFilterValue, DateRangeFilterOptions, FilterButtonBarProps, DefaultCellProps, EditableCellProps, TablePaginatorProps, TablePaginatorRendererProps, } from './Table';
85
85
  export { Tag, TagContainer } from './Tag';
@@ -104,5 +104,5 @@ export { Anchor, Body, Headline, Leading, Small, Subheading, Title, Blockquote,
104
104
  export type { AnchorProps, BodyProps, HeadlineProps, LeadingProps, SmallProps, SubheadingProps, TitleProps, BlockquoteProps, CodeProps, KbdProps, TextProps, } from './Typography';
105
105
  export { Wizard, Stepper, WorkflowDiagram } from './Stepper';
106
106
  export type { WizardProps, StepProperties, WizardType, WizardLocalization, StepperProps, StepperLocalization, WorkflowDiagramProps, } from './Stepper';
107
- export { getUserColor, useTheme, ColorValue, MiddleTextTruncation, LinkBox, LinkAction, Icon, Flex, } from './utils';
108
- export type { ThemeType, MiddleTextTruncationProps, IconProps, FlexProps, FlexItemProps, FlexSpacerProps, LinkBoxProps, LinkActionProps, } from './utils';
107
+ export { getUserColor, useTheme, ColorValue, MiddleTextTruncation, LinkBox, LinkAction, Icon, Flex, VisuallyHidden, Divider, } from './utils';
108
+ export type { ThemeType, MiddleTextTruncationProps, IconProps, FlexProps, FlexItemProps, FlexSpacerProps, DividerProps, LinkBoxProps, LinkActionProps, VisuallyHiddenProps, } from './utils';
package/cjs/core/index.js CHANGED
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Input = exports.InformationPanelContent = exports.InformationPanelBody = exports.InformationPanelHeader = exports.InformationPanelWrapper = exports.InformationPanel = exports.HorizontalTabs = exports.Tab = exports.Tabs = exports.VerticalTabs = exports.HeaderLogo = exports.HeaderButton = exports.HeaderBreadcrumbs = exports.Header = exports.defaultFooterElements = exports.Footer = exports.FileEmptyCard = exports.FileUploadCard = exports.FileUploadTemplate = exports.FileUpload = exports.Fieldset = exports.ExpandableBlock = exports.NonIdealState = exports.ErrorPage = exports.DropdownMenu = exports.Dialog = exports.generateLocalizedStrings = exports.DatePicker = exports.ComboBox = exports.ColorPalette = exports.ColorInputPanel = exports.ColorBuilder = exports.ColorSwatch = exports.ColorPicker = exports.Checkbox = exports.Carousel = exports.ButtonGroup = exports.SplitButton = exports.IdeasButton = exports.IconButton = exports.DropdownButton = exports.Button = exports.Breadcrumbs = exports.Badge = exports.Backdrop = exports.UserIconGroup = exports.AvatarGroup = exports.UserIcon = exports.Avatar = exports.Alert = void 0;
7
7
  exports.TreeNodeExpander = exports.TreeNode = exports.Tree = exports.Tooltip = exports.ToggleSwitch = exports.ThemeProvider = exports.toaster = exports.TimePicker = exports.Tile = exports.Textarea = exports.TagContainer = exports.Tag = exports.SelectionColumn = exports.ExpanderColumn = exports.ActionColumn = exports.TablePaginator = exports.EditableCell = exports.DefaultCell = exports.FilterButtonBar = exports.BaseFilter = exports.tableFilters = exports.Table = exports.Surface = exports.StatusMessage = exports.Slider = exports.SkipToContentLink = exports.SidenavSubmenuHeader = exports.SidenavSubmenu = exports.SidenavButton = exports.SideNavigation = exports.Select = exports.RadioTileGroup = exports.RadioTile = exports.Radio = exports.ProgressRadial = exports.ProgressLinear = exports.NotificationMarker = exports.ModalContent = exports.ModalButtonBar = exports.Modal = exports.MenuItemSkeleton = exports.MenuExtraContent = exports.MenuDivider = exports.MenuItem = exports.Menu = exports.LabeledTextarea = exports.LabeledSelect = exports.InputGroup = exports.LabeledInput = exports.Label = void 0;
8
- exports.Flex = exports.Icon = exports.LinkAction = exports.LinkBox = exports.MiddleTextTruncation = exports.ColorValue = exports.useTheme = exports.getUserColor = exports.WorkflowDiagram = exports.Stepper = exports.Wizard = exports.Text = exports.KbdKeys = exports.Kbd = exports.Code = exports.Blockquote = exports.Title = exports.Subheading = exports.Small = exports.Leading = exports.Headline = exports.Body = exports.Anchor = void 0;
8
+ exports.Divider = exports.VisuallyHidden = exports.Flex = exports.Icon = exports.LinkAction = exports.LinkBox = exports.MiddleTextTruncation = exports.ColorValue = exports.useTheme = exports.getUserColor = exports.WorkflowDiagram = exports.Stepper = exports.Wizard = exports.Text = exports.KbdKeys = exports.Kbd = exports.Code = exports.Blockquote = exports.Title = exports.Subheading = exports.Small = exports.Leading = exports.Headline = exports.Body = exports.Anchor = void 0;
9
9
  /*---------------------------------------------------------------------------------------------
10
10
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
11
11
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -187,3 +187,5 @@ Object.defineProperty(exports, "LinkBox", { enumerable: true, get: function () {
187
187
  Object.defineProperty(exports, "LinkAction", { enumerable: true, get: function () { return utils_1.LinkAction; } });
188
188
  Object.defineProperty(exports, "Icon", { enumerable: true, get: function () { return utils_1.Icon; } });
189
189
  Object.defineProperty(exports, "Flex", { enumerable: true, get: function () { return utils_1.Flex; } });
190
+ Object.defineProperty(exports, "VisuallyHidden", { enumerable: true, get: function () { return utils_1.VisuallyHidden; } });
191
+ Object.defineProperty(exports, "Divider", { enumerable: true, get: function () { return utils_1.Divider; } });
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import '@itwin/itwinui-css/css/utils.css';
3
+ export declare type DividerProps = {
4
+ /**
5
+ * Sets the orientation of the divider
6
+ * @default 'horizontal'
7
+ */
8
+ orientation?: 'horizontal' | 'vertical';
9
+ } & React.ComponentPropsWithRef<'hr'>;
10
+ /**
11
+ * Shows a divider
12
+ */
13
+ export declare const Divider: React.ForwardRefExoticComponent<Pick<DividerProps, "key" | "orientation" | keyof React.HTMLAttributes<HTMLHRElement>> & React.RefAttributes<HTMLHRElement>>;
14
+ export default Divider;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Divider = void 0;
7
+ /*---------------------------------------------------------------------------------------------
8
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
9
+ * See LICENSE.md in the project root for license terms and full copyright notice.
10
+ *--------------------------------------------------------------------------------------------*/
11
+ const react_1 = __importDefault(require("react"));
12
+ const classnames_1 = __importDefault(require("classnames"));
13
+ const hooks_1 = require("../hooks");
14
+ require("@itwin/itwinui-css/css/utils.css");
15
+ /**
16
+ * Shows a divider
17
+ */
18
+ exports.Divider = react_1.default.forwardRef((props, ref) => {
19
+ const { className, orientation = 'horizontal', ...rest } = props;
20
+ (0, hooks_1.useTheme)();
21
+ return (react_1.default.createElement("hr", { className: (0, classnames_1.default)('iui-divider', className), "aria-orientation": orientation === 'vertical' ? 'vertical' : undefined, ref: ref, ...rest }));
22
+ });
23
+ exports.default = exports.Divider;
@@ -40,8 +40,9 @@ const Resizer = (props) => {
40
40
  const minWidth = parseFloat(getComputedStyle(elementRef.current).minWidth);
41
41
  const minHeight = parseFloat(getComputedStyle(elementRef.current).minHeight);
42
42
  const resizer = event.currentTarget.dataset.iuiResizer;
43
- const originalUserSelect = elementRef.current.ownerDocument.body.style.userSelect;
44
- elementRef.current.ownerDocument.body.style.userSelect = 'none';
43
+ const ownerDocument = elementRef.current.ownerDocument || document;
44
+ const originalUserSelect = ownerDocument.body.style.userSelect;
45
+ ownerDocument.body.style.userSelect = 'none';
45
46
  const onResizePointerMove = (event) => {
46
47
  var _a, _b, _c, _d, _e, _f, _g;
47
48
  if (!elementRef.current) {
@@ -52,8 +53,8 @@ const Resizer = (props) => {
52
53
  onResizeStart === null || onResizeStart === void 0 ? void 0 : onResizeStart();
53
54
  }
54
55
  const containerRect = (_a = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
55
- const clientX = (0, functions_1.getBoundedValue)(event.clientX, (_b = containerRect === null || containerRect === void 0 ? void 0 : containerRect.left) !== null && _b !== void 0 ? _b : 0, (_d = (_c = containerRect === null || containerRect === void 0 ? void 0 : containerRect.right) !== null && _c !== void 0 ? _c : elementRef.current.ownerDocument.documentElement.clientWidth) !== null && _d !== void 0 ? _d : 0);
56
- const clientY = (0, functions_1.getBoundedValue)(event.clientY, (_e = containerRect === null || containerRect === void 0 ? void 0 : containerRect.top) !== null && _e !== void 0 ? _e : 0, (_g = (_f = containerRect === null || containerRect === void 0 ? void 0 : containerRect.bottom) !== null && _f !== void 0 ? _f : elementRef.current.ownerDocument.documentElement.clientHeight) !== null && _g !== void 0 ? _g : 0);
56
+ const clientX = (0, functions_1.getBoundedValue)(event.clientX, (_b = containerRect === null || containerRect === void 0 ? void 0 : containerRect.left) !== null && _b !== void 0 ? _b : 0, (_d = (_c = containerRect === null || containerRect === void 0 ? void 0 : containerRect.right) !== null && _c !== void 0 ? _c : ownerDocument.documentElement.clientWidth) !== null && _d !== void 0 ? _d : 0);
57
+ const clientY = (0, functions_1.getBoundedValue)(event.clientY, (_e = containerRect === null || containerRect === void 0 ? void 0 : containerRect.top) !== null && _e !== void 0 ? _e : 0, (_g = (_f = containerRect === null || containerRect === void 0 ? void 0 : containerRect.bottom) !== null && _f !== void 0 ? _f : ownerDocument.documentElement.clientHeight) !== null && _g !== void 0 ? _g : 0);
57
58
  const diffX = initialPointerX - clientX;
58
59
  const diffY = initialPointerY - clientY;
59
60
  switch (resizer) {
@@ -128,12 +129,11 @@ const Resizer = (props) => {
128
129
  break;
129
130
  }
130
131
  };
131
- elementRef.current.ownerDocument.addEventListener('pointermove', onResizePointerMove);
132
- elementRef.current.ownerDocument.addEventListener('pointerup', () => {
133
- document.removeEventListener('pointermove', onResizePointerMove);
132
+ ownerDocument.addEventListener('pointermove', onResizePointerMove);
133
+ ownerDocument.addEventListener('pointerup', () => {
134
+ ownerDocument.removeEventListener('pointermove', onResizePointerMove);
134
135
  if (elementRef.current) {
135
- elementRef.current.ownerDocument.body.style.userSelect =
136
- originalUserSelect;
136
+ ownerDocument.body.style.userSelect = originalUserSelect;
137
137
  isResizing.current = false;
138
138
  onResizeEnd === null || onResizeEnd === void 0 ? void 0 : onResizeEnd({
139
139
  width,
@@ -1,10 +1,24 @@
1
- import React from 'react';
2
1
  import '@itwin/itwinui-css/css/utils.css';
3
- export declare type VisuallyHiddenProps = React.ComponentPropsWithRef<'div'>;
2
+ import type { PolymorphicComponentProps, PolymorphicForwardRefComponent } from '../props';
3
+ declare type VisuallyHiddenOwnProps = {
4
+ /**
5
+ * When VisuallyHidden is used with an interactive element (e.g. button),
6
+ * that element will "unhide" (become visible again) when focused.
7
+ *
8
+ * @default true
9
+ */
10
+ unhideOnFocus?: boolean;
11
+ };
12
+ export declare type VisuallyHiddenProps = PolymorphicComponentProps<'span', VisuallyHiddenOwnProps>;
4
13
  /**
5
- * Hides content visually but is still accessible to screen readers.
14
+ * Hides content visually but keeps it still accessible to screen readers
15
+ * and other assistive technologies.
16
+ *
17
+ * @example
18
+ * <div aria-hidden='true'>★★★☆☆</div>
19
+ * <VisuallyHidden>3 stars out of 5</VisuallyHidden>
20
+ *
21
+ * @see https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html
6
22
  */
7
- export declare const VisuallyHidden: React.ForwardRefExoticComponent<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
8
- ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject<HTMLDivElement> | null | undefined;
9
- }, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & React.RefAttributes<HTMLDivElement>>;
23
+ export declare const VisuallyHidden: PolymorphicForwardRefComponent<"span", VisuallyHiddenOwnProps>;
10
24
  export default VisuallyHidden;
@@ -13,11 +13,18 @@ const classnames_1 = __importDefault(require("classnames"));
13
13
  const hooks_1 = require("../hooks");
14
14
  require("@itwin/itwinui-css/css/utils.css");
15
15
  /**
16
- * Hides content visually but is still accessible to screen readers.
16
+ * Hides content visually but keeps it still accessible to screen readers
17
+ * and other assistive technologies.
18
+ *
19
+ * @example
20
+ * <div aria-hidden='true'>★★★☆☆</div>
21
+ * <VisuallyHidden>3 stars out of 5</VisuallyHidden>
22
+ *
23
+ * @see https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html
17
24
  */
18
25
  exports.VisuallyHidden = react_1.default.forwardRef((props, ref) => {
19
- const { className, ...rest } = props;
26
+ const { as: Element = 'span', className, unhideOnFocus = true, ...rest } = props;
20
27
  (0, hooks_1.useTheme)();
21
- return (react_1.default.createElement("div", { className: (0, classnames_1.default)('iui-visually-hidden', className), ref: ref, ...rest }));
28
+ return (react_1.default.createElement(Element, { className: (0, classnames_1.default)('iui-visually-hidden', className), "data-iui-unhide-on-focus": unhideOnFocus ? true : undefined, ref: ref, ...rest }));
22
29
  });
23
30
  exports.default = exports.VisuallyHidden;
@@ -8,4 +8,5 @@ export * from './VirtualScroll';
8
8
  export * from './VisuallyHidden';
9
9
  export * from './Icon';
10
10
  export * from './Flex';
11
+ export * from './Divider';
11
12
  export * from './LinkAction';
@@ -28,4 +28,5 @@ __exportStar(require("./VirtualScroll"), exports);
28
28
  __exportStar(require("./VisuallyHidden"), exports);
29
29
  __exportStar(require("./Icon"), exports);
30
30
  __exportStar(require("./Flex"), exports);
31
+ __exportStar(require("./Divider"), exports);
31
32
  __exportStar(require("./LinkAction"), exports);
@@ -3,3 +3,4 @@ export * from './colors';
3
3
  export * from './numbers';
4
4
  export * from './focusable';
5
5
  export * from './styles';
6
+ export * from './supports';
@@ -23,3 +23,4 @@ __exportStar(require("./colors"), exports);
23
23
  __exportStar(require("./numbers"), exports);
24
24
  __exportStar(require("./focusable"), exports);
25
25
  __exportStar(require("./styles"), exports);
26
+ __exportStar(require("./supports"), exports);
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Returns true if the :has selector is supported in the browser
3
+ */
4
+ export declare const supportsHas: () => boolean | undefined;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.supportsHas = void 0;
8
+ const dom_1 = require("./dom");
9
+ /**
10
+ * Returns true if the :has selector is supported in the browser
11
+ */
12
+ const supportsHas = () => { var _a, _b, _c; return (_c = (_b = (_a = (0, dom_1.getWindow)()) === null || _a === void 0 ? void 0 : _a.CSS) === null || _b === void 0 ? void 0 : _b.supports) === null || _c === void 0 ? void 0 : _c.call(_b, 'selector(:has(+ *))'); };
13
+ exports.supportsHas = supportsHas;
@@ -94,10 +94,11 @@ const useDragAndDrop = (elementRef, containerRef, enabled = true) => {
94
94
  originalUserSelect.current = elementRef.current.style.userSelect;
95
95
  // Prevents from selecting inner content when dragging.
96
96
  elementRef.current.style.userSelect = 'none';
97
- elementRef.current.ownerDocument.addEventListener('pointermove', onPointerMove.current);
98
- elementRef.current.ownerDocument.addEventListener('pointerup', () => {
97
+ const ownerDocument = elementRef.current.ownerDocument || document;
98
+ ownerDocument.addEventListener('pointermove', onPointerMove.current);
99
+ ownerDocument.addEventListener('pointerup', () => {
99
100
  setTransform(`translate(${translateX.current}px, ${translateY.current}px)`);
100
- document.removeEventListener('pointermove', onPointerMove.current);
101
+ ownerDocument.removeEventListener('pointermove', onPointerMove.current);
101
102
  if (elementRef.current) {
102
103
  elementRef.current.style.userSelect = originalUserSelect.current;
103
104
  }
@@ -1,10 +1,34 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.useTheme = void 0;
4
27
  /*---------------------------------------------------------------------------------------------
5
28
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
29
  * See LICENSE.md in the project root for license terms and full copyright notice.
7
30
  *--------------------------------------------------------------------------------------------*/
31
+ const React = __importStar(require("react"));
8
32
  const functions_1 = require("../functions");
9
33
  const useIsomorphicLayoutEffect_1 = require("./useIsomorphicLayoutEffect");
10
34
  const useIsThemeAlreadySet_1 = require("./useIsThemeAlreadySet");
@@ -23,6 +47,7 @@ const useTheme = (theme, themeOptions) => {
23
47
  var _a;
24
48
  const ownerDocument = (_a = themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.ownerDocument) !== null && _a !== void 0 ? _a : (0, functions_1.getDocument)();
25
49
  const isThemeAlreadySet = (0, useIsThemeAlreadySet_1.useIsThemeAlreadySet)(ownerDocument);
50
+ useCorrectRootFontSize();
26
51
  (0, useIsomorphicLayoutEffect_1.useIsomorphicLayoutEffect)(() => {
27
52
  if (!ownerDocument || isThemeAlreadySet.current) {
28
53
  return;
@@ -81,3 +106,22 @@ const handleTheme = (theme, ownerDocument, highContrast) => {
81
106
  (_b = prefersHCQuery === null || prefersHCQuery === void 0 ? void 0 : prefersHCQuery.removeEventListener) === null || _b === void 0 ? void 0 : _b.call(prefersHCQuery, 'change', changeHandler);
82
107
  };
83
108
  };
109
+ let didLogWarning = false;
110
+ let isDev = false;
111
+ // wrapping in try-catch because process might be undefined
112
+ try {
113
+ isDev = process.env.NODE_ENV !== 'production';
114
+ }
115
+ catch (_a) { }
116
+ /** Shows console error if the page changes the root font size */
117
+ const useCorrectRootFontSize = () => {
118
+ React.useEffect(() => {
119
+ if (isDev && !didLogWarning) {
120
+ const rootFontSize = parseInt(getComputedStyle(document.documentElement).fontSize);
121
+ if (rootFontSize < 16) {
122
+ console.error('Root font size must not be overridden. \nSee https://github.com/iTwin/iTwinUI/wiki/iTwinUI-react-v2-migration-guide#relative-font-size');
123
+ didLogWarning = true;
124
+ }
125
+ }
126
+ }, []);
127
+ };
@@ -4,7 +4,7 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import React from 'react';
6
6
  import cx from 'classnames';
7
- import { FocusTrap, getTranslateValues, useLatestRef, Resizer, useMergedRefs, useTheme, useIsomorphicLayoutEffect, } from '../utils';
7
+ import { FocusTrap, getTranslateValues, Resizer, useMergedRefs, useTheme, useIsomorphicLayoutEffect, } from '../utils';
8
8
  import '@itwin/itwinui-css/css/dialog.css';
9
9
  import { useDialogContext } from './DialogContext';
10
10
  import { CSSTransition } from 'react-transition-group';
@@ -38,28 +38,7 @@ export const DialogMain = React.forwardRef((props, ref) => {
38
38
  const dialogRef = React.useRef(null);
39
39
  const refs = useMergedRefs(dialogRef, ref);
40
40
  const hasBeenResized = React.useRef(false);
41
- // Focuses dialog when opened and brings back focus to the previously focused element when closed.
42
41
  const previousFocusedElement = React.useRef();
43
- const setFocusRef = useLatestRef(setFocus);
44
- React.useEffect(() => {
45
- var _a, _b, _c;
46
- if (!setFocusRef.current) {
47
- return;
48
- }
49
- if (isOpen) {
50
- previousFocusedElement.current = (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.activeElement;
51
- (_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.focus();
52
- }
53
- else {
54
- (_c = previousFocusedElement.current) === null || _c === void 0 ? void 0 : _c.focus();
55
- }
56
- const ref = dialogRef.current;
57
- return () => {
58
- var _a;
59
- (ref === null || ref === void 0 ? void 0 : ref.contains(document.activeElement)) &&
60
- ((_a = previousFocusedElement.current) === null || _a === void 0 ? void 0 : _a.focus());
61
- };
62
- }, [isOpen, setFocusRef]);
63
42
  const originalBodyOverflow = React.useRef('');
64
43
  React.useEffect(() => {
65
44
  if (isOpen) {
@@ -130,7 +109,6 @@ export const DialogMain = React.forwardRef((props, ref) => {
130
109
  const content = (React.createElement("div", { className: cx('iui-dialog', {
131
110
  'iui-dialog-default': styleType === 'default',
132
111
  'iui-dialog-full-page': styleType === 'fullPage',
133
- 'iui-dialog-visible': isOpen,
134
112
  'iui-dialog-draggable': isDraggable,
135
113
  }, className), role: 'dialog', ref: refs, onKeyDown: handleKeyDown, tabIndex: -1, style: {
136
114
  transform,
@@ -145,7 +123,24 @@ export const DialogMain = React.forwardRef((props, ref) => {
145
123
  }
146
124
  }, onResizeEnd: setResizeStyle })),
147
125
  children));
148
- return (React.createElement(CSSTransition, { in: isOpen, classNames: 'iui-dialog-animation', timeout: { exit: 600 }, unmountOnExit: true, nodeRef: dialogRef },
126
+ return (React.createElement(CSSTransition, { in: isOpen, classNames: {
127
+ enter: 'iui-dialog-animation-enter',
128
+ enterActive: 'iui-dialog-animation-enter-active',
129
+ enterDone: 'iui-dialog-visible',
130
+ }, timeout: { exit: 600 },
131
+ // Focuses dialog when opened
132
+ onEntered: () => {
133
+ var _a, _b;
134
+ previousFocusedElement.current = (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.activeElement;
135
+ setFocus && ((_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.focus({ preventScroll: true }));
136
+ },
137
+ // Brings back focus to the previously focused element when closed
138
+ onExit: () => {
139
+ var _a, _b, _c;
140
+ if ((_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.contains((_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument.activeElement)) {
141
+ (_c = previousFocusedElement.current) === null || _c === void 0 ? void 0 : _c.focus();
142
+ }
143
+ }, unmountOnExit: true, nodeRef: dialogRef },
149
144
  React.createElement(DialogDragContext.Provider, { value: { onPointerDown: handlePointerDown } },
150
145
  trapFocus && React.createElement(FocusTrap, null, content),
151
146
  !trapFocus && content)));
@@ -1,6 +1,15 @@
1
1
  import React from 'react';
2
- import { CommonProps } from '../utils';
2
+ import { CommonProps, PolymorphicComponentProps, PolymorphicForwardRefComponent } from '../utils';
3
3
  import '@itwin/itwinui-css/css/surface.css';
4
+ declare type SurfaceHeaderOwnProps = {};
5
+ export declare type SurfaceHeaderProps<T extends React.ElementType = 'div'> = PolymorphicComponentProps<T, SurfaceHeaderOwnProps>;
6
+ declare type SurfaceBodyOwnProps = {
7
+ /**
8
+ * Gives padding to the surface body
9
+ */
10
+ isPadded?: boolean;
11
+ };
12
+ export declare type SurfaceBodyProps<T extends React.ElementType = 'div'> = PolymorphicComponentProps<T, SurfaceBodyOwnProps>;
4
13
  export declare type SurfaceProps = {
5
14
  /**
6
15
  * Sets the elevation of the surface
@@ -16,6 +25,10 @@ export declare type SurfaceProps = {
16
25
  * @example
17
26
  * <Surface>Surface Content</Surface>
18
27
  * <Surface elevation={2}>Surface Content</Surface>
28
+ * <Surface>
29
+ * <Surface.Header>Surface Header Content</Surface.Header>
30
+ * <Surface.Body isPadded={true}>Surface Body Content</Surface.Body>
31
+ * </Surface>
19
32
  */
20
33
  export declare const Surface: React.ForwardRefExoticComponent<{
21
34
  /**
@@ -26,5 +39,14 @@ export declare const Surface: React.ForwardRefExoticComponent<{
26
39
  * Content in the surface.
27
40
  */
28
41
  children: React.ReactNode;
29
- } & Omit<CommonProps, "title"> & React.RefAttributes<HTMLDivElement>>;
42
+ } & Omit<CommonProps, "title"> & React.RefAttributes<HTMLDivElement>> & {
43
+ /**
44
+ * Surface header subcomponent
45
+ */
46
+ Header: PolymorphicForwardRefComponent<"div", SurfaceHeaderOwnProps>;
47
+ /**
48
+ * Surface body subcomponent. Additional padding can be added to the body through the 'isPadded' prop
49
+ */
50
+ Body: PolymorphicForwardRefComponent<"div", SurfaceBodyOwnProps>;
51
+ };
30
52
  export default Surface;
@@ -4,7 +4,7 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import React from 'react';
6
6
  import cx from 'classnames';
7
- import { useTheme } from '../utils';
7
+ import { useSafeContext, useTheme, supportsHas, } from '../utils';
8
8
  import '@itwin/itwinui-css/css/surface.css';
9
9
  /**
10
10
  * Helper function that returns one of the preset surface elevation values.
@@ -27,19 +27,55 @@ const getSurfaceElevationValue = (elevation) => {
27
27
  return '';
28
28
  }
29
29
  };
30
+ const SurfaceHeader = React.forwardRef((props, ref) => {
31
+ const { as: Element = 'div', children, className, ...rest } = props;
32
+ const { setHasLayout } = useSafeContext(SurfaceContext);
33
+ React.useEffect(() => {
34
+ if (!supportsHas()) {
35
+ setHasLayout(true);
36
+ }
37
+ }, [setHasLayout]);
38
+ return (React.createElement(Element, { className: cx('iui-surface-header', className), ref: ref, ...rest }, children));
39
+ });
40
+ const SurfaceBody = React.forwardRef((props, ref) => {
41
+ const { as: Element = 'div', children, className, isPadded, ...rest } = props;
42
+ const { setHasLayout } = useSafeContext(SurfaceContext);
43
+ React.useEffect(() => {
44
+ if (!supportsHas()) {
45
+ setHasLayout(true);
46
+ }
47
+ }, [setHasLayout]);
48
+ return (React.createElement(Element, { className: cx('iui-surface-body', className), ref: ref, "data-iui-padded": isPadded ? 'true' : undefined, ...rest }, children));
49
+ });
30
50
  /**
31
51
  * The Surface container allows content to appear elevated through the use of a drop shadow
32
52
  * @example
33
53
  * <Surface>Surface Content</Surface>
34
54
  * <Surface elevation={2}>Surface Content</Surface>
55
+ * <Surface>
56
+ * <Surface.Header>Surface Header Content</Surface.Header>
57
+ * <Surface.Body isPadded={true}>Surface Body Content</Surface.Body>
58
+ * </Surface>
35
59
  */
36
- export const Surface = React.forwardRef((props, ref) => {
60
+ export const Surface = Object.assign(React.forwardRef((props, ref) => {
37
61
  const { elevation, className, style, children, ...rest } = props;
38
62
  useTheme();
63
+ const [hasLayout, setHasLayout] = React.useState(false);
39
64
  const _style = {
40
65
  '--iui-surface-elevation': getSurfaceElevationValue(elevation),
41
66
  ...style,
42
67
  };
43
- return (React.createElement("div", { className: cx('iui-surface', className), style: _style, ref: ref, ...rest }, children));
68
+ return (React.createElement("div", { className: cx('iui-surface', className), style: _style, ref: ref, "data-iui-layout": hasLayout ? 'true' : undefined, ...rest },
69
+ React.createElement(SurfaceContext.Provider, { value: { setHasLayout } }, children)));
70
+ }), {
71
+ /**
72
+ * Surface header subcomponent
73
+ */
74
+ Header: SurfaceHeader,
75
+ /**
76
+ * Surface body subcomponent. Additional padding can be added to the body through the 'isPadded' prop
77
+ */
78
+ Body: SurfaceBody,
44
79
  });
80
+ const SurfaceContext = React.createContext(undefined);
45
81
  export default Surface;
@@ -1,4 +1,4 @@
1
1
  export { Surface } from './Surface';
2
- export type { SurfaceProps } from './Surface';
2
+ export type { SurfaceProps, SurfaceHeaderProps, SurfaceBodyProps, } from './Surface';
3
3
  declare const _default: "./Surface";
4
4
  export default _default;
@@ -4,7 +4,7 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import React from 'react';
6
6
  import cx from 'classnames';
7
- import { StatusIconMap, useTheme, SvgMore, SvgNew, SvgCheckmark, LinkAction, useSafeContext, getWindow, } from '../utils';
7
+ import { StatusIconMap, useTheme, SvgMore, SvgNew, SvgCheckmark, LinkAction, useSafeContext, supportsHas, } from '../utils';
8
8
  import '@itwin/itwinui-css/css/tile.css';
9
9
  import { DropdownMenu } from '../DropdownMenu';
10
10
  import { IconButton } from '../Buttons';
@@ -19,14 +19,12 @@ const TileContext = React.createContext(undefined);
19
19
  * />
20
20
  */
21
21
  export const TileAction = (props) => {
22
- var _a, _b, _c;
23
22
  const tileContext = useSafeContext(TileContext);
24
- const supportsHas = (_c = (_b = (_a = getWindow()) === null || _a === void 0 ? void 0 : _a.CSS) === null || _b === void 0 ? void 0 : _b.supports) === null || _c === void 0 ? void 0 : _c.call(_b, 'selector(:has(+ *))');
25
23
  React.useEffect(() => {
26
- if (!supportsHas) {
24
+ if (!supportsHas()) {
27
25
  tileContext.setActionable(true);
28
26
  }
29
- }, [supportsHas, tileContext]);
27
+ }, [tileContext]);
30
28
  return React.createElement(LinkAction, { ...props });
31
29
  };
32
30
  /**
@@ -79,7 +79,7 @@ export type { SliderProps } from './Slider';
79
79
  export { StatusMessage } from './StatusMessage';
80
80
  export type { StatusMessageProps } from './StatusMessage';
81
81
  export { Surface } from './Surface';
82
- export type { SurfaceProps } from './Surface';
82
+ export type { SurfaceProps, SurfaceHeaderProps, SurfaceBodyProps, } from './Surface';
83
83
  export { Table, tableFilters, BaseFilter, FilterButtonBar, DefaultCell, EditableCell, TablePaginator, ActionColumn, ExpanderColumn, SelectionColumn, } from './Table';
84
84
  export type { TableProps, TableFilterProps, TableFilterValue, DateRangeFilterOptions, FilterButtonBarProps, DefaultCellProps, EditableCellProps, TablePaginatorProps, TablePaginatorRendererProps, } from './Table';
85
85
  export { Tag, TagContainer } from './Tag';
@@ -104,5 +104,5 @@ export { Anchor, Body, Headline, Leading, Small, Subheading, Title, Blockquote,
104
104
  export type { AnchorProps, BodyProps, HeadlineProps, LeadingProps, SmallProps, SubheadingProps, TitleProps, BlockquoteProps, CodeProps, KbdProps, TextProps, } from './Typography';
105
105
  export { Wizard, Stepper, WorkflowDiagram } from './Stepper';
106
106
  export type { WizardProps, StepProperties, WizardType, WizardLocalization, StepperProps, StepperLocalization, WorkflowDiagramProps, } from './Stepper';
107
- export { getUserColor, useTheme, ColorValue, MiddleTextTruncation, LinkBox, LinkAction, Icon, Flex, } from './utils';
108
- export type { ThemeType, MiddleTextTruncationProps, IconProps, FlexProps, FlexItemProps, FlexSpacerProps, LinkBoxProps, LinkActionProps, } from './utils';
107
+ export { getUserColor, useTheme, ColorValue, MiddleTextTruncation, LinkBox, LinkAction, Icon, Flex, VisuallyHidden, Divider, } from './utils';
108
+ export type { ThemeType, MiddleTextTruncationProps, IconProps, FlexProps, FlexItemProps, FlexSpacerProps, DividerProps, LinkBoxProps, LinkActionProps, VisuallyHiddenProps, } from './utils';
package/esm/core/index.js CHANGED
@@ -55,4 +55,4 @@ export { Tooltip } from './Tooltip';
55
55
  export { Tree, TreeNode, TreeNodeExpander } from './Tree';
56
56
  export { Anchor, Body, Headline, Leading, Small, Subheading, Title, Blockquote, Code, Kbd, KbdKeys, Text, } from './Typography';
57
57
  export { Wizard, Stepper, WorkflowDiagram } from './Stepper';
58
- export { getUserColor, useTheme, ColorValue, MiddleTextTruncation, LinkBox, LinkAction, Icon, Flex, } from './utils';
58
+ export { getUserColor, useTheme, ColorValue, MiddleTextTruncation, LinkBox, LinkAction, Icon, Flex, VisuallyHidden, Divider, } from './utils';
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import '@itwin/itwinui-css/css/utils.css';
3
+ export declare type DividerProps = {
4
+ /**
5
+ * Sets the orientation of the divider
6
+ * @default 'horizontal'
7
+ */
8
+ orientation?: 'horizontal' | 'vertical';
9
+ } & React.ComponentPropsWithRef<'hr'>;
10
+ /**
11
+ * Shows a divider
12
+ */
13
+ export declare const Divider: React.ForwardRefExoticComponent<Pick<DividerProps, "key" | "orientation" | keyof React.HTMLAttributes<HTMLHRElement>> & React.RefAttributes<HTMLHRElement>>;
14
+ export default Divider;
@@ -0,0 +1,17 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import React from 'react';
6
+ import cx from 'classnames';
7
+ import { useTheme } from '../hooks';
8
+ import '@itwin/itwinui-css/css/utils.css';
9
+ /**
10
+ * Shows a divider
11
+ */
12
+ export const Divider = React.forwardRef((props, ref) => {
13
+ const { className, orientation = 'horizontal', ...rest } = props;
14
+ useTheme();
15
+ return (React.createElement("hr", { className: cx('iui-divider', className), "aria-orientation": orientation === 'vertical' ? 'vertical' : undefined, ref: ref, ...rest }));
16
+ });
17
+ export default Divider;
@@ -34,8 +34,9 @@ export const Resizer = (props) => {
34
34
  const minWidth = parseFloat(getComputedStyle(elementRef.current).minWidth);
35
35
  const minHeight = parseFloat(getComputedStyle(elementRef.current).minHeight);
36
36
  const resizer = event.currentTarget.dataset.iuiResizer;
37
- const originalUserSelect = elementRef.current.ownerDocument.body.style.userSelect;
38
- elementRef.current.ownerDocument.body.style.userSelect = 'none';
37
+ const ownerDocument = elementRef.current.ownerDocument || document;
38
+ const originalUserSelect = ownerDocument.body.style.userSelect;
39
+ ownerDocument.body.style.userSelect = 'none';
39
40
  const onResizePointerMove = (event) => {
40
41
  var _a, _b, _c, _d, _e, _f, _g;
41
42
  if (!elementRef.current) {
@@ -46,8 +47,8 @@ export const Resizer = (props) => {
46
47
  onResizeStart === null || onResizeStart === void 0 ? void 0 : onResizeStart();
47
48
  }
48
49
  const containerRect = (_a = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
49
- const clientX = getBoundedValue(event.clientX, (_b = containerRect === null || containerRect === void 0 ? void 0 : containerRect.left) !== null && _b !== void 0 ? _b : 0, (_d = (_c = containerRect === null || containerRect === void 0 ? void 0 : containerRect.right) !== null && _c !== void 0 ? _c : elementRef.current.ownerDocument.documentElement.clientWidth) !== null && _d !== void 0 ? _d : 0);
50
- const clientY = getBoundedValue(event.clientY, (_e = containerRect === null || containerRect === void 0 ? void 0 : containerRect.top) !== null && _e !== void 0 ? _e : 0, (_g = (_f = containerRect === null || containerRect === void 0 ? void 0 : containerRect.bottom) !== null && _f !== void 0 ? _f : elementRef.current.ownerDocument.documentElement.clientHeight) !== null && _g !== void 0 ? _g : 0);
50
+ const clientX = getBoundedValue(event.clientX, (_b = containerRect === null || containerRect === void 0 ? void 0 : containerRect.left) !== null && _b !== void 0 ? _b : 0, (_d = (_c = containerRect === null || containerRect === void 0 ? void 0 : containerRect.right) !== null && _c !== void 0 ? _c : ownerDocument.documentElement.clientWidth) !== null && _d !== void 0 ? _d : 0);
51
+ const clientY = getBoundedValue(event.clientY, (_e = containerRect === null || containerRect === void 0 ? void 0 : containerRect.top) !== null && _e !== void 0 ? _e : 0, (_g = (_f = containerRect === null || containerRect === void 0 ? void 0 : containerRect.bottom) !== null && _f !== void 0 ? _f : ownerDocument.documentElement.clientHeight) !== null && _g !== void 0 ? _g : 0);
51
52
  const diffX = initialPointerX - clientX;
52
53
  const diffY = initialPointerY - clientY;
53
54
  switch (resizer) {
@@ -122,12 +123,11 @@ export const Resizer = (props) => {
122
123
  break;
123
124
  }
124
125
  };
125
- elementRef.current.ownerDocument.addEventListener('pointermove', onResizePointerMove);
126
- elementRef.current.ownerDocument.addEventListener('pointerup', () => {
127
- document.removeEventListener('pointermove', onResizePointerMove);
126
+ ownerDocument.addEventListener('pointermove', onResizePointerMove);
127
+ ownerDocument.addEventListener('pointerup', () => {
128
+ ownerDocument.removeEventListener('pointermove', onResizePointerMove);
128
129
  if (elementRef.current) {
129
- elementRef.current.ownerDocument.body.style.userSelect =
130
- originalUserSelect;
130
+ ownerDocument.body.style.userSelect = originalUserSelect;
131
131
  isResizing.current = false;
132
132
  onResizeEnd === null || onResizeEnd === void 0 ? void 0 : onResizeEnd({
133
133
  width,
@@ -1,10 +1,24 @@
1
- import React from 'react';
2
1
  import '@itwin/itwinui-css/css/utils.css';
3
- export declare type VisuallyHiddenProps = React.ComponentPropsWithRef<'div'>;
2
+ import type { PolymorphicComponentProps, PolymorphicForwardRefComponent } from '../props';
3
+ declare type VisuallyHiddenOwnProps = {
4
+ /**
5
+ * When VisuallyHidden is used with an interactive element (e.g. button),
6
+ * that element will "unhide" (become visible again) when focused.
7
+ *
8
+ * @default true
9
+ */
10
+ unhideOnFocus?: boolean;
11
+ };
12
+ export declare type VisuallyHiddenProps = PolymorphicComponentProps<'span', VisuallyHiddenOwnProps>;
4
13
  /**
5
- * Hides content visually but is still accessible to screen readers.
14
+ * Hides content visually but keeps it still accessible to screen readers
15
+ * and other assistive technologies.
16
+ *
17
+ * @example
18
+ * <div aria-hidden='true'>★★★☆☆</div>
19
+ * <VisuallyHidden>3 stars out of 5</VisuallyHidden>
20
+ *
21
+ * @see https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html
6
22
  */
7
- export declare const VisuallyHidden: React.ForwardRefExoticComponent<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
8
- ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject<HTMLDivElement> | null | undefined;
9
- }, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & React.RefAttributes<HTMLDivElement>>;
23
+ export declare const VisuallyHidden: PolymorphicForwardRefComponent<"span", VisuallyHiddenOwnProps>;
10
24
  export default VisuallyHidden;
@@ -7,11 +7,18 @@ import cx from 'classnames';
7
7
  import { useTheme } from '../hooks';
8
8
  import '@itwin/itwinui-css/css/utils.css';
9
9
  /**
10
- * Hides content visually but is still accessible to screen readers.
10
+ * Hides content visually but keeps it still accessible to screen readers
11
+ * and other assistive technologies.
12
+ *
13
+ * @example
14
+ * <div aria-hidden='true'>★★★☆☆</div>
15
+ * <VisuallyHidden>3 stars out of 5</VisuallyHidden>
16
+ *
17
+ * @see https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html
11
18
  */
12
19
  export const VisuallyHidden = React.forwardRef((props, ref) => {
13
- const { className, ...rest } = props;
20
+ const { as: Element = 'span', className, unhideOnFocus = true, ...rest } = props;
14
21
  useTheme();
15
- return (React.createElement("div", { className: cx('iui-visually-hidden', className), ref: ref, ...rest }));
22
+ return (React.createElement(Element, { className: cx('iui-visually-hidden', className), "data-iui-unhide-on-focus": unhideOnFocus ? true : undefined, ref: ref, ...rest }));
16
23
  });
17
24
  export default VisuallyHidden;
@@ -8,4 +8,5 @@ export * from './VirtualScroll';
8
8
  export * from './VisuallyHidden';
9
9
  export * from './Icon';
10
10
  export * from './Flex';
11
+ export * from './Divider';
11
12
  export * from './LinkAction';
@@ -12,4 +12,5 @@ export * from './VirtualScroll';
12
12
  export * from './VisuallyHidden';
13
13
  export * from './Icon';
14
14
  export * from './Flex';
15
+ export * from './Divider';
15
16
  export * from './LinkAction';
@@ -3,3 +3,4 @@ export * from './colors';
3
3
  export * from './numbers';
4
4
  export * from './focusable';
5
5
  export * from './styles';
6
+ export * from './supports';
@@ -7,3 +7,4 @@ export * from './colors';
7
7
  export * from './numbers';
8
8
  export * from './focusable';
9
9
  export * from './styles';
10
+ export * from './supports';
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Returns true if the :has selector is supported in the browser
3
+ */
4
+ export declare const supportsHas: () => boolean | undefined;
@@ -0,0 +1,9 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { getWindow } from './dom';
6
+ /**
7
+ * Returns true if the :has selector is supported in the browser
8
+ */
9
+ export const supportsHas = () => { var _a, _b, _c; return (_c = (_b = (_a = getWindow()) === null || _a === void 0 ? void 0 : _a.CSS) === null || _b === void 0 ? void 0 : _b.supports) === null || _c === void 0 ? void 0 : _c.call(_b, 'selector(:has(+ *))'); };
@@ -88,10 +88,11 @@ export const useDragAndDrop = (elementRef, containerRef, enabled = true) => {
88
88
  originalUserSelect.current = elementRef.current.style.userSelect;
89
89
  // Prevents from selecting inner content when dragging.
90
90
  elementRef.current.style.userSelect = 'none';
91
- elementRef.current.ownerDocument.addEventListener('pointermove', onPointerMove.current);
92
- elementRef.current.ownerDocument.addEventListener('pointerup', () => {
91
+ const ownerDocument = elementRef.current.ownerDocument || document;
92
+ ownerDocument.addEventListener('pointermove', onPointerMove.current);
93
+ ownerDocument.addEventListener('pointerup', () => {
93
94
  setTransform(`translate(${translateX.current}px, ${translateY.current}px)`);
94
- document.removeEventListener('pointermove', onPointerMove.current);
95
+ ownerDocument.removeEventListener('pointermove', onPointerMove.current);
95
96
  if (elementRef.current) {
96
97
  elementRef.current.style.userSelect = originalUserSelect.current;
97
98
  }
@@ -2,6 +2,7 @@
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 * as React from 'react';
5
6
  import { getDocument, getWindow } from '../functions';
6
7
  import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
7
8
  import { useIsThemeAlreadySet } from './useIsThemeAlreadySet';
@@ -20,6 +21,7 @@ export const useTheme = (theme, themeOptions) => {
20
21
  var _a;
21
22
  const ownerDocument = (_a = themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.ownerDocument) !== null && _a !== void 0 ? _a : getDocument();
22
23
  const isThemeAlreadySet = useIsThemeAlreadySet(ownerDocument);
24
+ useCorrectRootFontSize();
23
25
  useIsomorphicLayoutEffect(() => {
24
26
  if (!ownerDocument || isThemeAlreadySet.current) {
25
27
  return;
@@ -77,3 +79,22 @@ const handleTheme = (theme, ownerDocument, highContrast) => {
77
79
  (_b = prefersHCQuery === null || prefersHCQuery === void 0 ? void 0 : prefersHCQuery.removeEventListener) === null || _b === void 0 ? void 0 : _b.call(prefersHCQuery, 'change', changeHandler);
78
80
  };
79
81
  };
82
+ let didLogWarning = false;
83
+ let isDev = false;
84
+ // wrapping in try-catch because process might be undefined
85
+ try {
86
+ isDev = process.env.NODE_ENV !== 'production';
87
+ }
88
+ catch (_a) { }
89
+ /** Shows console error if the page changes the root font size */
90
+ const useCorrectRootFontSize = () => {
91
+ React.useEffect(() => {
92
+ if (isDev && !didLogWarning) {
93
+ const rootFontSize = parseInt(getComputedStyle(document.documentElement).fontSize);
94
+ if (rootFontSize < 16) {
95
+ console.error('Root font size must not be overridden. \nSee https://github.com/iTwin/iTwinUI/wiki/iTwinUI-react-v2-migration-guide#relative-font-size');
96
+ didLogWarning = true;
97
+ }
98
+ }
99
+ }, []);
100
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/itwinui-react",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "author": "Bentley Systems",
5
5
  "license": "MIT",
6
6
  "main": "cjs/index.js",
@@ -62,7 +62,7 @@
62
62
  "dev:types": "concurrently \"tsc -p tsconfig.cjs.json --emitDeclarationOnly --watch --preserveWatchOutput\" \"tsc -p tsconfig.esm.json --emitDeclarationOnly --watch --preserveWatchOutput\""
63
63
  },
64
64
  "dependencies": {
65
- "@itwin/itwinui-css": "^1.8.0",
65
+ "@itwin/itwinui-css": "^1.9.0",
66
66
  "@itwin/itwinui-illustrations-react": "^2.0.0",
67
67
  "@itwin/itwinui-variables": "^2.0.0",
68
68
  "@tippyjs/react": "^4.2.6",