@itwin/itwinui-react 2.1.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +64 -39
  2. package/LICENSE.md +1 -1
  3. package/README.md +7 -7
  4. package/cjs/core/ComboBox/ComboBoxMenu.js +2 -1
  5. package/cjs/core/DatePicker/DatePicker.js +2 -2
  6. package/cjs/core/NotificationMarker/NotificationMarker.d.ts +51 -0
  7. package/cjs/core/NotificationMarker/NotificationMarker.js +32 -0
  8. package/cjs/core/NotificationMarker/index.d.ts +4 -0
  9. package/cjs/core/NotificationMarker/index.js +10 -0
  10. package/cjs/core/Table/Table.d.ts +1 -1
  11. package/cjs/core/Table/Table.js +19 -2
  12. package/cjs/core/Table/actionHandlers/filterHandler.d.ts +1 -1
  13. package/cjs/core/Table/actionHandlers/filterHandler.js +3 -2
  14. package/cjs/core/TimePicker/TimePicker.d.ts +26 -1
  15. package/cjs/core/TimePicker/TimePicker.js +89 -7
  16. package/cjs/core/index.d.ts +2 -0
  17. package/cjs/core/index.js +4 -2
  18. package/esm/core/ComboBox/ComboBoxMenu.js +2 -1
  19. package/esm/core/DatePicker/DatePicker.js +2 -2
  20. package/esm/core/NotificationMarker/NotificationMarker.d.ts +51 -0
  21. package/esm/core/NotificationMarker/NotificationMarker.js +26 -0
  22. package/esm/core/NotificationMarker/index.d.ts +4 -0
  23. package/esm/core/NotificationMarker/index.js +6 -0
  24. package/esm/core/Table/Table.d.ts +1 -1
  25. package/esm/core/Table/Table.js +19 -2
  26. package/esm/core/Table/actionHandlers/filterHandler.d.ts +1 -1
  27. package/esm/core/Table/actionHandlers/filterHandler.js +3 -2
  28. package/esm/core/TimePicker/TimePicker.d.ts +26 -1
  29. package/esm/core/TimePicker/TimePicker.js +89 -7
  30. package/esm/core/index.d.ts +2 -0
  31. package/esm/core/index.js +1 -0
  32. package/package.json +5 -6
package/CHANGELOG.md CHANGED
@@ -1,45 +1,69 @@
1
1
  # Changelog
2
2
 
3
- ### 2.1.1 (2022-12-16)
3
+ ## 2.2.1
4
4
 
5
- ### Fixes
5
+ ### Patch Changes
6
6
 
7
- * Use `import type` instead of `import { type }` for supporting older typescript versions ([#996](https://www.github.com/iTwin/iTwinUI-react/issues/996))
7
+ - 8e92e7e2: ComboBox dropdown width will now stay fixed when `enableVirtualization` is true.
8
+
9
+ ## [2.2.0](https://www.github.com/iTwin/iTwinUI-react/compare/v2.1.0...v2.2.0) (2022-12-19)
10
+
11
+ ### Minor changes
12
+
13
+ - **NotificationMarker:** Add new `NotificationMarker` component ([#829](https://www.github.com/iTwin/iTwinUI-react/issues/829))
14
+ - **Table:** `onFilter` gets filtered rows ([#958](https://www.github.com/iTwin/iTwinUI-react/issues/958))
15
+ - **Timepicker:** Add combined time column ([#844](https://www.github.com/iTwin/iTwinUI-react/issues/844))
16
+
17
+ ### Patch changes
18
+
19
+ - **Table:** Reset `columnOrder` when `columns` changes ([#983](https://www.github.com/iTwin/iTwinUI-react/issues/983))
20
+
21
+ ## 2.1.1 (2022-12-16)
22
+
23
+ ### Patch changes
24
+
25
+ - Use `import type` instead of `import { type }` for supporting older typescript versions ([#996](https://www.github.com/iTwin/iTwinUI-react/issues/996))
8
26
 
9
27
  ## [2.1.0](https://www.github.com/iTwin/iTwinUI-react/compare/v2.0.2...v2.1.0) (2022-12-12)
10
28
 
11
- ### What's new
29
+ ### Minor changes
30
+
31
+ - **Combobox:** Add support for multi-selection through `multiple` prop ([#830](https://www.github.com/iTwin/iTwinUI-react/issues/830))
32
+ - **ThemeProvider:** Add `applyBackground` to `themeOptions` prop. ([#974](https://www.github.com/iTwin/iTwinUI-react/issues/974))
33
+ - Defaults to true for the topmost ThemeProvider in the tree.
34
+ - **Table:** Ctrl + Shift click now keeps previous selection & also shift clicks ([#888](https://www.github.com/iTwin/iTwinUI-react/issues/888))
12
35
 
13
- * **Combobox:** Add support for multi-selection through `multiple` prop ([#830](https://www.github.com/iTwin/iTwinUI-react/issues/830)) ([ced7588](https://www.github.com/iTwin/iTwinUI-react/commit/ced7588acee5273e83c0b0d05a732f260997b9bb))
14
- * **ThemeProvider:** Add `applyBackground` to `themeOptions` prop. ([#974](https://www.github.com/iTwin/iTwinUI-react/issues/974)) ([13cff7f](https://www.github.com/iTwin/iTwinUI-react/commit/13cff7fab356e1015e2e7c361f15c6a7c8fe4d6b))
15
- * Defaults to true for the topmost ThemeProvider in the tree.
16
- * **Table:** Ctrl + Shift click now keeps previous selection & also shift clicks ([#888](https://www.github.com/iTwin/iTwinUI-react/issues/888)) ([13edfb5](https://www.github.com/iTwin/iTwinUI-react/commit/13edfb5ecc62de284ac03cc2fc27b8a41b4f7b61))
36
+ ### Patch changes
17
37
 
18
- ### Fixes
38
+ - **Table:** Ctrl and checkbox clicks update start row of shift selection ([#889](https://www.github.com/iTwin/iTwinUI-react/issues/889))
19
39
 
20
- * **Table:** Ctrl and checkbox clicks update start row of shift selection ([#889](https://www.github.com/iTwin/iTwinUI-react/issues/889)) ([21900d4](https://www.github.com/iTwin/iTwinUI-react/commit/21900d42900f7a03305bf2040cc64ddb29361b2d))
40
+ ## 2.0.4 (2022-12-16)
21
41
 
22
- ### 2.0.3 (2022-12-12)
42
+ ### Patch changes
23
43
 
24
- ### Fixes
44
+ - Use `import type` instead of `import { type }` for supporting older typescript versions ([#996](https://www.github.com/iTwin/iTwinUI-react/issues/996))
25
45
 
26
- * **ComboBox:** Move max-height to outer element to fix virtual scroll ([#986](https://www.github.com/iTwin/iTwinUI-react/issues/986)) ([596559e](https://www.github.com/iTwin/iTwinUI-react/commit/596559e7158877e09c98c5c672e8a58a9507a33d))
46
+ ## 2.0.3 (2022-12-12)
27
47
 
28
- ### [2.0.2](https://www.github.com/iTwin/iTwinUI-react/compare/v2.0.1...v2.0.2) (2022-12-07)
48
+ ### Patch changes
29
49
 
30
- ### Fixes
50
+ - **ComboBox:** Move max-height to outer element to fix virtual scroll ([#986](https://www.github.com/iTwin/iTwinUI-react/issues/986))
31
51
 
32
- * **ThemeProvider:** Improved types to exclude `ownerDocument` from `themeOptions` if children passed ([#973](https://www.github.com/iTwin/iTwinUI-react/issues/973)) ([36997de](https://www.github.com/iTwin/iTwinUI-react/commit/36997de383c4783c192318f2fb617289a7dce2dd))
52
+ ## [2.0.2](https://www.github.com/iTwin/iTwinUI-react/compare/v2.0.1...v2.0.2) (2022-12-07)
33
53
 
34
- ### [2.0.1](https://www.github.com/iTwin/iTwinUI-react/compare/v2.0.0...v2.0.1) (2022-12-05)
54
+ ### Patch changes
35
55
 
36
- ### Fixes
56
+ - **ThemeProvider:** Improved types to exclude `ownerDocument` from `themeOptions` if children passed ([#973](https://www.github.com/iTwin/iTwinUI-react/issues/973))
37
57
 
38
- * **useTheme:** Exit early if theme is already set on body ([#963](https://www.github.com/iTwin/iTwinUI-react/issues/963)) ([29033d4](https://www.github.com/iTwin/iTwinUI-react/commit/29033d488bc6cefb3ea064305898ade85475e2ff))
39
- * **ModalButtonBar, ModalContent:** Wrap `DialogButtonBar` and `DialogContent` instead of directly assigning ([#961](https://www.github.com/iTwin/iTwinUI-react/issues/961)) ([0881e92](https://www.github.com/iTwin/iTwinUI-react/commit/0881e92f037b7ce717f05742014ac2d6dd8c580d))
40
- * **Table:** Added localization for selected rows count ([#945](https://www.github.com/iTwin/iTwinUI-react/issues/945)) ([71f2326](https://www.github.com/iTwin/iTwinUI-react/commit/71f232605237e0095ebe0bff4cf01d241c143c49))
41
- * Replaced all instances of `useLayoutEffect` with `useIsomorphicLayoutEffect` to fix SSR warnings ([#964](https://www.github.com/iTwin/iTwinUI-react/issues/964)) ([15b0389](https://www.github.com/iTwin/iTwinUI-react/commit/15b038934e55d3f61631113d91f2952127426c1d))
42
- * Fixed css warnings about `start` vs `flex-start` through base itwinui-css update ([#962](https://www.github.com/iTwin/iTwinUI-react/issues/962))
58
+ ## [2.0.1](https://www.github.com/iTwin/iTwinUI-react/compare/v2.0.0...v2.0.1) (2022-12-05)
59
+
60
+ ### Patch changes
61
+
62
+ - **useTheme:** Exit early if theme is already set on body ([#963](https://www.github.com/iTwin/iTwinUI-react/issues/963))
63
+ - **ModalButtonBar, ModalContent:** Wrap `DialogButtonBar` and `DialogContent` instead of directly assigning ([#961](https://www.github.com/iTwin/iTwinUI-react/issues/961))
64
+ - **Table:** Added localization for selected rows count ([#945](https://www.github.com/iTwin/iTwinUI-react/issues/945))
65
+ - Replaced all instances of `useLayoutEffect` with `useIsomorphicLayoutEffect` to fix SSR warnings ([#964](https://www.github.com/iTwin/iTwinUI-react/issues/964))
66
+ - Fixed css warnings about `start` vs `flex-start` through base itwinui-css update ([#962](https://www.github.com/iTwin/iTwinUI-react/issues/962))
43
67
 
44
68
  ## [2.0.0](https://www.github.com/iTwin/iTwinUI-react/compare/v1.48.1...v2.0.0) (2022-11-15)
45
69
 
@@ -55,9 +79,10 @@ iTwinUI no longer supports Internet Explorer. The build output now targets `es20
55
79
 
56
80
  As for breaking API changes, there is only one:
57
81
 
58
- * **Table:** `columns` prop must now be an array. First level `Header` is no longer required ([#935](https://www.github.com/iTwin/iTwinUI-react/issues/935)) ([83d5cfe](https://www.github.com/iTwin/iTwinUI-react/commit/83d5cfe93980b628c79ec3951d05663a054699fc))
82
+ - **Table:** `columns` prop must now be an array. First level `Header` is no longer required ([#935](https://www.github.com/iTwin/iTwinUI-react/issues/935))
83
+
59
84
  ```diff
60
- - const columns = { Header: 'Table', columns: [{ accessor: 'name', Header: 'Name' }, … ] };
85
+ - const columns = [{ Header: 'Table', columns: [{ accessor: 'name', Header: 'Name' }, … ] }];
61
86
  + const columns = [{ accessor: 'name', Header: 'Name' }, … ];
62
87
 
63
88
  <Table columns={columns} data={data} />
@@ -65,29 +90,29 @@ As for breaking API changes, there is only one:
65
90
 
66
91
  Other than that, props and components that were already deprecated in v1 have been removed:
67
92
 
68
- * **Tabs:** Remove deprecated `HorizontalTab` and `HorizontalTabProps` ([#852](https://www.github.com/iTwin/iTwinUI-react/issues/852)) ([31ddeae](https://www.github.com/iTwin/iTwinUI-react/commit/31ddeaed3dc5919f69edb1bd9580d766fabc35c2))
69
- * **Checkbox, Radio:** Remove deprecated `checkmarkClassName` and `checkmarkStyle` ([#855](https://www.github.com/iTwin/iTwinUI-react/issues/855)) ([5c339be](https://www.github.com/iTwin/iTwinUI-react/commit/5c339beddd117bdf5a834b96dff65d4fd67d5255))
70
- * **Alert:** Remove deprecated `onClick` prop ([#851](https://www.github.com/iTwin/iTwinUI-react/issues/851)) ([f307fe9](https://www.github.com/iTwin/iTwinUI-react/commit/f307fe9448d0bf793885ddc0e5399cb8cd9dcadb))
93
+ - **Tabs:** Remove deprecated `HorizontalTab` and `HorizontalTabProps` ([#852](https://www.github.com/iTwin/iTwinUI-react/issues/852))
94
+ - **Checkbox, Radio:** Remove deprecated `checkmarkClassName` and `checkmarkStyle` ([#855](https://www.github.com/iTwin/iTwinUI-react/issues/855))
95
+ - **Alert:** Remove deprecated `onClick` prop ([#851](https://www.github.com/iTwin/iTwinUI-react/issues/851))
71
96
 
72
97
  ### Deprecations
73
98
 
74
99
  We have also taken this opportunity to deprecate a few more things while not removing them just yet, to minimize the number of breaking changes.
75
100
 
76
- * **Avatar, AvatarGroup:** Deprecate `UserIcon`/`UserIconGroup`, replace with `Avatar`/`AvatarGroup` ([#902](https://www.github.com/iTwin/iTwinUI-react/issues/902)) ([4001bd1](https://www.github.com/iTwin/iTwinUI-react/commit/4001bd12aa9021fdcbb3e49c271eec10ec853a83))
101
+ - **Avatar, AvatarGroup:** Deprecate `UserIcon`/`UserIconGroup`, replace with `Avatar`/`AvatarGroup` ([#902](https://www.github.com/iTwin/iTwinUI-react/issues/902))
77
102
  - Also deprecated `userIcon` prop in `Header`.
78
- * **Tabs:** Deprecate `HorizontalTabs`, `VerticalTabs` to use `Tabs` ([#908](https://www.github.com/iTwin/iTwinUI-react/issues/908)) ([f7e205e](https://www.github.com/iTwin/iTwinUI-react/commit/f7e205e9679169701bc52942ee7adf53679b8336))
79
- * **Typography:** Deprecate Headline, Leading, Small, Subheading, Title, Body. Replaced with `Text`. ([#914](https://www.github.com/iTwin/iTwinUI-react/issues/914)) ([30d6c02](https://www.github.com/iTwin/iTwinUI-react/commit/30d6c026a3a8e058418d25d382d030d68cbf20ff))
80
- * **Wizard:** Deprecate `Wizard` to use `Stepper`/`WorkflowDiagram` ([#905](https://www.github.com/iTwin/iTwinUI-react/issues/905)) ([8d16db3](https://www.github.com/iTwin/iTwinUI-react/commit/8d16db3350b60c548a7389d4a9ea0b95b3f9d6bd))
81
- * **ErrorPage:** Deprecate `ErrorPage` and add `NonIdealState` for lower bundle size and inversion of control. ([#924](https://www.github.com/iTwin/iTwinUI-react/issues/924)) ([88cafdb](https://www.github.com/iTwin/iTwinUI-react/commit/88cafdbcf2dd9af3ef9605fa676d2775ed59d7cb))
103
+ - **Tabs:** Deprecate `HorizontalTabs`, `VerticalTabs` to use `Tabs` ([#908](https://www.github.com/iTwin/iTwinUI-react/issues/908))
104
+ - **Typography:** Deprecate Headline, Leading, Small, Subheading, Title, Body. Replaced with `Text`. ([#914](https://www.github.com/iTwin/iTwinUI-react/issues/914))
105
+ - **Wizard:** Deprecate `Wizard` to use `Stepper`/`WorkflowDiagram` ([#905](https://www.github.com/iTwin/iTwinUI-react/issues/905))
106
+ - **ErrorPage:** Deprecate `ErrorPage` and add `NonIdealState` for lower bundle size and inversion of control. ([#924](https://www.github.com/iTwin/iTwinUI-react/issues/924))
82
107
 
83
108
  ### What's new
84
109
 
85
- * Allow scoped styles using `ThemeProvider` ([#825](https://github.com/iTwin/iTwinUI-react/pull/825))
86
- * Add `exports` field to package.json. This improves compatibility with ESM environments like vitest. ([#845](https://www.github.com/iTwin/iTwinUI-react/issues/845)) ([f58ca09](https://www.github.com/iTwin/iTwinUI-react/commit/f58ca09ae2301a10bc1a3d242c6feddccffea209))
87
- * Removed dependency on `@itwin/itwinui-icons`. The icons are now inlined. ([#917](https://www.github.com/iTwin/iTwinUI-react/issues/917)) ([a598632](https://www.github.com/iTwin/iTwinUI-react/commit/a5986322e46bd8146754ed963503fdafff5c2061))
88
- * **Table:** Add row loading state ([#871](https://www.github.com/iTwin/iTwinUI-react/issues/871)) ([22ac046](https://www.github.com/iTwin/iTwinUI-react/commit/22ac04661baba29fbfda49f9c2cb49176b26d7cb))
89
- * **Table:** Row selection count for paginator ([#837](https://www.github.com/iTwin/iTwinUI-react/issues/837)) ([e43148a](https://www.github.com/iTwin/iTwinUI-react/commit/e43148af9fc6250cf2470d258831a3ef8d33e582))
90
- * **Tile:** Add status and loading state ([#872](https://www.github.com/iTwin/iTwinUI-react/issues/872)) ([2fcb41f](https://www.github.com/iTwin/iTwinUI-react/commit/2fcb41f5c41a8a32d32a3312edecf8e2b646033e))
110
+ - Allow scoped styles using `ThemeProvider` ([#825](https://github.com/iTwin/iTwinUI-react/pull/825))
111
+ - Add `exports` field to package.json. This improves compatibility with ESM environments like vitest. ([#845](https://www.github.com/iTwin/iTwinUI-react/issues/845))
112
+ - Removed dependency on `@itwin/itwinui-icons`. The icons are now inlined. ([#917](https://www.github.com/iTwin/iTwinUI-react/issues/917))
113
+ - **Table:** Add row loading state ([#871](https://www.github.com/iTwin/iTwinUI-react/issues/871))
114
+ - **Table:** Row selection count for paginator ([#837](https://www.github.com/iTwin/iTwinUI-react/issues/837))
115
+ - **Tile:** Add status and loading state ([#872](https://www.github.com/iTwin/iTwinUI-react/issues/872))
91
116
 
92
117
  If you're interested in more details about every signle change, check out a full diff in [`v1.48.1..v2.0.0`](https://www.github.com/iTwin/iTwinUI-react/compare/v1.48.1...v2.0.0).
93
118
 
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright © Bentley Systems, Incorporated. All rights reserved.
3
+ Copyright © 2021-2023 Bentley Systems, Incorporated. All rights reserved.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
6
 
package/README.md CHANGED
@@ -16,14 +16,14 @@
16
16
  <div align="center">
17
17
 
18
18
  [![itwinui-react on npm](https://img.shields.io/npm/v/@itwin/itwinui-react)](https://www.npmjs.com/package/@itwin/itwinui-react)
19
- [![Build status](https://github.com/iTwin/iTwinUI-react/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/iTwin/iTwinUI-react/actions/workflows/build.yml?query=branch%3Amain)
19
+ [![Build status](https://github.com/iTwin/iTwinUI/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/iTwin/iTwinUI/actions/workflows/build.yml?query=branch%3Amain)
20
20
 
21
21
  </div>
22
22
 
23
23
  ## What is iTwinUI-react?
24
24
 
25
- iTwinUI-react is a library built on top of the [iTwinUI](https://github.com/iTwin/iTwinUI) library.
26
- The goal of this project is to provide React components for using the styles and components from the core `iTwinUI` project. Check out the [demo website](https://itwin.github.io/iTwinUI-react) to see the components in action.
25
+ iTwinUI-react is a React component library for [iTwinUI](https://github.com/iTwin/iTwinUI).
26
+ The goal of this package is to provide React components that make it easier to use the styles from [`@itwin/itwinui-css`](https://github.com/iTwin/iTwinUI/tree/main/packages/itwinui-css). Check out the [demo website](https://itwin.github.io/iTwinUI-react) to see the components in action.
27
27
 
28
28
  ---
29
29
 
@@ -80,17 +80,17 @@ const App = () => (
80
80
 
81
81
  ## FAQ
82
82
 
83
- For a list of frequently asked questions, visit the [wiki](https://github.com/iTwin/iTwinUI-react/wiki/FAQ).
83
+ For a list of frequently asked questions, visit the [wiki](https://github.com/iTwin/iTwinUI/wiki/FAQ).
84
84
 
85
85
  ---
86
86
 
87
87
  ## Contributing
88
88
 
89
- We welcome you to contribute and make this UI design system better. You can submit feature requests or bugs by creating an [issue](https://github.com/iTwin/iTwinUI-react/issues).
90
- Please read our [CONTRIBUTING.md](https://github.com/iTwin/iTwinUI-react/blob/main/CONTRIBUTING.md) for more information.
89
+ We welcome you to contribute and make this UI design system better. You can submit feature requests or bugs by creating an [issue](https://github.com/iTwin/iTwinUI/issues).
90
+ Please read our [CONTRIBUTING.md](https://github.com/iTwin/iTwinUI/blob/main/CONTRIBUTING.md) for more information.
91
91
 
92
92
  ---
93
93
 
94
94
  ## Changelog
95
95
 
96
- Read our [CHANGELOG.md](https://github.com/iTwin/iTwinUI-react/blob/main/packages/iTwinUI-react/CHANGELOG.md) to find recent changes.
96
+ Read our [CHANGELOG.md](https://github.com/iTwin/iTwinUI/blob/main/packages/itwinui-react/CHANGELOG.md) to find recent changes.
@@ -39,7 +39,8 @@ const VirtualizedComboBoxMenu = react_1.default.forwardRef(({ children, classNam
39
39
  });
40
40
  const surfaceStyles = {
41
41
  minWidth,
42
- maxWidth: `min(${minWidth * 2}px, 90vw)`,
42
+ // set as constant because we don't want it shifting when items are unmounted
43
+ maxWidth: minWidth,
43
44
  // max-height must be on the outermost element for virtual scroll
44
45
  maxHeight: 'calc((var(--iui-component-height) - 1px) * 8.5)',
45
46
  overflowY: isOverflowOverlaySupported() ? 'overlay' : 'auto',
@@ -130,7 +130,7 @@ exports.generateLocalizedStrings = generateLocalizedStrings;
130
130
  */
131
131
  const DatePicker = (props) => {
132
132
  var _a, _b, _c, _d, _e, _f, _g, _h;
133
- const { date, onChange, localizedNames, className, style, setFocus = false, showTime = false, use12Hours = false, precision, hourStep, minuteStep, secondStep, showYearSelection = false, enableRangeSelect = false, startDate, endDate, ...rest } = props;
133
+ const { date, onChange, localizedNames, className, style, setFocus = false, showTime = false, use12Hours = false, precision, hourStep, minuteStep, secondStep, useCombinedRenderer, combinedRenderer, hourRenderer, minuteRenderer, secondRenderer, meridiemRenderer, showYearSelection = false, enableRangeSelect = false, startDate, endDate, ...rest } = props;
134
134
  (0, utils_1.useTheme)();
135
135
  const monthNames = (_a = localizedNames === null || localizedNames === void 0 ? void 0 : localizedNames.months) !== null && _a !== void 0 ? _a : defaultMonths;
136
136
  const shortDays = (_b = localizedNames === null || localizedNames === void 0 ? void 0 : localizedNames.shortDays) !== null && _b !== void 0 ? _b : defaultShortDays;
@@ -368,7 +368,7 @@ const DatePicker = (props) => {
368
368
  (element === null || element === void 0 ? void 0 : element.focus()) }, dateValue));
369
369
  })));
370
370
  }))),
371
- showTime && (react_1.default.createElement(TimePicker_1.TimePicker, { date: selectedStartDay !== null && selectedStartDay !== void 0 ? selectedStartDay : selectedDay, use12Hours: use12Hours, precision: precision, hourStep: hourStep, minuteStep: minuteStep, secondStep: secondStep, onChange: (date) => {
371
+ showTime && (react_1.default.createElement(TimePicker_1.TimePicker, { date: selectedStartDay !== null && selectedStartDay !== void 0 ? selectedStartDay : selectedDay, use12Hours: use12Hours, precision: precision, hourStep: hourStep, minuteStep: minuteStep, secondStep: secondStep, useCombinedRenderer: useCombinedRenderer, combinedRenderer: combinedRenderer, hourRenderer: hourRenderer, minuteRenderer: minuteRenderer, secondRenderer: secondRenderer, meridiemRenderer: meridiemRenderer, onChange: (date) => {
372
372
  var _a, _b, _c, _d, _e, _f;
373
373
  return isSingleOnChange(onChange, enableRangeSelect)
374
374
  ? onChange === null || onChange === void 0 ? void 0 : onChange(date)
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import '@itwin/itwinui-css/css/utils.css';
3
+ export declare type NotificationMarkerProps = {
4
+ /**
5
+ * Content of the NotificationMarker.
6
+ */
7
+ children: React.ReactNode;
8
+ /**
9
+ * Status of notification
10
+ *
11
+ * - 'primary' = blue,
12
+ * - 'positive' = green,
13
+ * - 'warning' = orange,
14
+ * - 'negative' = red,
15
+ * - 'white' = white (useful for notifications in buttons with `style` = `high-visibility` | `cta`),
16
+ * @default 'primary'
17
+ */
18
+ status?: 'primary' | 'positive' | 'warning' | 'negative' | 'white';
19
+ /**
20
+ * Adds a pulse effect to the notification.
21
+ *
22
+ * **WARNING**: Avoid overuse of this prop.
23
+ * @default false
24
+ */
25
+ pulsing?: boolean;
26
+ /**
27
+ * Set this programmatically to false when you just want to render the passed children without the notification
28
+ * @default true
29
+ * @example
30
+ * let [newMessagesCount, ...] = useState(0);
31
+ * ...
32
+ * <NotificationMarker enabled={newMessagesCount > 0}>
33
+ * <SvgNotification />
34
+ * </NotificationMarker>
35
+ */
36
+ enabled?: boolean;
37
+ } & React.ComponentProps<'span'>;
38
+ /**
39
+ * A small notification circle to the top-right of the passed children prop.
40
+ * This can be applied to almost anything but mostly intended for icons within buttons with `styleType = default / borderless`.
41
+ * @example
42
+ * <IconButton styleType='borderless'>
43
+ * <NotificationMarker>
44
+ * <SvgNotification />
45
+ * </NotificationMarker>
46
+ * </IconButton>
47
+ * @example
48
+ * <NotificationMarker status='positive' pulsing={true}>Live</NotificationMarker>
49
+ */
50
+ export declare const NotificationMarker: React.ForwardRefExoticComponent<Pick<NotificationMarkerProps, "key" | "status" | keyof React.HTMLAttributes<HTMLSpanElement> | "enabled" | "pulsing"> & React.RefAttributes<HTMLSpanElement>>;
51
+ export default NotificationMarker;
@@ -0,0 +1,32 @@
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.NotificationMarker = 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 utils_1 = require("../utils");
13
+ const classnames_1 = __importDefault(require("classnames"));
14
+ require("@itwin/itwinui-css/css/utils.css");
15
+ /**
16
+ * A small notification circle to the top-right of the passed children prop.
17
+ * This can be applied to almost anything but mostly intended for icons within buttons with `styleType = default / borderless`.
18
+ * @example
19
+ * <IconButton styleType='borderless'>
20
+ * <NotificationMarker>
21
+ * <SvgNotification />
22
+ * </NotificationMarker>
23
+ * </IconButton>
24
+ * @example
25
+ * <NotificationMarker status='positive' pulsing={true}>Live</NotificationMarker>
26
+ */
27
+ exports.NotificationMarker = react_1.default.forwardRef((props, ref) => {
28
+ const { className, children, status = 'primary', pulsing = false, enabled = true, ...rest } = props;
29
+ (0, utils_1.useTheme)();
30
+ return (react_1.default.createElement("span", { ref: ref, className: (0, classnames_1.default)({ 'iui-notification-marker': enabled }, className), "data-iui-variant": enabled ? status : null, "data-iui-urgent": enabled ? pulsing : null, ...rest }, children));
31
+ });
32
+ exports.default = exports.NotificationMarker;
@@ -0,0 +1,4 @@
1
+ export { NotificationMarker } from './NotificationMarker';
2
+ export type { NotificationMarkerProps } from './NotificationMarker';
3
+ declare const _default: "./NotificationMarker";
4
+ export default _default;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotificationMarker = void 0;
4
+ /*---------------------------------------------------------------------------------------------
5
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
+ * See LICENSE.md in the project root for license terms and full copyright notice.
7
+ *--------------------------------------------------------------------------------------------*/
8
+ var NotificationMarker_1 = require("./NotificationMarker");
9
+ Object.defineProperty(exports, "NotificationMarker", { enumerable: true, get: function () { return NotificationMarker_1.NotificationMarker; } });
10
+ exports.default = './NotificationMarker';
@@ -117,7 +117,7 @@ export declare type TableProps<T extends Record<string, unknown> = Record<string
117
117
  * Use with `manualFilters` to handle filtering yourself e.g. filter in server-side.
118
118
  * Must be memoized.
119
119
  */
120
- onFilter?: (filters: TableFilterValue<T>[], state: TableState<T>) => void;
120
+ onFilter?: (filters: TableFilterValue<T>[], state: TableState<T>, filteredData?: Row<T>[]) => void;
121
121
  /**
122
122
  * Value used for global filtering.
123
123
  * Use with `globalFilter` and/or `manualGlobalFilter` to handle filtering yourself e.g. filter in server-side.
@@ -123,13 +123,15 @@ const Table = (props) => {
123
123
  disableUserSelect,
124
124
  enableUserSelect,
125
125
  ]);
126
+ const previousFilter = react_1.default.useRef([]);
127
+ const currentFilter = react_1.default.useRef(previousFilter.current);
126
128
  const tableStateReducer = react_1.default.useCallback((newState, action, previousState, instance) => {
127
129
  switch (action.type) {
128
130
  case react_table_1.actions.toggleSortBy:
129
131
  onSort === null || onSort === void 0 ? void 0 : onSort(newState);
130
132
  break;
131
133
  case react_table_1.actions.setFilter:
132
- (0, actionHandlers_1.onFilterHandler)(newState, action, previousState, instance, onFilter);
134
+ currentFilter.current = (0, actionHandlers_1.onFilterHandler)(newState, action, previousState, currentFilter.current, instance);
133
135
  break;
134
136
  case react_table_1.actions.toggleRowExpanded:
135
137
  case react_table_1.actions.toggleAllRowsExpanded:
@@ -173,7 +175,6 @@ const Table = (props) => {
173
175
  hasManualSelectionColumn,
174
176
  isRowDisabled,
175
177
  onExpand,
176
- onFilter,
177
178
  onSelect,
178
179
  onSort,
179
180
  stateReducer,
@@ -249,6 +250,22 @@ const Table = (props) => {
249
250
  react_1.default.useEffect(() => {
250
251
  setPageSize(pageSize);
251
252
  }, [pageSize, setPageSize]);
253
+ react_1.default.useEffect(() => {
254
+ if (previousFilter.current !== currentFilter.current) {
255
+ previousFilter.current = currentFilter.current;
256
+ onFilter === null || onFilter === void 0 ? void 0 : onFilter(currentFilter.current, state, instance.filteredRows);
257
+ }
258
+ }, [state, instance.filteredRows, onFilter]);
259
+ const lastPassedColumns = react_1.default.useRef([]);
260
+ // Reset the column order whenever new columns are passed
261
+ // This is to avoid the old columnOrder from affecting the new columns' columnOrder
262
+ react_1.default.useEffect(() => {
263
+ // Check if columns have changed (by value)
264
+ if (JSON.stringify(lastPassedColumns.current) !== JSON.stringify(columns)) {
265
+ instance.setColumnOrder([]);
266
+ }
267
+ lastPassedColumns.current = columns;
268
+ }, [columns, instance]);
252
269
  const paginatorRendererProps = react_1.default.useMemo(() => ({
253
270
  currentPage: state.pageIndex,
254
271
  pageSize: state.pageSize,
@@ -1,3 +1,3 @@
1
1
  import { ActionType, TableInstance, TableState } from 'react-table';
2
2
  import { TableFilterValue } from '../filters';
3
- export declare const onFilterHandler: <T extends Record<string, unknown>>(newState: TableState<T>, action: ActionType, previousState: TableState<T>, instance?: TableInstance<T> | undefined, onFilter?: ((filters: TableFilterValue<T>[], state: TableState<T>) => void) | undefined) => void;
3
+ export declare const onFilterHandler: <T extends Record<string, unknown>>(newState: TableState<T>, action: ActionType, previousState: TableState<T>, currentFilter: TableFilterValue<T>[], instance?: TableInstance<T> | undefined) => TableFilterValue<T>[];
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.onFilterHandler = void 0;
4
- const onFilterHandler = (newState, action, previousState, instance, onFilter) => {
4
+ const onFilterHandler = (newState, action, previousState, currentFilter, instance) => {
5
5
  const previousFilter = previousState.filters.find((f) => f.id === action.columnId);
6
6
  if ((previousFilter === null || previousFilter === void 0 ? void 0 : previousFilter.value) != action.filterValue) {
7
7
  const filters = newState.filters.map((f) => {
@@ -14,7 +14,8 @@ const onFilterHandler = (newState, action, previousState, instance, onFilter) =>
14
14
  filterType: (_b = column === null || column === void 0 ? void 0 : column.filter) !== null && _b !== void 0 ? _b : 'text',
15
15
  };
16
16
  });
17
- onFilter === null || onFilter === void 0 ? void 0 : onFilter(filters, newState);
17
+ return filters;
18
18
  }
19
+ return currentFilter;
19
20
  };
20
21
  exports.onFilterHandler = onFilterHandler;
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { StylingProps } from '../utils';
3
3
  import '@itwin/itwinui-css/css/time-picker.css';
4
4
  export declare type MeridiemType = 'AM' | 'PM';
5
+ export declare type Precision = 'hours' | 'minutes' | 'seconds';
5
6
  export declare type TimePickerProps = {
6
7
  /**
7
8
  * Selected date. Only time is used from Date object.
@@ -20,7 +21,7 @@ export declare type TimePickerProps = {
20
21
  * Precision of the time.
21
22
  * @default 'minutes'
22
23
  */
23
- precision?: 'hours' | 'minutes' | 'seconds';
24
+ precision?: Precision;
24
25
  /**
25
26
  * Change step of the hours displayed.
26
27
  * @default 1
@@ -61,6 +62,30 @@ export declare type TimePickerProps = {
61
62
  * @default (meridiem: MeridiemType) => meridiem
62
63
  */
63
64
  meridiemRenderer?: (meridiem: MeridiemType) => React.ReactNode;
65
+ /**
66
+ * Use combined time renderer. Combines hour, minute, and seconds into one column.
67
+ * **WARNING**: Using the combined renderer with a `precision` of 'seconds' along with
68
+ * small time steps (`hourStep`, `minuteStep`, and especially `secondStep`) can result in slow performance!
69
+ * @default false
70
+ */
71
+ useCombinedRenderer?: boolean;
72
+ /**
73
+ * Custom combined time renderer.
74
+ * Default returns time in `HH:MM:SS` format
75
+ * @default (date: Date, precision: Precision) => {
76
+ * let dateString = '';
77
+ * switch (precision) {
78
+ * case 'seconds':
79
+ * dateString = ':' + date.getSeconds().toLocaleString(undefined, { minimumIntegerDigits: 2 });
80
+ * case 'minutes':
81
+ * dateString = ':' + date.getMinutes().toLocaleString(undefined, { minimumIntegerDigits: 2 }) + dateString;
82
+ * case 'hours':
83
+ * dateString = date.getHours().toLocaleString(undefined, { minimumIntegerDigits: 2 }) + dateString;
84
+ * }
85
+ * return dateString;
86
+ * }
87
+ */
88
+ combinedRenderer?: (date: Date, precision: Precision) => React.ReactNode;
64
89
  } & StylingProps;
65
90
  /**
66
91
  * Time picker component
@@ -27,6 +27,24 @@ const isSameMinute = (date1, date2) => {
27
27
  const isSameSecond = (date1, date2) => {
28
28
  return !!date2 && date1.getSeconds() === date2.getSeconds();
29
29
  };
30
+ const isSameTime = (date1, date2, precision, meridiem) => {
31
+ let isSameTime = true;
32
+ switch (precision) {
33
+ case 'seconds':
34
+ isSameTime = isSameSecond(date1, date2);
35
+ if (!isSameTime) {
36
+ break;
37
+ }
38
+ case 'minutes':
39
+ isSameTime = isSameMinute(date1, date2);
40
+ if (!isSameTime) {
41
+ break;
42
+ }
43
+ case 'hours':
44
+ isSameTime = isSameHour(date1, date2, meridiem);
45
+ }
46
+ return isSameTime;
47
+ };
30
48
  const isSameMeridiem = (meridiem, date) => {
31
49
  return (!!date && (meridiem === 'AM' ? date.getHours() < 12 : date.getHours() >= 12));
32
50
  };
@@ -37,13 +55,36 @@ const formatHourFrom12 = (hour, meridiem) => {
37
55
  const setHours = (hour, date) => {
38
56
  return new Date(date.getFullYear(), date.getMonth(), date.getDate(), hour, date.getMinutes(), date.getSeconds());
39
57
  };
58
+ const defaultCombinedRenderer = (date, precision) => {
59
+ let dateString = '';
60
+ switch (precision) {
61
+ case 'seconds':
62
+ dateString =
63
+ ':' +
64
+ date
65
+ .getSeconds()
66
+ .toLocaleString(undefined, { minimumIntegerDigits: 2 });
67
+ case 'minutes':
68
+ dateString =
69
+ ':' +
70
+ date
71
+ .getMinutes()
72
+ .toLocaleString(undefined, { minimumIntegerDigits: 2 }) +
73
+ dateString;
74
+ case 'hours':
75
+ dateString =
76
+ date.getHours().toLocaleString(undefined, { minimumIntegerDigits: 2 }) +
77
+ dateString;
78
+ }
79
+ return dateString;
80
+ };
40
81
  /**
41
82
  * Time picker component
42
83
  * @example
43
84
  * <TimePicker date={new Date()} onChange={(e) => console.log('New time value: ' + e)} />
44
85
  */
45
86
  const TimePicker = (props) => {
46
- const { date, onChange, use12Hours = false, precision = 'minutes', hourStep = 1, minuteStep = 1, secondStep = 1, setFocusHour = false, hourRenderer = (date) => date.getHours().toLocaleString(undefined, { minimumIntegerDigits: 2 }), minuteRenderer = (date) => date.getMinutes().toLocaleString(undefined, { minimumIntegerDigits: 2 }), secondRenderer = (date) => date.getSeconds().toLocaleString(undefined, { minimumIntegerDigits: 2 }), meridiemRenderer = (meridiem) => meridiem, className, ...rest } = props;
87
+ const { date, onChange, use12Hours = false, precision = 'minutes', hourStep = 1, minuteStep = 1, secondStep = 1, setFocusHour = false, hourRenderer = (date) => date.getHours().toLocaleString(undefined, { minimumIntegerDigits: 2 }), minuteRenderer = (date) => date.getMinutes().toLocaleString(undefined, { minimumIntegerDigits: 2 }), secondRenderer = (date) => date.getSeconds().toLocaleString(undefined, { minimumIntegerDigits: 2 }), meridiemRenderer = (meridiem) => meridiem, useCombinedRenderer = false, combinedRenderer = defaultCombinedRenderer, className, ...rest } = props;
47
88
  (0, utils_1.useTheme)();
48
89
  const [selectedTime, setSelectedTime] = react_1.default.useState(date);
49
90
  const [focusedTime, setFocusedTime] = react_1.default.useState(selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date());
@@ -59,6 +100,13 @@ const TimePicker = (props) => {
59
100
  const adjustedSelectedTime = setHours(adjustedHour, selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date());
60
101
  updateCurrentTime(adjustedSelectedTime);
61
102
  };
103
+ const onTimeClick = (date) => {
104
+ const adjustedHour = use12Hours
105
+ ? formatHourFrom12(date.getHours(), meridiem)
106
+ : date.getHours();
107
+ const adjustedSelectedTime = setHours(adjustedHour, date);
108
+ updateCurrentTime(adjustedSelectedTime);
109
+ };
62
110
  const onMeridiemClick = (value) => {
63
111
  let adjustedSelectedTime = selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date();
64
112
  const currentHours = adjustedSelectedTime.getHours();
@@ -90,6 +138,12 @@ const TimePicker = (props) => {
90
138
  : date.getHours();
91
139
  setFocusedTime(setHours(adjustedHour, focusedTime));
92
140
  };
141
+ const onTimeFocus = (date) => {
142
+ const adjustedHour = use12Hours
143
+ ? formatHourFrom12(date.getHours(), meridiem)
144
+ : date.getHours();
145
+ setFocusedTime(setHours(adjustedHour, date));
146
+ };
93
147
  const onMeridiemFocus = (value) => {
94
148
  let adjustedSelectedTime = selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date();
95
149
  const currentHours = adjustedSelectedTime.getHours();
@@ -105,13 +159,40 @@ const TimePicker = (props) => {
105
159
  };
106
160
  const generateDataList = (size, value, step) => {
107
161
  const data = [];
108
- for (let i = 0; i < size; ++i) {
162
+ for (let i = 0; i < size; i++) {
109
163
  if (i % step === 0) {
110
164
  data.push(value(i));
111
165
  }
112
166
  }
113
167
  return data;
114
168
  };
169
+ const time = react_1.default.useMemo(() => {
170
+ const time = selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date();
171
+ const data = [];
172
+ const hoursArray = Array.from(Array(use12Hours ? 12 : 24).keys())
173
+ .filter((i) => i % hourStep === 0)
174
+ .map((i) => (use12Hours && i === 0 ? 12 : i));
175
+ const minutesArray = Array.from(Array(60).keys()).filter((i) => i % minuteStep === 0);
176
+ const secondsArray = Array.from(Array(60).keys()).filter((i) => i % secondStep === 0);
177
+ hoursArray.forEach((hour) => {
178
+ if (precision === 'hours') {
179
+ data.push(new Date(time.getFullYear(), time.getMonth(), time.getDate(), hour, time.getMinutes(), time.getSeconds()));
180
+ }
181
+ else {
182
+ minutesArray.forEach((minute) => {
183
+ if (precision === 'minutes') {
184
+ data.push(new Date(time.getFullYear(), time.getMonth(), time.getDate(), hour, minute, time.getSeconds()));
185
+ }
186
+ else {
187
+ secondsArray.forEach((second) => {
188
+ data.push(new Date(time.getFullYear(), time.getMonth(), time.getDate(), hour, minute, second));
189
+ });
190
+ }
191
+ });
192
+ }
193
+ });
194
+ return data;
195
+ }, [hourStep, minuteStep, secondStep, selectedTime, use12Hours, precision]);
115
196
  const hours = react_1.default.useMemo(() => {
116
197
  const time = selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date();
117
198
  return generateDataList(use12Hours ? 12 : 24, (i) => new Date(time.getFullYear(), time.getMonth(), time.getDate(), use12Hours && i === 0 ? 12 : i, time.getMinutes(), time.getSeconds()), hourStep);
@@ -125,14 +206,15 @@ const TimePicker = (props) => {
125
206
  return generateDataList(60, (i) => new Date(time.getFullYear(), time.getMonth(), time.getDate(), time.getHours(), time.getMinutes(), i), secondStep);
126
207
  }, [secondStep, selectedTime]);
127
208
  return (react_1.default.createElement("div", { className: (0, classnames_1.default)('iui-time-picker', className), ...rest },
128
- react_1.default.createElement(TimePickerColumn, { data: hours, isSameFocused: (val) => isSameHour(val, focusedTime, use12Hours ? meridiem : undefined), isSameSelected: (val) => isSameHour(val, selectedTime, use12Hours ? meridiem : undefined), onFocusChange: onHourFocus, onSelectChange: onHourClick, setFocus: setFocusHour, valueRenderer: hourRenderer }),
129
- precision != 'hours' && (react_1.default.createElement(TimePickerColumn, { data: minutes, isSameFocused: (val) => isSameMinute(val, focusedTime), isSameSelected: (val) => isSameMinute(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: minuteRenderer })),
130
- precision == 'seconds' && (react_1.default.createElement(TimePickerColumn, { data: seconds, isSameFocused: (val) => isSameSecond(val, focusedTime), isSameSelected: (val) => isSameSecond(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: secondRenderer })),
209
+ useCombinedRenderer ? (react_1.default.createElement(TimePickerColumn, { data: time, isSameFocused: (val) => isSameTime(val, focusedTime, precision, use12Hours ? meridiem : undefined), isSameSelected: (val) => isSameTime(val, selectedTime, precision, use12Hours ? meridiem : undefined), onFocusChange: onTimeFocus, onSelectChange: onTimeClick, setFocus: setFocusHour, precision: precision, valueRenderer: combinedRenderer })) : (react_1.default.createElement(react_1.default.Fragment, null,
210
+ react_1.default.createElement(TimePickerColumn, { data: hours, isSameFocused: (val) => isSameHour(val, focusedTime, use12Hours ? meridiem : undefined), isSameSelected: (val) => isSameHour(val, selectedTime, use12Hours ? meridiem : undefined), onFocusChange: onHourFocus, onSelectChange: onHourClick, setFocus: setFocusHour, valueRenderer: hourRenderer }),
211
+ precision !== 'hours' && (react_1.default.createElement(TimePickerColumn, { data: minutes, isSameFocused: (val) => isSameMinute(val, focusedTime), isSameSelected: (val) => isSameMinute(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: minuteRenderer })),
212
+ precision === 'seconds' && (react_1.default.createElement(TimePickerColumn, { data: seconds, isSameFocused: (val) => isSameSecond(val, focusedTime), isSameSelected: (val) => isSameSecond(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: secondRenderer })))),
131
213
  use12Hours && (react_1.default.createElement(TimePickerColumn, { data: ['AM', 'PM'], isSameFocused: (val) => isSameMeridiem(val, focusedTime), isSameSelected: (val) => isSameMeridiem(val, selectedTime), onFocusChange: (date) => onMeridiemFocus(date), onSelectChange: (value) => onMeridiemClick(value), valueRenderer: meridiemRenderer, className: 'iui-period' }))));
132
214
  };
133
215
  exports.TimePicker = TimePicker;
134
216
  const TimePickerColumn = (props) => {
135
- const { data, onFocusChange, onSelectChange, isSameFocused, isSameSelected, setFocus = false, valueRenderer, className = 'iui-time', } = props;
217
+ const { data, onFocusChange, onSelectChange, isSameFocused, isSameSelected, setFocus = false, valueRenderer, precision = 'minutes', className = 'iui-time', } = props;
136
218
  const needFocus = react_1.default.useRef(setFocus);
137
219
  // Used to focus row only when changed (keyboard navigation)
138
220
  // e.g. without this on every rerender it would be focused
@@ -182,7 +264,7 @@ const TimePickerColumn = (props) => {
182
264
  needFocus.current && isSameFocus && (ref === null || ref === void 0 ? void 0 : ref.focus());
183
265
  }, onClick: () => {
184
266
  onSelectChange(value);
185
- } }, valueRenderer(value)));
267
+ } }, valueRenderer(value, precision)));
186
268
  }))));
187
269
  };
188
270
  exports.default = exports.TimePicker;
@@ -60,6 +60,8 @@ export { Menu, MenuItem, MenuDivider, MenuExtraContent, MenuItemSkeleton, } from
60
60
  export type { MenuProps, MenuItemProps, MenuDividerProps, MenuExtraContentProps, MenuItemSkeletonProps, } from './Menu';
61
61
  export { Modal, ModalButtonBar, ModalContent } from './Modal';
62
62
  export type { ModalProps, ModalButtonBarProps, ModalContentProps, } from './Modal';
63
+ export { NotificationMarker } from './NotificationMarker';
64
+ export type { NotificationMarkerProps } from './NotificationMarker';
63
65
  export { ProgressLinear, ProgressRadial } from './ProgressIndicators';
64
66
  export type { ProgressLinearProps, ProgressRadialProps, } from './ProgressIndicators';
65
67
  export { Radio } from './Radio';
package/cjs/core/index.js CHANGED
@@ -4,8 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.LabeledInput = exports.Label = 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.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
- exports.Headline = exports.Body = exports.Anchor = 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.ModalContent = exports.ModalButtonBar = exports.Modal = exports.MenuItemSkeleton = exports.MenuExtraContent = exports.MenuDivider = exports.MenuItem = exports.Menu = exports.LabeledTextarea = exports.LabeledSelect = exports.InputGroup = void 0;
8
- 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 = void 0;
7
+ exports.Body = exports.Anchor = 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 = void 0;
8
+ 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 = 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.
@@ -102,6 +102,8 @@ var Modal_1 = require("./Modal");
102
102
  Object.defineProperty(exports, "Modal", { enumerable: true, get: function () { return Modal_1.Modal; } });
103
103
  Object.defineProperty(exports, "ModalButtonBar", { enumerable: true, get: function () { return Modal_1.ModalButtonBar; } });
104
104
  Object.defineProperty(exports, "ModalContent", { enumerable: true, get: function () { return Modal_1.ModalContent; } });
105
+ var NotificationMarker_1 = require("./NotificationMarker");
106
+ Object.defineProperty(exports, "NotificationMarker", { enumerable: true, get: function () { return NotificationMarker_1.NotificationMarker; } });
105
107
  var ProgressIndicators_1 = require("./ProgressIndicators");
106
108
  Object.defineProperty(exports, "ProgressLinear", { enumerable: true, get: function () { return ProgressIndicators_1.ProgressLinear; } });
107
109
  Object.defineProperty(exports, "ProgressRadial", { enumerable: true, get: function () { return ProgressIndicators_1.ProgressRadial; } });
@@ -33,7 +33,8 @@ const VirtualizedComboBoxMenu = React.forwardRef(({ children, className, style,
33
33
  });
34
34
  const surfaceStyles = {
35
35
  minWidth,
36
- maxWidth: `min(${minWidth * 2}px, 90vw)`,
36
+ // set as constant because we don't want it shifting when items are unmounted
37
+ maxWidth: minWidth,
37
38
  // max-height must be on the outermost element for virtual scroll
38
39
  maxHeight: 'calc((var(--iui-component-height) - 1px) * 8.5)',
39
40
  overflowY: isOverflowOverlaySupported() ? 'overlay' : 'auto',
@@ -123,7 +123,7 @@ export const generateLocalizedStrings = (locale) => {
123
123
  */
124
124
  export const DatePicker = (props) => {
125
125
  var _a, _b, _c, _d, _e, _f, _g, _h;
126
- const { date, onChange, localizedNames, className, style, setFocus = false, showTime = false, use12Hours = false, precision, hourStep, minuteStep, secondStep, showYearSelection = false, enableRangeSelect = false, startDate, endDate, ...rest } = props;
126
+ const { date, onChange, localizedNames, className, style, setFocus = false, showTime = false, use12Hours = false, precision, hourStep, minuteStep, secondStep, useCombinedRenderer, combinedRenderer, hourRenderer, minuteRenderer, secondRenderer, meridiemRenderer, showYearSelection = false, enableRangeSelect = false, startDate, endDate, ...rest } = props;
127
127
  useTheme();
128
128
  const monthNames = (_a = localizedNames === null || localizedNames === void 0 ? void 0 : localizedNames.months) !== null && _a !== void 0 ? _a : defaultMonths;
129
129
  const shortDays = (_b = localizedNames === null || localizedNames === void 0 ? void 0 : localizedNames.shortDays) !== null && _b !== void 0 ? _b : defaultShortDays;
@@ -361,7 +361,7 @@ export const DatePicker = (props) => {
361
361
  (element === null || element === void 0 ? void 0 : element.focus()) }, dateValue));
362
362
  })));
363
363
  }))),
364
- showTime && (React.createElement(TimePicker, { date: selectedStartDay !== null && selectedStartDay !== void 0 ? selectedStartDay : selectedDay, use12Hours: use12Hours, precision: precision, hourStep: hourStep, minuteStep: minuteStep, secondStep: secondStep, onChange: (date) => {
364
+ showTime && (React.createElement(TimePicker, { date: selectedStartDay !== null && selectedStartDay !== void 0 ? selectedStartDay : selectedDay, use12Hours: use12Hours, precision: precision, hourStep: hourStep, minuteStep: minuteStep, secondStep: secondStep, useCombinedRenderer: useCombinedRenderer, combinedRenderer: combinedRenderer, hourRenderer: hourRenderer, minuteRenderer: minuteRenderer, secondRenderer: secondRenderer, meridiemRenderer: meridiemRenderer, onChange: (date) => {
365
365
  var _a, _b, _c, _d, _e, _f;
366
366
  return isSingleOnChange(onChange, enableRangeSelect)
367
367
  ? onChange === null || onChange === void 0 ? void 0 : onChange(date)
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import '@itwin/itwinui-css/css/utils.css';
3
+ export declare type NotificationMarkerProps = {
4
+ /**
5
+ * Content of the NotificationMarker.
6
+ */
7
+ children: React.ReactNode;
8
+ /**
9
+ * Status of notification
10
+ *
11
+ * - 'primary' = blue,
12
+ * - 'positive' = green,
13
+ * - 'warning' = orange,
14
+ * - 'negative' = red,
15
+ * - 'white' = white (useful for notifications in buttons with `style` = `high-visibility` | `cta`),
16
+ * @default 'primary'
17
+ */
18
+ status?: 'primary' | 'positive' | 'warning' | 'negative' | 'white';
19
+ /**
20
+ * Adds a pulse effect to the notification.
21
+ *
22
+ * **WARNING**: Avoid overuse of this prop.
23
+ * @default false
24
+ */
25
+ pulsing?: boolean;
26
+ /**
27
+ * Set this programmatically to false when you just want to render the passed children without the notification
28
+ * @default true
29
+ * @example
30
+ * let [newMessagesCount, ...] = useState(0);
31
+ * ...
32
+ * <NotificationMarker enabled={newMessagesCount > 0}>
33
+ * <SvgNotification />
34
+ * </NotificationMarker>
35
+ */
36
+ enabled?: boolean;
37
+ } & React.ComponentProps<'span'>;
38
+ /**
39
+ * A small notification circle to the top-right of the passed children prop.
40
+ * This can be applied to almost anything but mostly intended for icons within buttons with `styleType = default / borderless`.
41
+ * @example
42
+ * <IconButton styleType='borderless'>
43
+ * <NotificationMarker>
44
+ * <SvgNotification />
45
+ * </NotificationMarker>
46
+ * </IconButton>
47
+ * @example
48
+ * <NotificationMarker status='positive' pulsing={true}>Live</NotificationMarker>
49
+ */
50
+ export declare const NotificationMarker: React.ForwardRefExoticComponent<Pick<NotificationMarkerProps, "key" | "status" | keyof React.HTMLAttributes<HTMLSpanElement> | "enabled" | "pulsing"> & React.RefAttributes<HTMLSpanElement>>;
51
+ export default NotificationMarker;
@@ -0,0 +1,26 @@
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 { useTheme } from '../utils';
7
+ import cx from 'classnames';
8
+ import '@itwin/itwinui-css/css/utils.css';
9
+ /**
10
+ * A small notification circle to the top-right of the passed children prop.
11
+ * This can be applied to almost anything but mostly intended for icons within buttons with `styleType = default / borderless`.
12
+ * @example
13
+ * <IconButton styleType='borderless'>
14
+ * <NotificationMarker>
15
+ * <SvgNotification />
16
+ * </NotificationMarker>
17
+ * </IconButton>
18
+ * @example
19
+ * <NotificationMarker status='positive' pulsing={true}>Live</NotificationMarker>
20
+ */
21
+ export const NotificationMarker = React.forwardRef((props, ref) => {
22
+ const { className, children, status = 'primary', pulsing = false, enabled = true, ...rest } = props;
23
+ useTheme();
24
+ return (React.createElement("span", { ref: ref, className: cx({ 'iui-notification-marker': enabled }, className), "data-iui-variant": enabled ? status : null, "data-iui-urgent": enabled ? pulsing : null, ...rest }, children));
25
+ });
26
+ export default NotificationMarker;
@@ -0,0 +1,4 @@
1
+ export { NotificationMarker } from './NotificationMarker';
2
+ export type { NotificationMarkerProps } from './NotificationMarker';
3
+ declare const _default: "./NotificationMarker";
4
+ export default _default;
@@ -0,0 +1,6 @@
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
+ export { NotificationMarker } from './NotificationMarker';
6
+ export default './NotificationMarker';
@@ -117,7 +117,7 @@ export declare type TableProps<T extends Record<string, unknown> = Record<string
117
117
  * Use with `manualFilters` to handle filtering yourself e.g. filter in server-side.
118
118
  * Must be memoized.
119
119
  */
120
- onFilter?: (filters: TableFilterValue<T>[], state: TableState<T>) => void;
120
+ onFilter?: (filters: TableFilterValue<T>[], state: TableState<T>, filteredData?: Row<T>[]) => void;
121
121
  /**
122
122
  * Value used for global filtering.
123
123
  * Use with `globalFilter` and/or `manualGlobalFilter` to handle filtering yourself e.g. filter in server-side.
@@ -117,13 +117,15 @@ export const Table = (props) => {
117
117
  disableUserSelect,
118
118
  enableUserSelect,
119
119
  ]);
120
+ const previousFilter = React.useRef([]);
121
+ const currentFilter = React.useRef(previousFilter.current);
120
122
  const tableStateReducer = React.useCallback((newState, action, previousState, instance) => {
121
123
  switch (action.type) {
122
124
  case TableActions.toggleSortBy:
123
125
  onSort === null || onSort === void 0 ? void 0 : onSort(newState);
124
126
  break;
125
127
  case TableActions.setFilter:
126
- onFilterHandler(newState, action, previousState, instance, onFilter);
128
+ currentFilter.current = onFilterHandler(newState, action, previousState, currentFilter.current, instance);
127
129
  break;
128
130
  case TableActions.toggleRowExpanded:
129
131
  case TableActions.toggleAllRowsExpanded:
@@ -167,7 +169,6 @@ export const Table = (props) => {
167
169
  hasManualSelectionColumn,
168
170
  isRowDisabled,
169
171
  onExpand,
170
- onFilter,
171
172
  onSelect,
172
173
  onSort,
173
174
  stateReducer,
@@ -243,6 +244,22 @@ export const Table = (props) => {
243
244
  React.useEffect(() => {
244
245
  setPageSize(pageSize);
245
246
  }, [pageSize, setPageSize]);
247
+ React.useEffect(() => {
248
+ if (previousFilter.current !== currentFilter.current) {
249
+ previousFilter.current = currentFilter.current;
250
+ onFilter === null || onFilter === void 0 ? void 0 : onFilter(currentFilter.current, state, instance.filteredRows);
251
+ }
252
+ }, [state, instance.filteredRows, onFilter]);
253
+ const lastPassedColumns = React.useRef([]);
254
+ // Reset the column order whenever new columns are passed
255
+ // This is to avoid the old columnOrder from affecting the new columns' columnOrder
256
+ React.useEffect(() => {
257
+ // Check if columns have changed (by value)
258
+ if (JSON.stringify(lastPassedColumns.current) !== JSON.stringify(columns)) {
259
+ instance.setColumnOrder([]);
260
+ }
261
+ lastPassedColumns.current = columns;
262
+ }, [columns, instance]);
246
263
  const paginatorRendererProps = React.useMemo(() => ({
247
264
  currentPage: state.pageIndex,
248
265
  pageSize: state.pageSize,
@@ -1,3 +1,3 @@
1
1
  import { ActionType, TableInstance, TableState } from 'react-table';
2
2
  import { TableFilterValue } from '../filters';
3
- export declare const onFilterHandler: <T extends Record<string, unknown>>(newState: TableState<T>, action: ActionType, previousState: TableState<T>, instance?: TableInstance<T> | undefined, onFilter?: ((filters: TableFilterValue<T>[], state: TableState<T>) => void) | undefined) => void;
3
+ export declare const onFilterHandler: <T extends Record<string, unknown>>(newState: TableState<T>, action: ActionType, previousState: TableState<T>, currentFilter: TableFilterValue<T>[], instance?: TableInstance<T> | undefined) => TableFilterValue<T>[];
@@ -1,4 +1,4 @@
1
- export const onFilterHandler = (newState, action, previousState, instance, onFilter) => {
1
+ export const onFilterHandler = (newState, action, previousState, currentFilter, instance) => {
2
2
  const previousFilter = previousState.filters.find((f) => f.id === action.columnId);
3
3
  if ((previousFilter === null || previousFilter === void 0 ? void 0 : previousFilter.value) != action.filterValue) {
4
4
  const filters = newState.filters.map((f) => {
@@ -11,6 +11,7 @@ export const onFilterHandler = (newState, action, previousState, instance, onFil
11
11
  filterType: (_b = column === null || column === void 0 ? void 0 : column.filter) !== null && _b !== void 0 ? _b : 'text',
12
12
  };
13
13
  });
14
- onFilter === null || onFilter === void 0 ? void 0 : onFilter(filters, newState);
14
+ return filters;
15
15
  }
16
+ return currentFilter;
16
17
  };
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { StylingProps } from '../utils';
3
3
  import '@itwin/itwinui-css/css/time-picker.css';
4
4
  export declare type MeridiemType = 'AM' | 'PM';
5
+ export declare type Precision = 'hours' | 'minutes' | 'seconds';
5
6
  export declare type TimePickerProps = {
6
7
  /**
7
8
  * Selected date. Only time is used from Date object.
@@ -20,7 +21,7 @@ export declare type TimePickerProps = {
20
21
  * Precision of the time.
21
22
  * @default 'minutes'
22
23
  */
23
- precision?: 'hours' | 'minutes' | 'seconds';
24
+ precision?: Precision;
24
25
  /**
25
26
  * Change step of the hours displayed.
26
27
  * @default 1
@@ -61,6 +62,30 @@ export declare type TimePickerProps = {
61
62
  * @default (meridiem: MeridiemType) => meridiem
62
63
  */
63
64
  meridiemRenderer?: (meridiem: MeridiemType) => React.ReactNode;
65
+ /**
66
+ * Use combined time renderer. Combines hour, minute, and seconds into one column.
67
+ * **WARNING**: Using the combined renderer with a `precision` of 'seconds' along with
68
+ * small time steps (`hourStep`, `minuteStep`, and especially `secondStep`) can result in slow performance!
69
+ * @default false
70
+ */
71
+ useCombinedRenderer?: boolean;
72
+ /**
73
+ * Custom combined time renderer.
74
+ * Default returns time in `HH:MM:SS` format
75
+ * @default (date: Date, precision: Precision) => {
76
+ * let dateString = '';
77
+ * switch (precision) {
78
+ * case 'seconds':
79
+ * dateString = ':' + date.getSeconds().toLocaleString(undefined, { minimumIntegerDigits: 2 });
80
+ * case 'minutes':
81
+ * dateString = ':' + date.getMinutes().toLocaleString(undefined, { minimumIntegerDigits: 2 }) + dateString;
82
+ * case 'hours':
83
+ * dateString = date.getHours().toLocaleString(undefined, { minimumIntegerDigits: 2 }) + dateString;
84
+ * }
85
+ * return dateString;
86
+ * }
87
+ */
88
+ combinedRenderer?: (date: Date, precision: Precision) => React.ReactNode;
64
89
  } & StylingProps;
65
90
  /**
66
91
  * Time picker component
@@ -21,6 +21,24 @@ const isSameMinute = (date1, date2) => {
21
21
  const isSameSecond = (date1, date2) => {
22
22
  return !!date2 && date1.getSeconds() === date2.getSeconds();
23
23
  };
24
+ const isSameTime = (date1, date2, precision, meridiem) => {
25
+ let isSameTime = true;
26
+ switch (precision) {
27
+ case 'seconds':
28
+ isSameTime = isSameSecond(date1, date2);
29
+ if (!isSameTime) {
30
+ break;
31
+ }
32
+ case 'minutes':
33
+ isSameTime = isSameMinute(date1, date2);
34
+ if (!isSameTime) {
35
+ break;
36
+ }
37
+ case 'hours':
38
+ isSameTime = isSameHour(date1, date2, meridiem);
39
+ }
40
+ return isSameTime;
41
+ };
24
42
  const isSameMeridiem = (meridiem, date) => {
25
43
  return (!!date && (meridiem === 'AM' ? date.getHours() < 12 : date.getHours() >= 12));
26
44
  };
@@ -31,13 +49,36 @@ const formatHourFrom12 = (hour, meridiem) => {
31
49
  const setHours = (hour, date) => {
32
50
  return new Date(date.getFullYear(), date.getMonth(), date.getDate(), hour, date.getMinutes(), date.getSeconds());
33
51
  };
52
+ const defaultCombinedRenderer = (date, precision) => {
53
+ let dateString = '';
54
+ switch (precision) {
55
+ case 'seconds':
56
+ dateString =
57
+ ':' +
58
+ date
59
+ .getSeconds()
60
+ .toLocaleString(undefined, { minimumIntegerDigits: 2 });
61
+ case 'minutes':
62
+ dateString =
63
+ ':' +
64
+ date
65
+ .getMinutes()
66
+ .toLocaleString(undefined, { minimumIntegerDigits: 2 }) +
67
+ dateString;
68
+ case 'hours':
69
+ dateString =
70
+ date.getHours().toLocaleString(undefined, { minimumIntegerDigits: 2 }) +
71
+ dateString;
72
+ }
73
+ return dateString;
74
+ };
34
75
  /**
35
76
  * Time picker component
36
77
  * @example
37
78
  * <TimePicker date={new Date()} onChange={(e) => console.log('New time value: ' + e)} />
38
79
  */
39
80
  export const TimePicker = (props) => {
40
- const { date, onChange, use12Hours = false, precision = 'minutes', hourStep = 1, minuteStep = 1, secondStep = 1, setFocusHour = false, hourRenderer = (date) => date.getHours().toLocaleString(undefined, { minimumIntegerDigits: 2 }), minuteRenderer = (date) => date.getMinutes().toLocaleString(undefined, { minimumIntegerDigits: 2 }), secondRenderer = (date) => date.getSeconds().toLocaleString(undefined, { minimumIntegerDigits: 2 }), meridiemRenderer = (meridiem) => meridiem, className, ...rest } = props;
81
+ const { date, onChange, use12Hours = false, precision = 'minutes', hourStep = 1, minuteStep = 1, secondStep = 1, setFocusHour = false, hourRenderer = (date) => date.getHours().toLocaleString(undefined, { minimumIntegerDigits: 2 }), minuteRenderer = (date) => date.getMinutes().toLocaleString(undefined, { minimumIntegerDigits: 2 }), secondRenderer = (date) => date.getSeconds().toLocaleString(undefined, { minimumIntegerDigits: 2 }), meridiemRenderer = (meridiem) => meridiem, useCombinedRenderer = false, combinedRenderer = defaultCombinedRenderer, className, ...rest } = props;
41
82
  useTheme();
42
83
  const [selectedTime, setSelectedTime] = React.useState(date);
43
84
  const [focusedTime, setFocusedTime] = React.useState(selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date());
@@ -53,6 +94,13 @@ export const TimePicker = (props) => {
53
94
  const adjustedSelectedTime = setHours(adjustedHour, selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date());
54
95
  updateCurrentTime(adjustedSelectedTime);
55
96
  };
97
+ const onTimeClick = (date) => {
98
+ const adjustedHour = use12Hours
99
+ ? formatHourFrom12(date.getHours(), meridiem)
100
+ : date.getHours();
101
+ const adjustedSelectedTime = setHours(adjustedHour, date);
102
+ updateCurrentTime(adjustedSelectedTime);
103
+ };
56
104
  const onMeridiemClick = (value) => {
57
105
  let adjustedSelectedTime = selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date();
58
106
  const currentHours = adjustedSelectedTime.getHours();
@@ -84,6 +132,12 @@ export const TimePicker = (props) => {
84
132
  : date.getHours();
85
133
  setFocusedTime(setHours(adjustedHour, focusedTime));
86
134
  };
135
+ const onTimeFocus = (date) => {
136
+ const adjustedHour = use12Hours
137
+ ? formatHourFrom12(date.getHours(), meridiem)
138
+ : date.getHours();
139
+ setFocusedTime(setHours(adjustedHour, date));
140
+ };
87
141
  const onMeridiemFocus = (value) => {
88
142
  let adjustedSelectedTime = selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date();
89
143
  const currentHours = adjustedSelectedTime.getHours();
@@ -99,13 +153,40 @@ export const TimePicker = (props) => {
99
153
  };
100
154
  const generateDataList = (size, value, step) => {
101
155
  const data = [];
102
- for (let i = 0; i < size; ++i) {
156
+ for (let i = 0; i < size; i++) {
103
157
  if (i % step === 0) {
104
158
  data.push(value(i));
105
159
  }
106
160
  }
107
161
  return data;
108
162
  };
163
+ const time = React.useMemo(() => {
164
+ const time = selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date();
165
+ const data = [];
166
+ const hoursArray = Array.from(Array(use12Hours ? 12 : 24).keys())
167
+ .filter((i) => i % hourStep === 0)
168
+ .map((i) => (use12Hours && i === 0 ? 12 : i));
169
+ const minutesArray = Array.from(Array(60).keys()).filter((i) => i % minuteStep === 0);
170
+ const secondsArray = Array.from(Array(60).keys()).filter((i) => i % secondStep === 0);
171
+ hoursArray.forEach((hour) => {
172
+ if (precision === 'hours') {
173
+ data.push(new Date(time.getFullYear(), time.getMonth(), time.getDate(), hour, time.getMinutes(), time.getSeconds()));
174
+ }
175
+ else {
176
+ minutesArray.forEach((minute) => {
177
+ if (precision === 'minutes') {
178
+ data.push(new Date(time.getFullYear(), time.getMonth(), time.getDate(), hour, minute, time.getSeconds()));
179
+ }
180
+ else {
181
+ secondsArray.forEach((second) => {
182
+ data.push(new Date(time.getFullYear(), time.getMonth(), time.getDate(), hour, minute, second));
183
+ });
184
+ }
185
+ });
186
+ }
187
+ });
188
+ return data;
189
+ }, [hourStep, minuteStep, secondStep, selectedTime, use12Hours, precision]);
109
190
  const hours = React.useMemo(() => {
110
191
  const time = selectedTime !== null && selectedTime !== void 0 ? selectedTime : new Date();
111
192
  return generateDataList(use12Hours ? 12 : 24, (i) => new Date(time.getFullYear(), time.getMonth(), time.getDate(), use12Hours && i === 0 ? 12 : i, time.getMinutes(), time.getSeconds()), hourStep);
@@ -119,13 +200,14 @@ export const TimePicker = (props) => {
119
200
  return generateDataList(60, (i) => new Date(time.getFullYear(), time.getMonth(), time.getDate(), time.getHours(), time.getMinutes(), i), secondStep);
120
201
  }, [secondStep, selectedTime]);
121
202
  return (React.createElement("div", { className: cx('iui-time-picker', className), ...rest },
122
- React.createElement(TimePickerColumn, { data: hours, isSameFocused: (val) => isSameHour(val, focusedTime, use12Hours ? meridiem : undefined), isSameSelected: (val) => isSameHour(val, selectedTime, use12Hours ? meridiem : undefined), onFocusChange: onHourFocus, onSelectChange: onHourClick, setFocus: setFocusHour, valueRenderer: hourRenderer }),
123
- precision != 'hours' && (React.createElement(TimePickerColumn, { data: minutes, isSameFocused: (val) => isSameMinute(val, focusedTime), isSameSelected: (val) => isSameMinute(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: minuteRenderer })),
124
- precision == 'seconds' && (React.createElement(TimePickerColumn, { data: seconds, isSameFocused: (val) => isSameSecond(val, focusedTime), isSameSelected: (val) => isSameSecond(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: secondRenderer })),
203
+ useCombinedRenderer ? (React.createElement(TimePickerColumn, { data: time, isSameFocused: (val) => isSameTime(val, focusedTime, precision, use12Hours ? meridiem : undefined), isSameSelected: (val) => isSameTime(val, selectedTime, precision, use12Hours ? meridiem : undefined), onFocusChange: onTimeFocus, onSelectChange: onTimeClick, setFocus: setFocusHour, precision: precision, valueRenderer: combinedRenderer })) : (React.createElement(React.Fragment, null,
204
+ React.createElement(TimePickerColumn, { data: hours, isSameFocused: (val) => isSameHour(val, focusedTime, use12Hours ? meridiem : undefined), isSameSelected: (val) => isSameHour(val, selectedTime, use12Hours ? meridiem : undefined), onFocusChange: onHourFocus, onSelectChange: onHourClick, setFocus: setFocusHour, valueRenderer: hourRenderer }),
205
+ precision !== 'hours' && (React.createElement(TimePickerColumn, { data: minutes, isSameFocused: (val) => isSameMinute(val, focusedTime), isSameSelected: (val) => isSameMinute(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: minuteRenderer })),
206
+ precision === 'seconds' && (React.createElement(TimePickerColumn, { data: seconds, isSameFocused: (val) => isSameSecond(val, focusedTime), isSameSelected: (val) => isSameSecond(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: secondRenderer })))),
125
207
  use12Hours && (React.createElement(TimePickerColumn, { data: ['AM', 'PM'], isSameFocused: (val) => isSameMeridiem(val, focusedTime), isSameSelected: (val) => isSameMeridiem(val, selectedTime), onFocusChange: (date) => onMeridiemFocus(date), onSelectChange: (value) => onMeridiemClick(value), valueRenderer: meridiemRenderer, className: 'iui-period' }))));
126
208
  };
127
209
  const TimePickerColumn = (props) => {
128
- const { data, onFocusChange, onSelectChange, isSameFocused, isSameSelected, setFocus = false, valueRenderer, className = 'iui-time', } = props;
210
+ const { data, onFocusChange, onSelectChange, isSameFocused, isSameSelected, setFocus = false, valueRenderer, precision = 'minutes', className = 'iui-time', } = props;
129
211
  const needFocus = React.useRef(setFocus);
130
212
  // Used to focus row only when changed (keyboard navigation)
131
213
  // e.g. without this on every rerender it would be focused
@@ -175,7 +257,7 @@ const TimePickerColumn = (props) => {
175
257
  needFocus.current && isSameFocus && (ref === null || ref === void 0 ? void 0 : ref.focus());
176
258
  }, onClick: () => {
177
259
  onSelectChange(value);
178
- } }, valueRenderer(value)));
260
+ } }, valueRenderer(value, precision)));
179
261
  }))));
180
262
  };
181
263
  export default TimePicker;
@@ -60,6 +60,8 @@ export { Menu, MenuItem, MenuDivider, MenuExtraContent, MenuItemSkeleton, } from
60
60
  export type { MenuProps, MenuItemProps, MenuDividerProps, MenuExtraContentProps, MenuItemSkeletonProps, } from './Menu';
61
61
  export { Modal, ModalButtonBar, ModalContent } from './Modal';
62
62
  export type { ModalProps, ModalButtonBarProps, ModalContentProps, } from './Modal';
63
+ export { NotificationMarker } from './NotificationMarker';
64
+ export type { NotificationMarkerProps } from './NotificationMarker';
63
65
  export { ProgressLinear, ProgressRadial } from './ProgressIndicators';
64
66
  export type { ProgressLinearProps, ProgressRadialProps, } from './ProgressIndicators';
65
67
  export { Radio } from './Radio';
package/esm/core/index.js CHANGED
@@ -33,6 +33,7 @@ export { LabeledSelect } from './LabeledSelect';
33
33
  export { LabeledTextarea } from './LabeledTextarea';
34
34
  export { Menu, MenuItem, MenuDivider, MenuExtraContent, MenuItemSkeleton, } from './Menu';
35
35
  export { Modal, ModalButtonBar, ModalContent } from './Modal';
36
+ export { NotificationMarker } from './NotificationMarker';
36
37
  export { ProgressLinear, ProgressRadial } from './ProgressIndicators';
37
38
  export { Radio } from './Radio';
38
39
  export { RadioTile, RadioTileGroup } from './RadioTiles';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/itwinui-react",
3
- "version": "2.1.1",
3
+ "version": "2.2.1",
4
4
  "author": "Bentley Systems",
5
5
  "license": "MIT",
6
6
  "main": "cjs/index.js",
@@ -29,8 +29,8 @@
29
29
  "CHANGELOG.md",
30
30
  "LICENSE.md"
31
31
  ],
32
- "description": "A react implementation of our iTwinUI UX standards",
33
- "homepage": "https://github.com/iTwin/iTwinUI-react",
32
+ "description": "A react component library for iTwinUI",
33
+ "homepage": "https://github.com/iTwin/iTwinUI",
34
34
  "keywords": [
35
35
  "component",
36
36
  "components",
@@ -55,7 +55,7 @@
55
55
  "test:watch": "jest --watch",
56
56
  "format": "prettier --config .prettierrc **/*.{tsx,ts,js} --ignore-path .gitignore --write",
57
57
  "lint": "eslint \"**/*.{js,ts,tsx}\" --max-warnings=0",
58
- "lint:fix": "yarn lint --fix && node ../configs/copyrightLinter.js --fix \"*/**/*.{js,ts,tsx}\"",
58
+ "lint:fix": "yarn lint --fix && node ../../scripts/copyrightLinter.js --fix \"*/**/*.{js,ts,tsx}\"",
59
59
  "dev": "yarn clean:build && concurrently \"yarn dev:esm\" \"yarn dev:cjs\" \"yarn dev:types\"",
60
60
  "dev:esm": "swc src -d esm --watch",
61
61
  "dev:cjs": "swc src -d cjs --watch -C module.type=commonjs",
@@ -90,7 +90,6 @@
90
90
  "@typescript-eslint/parser": "^5.17.0",
91
91
  "babel-loader": "^8.2.2",
92
92
  "concurrently": "^5.3.0",
93
- "configs": "*",
94
93
  "eslint": "^8.12.0",
95
94
  "eslint-config-prettier": "^8.5.0",
96
95
  "inquirer": "^6.2.2",
@@ -113,7 +112,7 @@
113
112
  "lint-staged": {
114
113
  "*.{tsx,ts,jsx,js}": [
115
114
  "prettier --write",
116
- "node ../configs/copyrightLinter.js --fix"
115
+ "node ../../scripts/copyrightLinter.js --fix"
117
116
  ],
118
117
  "*.{tsx,ts}": [
119
118
  "eslint --max-warnings=0 --fix"