@itwin/imodel-components-react 4.10.0-dev.1 → 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 (96) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/lib/cjs/imodel-components-react/color/AlphaSlider.d.ts.map +1 -1
  3. package/lib/cjs/imodel-components-react/color/AlphaSlider.js +8 -6
  4. package/lib/cjs/imodel-components-react/color/AlphaSlider.js.map +1 -1
  5. package/lib/cjs/imodel-components-react/color/HueSlider.d.ts.map +1 -1
  6. package/lib/cjs/imodel-components-react/color/HueSlider.js +8 -6
  7. package/lib/cjs/imodel-components-react/color/HueSlider.js.map +1 -1
  8. package/lib/cjs/imodel-components-react/color/SaturationPicker.js +8 -8
  9. package/lib/cjs/imodel-components-react/color/SaturationPicker.js.map +1 -1
  10. package/lib/cjs/imodel-components-react/editors/ColorEditor.js +1 -1
  11. package/lib/cjs/imodel-components-react/editors/ColorEditor.js.map +1 -1
  12. package/lib/cjs/imodel-components-react/editors/WeightEditor.d.ts.map +1 -1
  13. package/lib/cjs/imodel-components-react/editors/WeightEditor.js.map +1 -1
  14. package/lib/cjs/imodel-components-react/inputs/QuantityNumberInput.js +4 -4
  15. package/lib/cjs/imodel-components-react/inputs/QuantityNumberInput.js.map +1 -1
  16. package/lib/cjs/imodel-components-react/lineweight/WeightPickerButton.js +3 -3
  17. package/lib/cjs/imodel-components-react/lineweight/WeightPickerButton.js.map +1 -1
  18. package/lib/cjs/imodel-components-react/navigationaids/DrawingNavigationAid.d.ts.map +1 -1
  19. package/lib/cjs/imodel-components-react/navigationaids/DrawingNavigationAid.js +2 -1
  20. package/lib/cjs/imodel-components-react/navigationaids/DrawingNavigationAid.js.map +1 -1
  21. package/lib/cjs/imodel-components-react/quantityformat/FormatSample.js +1 -1
  22. package/lib/cjs/imodel-components-react/quantityformat/FormatSample.js.map +1 -1
  23. package/lib/cjs/imodel-components-react/quantityformat/MiscFormatOptions.js +1 -1
  24. package/lib/cjs/imodel-components-react/quantityformat/MiscFormatOptions.js.map +1 -1
  25. package/lib/cjs/imodel-components-react/timeline/InlineEdit.js +2 -2
  26. package/lib/cjs/imodel-components-react/timeline/InlineEdit.js.map +1 -1
  27. package/lib/cjs/imodel-components-react/timeline/PlayButton.d.ts +24 -0
  28. package/lib/cjs/imodel-components-react/timeline/PlayButton.d.ts.map +1 -0
  29. package/lib/cjs/imodel-components-react/timeline/{PlayerButton.js → PlayButton.js} +5 -25
  30. package/lib/cjs/imodel-components-react/timeline/PlayButton.js.map +1 -0
  31. package/lib/cjs/imodel-components-react/timeline/{PlayerButton.scss → PlayButton.scss} +1 -1
  32. package/lib/cjs/imodel-components-react/timeline/Scrubber.d.ts +0 -1
  33. package/lib/cjs/imodel-components-react/timeline/Scrubber.d.ts.map +1 -1
  34. package/lib/cjs/imodel-components-react/timeline/Scrubber.js.map +1 -1
  35. package/lib/cjs/imodel-components-react/timeline/SolarTimeline.js +2 -2
  36. package/lib/cjs/imodel-components-react/timeline/SolarTimeline.js.map +1 -1
  37. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.d.ts +28 -66
  38. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.d.ts.map +1 -1
  39. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.js +216 -329
  40. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.js.map +1 -1
  41. package/lib/cjs/imodel-components-react/timeline/TimelineComponent.scss +27 -140
  42. package/lib/cjs/imodel-components-react.d.ts +0 -1
  43. package/lib/cjs/imodel-components-react.d.ts.map +1 -1
  44. package/lib/cjs/imodel-components-react.js +0 -1
  45. package/lib/cjs/imodel-components-react.js.map +1 -1
  46. package/lib/esm/imodel-components-react/color/AlphaSlider.d.ts.map +1 -1
  47. package/lib/esm/imodel-components-react/color/AlphaSlider.js +8 -6
  48. package/lib/esm/imodel-components-react/color/AlphaSlider.js.map +1 -1
  49. package/lib/esm/imodel-components-react/color/HueSlider.d.ts.map +1 -1
  50. package/lib/esm/imodel-components-react/color/HueSlider.js +8 -6
  51. package/lib/esm/imodel-components-react/color/HueSlider.js.map +1 -1
  52. package/lib/esm/imodel-components-react/color/SaturationPicker.js +8 -8
  53. package/lib/esm/imodel-components-react/color/SaturationPicker.js.map +1 -1
  54. package/lib/esm/imodel-components-react/editors/ColorEditor.js +1 -1
  55. package/lib/esm/imodel-components-react/editors/ColorEditor.js.map +1 -1
  56. package/lib/esm/imodel-components-react/editors/WeightEditor.d.ts.map +1 -1
  57. package/lib/esm/imodel-components-react/editors/WeightEditor.js.map +1 -1
  58. package/lib/esm/imodel-components-react/inputs/QuantityNumberInput.js +4 -4
  59. package/lib/esm/imodel-components-react/inputs/QuantityNumberInput.js.map +1 -1
  60. package/lib/esm/imodel-components-react/lineweight/WeightPickerButton.js +3 -3
  61. package/lib/esm/imodel-components-react/lineweight/WeightPickerButton.js.map +1 -1
  62. package/lib/esm/imodel-components-react/navigationaids/DrawingNavigationAid.d.ts.map +1 -1
  63. package/lib/esm/imodel-components-react/navigationaids/DrawingNavigationAid.js +2 -1
  64. package/lib/esm/imodel-components-react/navigationaids/DrawingNavigationAid.js.map +1 -1
  65. package/lib/esm/imodel-components-react/quantityformat/FormatSample.js +1 -1
  66. package/lib/esm/imodel-components-react/quantityformat/FormatSample.js.map +1 -1
  67. package/lib/esm/imodel-components-react/quantityformat/MiscFormatOptions.js +1 -1
  68. package/lib/esm/imodel-components-react/quantityformat/MiscFormatOptions.js.map +1 -1
  69. package/lib/esm/imodel-components-react/timeline/InlineEdit.js +2 -2
  70. package/lib/esm/imodel-components-react/timeline/InlineEdit.js.map +1 -1
  71. package/lib/esm/imodel-components-react/timeline/PlayButton.d.ts +24 -0
  72. package/lib/esm/imodel-components-react/timeline/PlayButton.d.ts.map +1 -0
  73. package/lib/esm/imodel-components-react/timeline/{PlayerButton.js → PlayButton.js} +4 -23
  74. package/lib/esm/imodel-components-react/timeline/PlayButton.js.map +1 -0
  75. package/lib/esm/imodel-components-react/timeline/{PlayerButton.scss → PlayButton.scss} +1 -1
  76. package/lib/esm/imodel-components-react/timeline/Scrubber.d.ts +0 -1
  77. package/lib/esm/imodel-components-react/timeline/Scrubber.d.ts.map +1 -1
  78. package/lib/esm/imodel-components-react/timeline/Scrubber.js.map +1 -1
  79. package/lib/esm/imodel-components-react/timeline/SolarTimeline.js +1 -1
  80. package/lib/esm/imodel-components-react/timeline/SolarTimeline.js.map +1 -1
  81. package/lib/esm/imodel-components-react/timeline/TimelineComponent.d.ts +28 -66
  82. package/lib/esm/imodel-components-react/timeline/TimelineComponent.d.ts.map +1 -1
  83. package/lib/esm/imodel-components-react/timeline/TimelineComponent.js +217 -327
  84. package/lib/esm/imodel-components-react/timeline/TimelineComponent.js.map +1 -1
  85. package/lib/esm/imodel-components-react/timeline/TimelineComponent.scss +27 -140
  86. package/lib/esm/imodel-components-react.d.ts +0 -1
  87. package/lib/esm/imodel-components-react.d.ts.map +1 -1
  88. package/lib/esm/imodel-components-react.js +0 -1
  89. package/lib/esm/imodel-components-react.js.map +1 -1
  90. package/package.json +16 -16
  91. package/lib/cjs/imodel-components-react/timeline/PlayerButton.d.ts +0 -34
  92. package/lib/cjs/imodel-components-react/timeline/PlayerButton.d.ts.map +0 -1
  93. package/lib/cjs/imodel-components-react/timeline/PlayerButton.js.map +0 -1
  94. package/lib/esm/imodel-components-react/timeline/PlayerButton.d.ts +0 -34
  95. package/lib/esm/imodel-components-react/timeline/PlayerButton.d.ts.map +0 -1
  96. package/lib/esm/imodel-components-react/timeline/PlayerButton.js.map +0 -1
@@ -22,370 +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 ?? 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 ?? 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
- }, startIcon: 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" },
266
- React.createElement("span", { "data-testid": "timeline-settings", className: "timeline-settings icon", role: "button", tabIndex: -1, title: components_react_1.UiComponents.translate("button.label.settings") },
267
- React.createElement(core_react_1.Icon, { iconSpec: React.createElement(itwinui_icons_react_1.SvgMoreVertical, null) }))));
268
- };
269
- this.state = {
270
- isPlaying: false,
271
- minimized: true,
272
- currentDuration: props.initialDuration
273
- ? props.initialDuration
274
- : /* istanbul ignore next */ 0,
275
- totalDuration: this.props.totalDuration,
276
- repeat: this.props.repeat ? true : false,
277
- includeRepeat: this.props.includeRepeat || this.props.includeRepeat === undefined
278
- ? true
279
- : false,
280
- };
281
- this._repeatLabel = UiIModelComponents_1.UiIModelComponents.translate("timeline.repeat");
282
- // istanbul ignore else
283
- if (this.props.componentId) {
284
- // can't handle an event if we have no id
285
- this._removeListener = appui_abstract_1.UiAdmin.onGenericUiEvent.addListener(this._handleTimelinePausePlayEvent);
146
+ pause();
286
147
  }
287
- }
288
- componentWillUnmount() {
289
- if (this._removeListener)
290
- this._removeListener();
291
- window.cancelAnimationFrame(this._requestFrame);
292
- this._unmounted = true;
293
- }
294
- shouldComponentUpdate(nextProps, nextState) {
295
- let result = false;
296
- // istanbul ignore next
297
- if (nextState !== this.state ||
298
- nextProps !== this.props ||
299
- nextProps.startDate !== this.props.startDate ||
300
- nextProps.endDate !== this.props.endDate ||
301
- nextProps.initialDuration !== this.props.initialDuration ||
302
- nextProps.repeat !== this.props.repeat)
303
- result = true;
304
- return result;
305
- }
306
- componentDidUpdate(prevProps) {
307
- // istanbul ignore else
308
- if (this.props.initialDuration !== prevProps.initialDuration) {
309
- this._setDuration(this.props.initialDuration
310
- ? this.props.initialDuration
311
- : /* istanbul ignore next */ 0, this.props.totalDuration !== prevProps.totalDuration
312
- ? this.props.totalDuration
313
- : 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;
314
197
  }
315
- // istanbul ignore else
316
- if (this.props.repeat !== prevProps.repeat) {
317
- this._changeRepeatSetting(this.props.repeat);
198
+ if (appMenuItemOption === "append") {
199
+ return [...standardItems, ...appMenuItems];
318
200
  }
319
- // istanbul ignore else
320
- if (this.props.totalDuration !== prevProps.totalDuration) {
321
- this._onSetTotalDuration(this.props.totalDuration);
201
+ if (appMenuItemOption === "prefix") {
202
+ return [...appMenuItems, ...standardItems];
322
203
  }
323
- }
324
- _play() {
325
- // start playing
326
- this.setState({ isPlaying: true }, () => {
327
- // request the next frame
328
- this._timeLastCycle = new Date().getTime();
329
- this._requestFrame = window.requestAnimationFrame(this._updateAnimation);
330
- });
331
- }
332
- _displayTime(millisec) {
333
- const addZero = (i) => {
334
- 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);
335
251
  };
336
- const date = new Date(millisec);
337
- // const hours = date.getUTCHours();
338
- const minutes = date.getUTCMinutes();
339
- const seconds = date.getUTCSeconds();
340
- return `${addZero(minutes)}:${addZero(seconds)}`;
341
- }
342
- _getMilliseconds(time) {
343
- // istanbul ignore else - WIP
344
- if (time.indexOf(":") !== -1) {
345
- return ((Number(time.split(":")[0]) * 60 + Number(time.split(":")[1])) * 1000);
346
- }
347
- else {
348
- return Number(time) * 1000;
349
- }
350
- }
351
- _createMenuItemNode(item, index, currentTimelineDuration, close) {
352
- const label = item.label;
353
- const checked = currentTimelineDuration === item.timelineDuration;
354
- const icon = checked ? (React.createElement("span", { className: "icon" },
355
- React.createElement(core_react_1.Icon, { iconSpec: React.createElement(itwinui_icons_react_1.SvgCheckmark, null) }),
356
- " ")) : (React.createElement("span", null));
357
- return (React.createElement(itwinui_react_1.MenuItem, { key: index, startIcon: icon, onClick: () => {
358
- this._onSetTotalDuration(item.timelineDuration);
359
- close();
360
- } }, 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);
361
263
  }
362
- render() {
363
- const { startDate, endDate, showDuration, timeZoneOffset, dateFormatOptions, timeFormatOptions, } = this.props;
364
- const { currentDuration, totalDuration, minimized } = this.state;
365
- const currentDate = this._currentDate();
366
- const durationString = this._displayTime(currentDuration);
367
- const totalDurationString = this._displayTime(totalDuration);
368
- const hasDates = !!startDate && !!endDate;
369
- return (React.createElement("div", { "data-testid": "timeline-component", className: (0, classnames_1.default)("timeline-component", !!minimized && "minimized", hasDates && "has-dates") },
370
- React.createElement("div", { className: "header" },
371
- React.createElement(PlayerButton_1.PlayButton, { className: "play-button", isPlaying: this.state.isPlaying, onPlay: this._onPlay, onPause: this._onPause, "data-testid": "timeline-play" }),
372
- 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") }),
373
- 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") }),
374
- 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") }),
375
- React.createElement("span", { className: "current-date" }, (0, components_react_1.toDateString)(currentDate, timeZoneOffset, dateFormatOptions))),
376
- React.createElement("div", { className: "scrubber" },
377
- React.createElement(PlayerButton_1.PlayButton, { className: "play-button", isPlaying: this.state.isPlaying, onPlay: this._onPlay, onPause: this._onPause }),
378
- React.createElement("div", { className: "start-time-container" },
379
- hasDates && (React.createElement("span", { "data-testid": "test-start-date", className: "start-date" }, (0, components_react_1.toDateString)(startDate, timeZoneOffset, dateFormatOptions))),
380
- hasDates && !showDuration && (React.createElement("span", { "data-testid": "test-start-time", className: "start-time" }, (0, components_react_1.toTimeString)(startDate, timeZoneOffset, timeFormatOptions))),
381
- showDuration && (React.createElement("span", { className: "duration-start-time" }, durationString))),
382
- 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 }),
383
- React.createElement("div", { className: "end-time-container" },
384
- hasDates && (React.createElement("span", { className: "end-date" }, (0, components_react_1.toDateString)(endDate, timeZoneOffset))),
385
- hasDates && !showDuration && (React.createElement("span", { className: "end-time" }, (0, components_react_1.toTimeString)(endDate, timeZoneOffset, timeFormatOptions))),
386
- showDuration && (React.createElement(InlineEdit_1.InlineEdit, { className: "duration-end-time", defaultValue: totalDurationString, onChange: this._onTotalDurationChange }))),
387
- minimized && this._renderSettings())));
264
+ else {
265
+ return Number(time) * 1000;
388
266
  }
389
267
  }
390
- 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
+ }
391
278
  //# sourceMappingURL=TimelineComponent.js.map