@itwin/imodel-components-react 4.9.0 → 4.10.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 (160) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/lib/cjs/imodel-components-react/UiIModelComponents.js +2 -4
  3. package/lib/cjs/imodel-components-react/UiIModelComponents.js.map +1 -1
  4. package/lib/cjs/imodel-components-react/color/AlphaSlider.d.ts.map +1 -1
  5. package/lib/cjs/imodel-components-react/color/AlphaSlider.js +8 -6
  6. package/lib/cjs/imodel-components-react/color/AlphaSlider.js.map +1 -1
  7. package/lib/cjs/imodel-components-react/color/ColorPickerButton.js +1 -1
  8. package/lib/cjs/imodel-components-react/color/ColorPickerButton.js.map +1 -1
  9. package/lib/cjs/imodel-components-react/color/HueSlider.d.ts.map +1 -1
  10. package/lib/cjs/imodel-components-react/color/HueSlider.js +8 -6
  11. package/lib/cjs/imodel-components-react/color/HueSlider.js.map +1 -1
  12. package/lib/cjs/imodel-components-react/color/SaturationPicker.js +8 -8
  13. package/lib/cjs/imodel-components-react/color/SaturationPicker.js.map +1 -1
  14. package/lib/cjs/imodel-components-react/editors/ColorEditor.js +1 -1
  15. package/lib/cjs/imodel-components-react/editors/ColorEditor.js.map +1 -1
  16. package/lib/cjs/imodel-components-react/editors/WeightEditor.d.ts.map +1 -1
  17. package/lib/cjs/imodel-components-react/editors/WeightEditor.js.map +1 -1
  18. package/lib/cjs/imodel-components-react/inputs/QuantityNumberInput.d.ts +3 -1
  19. package/lib/cjs/imodel-components-react/inputs/QuantityNumberInput.d.ts.map +1 -1
  20. package/lib/cjs/imodel-components-react/inputs/QuantityNumberInput.js +5 -5
  21. package/lib/cjs/imodel-components-react/inputs/QuantityNumberInput.js.map +1 -1
  22. package/lib/cjs/imodel-components-react/lineweight/WeightPickerButton.js +3 -3
  23. package/lib/cjs/imodel-components-react/lineweight/WeightPickerButton.js.map +1 -1
  24. package/lib/cjs/imodel-components-react/navigationaids/CubeNavigationAid.js +5 -10
  25. package/lib/cjs/imodel-components-react/navigationaids/CubeNavigationAid.js.map +1 -1
  26. package/lib/cjs/imodel-components-react/navigationaids/DrawingNavigationAid.d.ts.map +1 -1
  27. package/lib/cjs/imodel-components-react/navigationaids/DrawingNavigationAid.js +2 -1
  28. package/lib/cjs/imodel-components-react/navigationaids/DrawingNavigationAid.js.map +1 -1
  29. package/lib/cjs/imodel-components-react/quantityformat/FormatPanel.js +1 -1
  30. package/lib/cjs/imodel-components-react/quantityformat/FormatPanel.js.map +1 -1
  31. package/lib/cjs/imodel-components-react/quantityformat/FormatPanel.scss +0 -4
  32. package/lib/cjs/imodel-components-react/quantityformat/FormatPrecision.js +1 -2
  33. package/lib/cjs/imodel-components-react/quantityformat/FormatPrecision.js.map +1 -1
  34. package/lib/cjs/imodel-components-react/quantityformat/FormatSample.js +3 -3
  35. package/lib/cjs/imodel-components-react/quantityformat/FormatSample.js.map +1 -1
  36. package/lib/cjs/imodel-components-react/quantityformat/FormatType.js +3 -2
  37. package/lib/cjs/imodel-components-react/quantityformat/FormatType.js.map +1 -1
  38. package/lib/cjs/imodel-components-react/quantityformat/FormatUnitLabel.js +1 -2
  39. package/lib/cjs/imodel-components-react/quantityformat/FormatUnitLabel.js.map +1 -1
  40. package/lib/cjs/imodel-components-react/quantityformat/FormatUnits.js +6 -10
  41. package/lib/cjs/imodel-components-react/quantityformat/FormatUnits.js.map +1 -1
  42. package/lib/cjs/imodel-components-react/quantityformat/MiscFormatOptions.d.ts.map +1 -1
  43. package/lib/cjs/imodel-components-react/quantityformat/MiscFormatOptions.js +6 -10
  44. package/lib/cjs/imodel-components-react/quantityformat/MiscFormatOptions.js.map +1 -1
  45. package/lib/cjs/imodel-components-react/quantityformat/misc/ThousandsSelector.d.ts.map +1 -1
  46. package/lib/cjs/imodel-components-react/quantityformat/misc/ThousandsSelector.js +2 -5
  47. package/lib/cjs/imodel-components-react/quantityformat/misc/ThousandsSelector.js.map +1 -1
  48. package/lib/cjs/imodel-components-react/quantityformat/misc/ThousandsSeparator.js +1 -2
  49. package/lib/cjs/imodel-components-react/quantityformat/misc/ThousandsSeparator.js.map +1 -1
  50. package/lib/cjs/imodel-components-react/timeline/InlineEdit.js +2 -2
  51. package/lib/cjs/imodel-components-react/timeline/InlineEdit.js.map +1 -1
  52. package/lib/cjs/imodel-components-react/timeline/InlineEdit.scss +1 -4
  53. package/lib/cjs/imodel-components-react/timeline/PlayButton.d.ts +24 -0
  54. package/lib/cjs/imodel-components-react/timeline/PlayButton.d.ts.map +1 -0
  55. package/lib/cjs/imodel-components-react/timeline/{PlayerButton.js → PlayButton.js} +5 -25
  56. package/lib/cjs/imodel-components-react/timeline/PlayButton.js.map +1 -0
  57. package/lib/cjs/imodel-components-react/timeline/{PlayerButton.scss → PlayButton.scss} +1 -1
  58. package/lib/cjs/imodel-components-react/timeline/Scrubber.d.ts +1 -4
  59. package/lib/cjs/imodel-components-react/timeline/Scrubber.d.ts.map +1 -1
  60. package/lib/cjs/imodel-components-react/timeline/Scrubber.js +13 -33
  61. package/lib/cjs/imodel-components-react/timeline/Scrubber.js.map +1 -1
  62. package/lib/cjs/imodel-components-react/timeline/Scrubber.scss +5 -5
  63. package/lib/cjs/imodel-components-react/timeline/SolarTimeline.d.ts.map +1 -1
  64. package/lib/cjs/imodel-components-react/timeline/SolarTimeline.js +10 -27
  65. package/lib/cjs/imodel-components-react/timeline/SolarTimeline.js.map +1 -1
  66. package/lib/cjs/imodel-components-react/timeline/SolarTimeline.scss +7 -13
  67. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.d.ts +28 -66
  68. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.d.ts.map +1 -1
  69. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.js +216 -359
  70. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.js.map +1 -1
  71. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.scss +27 -157
  72. package/lib/cjs/imodel-components-react/viewport/ViewportComponent.js +7 -9
  73. package/lib/cjs/imodel-components-react/viewport/ViewportComponent.js.map +1 -1
  74. package/lib/cjs/imodel-components-react.d.ts +0 -1
  75. package/lib/cjs/imodel-components-react.d.ts.map +1 -1
  76. package/lib/cjs/imodel-components-react.js +0 -1
  77. package/lib/cjs/imodel-components-react.js.map +1 -1
  78. package/lib/esm/imodel-components-react/UiIModelComponents.js +2 -4
  79. package/lib/esm/imodel-components-react/UiIModelComponents.js.map +1 -1
  80. package/lib/esm/imodel-components-react/color/AlphaSlider.d.ts.map +1 -1
  81. package/lib/esm/imodel-components-react/color/AlphaSlider.js +8 -6
  82. package/lib/esm/imodel-components-react/color/AlphaSlider.js.map +1 -1
  83. package/lib/esm/imodel-components-react/color/ColorPickerButton.js +1 -1
  84. package/lib/esm/imodel-components-react/color/ColorPickerButton.js.map +1 -1
  85. package/lib/esm/imodel-components-react/color/HueSlider.d.ts.map +1 -1
  86. package/lib/esm/imodel-components-react/color/HueSlider.js +8 -6
  87. package/lib/esm/imodel-components-react/color/HueSlider.js.map +1 -1
  88. package/lib/esm/imodel-components-react/color/SaturationPicker.js +8 -8
  89. package/lib/esm/imodel-components-react/color/SaturationPicker.js.map +1 -1
  90. package/lib/esm/imodel-components-react/editors/ColorEditor.js +1 -1
  91. package/lib/esm/imodel-components-react/editors/ColorEditor.js.map +1 -1
  92. package/lib/esm/imodel-components-react/editors/WeightEditor.d.ts.map +1 -1
  93. package/lib/esm/imodel-components-react/editors/WeightEditor.js.map +1 -1
  94. package/lib/esm/imodel-components-react/inputs/QuantityNumberInput.d.ts +3 -1
  95. package/lib/esm/imodel-components-react/inputs/QuantityNumberInput.d.ts.map +1 -1
  96. package/lib/esm/imodel-components-react/inputs/QuantityNumberInput.js +5 -5
  97. package/lib/esm/imodel-components-react/inputs/QuantityNumberInput.js.map +1 -1
  98. package/lib/esm/imodel-components-react/lineweight/WeightPickerButton.js +3 -3
  99. package/lib/esm/imodel-components-react/lineweight/WeightPickerButton.js.map +1 -1
  100. package/lib/esm/imodel-components-react/navigationaids/CubeNavigationAid.js +5 -10
  101. package/lib/esm/imodel-components-react/navigationaids/CubeNavigationAid.js.map +1 -1
  102. package/lib/esm/imodel-components-react/navigationaids/DrawingNavigationAid.d.ts.map +1 -1
  103. package/lib/esm/imodel-components-react/navigationaids/DrawingNavigationAid.js +2 -1
  104. package/lib/esm/imodel-components-react/navigationaids/DrawingNavigationAid.js.map +1 -1
  105. package/lib/esm/imodel-components-react/quantityformat/FormatPanel.js +1 -1
  106. package/lib/esm/imodel-components-react/quantityformat/FormatPanel.js.map +1 -1
  107. package/lib/esm/imodel-components-react/quantityformat/FormatPanel.scss +0 -4
  108. package/lib/esm/imodel-components-react/quantityformat/FormatPrecision.js +1 -2
  109. package/lib/esm/imodel-components-react/quantityformat/FormatPrecision.js.map +1 -1
  110. package/lib/esm/imodel-components-react/quantityformat/FormatSample.js +3 -3
  111. package/lib/esm/imodel-components-react/quantityformat/FormatSample.js.map +1 -1
  112. package/lib/esm/imodel-components-react/quantityformat/FormatType.js +3 -2
  113. package/lib/esm/imodel-components-react/quantityformat/FormatType.js.map +1 -1
  114. package/lib/esm/imodel-components-react/quantityformat/FormatUnitLabel.js +1 -2
  115. package/lib/esm/imodel-components-react/quantityformat/FormatUnitLabel.js.map +1 -1
  116. package/lib/esm/imodel-components-react/quantityformat/FormatUnits.js +6 -10
  117. package/lib/esm/imodel-components-react/quantityformat/FormatUnits.js.map +1 -1
  118. package/lib/esm/imodel-components-react/quantityformat/MiscFormatOptions.d.ts.map +1 -1
  119. package/lib/esm/imodel-components-react/quantityformat/MiscFormatOptions.js +6 -10
  120. package/lib/esm/imodel-components-react/quantityformat/MiscFormatOptions.js.map +1 -1
  121. package/lib/esm/imodel-components-react/quantityformat/misc/ThousandsSelector.d.ts.map +1 -1
  122. package/lib/esm/imodel-components-react/quantityformat/misc/ThousandsSelector.js +2 -5
  123. package/lib/esm/imodel-components-react/quantityformat/misc/ThousandsSelector.js.map +1 -1
  124. package/lib/esm/imodel-components-react/quantityformat/misc/ThousandsSeparator.js +1 -2
  125. package/lib/esm/imodel-components-react/quantityformat/misc/ThousandsSeparator.js.map +1 -1
  126. package/lib/esm/imodel-components-react/timeline/InlineEdit.js +2 -2
  127. package/lib/esm/imodel-components-react/timeline/InlineEdit.js.map +1 -1
  128. package/lib/esm/imodel-components-react/timeline/InlineEdit.scss +1 -4
  129. package/lib/esm/imodel-components-react/timeline/PlayButton.d.ts +24 -0
  130. package/lib/esm/imodel-components-react/timeline/PlayButton.d.ts.map +1 -0
  131. package/lib/esm/imodel-components-react/timeline/{PlayerButton.js → PlayButton.js} +4 -23
  132. package/lib/esm/imodel-components-react/timeline/PlayButton.js.map +1 -0
  133. package/lib/esm/imodel-components-react/timeline/{PlayerButton.scss → PlayButton.scss} +1 -1
  134. package/lib/esm/imodel-components-react/timeline/Scrubber.d.ts +1 -4
  135. package/lib/esm/imodel-components-react/timeline/Scrubber.d.ts.map +1 -1
  136. package/lib/esm/imodel-components-react/timeline/Scrubber.js +13 -33
  137. package/lib/esm/imodel-components-react/timeline/Scrubber.js.map +1 -1
  138. package/lib/esm/imodel-components-react/timeline/Scrubber.scss +5 -5
  139. package/lib/esm/imodel-components-react/timeline/SolarTimeline.d.ts.map +1 -1
  140. package/lib/esm/imodel-components-react/timeline/SolarTimeline.js +9 -26
  141. package/lib/esm/imodel-components-react/timeline/SolarTimeline.js.map +1 -1
  142. package/lib/esm/imodel-components-react/timeline/SolarTimeline.scss +7 -13
  143. package/lib/esm/imodel-components-react/timeline/TimelineComponent.d.ts +28 -66
  144. package/lib/esm/imodel-components-react/timeline/TimelineComponent.d.ts.map +1 -1
  145. package/lib/esm/imodel-components-react/timeline/TimelineComponent.js +217 -357
  146. package/lib/esm/imodel-components-react/timeline/TimelineComponent.js.map +1 -1
  147. package/lib/esm/imodel-components-react/timeline/TimelineComponent.scss +27 -157
  148. package/lib/esm/imodel-components-react/viewport/ViewportComponent.js +7 -9
  149. package/lib/esm/imodel-components-react/viewport/ViewportComponent.js.map +1 -1
  150. package/lib/esm/imodel-components-react.d.ts +0 -1
  151. package/lib/esm/imodel-components-react.d.ts.map +1 -1
  152. package/lib/esm/imodel-components-react.js +0 -1
  153. package/lib/esm/imodel-components-react.js.map +1 -1
  154. package/package.json +22 -22
  155. package/lib/cjs/imodel-components-react/timeline/PlayerButton.d.ts +0 -34
  156. package/lib/cjs/imodel-components-react/timeline/PlayerButton.d.ts.map +0 -1
  157. package/lib/cjs/imodel-components-react/timeline/PlayerButton.js.map +0 -1
  158. package/lib/esm/imodel-components-react/timeline/PlayerButton.d.ts +0 -34
  159. package/lib/esm/imodel-components-react/timeline/PlayerButton.d.ts.map +0 -1
  160. package/lib/esm/imodel-components-react/timeline/PlayerButton.js.map +0 -1
@@ -22,400 +22,257 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  exports.TimelineComponent = void 0;
27
+ /*---------------------------------------------------------------------------------------------
28
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
29
+ * See LICENSE.md in the project root for license terms and full copyright notice.
30
+ *--------------------------------------------------------------------------------------------*/
31
+ /** @packageDocumentation
32
+ * @module Timeline
33
+ */
34
+ require("./TimelineComponent.scss");
35
+ const React = __importStar(require("react"));
30
36
  const appui_abstract_1 = require("@itwin/appui-abstract");
31
37
  const components_react_1 = require("@itwin/components-react");
32
- const core_react_1 = require("@itwin/core-react");
33
38
  const itwinui_icons_react_1 = require("@itwin/itwinui-icons-react");
34
39
  const itwinui_react_1 = require("@itwin/itwinui-react");
35
- const classnames_1 = __importDefault(require("classnames"));
36
- const React = __importStar(require("react"));
37
40
  const UiIModelComponents_1 = require("../UiIModelComponents");
38
41
  const InlineEdit_1 = require("./InlineEdit");
39
42
  const interfaces_1 = require("./interfaces");
40
- const PlayerButton_1 = require("./PlayerButton");
43
+ const PlayButton_1 = require("./PlayButton");
41
44
  const Scrubber_1 = require("./Scrubber");
42
- require("./TimelineComponent.scss");
43
- // cspell:ignore millisec
44
45
  const slowSpeed = 60 * 1000;
45
46
  const mediumSpeed = 20 * 1000;
46
47
  const fastSpeed = 10 * 1000;
47
- /**
48
- * [[TimelineComponent]] is used to playback timeline data
48
+ /** [[TimelineComponent]] is used to playback timeline data
49
49
  * @public
50
50
  */
51
- class TimelineComponent extends React.Component {
52
- constructor(props) {
53
- super(props);
54
- this._timeLastCycle = 0;
55
- this._requestFrame = 0;
56
- this._unmounted = false;
57
- this._standardTimelineMenuItems = [
58
- {
59
- label: UiIModelComponents_1.UiIModelComponents.translate("timeline.slow"),
60
- timelineDuration: slowSpeed,
61
- },
62
- {
63
- label: UiIModelComponents_1.UiIModelComponents.translate("timeline.medium"),
64
- timelineDuration: mediumSpeed,
65
- },
66
- {
67
- label: UiIModelComponents_1.UiIModelComponents.translate("timeline.fast"),
68
- timelineDuration: fastSpeed,
69
- },
70
- ];
71
- this._handleTimelinePausePlayEvent = (args) => {
51
+ function TimelineComponent(props) {
52
+ const { appMenuItemOption = "replace", startDate, endDate, showDuration, timeZoneOffset, dateFormatOptions, timeFormatOptions, includeRepeat = true, onSettingsChange, onChange, onPlayPause, } = props;
53
+ const [isPlaying, setIsPlaying] = React.useState(false);
54
+ const [currentDuration, setCurrentDuration] = React.useState(props.initialDuration ?? 0);
55
+ const [totalDuration, setTotalDuration] = React.useState(props.totalDuration);
56
+ const [repeat, setRepeat] = React.useState(props.repeat ?? false);
57
+ const playOrReplay = React.useCallback(() => {
58
+ if (isPlaying)
59
+ return;
60
+ if (currentDuration >= totalDuration) {
61
+ setCurrentDuration(0);
62
+ }
63
+ setIsPlaying(true);
64
+ onPlayPause?.(true);
65
+ }, [isPlaying, onPlayPause, currentDuration, totalDuration]);
66
+ const pause = React.useCallback(() => {
67
+ if (!isPlaying)
68
+ return;
69
+ setIsPlaying(false);
70
+ onPlayPause?.(false);
71
+ }, [isPlaying, onPlayPause]);
72
+ const updateTotalDuration = (newTotalDuration) => {
73
+ if (newTotalDuration === totalDuration)
74
+ return;
75
+ const fraction = currentDuration / totalDuration;
76
+ const newCurrentDuration = fraction * newTotalDuration;
77
+ setTotalDuration(newTotalDuration);
78
+ setCurrentDuration(newCurrentDuration);
79
+ onSettingsChange?.({ duration: newTotalDuration });
80
+ };
81
+ const updateDuration = (newDuration, currentTotalDuration = totalDuration) => {
82
+ newDuration = Math.max(newDuration, 0);
83
+ newDuration = Math.min(newDuration, currentTotalDuration);
84
+ if (newDuration === currentDuration)
85
+ return;
86
+ setCurrentDuration(newDuration);
87
+ const fraction = newDuration / currentTotalDuration;
88
+ onChange?.(fraction);
89
+ };
90
+ const updateRepeat = (newRepeat) => {
91
+ if (newRepeat === repeat)
92
+ return;
93
+ setRepeat(newRepeat);
94
+ onSettingsChange?.({ loop: newRepeat });
95
+ };
96
+ const [prevTotalDuration, setPrevTotalDuration] = React.useState(props.totalDuration);
97
+ if (prevTotalDuration !== props.totalDuration) {
98
+ setPrevTotalDuration(props.totalDuration);
99
+ updateTotalDuration(props.totalDuration);
100
+ }
101
+ const [prevInitialDuration, setPrevInitialDuration] = React.useState(props.initialDuration);
102
+ if (prevInitialDuration !== props.initialDuration) {
103
+ setPrevInitialDuration(props.initialDuration);
104
+ updateDuration(props.initialDuration ?? 0, props.totalDuration);
105
+ }
106
+ const [prevRepeat, setPrevRepeat] = React.useState(props.repeat);
107
+ if (prevRepeat !== props.repeat) {
108
+ setPrevRepeat(props.repeat);
109
+ updateRepeat(props.repeat ?? repeat);
110
+ }
111
+ React.useEffect(() => {
112
+ if (!props.componentId)
113
+ return;
114
+ return appui_abstract_1.UiAdmin.onGenericUiEvent.addListener((args) => {
72
115
  const timelineArgs = args;
73
- // istanbul ignore else
74
116
  if (!timelineArgs ||
75
- this.props.componentId !== timelineArgs.uiComponentId ||
117
+ props.componentId !== timelineArgs.uiComponentId ||
76
118
  timelineArgs.timelineAction === undefined)
77
119
  return;
78
- let startPlaying;
79
120
  switch (timelineArgs.timelineAction) {
80
121
  case interfaces_1.TimelinePausePlayAction.Play:
81
- startPlaying = true;
122
+ playOrReplay();
82
123
  break;
83
124
  case interfaces_1.TimelinePausePlayAction.Pause:
84
- startPlaying = false;
125
+ pause();
85
126
  break;
86
127
  case interfaces_1.TimelinePausePlayAction.Toggle:
87
- startPlaying = !this.state.isPlaying;
128
+ if (isPlaying) {
129
+ pause();
130
+ }
131
+ else {
132
+ playOrReplay();
133
+ }
88
134
  break;
89
- // istanbul ignore next
90
- default:
91
- return; // throw error?
92
- }
93
- if (startPlaying)
94
- this._onPlay();
95
- else
96
- this._onPause();
97
- };
98
- // user clicked backward button
99
- this._onBackward = () => {
100
- // istanbul ignore else
101
- if (this.props.onJump)
102
- this.props.onJump(false);
103
- };
104
- // user clicked forward button
105
- this._onForward = () => {
106
- // istanbul ignore else
107
- if (this.props.onJump)
108
- this.props.onJump(true);
109
- };
110
- // user clicked play button
111
- this._onPlay = () => {
112
- // istanbul ignore if
113
- if (this.state.isPlaying)
114
- return;
115
- // timeline was complete, restart from the beginning
116
- if (this.state.currentDuration >= this.state.totalDuration) {
117
- this._replay();
118
- }
119
- else
120
- this._play();
121
- // istanbul ignore else
122
- if (this.props.onPlayPause)
123
- this.props.onPlayPause(true);
124
- };
125
- // user clicked pause button
126
- this._onPause = () => {
127
- // istanbul ignore if
128
- if (!this.state.isPlaying)
129
- return;
130
- // stop requesting frames
131
- window.cancelAnimationFrame(this._requestFrame);
132
- // stop playing
133
- this.setState({ isPlaying: false });
134
- // istanbul ignore else
135
- if (this.props.onPlayPause)
136
- this.props.onPlayPause(false);
137
- };
138
- // user clicked on timeline rail or dragged scrubber handle
139
- this._onTimelineChange = (values) => {
140
- const currentDuration = values[0];
141
- this._setDuration(currentDuration);
142
- };
143
- // set the current duration, which will call the OnChange callback
144
- this._setDuration = (currentDuration, updatedTotal) => {
145
- const actualDuration = Math.min(updatedTotal !== null && updatedTotal !== void 0 ? updatedTotal : this.state.totalDuration, Math.max(currentDuration, 0));
146
- this._timeLastCycle = new Date().getTime();
147
- // istanbul ignore else
148
- if (!this._unmounted)
149
- this.setState({ currentDuration: actualDuration });
150
- // istanbul ignore else
151
- if (this.props.onChange) {
152
- const fraction = actualDuration / (updatedTotal !== null && updatedTotal !== void 0 ? updatedTotal : this.state.totalDuration);
153
- this.props.onChange(fraction);
154
- }
155
- };
156
- // recursively update the animation until we hit the end or the pause button is clicked
157
- this._updateAnimation = (_timestamp) => {
158
- // istanbul ignore else
159
- if (!this.state.isPlaying && !this._unmounted) {
160
- return;
161
135
  }
162
- // update duration
163
- const currentTime = new Date().getTime();
164
- const millisecondsElapsed = currentTime - this._timeLastCycle;
165
- const duration = this.state.currentDuration + millisecondsElapsed;
166
- this._setDuration(duration);
167
- // stop the animation!
168
- if (duration >= this.state.totalDuration) {
169
- window.cancelAnimationFrame(this._requestFrame);
170
- this.setState({ isPlaying: false });
171
- if (this.state.repeat)
172
- this._replay();
173
- else {
174
- // istanbul ignore else
175
- if (this.props.onPlayPause)
176
- this.props.onPlayPause(false);
177
- }
136
+ });
137
+ }, [isPlaying, pause, playOrReplay, props.componentId]);
138
+ useAnimation(({ delta }) => {
139
+ const duration = currentDuration + delta;
140
+ updateDuration(duration);
141
+ if (duration >= totalDuration) {
142
+ if (repeat) {
143
+ setCurrentDuration(0);
178
144
  return;
179
145
  }
180
- // continue the animation - request the next frame
181
- this._requestFrame = window.requestAnimationFrame(this._updateAnimation);
182
- };
183
- this._replay = () => {
184
- // timeline was complete, restart from the beginning
185
- this.setState({ currentDuration: 0 }, () => this._play());
186
- };
187
- // user changed the total duration
188
- this._onTotalDurationChange = (value) => {
189
- // NOTE: we should reset the current duration to 0
190
- const milliseconds = this._getMilliseconds(value);
191
- this._onSetTotalDuration(milliseconds);
192
- };
193
- this._changeRepeatSetting = (newValue) => {
194
- // istanbul ignore else
195
- if (newValue !== undefined) {
196
- this.setState(() => ({ repeat: newValue }), () => {
197
- // istanbul ignore else
198
- if (this.props.onSettingsChange) {
199
- this.props.onSettingsChange({ loop: this.state.repeat });
200
- }
201
- });
202
- }
203
- };
204
- this._onRepeatChanged = () => {
205
- this.setState((prevState) => ({ repeat: !prevState.repeat }), () => {
206
- // istanbul ignore else
207
- if (this.props.onSettingsChange) {
208
- this.props.onSettingsChange({ loop: this.state.repeat });
209
- }
210
- });
211
- };
212
- this._currentDate = () => {
213
- const fraction = this.state.currentDuration / this.state.totalDuration;
214
- if (this.props.endDate && this.props.startDate) {
215
- const timeElapsed = (this.props.endDate.getTime() - this.props.startDate.getTime()) *
216
- fraction;
217
- return new Date(this.props.startDate.getTime() + timeElapsed);
218
- }
219
- return new Date();
220
- };
221
- this._onSetTotalDuration = (milliseconds) => {
222
- this.setState({ totalDuration: milliseconds }, () => {
223
- // istanbul ignore else
224
- if (this.props.onSettingsChange) {
225
- this.props.onSettingsChange({ duration: milliseconds });
226
- }
227
- });
228
- };
229
- this._renderSettings = () => {
230
- const createMenuItemNodes = (close) => {
231
- const { totalDuration } = this.state;
232
- let contextMenuItems = [];
233
- if (!this.props.appMenuItems) {
234
- contextMenuItems = this._standardTimelineMenuItems;
235
- }
236
- else {
237
- if (this.props.appMenuItemOption === "append") {
238
- contextMenuItems = this._standardTimelineMenuItems.concat(this.props.appMenuItems);
239
- }
240
- else if (this.props.appMenuItemOption === "prefix") {
241
- contextMenuItems = this.props.appMenuItems.concat(this._standardTimelineMenuItems);
242
- }
243
- else {
244
- contextMenuItems = this.props.appMenuItems;
245
- }
246
- }
247
- const itemNodes = [];
248
- let keyIndex = 0;
249
- if (this.state.includeRepeat) {
250
- const checked = this.state.repeat;
251
- const icon = checked ? (React.createElement("span", { className: "icon" },
252
- React.createElement(core_react_1.Icon, { iconSpec: React.createElement(itwinui_icons_react_1.SvgCheckmark, null) }),
253
- " ")) : (React.createElement("span", null));
254
- itemNodes.push(React.createElement(itwinui_react_1.MenuItem, { key: ++keyIndex, onClick: () => {
255
- this._onRepeatChanged();
256
- close();
257
- }, icon: icon }, this._repeatLabel));
258
- itemNodes.push(React.createElement(itwinui_react_1.MenuDivider, { key: ++keyIndex }));
259
- }
260
- contextMenuItems.forEach((item, index) => {
261
- itemNodes.push(this._createMenuItemNode(item, index + keyIndex + 1, totalDuration, close));
262
- });
263
- return itemNodes;
264
- };
265
- return (React.createElement(itwinui_react_1.DropdownMenu, { menuItems: createMenuItemNodes, placement: "top-start", popperOptions: {
266
- modifiers: [
267
- {
268
- name: "hide", // When the timeline is no longer visible, hide the popper.
269
- },
270
- {
271
- name: "preventOverflow",
272
- options: {
273
- altAxis: true, // Allow the popper to go below the reference element and use as much space as needed.
274
- },
275
- },
276
- {
277
- name: "computeStyles",
278
- options: {
279
- roundOffsets: ({ x, y }) => ({
280
- x,
281
- y: Math.max(y, 0), // Ensure that the top of the popper will not go over the top of the document.
282
- }),
283
- },
284
- },
285
- {
286
- name: "setPopperClass",
287
- enabled: true,
288
- phase: "beforeWrite",
289
- fn({ state }) {
290
- state.attributes.popper.class =
291
- "timeline-component-max-sized-scrolling-menu";
292
- },
293
- },
294
- ],
295
- } },
296
- React.createElement("span", { "data-testid": "timeline-settings", className: "timeline-settings icon", role: "button", tabIndex: -1, title: components_react_1.UiComponents.translate("button.label.settings") },
297
- React.createElement(core_react_1.Icon, { iconSpec: React.createElement(itwinui_icons_react_1.SvgMoreVertical, null) }))));
298
- };
299
- this.state = {
300
- isPlaying: false,
301
- minimized: true,
302
- currentDuration: props.initialDuration
303
- ? props.initialDuration
304
- : /* istanbul ignore next */ 0,
305
- totalDuration: this.props.totalDuration,
306
- repeat: this.props.repeat ? true : false,
307
- includeRepeat: this.props.includeRepeat || this.props.includeRepeat === undefined
308
- ? true
309
- : false,
310
- };
311
- this._repeatLabel = UiIModelComponents_1.UiIModelComponents.translate("timeline.repeat");
312
- // istanbul ignore else
313
- if (this.props.componentId) {
314
- // can't handle an event if we have no id
315
- this._removeListener = appui_abstract_1.UiAdmin.onGenericUiEvent.addListener(this._handleTimelinePausePlayEvent);
146
+ pause();
316
147
  }
317
- }
318
- componentWillUnmount() {
319
- if (this._removeListener)
320
- this._removeListener();
321
- window.cancelAnimationFrame(this._requestFrame);
322
- this._unmounted = true;
323
- }
324
- shouldComponentUpdate(nextProps, nextState) {
325
- let result = false;
326
- // istanbul ignore next
327
- if (nextState !== this.state ||
328
- nextProps !== this.props ||
329
- nextProps.startDate !== this.props.startDate ||
330
- nextProps.endDate !== this.props.endDate ||
331
- nextProps.initialDuration !== this.props.initialDuration ||
332
- nextProps.repeat !== this.props.repeat)
333
- result = true;
334
- return result;
335
- }
336
- componentDidUpdate(prevProps) {
337
- // istanbul ignore else
338
- if (this.props.initialDuration !== prevProps.initialDuration) {
339
- this._setDuration(this.props.initialDuration
340
- ? this.props.initialDuration
341
- : /* istanbul ignore next */ 0, this.props.totalDuration !== prevProps.totalDuration
342
- ? this.props.totalDuration
343
- : undefined);
148
+ }, isPlaying);
149
+ const onTimelineChange = (values) => {
150
+ const newDuration = values[0];
151
+ updateDuration(newDuration);
152
+ };
153
+ const currentDurationStr = toDisplayTime(currentDuration);
154
+ const totalDurationStr = toDisplayTime(totalDuration);
155
+ const hasDates = !!startDate && !!endDate;
156
+ return (React.createElement("div", { "data-testid": "timeline-component", className: "timeline-component" },
157
+ React.createElement(PlayButton_1.PlayButton, { isPlaying: isPlaying, onPlay: playOrReplay, onPause: pause }),
158
+ React.createElement("div", { className: "time-container" },
159
+ hasDates && (React.createElement("span", { "data-testid": "test-start-date", className: "timeline-date" }, (0, components_react_1.toDateString)(startDate, timeZoneOffset, dateFormatOptions))),
160
+ hasDates && !showDuration && (React.createElement("span", { "data-testid": "test-start-time", className: "timeline-time" }, (0, components_react_1.toTimeString)(startDate, timeZoneOffset, timeFormatOptions))),
161
+ showDuration && (React.createElement("span", { className: "timeline-duration-time" }, currentDurationStr))),
162
+ React.createElement(Scrubber_1.Scrubber, { className: "slider", currentDuration: currentDuration, totalDuration: totalDuration, startDate: startDate, endDate: endDate, isPlaying: isPlaying, showTime: !showDuration, onChange: onTimelineChange, onUpdate: onTimelineChange, timeZoneOffset: props.timeZoneOffset, markDate: props.markDate }),
163
+ React.createElement("div", { className: "time-container" },
164
+ hasDates && (React.createElement("span", { "data-testid": "test-end-date", className: "timeline-date" }, (0, components_react_1.toDateString)(endDate, timeZoneOffset))),
165
+ hasDates && !showDuration && (React.createElement("span", { className: "timeline-time" }, (0, components_react_1.toTimeString)(endDate, timeZoneOffset, timeFormatOptions))),
166
+ showDuration && (React.createElement(InlineEdit_1.InlineEdit, { className: "timeline-duration-time", defaultValue: totalDurationStr, onChange: (value) => {
167
+ const newTotalDuration = timeToMs(value);
168
+ updateTotalDuration(newTotalDuration);
169
+ } }))),
170
+ React.createElement(SettingsMenu, { appMenuItems: props.appMenuItems, appMenuItemOption: appMenuItemOption, includeRepeat: includeRepeat, repeat: repeat, totalDuration: totalDuration, onRepeatClick: () => {
171
+ updateRepeat(!repeat);
172
+ }, onTotalDurationChange: (newTotalDuration) => {
173
+ updateTotalDuration(newTotalDuration);
174
+ } })));
175
+ }
176
+ exports.TimelineComponent = TimelineComponent;
177
+ function SettingsMenu({ appMenuItems, appMenuItemOption, includeRepeat, repeat, totalDuration, onRepeatClick, onTotalDurationChange, }) {
178
+ const settingsLabel = React.useMemo(() => components_react_1.UiComponents.translate("button.label.settings"), []);
179
+ const repeatLabel = React.useMemo(() => UiIModelComponents_1.UiIModelComponents.translate("timeline.repeat"), []);
180
+ const standardItems = React.useMemo(() => [
181
+ {
182
+ label: UiIModelComponents_1.UiIModelComponents.translate("timeline.slow"),
183
+ timelineDuration: slowSpeed,
184
+ },
185
+ {
186
+ label: UiIModelComponents_1.UiIModelComponents.translate("timeline.medium"),
187
+ timelineDuration: mediumSpeed,
188
+ },
189
+ {
190
+ label: UiIModelComponents_1.UiIModelComponents.translate("timeline.fast"),
191
+ timelineDuration: fastSpeed,
192
+ },
193
+ ], []);
194
+ const menuItems = React.useMemo(() => {
195
+ if (!appMenuItems) {
196
+ return standardItems;
344
197
  }
345
- // istanbul ignore else
346
- if (this.props.repeat !== prevProps.repeat) {
347
- this._changeRepeatSetting(this.props.repeat);
198
+ if (appMenuItemOption === "append") {
199
+ return [...standardItems, ...appMenuItems];
348
200
  }
349
- // istanbul ignore else
350
- if (this.props.totalDuration !== prevProps.totalDuration) {
351
- this._onSetTotalDuration(this.props.totalDuration);
201
+ if (appMenuItemOption === "prefix") {
202
+ return [...appMenuItems, ...standardItems];
352
203
  }
353
- }
354
- _play() {
355
- // start playing
356
- this.setState({ isPlaying: true }, () => {
357
- // request the next frame
358
- this._timeLastCycle = new Date().getTime();
359
- this._requestFrame = window.requestAnimationFrame(this._updateAnimation);
360
- });
361
- }
362
- _displayTime(millisec) {
363
- const addZero = (i) => {
364
- return i < 10 ? `0${i}` : i;
204
+ // Replace
205
+ return appMenuItems;
206
+ }, [appMenuItemOption, appMenuItems, standardItems]);
207
+ return (React.createElement(itwinui_react_1.DropdownMenu, { menuItems: (close) => {
208
+ return [
209
+ ...(includeRepeat
210
+ ? [
211
+ React.createElement(itwinui_react_1.MenuItem, { key: "repeat", onClick: () => {
212
+ onRepeatClick();
213
+ close();
214
+ }, startIcon: repeat ? React.createElement(itwinui_icons_react_1.SvgCheckmark, null) : React.createElement(React.Fragment, null) }, repeatLabel),
215
+ React.createElement(itwinui_react_1.MenuDivider, { key: "divider" }),
216
+ ]
217
+ : []),
218
+ ...menuItems.map((item, index) => {
219
+ const checked = totalDuration === item.timelineDuration;
220
+ return (React.createElement(itwinui_react_1.MenuItem, { key: index, startIcon: checked ? React.createElement(itwinui_icons_react_1.SvgCheckmark, null) : React.createElement(React.Fragment, null), onClick: () => {
221
+ onTotalDurationChange(item.timelineDuration);
222
+ close();
223
+ } }, item.label));
224
+ }),
225
+ ];
226
+ }, placement: "top-start" },
227
+ React.createElement(itwinui_react_1.IconButton, { "data-testid": "timeline-settings", title: settingsLabel, styleType: "borderless" },
228
+ React.createElement(itwinui_icons_react_1.SvgMoreVertical, null))));
229
+ }
230
+ function useAnimation(onAnimate, playing = true) {
231
+ const onAnimateRef = React.useRef(onAnimate);
232
+ onAnimateRef.current = onAnimate;
233
+ const lastTimeRef = React.useRef();
234
+ React.useEffect(() => {
235
+ if (!playing)
236
+ return;
237
+ let handle = 0;
238
+ let didCancel = false;
239
+ const animate = (time) => {
240
+ if (lastTimeRef.current === undefined) {
241
+ lastTimeRef.current = time;
242
+ }
243
+ const delta = time - lastTimeRef.current;
244
+ lastTimeRef.current = time;
245
+ onAnimateRef.current({
246
+ delta,
247
+ });
248
+ if (didCancel)
249
+ return;
250
+ handle = window.requestAnimationFrame(animate);
365
251
  };
366
- const date = new Date(millisec);
367
- // const hours = date.getUTCHours();
368
- const minutes = date.getUTCMinutes();
369
- const seconds = date.getUTCSeconds();
370
- return `${addZero(minutes)}:${addZero(seconds)}`;
371
- }
372
- _getMilliseconds(time) {
373
- // istanbul ignore else - WIP
374
- if (time.indexOf(":") !== -1) {
375
- return ((Number(time.split(":")[0]) * 60 + Number(time.split(":")[1])) * 1000);
376
- }
377
- else {
378
- return Number(time) * 1000;
379
- }
380
- }
381
- _createMenuItemNode(item, index, currentTimelineDuration, close) {
382
- const label = item.label;
383
- const checked = currentTimelineDuration === item.timelineDuration;
384
- const icon = checked ? (React.createElement("span", { className: "icon" },
385
- React.createElement(core_react_1.Icon, { iconSpec: React.createElement(itwinui_icons_react_1.SvgCheckmark, null) }),
386
- " ")) : (React.createElement("span", null));
387
- return (React.createElement(itwinui_react_1.MenuItem, { key: index, icon: icon, onClick: () => {
388
- this._onSetTotalDuration(item.timelineDuration);
389
- close();
390
- } }, label));
252
+ handle = window.requestAnimationFrame(animate);
253
+ return () => {
254
+ didCancel = true;
255
+ lastTimeRef.current = undefined;
256
+ window.cancelAnimationFrame(handle);
257
+ };
258
+ }, [playing]);
259
+ }
260
+ function timeToMs(time) {
261
+ if (time.indexOf(":") !== -1) {
262
+ return ((Number(time.split(":")[0]) * 60 + Number(time.split(":")[1])) * 1000);
391
263
  }
392
- render() {
393
- const { startDate, endDate, showDuration, timeZoneOffset, dateFormatOptions, timeFormatOptions, } = this.props;
394
- const { currentDuration, totalDuration, minimized } = this.state;
395
- const currentDate = this._currentDate();
396
- const durationString = this._displayTime(currentDuration);
397
- const totalDurationString = this._displayTime(totalDuration);
398
- const hasDates = !!startDate && !!endDate;
399
- return (React.createElement("div", { "data-testid": "timeline-component", className: (0, classnames_1.default)("timeline-component", !!minimized && "minimized", hasDates && "has-dates") },
400
- React.createElement("div", { className: "header" },
401
- React.createElement(PlayerButton_1.PlayButton, { className: "play-button", isPlaying: this.state.isPlaying, onPlay: this._onPlay, onPause: this._onPause, "data-testid": "timeline-play" }),
402
- React.createElement(PlayerButton_1.PlayerButton, { className: "play-backward", icon: React.createElement(itwinui_icons_react_1.SvgCaretLeft, null), onClick: this._onBackward, title: UiIModelComponents_1.UiIModelComponents.translate("timeline.backward") }),
403
- React.createElement(PlayerButton_1.PlayerButton, { className: "play-button-step", icon: React.createElement(itwinui_icons_react_1.SvgPlayCircular, null), isPlaying: this.state.isPlaying, onPlay: this._onPlay, onPause: this._onPause, title: UiIModelComponents_1.UiIModelComponents.translate("timeline.step") }),
404
- React.createElement(PlayerButton_1.PlayerButton, { className: "play-forward", icon: React.createElement(itwinui_icons_react_1.SvgCaretRight, null), onClick: this._onForward, title: UiIModelComponents_1.UiIModelComponents.translate("timeline.backward") }),
405
- React.createElement("span", { className: "current-date" }, (0, components_react_1.toDateString)(currentDate, timeZoneOffset, dateFormatOptions))),
406
- React.createElement("div", { className: "scrubber" },
407
- React.createElement(PlayerButton_1.PlayButton, { className: "play-button", isPlaying: this.state.isPlaying, onPlay: this._onPlay, onPause: this._onPause }),
408
- React.createElement("div", { className: "start-time-container" },
409
- hasDates && (React.createElement("span", { "data-testid": "test-start-date", className: "start-date" }, (0, components_react_1.toDateString)(startDate, timeZoneOffset, dateFormatOptions))),
410
- hasDates && !showDuration && (React.createElement("span", { "data-testid": "test-start-time", className: "start-time" }, (0, components_react_1.toTimeString)(startDate, timeZoneOffset, timeFormatOptions))),
411
- showDuration && (React.createElement("span", { className: "duration-start-time" }, durationString))),
412
- React.createElement(Scrubber_1.Scrubber, { className: "slider", currentDuration: this.state.currentDuration, totalDuration: totalDuration, startDate: startDate, endDate: endDate, isPlaying: this.state.isPlaying, inMiniMode: !!minimized, showTime: !showDuration, onChange: this._onTimelineChange, onUpdate: this._onTimelineChange, timeZoneOffset: this.props.timeZoneOffset, markDate: this.props.markDate }),
413
- React.createElement("div", { className: "end-time-container" },
414
- hasDates && (React.createElement("span", { className: "end-date" }, (0, components_react_1.toDateString)(endDate, timeZoneOffset))),
415
- hasDates && !showDuration && (React.createElement("span", { className: "end-time" }, (0, components_react_1.toTimeString)(endDate, timeZoneOffset, timeFormatOptions))),
416
- showDuration && (React.createElement(InlineEdit_1.InlineEdit, { className: "duration-end-time", defaultValue: totalDurationString, onChange: this._onTotalDurationChange }))),
417
- minimized && this._renderSettings())));
264
+ else {
265
+ return Number(time) * 1000;
418
266
  }
419
267
  }
420
- exports.TimelineComponent = TimelineComponent;
268
+ function toDisplayTime(ms) {
269
+ const addZero = (i) => {
270
+ return i < 10 ? `0${i}` : i;
271
+ };
272
+ const date = new Date(ms);
273
+ // const hours = date.getUTCHours();
274
+ const minutes = date.getUTCMinutes();
275
+ const seconds = date.getUTCSeconds();
276
+ return `${addZero(minutes)}:${addZero(seconds)}`;
277
+ }
421
278
  //# sourceMappingURL=TimelineComponent.js.map